@dumiflex/wp-kit 0.0.0-stage → 0.3.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 (128) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/LICENSE +674 -0
  3. package/README.md +76 -3
  4. package/package.json +77 -6
  5. package/src/Avatar.vue +83 -0
  6. package/src/Badge.vue +97 -0
  7. package/src/Banner.vue +118 -0
  8. package/src/BookmarkButton.vue +27 -0
  9. package/src/BundleMeta.vue +51 -0
  10. package/src/Button.vue +103 -0
  11. package/src/Card.vue +68 -0
  12. package/src/Checkbox.vue +107 -0
  13. package/src/Chip.vue +97 -0
  14. package/src/ChipToggle.vue +92 -0
  15. package/src/ChoiceCards.vue +133 -0
  16. package/src/CloseButton.vue +69 -0
  17. package/src/CodeBlock.vue +119 -0
  18. package/src/ColorField.vue +206 -0
  19. package/src/ColorPicker.vue +201 -0
  20. package/src/Combobox.vue +334 -0
  21. package/src/ConfirmDialog.vue +163 -0
  22. package/src/ConfirmModal.vue +147 -0
  23. package/src/ConstraintMatrixPreview.vue +708 -0
  24. package/src/ContextMenu.vue +379 -0
  25. package/src/CopyButton.vue +156 -0
  26. package/src/DataTable.vue +292 -0
  27. package/src/DatePicker.vue +234 -0
  28. package/src/DescriptionList.vue +73 -0
  29. package/src/DiffView.vue +68 -0
  30. package/src/Disclosure.vue +166 -0
  31. package/src/DragHandle.vue +49 -0
  32. package/src/Drawer.vue +131 -0
  33. package/src/DropZone.vue +196 -0
  34. package/src/DropdownMenu.vue +72 -0
  35. package/src/EmptyState.vue +111 -0
  36. package/src/Field.vue +28 -0
  37. package/src/HsvPicker.vue +208 -0
  38. package/src/Icon.vue +39 -0
  39. package/src/IconPicker.vue +209 -0
  40. package/src/ImageGrid.vue +125 -0
  41. package/src/InlineEdit.vue +183 -0
  42. package/src/Input.vue +99 -0
  43. package/src/Kbd.vue +56 -0
  44. package/src/KindChip.vue +53 -0
  45. package/src/Lightbox.vue +173 -0
  46. package/src/ListFilter.vue +85 -0
  47. package/src/ListRow.vue +204 -0
  48. package/src/LoadingMark.vue +161 -0
  49. package/src/Logo.vue +60 -0
  50. package/src/Modal.vue +76 -0
  51. package/src/ModalShell.vue +107 -0
  52. package/src/Pagination.vue +106 -0
  53. package/src/Popover.vue +171 -0
  54. package/src/PostCard.vue +211 -0
  55. package/src/ProgressBar.vue +90 -0
  56. package/src/RadioGroup.vue +177 -0
  57. package/src/RangeSlider.vue +183 -0
  58. package/src/RatingBadge.vue +42 -0
  59. package/src/RelativeDate.vue +35 -0
  60. package/src/ResizeHandle.vue +143 -0
  61. package/src/SearchInput.vue +199 -0
  62. package/src/Select.vue +641 -0
  63. package/src/Separator.vue +54 -0
  64. package/src/Skeleton.vue +82 -0
  65. package/src/Slider.vue +198 -0
  66. package/src/SortableList.vue +260 -0
  67. package/src/SplitPane.vue +68 -0
  68. package/src/StarButton.vue +40 -0
  69. package/src/Stepper.vue +141 -0
  70. package/src/SupportLinks.vue +93 -0
  71. package/src/TagInput.vue +300 -0
  72. package/src/Textarea.vue +57 -0
  73. package/src/Timeline.vue +92 -0
  74. package/src/ToastCard.vue +119 -0
  75. package/src/ToastHost.vue +40 -0
  76. package/src/Toggle.vue +36 -0
  77. package/src/TokenizedValue.vue +310 -0
  78. package/src/Toolbar.vue +110 -0
  79. package/src/VirtualList.vue +87 -0
  80. package/src/VisuallyHidden.vue +29 -0
  81. package/src/WpButton.vue +75 -0
  82. package/src/WpCheck.vue +102 -0
  83. package/src/WpIconButton.vue +107 -0
  84. package/src/WpImageZoom.vue +544 -0
  85. package/src/WpNumber.vue +183 -0
  86. package/src/WpSegmented.vue +175 -0
  87. package/src/WpSelect.vue +89 -0
  88. package/src/WpSwitch.vue +163 -0
  89. package/src/WpTabs.vue +188 -0
  90. package/src/_modal-motion.css +33 -0
  91. package/src/_skeleton.css +50 -0
  92. package/src/axis-color.ts +42 -0
  93. package/src/button.css +169 -0
  94. package/src/calendar.ts +59 -0
  95. package/src/clipboard.ts +50 -0
  96. package/src/colour-presets.ts +12 -0
  97. package/src/diff.ts +51 -0
  98. package/src/drop-zone.ts +41 -0
  99. package/src/flip.ts +237 -0
  100. package/src/floating.ts +99 -0
  101. package/src/hsv.ts +100 -0
  102. package/src/icon-catalog.ts +52 -0
  103. package/src/image-zoom.ts +93 -0
  104. package/src/logo-paths.ts +21 -0
  105. package/src/matrix-axis.ts +91 -0
  106. package/src/pagination.ts +27 -0
  107. package/src/platform-keys.ts +29 -0
  108. package/src/rich-tokenize.ts +357 -0
  109. package/src/select-types.ts +32 -0
  110. package/src/slider-math.ts +45 -0
  111. package/src/sortable.ts +22 -0
  112. package/src/theme/fonts/OFL-Fraunces.txt +93 -0
  113. package/src/theme/fonts/OFL-JetBrainsMono.txt +93 -0
  114. package/src/theme/fonts/OFL-Manrope.txt +93 -0
  115. package/src/theme/fonts/fraunces-latin-wght-normal.woff2 +0 -0
  116. package/src/theme/fonts/jetbrains-mono-latin.woff2 +0 -0
  117. package/src/theme/fonts/manrope-latin-wght-normal.woff2 +0 -0
  118. package/src/theme/looks.css +428 -0
  119. package/src/theme/palettes.css +254 -0
  120. package/src/theme/tokens.css +2894 -0
  121. package/src/tokens.ts +56 -0
  122. package/src/tooltip.css +43 -0
  123. package/src/tooltip.ts +146 -0
  124. package/src/useDialogFocus.ts +73 -0
  125. package/src/useGrowableField.ts +357 -0
  126. package/src/useModalKeyShield.ts +116 -0
  127. package/src/useToast.ts +48 -0
  128. package/src/wp-logo.svg +14 -0
