blessing-ui 0.1.0 → 0.2.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 (96) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +65 -43
  3. package/dist/blessing-ui.css +60 -0
  4. package/dist/components/BlessCodeBlock.css +1 -0
  5. package/dist/components/BlessCodeBlock.js +6 -0
  6. package/dist/components/BlessCodeBlock.vue.d.ts +62 -0
  7. package/dist/components/BlessCodeBlock.vue_vue_type_script_setup_true_lang.js +134 -0
  8. package/dist/components/BlessCountUp.css +1 -0
  9. package/dist/components/BlessCountUp.js +6 -0
  10. package/dist/components/BlessCountUp.vue.d.ts +18 -0
  11. package/dist/components/BlessCountUp.vue_vue_type_script_setup_true_lang.js +49 -0
  12. package/dist/components/BlessCropper.css +1 -0
  13. package/dist/components/BlessCropper.js +6 -0
  14. package/dist/components/BlessCropper.vue.d.ts +54 -0
  15. package/dist/components/BlessCropper.vue_vue_type_script_setup_true_lang.js +212 -0
  16. package/dist/components/BlessDiff.css +1 -0
  17. package/dist/components/BlessDiff.js +6 -0
  18. package/dist/components/BlessDiff.vue.d.ts +22 -0
  19. package/dist/components/BlessDiff.vue_vue_type_script_setup_true_lang.js +148 -0
  20. package/dist/components/BlessGantt.css +1 -0
  21. package/dist/components/BlessGantt.js +6 -0
  22. package/dist/components/BlessGantt.vue.d.ts +69 -0
  23. package/dist/components/BlessGantt.vue_vue_type_script_setup_true_lang.js +270 -0
  24. package/dist/components/BlessGauge.css +1 -0
  25. package/dist/components/BlessGauge.js +6 -0
  26. package/dist/components/BlessGauge.vue.d.ts +36 -0
  27. package/dist/components/BlessGauge.vue_vue_type_script_setup_true_lang.js +100 -0
  28. package/dist/components/BlessHeatmapCalendar.css +1 -0
  29. package/dist/components/BlessHeatmapCalendar.js +6 -0
  30. package/dist/components/BlessHeatmapCalendar.vue.d.ts +38 -0
  31. package/dist/components/BlessHeatmapCalendar.vue_vue_type_script_setup_true_lang.js +146 -0
  32. package/dist/components/BlessHotspots.css +1 -0
  33. package/dist/components/BlessHotspots.js +6 -0
  34. package/dist/components/BlessHotspots.vue.d.ts +49 -0
  35. package/dist/components/BlessHotspots.vue_vue_type_script_setup_true_lang.js +127 -0
  36. package/dist/components/BlessKanban.css +1 -0
  37. package/dist/components/BlessKanban.js +6 -0
  38. package/dist/components/BlessKanban.vue.d.ts +55 -0
  39. package/dist/components/BlessKanban.vue_vue_type_script_setup_true_lang.js +165 -0
  40. package/dist/components/BlessLoupe.css +1 -0
  41. package/dist/components/BlessLoupe.js +6 -0
  42. package/dist/components/BlessLoupe.vue.d.ts +16 -0
  43. package/dist/components/BlessLoupe.vue_vue_type_script_setup_true_lang.js +93 -0
  44. package/dist/components/BlessMarquee.css +1 -0
  45. package/dist/components/BlessMarquee.js +6 -0
  46. package/dist/components/BlessMarquee.vue.d.ts +40 -0
  47. package/dist/components/BlessMarquee.vue_vue_type_script_setup_true_lang.js +64 -0
  48. package/dist/components/BlessMasonry.css +1 -0
  49. package/dist/components/BlessMasonry.js +6 -0
  50. package/dist/components/BlessMasonry.vue.d.ts +33 -0
  51. package/dist/components/BlessMasonry.vue_vue_type_script_setup_true_lang.js +79 -0
  52. package/dist/components/BlessMention.css +1 -0
  53. package/dist/components/BlessMention.js +6 -0
  54. package/dist/components/BlessMention.vue.d.ts +32 -0
  55. package/dist/components/BlessMention.vue_vue_type_script_setup_true_lang.js +116 -0
  56. package/dist/components/BlessRadialMenu.css +1 -0
  57. package/dist/components/BlessRadialMenu.js +6 -0
  58. package/dist/components/BlessRadialMenu.vue.d.ts +45 -0
  59. package/dist/components/BlessRadialMenu.vue_vue_type_script_setup_true_lang.js +146 -0
  60. package/dist/components/BlessShortcutRecorder.css +1 -0
  61. package/dist/components/BlessShortcutRecorder.js +6 -0
  62. package/dist/components/BlessShortcutRecorder.vue.d.ts +29 -0
  63. package/dist/components/BlessShortcutRecorder.vue_vue_type_script_setup_true_lang.js +116 -0
  64. package/dist/components/BlessSliderCaptcha.css +1 -0
  65. package/dist/components/BlessSliderCaptcha.js +6 -0
  66. package/dist/components/BlessSliderCaptcha.vue.d.ts +33 -0
  67. package/dist/components/BlessSliderCaptcha.vue_vue_type_script_setup_true_lang.js +141 -0
  68. package/dist/components/BlessSortable.css +1 -0
  69. package/dist/components/BlessSortable.js +6 -0
  70. package/dist/components/BlessSortable.vue.d.ts +33 -0
  71. package/dist/components/BlessSortable.vue_vue_type_script_setup_true_lang.js +87 -0
  72. package/dist/components/BlessSplitView.css +1 -0
  73. package/dist/components/BlessSplitView.js +6 -0
  74. package/dist/components/BlessSplitView.vue.d.ts +61 -0
  75. package/dist/components/BlessSplitView.vue_vue_type_script_setup_true_lang.js +92 -0
  76. package/dist/components/BlessSwipeDeck.css +1 -0
  77. package/dist/components/BlessSwipeDeck.js +6 -0
  78. package/dist/components/BlessSwipeDeck.vue.d.ts +46 -0
  79. package/dist/components/BlessSwipeDeck.vue_vue_type_script_setup_true_lang.js +199 -0
  80. package/dist/components/BlessTimer.css +1 -0
  81. package/dist/components/BlessTimer.js +6 -0
  82. package/dist/components/BlessTimer.vue.d.ts +56 -0
  83. package/dist/components/BlessTimer.vue_vue_type_script_setup_true_lang.js +130 -0
  84. package/dist/composables/cropBox.d.ts +22 -0
  85. package/dist/composables/cropBox.js +39 -0
  86. package/dist/composables/diffLines.d.ts +10 -0
  87. package/dist/composables/diffLines.js +55 -0
  88. package/dist/composables/radial.d.ts +15 -0
  89. package/dist/composables/radial.js +22 -0
  90. package/dist/composables/shortcut.d.ts +12 -0
  91. package/dist/composables/shortcut.js +35 -0
  92. package/dist/composables/useSortable.d.ts +18 -0
  93. package/dist/composables/useSortable.js +34 -0
  94. package/dist/index.d.ts +37 -0
  95. package/dist/index.js +78 -53
  96. package/package.json +20 -18
