@kushagradhawan/kookie-ui 0.1.37 → 0.1.39
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/components.css +130 -74
- package/dist/cjs/components/_internal/base-button.props.d.ts +1 -1
- package/dist/cjs/components/_internal/base-button.props.js +1 -1
- package/dist/cjs/components/_internal/base-button.props.js.map +2 -2
- package/dist/cjs/components/_internal/base-checkbox.props.d.ts +1 -1
- package/dist/cjs/components/_internal/base-checkbox.props.js +1 -1
- package/dist/cjs/components/_internal/base-checkbox.props.js.map +2 -2
- package/dist/cjs/components/avatar.props.d.ts +1 -1
- package/dist/cjs/components/avatar.props.js +1 -1
- package/dist/cjs/components/avatar.props.js.map +2 -2
- package/dist/cjs/components/button.d.ts +40 -2
- package/dist/cjs/components/button.d.ts.map +1 -1
- package/dist/cjs/components/button.js +1 -1
- package/dist/cjs/components/button.js.map +3 -3
- package/dist/cjs/components/chatbar.d.ts.map +1 -1
- package/dist/cjs/components/chatbar.js +1 -1
- package/dist/cjs/components/chatbar.js.map +2 -2
- package/dist/cjs/components/checkbox-cards.props.d.ts +2 -2
- package/dist/cjs/components/checkbox-cards.props.js +1 -1
- package/dist/cjs/components/checkbox-cards.props.js.map +2 -2
- package/dist/cjs/components/checkbox-group.d.ts.map +1 -1
- package/dist/cjs/components/checkbox-group.js +1 -1
- package/dist/cjs/components/checkbox-group.js.map +3 -3
- package/dist/cjs/components/checkbox-group.props.d.ts +1 -1
- package/dist/cjs/components/dialog.d.ts.map +1 -1
- package/dist/cjs/components/dialog.js +1 -1
- package/dist/cjs/components/dialog.js.map +3 -3
- package/dist/cjs/components/flex.props.d.ts +3 -3
- package/dist/cjs/components/grid.props.d.ts +3 -3
- package/dist/cjs/components/radio-cards.props.d.ts +2 -2
- package/dist/cjs/components/radio-cards.props.js +1 -1
- package/dist/cjs/components/radio-cards.props.js.map +2 -2
- package/dist/cjs/components/select.d.ts.map +1 -1
- package/dist/cjs/components/select.js +1 -1
- package/dist/cjs/components/select.js.map +3 -3
- package/dist/cjs/components/shell.d.ts.map +1 -1
- package/dist/cjs/components/shell.js +1 -1
- package/dist/cjs/components/shell.js.map +3 -3
- package/dist/cjs/components/sidebar.d.ts +7 -1
- package/dist/cjs/components/sidebar.d.ts.map +1 -1
- package/dist/cjs/components/sidebar.js +1 -1
- package/dist/cjs/components/sidebar.js.map +3 -3
- package/dist/cjs/components/sidebar.props.d.ts +6 -0
- package/dist/cjs/components/sidebar.props.d.ts.map +1 -1
- package/dist/cjs/components/sidebar.props.js +1 -1
- package/dist/cjs/components/sidebar.props.js.map +3 -3
- package/dist/cjs/components/table.props.d.ts +7 -7
- package/dist/cjs/components/text-field.props.d.ts +4 -4
- package/dist/cjs/helpers/extract-margin-props.d.ts +7 -7
- package/dist/cjs/hooks/index.d.ts +1 -0
- package/dist/cjs/hooks/index.d.ts.map +1 -1
- package/dist/cjs/hooks/index.js +1 -1
- package/dist/cjs/hooks/index.js.map +3 -3
- package/dist/cjs/hooks/use-body-pointer-events-cleanup.d.ts +9 -0
- package/dist/cjs/hooks/use-body-pointer-events-cleanup.d.ts.map +1 -0
- package/dist/cjs/hooks/use-body-pointer-events-cleanup.js +2 -0
- package/dist/cjs/hooks/use-body-pointer-events-cleanup.js.map +7 -0
- package/dist/cjs/props/gap.props.d.ts +3 -3
- package/dist/cjs/props/gap.props.js +1 -1
- package/dist/cjs/props/gap.props.js.map +2 -2
- package/dist/cjs/props/layout.props.d.ts +7 -7
- package/dist/cjs/props/margin.props.d.ts +7 -7
- package/dist/cjs/props/margin.props.js +1 -1
- package/dist/cjs/props/margin.props.js.map +2 -2
- package/dist/cjs/props/padding.props.d.ts +7 -7
- package/dist/cjs/props/padding.props.js +1 -1
- package/dist/cjs/props/padding.props.js.map +2 -2
- package/dist/esm/components/_internal/base-button.props.d.ts +1 -1
- package/dist/esm/components/_internal/base-button.props.js +1 -1
- package/dist/esm/components/_internal/base-button.props.js.map +2 -2
- package/dist/esm/components/_internal/base-checkbox.props.d.ts +1 -1
- package/dist/esm/components/_internal/base-checkbox.props.js +1 -1
- package/dist/esm/components/_internal/base-checkbox.props.js.map +2 -2
- package/dist/esm/components/avatar.props.d.ts +1 -1
- package/dist/esm/components/avatar.props.js +1 -1
- package/dist/esm/components/avatar.props.js.map +2 -2
- package/dist/esm/components/button.d.ts +40 -2
- package/dist/esm/components/button.d.ts.map +1 -1
- package/dist/esm/components/button.js +1 -1
- package/dist/esm/components/button.js.map +3 -3
- package/dist/esm/components/chatbar.d.ts.map +1 -1
- package/dist/esm/components/chatbar.js +1 -1
- package/dist/esm/components/chatbar.js.map +2 -2
- package/dist/esm/components/checkbox-cards.props.d.ts +2 -2
- package/dist/esm/components/checkbox-cards.props.js +1 -1
- package/dist/esm/components/checkbox-cards.props.js.map +2 -2
- package/dist/esm/components/checkbox-group.d.ts.map +1 -1
- package/dist/esm/components/checkbox-group.js +1 -1
- package/dist/esm/components/checkbox-group.js.map +3 -3
- package/dist/esm/components/checkbox-group.props.d.ts +1 -1
- package/dist/esm/components/dialog.d.ts.map +1 -1
- package/dist/esm/components/dialog.js +1 -1
- package/dist/esm/components/dialog.js.map +3 -3
- package/dist/esm/components/flex.props.d.ts +3 -3
- package/dist/esm/components/grid.props.d.ts +3 -3
- package/dist/esm/components/radio-cards.props.d.ts +2 -2
- package/dist/esm/components/radio-cards.props.js +1 -1
- package/dist/esm/components/radio-cards.props.js.map +2 -2
- package/dist/esm/components/select.d.ts.map +1 -1
- package/dist/esm/components/select.js +1 -1
- package/dist/esm/components/select.js.map +3 -3
- package/dist/esm/components/shell.d.ts.map +1 -1
- package/dist/esm/components/shell.js +1 -1
- package/dist/esm/components/shell.js.map +3 -3
- package/dist/esm/components/sidebar.d.ts +7 -1
- package/dist/esm/components/sidebar.d.ts.map +1 -1
- package/dist/esm/components/sidebar.js +1 -1
- package/dist/esm/components/sidebar.js.map +3 -3
- package/dist/esm/components/sidebar.props.d.ts +6 -0
- package/dist/esm/components/sidebar.props.d.ts.map +1 -1
- package/dist/esm/components/sidebar.props.js +1 -1
- package/dist/esm/components/sidebar.props.js.map +3 -3
- package/dist/esm/components/table.props.d.ts +7 -7
- package/dist/esm/components/text-field.props.d.ts +4 -4
- package/dist/esm/helpers/extract-margin-props.d.ts +7 -7
- package/dist/esm/hooks/index.d.ts +1 -0
- package/dist/esm/hooks/index.d.ts.map +1 -1
- package/dist/esm/hooks/index.js +1 -1
- package/dist/esm/hooks/index.js.map +3 -3
- package/dist/esm/hooks/use-body-pointer-events-cleanup.d.ts +9 -0
- package/dist/esm/hooks/use-body-pointer-events-cleanup.d.ts.map +1 -0
- package/dist/esm/hooks/use-body-pointer-events-cleanup.js +2 -0
- package/dist/esm/hooks/use-body-pointer-events-cleanup.js.map +7 -0
- package/dist/esm/props/gap.props.d.ts +3 -3
- package/dist/esm/props/gap.props.js +1 -1
- package/dist/esm/props/gap.props.js.map +2 -2
- package/dist/esm/props/layout.props.d.ts +7 -7
- package/dist/esm/props/margin.props.d.ts +7 -7
- package/dist/esm/props/margin.props.js +1 -1
- package/dist/esm/props/margin.props.js.map +2 -2
- package/dist/esm/props/padding.props.d.ts +7 -7
- package/dist/esm/props/padding.props.js +1 -1
- package/dist/esm/props/padding.props.js.map +2 -2
- package/layout/tokens.css +3 -0
- package/layout/utilities.css +1806 -42
- package/layout.css +1809 -42
- package/package.json +1 -1
- package/src/components/_internal/base-button.css +179 -73
- package/src/components/_internal/base-button.props.ts +1 -1
- package/src/components/_internal/base-checkbox.props.ts +1 -1
- package/src/components/avatar.props.tsx +1 -1
- package/src/components/button.css +13 -21
- package/src/components/button.tsx +79 -2
- package/src/components/chatbar.tsx +5 -2
- package/src/components/checkbox-cards.props.tsx +1 -1
- package/src/components/checkbox-group.tsx +14 -6
- package/src/components/dialog.tsx +4 -0
- package/src/components/radio-cards.props.tsx +1 -1
- package/src/components/select.css +9 -0
- package/src/components/select.tsx +11 -1
- package/src/components/shell.tsx +34 -3
- package/src/components/sidebar.css +15 -3
- package/src/components/sidebar.props.tsx +3 -0
- package/src/components/sidebar.tsx +27 -0
- package/src/hooks/index.ts +2 -1
- package/src/hooks/use-body-pointer-events-cleanup.ts +81 -0
- package/src/props/gap.props.ts +1 -1
- package/src/props/margin.props.ts +1 -1
- package/src/props/padding.props.ts +1 -1
- package/src/styles/tokens/blur.css +3 -0
- package/src/styles/tokens/constants.css +38 -35
- package/src/styles/tokens/radius.css +3 -0
- package/src/styles/tokens/shadow.css +64 -89
- package/src/styles/tokens/space.css +3 -0
- package/src/styles/tokens/transition.css +25 -12
- package/src/styles/utilities/gap.css +27 -0
- package/src/styles/utilities/margin.css +205 -7
- package/src/styles/utilities/padding.css +69 -0
- package/styles.css +1973 -144
- package/tokens/base.css +34 -25
- package/tokens.css +37 -28
- package/utilities.css +1806 -42
|
@@ -5,6 +5,40 @@ import { BaseButton } from './_internal/base-button.js';
|
|
|
5
5
|
import { Tooltip } from './tooltip.js';
|
|
6
6
|
import type { BaseButtonProps } from './_internal/base-button.js';
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Styles that can be overridden for a particular interaction state
|
|
10
|
+
*/
|
|
11
|
+
interface ButtonOverrideStateStyles {
|
|
12
|
+
color?: string;
|
|
13
|
+
background?: string;
|
|
14
|
+
backgroundColor?: string;
|
|
15
|
+
boxShadow?: string;
|
|
16
|
+
filter?: string;
|
|
17
|
+
outline?: string;
|
|
18
|
+
outlineOffset?: string;
|
|
19
|
+
opacity?: string | number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Full set of override styles keyed by interaction state
|
|
24
|
+
*/
|
|
25
|
+
interface ButtonOverrideStyles {
|
|
26
|
+
/** Default/idle state styles */
|
|
27
|
+
normal?: ButtonOverrideStateStyles;
|
|
28
|
+
/** Hover state styles */
|
|
29
|
+
hover?: ButtonOverrideStateStyles;
|
|
30
|
+
/** Active (mouse down) state styles */
|
|
31
|
+
active?: ButtonOverrideStateStyles;
|
|
32
|
+
/** Toggle pressed state styles (data-state="on") */
|
|
33
|
+
pressed?: ButtonOverrideStateStyles;
|
|
34
|
+
/** Open state styles (e.g., when used as a trigger) */
|
|
35
|
+
open?: ButtonOverrideStateStyles;
|
|
36
|
+
/** Disabled state styles */
|
|
37
|
+
disabled?: ButtonOverrideStateStyles;
|
|
38
|
+
/** Focus-visible outline styles */
|
|
39
|
+
focus?: Pick<ButtonOverrideStateStyles, 'outline' | 'outlineOffset'>;
|
|
40
|
+
}
|
|
41
|
+
|
|
8
42
|
type ButtonElement = React.ElementRef<typeof BaseButton>;
|
|
9
43
|
|
|
10
44
|
/**
|
|
@@ -28,7 +62,14 @@ interface ButtonTooltipProps {
|
|
|
28
62
|
* Core Button props excluding the 'as' prop for polymorphic behavior
|
|
29
63
|
* Combines BaseButton props with tooltip functionality
|
|
30
64
|
*/
|
|
31
|
-
type ButtonOwnProps = Omit<BaseButtonProps, 'as'> &
|
|
65
|
+
type ButtonOwnProps = Omit<BaseButtonProps, 'as'> &
|
|
66
|
+
ButtonTooltipProps & {
|
|
67
|
+
/**
|
|
68
|
+
* When using variant="override", provide token-based styles per state.
|
|
69
|
+
* We propagate these into CSS variables consumed by the override variant.
|
|
70
|
+
*/
|
|
71
|
+
overrideStyles?: ButtonOverrideStyles;
|
|
72
|
+
};
|
|
32
73
|
|
|
33
74
|
/**
|
|
34
75
|
* Polymorphic Button props that support rendering as different HTML elements
|
|
@@ -79,6 +120,7 @@ const Button = React.forwardRef(
|
|
|
79
120
|
tooltipAlign = 'center',
|
|
80
121
|
tooltipDelayDuration,
|
|
81
122
|
tooltipDisableHoverableContent,
|
|
123
|
+
overrideStyles,
|
|
82
124
|
...props
|
|
83
125
|
}: ButtonProps,
|
|
84
126
|
forwardedRef: React.ForwardedRef<ButtonElement>,
|
|
@@ -94,12 +136,47 @@ const Button = React.forwardRef(
|
|
|
94
136
|
);
|
|
95
137
|
|
|
96
138
|
// Create the base button element with tooltip accessibility props
|
|
139
|
+
// Map overrideStyles to CSS variables consumed by the override variant rules
|
|
140
|
+
const overrideVars = React.useMemo(() => {
|
|
141
|
+
if (!overrideStyles) return undefined;
|
|
142
|
+
const vars: Record<string, string | number> = {};
|
|
143
|
+
const setVar = (key: string, value: string | number | undefined) => {
|
|
144
|
+
if (value !== undefined) vars[key] = value;
|
|
145
|
+
};
|
|
146
|
+
const apply = (prefix: string, s?: ButtonOverrideStateStyles) => {
|
|
147
|
+
if (!s) return;
|
|
148
|
+
setVar(`--button-override-${prefix}color`, s.color);
|
|
149
|
+
setVar(`--button-override-${prefix}background`, s.background);
|
|
150
|
+
setVar(`--button-override-${prefix}background-color`, s.backgroundColor);
|
|
151
|
+
setVar(`--button-override-${prefix}box-shadow`, s.boxShadow);
|
|
152
|
+
setVar(`--button-override-${prefix}filter`, s.filter);
|
|
153
|
+
setVar(`--button-override-${prefix}outline`, s.outline);
|
|
154
|
+
setVar(`--button-override-${prefix}outline-offset`, s.outlineOffset);
|
|
155
|
+
setVar(`--button-override-${prefix}opacity`, s.opacity as any);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
apply('', overrideStyles.normal);
|
|
159
|
+
apply('hover-', overrideStyles.hover);
|
|
160
|
+
apply('active-', overrideStyles.active);
|
|
161
|
+
apply('pressed-', overrideStyles.pressed);
|
|
162
|
+
apply('open-', overrideStyles.open);
|
|
163
|
+
apply('disabled-', overrideStyles.disabled);
|
|
164
|
+
|
|
165
|
+
if (overrideStyles.focus) {
|
|
166
|
+
setVar('--button-override-focus-outline', overrideStyles.focus.outline);
|
|
167
|
+
setVar('--button-override-focus-outline-offset', overrideStyles.focus.outlineOffset);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return vars as unknown as React.CSSProperties;
|
|
171
|
+
}, [overrideStyles]);
|
|
172
|
+
|
|
97
173
|
const button = (
|
|
98
174
|
<BaseButton
|
|
99
175
|
{...props}
|
|
100
176
|
{...tooltipAccessibilityProps}
|
|
101
177
|
ref={forwardedRef}
|
|
102
178
|
className={classNames('rt-Button', className)}
|
|
179
|
+
style={overrideVars ? { ...overrideVars, ...(props as any).style } : (props as any).style}
|
|
103
180
|
/>
|
|
104
181
|
);
|
|
105
182
|
|
|
@@ -128,4 +205,4 @@ const Button = React.forwardRef(
|
|
|
128
205
|
Button.displayName = 'Button';
|
|
129
206
|
|
|
130
207
|
export { Button };
|
|
131
|
-
export type { ButtonProps };
|
|
208
|
+
export type { ButtonProps, ButtonOverrideStyles, ButtonOverrideStateStyles };
|
|
@@ -253,11 +253,14 @@ const Root = React.forwardRef<RootElement, RootProps>((props, forwardedRef) => {
|
|
|
253
253
|
const textareaRef = React.useRef<HTMLTextAreaElement>(null);
|
|
254
254
|
|
|
255
255
|
// Attachments state
|
|
256
|
-
|
|
256
|
+
// Treat `attachments` as controlled if the prop is provided, even if its value is `undefined`.
|
|
257
|
+
// This avoids switching between controlled and uncontrolled when a consumer sets
|
|
258
|
+
// `attachments={undefined}` to clear attachments. In that case we normalize to an empty array.
|
|
259
|
+
const isAttachmentsControlled = 'attachments' in props;
|
|
257
260
|
const [attachmentsUncontrolled, setAttachmentsUncontrolled] =
|
|
258
261
|
React.useState<ChatbarAttachment[]>(defaultAttachments);
|
|
259
262
|
const attachments = isAttachmentsControlled
|
|
260
|
-
? (attachmentsProp as ChatbarAttachment[])
|
|
263
|
+
? ((attachmentsProp ?? []) as ChatbarAttachment[])
|
|
261
264
|
: attachmentsUncontrolled;
|
|
262
265
|
|
|
263
266
|
// Track generated object URLs for cleanup
|
|
@@ -5,7 +5,7 @@ import { gridPropDefs } from './grid.props.js';
|
|
|
5
5
|
|
|
6
6
|
import type { PropDef } from '../props/prop-def.js';
|
|
7
7
|
|
|
8
|
-
const sizes = ['1', '2', '3', '4', '5'] as const;
|
|
8
|
+
const sizes = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'] as const;
|
|
9
9
|
const variants = ['outline', 'classic', 'ghost', 'soft', 'surface'] as const;
|
|
10
10
|
const panelBackgrounds = ['solid', 'translucent'] as const;
|
|
11
11
|
|
|
@@ -47,7 +47,7 @@ const CheckboxGroupRoot = React.forwardRef<CheckboxGroupRootElement, CheckboxGro
|
|
|
47
47
|
variant = checkboxGroupRootPropDefs.variant.default,
|
|
48
48
|
...props
|
|
49
49
|
}: ScopedProps<CheckboxGroupRootProps>,
|
|
50
|
-
forwardedRef
|
|
50
|
+
forwardedRef,
|
|
51
51
|
) => {
|
|
52
52
|
const { __scopeCheckboxGroup, className, ...rootProps } = extractProps(props, marginPropDefs);
|
|
53
53
|
const checkboxGroupScope = useCheckboxGroupScope(__scopeCheckboxGroup);
|
|
@@ -67,7 +67,7 @@ const CheckboxGroupRoot = React.forwardRef<CheckboxGroupRootElement, CheckboxGro
|
|
|
67
67
|
/>
|
|
68
68
|
</CheckboxGroupProvider>
|
|
69
69
|
);
|
|
70
|
-
}
|
|
70
|
+
},
|
|
71
71
|
);
|
|
72
72
|
CheckboxGroupRoot.displayName = 'CheckboxGroup.Root';
|
|
73
73
|
|
|
@@ -80,13 +80,21 @@ const CheckboxGroupItem = React.forwardRef<CheckboxGroupItemElement, CheckboxGro
|
|
|
80
80
|
const { __scopeCheckboxGroup, children, className, style, ...props } = _props;
|
|
81
81
|
const { size } = useCheckboxGroupContext('CheckboxGroupItem', __scopeCheckboxGroup);
|
|
82
82
|
|
|
83
|
+
// Helper to safely convert size to Text-compatible size
|
|
84
|
+
const getTextSize = (sizeValue: any): '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => {
|
|
85
|
+
if (typeof sizeValue === 'string' && /^[1-9]$/.test(sizeValue)) {
|
|
86
|
+
return sizeValue as any;
|
|
87
|
+
}
|
|
88
|
+
return '3';
|
|
89
|
+
};
|
|
90
|
+
|
|
83
91
|
// Render `<Text as="label">` if children are provided, otherwise render
|
|
84
92
|
// the solo checkbox to allow building out your custom layouts with it.
|
|
85
93
|
if (children) {
|
|
86
94
|
return (
|
|
87
95
|
<Text
|
|
88
96
|
as="label"
|
|
89
|
-
size={size}
|
|
97
|
+
size={getTextSize(size)}
|
|
90
98
|
className={classNames('rt-CheckboxGroupItem', className)}
|
|
91
99
|
style={style}
|
|
92
100
|
>
|
|
@@ -109,7 +117,7 @@ const CheckboxGroupItem = React.forwardRef<CheckboxGroupItemElement, CheckboxGro
|
|
|
109
117
|
style={style}
|
|
110
118
|
/>
|
|
111
119
|
);
|
|
112
|
-
}
|
|
120
|
+
},
|
|
113
121
|
);
|
|
114
122
|
CheckboxGroupItem.displayName = 'CheckboxGroup.Item';
|
|
115
123
|
|
|
@@ -125,7 +133,7 @@ const CheckboxGroupItemCheckbox = React.forwardRef<
|
|
|
125
133
|
const { color, className } = extractProps(
|
|
126
134
|
{ ...props, ...context },
|
|
127
135
|
checkboxGroupRootPropDefs,
|
|
128
|
-
marginPropDefs
|
|
136
|
+
marginPropDefs,
|
|
129
137
|
);
|
|
130
138
|
return (
|
|
131
139
|
<CheckboxGroupPrimitive.Item
|
|
@@ -137,7 +145,7 @@ const CheckboxGroupItemCheckbox = React.forwardRef<
|
|
|
137
145
|
'rt-reset',
|
|
138
146
|
'rt-BaseCheckboxRoot',
|
|
139
147
|
'rt-CheckboxGroupItemCheckbox',
|
|
140
|
-
className
|
|
148
|
+
className,
|
|
141
149
|
)}
|
|
142
150
|
>
|
|
143
151
|
<CheckboxGroupPrimitive.Indicator
|
|
@@ -8,6 +8,7 @@ import { Text } from './text.js';
|
|
|
8
8
|
import { Theme } from './theme.js';
|
|
9
9
|
import { extractProps } from '../helpers/extract-props.js';
|
|
10
10
|
import { requireReactElement } from '../helpers/require-react-element.js';
|
|
11
|
+
import { useBodyPointerEventsCleanup } from '../hooks/use-body-pointer-events-cleanup.js';
|
|
11
12
|
|
|
12
13
|
import type { DialogContentOwnProps } from './dialog.props.js';
|
|
13
14
|
import type {
|
|
@@ -93,6 +94,9 @@ const DialogContent = React.forwardRef<DialogContentElement, DialogContentProps>
|
|
|
93
94
|
[forwardedRef],
|
|
94
95
|
);
|
|
95
96
|
|
|
97
|
+
// Cleanup stuck pointer-events on body
|
|
98
|
+
useBodyPointerEventsCleanup();
|
|
99
|
+
|
|
96
100
|
// Focus trap effect
|
|
97
101
|
React.useEffect(() => {
|
|
98
102
|
// SSR safety - only run on client
|
|
@@ -5,7 +5,7 @@ import { gridPropDefs } from './grid.props.js';
|
|
|
5
5
|
|
|
6
6
|
import type { PropDef } from '../props/prop-def.js';
|
|
7
7
|
|
|
8
|
-
const sizes = ['1', '2', '3', '4', '5'] as const;
|
|
8
|
+
const sizes = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'] as const;
|
|
9
9
|
const variants = ['outline', 'classic', 'ghost', 'soft', 'surface'] as const;
|
|
10
10
|
const panelBackgrounds = ['solid', 'translucent'] as const;
|
|
11
11
|
|
|
@@ -116,6 +116,15 @@
|
|
|
116
116
|
&:where([data-disabled]) {
|
|
117
117
|
cursor: default;
|
|
118
118
|
}
|
|
119
|
+
|
|
120
|
+
/* Allow rich content to expand height */
|
|
121
|
+
&:where(.rt-SelectItemRich) {
|
|
122
|
+
height: auto;
|
|
123
|
+
min-height: var(--select-item-height);
|
|
124
|
+
align-items: flex-start;
|
|
125
|
+
padding-top: var(--space-2);
|
|
126
|
+
padding-bottom: var(--space-2);
|
|
127
|
+
}
|
|
119
128
|
}
|
|
120
129
|
|
|
121
130
|
.rt-SelectItemIndicator {
|
|
@@ -189,12 +189,22 @@ interface SelectItemProps
|
|
|
189
189
|
extends ComponentPropsWithout<typeof SelectPrimitive.Item, RemovedProps> {}
|
|
190
190
|
const SelectItem = React.forwardRef<SelectItemElement, SelectItemProps>((props, forwardedRef) => {
|
|
191
191
|
const { className, children, ...itemProps } = props;
|
|
192
|
+
|
|
193
|
+
// Detect if this is rich content (not just a string)
|
|
194
|
+
const isRichContent = typeof children !== 'string';
|
|
195
|
+
|
|
192
196
|
return (
|
|
193
197
|
<SelectPrimitive.Item
|
|
194
198
|
{...itemProps}
|
|
195
199
|
asChild={false}
|
|
196
200
|
ref={forwardedRef}
|
|
197
|
-
className={classNames(
|
|
201
|
+
className={classNames(
|
|
202
|
+
'rt-reset',
|
|
203
|
+
'rt-BaseMenuItem',
|
|
204
|
+
'rt-SelectItem',
|
|
205
|
+
{ 'rt-SelectItemRich': isRichContent },
|
|
206
|
+
className,
|
|
207
|
+
)}
|
|
198
208
|
>
|
|
199
209
|
<SelectPrimitive.ItemIndicator className="rt-SelectItemIndicator">
|
|
200
210
|
<ThickCheckIcon className="rt-SelectItemIndicatorIcon" />
|
package/src/components/shell.tsx
CHANGED
|
@@ -34,6 +34,9 @@ import { ChevronDownIcon } from './icons.js';
|
|
|
34
34
|
import { inert } from '../helpers/inert.js';
|
|
35
35
|
import * as Sheet from './sheet.js';
|
|
36
36
|
import { VisuallyHidden } from './visually-hidden.js';
|
|
37
|
+
import { ShellSidebarSectionContext } from './sidebar.js';
|
|
38
|
+
|
|
39
|
+
import type { ShellSidebarSectionContextValue } from './sidebar.js';
|
|
37
40
|
|
|
38
41
|
/** Logical document direction. Derived from document root unless `rtl` is passed. */
|
|
39
42
|
type ShellDirection = 'ltr' | 'rtl';
|
|
@@ -508,7 +511,21 @@ const Rail = Object.assign(
|
|
|
508
511
|
[shell, side],
|
|
509
512
|
);
|
|
510
513
|
|
|
511
|
-
|
|
514
|
+
const sidebarSectionContext = React.useMemo<ShellSidebarSectionContextValue>(
|
|
515
|
+
() => ({
|
|
516
|
+
side,
|
|
517
|
+
section: 'rail',
|
|
518
|
+
}),
|
|
519
|
+
[side],
|
|
520
|
+
);
|
|
521
|
+
|
|
522
|
+
return (
|
|
523
|
+
<RailContext.Provider value={railContext}>
|
|
524
|
+
<ShellSidebarSectionContext.Provider value={sidebarSectionContext}>
|
|
525
|
+
{children}
|
|
526
|
+
</ShellSidebarSectionContext.Provider>
|
|
527
|
+
</RailContext.Provider>
|
|
528
|
+
);
|
|
512
529
|
}),
|
|
513
530
|
{ displayName: 'Shell.Sidebar.Rail', __shellSlot: 'rail' as const },
|
|
514
531
|
);
|
|
@@ -530,7 +547,21 @@ const Panel = Object.assign(
|
|
|
530
547
|
[shell.activeToolBySide, shell.activeContextBySide, side],
|
|
531
548
|
);
|
|
532
549
|
|
|
533
|
-
|
|
550
|
+
const sidebarSectionContext = React.useMemo<ShellSidebarSectionContextValue>(
|
|
551
|
+
() => ({
|
|
552
|
+
side,
|
|
553
|
+
section: 'panel',
|
|
554
|
+
}),
|
|
555
|
+
[side],
|
|
556
|
+
);
|
|
557
|
+
|
|
558
|
+
return (
|
|
559
|
+
<PanelContext.Provider value={panelContext}>
|
|
560
|
+
<ShellSidebarSectionContext.Provider value={sidebarSectionContext}>
|
|
561
|
+
{children}
|
|
562
|
+
</ShellSidebarSectionContext.Provider>
|
|
563
|
+
</PanelContext.Provider>
|
|
564
|
+
);
|
|
534
565
|
}),
|
|
535
566
|
{ displayName: 'Shell.Sidebar.Panel', __shellSlot: 'panel' as const },
|
|
536
567
|
);
|
|
@@ -935,7 +966,7 @@ const Trigger = React.forwardRef<React.ElementRef<typeof IconButton>, GlobalTrig
|
|
|
935
966
|
<IconButton
|
|
936
967
|
{...props}
|
|
937
968
|
ref={ref}
|
|
938
|
-
variant="
|
|
969
|
+
variant="ghost"
|
|
939
970
|
aria-controls={controlsId}
|
|
940
971
|
aria-expanded={expanded}
|
|
941
972
|
onClick={(e) => {
|
|
@@ -3,15 +3,20 @@
|
|
|
3
3
|
@import './_internal/base-sidebar-menu.css';
|
|
4
4
|
|
|
5
5
|
/*
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
6
|
+
Layout-specific presentation
|
|
7
|
+
- Rail layout: compact, icon-focused
|
|
8
|
+
- Panel layout: full-width with text labels
|
|
9
|
+
- Context-aware: works with Shell.Sidebar or standalone
|
|
9
10
|
*/
|
|
11
|
+
|
|
12
|
+
/* Rail Layout Styling */
|
|
13
|
+
:where(.rt-SidebarContainer.rt-layout-rail .rt-SidebarContent),
|
|
10
14
|
.rt-ShellSidebarRail :where(.rt-SidebarContent),
|
|
11
15
|
:where(.rt-ShellSidebar[data-state='rail'] .rt-SidebarContent) {
|
|
12
16
|
padding: var(--space-2);
|
|
13
17
|
}
|
|
14
18
|
|
|
19
|
+
:where(.rt-SidebarContainer.rt-layout-rail .rt-SidebarMenuButton),
|
|
15
20
|
.rt-ShellSidebarRail :where(.rt-SidebarMenuButton),
|
|
16
21
|
:where(.rt-ShellSidebar[data-state='rail'] .rt-SidebarMenuButton) {
|
|
17
22
|
justify-content: center;
|
|
@@ -21,6 +26,8 @@
|
|
|
21
26
|
padding: var(--space-2) var(--space-1);
|
|
22
27
|
}
|
|
23
28
|
|
|
29
|
+
:where(.rt-SidebarContainer.rt-layout-rail .rt-SidebarMenuBadge),
|
|
30
|
+
:where(.rt-SidebarContainer.rt-layout-rail .rt-SidebarMenuShortcut),
|
|
24
31
|
.rt-ShellSidebarRail :where(.rt-SidebarMenuBadge),
|
|
25
32
|
.rt-ShellSidebarRail :where(.rt-SidebarMenuShortcut),
|
|
26
33
|
:where(.rt-ShellSidebar[data-state='rail'] .rt-SidebarMenuBadge),
|
|
@@ -28,6 +35,7 @@
|
|
|
28
35
|
display: none;
|
|
29
36
|
}
|
|
30
37
|
|
|
38
|
+
:where(.rt-SidebarContainer.rt-layout-rail .rt-SidebarGroupLabel),
|
|
31
39
|
.rt-ShellSidebarRail :where(.rt-SidebarGroupLabel),
|
|
32
40
|
:where(.rt-ShellSidebar[data-state='rail'] .rt-SidebarGroupLabel) {
|
|
33
41
|
display: block;
|
|
@@ -39,11 +47,13 @@
|
|
|
39
47
|
}
|
|
40
48
|
|
|
41
49
|
/* Hide submenu chevrons and flatten sublists in rail */
|
|
50
|
+
:where(.rt-SidebarContainer.rt-layout-rail .rt-SidebarMenuSubTriggerIcon),
|
|
42
51
|
.rt-ShellSidebarRail :where(.rt-SidebarMenuSubTriggerIcon),
|
|
43
52
|
:where(.rt-ShellSidebar[data-state='rail'] .rt-SidebarMenuSubTriggerIcon) {
|
|
44
53
|
display: none;
|
|
45
54
|
}
|
|
46
55
|
|
|
56
|
+
:where(.rt-SidebarContainer.rt-layout-rail .rt-SidebarMenuSubList),
|
|
47
57
|
.rt-ShellSidebarRail :where(.rt-SidebarMenuSubList),
|
|
48
58
|
:where(.rt-ShellSidebar[data-state='rail'] .rt-SidebarMenuSubList) {
|
|
49
59
|
padding-left: 0;
|
|
@@ -51,6 +61,8 @@
|
|
|
51
61
|
margin-left: 0;
|
|
52
62
|
}
|
|
53
63
|
|
|
64
|
+
/* Panel Layout Styling (default) - inherits existing styles */
|
|
65
|
+
|
|
54
66
|
/* Note: label styling omitted to avoid type-selector-specificity; use Text component for fine control */
|
|
55
67
|
|
|
56
68
|
/* Container Variants */
|
|
@@ -19,6 +19,7 @@ const menuVariants = ['solid', 'soft'] as const;
|
|
|
19
19
|
const types = ['sidebar', 'floating'] as const;
|
|
20
20
|
const sides = ['left', 'right'] as const;
|
|
21
21
|
const collapsibleModes = ['offcanvas', 'icon', 'none'] as const;
|
|
22
|
+
const layouts = ['rail', 'panel'] as const;
|
|
22
23
|
|
|
23
24
|
const sidebarPropDefs = {
|
|
24
25
|
...asChildPropDef,
|
|
@@ -38,6 +39,7 @@ const sidebarPropDefs = {
|
|
|
38
39
|
values: collapsibleModes,
|
|
39
40
|
default: 'offcanvas',
|
|
40
41
|
},
|
|
42
|
+
layout: { type: 'enum', className: 'rt-layout', values: layouts, default: undefined },
|
|
41
43
|
panelBackground: { type: 'enum', values: ['solid', 'translucent'], default: undefined },
|
|
42
44
|
...colorPropDef,
|
|
43
45
|
...highContrastPropDef,
|
|
@@ -48,6 +50,7 @@ const sidebarPropDefs = {
|
|
|
48
50
|
type: PropDef<(typeof types)[number]>;
|
|
49
51
|
side: PropDef<(typeof sides)[number]>;
|
|
50
52
|
collapsible: PropDef<(typeof collapsibleModes)[number]>;
|
|
53
|
+
layout: PropDef<(typeof layouts)[number]>;
|
|
51
54
|
panelBackground: PropDef<'solid' | 'translucent'>;
|
|
52
55
|
};
|
|
53
56
|
|
|
@@ -39,6 +39,22 @@ function useSidebarVisual() {
|
|
|
39
39
|
return React.useContext(SidebarVisualContext);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
// Context detection for Shell.Sidebar integration
|
|
43
|
+
type ShellSidebarSectionContextValue = {
|
|
44
|
+
side: 'start' | 'end';
|
|
45
|
+
section: 'rail' | 'panel';
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// Create a context that Shell.Sidebar can provide
|
|
49
|
+
const ShellSidebarSectionContext = React.createContext<ShellSidebarSectionContextValue | null>(
|
|
50
|
+
null,
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
// This context comes from Shell.Sidebar when Sidebar is used within Shell
|
|
54
|
+
function useShellSidebarSection(): ShellSidebarSectionContextValue | null {
|
|
55
|
+
return React.useContext(ShellSidebarSectionContext);
|
|
56
|
+
}
|
|
57
|
+
|
|
42
58
|
// Main Sidebar component
|
|
43
59
|
type SidebarOwnProps = GetPropDefTypes<typeof sidebarPropDefs>;
|
|
44
60
|
interface SidebarProps extends ComponentPropsWithout<'div', RemovedProps>, SidebarOwnProps {}
|
|
@@ -50,6 +66,7 @@ const Sidebar = React.forwardRef<HTMLDivElement, SidebarProps>((props, forwarded
|
|
|
50
66
|
size = sidebarPropDefs.size.default,
|
|
51
67
|
variant = sidebarPropDefs.variant.default,
|
|
52
68
|
menuVariant = sidebarPropDefs.menuVariant.default,
|
|
69
|
+
layout = sidebarPropDefs.layout.default,
|
|
53
70
|
// type = sidebarPropDefs.type.default,
|
|
54
71
|
// side = sidebarPropDefs.side.default,
|
|
55
72
|
// collapsible = sidebarPropDefs.collapsible.default,
|
|
@@ -62,6 +79,10 @@ const Sidebar = React.forwardRef<HTMLDivElement, SidebarProps>((props, forwarded
|
|
|
62
79
|
const { asChild: _, panelBackground: __, ...safeRootProps } = rootProps; // Remove asChild and panelBackground from DOM props
|
|
63
80
|
const resolvedColor = color || themeContext.accentColor;
|
|
64
81
|
|
|
82
|
+
// Detect Shell.Sidebar context to auto-resolve layout
|
|
83
|
+
const shellSection = useShellSidebarSection();
|
|
84
|
+
const resolvedLayout = layout || shellSection?.section || 'panel'; // Default to 'panel' if no context
|
|
85
|
+
|
|
65
86
|
// Update context with current props - we'll pass the resolved values
|
|
66
87
|
const resolvedSize = typeof size === 'object' ? size.initial || '2' : size;
|
|
67
88
|
return (
|
|
@@ -78,10 +99,12 @@ const Sidebar = React.forwardRef<HTMLDivElement, SidebarProps>((props, forwarded
|
|
|
78
99
|
`rt-variant-${variant}`,
|
|
79
100
|
`rt-r-size-${resolvedSize}`,
|
|
80
101
|
`rt-menu-variant-${menuVariant}`,
|
|
102
|
+
resolvedLayout && `rt-layout-${resolvedLayout}`,
|
|
81
103
|
)}
|
|
82
104
|
data-accent-color={resolvedColor}
|
|
83
105
|
data-high-contrast={highContrast || undefined}
|
|
84
106
|
data-panel-background={panelBackground}
|
|
107
|
+
data-layout={resolvedLayout}
|
|
85
108
|
>
|
|
86
109
|
{children}
|
|
87
110
|
</div>
|
|
@@ -592,4 +615,8 @@ export type {
|
|
|
592
615
|
SidebarHeaderProps as HeaderProps,
|
|
593
616
|
SidebarFooterProps as FooterProps,
|
|
594
617
|
BadgeConfig,
|
|
618
|
+
ShellSidebarSectionContextValue,
|
|
595
619
|
};
|
|
620
|
+
|
|
621
|
+
// Export context for Shell.Sidebar integration
|
|
622
|
+
export { ShellSidebarSectionContext };
|
package/src/hooks/index.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export { useLiveAnnouncer } from './use-live-announcer.js';
|
|
1
|
+
export { useLiveAnnouncer } from './use-live-announcer.js';
|
|
2
|
+
export { useBodyPointerEventsCleanup } from './use-body-pointer-events-cleanup.js';
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
let bodyCleanupInstalled = false;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Hook to cleanup stuck pointer-events: none on document.body
|
|
7
|
+
*
|
|
8
|
+
* This addresses an issue where react-remove-scroll (used by Radix UI Dialog)
|
|
9
|
+
* sometimes fails to restore body pointer-events after dialog closes,
|
|
10
|
+
* leaving the page unclickable.
|
|
11
|
+
*/
|
|
12
|
+
export function useBodyPointerEventsCleanup() {
|
|
13
|
+
React.useEffect(() => {
|
|
14
|
+
if (typeof document === 'undefined') return;
|
|
15
|
+
|
|
16
|
+
let timeoutId: number | undefined;
|
|
17
|
+
|
|
18
|
+
const hasOpenModal = (): boolean => {
|
|
19
|
+
// Detect any open modal dialogs/alertdialogs
|
|
20
|
+
return Boolean(
|
|
21
|
+
document.querySelector(
|
|
22
|
+
'[role="dialog"][aria-modal="true"], [role="alertdialog"][aria-modal="true"]',
|
|
23
|
+
),
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const cleanup = () => {
|
|
28
|
+
if (document.body.style.pointerEvents === 'none' && !hasOpenModal()) {
|
|
29
|
+
document.body.style.pointerEvents = '';
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const scheduleCleanup = (delay = 50) => {
|
|
34
|
+
if (timeoutId) window.clearTimeout(timeoutId);
|
|
35
|
+
timeoutId = window.setTimeout(cleanup, delay);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// Initial run to catch already-stuck state
|
|
39
|
+
scheduleCleanup(100);
|
|
40
|
+
|
|
41
|
+
// If already installed globally, don't re-register listeners/observers
|
|
42
|
+
if (bodyCleanupInstalled) {
|
|
43
|
+
return () => {
|
|
44
|
+
if (timeoutId) window.clearTimeout(timeoutId);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
bodyCleanupInstalled = true;
|
|
49
|
+
|
|
50
|
+
const onPointer = () => scheduleCleanup(50);
|
|
51
|
+
const onKey = (event: KeyboardEvent) => {
|
|
52
|
+
if (event.key === 'Escape' || event.key === 'Enter' || event.key === ' ') scheduleCleanup(50);
|
|
53
|
+
};
|
|
54
|
+
const onVisibility = () => {
|
|
55
|
+
if (!document.hidden) scheduleCleanup(50);
|
|
56
|
+
};
|
|
57
|
+
const onTransitionEnd = () => scheduleCleanup(0);
|
|
58
|
+
const onAnimationEnd = () => scheduleCleanup(0);
|
|
59
|
+
|
|
60
|
+
// Listen for common interactions that close overlays/menus
|
|
61
|
+
document.addEventListener('pointerup', onPointer, true);
|
|
62
|
+
document.addEventListener('click', onPointer, true);
|
|
63
|
+
document.addEventListener('keydown', onKey, true);
|
|
64
|
+
document.addEventListener('keyup', onKey, true);
|
|
65
|
+
document.addEventListener('visibilitychange', onVisibility);
|
|
66
|
+
document.addEventListener('transitionend', onTransitionEnd, true);
|
|
67
|
+
document.addEventListener('animationend', onAnimationEnd, true);
|
|
68
|
+
|
|
69
|
+
// Observe body style changes (where pointer-events is applied) and DOM mutations
|
|
70
|
+
const bodyObserver = new MutationObserver(() => scheduleCleanup(0));
|
|
71
|
+
bodyObserver.observe(document.body, { attributes: true, attributeFilter: ['style'] });
|
|
72
|
+
|
|
73
|
+
const domObserver = new MutationObserver(() => scheduleCleanup(0));
|
|
74
|
+
domObserver.observe(document, { childList: true, subtree: true });
|
|
75
|
+
|
|
76
|
+
// Keep listeners/observers for the app lifetime to ensure cleanup even after overlays unmount
|
|
77
|
+
return () => {
|
|
78
|
+
if (timeoutId) window.clearTimeout(timeoutId);
|
|
79
|
+
};
|
|
80
|
+
}, []);
|
|
81
|
+
}
|
package/src/props/gap.props.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { PropDef, GetPropDefTypes } from './prop-def.js';
|
|
2
2
|
|
|
3
3
|
// prettier-ignore
|
|
4
|
-
const marginValues = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-1', '-2', '-3', '-4', '-5', '-6', '-7', '-8', '-9'] as const;
|
|
4
|
+
const marginValues = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '-1', '-2', '-3', '-4', '-5', '-6', '-7', '-8', '-9', '-10', '-11', '-12'] as const;
|
|
5
5
|
|
|
6
6
|
const marginPropDefs = {
|
|
7
7
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { GetPropDefTypes, PropDef } from './prop-def.js';
|
|
2
2
|
|
|
3
|
-
const paddingValues = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] as const;
|
|
3
|
+
const paddingValues = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'] as const;
|
|
4
4
|
|
|
5
5
|
const paddingPropDefs = {
|
|
6
6
|
/**
|
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
--blur-7: calc(28px * var(--scaling) * var(--blur-factor));
|
|
10
10
|
--blur-8: calc(36px * var(--scaling) * var(--blur-factor));
|
|
11
11
|
--blur-9: calc(44px * var(--scaling) * var(--blur-factor));
|
|
12
|
+
--blur-10: calc(52px * var(--scaling) * var(--blur-factor));
|
|
13
|
+
--blur-11: calc(60px * var(--scaling) * var(--blur-factor));
|
|
14
|
+
--blur-12: calc(68px * var(--scaling) * var(--blur-factor));
|
|
12
15
|
}
|
|
13
16
|
|
|
14
17
|
[data-blur='none'] {
|