@autoguru/overdrive 4.48.0 → 4.49.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/dist/components/Tabs/Tabs.d.ts +44 -0
- package/dist/components/Tabs/Tabs.d.ts.map +1 -1
- package/dist/components/Tabs/Tabs.js +41 -0
- package/dist/components/ToggleButtons/ToggleButtons.css.d.ts +18 -0
- package/dist/components/ToggleButtons/ToggleButtons.css.d.ts.map +1 -0
- package/dist/components/ToggleButtons/ToggleButtons.css.js +138 -0
- package/dist/components/ToggleButtons/ToggleButtons.d.ts +113 -0
- package/dist/components/ToggleButtons/ToggleButtons.d.ts.map +1 -0
- package/dist/components/ToggleButtons/ToggleButtons.js +199 -0
- package/dist/components/ToggleButtons/index.d.ts +2 -0
- package/dist/components/ToggleButtons/index.d.ts.map +1 -0
- package/dist/components/ToggleButtons/index.js +3 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useContainerWidth/index.d.ts +2 -0
- package/dist/hooks/useContainerWidth/index.d.ts.map +1 -0
- package/dist/hooks/useContainerWidth/index.js +3 -0
- package/dist/hooks/useContainerWidth/useContainerWidth.d.ts +27 -0
- package/dist/hooks/useContainerWidth/useContainerWidth.d.ts.map +1 -0
- package/dist/hooks/useContainerWidth/useContainerWidth.js +68 -0
- package/package.json +23 -23
|
@@ -10,11 +10,55 @@ interface TabsContextValue {
|
|
|
10
10
|
getTabCount: () => number;
|
|
11
11
|
}
|
|
12
12
|
export declare const TabsContext: React.Context<TabsContextValue | null>;
|
|
13
|
+
/**
|
|
14
|
+
* ## Tabs
|
|
15
|
+
*
|
|
16
|
+
* A tabbed interface component that manages tab navigation and content panels. The tabs system consists of several coordinated components:
|
|
17
|
+
*
|
|
18
|
+
* ### Component Structure
|
|
19
|
+
*
|
|
20
|
+
* - **Tabs** - Root container that provides context and state management
|
|
21
|
+
* - **TabList** - Container for tab navigation elements with keyboard navigation and scrolling support
|
|
22
|
+
* - **Tab** - Individual clickable tab with support for indications and custom rendering
|
|
23
|
+
* - **TabPanes** - Container for tab content panels with optional inactive rendering
|
|
24
|
+
* - **TabPane** - Individual content panel associated with each tab
|
|
25
|
+
*
|
|
26
|
+
* ### Component Props Overview
|
|
27
|
+
*
|
|
28
|
+
* #### TabList Props
|
|
29
|
+
* - `stretch?: boolean` - Whether tabs should stretch to fill available width
|
|
30
|
+
* - `scrollable?: boolean` - Enable horizontal scrolling with navigation buttons (cannot be used with stretch)
|
|
31
|
+
*
|
|
32
|
+
* #### Tab Props
|
|
33
|
+
* - `id?: string` - Custom ID for the tab element (auto-generated if not provided)
|
|
34
|
+
* - `as?: ElementType | ReactElement` - Custom component or element to render the tab as
|
|
35
|
+
* - `indication?: number` - Optional numeric badge displayed on the tab
|
|
36
|
+
*
|
|
37
|
+
* #### TabPanes Props
|
|
38
|
+
* - `renderInactivePanes?: boolean` - Whether to render inactive tab panels in the DOM (hidden but present)
|
|
39
|
+
* - `paddingTop?: string` - Top padding for the panes container (default: '6')
|
|
40
|
+
* - `paddingBottom?: string` - Bottom padding for the panes container (default: '6')
|
|
41
|
+
*
|
|
42
|
+
* #### TabPane Props
|
|
43
|
+
* - `id?: string` - Custom ID for the tab panel element (auto-generated if not provided)
|
|
44
|
+
*
|
|
45
|
+
* ### Visual Variants
|
|
46
|
+
*
|
|
47
|
+
* The `appearance` prop supports different visual styles:
|
|
48
|
+
* - `"underlined"` (default) - Tabs with bottom border indication
|
|
49
|
+
* - `"pill"`
|
|
50
|
+
* - `"minimal"`
|
|
51
|
+
*/
|
|
13
52
|
export interface TabsProps {
|
|
53
|
+
/** Custom ID for the tabs container. Auto-generated if not provided. */
|
|
14
54
|
id?: string | null;
|
|
55
|
+
/** Index of the currently active tab (0-based) */
|
|
15
56
|
active: number;
|
|
57
|
+
/** Visual appearance style for the tabs */
|
|
16
58
|
appearance?: TabAppearance;
|
|
59
|
+
/** Tab navigation and content elements (typically TabList and TabPanes) */
|
|
17
60
|
children?: ReactNode;
|
|
61
|
+
/** Callback fired when the active tab changes */
|
|
18
62
|
onChange?: (index: number) => void;
|
|
19
63
|
}
|
|
20
64
|
export declare const Tabs: FunctionComponent<TabsProps>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../../lib/components/Tabs/Tabs.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAEb,KAAK,iBAAiB,EACtB,KAAK,SAAS,EAId,MAAM,OAAO,CAAC;AAIf,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,UAAU,gBAAgB;IACzB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,aAAa,CAAC;IAC1B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC;IAC7D,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,WAAW,GAAG,SAAS,CAAC;IACnD,WAAW,EAAE,MAAM,MAAM,CAAC;CAC1B;AAED,eAAO,MAAM,WAAW,wCAA+C,CAAC;AAExE,MAAM,WAAW,SAAS;IACzB,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,eAAO,MAAM,IAAI,EAAE,iBAAiB,CAAC,SAAS,CAuD7C,CAAC"}
|
|
1
|
+
{"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../../lib/components/Tabs/Tabs.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAEb,KAAK,iBAAiB,EACtB,KAAK,SAAS,EAId,MAAM,OAAO,CAAC;AAIf,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,UAAU,gBAAgB;IACzB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,aAAa,CAAC;IAC1B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC;IAC7D,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,WAAW,GAAG,SAAS,CAAC;IACnD,WAAW,EAAE,MAAM,MAAM,CAAC;CAC1B;AAED,eAAO,MAAM,WAAW,wCAA+C,CAAC;AAExE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,MAAM,WAAW,SAAS;IACzB,wEAAwE;IACxE,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,eAAO,MAAM,IAAI,EAAE,iBAAiB,CAAC,SAAS,CAuD7C,CAAC"}
|
|
@@ -4,6 +4,47 @@ import React, { createContext, useCallback, useMemo, useRef } from 'react';
|
|
|
4
4
|
import { useId, useUncontrolledState } from "../../utils/index.js";
|
|
5
5
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
6
|
export const TabsContext = /*#__PURE__*/createContext(null);
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* ## Tabs
|
|
10
|
+
*
|
|
11
|
+
* A tabbed interface component that manages tab navigation and content panels. The tabs system consists of several coordinated components:
|
|
12
|
+
*
|
|
13
|
+
* ### Component Structure
|
|
14
|
+
*
|
|
15
|
+
* - **Tabs** - Root container that provides context and state management
|
|
16
|
+
* - **TabList** - Container for tab navigation elements with keyboard navigation and scrolling support
|
|
17
|
+
* - **Tab** - Individual clickable tab with support for indications and custom rendering
|
|
18
|
+
* - **TabPanes** - Container for tab content panels with optional inactive rendering
|
|
19
|
+
* - **TabPane** - Individual content panel associated with each tab
|
|
20
|
+
*
|
|
21
|
+
* ### Component Props Overview
|
|
22
|
+
*
|
|
23
|
+
* #### TabList Props
|
|
24
|
+
* - `stretch?: boolean` - Whether tabs should stretch to fill available width
|
|
25
|
+
* - `scrollable?: boolean` - Enable horizontal scrolling with navigation buttons (cannot be used with stretch)
|
|
26
|
+
*
|
|
27
|
+
* #### Tab Props
|
|
28
|
+
* - `id?: string` - Custom ID for the tab element (auto-generated if not provided)
|
|
29
|
+
* - `as?: ElementType | ReactElement` - Custom component or element to render the tab as
|
|
30
|
+
* - `indication?: number` - Optional numeric badge displayed on the tab
|
|
31
|
+
*
|
|
32
|
+
* #### TabPanes Props
|
|
33
|
+
* - `renderInactivePanes?: boolean` - Whether to render inactive tab panels in the DOM (hidden but present)
|
|
34
|
+
* - `paddingTop?: string` - Top padding for the panes container (default: '6')
|
|
35
|
+
* - `paddingBottom?: string` - Bottom padding for the panes container (default: '6')
|
|
36
|
+
*
|
|
37
|
+
* #### TabPane Props
|
|
38
|
+
* - `id?: string` - Custom ID for the tab panel element (auto-generated if not provided)
|
|
39
|
+
*
|
|
40
|
+
* ### Visual Variants
|
|
41
|
+
*
|
|
42
|
+
* The `appearance` prop supports different visual styles:
|
|
43
|
+
* - `"underlined"` (default) - Tabs with bottom border indication
|
|
44
|
+
* - `"pill"`
|
|
45
|
+
* - `"minimal"`
|
|
46
|
+
*/
|
|
47
|
+
|
|
7
48
|
export const Tabs = ({
|
|
8
49
|
id: incomingId,
|
|
9
50
|
active = 0,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { cssLayerComponent } from '../../styles/layers.css';
|
|
2
|
+
export declare const toggleButtonsContainer: string;
|
|
3
|
+
export declare const toggleButtonsContainerStyle: string;
|
|
4
|
+
export declare const toggleButtonGroup: import("@vanilla-extract/recipes").RuntimeFn<{
|
|
5
|
+
iconOnly: {
|
|
6
|
+
true: {
|
|
7
|
+
'@layer': {
|
|
8
|
+
[cssLayerComponent]: {
|
|
9
|
+
color: `var(--${string})`;
|
|
10
|
+
display: "block";
|
|
11
|
+
lineHeight: number;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
}>;
|
|
17
|
+
export declare const toggleButton: string;
|
|
18
|
+
//# sourceMappingURL=ToggleButtons.css.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToggleButtons.css.d.ts","sourceRoot":"","sources":["../../../lib/components/ToggleButtons/ToggleButtons.css.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAS5D,eAAO,MAAM,sBAAsB,QAAoB,CAAC;AACxD,eAAO,MAAM,2BAA2B,QAOtC,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;;gBAuBzB,CAAC,iBAAiB,CAAC;;;;kBAIlB;;;;EAQJ,CAAC;AAIH,eAAO,MAAM,YAAY,QA0FvB,CAAC"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import * as __vanilla_filescope__ from '@vanilla-extract/css/fileScope';
|
|
4
|
+
__vanilla_filescope__.setFileScope("lib/components/ToggleButtons/ToggleButtons.css.ts", "@autoguru/overdrive");
|
|
5
|
+
import { createContainer, style } from '@vanilla-extract/css';
|
|
6
|
+
import { recipe } from '@vanilla-extract/recipes';
|
|
7
|
+
import { elementReset } from "../../styles/elementReset.css.js";
|
|
8
|
+
import { focusOutlineStyle } from "../../styles/focusOutline.css.js";
|
|
9
|
+
import { cssLayerComponent } from "../../styles/layers.css.js";
|
|
10
|
+
import { selectors } from "../../styles/selectors.js";
|
|
11
|
+
import { sprinkles } from "../../styles/sprinkles.css.js";
|
|
12
|
+
import { overdriveTokens as vars } from "../../themes/theme.css.js";
|
|
13
|
+
import { WIDTH_COMPACT_ORIENTATION } from "./ToggleButtons.js";
|
|
14
|
+
const TOGGLE_BUTTON_HEIGHT = '40px';
|
|
15
|
+
export const toggleButtonsContainer = createContainer("toggleButtonsContainer");
|
|
16
|
+
export const toggleButtonsContainerStyle = style({
|
|
17
|
+
'@layer': {
|
|
18
|
+
[cssLayerComponent]: {
|
|
19
|
+
containerName: toggleButtonsContainer,
|
|
20
|
+
containerType: 'inline-size'
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}, "toggleButtonsContainerStyle");
|
|
24
|
+
export const toggleButtonGroup = recipe({
|
|
25
|
+
base: [{
|
|
26
|
+
'@layer': {
|
|
27
|
+
[cssLayerComponent]: {
|
|
28
|
+
color: vars.color.gamut.gray[500],
|
|
29
|
+
display: 'grid',
|
|
30
|
+
gridTemplateColumns: '1fr',
|
|
31
|
+
'@container': {
|
|
32
|
+
[`${toggleButtonsContainer} (min-width: ${WIDTH_COMPACT_ORIENTATION}px)`]: {
|
|
33
|
+
gridTemplateColumns: 'repeat(auto-fit, minmax(0, 1fr))'
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}],
|
|
39
|
+
variants: {
|
|
40
|
+
iconOnly: {
|
|
41
|
+
true: {
|
|
42
|
+
'@layer': {
|
|
43
|
+
[cssLayerComponent]: {
|
|
44
|
+
color: vars.color.content.normal,
|
|
45
|
+
display: 'block',
|
|
46
|
+
lineHeight: 1
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
defaultVariants: {
|
|
53
|
+
iconOnly: false
|
|
54
|
+
}
|
|
55
|
+
}, "toggleButtonGroup");
|
|
56
|
+
const selectorNotIconOnly = `${toggleButtonGroup.classNames.base}:not([data-icon-only])`;
|
|
57
|
+
export const toggleButton = style([elementReset.button, focusOutlineStyle, sprinkles({
|
|
58
|
+
backgroundColor: 'page',
|
|
59
|
+
borderColour: 'gray',
|
|
60
|
+
borderStyle: 'solid',
|
|
61
|
+
borderWidth: '1',
|
|
62
|
+
px: '3',
|
|
63
|
+
text: '4',
|
|
64
|
+
textWrap: 'nowrap'
|
|
65
|
+
}), {
|
|
66
|
+
'@layer': {
|
|
67
|
+
[cssLayerComponent]: {
|
|
68
|
+
appearance: 'none',
|
|
69
|
+
color: 'inherit',
|
|
70
|
+
height: TOGGLE_BUTTON_HEIGHT,
|
|
71
|
+
overflow: 'hidden',
|
|
72
|
+
textOverflow: 'ellipsis',
|
|
73
|
+
transitionDuration: '0.1s',
|
|
74
|
+
transitionProperty: 'background-color, border-color, box-shadow, color',
|
|
75
|
+
transitionTimingFunction: vars.animation.easing.standard,
|
|
76
|
+
userSelect: 'none',
|
|
77
|
+
selectors: {
|
|
78
|
+
'&:first-child': {
|
|
79
|
+
borderBottomLeftRadius: vars.border.radius.md,
|
|
80
|
+
borderTopLeftRadius: vars.border.radius.md
|
|
81
|
+
},
|
|
82
|
+
'&:last-child': {
|
|
83
|
+
borderBottomRightRadius: vars.border.radius.md,
|
|
84
|
+
borderTopRightRadius: vars.border.radius.md
|
|
85
|
+
},
|
|
86
|
+
'&:focus-visible': {
|
|
87
|
+
position: 'relative',
|
|
88
|
+
zIndex: 1
|
|
89
|
+
},
|
|
90
|
+
'&+&': {
|
|
91
|
+
borderLeftStyle: 'none'
|
|
92
|
+
},
|
|
93
|
+
[selectors.hoverNotDisabled]: {
|
|
94
|
+
cursor: 'pointer'
|
|
95
|
+
},
|
|
96
|
+
[selectors.hoverNotSelected]: {
|
|
97
|
+
backgroundColor: vars.color.gamut.gray[200],
|
|
98
|
+
boxShadow: 'inset 0 1px 5px 0 rgba(0, 0, 0, 0.03), inset 0 2px 2px 0 rgba(0, 0, 0, 0.03), inset 0 3px 1px -2px rgba(0, 0, 0, 0.05)',
|
|
99
|
+
transitionDelay: '50ms',
|
|
100
|
+
transitionDuration: '0.2s'
|
|
101
|
+
},
|
|
102
|
+
[selectors.selected]: {
|
|
103
|
+
backgroundColor: vars.color.surface.hard,
|
|
104
|
+
borderColor: vars.color.surface.hard,
|
|
105
|
+
color: vars.color.content.inverse
|
|
106
|
+
},
|
|
107
|
+
[selectors.disabled]: {
|
|
108
|
+
cursor: 'not-allowed',
|
|
109
|
+
opacity: 0.6
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
// Container-based responsive styles for mobile stacking (only for non-iconOnly)
|
|
113
|
+
'@container': {
|
|
114
|
+
[`${toggleButtonsContainer} (max-width: ${WIDTH_COMPACT_ORIENTATION}px)`]: {
|
|
115
|
+
selectors: {
|
|
116
|
+
[`${selectorNotIconOnly} &`]: {
|
|
117
|
+
borderLeftStyle: 'solid'
|
|
118
|
+
},
|
|
119
|
+
[`${selectorNotIconOnly} &+&`]: {
|
|
120
|
+
borderTopStyle: 'none'
|
|
121
|
+
},
|
|
122
|
+
[`${selectorNotIconOnly} &:first-child`]: {
|
|
123
|
+
borderBottomLeftRadius: 0,
|
|
124
|
+
borderTopLeftRadius: vars.border.radius.md,
|
|
125
|
+
borderTopRightRadius: vars.border.radius.md
|
|
126
|
+
},
|
|
127
|
+
[`${selectorNotIconOnly} &:last-child`]: {
|
|
128
|
+
borderBottomLeftRadius: vars.border.radius.md,
|
|
129
|
+
borderBottomRightRadius: vars.border.radius.md,
|
|
130
|
+
borderTopRightRadius: 0
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}], "toggleButton");
|
|
138
|
+
__vanilla_filescope__.endFileScope();
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { AriaToggleButtonGroupItemProps } from '@react-types/button';
|
|
2
|
+
import type { Key } from '@react-types/shared';
|
|
3
|
+
import React, { type ReactNode } from 'react';
|
|
4
|
+
import { type AriaToggleButtonGroupProps } from 'react-aria';
|
|
5
|
+
import type { TestIdProp } from '../../types';
|
|
6
|
+
import { type UseBoxProps } from '../Box/useBox/useBox';
|
|
7
|
+
export interface ToggleButtonsProps extends AriaToggleButtonGroupProps, UseBoxProps, TestIdProp {
|
|
8
|
+
/**
|
|
9
|
+
* The toggle buttons to display in the group
|
|
10
|
+
* ```tsx
|
|
11
|
+
* <ToggleButton id="option1">Option 1</ToggleButton>
|
|
12
|
+
* <ToggleButton id="option2">Option 2</ToggleButton>
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
/** Whether the buttons contain only icons (affects layout styling) */
|
|
17
|
+
iconOnly?: boolean;
|
|
18
|
+
/** Whether single or multiple selection is enabled. @default 'single' */
|
|
19
|
+
selectionMode?: 'single' | 'multiple';
|
|
20
|
+
/** Whether the collection allows empty selection. @default true */
|
|
21
|
+
disallowEmptySelection?: boolean;
|
|
22
|
+
/** The currently selected keys in the collection (controlled). */
|
|
23
|
+
selectedKeys?: Iterable<Key>;
|
|
24
|
+
/** The initial selected keys in the collection (uncontrolled). */
|
|
25
|
+
defaultSelectedKeys?: Iterable<Key>;
|
|
26
|
+
/** Handler that is called when the selection changes. */
|
|
27
|
+
onSelectionChange?: (keys: Set<Key>) => void;
|
|
28
|
+
/** Whether all toggle buttons are disabled. */
|
|
29
|
+
isDisabled?: boolean;
|
|
30
|
+
/** (_Not in use_) The orientation of the toggle button group. @default 'horizontal' */
|
|
31
|
+
orientation?: 'horizontal' | 'vertical';
|
|
32
|
+
}
|
|
33
|
+
export declare const WIDTH_COMPACT_ORIENTATION = 640;
|
|
34
|
+
/**
|
|
35
|
+
* ## ToggleButtons
|
|
36
|
+
*
|
|
37
|
+
* A toggle button group component that allows users to select one option from a set (multiple selection
|
|
38
|
+
* configurable). The ToggleButtons component also exports `ToggleButton` which are the child contents.
|
|
39
|
+
* Each `ToggleButton` item must be populated with an `id="[value]"` prop which is used to identify it
|
|
40
|
+
* both for default selection and in the on-change event.
|
|
41
|
+
*
|
|
42
|
+
* ### Configuration Overview
|
|
43
|
+
* - **Selection mode**: `selectionMode` - "single" or "multiple" behavior
|
|
44
|
+
* - **Default selection**: `defaultSelectedKeys` - initial selected keys as `string[]` (uncontrolled)
|
|
45
|
+
* - **Controlled mode**: `selectedKeys` + `onSelectionChange` - external state control
|
|
46
|
+
* - **Icon-only**: `iconOnly` - changes layout for single icon content (ARIA label or hidden text label required)
|
|
47
|
+
* - `disallowEmptySelection`: Prevents deselecting all options (**default**: `true`)
|
|
48
|
+
* - `isDisabled`: Disables the entire group
|
|
49
|
+
*
|
|
50
|
+
* ### Responsive Behaviour
|
|
51
|
+
* - For toggle buttons that are not `iconOnly` the layout will be vertical below tablet viewport width
|
|
52
|
+
*
|
|
53
|
+
* ### Accessibility
|
|
54
|
+
* - **Group Label**: When the button group has a label, associate it with `aria-labelledby` to and `id` on the heading text.
|
|
55
|
+
* To add a label without a heading use `aria-label`
|
|
56
|
+
* - **Button Label**: For icons and other visual-only buttons add `aria-label` or label text within VisuallyHidden
|
|
57
|
+
*
|
|
58
|
+
* ### Selection Handling
|
|
59
|
+
* The `onSelectionChange` callback receives a `Set<Key>` containing the IDs of current selected buttons.
|
|
60
|
+
* Since a Set is not seralizable, the common approach is to convert it to an array for operations:
|
|
61
|
+
* ```tsx
|
|
62
|
+
* onSelectionChange={(keys) => {
|
|
63
|
+
* console.log([...keys]); // Convert Set to array: ["option1", "option3"]
|
|
64
|
+
* setSelected(new Set(keys)); // Store as Set for controlled state
|
|
65
|
+
* }}
|
|
66
|
+
* ```
|
|
67
|
+
* @example
|
|
68
|
+
* ```tsx
|
|
69
|
+
* // Uncontrolled (recommended)
|
|
70
|
+
* <ToggleButtons
|
|
71
|
+
* defaultSelectedKeys={['confirm']}
|
|
72
|
+
* onSelectionChange={(keys) => handleChange(keys)}
|
|
73
|
+
* >
|
|
74
|
+
* <ToggleButton id="confirm">Confirm</ToggleButton>
|
|
75
|
+
* <ToggleButton id="decline">Decline</ToggleButton>
|
|
76
|
+
* <ToggleButton id="change-date">Change date</ToggleButton>
|
|
77
|
+
* </ToggleButtons>
|
|
78
|
+
* ```
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```tsx
|
|
82
|
+
* // Controlled mode
|
|
83
|
+
* const [selected, setSelected] = useState(new Set(['list']));
|
|
84
|
+
*
|
|
85
|
+
* <ToggleButtons
|
|
86
|
+
* selectedKeys={selected}
|
|
87
|
+
* onSelectionChange={setSelected}
|
|
88
|
+
* >
|
|
89
|
+
* <ToggleButton id="list">List</ToggleButton>
|
|
90
|
+
* <ToggleButton id="grid">Grid</ToggleButton>
|
|
91
|
+
* </ToggleButtons>
|
|
92
|
+
* ```
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```tsx
|
|
96
|
+
* // Icon-only buttons
|
|
97
|
+
* <ToggleButtons
|
|
98
|
+
* defaultSelectedKeys={['list']}
|
|
99
|
+
* iconOnly
|
|
100
|
+
* onSelectionChange={handleViewChange}
|
|
101
|
+
* >
|
|
102
|
+
* <ToggleButton id="list" aria-label="List view">
|
|
103
|
+
* <Icon icon={ListIcon} />
|
|
104
|
+
* </ToggleButton>
|
|
105
|
+
* <ToggleButton id="map" aria-label="Map view">
|
|
106
|
+
* <Icon icon={MapIcon} />
|
|
107
|
+
* </ToggleButton>
|
|
108
|
+
* </ToggleButtons>
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
export declare const ToggleButtons: React.ForwardRefExoticComponent<ToggleButtonsProps & React.RefAttributes<HTMLDivElement>>;
|
|
112
|
+
export declare const ToggleButton: React.ForwardRefExoticComponent<AriaToggleButtonGroupItemProps<"button"> & React.RefAttributes<HTMLButtonElement>>;
|
|
113
|
+
//# sourceMappingURL=ToggleButtons.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToggleButtons.d.ts","sourceRoot":"","sources":["../../../lib/components/ToggleButtons/ToggleButtons.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,KAAK,EAAE,EAIb,KAAK,SAAS,EAEd,MAAM,OAAO,CAAC;AACf,OAAO,EAGN,KAAK,0BAA0B,EAC/B,MAAM,YAAY,CAAC;AAIpB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAIhE,MAAM,WAAW,kBAChB,SAAQ,0BAA0B,EACjC,WAAW,EACX,UAAU;IACX;;;;;;OAMG;IACH,QAAQ,EAAE,SAAS,CAAC;IACpB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yEAAyE;IACzE,aAAa,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;IACtC,mEAAmE;IACnE,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,kEAAkE;IAClE,YAAY,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC7B,kEAAkE;IAClE,mBAAmB,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;IACpC,yDAAyD;IACzD,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC;IAC7C,+CAA+C;IAC/C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,uFAAuF;IACvF,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;CACxC;AAGD,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAM7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4EG;AACH,eAAO,MAAM,aAAa,2FA0FzB,CAAC;AAIF,eAAO,MAAM,YAAY,oHAsCvB,CAAC"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
|
4
|
+
import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
|
|
5
|
+
const _excluded = ["children", "disallowEmptySelection", "iconOnly", "orientation", "selectionMode"],
|
|
6
|
+
_excluded2 = ["selectedKeys", "defaultSelectedKeys", "onSelectionChange", "isDisabled", "aria-describedby", "aria-details", "aria-label", "aria-labelledby"],
|
|
7
|
+
_excluded3 = ["children"];
|
|
8
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
9
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
10
|
+
import { invariant } from '@autoguru/utilities';
|
|
11
|
+
import React, { Children, forwardRef, useRef } from 'react';
|
|
12
|
+
import { useToggleButtonGroup, useToggleButtonGroupItem } from 'react-aria';
|
|
13
|
+
import { useToggleGroupState } from 'react-stately';
|
|
14
|
+
import { useContainerWidth } from "../../hooks/index.js";
|
|
15
|
+
import { mergeRefs } from "../../utils/index.js";
|
|
16
|
+
import { dataAttrs } from "../../utils/dataAttrs.js";
|
|
17
|
+
import { useBox } from "../Box/useBox/useBox.js";
|
|
18
|
+
import * as styles from "./ToggleButtons.css.js";
|
|
19
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
20
|
+
// only applies to non `iconOnly` layout
|
|
21
|
+
export const WIDTH_COMPACT_ORIENTATION = 640;
|
|
22
|
+
const ToggleButtonGroupContext = /*#__PURE__*/React.createContext(null);
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* ## ToggleButtons
|
|
26
|
+
*
|
|
27
|
+
* A toggle button group component that allows users to select one option from a set (multiple selection
|
|
28
|
+
* configurable). The ToggleButtons component also exports `ToggleButton` which are the child contents.
|
|
29
|
+
* Each `ToggleButton` item must be populated with an `id="[value]"` prop which is used to identify it
|
|
30
|
+
* both for default selection and in the on-change event.
|
|
31
|
+
*
|
|
32
|
+
* ### Configuration Overview
|
|
33
|
+
* - **Selection mode**: `selectionMode` - "single" or "multiple" behavior
|
|
34
|
+
* - **Default selection**: `defaultSelectedKeys` - initial selected keys as `string[]` (uncontrolled)
|
|
35
|
+
* - **Controlled mode**: `selectedKeys` + `onSelectionChange` - external state control
|
|
36
|
+
* - **Icon-only**: `iconOnly` - changes layout for single icon content (ARIA label or hidden text label required)
|
|
37
|
+
* - `disallowEmptySelection`: Prevents deselecting all options (**default**: `true`)
|
|
38
|
+
* - `isDisabled`: Disables the entire group
|
|
39
|
+
*
|
|
40
|
+
* ### Responsive Behaviour
|
|
41
|
+
* - For toggle buttons that are not `iconOnly` the layout will be vertical below tablet viewport width
|
|
42
|
+
*
|
|
43
|
+
* ### Accessibility
|
|
44
|
+
* - **Group Label**: When the button group has a label, associate it with `aria-labelledby` to and `id` on the heading text.
|
|
45
|
+
* To add a label without a heading use `aria-label`
|
|
46
|
+
* - **Button Label**: For icons and other visual-only buttons add `aria-label` or label text within VisuallyHidden
|
|
47
|
+
*
|
|
48
|
+
* ### Selection Handling
|
|
49
|
+
* The `onSelectionChange` callback receives a `Set<Key>` containing the IDs of current selected buttons.
|
|
50
|
+
* Since a Set is not seralizable, the common approach is to convert it to an array for operations:
|
|
51
|
+
* ```tsx
|
|
52
|
+
* onSelectionChange={(keys) => {
|
|
53
|
+
* console.log([...keys]); // Convert Set to array: ["option1", "option3"]
|
|
54
|
+
* setSelected(new Set(keys)); // Store as Set for controlled state
|
|
55
|
+
* }}
|
|
56
|
+
* ```
|
|
57
|
+
* @example
|
|
58
|
+
* ```tsx
|
|
59
|
+
* // Uncontrolled (recommended)
|
|
60
|
+
* <ToggleButtons
|
|
61
|
+
* defaultSelectedKeys={['confirm']}
|
|
62
|
+
* onSelectionChange={(keys) => handleChange(keys)}
|
|
63
|
+
* >
|
|
64
|
+
* <ToggleButton id="confirm">Confirm</ToggleButton>
|
|
65
|
+
* <ToggleButton id="decline">Decline</ToggleButton>
|
|
66
|
+
* <ToggleButton id="change-date">Change date</ToggleButton>
|
|
67
|
+
* </ToggleButtons>
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```tsx
|
|
72
|
+
* // Controlled mode
|
|
73
|
+
* const [selected, setSelected] = useState(new Set(['list']));
|
|
74
|
+
*
|
|
75
|
+
* <ToggleButtons
|
|
76
|
+
* selectedKeys={selected}
|
|
77
|
+
* onSelectionChange={setSelected}
|
|
78
|
+
* >
|
|
79
|
+
* <ToggleButton id="list">List</ToggleButton>
|
|
80
|
+
* <ToggleButton id="grid">Grid</ToggleButton>
|
|
81
|
+
* </ToggleButtons>
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```tsx
|
|
86
|
+
* // Icon-only buttons
|
|
87
|
+
* <ToggleButtons
|
|
88
|
+
* defaultSelectedKeys={['list']}
|
|
89
|
+
* iconOnly
|
|
90
|
+
* onSelectionChange={handleViewChange}
|
|
91
|
+
* >
|
|
92
|
+
* <ToggleButton id="list" aria-label="List view">
|
|
93
|
+
* <Icon icon={ListIcon} />
|
|
94
|
+
* </ToggleButton>
|
|
95
|
+
* <ToggleButton id="map" aria-label="Map view">
|
|
96
|
+
* <Icon icon={MapIcon} />
|
|
97
|
+
* </ToggleButton>
|
|
98
|
+
* </ToggleButtons>
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
export const ToggleButtons = /*#__PURE__*/forwardRef((_ref, forwardedRef) => {
|
|
102
|
+
let {
|
|
103
|
+
children,
|
|
104
|
+
disallowEmptySelection = true,
|
|
105
|
+
iconOnly = false,
|
|
106
|
+
orientation: incomingOrientation,
|
|
107
|
+
selectionMode = 'single'
|
|
108
|
+
} = _ref,
|
|
109
|
+
withBoxProps = _objectWithoutProperties(_ref, _excluded);
|
|
110
|
+
const {
|
|
111
|
+
selectedKeys,
|
|
112
|
+
defaultSelectedKeys,
|
|
113
|
+
onSelectionChange,
|
|
114
|
+
isDisabled,
|
|
115
|
+
'aria-describedby': ariaDescribedBy,
|
|
116
|
+
'aria-details': ariaDetails,
|
|
117
|
+
'aria-label': ariaLabel,
|
|
118
|
+
'aria-labelledby': ariaLabelledBy
|
|
119
|
+
} = withBoxProps,
|
|
120
|
+
boxProps = _objectWithoutProperties(withBoxProps, _excluded2);
|
|
121
|
+
const childArray = Children.toArray(children);
|
|
122
|
+
!(childArray.length > 0) ? process.env.NODE_ENV !== "production" ? invariant(false, 'ToggleButtons: Must contain at least one ToggleButton child') : invariant(false) : void 0;
|
|
123
|
+
const internalRef = useRef(null);
|
|
124
|
+
const containerWidth = useContainerWidth({
|
|
125
|
+
containerRef: internalRef
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// Determine orientation based on container width (not iconOnly)
|
|
129
|
+
const hasCompactLayout = !iconOnly && containerWidth > 0 && containerWidth < WIDTH_COMPACT_ORIENTATION;
|
|
130
|
+
const orientation = hasCompactLayout ? 'vertical' : incomingOrientation !== null && incomingOrientation !== void 0 ? incomingOrientation : 'horizontal';
|
|
131
|
+
const ariaProps = {
|
|
132
|
+
disallowEmptySelection,
|
|
133
|
+
defaultSelectedKeys,
|
|
134
|
+
isDisabled,
|
|
135
|
+
selectionMode,
|
|
136
|
+
onSelectionChange,
|
|
137
|
+
orientation,
|
|
138
|
+
selectedKeys,
|
|
139
|
+
'aria-describedby': ariaDescribedBy,
|
|
140
|
+
'aria-details': ariaDetails,
|
|
141
|
+
'aria-label': ariaLabel,
|
|
142
|
+
'aria-labelledby': ariaLabelledBy
|
|
143
|
+
};
|
|
144
|
+
const state = useToggleGroupState(ariaProps);
|
|
145
|
+
const {
|
|
146
|
+
groupProps
|
|
147
|
+
} = useToggleButtonGroup(ariaProps, state, internalRef);
|
|
148
|
+
const {
|
|
149
|
+
Component,
|
|
150
|
+
componentProps
|
|
151
|
+
} = useBox(_objectSpread(_objectSpread({}, boxProps), {}, {
|
|
152
|
+
className: !iconOnly && styles.toggleButtonsContainerStyle,
|
|
153
|
+
display: iconOnly ? 'flex' : undefined,
|
|
154
|
+
odComponent: 'toggle-buttons'
|
|
155
|
+
}));
|
|
156
|
+
return /*#__PURE__*/_jsx(Component, _objectSpread(_objectSpread({}, componentProps), {}, {
|
|
157
|
+
ref: mergeRefs([internalRef, forwardedRef]),
|
|
158
|
+
children: /*#__PURE__*/_jsx("div", _objectSpread(_objectSpread(_objectSpread({
|
|
159
|
+
className: styles.toggleButtonGroup({
|
|
160
|
+
iconOnly
|
|
161
|
+
})
|
|
162
|
+
}, groupProps), dataAttrs({
|
|
163
|
+
iconOnly
|
|
164
|
+
})), {}, {
|
|
165
|
+
children: /*#__PURE__*/_jsx(ToggleButtonGroupContext.Provider, {
|
|
166
|
+
value: state,
|
|
167
|
+
children: children
|
|
168
|
+
})
|
|
169
|
+
}))
|
|
170
|
+
}));
|
|
171
|
+
});
|
|
172
|
+
ToggleButtons.displayName = 'ToggleButtons';
|
|
173
|
+
export const ToggleButton = /*#__PURE__*/forwardRef((_ref2, forwardedRef) => {
|
|
174
|
+
let {
|
|
175
|
+
children
|
|
176
|
+
} = _ref2,
|
|
177
|
+
props = _objectWithoutProperties(_ref2, _excluded3);
|
|
178
|
+
const internalRef = useRef(null);
|
|
179
|
+
const state = React.useContext(ToggleButtonGroupContext);
|
|
180
|
+
!(state !== null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'ToggleButton: Must be used within ToggleButtons component') : invariant(false) : void 0;
|
|
181
|
+
!(props.id !== undefined) ? process.env.NODE_ENV !== "production" ? invariant(false, 'ToggleButton: Missing required "id" prop') : invariant(false) : void 0;
|
|
182
|
+
const {
|
|
183
|
+
buttonProps,
|
|
184
|
+
isSelected
|
|
185
|
+
} = useToggleButtonGroupItem(props, state, internalRef);
|
|
186
|
+
const {
|
|
187
|
+
isDisabled
|
|
188
|
+
} = props;
|
|
189
|
+
return /*#__PURE__*/_jsx("button", _objectSpread(_objectSpread(_objectSpread({}, buttonProps), {}, {
|
|
190
|
+
className: styles.toggleButton
|
|
191
|
+
}, dataAttrs({
|
|
192
|
+
selected: isSelected,
|
|
193
|
+
disabled: isDisabled
|
|
194
|
+
})), {}, {
|
|
195
|
+
ref: mergeRefs([internalRef, forwardedRef]),
|
|
196
|
+
children: children
|
|
197
|
+
}));
|
|
198
|
+
});
|
|
199
|
+
ToggleButton.displayName = 'ToggleButton';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../lib/components/ToggleButtons/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,aAAa,EACb,YAAY,EACZ,KAAK,kBAAkB,GACvB,MAAM,iBAAiB,CAAC"}
|
|
@@ -65,6 +65,7 @@ export * from './TextContainer';
|
|
|
65
65
|
export * from './TextInput';
|
|
66
66
|
export * from './TextLink';
|
|
67
67
|
export * from './Toaster';
|
|
68
|
+
export * from './ToggleButtons';
|
|
68
69
|
export * from './Tooltip';
|
|
69
70
|
export * from './VisuallyHidden';
|
|
70
71
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC;AACtB,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,0BAA0B,CAAC;AACzC,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,cAAc,CAAC;AAC7B,cAAc,QAAQ,CAAC;AACvB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,SAAS,CAAC;AACxB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,UAAU,CAAC;AACzB,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC;AACtB,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,0BAA0B,CAAC;AACzC,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,cAAc,CAAC;AAC7B,cAAc,QAAQ,CAAC;AACvB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,SAAS,CAAC;AACxB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,UAAU,CAAC;AACzB,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC"}
|
package/dist/components/index.js
CHANGED
|
@@ -67,5 +67,6 @@ export * from "./TextContainer/index.js";
|
|
|
67
67
|
export * from "./TextInput/index.js";
|
|
68
68
|
export * from "./TextLink/index.js";
|
|
69
69
|
export * from "./Toaster/index.js";
|
|
70
|
+
export * from "./ToggleButtons/index.js";
|
|
70
71
|
export * from "./Tooltip/index.js";
|
|
71
72
|
export * from "./VisuallyHidden/index.js";
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC"}
|
package/dist/hooks/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
export * from "./useAnimationEvents/index.js";
|
|
4
4
|
export * from "./useAttachedBoxes/index.js";
|
|
5
|
+
export * from "./useContainerWidth/index.js";
|
|
5
6
|
export * from "./useDeepCompareMemo/index.js";
|
|
6
7
|
export * from "./useDocumentBodyStyles/index.js";
|
|
7
8
|
export * from "./useNegativeMargin/index.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../lib/hooks/useContainerWidth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,iBAAiB,EACjB,KAAK,sBAAsB,GAC3B,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
export interface UseContainerWidthProps {
|
|
3
|
+
containerRef: RefObject<HTMLElement>;
|
|
4
|
+
/**
|
|
5
|
+
* Debounce delay in milliseconds to prevent excessive updates during resize
|
|
6
|
+
* @default 32 (roughly 30fps)
|
|
7
|
+
*/
|
|
8
|
+
debounceMs?: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Hook to observe and return the width of a container element
|
|
12
|
+
*
|
|
13
|
+
* @param containerRef - Reference to the container element to measure
|
|
14
|
+
* @param debounceMs - Debounce delay in milliseconds (default: 32ms for ~30fps)
|
|
15
|
+
* @returns Current width of the container in pixels
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* const containerRef = useRef<HTMLDivElement>(null);
|
|
20
|
+
* const width = useContainerWidth({ containerRef });
|
|
21
|
+
*
|
|
22
|
+
* // With custom debounce
|
|
23
|
+
* const width = useContainerWidth({ containerRef, debounceMs: 100 });
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare const useContainerWidth: ({ containerRef, debounceMs, }: UseContainerWidthProps) => number;
|
|
27
|
+
//# sourceMappingURL=useContainerWidth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useContainerWidth.d.ts","sourceRoot":"","sources":["../../../lib/hooks/useContainerWidth/useContainerWidth.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,SAAS,EAKT,MAAM,OAAO,CAAC;AAEf,MAAM,WAAW,sBAAsB;IACtC,YAAY,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC;IACrC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,iBAAiB,GAAI,+BAG/B,sBAAsB,KAAG,MA2D3B,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useLayoutEffect, useState, useRef, useCallback } from 'react';
|
|
4
|
+
/**
|
|
5
|
+
* Hook to observe and return the width of a container element
|
|
6
|
+
*
|
|
7
|
+
* @param containerRef - Reference to the container element to measure
|
|
8
|
+
* @param debounceMs - Debounce delay in milliseconds (default: 32ms for ~30fps)
|
|
9
|
+
* @returns Current width of the container in pixels
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* const containerRef = useRef<HTMLDivElement>(null);
|
|
14
|
+
* const width = useContainerWidth({ containerRef });
|
|
15
|
+
*
|
|
16
|
+
* // With custom debounce
|
|
17
|
+
* const width = useContainerWidth({ containerRef, debounceMs: 100 });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export const useContainerWidth = ({
|
|
21
|
+
containerRef,
|
|
22
|
+
debounceMs = 32
|
|
23
|
+
}) => {
|
|
24
|
+
const [containerWidth, setContainerWidth] = useState(0);
|
|
25
|
+
const debounceRef = useRef(debounceMs);
|
|
26
|
+
const debouncedSetWidth = useCallback(newWidth => {
|
|
27
|
+
if (debounceRef.current) {
|
|
28
|
+
clearTimeout(debounceRef.current);
|
|
29
|
+
}
|
|
30
|
+
debounceRef.current = window.setTimeout(() => {
|
|
31
|
+
setContainerWidth(newWidth);
|
|
32
|
+
}, debounceMs);
|
|
33
|
+
}, [debounceMs]);
|
|
34
|
+
useLayoutEffect(() => {
|
|
35
|
+
if (!(containerRef !== null && containerRef !== void 0 && containerRef.current)) return;
|
|
36
|
+
const resize = () => {
|
|
37
|
+
if (containerRef.current) {
|
|
38
|
+
const newWidth = containerRef.current.getBoundingClientRect().width;
|
|
39
|
+
|
|
40
|
+
// For test environments or initial measurement, set immediately
|
|
41
|
+
if (typeof ResizeObserver === 'undefined' || containerWidth === 0) {
|
|
42
|
+
setContainerWidth(newWidth);
|
|
43
|
+
} else {
|
|
44
|
+
debouncedSetWidth(newWidth);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Check if ResizeObserver is available (not available in some test environments)
|
|
50
|
+
if (typeof ResizeObserver === 'undefined') {
|
|
51
|
+
// Fallback for test environments - just measure once
|
|
52
|
+
resize();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const resizeObserver = new ResizeObserver(resize);
|
|
56
|
+
resizeObserver.observe(containerRef.current);
|
|
57
|
+
|
|
58
|
+
// Initial measurement (immediate)
|
|
59
|
+
resize();
|
|
60
|
+
return () => {
|
|
61
|
+
resizeObserver.disconnect();
|
|
62
|
+
if (debounceRef.current) {
|
|
63
|
+
clearTimeout(debounceRef.current);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}, [containerRef, debouncedSetWidth, containerWidth]);
|
|
67
|
+
return containerWidth;
|
|
68
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autoguru/overdrive",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.49.0",
|
|
4
4
|
"description": "Overdrive is a product component library, and design system for AutoGuru.",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -85,22 +85,22 @@
|
|
|
85
85
|
"@octokit/rest": "22.0.0",
|
|
86
86
|
"@popperjs/core": "2.11.8",
|
|
87
87
|
"@react-stately/toggle": "3.9.1",
|
|
88
|
-
"@storybook/addon-a11y": "9.1.
|
|
89
|
-
"@storybook/addon-docs": "9.1.
|
|
90
|
-
"@storybook/addon-links": "9.1.
|
|
91
|
-
"@storybook/addon-onboarding": "9.1.
|
|
92
|
-
"@storybook/addon-vitest": "9.1.
|
|
93
|
-
"@storybook/react-vite": "9.1.
|
|
88
|
+
"@storybook/addon-a11y": "9.1.8",
|
|
89
|
+
"@storybook/addon-docs": "9.1.8",
|
|
90
|
+
"@storybook/addon-links": "9.1.8",
|
|
91
|
+
"@storybook/addon-onboarding": "9.1.8",
|
|
92
|
+
"@storybook/addon-vitest": "9.1.8",
|
|
93
|
+
"@storybook/react-vite": "9.1.8",
|
|
94
94
|
"@testing-library/dom": "^10.4.1",
|
|
95
95
|
"@testing-library/jest-dom": "6.8.0",
|
|
96
96
|
"@testing-library/react": "16.3.0",
|
|
97
97
|
"@testing-library/react-hooks": "8.0.1",
|
|
98
98
|
"@testing-library/user-event": "14.6.1",
|
|
99
|
-
"@types/node": "24.
|
|
100
|
-
"@types/react": "19.1.
|
|
99
|
+
"@types/node": "24.6.0",
|
|
100
|
+
"@types/react": "19.1.15",
|
|
101
101
|
"@types/react-dom": "19.1.9",
|
|
102
102
|
"@types/webpack-env": "1.18.8",
|
|
103
|
-
"@typescript-eslint/utils": "8.
|
|
103
|
+
"@typescript-eslint/utils": "8.44.1",
|
|
104
104
|
"@vanilla-extract/babel-plugin": "1.2.0",
|
|
105
105
|
"@vanilla-extract/css": "1.17.4",
|
|
106
106
|
"@vanilla-extract/dynamic": "2.1.5",
|
|
@@ -110,12 +110,12 @@
|
|
|
110
110
|
"@vanilla-extract/webpack-plugin": "2.3.22",
|
|
111
111
|
"@vitest/browser": "3.2.4",
|
|
112
112
|
"@vitest/coverage-v8": "3.2.4",
|
|
113
|
-
"@vitest/eslint-plugin": "1.3.
|
|
113
|
+
"@vitest/eslint-plugin": "1.3.13",
|
|
114
114
|
"babel-plugin-add-import-extension": "1.6.0",
|
|
115
115
|
"babel-plugin-dev-expression": "0.2.3",
|
|
116
116
|
"babel-plugin-macros": "3.1.0",
|
|
117
|
-
"browserslist-config-autoguru": "2.5.
|
|
118
|
-
"chromatic": "13.
|
|
117
|
+
"browserslist-config-autoguru": "2.5.2",
|
|
118
|
+
"chromatic": "13.3.0",
|
|
119
119
|
"clsx": "2.1.1",
|
|
120
120
|
"colord": "2.9.3",
|
|
121
121
|
"concurrently": "9.2.1",
|
|
@@ -124,16 +124,16 @@
|
|
|
124
124
|
"deepmerge": "4.3.1",
|
|
125
125
|
"es-toolkit": "1.39.10",
|
|
126
126
|
"eslint": "9.34.0",
|
|
127
|
-
"eslint-plugin-storybook": "9.1.
|
|
127
|
+
"eslint-plugin-storybook": "9.1.8",
|
|
128
128
|
"husky": "9.1.7",
|
|
129
129
|
"intersection-observer": "0.12.2",
|
|
130
130
|
"jsdom": "26.1.0",
|
|
131
|
-
"lint-staged": "16.
|
|
131
|
+
"lint-staged": "16.2.3",
|
|
132
132
|
"magic-string": "0.30.19",
|
|
133
133
|
"mini-css-extract-plugin": "2.9.4",
|
|
134
134
|
"mockdate": "3.0.5",
|
|
135
|
-
"playwright": "1.55.
|
|
136
|
-
"plop": "4.0.
|
|
135
|
+
"playwright": "1.55.1",
|
|
136
|
+
"plop": "4.0.4",
|
|
137
137
|
"postcss": "8.5.6",
|
|
138
138
|
"prettier": "3.6.2",
|
|
139
139
|
"prop-types": "15.8.1",
|
|
@@ -148,13 +148,13 @@
|
|
|
148
148
|
"react-stately": "3.41.0",
|
|
149
149
|
"react-swipeable": "7.0.2",
|
|
150
150
|
"rollup-plugin-visualizer": "6.0.3",
|
|
151
|
-
"storybook": "9.1.
|
|
151
|
+
"storybook": "9.1.8",
|
|
152
152
|
"storybook-addon-tag-badges": "2.0.2",
|
|
153
153
|
"typescript": "5.9.2",
|
|
154
154
|
"url-loader": "4.1.1",
|
|
155
|
-
"vite": "7.1.
|
|
155
|
+
"vite": "7.1.7",
|
|
156
156
|
"vitest": "3.2.4",
|
|
157
|
-
"webpack": "5.
|
|
157
|
+
"webpack": "5.102.0"
|
|
158
158
|
},
|
|
159
159
|
"peerDependencies": {
|
|
160
160
|
"@autoguru/icons": ">=1.8.8",
|
|
@@ -177,8 +177,8 @@
|
|
|
177
177
|
"webpack": "*"
|
|
178
178
|
},
|
|
179
179
|
"volta": {
|
|
180
|
-
"node": "22.
|
|
181
|
-
"yarn": "4.
|
|
180
|
+
"node": "22.20.0",
|
|
181
|
+
"yarn": "4.10.3"
|
|
182
182
|
},
|
|
183
|
-
"packageManager": "yarn@4.
|
|
183
|
+
"packageManager": "yarn@4.10.3"
|
|
184
184
|
}
|