@@ -0,0 +1,146 @@
1
+ import { logicalKey as e } from "../composables/rtl.js";
2
+ import { keepInside as t, polar as n, sectorAt as r } from "../composables/radial.js";
3
+ import { Fragment as i, computed as a, createElementBlock as o, createElementVNode as s, createTextVNode as c, defineComponent as l, mergeModels as u, mergeProps as d, nextTick as f, normalizeClass as p, normalizeStyle as m, onBeforeUnmount as h, openBlock as g, ref as _, renderList as v, renderSlot as y, toDisplayString as b, unref as x, useId as S, useModel as C, watch as w, withModifiers as T } from "vue";
4
+ //#region src/components/BlessRadialMenu.vue?vue&type=script&setup=true&lang.ts
5
+ var E = ["id", "aria-label"], ee = {
6
+ class: "bless-radial__core",
7
+ "aria-hidden": "true"
8
+ }, te = [
9
+ "aria-label",
10
+ "aria-disabled",
11
+ "tabindex",
12
+ "onClick",
13
+ "onPointerenter"
14
+ ], D = /*@__PURE__*/ l({
15
+ name: "BlessRadialMenu",
16
+ inheritAttrs: !1,
17
+ __name: "BlessRadialMenu",
18
+ props: /*@__PURE__*/ u({
19
+ items: {},
20
+ radius: { default: 84 },
21
+ holdMs: { default: 450 },
22
+ disabled: { type: Boolean },
23
+ label: { default: "Actions" }
24
+ }, {
25
+ open: {
26
+ type: Boolean,
27
+ default: !1
28
+ },
29
+ openModifiers: {}
30
+ }),
31
+ emits: /*@__PURE__*/ u(["select"], ["update:open"]),
32
+ setup(l, { emit: u }) {
33
+ let D = l, O = C(l, "open"), k = u, A = S(), j = _(), M = _(), N = _({
34
+ x: 0,
35
+ y: 0
36
+ }), P = _(null), F = !1, I, L = null, R = a(() => D.radius + 22), z = a(() => D.items.map((e, t) => n(t, D.items.length, D.radius))), B = a(() => D.items.map((e, t) => e.disabled ? -1 : t).filter((e) => e >= 0));
37
+ function V(e, n, r = !1) {
38
+ !D.disabled && D.items.length && (N.value = t(e, n, R.value, window.innerWidth, window.innerHeight), P.value = null, F = r, O.value = !0);
39
+ }
40
+ function H(e = !0) {
41
+ F = !1, O.value && (O.value = !1, e && (j.value?.querySelector("[tabindex],button,a,input") ?? j.value)?.focus?.());
42
+ }
43
+ function U(e) {
44
+ let t = D.items[e];
45
+ t && !t.disabled && (k("select", t), H());
46
+ }
47
+ function W(e) {
48
+ D.disabled || (e.preventDefault(), clearTimeout(I), O.value || V(e.clientX, e.clientY));
49
+ }
50
+ function G(e) {
51
+ D.disabled || e.pointerType === "mouse" || (L = {
52
+ x: e.clientX,
53
+ y: e.clientY
54
+ }, clearTimeout(I), I = setTimeout(() => {
55
+ L && V(L.x, L.y, !0);
56
+ }, D.holdMs));
57
+ }
58
+ function K(e) {
59
+ L && !O.value && Math.hypot(e.clientX - L.x, e.clientY - L.y) > 8 && (clearTimeout(I), L = null);
60
+ }
61
+ function q() {
62
+ clearTimeout(I), L = null;
63
+ }
64
+ function J(e) {
65
+ if (e.key === "ContextMenu" || e.shiftKey && e.key === "F10") {
66
+ e.preventDefault();
67
+ let t = e.target.getBoundingClientRect();
68
+ V(t.left + t.width / 2, t.top + t.height / 2);
69
+ }
70
+ }
71
+ function Y(e) {
72
+ if (!O.value) return;
73
+ let t = r(e.clientX - N.value.x, e.clientY - N.value.y, D.items.length);
74
+ F && (P.value = t !== null && !D.items[t]?.disabled ? t : null);
75
+ }
76
+ function X() {
77
+ O.value && F && (F = !1, L = null, P.value !== null && U(P.value));
78
+ }
79
+ function Z(t) {
80
+ let n = e(t), r = B.value;
81
+ if (!r.length) return;
82
+ let i = P.value === null ? -1 : r.indexOf(P.value);
83
+ n === "ArrowRight" || n === "ArrowDown" ? (t.preventDefault(), Q(r[(i + 1) % r.length])) : n === "ArrowLeft" || n === "ArrowUp" ? (t.preventDefault(), Q(r[(i - 1 + r.length) % r.length])) : t.key === "Home" ? (t.preventDefault(), Q(r[0])) : t.key === "End" ? (t.preventDefault(), Q(r.at(-1))) : t.key === "Escape" ? (t.preventDefault(), t.stopPropagation(), H()) : t.key === "Tab" && H(!1);
84
+ }
85
+ function Q(e) {
86
+ P.value = e, f(() => M.value?.querySelectorAll("[role=\"menuitem\"]")[e]?.focus());
87
+ }
88
+ w(O, async (e) => {
89
+ await f();
90
+ let t = M.value;
91
+ t && typeof t.showPopover == "function" && (e ? (t.matches(":popover-open") || t.showPopover(), window.addEventListener("pointermove", Y), window.addEventListener("pointerup", X), window.addEventListener("pointercancel", X), window.addEventListener("pointerdown", $, !0), F || Q(B.value[0] ?? 0)) : (t.matches(":popover-open") && t.hidePopover(), window.removeEventListener("pointermove", Y), window.removeEventListener("pointerup", X), window.removeEventListener("pointercancel", X), window.removeEventListener("pointerdown", $, !0)));
92
+ });
93
+ function $(e) {
94
+ !M.value?.contains(e.target) && !F && H(!1);
95
+ }
96
+ return h(() => {
97
+ clearTimeout(I), window.removeEventListener("pointermove", Y), window.removeEventListener("pointerup", X), window.removeEventListener("pointercancel", X), window.removeEventListener("pointerdown", $, !0);
98
+ }), (e, t) => (g(), o(i, null, [s("div", d({
99
+ ref_key: "area",
100
+ ref: j,
101
+ class: "bless-radial__area"
102
+ }, e.$attrs, {
103
+ onContextmenu: W,
104
+ onPointerdown: G,
105
+ onPointermove: K,
106
+ onPointerup: q,
107
+ onPointercancel: q,
108
+ onKeydown: J
109
+ }), [y(e.$slots, "default")], 16), s("div", {
110
+ id: x(A),
111
+ ref_key: "panel",
112
+ ref: M,
113
+ popover: "manual",
114
+ class: "bless-radial",
115
+ role: "menu",
116
+ "aria-label": l.label,
117
+ style: m({
118
+ left: `${N.value.x - R.value}px`,
119
+ top: `${N.value.y - R.value}px`,
120
+ width: `${R.value * 2}px`,
121
+ height: `${R.value * 2}px`
122
+ }),
123
+ onKeydown: Z,
124
+ onContextmenu: t[0] ||= T(() => {}, ["prevent"])
125
+ }, [s("span", ee, b(P.value === null ? "" : l.items[P.value]?.label), 1), (g(!0), o(i, null, v(l.items, (t, n) => (g(), o("button", {
126
+ key: t.id,
127
+ type: "button",
128
+ role: "menuitem",
129
+ class: p(["bless-radial__item", { "bless-radial__item--on": P.value === n }]),
130
+ style: m({
131
+ left: `calc(50% + ${z.value[n].x}px)`,
132
+ top: `calc(50% + ${z.value[n].y}px)`
133
+ }),
134
+ "aria-label": t.label,
135
+ "aria-disabled": t.disabled || void 0,
136
+ tabindex: P.value === n ? 0 : -1,
137
+ onClick: (e) => U(n),
138
+ onPointerenter: (e) => !t.disabled && !x(F) && (P.value = n)
139
+ }, [y(e.$slots, "item", {
140
+ item: t,
141
+ index: n
142
+ }, () => [c(b(t.icon ?? t.label.slice(0, 1)), 1)])], 46, te))), 128))], 44, E)], 64));
143
+ }
144
+ });
145
+ //#endregion
146
+ export { D as default };
@@ -0,0 +1 @@
1
+ .bless-shortcut{gap:var(--bless-space-1);font-family:var(--bless-font-sans);font-size:var(--bless-text-sm);flex-direction:column;display:inline-flex;position:relative}.bless-shortcut__btn{min-width:160px;min-height:36px;padding:var(--bless-space-1) var(--bless-space-3);border:var(--bless-border-width) solid var(--bless-color-border);background:var(--bless-color-bg);color:var(--bless-color-text);font:inherit;cursor:pointer;align-items:center;display:inline-flex}.bless-shortcut__btn:focus-visible{outline:2px solid var(--bless-color-accent);outline-offset:2px}.bless-shortcut--rec .bless-shortcut__btn{border-color:var(--bless-color-accent)}.bless-shortcut--bad .bless-shortcut__btn{border-color:var(--bless-color-danger-text)}.bless-shortcut__btn:disabled{opacity:.5;cursor:not-allowed}.bless-shortcut__hint{color:var(--bless-color-text-muted)}.bless-shortcut__error{color:var(--bless-color-danger-text);font-size:var(--bless-text-xs);margin:0}.bless-shortcut__live{clip-path:inset(50%);width:1px;height:1px;position:absolute;overflow:hidden}
@@ -0,0 +1,6 @@
1
+ import "./BlessShortcutRecorder.css";
2
+ import e from "./BlessShortcutRecorder.vue_vue_type_script_setup_true_lang.js";
3
+ //#region src/components/BlessShortcutRecorder.vue
4
+ var t = e;
5
+ //#endregion
6
+ export { t as default };
@@ -0,0 +1,29 @@
1
+ type __VLS_Props = {
2
+ /** combos already taken, as a list or `{ "Ctrl+K": "Open search" }` to say by what */
3
+ taken?: string[] | Record<string, string>;
4
+ /** accept a bare key such as `G`; off asks for Ctrl, Alt or Meta, or a function key */
5
+ allowBare?: boolean;
6
+ disabled?: boolean;
7
+ label?: string;
8
+ placeholder?: string;
9
+ };
10
+ declare function start(): void;
11
+ type __VLS_ModelProps = {
12
+ modelValue?: string;
13
+ };
14
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
15
+ declare const __VLS_export: import('vue').DefineComponent<__VLS_PublicProps, {
16
+ start: typeof start;
17
+ focus: () => void | undefined;
18
+ }, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
19
+ "update:modelValue": (value: string) => any;
20
+ conflict: (combo: string, by: string | undefined) => any;
21
+ }, string, import('vue').PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
22
+ "onUpdate:modelValue"?: ((value: string) => any) | undefined;
23
+ onConflict?: ((combo: string, by: string | undefined) => any) | undefined;
24
+ }>, {
25
+ label: string;
26
+ placeholder: string;
27
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
28
+ declare const _default: typeof __VLS_export;
29
+ export default _default;
@@ -0,0 +1,116 @@
1
+ import e from "./BlessKbd.js";
2
+ import { isModifierKey as t, shortcutFromEvent as n, splitShortcut as r } from "../composables/shortcut.js";
3
+ import { computed as i, createBlock as a, createCommentVNode as o, createElementBlock as s, createElementVNode as c, defineComponent as l, mergeModels as u, normalizeClass as d, openBlock as f, ref as p, toDisplayString as m, unref as h, useId as g, useModel as _ } from "vue";
4
+ //#region src/components/BlessShortcutRecorder.vue?vue&type=script&setup=true&lang.ts
5
+ var v = [
6
+ "id",
7
+ "disabled",
8
+ "aria-label",
9
+ "aria-describedby",
10
+ "aria-invalid"
11
+ ], y = {
12
+ key: 0,
13
+ class: "bless-shortcut__hint"
14
+ }, b = {
15
+ key: 2,
16
+ class: "bless-shortcut__hint"
17
+ }, x = ["id"], S = {
18
+ class: "bless-shortcut__live",
19
+ "aria-live": "polite"
20
+ }, C = /*@__PURE__*/ l({
21
+ name: "BlessShortcutRecorder",
22
+ __name: "BlessShortcutRecorder",
23
+ props: /*@__PURE__*/ u({
24
+ taken: {},
25
+ allowBare: { type: Boolean },
26
+ disabled: { type: Boolean },
27
+ label: { default: "Shortcut" },
28
+ placeholder: { default: "Not set" }
29
+ }, {
30
+ modelValue: { default: "" },
31
+ modelModifiers: {}
32
+ }),
33
+ emits: /*@__PURE__*/ u(["conflict"], ["update:modelValue"]),
34
+ setup(l, { expose: u, emit: C }) {
35
+ let w = l, T = _(l, "modelValue"), E = C, D = g(), O = p(!1), k = p(""), A = p(""), j = p(""), M = p(), N = (e) => Array.isArray(w.taken) ? w.taken.includes(e) ? "" : void 0 : w.taken?.[e], P = i(() => O.value ? k.value : T.value), F = i(() => P.value ? r(P.value) : []);
36
+ function I() {
37
+ w.disabled || (O.value = !0, k.value = "", A.value = "", j.value = "Recording. Press the keys you want. Escape cancels, Backspace clears.");
38
+ }
39
+ function L(e = "") {
40
+ O.value = !1, k.value = "", j.value = e;
41
+ }
42
+ let R = (e) => !w.allowBare && !/^(Ctrl|Alt|Meta)\+/.test(e.replace(/Shift\+/, "")) && !/^F\d{1,2}$/.test(e.split("+").at(-1));
43
+ function z(e) {
44
+ if (!O.value) {
45
+ (e.key === "Enter" || e.key === " ") && (e.preventDefault(), I());
46
+ return;
47
+ }
48
+ if (e.preventDefault(), e.stopPropagation(), t(e)) {
49
+ k.value = [
50
+ e.ctrlKey && "Ctrl",
51
+ e.altKey && "Alt",
52
+ e.shiftKey && "Shift",
53
+ e.metaKey && "Meta"
54
+ ].filter(Boolean).join("+");
55
+ return;
56
+ }
57
+ let r = !e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey;
58
+ if (r && e.key === "Escape") return L("Cancelled");
59
+ if (r && (e.key === "Backspace" || e.key === "Delete")) return T.value = "", A.value = "", L("Cleared");
60
+ let i = n(e);
61
+ if (R(i)) {
62
+ k.value = i, A.value = `Add Ctrl, Alt or Meta to ${i}`, j.value = A.value;
63
+ return;
64
+ }
65
+ let a = N(i);
66
+ if (a !== void 0 && i !== T.value) {
67
+ k.value = i, A.value = a ? `${i} is already used by ${a}` : `${i} is already taken`, j.value = A.value, E("conflict", i, a || void 0);
68
+ return;
69
+ }
70
+ T.value = i, A.value = "", L(`Set to ${i}`);
71
+ }
72
+ function B(e) {
73
+ O.value && t(e) && !A.value && (k.value = [
74
+ e.ctrlKey && "Ctrl",
75
+ e.altKey && "Alt",
76
+ e.shiftKey && "Shift",
77
+ e.metaKey && "Meta"
78
+ ].filter(Boolean).join("+"));
79
+ }
80
+ return u({
81
+ start: I,
82
+ focus: () => M.value?.focus()
83
+ }), (t, n) => (f(), s("div", { class: d(["bless-shortcut", {
84
+ "bless-shortcut--rec": O.value,
85
+ "bless-shortcut--bad": !!A.value
86
+ }]) }, [
87
+ c("button", {
88
+ id: h(D),
89
+ ref_key: "btn",
90
+ ref: M,
91
+ type: "button",
92
+ class: "bless-shortcut__btn",
93
+ disabled: l.disabled,
94
+ "aria-label": `${l.label}: ${T.value || "not set"}. Press Enter to change.`,
95
+ "aria-describedby": A.value ? `${h(D)}-err` : void 0,
96
+ "aria-invalid": !!A.value || void 0,
97
+ onClick: n[0] ||= (e) => O.value ? L() : I(),
98
+ onKeydown: z,
99
+ onKeyup: B,
100
+ onBlur: n[1] ||= (e) => O.value && L()
101
+ }, [O.value && !F.value.length ? (f(), s("span", y, "Press keys…")) : F.value.length ? (f(), a(e, {
102
+ key: 1,
103
+ keys: F.value
104
+ }, null, 8, ["keys"])) : (f(), s("span", b, m(l.placeholder), 1))], 40, v),
105
+ A.value ? (f(), s("p", {
106
+ key: 0,
107
+ id: `${h(D)}-err`,
108
+ class: "bless-shortcut__error",
109
+ role: "alert"
110
+ }, m(A.value), 9, x)) : o("", !0),
111
+ c("span", S, m(j.value), 1)
112
+ ], 2));
113
+ }
114
+ });
115
+ //#endregion
116
+ export { C as default };
@@ -0,0 +1 @@
1
+ .bless-captcha{max-width:360px;font-family:var(--bless-font-sans);font-size:var(--bless-text-sm);color:var(--bless-color-text);position:relative}.bless-captcha__stage{border:var(--bless-border-width) solid var(--bless-color-border);background-color:var(--bless-color-surface);background-image:conic-gradient(var(--bless-color-border) 25%, transparent 0 50%, var(--bless-color-border) 0 75%, transparent 0);-webkit-user-select:none;user-select:none;background-size:24px 24px;position:relative;overflow:hidden}.bless-captcha__gap{background:color-mix(in srgb, var(--bless-color-text) 55%, transparent);box-shadow:inset 0 0 0 2px var(--bless-color-bg);position:absolute}.bless-captcha__piece{background-color:var(--bless-color-surface);background-image:conic-gradient(var(--bless-color-border) 25%, transparent 0 50%, var(--bless-color-border) 0 75%, transparent 0);border:2px solid var(--bless-color-bg);outline:1px solid var(--bless-color-text);box-shadow:var(--bless-shadow-plate);transition:left var(--bless-duration-slow) var(--bless-ease-out);background-size:24px 24px;position:absolute}.bless-captcha__piece--drag{transition:none}.bless-captcha__track{height:40px;margin-top:var(--bless-space-2);background:var(--bless-color-surface);border:var(--bless-border-width) solid var(--bless-color-border);color:var(--bless-color-text-muted);justify-content:center;align-items:center;display:flex;position:relative}.bless-captcha__handle{background:var(--bless-color-text);width:44px;color:var(--bless-color-on-text);font:inherit;cursor:grab;touch-action:none;transition:left var(--bless-duration-slow) var(--bless-ease-out), translate var(--bless-duration-slow) var(--bless-ease-out);border:0;position:absolute;top:-1px;bottom:-1px}.bless-captcha__handle--drag{cursor:grabbing;transition:none}.bless-captcha__handle:focus-visible{outline:2px solid var(--bless-color-accent);outline-offset:2px}.bless-captcha--ok .bless-captcha__handle{background:var(--bless-color-accent);color:var(--bless-color-on-accent);cursor:default}.bless-captcha--fail .bless-captcha__track{border-color:var(--bless-color-danger-text)}.bless-captcha__live{clip-path:inset(50%);width:1px;height:1px;position:absolute;overflow:hidden}@media (prefers-reduced-motion:reduce){.bless-captcha__piece,.bless-captcha__handle{transition:none}}
@@ -0,0 +1,6 @@
1
+ import "./BlessSliderCaptcha.css";
2
+ import e from "./BlessSliderCaptcha.vue_vue_type_script_setup_true_lang.js";
3
+ //#region src/components/BlessSliderCaptcha.vue
4
+ var t = e;
5
+ //#endregion
6
+ export { t as default };
@@ -0,0 +1,33 @@
1
+ type __VLS_Props = {
2
+ /** background picture; without it a checker pattern is drawn */
3
+ src?: string;
4
+ /** how close counts, as a fraction of the track (0.03 = 3%) */
5
+ tolerance?: number;
6
+ label?: string;
7
+ };
8
+ declare function reset(): void;
9
+ type __VLS_ModelProps = {
10
+ /** true once solved; the widget then stays locked until `reset()` */
11
+ "verified"?: boolean;
12
+ };
13
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
14
+ declare const __VLS_export: import('vue').DefineComponent<__VLS_PublicProps, {
15
+ reset: typeof reset;
16
+ }, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
17
+ verify: (info: {
18
+ ms: number;
19
+ }) => any;
20
+ fail: () => any;
21
+ "update:verified": (value: boolean) => any;
22
+ }, string, import('vue').PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
23
+ onVerify?: ((info: {
24
+ ms: number;
25
+ }) => any) | undefined;
26
+ onFail?: (() => any) | undefined;
27
+ "onUpdate:verified"?: ((value: boolean) => any) | undefined;
28
+ }>, {
29
+ label: string;
30
+ tolerance: number;
31
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
32
+ declare const _default: typeof __VLS_export;
33
+ export default _default;
@@ -0,0 +1,141 @@
1
+ import { createElementBlock as e, createElementVNode as t, defineComponent as n, mergeModels as r, normalizeClass as i, normalizeStyle as a, onBeforeUnmount as o, onMounted as s, openBlock as c, ref as l, toDisplayString as u, unref as d, useId as f, useModel as p } from "vue";
2
+ //#region src/components/BlessSliderCaptcha.vue?vue&type=script&setup=true&lang.ts
3
+ var m = ["id"], h = [
4
+ "aria-labelledby",
5
+ "aria-valuenow",
6
+ "aria-disabled"
7
+ ], g = { "aria-hidden": "true" }, _ = {
8
+ class: "bless-captcha__live",
9
+ "aria-live": "polite"
10
+ }, v = .16, y = /*@__PURE__*/ n({
11
+ name: "BlessSliderCaptcha",
12
+ __name: "BlessSliderCaptcha",
13
+ props: /*@__PURE__*/ r({
14
+ src: {},
15
+ tolerance: { default: .03 },
16
+ label: { default: "Slide the piece into the gap" }
17
+ }, {
18
+ verified: {
19
+ type: Boolean,
20
+ default: !1
21
+ },
22
+ verifiedModifiers: {}
23
+ }),
24
+ emits: /*@__PURE__*/ r(["verify", "fail"], ["update:verified"]),
25
+ setup(n, { expose: r, emit: y }) {
26
+ let b = n, x = p(n, "verified"), S = y, C = f(), w = l(), T = l(), E = l(), D = l(320), O = () => Math.round(D.value / 2), k = l(0), A = l({
27
+ at: .6,
28
+ y: .3
29
+ }), j = l(!1), M = l(!1), N = l(""), P = 0;
30
+ function F() {
31
+ A.value = {
32
+ at: .35 + Math.random() * .55,
33
+ y: .1 + Math.random() * .5
34
+ };
35
+ }
36
+ let I;
37
+ s(() => {
38
+ F();
39
+ let e = w.value;
40
+ e && (D.value = e.clientWidth || 320, typeof ResizeObserver < "u" && (I = new ResizeObserver(() => D.value = e.clientWidth || 320), I.observe(e)));
41
+ }), o(() => I?.disconnect());
42
+ let L = () => D.value * v, R = () => A.value.at * D.value * .84, z = () => A.value.y * (O() - L()), B = () => b.src ? {
43
+ backgroundImage: `url(${b.src})`,
44
+ backgroundSize: `${D.value}px ${O()}px`
45
+ } : {};
46
+ function V() {
47
+ x.value || (Math.abs(k.value - A.value.at) <= b.tolerance ? (x.value = !0, k.value = A.value.at, N.value = "Verified", S("verify", { ms: Math.round(performance.now() - P) })) : (M.value = !0, N.value = "Not quite, try again", S("fail"), k.value = 0, F(), setTimeout(() => M.value = !1, 400)));
48
+ }
49
+ function H() {
50
+ x.value = !1, M.value = !1, k.value = 0, N.value = "", F();
51
+ }
52
+ r({ reset: H });
53
+ let U = {
54
+ x: 0,
55
+ f: 0
56
+ };
57
+ function W(e) {
58
+ x.value || e.button || (e.currentTarget.setPointerCapture?.(e.pointerId), U = {
59
+ x: e.clientX,
60
+ f: k.value
61
+ }, j.value = !0, (!P || k.value === 0) && (P = performance.now()));
62
+ }
63
+ function G(e) {
64
+ if (!j.value) return;
65
+ let t = T.value?.clientWidth || 0, n = E.value?.offsetWidth || 0, r = t && n ? t - n : (w.value?.clientWidth || D.value) - L();
66
+ k.value = Math.min(1, Math.max(0, U.f + (e.clientX - U.x) / r));
67
+ }
68
+ function K() {
69
+ j.value && (j.value = !1, V());
70
+ }
71
+ function q(e) {
72
+ if (x.value) return;
73
+ let t = e.shiftKey ? .1 : .01;
74
+ e.key === "ArrowRight" || e.key === "ArrowLeft" ? (e.preventDefault(), k.value || (P = performance.now()), k.value = Math.min(1, Math.max(0, k.value + (e.key === "ArrowRight" ? t : -t)))) : (e.key === "Enter" || e.key === " ") && (e.preventDefault(), V());
75
+ }
76
+ return (r, o) => (c(), e("div", { class: i(["bless-captcha", {
77
+ "bless-captcha--ok": x.value,
78
+ "bless-captcha--fail": M.value
79
+ }]) }, [
80
+ t("div", {
81
+ ref_key: "stage",
82
+ ref: w,
83
+ class: "bless-captcha__stage",
84
+ style: a({
85
+ height: `${O()}px`,
86
+ ...B()
87
+ }),
88
+ "aria-hidden": "true"
89
+ }, [t("span", {
90
+ class: "bless-captcha__gap",
91
+ style: a({
92
+ width: `${L()}px`,
93
+ height: `${L()}px`,
94
+ left: `${R()}px`,
95
+ top: `${z()}px`
96
+ })
97
+ }, null, 4), t("span", {
98
+ class: i(["bless-captcha__piece", { "bless-captcha__piece--drag": j.value }]),
99
+ style: a({
100
+ width: `${L()}px`,
101
+ height: `${L()}px`,
102
+ top: `${z()}px`,
103
+ left: `${k.value * (D.value - L())}px`,
104
+ ...B(),
105
+ backgroundPosition: `-${R()}px -${z()}px`
106
+ })
107
+ }, null, 6)], 4),
108
+ t("div", {
109
+ ref_key: "track",
110
+ ref: T,
111
+ class: "bless-captcha__track"
112
+ }, [t("span", {
113
+ id: `${d(C)}-l`,
114
+ class: "bless-captcha__label"
115
+ }, u(x.value ? "Verified" : n.label), 9, m), t("button", {
116
+ ref_key: "handleEl",
117
+ ref: E,
118
+ type: "button",
119
+ class: i(["bless-captcha__handle", { "bless-captcha__handle--drag": j.value }]),
120
+ role: "slider",
121
+ "aria-labelledby": `${d(C)}-l`,
122
+ "aria-valuemin": "0",
123
+ "aria-valuemax": "100",
124
+ "aria-valuenow": Math.round(k.value * 100),
125
+ "aria-disabled": x.value || void 0,
126
+ style: a({
127
+ left: `${k.value * 100}%`,
128
+ translate: `${-k.value * 100}% 0`
129
+ }),
130
+ onPointerdown: W,
131
+ onPointermove: G,
132
+ onPointerup: K,
133
+ onPointercancel: K,
134
+ onKeydown: q
135
+ }, [t("span", g, u(x.value ? "✓" : "→"), 1)], 46, h)], 512),
136
+ t("span", _, u(N.value), 1)
137
+ ], 2));
138
+ }
139
+ });
140
+ //#endregion
141
+ export { y as default };
@@ -0,0 +1 @@
1
+ .bless-sortable{font-family:var(--bless-font-sans);font-size:var(--bless-text-sm);color:var(--bless-color-text);position:relative}.bless-sortable__list{gap:var(--bless-space-2);margin:0;padding:0;list-style:none;display:grid}.bless-sortable__list--grid{grid-template-columns:repeat(var(--bless-sortable-cols), minmax(0, 1fr))}.bless-sortable__item{align-items:center;gap:var(--bless-space-2);padding:var(--bless-space-2) var(--bless-space-3);border:var(--bless-border-width) solid var(--bless-color-border);background:var(--bless-color-bg);display:flex}.bless-sortable__item--drag{opacity:.4}.bless-sortable__item--held{border-color:var(--bless-color-accent)}.bless-sortable__item--before{box-shadow:inset 0 2px 0 var(--bless-color-accent)}.bless-sortable__item--after{box-shadow:inset 0 -2px 0 var(--bless-color-accent)}.bless-sortable__list--grid .bless-sortable__item--before{box-shadow:inset 2px 0 0 var(--bless-color-accent)}.bless-sortable__list--grid .bless-sortable__item--after,[dir=rtl] .bless-sortable__list--grid .bless-sortable__item--before{box-shadow:inset -2px 0 0 var(--bless-color-accent)}[dir=rtl] .bless-sortable__list--grid .bless-sortable__item--after{box-shadow:inset 2px 0 0 var(--bless-color-accent)}.bless-sortable__grip{padding:var(--bless-space-1) var(--bless-space-2);color:var(--bless-color-text-muted);font:inherit;letter-spacing:-3px;cursor:grab;touch-action:none;background:0 0;border:0;flex:none}.bless-sortable__grip:active{cursor:grabbing}.bless-sortable__grip:focus-visible{outline:2px solid var(--bless-color-accent)}.bless-sortable__body{flex:1;min-width:0}.bless-sortable__live{clip-path:inset(50%);width:1px;height:1px;position:absolute;overflow:hidden}
@@ -0,0 +1,6 @@
1
+ import "./BlessSortable.css";
2
+ import e from "./BlessSortable.vue_vue_type_script_setup_true_lang.js";
3
+ //#region src/components/BlessSortable.vue
4
+ var t = e;
5
+ //#endregion
6
+ export { t as default };
@@ -0,0 +1,33 @@
1
+ declare const __VLS_export: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
2
+ props: import('vue').PublicProps & __VLS_PrettifyLocal<({
3
+ rowKey?: (item: T, index: number) => string | number;
4
+ label?: string;
5
+ /** lay the items out in this many equal columns (a grid); 1 is a list */
6
+ columns?: number;
7
+ } & {
8
+ modelValue?: T[];
9
+ }) & {
10
+ "onUpdate:modelValue"?: ((value: T[]) => any) | undefined;
11
+ onMove?: ((from: number, to: number) => any) | undefined;
12
+ }> & (typeof globalThis extends {
13
+ __VLS_PROPS_FALLBACK: infer P;
14
+ } ? P : {});
15
+ expose: (exposed: {}) => void;
16
+ attrs: any;
17
+ slots: {
18
+ default?: (props: {
19
+ item: T;
20
+ index: number;
21
+ }) => any;
22
+ };
23
+ emit: ((evt: "move", from: number, to: number) => void) & ((event: "update:modelValue", value: T[]) => void);
24
+ }>) => import('vue').VNode & {
25
+ __ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
26
+ };
27
+ declare const _default: typeof __VLS_export;
28
+ export default _default;
29
+ type __VLS_PrettifyLocal<T> = (T extends any ? {
30
+ [K in keyof T]: T[K];
31
+ } : {
32
+ [K in keyof T as K]: T[K];
33
+ }) & {};
@@ -0,0 +1,87 @@
1
+ import { logicalKey as e } from "../composables/rtl.js";
2
+ import { moveItem as t, useSortable as n } from "../composables/useSortable.js";
3
+ import { Fragment as r, createElementBlock as i, createElementVNode as a, createTextVNode as o, defineComponent as s, mergeModels as c, nextTick as l, normalizeClass as u, normalizeStyle as d, openBlock as f, ref as p, renderList as m, renderSlot as h, toDisplayString as g, unref as _, useId as v, useModel as y } from "vue";
4
+ //#region src/components/BlessSortable.vue?vue&type=script&setup=true&lang.ts
5
+ var b = ["aria-label"], x = [
6
+ "aria-label",
7
+ "aria-pressed",
8
+ "onPointerdown",
9
+ "onKeydown"
10
+ ], S = { class: "bless-sortable__body" }, C = {
11
+ class: "bless-sortable__live",
12
+ "aria-live": "polite"
13
+ }, w = /*@__PURE__*/ s({
14
+ name: "BlessSortable",
15
+ __name: "BlessSortable",
16
+ props: /*@__PURE__*/ c({
17
+ rowKey: {},
18
+ label: { default: "Sortable" },
19
+ columns: { default: 1 }
20
+ }, {
21
+ modelValue: { default: () => [] },
22
+ modelModifiers: {}
23
+ }),
24
+ emits: /*@__PURE__*/ c(["move"], ["update:modelValue"]),
25
+ setup(s, { emit: c }) {
26
+ let w = y(s, "modelValue"), T = c, E = p(), D = p(""), O = `${v()}-hint`, k = p(null), A = [], j = 0;
27
+ function M(e, n) {
28
+ e === n || n < 0 || n >= w.value.length || (w.value = t(w.value, e, n), T("move", e, n), D.value = `Moved to position ${n + 1} of ${w.value.length}`);
29
+ }
30
+ let N = n(E, M), { drag: P, over: F } = N, I = () => E.value?.querySelectorAll(".bless-sortable__grip") ?? [], L = (e) => l(() => I()[e]?.focus());
31
+ function R(t, n) {
32
+ let r = e(n);
33
+ if (n.key === " " || n.key === "Enter") n.preventDefault(), k.value == null ? (k.value = t, A = w.value.slice(), j = t, D.value = `Grabbed item ${t + 1} of ${w.value.length}. Arrow keys move it, Space drops it, Escape cancels.`) : (D.value = `Dropped at position ${k.value + 1} of ${w.value.length}`, k.value = null);
34
+ else if (n.key === "Escape" && k.value != null) n.preventDefault(), w.value = A, k.value = null, D.value = "Cancelled, order restored", L(j);
35
+ else if (k.value != null) {
36
+ let e = r === "ArrowUp" || r === "ArrowLeft" ? -1 : +(r === "ArrowDown" || r === "ArrowRight");
37
+ if (!e) return;
38
+ n.preventDefault(), M(k.value, k.value + e), k.value = Math.min(Math.max(k.value + e, 0), w.value.length - 1), L(k.value);
39
+ }
40
+ }
41
+ let z = () => requestAnimationFrame(() => {
42
+ k.value != null && !E.value?.contains(document.activeElement) && (k.value = null);
43
+ }), B = (e) => F.value === e && P.value != null && P.value !== e ? e > P.value ? "after" : "before" : null;
44
+ return (e, t) => (f(), i("div", {
45
+ ref_key: "root",
46
+ ref: E,
47
+ class: "bless-sortable"
48
+ }, [
49
+ a("ul", {
50
+ class: u(["bless-sortable__list", { "bless-sortable__list--grid": s.columns > 1 }]),
51
+ role: "list",
52
+ "aria-label": s.label,
53
+ style: d(s.columns > 1 ? { "--bless-sortable-cols": s.columns } : void 0)
54
+ }, [(f(!0), i(r, null, m(w.value, (n, r) => (f(), i("li", {
55
+ key: s.rowKey ? s.rowKey(n, r) : r,
56
+ "data-sortable-item": "",
57
+ class: u(["bless-sortable__item", [{
58
+ "bless-sortable__item--drag": _(P) === r,
59
+ "bless-sortable__item--held": k.value === r
60
+ }, B(r) && `bless-sortable__item--${B(r)}`]])
61
+ }, [a("button", {
62
+ type: "button",
63
+ class: "bless-sortable__grip",
64
+ "aria-label": `Reorder item ${r + 1}`,
65
+ "aria-roledescription": "sortable item",
66
+ "aria-pressed": k.value === r,
67
+ "aria-describedby": O,
68
+ onPointerdown: (e) => _(N).grab(r, e),
69
+ onPointermove: t[0] ||= (...e) => _(N).track && _(N).track(...e),
70
+ onPointerup: t[1] ||= (...e) => _(N).drop && _(N).drop(...e),
71
+ onPointercancel: t[2] ||= (...e) => _(N).cancel && _(N).cancel(...e),
72
+ onKeydown: (e) => R(r, e),
73
+ onBlur: z
74
+ }, [...t[3] ||= [a("span", { "aria-hidden": "true" }, "⋮⋮", -1)]], 40, x), a("span", S, [h(e.$slots, "default", {
75
+ item: n,
76
+ index: r
77
+ }, () => [o(g(n), 1)])])], 2))), 128))], 14, b),
78
+ a("span", {
79
+ id: O,
80
+ hidden: ""
81
+ }, "Press Space to grab, arrow keys to move, Space to drop, Escape to cancel."),
82
+ a("span", C, g(D.value), 1)
83
+ ], 512));
84
+ }
85
+ });
86
+ //#endregion
87
+ export { w as default };
@@ -0,0 +1 @@
1
+ .bless-split{min-width:0;height:100%;font-family:var(--bless-font-sans);color:var(--bless-color-text)}.bless-split--stacked .bless-split__pane{height:100%;overflow:auto}.bless-split__pane:focus{outline:none}.bless-split__pane:focus-visible{outline:2px solid var(--bless-color-accent);outline-offset:-2px}.bless-split__back{gap:var(--bless-space-1);margin:var(--bless-space-2);padding:var(--bless-space-1) var(--bless-space-2);border:var(--bless-border-width) solid var(--bless-color-border);background:var(--bless-color-bg);color:inherit;font:inherit;cursor:pointer;display:inline-flex}.bless-split__back:focus-visible{outline:2px solid var(--bless-color-accent);outline-offset:2px}[dir=rtl] .bless-split__back span{display:inline-block;transform:scaleX(-1)}
@@ -0,0 +1,6 @@
1
+ import "./BlessSplitView.css";
2
+ import e from "./BlessSplitView.vue_vue_type_script_setup_true_lang.js";
3
+ //#region src/components/BlessSplitView.vue
4
+ var t = e;
5
+ //#endregion
6
+ export { t as default };