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,61 @@
1
+ type __VLS_Props = {
2
+ /** under this width (px of the view itself) the panes stack: one at a time */
3
+ breakpoint?: number;
4
+ min?: number;
5
+ max?: number;
6
+ /** remember the divider in localStorage under this key */
7
+ storageKey?: string;
8
+ /** text of the button that goes back from the detail when stacked */
9
+ backLabel?: string;
10
+ label?: string;
11
+ };
12
+ type __VLS_ModelProps = {
13
+ /** master pane width in % */
14
+ modelValue?: number;
15
+ /** when stacked: is the detail showing (true) or the list (false)? */
16
+ "detail"?: boolean;
17
+ };
18
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
19
+ declare var __VLS_1: {
20
+ open: () => boolean;
21
+ stacked: boolean;
22
+ }, __VLS_3: {
23
+ stacked: boolean;
24
+ }, __VLS_12: {
25
+ open: () => boolean;
26
+ stacked: boolean;
27
+ }, __VLS_15: {
28
+ stacked: boolean;
29
+ };
30
+ type __VLS_Slots = {} & {
31
+ master?: (props: typeof __VLS_1) => any;
32
+ } & {
33
+ detail?: (props: typeof __VLS_3) => any;
34
+ } & {
35
+ master?: (props: typeof __VLS_12) => any;
36
+ } & {
37
+ detail?: (props: typeof __VLS_15) => any;
38
+ };
39
+ declare const __VLS_base: import('vue').DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
40
+ "update:modelValue": (value: number) => any;
41
+ back: () => any;
42
+ "update:detail": (value: boolean) => any;
43
+ }, string, import('vue').PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
44
+ "onUpdate:modelValue"?: ((value: number) => any) | undefined;
45
+ onBack?: (() => any) | undefined;
46
+ "onUpdate:detail"?: ((value: boolean) => any) | undefined;
47
+ }>, {
48
+ label: string;
49
+ min: number;
50
+ max: number;
51
+ breakpoint: number;
52
+ backLabel: string;
53
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
54
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
55
+ declare const _default: typeof __VLS_export;
56
+ export default _default;
57
+ type __VLS_WithSlots<T, S> = T & {
58
+ new (): {
59
+ $slots: S;
60
+ };
61
+ };
@@ -0,0 +1,92 @@
1
+ import e from "./BlessResizable.js";
2
+ import { Fragment as t, createBlock as n, createElementBlock as r, createElementVNode as i, createTextVNode as a, defineComponent as o, mergeModels as s, nextTick as c, normalizeClass as l, onBeforeUnmount as u, onMounted as d, openBlock as f, ref as p, renderSlot as m, toDisplayString as h, useModel as g, vShow as _, watch as v, withCtx as y, withDirectives as b } from "vue";
3
+ //#region src/components/BlessSplitView.vue?vue&type=script&setup=true&lang.ts
4
+ var x = /*@__PURE__*/ o({
5
+ name: "BlessSplitView",
6
+ __name: "BlessSplitView",
7
+ props: /*@__PURE__*/ s({
8
+ breakpoint: { default: 560 },
9
+ min: { default: 20 },
10
+ max: { default: 60 },
11
+ storageKey: {},
12
+ backLabel: { default: "Back" },
13
+ label: { default: "Resize list" }
14
+ }, {
15
+ modelValue: { default: 35 },
16
+ modelModifiers: {},
17
+ detail: {
18
+ type: Boolean,
19
+ default: !1
20
+ },
21
+ detailModifiers: {}
22
+ }),
23
+ emits: /*@__PURE__*/ s(["back"], ["update:modelValue", "update:detail"]),
24
+ setup(o, { emit: s }) {
25
+ let x = o, S = g(o, "modelValue"), C = g(o, "detail"), w = s, T = p(), E = p(!1), D = p(), O = p();
26
+ function k() {
27
+ E.value = (T.value?.clientWidth ?? Infinity) < x.breakpoint;
28
+ }
29
+ let A;
30
+ d(() => {
31
+ if (x.storageKey) try {
32
+ let e = parseFloat(localStorage.getItem(x.storageKey) ?? "");
33
+ e >= x.min && e <= x.max && (S.value = e);
34
+ } catch {}
35
+ k(), typeof ResizeObserver < "u" && T.value && (A = new ResizeObserver(k), A.observe(T.value));
36
+ }), u(() => A?.disconnect()), v(S, (e) => {
37
+ if (x.storageKey) try {
38
+ localStorage.setItem(x.storageKey, String(e));
39
+ } catch {}
40
+ }), v(C, (e) => {
41
+ E.value && c(() => {
42
+ e ? D.value?.focus() : O.value?.focus();
43
+ });
44
+ });
45
+ function j() {
46
+ C.value = !1, w("back");
47
+ }
48
+ return (s, c) => (f(), r("div", {
49
+ ref_key: "root",
50
+ ref: T,
51
+ class: l(["bless-split", { "bless-split--stacked": E.value }])
52
+ }, [E.value ? (f(), r(t, { key: 0 }, [b(i("div", {
53
+ ref_key: "masterEl",
54
+ ref: O,
55
+ class: "bless-split__pane",
56
+ tabindex: "-1"
57
+ }, [m(s.$slots, "master", {
58
+ open: () => C.value = !0,
59
+ stacked: !0
60
+ })], 512), [[_, !C.value]]), b(i("div", {
61
+ ref_key: "detailEl",
62
+ ref: D,
63
+ class: "bless-split__pane",
64
+ tabindex: "-1"
65
+ }, [i("button", {
66
+ type: "button",
67
+ class: "bless-split__back",
68
+ onClick: j
69
+ }, [c[1] ||= i("span", { "aria-hidden": "true" }, "←", -1), a(" " + h(o.backLabel), 1)]), m(s.$slots, "detail", { stacked: !0 })], 512), [[_, C.value]])], 64)) : (f(), n(e, {
70
+ key: 1,
71
+ modelValue: S.value,
72
+ "onUpdate:modelValue": c[0] ||= (e) => S.value = e,
73
+ min: o.min,
74
+ max: o.max,
75
+ label: o.label
76
+ }, {
77
+ a: y(() => [m(s.$slots, "master", {
78
+ open: () => C.value = !0,
79
+ stacked: !1
80
+ })]),
81
+ b: y(() => [m(s.$slots, "detail", { stacked: !1 })]),
82
+ _: 3
83
+ }, 8, [
84
+ "modelValue",
85
+ "min",
86
+ "max",
87
+ "label"
88
+ ]))], 2));
89
+ }
90
+ });
91
+ //#endregion
92
+ export { x as default };
@@ -0,0 +1 @@
1
+ .bless-deck{font-family:var(--bless-font-sans);font-size:var(--bless-text-sm);color:var(--bless-color-text);position:relative}.bless-deck__stage{min-height:240px;display:grid;position:relative}.bless-deck__stage:focus-visible{outline:2px solid var(--bless-color-accent);outline-offset:4px}.bless-deck__card{padding:var(--bless-space-8) var(--bless-space-4) var(--bless-space-4);background:var(--bless-color-bg);border:var(--bless-border-width) solid var(--bless-color-border);box-shadow:var(--bless-shadow-plate);translate:0 calc(var(--bless-deck-depth,0) * 8px);scale:calc(1 - var(--bless-deck-depth,0) * .04);transition:transform var(--bless-duration-slow) var(--bless-ease-out), translate var(--bless-duration-slow) var(--bless-ease-out), scale var(--bless-duration-slow) var(--bless-ease-out), opacity var(--bless-duration-slow) var(--bless-ease-out);-webkit-user-select:none;user-select:none;grid-area:1/1;position:relative}.bless-deck__card--top{z-index:3;cursor:grab;touch-action:none}.bless-deck__card:nth-child(2){z-index:2}.bless-deck__card:nth-child(3){z-index:1}.bless-deck-leave-active{z-index:4;pointer-events:none}.bless-deck-leave-to{opacity:0;translate:calc(var(--bless-deck-x) * 140%) calc(var(--bless-deck-y) * 140%)}.bless-deck-enter-from{opacity:0}.bless-deck__stamp{top:var(--bless-space-3);padding:0 var(--bless-space-2);text-transform:uppercase;pointer-events:none;opacity:0;border:2px solid;font-weight:700;position:absolute}.bless-deck__stamp--accept{inset-inline-start:var(--bless-space-3)}.bless-deck__stamp--reject{inset-inline-end:var(--bless-space-3)}.bless-deck__stamp--skip{inset-inline-start:50%;translate:-50%}.bless-deck__empty{color:var(--bless-color-text-muted);grid-area:1/1;place-items:center;display:grid}.bless-deck__controls{justify-content:center;gap:var(--bless-space-2);margin-top:var(--bless-space-4);flex-wrap:wrap;display:flex}.bless-deck__live{clip-path:inset(50%);width:1px;height:1px;position:absolute;overflow:hidden}@media (prefers-reduced-motion:reduce){.bless-deck__card{transition:none}}
@@ -0,0 +1,6 @@
1
+ import "./BlessSwipeDeck.css";
2
+ import e from "./BlessSwipeDeck.vue_vue_type_script_setup_true_lang.js";
3
+ //#region src/components/BlessSwipeDeck.vue
4
+ var t = e;
5
+ //#endregion
6
+ export { t as default };
@@ -0,0 +1,46 @@
1
+ export type BlessSwipeDecision = "accept" | "reject" | "skip";
2
+ declare const _default: typeof __VLS_export;
3
+ export default _default;
4
+ 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<{
5
+ props: import('vue').PublicProps & __VLS_PrettifyLocal<({
6
+ rowKey?: (item: T) => string | number;
7
+ label?: string;
8
+ /** show the buttons under the deck */
9
+ controls?: boolean;
10
+ /** how far (px) a drag must travel to count */
11
+ threshold?: number;
12
+ labels?: Partial<Record<BlessSwipeDecision | "undo", string>>;
13
+ } & {
14
+ /** the cards still to decide, top of the deck first */
15
+ modelValue?: T[];
16
+ }) & {
17
+ "onUpdate:modelValue"?: ((value: T[]) => any) | undefined;
18
+ onDecide?: ((item: T, decision: BlessSwipeDecision) => any) | undefined;
19
+ onUndo?: ((item: T) => any) | undefined;
20
+ }> & (typeof globalThis extends {
21
+ __VLS_PROPS_FALLBACK: infer P;
22
+ } ? P : {});
23
+ expose: (exposed: import('vue').ShallowUnwrapRef<{
24
+ accept: () => void;
25
+ reject: () => void;
26
+ skip: () => void;
27
+ undo: () => void;
28
+ }>) => void;
29
+ attrs: any;
30
+ slots: {
31
+ card?: (props: {
32
+ item: T;
33
+ index: number;
34
+ }) => any;
35
+ } & {
36
+ empty?: (props: {}) => any;
37
+ };
38
+ emit: (((evt: "decide", item: T, decision: BlessSwipeDecision) => void) & ((evt: "undo", item: T) => void)) & ((event: "update:modelValue", value: T[]) => void);
39
+ }>) => import('vue').VNode & {
40
+ __ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
41
+ };
42
+ type __VLS_PrettifyLocal<T> = (T extends any ? {
43
+ [K in keyof T]: T[K];
44
+ } : {
45
+ [K in keyof T as K]: T[K];
46
+ }) & {};
@@ -0,0 +1,199 @@
1
+ import e from "./BlessButton.js";
2
+ import { Fragment as t, TransitionGroup as n, computed as r, createCommentVNode as i, createElementBlock as a, createElementVNode as o, createTextVNode as s, createVNode as c, defineComponent as l, mergeModels as u, normalizeClass as d, normalizeStyle as f, openBlock as p, ref as m, renderList as h, renderSlot as g, toDisplayString as _, useModel as v, withCtx as y } from "vue";
3
+ //#region src/components/BlessSwipeDeck.vue?vue&type=script&setup=true&lang.ts
4
+ var b = ["aria-label"], x = [
5
+ "aria-hidden",
6
+ "inert",
7
+ "onPointerdown",
8
+ "onPointermove",
9
+ "onPointerup",
10
+ "onPointercancel"
11
+ ], S = {
12
+ key: 0,
13
+ class: "bless-deck__empty"
14
+ }, C = {
15
+ key: 0,
16
+ class: "bless-deck__controls"
17
+ }, w = {
18
+ class: "bless-deck__live",
19
+ "aria-live": "polite"
20
+ }, T = /*@__PURE__*/ l({
21
+ name: "BlessSwipeDeck",
22
+ __name: "BlessSwipeDeck",
23
+ props: /*@__PURE__*/ u({
24
+ rowKey: {},
25
+ label: { default: "Cards" },
26
+ controls: {
27
+ type: Boolean,
28
+ default: !0
29
+ },
30
+ threshold: { default: 100 },
31
+ labels: {}
32
+ }, {
33
+ modelValue: { default: () => [] },
34
+ modelModifiers: {}
35
+ }),
36
+ emits: /*@__PURE__*/ u(["decide", "undo"], ["update:modelValue"]),
37
+ setup(l, { expose: u, emit: T }) {
38
+ let E = l, D = v(l, "modelValue"), O = T, k = r(() => ({
39
+ accept: "Accept",
40
+ reject: "Reject",
41
+ skip: "Skip",
42
+ undo: "Undo",
43
+ ...E.labels
44
+ })), A = [], j = m(0), M = m(""), N = {
45
+ accept: [1, 0],
46
+ reject: [-1, 0],
47
+ skip: [0, -1]
48
+ }, P = m([0, 0]);
49
+ function F(e) {
50
+ let [t, ...n] = D.value;
51
+ t !== void 0 && (P.value = N[e], A.push({
52
+ item: t,
53
+ decision: e
54
+ }), j.value = A.length, D.value = n, O("decide", t, e), M.value = `${k.value[e]}. ${n.length} left.`);
55
+ }
56
+ function I() {
57
+ let e = A.pop();
58
+ e && (j.value = A.length, P.value = [0, 0], D.value = [e.item, ...D.value], O("undo", e.item), M.value = `${k.value.undo}. ${D.value.length} left.`);
59
+ }
60
+ u({
61
+ accept: () => F("accept"),
62
+ reject: () => F("reject"),
63
+ skip: () => F("skip"),
64
+ undo: I
65
+ });
66
+ let L = m(null);
67
+ function R(e) {
68
+ e.button || (e.currentTarget.setPointerCapture?.(e.pointerId), L.value = {
69
+ x: 0,
70
+ y: 0,
71
+ sx: e.clientX,
72
+ sy: e.clientY
73
+ });
74
+ }
75
+ function z(e) {
76
+ let t = L.value;
77
+ t && (t.x = e.clientX - t.sx, t.y = e.clientY - t.sy);
78
+ }
79
+ function B() {
80
+ let e = L.value;
81
+ if (!e) return;
82
+ let t = E.threshold, n = Math.abs(e.x), r = Math.abs(e.y), i = n >= r && n > t ? e.x > 0 ? "accept" : "reject" : r > n && e.y < -t ? "skip" : null;
83
+ i && F(i), L.value = null;
84
+ }
85
+ let V = r(() => {
86
+ let e = L.value;
87
+ if (!e) return {
88
+ accept: 0,
89
+ reject: 0,
90
+ skip: 0
91
+ };
92
+ let t = (e) => Math.min(1, Math.max(0, e / E.threshold));
93
+ return {
94
+ accept: t(e.x),
95
+ reject: t(-e.x),
96
+ skip: t(-e.y)
97
+ };
98
+ }), H = r(() => {
99
+ let e = L.value;
100
+ return e ? {
101
+ transform: `translate(${e.x}px, ${e.y}px) rotate(${e.x / 24}deg)`,
102
+ transition: "none"
103
+ } : void 0;
104
+ });
105
+ function U(e) {
106
+ let t = {
107
+ ArrowRight: "accept",
108
+ ArrowLeft: "reject",
109
+ ArrowUp: "skip"
110
+ };
111
+ t[e.key] ? (e.preventDefault(), F(t[e.key])) : (e.key === "Backspace" || (e.ctrlKey || e.metaKey) && e.key === "z") && (e.preventDefault(), I());
112
+ }
113
+ let W = r(() => D.value.slice(0, 3));
114
+ return (r, u) => (p(), a("div", {
115
+ class: "bless-deck",
116
+ style: f({
117
+ "--bless-deck-x": P.value[0],
118
+ "--bless-deck-y": P.value[1]
119
+ })
120
+ }, [
121
+ o("div", {
122
+ class: "bless-deck__stage",
123
+ tabindex: "0",
124
+ role: "group",
125
+ "aria-roledescription": "deck of cards",
126
+ "aria-label": `${l.label}, ${D.value.length} left. Right arrow ${k.value.accept}, left arrow ${k.value.reject}, up arrow ${k.value.skip}, Backspace ${k.value.undo}.`,
127
+ onKeydown: U
128
+ }, [c(n, { name: "bless-deck" }, {
129
+ default: y(() => [(p(!0), a(t, null, h(W.value, (e, n) => (p(), a("div", {
130
+ key: l.rowKey ? l.rowKey(e) : D.value.length - n,
131
+ class: d(["bless-deck__card", { "bless-deck__card--top": n === 0 }]),
132
+ style: f(n === 0 ? H.value : { "--bless-deck-depth": n }),
133
+ "aria-hidden": n > 0 || void 0,
134
+ inert: n > 0 || void 0,
135
+ onPointerdown: (e) => n === 0 && R(e),
136
+ onPointermove: (e) => n === 0 && z(e),
137
+ onPointerup: (e) => n === 0 && B(),
138
+ onPointercancel: (e) => n === 0 && (L.value = null)
139
+ }, [g(r.$slots, "card", {
140
+ item: e,
141
+ index: n
142
+ }, () => [s(_(e), 1)]), n === 0 ? (p(), a(t, { key: 0 }, [
143
+ o("span", {
144
+ class: "bless-deck__stamp bless-deck__stamp--accept",
145
+ "aria-hidden": "true",
146
+ style: f({ opacity: V.value.accept })
147
+ }, _(k.value.accept), 5),
148
+ o("span", {
149
+ class: "bless-deck__stamp bless-deck__stamp--reject",
150
+ "aria-hidden": "true",
151
+ style: f({ opacity: V.value.reject })
152
+ }, _(k.value.reject), 5),
153
+ o("span", {
154
+ class: "bless-deck__stamp bless-deck__stamp--skip",
155
+ "aria-hidden": "true",
156
+ style: f({ opacity: V.value.skip })
157
+ }, _(k.value.skip), 5)
158
+ ], 64)) : i("", !0)], 46, x))), 128))]),
159
+ _: 3
160
+ }), D.value.length ? i("", !0) : (p(), a("div", S, [g(r.$slots, "empty", {}, () => [u[3] ||= s("No cards left", -1)])]))], 40, b),
161
+ l.controls ? (p(), a("div", C, [
162
+ c(e, {
163
+ variant: "outline",
164
+ disabled: !j.value,
165
+ onClick: I
166
+ }, {
167
+ default: y(() => [s(_(k.value.undo), 1)]),
168
+ _: 1
169
+ }, 8, ["disabled"]),
170
+ c(e, {
171
+ variant: "outline",
172
+ disabled: !D.value.length,
173
+ onClick: u[0] ||= (e) => F("reject")
174
+ }, {
175
+ default: y(() => [s(_(k.value.reject), 1)]),
176
+ _: 1
177
+ }, 8, ["disabled"]),
178
+ c(e, {
179
+ variant: "outline",
180
+ disabled: !D.value.length,
181
+ onClick: u[1] ||= (e) => F("skip")
182
+ }, {
183
+ default: y(() => [s(_(k.value.skip), 1)]),
184
+ _: 1
185
+ }, 8, ["disabled"]),
186
+ c(e, {
187
+ disabled: !D.value.length,
188
+ onClick: u[2] ||= (e) => F("accept")
189
+ }, {
190
+ default: y(() => [s(_(k.value.accept), 1)]),
191
+ _: 1
192
+ }, 8, ["disabled"])
193
+ ])) : i("", !0),
194
+ o("span", w, _(M.value), 1)
195
+ ], 4));
196
+ }
197
+ });
198
+ //#endregion
199
+ export { T as default };
@@ -0,0 +1 @@
1
+ .bless-timer{align-items:center;gap:var(--bless-space-2);font-family:var(--bless-font-sans);color:var(--bless-color-text);flex-direction:column;display:inline-flex;position:relative}.bless-timer__clock{font-size:calc(var(--bless-text-xl) * 1.6);font-variant-numeric:tabular-nums;font-weight:600;line-height:1}.bless-timer__phase{font-size:var(--bless-text-sm);color:var(--bless-color-text-muted)}.bless-timer--done .bless-timer__clock{color:var(--bless-color-danger-text)}.bless-timer__controls{gap:var(--bless-space-2);display:inline-flex}.bless-timer__live{clip-path:inset(50%);width:1px;height:1px;position:absolute;overflow:hidden}
@@ -0,0 +1,6 @@
1
+ import "./BlessTimer.css";
2
+ import e from "./BlessTimer.vue_vue_type_script_setup_true_lang.js";
3
+ //#region src/components/BlessTimer.vue
4
+ var t = e;
5
+ //#endregion
6
+ export { t as default };
@@ -0,0 +1,56 @@
1
+ export interface BlessTimerPhase {
2
+ label: string;
3
+ seconds: number;
4
+ }
5
+ declare const _default: typeof __VLS_export;
6
+ export default _default;
7
+ declare const __VLS_export: import('vue').DefineComponent<{
8
+ /** `countdown` from `duration`, `stopwatch` up from 0, `interval` through `phases` */
9
+ mode?: "countdown" | "stopwatch" | "interval";
10
+ /** seconds, for a countdown */
11
+ duration?: number;
12
+ /** for `interval`: e.g. `[{ label: "Work", seconds: 25 }, { label: "Rest", seconds: 5 }]` */
13
+ phases?: BlessTimerPhase[];
14
+ /** how many times the phases repeat */
15
+ rounds?: number;
16
+ autostart?: boolean;
17
+ /** show Start / Pause / Reset */
18
+ controls?: boolean;
19
+ label?: string;
20
+ } & {
21
+ running?: boolean;
22
+ }, {
23
+ start: () => void;
24
+ pause: () => void;
25
+ reset: () => void;
26
+ toggle: () => boolean;
27
+ }, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
28
+ "update:running": (value: boolean) => any;
29
+ finish: () => any;
30
+ phase: (phase: BlessTimerPhase, index: number, round: number) => any;
31
+ }, string, import('vue').PublicProps, Readonly<{
32
+ /** `countdown` from `duration`, `stopwatch` up from 0, `interval` through `phases` */
33
+ mode?: "countdown" | "stopwatch" | "interval";
34
+ /** seconds, for a countdown */
35
+ duration?: number;
36
+ /** for `interval`: e.g. `[{ label: "Work", seconds: 25 }, { label: "Rest", seconds: 5 }]` */
37
+ phases?: BlessTimerPhase[];
38
+ /** how many times the phases repeat */
39
+ rounds?: number;
40
+ autostart?: boolean;
41
+ /** show Start / Pause / Reset */
42
+ controls?: boolean;
43
+ label?: string;
44
+ } & {
45
+ running?: boolean;
46
+ }> & Readonly<{
47
+ "onUpdate:running"?: ((value: boolean) => any) | undefined;
48
+ onFinish?: (() => any) | undefined;
49
+ onPhase?: ((phase: BlessTimerPhase, index: number, round: number) => any) | undefined;
50
+ }>, {
51
+ label: string;
52
+ mode: "countdown" | "stopwatch" | "interval";
53
+ duration: number;
54
+ rounds: number;
55
+ controls: boolean;
56
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
@@ -0,0 +1,130 @@
1
+ import e from "./BlessButton.js";
2
+ import { computed as t, createBlock as n, createCommentVNode as r, createElementBlock as i, createElementVNode as a, createTextVNode as o, createVNode as s, defineComponent as c, mergeModels as l, normalizeClass as u, onBeforeUnmount as d, openBlock as f, ref as p, toDisplayString as m, useModel as h, watch as g, withCtx as _ } from "vue";
3
+ //#region src/components/BlessTimer.vue?vue&type=script&setup=true&lang.ts
4
+ var v = ["aria-label"], y = {
5
+ key: 0,
6
+ class: "bless-timer__phase"
7
+ }, b = { class: "bless-timer__clock" }, x = {
8
+ key: 1,
9
+ class: "bless-timer__controls"
10
+ }, S = {
11
+ class: "bless-timer__live",
12
+ "aria-live": "polite"
13
+ }, C = /*@__PURE__*/ c({
14
+ name: "BlessTimer",
15
+ __name: "BlessTimer",
16
+ props: /*@__PURE__*/ l({
17
+ mode: { default: "countdown" },
18
+ duration: { default: 60 },
19
+ phases: {},
20
+ rounds: { default: 1 },
21
+ autostart: { type: Boolean },
22
+ controls: {
23
+ type: Boolean,
24
+ default: !0
25
+ },
26
+ label: { default: "Timer" }
27
+ }, {
28
+ running: {
29
+ type: Boolean,
30
+ default: !1
31
+ },
32
+ runningModifiers: {}
33
+ }),
34
+ emits: /*@__PURE__*/ l(["finish", "phase"], ["update:running"]),
35
+ setup(c, { expose: l, emit: C }) {
36
+ let w = c, T = h(c, "running"), E = C, D = p(0), O = p(!1), k = p(""), A = 0, j = 0, M, N = t(() => w.mode === "interval" ? w.phases ?? [] : [{
37
+ label: "",
38
+ seconds: w.duration
39
+ }]), P = t(() => w.mode === "interval" ? w.rounds : 1), F = t(() => N.value.reduce((e, t) => e + t.seconds, 0) * 1e3), I = t(() => F.value * P.value), L = t(() => {
40
+ if (w.mode === "stopwatch") return {
41
+ i: 0,
42
+ round: 1,
43
+ left: D.value
44
+ };
45
+ let e = Math.min(D.value, I.value), t = F.value ? e >= I.value ? F.value : e % F.value : 0, n = Math.min(P.value, Math.floor(e / (F.value || 1)) + 1), r = 0;
46
+ for (let i = 0; i < N.value.length; i++) {
47
+ let a = N.value[i].seconds * 1e3;
48
+ if (t < r + a || i === N.value.length - 1) return {
49
+ i,
50
+ round: e >= I.value ? P.value : n,
51
+ left: Math.max(0, r + a - t)
52
+ };
53
+ r += a;
54
+ }
55
+ return {
56
+ i: 0,
57
+ round: 1,
58
+ left: 0
59
+ };
60
+ }), R = (e) => String(e).padStart(2, "0"), z = (e, t) => {
61
+ let n = t ? Math.floor(e / 1e3) : Math.ceil(e / 1e3), r = Math.floor(n / 3600), i = Math.floor(n % 3600 / 60);
62
+ return `${r ? `${r}:${R(i)}` : R(i)}:${R(n % 60)}`;
63
+ }, B = t(() => z(L.value.left, w.mode === "stopwatch")), V = t(() => w.mode === "interval" ? N.value[L.value.i] : void 0), H = t(() => V.value ? `${V.value.label} · round ${L.value.round} of ${P.value}` : "");
64
+ function U() {
65
+ D.value = A + (performance.now() - j), w.mode !== "stopwatch" && D.value >= I.value && (D.value = I.value, W(), O.value = !0, T.value = !1, k.value = "Finished", E("finish"));
66
+ }
67
+ function W() {
68
+ clearInterval(M), M = void 0;
69
+ }
70
+ function G() {
71
+ M || w.mode !== "stopwatch" && !I.value || (O.value && J(), A = D.value, j = performance.now(), M = setInterval(U, 100));
72
+ }
73
+ function K() {
74
+ T.value = !0;
75
+ }
76
+ function q() {
77
+ T.value = !1;
78
+ }
79
+ function J() {
80
+ W(), D.value = 0, A = 0, O.value = !1, k.value = "", T.value && G();
81
+ }
82
+ return g(T, (e) => {
83
+ e ? G() : M && (U(), W());
84
+ }, { immediate: !1 }), w.autostart && (T.value = !0), g(() => [
85
+ w.mode,
86
+ w.duration,
87
+ w.phases,
88
+ w.rounds
89
+ ], () => J()), g(() => `${L.value.i}:${L.value.round}`, (e, t) => {
90
+ let n = N.value[L.value.i];
91
+ t !== void 0 && n && w.mode === "interval" && T.value && (k.value = `${n.label}, round ${L.value.round} of ${P.value}`, E("phase", n, L.value.i, L.value.round));
92
+ }), d(W), l({
93
+ start: K,
94
+ pause: q,
95
+ reset: J,
96
+ toggle: () => T.value = !T.value
97
+ }), (t, l) => (f(), i("div", {
98
+ class: u(["bless-timer", { "bless-timer--done": O.value }]),
99
+ role: "timer",
100
+ "aria-label": c.label
101
+ }, [
102
+ H.value ? (f(), i("span", y, m(H.value), 1)) : r("", !0),
103
+ a("span", b, m(B.value), 1),
104
+ c.controls ? (f(), i("span", x, [T.value ? (f(), n(e, {
105
+ key: 1,
106
+ variant: "outline",
107
+ onClick: q
108
+ }, {
109
+ default: _(() => [...l[0] ||= [o("Pause", -1)]]),
110
+ _: 1
111
+ })) : (f(), n(e, {
112
+ key: 0,
113
+ onClick: K
114
+ }, {
115
+ default: _(() => [o(m(D.value && !O.value ? "Resume" : "Start"), 1)]),
116
+ _: 1
117
+ })), s(e, {
118
+ variant: "ghost",
119
+ disabled: !D.value,
120
+ onClick: J
121
+ }, {
122
+ default: _(() => [...l[1] ||= [o("Reset", -1)]]),
123
+ _: 1
124
+ }, 8, ["disabled"])])) : r("", !0),
125
+ a("span", S, m(k.value), 1)
126
+ ], 10, v));
127
+ }
128
+ });
129
+ //#endregion
130
+ export { C as default };
@@ -0,0 +1,22 @@
1
+ /** A crop box as fractions (0..1) of the displayed image: left, top, right, bottom. */
2
+ export interface CropBox {
3
+ l: number;
4
+ t: number;
5
+ r: number;
6
+ b: number;
7
+ }
8
+ export declare const MIN = 0.05;
9
+ /**
10
+ * Largest centred box covering `fill` of the image. `ratio` is width / height in fractions
11
+ * (pixel aspect × image height / image width); 0 means free.
12
+ */
13
+ export declare function initialBox(ratio: number, fill?: number): CropBox;
14
+ /** Shift the whole box by (dx, dy) fractions, stopping at the image edge. */
15
+ export declare function moveBox(box: CropBox, dx: number, dy: number): CropBox;
16
+ /**
17
+ * Drag the handle `h` ("n", "se", …) to the point (x, y). The opposite edges stay put; with a
18
+ * `ratio` (corners only) the box keeps its shape by giving up the longer side.
19
+ */
20
+ export declare function resizeBox(box: CropBox, h: string, x: number, y: number, ratio?: number): CropBox;
21
+ /** Grow (+) or shrink (−) around the centre by `d` of the image, keeping shape and staying inside. */
22
+ export declare function scaleBox(box: CropBox, d: number): CropBox;
@@ -0,0 +1,39 @@
1
+ //#region src/composables/cropBox.ts
2
+ var e = .05, t = (e, t, n) => Math.min(Math.max(e, t), n);
3
+ function n(e, t = .9) {
4
+ let n = t, r = t;
5
+ return e > 0 && (e > 1 ? r = n / e : n = r * e), {
6
+ l: (1 - n) / 2,
7
+ t: (1 - r) / 2,
8
+ r: (1 + n) / 2,
9
+ b: (1 + r) / 2
10
+ };
11
+ }
12
+ function r(e, n, r) {
13
+ let i = e.r - e.l, a = e.b - e.t, o = t(e.l + n, 0, 1 - i), s = t(e.t + r, 0, 1 - a);
14
+ return {
15
+ l: o,
16
+ t: s,
17
+ r: o + i,
18
+ b: s + a
19
+ };
20
+ }
21
+ function i(n, r, i, a, o = 0) {
22
+ let s = { ...n };
23
+ if (r.includes("w") && (s.l = t(i, 0, n.r - e)), r.includes("e") && (s.r = t(i, n.l + e, 1)), r.includes("n") && (s.t = t(a, 0, n.b - e)), r.includes("s") && (s.b = t(a, n.t + e, 1)), o > 0 && r.length === 2) {
24
+ let e = s.r - s.l, t = s.b - s.t, n = e / t > o ? t * o : e, i = e / t > o ? t : e / o;
25
+ r.includes("e") ? s.r = s.l + n : s.l = s.r - n, r.includes("s") ? s.b = s.t + i : s.t = s.b - i;
26
+ }
27
+ return s;
28
+ }
29
+ function a(n, r) {
30
+ let i = n.r - n.l, a = n.b - n.t, o = t((Math.min(i, a) + r) / Math.min(i, a), e / Math.min(i, a), 1 / Math.max(i, a)), s = i * o, c = a * o, l = t((n.l + n.r) / 2, s / 2, 1 - s / 2), u = t((n.t + n.b) / 2, c / 2, 1 - c / 2);
31
+ return {
32
+ l: l - s / 2,
33
+ t: u - c / 2,
34
+ r: l + s / 2,
35
+ b: u + c / 2
36
+ };
37
+ }
38
+ //#endregion
39
+ export { e as MIN, n as initialBox, r as moveBox, i as resizeBox, a as scaleBox };