@svelte-atoms/core 1.0.0-alpha.30 → 1.0.0-alpha.32
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/LICENSE +21 -0
- package/README.md +176 -739
- package/dist/attachments/index.d.ts +1 -0
- package/dist/attachments/index.js +1 -0
- package/dist/components/accordion/accordion-root.svelte +65 -61
- package/dist/components/accordion/accordion.stories.svelte +70 -145
- package/dist/components/accordion/item/accordion-item-body.svelte +6 -4
- package/dist/components/accordion/item/accordion-item-header.svelte +2 -1
- package/dist/components/accordion/item/accordion-item-indicator.svelte +2 -1
- package/dist/components/accordion/item/accordion-item-root.svelte +2 -1
- package/dist/components/accordion/item/bond.svelte.d.ts +2 -0
- package/dist/components/accordion/item/index.d.ts +3 -0
- package/dist/components/accordion/item/index.js +3 -0
- package/dist/components/accordion/item/motion.svelte.d.ts +15 -0
- package/dist/components/accordion/item/motion.svelte.js +30 -0
- package/dist/components/accordion/item/types.d.ts +7 -24
- package/dist/components/alert/alert-close-button.svelte +32 -36
- package/dist/components/alert/alert-description.svelte +1 -1
- package/dist/components/alert/alert-description.svelte.d.ts +3 -6
- package/dist/components/alert/alert-root.svelte +3 -38
- package/dist/components/alert/alert-root.svelte.d.ts +2 -2
- package/dist/components/alert/alert.stories.svelte +400 -400
- package/dist/components/alert/bond.svelte.d.ts +0 -13
- package/dist/components/alert/bond.svelte.js +0 -32
- package/dist/components/alert/types.d.ts +8 -32
- package/dist/components/atom/html-atom.svelte +93 -261
- package/dist/components/atom/types.d.ts +3 -2
- package/dist/components/atom/utils.d.ts +37 -0
- package/dist/components/atom/utils.js +208 -0
- package/dist/components/avatar/avatar.stories.svelte +22 -22
- package/dist/components/badge/badge.stories.svelte +12 -12
- package/dist/components/badge/badge.svelte +19 -19
- package/dist/components/breadcrumb/breadcrumb-item.svelte +1 -1
- package/dist/components/breadcrumb/breadcrumb-separator.svelte +5 -1
- package/dist/components/breadcrumb/breadcrumb.stories.svelte +16 -16
- package/dist/components/button/button.stories.svelte +27 -27
- package/dist/components/calendar/calendar-day.svelte +9 -4
- package/dist/components/calendar/calendar.stories.svelte +26 -26
- package/dist/components/card/card-body.svelte +39 -39
- package/dist/components/card/card-footer.svelte +41 -41
- package/dist/components/card/card-root.svelte +91 -91
- package/dist/components/card/card.stories.svelte +133 -133
- package/dist/components/checkbox/checkbox.stories.svelte +22 -22
- package/dist/components/checkbox/checkbox.svelte +159 -155
- package/dist/components/collapsible/bond.svelte.js +2 -1
- package/dist/components/collapsible/collapsible-body.svelte +3 -2
- package/dist/components/collapsible/collapsible.stories.svelte +172 -172
- package/dist/components/collapsible/motion.svelte.d.ts +6 -0
- package/dist/components/collapsible/motion.svelte.js +15 -0
- package/dist/components/combobox/atoms.d.ts +3 -3
- package/dist/components/combobox/atoms.js +3 -3
- package/dist/components/combobox/bond.svelte.d.ts +6 -6
- package/dist/components/combobox/bond.svelte.js +3 -26
- package/dist/components/combobox/combobox-control.svelte +52 -52
- package/dist/components/combobox/{compobox-item.svelte → combobox-item.svelte} +62 -68
- package/dist/components/combobox/combobox-item.svelte.d.ts +12 -0
- package/dist/components/combobox/combobox-root.svelte +65 -65
- package/dist/components/combobox/combobox.stories.svelte +50 -0
- package/dist/components/combobox/combobox.stories.svelte.d.ts +3 -0
- package/dist/components/combobox/index.d.ts +1 -0
- package/dist/components/container/container.stories.svelte +20 -20
- package/dist/components/container/container.svelte.d.ts +1 -1
- package/dist/components/datagrid/datagrid.stories.svelte +72 -72
- package/dist/components/datagrid/tr/bond.svelte.d.ts +4 -2
- package/dist/components/datagrid/tr/bond.svelte.js +9 -7
- package/dist/components/datagrid/tr/datagrid-tr.svelte +9 -7
- package/dist/components/date-picker/bond.svelte.d.ts +15 -5
- package/dist/components/date-picker/bond.svelte.js +5 -11
- package/dist/components/date-picker/date-picker-calendar.svelte +2 -2
- package/dist/components/date-picker/date-picker-root.svelte +95 -95
- package/dist/components/date-picker/date-picker.stories.svelte +35 -35
- package/dist/components/dialog/bond.svelte.d.ts +13 -3
- package/dist/components/dialog/bond.svelte.js +52 -6
- package/dist/components/dialog/dialog-content.svelte +2 -20
- package/dist/components/dialog/dialog-root.svelte +3 -22
- package/dist/components/dialog/dialog.stories.svelte +64 -64
- package/dist/components/dialog/motion.svelte.d.ts +13 -0
- package/dist/components/dialog/motion.svelte.js +44 -0
- package/dist/components/drawer/attachments.svelte.d.ts +1 -1
- package/dist/components/drawer/attachments.svelte.js +1 -3
- package/dist/components/drawer/bond.svelte.d.ts +30 -9
- package/dist/components/drawer/bond.svelte.js +80 -24
- package/dist/components/drawer/drawer-content.svelte +49 -57
- package/dist/components/drawer/drawer-root.svelte +5 -4
- package/dist/components/drawer/drawer.stories.svelte +141 -212
- package/dist/components/drawer/index.d.ts +2 -0
- package/dist/components/drawer/index.js +2 -0
- package/dist/components/drawer/motion.d.ts +15 -0
- package/dist/components/drawer/motion.js +28 -0
- package/dist/components/dropdown/atoms.d.ts +1 -1
- package/dist/components/dropdown/atoms.js +1 -1
- package/dist/components/dropdown/bond.svelte.d.ts +22 -19
- package/dist/components/dropdown/bond.svelte.js +29 -53
- package/dist/components/dropdown/dropdown-root.svelte +7 -1
- package/dist/components/dropdown/dropdown-values.svelte +17 -17
- package/dist/components/dropdown/dropdown-values.svelte.d.ts +1 -2
- package/dist/components/dropdown/dropdown.stories.svelte +13 -10
- package/dist/components/dropdown/index.d.ts +2 -0
- package/dist/components/dropdown/index.js +1 -0
- package/dist/components/dropdown/item/attachments.svelte.d.ts +2 -2
- package/dist/components/dropdown/item/attachments.svelte.js +2 -2
- package/dist/components/dropdown/item/controller.svelte.d.ts +34 -0
- package/dist/components/dropdown/item/controller.svelte.js +82 -0
- package/dist/components/dropdown/item/dropdown-item.svelte +109 -102
- package/dist/components/dropdown/item/dropdown-item.svelte.d.ts +13 -28
- package/dist/components/dropdown/item/index.d.ts +3 -0
- package/dist/components/dropdown/item/index.js +3 -0
- package/dist/components/dropdown/item/types.d.ts +29 -0
- package/dist/components/dropdown/item/types.js +1 -0
- package/dist/components/form/form.stories.svelte +96 -96
- package/dist/components/image/image.stories.svelte +20 -20
- package/dist/components/input/input.stories.svelte +35 -35
- package/dist/components/label/label.stories.svelte +15 -15
- package/dist/components/lazy/lazy.stories.svelte +28 -28
- package/dist/components/link/link.stories.svelte +15 -15
- package/dist/components/list/list-item.svelte +2 -2
- package/dist/components/menu/atoms.d.ts +9 -3
- package/dist/components/menu/atoms.js +9 -3
- package/dist/components/menu/bond.svelte.d.ts +54 -0
- package/dist/components/menu/bond.svelte.js +132 -0
- package/dist/components/menu/index.d.ts +3 -1
- package/dist/components/menu/index.js +2 -1
- package/dist/components/menu/item/controller.svelte.d.ts +26 -0
- package/dist/components/menu/item/controller.svelte.js +69 -0
- package/dist/components/menu/item/index.d.ts +2 -0
- package/dist/components/menu/item/index.js +2 -0
- package/dist/components/menu/item/menu-item.svelte +103 -0
- package/dist/components/menu/item/menu-item.svelte.d.ts +31 -0
- package/dist/components/menu/item/types.d.ts +62 -0
- package/dist/components/menu/item/types.js +1 -0
- package/dist/components/menu/{menu-list.svelte → menu-content.svelte} +40 -40
- package/dist/components/menu/{menu-list.svelte.d.ts → menu-content.svelte.d.ts} +3 -3
- package/dist/components/menu/menu-root.svelte +15 -0
- package/dist/components/menu/menu-root.svelte.d.ts +8 -0
- package/dist/components/menu/menu.stories.svelte +5 -5
- package/dist/components/menu/types.d.ts +0 -7
- package/dist/components/popover/bond.svelte.d.ts +18 -8
- package/dist/components/popover/bond.svelte.js +76 -40
- package/dist/components/popover/motion.d.ts +6 -0
- package/dist/components/popover/motion.js +56 -0
- package/dist/components/popover/popover-arrow.svelte +111 -111
- package/dist/components/popover/popover-content.svelte +137 -175
- package/dist/components/popover/popover-indicator.svelte +44 -44
- package/dist/components/popover/popover-root.svelte +48 -48
- package/dist/components/popover/popover.stories.svelte +37 -49
- package/dist/components/popover/types.d.ts +9 -7
- package/dist/components/portal/active-portal.svelte +12 -5
- package/dist/components/portal/active-portal.svelte.d.ts +2 -9
- package/dist/components/portal/portal-root.svelte +1 -8
- package/dist/components/portal/portal-root.svelte.d.ts +4 -6
- package/dist/components/portal/teleport.svelte +1 -2
- package/dist/components/portal/teleport.svelte.d.ts +3 -4
- package/dist/components/qr-code/qr-code.stories.svelte +18 -18
- package/dist/components/radio/radio-group.stories.svelte +41 -41
- package/dist/components/radio/radio.stories.svelte +17 -17
- package/dist/components/radio/radio.svelte +109 -109
- package/dist/components/radio/types.d.ts +98 -0
- package/dist/components/radio/types.js +2 -0
- package/dist/components/root/index.d.ts +1 -0
- package/dist/components/root/index.js +1 -0
- package/dist/components/root/l0-portal.svelte +8 -0
- package/dist/components/{radio/types.svelte.d.ts → root/l0-portal.svelte.d.ts} +3 -3
- package/dist/components/root/l1-portal.svelte +7 -0
- package/dist/components/root/l1-portal.svelte.d.ts +26 -0
- package/dist/components/root/root.css +119 -119
- package/dist/components/root/root.svelte +26 -44
- package/dist/components/root/root.svelte.d.ts +2 -6
- package/dist/components/root/toasts-portal.svelte +7 -0
- package/dist/components/root/toasts-portal.svelte.d.ts +26 -0
- package/dist/components/root/types.d.ts +17 -0
- package/dist/components/scrollable/scrollable-root.svelte.d.ts +2 -2
- package/dist/components/scrollable/scrollable.stories.svelte +116 -116
- package/dist/components/sidebar/index.d.ts +2 -0
- package/dist/components/sidebar/index.js +2 -0
- package/dist/components/sidebar/motion.svelte.d.ts +11 -0
- package/dist/components/sidebar/motion.svelte.js +16 -0
- package/dist/components/sidebar/sidebar-content.svelte +40 -50
- package/dist/components/sidebar/sidebar-root.svelte +39 -39
- package/dist/components/sidebar/sidebar.stories.svelte +43 -43
- package/dist/components/sidebar/types.d.ts +2 -12
- package/dist/components/tabs/tabs.stories.svelte +56 -56
- package/dist/components/textarea/atoms.d.ts +1 -0
- package/dist/components/textarea/atoms.js +1 -0
- package/dist/components/textarea/textarea-input.svelte +4 -1
- package/dist/components/textarea/textarea-root.svelte +2 -2
- package/dist/components/textarea/textarea-root.svelte.d.ts +2 -0
- package/dist/components/tooltip/tooltip-trigger.svelte +39 -39
- package/dist/components/tooltip/tooltip-trigger.svelte.d.ts +1 -0
- package/dist/components/tooltip/tooltip.stories.svelte +32 -32
- package/dist/components/tree/index.d.ts +1 -0
- package/dist/components/tree/index.js +1 -0
- package/dist/components/tree/motion.svelte.d.ts +6 -0
- package/dist/components/tree/motion.svelte.js +14 -0
- package/dist/components/tree/tree-body.svelte +4 -3
- package/dist/components/tree/tree.stories.svelte +142 -142
- package/dist/context/preset.svelte.d.ts +3 -1
- package/dist/icons/icon-copy.svelte +6 -0
- package/dist/icons/icon-copy.svelte.d.ts +26 -0
- package/dist/utils/dom.svelte.d.ts +2 -0
- package/dist/utils/dom.svelte.js +21 -0
- package/dist/utils/function.d.ts +1 -1
- package/dist/utils/promise.svelte.d.ts +5 -0
- package/dist/utils/promise.svelte.js +20 -0
- package/package.json +4 -3
- package/dist/components/combobox/compobox-item.svelte.d.ts +0 -34
- package/dist/components/combobox/compobox.stories.svelte +0 -51
- package/dist/components/combobox/compobox.stories.svelte.d.ts +0 -3
- package/dist/components/dropdown/item/bond.svelte.d.ts +0 -42
- package/dist/components/dropdown/item/bond.svelte.js +0 -99
- package/dist/components/menu/menu-item.svelte +0 -51
- package/dist/components/menu/menu-item.svelte.d.ts +0 -36
- package/dist/components/radio/types.svelte +0 -0
- package/llm/composition.md +0 -395
- package/llm/crafting.md +0 -838
- package/llm/motion.md +0 -970
- package/llm/philosophy.md +0 -23
- package/llm/preset-variant-integration.md +0 -516
- package/llm/preset.md +0 -383
- package/llm/styling.md +0 -216
- package/llm/usage.md +0 -46
- package/llm/variants.md +0 -1259
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { getContext, setContext, untrack } from 'svelte';
|
|
2
2
|
import { createAttachmentKey } from 'svelte/attachments';
|
|
3
3
|
import { autoUpdate, computePosition, arrow, flip, offset } from '@floating-ui/dom';
|
|
4
|
-
import {
|
|
5
|
-
import { getElementId, isBrowser } from '../../utils/dom.svelte.js';
|
|
4
|
+
import { focus, focusTrap, getElementId, isBrowser } from '../../utils/dom.svelte.js';
|
|
6
5
|
import { Bond, BondState } from '../../shared/bond.svelte.js';
|
|
7
6
|
const POPOVER_ELEMENTS_KIND = {
|
|
8
7
|
trigger: 'popover-trigger',
|
|
@@ -12,14 +11,11 @@ const POPOVER_ELEMENTS_KIND = {
|
|
|
12
11
|
};
|
|
13
12
|
export class PopoverBond extends Bond {
|
|
14
13
|
static CONTEXT_KEY = '@atomic-sv/bonds/popover';
|
|
15
|
-
|
|
14
|
+
position = $state();
|
|
16
15
|
constructor(state) {
|
|
17
16
|
super(state);
|
|
18
17
|
}
|
|
19
|
-
|
|
20
|
-
return this.#position;
|
|
21
|
-
}
|
|
22
|
-
trigger(props = {}) {
|
|
18
|
+
trigger() {
|
|
23
19
|
const isButtonElement = isBrowser()
|
|
24
20
|
? this.elements.trigger instanceof HTMLButtonElement
|
|
25
21
|
: false;
|
|
@@ -30,12 +26,13 @@ export class PopoverBond extends Bond {
|
|
|
30
26
|
const overlayId = getElementId(this.id, POPOVER_ELEMENTS_KIND.content);
|
|
31
27
|
return {
|
|
32
28
|
id,
|
|
33
|
-
role: isButtonElement ? '' : 'button',
|
|
29
|
+
role: isButtonElement ? '' : 'button',
|
|
34
30
|
disabled: isButtonElement ? isDisabled : undefined,
|
|
35
|
-
tabindex: isDisabled ? -1 : 0,
|
|
31
|
+
tabindex: isDisabled ? -1 : 0,
|
|
36
32
|
'aria-expanded': isOpen,
|
|
37
33
|
'aria-disabled': isDisabled,
|
|
38
34
|
'aria-controls': overlayId,
|
|
35
|
+
'aria-haspopup': 'dialog',
|
|
39
36
|
'data-kind': kind,
|
|
40
37
|
onclick: (ev) => {
|
|
41
38
|
if (ev.button === 2) {
|
|
@@ -46,16 +43,30 @@ export class PopoverBond extends Bond {
|
|
|
46
43
|
}
|
|
47
44
|
this.state.toggle();
|
|
48
45
|
},
|
|
49
|
-
|
|
46
|
+
onkeydown: (ev) => {
|
|
47
|
+
if (isDisabled)
|
|
48
|
+
return;
|
|
49
|
+
// Toggle on Enter or Space
|
|
50
|
+
if (ev.key === 'Enter' || ev.key === ' ') {
|
|
51
|
+
this.state.toggle();
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (ev.key === 'Tab') {
|
|
55
|
+
this.elements.content?.focus();
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (ev.key === 'Escape') {
|
|
59
|
+
this.state.close();
|
|
60
|
+
}
|
|
61
|
+
},
|
|
50
62
|
[createAttachmentKey()]: (node) => {
|
|
51
63
|
this.elements.trigger = node;
|
|
52
|
-
const position = untrack(() => this
|
|
64
|
+
const position = untrack(() => this.position);
|
|
53
65
|
if (!position) {
|
|
54
66
|
const init = async () => {
|
|
55
67
|
popover(this)({
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
this.#position = position;
|
|
68
|
+
onchange: (_node, position) => {
|
|
69
|
+
this.position = position;
|
|
59
70
|
}
|
|
60
71
|
});
|
|
61
72
|
const pointerLeaveHandler = () => {
|
|
@@ -72,61 +83,85 @@ export class PopoverBond extends Bond {
|
|
|
72
83
|
}
|
|
73
84
|
};
|
|
74
85
|
}
|
|
75
|
-
content(
|
|
86
|
+
content() {
|
|
76
87
|
const kind = POPOVER_ELEMENTS_KIND.content;
|
|
77
88
|
const id = getElementId(this.id, kind);
|
|
78
89
|
const triggerId = getElementId(this.id, POPOVER_ELEMENTS_KIND.trigger);
|
|
79
90
|
const isOpen = this.state?.props?.open ?? false;
|
|
80
91
|
const isDisabled = this.state?.props?.disabled ?? false;
|
|
81
92
|
const isActive = isOpen && !isDisabled;
|
|
93
|
+
// Focus management
|
|
94
|
+
const focusManager = (ev) => {
|
|
95
|
+
if (ev.key === 'Escape') {
|
|
96
|
+
this.state.close();
|
|
97
|
+
this.elements.trigger?.focus();
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
focusTrap(ev);
|
|
101
|
+
};
|
|
82
102
|
return {
|
|
83
103
|
id,
|
|
84
|
-
role: 'dialog',
|
|
85
|
-
'aria-modal':
|
|
86
|
-
'aria-labelledby': triggerId,
|
|
87
|
-
|
|
104
|
+
role: 'dialog',
|
|
105
|
+
'aria-modal': false,
|
|
106
|
+
'aria-labelledby': triggerId,
|
|
107
|
+
inert: !isActive ? true : undefined,
|
|
108
|
+
tabindex: -1,
|
|
88
109
|
'data-atom': this.id,
|
|
89
|
-
'data-kind': '
|
|
110
|
+
'data-kind': 'content',
|
|
90
111
|
'data-active': isActive,
|
|
91
|
-
|
|
112
|
+
onkeydown: isOpen ? focusManager : undefined,
|
|
92
113
|
[createAttachmentKey()]: (node) => {
|
|
93
114
|
this.elements.content = node;
|
|
94
|
-
|
|
115
|
+
const triggerElement = this.elements.trigger;
|
|
116
|
+
if (!triggerElement) {
|
|
95
117
|
return;
|
|
96
118
|
}
|
|
97
|
-
if (!this.state.isOpen)
|
|
119
|
+
if (!this.state.isOpen) {
|
|
98
120
|
return;
|
|
99
|
-
|
|
100
|
-
|
|
121
|
+
}
|
|
122
|
+
// check if trigger contains a focusable element and the focus is already inside
|
|
123
|
+
// check if the in-focus element is an input, textarea or select to avoid stealing focus
|
|
124
|
+
const activeElement = document.activeElement;
|
|
125
|
+
const triggerContainsFocus = ['input', 'textarea'].includes(activeElement.tagName.toLowerCase()) ||
|
|
126
|
+
triggerElement === activeElement ||
|
|
127
|
+
triggerElement.contains(activeElement);
|
|
128
|
+
// Move focus to popover when opened
|
|
129
|
+
if (!triggerContainsFocus) {
|
|
130
|
+
setTimeout(() => focus(node), 0);
|
|
131
|
+
}
|
|
132
|
+
const cleanup = popover(this)({
|
|
101
133
|
onchange: (node, position) => {
|
|
102
|
-
this
|
|
103
|
-
props.onchange?.(node, position);
|
|
134
|
+
this.position = position;
|
|
104
135
|
}
|
|
105
136
|
}, autoUpdate);
|
|
137
|
+
return () => {
|
|
138
|
+
cleanup?.();
|
|
139
|
+
};
|
|
106
140
|
}
|
|
107
141
|
};
|
|
108
142
|
}
|
|
109
|
-
indicator(
|
|
143
|
+
indicator() {
|
|
110
144
|
const kind = POPOVER_ELEMENTS_KIND.indicator;
|
|
111
145
|
const id = getElementId(this.id, kind);
|
|
112
|
-
const
|
|
146
|
+
const isOpen = this.state?.props?.open ?? false;
|
|
113
147
|
return {
|
|
114
148
|
id,
|
|
115
|
-
'aria-
|
|
149
|
+
'aria-hidden': true,
|
|
150
|
+
'aria-live': isOpen ? 'polite' : 'off',
|
|
116
151
|
'data-kind': kind,
|
|
117
|
-
...props,
|
|
118
152
|
[createAttachmentKey()]: (node) => {
|
|
119
153
|
this.elements.indicator = node;
|
|
120
154
|
}
|
|
121
155
|
};
|
|
122
156
|
}
|
|
123
|
-
arrow(
|
|
157
|
+
arrow() {
|
|
124
158
|
const kind = POPOVER_ELEMENTS_KIND.arrow;
|
|
125
159
|
const id = getElementId(this.id, kind);
|
|
126
160
|
return {
|
|
127
161
|
id: id,
|
|
162
|
+
role: 'presentation',
|
|
163
|
+
'aria-hidden': true,
|
|
128
164
|
'data-kind': kind,
|
|
129
|
-
...props,
|
|
130
165
|
[createAttachmentKey()]: (node) => {
|
|
131
166
|
this.elements.arrow = node;
|
|
132
167
|
}
|
|
@@ -167,8 +202,6 @@ function popover(bond) {
|
|
|
167
202
|
return;
|
|
168
203
|
}
|
|
169
204
|
const { content, trigger, arrow: arrowElement } = bond.elements;
|
|
170
|
-
// Set minimum width to match trigger
|
|
171
|
-
content.style.minWidth = `${trigger.clientWidth}px`;
|
|
172
205
|
// Build middleware stack
|
|
173
206
|
const middleware = [
|
|
174
207
|
offset(ofs),
|
|
@@ -183,17 +216,20 @@ function popover(bond) {
|
|
|
183
216
|
}
|
|
184
217
|
// Debounce position change callback
|
|
185
218
|
const onchangeCallback = props.onchange;
|
|
186
|
-
const onchangeDebounced = debounce((node, position) => {
|
|
187
|
-
onchangeCallback?.(node, position);
|
|
188
|
-
}, 1000 / 60 // ~16ms for 60fps
|
|
189
|
-
);
|
|
190
219
|
// Compute position and notify listeners
|
|
191
220
|
const compute = async () => {
|
|
221
|
+
// Wait for next frame to ensure DOM has settled and styles are applied
|
|
222
|
+
// Double requestAnimationFrame - This ensures the browser has completed both layout calculation AND painting, giving us accurate final dimensions
|
|
223
|
+
await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(resolve)));
|
|
192
224
|
const position = await computePosition(trigger, content, {
|
|
193
225
|
placement: placement ?? 'bottom',
|
|
194
226
|
middleware
|
|
195
227
|
});
|
|
196
|
-
|
|
228
|
+
onchangeCallback?.(content, position);
|
|
229
|
+
// Set minimum width to match trigger
|
|
230
|
+
requestAnimationFrame(() => {
|
|
231
|
+
content.style.minWidth = `${trigger.clientWidth}px`;
|
|
232
|
+
});
|
|
197
233
|
};
|
|
198
234
|
// Use auto-update if provided, otherwise compute once
|
|
199
235
|
if (updater) {
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { animate } from 'motion';
|
|
2
|
+
import { PopoverBond } from '.';
|
|
3
|
+
import { DURATION } from '../../shared';
|
|
4
|
+
export function animatePopoverContent(params = {}) {
|
|
5
|
+
return (node) => {
|
|
6
|
+
const bond = PopoverBond.get();
|
|
7
|
+
const { duration = DURATION.quick / 1000, delay = 0, ease = 'easeInOut' } = params;
|
|
8
|
+
const isOpen = bond?.state.props.open ?? false;
|
|
9
|
+
const position = bond.position;
|
|
10
|
+
const placement = position?.placement;
|
|
11
|
+
const x = position?.x ?? 0;
|
|
12
|
+
const y = position?.y ?? 0;
|
|
13
|
+
const dy = placement?.startsWith('top') ? -1 : placement?.startsWith('bottom') ? 1 : 0;
|
|
14
|
+
const dx = placement?.startsWith('left') ? -1 : placement?.startsWith('right') ? 1 : 0;
|
|
15
|
+
const offset = bond.state.props.offset;
|
|
16
|
+
const xOffset = dx * offset;
|
|
17
|
+
const yOffset = dy * offset;
|
|
18
|
+
const openAsNumber = +isOpen;
|
|
19
|
+
const deltaArrow = position?.middlewareData?.arrow ? 1 : 0;
|
|
20
|
+
const arrowClientWidth = bond?.elements.arrow?.clientWidth ?? 0;
|
|
21
|
+
const arrowClientHeight = bond?.elements.arrow?.clientHeight ?? 0;
|
|
22
|
+
const getTransformOrigin = () => {
|
|
23
|
+
switch (placement) {
|
|
24
|
+
case 'top':
|
|
25
|
+
case 'top-start':
|
|
26
|
+
case 'top-end':
|
|
27
|
+
return 'bottom';
|
|
28
|
+
case 'bottom':
|
|
29
|
+
case 'bottom-start':
|
|
30
|
+
case 'bottom-end':
|
|
31
|
+
return 'top';
|
|
32
|
+
case 'left':
|
|
33
|
+
case 'left-start':
|
|
34
|
+
case 'left-end':
|
|
35
|
+
return 'right';
|
|
36
|
+
case 'right':
|
|
37
|
+
case 'right-start':
|
|
38
|
+
case 'right-end':
|
|
39
|
+
return 'left';
|
|
40
|
+
default:
|
|
41
|
+
return 'center';
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const transformOrigin = getTransformOrigin();
|
|
45
|
+
const from = isOpen ? 1 : 0.95;
|
|
46
|
+
animate(node, {
|
|
47
|
+
opacity: openAsNumber,
|
|
48
|
+
y: dy * (!isOpen ? -1 : 0) * (arrowClientHeight + yOffset),
|
|
49
|
+
x: dx * (!isOpen ? -1 : 0) * (arrowClientWidth + xOffset),
|
|
50
|
+
scaleY: dy ? (isOpen ? [from, 1] : [1, 0.8]) : undefined,
|
|
51
|
+
scaleX: dx ? (isOpen ? [from, 1] : [1, 0.8]) : undefined,
|
|
52
|
+
transformOrigin
|
|
53
|
+
}, { duration, delay, ease });
|
|
54
|
+
animate(node, { opacity: +isOpen }, { duration, ease, delay });
|
|
55
|
+
};
|
|
56
|
+
}
|
|
@@ -1,111 +1,111 @@
|
|
|
1
|
-
<script lang="ts" generics="E extends keyof HTMLElementTagNameMap = 'div', B extends Base = Base">
|
|
2
|
-
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
-
import { animate as motion } from 'motion';
|
|
4
|
-
import { HtmlAtom, type Base } from '../atom';
|
|
5
|
-
import { PopoverBond } from './bond.svelte';
|
|
6
|
-
import type { PopoverArrowProps } from './types';
|
|
7
|
-
|
|
8
|
-
type Element = HTMLElementTagNameMap[E];
|
|
9
|
-
|
|
10
|
-
const bond = PopoverBond.get();
|
|
11
|
-
|
|
12
|
-
if (!bond) {
|
|
13
|
-
throw new Error('');
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
let {
|
|
17
|
-
class: klass = '',
|
|
18
|
-
children = undefined,
|
|
19
|
-
onmount = undefined,
|
|
20
|
-
ondestroy = undefined,
|
|
21
|
-
animate = _animate,
|
|
22
|
-
enter = undefined,
|
|
23
|
-
exit = undefined,
|
|
24
|
-
initial = undefined,
|
|
25
|
-
...restProps
|
|
26
|
-
}: PopoverArrowProps<E, B> & HTMLAttributes<Element> = $props();
|
|
27
|
-
|
|
28
|
-
const position = $derived(bond.position);
|
|
29
|
-
const middlewareArrowData = $derived(position?.middlewareData?.arrow);
|
|
30
|
-
const isReady = $derived(!!middlewareArrowData);
|
|
31
|
-
const side = $derived(position?.placement?.split('-')[0] ?? 'top');
|
|
32
|
-
|
|
33
|
-
const arrowProps = $derived({
|
|
34
|
-
...bond.arrow(),
|
|
35
|
-
...restProps
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
// Rotation based on placement side
|
|
39
|
-
const rotation = $derived.by(() => {
|
|
40
|
-
switch (side) {
|
|
41
|
-
case 'top':
|
|
42
|
-
return 180;
|
|
43
|
-
case 'bottom':
|
|
44
|
-
return 0;
|
|
45
|
-
case 'left':
|
|
46
|
-
return 90;
|
|
47
|
-
case 'right':
|
|
48
|
-
return -90;
|
|
49
|
-
default:
|
|
50
|
-
return 0;
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
function _animate(node: HTMLElement) {
|
|
55
|
-
if (!middlewareArrowData) {
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const { x, y } = middlewareArrowData;
|
|
60
|
-
|
|
61
|
-
const isMainAxis = side === 'top' || side === 'bottom';
|
|
62
|
-
|
|
63
|
-
const crossAxisStyle = isMainAxis
|
|
64
|
-
? {
|
|
65
|
-
left: 0
|
|
66
|
-
}
|
|
67
|
-
: {
|
|
68
|
-
top: 0
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
motion(
|
|
72
|
-
node,
|
|
73
|
-
{
|
|
74
|
-
x: x ?? 0,
|
|
75
|
-
y: y ?? 0,
|
|
76
|
-
opacity: 1,
|
|
77
|
-
...crossAxisStyle
|
|
78
|
-
},
|
|
79
|
-
{ duration: 0 }
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
</script>
|
|
83
|
-
|
|
84
|
-
<HtmlAtom
|
|
85
|
-
{bond}
|
|
86
|
-
preset="popover.arrow"
|
|
87
|
-
class={['text-border border-border pointer-events-none absolute opacity-0', '$preset', klass]}
|
|
88
|
-
onmount={onmount?.bind(bond.state)}
|
|
89
|
-
ondestroy={ondestroy?.bind(bond.state)}
|
|
90
|
-
animate={animate?.bind(bond.state)}
|
|
91
|
-
enter={enter?.bind(bond.state)}
|
|
92
|
-
exit={exit?.bind(bond.state)}
|
|
93
|
-
initial={initial?.bind(bond.state)}
|
|
94
|
-
style="{side}: 100%;"
|
|
95
|
-
{...arrowProps}
|
|
96
|
-
>
|
|
97
|
-
{#if children}
|
|
98
|
-
{@render children({ popover: bond })}
|
|
99
|
-
{:else}
|
|
100
|
-
<svg
|
|
101
|
-
width="16"
|
|
102
|
-
height="8"
|
|
103
|
-
viewBox="0 0 16 8"
|
|
104
|
-
fill="none"
|
|
105
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
106
|
-
style="transform: rotate({rotation}deg);"
|
|
107
|
-
>
|
|
108
|
-
<path d="M0 8C2 8 6 4 8 0C10 4 14 8 16 8H0Z" fill="currentColor" />
|
|
109
|
-
</svg>
|
|
110
|
-
{/if}
|
|
111
|
-
</HtmlAtom>
|
|
1
|
+
<script lang="ts" generics="E extends keyof HTMLElementTagNameMap = 'div', B extends Base = Base">
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
import { animate as motion } from 'motion';
|
|
4
|
+
import { HtmlAtom, type Base } from '../atom';
|
|
5
|
+
import { PopoverBond } from './bond.svelte';
|
|
6
|
+
import type { PopoverArrowProps } from './types';
|
|
7
|
+
|
|
8
|
+
type Element = HTMLElementTagNameMap[E];
|
|
9
|
+
|
|
10
|
+
const bond = PopoverBond.get();
|
|
11
|
+
|
|
12
|
+
if (!bond) {
|
|
13
|
+
throw new Error('');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let {
|
|
17
|
+
class: klass = '',
|
|
18
|
+
children = undefined,
|
|
19
|
+
onmount = undefined,
|
|
20
|
+
ondestroy = undefined,
|
|
21
|
+
animate = _animate,
|
|
22
|
+
enter = undefined,
|
|
23
|
+
exit = undefined,
|
|
24
|
+
initial = undefined,
|
|
25
|
+
...restProps
|
|
26
|
+
}: PopoverArrowProps<E, B> & HTMLAttributes<Element> = $props();
|
|
27
|
+
|
|
28
|
+
const position = $derived(bond.position);
|
|
29
|
+
const middlewareArrowData = $derived(position?.middlewareData?.arrow);
|
|
30
|
+
const isReady = $derived(!!middlewareArrowData);
|
|
31
|
+
const side = $derived(position?.placement?.split('-')[0] ?? 'top');
|
|
32
|
+
|
|
33
|
+
const arrowProps = $derived({
|
|
34
|
+
...bond.arrow(),
|
|
35
|
+
...restProps
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Rotation based on placement side
|
|
39
|
+
const rotation = $derived.by(() => {
|
|
40
|
+
switch (side) {
|
|
41
|
+
case 'top':
|
|
42
|
+
return 180;
|
|
43
|
+
case 'bottom':
|
|
44
|
+
return 0;
|
|
45
|
+
case 'left':
|
|
46
|
+
return 90;
|
|
47
|
+
case 'right':
|
|
48
|
+
return -90;
|
|
49
|
+
default:
|
|
50
|
+
return 0;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
function _animate(node: HTMLElement) {
|
|
55
|
+
if (!middlewareArrowData) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const { x, y } = middlewareArrowData;
|
|
60
|
+
|
|
61
|
+
const isMainAxis = side === 'top' || side === 'bottom';
|
|
62
|
+
|
|
63
|
+
const crossAxisStyle = isMainAxis
|
|
64
|
+
? {
|
|
65
|
+
left: 0
|
|
66
|
+
}
|
|
67
|
+
: {
|
|
68
|
+
top: 0
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
motion(
|
|
72
|
+
node,
|
|
73
|
+
{
|
|
74
|
+
x: x ?? 0,
|
|
75
|
+
y: y ?? 0,
|
|
76
|
+
opacity: 1,
|
|
77
|
+
...crossAxisStyle
|
|
78
|
+
},
|
|
79
|
+
{ duration: 0 }
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
</script>
|
|
83
|
+
|
|
84
|
+
<HtmlAtom
|
|
85
|
+
{bond}
|
|
86
|
+
preset="popover.arrow"
|
|
87
|
+
class={['text-border border-border pointer-events-none absolute opacity-0', '$preset', klass]}
|
|
88
|
+
onmount={onmount?.bind(bond.state)}
|
|
89
|
+
ondestroy={ondestroy?.bind(bond.state)}
|
|
90
|
+
animate={animate?.bind(bond.state)}
|
|
91
|
+
enter={enter?.bind(bond.state)}
|
|
92
|
+
exit={exit?.bind(bond.state)}
|
|
93
|
+
initial={initial?.bind(bond.state)}
|
|
94
|
+
style="{side}: 100%;"
|
|
95
|
+
{...arrowProps}
|
|
96
|
+
>
|
|
97
|
+
{#if children}
|
|
98
|
+
{@render children({ popover: bond })}
|
|
99
|
+
{:else}
|
|
100
|
+
<svg
|
|
101
|
+
width="16"
|
|
102
|
+
height="8"
|
|
103
|
+
viewBox="0 0 16 8"
|
|
104
|
+
fill="none"
|
|
105
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
106
|
+
style="transform: rotate({rotation}deg);"
|
|
107
|
+
>
|
|
108
|
+
<path d="M0 8C2 8 6 4 8 0C10 4 14 8 16 8H0Z" fill="currentColor" />
|
|
109
|
+
</svg>
|
|
110
|
+
{/if}
|
|
111
|
+
</HtmlAtom>
|