@wordpress/block-library
Version:
Block library for the WordPress editor.
298 lines (297 loc) • 9.1 kB
JavaScript
// packages/block-library/src/icon/edit.jsx
import clsx from "clsx";
import { __, sprintf } from "@wordpress/i18n";
import {
DropdownMenu,
TextControl,
ToolbarButton,
__experimentalToolsPanel as ToolsPanel,
__experimentalToolsPanelItem as ToolsPanelItem
} from "@wordpress/components";
import {
flipHorizontal as flipHorizontalIcon,
flipVertical as flipVerticalIcon,
rotateRight
} from "@wordpress/icons";
import {
BlockControls,
InspectorControls,
useBlockProps,
useBlockEditingMode,
__experimentalUseColorProps as useColorProps,
__experimentalUseBorderProps as useBorderProps,
__experimentalGetSpacingClassesAndStyles as useSpacingProps,
getDimensionsClassesAndStyles as useDimensionsProps
} from "@wordpress/block-editor";
import { getBlockBindingsSource } from "@wordpress/blocks";
import { useState } from "@wordpress/element";
import { SVG, Rect, Path } from "@wordpress/primitives";
import { useSelect } from "@wordpress/data";
import { store as coreDataStore } from "@wordpress/core-data";
import { useToolsPanelDropdownMenuProps } from "../utils/hooks.mjs";
import HtmlRenderer from "../utils/html-renderer.mjs";
import { CustomInserterModal } from "./components/index.mjs";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
var ICON_NAME_REGEX = /^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?\/[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?$/;
var IconPlaceholder = ({ className, style }) => /* @__PURE__ */ jsxs(
SVG,
{
xmlns: "http://www.w3.org/2000/svg",
viewBox: "0 0 60 60",
preserveAspectRatio: "none",
fill: "none",
"aria-hidden": "true",
className: clsx("wp-block-icon__placeholder", className),
style,
children: [
/* @__PURE__ */ jsx(Rect, { width: "60", height: "60", fill: "currentColor", fillOpacity: 0.1 }),
/* @__PURE__ */ jsx(
Path,
{
vectorEffect: "non-scaling-stroke",
stroke: "currentColor",
strokeOpacity: 0.25,
d: "M60 60 0 0"
}
)
]
}
);
function Edit({ attributes, setAttributes, isSelected, context }) {
const {
icon,
ariaLabel,
flipHorizontal,
flipVertical,
rotation,
metadata
} = attributes;
const [isInserterOpen, setInserterOpen] = useState(false);
const isContentOnlyMode = useBlockEditingMode() === "contentOnly";
const { isIconBindingReadOnly = false, iconBindingReadOnlyMessage } = useSelect(
(select) => {
if (!isSelected) {
return {};
}
const iconBinding = metadata?.bindings?.icon;
const blockBindingsSource = getBlockBindingsSource(
iconBinding?.source
);
return {
isIconBindingReadOnly: !!iconBinding && !blockBindingsSource?.canUserEditValue?.({
select,
context,
args: iconBinding.args
}),
iconBindingReadOnlyMessage: blockBindingsSource?.label ? sprintf(
/* translators: %s: Label of the bindings source. */
__("Connected to %s"),
blockBindingsSource.label
) : __("Connected to dynamic data")
};
},
[context, isSelected, metadata?.bindings?.icon]
);
const colorProps = useColorProps(attributes);
const spacingProps = useSpacingProps({
style: {
spacing: {
padding: attributes.style?.spacing?.padding
}
}
});
const borderProps = useBorderProps(attributes);
const dimensionsProps = useDimensionsProps(attributes);
const selectedIcon = useSelect(
(select) => {
if (typeof icon !== "string" || !ICON_NAME_REGEX.test(icon)) {
return null;
}
return select(coreDataStore).getEntityRecord(
"root",
"icon",
icon
);
},
[icon]
);
const iconToDisplay = selectedIcon?.content || "";
const flipClasses = {
"is-flip-horizontal": flipHorizontal,
"is-flip-vertical": flipVertical
};
const rotationStyle = rotation ? { rotate: `${rotation}deg` } : {};
const iconToolbarButtonLabel = icon ? __("Replace") : __("Choose icon");
const blockControls = /* @__PURE__ */ jsxs(Fragment, { children: [
icon && /* @__PURE__ */ jsxs(BlockControls, { group: "block", children: [
/* @__PURE__ */ jsx(
ToolbarButton,
{
icon: flipHorizontalIcon,
label: __("Flip horizontal"),
isPressed: flipHorizontal,
onClick: () => setAttributes({
flipHorizontal: !flipHorizontal
})
}
),
/* @__PURE__ */ jsx(
ToolbarButton,
{
icon: flipVerticalIcon,
label: __("Flip vertical"),
isPressed: flipVertical,
onClick: () => setAttributes({
flipVertical: !flipVertical
})
}
),
/* @__PURE__ */ jsx(
ToolbarButton,
{
icon: rotateRight,
label: __("Rotate"),
onClick: () => setAttributes({
rotation: ((rotation || 0) + 90) % 360
})
}
)
] }),
/* @__PURE__ */ jsxs(BlockControls, { group: "other", children: [
/* @__PURE__ */ jsx(
ToolbarButton,
{
disabled: isIconBindingReadOnly,
label: isIconBindingReadOnly ? iconBindingReadOnlyMessage : void 0,
showTooltip: isIconBindingReadOnly,
"aria-label": isIconBindingReadOnly ? iconToolbarButtonLabel : void 0,
onClick: () => {
setInserterOpen(true);
},
children: iconToolbarButtonLabel
}
),
isContentOnlyMode && icon && // Add some extra controls for content attributes when content only mode is active.
// With content only mode active, the inspector is hidden, so users need another way
// to edit these attributes.
/* @__PURE__ */ jsx(
DropdownMenu,
{
icon: "",
toggleProps: {
as: ToolbarButton
},
popoverProps: {
className: "is-alternate"
},
text: __("Label"),
children: () => /* @__PURE__ */ jsx(
TextControl,
{
className: "wp-block-icon__toolbar-content",
label: __("Label"),
value: ariaLabel || "",
onChange: (value) => setAttributes({
ariaLabel: value
}),
help: __(
"Briefly describe the icon to help screen reader users. Leave blank for decorative icons."
)
}
)
}
)
] })
] });
const dropdownMenuProps = useToolsPanelDropdownMenuProps();
const inspectorControls = icon && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(InspectorControls, { group: "settings", children: /* @__PURE__ */ jsx(
ToolsPanel,
{
label: __("Settings"),
resetAll: () => setAttributes({
ariaLabel: void 0
}),
dropdownMenuProps,
children: /* @__PURE__ */ jsx(
ToolsPanelItem,
{
label: __("Label"),
isShownByDefault: true,
hasValue: () => !!ariaLabel,
onDeselect: () => setAttributes({ ariaLabel: void 0 }),
children: /* @__PURE__ */ jsx(
TextControl,
{
label: __("Label"),
help: __(
"Briefly describe the icon to help screen reader users. Leave blank for decorative icons."
),
value: ariaLabel || "",
onChange: (value) => setAttributes({ ariaLabel: value })
}
)
}
)
}
) }) });
return /* @__PURE__ */ jsxs(Fragment, { children: [
blockControls,
inspectorControls,
/* @__PURE__ */ jsx("div", { ...useBlockProps(), children: iconToDisplay ? /* @__PURE__ */ jsx(
HtmlRenderer,
{
html: iconToDisplay,
wrapperProps: {
className: clsx(
colorProps.className,
borderProps.className,
spacingProps.className,
dimensionsProps.className,
flipClasses
),
style: {
...colorProps.style,
...borderProps.style,
...spacingProps.style,
...dimensionsProps.style,
...rotationStyle
}
}
}
) : /* @__PURE__ */ jsx(
IconPlaceholder,
{
className: clsx(
borderProps.className,
spacingProps.className,
dimensionsProps.className,
flipClasses
),
style: {
...borderProps.style,
...spacingProps.style,
...dimensionsProps.style,
...rotationStyle,
height: "auto"
}
}
) }),
isInserterOpen && /* @__PURE__ */ jsx(
CustomInserterModal,
{
onClose: () => setInserterOpen(false),
value: attributes.icon,
onChange: (name) => {
setAttributes({ icon: name });
setInserterOpen(false);
}
}
)
] });
}
var edit_default = Edit;
export {
Edit,
edit_default as default
};
//# sourceMappingURL=edit.mjs.map