@sparklingopinions/sparkling-ui 0.16.0 → 0.17.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.
Files changed (37) hide show
  1. package/dist/aliases.d.ts +43 -30
  2. package/dist/aliases.js +9 -9
  3. package/dist/aliases.js.map +1 -1
  4. package/dist/components/ActionBar/ActionBar.js.map +1 -1
  5. package/dist/components/ActionBar/ActionBar.vue.d.ts +20 -2
  6. package/dist/components/ActionBar/ActionBar.vue_vue_type_script_setup_true_lang.js +106 -41
  7. package/dist/components/ActionBar/ActionBar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  8. package/dist/components/ActionBar/index.d.ts +1 -1
  9. package/dist/components/Board/Board.js.map +1 -1
  10. package/dist/components/Board/Board.vue_vue_type_script_setup_true_lang.js +80 -148
  11. package/dist/components/Board/Board.vue_vue_type_script_setup_true_lang.js.map +1 -1
  12. package/dist/components/ContextMenu/ContextMenu.vue.d.ts +4 -4
  13. package/dist/components/DataList/DataList.js.map +1 -1
  14. package/dist/components/DataList/DataList.vue.d.ts +7 -1
  15. package/dist/components/DataList/DataList.vue_vue_type_script_setup_true_lang.js +187 -147
  16. package/dist/components/DataList/DataList.vue_vue_type_script_setup_true_lang.js.map +1 -1
  17. package/dist/components/Dialog/Dialog.vue_vue_type_script_setup_true_lang.js +7 -7
  18. package/dist/components/Dialog/Dialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
  19. package/dist/components/DropdownMenu/DropdownMenu.vue.d.ts +2 -2
  20. package/dist/components/Filters/FilterChip.vue.d.ts +3 -3
  21. package/dist/components/Filters/FilterMenu.vue.d.ts +3 -3
  22. package/dist/components/Filters/SortMenu.vue.d.ts +3 -3
  23. package/dist/components/PropertyList/Editable.vue.d.ts +1 -1
  24. package/dist/components/Toast/ToastMessage.vue.d.ts +1 -1
  25. package/dist/components/Toast/Toaster.vue.d.ts +1 -1
  26. package/dist/components/internal/useDragMove.d.ts +50 -0
  27. package/dist/components/internal/useDragMove.js +132 -0
  28. package/dist/components/internal/useDragMove.js.map +1 -0
  29. package/dist/composables/toast.d.ts +12 -1
  30. package/dist/composables/toast.js +40 -21
  31. package/dist/composables/toast.js.map +1 -1
  32. package/dist/index.d.ts +2 -1
  33. package/dist/index.js +25 -24
  34. package/dist/utils/settle.d.ts +18 -0
  35. package/dist/utils/settle.js +24 -0
  36. package/dist/utils/settle.js.map +1 -0
  37. package/package.json +1 -1
