@svelte-atoms/core 1.0.0-alpha.31 → 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 +289 -853
- package/dist/attachments/index.d.ts +1 -0
- package/dist/attachments/index.js +1 -0
- package/dist/components/accordion/accordion-root.svelte +65 -65
- package/dist/components/accordion/accordion.stories.svelte +70 -70
- package/dist/components/accordion/item/accordion-item-body.svelte +44 -44
- package/dist/components/accordion/item/accordion-item-header.svelte +51 -51
- package/dist/components/accordion/item/accordion-item-indicator.svelte +51 -51
- package/dist/components/accordion/item/accordion-item-root.svelte +66 -66
- package/dist/components/alert/alert-close-button.svelte +66 -66
- package/dist/components/alert/alert-description.svelte +42 -42
- package/dist/components/alert/alert-root.svelte +68 -68
- package/dist/components/atom/html-atom.svelte +26 -194
- 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/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/calendar/calendar-day.svelte +101 -101
- package/dist/components/checkbox/checkbox.svelte +159 -159
- package/dist/components/collapsible/bond.svelte.js +2 -1
- package/dist/components/collapsible/collapsible-body.svelte +3 -2
- 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.stories.svelte +50 -0
- package/dist/components/combobox/combobox.stories.svelte.d.ts +3 -0
- package/dist/components/datagrid/tr/datagrid-tr.svelte +90 -90
- 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 +67 -67
- package/dist/components/dialog/bond.svelte.js +5 -20
- package/dist/components/dialog/dialog-content.svelte +44 -44
- package/dist/components/dialog/dialog-root.svelte +91 -91
- package/dist/components/drawer/bond.svelte.d.ts +18 -16
- package/dist/components/drawer/bond.svelte.js +8 -18
- package/dist/components/drawer/drawer-content.svelte +49 -49
- package/dist/components/drawer/drawer-root.svelte +5 -4
- package/dist/components/drawer/drawer.stories.svelte +141 -144
- package/dist/components/drawer/motion.js +1 -1
- 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 +21 -22
- package/dist/components/dropdown/bond.svelte.js +29 -53
- package/dist/components/dropdown/dropdown-root.svelte +65 -59
- 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 +83 -80
- package/dist/components/dropdown/index.d.ts +1 -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/list/list-item.svelte +20 -20
- package/dist/components/menu/atoms.d.ts +8 -3
- package/dist/components/menu/atoms.js +8 -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 +1 -0
- package/dist/components/menu/index.js +1 -0
- 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 +33 -33
- package/dist/components/menu/types.d.ts +0 -7
- package/dist/components/popover/bond.svelte.d.ts +11 -14
- package/dist/components/popover/bond.svelte.js +27 -44
- package/dist/components/popover/popover-content.svelte +137 -137
- package/dist/components/popover/popover.stories.svelte +37 -49
- package/dist/components/portal/active-portal.svelte +29 -29
- package/dist/components/portal/portal-root.svelte +76 -76
- package/dist/components/portal/teleport.svelte +49 -49
- package/dist/components/radio/radio.svelte +109 -109
- 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/root/l0-portal.svelte.d.ts +26 -0
- 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 +17 -18
- 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/sidebar/motion.svelte.js +3 -3
- package/dist/components/sidebar/sidebar-content.svelte +40 -40
- package/dist/components/textarea/textarea-input.svelte +9 -9
- package/dist/components/textarea/textarea-root.svelte +9 -9
- package/dist/components/tooltip/tooltip-trigger.svelte +39 -39
- 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/context/preset.svelte.d.ts +3 -1
- package/dist/icons/icon-copy.svelte +6 -6
- 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 -2
- 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 -69
- package/dist/components/menu/menu-item.svelte.d.ts +0 -37
- package/dist/utils/markdown-to-llm.d.ts +0 -28
- package/dist/utils/markdown-to-llm.js +0 -76
|
@@ -1,7 +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 { getElementId, isBrowser } from '../../utils/dom.svelte.js';
|
|
4
|
+
import { focus, focusTrap, getElementId, isBrowser } from '../../utils/dom.svelte.js';
|
|
5
5
|
import { Bond, BondState } from '../../shared/bond.svelte.js';
|
|
6
6
|
const POPOVER_ELEMENTS_KIND = {
|
|
7
7
|
trigger: 'popover-trigger',
|
|
@@ -15,7 +15,7 @@ export class PopoverBond extends Bond {
|
|
|
15
15
|
constructor(state) {
|
|
16
16
|
super(state);
|
|
17
17
|
}
|
|
18
|
-
trigger(
|
|
18
|
+
trigger() {
|
|
19
19
|
const isButtonElement = isBrowser()
|
|
20
20
|
? this.elements.trigger instanceof HTMLButtonElement
|
|
21
21
|
: false;
|
|
@@ -42,32 +42,29 @@ export class PopoverBond extends Bond {
|
|
|
42
42
|
return;
|
|
43
43
|
}
|
|
44
44
|
this.state.toggle();
|
|
45
|
-
props.onclick?.(ev);
|
|
46
45
|
},
|
|
47
46
|
onkeydown: (ev) => {
|
|
48
47
|
if (isDisabled)
|
|
49
48
|
return;
|
|
50
49
|
// Toggle on Enter or Space
|
|
51
50
|
if (ev.key === 'Enter' || ev.key === ' ') {
|
|
52
|
-
ev.preventDefault();
|
|
53
51
|
this.state.toggle();
|
|
54
|
-
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (ev.key === 'Tab') {
|
|
55
|
+
this.elements.content?.focus();
|
|
56
|
+
return;
|
|
55
57
|
}
|
|
56
|
-
|
|
57
|
-
else if (ev.key === 'Escape' && isOpen) {
|
|
58
|
-
ev.preventDefault();
|
|
58
|
+
if (ev.key === 'Escape') {
|
|
59
59
|
this.state.close();
|
|
60
|
-
props.onkeydown?.(ev);
|
|
61
60
|
}
|
|
62
61
|
},
|
|
63
|
-
...props,
|
|
64
62
|
[createAttachmentKey()]: (node) => {
|
|
65
63
|
this.elements.trigger = node;
|
|
66
64
|
const position = untrack(() => this.position);
|
|
67
65
|
if (!position) {
|
|
68
66
|
const init = async () => {
|
|
69
67
|
popover(this)({
|
|
70
|
-
...props,
|
|
71
68
|
onchange: (_node, position) => {
|
|
72
69
|
this.position = position;
|
|
73
70
|
}
|
|
@@ -86,7 +83,7 @@ export class PopoverBond extends Bond {
|
|
|
86
83
|
}
|
|
87
84
|
};
|
|
88
85
|
}
|
|
89
|
-
content(
|
|
86
|
+
content() {
|
|
90
87
|
const kind = POPOVER_ELEMENTS_KIND.content;
|
|
91
88
|
const id = getElementId(this.id, kind);
|
|
92
89
|
const triggerId = getElementId(this.id, POPOVER_ELEMENTS_KIND.trigger);
|
|
@@ -94,59 +91,47 @@ export class PopoverBond extends Bond {
|
|
|
94
91
|
const isDisabled = this.state?.props?.disabled ?? false;
|
|
95
92
|
const isActive = isOpen && !isDisabled;
|
|
96
93
|
// Focus management
|
|
97
|
-
const
|
|
98
|
-
const node = ev.currentTarget;
|
|
94
|
+
const focusManager = (ev) => {
|
|
99
95
|
if (ev.key === 'Escape') {
|
|
100
|
-
ev.preventDefault();
|
|
101
96
|
this.state.close();
|
|
102
97
|
this.elements.trigger?.focus();
|
|
98
|
+
return;
|
|
103
99
|
}
|
|
104
|
-
|
|
105
|
-
else if (ev.key === 'Tab') {
|
|
106
|
-
const focusableElements = node.querySelectorAll('a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])');
|
|
107
|
-
const firstElement = focusableElements[0];
|
|
108
|
-
const lastElement = focusableElements[focusableElements.length - 1];
|
|
109
|
-
if (ev.shiftKey && document.activeElement === firstElement) {
|
|
110
|
-
ev.preventDefault();
|
|
111
|
-
lastElement?.focus();
|
|
112
|
-
}
|
|
113
|
-
else if (!ev.shiftKey && document.activeElement === lastElement) {
|
|
114
|
-
ev.preventDefault();
|
|
115
|
-
firstElement?.focus();
|
|
116
|
-
}
|
|
117
|
-
}
|
|
100
|
+
focusTrap(ev);
|
|
118
101
|
};
|
|
119
102
|
return {
|
|
120
103
|
id,
|
|
121
104
|
role: 'dialog',
|
|
122
105
|
'aria-modal': false,
|
|
123
106
|
'aria-labelledby': triggerId,
|
|
124
|
-
|
|
125
|
-
inert: !isActive ? '' : undefined,
|
|
107
|
+
inert: !isActive ? true : undefined,
|
|
126
108
|
tabindex: -1,
|
|
127
109
|
'data-atom': this.id,
|
|
128
110
|
'data-kind': 'content',
|
|
129
111
|
'data-active': isActive,
|
|
130
|
-
onkeydown: isOpen ?
|
|
131
|
-
...props,
|
|
112
|
+
onkeydown: isOpen ? focusManager : undefined,
|
|
132
113
|
[createAttachmentKey()]: (node) => {
|
|
133
114
|
this.elements.content = node;
|
|
134
|
-
|
|
115
|
+
const triggerElement = this.elements.trigger;
|
|
116
|
+
if (!triggerElement) {
|
|
135
117
|
return;
|
|
136
118
|
}
|
|
137
119
|
if (!this.state.isOpen) {
|
|
138
120
|
return;
|
|
139
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);
|
|
140
128
|
// Move focus to popover when opened
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
}, 0);
|
|
129
|
+
if (!triggerContainsFocus) {
|
|
130
|
+
setTimeout(() => focus(node), 0);
|
|
131
|
+
}
|
|
145
132
|
const cleanup = popover(this)({
|
|
146
|
-
...props,
|
|
147
133
|
onchange: (node, position) => {
|
|
148
134
|
this.position = position;
|
|
149
|
-
props.onchange?.(node, position);
|
|
150
135
|
}
|
|
151
136
|
}, autoUpdate);
|
|
152
137
|
return () => {
|
|
@@ -155,7 +140,7 @@ export class PopoverBond extends Bond {
|
|
|
155
140
|
}
|
|
156
141
|
};
|
|
157
142
|
}
|
|
158
|
-
indicator(
|
|
143
|
+
indicator() {
|
|
159
144
|
const kind = POPOVER_ELEMENTS_KIND.indicator;
|
|
160
145
|
const id = getElementId(this.id, kind);
|
|
161
146
|
const isOpen = this.state?.props?.open ?? false;
|
|
@@ -164,13 +149,12 @@ export class PopoverBond extends Bond {
|
|
|
164
149
|
'aria-hidden': true,
|
|
165
150
|
'aria-live': isOpen ? 'polite' : 'off',
|
|
166
151
|
'data-kind': kind,
|
|
167
|
-
...props,
|
|
168
152
|
[createAttachmentKey()]: (node) => {
|
|
169
153
|
this.elements.indicator = node;
|
|
170
154
|
}
|
|
171
155
|
};
|
|
172
156
|
}
|
|
173
|
-
arrow(
|
|
157
|
+
arrow() {
|
|
174
158
|
const kind = POPOVER_ELEMENTS_KIND.arrow;
|
|
175
159
|
const id = getElementId(this.id, kind);
|
|
176
160
|
return {
|
|
@@ -178,7 +162,6 @@ export class PopoverBond extends Bond {
|
|
|
178
162
|
role: 'presentation',
|
|
179
163
|
'aria-hidden': true,
|
|
180
164
|
'data-kind': kind,
|
|
181
|
-
...props,
|
|
182
165
|
[createAttachmentKey()]: (node) => {
|
|
183
166
|
this.elements.arrow = node;
|
|
184
167
|
}
|
|
@@ -1,137 +1,137 @@
|
|
|
1
|
-
<script lang="ts" generics="E extends HtmlElementTagName, B extends Base = Base">
|
|
2
|
-
import { PortalBond, PortalsBond, Teleport } from '../portal';
|
|
3
|
-
import { HtmlAtom, type Base } from '../atom';
|
|
4
|
-
import type { HtmlElementTagName, HtmlElementType } from '../element';
|
|
5
|
-
import { PopoverBond } from './bond.svelte';
|
|
6
|
-
import type { AnimateParams, PopoverContentProps } from './types';
|
|
7
|
-
import { animatePopoverContent } from './motion';
|
|
8
|
-
|
|
9
|
-
type Element = HtmlElementType<E>;
|
|
10
|
-
|
|
11
|
-
const bond = PopoverBond.get();
|
|
12
|
-
const activePortalBond = (() => {
|
|
13
|
-
const key = bond.state.props.portal;
|
|
14
|
-
if (key instanceof PortalBond) {
|
|
15
|
-
return key;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
let portal: PortalBond | undefined | null = undefined;
|
|
19
|
-
|
|
20
|
-
if (typeof key === 'string') {
|
|
21
|
-
portal = PortalsBond.get()?.state.get(key);
|
|
22
|
-
console.error('portal was not found');
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return portal ?? PortalBond.get();
|
|
26
|
-
})();
|
|
27
|
-
|
|
28
|
-
if (!bond) {
|
|
29
|
-
throw new Error('<PopoverOverlay /> must be used within a <Popover />');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
let {
|
|
33
|
-
class: klass = '',
|
|
34
|
-
children = undefined,
|
|
35
|
-
onmount = undefined,
|
|
36
|
-
ondestroy = undefined,
|
|
37
|
-
animate = animatePopoverContent(),
|
|
38
|
-
enter = undefined,
|
|
39
|
-
exit = undefined,
|
|
40
|
-
initial = undefined,
|
|
41
|
-
...restProps
|
|
42
|
-
}: PopoverContentProps<E, B> = $props();
|
|
43
|
-
|
|
44
|
-
const isOpen = $derived(bond.state.isOpen && !!bond.elements.trigger);
|
|
45
|
-
const portalId = $derived(activePortalBond?.id);
|
|
46
|
-
|
|
47
|
-
let isInitialized = false;
|
|
48
|
-
|
|
49
|
-
function _containerInitial(this: typeof bond.state, node: Element) {
|
|
50
|
-
const position = bond.position;
|
|
51
|
-
const placement = position?.placement;
|
|
52
|
-
|
|
53
|
-
const x = position?.x ?? 0;
|
|
54
|
-
const y = position?.y ?? 0;
|
|
55
|
-
|
|
56
|
-
const dy = placement?.startsWith('top') ? -1 : placement?.startsWith('bottom') ? 1 : 0;
|
|
57
|
-
const dx = placement?.startsWith('left') ? -1 : placement?.startsWith('right') ? 1 : 0;
|
|
58
|
-
|
|
59
|
-
const offset = bond.state.props.offset;
|
|
60
|
-
|
|
61
|
-
const xOffset = dx * offset;
|
|
62
|
-
const yOffset = dy * offset;
|
|
63
|
-
|
|
64
|
-
const openAsNumber = +isOpen;
|
|
65
|
-
const deltaArrow = position?.middlewareData?.arrow ? 1 : 0;
|
|
66
|
-
|
|
67
|
-
const arrowClientWidth = bond?.elements.arrow?.clientWidth ?? 0;
|
|
68
|
-
const arrowClientHeight = bond?.elements.arrow?.clientHeight ?? 0;
|
|
69
|
-
|
|
70
|
-
const _x = x + xOffset * openAsNumber + deltaArrow * dx * arrowClientWidth;
|
|
71
|
-
const _y = y + yOffset * openAsNumber + deltaArrow * dy * arrowClientHeight;
|
|
72
|
-
|
|
73
|
-
node.style.transform = `translate3d(${_x}px, ${_y}px, 1px)`;
|
|
74
|
-
|
|
75
|
-
isInitialized = true;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function _containerAnimate(this: typeof bond.state, node: Element, _?: AnimateParams) {
|
|
79
|
-
if (!isInitialized) {
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const position = bond.position;
|
|
84
|
-
const placement = position?.placement;
|
|
85
|
-
|
|
86
|
-
const x = position?.x ?? 0;
|
|
87
|
-
const y = position?.y ?? 0;
|
|
88
|
-
|
|
89
|
-
const dy = placement?.startsWith('top') ? -1 : placement?.startsWith('bottom') ? 1 : 0;
|
|
90
|
-
const dx = placement?.startsWith('left') ? -1 : placement?.startsWith('right') ? 1 : 0;
|
|
91
|
-
|
|
92
|
-
const offset = bond.state.props.offset;
|
|
93
|
-
|
|
94
|
-
const xOffset = dx * offset;
|
|
95
|
-
const yOffset = dy * offset;
|
|
96
|
-
|
|
97
|
-
const openAsNumber = +isOpen;
|
|
98
|
-
const deltaArrow = position?.middlewareData?.arrow ? 1 : 0;
|
|
99
|
-
|
|
100
|
-
const arrowClientWidth = bond?.elements.arrow?.clientWidth ?? 0;
|
|
101
|
-
const arrowClientHeight = bond?.elements.arrow?.clientHeight ?? 0;
|
|
102
|
-
|
|
103
|
-
const _x = x + xOffset * openAsNumber + deltaArrow * dx * arrowClientWidth;
|
|
104
|
-
const _y = y + yOffset * openAsNumber + deltaArrow * dy * arrowClientHeight;
|
|
105
|
-
|
|
106
|
-
node.style.transform = `translate3d(${_x}px, ${_y}px, 1px)`;
|
|
107
|
-
}
|
|
108
|
-
</script>
|
|
109
|
-
|
|
110
|
-
<Teleport
|
|
111
|
-
portal={portalId ?? 'root.l0'}
|
|
112
|
-
as="div"
|
|
113
|
-
class="absolute top-0 left-0 h-min w-fit outline-none"
|
|
114
|
-
initial={_containerInitial?.bind(bond.state)}
|
|
115
|
-
animate={_containerAnimate?.bind(bond.state)}
|
|
116
|
-
{...bond.content({ onchange: _containerInitial })}
|
|
117
|
-
>
|
|
118
|
-
<HtmlAtom
|
|
119
|
-
{bond}
|
|
120
|
-
preset="popover.content"
|
|
121
|
-
class={[
|
|
122
|
-
'popover-content bg-popover text-popover-foreground border-border rounded-md border p-2 opacity-0 shadow-lg outline-none',
|
|
123
|
-
isOpen && 'pointer-events-auto',
|
|
124
|
-
'$preset',
|
|
125
|
-
klass
|
|
126
|
-
]}
|
|
127
|
-
enter={enter?.bind(bond.state)}
|
|
128
|
-
exit={exit?.bind(bond.state)}
|
|
129
|
-
initial={initial?.bind(bond.state)}
|
|
130
|
-
animate={animate?.bind(bond.state)}
|
|
131
|
-
onmount={onmount?.bind(bond.state)}
|
|
132
|
-
ondestroy={ondestroy?.bind(bond.state)}
|
|
133
|
-
{...restProps}
|
|
134
|
-
>
|
|
135
|
-
{@render children?.({ popover: bond })}
|
|
136
|
-
</HtmlAtom>
|
|
137
|
-
</Teleport>
|
|
1
|
+
<script lang="ts" generics="E extends HtmlElementTagName, B extends Base = Base">
|
|
2
|
+
import { PortalBond, PortalsBond, Teleport } from '../portal';
|
|
3
|
+
import { HtmlAtom, type Base } from '../atom';
|
|
4
|
+
import type { HtmlElementTagName, HtmlElementType } from '../element';
|
|
5
|
+
import { PopoverBond } from './bond.svelte';
|
|
6
|
+
import type { AnimateParams, PopoverContentProps } from './types';
|
|
7
|
+
import { animatePopoverContent } from './motion';
|
|
8
|
+
|
|
9
|
+
type Element = HtmlElementType<E>;
|
|
10
|
+
|
|
11
|
+
const bond = PopoverBond.get();
|
|
12
|
+
const activePortalBond = (() => {
|
|
13
|
+
const key = bond.state.props.portal;
|
|
14
|
+
if (key instanceof PortalBond) {
|
|
15
|
+
return key;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let portal: PortalBond | undefined | null = undefined;
|
|
19
|
+
|
|
20
|
+
if (typeof key === 'string') {
|
|
21
|
+
portal = PortalsBond.get()?.state.get(key);
|
|
22
|
+
console.error('portal was not found');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return portal ?? PortalBond.get();
|
|
26
|
+
})();
|
|
27
|
+
|
|
28
|
+
if (!bond) {
|
|
29
|
+
throw new Error('<PopoverOverlay /> must be used within a <Popover />');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let {
|
|
33
|
+
class: klass = '',
|
|
34
|
+
children = undefined,
|
|
35
|
+
onmount = undefined,
|
|
36
|
+
ondestroy = undefined,
|
|
37
|
+
animate = animatePopoverContent(),
|
|
38
|
+
enter = undefined,
|
|
39
|
+
exit = undefined,
|
|
40
|
+
initial = undefined,
|
|
41
|
+
...restProps
|
|
42
|
+
}: PopoverContentProps<E, B> = $props();
|
|
43
|
+
|
|
44
|
+
const isOpen = $derived(bond.state.isOpen && !!bond.elements.trigger);
|
|
45
|
+
const portalId = $derived(activePortalBond?.id);
|
|
46
|
+
|
|
47
|
+
let isInitialized = false;
|
|
48
|
+
|
|
49
|
+
function _containerInitial(this: typeof bond.state, node: Element) {
|
|
50
|
+
const position = bond.position;
|
|
51
|
+
const placement = position?.placement;
|
|
52
|
+
|
|
53
|
+
const x = position?.x ?? 0;
|
|
54
|
+
const y = position?.y ?? 0;
|
|
55
|
+
|
|
56
|
+
const dy = placement?.startsWith('top') ? -1 : placement?.startsWith('bottom') ? 1 : 0;
|
|
57
|
+
const dx = placement?.startsWith('left') ? -1 : placement?.startsWith('right') ? 1 : 0;
|
|
58
|
+
|
|
59
|
+
const offset = bond.state.props.offset;
|
|
60
|
+
|
|
61
|
+
const xOffset = dx * offset;
|
|
62
|
+
const yOffset = dy * offset;
|
|
63
|
+
|
|
64
|
+
const openAsNumber = +isOpen;
|
|
65
|
+
const deltaArrow = position?.middlewareData?.arrow ? 1 : 0;
|
|
66
|
+
|
|
67
|
+
const arrowClientWidth = bond?.elements.arrow?.clientWidth ?? 0;
|
|
68
|
+
const arrowClientHeight = bond?.elements.arrow?.clientHeight ?? 0;
|
|
69
|
+
|
|
70
|
+
const _x = x + xOffset * openAsNumber + deltaArrow * dx * arrowClientWidth;
|
|
71
|
+
const _y = y + yOffset * openAsNumber + deltaArrow * dy * arrowClientHeight;
|
|
72
|
+
|
|
73
|
+
node.style.transform = `translate3d(${_x}px, ${_y}px, 1px)`;
|
|
74
|
+
|
|
75
|
+
isInitialized = true;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function _containerAnimate(this: typeof bond.state, node: Element, _?: AnimateParams) {
|
|
79
|
+
if (!isInitialized) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const position = bond.position;
|
|
84
|
+
const placement = position?.placement;
|
|
85
|
+
|
|
86
|
+
const x = position?.x ?? 0;
|
|
87
|
+
const y = position?.y ?? 0;
|
|
88
|
+
|
|
89
|
+
const dy = placement?.startsWith('top') ? -1 : placement?.startsWith('bottom') ? 1 : 0;
|
|
90
|
+
const dx = placement?.startsWith('left') ? -1 : placement?.startsWith('right') ? 1 : 0;
|
|
91
|
+
|
|
92
|
+
const offset = bond.state.props.offset;
|
|
93
|
+
|
|
94
|
+
const xOffset = dx * offset;
|
|
95
|
+
const yOffset = dy * offset;
|
|
96
|
+
|
|
97
|
+
const openAsNumber = +isOpen;
|
|
98
|
+
const deltaArrow = position?.middlewareData?.arrow ? 1 : 0;
|
|
99
|
+
|
|
100
|
+
const arrowClientWidth = bond?.elements.arrow?.clientWidth ?? 0;
|
|
101
|
+
const arrowClientHeight = bond?.elements.arrow?.clientHeight ?? 0;
|
|
102
|
+
|
|
103
|
+
const _x = x + xOffset * openAsNumber + deltaArrow * dx * arrowClientWidth;
|
|
104
|
+
const _y = y + yOffset * openAsNumber + deltaArrow * dy * arrowClientHeight;
|
|
105
|
+
|
|
106
|
+
node.style.transform = `translate3d(${_x}px, ${_y}px, 1px)`;
|
|
107
|
+
}
|
|
108
|
+
</script>
|
|
109
|
+
|
|
110
|
+
<Teleport
|
|
111
|
+
portal={portalId ?? 'root.l0'}
|
|
112
|
+
as="div"
|
|
113
|
+
class="absolute top-0 left-0 h-min w-fit outline-none"
|
|
114
|
+
initial={_containerInitial?.bind(bond.state)}
|
|
115
|
+
animate={_containerAnimate?.bind(bond.state)}
|
|
116
|
+
{...bond.content({ onchange: _containerInitial })}
|
|
117
|
+
>
|
|
118
|
+
<HtmlAtom
|
|
119
|
+
{bond}
|
|
120
|
+
preset="popover.content"
|
|
121
|
+
class={[
|
|
122
|
+
'popover-content bg-popover text-popover-foreground border-border rounded-md border p-2 opacity-0 shadow-lg outline-none',
|
|
123
|
+
isOpen && 'pointer-events-auto',
|
|
124
|
+
'$preset',
|
|
125
|
+
klass
|
|
126
|
+
]}
|
|
127
|
+
enter={enter?.bind(bond.state)}
|
|
128
|
+
exit={exit?.bind(bond.state)}
|
|
129
|
+
initial={initial?.bind(bond.state)}
|
|
130
|
+
animate={animate?.bind(bond.state)}
|
|
131
|
+
onmount={onmount?.bind(bond.state)}
|
|
132
|
+
ondestroy={ondestroy?.bind(bond.state)}
|
|
133
|
+
{...restProps}
|
|
134
|
+
>
|
|
135
|
+
{@render children?.({ popover: bond })}
|
|
136
|
+
</HtmlAtom>
|
|
137
|
+
</Teleport>
|
|
@@ -1,49 +1,37 @@
|
|
|
1
|
-
<script module>
|
|
2
|
-
import { defineMeta } from '@storybook/addon-svelte-csf';
|
|
3
|
-
import { Popover as Popover_ } from '.';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
<
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
{@attach clickoutPopover((_, atom) => {
|
|
39
|
-
atom.state.close();
|
|
40
|
-
})}
|
|
41
|
-
class="bg-card"
|
|
42
|
-
>
|
|
43
|
-
<div>Hello World !</div>
|
|
44
|
-
<Popover_.Arrow />
|
|
45
|
-
</Popover_.Content>
|
|
46
|
-
{/snippet}
|
|
47
|
-
</Popover_.Root>
|
|
48
|
-
{/snippet}
|
|
49
|
-
</Story>
|
|
1
|
+
<script module>
|
|
2
|
+
import { defineMeta } from '@storybook/addon-svelte-csf';
|
|
3
|
+
import { Popover as Popover_ } from '.';
|
|
4
|
+
import { Button } from '../button';
|
|
5
|
+
|
|
6
|
+
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories
|
|
7
|
+
const { Story } = defineMeta({
|
|
8
|
+
title: 'Atoms/Popover',
|
|
9
|
+
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
|
|
10
|
+
|
|
11
|
+
parameters: {
|
|
12
|
+
// More on how to position stories at: https://storybook.js.org/docs/configure/story-layout
|
|
13
|
+
layout: 'fullscreen'
|
|
14
|
+
},
|
|
15
|
+
args: {}
|
|
16
|
+
});
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<script lang="ts">
|
|
20
|
+
let open = $state(false);
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<Story name="Popover" args={{}}>
|
|
24
|
+
{#snippet children(args)}
|
|
25
|
+
<Popover_.Root bind:open offset={0} {...args}>
|
|
26
|
+
<Popover_.Trigger base={Button} class="items-center gap-4">
|
|
27
|
+
<div>Open Popover</div>
|
|
28
|
+
<Popover_.Indicator />
|
|
29
|
+
</Popover_.Trigger>
|
|
30
|
+
|
|
31
|
+
<Popover_.Content class="bg-card" autoClose>
|
|
32
|
+
<div>Hello World !</div>
|
|
33
|
+
<Popover_.Arrow />
|
|
34
|
+
</Popover_.Content>
|
|
35
|
+
</Popover_.Root>
|
|
36
|
+
{/snippet}
|
|
37
|
+
</Story>
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { PortalBond } from './bond.svelte';
|
|
3
|
-
import { PortalsBond } from './portals/bond.svelte';
|
|
4
|
-
|
|
5
|
-
let { portal, children = undefined } = $props();
|
|
6
|
-
|
|
7
|
-
const portalsBond = PortalsBond.get();
|
|
8
|
-
const activePortal = $derived.by(() => {
|
|
9
|
-
if (typeof portal === 'string') {
|
|
10
|
-
return portalsBond?.state?.get(portal) ?? undefined;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
return portal as PortalBond;
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
if (!portalsBond) {
|
|
17
|
-
throw new Error('Portals bond is not found');
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function proxy(...args: any[]) {
|
|
21
|
-
activePortal?.share();
|
|
22
|
-
|
|
23
|
-
return children?.(...args);
|
|
24
|
-
}
|
|
25
|
-
</script>
|
|
26
|
-
|
|
27
|
-
{#if activePortal}
|
|
28
|
-
{@render proxy?.()}
|
|
29
|
-
{/if}
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { PortalBond } from './bond.svelte';
|
|
3
|
+
import { PortalsBond } from './portals/bond.svelte';
|
|
4
|
+
|
|
5
|
+
let { portal, children = undefined } = $props();
|
|
6
|
+
|
|
7
|
+
const portalsBond = PortalsBond.get();
|
|
8
|
+
const activePortal = $derived.by(() => {
|
|
9
|
+
if (typeof portal === 'string') {
|
|
10
|
+
return portalsBond?.state?.get(portal) ?? undefined;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return portal as PortalBond;
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
if (!portalsBond) {
|
|
17
|
+
throw new Error('Portals bond is not found');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function proxy(...args: any[]) {
|
|
21
|
+
activePortal?.share();
|
|
22
|
+
|
|
23
|
+
return children?.(...args);
|
|
24
|
+
}
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
{#if activePortal}
|
|
28
|
+
{@render proxy?.()}
|
|
29
|
+
{/if}
|