@devslab/dds-solid 0.17.1 → 0.19.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/dist/server.js CHANGED
@@ -1,6 +1,19 @@
1
- import { For, Show, createContext, createEffect, createSignal, createUniqueId, onCleanup, onMount, splitProps, useContext } from "solid-js";
2
- import { createComponent, escape, memo, mergeProps, ssr, ssrAttribute, ssrElement, ssrHydrationKey } from "solid-js/web";
1
+ import { For, Show, createContext, createEffect, createMemo, createSignal, createUniqueId, mergeProps, onCleanup, onMount, splitProps, useContext } from "solid-js";
2
+ import { Dynamic, Portal, createComponent, escape, isServer, memo, mergeProps as mergeProps$1, ssr, ssrAttribute, ssrElement, ssrHydrationKey } from "solid-js/web";
3
+ import { useCheckbox } from "@ark-ui/solid/checkbox";
4
+ import { useSwitch } from "@ark-ui/solid/switch";
5
+ import { Field as Field$1 } from "@ark-ui/solid/field";
6
+ import { Dialog as Dialog$1, useDialog } from "@ark-ui/solid/dialog";
7
+ import { usePresenceContext } from "@ark-ui/solid/presence";
8
+ import { FocusTrap } from "@zag-js/focus-trap";
9
+ import { ariaHidden } from "@zag-js/aria-hidden";
10
+ import { RadioGroup as RadioGroup$1 } from "@ark-ui/solid/radio-group";
3
11
  import { directionPolicy, icons } from "@devslab/dds-icons";
12
+ import { Tabs as Tabs$1, useTabsContext } from "@ark-ui/solid/tabs";
13
+ import { LocaleProvider } from "@ark-ui/solid/locale";
14
+ import { Toast, Toaster, createToaster } from "@ark-ui/solid/toast";
15
+ import { space } from "@devslab/dds-tokens";
16
+ import { Tooltip as Tooltip$1, useTooltip } from "@ark-ui/solid/tooltip";
4
17
  //#region src/controllable.ts
