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

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
@@ -7,6 +7,7 @@
7
7
  */
8
8
  declare abstract class DogsbayElement extends HTMLElement {
9
9
  private _initialized;
10
+ private _deferred;
10
11
  connectedCallback(): void;
11
12
  disconnectedCallback(): void;
12
13
  /** One-time setup: query children, generate IDs, set ARIA. */
@@ -0,0 +1,233 @@
1
+ import {
2
+ own,
3
+ uid
4
+ } from "./chunk-KXCPLIQD.js";
5
+ import {
6
+ DogsbayElement,
7
+ ensureDefaultDisplay
8
+ } from "./chunk-MZDGSTI4.js";
9
+
10
+ // src/db-nav-tree.ts
11
+ var DbNavTree = class extends DogsbayElement {
12
+ /** Nav data for lazy sections. Falls back to `window[data-source]`. */
13
+ navData = null;
14
+ onClick = (e) => {
15
+ const toggle = e.target.closest("[data-part='toggle']");
16
+ if (!toggle || toggle.closest("db-nav-tree") !== this) return;
17
+ const item = toggle.closest("[data-part='item']");
18
+ if (item) this.toggle(item);
19
+ };
20
+ onKey = (e) => {
21
+ if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return;
22
+ const active = document.activeElement;
23
+ if (!active || !this.contains(active)) return;
24
+ const rows = this.visibleRows();
25
+ const row = active.closest("[data-part='row']");
26
+ const i = row ? rows.indexOf(row) : -1;
27
+ if (i < 0) return;
28
+ const item = row.closest("[data-part='item']");
29
+ const hasGroup = !!this.groupOf(item);
30
+ const focusRow = (r) => {
31
+ if (!r) return;
32
+ e.preventDefault();
33
+ this.primary(r)?.focus();
34
+ };
35
+ switch (e.key) {
36
+ case "ArrowDown":
37
+ return focusRow(rows[i + 1]);
38
+ case "ArrowUp":
39
+ return focusRow(rows[i - 1]);
40
+ case "Home":
41
+ return focusRow(rows[0]);
42
+ case "End":
43
+ return focusRow(rows[rows.length - 1]);
44
+ case "ArrowRight":
45
+ if (!hasGroup) return;
46
+ e.preventDefault();
47
+ if (!this.isOpen(item)) this.setOpen(item, true);
48
+ else focusRow(this.visibleRows()[i + 1]);
49
+ return;
50
+ case "ArrowLeft": {
51
+ e.preventDefault();
52
+ if (hasGroup && this.isOpen(item)) return this.setOpen(item, false);
53
+ const parent = item.parentElement?.closest("[data-part='item']");
54
+ if (parent && this.contains(parent)) {
55
+ const pr = parent.querySelector(":scope > [data-part='row']");
56
+ if (pr) this.primary(pr)?.focus();
57
+ }
58
+ return;
59
+ }
60
+ }
61
+ };
62
+ setup() {
63
+ for (const item of own(this, "[data-part='item']")) this.prepareItem(item);
64
+ }
65
+ connect() {
66
+ this.addEventListener("click", this.onClick);
67
+ this.addEventListener("keydown", this.onKey);
68
+ for (const g of own(this, "[data-part='group'][data-lazy]")) {
69
+ const item = g.closest("[data-part='item']");
70
+ if (item && this.isOpen(item)) this.fill(g);
71
+ }
72
+ if (this.hasAttribute("scroll-current")) requestAnimationFrame(() => this.revealCurrent());
73
+ }
74
+ disconnect() {
75
+ this.removeEventListener("click", this.onClick);
76
+ this.removeEventListener("keydown", this.onKey);
77
+ }
78
+ prepareItem(item) {
79
+ const group = this.groupOf(item);
80
+ const toggle = item.querySelector(":scope > [data-part='row'] > [data-part='toggle']");
81
+ if (!group || !toggle) return;
82
+ group.id ||= uid("db-nav-group");
83
+ toggle.setAttribute("aria-controls", group.id);
84
+ if (toggle instanceof HTMLButtonElement && !toggle.hasAttribute("type")) toggle.type = "button";
85
+ const open = toggle.getAttribute("aria-expanded") === "true" || item.getAttribute("data-state") === "open";
86
+ this.apply(item, open);
87
+ }
88
+ groupOf(item) {
89
+ return item.querySelector(":scope > [data-part='group']");
90
+ }
91
+ toggleOf(item) {
92
+ return item.querySelector(":scope > [data-part='row'] > [data-part='toggle']");
93
+ }
94
+ /** The row's main focus target: its link, or its toggle for a label-only section. */
95
+ primary(row) {
96
+ return row.querySelector(":scope > [data-part='link']") ?? row.querySelector(":scope > [data-part='toggle']");
97
+ }
98
+ visibleRows() {
99
+ return own(this, "[data-part='row']").filter((r) => !r.closest("[hidden]"));
100
+ }
101
+ isOpen(item) {
102
+ return item.getAttribute("data-state") === "open";
103
+ }
104
+ toggle(item) {
105
+ this.setOpen(item, !this.isOpen(item));
106
+ }
107
+ setOpen(item, open) {
108
+ const group = this.groupOf(item);
109
+ if (!group || this.isOpen(item) === open) return;
110
+ if (open && group.hasAttribute("data-lazy")) this.fill(group);
111
+ this.apply(item, open);
112
+ this.dispatchEvent(new CustomEvent("db-nav-tree:toggle", { detail: { item, open }, bubbles: true }));
113
+ }
114
+ apply(item, open) {
115
+ const group = this.groupOf(item);
116
+ const toggle = this.toggleOf(item);
117
+ if (group) group.hidden = !open;
118
+ toggle?.setAttribute("aria-expanded", String(open));
119
+ item.setAttribute("data-state", open ? "open" : "closed");
120
+ }
121
+ /** Expand every section on the path to the current page. */
122
+ revealCurrent() {
123
+ const cur = this.querySelector("[aria-current='page']");
124
+ if (!cur) return;
125
+ for (let item = cur.closest("[data-part='item']"); item && this.contains(item); item = item.parentElement?.closest("[data-part='item']") ?? null) {
126
+ if (this.groupOf(item) && !this.groupOf(item).contains(cur)) continue;
127
+ if (this.groupOf(item)) this.setOpen(item, true);
128
+ }
129
+ const scroller = scrollParent(this);
130
+ if (!scroller) return;
131
+ const r = cur.getBoundingClientRect();
132
+ const s = scroller.getBoundingClientRect();
133
+ if (r.top < s.top || r.bottom > s.bottom) scroller.scrollTop += r.top - s.top - s.height / 2 + r.height / 2;
134
+ }
135
+ data() {
136
+ if (this.navData) return this.navData;
137
+ const name = this.getAttribute("data-source");
138
+ const g = name ? globalThis[name] : void 0;
139
+ return Array.isArray(g) ? g : null;
140
+ }
141
+ /** Fill a lazy group from nav data. */
142
+ fill(group) {
143
+ const data = this.data();
144
+ const path = group.dataset.path;
145
+ if (!data || path == null) return;
146
+ let list = data;
147
+ let node;
148
+ for (const i of path.split(".").map(Number)) {
149
+ node = list?.[i];
150
+ list = node?.[2];
151
+ }
152
+ if (!node?.[2]) return;
153
+ group.replaceChildren(...this.build(node[2], path));
154
+ group.removeAttribute("data-lazy");
155
+ }
156
+ build(items, path) {
157
+ const base = this.getAttribute("base") ?? "";
158
+ const tmpl = this.getAttribute("toggle-label") ?? "Toggle {label}";
159
+ const current = location.href.split("#")[0];
160
+ return items.map(([label, url, kids, noCurrent], i) => {
161
+ const here = `${path}.${i}`;
162
+ const li = document.createElement("li");
163
+ li.setAttribute("data-part", "item");
164
+ li.style.setProperty("--db-level", String(here.split(".").length - 1));
165
+ const row = document.createElement("div");
166
+ row.setAttribute("data-part", "row");
167
+ li.appendChild(row);
168
+ const probe = url?.replace(/[\u0000-\u0020]/g, "") ?? "";
169
+ if (url != null && /^[a-z][a-z0-9+.-]*:/i.test(probe) && !/^(?:https?|mailto):/i.test(probe)) url = null;
170
+ const external = url != null && /^[a-z][a-z0-9+.-]*:|^\/\//i.test(probe);
171
+ let toggle = null;
172
+ if (kids?.length) {
173
+ toggle = document.createElement("button");
174
+ toggle.type = "button";
175
+ toggle.setAttribute("data-part", "toggle");
176
+ toggle.setAttribute("aria-expanded", "false");
177
+ if (url != null) toggle.setAttribute("aria-label", tmpl.replace("{label}", () => label));
178
+ else {
179
+ const span = document.createElement("span");
180
+ span.setAttribute("data-part", "label");
181
+ span.textContent = label;
182
+ toggle.appendChild(span);
183
+ }
184
+ toggle.insertAdjacentHTML("beforeend", CHEVRON);
185
+ }
186
+ const atEnd = this.getAttribute("toggle-position") === "end";
187
+ if (toggle && !atEnd) row.appendChild(toggle);
188
+ if (url != null) {
189
+ const a = document.createElement("a");
190
+ a.setAttribute("data-part", "link");
191
+ a.textContent = label;
192
+ a.href = external ? url : base + url;
193
+ if (external) a.rel = "noopener";
194
+ if (!noCurrent && a.href.split("#")[0] === current) a.setAttribute("aria-current", "page");
195
+ row.appendChild(a);
196
+ }
197
+ if (url == null && !kids?.length) {
198
+ const span = document.createElement("span");
199
+ span.setAttribute("data-part", "label");
200
+ span.textContent = label;
201
+ row.appendChild(span);
202
+ }
203
+ if (toggle && atEnd) row.appendChild(toggle);
204
+ if (kids?.length) {
205
+ const ul = document.createElement("ul");
206
+ ul.setAttribute("data-part", "group");
207
+ ul.dataset.lazy = "";
208
+ ul.dataset.path = here;
209
+ ul.hidden = true;
210
+ li.setAttribute("data-state", "closed");
211
+ li.appendChild(ul);
212
+ this.prepareItem(li);
213
+ }
214
+ return li;
215
+ });
216
+ }
217
+ };
218
+ var CHEVRON = '<svg data-part="chevron" viewBox="0 0 24 24" width="16" height="16" aria-hidden="true" focusable="false"><path d="m9 18 6-6-6-6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>';
219
+ function scrollParent(el) {
220
+ for (let p = el.parentElement; p; p = p.parentElement) {
221
+ const o = getComputedStyle(p).overflowY;
222
+ if ((o === "auto" || o === "scroll") && p.scrollHeight > p.clientHeight) return p;
223
+ }
224
+ return null;
225
+ }
226
+ ensureDefaultDisplay();
227
+ if (!customElements.get("db-nav-tree")) {
228
+ customElements.define("db-nav-tree", DbNavTree);
229
+ }
230
+
231
+ export {
232
+ DbNavTree
233
+ };
@@ -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-accordion.ts
6
7
  import { CompositeNavigation } from "@dogsbay/primitives/composite";
@@ -85,6 +86,7 @@ var DbAccordion = class extends DogsbayElement {
85
86
  );
86
87
  }
