@kushagradhawan/kookie-ui 0.1.32 → 0.1.34
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 +937 -458
- package/dist/cjs/components/_internal/base-button.d.ts.map +1 -1
- package/dist/cjs/components/_internal/base-button.js +1 -1
- package/dist/cjs/components/_internal/base-button.js.map +3 -3
- package/dist/cjs/components/chatbar.d.ts +202 -0
- package/dist/cjs/components/chatbar.d.ts.map +1 -0
- package/dist/cjs/components/chatbar.js +2 -0
- package/dist/cjs/components/chatbar.js.map +7 -0
- package/dist/cjs/components/icon-button.d.ts.map +1 -1
- package/dist/cjs/components/icon-button.js +2 -2
- package/dist/cjs/components/icon-button.js.map +3 -3
- package/dist/cjs/components/icons.d.ts +6 -1
- package/dist/cjs/components/icons.d.ts.map +1 -1
- package/dist/cjs/components/icons.js +1 -1
- package/dist/cjs/components/icons.js.map +3 -3
- package/dist/cjs/components/index.d.ts +3 -0
- package/dist/cjs/components/index.d.ts.map +1 -1
- package/dist/cjs/components/index.js +1 -1
- package/dist/cjs/components/index.js.map +3 -3
- package/dist/cjs/components/popover.d.ts +13 -1
- package/dist/cjs/components/popover.d.ts.map +1 -1
- package/dist/cjs/components/popover.js +1 -1
- package/dist/cjs/components/popover.js.map +3 -3
- package/dist/cjs/components/sheet.d.ts +82 -0
- package/dist/cjs/components/sheet.d.ts.map +1 -0
- package/dist/cjs/components/sheet.js +2 -0
- package/dist/cjs/components/sheet.js.map +7 -0
- package/dist/cjs/components/shell.d.ts +180 -0
- package/dist/cjs/components/shell.d.ts.map +1 -0
- package/dist/cjs/components/shell.js +2 -0
- package/dist/cjs/components/shell.js.map +7 -0
- package/dist/cjs/components/sidebar.d.ts +4 -33
- 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/skeleton.d.ts.map +1 -1
- package/dist/cjs/components/skeleton.js +1 -1
- package/dist/cjs/components/skeleton.js.map +2 -2
- package/dist/cjs/helpers/inert.d.ts +1 -1
- package/dist/cjs/helpers/inert.d.ts.map +1 -1
- package/dist/cjs/helpers/inert.js +1 -1
- package/dist/cjs/helpers/inert.js.map +2 -2
- package/dist/esm/components/_internal/base-button.d.ts.map +1 -1
- package/dist/esm/components/_internal/base-button.js +1 -1
- package/dist/esm/components/_internal/base-button.js.map +3 -3
- package/dist/esm/components/chatbar.d.ts +202 -0
- package/dist/esm/components/chatbar.d.ts.map +1 -0
- package/dist/esm/components/chatbar.js +2 -0
- package/dist/esm/components/chatbar.js.map +7 -0
- package/dist/esm/components/icon-button.d.ts.map +1 -1
- package/dist/esm/components/icon-button.js +2 -2
- package/dist/esm/components/icon-button.js.map +3 -3
- package/dist/esm/components/icons.d.ts +6 -1
- package/dist/esm/components/icons.d.ts.map +1 -1
- package/dist/esm/components/icons.js +1 -1
- package/dist/esm/components/icons.js.map +3 -3
- package/dist/esm/components/index.d.ts +3 -0
- package/dist/esm/components/index.d.ts.map +1 -1
- package/dist/esm/components/index.js +1 -1
- package/dist/esm/components/index.js.map +3 -3
- package/dist/esm/components/popover.d.ts +13 -1
- package/dist/esm/components/popover.d.ts.map +1 -1
- package/dist/esm/components/popover.js +1 -1
- package/dist/esm/components/popover.js.map +3 -3
- package/dist/esm/components/sheet.d.ts +82 -0
- package/dist/esm/components/sheet.d.ts.map +1 -0
- package/dist/esm/components/sheet.js +2 -0
- package/dist/esm/components/sheet.js.map +7 -0
- package/dist/esm/components/shell.d.ts +180 -0
- package/dist/esm/components/shell.d.ts.map +1 -0
- package/dist/esm/components/shell.js +2 -0
- package/dist/esm/components/shell.js.map +7 -0
- package/dist/esm/components/sidebar.d.ts +4 -33
- 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/skeleton.d.ts.map +1 -1
- package/dist/esm/components/skeleton.js.map +2 -2
- package/dist/esm/helpers/inert.d.ts +1 -1
- package/dist/esm/helpers/inert.d.ts.map +1 -1
- package/dist/esm/helpers/inert.js +1 -1
- package/dist/esm/helpers/inert.js.map +2 -2
- package/package.json +2 -1
- package/src/components/_internal/base-button.tsx +8 -0
- package/src/components/_internal/base-card.css +18 -18
- package/src/components/_internal/base-dialog.css +11 -49
- package/src/components/_internal/base-menu.css +2 -2
- package/src/components/_internal/base-sidebar-menu.css +3 -3
- package/src/components/accordion.css +6 -6
- package/src/components/animations.css +65 -81
- package/src/components/callout.css +3 -3
- package/src/components/chatbar.css +214 -0
- package/src/components/chatbar.tsx +1181 -0
- package/src/components/icon-button.tsx +11 -0
- package/src/components/icons.tsx +97 -2
- package/src/components/image.css +3 -3
- package/src/components/index.css +3 -0
- package/src/components/index.tsx +3 -0
- package/src/components/popover.css +53 -8
- package/src/components/popover.tsx +180 -2
- package/src/components/scroll-area.css +3 -3
- package/src/components/segmented-control.css +3 -3
- package/src/components/sheet.css +90 -0
- package/src/components/sheet.tsx +247 -0
- package/src/components/shell.css +137 -0
- package/src/components/shell.tsx +1032 -0
- package/src/components/sidebar.css +55 -268
- package/src/components/sidebar.tsx +40 -262
- package/src/components/skeleton.tsx +1 -2
- package/src/components/text-area.css +6 -5
- package/src/components/tooltip.css +2 -2
- package/src/helpers/inert.ts +3 -3
- package/src/styles/tokens/constants.css +6 -3
- package/src/styles/tokens/index.css +1 -0
- package/src/styles/tokens/radius.css +7 -2
- package/src/styles/tokens/space.css +6 -0
- package/src/styles/tokens/transition.css +91 -46
- package/styles.css +998 -496
- package/tokens/base.css +57 -35
- package/tokens.css +61 -38
|
@@ -114,6 +114,8 @@ const IconButton = React.forwardRef(
|
|
|
114
114
|
}: IconButtonProps,
|
|
115
115
|
forwardedRef: React.ForwardedRef<IconButtonElement>,
|
|
116
116
|
) => {
|
|
117
|
+
// Generate unique ID for tooltip accessibility
|
|
118
|
+
const tooltipId = React.useId();
|
|
117
119
|
// Runtime accessibility validation to ensure WCAG compliance
|
|
118
120
|
// This helps catch accessibility issues during development
|
|
119
121
|
const hasAriaLabel = 'aria-label' in props && props['aria-label'];
|
|
@@ -130,10 +132,18 @@ const IconButton = React.forwardRef(
|
|
|
130
132
|
);
|
|
131
133
|
}
|
|
132
134
|
|
|
135
|
+
// Prepare accessibility props for tooltip integration
|
|
136
|
+
const hasTooltip = Boolean(tooltip);
|
|
137
|
+
const tooltipAccessibilityProps = React.useMemo(
|
|
138
|
+
() => (hasTooltip ? { 'aria-describedby': tooltipId } : {}),
|
|
139
|
+
[hasTooltip, tooltipId],
|
|
140
|
+
);
|
|
141
|
+
|
|
133
142
|
// Create the base icon button element with accessibility props
|
|
134
143
|
const iconButton = (
|
|
135
144
|
<BaseButton
|
|
136
145
|
{...props}
|
|
146
|
+
{...tooltipAccessibilityProps}
|
|
137
147
|
ref={forwardedRef}
|
|
138
148
|
className={classNames('rt-IconButton', className)}
|
|
139
149
|
/>
|
|
@@ -153,6 +163,7 @@ const IconButton = React.forwardRef(
|
|
|
153
163
|
align={tooltipAlign}
|
|
154
164
|
delayDuration={tooltipDelayDuration}
|
|
155
165
|
disableHoverableContent={tooltipDisableHoverableContent}
|
|
166
|
+
id={tooltipId}
|
|
156
167
|
>
|
|
157
168
|
{iconButton}
|
|
158
169
|
</Tooltip>
|
package/src/components/icons.tsx
CHANGED
|
@@ -24,7 +24,7 @@ const ThickDividerHorizontalIcon = React.forwardRef<IconElement, IconProps>(
|
|
|
24
24
|
/>
|
|
25
25
|
</svg>
|
|
26
26
|
);
|
|
27
|
-
}
|
|
27
|
+
},
|
|
28
28
|
);
|
|
29
29
|
|
|
30
30
|
ThickDividerHorizontalIcon.displayName = 'ThickDividerHorizontalIcon';
|
|
@@ -105,5 +105,100 @@ const ThickDotIcon = React.forwardRef<IconElement, IconProps>((props, forwardedR
|
|
|
105
105
|
});
|
|
106
106
|
ThickDotIcon.displayName = 'ThickDotIcon';
|
|
107
107
|
|
|
108
|
-
export {
|
|
108
|
+
export {
|
|
109
|
+
ChevronDownIcon,
|
|
110
|
+
ThickCheckIcon,
|
|
111
|
+
ThickChevronRightIcon,
|
|
112
|
+
ThickDividerHorizontalIcon,
|
|
113
|
+
ThickDotIcon,
|
|
114
|
+
};
|
|
109
115
|
export type { IconProps };
|
|
116
|
+
|
|
117
|
+
// Additional minimal icons
|
|
118
|
+
const CloseIcon = React.forwardRef<IconElement, IconProps>((_props, _forwardedRef) => {
|
|
119
|
+
return (
|
|
120
|
+
<svg
|
|
121
|
+
{..._props}
|
|
122
|
+
ref={_forwardedRef}
|
|
123
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
124
|
+
width="24"
|
|
125
|
+
height="24"
|
|
126
|
+
viewBox="0 0 24 24"
|
|
127
|
+
fill="none"
|
|
128
|
+
stroke="currentColor"
|
|
129
|
+
strokeWidth="2"
|
|
130
|
+
strokeLinecap="round"
|
|
131
|
+
strokeLinejoin="round"
|
|
132
|
+
>
|
|
133
|
+
<path d="M18 6 6 18" />
|
|
134
|
+
<path d="m6 6 12 12" />
|
|
135
|
+
</svg>
|
|
136
|
+
);
|
|
137
|
+
});
|
|
138
|
+
CloseIcon.displayName = 'CloseIcon';
|
|
139
|
+
|
|
140
|
+
const PaperclipIcon = React.forwardRef<IconElement, IconProps>((props, forwardedRef) => {
|
|
141
|
+
return (
|
|
142
|
+
<svg
|
|
143
|
+
{...props}
|
|
144
|
+
ref={forwardedRef}
|
|
145
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
146
|
+
width="24"
|
|
147
|
+
height="24"
|
|
148
|
+
viewBox="0 0 24 24"
|
|
149
|
+
fill="none"
|
|
150
|
+
stroke="currentColor"
|
|
151
|
+
strokeWidth="2"
|
|
152
|
+
strokeLinecap="round"
|
|
153
|
+
strokeLinejoin="round"
|
|
154
|
+
>
|
|
155
|
+
<path d="m16 6-8.414 8.586a2 2 0 0 0 2.829 2.829l8.414-8.586a4 4 0 1 0-5.657-5.657l-8.379 8.551a6 6 0 1 0 8.485 8.485l8.379-8.551" />
|
|
156
|
+
</svg>
|
|
157
|
+
);
|
|
158
|
+
});
|
|
159
|
+
PaperclipIcon.displayName = 'PaperclipIcon';
|
|
160
|
+
|
|
161
|
+
const FileIcon = React.forwardRef<IconElement, IconProps>((props, forwardedRef) => {
|
|
162
|
+
return (
|
|
163
|
+
<svg
|
|
164
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
165
|
+
width="24"
|
|
166
|
+
height="24"
|
|
167
|
+
viewBox="0 0 24 24"
|
|
168
|
+
fill="none"
|
|
169
|
+
stroke="currentColor"
|
|
170
|
+
strokeWidth="2"
|
|
171
|
+
strokeLinecap="round"
|
|
172
|
+
strokeLinejoin="round"
|
|
173
|
+
>
|
|
174
|
+
<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" />
|
|
175
|
+
<path d="M14 2v4a2 2 0 0 0 2 2h4" />
|
|
176
|
+
</svg>
|
|
177
|
+
);
|
|
178
|
+
});
|
|
179
|
+
FileIcon.displayName = 'FileIcon';
|
|
180
|
+
|
|
181
|
+
const FileTextIcon = React.forwardRef<IconElement, IconProps>((_props, _forwardedRef) => {
|
|
182
|
+
return (
|
|
183
|
+
<svg
|
|
184
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
185
|
+
width="24"
|
|
186
|
+
height="24"
|
|
187
|
+
viewBox="0 0 24 24"
|
|
188
|
+
fill="none"
|
|
189
|
+
stroke="currentColor"
|
|
190
|
+
strokeWidth="2"
|
|
191
|
+
strokeLinecap="round"
|
|
192
|
+
strokeLinejoin="round"
|
|
193
|
+
>
|
|
194
|
+
<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" />
|
|
195
|
+
<path d="M14 2v4a2 2 0 0 0 2 2h4" />
|
|
196
|
+
<path d="M10 9H8" />
|
|
197
|
+
<path d="M16 13H8" />
|
|
198
|
+
<path d="M16 17H8" />
|
|
199
|
+
</svg>
|
|
200
|
+
);
|
|
201
|
+
});
|
|
202
|
+
FileTextIcon.displayName = 'FileTextIcon';
|
|
203
|
+
|
|
204
|
+
export { CloseIcon, PaperclipIcon, FileIcon, FileTextIcon };
|
package/src/components/image.css
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
.rt-Image {
|
|
26
26
|
display: block;
|
|
27
27
|
object-fit: var(--object-fit); /* Controlled by fit prop */
|
|
28
|
-
border-radius: var(--radius-
|
|
28
|
+
border-radius: var(--radius-2); /* Default radius, can be overridden */
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/*
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
*/
|
|
79
79
|
.rt-Image:where(:any-link, button, label) {
|
|
80
80
|
cursor: pointer;
|
|
81
|
-
transition: var(--transition-card), filter var(--duration-
|
|
81
|
+
transition: var(--transition-card), filter var(--motion-duration-small) var(--motion-ease-standard); /* Smooth transitions for interactive states */
|
|
82
82
|
|
|
83
83
|
/*
|
|
84
84
|
* Hover effects with progressive enhancement
|
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
*/
|
|
117
117
|
:where(:any-link, button, label) {
|
|
118
118
|
cursor: pointer;
|
|
119
|
-
transition: var(--transition-card), filter var(--duration-
|
|
119
|
+
transition: var(--transition-card), filter var(--motion-duration-small) var(--motion-ease-standard); /* Smooth transitions for interactive states */
|
|
120
120
|
|
|
121
121
|
/* Hover effects for wrapper elements */
|
|
122
122
|
@media (hover: hover) {
|
package/src/components/index.css
CHANGED
|
@@ -38,11 +38,13 @@
|
|
|
38
38
|
@import './radio-cards.css';
|
|
39
39
|
@import './radio-group.css';
|
|
40
40
|
@import './radio.css';
|
|
41
|
+
@import './sheet.css';
|
|
41
42
|
@import './scroll-area.css';
|
|
42
43
|
@import './segmented-control.css';
|
|
43
44
|
@import './select.css';
|
|
44
45
|
@import './separator.css';
|
|
45
46
|
@import './sidebar.css';
|
|
47
|
+
@import './shell.css';
|
|
46
48
|
@import './slider.css';
|
|
47
49
|
@import './spinner.css';
|
|
48
50
|
@import './strong.css';
|
|
@@ -55,6 +57,7 @@
|
|
|
55
57
|
@import './theme-panel.css';
|
|
56
58
|
@import './tooltip.css';
|
|
57
59
|
@import './user-card.css';
|
|
60
|
+
@import './chatbar.css';
|
|
58
61
|
|
|
59
62
|
.radix-themes:where([data-is-root-theme='true']) {
|
|
60
63
|
/* Create a new stacking context on the root `Theme` so layered components work out of the box */
|
package/src/components/index.tsx
CHANGED
|
@@ -68,3 +68,6 @@ export { Tooltip, type TooltipProps } from './tooltip.js';
|
|
|
68
68
|
export { UserCard, type UserCardProps } from './user-card.js';
|
|
69
69
|
export { VisuallyHidden, type VisuallyHiddenProps } from './visually-hidden.js';
|
|
70
70
|
export * as Sidebar from './sidebar.js';
|
|
71
|
+
export * as Shell from './shell.js';
|
|
72
|
+
export * as Sheet from './sheet.js';
|
|
73
|
+
export * as Chatbar from './chatbar.js';
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
--inset-padding-right: var(--popover-content-padding);
|
|
14
14
|
--inset-padding-bottom: var(--popover-content-padding);
|
|
15
15
|
--inset-padding-left: var(--popover-content-padding);
|
|
16
|
+
/* Default toolbar padding maps to content padding; overridden per size below */
|
|
17
|
+
--popover-toolbar-padding: var(--popover-content-padding);
|
|
16
18
|
padding: var(--popover-content-padding);
|
|
17
19
|
box-sizing: border-box;
|
|
18
20
|
|
|
@@ -33,6 +35,45 @@
|
|
|
33
35
|
background-color: var(--color-panel-translucent);
|
|
34
36
|
backdrop-filter: var(--backdrop-filter-panel);
|
|
35
37
|
}
|
|
38
|
+
|
|
39
|
+
/* Toolbar integration */
|
|
40
|
+
&:where([data-has-toolbar]) {
|
|
41
|
+
/* When toolbar is present, top padding equals toolbar height */
|
|
42
|
+
padding-top: var(--popover-toolbar-offset, var(--popover-content-padding));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.rt-PopoverToolbar {
|
|
47
|
+
position: absolute;
|
|
48
|
+
top: 0;
|
|
49
|
+
left: 0;
|
|
50
|
+
right: 0;
|
|
51
|
+
z-index: 1;
|
|
52
|
+
display: grid;
|
|
53
|
+
grid-template-columns: 1fr auto 1fr;
|
|
54
|
+
align-items: center;
|
|
55
|
+
column-gap: var(--space-1);
|
|
56
|
+
padding: var(--popover-toolbar-padding);
|
|
57
|
+
background-color: var(--color-panel);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.rt-PopoverToolbarSection {
|
|
61
|
+
display: flex;
|
|
62
|
+
align-items: center;
|
|
63
|
+
gap: var(--space-2);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.rt-PopoverToolbarLeft { justify-self: start; }
|
|
67
|
+
|
|
68
|
+
.rt-PopoverToolbarCenter { grid-column: 2; justify-self: center; min-width: 0; text-align: center; }
|
|
69
|
+
|
|
70
|
+
.rt-PopoverToolbarRight { justify-self: end; }
|
|
71
|
+
|
|
72
|
+
.rt-PopoverToolbarTitle {
|
|
73
|
+
display: inline-block;
|
|
74
|
+
white-space: nowrap;
|
|
75
|
+
overflow: hidden;
|
|
76
|
+
text-overflow: ellipsis;
|
|
36
77
|
}
|
|
37
78
|
|
|
38
79
|
/***************************************************************************************************
|
|
@@ -44,20 +85,24 @@
|
|
|
44
85
|
@breakpoints {
|
|
45
86
|
.rt-PopoverContent {
|
|
46
87
|
&:where(.rt-r-size-1) {
|
|
47
|
-
--popover-content-padding: var(--space-
|
|
48
|
-
|
|
88
|
+
--popover-content-padding: var(--space-5);
|
|
89
|
+
--popover-toolbar-padding: var(--space-2);
|
|
90
|
+
border-radius: min(var(--radius-5), calc(var(--radius-1) + var(--space-2)));
|
|
49
91
|
}
|
|
50
92
|
&:where(.rt-r-size-2) {
|
|
51
|
-
--popover-content-padding: var(--space-
|
|
52
|
-
|
|
93
|
+
--popover-content-padding: var(--space-6);
|
|
94
|
+
--popover-toolbar-padding: var(--space-2);
|
|
95
|
+
border-radius: min(var(--radius-6), calc(var(--radius-2) + var(--space-3)));
|
|
53
96
|
}
|
|
54
97
|
&:where(.rt-r-size-3) {
|
|
55
|
-
--popover-content-padding: var(--space-
|
|
56
|
-
|
|
98
|
+
--popover-content-padding: var(--space-7);
|
|
99
|
+
--popover-toolbar-padding: var(--space-3);
|
|
100
|
+
border-radius: min(var(--radius-7), calc(var(--radius-3) + var(--space-4)));
|
|
57
101
|
}
|
|
58
102
|
&:where(.rt-r-size-4) {
|
|
59
|
-
--popover-content-padding: var(--space-
|
|
60
|
-
|
|
103
|
+
--popover-content-padding: var(--space-8);
|
|
104
|
+
--popover-toolbar-padding: var(--space-4);
|
|
105
|
+
border-radius: min(var(--radius-8), calc(var(--radius-4) + var(--space-5)));
|
|
61
106
|
}
|
|
62
107
|
}
|
|
63
108
|
}
|
|
@@ -11,6 +11,29 @@ import { useThemeContext } from './theme.js';
|
|
|
11
11
|
import type { PopoverContentOwnProps } from './popover.props.js';
|
|
12
12
|
import type { ComponentPropsWithout, RemovedProps } from '../helpers/component-props.js';
|
|
13
13
|
|
|
14
|
+
// ---------------------------------------------
|
|
15
|
+
// Popover Content Context
|
|
16
|
+
// ---------------------------------------------
|
|
17
|
+
type PopoverContentContextValue = {
|
|
18
|
+
/** Ref to the Popover.Content DOM node */
|
|
19
|
+
contentRef: React.MutableRefObject<HTMLDivElement | null>;
|
|
20
|
+
/** Update content's toolbar offset variable and presence flag */
|
|
21
|
+
setToolbarOffset: (offsetPx: number) => void;
|
|
22
|
+
/** Wire up aria-labelledby for toolbar title */
|
|
23
|
+
setLabelId: (id: string | undefined) => void;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const PopoverContentContext = React.createContext<PopoverContentContextValue | null>(null);
|
|
27
|
+
const usePopoverContentContext = (caller: string) => {
|
|
28
|
+
const ctx = React.useContext(PopoverContentContext);
|
|
29
|
+
if (!ctx) {
|
|
30
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
31
|
+
console.warn(`${caller} must be used within Popover.Content`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return ctx;
|
|
35
|
+
};
|
|
36
|
+
|
|
14
37
|
interface PopoverRootProps extends React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Root> {}
|
|
15
38
|
const PopoverRoot: React.FC<PopoverRootProps> = (props: PopoverRootProps) => (
|
|
16
39
|
<PopoverPrimitive.Root {...props} />
|
|
@@ -46,6 +69,35 @@ const PopoverContent = React.forwardRef<PopoverContentElement, PopoverContentPro
|
|
|
46
69
|
panelBackground: _,
|
|
47
70
|
...contentProps
|
|
48
71
|
} = extractProps(props, popoverContentPropDefs);
|
|
72
|
+
|
|
73
|
+
// Manage refs (we need the DOM node to apply CSS variables)
|
|
74
|
+
const contentRef = React.useRef<HTMLDivElement>(null);
|
|
75
|
+
const combinedRef = React.useCallback(
|
|
76
|
+
(node: HTMLDivElement | null) => {
|
|
77
|
+
contentRef.current = node;
|
|
78
|
+
if (typeof forwardedRef === 'function') {
|
|
79
|
+
forwardedRef(node);
|
|
80
|
+
} else if (forwardedRef) {
|
|
81
|
+
(forwardedRef as React.MutableRefObject<HTMLDivElement | null>).current = node;
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
[forwardedRef],
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const [labelId, setLabelId] = React.useState<string | undefined>(undefined);
|
|
88
|
+
|
|
89
|
+
const setToolbarOffset = React.useCallback((offsetPx: number) => {
|
|
90
|
+
const el = contentRef.current;
|
|
91
|
+
if (!el) return;
|
|
92
|
+
if (offsetPx > 0) {
|
|
93
|
+
el.style.setProperty('--popover-toolbar-offset', `${offsetPx}px`);
|
|
94
|
+
el.setAttribute('data-has-toolbar', 'true');
|
|
95
|
+
} else {
|
|
96
|
+
el.style.removeProperty('--popover-toolbar-offset');
|
|
97
|
+
el.removeAttribute('data-has-toolbar');
|
|
98
|
+
}
|
|
99
|
+
}, []);
|
|
100
|
+
|
|
49
101
|
return (
|
|
50
102
|
<PopoverPrimitive.Portal container={container} forceMount={forceMount}>
|
|
51
103
|
<Theme asChild>
|
|
@@ -54,10 +106,15 @@ const PopoverContent = React.forwardRef<PopoverContentElement, PopoverContentPro
|
|
|
54
106
|
sideOffset={8}
|
|
55
107
|
collisionPadding={10}
|
|
56
108
|
{...contentProps}
|
|
57
|
-
ref={
|
|
109
|
+
ref={combinedRef}
|
|
110
|
+
aria-labelledby={labelId}
|
|
58
111
|
data-panel-background={panelBackground}
|
|
59
112
|
className={classNames('rt-PopperContent', 'rt-PopoverContent', className)}
|
|
60
|
-
|
|
113
|
+
>
|
|
114
|
+
<PopoverContentContext.Provider value={{ contentRef, setToolbarOffset, setLabelId }}>
|
|
115
|
+
{props.children}
|
|
116
|
+
</PopoverContentContext.Provider>
|
|
117
|
+
</PopoverPrimitive.Content>
|
|
61
118
|
</Theme>
|
|
62
119
|
</PopoverPrimitive.Portal>
|
|
63
120
|
);
|
|
@@ -88,12 +145,133 @@ const PopoverAnchor = React.forwardRef<PopoverAnchorElement, PopoverAnchorProps>
|
|
|
88
145
|
|
|
89
146
|
PopoverAnchor.displayName = 'Popover.Anchor';
|
|
90
147
|
|
|
148
|
+
// ---------------------------------------------
|
|
149
|
+
// Toolbar (Popover-only)
|
|
150
|
+
// ---------------------------------------------
|
|
151
|
+
|
|
152
|
+
type PopoverToolbarElement = HTMLDivElement;
|
|
153
|
+
type PopoverToolbarProps = React.ComponentPropsWithoutRef<'div'>;
|
|
154
|
+
|
|
155
|
+
const PopoverToolbarBase = React.forwardRef<PopoverToolbarElement, PopoverToolbarProps>(
|
|
156
|
+
({ className, children, ...props }, forwardedRef) => {
|
|
157
|
+
const ctx = usePopoverContentContext('Popover.Toolbar');
|
|
158
|
+
|
|
159
|
+
const localRef = React.useRef<HTMLDivElement | null>(null);
|
|
160
|
+
const setRefs = React.useCallback(
|
|
161
|
+
(node: HTMLDivElement | null) => {
|
|
162
|
+
localRef.current = node;
|
|
163
|
+
if (typeof forwardedRef === 'function') forwardedRef(node);
|
|
164
|
+
else if (forwardedRef)
|
|
165
|
+
(forwardedRef as React.MutableRefObject<HTMLDivElement | null>).current = node;
|
|
166
|
+
},
|
|
167
|
+
[forwardedRef],
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
React.useEffect(() => {
|
|
171
|
+
if (!ctx || !localRef.current) return;
|
|
172
|
+
const el = localRef.current;
|
|
173
|
+
const update = () => {
|
|
174
|
+
const height = el.getBoundingClientRect().height;
|
|
175
|
+
ctx.setToolbarOffset(height);
|
|
176
|
+
};
|
|
177
|
+
update();
|
|
178
|
+
const ro = new ResizeObserver(update);
|
|
179
|
+
ro.observe(el);
|
|
180
|
+
return () => {
|
|
181
|
+
ro.disconnect();
|
|
182
|
+
ctx.setToolbarOffset(0);
|
|
183
|
+
};
|
|
184
|
+
}, [ctx]);
|
|
185
|
+
|
|
186
|
+
return (
|
|
187
|
+
<div {...props} ref={setRefs} className={classNames('rt-PopoverToolbar', className)}>
|
|
188
|
+
{children}
|
|
189
|
+
</div>
|
|
190
|
+
);
|
|
191
|
+
},
|
|
192
|
+
);
|
|
193
|
+
(PopoverToolbarBase as any).displayName = 'Popover.Toolbar';
|
|
194
|
+
|
|
195
|
+
type SectionProps = React.ComponentPropsWithoutRef<'div'>;
|
|
196
|
+
|
|
197
|
+
const PopoverToolbarLeft = React.forwardRef<HTMLDivElement, SectionProps>(
|
|
198
|
+
({ className, ...props }, ref) => (
|
|
199
|
+
<div
|
|
200
|
+
{...props}
|
|
201
|
+
ref={ref}
|
|
202
|
+
className={classNames('rt-PopoverToolbarSection', 'rt-PopoverToolbarLeft', className)}
|
|
203
|
+
/>
|
|
204
|
+
),
|
|
205
|
+
);
|
|
206
|
+
PopoverToolbarLeft.displayName = 'Popover.Toolbar.Left';
|
|
207
|
+
|
|
208
|
+
const PopoverToolbarCenter = React.forwardRef<HTMLDivElement, SectionProps>(
|
|
209
|
+
({ className, ...props }, ref) => (
|
|
210
|
+
<div
|
|
211
|
+
{...props}
|
|
212
|
+
ref={ref}
|
|
213
|
+
className={classNames('rt-PopoverToolbarSection', 'rt-PopoverToolbarCenter', className)}
|
|
214
|
+
/>
|
|
215
|
+
),
|
|
216
|
+
);
|
|
217
|
+
PopoverToolbarCenter.displayName = 'Popover.Toolbar.Center';
|
|
218
|
+
|
|
219
|
+
const PopoverToolbarRight = React.forwardRef<HTMLDivElement, SectionProps>(
|
|
220
|
+
({ className, ...props }, ref) => (
|
|
221
|
+
<div
|
|
222
|
+
{...props}
|
|
223
|
+
ref={ref}
|
|
224
|
+
className={classNames('rt-PopoverToolbarSection', 'rt-PopoverToolbarRight', className)}
|
|
225
|
+
/>
|
|
226
|
+
),
|
|
227
|
+
);
|
|
228
|
+
PopoverToolbarRight.displayName = 'Popover.Toolbar.Right';
|
|
229
|
+
|
|
230
|
+
type TitleProps = React.ComponentPropsWithoutRef<'span'>;
|
|
231
|
+
const PopoverToolbarTitle = React.forwardRef<HTMLSpanElement, TitleProps>(
|
|
232
|
+
({ className, id: idProp, ...props }, ref) => {
|
|
233
|
+
const ctx = usePopoverContentContext('Popover.Toolbar.Title');
|
|
234
|
+
const reactId = React.useId();
|
|
235
|
+
const id = idProp ?? `rt-popover-toolbar-title-${reactId}`;
|
|
236
|
+
React.useEffect(() => {
|
|
237
|
+
ctx?.setLabelId(id);
|
|
238
|
+
return () => ctx?.setLabelId(undefined);
|
|
239
|
+
}, [ctx, id]);
|
|
240
|
+
return (
|
|
241
|
+
<span
|
|
242
|
+
{...props}
|
|
243
|
+
id={id}
|
|
244
|
+
ref={ref}
|
|
245
|
+
className={classNames('rt-PopoverToolbarTitle', className)}
|
|
246
|
+
/>
|
|
247
|
+
);
|
|
248
|
+
},
|
|
249
|
+
);
|
|
250
|
+
PopoverToolbarTitle.displayName = 'Popover.Toolbar.Title';
|
|
251
|
+
|
|
252
|
+
type PopoverToolbarComponent = React.ForwardRefExoticComponent<
|
|
253
|
+
React.PropsWithoutRef<PopoverToolbarProps> & React.RefAttributes<HTMLDivElement>
|
|
254
|
+
> & {
|
|
255
|
+
Left: typeof PopoverToolbarLeft;
|
|
256
|
+
Center: typeof PopoverToolbarCenter;
|
|
257
|
+
Right: typeof PopoverToolbarRight;
|
|
258
|
+
Title: typeof PopoverToolbarTitle;
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
const PopoverToolbar = Object.assign(PopoverToolbarBase, {
|
|
262
|
+
Left: PopoverToolbarLeft,
|
|
263
|
+
Center: PopoverToolbarCenter,
|
|
264
|
+
Right: PopoverToolbarRight,
|
|
265
|
+
Title: PopoverToolbarTitle,
|
|
266
|
+
}) as PopoverToolbarComponent;
|
|
267
|
+
|
|
91
268
|
export {
|
|
92
269
|
PopoverRoot as Root,
|
|
93
270
|
PopoverContent as Content,
|
|
94
271
|
PopoverTrigger as Trigger,
|
|
95
272
|
PopoverClose as Close,
|
|
96
273
|
PopoverAnchor as Anchor,
|
|
274
|
+
PopoverToolbar as Toolbar,
|
|
97
275
|
};
|
|
98
276
|
export type {
|
|
99
277
|
PopoverRootProps as RootProps,
|
|
@@ -109,8 +109,8 @@
|
|
|
109
109
|
background-color: var(--gray-a3);
|
|
110
110
|
border-radius: var(--scrollarea-scrollbar-border-radius);
|
|
111
111
|
|
|
112
|
-
animation-duration:
|
|
113
|
-
animation-timing-function: ease-
|
|
112
|
+
animation-duration: var(--motion-duration-micro);
|
|
113
|
+
animation-timing-function: var(--motion-ease-standard);
|
|
114
114
|
|
|
115
115
|
&:where([data-state='visible']) {
|
|
116
116
|
animation-name: rt-fade-in;
|
|
@@ -135,7 +135,7 @@
|
|
|
135
135
|
.rt-ScrollAreaThumb {
|
|
136
136
|
background-color: var(--gray-a8);
|
|
137
137
|
border-radius: inherit;
|
|
138
|
-
transition: background-color
|
|
138
|
+
transition: background-color var(--motion-duration-micro) var(--motion-ease-standard);
|
|
139
139
|
|
|
140
140
|
@media (hover: hover) {
|
|
141
141
|
&:where(:hover) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
.radix-themes {
|
|
2
2
|
/* Use standard duration token instead of custom duration */
|
|
3
|
-
--segmented-control-transition-duration: var(--duration-
|
|
3
|
+
--segmented-control-transition-duration: var(--motion-duration-micro); /* Micro-interactions */
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
.rt-SegmentedControlRoot {
|
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
margin-right: calc(-1 * var(--border-width-standard) * 0.5); /* -0.5px */
|
|
139
139
|
width: var(--border-width-standard); /* 1px */
|
|
140
140
|
background-color: var(--gray-a4);
|
|
141
|
-
transition: opacity calc(0.8 * var(--segmented-control-transition-duration)) var(--ease-
|
|
141
|
+
transition: opacity calc(0.8 * var(--segmented-control-transition-duration)) var(--motion-ease-standard);
|
|
142
142
|
|
|
143
143
|
/* Make separators slow to disappear and fast to appear, syncing it well with the indicator motion */
|
|
144
144
|
|
|
@@ -166,7 +166,7 @@
|
|
|
166
166
|
left: 0;
|
|
167
167
|
height: 100%;
|
|
168
168
|
pointer-events: none;
|
|
169
|
-
transition: transform var(--segmented-control-transition-duration) var(--
|
|
169
|
+
transition: transform var(--segmented-control-transition-duration) var(--motion-spring-snappy);
|
|
170
170
|
|
|
171
171
|
&::before {
|
|
172
172
|
inset: var(--border-width-standard); /* 1px */
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
:where(.rt-SheetContent) {
|
|
2
|
+
position: fixed !important;
|
|
3
|
+
/* Use physical properties to integrate with width/height responsive utilities */
|
|
4
|
+
width: var(--width, 90vw) !important;
|
|
5
|
+
max-width: var(--max-width, 100vw) !important;
|
|
6
|
+
height: 100vh !important;
|
|
7
|
+
max-height: 100vh !important;
|
|
8
|
+
margin: 0 !important;
|
|
9
|
+
border-radius: 0 !important;
|
|
10
|
+
will-change: transform;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/* Logical side anchoring (RTL-aware via logical inset) */
|
|
14
|
+
:where(.rt-SheetContent[data-side='start']) {
|
|
15
|
+
top: 0 !important;
|
|
16
|
+
bottom: 0 !important;
|
|
17
|
+
left: 0 !important;
|
|
18
|
+
right: auto !important;
|
|
19
|
+
margin: 0 !important;
|
|
20
|
+
border-start-start-radius: 0;
|
|
21
|
+
border-end-start-radius: 0;
|
|
22
|
+
}
|
|
23
|
+
:where(.rt-SheetContent[data-side='end']) {
|
|
24
|
+
top: 0 !important;
|
|
25
|
+
bottom: 0 !important;
|
|
26
|
+
right: 0 !important;
|
|
27
|
+
left: auto !important;
|
|
28
|
+
margin: 0 !important;
|
|
29
|
+
border-start-end-radius: 0;
|
|
30
|
+
border-end-end-radius: 0;
|
|
31
|
+
}
|
|
32
|
+
:where(.rt-SheetContent[data-side='top']) {
|
|
33
|
+
top: 0 !important;
|
|
34
|
+
left: 0 !important;
|
|
35
|
+
right: 0 !important;
|
|
36
|
+
bottom: auto !important;
|
|
37
|
+
width: auto !important;
|
|
38
|
+
max-width: none !important;
|
|
39
|
+
height: var(--height, 75vh) !important;
|
|
40
|
+
margin: 0 !important;
|
|
41
|
+
border-start-start-radius: 0;
|
|
42
|
+
border-start-end-radius: 0;
|
|
43
|
+
}
|
|
44
|
+
:where(.rt-SheetContent[data-side='bottom']) {
|
|
45
|
+
bottom: 0 !important;
|
|
46
|
+
left: 0 !important;
|
|
47
|
+
right: 0 !important;
|
|
48
|
+
top: auto !important;
|
|
49
|
+
width: auto !important;
|
|
50
|
+
max-width: none !important;
|
|
51
|
+
height: var(--height, 75vh) !important;
|
|
52
|
+
margin: 0 !important;
|
|
53
|
+
border-end-start-radius: 0;
|
|
54
|
+
border-end-end-radius: 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* Overlay adjustments: avoid double-fade jank from base dialog */
|
|
58
|
+
:where(.rt-SheetOverlay)::before { opacity: 1; }
|
|
59
|
+
|
|
60
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
61
|
+
/* Override base dialog animations specifically for Sheet */
|
|
62
|
+
.rt-SheetContent:where([data-state='open']) {
|
|
63
|
+
animation-duration: var(--motion-duration-medium);
|
|
64
|
+
animation-timing-function: var(--motion-spring-snappy);
|
|
65
|
+
animation-fill-mode: both;
|
|
66
|
+
}
|
|
67
|
+
.rt-SheetContent:where([data-state='closed']) {
|
|
68
|
+
/* Keep visible to allow reverse slide-out */
|
|
69
|
+
opacity: 1;
|
|
70
|
+
animation-duration: var(--motion-duration-small);
|
|
71
|
+
animation-timing-function: var(--motion-spring-snappy);
|
|
72
|
+
animation-fill-mode: both;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.rt-SheetContent:where([data-state='open'][data-side='start']) { animation-name: rt-sheet-open-from-start, rt-fade-in !important; }
|
|
76
|
+
.rt-SheetContent:where([data-state='closed'][data-side='start']) { animation-name: rt-sheet-close-to-start, rt-fade-out !important; }
|
|
77
|
+
|
|
78
|
+
.rt-SheetContent:where([data-state='open'][data-side='end']) { animation-name: rt-sheet-open-from-end, rt-fade-in !important; }
|
|
79
|
+
.rt-SheetContent:where([data-state='closed'][data-side='end']) { animation-name: rt-sheet-close-to-end, rt-fade-out !important; }
|
|
80
|
+
|
|
81
|
+
.rt-SheetContent:where([data-state='open'][data-side='top']) { animation-name: rt-sheet-open-from-top, rt-fade-in !important; }
|
|
82
|
+
.rt-SheetContent:where([data-state='closed'][data-side='top']) { animation-name: rt-sheet-close-to-top, rt-fade-out !important; }
|
|
83
|
+
|
|
84
|
+
.rt-SheetContent:where([data-state='open'][data-side='bottom']) { animation-name: rt-sheet-open-from-bottom, rt-fade-in !important; }
|
|
85
|
+
.rt-SheetContent:where([data-state='closed'][data-side='bottom']) { animation-name: rt-sheet-close-to-bottom, rt-fade-out !important; }
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
@media (prefers-reduced-motion: reduce) {
|
|
89
|
+
.rt-SheetContent { animation: none !important; }
|
|
90
|
+
}
|