@livx.cc/bare-v3 0.1.0-alpha.10

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 (37) hide show
  1. package/README.md +39 -0
  2. package/dist/bare.css +1758 -0
  3. package/dist/bare.min.css +1 -0
  4. package/dist/manifest.json +457 -0
  5. package/dist/references/app-frame.md +9 -0
  6. package/dist/references/button.md +9 -0
  7. package/dist/references/card-structure.md +9 -0
  8. package/dist/references/command.md +9 -0
  9. package/dist/references/content.md +9 -0
  10. package/dist/references/control-structure.md +9 -0
  11. package/dist/references/conversation.md +9 -0
  12. package/dist/references/cross-screen.md +34 -0
  13. package/dist/references/data-display.md +9 -0
  14. package/dist/references/dialog.md +9 -0
  15. package/dist/references/disclosure.md +9 -0
  16. package/dist/references/feedback.md +9 -0
  17. package/dist/references/field.md +9 -0
  18. package/dist/references/form-composition.md +9 -0
  19. package/dist/references/foundation.md +9 -0
  20. package/dist/references/icons.md +14 -0
  21. package/dist/references/identity.md +9 -0
  22. package/dist/references/layout.md +9 -0
  23. package/dist/references/marketing.md +9 -0
  24. package/dist/references/mobile.md +9 -0
  25. package/dist/references/motion.md +44 -0
  26. package/dist/references/navigation.md +9 -0
  27. package/dist/references/page-layout.md +9 -0
  28. package/dist/references/reading.md +9 -0
  29. package/dist/references/row.md +9 -0
  30. package/dist/references/start.md +21 -0
  31. package/dist/references/status.md +9 -0
  32. package/dist/references/steps.md +9 -0
  33. package/dist/references/surface.md +9 -0
  34. package/dist/references/tabs.md +9 -0
  35. package/dist/references/type.md +9 -0
  36. package/dist/ui.js +598 -0
  37. package/package.json +47 -0
