@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/CONTRIBUTING.md +27 -0
- package/LICENSE.md +788 -0
- package/README.md +82 -0
- package/build-types/box/box.d.ts +10 -0
- package/build-types/box/box.d.ts.map +1 -0
- package/build-types/box/index.d.ts +2 -0
- package/build-types/box/index.d.ts.map +1 -0
- package/build-types/box/stories/index.story.d.ts +15 -0
- package/build-types/box/stories/index.story.d.ts.map +1 -0
- package/build-types/box/types.d.ts +58 -0
- package/build-types/box/types.d.ts.map +1 -0
- package/build-types/index.d.ts +2 -0
- package/build-types/index.d.ts.map +1 -0
- package/build-types/lock-unlock.d.ts +2 -0
- package/build-types/lock-unlock.d.ts.map +1 -0
- package/build-types/utils/element.d.ts +17 -0
- package/build-types/utils/element.d.ts.map +1 -0
- package/build-types/utils/types.d.ts +21 -0
- package/build-types/utils/types.d.ts.map +1 -0
- package/package.json +50 -0
- package/src/box/box.tsx +113 -0
- package/src/box/index.ts +1 -0
- package/src/box/stories/index.story.tsx +66 -0
- package/src/box/types.ts +95 -0
- package/src/index.ts +1 -0
- package/src/lock-unlock.ts +10 -0
- package/src/utils/element.ts +38 -0
- package/src/utils/types.ts +34 -0
- package/tsconfig.json +13 -0
- package/tsconfig.tsbuildinfo +1 -0
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 @@
|
|
|
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 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC"}
|
|
@@ -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
|
+
}
|
package/src/box/box.tsx
ADDED
|
@@ -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
|
+
} );
|
package/src/box/index.ts
ADDED
|
@@ -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
|
+
};
|
package/src/box/types.ts
ADDED
|
@@ -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
|
+
};
|