@dogsbay/elements 0.2.0-beta.13 → 0.2.0-beta.130

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.
Files changed (68) hide show
  1. package/dist/{base-BtvRtAsC.d.ts → base-D1Rz70fn.d.ts} +1 -0
  2. package/dist/chunk-2ZMWJ74J.js +233 -0
  3. package/dist/{chunk-7M7SFLKN.js → chunk-5KHESKQR.js} +4 -3
  4. package/dist/{chunk-TTNTPXBA.js → chunk-5WY3DHVB.js} +4 -3
  5. package/dist/chunk-6QAYHFIQ.js +115 -0
  6. package/dist/{chunk-LVXR7KTB.js → chunk-6ZKFQBCF.js} +40 -12
  7. package/dist/{chunk-5T4OXQA2.js → chunk-AVQ7KRRE.js} +5 -6
  8. package/dist/{chunk-FWAAU5UY.js → chunk-CD3G6HKT.js} +4 -3
  9. package/dist/chunk-EPHDSTM7.js +85 -0
  10. package/dist/chunk-GC5HL7FU.js +255 -0
  11. package/dist/chunk-HMNRE3FZ.js +382 -0
  12. package/dist/chunk-HMV62CBN.js +139 -0
  13. package/dist/{chunk-7BIVQSGP.js → chunk-JRAYNKQ6.js} +4 -3
  14. package/dist/chunk-KFY2MTR3.js +190 -0
  15. package/dist/chunk-KXCPLIQD.js +77 -0
  16. package/dist/chunk-MZDGSTI4.js +72 -0
  17. package/dist/chunk-RZ3KZOM3.js +207 -0
  18. package/dist/{chunk-LFXZQ4YV.js → chunk-US4H4ZPZ.js} +4 -3
  19. package/dist/db-accordion.d.ts +1 -1
  20. package/dist/db-accordion.js +2 -3
  21. package/dist/db-card.d.ts +1 -1
  22. package/dist/db-card.js +2 -3
  23. package/dist/db-code-block.d.ts +1 -1
  24. package/dist/db-code-block.js +2 -3
  25. package/dist/db-collapsible.d.ts +1 -1
  26. package/dist/db-collapsible.js +2 -3
  27. package/dist/db-combobox.d.ts +70 -0
  28. package/dist/db-combobox.js +8 -0
  29. package/dist/db-details-sheet.d.ts +53 -0
  30. package/dist/db-details-sheet.js +8 -0
  31. package/dist/db-dialog.d.ts +62 -0
  32. package/dist/db-dialog.js +8 -0
  33. package/dist/db-link-button.d.ts +1 -1
  34. package/dist/db-link-button.js +2 -3
  35. package/dist/db-nav-tree.d.ts +83 -0
  36. package/dist/db-nav-tree.js +8 -0
  37. package/dist/db-popover.d.ts +42 -0
  38. package/dist/db-popover.js +8 -0
  39. package/dist/db-select.d.ts +72 -0
  40. package/dist/db-select.js +8 -0
  41. package/dist/db-steps.d.ts +1 -1
  42. package/dist/db-steps.js +2 -3
  43. package/dist/db-tabs.d.ts +28 -1
  44. package/dist/db-tabs.js +2 -3
  45. package/dist/db-toc.d.ts +32 -0
  46. package/dist/db-toc.js +8 -0
  47. package/dist/db-tooltip.d.ts +48 -0
  48. package/dist/db-tooltip.js +8 -0
  49. package/dist/index.d.ts +9 -1
  50. package/dist/index.js +44 -12
  51. package/package.json +38 -6
  52. package/dist/chunk-5T4OXQA2.js.map +0 -1
  53. package/dist/chunk-7BIVQSGP.js.map +0 -1
  54. package/dist/chunk-7M7SFLKN.js.map +0 -1
  55. package/dist/chunk-FWAAU5UY.js.map +0 -1
  56. package/dist/chunk-LFXZQ4YV.js.map +0 -1
  57. package/dist/chunk-LVXR7KTB.js.map +0 -1
  58. package/dist/chunk-TTNTPXBA.js.map +0 -1
  59. package/dist/chunk-XBMLE4N3.js +0 -28
  60. package/dist/chunk-XBMLE4N3.js.map +0 -1
  61. package/dist/db-accordion.js.map +0 -1
  62. package/dist/db-card.js.map +0 -1
  63. package/dist/db-code-block.js.map +0 -1
  64. package/dist/db-collapsible.js.map +0 -1
  65. package/dist/db-link-button.js.map +0 -1
  66. package/dist/db-steps.js.map +0 -1
  67. package/dist/db-tabs.js.map +0 -1
  68. package/dist/index.js.map +0 -1