@@ -0,0 +1,132 @@
1
+ import { onBeforeUnmount as e, ref as t } from "vue";
2
+ //#region src/components/internal/useDragMove.ts
3
+ var n = 4, r = 8, i = 250, a = 48;
4
+ function o(o) {
5
+ let c = t(null), l = t(null), u = null, d, f = null, p = null, m = {
6
+ x: 0,
7
+ y: 0
8
+ }, h = !1;
9
+ function g(e, t, n, r) {
10
+ let a = e.target;
11
+ if (e.button !== 0 || a.closest("input, textarea, select, [contenteditable], [data-no-drag]")) return;
12
+ let o = e.pointerType === "touch";
13
+ u = {
14
+ id: t,
15
+ zone: n,
16
+ index: r,
17
+ x: e.clientX,
18
+ y: e.clientY,
19
+ el: e.currentTarget,
20
+ touch: o
21
+ }, o && (d = window.setTimeout(() => u && _(), i)), window.addEventListener("pointermove", v), window.addEventListener("pointerup", S), window.addEventListener("pointercancel", T), window.addEventListener("touchmove", C, { passive: !1 }), window.addEventListener("keydown", w);
22
+ }
23
+ function _() {
24
+ if (!u) return;
25
+ let e = u.el.getBoundingClientRect(), t = Math.min(e.width, o.ghostMaxWidth ?? Infinity);
26
+ m = {
27
+ x: Math.min(u.x - e.left, t - 16),
28
+ y: u.y - e.top
29
+ }, f = u.el.cloneNode(!0), f.removeAttribute("id"), f.setAttribute("aria-hidden", "true"), Object.assign(f.style, {
30
+ position: "fixed",
31
+ top: "0",
32
+ left: "0",
33
+ margin: "0",
34
+ zIndex: "1300",
35
+ pointerEvents: "none",
36
+ width: `${t}px`,
37
+ overflow: "hidden",
38
+ height: `${e.height}px`,
39
+ opacity: "0.96",
40
+ borderRadius: "12px",
41
+ boxShadow: "var(--sui-shadow-floating)",
42
+ transition: "none",
43
+ ...o.ghostStyle
44
+ }), document.body.appendChild(f), p = s(o.root.value), y(u.x, u.y), c.value = {
45
+ id: u.id,
46
+ zone: u.zone,
47
+ index: u.index
48
+ };
49
+ }
50
+ function v(e) {
51
+ if (u) {
52
+ if (!c.value) {
53
+ let t = Math.hypot(e.clientX - u.x, e.clientY - u.y);
54
+ if (u.touch) return t > r ? T() : void 0;
55
+ if (t < n) return;
56
+ _();
57
+ }
58
+ e.preventDefault(), y(e.clientX, e.clientY), b(e.clientX, e.clientY), x(e.clientX, e.clientY);
59
+ }
60
+ }
61
+ function y(e, t) {
62
+ f && (f.style.transform = `translate(${e - m.x}px, ${t - m.y}px)${o.tilt === !1 ? "" : " rotate(1deg)"}`);
63
+ }
64
+ function b(e, t) {
65
+ let n = document.elementFromPoint(e, t), r = n?.closest("[data-drag-zone]");
66
+ if (!r || !o.root.value?.contains(r)) {
67
+ l.value = null;
68
+ return;
69
+ }
70
+ let i = r.dataset.dragZone, a = n.closest("[data-drag-index]"), s = o.countOf(i);
71
+ if (a && r.contains(a)) {
72
+ let e = a.getBoundingClientRect();
73
+ s = Number(a.dataset.dragIndex) + (t < e.top + e.height / 2 ? 0 : 1);
74
+ }
75
+ (l.value?.zone !== i || l.value.index !== s) && (l.value = {
76
+ zone: i,
77
+ index: s
78
+ });
79
+ }
80
+ function x(e, t) {
81
+ let n = document.elementFromPoint(e, t)?.closest("[data-drag-zone]");
82
+ if (n && n.scrollHeight > n.clientHeight) {
83
+ let e = n.getBoundingClientRect();
84
+ t < e.top + a ? n.scrollTop -= 12 : t > e.bottom - a && (n.scrollTop += 12);
85
+ }
86
+ let r = o.root.value;
87
+ if (r && r.scrollWidth > r.clientWidth) {
88
+ let t = r.getBoundingClientRect();
89
+ e < t.left + a ? r.scrollLeft -= 12 : e > t.right - a && (r.scrollLeft += 12);
90
+ }
91
+ if (p) {
92
+ let e = p.getBoundingClientRect();
93
+ t < e.top + a ? p.scrollTop -= 12 : t > e.bottom - a && (p.scrollTop += 12);
94
+ }
95
+ }
96
+ function S() {
97
+ let e = c.value, t = l.value;
98
+ if (e && t) {
99
+ let n = t.index;
100
+ e.zone === t.zone ? (n > e.index && n--, o.sortable?.() && n !== e.index && o.onMove(e.id, t.zone, n)) : o.onMove(e.id, t.zone, n);
101
+ }
102
+ T();
103
+ }
104
+ function C(e) {
105
+ c.value && e.preventDefault();
106
+ }
107
+ function w(e) {
108
+ e.key === "Escape" && c.value && (e.preventDefault(), T());
109
+ }
110
+ function T() {
111
+ window.clearTimeout(d), window.removeEventListener("pointermove", v), window.removeEventListener("pointerup", S), window.removeEventListener("pointercancel", T), window.removeEventListener("touchmove", C), window.removeEventListener("keydown", w), f?.remove(), f = null, p = null, c.value && (h = !0, window.setTimeout(() => h = !1)), u = null, c.value = null, l.value = null;
112
+ }
113
+ return e(T), {
114
+ dragged: c,
115
+ target: l,
116
+ onPointerDown: g,
117
+ endedDrag: () => h
118
+ };
119
+ }
120
+ function s(e) {
121
+ let t = e?.parentElement ?? null;
122
+ for (; t;) {
123
+ let e = getComputedStyle(t).overflowY;
124
+ if ((e === "auto" || e === "scroll") && t.scrollHeight > t.clientHeight) return t;
125
+ t = t.parentElement;
126
+ }
127
+ return null;
128
+ }
129
+ //#endregion
130
+ export { o as useDragMove };
131
+
132
+ //# sourceMappingURL=useDragMove.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDragMove.js","names":["MOUSE_SLOP","TOUCH_SLOP","TOUCH_DELAY","EDGE","useDragMove","dragged","ref","target","pending","pressTimer","ghost","scroller","grab","justDragged","onPointerDown","from","event","touch","start","onPointerMove","onPointerUp","stop","holdScroll","onEscape","rect","width","options","scrollParent","follow","moved","aim","scrollNear","x","y","under","zoneEl","zone","item","index","root","to","onBeforeUnmount","node","el","overflow"],"sources":["../../../src/components/internal/useDragMove.ts"],"sourcesContent":["import { type Ref, onBeforeUnmount, ref } from 'vue'\n\n/**\n * Dragging an item between zones (a Board's columns, a DataList's groups) on pointer events, so it works with a mouse,\n * a pen and a finger. A mouse drags once it moves a few pixels, so a click still clicks; a finger after a short press,\n * so a swipe still scrolls. A copy of the item follows the pointer; Escape puts it back.\n *\n * Zones carry `data-drag-zone=\"<id>\"` and items `data-drag-index=\"<i>\"` inside them.\n */\nexport interface DragMoveOptions {\n root: Ref<HTMLElement | null | undefined>\n /** How many items a zone holds, for a drop past its last one. */\n countOf: (zone: string) => number\n /** Items also reorder within their zone. */\n sortable?: () => boolean\n onMove: (id: unknown, zone: string, index: number) => void\n /** Extra inline style for the copy that follows the pointer, e.g. a ground for a row that has none of its own. */\n ghostStyle?: Partial<CSSStyleDeclaration>\n /** The copy's widest, so a full-width row follows the pointer as a compact line. */\n ghostMaxWidth?: number\n /** The copy leans a little, as a card picked up does; off for rows. */\n tilt?: boolean\n}\n\nconst MOUSE_SLOP = 4\nconst TOUCH_SLOP = 8\nconst TOUCH_DELAY = 250\nconst EDGE = 48\n\nexport function useDragMove(options: DragMoveOptions) {\n const dragged = ref<{ id: unknown; zone: string; index: number } | null>(null)\n const target = ref<{ zone: string; index: number } | null>(null)\n\n let pending: {\n id: unknown\n zone: string\n index: number\n x: number\n y: number\n el: HTMLElement\n touch: boolean\n } | null = null\n let pressTimer: number | undefined\n let ghost: HTMLElement | null = null\n let scroller: HTMLElement | null = null\n let grab = { x: 0, y: 0 }\n let justDragged = false\n\n function onPointerDown(event: PointerEvent, id: unknown, zone: string, index: number) {\n const from = event.target as HTMLElement\n if (event.button !== 0 || from.closest('input, textarea, select, [contenteditable], [data-no-drag]')) return\n const touch = event.pointerType === 'touch'\n pending = { id, zone, index, x: event.clientX, y: event.clientY, el: event.currentTarget as HTMLElement, touch }\n if (touch) pressTimer = window.setTimeout(() => pending && start(), TOUCH_DELAY)\n window.addEventListener('pointermove', onPointerMove)\n window.addEventListener('pointerup', onPointerUp)\n window.addEventListener('pointercancel', stop)\n window.addEventListener('touchmove', holdScroll, { passive: false })\n window.addEventListener('keydown', onEscape)\n }\n\n function start() {\n if (!pending) return\n const rect = pending.el.getBoundingClientRect()\n const width = Math.min(rect.width, options.ghostMaxWidth ?? Infinity)\n // Keep the grab point inside a narrowed copy.\n grab = { x: Math.min(pending.x - rect.left, width - 16), y: pending.y - rect.top }\n ghost = pending.el.cloneNode(true) as HTMLElement\n ghost.removeAttribute('id')\n ghost.setAttribute('aria-hidden', 'true')\n // Inline, so no class the item carries (`relative`, an app's own) can put the copy back in the page's flow.\n Object.assign(ghost.style, {\n position: 'fixed',\n top: '0',\n left: '0',\n margin: '0',\n zIndex: '1300',\n pointerEvents: 'none',\n width: `${width}px`,\n overflow: 'hidden',\n height: `${rect.height}px`,\n opacity: '0.96',\n borderRadius: '12px',\n boxShadow: 'var(--sui-shadow-floating)',\n transition: 'none',\n ...options.ghostStyle\n })\n document.body.appendChild(ghost)\n scroller = scrollParent(options.root.value)\n follow(pending.x, pending.y)\n dragged.value = { id: pending.id, zone: pending.zone, index: pending.index }\n }\n\n function onPointerMove(event: PointerEvent) {\n if (!pending) return\n if (!dragged.value) {\n const moved = Math.hypot(event.clientX - pending.x, event.clientY - pending.y)\n // A finger that moves before the press is long enough is scrolling.\n if (pending.touch) return moved > TOUCH_SLOP ? stop() : undefined\n if (moved < MOUSE_SLOP) return\n start()\n }\n event.preventDefault()\n follow(event.clientX, event.clientY)\n aim(event.clientX, event.clientY)\n scrollNear(event.clientX, event.clientY)\n }\n\n function follow(x: number, y: number) {\n if (ghost)\n ghost.style.transform = `translate(${x - grab.x}px, ${y - grab.y}px)${options.tilt === false ? '' : ' rotate(1deg)'}`\n }\n\n // What's under the pointer: an item's top half drops before it, the bottom half after; the rest of a zone, at its end.\n function aim(x: number, y: number) {\n const under = document.elementFromPoint(x, y)\n const zoneEl = under?.closest<HTMLElement>('[data-drag-zone]')\n if (!zoneEl || !options.root.value?.contains(zoneEl)) {\n target.value = null\n return\n }\n const zone = zoneEl.dataset.dragZone!\n const item = under!.closest<HTMLElement>('[data-drag-index]')\n let index = options.countOf(zone)\n if (item && zoneEl.contains(item)) {\n const rect = item.getBoundingClientRect()\n index = Number(item.dataset.dragIndex) + (y < rect.top + rect.height / 2 ? 0 : 1)\n }\n if (target.value?.zone !== zone || target.value.index !== index) target.value = { zone, index }\n }\n\n // Near the edges of a zone that scrolls, or of the page's scroller, it scrolls that way.\n function scrollNear(x: number, y: number) {\n const zoneEl = document.elementFromPoint(x, y)?.closest<HTMLElement>('[data-drag-zone]')\n if (zoneEl && zoneEl.scrollHeight > zoneEl.clientHeight) {\n const rect = zoneEl.getBoundingClientRect()\n if (y < rect.top + EDGE) zoneEl.scrollTop -= 12\n else if (y > rect.bottom - EDGE) zoneEl.scrollTop += 12\n }\n const root = options.root.value\n if (root && root.scrollWidth > root.clientWidth) {\n const rect = root.getBoundingClientRect()\n if (x < rect.left + EDGE) root.scrollLeft -= 12\n else if (x > rect.right - EDGE) root.scrollLeft += 12\n }\n if (scroller) {\n const rect = scroller.getBoundingClientRect()\n if (y < rect.top + EDGE) scroller.scrollTop -= 12\n else if (y > rect.bottom - EDGE) scroller.scrollTop += 12\n }\n }\n\n function onPointerUp() {\n const from = dragged.value\n const to = target.value\n if (from && to) {\n let index = to.index\n if (from.zone === to.zone) {\n // Within a zone the dragged item leaves its old slot first.\n if (index > from.index) index--\n if (options.sortable?.() && index !== from.index) options.onMove(from.id, to.zone, index)\n } else {\n options.onMove(from.id, to.zone, index)\n }\n }\n stop()\n }\n\n function holdScroll(event: TouchEvent) {\n if (dragged.value) event.preventDefault()\n }\n\n function onEscape(event: KeyboardEvent) {\n if (event.key === 'Escape' && dragged.value) {\n event.preventDefault()\n stop()\n }\n }\n\n function stop() {\n window.clearTimeout(pressTimer)\n window.removeEventListener('pointermove', onPointerMove)\n window.removeEventListener('pointerup', onPointerUp)\n window.removeEventListener('pointercancel', stop)\n window.removeEventListener('touchmove', holdScroll)\n window.removeEventListener('keydown', onEscape)\n ghost?.remove()\n ghost = null\n scroller = null\n // The click that ends a drag isn't a click on the item.\n if (dragged.value) {\n justDragged = true\n window.setTimeout(() => (justDragged = false))\n }\n pending = null\n dragged.value = null\n target.value = null\n }\n\n onBeforeUnmount(stop)\n\n return {\n dragged,\n target,\n onPointerDown,\n /** The click that ended a drag, to ignore. */\n endedDrag: () => justDragged\n }\n}\n\n/** The nearest ancestor that scrolls vertically, so a long list scrolls while dragging past its edge. */\nfunction scrollParent(el: HTMLElement | null | undefined): HTMLElement | null {\n let node = el?.parentElement ?? null\n while (node) {\n const overflow = getComputedStyle(node).overflowY\n if ((overflow === 'auto' || overflow === 'scroll') && node.scrollHeight > node.clientHeight) return node\n node = node.parentElement\n }\n return null\n}\n"],"mappings":"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"}
@@ -29,10 +29,21 @@ export declare function toastActions(options: Pick<ToastOptions, 'action' | 'act
29
29
  export declare const toasts: import("vue").ShallowReactive<ToastItem[]>;
30
30
  /** Closes a toast, then removes it once its closing animation has had time to play. */
31
31
  export declare function removeToast(id: number, reason?: ToastDismissReason): void;
32
- /** Shows a message in the app's <Toaster />: `toast.info('Saved')`. */
32
+ export interface UndoToastOptions extends Omit<ToastOptions, 'action' | 'actions' | 'onDismiss'> {
33
+ undoLabel?: string;
34
+ /** Shown once the undo worked. */
35
+ undoneLabel?: string;
36
+ /** Shown when the undo failed and the server gave no reason. */
37
+ failedLabel?: string;
38
+ }
39
+ /** A one-tap change's receipt with Undo, which runs only when pressed; a refused undo says why. */
40
+ declare function undo(summary: string, run?: (() => unknown) | null, options?: UndoToastOptions): void;
41
+ /** Shows a message in the app's <Toaster />: `toast.info('Saved')`; `toast.undo('Archived 3 loops', restore)`. */
33
42
  export declare const toast: {
43
+ undo: typeof undo;
34
44
  info: (summary: string, options?: ToastOptions) => void;
35
45
  success: (summary: string, options?: ToastOptions) => void;
36
46
  warning: (summary: string, options?: ToastOptions) => void;
37
47
  error: (summary: string, options?: ToastOptions) => void;
38
48
  };
49
+ export {};
@@ -1,40 +1,59 @@
1
- import { shallowReactive as e } from "vue";
1
+ import { errorMessage as e } from "../utils/settle.js";
2
+ import { shallowReactive as t } from "vue";
2
3
  //#region src/composables/toast.ts
3
- function t(e) {
4
+ function n(e) {
4
5
  return (e.actions ?? (e.action ? [e.action] : [])).slice(0, 2);
5
6
  }
6
- var n = e([]), r = 0;
7
- function i(e, i, a = {}) {
8
- let { action: o, ...s } = a, c = t(a);
9
- n.push({
7
+ var r = t([]), i = 0;
8
+ function a(e, t, a = {}) {
9
+ let { action: o, ...s } = a, c = n(a);
10
+ r.push({
10
11
  ...s,
11
12
  life: a.life ?? (c.length ? 6e3 : 3e3),
12
13
  actions: c,
13
- id: r++,
14
+ id: i++,
14
15
  severity: e,
15
- summary: i,
16
+ summary: t,
16
17
  open: !0
17
18
  });
18
19
  }
19
- function a(e, t = "close") {
20
- let r = n.findIndex((t) => t.id === e);
21
- if (r < 0 || !n[r].open) return;
22
- let i = n[r];
23
- n[r] = {
20
+ function o(e, t = "close") {
21
+ let n = r.findIndex((t) => t.id === e);
22
+ if (n < 0 || !r[n].open) return;
23
+ let i = r[n];
24
+ r[n] = {
24
25
  ...i,
25
26
  open: !1
26
27
  }, i.onDismiss?.(t), setTimeout(() => {
27
- let t = n.findIndex((t) => t.id === e);
28
- t >= 0 && n.splice(t, 1);
28
+ let t = r.findIndex((t) => t.id === e);
29
+ t >= 0 && r.splice(t, 1);
29
30
  }, 500);
30
31
  }
31
- var o = {
32
- info: (e, t) => i("info", e, t),
33
- success: (e, t) => i("success", e, t),
34
- warning: (e, t) => i("warning", e, t),
35
- error: (e, t) => i("error", e, t)
32
+ function s(t, n, r = {}) {
33
+ let { undoLabel: i = "Undo", undoneLabel: o = "Undone", failedLabel: s = "This can no longer be undone.", ...c } = r;
34
+ return n ? a("success", t, {
35
+ ...c,
36
+ action: {
37
+ label: i,
38
+ onClick: () => {}
39
+ },
40
+ onDismiss: async (t) => {
41
+ if (t === "action") try {
42
+ await n(), a("info", o);
43
+ } catch (t) {
44
+ a("error", e(t, s));
45
+ }
46
+ }
47
+ }) : a("success", t, c);
48
+ }
49
+ var c = {
50
+ undo: s,
51
+ info: (e, t) => a("info", e, t),
52
+ success: (e, t) => a("success", e, t),
53
+ warning: (e, t) => a("warning", e, t),
54
+ error: (e, t) => a("error", e, t)
36
55
  };
37
56
  //#endregion
38
- export { a as removeToast, o as toast, t as toastActions, n as toasts };
57
+ export { o as removeToast, c as toast, n as toastActions, r as toasts };
39
58
 
40
59
  //# sourceMappingURL=toast.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"toast.js","names":["toastActions","options","toasts","shallowReactive","nextId","add","_","rest","actions","removeToast","index","item","id","reason","at","toast","summary"],"sources":["../../src/composables/toast.ts"],"sourcesContent":["import { shallowReactive } from 'vue'\n\nexport type ToastSeverity = 'info' | 'success' | 'warning' | 'error'\n\n/** A button on the toast: pressing it runs `onClick`, then closes the toast. */\nexport interface ToastAction {\n label: string\n onClick: () => void\n}\n\n/** Why a toast left: one of its actions, its close button (or Escape), or its timer running out. */\nexport type ToastDismissReason = 'action' | 'close' | 'timeout'\n\nexport interface ToastOptions {\n /** A second line under the message. */\n detail?: string\n /** How long it stays, in ms; 0 keeps it until closed. 3000 by default, 6000 with an action. */\n life?: number\n closable?: boolean\n action?: ToastAction\n /** One or two; any more are ignored. */\n actions?: ToastAction[]\n onDismiss?: (reason: ToastDismissReason) => void\n}\n\nexport interface ToastItem extends Omit<ToastOptions, 'action'> {\n id: number\n severity: ToastSeverity\n summary: string\n actions: ToastAction[]\n open: boolean\n}\n\n/** A toast's actions, from `action` or `actions`, at most two. */\nexport function toastActions(options: Pick<ToastOptions, 'action' | 'actions'>): ToastAction[] {\n return (options.actions ?? (options.action ? [options.action] : [])).slice(0, 2)\n}\n\n// The messages one <Toaster /> near the app root shows.\nexport const toasts = shallowReactive<ToastItem[]>([])\n\nlet nextId = 0\n\nfunction add(severity: ToastSeverity, summary: string, options: ToastOptions = {}) {\n const { action: _, ...rest } = options\n const actions = toastActions(options)\n toasts.push({\n ...rest,\n life: options.life ?? (actions.length ? 6000 : 3000),\n actions,\n id: nextId++,\n severity,\n summary,\n open: true\n })\n}\n\n/** Closes a toast, then removes it once its closing animation has had time to play. */\nexport function removeToast(id: number, reason: ToastDismissReason = 'close') {\n const index = toasts.findIndex((item) => item.id === id)\n if (index < 0 || !toasts[index]!.open) return\n const item = toasts[index]!\n toasts[index] = { ...item, open: false }\n item.onDismiss?.(reason)\n setTimeout(() => {\n const at = toasts.findIndex((item) => item.id === id)\n if (at >= 0) toasts.splice(at, 1)\n }, 500)\n}\n\n/** Shows a message in the app's <Toaster />: `toast.info('Saved')`. */\nexport const toast = {\n info: (summary: string, options?: ToastOptions) => add('info', summary, options),\n success: (summary: string, options?: ToastOptions) => add('success', summary, options),\n warning: (summary: string, options?: ToastOptions) => add('warning', summary, options),\n error: (summary: string, options?: ToastOptions) => add('error', summary, options)\n}\n"],"mappings":";;AAkCA,SAAgBA,EAAa,GAAkE;CAC7F,QAAQC,EAAQ,YAAYA,EAAQ,SAAS,CAACA,EAAQ,MAAM,IAAI,CAAC,GAAA,CAAI,MAAM,GAAG,CAAC;AACjF;AAGA,IAAaC,IAASC,EAA6B,CAAC,CAAC,GAEjDC,IAAS;AAEb,SAASC,EAAI,GAAyB,GAAiB,IAAwB,CAAC,GAAG;CACjF,IAAM,EAAE,QAAQC,GAAG,GAAGC,MAASN,GACzBO,IAAUR,EAAaC,CAAO;CACpC,EAAO,KAAK;EACV,GAAGM;EACH,MAAMN,EAAQ,SAASO,EAAQ,SAAS,MAAO;EAC/C;EACA,IAAI;EACJ;EACA;EACA,MAAM;CACR,CAAC;AACH;AAGA,SAAgBC,EAAY,GAAY,IAA6B,SAAS;CAC5E,IAAMC,IAAQR,EAAO,WAAW,MAASS,EAAK,OAAOC,CAAE;CACvD,IAAIF,IAAQ,KAAK,CAACR,EAAOQ,EAAM,CAAE,MAAM;CACvC,IAAMC,IAAOT,EAAOQ;CAGpB,AAFA,EAAOA,KAAS;EAAE,GAAGC;EAAM,MAAM;CAAM,GACvCA,EAAK,YAAYE,CAAM,GACvB,iBAAiB;EACf,IAAMC,IAAKZ,EAAO,WAAW,MAASS,EAAK,OAAOC,CAAE;EACpD,AAAIE,KAAM,KAAGZ,EAAO,OAAOY,GAAI,CAAC;CAClC,GAAG,GAAG;AACR;AAGA,IAAaC,IAAQ;CACnB,OAAO,GAAiB,MAA2BV,EAAI,QAAQW,GAASf,CAAO;CAC/E,UAAU,GAAiB,MAA2BI,EAAI,WAAWW,GAASf,CAAO;CACrF,UAAU,GAAiB,MAA2BI,EAAI,WAAWW,GAASf,CAAO;CACrF,QAAQ,GAAiB,MAA2BI,EAAI,SAASW,GAASf,CAAO;AACnF"}
1
+ {"version":3,"file":"toast.js","names":["toastActions","options","toasts","shallowReactive","nextId","add","_","rest","actions","removeToast","index","item","id","reason","at","undo","run","summary","undoLabel","undoneLabel","error","errorMessage","failedLabel","toast"],"sources":["../../src/composables/toast.ts"],"sourcesContent":["import { shallowReactive } from 'vue'\n\nimport { errorMessage } from '../utils/settle'\n\nexport type ToastSeverity = 'info' | 'success' | 'warning' | 'error'\n\n/** A button on the toast: pressing it runs `onClick`, then closes the toast. */\nexport interface ToastAction {\n label: string\n onClick: () => void\n}\n\n/** Why a toast left: one of its actions, its close button (or Escape), or its timer running out. */\nexport type ToastDismissReason = 'action' | 'close' | 'timeout'\n\nexport interface ToastOptions {\n /** A second line under the message. */\n detail?: string\n /** How long it stays, in ms; 0 keeps it until closed. 3000 by default, 6000 with an action. */\n life?: number\n closable?: boolean\n action?: ToastAction\n /** One or two; any more are ignored. */\n actions?: ToastAction[]\n onDismiss?: (reason: ToastDismissReason) => void\n}\n\nexport interface ToastItem extends Omit<ToastOptions, 'action'> {\n id: number\n severity: ToastSeverity\n summary: string\n actions: ToastAction[]\n open: boolean\n}\n\n/** A toast's actions, from `action` or `actions`, at most two. */\nexport function toastActions(options: Pick<ToastOptions, 'action' | 'actions'>): ToastAction[] {\n return (options.actions ?? (options.action ? [options.action] : [])).slice(0, 2)\n}\n\n// The messages one <Toaster /> near the app root shows.\nexport const toasts = shallowReactive<ToastItem[]>([])\n\nlet nextId = 0\n\nfunction add(severity: ToastSeverity, summary: string, options: ToastOptions = {}) {\n const { action: _, ...rest } = options\n const actions = toastActions(options)\n toasts.push({\n ...rest,\n life: options.life ?? (actions.length ? 6000 : 3000),\n actions,\n id: nextId++,\n severity,\n summary,\n open: true\n })\n}\n\n/** Closes a toast, then removes it once its closing animation has had time to play. */\nexport function removeToast(id: number, reason: ToastDismissReason = 'close') {\n const index = toasts.findIndex((item) => item.id === id)\n if (index < 0 || !toasts[index]!.open) return\n const item = toasts[index]!\n toasts[index] = { ...item, open: false }\n item.onDismiss?.(reason)\n setTimeout(() => {\n const at = toasts.findIndex((item) => item.id === id)\n if (at >= 0) toasts.splice(at, 1)\n }, 500)\n}\n\nexport interface UndoToastOptions extends Omit<ToastOptions, 'action' | 'actions' | 'onDismiss'> {\n undoLabel?: string\n /** Shown once the undo worked. */\n undoneLabel?: string\n /** Shown when the undo failed and the server gave no reason. */\n failedLabel?: string\n}\n\n/** A one-tap change's receipt with Undo, which runs only when pressed; a refused undo says why. */\nfunction undo(summary: string, run?: (() => unknown) | null, options: UndoToastOptions = {}) {\n const { undoLabel = 'Undo', undoneLabel = 'Undone', failedLabel = 'This can no longer be undone.', ...rest } = options\n if (!run) return add('success', summary, rest)\n return add('success', summary, {\n ...rest,\n action: { label: undoLabel, onClick: () => {} },\n onDismiss: async (reason) => {\n if (reason !== 'action') return\n try {\n await run()\n add('info', undoneLabel)\n } catch (error) {\n add('error', errorMessage(error, failedLabel))\n }\n }\n })\n}\n\n/** Shows a message in the app's <Toaster />: `toast.info('Saved')`; `toast.undo('Archived 3 loops', restore)`. */\nexport const toast = {\n undo,\n info: (summary: string, options?: ToastOptions) => add('info', summary, options),\n success: (summary: string, options?: ToastOptions) => add('success', summary, options),\n warning: (summary: string, options?: ToastOptions) => add('warning', summary, options),\n error: (summary: string, options?: ToastOptions) => add('error', summary, options)\n}\n"],"mappings":";;;AAoCA,SAAgBA,EAAa,GAAkE;CAC7F,QAAQC,EAAQ,YAAYA,EAAQ,SAAS,CAACA,EAAQ,MAAM,IAAI,CAAC,GAAA,CAAI,MAAM,GAAG,CAAC;AACjF;AAGA,IAAaC,IAASC,EAA6B,CAAC,CAAC,GAEjDC,IAAS;AAEb,SAASC,EAAI,GAAyB,GAAiB,IAAwB,CAAC,GAAG;CACjF,IAAM,EAAE,QAAQC,GAAG,GAAGC,MAASN,GACzBO,IAAUR,EAAaC,CAAO;CACpC,EAAO,KAAK;EACV,GAAGM;EACH,MAAMN,EAAQ,SAASO,EAAQ,SAAS,MAAO;EAC/C;EACA,IAAI;EACJ;EACA;EACA,MAAM;CACR,CAAC;AACH;AAGA,SAAgBC,EAAY,GAAY,IAA6B,SAAS;CAC5E,IAAMC,IAAQR,EAAO,WAAW,MAASS,EAAK,OAAOC,CAAE;CACvD,IAAIF,IAAQ,KAAK,CAACR,EAAOQ,EAAM,CAAE,MAAM;CACvC,IAAMC,IAAOT,EAAOQ;CAGpB,AAFA,EAAOA,KAAS;EAAE,GAAGC;EAAM,MAAM;CAAM,GACvCA,EAAK,YAAYE,CAAM,GACvB,iBAAiB;EACf,IAAMC,IAAKZ,EAAO,WAAW,MAASS,EAAK,OAAOC,CAAE;EACpD,AAAIE,KAAM,KAAGZ,EAAO,OAAOY,GAAI,CAAC;CAClC,GAAG,GAAG;AACR;AAWA,SAASC,EAAK,GAAiB,GAA8B,IAA4B,CAAC,GAAG;CAC3F,IAAM,EAAE,eAAY,QAAQ,iBAAc,UAAU,iBAAc,iCAAiC,GAAGR,MAASN;CAE/G,OADKe,IACEX,EAAI,WAAWY,GAAS;EAC7B,GAAGV;EACH,QAAQ;GAAE,OAAOW;GAAW,eAAe,CAAC;EAAE;EAC9C,WAAW,OAAO,MAAW;GAC3B,IAAIL,MAAW,UACf,IAAI;IAEF,AADA,MAAMG,EAAI,GACVX,EAAI,QAAQc,CAAW;GACzB,SAASC,GAAO;IACd,EAAI,SAASC,EAAaD,GAAOE,CAAW,CAAC;GAC/C;EACF;CACF,CAAC,IAbgBjB,EAAI,WAAWY,GAASV,CAAI;AAc/C;AAGA,IAAagB,IAAQ;CACnB;CACA,OAAO,GAAiB,MAA2BlB,EAAI,QAAQY,GAAShB,CAAO;CAC/E,UAAU,GAAiB,MAA2BI,EAAI,WAAWY,GAAShB,CAAO;CACrF,UAAU,GAAiB,MAA2BI,EAAI,WAAWY,GAAShB,CAAO;CACrF,QAAQ,GAAiB,MAA2BI,EAAI,SAASY,GAAShB,CAAO;AACnF"}
package/dist/index.d.ts CHANGED
@@ -38,7 +38,8 @@ export * from './components/Toolbar';
38
38
  export * from './components/Tooltip';
39
39
  export * from './components/TypingIndicator';
40
40
  export { hueFor, type Hue } from './utils/hues';
41
+ export { errorMessage, settleEach, type Refusal } from './utils/settle';
41
42
  export { initColorMode, useColorMode, useForceLightMode, type ColorMode } from './composables/useColorMode';
42
- export { toast, type ToastAction, type ToastDismissReason, type ToastOptions, type ToastSeverity } from './composables/toast';
43
+ export { toast, type ToastAction, type ToastDismissReason, type ToastOptions, type ToastSeverity, type UndoToastOptions } from './composables/toast';
43
44
  export { useConfirm, type ConfirmOptions } from './composables/useConfirm';
44
45
  export * from './aliases';
package/dist/index.js CHANGED
@@ -2,23 +2,23 @@ import e from "./components/Button/Button.js";
2
2
  import { iconNames as t, setIconResolver as n } from "./components/Icon/resolver.js";
3
3
  import r from "./components/Icon/Icon.js";
4
4
  import i from "./components/Tooltip/Tooltip.js";
5
- import a from "./components/ActionBar/ActionBar.js";
6
- import o from "./components/Alert/Alert.js";
7
- import { useConfirm as s } from "./composables/useConfirm.js";
8
- import c from "./components/AlertDialog/AlertDialog.js";
9
- import { hueFor as l } from "./utils/hues.js";
10
- import u from "./components/Avatar/Avatar.js";
11
- import d from "./components/Badge/Badge.js";
12
- import f from "./components/Skeleton/Skeleton.js";
13
- import p from "./components/Board/Board.js";
14
- import m from "./components/Calendar/Calendar.js";
15
- import h from "./components/Checkbox/Checkbox.js";
16
- import g from "./components/ContextMenu/ContextMenu.js";
17
- import _ from "./components/DataList/DataList.js";
18
- import v from "./components/Kbd/Kbd.js";
19
- import { saveHint as y } from "./components/Dialog/focus.js";
20
- import b from "./components/Dialog/Dialog.js";
21
- import x from "./components/DropdownMenu/DropdownMenu.js";
5
+ import { useConfirm as a } from "./composables/useConfirm.js";
6
+ import o from "./components/DropdownMenu/DropdownMenu.js";
7
+ import s from "./components/Kbd/Kbd.js";
8
+ import c from "./components/ActionBar/ActionBar.js";
9
+ import l from "./components/Alert/Alert.js";
10
+ import u from "./components/AlertDialog/AlertDialog.js";
11
+ import { hueFor as d } from "./utils/hues.js";
12
+ import f from "./components/Avatar/Avatar.js";
13
+ import p from "./components/Badge/Badge.js";
14
+ import m from "./components/Skeleton/Skeleton.js";
15
+ import h from "./components/Board/Board.js";
16
+ import g from "./components/Calendar/Calendar.js";
17
+ import _ from "./components/Checkbox/Checkbox.js";
18
+ import v from "./components/ContextMenu/ContextMenu.js";
19
+ import y from "./components/DataList/DataList.js";
20
+ import { saveHint as b } from "./components/Dialog/focus.js";
21
+ import x from "./components/Dialog/Dialog.js";
22
22
  import S from "./components/EmptyState/EmptyState.js";
23
23
  import C from "./components/ErrorSummary/ErrorSummary.js";
24
24
  import w from "./components/Input/Input.js";
@@ -44,10 +44,11 @@ import K from "./components/PropertyRow/Collapsible.js";
44
44
  import q from "./components/PropertyRow/PropertyRow.js";
45
45
  import J from "./components/Radio/Radio.js";
46
46
  import Y from "./components/Table/Table.js";
47
- import { toast as X } from "./composables/toast.js";
48
- import Z from "./components/Toast/Toaster.js";
49
- import Q from "./components/Toolbar/Toolbar.js";
50
- import $ from "./components/TypingIndicator/TypingIndicator.js";
51
- import { initColorMode as ee, useColorMode as te, useForceLightMode as ne } from "./composables/useColorMode.js";
52
- import { Banner as re, BulkActions as ie, CalendarMonth as ae, Chip as oe, ConfirmDialog as se, Field as ce, FilterFieldPicker as le, FormErrors as ue, ImageInput as de, InlineField as fe, InlineForm as pe, LedgerMore as me, LedgerRow as he, List as ge, Modal as _e, OptionsMenu as ve, Pill as ye, SortControl as be, TextInput as xe, TypingDots as Se } from "./aliases.js";
53
- export { a as ActionBar, o as Alert, c as AlertDialog, u as Avatar, d as Badge, re as Banner, p as Board, ie as BulkActions, e as Button, m as Calendar, ae as CalendarMonth, h as Checkbox, oe as Chip, K as Collapsible, se as ConfirmDialog, g as ContextMenu, _ as DataList, b as Dialog, x as DropdownMenu, W as Editable, S as EmptyState, C as ErrorSummary, ce as Field, A as FilterChip, le as FilterFieldPicker, j as FilterMenu, ue as FormErrors, N as FormField, r as Icon, de as ImageInput, P as ImageUpload, fe as InlineField, pe as InlineForm, w as Input, v as Kbd, me as LedgerMore, he as LedgerRow, ge as List, F as Meter, _e as Modal, ve as OptionsMenu, I as Pagination, ye as Pill, L as Popover, R as PopoverDialog, z as PricingCard, G as PropertyList, q as PropertyRow, J as Radio, T as SegmentedControl, H as Select, f as Skeleton, be as SortControl, M as SortMenu, B as Spinner, Y as Table, V as Tag, xe as TextInput, U as Textarea, Z as Toaster, Q as Toolbar, i as Tooltip, Se as TypingDots, $ as TypingIndicator, E as datePresets, D as describeFilter, O as filterOperators, l as hueFor, t as iconNames, ee as initColorMode, y as saveHint, n as setIconResolver, k as sortDirections, X as toast, te as useColorMode, s as useConfirm, ne as useForceLightMode };
47
+ import { errorMessage as X, settleEach as Z } from "./utils/settle.js";
48
+ import { toast as Q } from "./composables/toast.js";
49
+ import $ from "./components/Toast/Toaster.js";
50
+ import ee from "./components/Toolbar/Toolbar.js";
51
+ import te from "./components/TypingIndicator/TypingIndicator.js";
52
+ import { initColorMode as ne, useColorMode as re, useForceLightMode as ie } from "./composables/useColorMode.js";
53
+ import { Banner as ae, BulkActions as oe, CalendarMonth as se, Chip as ce, ConfirmDialog as le, Field as ue, FilterFieldPicker as de, FormErrors as fe, ImageInput as pe, InlineField as me, InlineForm as he, LedgerMore as ge, LedgerRow as _e, List as ve, Modal as ye, OptionsMenu as be, Pill as xe, SortControl as Se, TextInput as Ce, TypingDots as we } from "./aliases.js";
54
+ export { c as ActionBar, l as Alert, u as AlertDialog, f as Avatar, p as Badge, ae as Banner, h as Board, oe as BulkActions, e as Button, g as Calendar, se as CalendarMonth, _ as Checkbox, ce as Chip, K as Collapsible, le as ConfirmDialog, v as ContextMenu, y as DataList, x as Dialog, o as DropdownMenu, W as Editable, S as EmptyState, C as ErrorSummary, ue as Field, A as FilterChip, de as FilterFieldPicker, j as FilterMenu, fe as FormErrors, N as FormField, r as Icon, pe as ImageInput, P as ImageUpload, me as InlineField, he as InlineForm, w as Input, s as Kbd, ge as LedgerMore, _e as LedgerRow, ve as List, F as Meter, ye as Modal, be as OptionsMenu, I as Pagination, xe as Pill, L as Popover, R as PopoverDialog, z as PricingCard, G as PropertyList, q as PropertyRow, J as Radio, T as SegmentedControl, H as Select, m as Skeleton, Se as SortControl, M as SortMenu, B as Spinner, Y as Table, V as Tag, Ce as TextInput, U as Textarea, $ as Toaster, ee as Toolbar, i as Tooltip, we as TypingDots, te as TypingIndicator, E as datePresets, D as describeFilter, X as errorMessage, O as filterOperators, d as hueFor, t as iconNames, ne as initColorMode, b as saveHint, n as setIconResolver, Z as settleEach, k as sortDirections, Q as toast, re as useColorMode, a as useConfirm, ie as useForceLightMode };
@@ -0,0 +1,18 @@
1
+ /** A record an action couldn't change, and why, in the words the server gave. */
2
+ export interface Refusal<T> {
3
+ item: T;
4
+ message: string;
5
+ }
6
+ /** The server's reason, from an error shaped like a failed fetch or axios request; else the fallback. */
7
+ export declare function errorMessage(error: unknown, fallback?: string): string;
8
+ /**
9
+ * Runs an action on each record, all at once, and sorts out what happened: the ones done, with their results, and the
10
+ * ones refused, with their reasons. For a bulk action without a bulk endpoint; nothing stops on the first refusal.
11
+ */
12
+ export declare function settleEach<T, R>(items: T[], run: (item: T) => Promise<R>, messageOf?: (error: unknown) => string): Promise<{
13
+ done: {
14
+ item: T;
15
+ result: R;
16
+ }[];
17
+ refused: Refusal<T>[];
18
+ }>;
@@ -0,0 +1,24 @@
1
+ //#region src/utils/settle.ts
2
+ function e(e, t = "This couldn’t be changed.") {
3
+ let n = e?.response?.data;
4
+ return typeof n?.message == "string" && n.message.trim() ? n.message : e instanceof Error && e.message && !/^Request failed/.test(e.message) ? e.message : t;
5
+ }
6
+ async function t(t, n, r = (t) => e(t)) {
7
+ let i = await Promise.allSettled(t.map((e) => n(e))), a = [], o = [];
8
+ return i.forEach((e, n) => {
9
+ e.status === "fulfilled" ? a.push({
10
+ item: t[n],
11
+ result: e.value
12
+ }) : o.push({
13
+ item: t[n],
14
+ message: r(e.reason)
15
+ });
16
+ }), {
17
+ done: a,
18
+ refused: o
19
+ };
20
+ }
21
+ //#endregion
22
+ export { e as errorMessage, t as settleEach };
23
+
24
+ //# sourceMappingURL=settle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settle.js","names":["errorMessage","data","error","fallback","settleEach","outcomes","items","run","item","done","refused","outcome","i","messageOf"],"sources":["../../src/utils/settle.ts"],"sourcesContent":["/** A record an action couldn't change, and why, in the words the server gave. */\nexport interface Refusal<T> {\n item: T\n message: string\n}\n\n/** The server's reason, from an error shaped like a failed fetch or axios request; else the fallback. */\nexport function errorMessage(error: unknown, fallback = 'This couldn’t be changed.'): string {\n const data = (error as { response?: { data?: { message?: unknown } } })?.response?.data\n if (typeof data?.message === 'string' && data.message.trim()) return data.message\n if (error instanceof Error && error.message && !/^Request failed/.test(error.message)) return error.message\n return fallback\n}\n\n/**\n * Runs an action on each record, all at once, and sorts out what happened: the ones done, with their results, and the\n * ones refused, with their reasons. For a bulk action without a bulk endpoint; nothing stops on the first refusal.\n */\nexport async function settleEach<T, R>(\n items: T[],\n run: (item: T) => Promise<R>,\n messageOf: (error: unknown) => string = (error) => errorMessage(error)\n): Promise<{ done: { item: T; result: R }[]; refused: Refusal<T>[] }> {\n const outcomes = await Promise.allSettled(items.map((item) => run(item)))\n const done: { item: T; result: R }[] = []\n const refused: Refusal<T>[] = []\n outcomes.forEach((outcome, i) => {\n if (outcome.status === 'fulfilled') done.push({ item: items[i]!, result: outcome.value })\n else refused.push({ item: items[i]!, message: messageOf(outcome.reason) })\n })\n return { done, refused }\n}\n"],"mappings":";AAOA,SAAgBA,EAAa,GAAgB,IAAW,6BAAqC;CAC3F,IAAMC,IAAQC,GAA2D,UAAU;CAGnF,OAFI,OAAOD,GAAM,WAAY,YAAYA,EAAK,QAAQ,KAAK,IAAUA,EAAK,UACtEC,aAAiB,SAASA,EAAM,WAAW,CAAC,kBAAkB,KAAKA,EAAM,OAAO,IAAUA,EAAM,UAC7FC;AACT;AAMA,eAAsBC,EACpB,GACA,GACA,KAAyC,MAAUJ,EAAaE,CAAK,GACD;CACpE,IAAMG,IAAW,MAAM,QAAQ,WAAWC,EAAM,KAAK,MAASC,EAAIC,CAAI,CAAC,CAAC,GAClEC,IAAiC,CAAC,GAClCC,IAAwB,CAAC;CAK/B,OAJAL,EAAS,SAAS,GAAS,MAAM;EAC/B,AAAIM,EAAQ,WAAW,cAAaF,EAAK,KAAK;GAAE,MAAMH,EAAMM;GAAK,QAAQD,EAAQ;EAAM,CAAC,IACnFD,EAAQ,KAAK;GAAE,MAAMJ,EAAMM;GAAK,SAASC,EAAUF,EAAQ,MAAM;EAAE,CAAC;CAC3E,CAAC,GACM;EAAE;EAAM;CAAQ;AACzB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sparklingopinions/sparkling-ui",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "description": "A product-agnostic Vue 3 component library, themed by semantic tokens",
5
5
  "type": "module",
6
6
  "license": "MIT",