sinwan-ui-core 0.0.0 → 1.0.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/CHANGELOG.md +22 -0
- package/README.md +31 -12
- package/dist/chunks/chunk-6r59k5mb.js +384 -0
- package/dist/chunks/chunk-7r6fwdyt.js +16 -0
- package/dist/chunks/chunk-8zvv4kad.js +116 -0
- package/dist/chunks/chunk-94xhejch.js +511 -0
- package/dist/chunks/chunk-9whagkb6.js +31 -0
- package/dist/chunks/chunk-bw9vp0y9.js +69 -0
- package/dist/chunks/chunk-ejwby1pn.js +107 -0
- package/dist/chunks/chunk-f6hw8ash.js +29 -0
- package/dist/chunks/chunk-te52bwb8.js +448 -0
- package/dist/chunks/chunk-xaegn57w.js +189 -0
- package/dist/controls.d.ts +141 -0
- package/dist/controls.js +55 -0
- package/dist/core.d.ts +24 -0
- package/dist/core.js +42 -0
- package/dist/direction.d.ts +15 -0
- package/dist/direction.js +10 -0
- package/dist/dismiss.d.ts +1 -0
- package/dist/dismiss.js +6 -0
- package/dist/floating.d.ts +105 -0
- package/dist/floating.js +24 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +166 -0
- package/dist/menu-sub.d.ts +34 -0
- package/dist/menu-sub.js +14 -0
- package/dist/overlay.d.ts +111 -0
- package/dist/overlay.js +47 -0
- package/dist/slot.d.ts +8 -0
- package/dist/slot.js +7 -0
- package/dist/theme.d.ts +34 -0
- package/dist/theme.js +12 -0
- package/dist/types.d.ts +11 -0
- package/dist/types.js +8 -0
- package/package.json +108 -5
- package/.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc +0 -119
- package/bun.lock +0 -66
- package/index.ts +0 -1
- package/tsconfig.json +0 -30
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Slot2
|
|
3
|
+
} from "./chunk-bw9vp0y9.js";
|
|
4
|
+
import {
|
|
5
|
+
useAnchorPosition2
|
|
6
|
+
} from "./chunk-6r59k5mb.js";
|
|
7
|
+
import {
|
|
8
|
+
Presence2,
|
|
9
|
+
UiPortal2,
|
|
10
|
+
trapFocus2
|
|
11
|
+
} from "./chunk-ejwby1pn.js";
|
|
12
|
+
import {
|
|
13
|
+
isDismissExemptPointerTarget2
|
|
14
|
+
} from "./chunk-9whagkb6.js";
|
|
15
|
+
|
|
16
|
+
// src/overlay.tsx
|
|
17
|
+
import { _$createTemplate } from "sinwan/renderer/web";
|
|
18
|
+
import { unwrap as _$unwrap } from "sinwan/reactivity";
|
|
19
|
+
import {
|
|
20
|
+
cc,
|
|
21
|
+
inject,
|
|
22
|
+
onMounted,
|
|
23
|
+
onUnmounted,
|
|
24
|
+
provide,
|
|
25
|
+
createLiveRest as _$createLiveRest,
|
|
26
|
+
getSpreadProps as _$getSpreadProps
|
|
27
|
+
} from "sinwan/component";
|
|
28
|
+
import { computed, signal } from "sinwan/reactivity";
|
|
29
|
+
import { jsx, Fragment } from "sinwan/jsx-runtime";
|
|
30
|
+
var _$tmpl_0 = {
|
|
31
|
+
html: '<button type="button" data-slot="dialog-trigger"></button>',
|
|
32
|
+
slots: [
|
|
33
|
+
{ path: [], type: "attr", name: "class" },
|
|
34
|
+
{ path: [], type: "event", name: "onclick" },
|
|
35
|
+
{ path: [], type: "ref", name: "ref" },
|
|
36
|
+
{ path: [], type: "child" }
|
|
37
|
+
]
|
|
38
|
+
};
|
|
39
|
+
var _$tmpl_1 = {
|
|
40
|
+
html: '<button type="button" data-slot="dialog-close"></button>',
|
|
41
|
+
slots: [
|
|
42
|
+
{ path: [], type: "attr", name: "class" },
|
|
43
|
+
{ path: [], type: "event", name: "onclick" },
|
|
44
|
+
{ path: [], type: "child" }
|
|
45
|
+
]
|
|
46
|
+
};
|
|
47
|
+
var _$tmpl_2 = {
|
|
48
|
+
html: '<div data-slot="collapsible" data-state=""></div>',
|
|
49
|
+
slots: [
|
|
50
|
+
{ path: [], type: "attr", name: "data-state" },
|
|
51
|
+
{ path: [], type: "attr", name: "class" },
|
|
52
|
+
{ path: [], type: "child" }
|
|
53
|
+
]
|
|
54
|
+
};
|
|
55
|
+
var _$tmpl_3 = {
|
|
56
|
+
html: '<button type="button" data-slot="collapsible-trigger" aria-expanded=""></button>',
|
|
57
|
+
slots: [
|
|
58
|
+
{ path: [], type: "attr", name: "class" },
|
|
59
|
+
{ path: [], type: "attr", name: "aria-expanded" },
|
|
60
|
+
{ path: [], type: "event", name: "onclick" },
|
|
61
|
+
{ path: [], type: "child" }
|
|
62
|
+
]
|
|
63
|
+
};
|
|
64
|
+
var _$tmpl_4 = {
|
|
65
|
+
html: '<button type="button" data-slot="popover-trigger" aria-expanded=""></button>',
|
|
66
|
+
slots: [
|
|
67
|
+
{ path: [], type: "attr", name: "class" },
|
|
68
|
+
{ path: [], type: "attr", name: "aria-expanded" },
|
|
69
|
+
{ path: [], type: "event", name: "onclick" },
|
|
70
|
+
{ path: [], type: "ref", name: "ref" },
|
|
71
|
+
{ path: [], type: "child" }
|
|
72
|
+
]
|
|
73
|
+
};
|
|
74
|
+
var REOPEN_LOCK_MS = 280;
|
|
75
|
+
function createOpenState(props) {
|
|
76
|
+
const openLocal = signal(props.defaultOpen ?? false);
|
|
77
|
+
const open = "open" in props ? computed(() => Boolean(props.open)) : openLocal;
|
|
78
|
+
const set = (next) => {
|
|
79
|
+
if (!("open" in props))
|
|
80
|
+
openLocal.value = next;
|
|
81
|
+
};
|
|
82
|
+
let closeTimer;
|
|
83
|
+
let pointerOverTrigger = false;
|
|
84
|
+
let hoverOpenBlocked = false;
|
|
85
|
+
let reopenLockUntil = 0;
|
|
86
|
+
function cancelClose() {
|
|
87
|
+
if (closeTimer !== undefined) {
|
|
88
|
+
window.clearTimeout(closeTimer);
|
|
89
|
+
closeTimer = undefined;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function setOpen(value) {
|
|
93
|
+
cancelClose();
|
|
94
|
+
if (value) {
|
|
95
|
+
if (Date.now() < reopenLockUntil)
|
|
96
|
+
return;
|
|
97
|
+
} else {
|
|
98
|
+
if (pointerOverTrigger)
|
|
99
|
+
hoverOpenBlocked = true;
|
|
100
|
+
reopenLockUntil = Date.now() + REOPEN_LOCK_MS;
|
|
101
|
+
}
|
|
102
|
+
set(value);
|
|
103
|
+
props.onOpenChange?.(value);
|
|
104
|
+
}
|
|
105
|
+
function requestClose(delayMs = 0) {
|
|
106
|
+
cancelClose();
|
|
107
|
+
closeTimer = window.setTimeout(() => {
|
|
108
|
+
closeTimer = undefined;
|
|
109
|
+
setOpen(false);
|
|
110
|
+
}, delayMs);
|
|
111
|
+
}
|
|
112
|
+
function isHoverOpenBlocked() {
|
|
113
|
+
return hoverOpenBlocked;
|
|
114
|
+
}
|
|
115
|
+
function setPointerOverTrigger(over) {
|
|
116
|
+
pointerOverTrigger = over;
|
|
117
|
+
if (!over)
|
|
118
|
+
hoverOpenBlocked = false;
|
|
119
|
+
}
|
|
120
|
+
onUnmounted(cancelClose);
|
|
121
|
+
return {
|
|
122
|
+
open,
|
|
123
|
+
setOpen,
|
|
124
|
+
triggerEl: signal(null),
|
|
125
|
+
requestClose,
|
|
126
|
+
cancelClose,
|
|
127
|
+
isHoverOpenBlocked,
|
|
128
|
+
setPointerOverTrigger
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
var DialogKey2 = Symbol("sinwan-ui.dialog");
|
|
132
|
+
var DialogRoot2 = cc((props) => {
|
|
133
|
+
const api = createOpenState(props);
|
|
134
|
+
provide(DialogKey2, api);
|
|
135
|
+
return /* @__PURE__ */ jsx(Fragment, {
|
|
136
|
+
children: () => _$unwrap(props).children
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
var DialogTrigger2 = cc((props) => {
|
|
140
|
+
const api = inject(DialogKey2);
|
|
141
|
+
const onClick = () => {
|
|
142
|
+
api.setOpen(true);
|
|
143
|
+
};
|
|
144
|
+
const ref = (el) => {
|
|
145
|
+
api.triggerEl.value = el;
|
|
146
|
+
};
|
|
147
|
+
if (props.asChild) {
|
|
148
|
+
return /* @__PURE__ */ jsx(Slot2, {
|
|
149
|
+
class: () => _$unwrap(props).class,
|
|
150
|
+
onclick: onClick,
|
|
151
|
+
ref,
|
|
152
|
+
children: () => _$unwrap(props).children
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
return _$createTemplate(_$tmpl_0, [
|
|
156
|
+
() => _$unwrap(props).class,
|
|
157
|
+
onClick,
|
|
158
|
+
ref,
|
|
159
|
+
() => _$unwrap(props).children
|
|
160
|
+
]);
|
|
161
|
+
});
|
|
162
|
+
var DialogClose2 = cc((props) => {
|
|
163
|
+
const api = inject(DialogKey2);
|
|
164
|
+
const onClick = () => {
|
|
165
|
+
api.setOpen(false);
|
|
166
|
+
};
|
|
167
|
+
if (props.asChild) {
|
|
168
|
+
return /* @__PURE__ */ jsx(Slot2, {
|
|
169
|
+
class: () => _$unwrap(props).class,
|
|
170
|
+
onclick: onClick,
|
|
171
|
+
children: () => _$unwrap(props).children
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
return _$createTemplate(_$tmpl_1, [
|
|
175
|
+
() => _$unwrap(props).class,
|
|
176
|
+
onClick,
|
|
177
|
+
() => _$unwrap(props).children
|
|
178
|
+
]);
|
|
179
|
+
});
|
|
180
|
+
var DialogOverlay2 = cc((props) => {
|
|
181
|
+
const api = inject(DialogKey2);
|
|
182
|
+
function dismiss() {
|
|
183
|
+
api.setOpen(false);
|
|
184
|
+
}
|
|
185
|
+
function overlayState() {
|
|
186
|
+
return api.open.value ? "open" : "closed";
|
|
187
|
+
}
|
|
188
|
+
return /* @__PURE__ */ jsx(Presence2, {
|
|
189
|
+
present: () => api.open.value,
|
|
190
|
+
children: /* @__PURE__ */ jsx(UiPortal2, {
|
|
191
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
192
|
+
"data-slot": "dialog-overlay",
|
|
193
|
+
"data-state": overlayState,
|
|
194
|
+
class: () => _$unwrap(props).class,
|
|
195
|
+
onclick: dismiss
|
|
196
|
+
})
|
|
197
|
+
})
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
var DialogContent2 = cc((props) => {
|
|
201
|
+
const dataAttrs = _$createLiveRest(props, [
|
|
202
|
+
"children",
|
|
203
|
+
"class",
|
|
204
|
+
"onEscapeKeyDown",
|
|
205
|
+
"data-side",
|
|
206
|
+
"data-size",
|
|
207
|
+
"data-vaul-drawer-direction",
|
|
208
|
+
"data-slot"
|
|
209
|
+
]);
|
|
210
|
+
const api = inject(DialogKey2);
|
|
211
|
+
let contentEl = null;
|
|
212
|
+
let previousFocus = null;
|
|
213
|
+
onMounted(() => {
|
|
214
|
+
function onKey(e) {
|
|
215
|
+
if (!api.open.value)
|
|
216
|
+
return;
|
|
217
|
+
if (e.key === "Escape") {
|
|
218
|
+
props.onEscapeKeyDown?.(e);
|
|
219
|
+
if (!e.defaultPrevented)
|
|
220
|
+
api.setOpen(false);
|
|
221
|
+
}
|
|
222
|
+
if (contentEl)
|
|
223
|
+
trapFocus2(e, contentEl);
|
|
224
|
+
}
|
|
225
|
+
function cleanup() {
|
|
226
|
+
document.removeEventListener("keydown", onKey);
|
|
227
|
+
}
|
|
228
|
+
document.addEventListener("keydown", onKey);
|
|
229
|
+
onUnmounted(cleanup);
|
|
230
|
+
});
|
|
231
|
+
function contentState() {
|
|
232
|
+
return api.open.value ? "open" : "closed";
|
|
233
|
+
}
|
|
234
|
+
return /* @__PURE__ */ jsx(Presence2, {
|
|
235
|
+
present: () => api.open.value,
|
|
236
|
+
children: /* @__PURE__ */ jsx(UiPortal2, {
|
|
237
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
238
|
+
..._$getSpreadProps(dataAttrs),
|
|
239
|
+
role: "dialog",
|
|
240
|
+
"aria-modal": "true",
|
|
241
|
+
"data-slot": () => props["data-slot"] === undefined ? "dialog-content" : props["data-slot"],
|
|
242
|
+
"data-state": contentState,
|
|
243
|
+
"data-side": () => props["data-side"],
|
|
244
|
+
"data-size": () => props["data-size"],
|
|
245
|
+
"data-vaul-drawer-direction": () => props["data-vaul-drawer-direction"],
|
|
246
|
+
class: () => _$unwrap(props).class,
|
|
247
|
+
ref: function contentRef(el) {
|
|
248
|
+
contentEl = el;
|
|
249
|
+
if (el) {
|
|
250
|
+
previousFocus = document.activeElement;
|
|
251
|
+
el.focus?.();
|
|
252
|
+
} else if (previousFocus) {
|
|
253
|
+
previousFocus.focus?.();
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
tabIndex: -1,
|
|
257
|
+
onclick: function stopBubble(e) {
|
|
258
|
+
e.stopPropagation();
|
|
259
|
+
},
|
|
260
|
+
children: () => _$unwrap(props).children
|
|
261
|
+
})
|
|
262
|
+
})
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
var CollapsibleKey2 = Symbol("sinwan-ui.collapsible");
|
|
266
|
+
var CollapsibleRoot2 = cc((props) => {
|
|
267
|
+
const openLocal = signal(props.defaultOpen ?? false);
|
|
268
|
+
const open = "open" in props ? computed(() => Boolean(props.open)) : openLocal;
|
|
269
|
+
const set = (next) => {
|
|
270
|
+
if (!("open" in props))
|
|
271
|
+
openLocal.value = next;
|
|
272
|
+
};
|
|
273
|
+
provide(CollapsibleKey2, {
|
|
274
|
+
open,
|
|
275
|
+
setOpen: function setOpen(v) {
|
|
276
|
+
set(v);
|
|
277
|
+
props.onOpenChange?.(v);
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
return _$createTemplate(_$tmpl_2, [
|
|
281
|
+
function stateAttr() {
|
|
282
|
+
return open.value ? "open" : "closed";
|
|
283
|
+
},
|
|
284
|
+
() => _$unwrap(props).class,
|
|
285
|
+
() => _$unwrap(props).children
|
|
286
|
+
]);
|
|
287
|
+
});
|
|
288
|
+
var CollapsibleTrigger2 = cc((props) => {
|
|
289
|
+
const api = inject(CollapsibleKey2);
|
|
290
|
+
const toggle = () => {
|
|
291
|
+
api.setOpen(!api.open.value);
|
|
292
|
+
};
|
|
293
|
+
if (props.asChild) {
|
|
294
|
+
return /* @__PURE__ */ jsx(Slot2, {
|
|
295
|
+
class: () => _$unwrap(props).class,
|
|
296
|
+
onclick: toggle,
|
|
297
|
+
children: () => _$unwrap(props).children
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
return _$createTemplate(_$tmpl_3, [
|
|
301
|
+
() => _$unwrap(props).class,
|
|
302
|
+
function expanded() {
|
|
303
|
+
return api.open.value;
|
|
304
|
+
},
|
|
305
|
+
toggle,
|
|
306
|
+
() => _$unwrap(props).children
|
|
307
|
+
]);
|
|
308
|
+
});
|
|
309
|
+
var CollapsibleContent2 = cc((props) => {
|
|
310
|
+
const api = inject(CollapsibleKey2);
|
|
311
|
+
function stateAttr() {
|
|
312
|
+
return api.open.value ? "open" : "closed";
|
|
313
|
+
}
|
|
314
|
+
function bindContent(el) {
|
|
315
|
+
if (el == null)
|
|
316
|
+
return;
|
|
317
|
+
const node = el;
|
|
318
|
+
function measure() {
|
|
319
|
+
const inner = node.firstElementChild;
|
|
320
|
+
const height = inner instanceof HTMLElement ? inner.scrollHeight : node.scrollHeight;
|
|
321
|
+
node.style.setProperty("--radix-collapsible-content-height", `${height}px`);
|
|
322
|
+
}
|
|
323
|
+
measure();
|
|
324
|
+
requestAnimationFrame(measure);
|
|
325
|
+
}
|
|
326
|
+
return /* @__PURE__ */ jsx(Presence2, {
|
|
327
|
+
present: () => api.open.value,
|
|
328
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
329
|
+
"data-slot": "collapsible-content",
|
|
330
|
+
"data-state": stateAttr,
|
|
331
|
+
class: () => _$unwrap(props).class,
|
|
332
|
+
ref: bindContent,
|
|
333
|
+
children: () => _$unwrap(props).children
|
|
334
|
+
})
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
var PopoverKey2 = Symbol("sinwan-ui.popover");
|
|
338
|
+
var PopoverRoot2 = cc((props) => {
|
|
339
|
+
const api = createOpenState(props);
|
|
340
|
+
provide(PopoverKey2, {
|
|
341
|
+
...api,
|
|
342
|
+
placement: props.placement ?? "bottom",
|
|
343
|
+
align: props.align ?? "center"
|
|
344
|
+
});
|
|
345
|
+
return /* @__PURE__ */ jsx(Fragment, {
|
|
346
|
+
children: () => _$unwrap(props).children
|
|
347
|
+
});
|
|
348
|
+
});
|
|
349
|
+
var PopoverTrigger2 = cc((props) => {
|
|
350
|
+
const api = inject(PopoverKey2);
|
|
351
|
+
function onClick() {
|
|
352
|
+
api.setOpen(!api.open.value);
|
|
353
|
+
}
|
|
354
|
+
const ref = (el) => {
|
|
355
|
+
api.triggerEl.value = el;
|
|
356
|
+
};
|
|
357
|
+
if (props.asChild) {
|
|
358
|
+
return /* @__PURE__ */ jsx(Slot2, {
|
|
359
|
+
class: () => _$unwrap(props).class,
|
|
360
|
+
onclick: onClick,
|
|
361
|
+
ref,
|
|
362
|
+
children: () => _$unwrap(props).children
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
return _$createTemplate(_$tmpl_4, [
|
|
366
|
+
() => _$unwrap(props).class,
|
|
367
|
+
function expanded() {
|
|
368
|
+
return api.open.value;
|
|
369
|
+
},
|
|
370
|
+
onClick,
|
|
371
|
+
ref,
|
|
372
|
+
() => _$unwrap(props).children
|
|
373
|
+
]);
|
|
374
|
+
});
|
|
375
|
+
var PopoverContent2 = cc((props) => {
|
|
376
|
+
const api = inject(PopoverKey2);
|
|
377
|
+
const contentEl = signal(null);
|
|
378
|
+
const { style, side: resolvedSide } = useAnchorPosition2({
|
|
379
|
+
open: api.open,
|
|
380
|
+
trigger: api.triggerEl,
|
|
381
|
+
content: contentEl,
|
|
382
|
+
placement: props.side ?? api.placement,
|
|
383
|
+
align: props.align ?? api.align,
|
|
384
|
+
gap: props.sideOffset === undefined ? 8 : props.sideOffset,
|
|
385
|
+
fallbackSize: { width: 240, height: 160 }
|
|
386
|
+
});
|
|
387
|
+
onMounted(() => {
|
|
388
|
+
function onDoc(e) {
|
|
389
|
+
if (!api.open.value)
|
|
390
|
+
return;
|
|
391
|
+
const t = e.target;
|
|
392
|
+
if (t instanceof Node && api.triggerEl.value?.contains(t) || isDismissExemptPointerTarget2(t)) {
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
api.setOpen(false);
|
|
396
|
+
}
|
|
397
|
+
function onKey(e) {
|
|
398
|
+
if (e.key === "Escape") {
|
|
399
|
+
api.setOpen(false);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
document.addEventListener("pointerdown", onDoc);
|
|
403
|
+
document.addEventListener("keydown", onKey);
|
|
404
|
+
onUnmounted(() => {
|
|
405
|
+
document.removeEventListener("pointerdown", onDoc);
|
|
406
|
+
document.removeEventListener("keydown", onKey);
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
function popoverState() {
|
|
410
|
+
return api.open.value ? "open" : "closed";
|
|
411
|
+
}
|
|
412
|
+
return /* @__PURE__ */ jsx(Presence2, {
|
|
413
|
+
present: () => api.open.value,
|
|
414
|
+
children: /* @__PURE__ */ jsx(UiPortal2, {
|
|
415
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
416
|
+
"data-slot": "popover-content",
|
|
417
|
+
"data-state": popoverState,
|
|
418
|
+
"data-side": () => resolvedSide.value,
|
|
419
|
+
class: () => _$unwrap(props).class,
|
|
420
|
+
style: () => style.value,
|
|
421
|
+
role: "dialog",
|
|
422
|
+
onmouseenter: props.onmouseenter,
|
|
423
|
+
onmouseleave: props.onmouseleave,
|
|
424
|
+
ref: (el) => {
|
|
425
|
+
contentEl.value = el;
|
|
426
|
+
},
|
|
427
|
+
children: () => _$unwrap(props).children
|
|
428
|
+
})
|
|
429
|
+
})
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
var TooltipKey2 = Symbol("sinwan-ui.tooltip");
|
|
433
|
+
var TooltipProvider2 = cc((props) => {
|
|
434
|
+
props.delayDuration;
|
|
435
|
+
return props.children ?? null;
|
|
436
|
+
});
|
|
437
|
+
var TooltipRoot2 = cc((props) => {
|
|
438
|
+
const api = createOpenState(props);
|
|
439
|
+
provide(TooltipKey2, api);
|
|
440
|
+
return /* @__PURE__ */ jsx(Fragment, {
|
|
441
|
+
children: () => _$unwrap(props).children
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
var TooltipTrigger2 = cc((props) => {
|
|
445
|
+
const api = inject(TooltipKey2);
|
|
446
|
+
const show = () => {
|
|
447
|
+
api.setOpen(true);
|
|
448
|
+
};
|
|
449
|
+
const hide = () => {
|
|
450
|
+
api.setOpen(false);
|
|
451
|
+
};
|
|
452
|
+
const ref = (el) => {
|
|
453
|
+
api.triggerEl.value = el;
|
|
454
|
+
};
|
|
455
|
+
const handlers = {
|
|
456
|
+
onmouseenter: show,
|
|
457
|
+
onmouseleave: hide,
|
|
458
|
+
onfocus: show,
|
|
459
|
+
onblur: hide,
|
|
460
|
+
ref
|
|
461
|
+
};
|
|
462
|
+
if (props.asChild) {
|
|
463
|
+
return /* @__PURE__ */ jsx(Slot2, {
|
|
464
|
+
class: () => _$unwrap(props).class,
|
|
465
|
+
...handlers,
|
|
466
|
+
children: () => _$unwrap(props).children
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
return /* @__PURE__ */ jsx("button", {
|
|
470
|
+
type: "button",
|
|
471
|
+
class: () => _$unwrap(props).class,
|
|
472
|
+
"data-slot": "tooltip-trigger",
|
|
473
|
+
...handlers,
|
|
474
|
+
children: () => _$unwrap(props).children
|
|
475
|
+
});
|
|
476
|
+
});
|
|
477
|
+
var TooltipContent2 = cc((props) => {
|
|
478
|
+
const api = inject(TooltipKey2);
|
|
479
|
+
const contentEl = signal(null);
|
|
480
|
+
const { style, side: resolvedSide } = useAnchorPosition2({
|
|
481
|
+
open: api.open,
|
|
482
|
+
trigger: api.triggerEl,
|
|
483
|
+
content: contentEl,
|
|
484
|
+
placement: props.side === undefined ? "top" : props.side,
|
|
485
|
+
align: "center",
|
|
486
|
+
gap: props.sideOffset === undefined ? 8 : props.sideOffset,
|
|
487
|
+
fallbackSize: { width: 120, height: 32 }
|
|
488
|
+
});
|
|
489
|
+
function tooltipState() {
|
|
490
|
+
return api.open.value ? "open" : "closed";
|
|
491
|
+
}
|
|
492
|
+
return /* @__PURE__ */ jsx(Presence2, {
|
|
493
|
+
present: () => api.open.value,
|
|
494
|
+
children: /* @__PURE__ */ jsx(UiPortal2, {
|
|
495
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
496
|
+
role: "tooltip",
|
|
497
|
+
"data-slot": "tooltip-content",
|
|
498
|
+
"data-state": tooltipState,
|
|
499
|
+
"data-side": () => resolvedSide.value,
|
|
500
|
+
class: () => _$unwrap(props).class,
|
|
501
|
+
style: () => style.value,
|
|
502
|
+
ref: (el) => {
|
|
503
|
+
contentEl.value = el;
|
|
504
|
+
},
|
|
505
|
+
children: () => _$unwrap(props).children
|
|
506
|
+
})
|
|
507
|
+
})
|
|
508
|
+
});
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
export { DialogKey2, DialogRoot2, DialogTrigger2, DialogClose2, DialogOverlay2, DialogContent2, CollapsibleKey2, CollapsibleRoot2, CollapsibleTrigger2, CollapsibleContent2, PopoverKey2, PopoverRoot2, PopoverTrigger2, PopoverContent2, TooltipKey2, TooltipProvider2, TooltipRoot2, TooltipTrigger2, TooltipContent2 };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// src/dismiss.ts
|
|
2
|
+
var DISMISS_EXEMPT_SELECTOR = [
|
|
3
|
+
"[data-slot$='-menu-content']",
|
|
4
|
+
"[data-slot='menubar-content']",
|
|
5
|
+
"[data-slot$='-sub-content']",
|
|
6
|
+
"[data-slot='select-content']",
|
|
7
|
+
"[data-slot='popover-content']",
|
|
8
|
+
"[data-slot='dialog-content']",
|
|
9
|
+
"[data-slot='alert-dialog-content']",
|
|
10
|
+
"[data-slot='sheet-content']",
|
|
11
|
+
"[data-slot='drawer-content']",
|
|
12
|
+
"[data-slot$='-overlay']",
|
|
13
|
+
"select",
|
|
14
|
+
"option",
|
|
15
|
+
"optgroup"
|
|
16
|
+
].join(",");
|
|
17
|
+
function isDismissExemptPointerTarget2(target) {
|
|
18
|
+
if (target == null)
|
|
19
|
+
return false;
|
|
20
|
+
let el = null;
|
|
21
|
+
if (target instanceof Element) {
|
|
22
|
+
el = target;
|
|
23
|
+
} else if (target instanceof Node) {
|
|
24
|
+
el = target.parentElement;
|
|
25
|
+
}
|
|
26
|
+
if (el == null)
|
|
27
|
+
return false;
|
|
28
|
+
return el.closest(DISMISS_EXEMPT_SELECTOR) != null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export { isDismissExemptPointerTarget2 };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isSinwanElement2,
|
|
3
|
+
flattenChildren2
|
|
4
|
+
} from "./chunk-7r6fwdyt.js";
|
|
5
|
+
|
|
6
|
+
// src/slot.ts
|
|
7
|
+
import { isComputed, isSignal, resolve } from "sinwan/reactivity";
|
|
8
|
+
function isClassSource(value) {
|
|
9
|
+
return typeof value === "string" || isSignal(value) || isComputed(value) || typeof value === "function" && value.length === 0;
|
|
10
|
+
}
|
|
11
|
+
function classText(value) {
|
|
12
|
+
if (value == null)
|
|
13
|
+
return "";
|
|
14
|
+
if (!isClassSource(value))
|
|
15
|
+
return "";
|
|
16
|
+
const resolved = resolve(value);
|
|
17
|
+
return typeof resolved === "string" ? resolved : "";
|
|
18
|
+
}
|
|
19
|
+
function mergeClass(a, b) {
|
|
20
|
+
const aReactive = isClassSource(a) && typeof a !== "string";
|
|
21
|
+
const bReactive = isClassSource(b) && typeof b !== "string";
|
|
22
|
+
if (aReactive || bReactive || typeof a === "function" || typeof b === "function") {
|
|
23
|
+
return () => {
|
|
24
|
+
const parts = [classText(a), classText(b)].filter((part) => part.length > 0);
|
|
25
|
+
return parts.length === 0 ? undefined : parts.join(" ");
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const parts = [a, b].filter((v) => typeof v === "string" && v.length > 0);
|
|
29
|
+
if (parts.length === 0)
|
|
30
|
+
return;
|
|
31
|
+
return parts.join(" ");
|
|
32
|
+
}
|
|
33
|
+
function mergeProps(slotProps, childProps) {
|
|
34
|
+
const merged = { ...childProps, ...slotProps };
|
|
35
|
+
const className = mergeClass(childProps.class, slotProps.class);
|
|
36
|
+
if (className !== undefined)
|
|
37
|
+
merged.class = className;
|
|
38
|
+
else {
|
|
39
|
+
delete merged.class;
|
|
40
|
+
}
|
|
41
|
+
for (const key of Object.keys(slotProps)) {
|
|
42
|
+
if (!key.startsWith("on"))
|
|
43
|
+
continue;
|
|
44
|
+
const slotHandler = slotProps[key];
|
|
45
|
+
const childHandler = childProps[key];
|
|
46
|
+
if (typeof slotHandler === "function" && typeof childHandler === "function") {
|
|
47
|
+
merged[key] = (...args) => {
|
|
48
|
+
childHandler(...args);
|
|
49
|
+
slotHandler(...args);
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return merged;
|
|
54
|
+
}
|
|
55
|
+
function Slot2(props) {
|
|
56
|
+
const { children, ...slotProps } = props;
|
|
57
|
+
const flat = flattenChildren2(children).filter((c) => c != null && c !== false && c !== true);
|
|
58
|
+
if (flat.length !== 1 || !isSinwanElement2(flat[0])) {
|
|
59
|
+
throw new Error("Slot expects exactly one Sinwan element child");
|
|
60
|
+
}
|
|
61
|
+
const child = flat[0];
|
|
62
|
+
return {
|
|
63
|
+
tag: child.tag,
|
|
64
|
+
props: mergeProps(slotProps, child.props),
|
|
65
|
+
children: child.children
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export { Slot2 };
|