5
18
  function createControllableSignal(options) {
6
19
  const [internal, setInternal] = createSignal(options.defaultValue);
@@ -24,34 +37,14 @@ function describedBy(...ids) {
24
37
  }
25
38
  //#endregion
26
39
  //#region src/controls.tsx
27
- var _tmpl$$6 = ["<span", " class=\"dds-spinner\" aria-hidden=\"true\"></span>"];
28
- var _tmpl$2$5 = [
29
- "<div",
30
- "><label class=\"dds-field__label\"",
31
- "><!--$-->",
32
- "<!--/--><!--$-->",
33
- "<!--/--></label><!--$-->",
34
- "<!--/--><!--$-->",
35
- "<!--/--><!--$-->",
36
- "<!--/--></div>"
37
- ];
38
- var _tmpl$3$3 = ["<span", " aria-hidden=\"true\"> *</span>"];
39
- var _tmpl$4$1 = [
40
- "<div",
41
- " class=\"dds-field__help\">",
42
- "</div>"
43
- ];
44
- var _tmpl$5$1 = [
45
- "<div",
46
- " class=\"dds-field__error\" role=\"alert\">",
47
- "</div>"
48
- ];
49
- var _tmpl$6$1 = [
40
+ var _tmpl$$5 = ["<span", " class=\"dds-spinner\" aria-hidden=\"true\"></span>"];
41
+ var _tmpl$2$3 = ["<span", " aria-hidden=\"true\"> *</span>"];
42
+ var _tmpl$3$1 = [
50
43
  "<span",
51
44
  ">",
52
45
  "</span>"
53
46
  ];
54
- var _tmpl$7$1 = [
47
+ var _tmpl$4$1 = [
55
48
  "<label",
56
49
  ">",
57
50
  "<span>",
@@ -67,7 +60,7 @@ function Button(props) {
67
60
  "type",
68
61
  "children"
69
62
  ]);
70
- return ssrElement("button", mergeProps(rest, {
63
+ return ssrElement("button", mergeProps$1(rest, {
71
64
  get type() {
72
65
  return local.type ?? "button";
73
66
  },
@@ -82,7 +75,7 @@ function Button(props) {
82
75
  }
83
76
  }), () => [
84
77
  "<!--$-->",
85
- local.loading && _tmpl$$6[0] + ssrHydrationKey() + _tmpl$$6[1],
78
+ local.loading && _tmpl$$5[0] + ssrHydrationKey() + _tmpl$$5[1],
86
79
  "<!--/-->",
87
80
  "<!--$-->",
88
81
  escape(local.children),
@@ -99,7 +92,7 @@ function IconButton(props) {
99
92
  "type",
100
93
  "children"
101
94
  ]);
102
- return ssrElement("button", mergeProps(rest, {
95
+ return ssrElement("button", mergeProps$1(rest, {
103
96
  get type() {
104
97
  return local.type ?? "button";
105
98
  },
@@ -112,7 +105,7 @@ function IconButton(props) {
112
105
  get ["aria-busy"]() {
113
106
  return local.loading ? "true" : void 0;
114
107
  }
115
- }), () => local.loading ? _tmpl$$6[0] + ssrHydrationKey() + _tmpl$$6[1] : escape(local.children), true);
108
+ }), () => local.loading ? _tmpl$$5[0] + ssrHydrationKey() + _tmpl$$5[1] : escape(local.children), true);
116
109
  }
117
110
  function Field(props) {
118
111
  const generated = createUniqueId();
@@ -125,7 +118,54 @@ function Field(props) {
125
118
  "aria-invalid": props.error ? "true" : void 0,
126
119
  "aria-required": props.required ? "true" : void 0
127
120
  });
128
- return ssr(_tmpl$2$5, ssrHydrationKey() + ssrAttribute("class", escape(classes("dds-field", props.error ? "dds-field--error" : void 0, props.class), true), false), ssrAttribute("for", escape(id(), true), false), escape(props.label), props.required && _tmpl$3$3[0] + ssrHydrationKey() + _tmpl$3$3[1], typeof props.children === "function" ? escape(props.children(control())) : escape(props.children), props.helpText && ssr(_tmpl$4$1, ssrHydrationKey() + ssrAttribute("id", escape(helpId(), true), false), escape(props.helpText)), props.error && ssr(_tmpl$5$1, ssrHydrationKey() + ssrAttribute("id", escape(errorId(), true), false), escape(props.error)));
121
+ return createComponent(Field$1.Root, {
122
+ get id() {
123
+ return id();
124
+ },
125
+ get required() {
126
+ return props.required ?? false;
127
+ },
128
+ get invalid() {
129
+ return Boolean(props.error);
130
+ },
131
+ get ids() {
132
+ return {
133
+ control: `${id()}-root`,
134
+ helperText: `${id()}-help`,
135
+ errorText: `${id()}-error`
136
+ };
137
+ },
138
+ get ["class"]() {
139
+ return classes("dds-field", props.error ? "dds-field--error" : void 0, props.class);
140
+ },
141
+ get children() {
142
+ return [
143
+ createComponent(Field$1.Label, {
144
+ "class": "dds-field__label",
145
+ get ["for"]() {
146
+ return id();
147
+ },
148
+ get children() {
149
+ return [props.label, props.required && ssr(_tmpl$2$3, ssrHydrationKey())];
150
+ }
151
+ }),
152
+ typeof props.children === "function" ? props.children(control()) : props.children,
153
+ props.helpText && createComponent(Field$1.HelperText, {
154
+ "class": "dds-field__help",
155
+ get children() {
156
+ return props.helpText;
157
+ }
158
+ }),
159
+ props.error && createComponent(Field$1.ErrorText, {
160
+ "class": "dds-field__error",
161
+ role: "alert",
162
+ get children() {
163
+ return props.error;
164
+ }
165
+ })
166
+ ];
167
+ }
168
+ });
129
169
  }
130
170
  function Select(props) {
131
171
  const [local, rest] = splitProps(props, [
@@ -133,7 +173,7 @@ function Select(props) {
133
173
  "invalid",
134
174
  "children"
135
175
  ]);
136
- return ssr(_tmpl$6$1, ssrHydrationKey() + ssrAttribute("class", escape(classes("dds-select", local.class), true), false), ssrElement("select", mergeProps(rest, {
176
+ return ssr(_tmpl$3$1, ssrHydrationKey() + ssrAttribute("class", escape(classes("dds-select", local.class), true), false), ssrElement("select", mergeProps$1(rest, {
137
177
  "class": "dds-select__input",
138
178
  get ["aria-invalid"]() {
139
179
  return local.invalid ? "true" : void 0;
@@ -156,7 +196,7 @@ function Checkable(props) {
156
196
  defaultValue: local.defaultChecked ?? false,
157
197
  onChange: local.onCheckedChange
158
198
  });
159
- return ssr(_tmpl$7$1, ssrHydrationKey() + ssrAttribute("class", escape(classes(local.role === "switch" ? "dds-switch" : "dds-check", local.class), true), false), ssrElement("input", mergeProps(rest, {
199
+ return ssr(_tmpl$4$1, ssrHydrationKey() + ssrAttribute("class", escape(classes(local.role === "switch" ? "dds-switch" : "dds-check", local.class), true), false), ssrElement("input", mergeProps$1(rest, {
160
200
  get type() {
161
201
  return local.type;
162
202
  },
@@ -171,25 +211,75 @@ function Checkable(props) {
171
211
  }
172
212
  }), void 0, false), escape(local.label));
173
213
  }
174
- var Checkbox = (props) => createComponent(Checkable, mergeProps(props, { type: "checkbox" }));
175
- var Radio = (props) => createComponent(Checkable, mergeProps(props, { type: "radio" }));
176
- var Switch = (props) => createComponent(Checkable, mergeProps(props, {
177
- type: "checkbox",
178
- role: "switch"
179
- }));
214
+ var Checkbox = (props) => createComponent(ArkCheckable, mergeProps$1(props, { kind: "checkbox" }));
215
+ var Radio = (props) => createComponent(Checkable, mergeProps$1(props, { type: "radio" }));
216
+ var Switch = (props) => createComponent(ArkCheckable, mergeProps$1(props, { kind: "switch" }));
217
+ function ArkCheckable(props) {
218
+ const generated = createUniqueId();
219
+ const [local, rest] = splitProps(props, [
220
+ "checked",
221
+ "defaultChecked",
222
+ "onCheckedChange",
223
+ "label",
224
+ "class",
225
+ "inputClass",
226
+ "kind",
227
+ "id",
228
+ "onClick",
229
+ "onFocusIn",
230
+ "onFocusOut",
231
+ "style"
232
+ ]);
233
+ const options = () => ({
234
+ id: `dds-check-${generated}`,
235
+ ids: { hiddenInput: local.id ?? `dds-check-${generated}-input` },
236
+ checked: local.checked,
237
+ defaultChecked: local.defaultChecked,
238
+ onCheckedChange: (details) => local.onCheckedChange?.(details.checked === true),
239
+ disabled: rest.disabled,
240
+ required: rest.required,
241
+ readOnly: rest.readonly,
242
+ name: rest.name,
243
+ form: rest.form,
244
+ value: String(rest.value ?? "on")
245
+ });
246
+ const api = local.kind === "switch" ? useSwitch(options) : useCheckbox(options);
247
+ const inputClass = () => local.kind === "switch" ? "dds-switch__input" : "dds-check__input";
248
+ const rootProps = () => {
249
+ const [, attributes] = splitProps(api().getRootProps(), ["onClick"]);
250
+ return attributes;
251
+ };
252
+ return ssrElement("label", mergeProps$1(rootProps, { get ["class"]() {
253
+ return classes(local.kind === "switch" ? "dds-switch" : "dds-check", local.class);
254
+ } }), () => [ssrElement("input", mergeProps$1(() => api().getHiddenInputProps(), rest, {
255
+ type: "checkbox",
256
+ get role() {
257
+ return local.kind === "switch" ? "switch" : void 0;
258
+ },
259
+ get ["class"]() {
260
+ return classes(inputClass(), local.inputClass);
261
+ },
262
+ get style() {
263
+ return local.style ?? {};
264
+ },
265
+ get checked() {
266
+ return api().checked;
267
+ }
268
+ }), void 0, false), ssrElement("span", api().getLabelProps(), () => escape(local.label), false)], true);
269
+ }
180
270
  //#endregion
181
271
  //#region src/console-shell.tsx
182
- var _tmpl$$5 = [
272
+ var _tmpl$$4 = [
183
273
  "<dl",
184
274
  " class=\"dds-console-rail__context\">",
185
275
  "</dl>"
186
276
  ];
187
- var _tmpl$2$4 = [
277
+ var _tmpl$2$2 = [
188
278
  "<div",
189
279
  " class=\"dds-console-rail__foot\">",
190
280
  "</div>"
191
281
  ];
192
- var _tmpl$3$2 = [
282
+ var _tmpl$3 = [
193
283
  "<p",
194
284
  " class=\"dds-console-page-eyebrow\">",
195
285
  "</p>"
@@ -280,7 +370,7 @@ function ConsoleShell(props) {
280
370
  return memo(() => !!props.context)() && props.context.length > 0;
281
371
  },
282
372
  get children() {
283
- return ssr(_tmpl$$5, ssrHydrationKey(), escape(createComponent(For, {
373
+ return ssr(_tmpl$$4, ssrHydrationKey(), escape(createComponent(For, {
284
374
  get each() {
285
375
  return props.context;
286
376
  },
@@ -312,14 +402,14 @@ function ConsoleShell(props) {
312
402
  return props.foot;
313
403
  },
314
404
  get children() {
315
- return ssr(_tmpl$2$4, ssrHydrationKey(), escape(props.foot));
405
+ return ssr(_tmpl$2$2, ssrHydrationKey(), escape(props.foot));
316
406
  }
317
407
  })), escape(createComponent(Show, {
318
408
  get when() {
319
409
  return props.header.eyebrow;
320
410
  },
321
411
  get children() {
322
- return ssr(_tmpl$3$2, ssrHydrationKey(), escape(props.header.eyebrow));
412
+ return ssr(_tmpl$3, ssrHydrationKey(), escape(props.header.eyebrow));
323
413
  }
324
414
  })), escape(props.header.title), escape(createComponent(Show, {
325
415
  get when() {
@@ -332,28 +422,12 @@ function ConsoleShell(props) {
332
422
  }
333
423
  //#endregion
334
424
  //#region src/dialog.tsx
335
- var _tmpl$$4 = [
425
+ var _tmpl$$3 = [
336
426
  "<div",
337
- " class=\"dds-dialog-overlay\"><div",
338
- " role=\"dialog\" aria-modal=\"true\"",
339
- " tabindex=\"-1\"><h2",
340
- " class=\"dds-dialog__title\">",
341
- "</h2><!--$-->",
342
- "<!--/--><!--$-->",
343
- "<!--/--><!--$-->",
344
- "<!--/--></div></div>"
345
- ];
346
- var _tmpl$2$3 = [
347
- "<div",
348
- " class=\"dds-dialog__body\">",
349
- "</div>"
350
- ];
351
- var _tmpl$3$1 = [
352
- "<div",
353
- " class=\"dds-dialog__actions\">",
427
+ ">",
354
428
  "</div>"
355
429
  ];
356
- var focusable = [
430
+ [
357
431
  "a[href]",
358
432
  "button:not([disabled])",
359
433
  "input:not([disabled])",
@@ -364,61 +438,215 @@ var focusable = [
364
438
  function Dialog(props) {
365
439
  const generated = createUniqueId();
366
440
  const id = () => props.id ?? `dds-dialog-${generated}`;
367
- const titleId = () => `${id()}-title`;
368
- const descriptionId = () => props.description ? `${id()}-description` : void 0;
369
- const [open, setOpen] = createControllableSignal({
370
- value: () => props.open,
371
- defaultValue: props.defaultOpen ?? false,
372
- onChange: props.onOpenChange
373
- });
374
- let panel;
375
- let previouslyFocused = null;
441
+ const [panel, setPanel] = createSignal();
442
+ const api = useDialog(() => ({
443
+ id: id(),
444
+ open: props.open,
445
+ defaultOpen: props.defaultOpen,
446
+ onOpenChange: (details) => props.onOpenChange?.(details.open),
447
+ closeOnEscape: props.closeOnEscape ?? true,
448
+ closeOnInteractOutside: props.closeOnOutside ?? true,
449
+ onEscapeKeyDown: props.onEscapeKeyDown,
450
+ initialFocusEl: () => props.initialFocus?.() ?? null,
451
+ finalFocusEl: () => props.finalFocus?.() ?? null,
452
+ restoreFocus: props.restoreFocus ?? true,
453
+ modal: !props.additionalFocusContainers,
454
+ trapFocus: !props.additionalFocusContainers,
455
+ preventScroll: true,
456
+ role: props.role ?? "dialog",
457
+ persistentElements: isServer ? [] : props.additionalFocusContainers?.().filter((element) => Boolean(element)).map((element) => () => element),
458
+ ids: {
459
+ content: id(),
460
+ title: `${id()}-title`,
461
+ description: `${id()}-description`
462
+ }
463
+ }));
464
+ const open = createMemo(() => api().open);
376
465
  createEffect(() => {
377
- if (!open()) return;
378
- previouslyFocused = document.activeElement instanceof HTMLElement ? document.activeElement : null;
379
- queueMicrotask(() => {});
380
- const onKeyDown = (event) => {
381
- if (event.key === "Escape" && props.closeOnEscape !== false) {
382
- event.preventDefault();
383
- setOpen(false);
384
- return;
385
- }
386
- if (event.key !== "Tab" || true) return;
387
- const candidates = [...panel.querySelectorAll(focusable)].filter((element) => !element.hidden && element.getAttribute("aria-hidden") !== "true");
388
- if (candidates.length === 0) {
389
- event.preventDefault();
390
- panel.focus();
391
- return;
392
- }
393
- const first = candidates[0];
394
- const last = candidates[candidates.length - 1];
395
- if (event.shiftKey && document.activeElement === first) {
396
- event.preventDefault();
397
- last.focus();
398
- } else if (!event.shiftKey && document.activeElement === last) {
399
- event.preventDefault();
400
- first.focus();
401
- }
402
- };
403
- document.addEventListener("keydown", onKeyDown);
466
+ const content = panel();
467
+ if (!open() || !props.additionalFocusContainers || !content) return;
468
+ const opener = content.ownerDocument.activeElement;
469
+ let trap;
470
+ let removeIsolation;
471
+ const [ready, setReady] = createSignal(false);
472
+ const containers = () => [content, ...props.additionalFocusContainers().filter((element) => Boolean(element?.isConnected && element.ownerDocument === content.ownerDocument))];
473
+ const frame = content.ownerDocument.defaultView.requestAnimationFrame(() => {
474
+ trap = new FocusTrap(containers(), {
475
+ document: content.ownerDocument,
476
+ escapeDeactivates: false,
477
+ allowOutsideClick: true,
478
+ preventScroll: true,
479
+ delayInitialFocus: false,
480
+ fallbackFocus: content,
481
+ getShadowRoot: true,
482
+ initialFocus: () => props.initialFocus?.() ?? void 0,
483
+ setReturnFocus: () => props.finalFocus?.() ?? (opener instanceof HTMLElement && opener.isConnected ? opener : false)
484
+ });
485
+ setReady(true);
486
+ trap.activate();
487
+ });
488
+ createEffect(() => {
489
+ if (!ready()) return;
490
+ const targets = containers();
491
+ trap.updateContainerElements(targets);
492
+ removeIsolation?.();
493
+ removeIsolation = ariaHidden(targets, { defer: false });
494
+ });
404
495
  onCleanup(() => {
405
- document.removeEventListener("keydown", onKeyDown);
406
- queueMicrotask(() => previouslyFocused?.focus());
496
+ content.ownerDocument.defaultView.cancelAnimationFrame(frame);
497
+ removeIsolation?.();
498
+ trap?.deactivate({ returnFocus: props.restoreFocus !== false });
407
499
  });
408
500
  });
409
- return createComponent(Show, {
410
- get when() {
411
- return open();
501
+ const cls = (base, extra) => classes(props.unstyled ? void 0 : base, extra);
502
+ const Content = () => {
503
+ usePresenceContext();
504
+ const nativeContent = (merge) => createComponent(Dynamic, mergeProps$1({ get component() {
505
+ return props.contentAs ?? "div";
506
+ } }, () => merge({})));
507
+ return createComponent(Dialog$1.Positioner, {
508
+ get ["class"]() {
509
+ return cls("dds-dialog-overlay", props.overlayClass);
510
+ },
511
+ get children() {
512
+ return createComponent(Dialog$1.Content, mergeProps$1(() => props.contentProps, { get ["class"]() {
513
+ return cls("dds-dialog", props.class);
514
+ } }, () => props.contentAs ? { asChild: nativeContent } : {}, {
515
+ get role() {
516
+ return props.role ?? "dialog";
517
+ },
518
+ "aria-modal": "true",
519
+ get ["aria-describedby"]() {
520
+ return memo(() => !!props.description)() ? `${id()}-description` : void 0;
521
+ },
522
+ get children() {
523
+ return (() => {
524
+ const parts = {
525
+ get title() {
526
+ return createComponent(Dialog$1.Title, {
527
+ get ["class"]() {
528
+ return cls("dds-dialog__title", props.titleClass);
529
+ },
530
+ get children() {
531
+ return props.title;
532
+ }
533
+ });
534
+ },
535
+ get description() {
536
+ return props.description && createComponent(Dialog$1.Description, {
537
+ get ["class"]() {
538
+ return cls("dds-dialog__body", props.descriptionClass);
539
+ },
540
+ get children() {
541
+ return props.description;
542
+ }
543
+ });
544
+ },
545
+ get children() {
546
+ return props.children;
547
+ },
548
+ get actions() {
549
+ return props.actions && ssr(_tmpl$$3, ssrHydrationKey() + ssrAttribute("class", escape(cls("dds-dialog__actions", props.actionsClass), true), false), escape(props.actions));
550
+ }
551
+ };
552
+ return props.frame ? props.frame(parts) : [
553
+ parts.title,
554
+ parts.description,
555
+ parts.children,
556
+ parts.actions
557
+ ];
558
+ })();
559
+ }
560
+ }));
561
+ }
562
+ });
563
+ };
564
+ return createComponent(Dialog$1.RootProvider, {
565
+ value: api,
566
+ lazyMount: true,
567
+ unmountOnExit: true,
568
+ get children() {
569
+ return createComponent(Show, {
570
+ get when() {
571
+ return props.portal;
572
+ },
573
+ get fallback() {
574
+ return createComponent(Content, {});
575
+ },
576
+ get children() {
577
+ return createComponent(Portal, mergeProps$1(() => props.portalMount ? { mount: props.portalMount } : {}, { get children() {
578
+ return createComponent(Content, {});
579
+ } }));
580
+ }
581
+ });
582
+ }
583
+ });
584
+ }
585
+ //#endregion
586
+ //#region src/radio-group.tsx
587
+ /** Grouped radios delegate selection and roving keyboard focus to Ark. */
588
+ function RadioGroup(props) {
589
+ props.value ?? props.defaultValue;
590
+ return createComponent(RadioGroup$1.Root, {
591
+ get value() {
592
+ return props.value;
593
+ },
594
+ get defaultValue() {
595
+ return props.defaultValue;
596
+ },
597
+ get name() {
598
+ return props.name;
599
+ },
600
+ get form() {
601
+ return props.form;
602
+ },
603
+ get disabled() {
604
+ return props.disabled;
605
+ },
606
+ get required() {
607
+ return props.required;
608
+ },
609
+ onValueChange: (details) => {
610
+ if (details.value !== null) props.onValueChange?.(details.value);
611
+ },
612
+ get ["class"]() {
613
+ return classes("dds-radio-group", props.class);
412
614
  },
413
615
  get children() {
414
- return ssr(_tmpl$$4, ssrHydrationKey(), ssrAttribute("id", escape(id(), true), false) + ssrAttribute("class", escape(classes("dds-dialog", props.class), true), false), ssrAttribute("aria-labelledby", escape(titleId(), true), false) + ssrAttribute("aria-describedby", escape(describedBy(descriptionId()), true), false), ssrAttribute("id", escape(titleId(), true), false), escape(props.title), props.description && ssr(_tmpl$2$3, ssrHydrationKey() + ssrAttribute("id", escape(descriptionId(), true), false), escape(props.description)), escape(props.children), props.actions && ssr(_tmpl$3$1, ssrHydrationKey(), escape(props.actions)));
616
+ return [createComponent(RadioGroup$1.Label, {
617
+ "class": "dds-field__label",
618
+ get children() {
619
+ return props.label;
620
+ }
621
+ }), createComponent(For, {
622
+ get each() {
623
+ return props.options;
624
+ },
625
+ children: (option) => createComponent(RadioGroup$1.Item, {
626
+ get value() {
627
+ return option.value;
628
+ },
629
+ get disabled() {
630
+ return option.disabled;
631
+ },
632
+ "class": "dds-check",
633
+ get children() {
634
+ return [createComponent(RadioGroup$1.ItemHiddenInput, {
635
+ "class": "dds-check__input",
636
+ style: {}
637
+ }), createComponent(RadioGroup$1.ItemText, { get children() {
638
+ return option.label;
639
+ } })];
640
+ }
641
+ })
642
+ })];
415
643
  }
416
644
  });
417
645
  }
418
646
  //#endregion
419
647
  //#region src/icon.tsx
420
- var _tmpl$$3 = ["<g>", "</g>"];
421
- var _tmpl$2$2 = [
648
+ var _tmpl$$2 = ["<g>", "</g>"];
649
+ var _tmpl$2$1 = [
422
650
  "<title",
423
651
  ">",
424
652
  "</title>"
@@ -433,7 +661,7 @@ function Icon(props) {
433
661
  ]);
434
662
  const icon = () => icons[local.name];
435
663
  const directional = () => local.directional ?? directionPolicy.mirrorInRtl.includes(local.name);
436
- return ssrElement("svg", mergeProps(rest, {
664
+ return ssrElement("svg", mergeProps$1(rest, {
437
665
  get ["class"]() {
438
666
  return classes(directional() && directionPolicy.cssClass, local.class);
439
667
  },
@@ -464,20 +692,20 @@ function Icon(props) {
464
692
  }
465
693
  }), () => [
466
694
  "<!--$-->",
467
- local.label && ssr(_tmpl$2$2, ssrHydrationKey(), escape(local.label)),
695
+ local.label && ssr(_tmpl$2$1, ssrHydrationKey(), escape(local.label)),
468
696
  "<!--/-->",
469
- ssr(_tmpl$$3, icon().body)
697
+ ssr(_tmpl$$2, icon().body)
470
698
  ], true);
471
699
  }
472
700
  //#endregion
473
701
  //#region src/status-pill.tsx
474
- var _tmpl$$2 = [
702
+ var _tmpl$$1 = [
475
703
  "<code",
476
704
  " data-status=\"",
477
705
  "\">",
478
706
  "</code>"
479
707
  ];
480
- var _tmpl$2$1 = [
708
+ var _tmpl$2 = [
481
709
  "<span",
482
710
  " data-status=\"",
483
711
  "\"",
@@ -505,195 +733,232 @@ function createStatusPill(config) {
505
733
  return known() || !open.has(props.domain);
506
734
  },
507
735
  get fallback() {
508
- return ssr(_tmpl$$2, ssrHydrationKey(), `${escape(props.domain, true)}.${escape(props.value, true)}`, escape(props.value));
736
+ return ssr(_tmpl$$1, ssrHydrationKey(), `${escape(props.domain, true)}.${escape(props.value, true)}`, escape(props.value));
509
737
  },
510
738
  get children() {
511
739
  return (() => {
512
740
  const value = resolved();
513
- return ssr(_tmpl$2$1, ssrHydrationKey() + ssrAttribute("class", value.tone === "neutral" ? "dds-badge" : `dds-badge dds-badge--${escape(value.tone, true)}`, false), `${escape(props.domain, true)}.${escape(props.value, true)}`, ssrAttribute("data-tone", escape(value.tone, true), false), escape(value.text));
741
+ return ssr(_tmpl$2, ssrHydrationKey() + ssrAttribute("class", value.tone === "neutral" ? "dds-badge" : `dds-badge dds-badge--${escape(value.tone, true)}`, false), `${escape(props.domain, true)}.${escape(props.value, true)}`, ssrAttribute("data-tone", escape(value.tone, true), false), escape(value.text));
514
742
  })();
515
743
  }
516
744
  });
517
745
  };
518
746
  }
519
747
  //#endregion
748
+ //#region src/direction.ts
749
+ /** SSR callers may supply direction; clients also inherit their containing DOM. */
750
+ function useDirection(element, explicit) {
751
+ const [ambient, setAmbient] = createSignal("ltr");
752
+ onMount(() => {
753
+ const parent = element()?.parentElement;
754
+ if (!parent) return;
755
+ const update = () => setAmbient(getComputedStyle(parent).direction === "rtl" ? "rtl" : "ltr");
756
+ update();
757
+ const observer = new MutationObserver(update);
758
+ observer.observe(parent.ownerDocument.documentElement, {
759
+ attributes: true,
760
+ subtree: true,
761
+ attributeFilter: ["dir"]
762
+ });
763
+ onCleanup(() => observer.disconnect());
764
+ });
765
+ return () => explicit() ?? ambient();
766
+ }
767
+ //#endregion
520
768
  //#region src/tabs.tsx
521
- var TabsContext = createContext();
522
- var useTabs = () => {
523
- const context = useContext(TabsContext);
524
- if (!context) throw new Error("Tab components must be rendered inside <Tabs>");
525
- return context;
526
- };
527
769
  function Tabs(props) {
528
770
  const generated = createUniqueId();
529
771
  const id = () => props.id ?? `dds-tabs-${generated}`;
530
- const [value, setValue] = createControllableSignal({
531
- value: () => props.value,
532
- defaultValue: props.defaultValue,
533
- onChange: props.onValueChange
534
- });
535
- const registered = [];
536
- const context = {
537
- value,
538
- setValue,
539
- orientation: props.orientation ?? "horizontal",
540
- register(tab) {
541
- registered.push(tab);
542
- return () => {
543
- const index = registered.indexOf(tab);
544
- if (index >= 0) registered.splice(index, 1);
545
- };
772
+ let root;
773
+ const direction = useDirection(() => root, () => props.dir);
774
+ const child = props.asChild ? (merge) => props.asChild(mergeProps(merge({}), { ref: (element) => {
775
+ root = element;
776
+ } })) : void 0;
777
+ return createComponent(LocaleProvider, {
778
+ get locale() {
779
+ return direction() === "rtl" ? "ar" : "en";
546
780
  },
547
- tabs: () => registered,
548
- tabId: (tabValue) => `${id()}-tab-${tabValue}`,
549
- panelId: (tabValue) => `${id()}-panel-${tabValue}`
550
- };
551
- return createComponent(TabsContext.Provider, {
552
- value: context,
553
781
  get children() {
554
- return props.children;
782
+ return createComponent(Tabs$1.Root, mergeProps$1({
783
+ get id() {
784
+ return id();
785
+ },
786
+ get value() {
787
+ return props.value;
788
+ },
789
+ get defaultValue() {
790
+ return props.defaultValue;
791
+ },
792
+ get orientation() {
793
+ return props.orientation ?? "horizontal";
794
+ },
795
+ get activationMode() {
796
+ return props.activationMode ?? "automatic";
797
+ },
798
+ onValueChange: (details) => props.onValueChange?.(details.value),
799
+ lazyMount: false,
800
+ unmountOnExit: false,
801
+ get ["class"]() {
802
+ return props.unstyled ? void 0 : "dds-tabs-root";
803
+ }
804
+ }, child ? { asChild: child } : {}, {
805
+ ids: {
806
+ trigger: (value) => props.tabId?.(value) ?? `${id()}-tab-${value}`,
807
+ content: (value) => props.panelId?.(value) ?? `${id()}-panel-${value}`
808
+ },
809
+ get children() {
810
+ return props.children;
811
+ }
812
+ }));
555
813
  }
556
814
  });
557
815
  }
558
816
  function TabList(props) {
559
- const context = useTabs();
560
817
  const [local, rest] = splitProps(props, [
561
818
  "class",
562
819
  "children",
563
- "onKeyDown"
820
+ "unstyled"
564
821
  ]);
565
- return ssrElement("div", mergeProps(rest, {
822
+ return createComponent(Tabs$1.List, mergeProps$1(rest, {
566
823
  get ["class"]() {
567
- return classes("dds-tabs", local.class);
824
+ return classes(!local.unstyled && "dds-tabs", local.class);
568
825
  },
569
- role: "tablist",
570
- get ["aria-orientation"]() {
571
- return context.orientation;
826
+ get children() {
827
+ return local.children;
572
828
  }
573
- }), () => escape(local.children), true);
829
+ }));
574
830
  }
575
831
  function Tab(props) {
576
- const context = useTabs();
577
832
  const [local, rest] = splitProps(props, [
578
- "value",
579
833
  "class",
580
834
  "children",
581
- "disabled",
582
- "onClick"
835
+ "value",
836
+ "unstyled",
837
+ "asChild"
583
838
  ]);
584
- let element;
585
- onMount(() => {
586
- const unregister = context.register({
587
- value: local.value,
588
- element,
589
- disabled: Boolean(local.disabled)
590
- });
591
- onCleanup(unregister);
592
- });
593
- return ssrElement("button", mergeProps(rest, {
594
- get id() {
595
- return context.tabId(local.value);
839
+ const child = local.asChild ? (merge) => local.asChild(mergeProps(merge({}), { ref: props.ref })) : void 0;
840
+ return createComponent(Tabs$1.Trigger, mergeProps$1(rest, {
841
+ get value() {
842
+ return local.value;
596
843
  },
597
- type: "button",
598
- role: "tab",
599
844
  get ["class"]() {
600
- return classes("dds-tab", local.class);
601
- },
602
- get ["aria-selected"]() {
603
- return context.value() === local.value;
604
- },
605
- get ["aria-controls"]() {
606
- return context.panelId(local.value);
607
- },
608
- get tabindex() {
609
- return context.value() === local.value ? 0 : -1;
610
- },
611
- get disabled() {
612
- return local.disabled;
845
+ return classes(!local.unstyled && "dds-tab", local.class);
613
846
  }
614
- }), () => escape(local.children), true);
847
+ }, child ? { asChild: child } : {}, { get children() {
848
+ return local.children;
849
+ } }));
615
850
  }
616
851
  function TabPanel(props) {
617
- const context = useTabs();
618
852
  const [local, rest] = splitProps(props, [
619
853
  "value",
620
- "class",
621
- "children"
854
+ "children",
855
+ "style"
622
856
  ]);
623
- return ssrElement("div", mergeProps(rest, {
624
- get id() {
625
- return context.panelId(local.value);
626
- },
627
- role: "tabpanel",
628
- get ["class"]() {
629
- return local.class;
857
+ const tabs = useTabsContext();
858
+ const inactive = () => tabs().value !== local.value;
859
+ const style = () => !inactive() ? local.style : typeof local.style === "string" ? `${local.style.replace(/;+\s*$/, "")};display:none;` : {
860
+ ...local.style,
861
+ display: "none"
862
+ };
863
+ return createComponent(Tabs$1.Content, mergeProps$1(rest, {
864
+ get value() {
865
+ return local.value;
630
866
  },
631
- get ["aria-labelledby"]() {
632
- return context.tabId(local.value);
867
+ get style() {
868
+ return style();
633
869
  },
634
870
  get hidden() {
635
- return context.value() !== local.value;
871
+ return inactive();
636
872
  },
637
- tabindex: "0"
638
- }), () => escape(local.children), true);
873
+ get inert() {
874
+ return inactive();
875
+ },
876
+ get children() {
877
+ return local.children;
878
+ }
879
+ }));
639
880
  }
640
881
  //#endregion
641
882
  //#region src/toast.tsx
642
- var _tmpl$$1 = [
643
- "<div",
644
- " aria-live=\"polite\" aria-relevant=\"additions removals\">",
645
- "</div>"
646
- ];
647
- var _tmpl$2 = [
648
- "<div",
649
- "><span>",
650
- "</span><!--$-->",
651
- "<!--/--></div>"
652
- ];
653
- var _tmpl$3 = [
654
- "<button",
655
- " type=\"button\" class=\"dds-iconbtn dds-iconbtn--sm\"",
656
- ">×</button>"
657
- ];
658
883
  var ToastContext = createContext();
659
884
  function ToastProvider(props) {
660
- const [toasts, setToasts] = createSignal([]);
661
- const timers = /* @__PURE__ */ new Map();
885
+ const prefix = createUniqueId();
886
+ let scopedDocument;
887
+ const getRootNode = () => scopedDocument ??= new Proxy(document, { get(target, property) {
888
+ if (property === "getElementById") return (id) => id === "toast-group:bottom-end" ? null : target.getElementById(id);
889
+ const value = Reflect.get(target, property, target);
890
+ return typeof value === "function" ? value.bind(target) : value;
891
+ } });
892
+ const toaster = createToaster({
893
+ placement: "bottom-end",
894
+ overlap: false,
895
+ gap: space[8],
896
+ offsets: "var(--dds-space-16)",
897
+ removeDelay: 0,
898
+ hotkey: ["DDS_NO_HOTKEY"],
899
+ max: Number.MAX_SAFE_INTEGER,
900
+ pauseOnPageIdle: true
901
+ });
662
902
  let sequence = 0;
663
- const dismiss = (id) => {
664
- const timer = timers.get(id);
665
- if (timer) clearTimeout(timer);
666
- timers.delete(id);
667
- setToasts((current) => current.filter((toast) => toast.id !== id));
668
- };
669
903
  const api = {
670
904
  show(input) {
671
- const id = `dds-toast-${++sequence}`;
672
- setToasts((current) => [...current, {
673
- ...input,
674
- id
675
- }]);
905
+ const id = `dds-toast-${prefix}-${++sequence}`;
676
906
  const duration = input.duration ?? props.defaultDuration ?? 5e3;
677
- if (duration > 0) timers.set(id, setTimeout(() => dismiss(id), duration));
907
+ toaster.create({
908
+ id,
909
+ description: input.message,
910
+ type: input.tone === "danger" ? "error" : input.tone ?? "info",
911
+ duration: duration > 0 ? duration : Infinity,
912
+ meta: { dds: {
913
+ ...input,
914
+ id
915
+ } }
916
+ });
678
917
  return id;
679
918
  },
680
- dismiss,
681
- clear() {
682
- for (const timer of timers.values()) clearTimeout(timer);
683
- timers.clear();
684
- setToasts([]);
685
- }
919
+ dismiss: (id) => toaster.remove(id),
920
+ clear: () => toaster.remove()
686
921
  };
687
922
  onCleanup(api.clear);
688
923
  return createComponent(ToastContext.Provider, {
689
924
  value: api,
690
925
  get children() {
691
- return [props.children, ssr(_tmpl$$1, ssrHydrationKey() + ssrAttribute("class", escape(classes("dds-toast-region", props.class), true), false), escape(createComponent(For, {
692
- get each() {
693
- return toasts();
926
+ return [props.children, createComponent(Toaster, {
927
+ toaster,
928
+ getRootNode,
929
+ id: `dds-toast-region-${prefix}`,
930
+ get ["class"]() {
931
+ return classes("dds-toast-region", props.class);
932
+ },
933
+ get role() {
934
+ return props.regionLabel ? "region" : "presentation";
694
935
  },
695
- children: (toast) => ssr(_tmpl$2, ssrHydrationKey() + ssrAttribute("class", escape(classes("dds-toast", `dds-toast--${toast.tone ?? "info"}`), true), false) + ssrAttribute("role", toast.tone === "danger" ? "alert" : "status", false), escape(toast.message), props.dismissLabel ? ssr(_tmpl$3, ssrHydrationKey(), ssrAttribute("aria-label", typeof props.dismissLabel === "function" ? escape(props.dismissLabel(toast), true) : escape(props.dismissLabel, true), false)) : escape(null))
696
- })))];
936
+ get ["aria-label"]() {
937
+ return props.regionLabel ?? "";
938
+ },
939
+ children: (toast) => {
940
+ const record = () => toast().meta?.dds;
941
+ return createComponent(Toast.Root, {
942
+ get ["class"]() {
943
+ return classes("dds-toast", `dds-toast--${record().tone ?? "info"}`);
944
+ },
945
+ get role() {
946
+ return record().tone === "danger" ? "alert" : "status";
947
+ },
948
+ get children() {
949
+ return [createComponent(Toast.Description, { get children() {
950
+ return toast().description;
951
+ } }), props.dismissLabel && createComponent(Toast.CloseTrigger, {
952
+ "class": "dds-iconbtn dds-iconbtn--sm",
953
+ get ["aria-label"]() {
954
+ return memo(() => typeof props.dismissLabel === "function")() ? props.dismissLabel(record()) : props.dismissLabel;
955
+ },
956
+ children: "×"
957
+ })];
958
+ }
959
+ });
960
+ }
961
+ })];
697
962
  }
698
963
  });
699
964
  }
@@ -707,10 +972,8 @@ function useToast() {
707
972
  var _tmpl$ = [
708
973
  "<span",
709
974
  "><!--$-->",
710
- "<!--/--><span",
711
- " class=\"dds-tooltip__bubble\" role=\"tooltip\"",
712
- ">",
713
- "</span></span>"
975
+ "<!--/--><!--$-->",
976
+ "<!--/--></span>"
714
977
  ];
715
978
  function Tooltip(props) {
716
979
  const generated = createUniqueId();
@@ -718,18 +981,43 @@ function Tooltip(props) {
718
981
  const [open, setOpen] = createControllableSignal({
719
982
  value: () => props.open,
720
983
  defaultValue: props.defaultOpen ?? false,
721
- onChange: props.onOpenChange
984
+ onChange: (next) => props.onOpenChange?.(next)
985
+ });
986
+ const api = useTooltip(() => ({
987
+ id: id(),
988
+ ids: { content: id() },
989
+ open: open(),
990
+ onOpenChange: (details) => setOpen(details.open),
991
+ openDelay: 0,
992
+ closeDelay: 0
993
+ }));
994
+ return createComponent(Tooltip$1.RootProvider, {
995
+ value: api,
996
+ lazyMount: false,
997
+ unmountOnExit: false,
998
+ get children() {
999
+ return ssr(_tmpl$, ssrHydrationKey() + ssrAttribute("class", escape(classes("dds-tooltip", props.class), true), false), escape(createComponent(Tooltip$1.Trigger, { asChild: (merge) => {
1000
+ const [, attributes] = splitProps(merge(), ["onFocusIn", "onFocusOut"]);
1001
+ return props.children({
1002
+ ...attributes,
1003
+ "aria-describedby": id(),
1004
+ onFocus: () => api().setOpen(true),
1005
+ onBlur: () => api().setOpen(false),
1006
+ onPointerEnter: () => api().setOpen(true),
1007
+ onPointerLeave: () => api().setOpen(false)
1008
+ });
1009
+ } })), escape(createComponent(Tooltip$1.Positioner, { get children() {
1010
+ return createComponent(Tooltip$1.Content, {
1011
+ "class": "dds-tooltip__bubble",
1012
+ get children() {
1013
+ return props.content;
1014
+ }
1015
+ });
1016
+ } })));
1017
+ }
722
1018
  });
723
- const trigger = {
724
- "aria-describedby": id(),
725
- onFocus: () => setOpen(true),
726
- onBlur: () => setOpen(false),
727
- onPointerEnter: () => setOpen(true),
728
- onPointerLeave: () => setOpen(false)
729
- };
730
- return ssr(_tmpl$, ssrHydrationKey() + ssrAttribute("class", escape(classes("dds-tooltip", props.class), true), false), escape(props.children(trigger)), ssrAttribute("id", escape(id(), true), false), ssrAttribute("hidden", !open(), true), escape(props.content));
731
1019
  }
732
1020
  //#endregion
733
- export { Button, Checkbox, ConsoleShell, Dialog, Field, Icon, IconButton, Radio, Select, Switch, Tab, TabList, TabPanel, Tabs, ToastProvider, Tooltip, createControllableSignal, createStatusPill, useToast };
1021
+ export { Button, Checkbox, ConsoleShell, Dialog, Field, Icon, IconButton, Radio, RadioGroup, Select, Switch, Tab, TabList, TabPanel, Tabs, ToastProvider, Tooltip, createControllableSignal, createStatusPill, useToast };
734
1022
 
735
1023
  //# sourceMappingURL=server.js.map