reshaped 3.6.0-canary.6 → 3.6.0-canary.8

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.
Files changed (93) hide show
  1. package/CHANGELOG.md +14 -1
  2. package/dist/bundle.css +1 -1
  3. package/dist/bundle.d.ts +4 -0
  4. package/dist/bundle.js +11 -11
  5. package/dist/cjs/cli/theming/reshaped.config.js +0 -1
  6. package/dist/cjs/themes/_generator/definitions/slate.d.ts +2 -2
  7. package/dist/cjs/themes/_generator/tokens/color/color.transforms.js +7 -5
  8. package/dist/cjs/themes/_generator/tokens/color/color.types.d.ts +3 -2
  9. package/dist/cjs/themes/_generator/tokens/color/utilities/convert.d.ts +1 -1
  10. package/dist/cjs/themes/_generator/tokens/color/utilities/generateColors.d.ts +2 -2
  11. package/dist/cjs/themes/_generator/tokens/color/utilities/generateColors.js +1 -1
  12. package/dist/cjs/themes/_generator/tokens/color/utilities/generateMetaColors.d.ts +2 -2
  13. package/dist/cjs/themes/_generator/tokens/shadow/shadow.transforms.js +1 -1
  14. package/dist/cjs/themes/_generator/tokens/types.d.ts +7 -4
  15. package/dist/cjs/themes/_generator/transform.js +5 -2
  16. package/dist/cjs/themes/slate/theme.css +1 -1
  17. package/dist/cjs/types/config.d.ts +1 -0
  18. package/dist/cli/theming/reshaped.config.js +0 -1
  19. package/dist/components/Badge/Badge.module.css +1 -1
  20. package/dist/components/Button/Button.module.css +1 -1
  21. package/dist/components/Button/tests/Button.stories.js +39 -6
  22. package/dist/components/Calendar/Calendar.module.css +1 -1
  23. package/dist/components/Card/Card.module.css +1 -1
  24. package/dist/components/Checkbox/Checkbox.module.css +1 -1
  25. package/dist/components/FileUpload/FileUpload.module.css +1 -1
  26. package/dist/components/Link/Link.module.css +1 -1
  27. package/dist/components/MenuItem/MenuItem.module.css +1 -1
  28. package/dist/components/Modal/tests/Modal.test.stories.js +1 -1
  29. package/dist/components/NumberField/NumberField.module.css +1 -1
  30. package/dist/components/NumberField/NumberFieldControlled.js +3 -1
  31. package/dist/components/NumberField/tests/NumberField.stories.d.ts +1 -0
  32. package/dist/components/NumberField/tests/NumberField.stories.js +24 -6
  33. package/dist/components/Overlay/tests/Overlay.stories.js +3 -3
  34. package/dist/components/Overlay/tests/Overlay.test.stories.js +1 -1
  35. package/dist/components/Radio/Radio.module.css +1 -1
  36. package/dist/components/Resizable/Resizable.js +5 -27
  37. package/dist/components/Resizable/Resizable.module.css +1 -1
  38. package/dist/components/Resizable/Resizable.types.d.ts +5 -2
  39. package/dist/components/Resizable/ResizableHandle.d.ts +5 -0
  40. package/dist/components/Resizable/ResizableHandle.js +32 -0
  41. package/dist/components/Resizable/tests/Resizable.stories.d.ts +22 -1
  42. package/dist/components/Resizable/tests/Resizable.stories.js +154 -65
  43. package/dist/components/Select/Select.js +1 -1
  44. package/dist/components/Select/Select.module.css +1 -1
  45. package/dist/components/Tabs/Tabs.module.css +1 -1
  46. package/dist/components/ToggleButton/ToggleButton.d.ts +3 -0
  47. package/dist/components/ToggleButton/ToggleButton.js +11 -0
  48. package/dist/components/ToggleButton/ToggleButton.types.d.ts +20 -0
  49. package/dist/components/ToggleButton/ToggleButton.types.js +1 -0
  50. package/dist/components/ToggleButton/ToggleButtonControlled.d.ts +3 -0
  51. package/dist/components/ToggleButton/ToggleButtonControlled.js +22 -0
  52. package/dist/components/ToggleButton/ToggleButtonUncontrolled.d.ts +3 -0
  53. package/dist/components/ToggleButton/ToggleButtonUncontrolled.js +15 -0
  54. package/dist/components/ToggleButton/index.d.ts +2 -0
  55. package/dist/components/ToggleButton/index.js +1 -0
  56. package/dist/components/ToggleButton/tests/ToggleButton.stories.d.ts +23 -0
  57. package/dist/components/ToggleButton/tests/ToggleButton.stories.js +87 -0
  58. package/dist/components/ToggleButtonGroup/ToggleButtonGroup.context.d.ts +5 -0
  59. package/dist/components/ToggleButtonGroup/ToggleButtonGroup.context.js +5 -0
  60. package/dist/components/ToggleButtonGroup/ToggleButtonGroup.d.ts +3 -0
  61. package/dist/components/ToggleButtonGroup/ToggleButtonGroup.js +11 -0
  62. package/dist/components/ToggleButtonGroup/ToggleButtonGroup.types.d.ts +24 -0
  63. package/dist/components/ToggleButtonGroup/ToggleButtonGroup.types.js +1 -0
  64. package/dist/components/ToggleButtonGroup/ToggleButtonGroupControlled.d.ts +3 -0
  65. package/dist/components/ToggleButtonGroup/ToggleButtonGroupControlled.js +44 -0
  66. package/dist/components/ToggleButtonGroup/ToggleButtonGroupUncontrolled.d.ts +4 -0
  67. package/dist/components/ToggleButtonGroup/ToggleButtonGroupUncontrolled.js +18 -0
  68. package/dist/components/ToggleButtonGroup/index.d.ts +3 -0
  69. package/dist/components/ToggleButtonGroup/index.js +2 -0
  70. package/dist/components/ToggleButtonGroup/tests/ToggleButtonGroup.stories.d.ts +21 -0
  71. package/dist/components/ToggleButtonGroup/tests/ToggleButtonGroup.stories.js +115 -0
  72. package/dist/hooks/tests/useDrag.stories.js +1 -1
  73. package/dist/hooks/tests/useToggle.stories.js +1 -1
  74. package/dist/hooks/useToggle.d.ts +1 -1
  75. package/dist/hooks/useToggle.js +2 -2
  76. package/dist/index.d.ts +4 -0
  77. package/dist/index.js +2 -0
  78. package/dist/styles/bleed/bleed.module.css +1 -1
  79. package/dist/themes/_generator/definitions/slate.d.ts +2 -2
  80. package/dist/themes/_generator/tokens/color/color.transforms.js +7 -5
  81. package/dist/themes/_generator/tokens/color/color.types.d.ts +3 -2
  82. package/dist/themes/_generator/tokens/color/utilities/convert.d.ts +1 -1
  83. package/dist/themes/_generator/tokens/color/utilities/generateColors.d.ts +2 -2
  84. package/dist/themes/_generator/tokens/color/utilities/generateColors.js +1 -1
  85. package/dist/themes/_generator/tokens/color/utilities/generateMetaColors.d.ts +2 -2
  86. package/dist/themes/_generator/tokens/shadow/shadow.transforms.js +1 -1
  87. package/dist/themes/_generator/tokens/types.d.ts +7 -4
  88. package/dist/themes/_generator/transform.js +5 -2
  89. package/dist/themes/slate/theme.css +1 -1
  90. package/dist/types/config.d.ts +1 -0
  91. package/package.json +27 -27
  92. package/dist/components/Resizable/tests/Resizable.test.stories.d.ts +0 -18
  93. package/dist/components/Resizable/tests/Resizable.test.stories.js +0 -25