package/dist/ui.js ADDED
@@ -0,0 +1,598 @@
1
+ // src/interactions/commands.js
2
+ function commands({ root, document: document2, options }) {
3
+ for (const dialog of root.querySelectorAll("dialog[data-b3-command]")) {
4
+ let select = function(item, scroll = true) {
5
+ active = item || null;
6
+ for (const option of list.querySelectorAll('[role="option"]'))
7
+ option.setAttribute("aria-selected", String(option === active));
8
+ if (active) {
9
+ input.setAttribute("aria-activedescendant", active.id);
10
+ if (scroll)
11
+ active.scrollIntoView({ block: "nearest" });
12
+ } else
13
+ input.removeAttribute("aria-activedescendant");
14
+ }, filter = function() {
15
+ const terms = input.value.trim().toLocaleLowerCase().split(/\s+/).filter(Boolean);
16
+ const items = [...list.querySelectorAll('[role="option"]')];
17
+ for (const item of items) {
18
+ const text = `${item.textContent} ${item.dataset.b3Keywords || ""}`.toLocaleLowerCase();
19
+ item.hidden = !terms.every((term) => text.includes(term));
20
+ }
21
+ for (const group of list.querySelectorAll('[role="group"]'))
22
+ group.hidden = ![...group.querySelectorAll('[role="option"]')].some((item) => !item.hidden);
23
+ const matches = items.filter((item) => !item.hidden);
24
+ available = matches.filter((item) => item.id && item.getAttribute("aria-disabled") !== "true");
25
+ list.hidden = !matches.length;
26
+ input.setAttribute("aria-expanded", String(dialog.open && !!matches.length));
27
+ if (empty)
28
+ empty.hidden = !!matches.length;
29
+ if (status)
30
+ status.textContent = `${available.length} ${available.length === 1 ? "action" : "actions"} available.`;
31
+ select(available[0], false);
32
+ }, choose = function(item) {
33
+ if (!item || !available.includes(item) || item.hidden || item.getAttribute("aria-disabled") === "true" || !list.contains(item))
34
+ return;
35
+ const accepted = dialog.dispatchEvent(new document2.defaultView.CustomEvent("b3:command", {
36
+ bubbles: true,
37
+ cancelable: true,
38
+ detail: { value: item.dataset.b3Value, item }
39
+ }));
40
+ if (accepted)
41
+ dialog.close();
42
+ };
43
+ const input = dialog.querySelector('input[role="combobox"]');
44
+ const list = dialog.querySelector('[role="listbox"]');
45
+ if (!input || !list?.id || input.getAttribute("aria-controls") !== list.id)
46
+ continue;
47
+ const empty = dialog.querySelector("[data-b3-command-empty]");
48
+ const status = dialog.querySelector("[data-b3-command-status]");
49
+ let active = null;
50
+ let available = [];
51
+ input.addEventListener("input", filter, options);
52
+ input.addEventListener("keydown", (event) => {
53
+ if (event.isComposing || event.altKey || event.ctrlKey || event.metaKey)
54
+ return;
55
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
56
+ event.preventDefault();
57
+ if (!available.length)
58
+ return;
59
+ const index = available.indexOf(active);
60
+ const next = event.key === "ArrowDown" ? Math.min(index + 1, available.length - 1) : Math.max(index - 1, 0);
61
+ select(available[next]);
62
+ } else if (event.key === "Enter") {
63
+ event.preventDefault();
64
+ choose(active);
65
+ }
66
+ }, options);
67
+ list.addEventListener("pointerdown", (event) => {
68
+ if (event.target.closest('[role="option"]'))
69
+ event.preventDefault();
70
+ }, options);
71
+ list.addEventListener("click", (event) => {
72
+ choose(event.target.closest('[role="option"]'));
73
+ }, options);
74
+ const observer = new document2.defaultView.MutationObserver(() => {
75
+ if (dialog.open) {
76
+ input.value = "";
77
+ filter();
78
+ } else {
79
+ input.setAttribute("aria-expanded", "false");
80
+ input.removeAttribute("aria-activedescendant");
81
+ }
82
+ });
83
+ observer.observe(dialog, { attributes: true, attributeFilter: ["open"] });
84
+ options.signal.addEventListener("abort", () => observer.disconnect(), { once: true });
85
+ filter();
86
+ }
87
+ }
88
+
89
+ // src/interactions/outline.js
90
+ function outline({ root, document: document2, find, options }) {
91
+ const view = document2.defaultView;
92
+ const outlines = [...root.querySelectorAll("[data-b3-toc]")].map((nav) => {
93
+ const items = [...nav.querySelectorAll('a[href^="#"]')].flatMap((link) => {
94
+ let id;
95
+ try {
96
+ id = decodeURIComponent(link.getAttribute("href").slice(1));
97
+ } catch {
98
+ return [];
99
+ }
100
+ const heading = find(id);
101
+ return heading ? [{ link, heading }] : [];
102
+ });
103
+ return items;
104
+ }).filter((items) => items.length);
105
+ if (!outlines.length)
106
+ return;
107
+ let frame = 0;
108
+ function update() {
109
+ frame = 0;
110
+ for (const items of outlines) {
111
+ const visible = items.filter(({ heading }) => heading.getClientRects().length);
112
+ let active = visible[0];
113
+ for (const item of visible) {
114
+ const offset = parseFloat(view.getComputedStyle(item.heading).scrollMarginBlockStart) || 0;
115
+ if (item.heading.getBoundingClientRect().top <= offset + 1)
116
+ active = item;
117
+ }
118
+ if (view.scrollY > 0 && view.scrollY + view.innerHeight >= document2.documentElement.scrollHeight - 2)
119
+ active = visible.at(-1);
120
+ for (const item of items) {
121
+ if (item === active)
122
+ item.link.setAttribute("aria-current", "location");
123
+ else
124
+ item.link.removeAttribute("aria-current");
125
+ }
126
+ }
127
+ }
128
+ function schedule() {
129
+ if (!frame)
130
+ frame = view.requestAnimationFrame(update);
131
+ }
132
+ view.addEventListener("scroll", schedule, { ...options, passive: true });
133
+ view.addEventListener("resize", schedule, options);
134
+ view.addEventListener("hashchange", schedule, options);
135
+ options.signal.addEventListener("abort", () => view.cancelAnimationFrame(frame), { once: true });
136
+ update();
137
+ }
138
+
139
+ // src/interactions/tabs.js
140
+ function tabs({ root, document: document2, find, options }) {
141
+ function activate(tab, focus = false) {
142
+ const list = tab.closest('[role="tablist"]');
143
+ if (!list || tab.disabled)
144
+ return;
145
+ for (const item of list.querySelectorAll('[role="tab"]')) {
146
+ if (item.closest('[role="tablist"]') !== list)
147
+ continue;
148
+ const selected = item === tab;
149
+ item.setAttribute("aria-selected", String(selected));
150
+ item.tabIndex = selected ? 0 : -1;
151
+ const panel = find(item.getAttribute("aria-controls"));
152
+ if (panel)
153
+ panel.hidden = !selected;
154
+ }
155
+ if (focus)
156
+ tab.focus();
157
+ }
158
+ for (const list of root.querySelectorAll('[role="tablist"][data-b3-tabs]')) {
159
+ const tabs2 = [...list.querySelectorAll('[role="tab"]')].filter((tab) => !tab.disabled && tab.closest('[role="tablist"]') === list);
160
+ const selected = tabs2.find((tab) => tab.getAttribute("aria-selected") === "true") || tabs2[0];
161
+ if (selected)
162
+ activate(selected);
163
+ }
164
+ root.addEventListener("click", (event) => {
165
+ const target = event.target.closest?.('[role="tab"]');
166
+ if (target && !target.disabled && target.closest("[data-b3-tabs]"))
167
+ activate(target);
168
+ }, options);
169
+ root.addEventListener("keydown", (event) => {
170
+ const tab = event.target.closest?.('[role="tab"]');
171
+ const list = tab?.closest('[role="tablist"][data-b3-tabs]');
172
+ if (list) {
173
+ const tabs2 = [...list.querySelectorAll('[role="tab"]')].filter((item) => !item.disabled && item.closest('[role="tablist"]') === list);
174
+ const index = tabs2.indexOf(tab);
175
+ const vertical = list.getAttribute("aria-orientation") === "vertical";
176
+ const rtl = document2.defaultView.getComputedStyle(list).direction === "rtl";
177
+ const next = vertical ? "ArrowDown" : rtl ? "ArrowLeft" : "ArrowRight";
178
+ const previous = vertical ? "ArrowUp" : rtl ? "ArrowRight" : "ArrowLeft";
179
+ let destination;
180
+ if (event.key === next)
181
+ destination = tabs2[(index + 1) % tabs2.length];
182
+ if (event.key === previous)
183
+ destination = tabs2[(index - 1 + tabs2.length) % tabs2.length];
184
+ if (event.key === "Home")
185
+ destination = tabs2[0];
186
+ if (event.key === "End")
187
+ destination = tabs2.at(-1);
188
+ if (destination) {
189
+ event.preventDefault();
190
+ activate(destination, true);
191
+ }
192
+ }
193
+ }, options);
194
+ }
195
+
196
+ // src/interactions/disclosures.js
197
+ function disclosures({ root, document: document2, options }) {
198
+ function placeDisclosure(disclosure) {
199
+ const panel = disclosure.querySelector(".b3-dropdown-panel");
200
+ if (!panel || !disclosure.open)
201
+ return;
202
+ panel.style.transform = "";
203
+ panel.style.insetBlockStart = "";
204
+ panel.style.insetBlockEnd = "";
205
+ const viewport = document2.defaultView;
206
+ const bounds = panel.getBoundingClientRect();
207
+ const shift = bounds.left < 8 ? 8 - bounds.left : bounds.right > viewport.innerWidth - 8 ? viewport.innerWidth - 8 - bounds.right : 0;
208
+ panel.style.transform = `translateX(${shift}px)`;
209
+ if (bounds.bottom > viewport.innerHeight - 8 && disclosure.getBoundingClientRect().top > bounds.height + 8) {
210
+ panel.style.insetBlockStart = "auto";
211
+ panel.style.insetBlockEnd = "calc(100% + .5rem)";
212
+ }
213
+ }
214
+ root.addEventListener("toggle", (event) => {
215
+ if (event.target.matches?.("details.b3-dropdown"))
216
+ placeDisclosure(event.target);
217
+ }, { ...options, capture: true });
218
+ document2.defaultView.addEventListener("resize", () => {
219
+ root.querySelectorAll("details.b3-dropdown[open]").forEach(placeDisclosure);
220
+ }, options);
221
+ root.addEventListener("keydown", (event) => {
222
+ if (event.key === "Escape") {
223
+ const disclosure = event.target.closest?.("details.b3-dropdown[open]");
224
+ if (disclosure) {
225
+ disclosure.open = false;
226
+ disclosure.querySelector("summary")?.focus();
227
+ }
228
+ }
229
+ }, options);
230
+ root.addEventListener("click", (event) => {
231
+ for (const disclosure of root.querySelectorAll("details.b3-dropdown[open]")) {
232
+ if (!disclosure.contains(event.target))
233
+ disclosure.open = false;
234
+ }
235
+ }, options);
236
+ }
237
+
238
+ // src/interactions/dialog-focus.js
239
+ function dialogFocus({ root, document: document2, options }) {
240
+ const prepared = new Map;
241
+ const restore = (title) => {
242
+ const original = prepared.get(title);
243
+ if (!original)
244
+ return;
245
+ for (const [name, value] of Object.entries(original)) {
246
+ const owned = name === "tabindex" ? "-1" : "";
247
+ if (title.getAttribute(name) !== owned)
248
+ continue;
249
+ if (value === null)
250
+ title.removeAttribute(name);
251
+ else
252
+ title.setAttribute(name, value);
253
+ }
254
+ prepared.delete(title);
255
+ };
256
+ const prepare = (dialog) => {
257
+ if (!dialog.matches?.("dialog.b3-sheet"))
258
+ return;
259
+ const explicit = [...dialog.querySelectorAll("[autofocus]")].find((node) => !prepared.has(node));
260
+ if (explicit) {
261
+ for (const title2 of prepared.keys())
262
+ if (dialog.contains(title2))
263
+ restore(title2);
264
+ return;
265
+ }
266
+ const id = dialog.getAttribute("aria-labelledby")?.trim().split(/\s+/)[0];
267
+ const title = id && document2.getElementById(id);
268
+ if (!title || !dialog.contains(title) || prepared.has(title))
269
+ return;
270
+ prepared.set(title, Object.fromEntries(["tabindex", "autofocus", "data-b3-initial-focus"].map((name) => [name, title.getAttribute(name)])));
271
+ title.setAttribute("tabindex", "-1");
272
+ title.setAttribute("autofocus", "");
273
+ title.setAttribute("data-b3-initial-focus", "");
274
+ };
275
+ prepare(root);
276
+ for (const dialog of root.querySelectorAll("dialog.b3-sheet"))
277
+ prepare(dialog);
278
+ root.addEventListener("beforetoggle", (event) => {
279
+ if (event.newState === "open")
280
+ prepare(event.target);
281
+ }, { ...options, capture: true });
282
+ options.signal.addEventListener("abort", () => {
283
+ for (const title of prepared.keys())
284
+ restore(title);
285
+ }, { once: true });
286
+ }
287
+
288
+ // src/interactions/motion.js
289
+ var running = new WeakMap;
290
+ var ease = "cubic-bezier(.16,1,.3,1)";
291
+ var presets = {
292
+ enter: { keyframes: [{ opacity: 0, transform: "translateY(12px) scale(.985)" }, { opacity: 1, transform: "none" }], duration: 320 },
293
+ exit: { keyframes: [{ opacity: 1, transform: "none" }, { opacity: 0, transform: "translateY(-6px) scale(.98)" }], duration: 180, easing: "cubic-bezier(.4,0,1,1)" },
294
+ update: { keyframes: [{ opacity: 0.35 }, { opacity: 1 }], duration: 180 },
295
+ confirm: { keyframes: [{ transform: "scale(.9)" }, { transform: "scale(1.08)", offset: 0.5 }, { transform: "scale(.985)", offset: 0.8 }, { transform: "scale(1)" }], duration: 380 },
296
+ reveal: { keyframes: [{ opacity: 0, clipPath: "inset(0 0 100%)", transform: "translateY(8px)" }, { opacity: 1, clipPath: "inset(0)", transform: "none" }], duration: 440 }
297
+ };
298
+ var reducedMotion = (element) => element.ownerDocument?.defaultView?.matchMedia("(prefers-reduced-motion: reduce)").matches || element.closest('[data-b3-motion="reduce"]');
299
+ function play(element, keyframes, options) {
300
+ running.get(element)?.cancel();
301
+ if (!element.isConnected || !element.animate || reducedMotion(element))
302
+ return null;
303
+ const animation = element.animate(keyframes, { easing: ease, fill: "backwards", ...options });
304
+ running.set(element, animation);
305
+ const preference = element.ownerDocument.defaultView.matchMedia("(prefers-reduced-motion: reduce)");
306
+ const reduce = () => {
307
+ if (preference.matches)
308
+ animation.cancel();
309
+ };
310
+ preference.addEventListener("change", reduce);
311
+ const cleanup = () => {
312
+ preference.removeEventListener("change", reduce);
313
+ if (running.get(element) === animation)
314
+ running.delete(element);
315
+ };
316
+ animation.addEventListener("finish", cleanup, { once: true });
317
+ animation.addEventListener("cancel", cleanup, { once: true });
318
+ return animation;
319
+ }
320
+ function motion(element, intent = "update", options = {}) {
321
+ const preset = presets[intent];
322
+ if (!preset)
323
+ throw new TypeError(`Unknown motion intent: ${intent}`);
324
+ return play(element, preset.keyframes, { duration: preset.duration, easing: preset.easing || ease, delay: Math.min(200, Math.max(0, options.delay || 0)) });
325
+ }
326
+ function sequence(elements, intent = "enter") {
327
+ return Array.from(elements, (element, index) => motion(element, intent, { delay: Math.min(index * 45, 180) })).filter(Boolean);
328
+ }
329
+ function layout(root, update) {
330
+ const measure = () => {
331
+ const entries = new Map;
332
+ for (const element of root.querySelectorAll("[data-b3-layout]")) {
333
+ const key = element.dataset.b3Layout;
334
+ if (!key || entries.has(key))
335
+ throw new Error("Layout motion requires unique, non-empty data-b3-layout keys");
336
+ entries.set(key, { element, rect: element.getBoundingClientRect() });
337
+ }
338
+ return entries;
339
+ };
340
+ const before = measure();
341
+ for (const { element } of before.values())
342
+ running.get(element)?.cancel();
343
+ update();
344
+ const animations = [];
345
+ for (const [key, { element, rect }] of measure()) {
346
+ const previous = before.get(key);
347
+ if (!previous || previous.element !== element) {
348
+ const a = motion(element, "enter");
349
+ if (a)
350
+ animations.push(a);
351
+ continue;
352
+ }
353
+ const from = previous.rect;
354
+ if (!rect.width || !rect.height || !from.width || !from.height)
355
+ continue;
356
+ const x = from.x - rect.x, y = from.y - rect.y;
357
+ const sx = from.width / rect.width, sy = from.height / rect.height;
358
+ if (Math.abs(x) + Math.abs(y) + Math.abs(sx - 1) + Math.abs(sy - 1) < 0.01)
359
+ continue;
360
+ const animation = play(element, [
361
+ { transformOrigin: "top left", transform: `translate(${x}px,${y}px) scale(${sx},${sy})` },
362
+ { transformOrigin: "top left", transform: "none" }
363
+ ], { duration: 420 });
364
+ if (animation)
365
+ animations.push(animation);
366
+ }
367
+ return animations;
368
+ }
369
+ function settle(element, { x = 0, y = 0 } = {}) {
370
+ if (!Number.isFinite(x) || !Number.isFinite(y))
371
+ throw new TypeError("Settle displacement must be finite");
372
+ const frames = Array.from({ length: 41 }, (_, index) => {
373
+ const t = index / 40;
374
+ const amount = index === 40 ? 0 : Math.exp(-7 * t) * (Math.cos(11 * t) + 0.6 * Math.sin(11 * t));
375
+ return { offset: t, transform: `translate(${x * amount}px,${y * amount}px)` };
376
+ });
377
+ return play(element, frames, { duration: 460, easing: "linear" });
378
+ }
379
+
380
+ // src/interactions/sheets.js
381
+ function sheets({ root, document: document2, options, dismiss }) {
382
+ let drag = null, suppressClick = null;
383
+ const settling = new Map;
384
+ const reset = (state, animate = true) => {
385
+ const { dialog, handle, pointerId, distance } = state;
386
+ drag = null;
387
+ delete dialog.dataset.b3Dragging;
388
+ dialog.style.removeProperty("transform");
389
+ if (handle.hasPointerCapture(pointerId))
390
+ handle.releasePointerCapture(pointerId);
391
+ if (animate && distance && dialog.open && !reducedMotion(dialog)) {
392
+ const animation = settle(dialog, { y: distance });
393
+ if (!animation)
394
+ return;
395
+ settling.set(dialog, animation);
396
+ animation.finished.catch(() => {}).finally(() => {
397
+ if (settling.get(dialog) === animation)
398
+ settling.delete(dialog);
399
+ });
400
+ }
401
+ };
402
+ root.addEventListener("pointerdown", (event) => {
403
+ suppressClick = null;
404
+ const handle = event.target.closest?.(".b3-sheet-handle");
405
+ const dialog = handle?.closest('dialog.b3-sheet[data-b3-drag="dismiss"]:modal');
406
+ if (!dialog || drag || !event.isPrimary || event.button !== 0 || dialog.hasAttribute("data-b3-closing"))
407
+ return;
408
+ settling.get(dialog)?.cancel();
409
+ for (const animation of dialog.getAnimations())
410
+ animation.cancel();
411
+ drag = { dialog, handle, pointerId: event.pointerId, y: event.clientY, distance: 0, moved: false };
412
+ dialog.dataset.b3Dragging = "";
413
+ handle.setPointerCapture(event.pointerId);
414
+ }, options);
415
+ root.addEventListener("pointermove", (event) => {
416
+ if (!drag || event.pointerId !== drag.pointerId)
417
+ return;
418
+ drag.distance = Math.max(0, event.clientY - drag.y);
419
+ drag.moved ||= Math.abs(event.clientY - drag.y) > 6;
420
+ drag.dialog.style.transform = `translateY(${drag.distance}px)`;
421
+ }, options);
422
+ root.addEventListener("pointerup", (event) => {
423
+ if (!drag || event.pointerId !== drag.pointerId)
424
+ return;
425
+ const state = drag;
426
+ if (state.moved)
427
+ suppressClick = { pointerId: state.pointerId, handle: state.handle };
428
+ const threshold = Math.min(120, state.dialog.offsetHeight * 0.25);
429
+ if (state.moved && state.distance >= threshold) {
430
+ const accepted = dismiss(state.dialog);
431
+ reset(state, !accepted);
432
+ } else
433
+ reset(state);
434
+ }, options);
435
+ const cancel = (event) => {
436
+ if (drag && event.pointerId === drag.pointerId)
437
+ reset(drag);
438
+ };
439
+ root.addEventListener("pointercancel", cancel, options);
440
+ root.addEventListener("lostpointercapture", cancel, options);
441
+ root.addEventListener("click", (event) => {
442
+ const suppressed = suppressClick;
443
+ suppressClick = null;
444
+ if (suppressed && event.detail !== 0 && (event.pointerId === suppressed.pointerId || suppressed.handle.contains(event.target))) {
445
+ event.preventDefault();
446
+ event.stopImmediatePropagation();
447
+ }
448
+ }, { ...options, capture: true });
449
+ root.addEventListener("close", (event) => {
450
+ if (drag?.dialog === event.target)
451
+ reset(drag, false);
452
+ settling.get(event.target)?.cancel();
453
+ }, { ...options, capture: true });
454
+ options.signal.addEventListener("abort", () => {
455
+ if (drag)
456
+ reset(drag, false);
457
+ for (const animation of settling.values())
458
+ animation.cancel();
459
+ settling.clear();
460
+ }, { once: true });
461
+ }
462
+
463
+ // src/interactions/dialogs.js
464
+ function dialogs({ root, document: document2, find, options }) {
465
+ dialogFocus({ root, document: document2, options });
466
+ const openers = new WeakMap;
467
+ const closing = new Map;
468
+ let backdropStart = null;
469
+ let backdropEnd = null;
470
+ const outside = (event, dialog) => {
471
+ const r = dialog.getBoundingClientRect();
472
+ return event.clientX < r.left || event.clientX > r.right || event.clientY < r.top || event.clientY > r.bottom;
473
+ };
474
+ const dismiss = (dialog) => {
475
+ if (!dialog.open || closing.has(dialog))
476
+ return false;
477
+ if (!dialog.dispatchEvent(new Event("cancel", { cancelable: true })))
478
+ return false;
479
+ if (reducedMotion(dialog) || !dialog.animate) {
480
+ dialog.close();
481
+ return true;
482
+ }
483
+ const css = document2.defaultView.getComputedStyle(dialog);
484
+ const end = dialog.matches(".b3-sheet") ? "translateY(100%)" : dialog.dataset.b3Placement === "end" ? `translateX(${css.direction === "rtl" ? "-" : ""}100%)` : "scale(.985)";
485
+ const animation = dialog.animate([{ transform: css.transform, opacity: 1 }, { transform: end, opacity: 0 }], { duration: 160, easing: "cubic-bezier(.4, 0, 1, 1)" });
486
+ closing.set(dialog, animation);
487
+ dialog.dataset.b3Closing = "";
488
+ animation.finished.then(() => {
489
+ if (dialog.open)
490
+ dialog.close();
491
+ }, () => {}).finally(() => {
492
+ closing.delete(dialog);
493
+ delete dialog.dataset.b3Closing;
494
+ });
495
+ return true;
496
+ };
497
+ root.addEventListener("cancel", (event) => {
498
+ if (!event.cancelable || event.defaultPrevented || !event.isTrusted || !event.target.matches?.("dialog.b3-dialog,dialog.b3-sheet"))
499
+ return;
500
+ event.preventDefault();
501
+ event.stopImmediatePropagation();
502
+ dismiss(event.target);
503
+ }, { ...options, capture: true });
504
+ sheets({ root, document: document2, options, dismiss });
505
+ options.signal.addEventListener("abort", () => {
506
+ for (const [dialog, animation] of closing) {
507
+ animation.cancel();
508
+ delete dialog.dataset.b3Closing;
509
+ }
510
+ closing.clear();
511
+ }, { once: true });
512
+ root.addEventListener("pointerdown", (event) => {
513
+ const dialog = event.target;
514
+ backdropEnd = null;
515
+ backdropStart = event.isPrimary && event.button === 0 && dialog.matches?.('dialog[data-b3-backdrop="dismiss"]:modal') && outside(event, dialog) ? { dialog, pointerId: event.pointerId } : null;
516
+ }, options);
517
+ root.addEventListener("pointerup", (event) => {
518
+ const start = backdropStart;
519
+ backdropStart = null;
520
+ if (start && start.pointerId === event.pointerId && event.target === start.dialog && outside(event, start.dialog))
521
+ backdropEnd = start;
522
+ }, options);
523
+ root.addEventListener("pointercancel", () => {
524
+ backdropStart = null;
525
+ backdropEnd = null;
526
+ }, options);
527
+ root.addEventListener("click", (event) => {
528
+ const end = backdropEnd;
529
+ backdropEnd = null;
530
+ if (!end || event.target !== end.dialog || !outside(event, end.dialog))
531
+ return;
532
+ event.preventDefault();
533
+ event.stopImmediatePropagation();
534
+ dismiss(end.dialog);
535
+ }, { ...options, capture: true });
536
+ root.addEventListener("close", (event) => {
537
+ closing.get(event.target)?.cancel();
538
+ closing.delete(event.target);
539
+ delete event.target.dataset.b3Closing;
540
+ const opener = openers.get(event.target);
541
+ if (opener?.isConnected && !opener.disabled)
542
+ opener.focus();
543
+ openers.delete(event.target);
544
+ }, { ...options, capture: true });
545
+ root.addEventListener("click", (event) => {
546
+ const target = event.target.closest?.("[data-b3-open],[data-b3-close]");
547
+ if (!target || target.disabled)
548
+ return;
549
+ if (target.dataset.b3Open) {
550
+ const dialog = find(target.dataset.b3Open);
551
+ if (dialog?.tagName === "DIALOG") {
552
+ openers.set(dialog, target);
553
+ if (!dialog.open)
554
+ dialog.showModal();
555
+ }
556
+ }
557
+ if (target.hasAttribute("data-b3-close")) {
558
+ const dialog = target.closest("dialog");
559
+ if (dialog)
560
+ dismiss(dialog);
561
+ }
562
+ }, options);
563
+ }
564
+
565
+ // src/interactions/toasts.js
566
+ function toasts({ root, options }) {
567
+ root.addEventListener("click", (event) => {
568
+ const target = event.target.closest?.("[data-b3-dismiss]");
569
+ if (target && !target.disabled)
570
+ target.closest(".b3-toast")?.remove();
571
+ }, options);
572
+ }
573
+
574
+ // src/ui.js
575
+ function mount(root = document) {
576
+ const controller = new AbortController;
577
+ const options = { signal: controller.signal };
578
+ const document2 = root.ownerDocument || root;
579
+ const find = (id) => {
580
+ const element = document2.getElementById(id);
581
+ return element && (root === document2 || root.contains(element)) ? element : null;
582
+ };
583
+ const context = { root, document: document2, find, options };
584
+ tabs(context);
585
+ disclosures(context);
586
+ dialogs(context);
587
+ toasts(context);
588
+ outline(context);
589
+ commands(context);
590
+ return () => controller.abort();
591
+ }
592
+ export {
593
+ layout,
594
+ motion,
595
+ mount,
596
+ sequence,
597
+ settle
598
+ };
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@livx.cc/bare-v3",
3
+ "version": "0.1.0-alpha.10",
4
+ "type": "module",
5
+ "files": [
6
+ "dist",
7
+ "README.md"
8
+ ],
9
+ "exports": {
10
+ "./css": "./dist/bare.css",
11
+ "./css/min": "./dist/bare.min.css",
12
+ "./manifest": "./dist/manifest.json",
13
+ "./references/*": "./dist/references/*",
14
+ "./ui": "./dist/ui.js"
15
+ },
16
+ "scripts": {
17
+ "build": "bun scripts/build.ts",
18
+ "test": "bun test",
19
+ "lab": "bun lab/cli.ts",
20
+ "check:package": "bun scripts/check-package.ts",
21
+ "typecheck": "tsc"
22
+ },
23
+ "devDependencies": {
24
+ "@livx.cc/agentx": "0.99.42",
25
+ "@livx.cc/bare-v2": "3.0.0",
26
+ "@picocss/pico": "2.1.1",
27
+ "@tailwindcss/cli": "4.3.3",
28
+ "@types/bun": "1.4.2",
29
+ "ai.libx.js": "0.18.29",
30
+ "basecoat-css": "1.0.2",
31
+ "daisyui": "5.7.28",
32
+ "lightningcss": "1.33.0",
33
+ "lucide-static": "1.31.0",
34
+ "tailwindcss": "4.3.3",
35
+ "typescript": "7.0.2"
36
+ },
37
+ "publishConfig": {
38
+ "access": "public",
39
+ "tag": "alpha"
40
+ },
41
+ "license": "UNLICENSED",
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "git+https://github.com/Livshitz/bare-v3.git"
45
+ },
46
+ "description": "Experimental semantic CSS and optional interactions with compact LLM reference packs"
47
+ }