@@ -0,0 +1,139 @@
1
+ import {
2
+ hideFloating,
3
+ ownOne,
4
+ resolveAsChild,
5
+ showFloating,
6
+ uid
7
+ } from "./chunk-KXCPLIQD.js";
8
+ import {
9
+ DogsbayElement,
10
+ ensureDefaultDisplay
11
+ } from "./chunk-MZDGSTI4.js";
12
+
13
+ // src/db-tooltip.ts
14
+ import { setupFloating } from "@dogsbay/primitives/floating";
15
+ var DbTooltip = class extends DogsbayElement {
16
+ trigger = null;
17
+ content = null;
18
+ cleanupFloating = null;
19
+ showTimer = null;
20
+ hideTimer = null;
21
+ _open = false;
22
+ get open() {
23
+ return this._open;
24
+ }
25
+ num(name, fallback) {
26
+ const v = Number(this.getAttribute(name));
27
+ return Number.isFinite(v) && this.hasAttribute(name) ? v : fallback;
28
+ }
29
+ onEnter = (e) => {
30
+ if (e.pointerType === "touch") return;
31
+ this.clearTimers();
32
+ if (!this._open) this.showTimer = setTimeout(() => this.show(), this.num("delay", 200));
33
+ };
34
+ onLeave = (e) => {
35
+ if (e.pointerType === "touch") return;
36
+ this.clearTimers();
37
+ this.hideTimer = setTimeout(() => this.hide(), this.num("close-delay", 100));
38
+ };
39
+ onContentEnter = () => this.clearTimers();
40
+ // Keyboard focus only: a mouse press focuses the button too, and would reopen
41
+ // the tooltip the press just closed.
42
+ onFocus = () => {
43
+ let keyboard = true;
44
+ try {
45
+ keyboard = this.trigger.matches(":focus-visible");
46
+ } catch {
47
+ }
48
+ if (!keyboard) return;
49
+ this.clearTimers();
50
+ this.show();
51
+ };
52
+ onBlur = () => this.hide();
53
+ onPress = () => this.hide();
54
+ // Capture phase, consumed: Escape dismisses only the tooltip, not a popover or
55
+ // dialog around its trigger (WCAG 1.4.13, APG tooltip).
56
+ onKey = (e) => {
57
+ if (e.key === "Escape" && this._open) {
58
+ e.preventDefault();
59
+ e.stopImmediatePropagation();
60
+ this.hide();
61
+ }
62
+ };
63
+ setup() {
64
+ this.trigger = resolveAsChild(ownOne(this, "[data-part='trigger']"));
65
+ this.content = ownOne(this, "[data-part='content']");
66
+ if (!this.trigger || !this.content) return;
67
+ this.content.id ||= uid("db-tooltip");
68
+ this.content.setAttribute("role", "tooltip");
69
+ this.content.hidden = true;
70
+ const described = (this.trigger.getAttribute("aria-describedby") ?? "").split(/\s+/).filter(Boolean);
71
+ if (!described.includes(this.content.id)) this.trigger.setAttribute("aria-describedby", [...described, this.content.id].join(" "));
72
+ this.setState("closed");
73
+ }
74
+ connect() {
75
+ const { trigger, content } = this;
76
+ if (!trigger || !content) return;
77
+ trigger.addEventListener("pointerenter", this.onEnter);
78
+ trigger.addEventListener("pointerleave", this.onLeave);
79
+ trigger.addEventListener("focus", this.onFocus);
80
+ trigger.addEventListener("blur", this.onBlur);
81
+ trigger.addEventListener("pointerdown", this.onPress);
82
+ content.addEventListener("pointerenter", this.onContentEnter);
83
+ content.addEventListener("pointerleave", this.onLeave);
84
+ }
85
+ disconnect() {
86
+ const { trigger, content } = this;
87
+ trigger?.removeEventListener("pointerenter", this.onEnter);
88
+ trigger?.removeEventListener("pointerleave", this.onLeave);
89
+ trigger?.removeEventListener("focus", this.onFocus);
90
+ trigger?.removeEventListener("blur", this.onBlur);
91
+ trigger?.removeEventListener("pointerdown", this.onPress);
92
+ content?.removeEventListener("pointerenter", this.onContentEnter);
93
+ content?.removeEventListener("pointerleave", this.onLeave);
94
+ this.hide();
95
+ }
96
+ clearTimers() {
97
+ if (this.showTimer) clearTimeout(this.showTimer);
98
+ if (this.hideTimer) clearTimeout(this.hideTimer);
99
+ this.showTimer = this.hideTimer = null;
100
+ }
101
+ setState(state) {
102
+ this.setAttribute("data-state", state);
103
+ this.content?.setAttribute("data-state", state);
104
+ }
105
+ show() {
106
+ const { trigger, content } = this;
107
+ if (!trigger || !content || this._open) return;
108
+ this._open = true;
109
+ this.clearTimers();
110
+ const layer = showFloating(content);
111
+ this.setState("open");
112
+ this.cleanupFloating = setupFloating(trigger, content, {
113
+ placement: this.getAttribute("placement") || content.dataset.side || "top",
114
+ offset: 8,
115
+ strategy: layer === "top-layer" ? "fixed" : "absolute"
116
+ });
117
+ document.addEventListener("keydown", this.onKey, true);
118
+ this.dispatchEvent(new CustomEvent("db-tooltip:open", { bubbles: true }));
119
+ }
120
+ hide() {
121
+ this.clearTimers();
122
+ if (!this._open || !this.content) return;
123
+ this._open = false;
124
+ document.removeEventListener("keydown", this.onKey, true);
125
+ this.cleanupFloating?.();
126
+ this.cleanupFloating = null;
127
+ hideFloating(this.content);
128
+ this.setState("closed");
129
+ this.dispatchEvent(new CustomEvent("db-tooltip:close", { bubbles: true }));
130
+ }
131
+ };
132
+ ensureDefaultDisplay();
133
+ if (!customElements.get("db-tooltip")) {
134
+ customElements.define("db-tooltip", DbTooltip);
135
+ }
136
+
137
+ export {
138
+ DbTooltip
139
+ };
@@ -1,6 +1,7 @@
1
1
  import {
2
- DogsbayElement
3
- } from "./chunk-XBMLE4N3.js";
2
+ DogsbayElement,
3
+ ensureDefaultDisplay
4
+ } from "./chunk-MZDGSTI4.js";
4
5
 