87
88
  };
89
+ ensureDefaultDisplay();
88
90
  if (!customElements.get("db-accordion")) {
89
91
  customElements.define("db-accordion", DbAccordion);
90
92
  }
@@ -92,4 +94,3 @@ if (!customElements.get("db-accordion")) {
92
94
  export {
93
95
  DbAccordion
94
96
  };
95
- //# sourceMappingURL=chunk-7M7SFLKN.js.map
@@ -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-collapsible.ts
6
7
  import { Collapsible } from "@dogsbay/primitives/collapsible";
@@ -36,6 +37,7 @@ var DbCollapsible = class extends DogsbayElement {
36
37
  }
37
38
  }
38
39
  };
40
+ ensureDefaultDisplay();
39
41
  if (!customElements.get("db-collapsible")) {
40
42
  customElements.define("db-collapsible", DbCollapsible);
41
43
  }
@@ -43,4 +45,3 @@ if (!customElements.get("db-collapsible")) {
43
45
  export {
44
46
  DbCollapsible
45
47
  };
46
- //# sourceMappingURL=chunk-TTNTPXBA.js.map
@@ -0,0 +1,115 @@
1
+ import {
2
+ focusables,
3
+ hideFloating,
4
+ ownOne,
5
+ resolveAsChild,
6
+ showFloating,
7
+ uid
8
+ } from "./chunk-KXCPLIQD.js";
9
+ import {
10
+ DogsbayElement,
11
+ ensureDefaultDisplay
12
+ } from "./chunk-MZDGSTI4.js";
13
+
14
+ // src/db-popover.ts
15
+ import { DismissController } from "@dogsbay/primitives/dismiss";
16
+ import { setupFloating } from "@dogsbay/primitives/floating";
17
+ var DbPopover = class extends DogsbayElement {
18
+ trigger = null;
19
+ content = null;
20
+ dismiss = null;
21
+ cleanupFloating = null;
22
+ _open = false;
23
+ get open() {
24
+ return this._open;
25
+ }
26
+ onTriggerClick = () => this.toggle();
27
+ onContentClick = (e) => {
28
+ const close = e.target.closest("[data-part='close']");
29
+ if (close && close.closest("db-popover") === this) this.close("close-press");
30
+ };
31
+ setup() {
32
+ this.trigger = resolveAsChild(ownOne(this, "[data-part='trigger']"));
33
+ this.content = ownOne(this, "[data-part='content']");
34
+ if (!this.trigger || !this.content) return;
35
+ const content = this.content;
36
+ content.id ||= uid("db-popover");
37
+ if (!content.hasAttribute("role")) content.setAttribute("role", "dialog");
38
+ if (!content.hasAttribute("aria-labelledby") && !content.hasAttribute("aria-label")) {
39
+ this.trigger.id ||= uid("db-popover-trigger");
40
+ content.setAttribute("aria-labelledby", this.trigger.id);
41
+ }
42
+ content.hidden = true;
43
+ this.trigger.setAttribute("aria-haspopup", "dialog");
44
+ this.trigger.setAttribute("aria-controls", content.id);
45
+ this.trigger.setAttribute("aria-expanded", "false");
46
+ this.setState("closed");
47
+ this.dismiss = new DismissController(content, { onDismiss: (reason) => this.close(reason) });
48
+ }
49
+ connect() {
50
+ this.trigger?.addEventListener("click", this.onTriggerClick);
51
+ this.content?.addEventListener("click", this.onContentClick);
52
+ }
53
+ disconnect() {
54
+ this.trigger?.removeEventListener("click", this.onTriggerClick);
55
+ this.content?.removeEventListener("click", this.onContentClick);
56
+ if (this._open) this.close("api");
57
+ }
58
+ setState(state) {
59
+ this.setAttribute("data-state", state);
60
+ this.content?.setAttribute("data-state", state);
61
+ }
62
+ placement() {
63
+ const attr = this.getAttribute("placement");
64
+ if (attr) return attr;
65
+ const side = this.content?.dataset.side || "bottom";
66
+ const align = this.content?.dataset.align || "center";
67
+ return `${side}${align !== "center" ? `-${align}` : ""}`;
68
+ }
69
+ toggle() {
70
+ if (this._open) this.close("trigger-press");
71
+ else this.show();
72
+ }
73
+ show() {
74
+ const { trigger, content } = this;
75
+ if (!trigger || !content || this._open) return;
76
+ this._open = true;
77
+ const layer = showFloating(content);
78
+ this.setState("open");
79
+ trigger.setAttribute("aria-expanded", "true");
80
+ this.cleanupFloating = setupFloating(trigger, content, {
81
+ placement: this.placement(),
82
+ offset: Number(this.getAttribute("offset") ?? 8),
83
+ strategy: layer === "top-layer" ? "fixed" : "absolute"
84
+ });
85
+ this.dismiss?.activate();
86
+ if (!this.hasAttribute("no-autofocus")) {
87
+ requestAnimationFrame(() => {
88
+ if (this._open) (focusables(content)[0] ?? content).focus({ preventScroll: true });
89
+ });
90
+ }
91
+ this.dispatchEvent(new CustomEvent("db-popover:open", { bubbles: true }));
92
+ }
93
+ close(reason = "api") {
94
+ const { trigger, content } = this;
95
+ if (!trigger || !content || !this._open) return;
96
+ this._open = false;
97
+ this.dismiss?.deactivate();
98
+ this.cleanupFloating?.();
99
+ this.cleanupFloating = null;
100
+ const hadFocus = content.contains(document.activeElement);
101
+ hideFloating(content);
102
+ this.setState("closed");
103
+ trigger.setAttribute("aria-expanded", "false");
104
+ if (reason !== "outside-press" && (hadFocus || reason === "escape-key" || reason === "close-press")) trigger.focus();
105
+ this.dispatchEvent(new CustomEvent("db-popover:close", { detail: { reason }, bubbles: true }));
106
+ }
107
+ };
108
+ ensureDefaultDisplay();
109
+ if (!customElements.get("db-popover")) {
110
+ customElements.define("db-popover", DbPopover);
111
+ }
112
+
113
+ export {
114
+ DbPopover
115
+ };
@@ -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-tabs.ts
6
7
  import { CompositeNavigation } from "@dogsbay/primitives/composite";
@@ -24,29 +25,56 @@ var DbTabs = class extends DogsbayElement {
24
25
  const value = trigger.dataset.value;
25
26
  if (value) this.select(value);
26
27
  };
28
+ /**
29
+ * A synced group follows only a value it HAS. Groups sharing a key need
30
+ * not share a tab set (a web-only snippet group beside an all-SDK one), and
31
+ * selecting a value with no trigger here left the group with every panel
32
+ * hidden and no tab selected.
33
+ */
34
+ has(value) {
35
+ return this.triggers.some((t) => t.dataset.value === value);
36
+ }
27
37
  handleStorage = (e) => {
28
38
  if (!this.syncKey || e.key !== `db-tabs-sync:${this.syncKey}`) return;
29
39
  const newValue = e.newValue;
30
- if (newValue && this.value !== newValue) {
40
+ if (newValue && this.value !== newValue && this.has(newValue)) {
31
41
  this.select(newValue);
32
42
  }
33
43
  };
34
44
  handleSyncEvent = ((e) => {
35
45
  const newValue = e.detail.value;
36
- if (newValue && this.value !== newValue) {
46
+ if (newValue && this.value !== newValue && this.has(newValue)) {
37
47
  this.select(newValue);
38
48
  }
39
49
  });
50
+ /**
51
+ * Descendants belonging to THIS tab group.
52
+ *
53
+ * Not `:scope >`, and not a bare descendant query — both were wrong
54
+ * here, in opposite directions:
55
+ *
56
+ * - Panels used `:scope > [data-part='content']`, so any wrapper
57
+ * between the element and its panels hid them. The vertical example
58
+ * wraps its list and panels in a flex row to sit them side by side,
59
+ * so `panels` was EMPTY: triggers moved `aria-selected`, and the
60
+ * content never changed. Nothing threw, and the server-rendered
61
+ * initial state looked right, so it read as working.
62
+ * - Triggers used a bare descendant query, which would reach into a
63
+ * NESTED tab group and drive the wrong panels.
64
+ *
65
+ * `closest("db-tabs") === this` allows arbitrary wrappers while
66
+ * stopping at a nested group, which is a real case — Obsidian
67
+ * alternates fence characters by depth precisely so tabs can nest.
68
+ */
69
+ own(selector) {
70
+ return Array.from(this.querySelectorAll(selector)).filter((el) => el.closest("db-tabs") === this);
71
+ }
40
72
  setup() {
41
- const list = this.querySelector("[data-part='list']");
73
+ const list = this.own("[data-part='list']")[0] ?? null;
42
74
  if (!list) return;
43
75
  this.list = list;
44
- this.triggers = Array.from(
45
- list.querySelectorAll("[data-part='trigger']")
46
- );
47
- this.panels = Array.from(
48
- this.querySelectorAll(":scope > [data-part='content']")
49
- );
76
+ this.triggers = this.own("[data-part='trigger']");
77
+ this.panels = this.own("[data-part='content']");
50
78
  this.orientation = this.getAttribute("orientation") || "horizontal";
51
79
  this.syncKey = this.getAttribute("sync-key") || null;
52
80
  list.setAttribute("role", "tablist");
@@ -151,6 +179,7 @@ var DbTabs = class extends DogsbayElement {
151
179
  );
152
180
  }
153
181
  };
182
+ ensureDefaultDisplay();
154
183
  if (!customElements.get("db-tabs")) {
155
184
  customElements.define("db-tabs", DbTabs);
156
185
  }
@@ -158,4 +187,3 @@ if (!customElements.get("db-tabs")) {
158
187
  export {
159
188
  DbTabs
160
189
  };
161
- //# sourceMappingURL=chunk-LVXR7KTB.js.map
@@ -1,19 +1,19 @@
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-steps.ts
6
7
  var DbSteps = class extends DogsbayElement {
7
8
  setup() {
8
9
  this.setAttribute("role", "list");
9
- const items = this.querySelectorAll(
10
- ":scope > [data-part='item']"
11
- );
10
+ const items = Array.from(this.querySelectorAll("[data-part='item']")).filter((el) => el.closest("db-steps") === this);
12
11
  for (const item of items) {
13
12
  item.setAttribute("role", "listitem");
14
13
  }
15
14
  }
16
15
  };
16
+ ensureDefaultDisplay();
17
17
  if (!customElements.get("db-steps")) {
18
18
  customElements.define("db-steps", DbSteps);
19
19
  }
@@ -21,4 +21,3 @@ if (!customElements.get("db-steps")) {
21
21
  export {
22
22
  DbSteps
23
23
  };
24
- //# sourceMappingURL=chunk-5T4OXQA2.js.map
@@ -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-code-block.ts
6
7
  var DbCodeBlock = class extends DogsbayElement {
@@ -79,6 +80,7 @@ var DbCodeBlock = class extends DogsbayElement {
79
80
  }
80
81
  }
81
82
  };
83
+ ensureDefaultDisplay();
82
84
  if (!customElements.get("db-code-block")) {
83
85
  customElements.define("db-code-block", DbCodeBlock);
84
86
  }
@@ -86,4 +88,3 @@ if (!customElements.get("db-code-block")) {
86
88
  export {
87
89
  DbCodeBlock
88
90
  };
89
- //# sourceMappingURL=chunk-FWAAU5UY.js.map
@@ -0,0 +1,85 @@
1
+ import {
2
+ safeDecode
3
+ } from "./chunk-KXCPLIQD.js";
4
+ import {
5
+ DogsbayElement,
6
+ ensureDefaultDisplay
7
+ } from "./chunk-MZDGSTI4.js";
8
+
9
+ // src/db-toc.ts
10
+ var DbToc = class extends DogsbayElement {
11
+ links = [];
12
+ headings = [];
13
+ observer = null;
14
+ active = null;
15
+ slugOf(a) {
16
+ return a.getAttribute("data-toc-slug") ?? safeDecode(a.getAttribute("href").slice(1));
17
+ }
18
+ // Headings in a short tail never reach the observed band; at the bottom of the
19
+ // page the last one is current.
20
+ onScroll = () => {
21
+ const doc = document.documentElement;
22
+ if (window.innerHeight + window.scrollY >= doc.scrollHeight - 2 && this.headings.length) {
23
+ this.setActive(this.headings[this.headings.length - 1].id);
24
+ }
25
+ };
26
+ setup() {
27
+ this.links = Array.from(this.querySelectorAll("a[href^='#'], a[data-toc-link]"));
28
+ }
29
+ onHash = () => {
30
+ const id = safeDecode(location.hash.slice(1));
31
+ if (id && this.headings.some((h) => h.id === id)) this.setActive(id);
32
+ };
33
+ connect() {
34
+ this.headings = this.links.map((a) => document.getElementById(this.slugOf(a))).filter((h) => !!h);
35
+ if (!this.headings.length) return;
36
+ const offset = Number(this.getAttribute("offset") ?? 80);
37
+ if (typeof IntersectionObserver !== "undefined") {
38
+ this.observer = new IntersectionObserver(
39
+ (entries) => {
40
+ const hit = entries.find((e) => e.isIntersecting);
41
+ if (hit) return this.setActive(hit.target.id);
42
+ this.setActive(this.lastAbove(offset)?.id ?? null);
43
+ },
44
+ { rootMargin: `-${offset}px 0px -70% 0px`, threshold: 0 }
45
+ );
46
+ this.headings.forEach((h) => this.observer.observe(h));
47
+ }
48
+ window.addEventListener("hashchange", this.onHash);
49
+ window.addEventListener("scroll", this.onScroll, { passive: true });
50
+ this.setActive(this.lastAbove(offset)?.id ?? this.headings[0].id);
51
+ }
52
+ disconnect() {
53
+ this.observer?.disconnect();
54
+ this.observer = null;
55
+ window.removeEventListener("hashchange", this.onHash);
56
+ window.removeEventListener("scroll", this.onScroll);
57
+ }
58
+ lastAbove(offset) {
59
+ let last = null;
60
+ for (const h of this.headings) if (h.getBoundingClientRect().top <= offset + 20) last = h;
61
+ return last;
62
+ }
63
+ setActive(id) {
64
+ if (!id || id === this.active) return;
65
+ this.active = id;
66
+ for (const a of this.links) {
67
+ if (this.slugOf(a) === id) {
68
+ a.setAttribute("aria-current", "location");
69
+ a.setAttribute("data-active", "");
70
+ } else {
71
+ a.removeAttribute("aria-current");
72
+ a.removeAttribute("data-active");
73
+ }
74
+ }
75
+ this.dispatchEvent(new CustomEvent("db-toc:change", { detail: { id }, bubbles: true }));
76
+ }
77
+ };
78
+ ensureDefaultDisplay();
79
+ if (!customElements.get("db-toc")) {
80
+ customElements.define("db-toc", DbToc);
81
+ }
82
+
83
+ export {
84
+ DbToc
85
+ };