@puzzle-ui/ui 0.3.0 → 0.5.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 (240) hide show
  1. package/README.md +70 -70
  2. package/dist/components/actions/button/button.css +5 -2
  3. package/dist/components/actions/button-group/button-group.css +16 -17
  4. package/dist/components/data-display/badge/badge.css +15 -2
  5. package/dist/components/data-display/badge/index.cjs +13 -2
  6. package/dist/components/data-display/badge/index.cjs.map +1 -1
  7. package/dist/components/data-display/badge/index.d.cts +7 -2
  8. package/dist/components/data-display/badge/index.d.ts +7 -2
  9. package/dist/components/data-display/badge/index.js +13 -2
  10. package/dist/components/data-display/badge/index.js.map +1 -1
  11. package/dist/components/data-display/empty-state/empty-state.css +128 -0
  12. package/dist/components/data-display/empty-state/empty-state.utils.cjs +6 -0
  13. package/dist/components/data-display/empty-state/empty-state.utils.cjs.map +1 -0
  14. package/dist/components/data-display/empty-state/empty-state.utils.js +6 -0
  15. package/dist/components/data-display/empty-state/empty-state.utils.js.map +1 -0
  16. package/dist/components/data-display/empty-state/index.cjs +49 -0
  17. package/dist/components/data-display/empty-state/index.cjs.map +1 -0
  18. package/dist/components/data-display/empty-state/index.d.cts +19 -0
  19. package/dist/components/data-display/empty-state/index.d.ts +19 -0
  20. package/dist/components/data-display/empty-state/index.js +44 -0
  21. package/dist/components/data-display/empty-state/index.js.map +1 -0
  22. package/dist/components/data-display/rating/index.cjs +84 -0
  23. package/dist/components/data-display/rating/index.cjs.map +1 -0
  24. package/dist/components/data-display/rating/index.d.cts +3 -0
  25. package/dist/components/data-display/rating/index.d.ts +3 -0
  26. package/dist/components/data-display/rating/index.js +84 -0
  27. package/dist/components/data-display/rating/index.js.map +1 -0
  28. package/dist/components/data-display/rating/rating.css +72 -0
  29. package/dist/components/data-display/rating/rating.types.d.cts +15 -0
  30. package/dist/components/data-display/rating/rating.types.d.ts +15 -0
  31. package/dist/components/data-display/rating/rating.utils.cjs +27 -0
  32. package/dist/components/data-display/rating/rating.utils.cjs.map +1 -0
  33. package/dist/components/data-display/rating/rating.utils.js +25 -0
  34. package/dist/components/data-display/rating/rating.utils.js.map +1 -0
  35. package/dist/components/editors/text-editor/editor.cjs.map +1 -1
  36. package/dist/components/editors/text-editor/editor.js.map +1 -1
  37. package/dist/components/editors/text-editor/text-document.cjs.map +1 -1
  38. package/dist/components/editors/text-editor/text-document.js.map +1 -1
  39. package/dist/components/editors/text-editor/text-parser.cjs.map +1 -1
  40. package/dist/components/editors/text-editor/text-parser.js.map +1 -1
  41. package/dist/components/editors/text-editor/text-renderer.cjs.map +1 -1
  42. package/dist/components/editors/text-editor/text-renderer.js.map +1 -1
  43. package/dist/components/forms/autocomplete/index.cjs.map +1 -1
  44. package/dist/components/forms/autocomplete/index.js.map +1 -1
  45. package/dist/components/forms/checkbox/checkbox.css +2 -10
  46. package/dist/components/forms/color-picker/color-picker.css +351 -0
  47. package/dist/components/forms/color-picker/color-picker.types.d.cts +25 -0
  48. package/dist/components/forms/color-picker/color-picker.types.d.ts +25 -0
  49. package/dist/components/forms/color-picker/color-picker.utils.cjs +116 -0
  50. package/dist/components/forms/color-picker/color-picker.utils.cjs.map +1 -0
  51. package/dist/components/forms/color-picker/color-picker.utils.js +109 -0
  52. package/dist/components/forms/color-picker/color-picker.utils.js.map +1 -0
  53. package/dist/components/forms/color-picker/index.cjs +340 -0
  54. package/dist/components/forms/color-picker/index.cjs.map +1 -0
  55. package/dist/components/forms/color-picker/index.d.cts +3 -0
  56. package/dist/components/forms/color-picker/index.d.ts +3 -0
  57. package/dist/components/forms/color-picker/index.js +340 -0
  58. package/dist/components/forms/color-picker/index.js.map +1 -0
  59. package/dist/components/forms/file-upload/file-upload.utils.cjs.map +1 -1
  60. package/dist/components/forms/file-upload/file-upload.utils.js.map +1 -1
  61. package/dist/components/forms/input/number-input.js +5 -5
  62. package/dist/components/forms/input/number-input.js.map +1 -1
  63. package/dist/components/forms/input-group/index.d.cts +3 -0
  64. package/dist/components/forms/input-group/index.d.ts +3 -0
  65. package/dist/components/forms/input-group/input-group.cjs +18 -0
  66. package/dist/components/forms/input-group/input-group.cjs.map +1 -0
  67. package/dist/components/forms/input-group/input-group.css +62 -0
  68. package/dist/components/forms/input-group/input-group.d.cts +7 -0
  69. package/dist/components/forms/input-group/input-group.d.ts +7 -0
  70. package/dist/components/forms/input-group/input-group.js +18 -0
  71. package/dist/components/forms/input-group/input-group.js.map +1 -0
  72. package/dist/components/forms/input-group/input-group.types.d.cts +7 -0
  73. package/dist/components/forms/input-group/input-group.types.d.ts +7 -0
  74. package/dist/components/forms/input-group/input-group.utils.cjs +5 -0
  75. package/dist/components/forms/input-group/input-group.utils.cjs.map +1 -0
  76. package/dist/components/forms/input-group/input-group.utils.js +5 -0
  77. package/dist/components/forms/input-group/input-group.utils.js.map +1 -0
  78. package/dist/components/forms/radio-group/index.d.cts +2 -1
  79. package/dist/components/forms/radio-group/index.d.ts +2 -1
  80. package/dist/components/forms/select/index.cjs.map +1 -1
  81. package/dist/components/forms/select/index.js.map +1 -1
  82. package/dist/components/forms/slider/index.cjs +1 -1
  83. package/dist/components/forms/slider/index.cjs.map +1 -1
  84. package/dist/components/forms/slider/index.js +1 -1
  85. package/dist/components/forms/slider/index.js.map +1 -1
  86. package/dist/components/forms/stepper/index.d.cts +4 -2
  87. package/dist/components/forms/stepper/index.d.ts +4 -2
  88. package/dist/components/forms/time-picker/index.cjs +108 -0
  89. package/dist/components/forms/time-picker/index.cjs.map +1 -0
  90. package/dist/components/forms/time-picker/index.d.cts +3 -0
  91. package/dist/components/forms/time-picker/index.d.ts +3 -0
  92. package/dist/components/forms/time-picker/index.js +108 -0
  93. package/dist/components/forms/time-picker/index.js.map +1 -0
  94. package/dist/components/forms/time-picker/time-picker.css +166 -0
  95. package/dist/components/forms/time-picker/time-picker.types.d.cts +34 -0
  96. package/dist/components/forms/time-picker/time-picker.types.d.ts +34 -0
  97. package/dist/components/forms/time-picker/time-picker.utils.cjs +25 -0
  98. package/dist/components/forms/time-picker/time-picker.utils.cjs.map +1 -0
  99. package/dist/components/forms/time-picker/time-picker.utils.js +24 -0
  100. package/dist/components/forms/time-picker/time-picker.utils.js.map +1 -0
  101. package/dist/components/forms/token-input/index.cjs +189 -0
  102. package/dist/components/forms/token-input/index.cjs.map +1 -0
  103. package/dist/components/forms/token-input/index.d.cts +3 -0
  104. package/dist/components/forms/token-input/index.d.ts +3 -0
  105. package/dist/components/forms/token-input/index.js +189 -0
  106. package/dist/components/forms/token-input/index.js.map +1 -0
  107. package/dist/components/forms/token-input/token-input.css +145 -0
  108. package/dist/components/forms/token-input/token-input.types.d.cts +48 -0
  109. package/dist/components/forms/token-input/token-input.types.d.ts +48 -0
  110. package/dist/components/forms/token-input/token-input.utils.cjs +30 -0
  111. package/dist/components/forms/token-input/token-input.utils.cjs.map +1 -0
  112. package/dist/components/forms/token-input/token-input.utils.js +24 -0
  113. package/dist/components/forms/token-input/token-input.utils.js.map +1 -0
  114. package/dist/components/layout/aspect-ratio/aspect-ratio.css +14 -0
  115. package/dist/components/layout/aspect-ratio/aspect-ratio.utils.cjs +11 -0
  116. package/dist/components/layout/aspect-ratio/aspect-ratio.utils.cjs.map +1 -0
  117. package/dist/components/layout/aspect-ratio/aspect-ratio.utils.js +11 -0
  118. package/dist/components/layout/aspect-ratio/aspect-ratio.utils.js.map +1 -0
  119. package/dist/components/layout/aspect-ratio/index.cjs +16 -0
  120. package/dist/components/layout/aspect-ratio/index.cjs.map +1 -0
  121. package/dist/components/layout/aspect-ratio/index.d.cts +11 -0
  122. package/dist/components/layout/aspect-ratio/index.d.ts +11 -0
  123. package/dist/components/layout/aspect-ratio/index.js +16 -0
  124. package/dist/components/layout/aspect-ratio/index.js.map +1 -0
  125. package/dist/components/layout/container/container.css +1 -0
  126. package/dist/components/layout/page-layout/page-layout.css +1 -0
  127. package/dist/components/layout/resizable-panels/index.cjs +1 -1
  128. package/dist/components/layout/resizable-panels/index.cjs.map +1 -1
  129. package/dist/components/layout/resizable-panels/index.js +1 -1
  130. package/dist/components/layout/resizable-panels/index.js.map +1 -1
  131. package/dist/components/layout/resizable-panels/resizable-panels.utils.cjs.map +1 -1
  132. package/dist/components/layout/resizable-panels/resizable-panels.utils.js.map +1 -1
  133. package/dist/components/layout/scroll-area/index.cjs +27 -0
  134. package/dist/components/layout/scroll-area/index.cjs.map +1 -0
  135. package/dist/components/layout/scroll-area/index.d.cts +15 -0
  136. package/dist/components/layout/scroll-area/index.d.ts +15 -0
  137. package/dist/components/layout/scroll-area/index.js +27 -0
  138. package/dist/components/layout/scroll-area/index.js.map +1 -0
  139. package/dist/components/layout/scroll-area/scroll-area.css +25 -0
  140. package/dist/components/layout/scroll-area/scroll-area.utils.cjs +8 -0
  141. package/dist/components/layout/scroll-area/scroll-area.utils.cjs.map +1 -0
  142. package/dist/components/layout/scroll-area/scroll-area.utils.d.cts +2 -0
  143. package/dist/components/layout/scroll-area/scroll-area.utils.d.ts +2 -0
  144. package/dist/components/layout/scroll-area/scroll-area.utils.js +8 -0
  145. package/dist/components/layout/scroll-area/scroll-area.utils.js.map +1 -0
  146. package/dist/components/layout/section/index.cjs +10 -4
  147. package/dist/components/layout/section/index.cjs.map +1 -1
  148. package/dist/components/layout/section/index.d.cts +1 -1
  149. package/dist/components/layout/section/index.d.ts +1 -1
  150. package/dist/components/layout/section/index.js +11 -5
  151. package/dist/components/layout/section/index.js.map +1 -1
  152. package/dist/components/layout/section/section.css +9 -3
  153. package/dist/components/layout/section/types.d.cts +5 -5
  154. package/dist/components/layout/section/types.d.ts +5 -5
  155. package/dist/components/layout/separator/index.cjs +18 -0
  156. package/dist/components/layout/separator/index.cjs.map +1 -0
  157. package/dist/components/layout/separator/index.d.cts +17 -0
  158. package/dist/components/layout/separator/index.d.ts +17 -0
  159. package/dist/components/layout/separator/index.js +18 -0
  160. package/dist/components/layout/separator/index.js.map +1 -0
  161. package/dist/components/layout/separator/separator.css +15 -0
  162. package/dist/components/layout/separator/separator.utils.cjs +11 -0
  163. package/dist/components/layout/separator/separator.utils.cjs.map +1 -0
  164. package/dist/components/layout/separator/separator.utils.d.cts +2 -0
  165. package/dist/components/layout/separator/separator.utils.d.ts +2 -0
  166. package/dist/components/layout/separator/separator.utils.js +11 -0
  167. package/dist/components/layout/separator/separator.utils.js.map +1 -0
  168. package/dist/components/layout/stack/index.cjs +18 -2
  169. package/dist/components/layout/stack/index.cjs.map +1 -1
  170. package/dist/components/layout/stack/index.d.cts +8 -6
  171. package/dist/components/layout/stack/index.d.ts +8 -6
  172. package/dist/components/layout/stack/index.js +18 -2
  173. package/dist/components/layout/stack/index.js.map +1 -1
  174. package/dist/components/layout/stack/stack.css +118 -138
  175. package/dist/components/navigation/accordion/index.cjs.map +1 -1
  176. package/dist/components/navigation/accordion/index.js.map +1 -1
  177. package/dist/components/navigation/carousel/index.cjs +5 -2
  178. package/dist/components/navigation/carousel/index.cjs.map +1 -1
  179. package/dist/components/navigation/carousel/index.js +5 -2
  180. package/dist/components/navigation/carousel/index.js.map +1 -1
  181. package/dist/components/navigation/pagination/index.cjs +146 -0
  182. package/dist/components/navigation/pagination/index.cjs.map +1 -0
  183. package/dist/components/navigation/pagination/index.d.cts +3 -0
  184. package/dist/components/navigation/pagination/index.d.ts +3 -0
  185. package/dist/components/navigation/pagination/index.js +146 -0
  186. package/dist/components/navigation/pagination/index.js.map +1 -0
  187. package/dist/components/navigation/pagination/pagination.css +134 -0
  188. package/dist/components/navigation/pagination/pagination.types.d.cts +38 -0
  189. package/dist/components/navigation/pagination/pagination.types.d.ts +38 -0
  190. package/dist/components/navigation/pagination/pagination.utils.cjs +54 -0
  191. package/dist/components/navigation/pagination/pagination.utils.cjs.map +1 -0
  192. package/dist/components/navigation/pagination/pagination.utils.js +53 -0
  193. package/dist/components/navigation/pagination/pagination.utils.js.map +1 -0
  194. package/dist/components/navigation/tabs/index.d.cts +3 -2
  195. package/dist/components/navigation/tabs/index.d.ts +3 -2
  196. package/dist/components/navigation/tree-view/index.cjs.map +1 -1
  197. package/dist/components/navigation/tree-view/index.js.map +1 -1
  198. package/dist/components/overlays/context-menu/context-menu.css +151 -0
  199. package/dist/components/overlays/context-menu/context-menu.types.d.cts +69 -0
  200. package/dist/components/overlays/context-menu/context-menu.types.d.ts +69 -0
  201. package/dist/components/overlays/context-menu/context-menu.utils.cjs +46 -0
  202. package/dist/components/overlays/context-menu/context-menu.utils.cjs.map +1 -0
  203. package/dist/components/overlays/context-menu/context-menu.utils.js +40 -0
  204. package/dist/components/overlays/context-menu/context-menu.utils.js.map +1 -0
  205. package/dist/components/overlays/context-menu/index.cjs +830 -0
  206. package/dist/components/overlays/context-menu/index.cjs.map +1 -0
  207. package/dist/components/overlays/context-menu/index.d.cts +42 -0
  208. package/dist/components/overlays/context-menu/index.d.ts +42 -0
  209. package/dist/components/overlays/context-menu/index.js +818 -0
  210. package/dist/components/overlays/context-menu/index.js.map +1 -0
  211. package/dist/components/overlays/dropdown-menu/dropdown-menu-content.cjs.map +1 -1
  212. package/dist/components/overlays/dropdown-menu/dropdown-menu-content.js.map +1 -1
  213. package/dist/components/overlays/dropdown-menu/dropdown-menu.utils.cjs.map +1 -1
  214. package/dist/components/overlays/dropdown-menu/dropdown-menu.utils.js.map +1 -1
  215. package/dist/components/typography/heading.cjs +6 -2
  216. package/dist/components/typography/heading.cjs.map +1 -1
  217. package/dist/components/typography/heading.d.cts +3 -2
  218. package/dist/components/typography/heading.d.ts +3 -2
  219. package/dist/components/typography/heading.js +6 -2
  220. package/dist/components/typography/heading.js.map +1 -1
  221. package/dist/components/typography/text.cjs +6 -2
  222. package/dist/components/typography/text.cjs.map +1 -1
  223. package/dist/components/typography/text.d.cts +3 -2
  224. package/dist/components/typography/text.d.ts +3 -2
  225. package/dist/components/typography/text.js +6 -2
  226. package/dist/components/typography/text.js.map +1 -1
  227. package/dist/components/utilities/preview/index.cjs +89 -21
  228. package/dist/components/utilities/preview/index.cjs.map +1 -1
  229. package/dist/components/utilities/preview/index.d.cts +6 -2
  230. package/dist/components/utilities/preview/index.d.ts +6 -2
  231. package/dist/components/utilities/preview/index.js +89 -21
  232. package/dist/components/utilities/preview/index.js.map +1 -1
  233. package/dist/components/utilities/preview/preview.css +26 -11
  234. package/dist/components/utilities/transition/index.d.cts +1 -1
  235. package/dist/components/utilities/transition/index.d.ts +1 -1
  236. package/dist/index.cjs +136 -97
  237. package/dist/index.d.cts +23 -2
  238. package/dist/index.d.ts +23 -2
  239. package/dist/index.js +12 -1
  240. package/package.json +7 -6