5
6
  // src/db-card.ts
6
7
  var DbCard = class extends DogsbayElement {
@@ -42,6 +43,7 @@ var DbCard = class extends DogsbayElement {
42
43
  );
43
44
  }
44
45
  };
46
+ ensureDefaultDisplay();
45
47
  if (!customElements.get("db-card")) {
46
48
  customElements.define("db-card", DbCard);
47
49
  }
@@ -49,4 +51,3 @@ if (!customElements.get("db-card")) {
49
51
  export {
50
52
  DbCard
51
53
  };
52
- //# sourceMappingURL=chunk-7BIVQSGP.js.map
@@ -0,0 +1,190 @@
1
+ import {
2
+ safeDecode,
3
+ uid
4
+ } from "./chunk-KXCPLIQD.js";
5
+ import {
6
+ DogsbayElement,
7
+ ensureDefaultDisplay
8
+ } from "./chunk-MZDGSTI4.js";
9
+
10
+ // src/db-details-sheet.ts
11
+ var DbDetailsSheet = class extends DogsbayElement {
12
+ details = null;
13
+ summary = null;
14
+ dialog = null;
15
+ body = null;
16
+ /** Where the moved nodes came from, and the nodes, while the sheet is open. */
17
+ source = null;
18
+ moved = [];
19
+ /** The fragment already acted on: moving a nested sheet in and out of a
20
+ * dialog reconnects it, and reopening on every connect made it undismissable. */
21
+ handledHash = null;
22
+ get open() {
23
+ return !!this.dialog?.open;
24
+ }
25
+ onSummaryClick = (e) => {
26
+ const t = e.target;
27
+ if (t && t !== this.summary && t.closest?.("a[href], button, input, select, textarea, label")?.closest("summary") === this.summary) return;
28
+ e.preventDefault();
29
+ this.show();
30
+ };
31
+ // A click on the ::backdrop targets the dialog itself, outside its box.
32
+ onDialogClick = (e) => {
33
+ const d = this.dialog;
34
+ if (!d || e.target !== d) return;
35
+ const r = d.getBoundingClientRect();
36
+ const inside = e.clientX >= r.left && e.clientX <= r.right && e.clientY >= r.top && e.clientY <= r.bottom;
37
+ if (!inside && (e.clientX !== 0 || e.clientY !== 0)) d.close();
38
+ };
39
+ // Every way the dialog closes (Escape, backdrop, button, api) ends here.
40
+ onDialogClose = () => this.restore();
41
+ // A link to the fragment the URL already has fires no hashchange: after the
42
+ // sheet was closed, a second click on the same link did nothing (#100)
43
+ onDocClick = (e) => {
44
+ if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
45
+ const a = e.target?.closest?.("a[href]");
46
+ if (!a || !this.details || this.open || a.hasAttribute("download") || a.target && a.target !== "_self") return;
47
+ const url = new URL(a.href, location.href);
48
+ if (!url.hash || url.hash !== location.hash || url.pathname !== location.pathname || url.search !== location.search) return;
49
+ const target = document.getElementById(safeDecode(url.hash.slice(1)));
50
+ if (!target || !this.details.contains(target)) return;
51
+ for (const inner of this.details.querySelectorAll("db-details-sheet")) inner.handledHash = null;
52
+ this.show(target);
53
+ };
54
+ onHash = () => {
55
+ this.handledHash = null;
56
+ this.openForHash();
57
+ };
58
+ setup() {
59
+ const details = Array.from(this.children).find((c) => c.tagName === "DETAILS") ?? null;
60
+ const summary = details ? Array.from(details.children).find((c) => c.tagName === "SUMMARY") ?? null : null;
61
+ const dialogOk = typeof HTMLDialogElement !== "undefined" && typeof HTMLDialogElement.prototype.showModal === "function";
62
+ if (!details || !summary || !dialogOk) return;
63
+ for (const c of Array.from(details.children)) if (c.getAttribute("role") === "status") c.setAttribute("aria-live", "off");
64
+ this.details = details;
65
+ this.summary = summary;
66
+ details.open = false;
67
+ ensureSheetStyles();
68
+ const title = (summary.querySelector("[data-part='title']")?.textContent ?? summary.textContent ?? "").trim();
69
+ const dialog = document.createElement("dialog");
70
+ dialog.className = "db-sheet";
71
+ dialog.id = uid("db-sheet");
72
+ const heading = document.createElement("h2");
73
+ heading.className = "db-sheet-title";
74
+ heading.id = uid("db-sheet-title");
75
+ heading.textContent = title;
76
+ dialog.setAttribute("aria-labelledby", heading.id);
77
+ const close = document.createElement("button");
78
+ close.type = "button";
79
+ close.className = "db-sheet-close";
80
+ close.setAttribute("aria-label", this.getAttribute("close-label") || "Close");
81
+ close.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>';
82
+ close.addEventListener("click", () => dialog.close());
83
+ const header = document.createElement("div");
84
+ header.className = "db-sheet-header";
85
+ header.append(heading, close);
86
+ const body = document.createElement("div");
87
+ body.className = "db-sheet-body";
88
+ dialog.append(header, body);
89
+ this.append(dialog);
90
+ this.dialog = dialog;
91
+ this.body = body;
92
+ summary.setAttribute("aria-haspopup", "dialog");
93
+ summary.setAttribute("aria-controls", dialog.id);
94
+ summary.setAttribute("aria-expanded", "false");
95
+ this.setAttribute("data-state", "closed");
96
+ }
97
+ connect() {
98
+ if (!this.dialog) return;
99
+ this.summary.addEventListener("click", this.onSummaryClick);
100
+ this.dialog.addEventListener("click", this.onDialogClick);
101
+ this.dialog.addEventListener("close", this.onDialogClose);
102
+ window.addEventListener("hashchange", this.onHash);
103
+ document.addEventListener("click", this.onDocClick);
104
+ queueMicrotask(() => this.isConnected && this.openForHash());
105
+ }
106
+ disconnect() {
107
+ if (!this.dialog) return;
108
+ if (this.dialog.open) this.dialog.close();
109
+ this.restore(false);
110
+ this.summary.removeEventListener("click", this.onSummaryClick);
111
+ this.dialog.removeEventListener("click", this.onDialogClick);
112
+ this.dialog.removeEventListener("close", this.onDialogClose);
113
+ window.removeEventListener("hashchange", this.onHash);
114
+ document.removeEventListener("click", this.onDocClick);
115
+ }
116
+ show(focusTarget) {
117
+ const { dialog, details, body } = this;
118
+ if (!dialog || !details || !body || dialog.open) return;
119
+ const rest = Array.from(details.childNodes).filter((n) => n !== this.summary);
120
+ const elements = rest.filter((n) => n.nodeType === Node.ELEMENT_NODE);
121
+ const wrapper = elements.length === 1 && rest.every((n) => n === elements[0] || !n.textContent?.trim()) ? elements[0] : null;
122
+ this.source = wrapper ?? details;
123
+ this.moved = wrapper ? Array.from(wrapper.childNodes) : rest;
124
+ body.append(...this.moved);
125
+ dialog.showModal();
126
+ this.summary.setAttribute("aria-expanded", "true");
127
+ this.setAttribute("data-state", "open");
128
+ if (focusTarget && focusTarget !== details) focusTarget.scrollIntoView?.({ block: "start" });
129
+ this.dispatchEvent(new CustomEvent("db-details-sheet:open", { bubbles: true }));
130
+ }
131
+ close() {
132
+ this.dialog?.close();
133
+ }
134
+ restore(focus = true) {
135
+ if (!this.source) return;
136
+ this.source.append(...this.moved);
137
+ this.source = null;
138
+ this.moved = [];
139
+ this.summary.setAttribute("aria-expanded", "false");
140
+ this.setAttribute("data-state", "closed");
141
+ if (focus && this.isConnected && this.summary.checkVisibility?.() !== false) this.summary.focus();
142
+ this.dispatchEvent(new CustomEvent("db-details-sheet:close", { bubbles: true }));
143
+ }
144
+ /** Open when the URL fragment names the details or something in its body. */
145
+ openForHash() {
146
+ const id = safeDecode(location.hash.slice(1));
147
+ if (!id || !this.details || this.handledHash === location.hash) return;
148
+ this.handledHash = location.hash;
149
+ if (this.open) return;
150
+ const target = document.getElementById(id);
151
+ if (target && this.details.contains(target)) this.show(target);
152
+ }
153
+ };
154
+ var STYLE_ID = "dogsbay-details-sheet";
155
+ function ensureSheetStyles() {
156
+ if (document.getElementById(STYLE_ID)) return;
157
+ const style = document.createElement("style");
158
+ style.id = STYLE_ID;
159
+ style.textContent = [
160
+ "dialog.db-sheet{position:fixed;inset:0 0 0 auto;margin:0;height:100dvh;max-height:none;width:min(32rem,100vw);max-width:100vw;padding:0;border:0;border-left:1px solid var(--border);background:var(--background);color:var(--foreground);box-shadow:0 10px 15px -3px rgb(0 0 0/.1),0 4px 6px -4px rgb(0 0 0/.1);flex-direction:column}",
161
+ "dialog.db-sheet[open]{display:flex}",
162
+ "dialog.db-sheet::backdrop{background:rgb(0 0 0/.6)}",
163
+ ".db-sheet-header{display:flex;align-items:center;justify-content:space-between;gap:1rem;padding:1rem 1.5rem;border-bottom:1px solid var(--border)}",
164
+ // The dialog sits inside the page's prose: its h2 rule (border, margins)
165
+ // would otherwise style the title. Element + class beats `.docs-prose h2`.
166
+ "dialog.db-sheet h2.db-sheet-title{margin:0;padding:0;border:0;font-size:1.125rem;line-height:1.75rem;font-weight:600;scroll-margin:0}",
167
+ ".db-sheet-close{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:0;border-radius:.375rem;background:transparent;color:var(--muted-foreground);cursor:pointer}",
168
+ ".db-sheet-close:hover{background:var(--accent,var(--muted));color:var(--foreground)}",
169
+ ".db-sheet-close:focus-visible{outline:2px solid var(--ring);outline-offset:2px}",
170
+ ".db-sheet-body{flex:1;overflow-y:auto;padding:1.5rem;font-size:.875rem;line-height:1.625}",
171
+ // Beats `.docs-prose p` (0,2,1): the first paragraph sat 12px down
172
+ "dialog.db-sheet .db-sheet-body>:first-child{margin-top:0}",
173
+ // A modal sheet: the page under it does not scroll
174
+ "html:has(dialog.db-sheet[open]){overflow:hidden}",
175
+ // The summary opens a panel, not a fold: its chevron points to the side.
176
+ "db-details-sheet>details>summary>span:last-child{transform:rotate(-90deg)}",
177
+ "@media (prefers-reduced-motion:no-preference){dialog.db-sheet[open]{animation:db-sheet-in .2s ease-out}dialog.db-sheet[open]::backdrop{animation:db-sheet-fade .2s ease-out}}",
178
+ "@keyframes db-sheet-in{from{transform:translateX(100%)}}",
179
+ "@keyframes db-sheet-fade{from{opacity:0}}"
180
+ ].join("");
181
+ document.head.append(style);
182
+ }
183
+ ensureDefaultDisplay();
184
+ if (!customElements.get("db-details-sheet")) {
185
+ customElements.define("db-details-sheet", DbDetailsSheet);
186
+ }
187
+
188
+ export {
189
+ DbDetailsSheet
190
+ };
@@ -0,0 +1,77 @@
1
+ // src/utils.ts
2
+ var counter = 0;
3
+ function uid(prefix) {
4
+ return `${prefix}-${++counter}`;
5
+ }
6
+ function own(host, selector) {
7
+ const tag = host.localName;
8
+ return Array.from(host.querySelectorAll(selector)).filter((el) => el.closest(tag) === host);
9
+ }
10
+ function ownOne(host, selector) {
11
+ return own(host, selector)[0] ?? null;
12
+ }
13
+ function resolveAsChild(el) {
14
+ if (!el || !el.hasAttribute("data-as-child")) return el;
15
+ const child = el.firstElementChild;
16
+ if (!child) return el;
17
+ const part = el.getAttribute("data-part");
18
+ if (part) child.setAttribute("data-part", part);
19
+ return child;
20
+ }
21
+ function isDisabled(el) {
22
+ return el.hasAttribute("disabled") || el.getAttribute("aria-disabled") === "true" || el.getAttribute("data-disabled") === "true";
23
+ }
24
+ function supportsPopover() {
25
+ return typeof HTMLElement !== "undefined" && typeof HTMLElement.prototype.showPopover === "function";
26
+ }
27
+ function showFloating(el) {
28
+ el.hidden = false;
29
+ if (!supportsPopover()) return "inline";
30
+ if (!el.hasAttribute("popover")) el.setAttribute("popover", "manual");
31
+ el.style.inset = "auto";
32
+ el.style.margin = "0";
33
+ try {
34
+ if (!el.matches(":popover-open")) el.showPopover();
35
+ } catch {
36
+ return "inline";
37
+ }
38
+ return "top-layer";
39
+ }
40
+ function hideFloating(el) {
41
+ if (supportsPopover()) {
42
+ try {
43
+ if (el.matches(":popover-open")) el.hidePopover();
44
+ } catch {
45
+ }
46
+ }
47
+ el.hidden = true;
48
+ }
49
+ var FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"]), [contenteditable="true"]';
50
+ function focusables(root) {
51
+ return Array.from(root.querySelectorAll(FOCUSABLE)).filter((el) => !el.closest("[hidden]") && !isDisabled(el));
52
+ }
53
+ function afterAnimations(el, done) {
54
+ const anims = typeof el.getAnimations === "function" ? el.getAnimations() : [];
55
+ if (!anims.length) return done();
56
+ Promise.all(anims.map((a) => a.finished)).then(done, done);
57
+ }
58
+ function safeDecode(s) {
59
+ try {
60
+ return decodeURIComponent(s);
61
+ } catch {
62
+ return s;
63
+ }
64
+ }
65
+
66
+ export {
67
+ uid,
68
+ own,
69
+ ownOne,
70
+ resolveAsChild,
71
+ isDisabled,
72
+ showFloating,
73
+ hideFloating,
74
+ focusables,
75
+ afterAnimations,
76
+ safeDecode
77
+ };
@@ -0,0 +1,72 @@
1
+ // src/base.ts
2
+ var DogsbayElement = class extends HTMLElement {
3
+ _initialized = false;
4
+ _deferred = false;
5
+ connectedCallback() {
6
+ if (!this._initialized && !this.firstElementChild && typeof document !== "undefined" && document.readyState === "loading") {
7
+ if (!this._deferred) {
8
+ this._deferred = true;
9
+ document.addEventListener(
10
+ "DOMContentLoaded",
11
+ () => {
12
+ this._deferred = false;
13
+ if (this.isConnected) this.connectedCallback();
14
+ },
15
+ { once: true }
16
+ );
17
+ }
18
+ return;
19
+ }
20
+ if (!this._initialized) {
21
+ this.setup();
22
+ this._initialized = true;
23
+ }
24
+ this.connect();
25
+ }
26
+ disconnectedCallback() {
27
+ this.disconnect();
28
+ }
29
+ /** One-time setup: query children, generate IDs, set ARIA. */
30
+ setup() {
31
+ }
32
+ /** Called on every connect: attach event listeners. */
33
+ connect() {
34
+ }
35
+ /** Called on every disconnect: remove event listeners. */
36
+ disconnect() {
37
+ }
38
+ };
39
+ var DEFAULT_DISPLAY = {
40
+ "db-tabs": "block",
41
+ "db-accordion": "block",
42
+ "db-collapsible": "block",
43
+ "db-details-sheet": "block",
44
+ "db-card": "block",
45
+ "db-steps": "block",
46
+ "db-code-block": "block",
47
+ // A link styled as a button — sits in a line of prose.
48
+ "db-link-button": "inline-block",
49
+ // A dialog host only groups its trigger and content; it takes no box of its own.
50
+ "db-dialog": "contents",
51
+ "db-popover": "inline-block",
52
+ "db-tooltip": "inline-block",
53
+ "db-select": "inline-block",
54
+ "db-combobox": "block",
55
+ "db-nav-tree": "block",
56
+ "db-toc": "block"
57
+ };
58
+ var STYLE_ID = "dogsbay-elements-display";
59
+ function ensureDefaultDisplay() {
60
+ if (typeof document === "undefined") return;
61
+ if (document.getElementById(STYLE_ID)) return;
62
+ const rules = Object.entries(DEFAULT_DISPLAY).map(([tag, display]) => `:where(${tag}){display:${display}}`).join("");
63
+ const style = document.createElement("style");
64
+ style.id = STYLE_ID;
65
+ style.textContent = rules;
66
+ document.head.prepend(style);
67
+ }
68
+
69
+ export {
70
+ DogsbayElement,
71
+ ensureDefaultDisplay
72
+ };