@wordpress/ui 0.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.
package/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # (Experimental) UI
2
+
3
+ A package that provides React UI components for the WordPress Design System, built on themeable design tokens.
4
+
5
+ While similar in scope to `@wordpress/components`, there are a few key differences:
6
+
7
+ - `@wordpress/components` grew organically as a collection of unrelated UI elements for WordPress screens. In contrast, this package is an implementation of a design system that guarantees user- and developer-facing cohesion between components.
8
+ - Unlike `@wordpress/components`, this package is not bundled as a WordPress script available on the `window.wp` global and is instead distributed as an npm package that follows [semantic versioning](https://semver.org/) for release changes.
9
+
10
+ This is a companion to the `@wordpress/theme` package that provides:
11
+
12
+ - **Design Tokens**: A comprehensive system of design tokens for colors, spacing, typography, and more
13
+ - **Theme System**: A flexible theming provider for consistent theming across applications
14
+
15
+ ## Usage
16
+
17
+ ### Basic Component Usage
18
+
19
+ ```tsx
20
+ import { Box } from '@wordpress/ui';
21
+
22
+ function MyComponent() {
23
+ return (
24
+ <Box background="neutral" padding="small">
25
+ Hello World
26
+ </Box>
27
+ );
28
+ }
29
+ ```
30
+
31
+ ## Core Design Principles
32
+
33
+ All components in the design system follow consistent patterns for maximum flexibility and developer experience:
34
+
35
+ ### Custom Rendering
36
+
37
+ Every component supports the `render` prop for complete control over the underlying HTML element:
38
+
39
+ ```tsx
40
+ import { Box } from '@wordpress/ui';
41
+
42
+ function MyComponent() {
43
+ // Render Box as a <span /> instead of the default <div />
44
+ return <Box render={ <span /> }>{ /* ... */ }</Box>;
45
+ }
46
+ ```
47
+
48
+ ### Ref Forwarding
49
+
50
+ All components forward refs to their underlying DOM elements:
51
+
52
+ ```tsx
53
+ import { useRef } from '@wordpress/element';
54
+ import { Box } from '@wordpress/ui';
55
+
56
+ function MyComponent() {
57
+ const boxRef = useRef< HTMLDivElement >( null );
58
+
59
+ return <Box ref={ boxRef }>{ /* ... */ }</Box>;
60
+ }
61
+ ```
62
+
63
+ ### Automatic `className` Merging
64
+
65
+ Components merge provided `className` props with their internal styles:
66
+
67
+ ```tsx
68
+ import { Box } from '@wordpress/ui';
69
+
70
+ function MyComponent() {
71
+ // Your custom CSS className is merged with component styles
72
+ return <Box className="my-custom-class">{ /* ... */ }</Box>;
73
+ }
74
+ ```
75
+
76
+ ## Contributing to this package
77
+
78
+ This is an individual package that's part of the Gutenberg project. The project is organized as a monorepo. It's made up of multiple self-contained software packages, each with a specific purpose. The packages in this monorepo are published to [npm](https://www.npmjs.com/) and used by [WordPress](https://make.wordpress.org/core/) as well as other software projects.
79
+
80
+ To find out more about contributing to this package or Gutenberg as a whole, please read the project's main [contributor guide](https://github.com/WordPress/gutenberg/tree/HEAD/CONTRIBUTING.md).
81
+
82
+ <br /><br /><p align="center"><img src="https://s.w.org/style/images/codeispoetry.png?1" alt="Code is Poetry." /></p>
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import { type BoxProps } from './types';
5
+ /**
6
+ * A low-level visual primitive that provides an interface for applying design
7
+ * token-based customization for background, text, padding, and more.
8
+ */
9
+ export declare const Box: import("react").ForwardRefExoticComponent<BoxProps & import("react").RefAttributes<HTMLDivElement>>;
10
+ //# sourceMappingURL=box.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"box.d.ts","sourceRoot":"","sources":["../../src/box/box.tsx"],"names":[],"mappings":"AAKA;;GAEG;AACH,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AAoExC;;;GAGG;AACH,eAAO,MAAM,GAAG,qGAgCb,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { Box } from './box';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/box/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { type Meta, type StoryObj } from '@storybook/react';
5
+ import '@wordpress/theme/design-tokens.css';
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import { Box } from '../box';
10
+ declare const meta: Meta<typeof Box>;
11
+ export default meta;
12
+ type Story = StoryObj<typeof Box>;
13
+ export declare const Default: Story;
14
+ export declare const DirectionalPadding: Story;
15
+ //# sourceMappingURL=index.story.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.story.d.ts","sourceRoot":"","sources":["../../../src/box/stories/index.story.tsx"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAM5D,OAAO,oCAAoC,CAAC;AAE5C;;GAEG;AACH,OAAO,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAK7B,QAAA,MAAM,IAAI,EAAE,IAAI,CAAE,OAAO,GAAG,CAW3B,CAAC;AACF,eAAe,IAAI,CAAC;AAEpB,KAAK,KAAK,GAAG,QAAQ,CAAE,OAAO,GAAG,CAAE,CAAC;AAEpC,eAAO,MAAM,OAAO,EAAE,KAiBrB,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,KAWhC,CAAC"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import { type ComponentProps } from '../utils/types';
5
+ type SizeToken = 'x-small' | 'small' | 'medium' | 'large';
6
+ type Size = number | SizeToken;
7
+ type BackgroundColor = 'neutral' | 'neutral-strong' | 'neutral-weak' | 'brand' | 'success' | 'success-weak' | 'info' | 'info-weak' | 'warning' | 'warning-weak' | 'caution' | 'caution-weak' | 'error' | 'error-weak';
8
+ type ForegroundColor = 'neutral' | 'neutral-weak' | 'success' | 'success-weak' | 'info' | 'info-weak' | 'warning' | 'warning-weak' | 'caution' | 'caution-weak' | 'error' | 'error-weak';
9
+ type DimensionVariant<T> = {
10
+ block?: T;
11
+ blockStart?: T;
12
+ blockEnd?: T;
13
+ inline?: T;
14
+ inlineStart?: T;
15
+ inlineEnd?: T;
16
+ };
17
+ export interface BoxProps extends ComponentProps<'div'> {
18
+ /**
19
+ * The target rendering element design token grouping to use for the box.
20
+ */
21
+ target?: string;
22
+ /**
23
+ * The surface background design token for box background color.
24
+ *
25
+ * Shorthand for `backgroundColor`.
26
+ */
27
+ bg?: BackgroundColor;
28
+ /**
29
+ * The surface background design token for box background color.
30
+ */
31
+ backgroundColor?: BackgroundColor;
32
+ /**
33
+ * The surface foreground design token for box text color.
34
+ *
35
+ * Shorthand for `color`.
36
+ */
37
+ fg?: ForegroundColor;
38
+ /**
39
+ * The surface foreground design token for box text color.
40
+ */
41
+ color?: ForegroundColor;
42
+ /**
43
+ * The surface spacing design token or base unit multiplier for box padding.
44
+ *
45
+ * Shorthand for `padding`.
46
+ */
47
+ p?: Size | DimensionVariant<Size>;
48
+ /**
49
+ * The surface spacing design token or base unit multiplier for box padding.
50
+ */
51
+ padding?: Size | DimensionVariant<Size>;
52
+ /**
53
+ * The content to be rendered inside the component.
54
+ */
55
+ children?: React.ReactNode;
56
+ }
57
+ export {};
58
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/box/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,KAAK,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE1D,KAAK,IAAI,GAAG,MAAM,GAAG,SAAS,CAAC;AAE/B,KAAK,eAAe,GACjB,SAAS,GACT,gBAAgB,GAChB,cAAc,GACd,OAAO,GACP,SAAS,GACT,cAAc,GACd,MAAM,GACN,WAAW,GACX,SAAS,GACT,cAAc,GACd,SAAS,GACT,cAAc,GACd,OAAO,GACP,YAAY,CAAC;AAEhB,KAAK,eAAe,GACjB,SAAS,GACT,cAAc,GACd,SAAS,GACT,cAAc,GACd,MAAM,GACN,WAAW,GACX,SAAS,GACT,cAAc,GACd,SAAS,GACT,cAAc,GACd,OAAO,GACP,YAAY,CAAC;AAEhB,KAAK,gBAAgB,CAAE,CAAC,IAAK;IAC5B,KAAK,CAAC,EAAE,CAAC,CAAC;IACV,UAAU,CAAC,EAAE,CAAC,CAAC;IACf,QAAQ,CAAC,EAAE,CAAC,CAAC;IACb,MAAM,CAAC,EAAE,CAAC,CAAC;IACX,WAAW,CAAC,EAAE,CAAC,CAAC;IAChB,SAAS,CAAC,EAAE,CAAC,CAAC;CACd,CAAC;AAEF,MAAM,WAAW,QAAS,SAAQ,cAAc,CAAE,KAAK,CAAE;IACxD;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;OAIG;IACH,EAAE,CAAC,EAAE,eAAe,CAAC;IAErB;;OAEG;IACH,eAAe,CAAC,EAAE,eAAe,CAAC;IAElC;;;;OAIG;IACH,EAAE,CAAC,EAAE,eAAe,CAAC;IAErB;;OAEG;IACH,KAAK,CAAC,EAAE,eAAe,CAAC;IAExB;;;;OAIG;IACH,CAAC,CAAC,EAAE,IAAI,GAAG,gBAAgB,CAAE,IAAI,CAAE,CAAC;IAEpC;;OAEG;IACH,OAAO,CAAC,EAAE,IAAI,GAAG,gBAAgB,CAAE,IAAI,CAAE,CAAC;IAE1C;;OAEG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B"}
@@ -0,0 +1,2 @@
1
+ export * from './box';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const lock: (object: unknown, privateData: unknown) => void, unlock: <T = any>(object: unknown) => T;
2
+ //# sourceMappingURL=lock-unlock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock-unlock.d.ts","sourceRoot":"","sources":["../src/lock-unlock.ts"],"names":[],"mappings":"AAKA,eAAO,MAAQ,IAAI,mDAAE,MAAM,iCAIzB,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import type { ComponentProps } from './types';
5
+ type RenderProp<E extends React.ElementType> = NonNullable<ComponentProps<E>['render']>;
6
+ /**
7
+ * Renders an element from a render prop (a component or an element), with
8
+ * merged props and ref.
9
+ *
10
+ * @param render The render prop (component or element).
11
+ * @param props Props to pass to or merge with the element.
12
+ * @param ref Optional ref to attach to the element.
13
+ * @return The rendered element.
14
+ */
15
+ export declare const renderElement: <E extends React.ElementType>(render: RenderProp<E>, props: Omit<ComponentProps<E>, "render">, ref?: React.Ref<E extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[E] : Element>) => React.ReactElement;
16
+ export {};
17
+ //# sourceMappingURL=element.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"element.d.ts","sourceRoot":"","sources":["../../src/utils/element.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,KAAK,UAAU,CAAE,CAAC,SAAS,KAAK,CAAC,WAAW,IAAK,WAAW,CAC3D,cAAc,CAAE,CAAC,CAAE,CAAE,QAAQ,CAAE,CAC/B,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,GAAK,CAAC,SAAS,KAAK,CAAC,WAAW,EACzD,QAAQ,UAAU,CAAE,CAAC,CAAE,EACvB,OAAO,IAAI,CAAE,cAAc,CAAE,CAAC,CAAE,EAAE,QAAQ,CAAE,EAC5C,MAAM,KAAK,CAAC,GAAG,CACd,CAAC,SAAS,MAAM,qBAAqB,GAClC,qBAAqB,CAAE,CAAC,CAAE,GAC1B,OAAO,CACV,KACC,KAAK,CAAC,YAMR,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { type ElementType, type ComponentPropsWithoutRef, type HTMLAttributes, type Ref } from 'react';
5
+ type HTMLAttributesWithRef<T extends ElementType = any> = HTMLAttributes<T> & {
6
+ ref?: Ref<T> | undefined;
7
+ };
8
+ type ComponentRenderFn<Props> = (props: Props) => React.ReactElement<unknown>;
9
+ export type ComponentProps<E extends ElementType> = Omit<ComponentPropsWithoutRef<E>, 'className' | 'children' | 'render'> & {
10
+ /**
11
+ * CSS class name to apply to the component.
12
+ */
13
+ className?: string;
14
+ /**
15
+ * Replaces the component's default HTML element using a given React
16
+ * element, or a function that returns a React element.
17
+ */
18
+ render?: ComponentRenderFn<HTMLAttributesWithRef> | React.ReactElement<Record<string, unknown>>;
19
+ };
20
+ export {};
21
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EACN,KAAK,WAAW,EAChB,KAAK,wBAAwB,EAC7B,KAAK,cAAc,EACnB,KAAK,GAAG,EACR,MAAM,OAAO,CAAC;AAEf,KAAK,qBAAqB,CAAE,CAAC,SAAS,WAAW,GAAG,GAAG,IACtD,cAAc,CAAE,CAAC,CAAE,GAAG;IAAE,GAAG,CAAC,EAAE,GAAG,CAAE,CAAC,CAAE,GAAG,SAAS,CAAA;CAAE,CAAC;AAEtD,KAAK,iBAAiB,CAAE,KAAK,IAAK,CACjC,KAAK,EAAE,KAAK,KACR,KAAK,CAAC,YAAY,CAAE,OAAO,CAAE,CAAC;AAEnC,MAAM,MAAM,cAAc,CAAE,CAAC,SAAS,WAAW,IAAK,IAAI,CACzD,wBAAwB,CAAE,CAAC,CAAE,EAC7B,WAAW,GAAG,UAAU,GAAG,QAAQ,CACnC,GAAG;IACH;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,MAAM,CAAC,EACJ,iBAAiB,CAAE,qBAAqB,CAAE,GAC1C,KAAK,CAAC,YAAY,CAAE,MAAM,CAAE,MAAM,EAAE,OAAO,CAAE,CAAE,CAAC;CACnD,CAAC"}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@wordpress/ui",
3
+ "version": "0.2.0",
4
+ "description": "Themeable React UI components for the WordPress Design System.",
5
+ "author": "The WordPress Contributors",
6
+ "license": "GPL-2.0-or-later",
7
+ "keywords": [
8
+ "wordpress",
9
+ "gutenberg",
10
+ "components"
11
+ ],
12
+ "homepage": "https://github.com/WordPress/gutenberg/tree/HEAD/packages/ui/README.md",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/WordPress/gutenberg.git",
16
+ "directory": "packages/ui"
17
+ },
18
+ "bugs": {
19
+ "url": "https://github.com/WordPress/gutenberg/issues"
20
+ },
21
+ "engines": {
22
+ "node": ">=20.10.0",
23
+ "npm": ">=10.2.3"
24
+ },
25
+ "exports": {
26
+ ".": {
27
+ "types": "./build-types/index.d.ts",
28
+ "import": "./build-module/index.js",
29
+ "default": "./build/index.js"
30
+ },
31
+ "./package.json": "./package.json"
32
+ },
33
+ "wpScript": false,
34
+ "sideEffects": false,
35
+ "dependencies": {
36
+ "@wordpress/element": "^6.35.0",
37
+ "@wordpress/private-apis": "^1.35.0"
38
+ },
39
+ "devDependencies": {
40
+ "@wordpress/theme": "^0.2.0"
41
+ },
42
+ "peerDependencies": {
43
+ "react": "^18.0.0",
44
+ "react-dom": "^18.0.0"
45
+ },
46
+ "publishConfig": {
47
+ "access": "public"
48
+ },
49
+ "gitHead": "77aa1f194edceafe8ac2a1b9438bf84b557e76e3"
50
+ }
@@ -0,0 +1,113 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { forwardRef } from '@wordpress/element';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import { type BoxProps } from './types';
10
+ import { renderElement } from '../utils/element';
11
+
12
+ /**
13
+ * Default render function that renders a div element with the given props.
14
+ *
15
+ * @param props The props to apply to the HTML element.
16
+ */
17
+ const DEFAULT_RENDER = ( props: React.ComponentPropsWithoutRef< 'div' > ) => (
18
+ <div { ...props } />
19
+ );
20
+
21
+ /**
22
+ * Capitalizes the first character of a string.
23
+ *
24
+ * @param str The string to capitalize.
25
+ * @return The capitalized string.
26
+ */
27
+ const capitalize = ( str: string ): string =>
28
+ str.charAt( 0 ).toUpperCase() + str.slice( 1 );
29
+
30
+ /**
31
+ * Converts a size value to a CSS design token property reference (with
32
+ * fallback) or a calculated value based on the base unit.
33
+ *
34
+ * @param property The CSS property name.
35
+ * @param target The design system token target.
36
+ * @param value The size value, either a number (multiplier of base unit) or a string (token name).
37
+ * @return A CSS value string with variable references.
38
+ */
39
+ const getSpacingValue = (
40
+ property: string,
41
+ target: string,
42
+ value: number | string
43
+ ): string =>
44
+ typeof value === 'number'
45
+ ? `calc(var(--wpds-dimension-base) * ${ value })`
46
+ : `var(--wpds-dimension-${ property }-${ target }-${ value }, var(--wpds-dimension-${ property }-surface-${ value }))`;
47
+
48
+ /**
49
+ * Generates CSS styles for properties with optionally directional values,
50
+ * normalizing single values and objects with directional keys for logical
51
+ * properties.
52
+ *
53
+ * @param property The CSS property name from BoxProps.
54
+ * @param target The design system token target.
55
+ * @param value The property value (single or object with directional keys).
56
+ * @return A CSSProperties object with the computed styles.
57
+ */
58
+ const getDimensionVariantStyles = < T extends keyof BoxProps >(
59
+ property: T,
60
+ target: string,
61
+ value: NonNullable< BoxProps[ T ] >
62
+ ): React.CSSProperties =>
63
+ typeof value !== 'object'
64
+ ? { [ property ]: getSpacingValue( property, target, value ) }
65
+ : Object.keys( value ).reduce(
66
+ ( result, key ) => ( {
67
+ ...result,
68
+ [ property + capitalize( key ) ]: getSpacingValue(
69
+ property,
70
+ target,
71
+ value[ key ]
72
+ ),
73
+ } ),
74
+ {} as Record< string, string >
75
+ );
76
+
77
+ /**
78
+ * A low-level visual primitive that provides an interface for applying design
79
+ * token-based customization for background, text, padding, and more.
80
+ */
81
+ export const Box = forwardRef< HTMLDivElement, BoxProps >( function Box(
82
+ {
83
+ target = 'surface',
84
+ backgroundColor,
85
+ color,
86
+ padding,
87
+ bg = backgroundColor,
88
+ fg = color,
89
+ p = padding,
90
+ render = DEFAULT_RENDER,
91
+ ...props
92
+ },
93
+ ref
94
+ ) {
95
+ const style: React.CSSProperties = {};
96
+
97
+ if ( bg ) {
98
+ style.backgroundColor = `var(--wpds-color-bg-${ target }-${ bg }, var(--wpds-color-bg-surface-${ bg }))`;
99
+ }
100
+
101
+ if ( fg ) {
102
+ style.color = `var(--wpds-color-fg-${ target }-${ fg }, var(--wpds-color-fg-content-${ fg }))`;
103
+ }
104
+
105
+ if ( p ) {
106
+ Object.assign(
107
+ style,
108
+ getDimensionVariantStyles( 'padding', target, p )
109
+ );
110
+ }
111
+
112
+ return renderElement< 'div' >( render, { style, ...props }, ref );
113
+ } );
@@ -0,0 +1 @@
1
+ export { Box } from './box';
@@ -0,0 +1,66 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { type Meta, type StoryObj } from '@storybook/react';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { privateApis } from '@wordpress/theme';
10
+ import '@wordpress/theme/design-tokens.css'; // eslint-disable-line no-restricted-syntax
11
+
12
+ /**
13
+ * Internal dependencies
14
+ */
15
+ import { Box } from '../box';
16
+ import { unlock } from '../../lock-unlock';
17
+
18
+ const { ThemeProvider } = unlock( privateApis );
19
+
20
+ const meta: Meta< typeof Box > = {
21
+ title: 'Design System/Components/Box',
22
+ component: Box,
23
+ decorators: [
24
+ ( Story ) => (
25
+ <ThemeProvider>
26
+ <Story />
27
+ </ThemeProvider>
28
+ ),
29
+ ],
30
+ tags: [ 'status-experimental' ],
31
+ };
32
+ export default meta;
33
+
34
+ type Story = StoryObj< typeof Box >;
35
+
36
+ export const Default: Story = {
37
+ args: {
38
+ children: 'Box',
39
+ backgroundColor: 'info',
40
+ color: 'info',
41
+ padding: 4,
42
+ },
43
+ argTypes: {
44
+ p: {
45
+ control: 'select',
46
+ options: [ 'x-small', 'small', 'medium', 'large', 1, 2, 3, 4 ],
47
+ },
48
+ padding: {
49
+ control: 'select',
50
+ options: [ 'x-small', 'small', 'medium', 'large', 1, 2, 3, 4 ],
51
+ },
52
+ },
53
+ };
54
+
55
+ export const DirectionalPadding: Story = {
56
+ args: {
57
+ children: 'Box',
58
+ backgroundColor: 'info',
59
+ color: 'info',
60
+ padding: {
61
+ blockStart: 'small',
62
+ inline: 'medium',
63
+ blockEnd: 'large',
64
+ },
65
+ },
66
+ };
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import { type ComponentProps } from '../utils/types';
5
+
6
+ type SizeToken = 'x-small' | 'small' | 'medium' | 'large';
7
+
8
+ type Size = number | SizeToken;
9
+
10
+ type BackgroundColor =
11
+ | 'neutral'
12
+ | 'neutral-strong'
13
+ | 'neutral-weak'
14
+ | 'brand'
15
+ | 'success'
16
+ | 'success-weak'
17
+ | 'info'
18
+ | 'info-weak'
19
+ | 'warning'
20
+ | 'warning-weak'
21
+ | 'caution'
22
+ | 'caution-weak'
23
+ | 'error'
24
+ | 'error-weak';
25
+
26
+ type ForegroundColor =
27
+ | 'neutral'
28
+ | 'neutral-weak'
29
+ | 'success'
30
+ | 'success-weak'
31
+ | 'info'
32
+ | 'info-weak'
33
+ | 'warning'
34
+ | 'warning-weak'
35
+ | 'caution'
36
+ | 'caution-weak'
37
+ | 'error'
38
+ | 'error-weak';
39
+
40
+ type DimensionVariant< T > = {
41
+ block?: T;
42
+ blockStart?: T;
43
+ blockEnd?: T;
44
+ inline?: T;
45
+ inlineStart?: T;
46
+ inlineEnd?: T;
47
+ };
48
+
49
+ export interface BoxProps extends ComponentProps< 'div' > {
50
+ /**
51
+ * The target rendering element design token grouping to use for the box.
52
+ */
53
+ target?: string;
54
+
55
+ /**
56
+ * The surface background design token for box background color.
57
+ *
58
+ * Shorthand for `backgroundColor`.
59
+ */
60
+ bg?: BackgroundColor;
61
+
62
+ /**
63
+ * The surface background design token for box background color.
64
+ */
65
+ backgroundColor?: BackgroundColor;
66
+
67
+ /**
68
+ * The surface foreground design token for box text color.
69
+ *
70
+ * Shorthand for `color`.
71
+ */
72
+ fg?: ForegroundColor;
73
+
74
+ /**
75
+ * The surface foreground design token for box text color.
76
+ */
77
+ color?: ForegroundColor;
78
+
79
+ /**
80
+ * The surface spacing design token or base unit multiplier for box padding.
81
+ *
82
+ * Shorthand for `padding`.
83
+ */
84
+ p?: Size | DimensionVariant< Size >;
85
+
86
+ /**
87
+ * The surface spacing design token or base unit multiplier for box padding.
88
+ */
89
+ padding?: Size | DimensionVariant< Size >;
90
+
91
+ /**
92
+ * The content to be rendered inside the component.
93
+ */
94
+ children?: React.ReactNode;
95
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './box';
@@ -0,0 +1,10 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/private-apis';
5
+
6
+ export const { lock, unlock } =
7
+ __dangerousOptInToUnstableAPIsOnlyForCoreModules(
8
+ 'I acknowledge private features are not for use in themes or plugins and doing so will break in the next version of WordPress.',
9
+ '@wordpress/dataviews'
10
+ );
@@ -0,0 +1,38 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { cloneElement } from '@wordpress/element';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import type { ComponentProps } from './types';
10
+
11
+ type RenderProp< E extends React.ElementType > = NonNullable<
12
+ ComponentProps< E >[ 'render' ]
13
+ >;
14
+
15
+ /**
16
+ * Renders an element from a render prop (a component or an element), with
17
+ * merged props and ref.
18
+ *
19
+ * @param render The render prop (component or element).
20
+ * @param props Props to pass to or merge with the element.
21
+ * @param ref Optional ref to attach to the element.
22
+ * @return The rendered element.
23
+ */
24
+ export const renderElement = < E extends React.ElementType >(
25
+ render: RenderProp< E >,
26
+ props: Omit< ComponentProps< E >, 'render' >,
27
+ ref?: React.Ref<
28
+ E extends keyof HTMLElementTagNameMap
29
+ ? HTMLElementTagNameMap[ E ]
30
+ : Element
31
+ >
32
+ ): React.ReactElement => {
33
+ const propsWithRef = ref ? { ...props, ref } : props;
34
+
35
+ return typeof render === 'function'
36
+ ? render( propsWithRef )
37
+ : cloneElement( render, propsWithRef );
38
+ };
@@ -0,0 +1,34 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import {
5
+ type ElementType,
6
+ type ComponentPropsWithoutRef,
7
+ type HTMLAttributes,
8
+ type Ref,
9
+ } from 'react';
10
+
11
+ type HTMLAttributesWithRef< T extends ElementType = any > =
12
+ HTMLAttributes< T > & { ref?: Ref< T > | undefined };
13
+
14
+ type ComponentRenderFn< Props > = (
15
+ props: Props
16
+ ) => React.ReactElement< unknown >;
17
+
18
+ export type ComponentProps< E extends ElementType > = Omit<
19
+ ComponentPropsWithoutRef< E >,
20
+ 'className' | 'children' | 'render'
21
+ > & {
22
+ /**
23
+ * CSS class name to apply to the component.
24
+ */
25
+ className?: string;
26
+
27
+ /**
28
+ * Replaces the component's default HTML element using a given React
29
+ * element, or a function that returns a React element.
30
+ */
31
+ render?:
32
+ | ComponentRenderFn< HTMLAttributesWithRef >
33
+ | React.ReactElement< Record< string, unknown > >;
34
+ };