@wordpress/block-editor
Version:
571 lines (570 loc) • 19 kB
JavaScript
// packages/block-editor/src/components/global-styles/typography-panel.js
import {
FontSizePicker,
__experimentalNumberControl as NumberControl,
__experimentalToolsPanel as ToolsPanel,
__experimentalToolsPanelItem as ToolsPanelItem,
Notice
} from "@wordpress/components";
import { __ } from "@wordpress/i18n";
import { useCallback, useMemo, useEffect } from "@wordpress/element";
import { getValueFromVariable } from "@wordpress/global-styles-engine";
import FontFamilyControl from "../font-family";
import FontAppearanceControl from "../font-appearance-control";
import LineHeightControl from "../line-height-control";
import LetterSpacingControl from "../letter-spacing-control";
import TextAlignmentControl from "../text-alignment-control";
import TextTransformControl from "../text-transform-control";
import TextDecorationControl from "../text-decoration-control";
import WritingModeControl from "../writing-mode-control";
import { useToolsPanelDropdownMenuProps } from "./utils";
import { setImmutably } from "../../utils/object";
import {
getMergedFontFamiliesAndFontFamilyFaces,
findNearestStyleAndWeight
} from "./typography-utils";
import { jsx, jsxs } from "react/jsx-runtime";
var MIN_TEXT_COLUMNS = 1;
var MAX_TEXT_COLUMNS = 6;
function useHasTypographyPanel(settings) {
const hasFontFamily = useHasFontFamilyControl(settings);
const hasLineHeight = useHasLineHeightControl(settings);
const hasFontAppearance = useHasAppearanceControl(settings);
const hasLetterSpacing = useHasLetterSpacingControl(settings);
const hasTextAlign = useHasTextAlignmentControl(settings);
const hasTextTransform = useHasTextTransformControl(settings);
const hasTextDecoration = useHasTextDecorationControl(settings);
const hasWritingMode = useHasWritingModeControl(settings);
const hasTextColumns = useHasTextColumnsControl(settings);
const hasFontSize = useHasFontSizeControl(settings);
return hasFontFamily || hasLineHeight || hasFontAppearance || hasLetterSpacing || hasTextAlign || hasTextTransform || hasFontSize || hasTextDecoration || hasWritingMode || hasTextColumns;
}
function useHasFontSizeControl(settings) {
return settings?.typography?.defaultFontSizes !== false && settings?.typography?.fontSizes?.default?.length || settings?.typography?.fontSizes?.theme?.length || settings?.typography?.fontSizes?.custom?.length || settings?.typography?.customFontSize;
}
function useHasFontFamilyControl(settings) {
return ["default", "theme", "custom"].some(
(key) => settings?.typography?.fontFamilies?.[key]?.length
);
}
function useHasLineHeightControl(settings) {
return settings?.typography?.lineHeight;
}
function useHasAppearanceControl(settings) {
return settings?.typography?.fontStyle || settings?.typography?.fontWeight;
}
function useAppearanceControlLabel(settings) {
if (!settings?.typography?.fontStyle) {
return __("Font weight");
}
if (!settings?.typography?.fontWeight) {
return __("Font style");
}
return __("Appearance");
}
function useHasLetterSpacingControl(settings) {
return settings?.typography?.letterSpacing;
}
function useHasTextTransformControl(settings) {
return settings?.typography?.textTransform;
}
function useHasTextAlignmentControl(settings) {
return settings?.typography?.textAlign;
}
function useHasTextDecorationControl(settings) {
return settings?.typography?.textDecoration;
}
function useHasWritingModeControl(settings) {
return settings?.typography?.writingMode;
}
function useHasTextColumnsControl(settings) {
return settings?.typography?.textColumns;
}
function getMergedFontSizes(settings) {
const fontSizes = settings?.typography?.fontSizes;
const defaultFontSizesEnabled = !!settings?.typography?.defaultFontSizes;
return [
...fontSizes?.custom ?? [],
...fontSizes?.theme ?? [],
...defaultFontSizesEnabled ? fontSizes?.default ?? [] : []
];
}
function TypographyToolsPanel({
resetAllFilter,
onChange,
value,
panelId,
children
}) {
const dropdownMenuProps = useToolsPanelDropdownMenuProps();
const resetAll = () => {
const updatedValue = resetAllFilter(value);
onChange(updatedValue);
};
return /* @__PURE__ */ jsx(
ToolsPanel,
{
label: __("Typography"),
resetAll,
panelId,
dropdownMenuProps,
children
}
);
}
var DEFAULT_CONTROLS = {
fontFamily: true,
fontSize: true,
fontAppearance: true,
lineHeight: true,
letterSpacing: true,
textAlign: true,
textTransform: true,
textDecoration: true,
writingMode: true,
textColumns: true
};
function TypographyPanel({
as: Wrapper = TypographyToolsPanel,
value,
onChange,
inheritedValue = value,
settings,
panelId,
defaultControls = DEFAULT_CONTROLS,
fitText = false
}) {
const decodeValue = (rawValue) => getValueFromVariable({ settings }, "", rawValue);
const hasFontFamilyEnabled = useHasFontFamilyControl(settings);
const fontFamily = decodeValue(inheritedValue?.typography?.fontFamily);
const { fontFamilies, fontFamilyFaces } = useMemo(() => {
return getMergedFontFamiliesAndFontFamilyFaces(settings, fontFamily);
}, [settings, fontFamily]);
const setFontFamily = (newValue) => {
const slug = fontFamilies?.find(
({ fontFamily: f }) => f === newValue
)?.slug;
onChange(
setImmutably(
value,
["typography", "fontFamily"],
slug ? `var:preset|font-family|${slug}` : newValue || void 0
)
);
};
const hasFontFamily = () => !!value?.typography?.fontFamily;
const resetFontFamily = () => setFontFamily(void 0);
const hasFontSizeEnabled = useHasFontSizeControl(settings);
const disableCustomFontSizes = !settings?.typography?.customFontSize;
const mergedFontSizes = getMergedFontSizes(settings);
const fontSize = decodeValue(inheritedValue?.typography?.fontSize);
const currentFontSizeSlug = (() => {
const rawValue = inheritedValue?.typography?.fontSize;
if (!rawValue || typeof rawValue !== "string") {
return void 0;
}
if (rawValue.startsWith("var:preset|font-size|")) {
return rawValue.replace("var:preset|font-size|", "");
}
const cssVarMatch = rawValue.match(
/^var\(--wp--preset--font-size--([^)]+)\)$/
);
if (cssVarMatch) {
return cssVarMatch[1];
}
return void 0;
})();
const setFontSize = (newValue, metadata) => {
const actualValue = !!metadata?.slug ? `var:preset|font-size|${metadata?.slug}` : newValue;
onChange(
setImmutably(
value,
["typography", "fontSize"],
actualValue || void 0
)
);
};
const hasFontSize = () => !!value?.typography?.fontSize;
const resetFontSize = () => setFontSize(void 0);
const hasAppearanceControl = useHasAppearanceControl(settings);
const appearanceControlLabel = useAppearanceControlLabel(settings);
const hasFontStyles = settings?.typography?.fontStyle;
const hasFontWeights = settings?.typography?.fontWeight;
const fontStyle = decodeValue(inheritedValue?.typography?.fontStyle);
const fontWeight = decodeValue(inheritedValue?.typography?.fontWeight);
const { nearestFontStyle, nearestFontWeight } = findNearestStyleAndWeight(
fontFamilyFaces,
fontStyle,
fontWeight
);
const setFontAppearance = useCallback(
({ fontStyle: newFontStyle, fontWeight: newFontWeight }) => {
if (newFontStyle !== fontStyle || newFontWeight !== fontWeight) {
onChange({
...value,
typography: {
...value?.typography,
fontStyle: newFontStyle || void 0,
fontWeight: newFontWeight || void 0
}
});
}
},
[fontStyle, fontWeight, onChange, value]
);
const hasFontAppearance = () => !!value?.typography?.fontStyle || !!value?.typography?.fontWeight;
const resetFontAppearance = useCallback(() => {
setFontAppearance({});
}, [setFontAppearance]);
useEffect(() => {
if (nearestFontStyle && nearestFontWeight) {
setFontAppearance({
fontStyle: nearestFontStyle,
fontWeight: nearestFontWeight
});
} else {
resetFontAppearance();
}
}, [
nearestFontStyle,
nearestFontWeight,
resetFontAppearance,
setFontAppearance
]);
const hasLineHeightEnabled = useHasLineHeightControl(settings);
const lineHeight = decodeValue(inheritedValue?.typography?.lineHeight);
const setLineHeight = (newValue) => {
onChange(
setImmutably(
value,
["typography", "lineHeight"],
newValue || void 0
)
);
};
const hasLineHeight = () => value?.typography?.lineHeight !== void 0;
const resetLineHeight = () => setLineHeight(void 0);
const hasLetterSpacingControl = useHasLetterSpacingControl(settings);
const letterSpacing = decodeValue(
inheritedValue?.typography?.letterSpacing
);
const setLetterSpacing = (newValue) => {
onChange(
setImmutably(
value,
["typography", "letterSpacing"],
newValue || void 0
)
);
};
const hasLetterSpacing = () => !!value?.typography?.letterSpacing;
const resetLetterSpacing = () => setLetterSpacing(void 0);
const hasTextColumnsControl = useHasTextColumnsControl(settings);
const textColumns = decodeValue(inheritedValue?.typography?.textColumns);
const setTextColumns = (newValue) => {
onChange(
setImmutably(
value,
["typography", "textColumns"],
newValue || void 0
)
);
};
const hasTextColumns = () => !!value?.typography?.textColumns;
const resetTextColumns = () => setTextColumns(void 0);
const hasTextTransformControl = useHasTextTransformControl(settings);
const textTransform = decodeValue(
inheritedValue?.typography?.textTransform
);
const setTextTransform = (newValue) => {
onChange(
setImmutably(
value,
["typography", "textTransform"],
newValue || void 0
)
);
};
const hasTextTransform = () => !!value?.typography?.textTransform;
const resetTextTransform = () => setTextTransform(void 0);
const hasTextDecorationControl = useHasTextDecorationControl(settings);
const textDecoration = decodeValue(
inheritedValue?.typography?.textDecoration
);
const setTextDecoration = (newValue) => {
onChange(
setImmutably(
value,
["typography", "textDecoration"],
newValue || void 0
)
);
};
const hasTextDecoration = () => !!value?.typography?.textDecoration;
const resetTextDecoration = () => setTextDecoration(void 0);
const hasWritingModeControl = useHasWritingModeControl(settings);
const writingMode = decodeValue(inheritedValue?.typography?.writingMode);
const setWritingMode = (newValue) => {
onChange(
setImmutably(
value,
["typography", "writingMode"],
newValue || void 0
)
);
};
const hasWritingMode = () => !!value?.typography?.writingMode;
const resetWritingMode = () => setWritingMode(void 0);
const hasTextAlignmentControl = useHasTextAlignmentControl(settings);
const textAlign = decodeValue(inheritedValue?.typography?.textAlign);
const setTextAlign = (newValue) => {
onChange(
setImmutably(
value,
["typography", "textAlign"],
newValue || void 0
)
);
};
const hasTextAlign = () => !!value?.typography?.textAlign;
const resetTextAlign = () => setTextAlign(void 0);
const resetAllFilter = useCallback((previousValue) => {
return {
...previousValue,
typography: {}
};
}, []);
return /* @__PURE__ */ jsxs(
Wrapper,
{
resetAllFilter,
value,
onChange,
panelId,
children: [
hasFontFamilyEnabled && /* @__PURE__ */ jsx(
ToolsPanelItem,
{
label: __("Font"),
hasValue: hasFontFamily,
onDeselect: resetFontFamily,
isShownByDefault: defaultControls.fontFamily,
panelId,
children: /* @__PURE__ */ jsx(
FontFamilyControl,
{
fontFamilies,
value: fontFamily,
onChange: setFontFamily,
size: "__unstable-large"
}
)
}
),
hasFontSizeEnabled && !fitText && /* @__PURE__ */ jsx(
ToolsPanelItem,
{
label: __("Size"),
hasValue: hasFontSize,
onDeselect: resetFontSize,
isShownByDefault: defaultControls.fontSize,
panelId,
children: /* @__PURE__ */ jsx(
FontSizePicker,
{
value: currentFontSizeSlug || fontSize,
valueMode: currentFontSizeSlug ? "slug" : "literal",
onChange: setFontSize,
fontSizes: mergedFontSizes,
disableCustomFontSizes,
withReset: false,
withSlider: true,
size: "__unstable-large"
}
)
}
),
hasAppearanceControl && /* @__PURE__ */ jsx(
ToolsPanelItem,
{
className: "single-column",
label: appearanceControlLabel,
hasValue: hasFontAppearance,
onDeselect: resetFontAppearance,
isShownByDefault: defaultControls.fontAppearance,
panelId,
children: /* @__PURE__ */ jsx(
FontAppearanceControl,
{
value: {
fontStyle,
fontWeight
},
onChange: setFontAppearance,
hasFontStyles,
hasFontWeights,
fontFamilyFaces,
size: "__unstable-large"
}
)
}
),
hasLineHeightEnabled && /* @__PURE__ */ jsx(
ToolsPanelItem,
{
className: "single-column",
label: __("Line height"),
hasValue: hasLineHeight,
onDeselect: resetLineHeight,
isShownByDefault: defaultControls.lineHeight,
panelId,
children: /* @__PURE__ */ jsx(
LineHeightControl,
{
__unstableInputWidth: "auto",
value: lineHeight,
onChange: setLineHeight,
size: "__unstable-large"
}
)
}
),
hasLetterSpacingControl && /* @__PURE__ */ jsx(
ToolsPanelItem,
{
className: "single-column",
label: __("Letter spacing"),
hasValue: hasLetterSpacing,
onDeselect: resetLetterSpacing,
isShownByDefault: defaultControls.letterSpacing,
panelId,
children: /* @__PURE__ */ jsx(
LetterSpacingControl,
{
value: letterSpacing,
onChange: setLetterSpacing,
size: "__unstable-large",
__unstableInputWidth: "auto"
}
)
}
),
hasTextColumnsControl && /* @__PURE__ */ jsx(
ToolsPanelItem,
{
className: "single-column",
label: __("Columns"),
hasValue: hasTextColumns,
onDeselect: resetTextColumns,
isShownByDefault: defaultControls.textColumns,
panelId,
children: /* @__PURE__ */ jsx(
NumberControl,
{
label: __("Columns"),
max: MAX_TEXT_COLUMNS,
min: MIN_TEXT_COLUMNS,
onChange: setTextColumns,
size: "__unstable-large",
spinControls: "custom",
value: textColumns,
initialPosition: 1
}
)
}
),
hasTextDecorationControl && /* @__PURE__ */ jsx(
ToolsPanelItem,
{
className: "single-column",
label: __("Decoration"),
hasValue: hasTextDecoration,
onDeselect: resetTextDecoration,
isShownByDefault: defaultControls.textDecoration,
panelId,
children: /* @__PURE__ */ jsx(
TextDecorationControl,
{
value: textDecoration,
onChange: setTextDecoration,
size: "__unstable-large",
__unstableInputWidth: "auto"
}
)
}
),
hasWritingModeControl && /* @__PURE__ */ jsx(
ToolsPanelItem,
{
className: "single-column",
label: __("Orientation"),
hasValue: hasWritingMode,
onDeselect: resetWritingMode,
isShownByDefault: defaultControls.writingMode,
panelId,
children: /* @__PURE__ */ jsx(
WritingModeControl,
{
value: writingMode,
onChange: setWritingMode,
size: "__unstable-large",
__nextHasNoMarginBottom: true
}
)
}
),
hasTextTransformControl && /* @__PURE__ */ jsx(
ToolsPanelItem,
{
label: __("Letter case"),
hasValue: hasTextTransform,
onDeselect: resetTextTransform,
isShownByDefault: defaultControls.textTransform,
panelId,
children: /* @__PURE__ */ jsx(
TextTransformControl,
{
value: textTransform,
onChange: setTextTransform,
showNone: true,
isBlock: true,
size: "__unstable-large",
__nextHasNoMarginBottom: true
}
)
}
),
hasTextAlignmentControl && /* @__PURE__ */ jsxs(
ToolsPanelItem,
{
label: __("Text alignment"),
hasValue: hasTextAlign,
onDeselect: resetTextAlign,
isShownByDefault: defaultControls.textAlign,
panelId,
children: [
/* @__PURE__ */ jsx(
TextAlignmentControl,
{
value: textAlign,
onChange: setTextAlign,
options: ["left", "center", "right", "justify"],
size: "__unstable-large",
__nextHasNoMarginBottom: true
}
),
textAlign === "justify" && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Notice, { status: "warning", isDismissible: false, children: __(
"Justified text can reduce readability. For better accessibility, use left-aligned text instead."
) }) })
]
}
)
]
}
);
}
export {
TypographyPanel as default,
useHasTypographyPanel
};
//# sourceMappingURL=typography-panel.js.map