@@ -0,0 +1,3 @@
1
+ import type * as T from "./ToggleButton.types";
2
+ declare const ToggleButtonControlled: React.FC<T.ControlledProps>;
3
+ export default ToggleButtonControlled;
@@ -0,0 +1,22 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import Button from "../Button/index.js";
4
+ import { useToggleButtonGroup } from "../ToggleButtonGroup/index.js";
5
+ const ToggleButtonControlled = (props) => {
6
+ const { variant = "outline", value, onChange, onClick, ...buttonProps } = props;
7
+ const toggleButtonGroup = useToggleButtonGroup();
8
+ const checked = (value ? toggleButtonGroup?.value?.includes(value) : undefined) ?? props.checked;
9
+ const handleClick = (event) => {
10
+ const changeArgs = { checked: !checked, value: value ?? "", event };
11
+ onClick?.(event);
12
+ if (toggleButtonGroup) {
13
+ toggleButtonGroup?.onChange?.(changeArgs);
14
+ }
15
+ else {
16
+ onChange?.(changeArgs);
17
+ }
18
+ };
19
+ return _jsx(Button, { ...buttonProps, variant: variant, onClick: handleClick, highlighted: checked });
20
+ };
21
+ ToggleButtonControlled.displayName = "ToggleButtonControlled";
22
+ export default ToggleButtonControlled;
@@ -0,0 +1,3 @@
1
+ import type * as T from "./ToggleButton.types";
2
+ declare const ToggleButtonUncontrolled: React.FC<T.UncontrolledProps>;
3
+ export default ToggleButtonUncontrolled;
@@ -0,0 +1,15 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import useToggle from "../../hooks/useToggle.js";
4
+ import ToggleButtonControlled from "./ToggleButtonControlled.js";
5
+ const ToggleButtonUncontrolled = (props) => {
6
+ const { defaultChecked, onChange, ...buttonProps } = props;
7
+ const buttonToggle = useToggle(defaultChecked);
8
+ const handleChange = (args) => {
9
+ onChange?.(args);
10
+ buttonToggle.toggle(args.checked);
11
+ };
12
+ return (_jsx(ToggleButtonControlled, { ...buttonProps, onChange: handleChange, checked: buttonToggle.active }));
13
+ };
14
+ ToggleButtonUncontrolled.displayName = "ToggleButtonUncontrolled";
15
+ export default ToggleButtonUncontrolled;
@@ -0,0 +1,2 @@
1
+ export { default } from "./ToggleButton";
2
+ export type { Props as ToggleButtonProps } from "./ToggleButton.types";
@@ -0,0 +1 @@
1
+ export { default } from "./ToggleButton.js";
@@ -0,0 +1,23 @@
1
+ import { type StoryObj } from "@storybook/react-vite";
2
+ import { type Mock } from "storybook/test";
3
+ declare const _default: {
4
+ title: string;
5
+ component: import("react").FC<import("..").ToggleButtonProps>;
6
+ parameters: {
7
+ iframe: {
8
+ url: string;
9
+ };
10
+ };
11
+ };
12
+ export default _default;
13
+ export declare const variant: {
14
+ name: string;
15
+ render: () => import("react").JSX.Element;
16
+ };
17
+ export declare const onChange: StoryObj<{
18
+ handleUncontrolledChange: Mock;
19
+ handleControlledChange: Mock;
20
+ }>;
21
+ export declare const onClick: StoryObj<{
22
+ handleClick: Mock;
23
+ }>;
@@ -0,0 +1,87 @@
1
+ import { expect, fn, userEvent } from "storybook/test";
2
+ import { Example } from "../../../utilities/storybook/index.js";
3
+ import ToggleButton from "../ToggleButton.js";
4
+ export default {
5
+ title: "Components/ToggleButton",
6
+ component: ToggleButton,
7
+ parameters: {
8
+ iframe: {
9
+ url: "https://reshaped.so/docs/components/toggle-button",
10
+ },
11
+ },
12
+ };
13
+ export const variant = {
14
+ name: "variant",
15
+ render: () => (<Example>
16
+ <Example.Item title="outline">
17
+ <ToggleButton>Button</ToggleButton>
18
+ </Example.Item>
19
+ <Example.Item title="ghost">
20
+ <ToggleButton variant="ghost">Button</ToggleButton>
21
+ </Example.Item>
22
+ </Example>),
23
+ };
24
+ export const onChange = {
25
+ name: "checked, defaultChecked, onChange",
26
+ args: {
27
+ handleUncontrolledChange: fn(),
28
+ handleControlledChange: fn(),
29
+ },
30
+ render: (args) => (<Example>
31
+ <Example.Item title="defaultChecked, onChange">
32
+ <ToggleButton defaultChecked onChange={args.handleUncontrolledChange} value="1">
33
+ Button
34
+ </ToggleButton>
35
+ </Example.Item>
36
+ <Example.Item title="checked, onChange">
37
+ <ToggleButton checked onChange={args.handleControlledChange} value="2">
38
+ Button
39
+ </ToggleButton>
40
+ </Example.Item>
41
+ </Example>),
42
+ play: async ({ canvas, args }) => {
43
+ const [uncontrolledButton, controlledButton] = canvas.getAllByRole("button");
44
+ await userEvent.click(uncontrolledButton);
45
+ expect(args.handleUncontrolledChange).toHaveBeenCalledTimes(1);
46
+ expect(args.handleUncontrolledChange).toHaveBeenLastCalledWith({
47
+ checked: false,
48
+ value: "1",
49
+ event: expect.objectContaining({ target: uncontrolledButton }),
50
+ });
51
+ await userEvent.click(uncontrolledButton);
52
+ expect(args.handleUncontrolledChange).toHaveBeenCalledTimes(2);
53
+ expect(args.handleUncontrolledChange).toHaveBeenLastCalledWith({
54
+ checked: true,
55
+ value: "1",
56
+ event: expect.objectContaining({ target: uncontrolledButton }),
57
+ });
58
+ await userEvent.click(controlledButton);
59
+ expect(args.handleControlledChange).toHaveBeenCalledTimes(1);
60
+ expect(args.handleControlledChange).toHaveBeenLastCalledWith({
61
+ checked: false,
62
+ value: "2",
63
+ event: expect.objectContaining({ target: controlledButton }),
64
+ });
65
+ await userEvent.click(controlledButton);
66
+ // Stayed checked after the first click
67
+ expect(args.handleControlledChange).toHaveBeenCalledTimes(2);
68
+ expect(args.handleControlledChange).toHaveBeenLastCalledWith({
69
+ checked: false,
70
+ value: "2",
71
+ event: expect.objectContaining({ target: uncontrolledButton }),
72
+ });
73
+ },
74
+ };
75
+ export const onClick = {
76
+ name: "onClick",
77
+ args: {
78
+ handleClick: fn(),
79
+ },
80
+ render: (args) => <ToggleButton onClick={args.handleClick}>Button</ToggleButton>,
81
+ play: async ({ canvas, args }) => {
82
+ const [button] = canvas.getAllByRole("button");
83
+ await userEvent.click(button);
84
+ expect(args.handleClick).toHaveBeenCalledOnce();
85
+ expect(args.handleClick).toHaveBeenLastCalledWith(expect.objectContaining({ target: button }));
86
+ },
87
+ };
@@ -0,0 +1,5 @@
1
+ import React from "react";
2
+ import type * as T from "./ToggleButtonGroup.types";
3
+ declare const ToggleButtonGroupContext: React.Context<T.Context | null>;
4
+ export declare const useToggleButtonGroup: () => T.Context | null;
5
+ export default ToggleButtonGroupContext;
@@ -0,0 +1,5 @@
1
+ "use client";
2
+ import React from "react";
3
+ const ToggleButtonGroupContext = React.createContext(null);
4
+ export const useToggleButtonGroup = () => React.useContext(ToggleButtonGroupContext);
5
+ export default ToggleButtonGroupContext;
@@ -0,0 +1,3 @@
1
+ import type * as T from "./ToggleButtonGroup.types";
2
+ declare const ToggleButtonGroup: React.FC<T.Props>;
3
+ export default ToggleButtonGroup;
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import ToggleButtonGroupControlled from "./ToggleButtonGroupControlled.js";
3
+ import ToggleButtonGroupUncontrolled from "./ToggleButtonGroupUncontrolled.js";
4
+ const ToggleButtonGroup = (props) => {
5
+ const { value } = props;
6
+ if (value !== undefined)
7
+ return _jsx(ToggleButtonGroupControlled, { ...props });
8
+ return _jsx(ToggleButtonGroupUncontrolled, { ...props });
9
+ };
10
+ ToggleButtonGroup.displayName = "ToggleButtonGroup";
11
+ export default ToggleButtonGroup;
@@ -0,0 +1,24 @@
1
+ import type React from "react";
2
+ import type { ToggleButtonProps } from "../ToggleButton";
3
+ type BaseProps = {
4
+ children?: React.ReactNode;
5
+ selectionMode?: "single" | "multiple";
6
+ onChange?: (args: {
7
+ value: string[];
8
+ event: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>;
9
+ }) => void;
10
+ };
11
+ export type ControlledProps = BaseProps & {
12
+ value: string[];
13
+ defaultValue?: never;
14
+ };
15
+ export type UncontrolledProps = BaseProps & {
16
+ value?: never;
17
+ defaultValue?: string[];
18
+ };
19
+ export type Props = ControlledProps | UncontrolledProps;
20
+ export type Context = {
21
+ onChange: ToggleButtonProps["onChange"];
22
+ value?: string[];
23
+ };
24
+ export {};
@@ -0,0 +1,3 @@
1
+ import type * as T from "./ToggleButtonGroup.types";
2
+ declare const ToggleButtonGroupControlled: React.FC<T.ControlledProps>;
3
+ export default ToggleButtonGroupControlled;
@@ -0,0 +1,44 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import Button from "../Button/index.js";
4
+ import useHotkeys from "../../hooks/useHotkeys.js";
5
+ import Context from "./ToggleButtonGroup.context.js";
6
+ import { focusFirstElement, focusLastElement, focusNextElement, focusPreviousElement, } from "../../utilities/a11y/index.js";
7
+ const ToggleButtonGroupControlled = (props) => {
8
+ const { onChange, value, children, selectionMode = "single" } = props;
9
+ const handleChange = (args) => {
10
+ const { event, value: itemValue, checked } = args;
11
+ if (!itemValue)
12
+ return;
13
+ let nextValue = selectionMode === "single" ? [itemValue] : [...value];
14
+ if (selectionMode === "multiple") {
15
+ if (checked) {
16
+ nextValue.push(itemValue);
17
+ }
18
+ else {
19
+ nextValue = nextValue.filter((v) => v !== itemValue);
20
+ }
21
+ }
22
+ if (onChange)
23
+ onChange({ value: nextValue, event });
24
+ };
25
+ const { ref: hotkeysRef } = useHotkeys({
26
+ "ArrowLeft, ArrowUp": () => {
27
+ focusPreviousElement(hotkeysRef.current);
28
+ },
29
+ "ArrowRight, ArrowDown": () => {
30
+ focusNextElement(hotkeysRef.current);
31
+ },
32
+ Home: () => {
33
+ focusFirstElement(hotkeysRef.current);
34
+ },
35
+ End: () => {
36
+ focusLastElement(hotkeysRef.current);
37
+ },
38
+ }, [], {
39
+ preventDefault: true,
40
+ });
41
+ return (_jsx(Context.Provider, { value: { onChange: handleChange, value }, children: _jsx(Button.Group, { attributes: { ref: hotkeysRef }, children: children }) }));
42
+ };
43
+ ToggleButtonGroupControlled.displayName = "ToggleButtonGroupControlled";
44
+ export default ToggleButtonGroupControlled;
@@ -0,0 +1,4 @@
1
+ import React from "react";
2
+ import type * as T from "./ToggleButtonGroup.types";
3
+ declare const ToggleButtonGroupUncontrolled: React.FC<T.UncontrolledProps>;
4
+ export default ToggleButtonGroupUncontrolled;
@@ -0,0 +1,18 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import React from "react";
4
+ import ToggleButtonGroupControlled from "./ToggleButtonGroupControlled.js";
5
+ const ToggleButtonGroupUncontrolled = (props) => {
6
+ const { defaultValue, onChange } = props;
7
+ const [value, setValue] = React.useState(defaultValue || []);
8
+ const handleChange = (args) => {
9
+ if (!args.value)
10
+ return;
11
+ setValue(args.value);
12
+ if (onChange)
13
+ onChange(args);
14
+ };
15
+ return (_jsx(ToggleButtonGroupControlled, { ...props, value: value, defaultValue: undefined, onChange: handleChange }));
16
+ };
17
+ ToggleButtonGroupUncontrolled.displayName = "ToggleButtonGroupUncontrolled";
18
+ export default ToggleButtonGroupUncontrolled;
@@ -0,0 +1,3 @@
1
+ export { default } from "./ToggleButtonGroup";
2
+ export type { Props as ToggleButtonGroupProps } from "./ToggleButtonGroup.types";
3
+ export { useToggleButtonGroup } from "./ToggleButtonGroup.context";
@@ -0,0 +1,2 @@
1
+ export { default } from "./ToggleButtonGroup.js";
2
+ export { useToggleButtonGroup } from "./ToggleButtonGroup.context.js";
@@ -0,0 +1,21 @@
1
+ import { StoryObj } from "@storybook/react-vite";
2
+ import { Mock } from "storybook/test";
3
+ declare const _default: {
4
+ title: string;
5
+ component: import("react").FC<import("./..").ToggleButtonGroupProps>;
6
+ parameters: {
7
+ iframe: {
8
+ url: string;
9
+ };
10
+ };
11
+ };
12
+ export default _default;
13
+ export declare const single: StoryObj<{
14
+ handleUncontrolledChange: Mock;
15
+ handleControlledChange: Mock;
16
+ handleItemChange: Mock;
17
+ }>;
18
+ export declare const multiple: StoryObj<{
19
+ handleUncontrolledChange: Mock;
20
+ handleControlledChange: Mock;
21
+ }>;
@@ -0,0 +1,115 @@
1
+ import { expect, fn, userEvent } from "storybook/test";
2
+ import { Example } from "../../../utilities/storybook/index.js";
3
+ import ToggleButtonGroup from "../index.js";
4
+ import ToggleButton from "../../ToggleButton/index.js";
5
+ export default {
6
+ title: "Components/ToggleButtonGroup",
7
+ component: ToggleButtonGroup,
8
+ parameters: {
9
+ iframe: {
10
+ url: "https://reshaped.so/docs/components/toggle-button-group",
11
+ },
12
+ },
13
+ };
14
+ export const single = {
15
+ name: "checked, defaultChecked, onChange",
16
+ args: {
17
+ handleUncontrolledChange: fn(),
18
+ handleControlledChange: fn(),
19
+ handleItemChange: fn(),
20
+ },
21
+ render: (args) => (<Example>
22
+ <Example.Item title="single, uncontrolled, onChange">
23
+ <ToggleButtonGroup onChange={args.handleUncontrolledChange}>
24
+ <ToggleButton value="1" onChange={args.handleItemChange}>
25
+ Button
26
+ </ToggleButton>
27
+ <ToggleButton value="2">Button</ToggleButton>
28
+ </ToggleButtonGroup>
29
+ </Example.Item>
30
+ <Example.Item title="single, controlled, onChange">
31
+ <ToggleButtonGroup onChange={args.handleControlledChange} value={[]}>
32
+ <ToggleButton value="3" onChange={args.handleItemChange}>
33
+ Button
34
+ </ToggleButton>
35
+ <ToggleButton value="4">Button</ToggleButton>
36
+ </ToggleButtonGroup>
37
+ </Example.Item>
38
+ </Example>),
39
+ play: async ({ canvas, args }) => {
40
+ const [uncontrolledButton1, uncontrolledButton2, controlledButton1, controlledButton2] = canvas.getAllByRole("button");
41
+ await userEvent.click(uncontrolledButton1);
42
+ expect(args.handleUncontrolledChange).toHaveBeenCalledTimes(1);
43
+ expect(args.handleUncontrolledChange).toHaveBeenLastCalledWith({
44
+ value: ["1"],
45
+ event: expect.objectContaining({ target: uncontrolledButton1 }),
46
+ });
47
+ await userEvent.click(uncontrolledButton2);
48
+ expect(args.handleUncontrolledChange).toHaveBeenCalledTimes(2);
49
+ expect(args.handleUncontrolledChange).toHaveBeenLastCalledWith({
50
+ value: ["2"],
51
+ event: expect.objectContaining({ target: uncontrolledButton2 }),
52
+ });
53
+ await userEvent.click(controlledButton1);
54
+ expect(args.handleControlledChange).toHaveBeenCalledTimes(1);
55
+ expect(args.handleControlledChange).toHaveBeenLastCalledWith({
56
+ value: ["3"],
57
+ event: expect.objectContaining({ target: controlledButton1 }),
58
+ });
59
+ await userEvent.click(controlledButton2);
60
+ expect(args.handleControlledChange).toHaveBeenCalledTimes(2);
61
+ expect(args.handleControlledChange).toHaveBeenLastCalledWith({
62
+ value: ["4"],
63
+ event: expect.objectContaining({ target: controlledButton2 }),
64
+ });
65
+ expect(args.handleItemChange).not.toHaveBeenCalled();
66
+ },
67
+ };
68
+ export const multiple = {
69
+ name: "selectionMode, checked, defaultChecked, onChange",
70
+ args: {
71
+ handleUncontrolledChange: fn(),
72
+ handleControlledChange: fn(),
73
+ },
74
+ render: (args) => (<Example>
75
+ <Example.Item title="multiple, uncontrolled, onChange">
76
+ <ToggleButtonGroup onChange={args.handleUncontrolledChange} selectionMode="multiple">
77
+ <ToggleButton value="1">Button</ToggleButton>
78
+ <ToggleButton value="2">Button</ToggleButton>
79
+ </ToggleButtonGroup>
80
+ </Example.Item>
81
+ <Example.Item title="multiple, controlled, onChange">
82
+ <ToggleButtonGroup onChange={args.handleControlledChange} value={[]} selectionMode="multiple">
83
+ <ToggleButton value="3">Button</ToggleButton>
84
+ <ToggleButton value="4">Button</ToggleButton>
85
+ </ToggleButtonGroup>
86
+ </Example.Item>
87
+ </Example>),
88
+ play: async ({ canvas, args }) => {
89
+ const [uncontrolledButton1, uncontrolledButton2, controlledButton1, controlledButton2] = canvas.getAllByRole("button");
90
+ await userEvent.click(uncontrolledButton1);
91
+ expect(args.handleUncontrolledChange).toHaveBeenCalledTimes(1);
92
+ expect(args.handleUncontrolledChange).toHaveBeenLastCalledWith({
93
+ value: ["1"],
94
+ event: expect.objectContaining({ target: uncontrolledButton1 }),
95
+ });
96
+ await userEvent.click(uncontrolledButton2);
97
+ expect(args.handleUncontrolledChange).toHaveBeenCalledTimes(2);
98
+ expect(args.handleUncontrolledChange).toHaveBeenLastCalledWith({
99
+ value: ["1", "2"],
100
+ event: expect.objectContaining({ target: uncontrolledButton2 }),
101
+ });
102
+ await userEvent.click(controlledButton1);
103
+ expect(args.handleControlledChange).toHaveBeenCalledTimes(1);
104
+ expect(args.handleControlledChange).toHaveBeenLastCalledWith({
105
+ value: ["3"],
106
+ event: expect.objectContaining({ target: controlledButton1 }),
107
+ });
108
+ await userEvent.click(controlledButton2);
109
+ expect(args.handleControlledChange).toHaveBeenCalledTimes(2);
110
+ expect(args.handleControlledChange).toHaveBeenLastCalledWith({
111
+ value: ["4"],
112
+ event: expect.objectContaining({ target: controlledButton2 }),
113
+ });
114
+ },
115
+ };
@@ -28,7 +28,7 @@ function Example() {
28
28
  style: { translate: `${state.x}px ${state.y}px`, cursor: active ? "grabbing" : "grab" },
29
29
  }}/>
