@plaudit/gutenberg-api-extensions 1.0.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1,2 @@
1
1
  export * from "./simple-block";
2
+ export * from "./layered-styles";
@@ -1 +1,2 @@
1
1
  export * from "./simple-block";
2
+ export * from "./layered-styles";
@@ -0,0 +1,31 @@
1
+ import type { BlockIcon } from "@wordpress/blocks";
2
+ import type { PickableOptions } from "../controls/types";
3
+ type BaseLayeredBlockStyleLayer = {
4
+ name: string;
5
+ title: string;
6
+ default?: string | undefined;
7
+ };
8
+ type LayeredBlockStyleColorLayer = BaseLayeredBlockStyleLayer & {
9
+ picker: 'color';
10
+ options: PickableOptions<{
11
+ color?: string;
12
+ }>;
13
+ };
14
+ type LayeredBlockStyleToggleLayer = BaseLayeredBlockStyleLayer & {
15
+ picker?: 'toggle-control';
16
+ options: PickableOptions<{
17
+ icon: BlockIcon;
18
+ }>;
19
+ };
20
+ type LayeredBlockStyleSelectOrRadioLayer = BaseLayeredBlockStyleLayer & {
21
+ picker: 'select' | 'radio';
22
+ options: PickableOptions;
23
+ };
24
+ export type LayeredBlockStyleLayer = LayeredBlockStyleColorLayer | LayeredBlockStyleToggleLayer | LayeredBlockStyleSelectOrRadioLayer;
25
+ export interface LayeredBlockStylesConfig {
26
+ block: `${string}/${string}`;
27
+ layers: LayeredBlockStyleLayer[];
28
+ }
29
+ export declare function registerLayeredBlockStyles(config: LayeredBlockStylesConfig): void;
30
+ export declare function installLayeredBlockStylesSupport(): void;
31
+ export {};
@@ -0,0 +1,81 @@
1
+ import { createHigherOrderComponent } from "@wordpress/compose";
2
+ import { addFilter } from "@wordpress/hooks";
3
+ import React from "react";
4
+ import { InspectorPanel, PickOneFromColors, PickOneFromRadios, PickOneFromSelect, PickOneFromToggleGroup } from "../controls";
5
+ export function registerLayeredBlockStyles(config) {
6
+ var _a;
7
+ const layeredBlockStyles = (_a = window.plauditLayeredBlockStyles) !== null && _a !== void 0 ? _a : (window.plauditLayeredBlockStyles = new Map());
8
+ layeredBlockStyles.set(config.block, config);
9
+ }
10
+ export function installLayeredBlockStylesSupport() {
11
+ var _a;
12
+ if (window.plauditLayeredBlockStylesInstalled) {
13
+ return;
14
+ }
15
+ window.plauditLayeredBlockStylesInstalled = true;
16
+ const layeredBlockStyles = (_a = window.plauditLayeredBlockStyles) !== null && _a !== void 0 ? _a : (window.plauditLayeredBlockStyles = new Map());
17
+ function convertLayersToRadios(layer, props) {
18
+ switch (layer.picker) {
19
+ case undefined:
20
+ case 'toggle-control':
21
+ return React.createElement(PickOneFromToggleGroup, Object.assign({}, layer, props, { attribute: `layeredStyles__${layer.name}` }));
22
+ case 'color':
23
+ return React.createElement(PickOneFromColors, Object.assign({}, layer, props, { attribute: `layeredStyles__${layer.name}` }));
24
+ case 'radio':
25
+ return React.createElement(PickOneFromRadios, Object.assign({}, layer, props, { attribute: `layeredStyles__${layer.name}` }));
26
+ case 'select':
27
+ return React.createElement(PickOneFromSelect, Object.assign({}, layer, props, { attribute: `layeredStyles__${layer.name}` }));
28
+ }
29
+ }
30
+ addFilter('blocks.registerBlockType', 'plaudit/gutenberg-api-extensions/layered-styles', (atts) => {
31
+ var _a;
32
+ if (layeredBlockStyles.has(atts.name)) {
33
+ (_a = layeredBlockStyles.get(atts.name)) === null || _a === void 0 ? void 0 : _a.layers.forEach(layer => {
34
+ const attName = `layeredStyles__${layer.name}`;
35
+ if (!atts.attributes[attName]) {
36
+ atts.attributes[attName] = { type: 'string', source: 'attribute', attribute: `data-layered-style-${layer.name}` };
37
+ }
38
+ });
39
+ }
40
+ return atts;
41
+ });
42
+ addFilter('blocks.getBlockAttributes', 'plaudit/gutenberg-api-extensions/layered-styles', (blockAttributes, blockType, innerHTML) => {
43
+ var _a;
44
+ if (layeredBlockStyles.has(blockType.name)) {
45
+ const blockRoot = new DOMParser().parseFromString(innerHTML, "application/xml").documentElement;
46
+ (_a = layeredBlockStyles.get(blockType.name)) === null || _a === void 0 ? void 0 : _a.layers.forEach(layer => {
47
+ var _a;
48
+ blockAttributes[`layeredStyles__${layer.name}`] = (_a = blockRoot.getAttribute(`data-layered-style-${layer.name}`)) !== null && _a !== void 0 ? _a : layer.default;
49
+ });
50
+ }
51
+ return blockAttributes;
52
+ });
53
+ addFilter('editor.BlockListBlock', 'plaudit/gutenberg-api-extensions/layered-styles', createHigherOrderComponent(BlockListBlock => (props) => {
54
+ var _a, _b;
55
+ const wrapperProps = Object.assign({}, ((_a = props.wrapperProps) !== null && _a !== void 0 ? _a : {}));
56
+ if (layeredBlockStyles.has(props.name)) {
57
+ (_b = layeredBlockStyles.get(props.name)) === null || _b === void 0 ? void 0 : _b.layers.forEach(layer => {
58
+ wrapperProps[`data-layered-style-${layer.name}`] = props.attributes[`layeredStyles__${layer.name}`];
59
+ });
60
+ }
61
+ return React.createElement(BlockListBlock, Object.assign({}, props, { wrapperProps: wrapperProps }));
62
+ }, 'layeredStylesMarkupInjector'));
63
+ addFilter('blocks.getSaveContent.extraProps', 'plaudit/gutenberg-api-extensions/layered-styles', (props, blockType, attributes) => {
64
+ if (!layeredBlockStyles.has(blockType.name)) {
65
+ return props;
66
+ }
67
+ const res = Object.assign({}, props);
68
+ layeredBlockStyles.get(blockType.name).layers.forEach(layer => {
69
+ res[`data-layered-style-${layer.name}`] = attributes[`layeredStyles__${layer.name}`];
70
+ });
71
+ return res;
72
+ });
73
+ addFilter('editor.BlockEdit', 'plaudit/gutenberg-api-extensions/layered-styles', createHigherOrderComponent(BlockEdit => (props) => {
74
+ if (!layeredBlockStyles.has(props['name'])) {
75
+ return React.createElement(BlockEdit, Object.assign({}, props));
76
+ }
77
+ return React.createElement(React.Fragment, null,
78
+ React.createElement(BlockEdit, Object.assign({}, props)),
79
+ React.createElement(InspectorPanel, { title: "Layered Styles", initialOpen: true }, ...layeredBlockStyles.get(props['name']).layers.map(layer => convertLayersToRadios(layer, props))));
80
+ }, 'plauditGutenbergApiExtensionsLayeredStyles'));
81
+ }
@@ -1,6 +1,19 @@
1
1
  import type { PickableOptions, SimpleBlockControlProps } from "./types";
