UNPKG

@wordpress/block-editor

Version:
375 lines (365 loc) 13.1 kB
/** * WordPress dependencies */ import { __ } from '@wordpress/i18n'; import { BaseControl, Flex, FlexItem, RangeControl, __experimentalNumberControl as NumberControl, __experimentalToggleGroupControl as ToggleGroupControl, __experimentalToggleGroupControlOption as ToggleGroupControlOption, __experimentalUnitControl as UnitControl, __experimentalParseQuantityAndUnitFromRawValue as parseQuantityAndUnitFromRawValue, __experimentalVStack as VStack } from '@wordpress/components'; import { useState } from '@wordpress/element'; /** * Internal dependencies */ import { appendSelectors, getBlockGapCSS } from './utils'; import { getGapCSSValue } from '../hooks/gap'; import { shouldSkipSerialization } from '../hooks/utils'; import { LAYOUT_DEFINITIONS } from './definitions'; import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; const RANGE_CONTROL_MAX_VALUES = { px: 600, '%': 100, vw: 100, vh: 100, em: 38, rem: 38, svw: 100, lvw: 100, dvw: 100, svh: 100, lvh: 100, dvh: 100, vi: 100, svi: 100, lvi: 100, dvi: 100, vb: 100, svb: 100, lvb: 100, dvb: 100, vmin: 100, svmin: 100, lvmin: 100, dvmin: 100, vmax: 100, svmax: 100, lvmax: 100, dvmax: 100 }; const units = [{ value: 'px', label: 'px', default: 0 }, { value: 'rem', label: 'rem', default: 0 }, { value: 'em', label: 'em', default: 0 }]; export default { name: 'grid', label: __('Grid'), inspectorControls: function GridLayoutInspectorControls({ layout = {}, onChange, layoutBlockSupport = {} }) { const { allowSizingOnChildren = false } = layoutBlockSupport; // In the experiment we want to also show column control in Auto mode, and // the minimum width control in Manual mode. const showColumnsControl = window.__experimentalEnableGridInteractivity || !!layout?.columnCount; const showMinWidthControl = window.__experimentalEnableGridInteractivity || !layout?.columnCount; return /*#__PURE__*/_jsxs(_Fragment, { children: [/*#__PURE__*/_jsx(GridLayoutTypeControl, { layout: layout, onChange: onChange }), /*#__PURE__*/_jsxs(VStack, { spacing: 4, children: [showColumnsControl && /*#__PURE__*/_jsx(GridLayoutColumnsAndRowsControl, { layout: layout, onChange: onChange, allowSizingOnChildren: allowSizingOnChildren }), showMinWidthControl && /*#__PURE__*/_jsx(GridLayoutMinimumWidthControl, { layout: layout, onChange: onChange })] })] }); }, toolBarControls: function GridLayoutToolbarControls() { return null; }, getLayoutStyle: function getLayoutStyle({ selector, layout, style, blockName, hasBlockGapSupport, layoutDefinitions = LAYOUT_DEFINITIONS }) { const { minimumColumnWidth = null, columnCount = null, rowCount = null } = layout; // Check that the grid layout attributes are of the correct type, so that we don't accidentally // write code that stores a string attribute instead of a number. if (process.env.NODE_ENV === 'development') { if (minimumColumnWidth && typeof minimumColumnWidth !== 'string') { throw new Error('minimumColumnWidth must be a string'); } if (columnCount && typeof columnCount !== 'number') { throw new Error('columnCount must be a number'); } if (rowCount && typeof rowCount !== 'number') { throw new Error('rowCount must be a number'); } } // If a block's block.json skips serialization for spacing or spacing.blockGap, // don't apply the user-defined value to the styles. const blockGapValue = style?.spacing?.blockGap && !shouldSkipSerialization(blockName, 'spacing', 'blockGap') ? getGapCSSValue(style?.spacing?.blockGap, '0.5em') : undefined; let output = ''; const rules = []; if (minimumColumnWidth && columnCount > 0) { const maxValue = `max(${minimumColumnWidth}, ( 100% - (${blockGapValue || '1.2rem'}*${columnCount - 1}) ) / ${columnCount})`; rules.push(`grid-template-columns: repeat(auto-fill, minmax(${maxValue}, 1fr))`, `container-type: inline-size`); if (rowCount) { rules.push(`grid-template-rows: repeat(${rowCount}, minmax(1rem, auto))`); } } else if (columnCount) { rules.push(`grid-template-columns: repeat(${columnCount}, minmax(0, 1fr))`); if (rowCount) { rules.push(`grid-template-rows: repeat(${rowCount}, minmax(1rem, auto))`); } } else { rules.push(`grid-template-columns: repeat(auto-fill, minmax(min(${minimumColumnWidth || '12rem'}, 100%), 1fr))`, 'container-type: inline-size'); } if (rules.length) { // Reason to disable: the extra line breaks added by prettier mess with the unit tests. // eslint-disable-next-line prettier/prettier output = `${appendSelectors(selector)} { ${rules.join('; ')}; }`; } // Output blockGap styles based on rules contained in layout definitions in theme.json. if (hasBlockGapSupport && blockGapValue) { output += getBlockGapCSS(selector, layoutDefinitions, 'grid', blockGapValue); } return output; }, getOrientation() { return 'horizontal'; }, getAlignments() { return []; } }; // Enables setting minimum width of grid items. function GridLayoutMinimumWidthControl({ layout, onChange }) { const { minimumColumnWidth, columnCount, isManualPlacement } = layout; const defaultValue = isManualPlacement || columnCount ? null : '12rem'; const value = minimumColumnWidth || defaultValue; const [quantity, unit = 'rem'] = parseQuantityAndUnitFromRawValue(value); const handleSliderChange = next => { onChange({ ...layout, minimumColumnWidth: [next, unit].join('') }); }; // Mostly copied from HeightControl. const handleUnitChange = newUnit => { // Attempt to smooth over differences between currentUnit and newUnit. // This should slightly improve the experience of switching between unit types. let newValue; if (['em', 'rem'].includes(newUnit) && unit === 'px') { // Convert pixel value to an approximate of the new unit, assuming a root size of 16px. newValue = (quantity / 16).toFixed(2) + newUnit; } else if (['em', 'rem'].includes(unit) && newUnit === 'px') { // Convert to pixel value assuming a root size of 16px. newValue = Math.round(quantity * 16) + newUnit; } onChange({ ...layout, minimumColumnWidth: newValue }); }; return /*#__PURE__*/_jsxs("fieldset", { children: [/*#__PURE__*/_jsx(BaseControl.VisualLabel, { as: "legend", children: __('Minimum column width') }), /*#__PURE__*/_jsxs(Flex, { gap: 4, children: [/*#__PURE__*/_jsx(FlexItem, { isBlock: true, children: /*#__PURE__*/_jsx(UnitControl, { size: "__unstable-large", onChange: newValue => { onChange({ ...layout, minimumColumnWidth: newValue === '' ? undefined : newValue }); }, onUnitChange: handleUnitChange, value: value, units: units, min: 0, label: __('Minimum column width'), hideLabelFromVision: true }) }), /*#__PURE__*/_jsx(FlexItem, { isBlock: true, children: /*#__PURE__*/_jsx(RangeControl, { __next40pxDefaultSize: true, __nextHasNoMarginBottom: true, onChange: handleSliderChange, value: quantity || 0, min: 0, max: RANGE_CONTROL_MAX_VALUES[unit] || 600, withInputField: false, label: __('Minimum column width'), hideLabelFromVision: true }) })] })] }); } // Enables setting number of grid columns function GridLayoutColumnsAndRowsControl({ layout, onChange, allowSizingOnChildren }) { // If the grid interactivity experiment is enabled, allow unsetting the column count. const defaultColumnCount = window.__experimentalEnableGridInteractivity ? undefined : 3; const { columnCount = defaultColumnCount, rowCount, isManualPlacement } = layout; return /*#__PURE__*/_jsx(_Fragment, { children: /*#__PURE__*/_jsxs("fieldset", { children: [(!window.__experimentalEnableGridInteractivity || !isManualPlacement) && /*#__PURE__*/_jsx(BaseControl.VisualLabel, { as: "legend", children: __('Columns') }), /*#__PURE__*/_jsxs(Flex, { gap: 4, children: [/*#__PURE__*/_jsx(FlexItem, { isBlock: true, children: /*#__PURE__*/_jsx(NumberControl, { size: "__unstable-large", onChange: value => { if (window.__experimentalEnableGridInteractivity) { // Allow unsetting the column count when in auto mode. const defaultNewColumnCount = isManualPlacement ? 1 : undefined; const newColumnCount = value === '' || value === '0' ? defaultNewColumnCount : parseInt(value, 10); onChange({ ...layout, columnCount: newColumnCount }); } else { // Don't allow unsetting the column count. const newColumnCount = value === '' || value === '0' ? 1 : parseInt(value, 10); onChange({ ...layout, columnCount: newColumnCount }); } }, value: columnCount, min: 1, label: __('Columns'), hideLabelFromVision: !window.__experimentalEnableGridInteractivity || !isManualPlacement }) }), /*#__PURE__*/_jsx(FlexItem, { isBlock: true, children: window.__experimentalEnableGridInteractivity && allowSizingOnChildren && isManualPlacement ? /*#__PURE__*/_jsx(NumberControl, { size: "__unstable-large", onChange: value => { // Don't allow unsetting the row count. const newRowCount = value === '' || value === '0' ? 1 : parseInt(value, 10); onChange({ ...layout, rowCount: newRowCount }); }, value: rowCount, min: 1, label: __('Rows') }) : /*#__PURE__*/_jsx(RangeControl, { __next40pxDefaultSize: true, __nextHasNoMarginBottom: true, value: columnCount !== null && columnCount !== void 0 ? columnCount : 1, onChange: value => onChange({ ...layout, columnCount: value === '' || value === '0' ? 1 : value }), min: 1, max: 16, withInputField: false, label: __('Columns'), hideLabelFromVision: true }) })] })] }) }); } // Enables switching between grid types function GridLayoutTypeControl({ layout, onChange }) { const { columnCount, rowCount, minimumColumnWidth, isManualPlacement } = layout; /** * When switching, temporarily save any custom values set on the * previous type so we can switch back without loss. */ const [tempColumnCount, setTempColumnCount] = useState(columnCount || 3); const [tempRowCount, setTempRowCount] = useState(rowCount); const [tempMinimumColumnWidth, setTempMinimumColumnWidth] = useState(minimumColumnWidth || '12rem'); const gridPlacement = isManualPlacement || !!columnCount && !window.__experimentalEnableGridInteractivity ? 'manual' : 'auto'; const onChangeType = value => { if (value === 'manual') { setTempMinimumColumnWidth(minimumColumnWidth || '12rem'); } else { setTempColumnCount(columnCount || 3); setTempRowCount(rowCount); } onChange({ ...layout, columnCount: value === 'manual' ? tempColumnCount : null, rowCount: value === 'manual' && window.__experimentalEnableGridInteractivity ? tempRowCount : undefined, isManualPlacement: value === 'manual' && window.__experimentalEnableGridInteractivity ? true : undefined, minimumColumnWidth: value === 'auto' ? tempMinimumColumnWidth : null }); }; const helpText = gridPlacement === 'manual' ? __('Grid items can be manually placed in any position on the grid.') : __('Grid items are placed automatically depending on their order.'); return /*#__PURE__*/_jsxs(ToggleGroupControl, { __next40pxDefaultSize: true, __nextHasNoMarginBottom: true, label: __('Grid item position'), value: gridPlacement, onChange: onChangeType, isBlock: true, help: window.__experimentalEnableGridInteractivity ? helpText : undefined, children: [/*#__PURE__*/_jsx(ToggleGroupControlOption, { value: "auto", label: __('Auto') }, "auto"), /*#__PURE__*/_jsx(ToggleGroupControlOption, { value: "manual", label: __('Manual') }, "manual")] }); } //# sourceMappingURL=grid.js.map