30
30
  </View>
31
- <Button onClick={disabledToggle.toggle}>
31
+ <Button onClick={() => disabledToggle.toggle()}>
32
32
  {disabledToggle.active ? "Enable" : "Disable"}
33
33
  </Button>
34
34
  </View>);
@@ -12,7 +12,7 @@ export const toggle = {
12
12
  name: "toggle",
13
13
  render: () => {
14
14
  const { toggle, active } = useToggle();
15
- return (<Button onClick={toggle} attributes={{ "data-active": active }}>
15
+ return (<Button onClick={() => toggle()} attributes={{ "data-active": active }}>
16
16
  {active ? "Deactivate" : "Activate"}
17
17
  </Button>);
18
18
  },
@@ -2,6 +2,6 @@ declare const useToggle: (defaultValue?: boolean) => {
2
2
  active: boolean;
3
3
  activate: () => void;
4
4
  deactivate: () => void;
5
- toggle: () => void;
5
+ toggle: (targetValue?: boolean) => void;
6
6
  };
7
7
  export default useToggle;
@@ -8,8 +8,8 @@ const useToggle = (defaultValue) => {
8
8
  const deactivate = React.useCallback(() => {
9
9
  setActive(false);
10
10
  }, []);
11
- const toggle = React.useCallback(() => {
12
- setActive((active) => !active);
11
+ const toggle = React.useCallback((targetValue) => {
12
+ setActive(targetValue ?? ((active) => !active));
13
13
  }, []);
14
14
  return React.useMemo(() => ({ active, activate, deactivate, toggle }), [activate, deactivate, toggle, active]);
15
15
  };
package/dist/index.d.ts CHANGED
@@ -83,6 +83,10 @@ export { default as Timeline } from "./components/Timeline";
83
83
  export type { TimelineProps, TimelineItemProps } from "./components/Timeline";
84
84
  export { useToast, ToastProvider } from "./components/Toast";
85
85
  export type { ToastProps, ToastProviderProps, ToastShowProps } from "./components/Toast";
86
+ export { default as ToggleButton } from "./components/ToggleButton";
87
+ export type { ToggleButtonProps } from "./components/ToggleButton";
88
+ export { default as ToggleButtonGroup } from "./components/ToggleButtonGroup";
89
+ export type { ToggleButtonGroupProps } from "./components/ToggleButtonGroup";
86
90
  export { default as Tooltip } from "./components/Tooltip";
87
91
  export type { TooltipProps } from "./components/Tooltip";
88
92
  /**
package/dist/index.js CHANGED
@@ -42,6 +42,8 @@ export { default as TextArea } from "./components/TextArea/index.js";
42
42
  export { default as TextField } from "./components/TextField/index.js";
43
43
  export { default as Timeline } from "./components/Timeline/index.js";
44
44
  export { useToast, ToastProvider } from "./components/Toast/index.js";
45
+ export { default as ToggleButton } from "./components/ToggleButton/index.js";
46
+ export { default as ToggleButtonGroup } from "./components/ToggleButtonGroup/index.js";
45
47
  export { default as Tooltip } from "./components/Tooltip/index.js";
46
48
  /**
47
49
  * Utility components
@@ -1 +1 @@
1
- .root[style*="--rs-bleed-"]{margin-left:calc(var(--rs-unit-x1) * var(--rs-bleed) * -1);margin-right:calc(var(--rs-unit-x1) * var(--rs-bleed) * -1);--rs-bleed-s:0;--rs-bleed-m:var(--rs-bleed-s);--rs-bleed-l:var(--rs-bleed-m);--rs-bleed-xl:var(--rs-bleed-l);--rs-bleed:var(--rs-bleed-s)}.--bleed{border-left-style:none!important;border-radius:0;border-right-style:none!important}@media (--rs-viewport-m ){.root[style*="--rs-bleed-"]{--rs-bleed:var(--rs-bleed-m)}.--bleed-true--m{border-left-style:none!important;border-radius:0;border-right-style:none!important}.--bleed-false--m{border-left-style:solid!important;border-radius:var(--rs-radius);border-right-style:solid!important}}@media (--rs-viewport-l ){.root[style*="--rs-bleed-"]{--rs-bleed:var(--rs-bleed-l)}.--bleed-true--l{border-left-style:none!important;border-radius:0;border-right-style:none!important}.--bleed-false--l{border-left-style:solid!important;border-radius:var(--rs-radius);border-right-style:solid!important}}@media (--rs-viewport-xl ){.root[style*="--rs-bleed-"]{--rs-bleed:var(--rs-bleed-xl)}.--bleed-true--xl{border-left-style:none!important;border-radius:0;border-right-style:none!important}.--bleed-false--xl{border-left-style:solid!important;border-radius:var(--rs-radius);border-right-style:solid!important}}
1
+ .root[style*="--rs-bleed-"]{margin-left:calc(var(--rs-unit-x1) * var(--rs-bleed) * -1);margin-right:calc(var(--rs-unit-x1) * var(--rs-bleed) * -1);--rs-bleed-s:0;--rs-bleed-m:var(--rs-bleed-s);--rs-bleed-l:var(--rs-bleed-m);--rs-bleed-xl:var(--rs-bleed-l);--rs-bleed:var(--rs-bleed-s)}.--bleed{border-left-style:none!important;border-radius:0!important;border-right-style:none!important}@media (--rs-viewport-m ){.root[style*="--rs-bleed-"]{--rs-bleed:var(--rs-bleed-m)}.--bleed-true--m{border-left-style:none!important;border-radius:0!important;border-right-style:none!important}.--bleed-false--m{border-left-style:solid!important;border-radius:var(--rs-radius)!important;border-right-style:solid!important}}@media (--rs-viewport-l ){.root[style*="--rs-bleed-"]{--rs-bleed:var(--rs-bleed-l)}.--bleed-true--l{border-left-style:none!important;border-radius:0!important;border-right-style:none!important}.--bleed-false--l{border-left-style:solid!important;border-radius:var(--rs-radius)!important;border-right-style:solid!important}}@media (--rs-viewport-xl ){.root[style*="--rs-bleed-"]{--rs-bleed:var(--rs-bleed-xl)}.--bleed-true--xl{border-left-style:none!important;border-radius:0!important;border-right-style:none!important}.--bleed-false--xl{border-left-style:solid!important;border-radius:var(--rs-radius)!important;border-right-style:solid!important}}
@@ -1,3 +1,3 @@
1
- import type { ThemeDefinition } from "../tokens/types";
2
- declare const theme: ThemeDefinition;
1
+ import type { PassedThemeDefinition } from "../tokens/types";
2
+ declare const theme: PassedThemeDefinition;
3
3
  export default theme;
@@ -1,6 +1,6 @@
1
- const transformTokenForMode = (args) => {
1
+ const transformTokenForMode = (args, themeOptions) => {
2
2
  const { hex, oklch } = args;
3
- if (oklch) {
3
+ if (oklch && themeOptions?.colorOutputFormat !== "hex") {
4
4
  const components = `${Number(oklch.l.toFixed(4))} ${Number(oklch.c.toFixed(4))} ${Number(oklch.h?.toFixed(4) || 0)}`;
5
5
  const alphaSuffix = oklch?.alpha === undefined ? "" : ` / ${Number(oklch.alpha.toFixed(4))}`;
6
6
  return `oklch(${components}${alphaSuffix})`;
@@ -9,12 +9,14 @@ const transformTokenForMode = (args) => {
9
9
  return hex;
10
10
  throw new Error(`[Reshaped] ${JSON.stringify(args)} is missing a color value`);
11
11
  };
12
- const transformToken = (name, token) => {
12
+ const transformToken = (name, token, { themeOptions }) => {
13
13
  const { hex, hexDark, oklch, oklchDark } = token;
14
14
  // Apply color to both modes if dark mode is not available
15
15
  const hasDark = !!hexDark || !!oklchDark;
16
- const value = transformTokenForMode({ oklch, hex });
17
- const darkValue = hasDark ? transformTokenForMode({ oklch: oklchDark, hex: hexDark }) : undefined;
16
+ const value = transformTokenForMode({ oklch, hex }, themeOptions);
17
+ const darkValue = hasDark
18
+ ? transformTokenForMode({ oklch: oklchDark, hex: hexDark }, themeOptions)
19
+ : undefined;
18
20
  const separateModes = hasDark && value !== darkValue;
19
21
  const defaultMode = separateModes ? "light" : undefined;
20
22
  const result = [
@@ -10,7 +10,7 @@ export type RgbColor = {
10
10
  };
11
11
  export type OklchColor = Omit<Oklch, "mode">;
12
12
  export type HexColor = string;
13
- export type ColorValue = HexColor | Token;
13
+ export type ColorValue = HexColor | PassedToken;
14
14
  export type OklchOnlyToken = {
15
15
  oklch: OklchColor;
16
16
  oklchDark?: OklchColor;
@@ -25,8 +25,9 @@ export type HexToken = {
25
25
  oklch?: never;
26
26
  oklchDark?: never;
27
27
  };
28
- export type Token = OklchToken | HexToken;
28
+ export type PassedToken = HexToken | OklchToken;
29
29
  export type InternalToken = {
30
30
  oklch: Oklch;
31
31
  oklchDark?: Oklch;
32
32
  };
33
+ export type Token = Pick<HexToken, "hex" | "hexDark"> & Partial<OklchOnlyToken>;
@@ -8,4 +8,4 @@ export declare const oklchToRgb: (oklch: Oklch) => {
8
8
  mode: "rgb";
9
9
  alpha?: number;
10
10
  };
11
- export declare const tokenToOklchToken: (token: TColor.Token) => TColor.InternalToken;
11
+ export declare const tokenToOklchToken: (token: TColor.PassedToken) => TColor.InternalToken;
@@ -1,4 +1,4 @@
1
- import type { ThemeDefinition } from "../../types";
1
+ import type { PassedThemeDefinition } from "../../types";
2
2
  import { type ColorValue, Hue } from "../color.types";
3
- declare const generateColors: (args?: Partial<Record<Hue, ColorValue>>) => ThemeDefinition["color"];
3
+ declare const generateColors: (args?: Partial<Record<Hue, ColorValue>>) => NonNullable<PassedThemeDefinition["color"]>;
4
4
  export default generateColors;
@@ -135,7 +135,7 @@ const getOklchToken = (color) => {
135
135
  return tokenToOklchToken(token);
136
136
  };
137
137
  const generateColors = (args = {}) => {
138
- const { primary = { oklch: { l: 0.55, c: 0.24, h: 262.67 } }, critical = { oklch: { l: 0.59, c: 0.22, h: 26.97 } }, warning = { oklch: { l: 0.86, c: 0.18, h: 89.84 } }, positive = { oklch: { l: 0.53, c: 0.13, h: 153.78 } }, neutral = { oklch: { l: 0.92, c: 0.01, h: 262.67 } }, brand, } = args;
138
+ const { primary = { oklch: { l: 0.55, c: 0.24, h: 262.67 } }, critical = { oklch: { l: 0.59, c: 0.22, h: 26.97 } }, warning = { oklch: { l: 0.83, c: 0.2, h: 80 } }, positive = { oklch: { l: 0.53, c: 0.13, h: 153.78 } }, neutral = { oklch: { l: 0.92, c: 0.01, h: 262.67 } }, brand, } = args;
139
139
  return {
140
140
  ...generateColorValues("primary", getOklchToken(primary)),
141
141
  ...generateColorValues("critical", getOklchToken(critical)),
@@ -1,4 +1,4 @@
1
1
  import type * as T from "../../../types";
2
- import { GeneratedThemeDefinition, PassedThemeDefinition } from "../../types";
3
- declare const generateMetaColors: (definition: PassedThemeDefinition, themeOptions?: T.PublicOptions["themeOptions"]) => GeneratedThemeDefinition["color"] | undefined;
2
+ import { PassedThemeDefinition } from "../../types";
3
+ declare const generateMetaColors: (definition: PassedThemeDefinition, themeOptions?: T.PublicOptions["themeOptions"]) => PassedThemeDefinition["color"] | undefined;
4
4
  export default generateMetaColors;
@@ -1,5 +1,5 @@
1
1
  import { hexToOklch, oklchToRgb } from "../color/utilities/convert.js";
2
- const transformToken = (name, token, theme) => [
2
+ const transformToken = (name, token, { theme }) => [
3
3
  {
4
4
  name,
5
5
  tokenType: "shadow",