@wordpress/ui 0.6.0 → 0.7.1-next.v.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/CHANGELOG.md +18 -1
- package/build/badge/badge.cjs +1 -1
- package/build/badge/badge.cjs.map +2 -2
- package/build/box/box.cjs +3 -7
- package/build/box/box.cjs.map +2 -2
- package/build/button/button.cjs +3 -3
- package/build/button/button.cjs.map +2 -2
- package/build/form/primitives/fieldset/root.cjs +3 -3
- package/build/form/primitives/fieldset/root.cjs.map +2 -2
- package/build/form/primitives/input-layout/input-layout.cjs +3 -3
- package/build/form/primitives/input-layout/input-layout.cjs.map +2 -2
- package/build/form/primitives/input-layout/slot.cjs +3 -3
- package/build/form/primitives/input-layout/slot.cjs.map +2 -2
- package/build/form/primitives/select/item.cjs +3 -3
- package/build/form/primitives/select/item.cjs.map +2 -2
- package/build/form/primitives/select/popup.cjs +3 -3
- package/build/form/primitives/select/popup.cjs.map +2 -2
- package/build/form/primitives/select/trigger.cjs +3 -3
- package/build/form/primitives/select/trigger.cjs.map +2 -2
- package/build/icon-button/icon-button.cjs +103 -0
- package/build/icon-button/icon-button.cjs.map +7 -0
- package/build/icon-button/index.cjs +31 -0
- package/build/icon-button/index.cjs.map +7 -0
- package/build/icon-button/types.cjs +19 -0
- package/build/icon-button/types.cjs.map +7 -0
- package/build/index.cjs +5 -0
- package/build/index.cjs.map +2 -2
- package/build/tabs/index.cjs +40 -0
- package/build/tabs/index.cjs.map +7 -0
- package/build/tabs/list.cjs +145 -0
- package/build/tabs/list.cjs.map +7 -0
- package/build/tabs/panel.cjs +67 -0
- package/build/tabs/panel.cjs.map +7 -0
- package/build/tabs/root.cjs +38 -0
- package/build/tabs/root.cjs.map +7 -0
- package/build/tabs/tab.cjs +71 -0
- package/build/tabs/tab.cjs.map +7 -0
- package/build/tabs/types.cjs +19 -0
- package/build/tabs/types.cjs.map +7 -0
- package/build/tooltip/popup.cjs +3 -3
- package/build/tooltip/popup.cjs.map +2 -2
- package/build-module/badge/badge.mjs +1 -1
- package/build-module/badge/badge.mjs.map +2 -2
- package/build-module/box/box.mjs +3 -7
- package/build-module/box/box.mjs.map +2 -2
- package/build-module/button/button.mjs +3 -3
- package/build-module/button/button.mjs.map +2 -2
- package/build-module/form/primitives/fieldset/root.mjs +3 -3
- package/build-module/form/primitives/fieldset/root.mjs.map +2 -2
- package/build-module/form/primitives/input-layout/input-layout.mjs +3 -3
- package/build-module/form/primitives/input-layout/input-layout.mjs.map +2 -2
- package/build-module/form/primitives/input-layout/slot.mjs +3 -3
- package/build-module/form/primitives/input-layout/slot.mjs.map +2 -2
- package/build-module/form/primitives/select/item.mjs +3 -3
- package/build-module/form/primitives/select/item.mjs.map +2 -2
- package/build-module/form/primitives/select/popup.mjs +3 -3
- package/build-module/form/primitives/select/popup.mjs.map +2 -2
- package/build-module/form/primitives/select/trigger.mjs +3 -3
- package/build-module/form/primitives/select/trigger.mjs.map +2 -2
- package/build-module/icon-button/icon-button.mjs +68 -0
- package/build-module/icon-button/icon-button.mjs.map +7 -0
- package/build-module/icon-button/index.mjs +6 -0
- package/build-module/icon-button/index.mjs.map +7 -0
- package/build-module/icon-button/types.mjs +1 -0
- package/build-module/icon-button/types.mjs.map +7 -0
- package/build-module/index.mjs +3 -0
- package/build-module/index.mjs.map +2 -2
- package/build-module/tabs/index.mjs +12 -0
- package/build-module/tabs/index.mjs.map +7 -0
- package/build-module/tabs/list.mjs +110 -0
- package/build-module/tabs/list.mjs.map +7 -0
- package/build-module/tabs/panel.mjs +32 -0
- package/build-module/tabs/panel.mjs.map +7 -0
- package/build-module/tabs/root.mjs +13 -0
- package/build-module/tabs/root.mjs.map +7 -0
- package/build-module/tabs/tab.mjs +36 -0
- package/build-module/tabs/tab.mjs.map +7 -0
- package/build-module/tabs/types.mjs +1 -0
- package/build-module/tabs/types.mjs.map +7 -0
- package/build-module/tooltip/popup.mjs +3 -3
- package/build-module/tooltip/popup.mjs.map +2 -2
- package/build-types/box/box.d.ts.map +1 -1
- package/build-types/box/stories/index.story.d.ts.map +1 -1
- package/build-types/button/stories/index.story.d.ts +1 -2
- package/build-types/button/stories/index.story.d.ts.map +1 -1
- package/build-types/form/primitives/field/stories/index.story.d.ts +0 -1
- package/build-types/form/primitives/field/stories/index.story.d.ts.map +1 -1
- package/build-types/form/primitives/select/stories/index.story.d.ts +0 -1
- package/build-types/form/primitives/select/stories/index.story.d.ts.map +1 -1
- package/build-types/icon-button/icon-button.d.ts +13 -0
- package/build-types/icon-button/icon-button.d.ts.map +1 -0
- package/build-types/icon-button/index.d.ts +2 -0
- package/build-types/icon-button/index.d.ts.map +1 -0
- package/build-types/icon-button/stories/index.story.d.ts +19 -0
- package/build-types/icon-button/stories/index.story.d.ts.map +1 -0
- package/build-types/icon-button/test/index.test.d.ts +2 -0
- package/build-types/icon-button/test/index.test.d.ts.map +1 -0
- package/build-types/icon-button/types.d.ts +36 -0
- package/build-types/icon-button/types.d.ts.map +1 -0
- package/build-types/index.d.ts +2 -0
- package/build-types/index.d.ts.map +1 -1
- package/build-types/tabs/index.d.ts +6 -0
- package/build-types/tabs/index.d.ts.map +1 -0
- package/build-types/tabs/list.d.ts +16 -0
- package/build-types/tabs/list.d.ts.map +1 -0
- package/build-types/tabs/panel.d.ts +15 -0
- package/build-types/tabs/panel.d.ts.map +1 -0
- package/build-types/tabs/root.d.ts +15 -0
- package/build-types/tabs/root.d.ts.map +1 -0
- package/build-types/tabs/stories/index.story.d.ts +13 -0
- package/build-types/tabs/stories/index.story.d.ts.map +1 -0
- package/build-types/tabs/tab.d.ts +15 -0
- package/build-types/tabs/tab.d.ts.map +1 -0
- package/build-types/tabs/test/index.test.d.ts +2 -0
- package/build-types/tabs/test/index.test.d.ts.map +1 -0
- package/build-types/tabs/types.d.ts +33 -0
- package/build-types/tabs/types.d.ts.map +1 -0
- package/package.json +11 -9
- package/src/badge/badge.tsx +1 -1
- package/src/box/box.tsx +4 -15
- package/src/box/stories/index.story.tsx +9 -1
- package/src/button/stories/index.story.tsx +3 -16
- package/src/button/style.module.css +6 -3
- package/src/form/primitives/field/stories/index.story.tsx +0 -1
- package/src/form/primitives/fieldset/style.module.css +1 -1
- package/src/form/primitives/input-layout/style.module.css +5 -8
- package/src/form/primitives/select/stories/index.story.tsx +0 -1
- package/src/icon-button/icon-button.tsx +64 -0
- package/src/icon-button/index.ts +1 -0
- package/src/icon-button/stories/index.story.tsx +128 -0
- package/src/icon-button/style.module.css +9 -0
- package/src/icon-button/test/index.test.tsx +86 -0
- package/src/icon-button/types.ts +38 -0
- package/src/index.ts +2 -0
- package/src/tabs/index.ts +6 -0
- package/src/tabs/list.tsx +130 -0
- package/src/tabs/panel.tsx +23 -0
- package/src/tabs/root.tsx +15 -0
- package/src/tabs/stories/best-practices.mdx +85 -0
- package/src/tabs/stories/index.story.tsx +363 -0
- package/src/tabs/style.module.css +269 -0
- package/src/tabs/tab.tsx +29 -0
- package/src/tabs/test/index.test.tsx +2260 -0
- package/src/tabs/types.ts +36 -0
- package/src/tooltip/style.module.css +2 -2
- package/src/utils/css/item-popup.module.css +1 -1
- package/src/utils/css/select-trigger.module.css +1 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Groups the tabs and the corresponding panels.
|
|
3
|
+
*
|
|
4
|
+
* `Tabs` is a collection of React components that combine to render
|
|
5
|
+
* an [ARIA-compliant tabs pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tabs/).
|
|
6
|
+
*/
|
|
7
|
+
export declare const Root: import("react").ForwardRefExoticComponent<Omit<Omit<import("@base-ui/react").TabsRootProps & import("react").RefAttributes<HTMLDivElement>, "ref">, "className" | "children" | "render"> & {
|
|
8
|
+
className?: string;
|
|
9
|
+
render?: ((props: import("react").HTMLAttributes<any> & {
|
|
10
|
+
ref?: import("react").Ref<any> | undefined;
|
|
11
|
+
}) => React.ReactElement<unknown>) | React.ReactElement<Record<string, unknown>>;
|
|
12
|
+
} & {
|
|
13
|
+
children?: import("react").ReactNode;
|
|
14
|
+
} & import("react").RefAttributes<HTMLDivElement>>;
|
|
15
|
+
//# sourceMappingURL=root.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"root.d.ts","sourceRoot":"","sources":["../../src/tabs/root.tsx"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH,eAAO,MAAM,IAAI;;;;;;;kDAIhB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
import { Tabs } from '../..';
|
|
3
|
+
declare const meta: Meta<typeof Tabs.Root>;
|
|
4
|
+
export default meta;
|
|
5
|
+
export declare const Default: StoryObj<typeof Tabs.Root>;
|
|
6
|
+
export declare const Minimal: StoryObj<typeof Tabs.Root>;
|
|
7
|
+
export declare const SizeAndOverflowPlayground: StoryObj<typeof Tabs.Root>;
|
|
8
|
+
export declare const Vertical: StoryObj<typeof Tabs.Root>;
|
|
9
|
+
export declare const WithDisabledTab: StoryObj<typeof Tabs.Root>;
|
|
10
|
+
export declare const WithTabIconsAndTooltips: StoryObj<typeof Tabs.Root>;
|
|
11
|
+
export declare const WithPanelsAlwaysMounted: StoryObj<typeof Tabs.Root>;
|
|
12
|
+
export declare const WithNonFocusablePanels: StoryObj<typeof Tabs.Root>;
|
|
13
|
+
//# sourceMappingURL=index.story.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.story.d.ts","sourceRoot":"","sources":["../../../src/tabs/stories/index.story.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAG5D,OAAO,EAAE,IAAI,EAAW,MAAM,OAAO,CAAC;AAEtC,QAAA,MAAM,IAAI,EAAE,IAAI,CAAE,OAAO,IAAI,CAAC,IAAI,CAQjC,CAAC;AACF,eAAe,IAAI,CAAC;AAUpB,eAAO,MAAM,OAAO,EAAE,QAAQ,CAAE,OAAO,IAAI,CAAC,IAAI,CAsB/C,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,QAAQ,CAAE,OAAO,IAAI,CAAC,IAAI,CAsB/C,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,QAAQ,CAAE,OAAO,IAAI,CAAC,IAAI,CAqHjE,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,QAAQ,CAAE,OAAO,IAAI,CAAC,IAAI,CAWhD,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,QAAQ,CAAE,OAAO,IAAI,CAAC,IAAI,CAyBvD,CAAC;AAgCF,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAE,OAAO,IAAI,CAAC,IAAI,CAsC/D,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAE,OAAO,IAAI,CAAC,IAAI,CAsB/D,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAAE,OAAO,IAAI,CAAC,IAAI,CAqC9D,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An individual interactive tab button that toggles the corresponding panel.
|
|
3
|
+
*
|
|
4
|
+
* `Tabs` is a collection of React components that combine to render
|
|
5
|
+
* an [ARIA-compliant tabs pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tabs/).
|
|
6
|
+
*/
|
|
7
|
+
export declare const Tab: import("react").ForwardRefExoticComponent<Omit<Omit<import("@base-ui/react").TabsTabProps & import("react").RefAttributes<Element>, "ref">, "className" | "children" | "render"> & {
|
|
8
|
+
className?: string;
|
|
9
|
+
render?: ((props: import("react").HTMLAttributes<any> & {
|
|
10
|
+
ref?: import("react").Ref<any> | undefined;
|
|
11
|
+
}) => React.ReactElement<unknown>) | React.ReactElement<Record<string, unknown>>;
|
|
12
|
+
} & {
|
|
13
|
+
children?: import("react").ReactNode;
|
|
14
|
+
} & import("react").RefAttributes<HTMLButtonElement>>;
|
|
15
|
+
//# sourceMappingURL=tab.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tab.d.ts","sourceRoot":"","sources":["../../src/tabs/tab.tsx"],"names":[],"mappings":"AAQA;;;;;GAKG;AACH,eAAO,MAAM,GAAG;;;;;;;qDAcb,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../../src/tabs/test/index.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { Tabs as _Tabs } from '@base-ui/react/tabs';
|
|
3
|
+
import type { ComponentProps } from '../utils/types';
|
|
4
|
+
export type TabRootProps = ComponentProps<typeof _Tabs.Root> & {
|
|
5
|
+
/**
|
|
6
|
+
* The content to be rendered inside the component.
|
|
7
|
+
*/
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
};
|
|
10
|
+
export type TabListProps = ComponentProps<typeof _Tabs.List> & {
|
|
11
|
+
/**
|
|
12
|
+
* The content to be rendered inside the component.
|
|
13
|
+
*/
|
|
14
|
+
children?: ReactNode;
|
|
15
|
+
/**
|
|
16
|
+
* The visual variant of the tab list.
|
|
17
|
+
* @default "default"
|
|
18
|
+
*/
|
|
19
|
+
variant?: 'minimal' | 'default';
|
|
20
|
+
};
|
|
21
|
+
export type TabProps = ComponentProps<typeof _Tabs.Tab> & {
|
|
22
|
+
/**
|
|
23
|
+
* The content to be rendered inside the component.
|
|
24
|
+
*/
|
|
25
|
+
children?: ReactNode;
|
|
26
|
+
};
|
|
27
|
+
export type TabPanelProps = ComponentProps<typeof _Tabs.Panel> & {
|
|
28
|
+
/**
|
|
29
|
+
* The content to be rendered inside the component.
|
|
30
|
+
*/
|
|
31
|
+
children?: ReactNode;
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/tabs/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,IAAI,IAAI,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,MAAM,YAAY,GAAG,cAAc,CAAE,OAAO,KAAK,CAAC,IAAI,CAAE,GAAG;IAChE;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,cAAc,CAAE,OAAO,KAAK,CAAC,IAAI,CAAE,GAAG;IAChE;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB;;;OAGG;IACH,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,cAAc,CAAE,OAAO,KAAK,CAAC,GAAG,CAAE,GAAG;IAC3D;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,cAAc,CAAE,OAAO,KAAK,CAAC,KAAK,CAAE,GAAG;IAClE;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;CACrB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordpress/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1-next.v.0+642962a6d",
|
|
4
4
|
"description": "Themeable React UI components for the WordPress Design System.",
|
|
5
5
|
"author": "The WordPress Contributors",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
|
@@ -44,13 +44,15 @@
|
|
|
44
44
|
"sideEffects": false,
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@base-ui/react": "^1.0.0",
|
|
47
|
-
"@wordpress/a11y": "^4.39.0",
|
|
48
|
-
"@wordpress/
|
|
49
|
-
"@wordpress/
|
|
50
|
-
"@wordpress/
|
|
51
|
-
"@wordpress/
|
|
52
|
-
"@wordpress/
|
|
53
|
-
"@wordpress/
|
|
47
|
+
"@wordpress/a11y": "^4.39.1-next.v.0+642962a6d",
|
|
48
|
+
"@wordpress/compose": "^7.39.1-next.v.0+642962a6d",
|
|
49
|
+
"@wordpress/element": "^6.39.1-next.v.0+642962a6d",
|
|
50
|
+
"@wordpress/i18n": "^6.12.1-next.v.0+642962a6d",
|
|
51
|
+
"@wordpress/icons": "^11.6.1-next.v.0+642962a6d",
|
|
52
|
+
"@wordpress/keycodes": "^4.39.1-next.v.0+642962a6d",
|
|
53
|
+
"@wordpress/primitives": "^4.39.1-next.v.0+642962a6d",
|
|
54
|
+
"@wordpress/private-apis": "^1.39.1-next.v.0+642962a6d",
|
|
55
|
+
"@wordpress/theme": "^0.7.1-next.v.0+642962a6d",
|
|
54
56
|
"clsx": "^2.1.1"
|
|
55
57
|
},
|
|
56
58
|
"devDependencies": {
|
|
@@ -68,5 +70,5 @@
|
|
|
68
70
|
"publishConfig": {
|
|
69
71
|
"access": "public"
|
|
70
72
|
},
|
|
71
|
-
"gitHead": "
|
|
73
|
+
"gitHead": "2de56f23b200b6dc4b1feda4408613ad088d160a"
|
|
72
74
|
}
|
package/src/badge/badge.tsx
CHANGED
|
@@ -70,7 +70,7 @@ export const Badge = forwardRef< HTMLDivElement, BadgeProps >( function Badge(
|
|
|
70
70
|
return (
|
|
71
71
|
<Box
|
|
72
72
|
{ ...intentStyles }
|
|
73
|
-
padding={ { inline: '
|
|
73
|
+
padding={ { inline: 'sm', block: 'xs' } }
|
|
74
74
|
borderRadius="lg"
|
|
75
75
|
render={ render }
|
|
76
76
|
style={ {
|
package/src/box/box.tsx
CHANGED
|
@@ -20,16 +20,11 @@ const capitalize = ( str: string ): string =>
|
|
|
20
20
|
* fallback).
|
|
21
21
|
*
|
|
22
22
|
* @param property The CSS property name.
|
|
23
|
-
* @param target The design system token target.
|
|
24
23
|
* @param value The size token name.
|
|
25
24
|
* @return A CSS value string with variable references.
|
|
26
25
|
*/
|
|
27
|
-
const getSpacingValue = (
|
|
28
|
-
property
|
|
29
|
-
target: string,
|
|
30
|
-
value: string
|
|
31
|
-
): string =>
|
|
32
|
-
`var(--wpds-dimension-${ property }-${ target }-${ value }, var(--wpds-dimension-${ property }-surface-${ value }))`;
|
|
26
|
+
const getSpacingValue = ( property: string, value: string ): string =>
|
|
27
|
+
`var(--wpds-dimension-${ property }-${ value }, var(--wpds-dimension-${ property }-${ value }))`;
|
|
33
28
|
|
|
34
29
|
/**
|
|
35
30
|
* Generates CSS styles for properties with optionally directional values,
|
|
@@ -37,23 +32,20 @@ const getSpacingValue = (
|
|
|
37
32
|
* properties.
|
|
38
33
|
*
|
|
39
34
|
* @param property The CSS property name from BoxProps.
|
|
40
|
-
* @param target The design system token target.
|
|
41
35
|
* @param value The property value (single or object with directional keys).
|
|
42
36
|
* @return A CSSProperties object with the computed styles.
|
|
43
37
|
*/
|
|
44
38
|
const getDimensionVariantStyles = < T extends keyof BoxProps >(
|
|
45
39
|
property: T,
|
|
46
|
-
target: string,
|
|
47
40
|
value: NonNullable< BoxProps[ T ] >
|
|
48
41
|
): React.CSSProperties =>
|
|
49
42
|
typeof value !== 'object'
|
|
50
|
-
? { [ property ]: getSpacingValue( property,
|
|
43
|
+
? { [ property ]: getSpacingValue( property, value ) }
|
|
51
44
|
: Object.keys( value ).reduce(
|
|
52
45
|
( result, key ) => ( {
|
|
53
46
|
...result,
|
|
54
47
|
[ property + capitalize( key ) ]: getSpacingValue(
|
|
55
48
|
property,
|
|
56
|
-
target,
|
|
57
49
|
value[ key ]
|
|
58
50
|
),
|
|
59
51
|
} ),
|
|
@@ -89,10 +81,7 @@ export const Box = forwardRef< HTMLDivElement, BoxProps >( function Box(
|
|
|
89
81
|
}
|
|
90
82
|
|
|
91
83
|
if ( padding ) {
|
|
92
|
-
Object.assign(
|
|
93
|
-
style,
|
|
94
|
-
getDimensionVariantStyles( 'padding', target, padding )
|
|
95
|
-
);
|
|
84
|
+
Object.assign( style, getDimensionVariantStyles( 'padding', padding ) );
|
|
96
85
|
}
|
|
97
86
|
|
|
98
87
|
if ( borderRadius ) {
|
|
@@ -23,7 +23,15 @@ export const Default: Story = {
|
|
|
23
23
|
argTypes: {
|
|
24
24
|
padding: {
|
|
25
25
|
control: 'select',
|
|
26
|
-
options: [
|
|
26
|
+
options: [
|
|
27
|
+
'xs',
|
|
28
|
+
'sm',
|
|
29
|
+
'md',
|
|
30
|
+
'lg',
|
|
31
|
+
'xl',
|
|
32
|
+
'2xl',
|
|
33
|
+
'3xl',
|
|
34
|
+
] satisfies PaddingSize[],
|
|
27
35
|
},
|
|
28
36
|
},
|
|
29
37
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Fragment
|
|
1
|
+
import { Fragment } from '@wordpress/element';
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
3
3
|
import { cog } from '@wordpress/icons';
|
|
4
4
|
import { Button } from '../index';
|
|
@@ -166,8 +166,7 @@ export const Loading: Story = {
|
|
|
166
166
|
|
|
167
167
|
/**
|
|
168
168
|
* The pressed state is only available for buttons with `tone="neutral"` and
|
|
169
|
-
* `variant="minimal"
|
|
170
|
-
* active/pressed state.
|
|
169
|
+
* `variant="minimal"` and can be toggled via the `aria-pressed` HTML attribute.
|
|
171
170
|
*/
|
|
172
171
|
export const Pressed: Story = {
|
|
173
172
|
...Default,
|
|
@@ -175,18 +174,6 @@ export const Pressed: Story = {
|
|
|
175
174
|
...Default.args,
|
|
176
175
|
tone: 'neutral',
|
|
177
176
|
variant: 'minimal',
|
|
178
|
-
|
|
179
|
-
render: ( args ) => {
|
|
180
|
-
const [ isPressed, setIsPressed ] = useState( true );
|
|
181
|
-
|
|
182
|
-
return (
|
|
183
|
-
<Button
|
|
184
|
-
{ ...args }
|
|
185
|
-
aria-pressed={ isPressed }
|
|
186
|
-
onClick={ () => setIsPressed( ! isPressed ) }
|
|
187
|
-
>
|
|
188
|
-
Button
|
|
189
|
-
</Button>
|
|
190
|
-
);
|
|
177
|
+
'aria-pressed': true,
|
|
191
178
|
},
|
|
192
179
|
};
|
|
@@ -17,10 +17,11 @@
|
|
|
17
17
|
--wp-ui-button-foreground-color: var(--wpds-color-fg-interactive-brand-strong);
|
|
18
18
|
--wp-ui-button-foreground-color-active: var(--wpds-color-fg-interactive-brand-strong-active);
|
|
19
19
|
--wp-ui-button-foreground-color-disabled: var(--wpds-color-fg-interactive-neutral-strong-disabled);
|
|
20
|
-
--wp-ui-button-padding-inline:
|
|
20
|
+
--wp-ui-button-padding-inline: var(--wpds-dimension-padding-md);
|
|
21
21
|
--wp-ui-button-height: 40px;
|
|
22
22
|
--wp-ui-button-aspect-ratio: auto; /* Useful for overrides such as icon buttons */
|
|
23
23
|
--wp-ui-button-font-size: var(--wpds-font-size-md);
|
|
24
|
+
--wp-ui-button-min-width: calc(4ch + 2 * var(--wp-ui-button-padding-inline));
|
|
24
25
|
|
|
25
26
|
/* by default, borders have the same color as the background */
|
|
26
27
|
--wp-ui-button-border-color: var(--wp-ui-button-background-color);
|
|
@@ -32,8 +33,9 @@
|
|
|
32
33
|
display: inline-flex;
|
|
33
34
|
justify-content: center;
|
|
34
35
|
align-items: center;
|
|
35
|
-
gap:
|
|
36
|
+
gap: var(--wpds-dimension-gap-sm);
|
|
36
37
|
aspect-ratio: var(--wp-ui-button-aspect-ratio);
|
|
38
|
+
min-width: var(--wp-ui-button-min-width);
|
|
37
39
|
height: var(--wp-ui-button-height);
|
|
38
40
|
padding-inline: var(--wp-ui-button-padding-inline);
|
|
39
41
|
border-style: solid;
|
|
@@ -119,7 +121,7 @@
|
|
|
119
121
|
}
|
|
120
122
|
|
|
121
123
|
.is-small {
|
|
122
|
-
--wp-ui-button-padding-inline:
|
|
124
|
+
--wp-ui-button-padding-inline: var(--wpds-dimension-padding-sm);
|
|
123
125
|
--wp-ui-button-height: 24px;
|
|
124
126
|
}
|
|
125
127
|
|
|
@@ -188,6 +190,7 @@
|
|
|
188
190
|
}
|
|
189
191
|
|
|
190
192
|
.is-unstyled {
|
|
193
|
+
min-width: unset;
|
|
191
194
|
border: none;
|
|
192
195
|
background: none;
|
|
193
196
|
}
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
@layer wp-ui-components {
|
|
4
4
|
.input-layout {
|
|
5
|
-
|
|
6
|
-
--wp-ui-input-layout-padding-inline: calc(var(--wpds-dimension-base) * 3);
|
|
5
|
+
--wp-ui-input-layout-padding-inline: var(--wpds-dimension-padding-md);
|
|
7
6
|
|
|
8
7
|
display: flex;
|
|
9
8
|
height: 40px;
|
|
@@ -22,14 +21,12 @@
|
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
&.is-size-compact {
|
|
25
|
-
|
|
26
|
-
--wp-ui-input-layout-padding-inline: calc(var(--wpds-dimension-base) * 2);
|
|
24
|
+
--wp-ui-input-layout-padding-inline: var(--wpds-dimension-padding-sm);
|
|
27
25
|
height: 32px;
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
&.is-size-small {
|
|
31
|
-
|
|
32
|
-
--wp-ui-input-layout-padding-inline: calc(var(--wpds-dimension-base) * 2);
|
|
29
|
+
--wp-ui-input-layout-padding-inline: var(--wpds-dimension-padding-sm);
|
|
33
30
|
height: 24px;
|
|
34
31
|
}
|
|
35
32
|
|
|
@@ -66,10 +63,10 @@
|
|
|
66
63
|
&.is-padding-minimal {
|
|
67
64
|
--wp-ui-input-layout-prefix-padding-start:
|
|
68
65
|
calc(var(--wp-ui-input-layout-padding-inline) -
|
|
69
|
-
var(--wpds-dimension-
|
|
66
|
+
var(--wpds-dimension-padding-xs));
|
|
70
67
|
--wp-ui-input-layout-suffix-padding-end:
|
|
71
68
|
calc(var(--wp-ui-input-layout-padding-inline) -
|
|
72
|
-
var(--wpds-dimension-
|
|
69
|
+
var(--wpds-dimension-padding-xs));
|
|
73
70
|
}
|
|
74
71
|
|
|
75
72
|
&.is-prefix {
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import clsx from 'clsx';
|
|
2
|
+
import { forwardRef } from '@wordpress/element';
|
|
3
|
+
import { Button } from '../button';
|
|
4
|
+
import { Icon } from '../icon';
|
|
5
|
+
import * as Tooltip from '../tooltip';
|
|
6
|
+
import styles from './style.module.css';
|
|
7
|
+
import { type IconButtonProps } from './types';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* An icon-only button with automatic tooltip and optimized styling.
|
|
11
|
+
* Inherits all Button props while providing icon-specific enhancements.
|
|
12
|
+
*/
|
|
13
|
+
export const IconButton = forwardRef< HTMLButtonElement, IconButtonProps >(
|
|
14
|
+
function IconButton(
|
|
15
|
+
{
|
|
16
|
+
label,
|
|
17
|
+
className,
|
|
18
|
+
// Prevent accidental forwarding of `children`
|
|
19
|
+
children: _children,
|
|
20
|
+
icon,
|
|
21
|
+
size,
|
|
22
|
+
shortcut,
|
|
23
|
+
...restProps
|
|
24
|
+
}: IconButtonProps & { children?: unknown },
|
|
25
|
+
ref
|
|
26
|
+
) {
|
|
27
|
+
const classes = clsx( styles[ 'icon-button' ], className );
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<Tooltip.Provider delay={ 0 }>
|
|
31
|
+
<Tooltip.Root>
|
|
32
|
+
<Tooltip.Trigger
|
|
33
|
+
ref={ ref }
|
|
34
|
+
render={
|
|
35
|
+
<Button
|
|
36
|
+
{ ...restProps }
|
|
37
|
+
size={ size }
|
|
38
|
+
aria-label={ label }
|
|
39
|
+
aria-keyshortcuts={ shortcut?.ariaKeyShortcut }
|
|
40
|
+
/>
|
|
41
|
+
}
|
|
42
|
+
className={ classes }
|
|
43
|
+
>
|
|
44
|
+
<Icon
|
|
45
|
+
icon={ icon }
|
|
46
|
+
size={ size === 'small' ? 22 : 24 }
|
|
47
|
+
/>
|
|
48
|
+
</Tooltip.Trigger>
|
|
49
|
+
<Tooltip.Popup>
|
|
50
|
+
{ label }
|
|
51
|
+
{ shortcut && (
|
|
52
|
+
<>
|
|
53
|
+
{ ' ' }
|
|
54
|
+
<span aria-hidden="true">
|
|
55
|
+
{ shortcut.displayShortcut }
|
|
56
|
+
</span>
|
|
57
|
+
</>
|
|
58
|
+
) }
|
|
59
|
+
</Tooltip.Popup>
|
|
60
|
+
</Tooltip.Root>
|
|
61
|
+
</Tooltip.Provider>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { IconButton } from './icon-button';
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
import {
|
|
3
|
+
cog,
|
|
4
|
+
copy,
|
|
5
|
+
download,
|
|
6
|
+
pencil,
|
|
7
|
+
plus,
|
|
8
|
+
trash,
|
|
9
|
+
upload,
|
|
10
|
+
wordpress,
|
|
11
|
+
} from '@wordpress/icons';
|
|
12
|
+
import { displayShortcut, ariaKeyShortcut } from '@wordpress/keycodes';
|
|
13
|
+
import { IconButton } from '../index';
|
|
14
|
+
|
|
15
|
+
const meta: Meta< typeof IconButton > = {
|
|
16
|
+
title: 'Design System/Components/IconButton',
|
|
17
|
+
component: IconButton,
|
|
18
|
+
argTypes: {
|
|
19
|
+
'aria-pressed': {
|
|
20
|
+
control: { type: 'boolean' },
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
export default meta;
|
|
25
|
+
|
|
26
|
+
type Story = StoryObj< typeof IconButton >;
|
|
27
|
+
|
|
28
|
+
export const Default: Story = {
|
|
29
|
+
args: {
|
|
30
|
+
icon: cog,
|
|
31
|
+
label: 'Settings',
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const Outline: Story = {
|
|
36
|
+
...Default,
|
|
37
|
+
args: {
|
|
38
|
+
...Default.args,
|
|
39
|
+
variant: 'outline',
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const Minimal: Story = {
|
|
44
|
+
...Default,
|
|
45
|
+
args: {
|
|
46
|
+
...Default.args,
|
|
47
|
+
variant: 'minimal',
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const Neutral: Story = {
|
|
52
|
+
...Default,
|
|
53
|
+
args: {
|
|
54
|
+
...Default.args,
|
|
55
|
+
tone: 'neutral',
|
|
56
|
+
label: 'Settings',
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const NeutralOutline: Story = {
|
|
61
|
+
...Default,
|
|
62
|
+
args: {
|
|
63
|
+
...Default.args,
|
|
64
|
+
tone: 'neutral',
|
|
65
|
+
variant: 'outline',
|
|
66
|
+
label: 'Settings',
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export const Disabled: Story = {
|
|
71
|
+
...Default,
|
|
72
|
+
args: {
|
|
73
|
+
...Default.args,
|
|
74
|
+
disabled: true,
|
|
75
|
+
label: 'Settings',
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export const WithDifferentIcons: Story = {
|
|
80
|
+
...Default,
|
|
81
|
+
render: ( args ) => (
|
|
82
|
+
<div
|
|
83
|
+
style={ {
|
|
84
|
+
display: 'flex',
|
|
85
|
+
gap: '1rem',
|
|
86
|
+
alignItems: 'center',
|
|
87
|
+
flexWrap: 'wrap',
|
|
88
|
+
} }
|
|
89
|
+
>
|
|
90
|
+
<IconButton { ...args } icon={ wordpress } label="WordPress" />
|
|
91
|
+
<IconButton { ...args } icon={ plus } label="Add" />
|
|
92
|
+
<IconButton { ...args } icon={ pencil } label="Edit" />
|
|
93
|
+
<IconButton { ...args } icon={ trash } label="Delete" />
|
|
94
|
+
<IconButton { ...args } icon={ download } label="Download" />
|
|
95
|
+
<IconButton { ...args } icon={ upload } label="Upload" />
|
|
96
|
+
</div>
|
|
97
|
+
),
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* The pressed state is only available for buttons with `tone="neutral"` and
|
|
102
|
+
* `variant="minimal"` and can be toggled via the `aria-pressed` HTML attribute.
|
|
103
|
+
*/
|
|
104
|
+
export const Pressed: Story = {
|
|
105
|
+
...Default,
|
|
106
|
+
args: {
|
|
107
|
+
...Default.args,
|
|
108
|
+
tone: 'neutral',
|
|
109
|
+
variant: 'minimal',
|
|
110
|
+
label: 'Toggle Settings',
|
|
111
|
+
'aria-pressed': true,
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const EXAMPLE_SHORTCUT_OBJECT = {
|
|
116
|
+
displayShortcut: displayShortcut.primary( 'c' ),
|
|
117
|
+
ariaKeyShortcut: ariaKeyShortcut.primary( 'c' ),
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
export const WithShortcut: Story = {
|
|
121
|
+
...Default,
|
|
122
|
+
args: {
|
|
123
|
+
...Default.args,
|
|
124
|
+
icon: copy,
|
|
125
|
+
label: 'Copy',
|
|
126
|
+
shortcut: EXAMPLE_SHORTCUT_OBJECT,
|
|
127
|
+
},
|
|
128
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { render, waitFor, screen } from '@testing-library/react';
|
|
2
|
+
import userEvent from '@testing-library/user-event';
|
|
3
|
+
import { createRef } from '@wordpress/element';
|
|
4
|
+
import { IconButton } from '../index';
|
|
5
|
+
|
|
6
|
+
describe( 'IconButton', () => {
|
|
7
|
+
it( 'forwards ref', () => {
|
|
8
|
+
const ref = createRef< HTMLButtonElement >();
|
|
9
|
+
|
|
10
|
+
render( <IconButton ref={ ref } label="Click me" icon={ <svg /> } /> );
|
|
11
|
+
|
|
12
|
+
expect( ref.current ).toBeInstanceOf( HTMLButtonElement );
|
|
13
|
+
} );
|
|
14
|
+
|
|
15
|
+
it( 'respects custom render prop as handled by Button', () => {
|
|
16
|
+
render(
|
|
17
|
+
<IconButton
|
|
18
|
+
label="Click me"
|
|
19
|
+
icon={ <svg /> }
|
|
20
|
+
variant="outline"
|
|
21
|
+
disabled
|
|
22
|
+
focusableWhenDisabled
|
|
23
|
+
render={ <button data-testid="button" /> }
|
|
24
|
+
/>
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
// Should render as a button from `render` prop...
|
|
28
|
+
const button = screen.getByRole( 'button', { name: 'Click me' } );
|
|
29
|
+
expect( button ).toHaveAttribute( 'data-testid', 'button' );
|
|
30
|
+
|
|
31
|
+
// ...and still inherit the behavior of Button
|
|
32
|
+
expect( button ).toBeEnabled();
|
|
33
|
+
expect( button ).toHaveAttribute( 'aria-disabled', 'true' );
|
|
34
|
+
} );
|
|
35
|
+
|
|
36
|
+
describe( 'shortcut', () => {
|
|
37
|
+
it( 'sets aria-keyshortcuts attribute on the button', () => {
|
|
38
|
+
const { rerender } = render(
|
|
39
|
+
<IconButton
|
|
40
|
+
label="Save"
|
|
41
|
+
icon={ <svg /> }
|
|
42
|
+
shortcut={ {
|
|
43
|
+
displayShortcut: '⌘S',
|
|
44
|
+
ariaKeyShortcut: 'Meta+S',
|
|
45
|
+
} }
|
|
46
|
+
/>
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const button = screen.getByRole( 'button', { name: 'Save' } );
|
|
50
|
+
expect( button ).toHaveAttribute( 'aria-keyshortcuts', 'Meta+S' );
|
|
51
|
+
|
|
52
|
+
// The aria-keyshortcuts attribute is removed when there is no
|
|
53
|
+
// `shortcut` prop.
|
|
54
|
+
rerender( <IconButton label="Save" icon={ <svg /> } /> );
|
|
55
|
+
expect( button ).not.toHaveAttribute( 'aria-keyshortcuts' );
|
|
56
|
+
} );
|
|
57
|
+
|
|
58
|
+
it( 'displays the shortcut in the tooltip but hides it from assistive technology', async () => {
|
|
59
|
+
const user = userEvent.setup();
|
|
60
|
+
|
|
61
|
+
render(
|
|
62
|
+
<IconButton
|
|
63
|
+
label="Save"
|
|
64
|
+
icon={ <svg /> }
|
|
65
|
+
shortcut={ {
|
|
66
|
+
displayShortcut: '⌘S',
|
|
67
|
+
ariaKeyShortcut: 'Meta+S',
|
|
68
|
+
} }
|
|
69
|
+
/>
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const button = screen.getByRole( 'button', { name: 'Save' } );
|
|
73
|
+
await user.hover( button );
|
|
74
|
+
|
|
75
|
+
await waitFor( () => {
|
|
76
|
+
const shortcutElement = screen.getByText( '⌘S' );
|
|
77
|
+
expect( shortcutElement ).toBeVisible();
|
|
78
|
+
} );
|
|
79
|
+
|
|
80
|
+
expect( screen.getByText( '⌘S' ) ).toHaveAttribute(
|
|
81
|
+
'aria-hidden',
|
|
82
|
+
'true'
|
|
83
|
+
);
|
|
84
|
+
} );
|
|
85
|
+
} );
|
|
86
|
+
} );
|