2
2
  import React from "react";
3
- export declare function PickOne<T extends string>(props: SimpleBlockControlProps<T, string> & {
3
+ import { BlockIcon } from "@wordpress/blocks";
4
+ export declare function PickOneFromToggleGroup<T extends string>(props: SimpleBlockControlProps<T, string> & {
5
+ options: PickableOptions<{
6
+ icon: BlockIcon;
7
+ }>;
8
+ }): React.JSX.Element;
9
+ export declare function PickOneFromSelect<T extends string>(props: SimpleBlockControlProps<T, string> & {
10
+ options: PickableOptions;
11
+ }): React.JSX.Element;
12
+ export declare function PickOneFromRadios<T extends string>(props: SimpleBlockControlProps<T, string> & {
4
13
  options: PickableOptions;
5
- layout: 'toggle-group' | 'dropdown' | 'radio';
14
+ }): React.JSX.Element;
15
+ export declare function PickOneFromColors<T extends string>(props: SimpleBlockControlProps<T, string> & {
16
+ options: PickableOptions<{
17
+ color?: string | undefined;
18
+ }>;
6
19
  }): React.JSX.Element;
@@ -1,4 +1,4 @@
1
- import { __experimentalToggleGroupControl as ToggleGroupControl, __experimentalToggleGroupControlOption as ToggleGroupControlOption, __experimentalToggleGroupControlOptionIcon as ToggleGroupControlOptionIcon, RadioControl, SelectControl } from "@wordpress/components";
1
+ import { __experimentalToggleGroupControl as ToggleGroupControl, __experimentalToggleGroupControlOption as ToggleGroupControlOption, __experimentalToggleGroupControlOptionIcon as ToggleGroupControlOptionIcon, ColorPalette, RadioControl, SelectControl } from "@wordpress/components";
2
2
  import React from "react";
3
3
  function makeSharedRadioAndSelectProps(props) {
4
4
  return {
@@ -9,17 +9,38 @@ function makeSharedRadioAndSelectProps(props) {
9
9
  }))
10
10
  };
11
11
  }
