reshaped 3.6.0-canary.7 → 3.6.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 +14 -1
- package/dist/bundle.css +1 -1
- package/dist/bundle.d.ts +5 -1
- package/dist/bundle.js +11 -11
- package/dist/cjs/cli/theming/reshaped.config.js +0 -1
- package/dist/cjs/themes/_generator/definitions/slate.d.ts +2 -2
- package/dist/cjs/themes/_generator/tokens/color/color.transforms.js +7 -5
- package/dist/cjs/themes/_generator/tokens/color/color.types.d.ts +3 -2
- package/dist/cjs/themes/_generator/tokens/color/utilities/convert.d.ts +1 -1
- package/dist/cjs/themes/_generator/tokens/color/utilities/generateColors.d.ts +2 -2
- package/dist/cjs/themes/_generator/tokens/color/utilities/generateColors.js +1 -1
- package/dist/cjs/themes/_generator/tokens/color/utilities/generateMetaColors.d.ts +2 -2
- package/dist/cjs/themes/_generator/tokens/shadow/shadow.transforms.js +1 -1
- package/dist/cjs/themes/_generator/tokens/types.d.ts +7 -4
- package/dist/cjs/themes/_generator/transform.js +4 -1
- package/dist/cjs/themes/slate/theme.css +1 -1
- package/dist/cjs/types/config.d.ts +1 -0
- package/dist/cli/theming/reshaped.config.js +0 -1
- package/dist/components/Badge/Badge.module.css +1 -1
- package/dist/components/Button/Button.module.css +1 -1
- package/dist/components/Button/index.d.ts +1 -1
- package/dist/components/Button/tests/Button.stories.js +39 -6
- package/dist/components/Calendar/Calendar.module.css +1 -1
- package/dist/components/Card/Card.module.css +1 -1
- package/dist/components/Checkbox/Checkbox.module.css +1 -1
- package/dist/components/FileUpload/FileUpload.module.css +1 -1
- package/dist/components/Flyout/FlyoutControlled.js +1 -1
- package/dist/components/Link/Link.module.css +1 -1
- package/dist/components/MenuItem/MenuItem.module.css +1 -1
- package/dist/components/Modal/tests/Modal.test.stories.js +1 -1
- package/dist/components/NumberField/NumberField.module.css +1 -1
- package/dist/components/NumberField/NumberFieldControlled.js +3 -1
- package/dist/components/NumberField/tests/NumberField.stories.d.ts +1 -0
- package/dist/components/NumberField/tests/NumberField.stories.js +24 -6
- package/dist/components/Overlay/tests/Overlay.stories.js +3 -3
- package/dist/components/Overlay/tests/Overlay.test.stories.js +1 -1
- package/dist/components/Radio/Radio.module.css +1 -1
- package/dist/components/Resizable/Resizable.js +5 -27
- package/dist/components/Resizable/Resizable.module.css +1 -1
- package/dist/components/Resizable/Resizable.types.d.ts +5 -2
- package/dist/components/Resizable/ResizableHandle.d.ts +5 -0
- package/dist/components/Resizable/ResizableHandle.js +32 -0
- package/dist/components/Resizable/tests/Resizable.stories.d.ts +22 -1
- package/dist/components/Resizable/tests/Resizable.stories.js +154 -65
- package/dist/components/Select/Select.js +1 -1
- package/dist/components/Select/Select.module.css +1 -1
- package/dist/components/Slider/tests/Slider.stories.js +0 -6
- package/dist/components/Tabs/Tabs.module.css +1 -1
- package/dist/components/Tabs/TabsPanel.d.ts +1 -0
- package/dist/components/Tabs/TabsPanel.js +22 -1
- package/dist/components/Tabs/tests/Tabs.stories.js +24 -1
- package/dist/components/TextField/TextField.module.css +1 -1
- package/dist/components/ToggleButton/ToggleButton.d.ts +3 -0
- package/dist/components/ToggleButton/ToggleButton.js +11 -0
- package/dist/components/ToggleButton/ToggleButton.types.d.ts +20 -0
- package/dist/components/ToggleButton/ToggleButton.types.js +1 -0
- package/dist/components/ToggleButton/ToggleButtonControlled.d.ts +3 -0
- package/dist/components/ToggleButton/ToggleButtonControlled.js +22 -0
- package/dist/components/ToggleButton/ToggleButtonUncontrolled.d.ts +3 -0
- package/dist/components/ToggleButton/ToggleButtonUncontrolled.js +15 -0
- package/dist/components/ToggleButton/index.d.ts +2 -0
- package/dist/components/ToggleButton/index.js +1 -0
- package/dist/components/ToggleButton/tests/ToggleButton.stories.d.ts +23 -0
- package/dist/components/ToggleButton/tests/ToggleButton.stories.js +87 -0
- package/dist/components/ToggleButtonGroup/ToggleButtonGroup.context.d.ts +5 -0
- package/dist/components/ToggleButtonGroup/ToggleButtonGroup.context.js +5 -0
- package/dist/components/ToggleButtonGroup/ToggleButtonGroup.d.ts +3 -0
- package/dist/components/ToggleButtonGroup/ToggleButtonGroup.js +11 -0
- package/dist/components/ToggleButtonGroup/ToggleButtonGroup.types.d.ts +24 -0
- package/dist/components/ToggleButtonGroup/ToggleButtonGroup.types.js +1 -0
- package/dist/components/ToggleButtonGroup/ToggleButtonGroupControlled.d.ts +4 -0
- package/dist/components/ToggleButtonGroup/ToggleButtonGroupControlled.js +67 -0
- package/dist/components/ToggleButtonGroup/ToggleButtonGroupUncontrolled.d.ts +4 -0
- package/dist/components/ToggleButtonGroup/ToggleButtonGroupUncontrolled.js +18 -0
- package/dist/components/ToggleButtonGroup/index.d.ts +3 -0
- package/dist/components/ToggleButtonGroup/index.js +2 -0
- package/dist/components/ToggleButtonGroup/tests/ToggleButtonGroup.stories.d.ts +22 -0
- package/dist/components/ToggleButtonGroup/tests/ToggleButtonGroup.stories.js +129 -0
- package/dist/hooks/tests/useDrag.stories.js +1 -1
- package/dist/hooks/tests/useToggle.stories.js +1 -1
- package/dist/hooks/useToggle.d.ts +1 -1
- package/dist/hooks/useToggle.js +2 -2
- package/dist/index.d.ts +5 -1
- package/dist/index.js +2 -0
- package/dist/styles/bleed/bleed.module.css +1 -1
- package/dist/themes/_generator/definitions/slate.d.ts +2 -2
- package/dist/themes/_generator/tokens/color/color.transforms.js +7 -5
- package/dist/themes/_generator/tokens/color/color.types.d.ts +3 -2
- package/dist/themes/_generator/tokens/color/utilities/convert.d.ts +1 -1
- package/dist/themes/_generator/tokens/color/utilities/generateColors.d.ts +2 -2
- package/dist/themes/_generator/tokens/color/utilities/generateColors.js +1 -1
- package/dist/themes/_generator/tokens/color/utilities/generateMetaColors.d.ts +2 -2
- package/dist/themes/_generator/tokens/shadow/shadow.transforms.js +1 -1
- package/dist/themes/_generator/tokens/types.d.ts +7 -4
- package/dist/themes/_generator/transform.js +4 -1
- package/dist/themes/slate/theme.css +1 -1
- package/dist/types/config.d.ts +1 -0
- package/dist/utilities/a11y/index.d.ts +1 -1
- package/dist/utilities/a11y/index.js +1 -1
- package/package.json +27 -27
- package/dist/components/Resizable/tests/Resizable.test.stories.d.ts +0 -18
- package/dist/components/Resizable/tests/Resizable.test.stories.js +0 -25
@@ -1,14 +1,35 @@
|
|
1
1
|
"use client";
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
3
|
+
import React from "react";
|
3
4
|
import { classNames } from "../../utilities/props.js";
|
5
|
+
import { getFocusableElements } from "../../utilities/a11y/index.js";
|
4
6
|
import { useTabs } from "./TabsContext.js";
|
5
7
|
import s from "./Tabs.module.css";
|
6
8
|
const TabsPanel = (props) => {
|
7
9
|
const { value: panelValue, children, className, attributes } = props;
|
8
10
|
const { value, panelId, buttonId } = useTabs(panelValue);
|
11
|
+
const [needsTabIndex, setNeedsTabIndex] = React.useState(true);
|
12
|
+
const rootRef = React.useRef(null);
|
9
13
|
const active = panelValue === value;
|
10
14
|
const panelClassNames = classNames(s.panel, !active && s["--panel-hidden"], className);
|
11
|
-
|
15
|
+
React.useEffect(() => {
|
16
|
+
const el = rootRef.current;
|
17
|
+
if (!el)
|
18
|
+
return;
|
19
|
+
const updateTabIndex = () => {
|
20
|
+
setNeedsTabIndex(!getFocusableElements(el).length);
|
21
|
+
};
|
22
|
+
updateTabIndex();
|
23
|
+
const observer = new MutationObserver(updateTabIndex);
|
24
|
+
observer.observe(el, {
|
25
|
+
childList: true,
|
26
|
+
subtree: true,
|
27
|
+
attributes: true,
|
28
|
+
attributeFilter: ["tabindex", "disabled", "href"],
|
29
|
+
});
|
30
|
+
return () => observer.disconnect();
|
31
|
+
}, []);
|
32
|
+
return (_jsx("div", { ...attributes, ref: rootRef, className: panelClassNames, tabIndex: needsTabIndex ? 0 : undefined, role: "tabpanel", id: panelId, "aria-labelledby": buttonId, children: active && children }));
|
12
33
|
};
|
13
34
|
TabsPanel.displayName = "Tabs.Panel";
|
14
35
|
export default TabsPanel;
|
@@ -5,6 +5,7 @@ import View from "../../View/index.js";
|
|
5
5
|
import Text from "../../Text/index.js";
|
6
6
|
import ScrollArea from "../../ScrollArea/index.js";
|
7
7
|
import IconZap from "../../../icons/Zap.js";
|
8
|
+
import Button from "../../Button/index.js";
|
8
9
|
export default {
|
9
10
|
title: "Components/Tabs",
|
10
11
|
component: Tabs,
|
@@ -127,7 +128,7 @@ export const direction = () => (<Example>
|
|
127
128
|
</Example.Item>
|
128
129
|
</Example>);
|
129
130
|
export const composition = () => (<Example>
|
130
|
-
<Example.Item title="
|
131
|
+
<Example.Item title="panels without focusable content">
|
131
132
|
<Tabs>
|
132
133
|
<View gap={4}>
|
133
134
|
<Tabs.List>
|
@@ -142,6 +143,28 @@ export const composition = () => (<Example>
|
|
142
143
|
</View>
|
143
144
|
</Tabs>
|
144
145
|
</Example.Item>
|
146
|
+
|
147
|
+
<Example.Item title="panels with focusable content">
|
148
|
+
<Tabs>
|
149
|
+
<View gap={4}>
|
150
|
+
<Tabs.List>
|
151
|
+
<Tabs.Item value="0">Item 1</Tabs.Item>
|
152
|
+
<Tabs.Item value="1">Long item 2</Tabs.Item>
|
153
|
+
<Tabs.Item value="2">Very long item 3</Tabs.Item>
|
154
|
+
</Tabs.List>
|
155
|
+
|
156
|
+
<Tabs.Panel value="0">
|
157
|
+
<Button onClick={() => { }}>Tab 1 action</Button>
|
158
|
+
</Tabs.Panel>
|
159
|
+
<Tabs.Panel value="1">
|
160
|
+
<Button onClick={() => { }}>Tab 2 action</Button>
|
161
|
+
</Tabs.Panel>
|
162
|
+
<Tabs.Panel value="2">
|
163
|
+
<Button onClick={() => { }}>Tab 3 action</Button>
|
164
|
+
</Tabs.Panel>
|
165
|
+
</View>
|
166
|
+
</Tabs>
|
167
|
+
</Example.Item>
|
145
168
|
</Example>);
|
146
169
|
export const icon = () => (<Example>
|
147
170
|
<Example.Item title="icon">
|
@@ -1 +1 @@
|
|
1
|
-
.root{--rs-p-h:var(--rs-text-field-gap);align-items:center;background:var(--rs-color-background-elevation-base);border:1px solid var(--rs-color-border-neutral);border-radius:var(--rs-text-field-radius);column-gap:var(--rs-text-field-gap);display:flex;padding:0 calc(var(--rs-text-field-gap) - 1px);position:relative;z-index:0}.root.--focused,.root:has(label:active),.root:not(:has(button:focus,a:focus,[tabindex="0"]:focus,[role=button]:focus)):focus-within{border-color:var(--rs-color-border-primary);box-shadow:0 0 0 1px var(--rs-color-border-primary)}.root.--multiline{flex-wrap:wrap}.root.--multiline .input{width:auto}.root.--rounded{border-radius:999px}.root.--rounded .affix:first-child,.root.--rounded .icon:first-child{padding-inline-start:var(--rs-unit-x1)}.root.--rounded .input:first-child{padding-inline-start:calc(var(--rs-text-field-gap) + var(--rs-unit-x1))}.inner{column-gap:var(--rs-text-field-gap);display:inline-flex;flex-grow:1}.input{background:none;border:none;box-sizing:border-box;color:var(--rs-color-foreground-neutral);flex-grow:1;font-family:var(--rs-font-family-body);font-weight:var(--rs-font-weight-regular);margin:0 calc(var(--rs-text-field-gap) * -1);outline:none;padding-block:calc(var(--rs-text-field-p-v) - 1px);padding-inline:var(--rs-text-field-gap);position:relative;width:100%;z-index:1}.input:-webkit-autofill{-webkit-background-clip:text;-webkit-text-fill-color:var(--rs-color-foreground-neutral)}.affix,.input{font-size:var(--rs-text-field-font-size);letter-spacing:var(--rs-text-field-letter-spacing);line-height:var(--rs-text-field-line-height)}.affix,.icon{cursor:text}.affix,.icon,.slot{align-items:center;display:flex;flex-shrink:0;max-width:100%;min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x4) - 2px);position:relative;z-index:5}.input+.affix--position-end,.input+.icon--position-end,.input+.slot--position-end{margin-inline-start:auto}.slot--position-end:last-child{margin-inline-end:calc(var(--rs-text-field-gap) * -1);padding-inline-end:var(--rs-text-field-action-inset)}.affix{color:var(--rs-color-foreground-neutral-faded)}.affix.affix--position-start{padding-inline-end:var(--rs-text-field-gap)}.affix.affix--position-start:after{border-inline-end:1px solid var(--rs-color-border-neutral-faded);content:"";inset-block:var(--rs-unit-x1);inset-inline-end:0;position:absolute}.affix.affix--position-end{padding-inline-start:var(--rs-text-field-gap)}.affix.affix--position-end:after{border-inline-start:1px solid var(--rs-color-border-neutral-faded);content:"";inset-block:var(--rs-unit-x1);inset-inline-start:0;position:absolute}.root.--disabled{background:var(--rs-color-background-disabled-faded);border-color:var(--rs-color-border-disabled)}.root.--disabled,.root.--disabled .input{color:var(--rs-color-foreground-disabled);cursor:not-allowed}.--size-small{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-small);--rs-text-field-p-v:var(--rs-unit-x1);--rs-text-field-font-size:var(--rs-font-size-body-3);--rs-text-field-line-height:var(--rs-line-height-body-3);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-3);--rs-text-field-action-inset:var(--rs-unit-x1)}.--size-medium{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-small);--rs-text-field-p-v:var(--rs-unit-x2);--rs-text-field-font-size:var(--rs-font-size-body-3);--rs-text-field-line-height:var(--rs-line-height-body-3);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-3);--rs-text-field-action-inset:var(--rs-unit-x1)}.--size-large{--rs-text-field-gap:var(--rs-unit-x3);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x3);--rs-text-field-font-size:var(--rs-font-size-body-2);--rs-text-field-line-height:var(--rs-line-height-body-2);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-2);--rs-text-field-action-inset:var(--rs-unit-x2)}.--size-xlarge{--rs-text-field-gap:var(--rs-unit-x4);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x4);--rs-text-field-font-size:var(--rs-font-size-body-2);--rs-text-field-line-height:var(--rs-line-height-body-2);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-2);--rs-text-field-action-inset:var(--rs-unit-x1)}.root.--variant-faded{background:var(--rs-color-background-neutral-faded);border-color:transparent}.root.--variant-faded.--focused,.root.--variant-faded:has(label:active),.root.--variant-faded:not(:has(button:focus,a:focus,[tabindex="0"]:focus,[role=button]:focus)):focus-within{border-color:var(--rs-color-border-primary)}.root.--variant-headless{background:transparent;border-color:transparent}.root.--variant-headless.--status-error,.root.--variant-headless.--status-error.--focused,.root.--variant-headless.--status-error:focus-within,.root.--variant-headless:focus-within{border-color:transparent;box-shadow:none}.root.--status-error{border-color:var(--rs-color-border-critical)}.root.--status-error.--focused,.root.--status-error:focus-within{border-color:var(--rs-color-border-primary)}@media (--rs-viewport-s ) and (hover:none){.input{font-size:var(--rs-font-size-body-2)!important}}@media (--rs-viewport-m ){.--size-small--m{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-small);--rs-text-field-p-v:var(--rs-unit-x1);--rs-text-field-font-size:var(--rs-font-size-body-3);--rs-text-field-line-height:var(--rs-line-height-body-3);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-3);--rs-text-field-action-inset:var(--rs-unit-x1)}.--size-medium--m{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-small);--rs-text-field-p-v:var(--rs-unit-x2);--rs-text-field-font-size:var(--rs-font-size-body-3);--rs-text-field-line-height:var(--rs-line-height-body-3);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-3);--rs-text-field-action-inset:var(--rs-unit-x1)}.--size-large--m{--rs-text-field-gap:var(--rs-unit-x3);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x3);--rs-text-field-font-size:var(--rs-font-size-body-2);--rs-text-field-line-height:var(--rs-line-height-body-2);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-2);--rs-text-field-action-inset:var(--rs-unit-x2)}.--size-xlarge--m{--rs-text-field-gap:var(--rs-unit-x4);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x4);--rs-text-field-font-size:var(--rs-font-size-body-2);--rs-text-field-line-height:var(--rs-line-height-body-2);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-2);--rs-text-field-action-inset:var(--rs-unit-x1)}}@media (--rs-viewport-l ){.--size-small--l{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-small);--rs-text-field-p-v:var(--rs-unit-x1);--rs-text-field-font-size:var(--rs-font-size-body-3);--rs-text-field-line-height:var(--rs-line-height-body-3);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-3);--rs-text-field-action-inset:var(--rs-unit-x1)}.--size-medium--l{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-small);--rs-text-field-p-v:var(--rs-unit-x2);--rs-text-field-font-size:var(--rs-font-size-body-3);--rs-text-field-line-height:var(--rs-line-height-body-3);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-3);--rs-text-field-action-inset:var(--rs-unit-x1)}.--size-large--l{--rs-text-field-gap:var(--rs-unit-x3);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x3);--rs-text-field-font-size:var(--rs-font-size-body-2);--rs-text-field-line-height:var(--rs-line-height-body-2);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-2);--rs-text-field-action-inset:var(--rs-unit-x2)}.--size-xlarge--l{--rs-text-field-gap:var(--rs-unit-x4);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x4);--rs-text-field-font-size:var(--rs-font-size-body-2);--rs-text-field-line-height:var(--rs-line-height-body-2);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-2);--rs-text-field-action-inset:var(--rs-unit-x1)}}@media (--rs-viewport-xl ){.--size-small--xl{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-small);--rs-text-field-p-v:var(--rs-unit-x1);--rs-text-field-font-size:var(--rs-font-size-body-3);--rs-text-field-line-height:var(--rs-line-height-body-3);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-3);--rs-text-field-action-inset:var(--rs-unit-x1)}.--size-medium--xl{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-small);--rs-text-field-p-v:var(--rs-unit-x2);--rs-text-field-font-size:var(--rs-font-size-body-3);--rs-text-field-line-height:var(--rs-line-height-body-3);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-3);--rs-text-field-action-inset:var(--rs-unit-x1)}.--size-large--xl{--rs-text-field-gap:var(--rs-unit-x3);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x3);--rs-text-field-font-size:var(--rs-font-size-body-2);--rs-text-field-line-height:var(--rs-line-height-body-2);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-2);--rs-text-field-action-inset:var(--rs-unit-x2)}.--size-xlarge--xl{--rs-text-field-gap:var(--rs-unit-x4);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x4);--rs-text-field-font-size:var(--rs-font-size-body-2);--rs-text-field-line-height:var(--rs-line-height-body-2);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-2);--rs-text-field-action-inset:var(--rs-unit-x1)}}
|
1
|
+
.root{--rs-p-h:var(--rs-text-field-gap);align-items:center;background:var(--rs-color-background-elevation-base);border:1px solid var(--rs-color-border-neutral);border-radius:var(--rs-text-field-radius);column-gap:var(--rs-text-field-gap);display:flex;padding:0 calc(var(--rs-text-field-gap) - 1px);position:relative;z-index:0}.root.--focused,.root:has(label:active),.root:not(:has(button:focus,a:focus,[tabindex="0"]:focus,[role=button]:focus)):focus-within{border-color:var(--rs-color-border-primary);box-shadow:0 0 0 1px var(--rs-color-border-primary)}.root.--multiline{flex-wrap:wrap}.root.--multiline .input{width:auto}.root.--rounded{border-radius:999px}.root.--rounded .affix:first-child,.root.--rounded .icon:first-child{padding-inline-start:var(--rs-unit-x1)}.root.--rounded .input:first-child{padding-inline-start:calc(var(--rs-text-field-gap) + var(--rs-unit-x1))}.inner{column-gap:var(--rs-text-field-gap);display:inline-flex;flex-grow:1}.input{background:none;border:none;box-sizing:border-box;color:var(--rs-color-foreground-neutral);flex-grow:1;font-family:var(--rs-font-family-body);font-weight:var(--rs-font-weight-regular);margin:0 calc(var(--rs-text-field-gap) * -1);outline:none;padding-block:calc(var(--rs-text-field-p-v) - 1px);padding-inline:var(--rs-text-field-gap);position:relative;width:100%;z-index:1}.input:-webkit-autofill{-webkit-background-clip:text;-webkit-text-fill-color:var(--rs-color-foreground-neutral)}.affix,.input{font-size:var(--rs-text-field-font-size);letter-spacing:var(--rs-text-field-letter-spacing);line-height:var(--rs-text-field-line-height)}.affix,.icon{cursor:text}.affix,.icon,.slot{align-items:center;display:flex;flex-shrink:0;max-width:100%;min-height:var(--rs-text-field-attachment-height);position:relative;z-index:5}.input+.affix--position-end,.input+.icon--position-end,.input+.slot--position-end{margin-inline-start:auto}.slot--position-end:last-child{margin-inline-end:calc(var(--rs-text-field-gap) * -1);padding-inline-end:var(--rs-text-field-action-inset)}.affix{color:var(--rs-color-foreground-neutral-faded)}.affix.affix--position-start{padding-inline-end:var(--rs-text-field-gap)}.affix.affix--position-start:after{border-inline-end:1px solid var(--rs-color-border-neutral-faded);content:"";inset-block:var(--rs-unit-x1);inset-inline-end:0;position:absolute}.affix.affix--position-end{padding-inline-start:var(--rs-text-field-gap)}.affix.affix--position-end:after{border-inline-start:1px solid var(--rs-color-border-neutral-faded);content:"";inset-block:var(--rs-unit-x1);inset-inline-start:0;position:absolute}.root.--disabled{background:var(--rs-color-background-disabled-faded);border-color:var(--rs-color-border-disabled)}.root.--disabled,.root.--disabled .input{color:var(--rs-color-foreground-disabled);cursor:not-allowed}.--size-small{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-small);--rs-text-field-p-v:var(--rs-unit-x1);--rs-text-field-font-size:var(--rs-font-size-body-3);--rs-text-field-line-height:var(--rs-line-height-body-3);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-3);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-attachment-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x2) - 2px)}.--size-medium{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-small);--rs-text-field-p-v:var(--rs-unit-x2);--rs-text-field-font-size:var(--rs-font-size-body-3);--rs-text-field-line-height:var(--rs-line-height-body-3);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-3);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-attachment-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x4) - 2px)}.--size-large{--rs-text-field-gap:var(--rs-unit-x3);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x3);--rs-text-field-font-size:var(--rs-font-size-body-2);--rs-text-field-line-height:var(--rs-line-height-body-2);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-2);--rs-text-field-action-inset:var(--rs-unit-x2);--rs-text-field-attachment-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x4) - 2px)}.--size-xlarge{--rs-text-field-gap:var(--rs-unit-x4);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x4);--rs-text-field-font-size:var(--rs-font-size-body-2);--rs-text-field-line-height:var(--rs-line-height-body-2);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-2);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-attachment-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x4) - 2px)}.root.--variant-faded{background:var(--rs-color-background-neutral-faded);border-color:transparent}.root.--variant-faded.--focused,.root.--variant-faded:has(label:active),.root.--variant-faded:not(:has(button:focus,a:focus,[tabindex="0"]:focus,[role=button]:focus)):focus-within{border-color:var(--rs-color-border-primary)}.root.--variant-headless{background:transparent;border-color:transparent}.root.--variant-headless.--status-error,.root.--variant-headless.--status-error.--focused,.root.--variant-headless.--status-error:focus-within,.root.--variant-headless:focus-within{border-color:transparent;box-shadow:none}.root.--status-error{border-color:var(--rs-color-border-critical)}.root.--status-error.--focused,.root.--status-error:focus-within{border-color:var(--rs-color-border-primary)}@media (--rs-viewport-s ) and (hover:none){.input{font-size:var(--rs-font-size-body-2)!important}}@media (--rs-viewport-m ){.--size-small--m{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-small);--rs-text-field-p-v:var(--rs-unit-x1);--rs-text-field-font-size:var(--rs-font-size-body-3);--rs-text-field-line-height:var(--rs-line-height-body-3);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-3);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-attachment-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x2) - 2px)}.--size-medium--m{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-small);--rs-text-field-p-v:var(--rs-unit-x2);--rs-text-field-font-size:var(--rs-font-size-body-3);--rs-text-field-line-height:var(--rs-line-height-body-3);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-3);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-attachment-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x4) - 2px)}.--size-large--m{--rs-text-field-gap:var(--rs-unit-x3);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x3);--rs-text-field-font-size:var(--rs-font-size-body-2);--rs-text-field-line-height:var(--rs-line-height-body-2);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-2);--rs-text-field-action-inset:var(--rs-unit-x2);--rs-text-field-attachment-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x4) - 2px)}.--size-xlarge--m{--rs-text-field-gap:var(--rs-unit-x4);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x4);--rs-text-field-font-size:var(--rs-font-size-body-2);--rs-text-field-line-height:var(--rs-line-height-body-2);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-2);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-attachment-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x4) - 2px)}}@media (--rs-viewport-l ){.--size-small--l{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-small);--rs-text-field-p-v:var(--rs-unit-x1);--rs-text-field-font-size:var(--rs-font-size-body-3);--rs-text-field-line-height:var(--rs-line-height-body-3);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-3);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-attachment-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x2) - 2px)}.--size-medium--l{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-small);--rs-text-field-p-v:var(--rs-unit-x2);--rs-text-field-font-size:var(--rs-font-size-body-3);--rs-text-field-line-height:var(--rs-line-height-body-3);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-3);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-attachment-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x4) - 2px)}.--size-large--l{--rs-text-field-gap:var(--rs-unit-x3);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x3);--rs-text-field-font-size:var(--rs-font-size-body-2);--rs-text-field-line-height:var(--rs-line-height-body-2);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-2);--rs-text-field-action-inset:var(--rs-unit-x2);--rs-text-field-attachment-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x4) - 2px)}.--size-xlarge--l{--rs-text-field-gap:var(--rs-unit-x4);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x4);--rs-text-field-font-size:var(--rs-font-size-body-2);--rs-text-field-line-height:var(--rs-line-height-body-2);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-2);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-attachment-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x4) - 2px)}}@media (--rs-viewport-xl ){.--size-small--xl{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-small);--rs-text-field-p-v:var(--rs-unit-x1);--rs-text-field-font-size:var(--rs-font-size-body-3);--rs-text-field-line-height:var(--rs-line-height-body-3);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-3);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-attachment-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x2) - 2px)}.--size-medium--xl{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-small);--rs-text-field-p-v:var(--rs-unit-x2);--rs-text-field-font-size:var(--rs-font-size-body-3);--rs-text-field-line-height:var(--rs-line-height-body-3);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-3);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-attachment-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x4) - 2px)}.--size-large--xl{--rs-text-field-gap:var(--rs-unit-x3);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x3);--rs-text-field-font-size:var(--rs-font-size-body-2);--rs-text-field-line-height:var(--rs-line-height-body-2);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-2);--rs-text-field-action-inset:var(--rs-unit-x2);--rs-text-field-attachment-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x4) - 2px)}.--size-xlarge--xl{--rs-text-field-gap:var(--rs-unit-x4);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x4);--rs-text-field-font-size:var(--rs-font-size-body-2);--rs-text-field-line-height:var(--rs-line-height-body-2);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-2);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-attachment-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x4) - 2px)}}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
2
|
+
import ToggleButtonControlled from "./ToggleButtonControlled.js";
|
3
|
+
import ToggleButtonUncontrolled from "./ToggleButtonUncontrolled.js";
|
4
|
+
const ToggleButton = (props) => {
|
5
|
+
const { checked } = props;
|
6
|
+
if (checked !== undefined)
|
7
|
+
return _jsx(ToggleButtonControlled, { ...props });
|
8
|
+
return _jsx(ToggleButtonUncontrolled, { ...props });
|
9
|
+
};
|
10
|
+
ToggleButton.displayName = "ToggleButton";
|
11
|
+
export default ToggleButton;
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import type { ButtonProps } from "../Button";
|
2
|
+
type BaseProps = Omit<ButtonProps, "variant" | "higlighted"> & {
|
3
|
+
variant?: Extract<ButtonProps["variant"], "outline" | "ghost">;
|
4
|
+
value?: string;
|
5
|
+
onChange?: (args: {
|
6
|
+
checked: boolean;
|
7
|
+
value: string;
|
8
|
+
event: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>;
|
9
|
+
}) => void;
|
10
|
+
};
|
11
|
+
export type ControlledProps = BaseProps & {
|
12
|
+
defaultChecked?: never;
|
13
|
+
checked: boolean;
|
14
|
+
};
|
15
|
+
export type UncontrolledProps = BaseProps & {
|
16
|
+
defaultChecked?: boolean;
|
17
|
+
checked?: never;
|
18
|
+
};
|
19
|
+
export type Props = ControlledProps | UncontrolledProps;
|
20
|
+
export {};
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -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, attributes: { ...buttonProps.attributes, "aria-pressed": checked } }));
|
20
|
+
};
|
21
|
+
ToggleButtonControlled.displayName = "ToggleButtonControlled";
|
22
|
+
export default ToggleButtonControlled;
|
@@ -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 @@
|
|
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,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 { ButtonGroupProps } from "../Button";
|
3
|
+
import type { ToggleButtonProps } from "../ToggleButton";
|
4
|
+
type BaseProps = {
|
5
|
+
selectionMode?: "single" | "multiple";
|
6
|
+
onChange?: (args: {
|
7
|
+
value: string[];
|
8
|
+
event: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>;
|
9
|
+
}) => void;
|
10
|
+
} & ButtonGroupProps;
|
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 @@
|
|
1
|
+
export {};
|
@@ -0,0 +1,67 @@
|
|
1
|
+
"use client";
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
3
|
+
import React from "react";
|
4
|
+
import Button from "../Button/index.js";
|
5
|
+
import useHotkeys from "../../hooks/useHotkeys.js";
|
6
|
+
import Context from "./ToggleButtonGroup.context.js";
|
7
|
+
import { focusFirstElement, focusLastElement, focusNextElement, focusPreviousElement, } from "../../utilities/a11y/index.js";
|
8
|
+
import ToggleButton from "../ToggleButton/index.js";
|
9
|
+
const ToggleButtonGroupItem = (props) => {
|
10
|
+
const { focusable, onFocus, ...buttonProps } = props;
|
11
|
+
return (_jsx(ToggleButton, { ...buttonProps, attributes: {
|
12
|
+
...buttonProps.attributes,
|
13
|
+
tabIndex: focusable ? 0 : -1,
|
14
|
+
onFocus,
|
15
|
+
} }));
|
16
|
+
};
|
17
|
+
const ToggleButtonGroupControlled = (props) => {
|
18
|
+
const { onChange, value, selectionMode = "single", children, ...buttonGroupProps } = props;
|
19
|
+
const focusableIndexRef = React.useRef(0);
|
20
|
+
let toggleButtonIndex = 0;
|
21
|
+
const renderedChildren = React.Children.map(children, (child) => {
|
22
|
+
if (!React.isValidElement(child) || child.type !== ToggleButton || !child.props) {
|
23
|
+
return child;
|
24
|
+
}
|
25
|
+
const boundIndex = toggleButtonIndex;
|
26
|
+
toggleButtonIndex += 1;
|
27
|
+
const focusable = focusableIndexRef.current === boundIndex;
|
28
|
+
return (_jsx(ToggleButtonGroupItem, { ...child.props, focusable: focusable, onFocus: () => {
|
29
|
+
focusableIndexRef.current = boundIndex;
|
30
|
+
} }));
|
31
|
+
});
|
32
|
+
const handleChange = (args) => {
|
33
|
+
const { event, value: itemValue, checked } = args;
|
34
|
+
if (!itemValue)
|
35
|
+
return;
|
36
|
+
let nextValue = selectionMode === "single" ? [itemValue] : [...value];
|
37
|
+
if (selectionMode === "multiple") {
|
38
|
+
if (checked) {
|
39
|
+
nextValue.push(itemValue);
|
40
|
+
}
|
41
|
+
else {
|
42
|
+
nextValue = nextValue.filter((v) => v !== itemValue);
|
43
|
+
}
|
44
|
+
}
|
45
|
+
if (onChange)
|
46
|
+
onChange({ value: nextValue, event });
|
47
|
+
};
|
48
|
+
const { ref: hotkeysRef } = useHotkeys({
|
49
|
+
"ArrowLeft, ArrowUp": () => {
|
50
|
+
focusPreviousElement(hotkeysRef.current);
|
51
|
+
},
|
52
|
+
"ArrowRight, ArrowDown": () => {
|
53
|
+
focusNextElement(hotkeysRef.current);
|
54
|
+
},
|
55
|
+
Home: () => {
|
56
|
+
focusFirstElement(hotkeysRef.current);
|
57
|
+
},
|
58
|
+
End: () => {
|
59
|
+
focusLastElement(hotkeysRef.current);
|
60
|
+
},
|
61
|
+
}, [], {
|
62
|
+
preventDefault: true,
|
63
|
+
});
|
64
|
+
return (_jsx(Context.Provider, { value: { onChange: handleChange, value }, children: _jsx(Button.Group, { ...buttonGroupProps, attributes: { ref: hotkeysRef, ...buttonGroupProps?.attributes }, children: renderedChildren }) }));
|
65
|
+
};
|
66
|
+
ToggleButtonGroupControlled.displayName = "ToggleButtonGroupControlled";
|
67
|
+
export default ToggleButtonGroupControlled;
|
@@ -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,22 @@
|
|
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
|
+
}>;
|
22
|
+
export declare const className: StoryObj;
|