@urbicon-ui/blocks 6.24.0 → 6.26.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/README.md +14 -0
- package/dist/components/Calendar/CalendarTimeGrid.svelte +2 -1
- package/dist/components/Calendar/calendar.variants.d.ts +63 -63
- package/dist/components/Calendar/calendar.variants.js +5 -3
- package/dist/components/CommandPalette/CommandPalette.svelte +32 -16
- package/dist/components/CommandPalette/CommandPalette.svelte.d.ts +1 -1
- package/dist/components/CommandPalette/commandPalette.variants.d.ts +10 -0
- package/dist/components/CommandPalette/commandPalette.variants.js +9 -7
- package/dist/components/CommandPalette/index.d.ts +19 -0
- package/dist/components/CompositionBar/CompositionBar.svelte +2 -2
- package/dist/components/CompositionBar/composition-bar.variants.js +1 -1
- package/dist/components/Planner/planner.variants.js +1 -1
- package/dist/components/Sankey/sankey.variants.js +1 -1
- package/dist/i18n/index.d.ts +378 -2
- package/dist/internal/charts/variants.js +2 -2
- package/dist/internal/date-grid/DateGridScaffold.svelte +9 -2
- package/dist/internal/date-grid/date-grid.svelte.d.ts +4 -2
- package/dist/internal/date-grid/date-grid.svelte.js +63 -7
- package/dist/primitives/Alert/alert.variants.d.ts +8 -8
- package/dist/primitives/Alert/alert.variants.js +1 -1
- package/dist/primitives/Avatar/Avatar.svelte +38 -24
- package/dist/primitives/Avatar/index.d.ts +1 -1
- package/dist/primitives/Badge/badge.variants.js +1 -1
- package/dist/primitives/Button/Button.svelte +12 -25
- package/dist/primitives/Button/button.variants.js +2 -2
- package/dist/primitives/ButtonGroup/ButtonGroup.svelte +5 -1
- package/dist/primitives/Checkbox/checkbox.variants.js +2 -2
- package/dist/primitives/Collapsible/Collapsible.svelte +10 -0
- package/dist/primitives/Collapsible/index.d.ts +13 -2
- package/dist/primitives/ConfirmDialog/ConfirmDialog.svelte +14 -0
- package/dist/primitives/ConfirmDialog/index.d.ts +13 -2
- package/dist/primitives/Dialog/Dialog.svelte +36 -8
- package/dist/primitives/Drawer/Drawer.svelte +34 -7
- package/dist/primitives/Input/Input.svelte +7 -1
- package/dist/primitives/JourneyTimeline/journey-timeline.variants.d.ts +22 -22
- package/dist/primitives/JourneyTimeline/journey-timeline.variants.js +3 -3
- package/dist/primitives/Menu/Menu.svelte +8 -0
- package/dist/primitives/Menu/index.d.ts +11 -13
- package/dist/primitives/Popover/Popover.svelte +107 -4
- package/dist/primitives/Popover/index.d.ts +15 -2
- package/dist/primitives/Popover/index.js +1 -1
- package/dist/primitives/Popover/popover.variants.d.ts +25 -0
- package/dist/primitives/Popover/popover.variants.js +35 -0
- package/dist/primitives/Progress/progress.variants.js +1 -1
- package/dist/primitives/RadioGroup/radioGroup.variants.js +2 -2
- package/dist/primitives/Select/index.d.ts +8 -1
- package/dist/primitives/Slider/Slider.svelte +32 -3
- package/dist/primitives/Spinner/spinner.variants.d.ts +16 -16
- package/dist/primitives/Stepper/stepper.variants.d.ts +11 -11
- package/dist/primitives/Stepper/stepper.variants.js +2 -2
- package/dist/primitives/Textarea/Textarea.svelte +5 -1
- package/dist/primitives/Toast/toast.variants.d.ts +12 -12
- package/dist/primitives/Tooltip/tooltip.variants.d.ts +3 -3
- package/dist/primitives/Tooltip/tooltip.variants.js +14 -3
- package/dist/style/foundation.css +41 -7
- package/dist/style/interaction.css +19 -2
- package/dist/style/semantic.css +84 -1
- package/dist/style/themes/forest.css +3 -1
- package/dist/style/themes/neutral.css +10 -1
- package/dist/style/themes/ocean.css +5 -1
- package/dist/style/themes/sunset.css +3 -1
- package/dist/utils/compose-handlers.d.ts +72 -0
- package/dist/utils/compose-handlers.js +65 -0
- package/dist/utils/figma-token-export.js +6 -2
- package/dist/utils/guide.svelte.js +92 -29
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/overlay-tokens.d.ts +17 -0
- package/dist/utils/overlay-tokens.js +30 -0
- package/dist/utils/overlay.js +24 -2
- package/dist/utils/use-floating-panel.svelte.js +9 -3
- package/dist/utils/variants.js +5 -1
- package/package.json +3 -3
|
@@ -2,7 +2,7 @@ import { type SlotNames, type VariantProps } from '../../utils/variants.js';
|
|
|
2
2
|
export declare const journeyTimelineVariants: ((props?: {
|
|
3
3
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
4
4
|
size?: "sm" | "md" | "lg" | undefined;
|
|
5
|
-
status?: "
|
|
5
|
+
status?: "complete" | "active" | "pending" | "attention" | "blocked" | "skipped" | undefined;
|
|
6
6
|
focused?: boolean | undefined;
|
|
7
7
|
interactive?: boolean | undefined;
|
|
8
8
|
travelled?: boolean | undefined;
|
|
@@ -13,7 +13,7 @@ export declare const journeyTimelineVariants: ((props?: {
|
|
|
13
13
|
base: (props?: ({
|
|
14
14
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
15
15
|
size?: "sm" | "md" | "lg" | undefined;
|
|
16
|
-
status?: "
|
|
16
|
+
status?: "complete" | "active" | "pending" | "attention" | "blocked" | "skipped" | undefined;
|
|
17
17
|
focused?: boolean | undefined;
|
|
18
18
|
interactive?: boolean | undefined;
|
|
19
19
|
travelled?: boolean | undefined;
|
|
@@ -26,7 +26,7 @@ export declare const journeyTimelineVariants: ((props?: {
|
|
|
26
26
|
rail: (props?: ({
|
|
27
27
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
28
28
|
size?: "sm" | "md" | "lg" | undefined;
|
|
29
|
-
status?: "
|
|
29
|
+
status?: "complete" | "active" | "pending" | "attention" | "blocked" | "skipped" | undefined;
|
|
30
30
|
focused?: boolean | undefined;
|
|
31
31
|
interactive?: boolean | undefined;
|
|
32
32
|
travelled?: boolean | undefined;
|
|
@@ -39,7 +39,7 @@ export declare const journeyTimelineVariants: ((props?: {
|
|
|
39
39
|
node: (props?: ({
|
|
40
40
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
41
41
|
size?: "sm" | "md" | "lg" | undefined;
|
|
42
|
-
status?: "
|
|
42
|
+
status?: "complete" | "active" | "pending" | "attention" | "blocked" | "skipped" | undefined;
|
|
43
43
|
focused?: boolean | undefined;
|
|
44
44
|
interactive?: boolean | undefined;
|
|
45
45
|
travelled?: boolean | undefined;
|
|
@@ -52,7 +52,7 @@ export declare const journeyTimelineVariants: ((props?: {
|
|
|
52
52
|
metaColumn: (props?: ({
|
|
53
53
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
54
54
|
size?: "sm" | "md" | "lg" | undefined;
|
|
55
|
-
status?: "
|
|
55
|
+
status?: "complete" | "active" | "pending" | "attention" | "blocked" | "skipped" | undefined;
|
|
56
56
|
focused?: boolean | undefined;
|
|
57
57
|
interactive?: boolean | undefined;
|
|
58
58
|
travelled?: boolean | undefined;
|
|
@@ -65,7 +65,7 @@ export declare const journeyTimelineVariants: ((props?: {
|
|
|
65
65
|
meta: (props?: ({
|
|
66
66
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
67
67
|
size?: "sm" | "md" | "lg" | undefined;
|
|
68
|
-
status?: "
|
|
68
|
+
status?: "complete" | "active" | "pending" | "attention" | "blocked" | "skipped" | undefined;
|
|
69
69
|
focused?: boolean | undefined;
|
|
70
70
|
interactive?: boolean | undefined;
|
|
71
71
|
travelled?: boolean | undefined;
|
|
@@ -78,7 +78,7 @@ export declare const journeyTimelineVariants: ((props?: {
|
|
|
78
78
|
markerColumn: (props?: ({
|
|
79
79
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
80
80
|
size?: "sm" | "md" | "lg" | undefined;
|
|
81
|
-
status?: "
|
|
81
|
+
status?: "complete" | "active" | "pending" | "attention" | "blocked" | "skipped" | undefined;
|
|
82
82
|
focused?: boolean | undefined;
|
|
83
83
|
interactive?: boolean | undefined;
|
|
84
84
|
travelled?: boolean | undefined;
|
|
@@ -91,7 +91,7 @@ export declare const journeyTimelineVariants: ((props?: {
|
|
|
91
91
|
marker: (props?: ({
|
|
92
92
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
93
93
|
size?: "sm" | "md" | "lg" | undefined;
|
|
94
|
-
status?: "
|
|
94
|
+
status?: "complete" | "active" | "pending" | "attention" | "blocked" | "skipped" | undefined;
|
|
95
95
|
focused?: boolean | undefined;
|
|
96
96
|
interactive?: boolean | undefined;
|
|
97
97
|
travelled?: boolean | undefined;
|
|
@@ -104,7 +104,7 @@ export declare const journeyTimelineVariants: ((props?: {
|
|
|
104
104
|
connector: (props?: ({
|
|
105
105
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
106
106
|
size?: "sm" | "md" | "lg" | undefined;
|
|
107
|
-
status?: "
|
|
107
|
+
status?: "complete" | "active" | "pending" | "attention" | "blocked" | "skipped" | undefined;
|
|
108
108
|
focused?: boolean | undefined;
|
|
109
109
|
interactive?: boolean | undefined;
|
|
110
110
|
travelled?: boolean | undefined;
|
|
@@ -117,7 +117,7 @@ export declare const journeyTimelineVariants: ((props?: {
|
|
|
117
117
|
content: (props?: ({
|
|
118
118
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
119
119
|
size?: "sm" | "md" | "lg" | undefined;
|
|
120
|
-
status?: "
|
|
120
|
+
status?: "complete" | "active" | "pending" | "attention" | "blocked" | "skipped" | undefined;
|
|
121
121
|
focused?: boolean | undefined;
|
|
122
122
|
interactive?: boolean | undefined;
|
|
123
123
|
travelled?: boolean | undefined;
|
|
@@ -130,7 +130,7 @@ export declare const journeyTimelineVariants: ((props?: {
|
|
|
130
130
|
card: (props?: ({
|
|
131
131
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
132
132
|
size?: "sm" | "md" | "lg" | undefined;
|
|
133
|
-
status?: "
|
|
133
|
+
status?: "complete" | "active" | "pending" | "attention" | "blocked" | "skipped" | undefined;
|
|
134
134
|
focused?: boolean | undefined;
|
|
135
135
|
interactive?: boolean | undefined;
|
|
136
136
|
travelled?: boolean | undefined;
|
|
@@ -143,7 +143,7 @@ export declare const journeyTimelineVariants: ((props?: {
|
|
|
143
143
|
header: (props?: ({
|
|
144
144
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
145
145
|
size?: "sm" | "md" | "lg" | undefined;
|
|
146
|
-
status?: "
|
|
146
|
+
status?: "complete" | "active" | "pending" | "attention" | "blocked" | "skipped" | undefined;
|
|
147
147
|
focused?: boolean | undefined;
|
|
148
148
|
interactive?: boolean | undefined;
|
|
149
149
|
travelled?: boolean | undefined;
|
|
@@ -156,7 +156,7 @@ export declare const journeyTimelineVariants: ((props?: {
|
|
|
156
156
|
trigger: (props?: ({
|
|
157
157
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
158
158
|
size?: "sm" | "md" | "lg" | undefined;
|
|
159
|
-
status?: "
|
|
159
|
+
status?: "complete" | "active" | "pending" | "attention" | "blocked" | "skipped" | undefined;
|
|
160
160
|
focused?: boolean | undefined;
|
|
161
161
|
interactive?: boolean | undefined;
|
|
162
162
|
travelled?: boolean | undefined;
|
|
@@ -169,7 +169,7 @@ export declare const journeyTimelineVariants: ((props?: {
|
|
|
169
169
|
trailing: (props?: ({
|
|
170
170
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
171
171
|
size?: "sm" | "md" | "lg" | undefined;
|
|
172
|
-
status?: "
|
|
172
|
+
status?: "complete" | "active" | "pending" | "attention" | "blocked" | "skipped" | undefined;
|
|
173
173
|
focused?: boolean | undefined;
|
|
174
174
|
interactive?: boolean | undefined;
|
|
175
175
|
travelled?: boolean | undefined;
|
|
@@ -182,7 +182,7 @@ export declare const journeyTimelineVariants: ((props?: {
|
|
|
182
182
|
labelGroup: (props?: ({
|
|
183
183
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
184
184
|
size?: "sm" | "md" | "lg" | undefined;
|
|
185
|
-
status?: "
|
|
185
|
+
status?: "complete" | "active" | "pending" | "attention" | "blocked" | "skipped" | undefined;
|
|
186
186
|
focused?: boolean | undefined;
|
|
187
187
|
interactive?: boolean | undefined;
|
|
188
188
|
travelled?: boolean | undefined;
|
|
@@ -195,7 +195,7 @@ export declare const journeyTimelineVariants: ((props?: {
|
|
|
195
195
|
title: (props?: ({
|
|
196
196
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
197
197
|
size?: "sm" | "md" | "lg" | undefined;
|
|
198
|
-
status?: "
|
|
198
|
+
status?: "complete" | "active" | "pending" | "attention" | "blocked" | "skipped" | undefined;
|
|
199
199
|
focused?: boolean | undefined;
|
|
200
200
|
interactive?: boolean | undefined;
|
|
201
201
|
travelled?: boolean | undefined;
|
|
@@ -208,7 +208,7 @@ export declare const journeyTimelineVariants: ((props?: {
|
|
|
208
208
|
subtitle: (props?: ({
|
|
209
209
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
210
210
|
size?: "sm" | "md" | "lg" | undefined;
|
|
211
|
-
status?: "
|
|
211
|
+
status?: "complete" | "active" | "pending" | "attention" | "blocked" | "skipped" | undefined;
|
|
212
212
|
focused?: boolean | undefined;
|
|
213
213
|
interactive?: boolean | undefined;
|
|
214
214
|
travelled?: boolean | undefined;
|
|
@@ -221,7 +221,7 @@ export declare const journeyTimelineVariants: ((props?: {
|
|
|
221
221
|
segment: (props?: ({
|
|
222
222
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
223
223
|
size?: "sm" | "md" | "lg" | undefined;
|
|
224
|
-
status?: "
|
|
224
|
+
status?: "complete" | "active" | "pending" | "attention" | "blocked" | "skipped" | undefined;
|
|
225
225
|
focused?: boolean | undefined;
|
|
226
226
|
interactive?: boolean | undefined;
|
|
227
227
|
travelled?: boolean | undefined;
|
|
@@ -234,7 +234,7 @@ export declare const journeyTimelineVariants: ((props?: {
|
|
|
234
234
|
detail: (props?: ({
|
|
235
235
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
236
236
|
size?: "sm" | "md" | "lg" | undefined;
|
|
237
|
-
status?: "
|
|
237
|
+
status?: "complete" | "active" | "pending" | "attention" | "blocked" | "skipped" | undefined;
|
|
238
238
|
focused?: boolean | undefined;
|
|
239
239
|
interactive?: boolean | undefined;
|
|
240
240
|
travelled?: boolean | undefined;
|
|
@@ -247,7 +247,7 @@ export declare const journeyTimelineVariants: ((props?: {
|
|
|
247
247
|
detailInner: (props?: ({
|
|
248
248
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
249
249
|
size?: "sm" | "md" | "lg" | undefined;
|
|
250
|
-
status?: "
|
|
250
|
+
status?: "complete" | "active" | "pending" | "attention" | "blocked" | "skipped" | undefined;
|
|
251
251
|
focused?: boolean | undefined;
|
|
252
252
|
interactive?: boolean | undefined;
|
|
253
253
|
travelled?: boolean | undefined;
|
|
@@ -260,7 +260,7 @@ export declare const journeyTimelineVariants: ((props?: {
|
|
|
260
260
|
detailContent: (props?: ({
|
|
261
261
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
262
262
|
size?: "sm" | "md" | "lg" | undefined;
|
|
263
|
-
status?: "
|
|
263
|
+
status?: "complete" | "active" | "pending" | "attention" | "blocked" | "skipped" | undefined;
|
|
264
264
|
focused?: boolean | undefined;
|
|
265
265
|
interactive?: boolean | undefined;
|
|
266
266
|
travelled?: boolean | undefined;
|
|
@@ -273,7 +273,7 @@ export declare const journeyTimelineVariants: ((props?: {
|
|
|
273
273
|
panel: (props?: ({
|
|
274
274
|
orientation?: "horizontal" | "vertical" | undefined;
|
|
275
275
|
size?: "sm" | "md" | "lg" | undefined;
|
|
276
|
-
status?: "
|
|
276
|
+
status?: "complete" | "active" | "pending" | "attention" | "blocked" | "skipped" | undefined;
|
|
277
277
|
focused?: boolean | undefined;
|
|
278
278
|
interactive?: boolean | undefined;
|
|
279
279
|
travelled?: boolean | undefined;
|
|
@@ -111,13 +111,13 @@ export const journeyTimelineVariants = tv({
|
|
|
111
111
|
},
|
|
112
112
|
size: {
|
|
113
113
|
sm: {
|
|
114
|
-
meta: 'text-
|
|
114
|
+
meta: 'text-2xs',
|
|
115
115
|
marker: 'size-2.5',
|
|
116
116
|
node: 'gap-x-2.5',
|
|
117
117
|
card: '-mx-1.5 px-1.5 py-1.5',
|
|
118
118
|
title: 'text-xs',
|
|
119
|
-
subtitle: 'text-
|
|
120
|
-
segment: 'text-
|
|
119
|
+
subtitle: 'text-2xs',
|
|
120
|
+
segment: 'text-2xs',
|
|
121
121
|
content: 'pb-4',
|
|
122
122
|
detailContent: 'text-xs pt-2',
|
|
123
123
|
panel: 'p-3 text-xs'
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { getTierContext } from '../../utils/tier-context';
|
|
9
9
|
const ChevronDownIcon = resolveIcon('chevronDown', ChevronDownIconDefault);
|
|
10
10
|
import Popover from '../Popover/Popover.svelte';
|
|
11
|
+
import { popoverMotion } from '../Popover/popover.variants';
|
|
11
12
|
import { setMenuContext, type MenuContext, type MenuRegistryItem } from './menu.context';
|
|
12
13
|
import MenuItemComp from './MenuItem.svelte';
|
|
13
14
|
import MenuSubmenu from './MenuSubmenu.svelte';
|
|
@@ -471,6 +472,12 @@
|
|
|
471
472
|
only painted layer. Without this, the panel renders as two stacked
|
|
472
473
|
surfaces (Popover wrapper + Menu content) and shows a near-empty box
|
|
473
474
|
with double borders.
|
|
475
|
+
|
|
476
|
+
The stripped default ALSO carried the enter/exit motion, so the exact
|
|
477
|
+
fragment (`popoverMotion`) is re-applied via `class` — it survives
|
|
478
|
+
Popover's `unstyled` by design and animates the transparent wrapper,
|
|
479
|
+
which fades/scales the Menu chrome inside it. A Menu-level `unstyled`
|
|
480
|
+
strips it again; consumers rebuild on the panel's `data-state`.
|
|
474
481
|
-->
|
|
475
482
|
<Popover
|
|
476
483
|
bind:open
|
|
@@ -479,6 +486,7 @@
|
|
|
479
486
|
{usePortal}
|
|
480
487
|
autoTrigger={false}
|
|
481
488
|
unstyled
|
|
489
|
+
class={unstyled ? undefined : popoverMotion}
|
|
482
490
|
syncMinWidth={contextTrigger ? false : syncWidth}
|
|
483
491
|
offsetDistance={effectiveTier === 'commit' ? 8 : 4}
|
|
484
492
|
trigger={contextTrigger ? undefined : triggerContent}
|
|
@@ -7,18 +7,9 @@ import type { Placement } from '../../utils/floating.js';
|
|
|
7
7
|
import type { InteractiveTier } from '../../utils/tier-context.js';
|
|
8
8
|
import type { MenuSlots } from './menu.variants.js';
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* `Select` (or `Combobox` for searchable). Menu and Select are deliberately
|
|
14
|
-
* disjoint: Menu's ARIA semantics, keyboard model (Tab through items, Enter
|
|
15
|
-
* triggers), and visual chrome match the Action surface family; Select's
|
|
16
|
-
* `role="listbox"` + arrow-navigation match the Form surface family.
|
|
17
|
-
*
|
|
18
|
-
* @tag action
|
|
19
|
-
* @related Select
|
|
20
|
-
* @related Combobox
|
|
21
|
-
* @related Popover
|
|
10
|
+
* Menu-specific props. The catalog JSDoc (`@description`/`@tag`/`@related`)
|
|
11
|
+
* lives on `MenuProps` below — the interface docs-gen actually picks up —
|
|
12
|
+
* so it is not duplicated here.
|
|
22
13
|
*
|
|
23
14
|
* @example Items array with `onSelect` callbacks
|
|
24
15
|
* ```svelte
|
|
@@ -172,7 +163,14 @@ export interface MenuSpecificProps<TItem extends MenuItemType = MenuItemType> {
|
|
|
172
163
|
mint?: MintProp;
|
|
173
164
|
}
|
|
174
165
|
/**
|
|
175
|
-
* @description Action menu triggered by a button with nested
|
|
166
|
+
* @description Action menu (`role="menu"`) triggered by a button, with nested
|
|
167
|
+
* submenus, sections, icons, and separators. Items are verbs the user can
|
|
168
|
+
* invoke — Edit, Delete, Share, Export — and dispatch an `onSelect` callback
|
|
169
|
+
* when activated; Menu holds no selection state. For picking a value from a
|
|
170
|
+
* list use `Select` (or `Combobox` for searchable). Menu and Select are
|
|
171
|
+
* deliberately disjoint: Menu's `role="menu"`/`menuitem` semantics with
|
|
172
|
+
* arrow-key roving and Action-family chrome versus Select's `role="listbox"`
|
|
173
|
+
* value commitment with Form-family chrome.
|
|
176
174
|
*
|
|
177
175
|
* @tag action
|
|
178
176
|
* @related Select
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { untrack } from 'svelte';
|
|
3
3
|
import { getBlocksConfig, resolveSlotClasses } from '../../provider';
|
|
4
|
-
import { useFloatingPanel, floatingPanelHidden } from '../../utils';
|
|
4
|
+
import { useFloatingPanel, floatingPanelHidden, maxTransitionDurationMs } from '../../utils';
|
|
5
5
|
import { popoverVariants } from './popover.variants';
|
|
6
6
|
import type { PopoverProps } from './index';
|
|
7
7
|
|
|
@@ -21,6 +21,9 @@
|
|
|
21
21
|
autoTrigger = true,
|
|
22
22
|
size = 'md',
|
|
23
23
|
|
|
24
|
+
transitionDuration,
|
|
25
|
+
transitionEasing,
|
|
26
|
+
|
|
24
27
|
onOpenChange,
|
|
25
28
|
onClickOutside: onClickOutsideProp,
|
|
26
29
|
onEscape: onEscapeProp,
|
|
@@ -47,11 +50,64 @@
|
|
|
47
50
|
resolveSlotClasses(blocksConfig, 'Popover', preset, { size }, slotClassesProp)
|
|
48
51
|
);
|
|
49
52
|
|
|
53
|
+
// Per-instance motion overrides. Set the shared popover CSS variables inline
|
|
54
|
+
// only when a prop is provided, so the unset default keeps inheriting the
|
|
55
|
+
// reduced-motion-aware token (mirrors Tooltip's transitionDuration path).
|
|
56
|
+
const popoverDurationInline = $derived(
|
|
57
|
+
transitionDuration != null ? `${transitionDuration}ms` : undefined
|
|
58
|
+
);
|
|
59
|
+
|
|
50
60
|
let internalTriggerElement = $state<HTMLElement | null>(null);
|
|
51
61
|
let popoverElement = $state<HTMLElement | null>(null);
|
|
52
62
|
|
|
53
63
|
const effectiveTriggerElement = $derived(triggerElement || internalTriggerElement);
|
|
54
64
|
|
|
65
|
+
// ── Exit-motion lag (ACC-3 rest) ───────────────────────────
|
|
66
|
+
//
|
|
67
|
+
// Closing used to tear three things down in one flush: `open` flips, the
|
|
68
|
+
// children block unmounts, and `useFloatingPanel` hides the panel. The CSS
|
|
69
|
+
// exit transition (see `popoverMotion` in popover.variants.ts) keeps the
|
|
70
|
+
// *panel element* painted via `allow-discrete`, but the children must
|
|
71
|
+
// outlive `open` or the panel fades out empty. `exiting` lags the teardown
|
|
72
|
+
// by the panel's actual computed transition duration — read from the live
|
|
73
|
+
// style so per-instance props, theme token overrides, and reduced motion all
|
|
74
|
+
// shorten it automatically. A zero duration (jsdom/node tests, browsers
|
|
75
|
+
// without the CSS, `unstyled` without rebuilt motion) tears down
|
|
76
|
+
// synchronously: exactly the pre-motion behaviour.
|
|
77
|
+
//
|
|
78
|
+
// `$effect.pre` matters: the flag must be `true` in the SAME flush that
|
|
79
|
+
// renders `open === false`, otherwise the children unmount one frame before
|
|
80
|
+
// the lag starts. The `prevOpenForExit` tracker (non-reactive, seeded via
|
|
81
|
+
// `untrack` like `prevPopoverMode` below) keeps the effect keyed on real
|
|
82
|
+
// transitions — without it, the `bind:this` assignment would re-run the
|
|
83
|
+
// effect on mount and flash a closed-by-default popover open for one lag.
|
|
84
|
+
const EXIT_MOTION_BUFFER_MS = 50;
|
|
85
|
+
let exiting = $state(false);
|
|
86
|
+
let exitTimer: ReturnType<typeof setTimeout> | undefined;
|
|
87
|
+
let prevOpenForExit = untrack(() => open);
|
|
88
|
+
$effect.pre(() => {
|
|
89
|
+
if (open === prevOpenForExit) return;
|
|
90
|
+
prevOpenForExit = open;
|
|
91
|
+
if (open) {
|
|
92
|
+
clearTimeout(exitTimer);
|
|
93
|
+
exiting = false;
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const ms = maxTransitionDurationMs(untrack(() => popoverElement));
|
|
97
|
+
if (ms <= 0) return;
|
|
98
|
+
exiting = true;
|
|
99
|
+
exitTimer = setTimeout(() => {
|
|
100
|
+
exiting = false;
|
|
101
|
+
}, ms + EXIT_MOTION_BUFFER_MS);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// While `exiting`, the panel is still fading: keep children mounted and (in
|
|
105
|
+
// the in-place modes) keep `display` un-hidden. `useFloatingPanel` stays on
|
|
106
|
+
// the raw `open` on purpose — `hidePopover()` fires immediately and the
|
|
107
|
+
// discrete transition carries the visual exit, so a re-open during the fade
|
|
108
|
+
// reverses smoothly instead of waiting out the lag.
|
|
109
|
+
const panelVisible = $derived(open || exiting);
|
|
110
|
+
|
|
55
111
|
// ── Floating UI positioning + native show/hide ─────────────
|
|
56
112
|
//
|
|
57
113
|
// Delegated to the shared `useFloatingPanel` helper — the same positioning
|
|
@@ -291,6 +347,27 @@
|
|
|
291
347
|
target?.focus();
|
|
292
348
|
}
|
|
293
349
|
|
|
350
|
+
// Un-arm `dismissedByTrigger` at the start of the NEXT pointer gesture,
|
|
351
|
+
// wherever it lands. Registered as a one-shot capture listener when the
|
|
352
|
+
// guard arms: capture order (document before trigger) guarantees a stale
|
|
353
|
+
// flag is cleared before any new arm, and `once` keeps at most one listener
|
|
354
|
+
// pending. This closes the aborted-click hole (pointerdown on the trigger,
|
|
355
|
+
// pointer released elsewhere → no click ever consumed the flag → the next
|
|
356
|
+
// trigger click was swallowed once).
|
|
357
|
+
function disarmDismissedByTrigger() {
|
|
358
|
+
dismissedByTrigger = false;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Unmount cleanup for the imperative leftovers: a pending exit-lag timer
|
|
362
|
+
// and a still-armed disarm listener. Dependency-free → runs once,
|
|
363
|
+
// teardown on destroy.
|
|
364
|
+
$effect(() => {
|
|
365
|
+
return () => {
|
|
366
|
+
clearTimeout(exitTimer);
|
|
367
|
+
document.removeEventListener('pointerdown', disarmDismissedByTrigger, true);
|
|
368
|
+
};
|
|
369
|
+
});
|
|
370
|
+
|
|
294
371
|
function handleTriggerPointerDown() {
|
|
295
372
|
// Arm the "this pointerdown already dismissed it" guard only in auto
|
|
296
373
|
// mode, where the browser's light dismiss really closes the popover
|
|
@@ -298,7 +375,15 @@
|
|
|
298
375
|
// re-opening it). In manual mode nothing light-dismisses — the click
|
|
299
376
|
// itself must toggle-close, so arming the guard there left the trigger
|
|
300
377
|
// unable to close its own popover.
|
|
301
|
-
if (open && popoverMode === 'auto')
|
|
378
|
+
if (open && popoverMode === 'auto') {
|
|
379
|
+
dismissedByTrigger = true;
|
|
380
|
+
// This event has already passed the document's capture phase, so the
|
|
381
|
+
// listener can only fire on a LATER pointerdown.
|
|
382
|
+
document.addEventListener('pointerdown', disarmDismissedByTrigger, {
|
|
383
|
+
capture: true,
|
|
384
|
+
once: true
|
|
385
|
+
});
|
|
386
|
+
}
|
|
302
387
|
}
|
|
303
388
|
|
|
304
389
|
function handleTriggerClick(event: MouseEvent) {
|
|
@@ -361,6 +446,20 @@
|
|
|
361
446
|
drops over a modal dialog (Codeberg #23).
|
|
362
447
|
-->
|
|
363
448
|
|
|
449
|
+
<!--
|
|
450
|
+
`data-state` sits after `{...restProps}` like the other load-bearing
|
|
451
|
+
attributes: it drives the enter/exit motion CSS (popoverMotion) and is the
|
|
452
|
+
documented styling hook for consumers rebuilding motion under `unstyled`.
|
|
453
|
+
`{#if panelVisible}` (not `open`) keeps the children mounted while the exit
|
|
454
|
+
transition plays; `style:display` follows the same lagged flag so the
|
|
455
|
+
in-place modes can fade out before they hide.
|
|
456
|
+
|
|
457
|
+
`inert` while closed (GuidePanel's pattern): the exit-fading children are
|
|
458
|
+
still mounted and displayed, so without it a Tab right after dismiss would
|
|
459
|
+
focus into the visually dismissed panel and Enter could re-fire a consumer
|
|
460
|
+
action; pointer-events-none (popoverMotion) only covers mouse/touch. Also
|
|
461
|
+
drops the fading subtree from the a11y tree immediately.
|
|
462
|
+
-->
|
|
364
463
|
<div
|
|
365
464
|
bind:this={popoverElement}
|
|
366
465
|
class={popoverClasses}
|
|
@@ -370,12 +469,16 @@
|
|
|
370
469
|
style:position={panel.strategy}
|
|
371
470
|
style:inset="auto"
|
|
372
471
|
style:margin="0"
|
|
373
|
-
style:display={floatingPanelHidden(panel,
|
|
472
|
+
style:display={floatingPanelHidden(panel, panelVisible) ? 'none' : null}
|
|
473
|
+
style:--blocks-popover-duration={popoverDurationInline}
|
|
474
|
+
style:--blocks-popover-easing={transitionEasing}
|
|
475
|
+
data-state={open ? 'open' : 'closed'}
|
|
476
|
+
inert={!open || undefined}
|
|
374
477
|
{role}
|
|
375
478
|
aria-modal={ariaModal || undefined}
|
|
376
479
|
{id}
|
|
377
480
|
>
|
|
378
|
-
{#if
|
|
481
|
+
{#if panelVisible}
|
|
379
482
|
{@render children()}
|
|
380
483
|
{/if}
|
|
381
484
|
</div>
|
|
@@ -70,6 +70,19 @@ export interface PopoverProps extends PopoverVariants, Omit<HTMLAttributes<HTMLD
|
|
|
70
70
|
open?: boolean;
|
|
71
71
|
/** When true (default), the trigger wrapper handles click and keyboard to toggle the popover. Set to `false` to manage `open` yourself. */
|
|
72
72
|
autoTrigger?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Override the enter/exit fade duration in ms. Defaults to the shared token
|
|
75
|
+
* `--blocks-popover-duration` (150ms; collapses to 1ms under
|
|
76
|
+
* `prefers-reduced-motion`).
|
|
77
|
+
*/
|
|
78
|
+
transitionDuration?: number;
|
|
79
|
+
/**
|
|
80
|
+
* Override the enter/exit easing as a CSS `<easing-function>` (e.g.
|
|
81
|
+
* `'linear'`, `'ease-out'`, `'cubic-bezier(0.4,0,0.2,1)'`). Defaults to the
|
|
82
|
+
* token `--blocks-popover-easing`. A CSS string, not a JS easing fn, because
|
|
83
|
+
* the popover motion is a pure CSS transition.
|
|
84
|
+
*/
|
|
85
|
+
transitionEasing?: string;
|
|
73
86
|
/**
|
|
74
87
|
* Whether the popover closes on Escape key. Default `true`.
|
|
75
88
|
* Set to `false` for cases where Escape should be intercepted by an
|
|
@@ -98,7 +111,7 @@ export interface PopoverProps extends PopoverVariants, Omit<HTMLAttributes<HTMLD
|
|
|
98
111
|
onEscape?: () => void;
|
|
99
112
|
/** Extra classes merged onto the floating panel element. */
|
|
100
113
|
class?: string;
|
|
101
|
-
/** Strip all default tv() classes. Combine with `class` or `slotClasses` for full custom styling. */
|
|
114
|
+
/** Strip all default tv() classes (including the enter/exit motion). Combine with `class` or `slotClasses` for full custom styling; the panel always carries `data-state="open" | "closed"`, so custom motion can rebuild on that hook (see `popoverMotion` in popover.variants.ts for the reference implementation). */
|
|
102
115
|
unstyled?: boolean;
|
|
103
116
|
/** Per-slot class overrides. Available slots: `base` (the floating panel). */
|
|
104
117
|
slotClasses?: Partial<Record<'base', string>>;
|
|
@@ -111,4 +124,4 @@ export interface PopoverProps extends PopoverVariants, Omit<HTMLAttributes<HTMLD
|
|
|
111
124
|
preset?: string;
|
|
112
125
|
}
|
|
113
126
|
export { default as Popover } from './Popover.svelte';
|
|
114
|
-
export { type PopoverVariants, popoverVariants } from './popover.variants.js';
|
|
127
|
+
export { type PopoverVariants, popoverMotion, popoverVariants } from './popover.variants.js';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { default as Popover } from './Popover.svelte';
|
|
2
|
-
export { popoverVariants } from './popover.variants.js';
|
|
2
|
+
export { popoverMotion, popoverVariants } from './popover.variants.js';
|
|
@@ -1,4 +1,29 @@
|
|
|
1
1
|
import { type VariantProps } from '../../utils/variants.js';
|
|
2
|
+
/**
|
|
3
|
+
* CSS-native enter/exit motion for the floating panel (ACC-3 rest), keyed on
|
|
4
|
+
* the `data-state` attribute Popover always stamps. Kept as its own fragment
|
|
5
|
+
* because two call sites need exactly these classes: `popoverVariants.base`
|
|
6
|
+
* below, and Menu — which renders its inner Popover `unstyled` (to avoid a
|
|
7
|
+
* double surface) and re-applies the fragment via Popover's `class` prop.
|
|
8
|
+
*
|
|
9
|
+
* How the two halves work:
|
|
10
|
+
* - **Enter** — the panel un-hides via `showPopover()` (top layer) or a
|
|
11
|
+
* `display` flip (in-place mode), so a plain transition has no before-state;
|
|
12
|
+
* `starting:` (`@starting-style`) supplies it.
|
|
13
|
+
* - **Exit** — `hidePopover()` / a native light dismiss yank the panel to
|
|
14
|
+
* `display: none` in the same style recalc that flips `data-state`;
|
|
15
|
+
* `transition-discrete` (`transition-behavior: allow-discrete`) on
|
|
16
|
+
* `display`/`overlay` keeps it painted (and in the top layer) until the
|
|
17
|
+
* fade lands. Popover lags the children-teardown to match — see the
|
|
18
|
+
* exit-motion block in Popover.svelte.
|
|
19
|
+
*
|
|
20
|
+
* Browsers without `@starting-style`/`allow-discrete` simply skip the motion
|
|
21
|
+
* and keep today's instant toggle. Duration/easing resolve through the
|
|
22
|
+
* `--blocks-popover-*` tokens (interaction.css), which reduced motion
|
|
23
|
+
* collapses to 1ms; `motion-reduce:duration-[1ms]` guards the inline
|
|
24
|
+
* per-instance override path, which can't see the media query.
|
|
25
|
+
*/
|
|
26
|
+
export declare const popoverMotion: string;
|
|
2
27
|
export declare const popoverVariants: ((props?: import("../../utils/variants.js").TVProps<{
|
|
3
28
|
size: {
|
|
4
29
|
sm: string;
|
|
@@ -1,9 +1,44 @@
|
|
|
1
1
|
import { tv } from '../../utils/variants.js';
|
|
2
|
+
/**
|
|
3
|
+
* CSS-native enter/exit motion for the floating panel (ACC-3 rest), keyed on
|
|
4
|
+
* the `data-state` attribute Popover always stamps. Kept as its own fragment
|
|
5
|
+
* because two call sites need exactly these classes: `popoverVariants.base`
|
|
6
|
+
* below, and Menu — which renders its inner Popover `unstyled` (to avoid a
|
|
7
|
+
* double surface) and re-applies the fragment via Popover's `class` prop.
|
|
8
|
+
*
|
|
9
|
+
* How the two halves work:
|
|
10
|
+
* - **Enter** — the panel un-hides via `showPopover()` (top layer) or a
|
|
11
|
+
* `display` flip (in-place mode), so a plain transition has no before-state;
|
|
12
|
+
* `starting:` (`@starting-style`) supplies it.
|
|
13
|
+
* - **Exit** — `hidePopover()` / a native light dismiss yank the panel to
|
|
14
|
+
* `display: none` in the same style recalc that flips `data-state`;
|
|
15
|
+
* `transition-discrete` (`transition-behavior: allow-discrete`) on
|
|
16
|
+
* `display`/`overlay` keeps it painted (and in the top layer) until the
|
|
17
|
+
* fade lands. Popover lags the children-teardown to match — see the
|
|
18
|
+
* exit-motion block in Popover.svelte.
|
|
19
|
+
*
|
|
20
|
+
* Browsers without `@starting-style`/`allow-discrete` simply skip the motion
|
|
21
|
+
* and keep today's instant toggle. Duration/easing resolve through the
|
|
22
|
+
* `--blocks-popover-*` tokens (interaction.css), which reduced motion
|
|
23
|
+
* collapses to 1ms; `motion-reduce:duration-[1ms]` guards the inline
|
|
24
|
+
* per-instance override path, which can't see the media query.
|
|
25
|
+
*/
|
|
26
|
+
export const popoverMotion = [
|
|
27
|
+
'transition-[opacity,scale,display,overlay] transition-discrete',
|
|
28
|
+
'duration-[var(--blocks-popover-duration)] ease-[var(--blocks-popover-easing)]',
|
|
29
|
+
'motion-reduce:duration-[1ms]',
|
|
30
|
+
// pointer-events-none while closed: during the exit fade the children are
|
|
31
|
+
// still mounted and painted — without this, a quick click on the fading
|
|
32
|
+
// panel would fire consumer handlers from a visually dismissed surface.
|
|
33
|
+
'data-[state=closed]:opacity-0 data-[state=closed]:scale-[0.98] data-[state=closed]:pointer-events-none',
|
|
34
|
+
'starting:data-[state=open]:opacity-0 starting:data-[state=open]:scale-[0.98]'
|
|
35
|
+
].join(' ');
|
|
2
36
|
export const popoverVariants = tv({
|
|
3
37
|
// tier: contain — floating panel surface.
|
|
4
38
|
base: [
|
|
5
39
|
'bg-surface-elevated border border-border-hairline rounded-contain',
|
|
6
40
|
'shadow-[var(--blocks-shadow-md)] backdrop-blur-sm',
|
|
41
|
+
popoverMotion,
|
|
7
42
|
// `calc(100dvh-4rem)` is the static design cap; Floating UI's `size`
|
|
8
43
|
// middleware (via useFloatingPanel) narrows it to the room actually left
|
|
9
44
|
// between the anchor and the visual viewport edge through
|
|
@@ -66,7 +66,7 @@ export const radioItemVariants = tv({
|
|
|
66
66
|
indicator: 'w-3.5 h-3.5 mt-px',
|
|
67
67
|
dot: 'w-1.5 h-1.5',
|
|
68
68
|
label: 'text-xs',
|
|
69
|
-
description: 'text-
|
|
69
|
+
description: 'text-3xs'
|
|
70
70
|
},
|
|
71
71
|
sm: {
|
|
72
72
|
item: 'gap-2',
|
|
@@ -157,7 +157,7 @@ export const radioItemVariants = tv({
|
|
|
157
157
|
{
|
|
158
158
|
checked: true,
|
|
159
159
|
intent: 'warning',
|
|
160
|
-
class: { indicator: 'bg-warning border-warning', dot: 'bg-
|
|
160
|
+
class: { indicator: 'bg-warning border-warning', dot: 'bg-text-on-warning' }
|
|
161
161
|
},
|
|
162
162
|
{
|
|
163
163
|
checked: true,
|
|
@@ -256,7 +256,14 @@ interface SelectBaseProps<T extends SelectValue = string> extends Omit<SelectVar
|
|
|
256
256
|
* and make the custom look reusable across the project.
|
|
257
257
|
*/
|
|
258
258
|
preset?: string;
|
|
259
|
-
/**
|
|
259
|
+
/**
|
|
260
|
+
* Explicit `id` for the component. Auto-generated if omitted.
|
|
261
|
+
*
|
|
262
|
+
* The id lands on the component's wrapper, which is not a labelable element.
|
|
263
|
+
* The focusable trigger is derived from it as `` `${id}-trigger` `` — that is
|
|
264
|
+
* the id an external `<label for>` has to address, since a `for` pointing at
|
|
265
|
+
* the wrapper focuses nothing.
|
|
266
|
+
*/
|
|
260
267
|
id?: string;
|
|
261
268
|
}
|
|
262
269
|
/**
|