@@ -0,0 +1,69 @@
1
+ import { ButtonHTMLAttributes, CSSProperties, HTMLAttributes, MouseEvent, ReactNode, Ref } from "react";
2
+ export type ContextMenuItemVariant = "default" | "danger";
3
+ export type ContextMenuCheckedState = boolean | "indeterminate";
4
+ export type ContextMenuProps = {
5
+ children: ReactNode;
6
+ open?: boolean;
7
+ defaultOpen?: boolean;
8
+ onOpenChange?: (open: boolean) => void;
9
+ disabled?: boolean;
10
+ triggerClassName?: string;
11
+ contentClassName?: string;
12
+ };
13
+ export type ContextMenuTriggerProps = Omit<HTMLAttributes<HTMLElement>, "children"> & {
14
+ children: ReactNode;
15
+ asChild?: boolean;
16
+ disabled?: boolean;
17
+ ref?: Ref<HTMLElement>;
18
+ };
19
+ export type ContextMenuContentProps = Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
20
+ children: ReactNode;
21
+ maxHeight?: CSSProperties["maxHeight"];
22
+ };
23
+ export type ContextMenuItemProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, "children" | "onSelect"> & {
24
+ children: ReactNode;
25
+ textValue?: string;
26
+ closeOnSelect?: boolean;
27
+ variant?: ContextMenuItemVariant;
28
+ onSelect?: (event: MouseEvent<HTMLElement>) => void;
29
+ };
30
+ export type ContextMenuGroupProps = Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
31
+ children: ReactNode;
32
+ };
33
+ export type ContextMenuLabelProps = Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
34
+ children: ReactNode;
35
+ };
36
+ export type ContextMenuSeparatorProps = HTMLAttributes<HTMLDivElement>;
37
+ export type ContextMenuCheckboxItemProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, "children" | "onSelect"> & {
38
+ children: ReactNode;
39
+ checked?: ContextMenuCheckedState;
40
+ defaultChecked?: boolean;
41
+ onCheckedChange?: (checked: boolean) => void;
42
+ closeOnSelect?: boolean;
43
+ textValue?: string;
44
+ onSelect?: (event: MouseEvent<HTMLElement>) => void;
45
+ };
46
+ export type ContextMenuRadioGroupProps = Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
47
+ children: ReactNode;
48
+ value?: string;
49
+ defaultValue?: string;
50
+ onValueChange?: (value: string) => void;
51
+ };
52
+ export type ContextMenuRadioItemProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, "children" | "onSelect"> & {
53
+ children: ReactNode;
54
+ value: string;
55
+ closeOnSelect?: boolean;
56
+ textValue?: string;
57
+ onSelect?: (event: MouseEvent<HTMLElement>) => void;
58
+ };
59
+ export type ContextMenuSubProps = {
60
+ children: ReactNode;
61
+ defaultOpen?: boolean;
62
+ };
63
+ export type ContextMenuSubTriggerProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, "children"> & {
64
+ children: ReactNode;
65
+ };
66
+ export type ContextMenuSubContentProps = Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
67
+ children: ReactNode;
68
+ maxHeight?: CSSProperties["maxHeight"];
69
+ };
@@ -0,0 +1,46 @@
1
+ // src/components/overlays/context-menu/context-menu.utils.ts
2
+ const normalizeMenuText = (value) => value.normalize("NFKD").replace(/\p{Diacritic}/gu, "").trim().toLocaleLowerCase();
3
+ const findNextMenuItemIndex = (items, currentIndex, direction, loop = true) => {
4
+ if (items.length === 0) return -1;
5
+ for (let step = 1; step <= items.length; step += 1) {
6
+ let index = currentIndex + step * direction;
7
+ if (loop) index = (index + items.length) % items.length;
8
+ else if (index < 0 || index >= items.length) return -1;
9
+ if (!items[index].disabled) return index;
10
+ }
11
+ return -1;
12
+ };
13
+ const findMenuItemIndexByText = (items, query, currentIndex = -1) => {
14
+ const normalizedQuery = normalizeMenuText(query);
15
+ if (!normalizedQuery || items.length === 0) return -1;
16
+ for (let step = 1; step <= items.length; step += 1) {
17
+ const index = (currentIndex + step + items.length) % items.length;
18
+ const item = items[index];
19
+ if (!item.disabled && normalizeMenuText(item.text ?? "").startsWith(normalizedQuery)) return index;
20
+ }
21
+ return -1;
22
+ };
23
+ const setRef = (ref, value) => {
24
+ if (typeof ref === "function") ref(value);
25
+ else if (ref) ref.current = value;
26
+ };
27
+ const getEnabledMenuItems = (menu) => Array.from(menu.querySelectorAll("[data-puzzle-context-menu-item=\"true\"]")).filter((item) => item.getAttribute("aria-disabled") !== "true" && !("disabled" in item && Boolean(item.disabled)) && !item.hasAttribute("hidden") && !item.closest("[hidden], [inert], [aria-hidden='true']"));
28
+ const focusElement = (element) => {
29
+ if (!element) return;
30
+ try {
31
+ element.focus({ preventScroll: true });
32
+ } catch {
33
+ element.focus();
34
+ }
35
+ element.scrollIntoView?.({ block: "nearest" });
36
+ };
37
+ const getMenuItemText = (item) => item.dataset.textValue ?? item.querySelector(".puzzle-context-menu__item-label")?.textContent ?? item.textContent ?? "";
38
+ exports.findMenuItemIndexByText = findMenuItemIndexByText;
39
+ exports.findNextMenuItemIndex = findNextMenuItemIndex;
40
+ exports.focusElement = focusElement;
41
+ exports.getEnabledMenuItems = getEnabledMenuItems;
42
+ exports.getMenuItemText = getMenuItemText;
43
+ exports.normalizeMenuText = normalizeMenuText;
44
+ exports.setRef = setRef;
45
+
46
+ //# sourceMappingURL=context-menu.utils.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-menu.utils.cjs","names":[],"sources":["../../../../src/components/overlays/context-menu/context-menu.utils.ts"],"sourcesContent":["import type { MutableRefObject, Ref } from \"react\";\n\nexport type MenuItemLike = {\n disabled?: boolean;\n text?: string;\n};\n\nconst normalizeMenuText = (value: string): string =>\n value\n .normalize(\"NFKD\")\n .replace(/\\p{Diacritic}/gu, \"\")\n .trim()\n .toLocaleLowerCase();\n\nconst findNextMenuItemIndex = <T extends MenuItemLike>(\n items: readonly T[],\n currentIndex: number,\n direction: -1 | 1,\n loop = true,\n): number => {\n if (items.length === 0) {\n return -1;\n }\n\n for (let step = 1; step <= items.length; step += 1) {\n let index = currentIndex + step * direction;\n\n if (loop) {\n index = (index + items.length) % items.length;\n } else if (index < 0 || index >= items.length) {\n return -1;\n }\n\n if (!items[index]!.disabled) {\n return index;\n }\n }\n\n return -1;\n};\n\nconst findMenuItemIndexByText = <T extends MenuItemLike>(\n items: readonly T[],\n query: string,\n currentIndex = -1,\n): number => {\n const normalizedQuery = normalizeMenuText(query);\n\n if (!normalizedQuery || items.length === 0) {\n return -1;\n }\n\n for (let step = 1; step <= items.length; step += 1) {\n const index = (currentIndex + step + items.length) % items.length;\n const item = items[index]!;\n\n if (\n !item.disabled &&\n normalizeMenuText(item.text ?? \"\").startsWith(normalizedQuery)\n ) {\n return index;\n }\n }\n\n return -1;\n};\n\nconst setRef = <T>(ref: Ref<T> | undefined, value: T | null): void => {\n if (typeof ref === \"function\") {\n ref(value);\n } else if (ref) {\n (ref as MutableRefObject<T | null>).current = value;\n }\n};\n\nconst getEnabledMenuItems = (menu: HTMLElement): HTMLElement[] =>\n Array.from(\n menu.querySelectorAll<HTMLElement>(\n '[data-puzzle-context-menu-item=\"true\"]',\n ),\n ).filter(\n (item) =>\n item.getAttribute(\"aria-disabled\") !== \"true\" &&\n !(\"disabled\" in item && Boolean((item as HTMLButtonElement).disabled)) &&\n !item.hasAttribute(\"hidden\") &&\n !item.closest(\"[hidden], [inert], [aria-hidden='true']\"),\n );\n\nconst focusElement = (element: HTMLElement | undefined): void => {\n if (!element) {\n return;\n }\n\n try {\n element.focus({ preventScroll: true });\n } catch {\n element.focus();\n }\n\n element.scrollIntoView?.({ block: \"nearest\" });\n};\n\nconst getMenuItemText = (item: HTMLElement): string =>\n item.dataset.textValue ??\n item.querySelector(\".puzzle-context-menu__item-label\")?.textContent ??\n item.textContent ??\n \"\";\n\nexport {\n findMenuItemIndexByText,\n findNextMenuItemIndex,\n focusElement,\n getEnabledMenuItems,\n getMenuItemText,\n normalizeMenuText,\n setRef,\n};\n"],"mappings":";AAOA,MAAM,qBAAqB,UACzB,MACG,UAAU,MAAM,CAAC,CACjB,QAAQ,mBAAmB,EAAE,CAAC,CAC9B,KAAK,CAAC,CACN,kBAAkB;AAEvB,MAAM,yBACJ,OACA,cACA,WACA,OAAO,SACI;CACX,IAAI,MAAM,WAAW,GACnB,OAAO;CAGT,KAAK,IAAI,OAAO,GAAG,QAAQ,MAAM,QAAQ,QAAQ,GAAG;EAClD,IAAI,QAAQ,eAAe,OAAO;EAElC,IAAI,MACF,SAAS,QAAQ,MAAM,UAAU,MAAM;OAClC,IAAI,QAAQ,KAAK,SAAS,MAAM,QACrC,OAAO;EAGT,IAAI,CAAC,MAAM,MAAM,CAAE,UACjB,OAAO;CAEX;CAEA,OAAO;AACT;AAEA,MAAM,2BACJ,OACA,OACA,eAAe,OACJ;CACX,MAAM,kBAAkB,kBAAkB,KAAK;CAE/C,IAAI,CAAC,mBAAmB,MAAM,WAAW,GACvC,OAAO;CAGT,KAAK,IAAI,OAAO,GAAG,QAAQ,MAAM,QAAQ,QAAQ,GAAG;EAClD,MAAM,SAAS,eAAe,OAAO,MAAM,UAAU,MAAM;EAC3D,MAAM,OAAO,MAAM;EAEnB,IACE,CAAC,KAAK,YACN,kBAAkB,KAAK,QAAQ,EAAE,CAAC,CAAC,WAAW,eAAe,GAE7D,OAAO;CAEX;CAEA,OAAO;AACT;AAEA,MAAM,UAAa,KAAyB,UAA0B;CACpE,IAAI,OAAO,QAAQ,YACjB,IAAI,KAAK;MACJ,IAAI,KACT,IAAoC,UAAU;AAElD;AAEA,MAAM,uBAAuB,SAC3B,MAAM,KACJ,KAAK,iBACH,0CACF,CACF,CAAC,CAAC,QACC,SACC,KAAK,aAAa,eAAe,MAAM,UACvC,EAAE,cAAc,QAAQ,QAAS,KAA2B,QAAQ,MACpE,CAAC,KAAK,aAAa,QAAQ,KAC3B,CAAC,KAAK,QAAQ,yCAAyC,CAC3D;AAEF,MAAM,gBAAgB,YAA2C;CAC/D,IAAI,CAAC,SACH;CAGF,IAAI;EACF,QAAQ,MAAM,EAAE,eAAe,KAAK,CAAC;CACvC,QAAQ;EACN,QAAQ,MAAM;CAChB;CAEA,QAAQ,iBAAiB,EAAE,OAAO,UAAU,CAAC;AAC/C;AAEA,MAAM,mBAAmB,SACvB,KAAK,QAAQ,aACb,KAAK,cAAc,kCAAkC,CAAC,EAAE,eACxD,KAAK,eACL"}
@@ -0,0 +1,40 @@
1
+ // src/components/overlays/context-menu/context-menu.utils.ts
2
+ const normalizeMenuText = (value) => value.normalize("NFKD").replace(/\p{Diacritic}/gu, "").trim().toLocaleLowerCase();
3
+ const findNextMenuItemIndex = (items, currentIndex, direction, loop = true) => {
4
+ if (items.length === 0) return -1;
5
+ for (let step = 1; step <= items.length; step += 1) {
6
+ let index = currentIndex + step * direction;
7
+ if (loop) index = (index + items.length) % items.length;
8
+ else if (index < 0 || index >= items.length) return -1;
9
+ if (!items[index].disabled) return index;
10
+ }
11
+ return -1;
12
+ };
13
+ const findMenuItemIndexByText = (items, query, currentIndex = -1) => {
14
+ const normalizedQuery = normalizeMenuText(query);
15
+ if (!normalizedQuery || items.length === 0) return -1;
16
+ for (let step = 1; step <= items.length; step += 1) {
17
+ const index = (currentIndex + step + items.length) % items.length;
18
+ const item = items[index];
19
+ if (!item.disabled && normalizeMenuText(item.text ?? "").startsWith(normalizedQuery)) return index;
20
+ }
21
+ return -1;
22
+ };
23
+ const setRef = (ref, value) => {
24
+ if (typeof ref === "function") ref(value);
25
+ else if (ref) ref.current = value;
26
+ };
27
+ const getEnabledMenuItems = (menu) => Array.from(menu.querySelectorAll("[data-puzzle-context-menu-item=\"true\"]")).filter((item) => item.getAttribute("aria-disabled") !== "true" && !("disabled" in item && Boolean(item.disabled)) && !item.hasAttribute("hidden") && !item.closest("[hidden], [inert], [aria-hidden='true']"));
28
+ const focusElement = (element) => {
29
+ if (!element) return;
30
+ try {
31
+ element.focus({ preventScroll: true });
32
+ } catch {
33
+ element.focus();
34
+ }
35
+ element.scrollIntoView?.({ block: "nearest" });
36
+ };
37
+ const getMenuItemText = (item) => item.dataset.textValue ?? item.querySelector(".puzzle-context-menu__item-label")?.textContent ?? item.textContent ?? "";
38
+ export { findMenuItemIndexByText, findNextMenuItemIndex, focusElement, getEnabledMenuItems, getMenuItemText, normalizeMenuText, setRef };
39
+
40
+ //# sourceMappingURL=context-menu.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-menu.utils.js","names":[],"sources":["../../../../src/components/overlays/context-menu/context-menu.utils.ts"],"sourcesContent":["import type { MutableRefObject, Ref } from \"react\";\n\nexport type MenuItemLike = {\n disabled?: boolean;\n text?: string;\n};\n\nconst normalizeMenuText = (value: string): string =>\n value\n .normalize(\"NFKD\")\n .replace(/\\p{Diacritic}/gu, \"\")\n .trim()\n .toLocaleLowerCase();\n\nconst findNextMenuItemIndex = <T extends MenuItemLike>(\n items: readonly T[],\n currentIndex: number,\n direction: -1 | 1,\n loop = true,\n): number => {\n if (items.length === 0) {\n return -1;\n }\n\n for (let step = 1; step <= items.length; step += 1) {\n let index = currentIndex + step * direction;\n\n if (loop) {\n index = (index + items.length) % items.length;\n } else if (index < 0 || index >= items.length) {\n return -1;\n }\n\n if (!items[index]!.disabled) {\n return index;\n }\n }\n\n return -1;\n};\n\nconst findMenuItemIndexByText = <T extends MenuItemLike>(\n items: readonly T[],\n query: string,\n currentIndex = -1,\n): number => {\n const normalizedQuery = normalizeMenuText(query);\n\n if (!normalizedQuery || items.length === 0) {\n return -1;\n }\n\n for (let step = 1; step <= items.length; step += 1) {\n const index = (currentIndex + step + items.length) % items.length;\n const item = items[index]!;\n\n if (\n !item.disabled &&\n normalizeMenuText(item.text ?? \"\").startsWith(normalizedQuery)\n ) {\n return index;\n }\n }\n\n return -1;\n};\n\nconst setRef = <T>(ref: Ref<T> | undefined, value: T | null): void => {\n if (typeof ref === \"function\") {\n ref(value);\n } else if (ref) {\n (ref as MutableRefObject<T | null>).current = value;\n }\n};\n\nconst getEnabledMenuItems = (menu: HTMLElement): HTMLElement[] =>\n Array.from(\n menu.querySelectorAll<HTMLElement>(\n '[data-puzzle-context-menu-item=\"true\"]',\n ),\n ).filter(\n (item) =>\n item.getAttribute(\"aria-disabled\") !== \"true\" &&\n !(\"disabled\" in item && Boolean((item as HTMLButtonElement).disabled)) &&\n !item.hasAttribute(\"hidden\") &&\n !item.closest(\"[hidden], [inert], [aria-hidden='true']\"),\n );\n\nconst focusElement = (element: HTMLElement | undefined): void => {\n if (!element) {\n return;\n }\n\n try {\n element.focus({ preventScroll: true });\n } catch {\n element.focus();\n }\n\n element.scrollIntoView?.({ block: \"nearest\" });\n};\n\nconst getMenuItemText = (item: HTMLElement): string =>\n item.dataset.textValue ??\n item.querySelector(\".puzzle-context-menu__item-label\")?.textContent ??\n item.textContent ??\n \"\";\n\nexport {\n findMenuItemIndexByText,\n findNextMenuItemIndex,\n focusElement,\n getEnabledMenuItems,\n getMenuItemText,\n normalizeMenuText,\n setRef,\n};\n"],"mappings":";AAOA,MAAM,qBAAqB,UACzB,MACG,UAAU,MAAM,CAAC,CACjB,QAAQ,mBAAmB,EAAE,CAAC,CAC9B,KAAK,CAAC,CACN,kBAAkB;AAEvB,MAAM,yBACJ,OACA,cACA,WACA,OAAO,SACI;CACX,IAAI,MAAM,WAAW,GACnB,OAAO;CAGT,KAAK,IAAI,OAAO,GAAG,QAAQ,MAAM,QAAQ,QAAQ,GAAG;EAClD,IAAI,QAAQ,eAAe,OAAO;EAElC,IAAI,MACF,SAAS,QAAQ,MAAM,UAAU,MAAM;OAClC,IAAI,QAAQ,KAAK,SAAS,MAAM,QACrC,OAAO;EAGT,IAAI,CAAC,MAAM,MAAM,CAAE,UACjB,OAAO;CAEX;CAEA,OAAO;AACT;AAEA,MAAM,2BACJ,OACA,OACA,eAAe,OACJ;CACX,MAAM,kBAAkB,kBAAkB,KAAK;CAE/C,IAAI,CAAC,mBAAmB,MAAM,WAAW,GACvC,OAAO;CAGT,KAAK,IAAI,OAAO,GAAG,QAAQ,MAAM,QAAQ,QAAQ,GAAG;EAClD,MAAM,SAAS,eAAe,OAAO,MAAM,UAAU,MAAM;EAC3D,MAAM,OAAO,MAAM;EAEnB,IACE,CAAC,KAAK,YACN,kBAAkB,KAAK,QAAQ,EAAE,CAAC,CAAC,WAAW,eAAe,GAE7D,OAAO;CAEX;CAEA,OAAO;AACT;AAEA,MAAM,UAAa,KAAyB,UAA0B;CACpE,IAAI,OAAO,QAAQ,YACjB,IAAI,KAAK;MACJ,IAAI,KACT,IAAoC,UAAU;AAElD;AAEA,MAAM,uBAAuB,SAC3B,MAAM,KACJ,KAAK,iBACH,0CACF,CACF,CAAC,CAAC,QACC,SACC,KAAK,aAAa,eAAe,MAAM,UACvC,EAAE,cAAc,QAAQ,QAAS,KAA2B,QAAQ,MACpE,CAAC,KAAK,aAAa,QAAQ,KAC3B,CAAC,KAAK,QAAQ,yCAAyC,CAC3D;AAEF,MAAM,gBAAgB,YAA2C;CAC/D,IAAI,CAAC,SACH;CAGF,IAAI;EACF,QAAQ,MAAM,EAAE,eAAe,KAAK,CAAC;CACvC,QAAQ;EACN,QAAQ,MAAM;CAChB;CAEA,QAAQ,iBAAiB,EAAE,OAAO,UAAU,CAAC;AAC/C;AAEA,MAAM,mBAAmB,SACvB,KAAK,QAAQ,aACb,KAAK,cAAc,kCAAkC,CAAC,EAAE,eACxD,KAAK,eACL"}