12
- export function PickOne(props) {
13
- switch (props.layout) {
14
- case 'toggle-group':
15
- return React.createElement(ToggleGroupControl, { label: props.label, value: props.attributes[props.attribute], onChange: value => props.setAttributes({ [props.attribute]: value }), children: Object.entries(props.options).map(([value, label]) => typeof label === 'string'
16
- ? React.createElement(ToggleGroupControlOption, { key: value, value: value, label: label })
17
- : React.createElement(ToggleGroupControlOptionIcon, { key: value, value: value, label: label.text, icon: label.icon })) });
18
- case 'dropdown':
19
- return React.createElement(SelectControl, Object.assign({}, makeSharedRadioAndSelectProps(props), { value: props.attributes[props.attribute] }));
20
- case 'radio':
21
- return React.createElement(RadioControl, Object.assign({}, makeSharedRadioAndSelectProps(props), { selected: props.attributes[props.attribute] }));
22
- default:
23
- throw new Error(`Unsupported layout: ${props.layout}`);
12
+ export function PickOneFromToggleGroup(props) {
13
+ return React.createElement(ToggleGroupControl, { label: props.label, value: props.attributes[props.attribute], onChange: value => props.setAttributes({ [props.attribute]: value }), children: Object.entries(props.options).map(([value, label]) => typeof label === 'string'
14
+ ? React.createElement(ToggleGroupControlOption, { key: value, value: value, label: label })
15
+ : React.createElement(ToggleGroupControlOptionIcon, { key: value, value: value, label: label.text, icon: label.icon })) });
16
+ }
17
+ export function PickOneFromSelect(props) {
18
+ return React.createElement(SelectControl, Object.assign({}, makeSharedRadioAndSelectProps(props), { value: props.attributes[props.attribute] }));
19
+ }
20
+ export function PickOneFromRadios(props) {
21
+ return React.createElement(RadioControl, Object.assign({}, makeSharedRadioAndSelectProps(props), { selected: props.attributes[props.attribute] }));
22
+ }
23
+ export function PickOneFromColors(props) {
24
+ var _a;
25
+ const valueToColorMap = new Map();
26
+ const colorToValueMap = new Map();
27
+ const colors = [];
28
+ for (const [value, display] of Object.entries(props.options)) {
29
+ if (typeof display === 'string') {
30
+ colors.push({ color: value, name: display });
31
+ }
32
+ else if (display.color) {
33
+ valueToColorMap.set(value, display.color);
34
+ colorToValueMap.set(display.color, value);
35
+ colors.push({ color: display.color, name: display.text });
36
+ }
37
+ else {
38
+ colors.push({ color: value, name: display.text });
39
+ }
24
40
  }
41
+ const currentColor = (_a = valueToColorMap.get(props.attributes[props.attribute])) !== null && _a !== void 0 ? _a : props.attributes[props.attribute];
42
+ const id = `layeredStyles__colorPicker--${Math.random().toString().replace(/[.\-]/, '')}`;
43
+ return React.createElement(React.Fragment, null,
44
+ React.createElement("label", { htmlFor: id }, props.label),
45
+ React.createElement(ColorPalette, { id: id, disableCustomColors: true, onChange: color => { var _a, _b; return props.setAttributes({ [props.attribute]: (_b = (_a = colorToValueMap.get(color !== null && color !== void 0 ? color : currentColor)) !== null && _a !== void 0 ? _a : color) !== null && _b !== void 0 ? _b : currentColor }); }, colors: colors, value: currentColor, clearable: false }));
25
46
  }
@@ -1,11 +1,10 @@
1
- import type { BlockEditProps, BlockIcon } from "@wordpress/blocks";
1
+ import type { BlockEditProps } from "@wordpress/blocks";
2
2
  export type SimpleBlockControlProps<T extends string, V> = {
3
3
  label: string;
4
4
  attribute: T;
5
5
  attributes: BlockEditProps<Record<T, V> & Record<string, unknown>>['attributes'];
6
6
  setAttributes: BlockEditProps<any>['setAttributes'];
7
7
  };
8
- export type PickableOptions = Record<string, string | {
8
+ export type PickableOptions<T extends object = {}> = Record<string, string | ({
9
9
  text: string;
10
- icon: BlockIcon;
11
- }>;
10
+ } & T)>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plaudit/gutenberg-api-extensions",
3
- "version": "1.0.2",
3
+ "version": "1.2.0",
4
4
  "scripts": {
5
5
  "prepublishOnly": "rm -rf build && mkdir build && tsc",
6
6
  "build": "tsc",
@@ -27,7 +27,7 @@
27
27
  "react-dom": "^18.2.0"
28
28
  },
29
29
  "devDependencies": {
30
- "@types/react": "^18.2.11",
30
+ "@types/react": "^18.2.13",
31
31
  "@types/wordpress__block-editor": "^11.5.1",
32
32
  "@types/wordpress__blocks": "^12.5.0",
33
33
  "typescript": "^5.1.3"