@@ -0,0 +1,116 @@
1
+ import { onBeforeUnmount, watch, type Ref } from "vue";
2
+
3
+ /**
4
+ * Stop keystrokes inside one of our modals from reaching ComfyUI's global
5
+ * shortcuts.
6
+ *
7
+ * ComfyUI binds `useEventListener(window, 'keydown', keybindHandler)` and only
8
+ * bails for text-editing targets:
9
+ *
10
+ * const target = event.composedPath()[0]
11
+ * if (keyCombo.isReservedByTextInput &&
12
+ * (target.tagName === 'TEXTAREA' || target.tagName === 'INPUT' ||
13
+ * target.contentEditable === 'true' || ...)) return
14
+ *
15
+ * So a plain letter pressed while focus sits on a button or a div inside our
16
+ * modal is not "reserved by text input" and runs the global keybinding —
17
+ * pressing `r` in an edit modal fired Refresh Node Definitions and froze the
18
+ * page. Its other guard, which skips global keybindings while a dialog is
19
+ * open, keys off ComfyUI's OWN dialog stack, which our modals never enter.
20
+ *
21
+ * The listener is bound to the modal ROOT in bubble phase. Anything inside the
22
+ * modal has already had its turn by then — inner `@keydown` handlers, input
23
+ * defaults, IME — and the event simply stops before it can climb to window.
24
+ *
25
+ * That alone is not enough, because a key only traverses the overlay if it is
26
+ * TARGETED inside it. Open a modal and type without clicking in it first and
27
+ * `document.activeElement` is still `<body>`, so the event goes body → window
28
+ * and never passes the shield at all — which is how `a` kept reaching ComfyUI
29
+ * even with the root listener in place. Two additions close that:
30
+ *
31
+ * - focus the overlay when it opens, so keystrokes land inside the modal;
32
+ * - guard at the document for keys targeted OUTSIDE the open modal, since a
33
+ * modal owns the keyboard while it is up. Escape still passes, so the
34
+ * modal's own window-level close handler keeps working.
35
+ *
36
+ * Because of that, a modal's own key handling must live on the root too, not
37
+ * on `window`: a window listener sits ABOVE the shield and would never see
38
+ * keys pressed inside its own modal. `onKey` is where that logic goes.
39
+ */
40
+ export interface ModalKeyShieldOptions {
41
+ /** Runs for every keydown inside the modal, before the event is stopped. */
42
+ onKey?: ((event: KeyboardEvent) => void) | undefined;
43
+ /**
44
+ * Let a key through to the rest of the page. Use sparingly — the point of
45
+ * the shield is that a modal owns the keyboard while it is open.
46
+ */
47
+ passThrough?: ((event: KeyboardEvent) => boolean) | undefined;
48
+ }
49
+
50
+ /** Wire the shield to a root element that exists only while the modal is open. */
51
+ export function useModalKeyShield(
52
+ root: Ref<HTMLElement | null | undefined>,
53
+ options: ModalKeyShieldOptions = {},
54
+ ): void {
55
+ let bound: HTMLElement | null = null;
56
+
57
+ const onKeydown = (event: KeyboardEvent): void => {
58
+ options.onKey?.(event);
59
+ if (options.passThrough?.(event)) return;
60
+ // stopPropagation only: the default action still happens, so typing,
61
+ // shortcuts inside inputs and IME composition all behave normally.
62
+ event.stopPropagation();
63
+ };
64
+
65
+ // Keyup carries no handling of ours, but extensions bind shortcuts on it
66
+ // and a half-seen chord is worse than none.
67
+ const onKeyup = (event: KeyboardEvent): void => {
68
+ if (options.passThrough?.(event)) return;
69
+ event.stopPropagation();
70
+ };
71
+
72
+ // Keys aimed outside the open modal — the canvas, the body — never reach the
73
+ // overlay, so they are stopped here instead. Document bubble runs before
74
+ // window, where ComfyUI's keybindHandler lives.
75
+ const onOutside = (event: KeyboardEvent): void => {
76
+ if (!bound) return;
77
+ const target = event.target;
78
+ if (target instanceof Node && bound.contains(target)) return;
79
+ // Escape belongs to whoever wants to close something.
80
+ if (event.key === "Escape") return;
81
+ if (options.passThrough?.(event)) return;
82
+ event.stopPropagation();
83
+ };
84
+
85
+ const detach = (): void => {
86
+ if (!bound) return;
87
+ bound.removeEventListener("keydown", onKeydown);
88
+ bound.removeEventListener("keyup", onKeyup);
89
+ document.removeEventListener("keydown", onOutside);
90
+ document.removeEventListener("keyup", onOutside);
91
+ bound = null;
92
+ };
93
+
94
+ watch(
95
+ root,
96
+ (el) => {
97
+ detach();
98
+ if (!el) return;
99
+ bound = el;
100
+ el.addEventListener("keydown", onKeydown);
101
+ el.addEventListener("keyup", onKeyup);
102
+ document.addEventListener("keydown", onOutside);
103
+ document.addEventListener("keyup", onOutside);
104
+ // Pull focus in, so typing lands inside the modal rather than on <body>.
105
+ // Only when focus is not already somewhere inside — an autofocused input
106
+ // must keep it.
107
+ if (!el.contains(document.activeElement)) {
108
+ if (!el.hasAttribute("tabindex")) el.setAttribute("tabindex", "-1");
109
+ el.focus({ preventScroll: true });
110
+ }
111
+ },
112
+ { immediate: true, flush: "post" },
113
+ );
114
+
115
+ onBeforeUnmount(detach);
116
+ }
@@ -0,0 +1,48 @@
1
+ import { ref } from "vue";
2
+
3
+ export type ToastSeverity = "info" | "success" | "warn" | "error";
4
+
5
+ export interface ToastAction {
6
+ label: string;
7
+ run: () => void | Promise<void>;
8
+ }
9
+
10
+ export interface ToastEntry {
11
+ id: string;
12
+ severity: ToastSeverity;
13
+ summary: string;
14
+ detail?: string;
15
+ life?: number;
16
+ /** Optional action button rendered inline with the toast. Click runs the handler
17
+ * and dismisses the toast. Reserved for Undo flows (Phase 3 bulk actions). */
18
+ action?: ToastAction;
19
+ }
20
+
21
+ const DEFAULT_LIFE = 2400;
22
+
23
+ const toasts = ref<ToastEntry[]>([]);
24
+
25
+ let nextId = 0;
26
+ function makeId() {
27
+ nextId += 1;
28
+ return `t${Date.now().toString(36)}_${nextId}`;
29
+ }
30
+
31
+ function dismiss(id: string) {
32
+ const i = toasts.value.findIndex((t) => t.id === id);
33
+ if (i >= 0) toasts.value.splice(i, 1);
34
+ }
35
+
36
+ function push(entry: Omit<ToastEntry, "id">): string {
37
+ const id = makeId();
38
+ const life = entry.life ?? DEFAULT_LIFE;
39
+ toasts.value.push({ ...entry, id });
40
+ if (life > 0) {
41
+ setTimeout(() => dismiss(id), life);
42
+ }
43
+ return id;
44
+ }
45
+
46
+ export function useToast() {
47
+ return { toasts, push, dismiss };
48
+ }
@@ -0,0 +1,14 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" data-name="Layer 1" viewBox="0 0 1024 1024" width="100%" height="100%"><defs>
2
+ <linearGradient id="wp-logo-grad-a" x1="312.56" y1="897.19" x2="312.56" y2="2" gradientUnits="userSpaceOnUse">
3
+ <stop offset="0" stop-color="#a970ff"></stop>
4
+ <stop offset="1" stop-color="#6366f1"></stop>
5
+ </linearGradient>
6
+ <linearGradient id="wp-logo-grad-b" x1="711.44" y1="126.81" x2="711.44" y2="1022" gradientUnits="userSpaceOnUse">
7
+ <stop offset="0" stop-color="#6366f1"></stop>
8
+ <stop offset="1" stop-color="#33d6c6"></stop>
9
+ </linearGradient>
10
+ </defs><path fill="url(#wp-logo-grad-a)" d="m512,2c-53.6,0-98.47,38.16-108.84,88.73-75.07,19.29-143.32,58.26-198.74,113.68-55.42,55.42-94.39,123.68-113.68,198.74-50.58,10.38-88.73,55.24-88.73,108.84s38.16,98.47,88.73,108.84c13.62,53.14,37.03,102.64,69.77,147.47,37.14,50.86,85.83,93.86,140.81,124.33,5.54,3.08,11.56,4.54,17.48,4.54,12.7,0,25.02-6.72,31.61-18.61,9.68-17.44,3.38-39.42-14.07-49.09-85.32-47.32-147.22-125.71-173.38-218.21,36.3-18.29,61.27-55.92,61.27-99.28s-24.94-80.97-61.23-99.27c34.22-119.96,129.79-215.52,249.74-249.74,18.3,36.29,55.92,61.23,99.27,61.23,61.27,0,111.11-49.84,111.11-111.11S573.27,2,512,2ZM113.11,473.11c21.44,0,38.89,17.44,38.89,38.89,0,20.1-15.32,36.69-34.91,38.69h-.01c-.18.02-.36.03-.53.04-1.13.1-2.28.16-3.43.16-21.44,0-38.89-17.44-38.89-38.89s17.44-38.89,38.89-38.89Zm398.89-321.11c-21.44,0-38.89-17.44-38.89-38.89s17.44-38.89,38.89-38.89,38.89,17.44,38.89,38.89-17.44,38.89-38.89,38.89Z"></path><path fill="url(#wp-logo-grad-b)" d="m933.27,403.16c-13.62-53.14-37.03-102.64-69.77-147.47-37.14-50.86-85.83-93.86-140.81-124.33-17.44-9.68-39.42-3.38-49.09,14.07-9.68,17.44-3.38,39.42,14.07,49.09,85.32,47.32,147.22,125.71,173.38,218.21-36.3,18.29-61.27,55.92-61.27,99.28s24.94,80.97,61.23,99.27c-34.22,119.96-129.79,215.52-249.74,249.74-18.3-36.29-55.92-61.23-99.27-61.23-61.27,0-111.11,49.84-111.11,111.11s49.84,111.11,111.11,111.11c53.6,0,98.47-38.16,108.84-88.73,75.07-19.29,143.32-58.26,198.74-113.68,55.42-55.42,94.39-123.68,113.68-198.74,50.58-10.38,88.73-55.24,88.73-108.84s-38.16-98.47-88.73-108.84Zm-421.27,546.62c-21.44,0-38.89-17.44-38.89-38.89s17.44-38.89,38.89-38.89,38.89,17.44,38.89,38.89-17.44,38.89-38.89,38.89Zm398.89-398.89c-21.44,0-38.89-17.44-38.89-38.89,0-20.03,15.22-36.58,34.72-38.67.38-.04.77-.08,1.16-.11h.02c.99-.08,1.99-.11,2.99-.11,21.44,0,38.89,17.44,38.89,38.89s-17.44,38.89-38.89,38.89Z"></path><g>
11
+ <path fill="#a970ff" d="m735.02,517.56c-153.82,30.87-186.59,63.64-217.46,217.46-1.22,6.08-9.9,6.08-11.12,0-30.87-153.82-63.64-186.59-217.46-217.46-6.08-1.22-6.08-9.9,0-11.12,153.82-30.87,186.59-63.64,217.46-217.46,1.22-6.08,9.9-6.08,11.12,0,30.87,153.82,63.64,186.59,217.46,217.46,6.08,1.22,6.08,9.9,0,11.12Z"></path>
12
+ <path fill="#6366f1" d="m434.06,665.85c-51.08,10.25-61.96,21.13-72.22,72.22-.41,2.02-3.29,2.02-3.69,0-10.25-51.08-21.13-61.96-72.22-72.22-2.02-.41-2.02-3.29,0-3.69,51.08-10.25,61.96-21.13,72.22-72.22.41-2.02,3.29-2.02,3.69,0,10.25,51.08,21.13,61.96,72.22,72.22,2.02.41,2.02,3.29,0,3.69Z"></path>
13
+ <path fill="#33d6c6" d="m738.07,361.84c-51.08,10.25-61.96,21.13-72.22,72.22-.41,2.02-3.29,2.02-3.69,0-10.25-51.08-21.13-61.96-72.22-72.22-2.02-.41-2.02-3.29,0-3.69,51.08-10.25,61.96-21.13,72.22-72.22.41-2.02,3.29-2.02,3.69,0,10.25,51.08,21.13,61.96,72.22,72.22,2.02.41,2.02,3.29,0,3.69Z"></path>
14
+ </g></svg>