@robert-stackflow/oneui 0.0.0-stage → 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 (380) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +72 -2
  3. package/assets/LUCIDE-LICENSE.txt +43 -0
  4. package/assets/character-metadata.json +1 -0
  5. package/assets/emoji.json +1 -0
  6. package/assets/icon-catalog.json +1 -0
  7. package/assets/symbols.json +1 -0
  8. package/components/Accessibility.module.css +8 -0
  9. package/components/Accordion.d.ts +7 -0
  10. package/components/Accordion.js +41 -0
  11. package/components/Accordion.module.css +38 -0
  12. package/components/Alert.d.ts +9 -0
  13. package/components/Alert.js +42 -0
  14. package/components/Alert.module.css +56 -0
  15. package/components/AppShell.d.ts +30 -0
  16. package/components/AppShell.js +152 -0
  17. package/components/AppShell.module.css +239 -0
  18. package/components/AppearanceSettings.d.ts +7 -0
  19. package/components/AppearanceSettings.js +201 -0
  20. package/components/AppearanceSettings.module.css +32 -0
  21. package/components/Avatar.d.ts +14 -0
  22. package/components/Avatar.js +69 -0
  23. package/components/Avatar.module.css +70 -0
  24. package/components/AvatarGroup.d.ts +15 -0
  25. package/components/AvatarGroup.js +115 -0
  26. package/components/AvatarGroup.module.css +54 -0
  27. package/components/Badge.d.ts +5 -0
  28. package/components/Badge.js +11 -0
  29. package/components/Badge.module.css +30 -0
  30. package/components/BlockedTab.d.ts +4 -0
  31. package/components/BlockedTab.js +10 -0
  32. package/components/Breadcrumb.d.ts +16 -0
  33. package/components/Breadcrumb.js +157 -0
  34. package/components/Breadcrumb.module.css +97 -0
  35. package/components/Button.d.ts +13 -0
  36. package/components/Button.js +52 -0
  37. package/components/Button.module.css +88 -0
  38. package/components/Calendar.d.ts +10 -0
  39. package/components/Calendar.js +260 -0
  40. package/components/Calendar.module.css +106 -0
  41. package/components/Card.d.ts +8 -0
  42. package/components/Card.js +29 -0
  43. package/components/Card.module.css +47 -0
  44. package/components/Cascader.d.ts +14 -0
  45. package/components/Cascader.js +296 -0
  46. package/components/CatalogIcon.d.ts +3 -0
  47. package/components/CatalogIcon.js +11 -0
  48. package/components/CharacterPicker.d.ts +15 -0
  49. package/components/CharacterPicker.js +200 -0
  50. package/components/Checkbox.d.ts +12 -0
  51. package/components/Checkbox.js +82 -0
  52. package/components/Checkbox.module.css +95 -0
  53. package/components/ColorField.d.ts +6 -0
  54. package/components/ColorField.js +61 -0
  55. package/components/ColorField.module.css +15 -0
  56. package/components/ColorPicker.d.ts +5 -0
  57. package/components/ColorPicker.js +188 -0
  58. package/components/ColorPicker.module.css +90 -0
  59. package/components/Combobox.d.ts +13 -0
  60. package/components/Combobox.js +338 -0
  61. package/components/Combobox.module.css +24 -0
  62. package/components/CommandPalette.d.ts +25 -0
  63. package/components/CommandPalette.js +269 -0
  64. package/components/CommandPalette.module.css +49 -0
  65. package/components/ContextMenu.d.ts +9 -0
  66. package/components/ContextMenu.js +363 -0
  67. package/components/ContextMenu.module.css +42 -0
  68. package/components/ContextMenuPanel.d.ts +22 -0
  69. package/components/ContextMenuPanel.js +155 -0
  70. package/components/ContributionCalendar.d.ts +18 -0
  71. package/components/ContributionCalendar.js +201 -0
  72. package/components/ContributionCalendar.module.css +114 -0
  73. package/components/ContributionCell.d.ts +11 -0
  74. package/components/ContributionCell.js +41 -0
  75. package/components/Control.module.css +86 -0
  76. package/components/DataTable.d.ts +49 -0
  77. package/components/DataTable.js +220 -0
  78. package/components/DataTable.module.css +112 -0
  79. package/components/DatePicker.d.ts +15 -0
  80. package/components/DatePicker.js +186 -0
  81. package/components/DatePicker.module.css +85 -0
  82. package/components/DateRangePicker.d.ts +9 -0
  83. package/components/DateRangePicker.js +168 -0
  84. package/components/Descriptions.d.ts +21 -0
  85. package/components/Descriptions.js +162 -0
  86. package/components/Descriptions.module.css +117 -0
  87. package/components/Dialog.d.ts +14 -0
  88. package/components/Dialog.js +125 -0
  89. package/components/Dialog.module.css +88 -0
  90. package/components/DialogVariants.d.ts +27 -0
  91. package/components/DialogVariants.js +161 -0
  92. package/components/DialogVariants.module.css +29 -0
  93. package/components/DisclosureChevron.d.ts +3 -0
  94. package/components/DisclosureChevron.js +17 -0
  95. package/components/DisclosureChevron.module.css +17 -0
  96. package/components/Divider.d.ts +5 -0
  97. package/components/Divider.js +24 -0
  98. package/components/Divider.module.css +19 -0
  99. package/components/Drawer.d.ts +18 -0
  100. package/components/Drawer.js +145 -0
  101. package/components/Drawer.module.css +109 -0
  102. package/components/EmojiPicker.d.ts +6 -0
  103. package/components/EmojiPicker.js +19 -0
  104. package/components/EmptyState.d.ts +8 -0
  105. package/components/EmptyState.js +20 -0
  106. package/components/EmptyState.module.css +30 -0
  107. package/components/FieldLabel.d.ts +8 -0
  108. package/components/FieldLabel.js +20 -0
  109. package/components/FieldMessages.d.ts +5 -0
  110. package/components/FieldMessages.js +15 -0
  111. package/components/FileDropOverlay.d.ts +5 -0
  112. package/components/FileDropOverlay.js +26 -0
  113. package/components/FileDropOverlay.module.css +55 -0
  114. package/components/FileDropZone.d.ts +15 -0
  115. package/components/FileDropZone.js +113 -0
  116. package/components/FileDropZone.module.css +6 -0
  117. package/components/FilePicker.d.ts +10 -0
  118. package/components/FilePicker.js +59 -0
  119. package/components/FileSelectionFeedback.d.ts +5 -0
  120. package/components/FileSelectionFeedback.js +23 -0
  121. package/components/FileSelectionFeedback.module.css +14 -0
  122. package/components/FileTree.d.ts +13 -0
  123. package/components/FileTree.js +125 -0
  124. package/components/FileTree.module.css +66 -0
  125. package/components/Form.d.ts +7 -0
  126. package/components/Form.js +26 -0
  127. package/components/Form.module.css +7 -0
  128. package/components/FormErrorSummary.d.ts +6 -0
  129. package/components/FormErrorSummary.js +27 -0
  130. package/components/FormErrorSummary.module.css +27 -0
  131. package/components/FormField.d.ts +9 -0
  132. package/components/FormField.js +59 -0
  133. package/components/FormField.module.css +85 -0
  134. package/components/FormGroup.d.ts +9 -0
  135. package/components/FormGroup.js +32 -0
  136. package/components/HierarchyPicker.module.css +181 -0
  137. package/components/IconButton.d.ts +7 -0
  138. package/components/IconButton.js +30 -0
  139. package/components/IconButton.module.css +42 -0
  140. package/components/IconPicker.d.ts +6 -0
  141. package/components/IconPicker.js +111 -0
  142. package/components/Indicator.d.ts +18 -0
  143. package/components/Indicator.js +97 -0
  144. package/components/Indicator.module.css +83 -0
  145. package/components/Input.d.ts +8 -0
  146. package/components/Input.js +37 -0
  147. package/components/Input.module.css +40 -0
  148. package/components/LoadingOverlay.d.ts +6 -0
  149. package/components/LoadingOverlay.js +16 -0
  150. package/components/LoadingOverlay.module.css +22 -0
  151. package/components/LoadingState.d.ts +7 -0
  152. package/components/LoadingState.js +40 -0
  153. package/components/LoadingState.module.css +17 -0
  154. package/components/Menu.d.ts +11 -0
  155. package/components/Menu.js +82 -0
  156. package/components/MenuItem.d.ts +15 -0
  157. package/components/MenuItem.js +51 -0
  158. package/components/MenuItem.module.css +172 -0
  159. package/components/MenuItemContent.d.ts +8 -0
  160. package/components/MenuItemContent.js +19 -0
  161. package/components/MultiSelect.d.ts +13 -0
  162. package/components/MultiSelect.js +225 -0
  163. package/components/MultiSelect.module.css +99 -0
  164. package/components/NumberInput.d.ts +12 -0
  165. package/components/NumberInput.js +114 -0
  166. package/components/NumberInput.module.css +33 -0
  167. package/components/OptionList.module.css +12 -0
  168. package/components/Page.d.ts +7 -0
  169. package/components/Page.js +22 -0
  170. package/components/Page.module.css +44 -0
  171. package/components/Pagination.d.ts +11 -0
  172. package/components/Pagination.js +160 -0
  173. package/components/Pagination.module.css +70 -0
  174. package/components/PasswordField.d.ts +9 -0
  175. package/components/PasswordField.js +102 -0
  176. package/components/PasswordField.module.css +64 -0
  177. package/components/Picker.module.css +52 -0
  178. package/components/PinInput.d.ts +13 -0
  179. package/components/PinInput.js +173 -0
  180. package/components/PinInput.module.css +72 -0
  181. package/components/Placeholder.d.ts +31 -0
  182. package/components/Placeholder.js +36 -0
  183. package/components/Popconfirm.d.ts +17 -0
  184. package/components/Popconfirm.js +159 -0
  185. package/components/Popconfirm.module.css +49 -0
  186. package/components/Popover.d.ts +16 -0
  187. package/components/Popover.js +156 -0
  188. package/components/Popover.module.css +19 -0
  189. package/components/Progress.d.ts +5 -0
  190. package/components/Progress.js +31 -0
  191. package/components/Progress.module.css +33 -0
  192. package/components/RadioGroup.d.ts +15 -0
  193. package/components/RadioGroup.js +73 -0
  194. package/components/RadioGroup.module.css +87 -0
  195. package/components/RangeSlider.d.ts +22 -0
  196. package/components/RangeSlider.js +278 -0
  197. package/components/RangeSlider.module.css +141 -0
  198. package/components/ResizablePanel.d.ts +21 -0
  199. package/components/ResizablePanel.js +219 -0
  200. package/components/ResizablePanel.module.css +101 -0
  201. package/components/SearchField.d.ts +11 -0
  202. package/components/SearchField.js +67 -0
  203. package/components/SearchField.module.css +37 -0
  204. package/components/Section.d.ts +6 -0
  205. package/components/Section.js +18 -0
  206. package/components/Section.module.css +14 -0
  207. package/components/Segmented.d.ts +11 -0
  208. package/components/Segmented.js +77 -0
  209. package/components/Segmented.module.css +82 -0
  210. package/components/Select.d.ts +11 -0
  211. package/components/Select.js +172 -0
  212. package/components/Select.module.css +24 -0
  213. package/components/SelectOptionContent.d.ts +5 -0
  214. package/components/SelectOptionContent.js +20 -0
  215. package/components/SelectOptionContent.module.css +7 -0
  216. package/components/SelectTrigger.d.ts +5 -0
  217. package/components/SelectTrigger.js +32 -0
  218. package/components/SelectTrigger.module.css +24 -0
  219. package/components/SelectionTag.d.ts +8 -0
  220. package/components/SelectionTag.js +39 -0
  221. package/components/SettingRow.d.ts +7 -0
  222. package/components/SettingRow.js +19 -0
  223. package/components/SettingRow.module.css +44 -0
  224. package/components/SettingsLayout.d.ts +11 -0
  225. package/components/SettingsLayout.js +61 -0
  226. package/components/SettingsLayout.module.css +68 -0
  227. package/components/ShortcutInput.d.ts +8 -0
  228. package/components/ShortcutInput.js +131 -0
  229. package/components/ShortcutInput.module.css +39 -0
  230. package/components/Skeleton.d.ts +5 -0
  231. package/components/Skeleton.js +19 -0
  232. package/components/Skeleton.module.css +27 -0
  233. package/components/SkeletonRows.d.ts +4 -0
  234. package/components/SkeletonRows.js +19 -0
  235. package/components/SkeletonRows.module.css +19 -0
  236. package/components/SkinTonePicker.d.ts +4 -0
  237. package/components/SkinTonePicker.js +43 -0
  238. package/components/SkinTonePicker.module.css +50 -0
  239. package/components/Slider.d.ts +10 -0
  240. package/components/Slider.js +40 -0
  241. package/components/Slider.module.css +19 -0
  242. package/components/Spinner.d.ts +6 -0
  243. package/components/Spinner.js +31 -0
  244. package/components/Spinner.module.css +57 -0
  245. package/components/SplitButton.d.ts +17 -0
  246. package/components/SplitButton.js +102 -0
  247. package/components/SplitButton.module.css +56 -0
  248. package/components/Statistic.d.ts +22 -0
  249. package/components/Statistic.js +102 -0
  250. package/components/Statistic.module.css +55 -0
  251. package/components/Steps.d.ts +19 -0
  252. package/components/Steps.js +102 -0
  253. package/components/Steps.module.css +176 -0
  254. package/components/Switch.d.ts +6 -0
  255. package/components/Switch.js +25 -0
  256. package/components/Switch.module.css +59 -0
  257. package/components/SymbolPicker.d.ts +6 -0
  258. package/components/SymbolPicker.js +18 -0
  259. package/components/Tab.module.css +145 -0
  260. package/components/TabList.d.ts +11 -0
  261. package/components/TabList.js +51 -0
  262. package/components/Table.d.ts +16 -0
  263. package/components/Table.js +30 -0
  264. package/components/Table.module.css +48 -0
  265. package/components/TableColumnFilter.d.ts +6 -0
  266. package/components/TableColumnFilter.js +76 -0
  267. package/components/TableColumnVisibility.d.ts +11 -0
  268. package/components/TableColumnVisibility.js +76 -0
  269. package/components/Tabs.d.ts +13 -0
  270. package/components/Tabs.js +49 -0
  271. package/components/Tabs.module.css +3 -0
  272. package/components/TagInput.d.ts +11 -0
  273. package/components/TagInput.js +142 -0
  274. package/components/TagInput.module.css +64 -0
  275. package/components/Textarea.d.ts +6 -0
  276. package/components/Textarea.js +24 -0
  277. package/components/Textarea.module.css +9 -0
  278. package/components/ThemePicker.d.ts +6 -0
  279. package/components/ThemePicker.js +78 -0
  280. package/components/ThemePicker.module.css +178 -0
  281. package/components/ThemeProvider.d.ts +11 -0
  282. package/components/ThemeProvider.js +94 -0
  283. package/components/ThemeStylePicker.d.ts +5 -0
  284. package/components/ThemeStylePicker.js +22 -0
  285. package/components/TimeColumns.d.ts +6 -0
  286. package/components/TimeColumns.js +55 -0
  287. package/components/TimeColumns.module.css +47 -0
  288. package/components/Timeline.d.ts +26 -0
  289. package/components/Timeline.js +131 -0
  290. package/components/Timeline.module.css +202 -0
  291. package/components/Toast.d.ts +6 -0
  292. package/components/Toast.js +181 -0
  293. package/components/Toast.module.css +175 -0
  294. package/components/ToastProvider.d.ts +35 -0
  295. package/components/ToastProvider.js +47 -0
  296. package/components/Tooltip.d.ts +10 -0
  297. package/components/Tooltip.js +169 -0
  298. package/components/Tooltip.module.css +53 -0
  299. package/components/TreeGuides.d.ts +9 -0
  300. package/components/TreeGuides.js +39 -0
  301. package/components/TreeGuides.module.css +45 -0
  302. package/components/TreeSelect.d.ts +26 -0
  303. package/components/TreeSelect.js +337 -0
  304. package/components/TreeTable.d.ts +15 -0
  305. package/components/TreeTable.js +151 -0
  306. package/components/TreeTable.module.css +53 -0
  307. package/components/UIProvider.d.ts +10 -0
  308. package/components/UIProvider.js +20 -0
  309. package/components/UnderlinedTab.d.ts +2 -0
  310. package/components/UnderlinedTab.js +8 -0
  311. package/components/Upload.d.ts +22 -0
  312. package/components/Upload.js +165 -0
  313. package/components/Upload.module.css +36 -0
  314. package/components/UploadList.d.ts +9 -0
  315. package/components/UploadList.js +14 -0
  316. package/components/UploadList.module.css +130 -0
  317. package/components/UploadListItem.d.ts +13 -0
  318. package/components/UploadListItem.js +122 -0
  319. package/components/VirtualPickerList.d.ts +25 -0
  320. package/components/VirtualPickerList.js +269 -0
  321. package/components/VirtualPickerList.module.css +93 -0
  322. package/components/appearance.d.ts +20 -0
  323. package/components/appearance.js +69 -0
  324. package/components/characterCatalog.d.ts +9 -0
  325. package/components/characterCatalog.js +55 -0
  326. package/components/color.d.ts +7 -0
  327. package/components/color.js +18 -0
  328. package/components/contribution.d.ts +57 -0
  329. package/components/contribution.js +86 -0
  330. package/components/dateConstraints.d.ts +13 -0
  331. package/components/dateConstraints.js +44 -0
  332. package/components/field.d.ts +58 -0
  333. package/components/field.js +57 -0
  334. package/components/fileSelection.d.ts +21 -0
  335. package/components/fileSelection.js +43 -0
  336. package/components/hierarchy.d.ts +23 -0
  337. package/components/hierarchy.js +33 -0
  338. package/components/iconCatalog.d.ts +13 -0
  339. package/components/iconCatalog.js +80 -0
  340. package/components/index.d.ts +152 -0
  341. package/components/index.js +225 -0
  342. package/components/menuFocus.d.ts +7 -0
  343. package/components/menuFocus.js +21 -0
  344. package/components/menuPointer.d.ts +6 -0
  345. package/components/menuPointer.js +13 -0
  346. package/components/menuTypes.d.ts +24 -0
  347. package/components/menuTypes.js +0 -0
  348. package/components/motion.d.ts +9 -0
  349. package/components/motion.js +82 -0
  350. package/components/rangeMath.d.ts +12 -0
  351. package/components/rangeMath.js +30 -0
  352. package/components/surfacePortal.d.ts +13 -0
  353. package/components/surfacePortal.js +22 -0
  354. package/components/tooltipState.d.ts +5 -0
  355. package/components/tooltipState.js +48 -0
  356. package/components/types.d.ts +9 -0
  357. package/components/types.js +0 -0
  358. package/components/uploadTypes.d.ts +21 -0
  359. package/components/uploadTypes.js +0 -0
  360. package/components/useFormState.d.ts +51 -0
  361. package/components/useFormState.js +218 -0
  362. package/components/useHierarchy.d.ts +8 -0
  363. package/components/useHierarchy.js +80 -0
  364. package/components/useMenuLayers.d.ts +17 -0
  365. package/components/useMenuLayers.js +23 -0
  366. package/components/useModalScrollLock.d.ts +1 -0
  367. package/components/useModalScrollLock.js +18 -0
  368. package/components/usePopover.d.ts +8 -0
  369. package/components/usePopover.js +22 -0
  370. package/components/useTabIndicator.d.ts +12 -0
  371. package/components/useTabIndicator.js +63 -0
  372. package/components/useUploadQueue.d.ts +20 -0
  373. package/components/useUploadQueue.js +175 -0
  374. package/package.json +810 -3
  375. package/styles/base.css +206 -0
  376. package/styles/blue.css +268 -0
  377. package/styles/desktop.css +2 -0
  378. package/styles/minimal.css +337 -0
  379. package/styles/themes.css +2 -0
  380. package/styles/web.css +2 -0
@@ -0,0 +1,48 @@
1
+ let active;
2
+ let lastHidden = -Infinity, keyboard = false, users = 0;
3
+ const dismiss = () => active?.();
4
+ const key = (e) => {
5
+ keyboard = e.key === "Tab" || e.key.startsWith("Arrow");
6
+ dismiss();
7
+ };
8
+ const pointer = () => {
9
+ keyboard = false;
10
+ dismiss();
11
+ };
12
+ const keyboardTooltip = () => keyboard;
13
+ const tooltipDelay = () => performance.now() - lastHidden < 200 ? 90 : 380;
14
+ function claimTooltip(hide) {
15
+ if (active !== hide) active?.(true);
16
+ active = hide;
17
+ }
18
+ function releaseTooltip(hide, visible) {
19
+ if (active === hide) active = void 0;
20
+ if (visible) lastHidden = performance.now();
21
+ }
22
+ function retainTooltipEvents() {
23
+ if (++users === 1) {
24
+ document.addEventListener("keydown", key, true);
25
+ document.addEventListener("pointerdown", pointer, true);
26
+ window.addEventListener("blur", dismiss);
27
+ window.addEventListener("resize", dismiss);
28
+ window.addEventListener("scroll", dismiss, true);
29
+ }
30
+ return () => {
31
+ if (--users === 0) {
32
+ document.removeEventListener("keydown", key, true);
33
+ document.removeEventListener("pointerdown", pointer, true);
34
+ window.removeEventListener("blur", dismiss);
35
+ window.removeEventListener("resize", dismiss);
36
+ window.removeEventListener("scroll", dismiss, true);
37
+ active = void 0;
38
+ keyboard = false;
39
+ }
40
+ };
41
+ }
42
+ export {
43
+ claimTooltip,
44
+ keyboardTooltip,
45
+ releaseTooltip,
46
+ retainTooltipEvents,
47
+ tooltipDelay
48
+ };
@@ -0,0 +1,9 @@
1
+ import type { ReactNode } from "react";
2
+ export interface SelectOption {
3
+ value: string;
4
+ label: string;
5
+ disabled?: boolean;
6
+ icon?: ReactNode;
7
+ description?: string;
8
+ shortcut?: string;
9
+ }
File without changes
@@ -0,0 +1,21 @@
1
+ export type UploadStatus = "ready" | "uploading" | "success" | "error" | "canceled";
2
+ export type UploadFile = {
3
+ id: string;
4
+ name: string;
5
+ size: number;
6
+ type?: string;
7
+ file?: File;
8
+ status: UploadStatus;
9
+ progress: number;
10
+ error?: string;
11
+ url?: string;
12
+ response?: unknown;
13
+ };
14
+ export type UploadResult = {
15
+ url?: string;
16
+ response?: unknown;
17
+ };
18
+ export type UploadRequest = (file: File, context: {
19
+ signal: AbortSignal;
20
+ onProgress(percent: number): void;
21
+ }) => Promise<UploadResult | void>;
File without changes
@@ -0,0 +1,51 @@
1
+ export type FieldRule<V, T> = {
2
+ label?: string;
3
+ required?: boolean | string;
4
+ mustBeTrue?: boolean | string;
5
+ minLength?: number;
6
+ maxLength?: number;
7
+ min?: number;
8
+ max?: number;
9
+ pattern?: RegExp;
10
+ disabled?: boolean;
11
+ validate?(value: V, values: Readonly<T>, signal: AbortSignal): string | undefined | Promise<string | undefined>;
12
+ };
13
+ export type FormRules<T> = {
14
+ [K in keyof T]?: FieldRule<T[K], T>;
15
+ };
16
+ export declare function useFormState<T extends Record<string, unknown>>({ initialValues, rules, mode, }: {
17
+ initialValues: T;
18
+ rules?: FormRules<T>;
19
+ mode?: "submit" | "blur" | "change";
20
+ }): {
21
+ values: T;
22
+ errors: Partial<Record<keyof T, string>>;
23
+ touched: Partial<Record<keyof T, boolean>>;
24
+ isSubmitting: boolean;
25
+ isValidating: boolean;
26
+ validating: string[];
27
+ submitError: string;
28
+ isDirty: boolean;
29
+ field: <K extends keyof T>(name: K) => {
30
+ id: string;
31
+ name: string;
32
+ required: boolean;
33
+ disabled: boolean | undefined;
34
+ error: Partial<Record<keyof T, string>>[K];
35
+ onBlur: () => void;
36
+ };
37
+ setValue: <K extends keyof T>(name: K, value: T[K]) => void;
38
+ touch: (name: keyof T) => void;
39
+ validate: () => Promise<{
40
+ valid: boolean;
41
+ first: keyof T | undefined;
42
+ }>;
43
+ focusField: (name: keyof T) => void;
44
+ reset: (next?: T) => void;
45
+ handleSubmit: (onSubmit: (values: T) => void | Promise<void>) => (event?: {
46
+ preventDefault(): void;
47
+ }) => Promise<void>;
48
+ setFieldError: (name: keyof T, error?: string) => void;
49
+ labels: Record<keyof T, string>;
50
+ };
51
+ export type FormController<T extends Record<string, unknown>> = ReturnType<typeof useFormState<T>>;
@@ -0,0 +1,218 @@
1
+ import { useCallback, useEffect, useId, useRef, useState } from "react";
2
+ function useFormState({
3
+ initialValues,
4
+ rules,
5
+ mode = "submit"
6
+ }) {
7
+ const id = useId(), defaults = useRef(structuredClone(initialValues)), current = useRef(structuredClone(initialValues)), rulesRef = useRef(rules), version = useRef(0), controllers = useRef(/* @__PURE__ */ new Map()), mounted = useRef(true), locked = useRef(false), attempted = useRef(false), touchedRef = useRef({});
8
+ rulesRef.current = rules;
9
+ const [values, setValues] = useState(current.current), [errors, setErrors] = useState({}), [touched, setTouched] = useState(touchedRef.current), [isSubmitting, setSubmitting] = useState(false), [validating, setValidating] = useState([]), [submitError, setSubmitError] = useState("");
10
+ const errorsRef = useRef(errors);
11
+ errorsRef.current = errors;
12
+ const abort = useCallback(() => {
13
+ controllers.current.forEach((controller) => controller.abort());
14
+ controllers.current.clear();
15
+ }, []);
16
+ useEffect(() => {
17
+ mounted.current = true;
18
+ return () => {
19
+ mounted.current = false;
20
+ version.current++;
21
+ abort();
22
+ };
23
+ }, [abort]);
24
+ const validateField = useCallback(
25
+ async (name, snapshot = current.current) => {
26
+ const rule = rulesRef.current?.[name];
27
+ if (rule?.disabled) {
28
+ if (mounted.current)
29
+ setErrors((old) => {
30
+ const next = { ...old };
31
+ delete next[name];
32
+ return next;
33
+ });
34
+ return void 0;
35
+ }
36
+ controllers.current.get(name)?.abort();
37
+ const controller = new AbortController();
38
+ controllers.current.set(name, controller);
39
+ const revision = version.current, value = snapshot[name], empty = value == null || typeof value === "string" && !value.trim() || Array.isArray(value) && value.every(
40
+ (item) => item == null || typeof item === "string" && !item.trim()
41
+ );
42
+ let error;
43
+ if (rule?.required && empty)
44
+ error = typeof rule.required === "string" ? rule.required : "\u8BF7\u586B\u5199" + (rule.label || String(name)) + "\u3002";
45
+ if (!error && rule?.mustBeTrue && value !== true)
46
+ error = typeof rule.mustBeTrue === "string" ? rule.mustBeTrue : "\u8BF7\u786E\u8BA4" + (rule.label || String(name)) + "\u3002";
47
+ if (!error && !empty && rule) {
48
+ const length = typeof value === "string" || Array.isArray(value) ? value.length : void 0;
49
+ if (length !== void 0 && rule.minLength !== void 0 && length < rule.minLength)
50
+ error = Array.isArray(value) ? "\u81F3\u5C11\u9009\u62E9 " + rule.minLength + " \u9879\u3002" : "\u81F3\u5C11\u8F93\u5165 " + rule.minLength + " \u4E2A\u5B57\u7B26\u3002";
51
+ if (length !== void 0 && rule.maxLength !== void 0 && length > rule.maxLength)
52
+ error = Array.isArray(value) ? "\u6700\u591A\u9009\u62E9 " + rule.maxLength + " \u9879\u3002" : "\u6700\u591A\u8F93\u5165 " + rule.maxLength + " \u4E2A\u5B57\u7B26\u3002";
53
+ if (typeof value === "number" && (Number.isNaN(value) || rule.min !== void 0 && value < rule.min || rule.max !== void 0 && value > rule.max))
54
+ error = "\u8BF7\u8F93\u5165\u6709\u6548\u8303\u56F4\u5185\u7684\u6570\u503C\u3002";
55
+ if (!error && rule.pattern) {
56
+ rule.pattern.lastIndex = 0;
57
+ if (!rule.pattern.test(String(value))) error = "\u683C\u5F0F\u4E0D\u6B63\u786E\u3002";
58
+ }
59
+ }
60
+ try {
61
+ if (!error && rule?.validate) {
62
+ setValidating((old) => [.../* @__PURE__ */ new Set([...old, String(name)])]);
63
+ error = await rule.validate(value, snapshot, controller.signal);
64
+ }
65
+ } catch {
66
+ if (!controller.signal.aborted) error = "\u6821\u9A8C\u672A\u5B8C\u6210\uFF0C\u8BF7\u91CD\u8BD5\u3002";
67
+ }
68
+ const valid = mounted.current && !controller.signal.aborted && revision === version.current && controllers.current.get(name) === controller;
69
+ if (valid) {
70
+ setErrors((old) => {
71
+ const next = { ...old };
72
+ if (error) next[name] = error;
73
+ else delete next[name];
74
+ return next;
75
+ });
76
+ controllers.current.delete(name);
77
+ setValidating((old) => old.filter((key) => key !== String(name)));
78
+ }
79
+ return valid ? error : void 0;
80
+ },
81
+ []
82
+ );
83
+ const setValue = useCallback(
84
+ (name, value) => {
85
+ if (locked.current) return;
86
+ version.current++;
87
+ abort();
88
+ setValidating([]);
89
+ const next = { ...current.current, [name]: value };
90
+ current.current = next;
91
+ setValues(next);
92
+ setSubmitError("");
93
+ const names = Object.keys(next);
94
+ for (const key of names)
95
+ if (mode === "change" || attempted.current || mode === "blur" && touchedRef.current[key] || errorsRef.current[key])
96
+ void validateField(key, next);
97
+ },
98
+ [abort, mode, validateField]
99
+ );
100
+ const touch = useCallback(
101
+ (name) => {
102
+ if (locked.current) return;
103
+ touchedRef.current = { ...touchedRef.current, [name]: true };
104
+ setTouched(touchedRef.current);
105
+ if (mode !== "submit" || attempted.current || errorsRef.current[name])
106
+ void validateField(name);
107
+ },
108
+ [mode, validateField]
109
+ );
110
+ const focusField = useCallback(
111
+ (name) => {
112
+ const node = document.getElementById(id + "-" + String(name));
113
+ const target = node instanceof HTMLFieldSetElement ? node.querySelector(
114
+ "input:not(:disabled),button:not(:disabled),[tabindex='0']"
115
+ ) : node;
116
+ target?.focus({ preventScroll: true });
117
+ target?.scrollIntoView({ block: "nearest", behavior: "instant" });
118
+ },
119
+ [id]
120
+ );
121
+ const validate = useCallback(async () => {
122
+ const snapshot = current.current, revision = version.current, names = Object.keys(snapshot);
123
+ const result = await Promise.all(
124
+ names.map((name) => validateField(name, snapshot))
125
+ );
126
+ const first = result.findIndex(Boolean);
127
+ return {
128
+ valid: revision === version.current && first < 0,
129
+ first: first < 0 ? void 0 : names[first]
130
+ };
131
+ }, [validateField]);
132
+ const reset = useCallback(
133
+ (next) => {
134
+ version.current++;
135
+ abort();
136
+ locked.current = false;
137
+ attempted.current = false;
138
+ if (next) defaults.current = structuredClone(next);
139
+ current.current = structuredClone(defaults.current);
140
+ touchedRef.current = {};
141
+ setValues(current.current);
142
+ setErrors({});
143
+ errorsRef.current = {};
144
+ setTouched({});
145
+ setValidating([]);
146
+ setSubmitting(false);
147
+ setSubmitError("");
148
+ },
149
+ [abort]
150
+ );
151
+ const handleSubmit = (onSubmit) => async (event) => {
152
+ event?.preventDefault();
153
+ if (locked.current) return;
154
+ locked.current = true;
155
+ attempted.current = true;
156
+ setSubmitting(true);
157
+ setSubmitError("");
158
+ const revision = version.current;
159
+ try {
160
+ const result = await validate();
161
+ if (!result.valid) {
162
+ if (result.first)
163
+ requestAnimationFrame(() => focusField(result.first));
164
+ return;
165
+ }
166
+ if (revision !== version.current) return;
167
+ await onSubmit(structuredClone(current.current));
168
+ } catch (error) {
169
+ if (mounted.current && revision === version.current)
170
+ setSubmitError(
171
+ error instanceof Error ? error.message : "\u63D0\u4EA4\u672A\u5B8C\u6210\uFF0C\u8BF7\u91CD\u8BD5\u3002"
172
+ );
173
+ } finally {
174
+ if (mounted.current && revision === version.current) {
175
+ locked.current = false;
176
+ setSubmitting(false);
177
+ }
178
+ }
179
+ };
180
+ const field = (name) => ({
181
+ id: id + "-" + String(name),
182
+ name: String(name),
183
+ required: !!(rules?.[name]?.required || rules?.[name]?.mustBeTrue),
184
+ disabled: rules?.[name]?.disabled,
185
+ error: errors[name],
186
+ onBlur: () => touch(name)
187
+ });
188
+ const setFieldError = (name, error) => setErrors((old) => {
189
+ const next = { ...old };
190
+ if (error) next[name] = error;
191
+ else delete next[name];
192
+ return next;
193
+ });
194
+ return {
195
+ values,
196
+ errors,
197
+ touched,
198
+ isSubmitting,
199
+ isValidating: validating.length > 0,
200
+ validating,
201
+ submitError,
202
+ isDirty: JSON.stringify(values) !== JSON.stringify(defaults.current),
203
+ field,
204
+ setValue,
205
+ touch,
206
+ validate,
207
+ focusField,
208
+ reset,
209
+ handleSubmit,
210
+ setFieldError,
211
+ labels: Object.fromEntries(
212
+ Object.keys(values).map((name) => [name, rules?.[name]?.label || name])
213
+ )
214
+ };
215
+ }
216
+ export {
217
+ useFormState
218
+ };
@@ -0,0 +1,8 @@
1
+ import { type HierarchyOption, type HierarchyLoader } from "./hierarchy";
2
+ export declare function useHierarchy(options: HierarchyOption[], loader?: HierarchyLoader): {
3
+ entries: Map<string, import("./hierarchy").HierarchyEntry>;
4
+ children: (node: HierarchyOption) => HierarchyOption[] | undefined;
5
+ load: (node: HierarchyOption) => Promise<boolean>;
6
+ loading: Set<string>;
7
+ error: (node: HierarchyOption) => string | undefined;
8
+ };
@@ -0,0 +1,80 @@
1
+ import { useEffect, useMemo, useRef, useState } from "react";
2
+ import {
3
+ indexHierarchy
4
+ } from "./hierarchy.js";
5
+ function useHierarchy(options, loader) {
6
+ const [cache, setCache] = useState(/* @__PURE__ */ new Map()), [loading, setLoading] = useState(/* @__PURE__ */ new Set()), [errors, setErrors] = useState(
7
+ /* @__PURE__ */ new Map()
8
+ );
9
+ const requests = useRef(
10
+ /* @__PURE__ */ new Map()
11
+ ), alive = useRef(true);
12
+ const children = (node) => node.children ?? (cache.get(node.value)?.source === node ? cache.get(node.value).children : void 0);
13
+ const entries = useMemo(
14
+ () => indexHierarchy(options, children, !!loader),
15
+ [options, cache, !!loader]
16
+ );
17
+ const current = useRef(entries);
18
+ current.current = entries;
19
+ useEffect(() => {
20
+ alive.current = true;
21
+ return () => {
22
+ alive.current = false;
23
+ requests.current.forEach((request) => request.controller.abort());
24
+ requests.current.clear();
25
+ };
26
+ }, []);
27
+ const load = (node) => {
28
+ if (children(node) !== void 0 || !loader || node.isLeaf !== false)
29
+ return Promise.resolve(true);
30
+ const existing = requests.current.get(node.value);
31
+ if (existing?.source === node) return existing.promise;
32
+ existing?.controller.abort();
33
+ const controller = new AbortController();
34
+ setLoading((old) => new Set(old).add(node.value));
35
+ setErrors((old) => {
36
+ const next = new Map(old);
37
+ next.delete(node.value);
38
+ return next;
39
+ });
40
+ const promise = Promise.resolve().then(() => loader(node, controller.signal)).then((result) => {
41
+ if (!Array.isArray(result)) throw new Error("\u52A0\u8F7D\u7ED3\u679C\u65E0\u6548");
42
+ if (controller.signal.aborted || !alive.current || current.current.get(node.value)?.node !== node)
43
+ return false;
44
+ setCache(
45
+ (old) => new Map(old).set(node.value, { source: node, children: result })
46
+ );
47
+ return true;
48
+ }).catch((error) => {
49
+ if (!controller.signal.aborted && alive.current && current.current.get(node.value)?.node === node)
50
+ setErrors(
51
+ (old) => new Map(old).set(node.value, {
52
+ source: node,
53
+ message: error instanceof Error ? error.message : "\u52A0\u8F7D\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5"
54
+ })
55
+ );
56
+ return false;
57
+ }).finally(() => {
58
+ if (requests.current.get(node.value)?.controller !== controller) return;
59
+ requests.current.delete(node.value);
60
+ if (alive.current)
61
+ setLoading((old) => {
62
+ const next = new Set(old);
63
+ next.delete(node.value);
64
+ return next;
65
+ });
66
+ });
67
+ requests.current.set(node.value, { controller, source: node, promise });
68
+ return promise;
69
+ };
70
+ return {
71
+ entries,
72
+ children,
73
+ load,
74
+ loading,
75
+ error: (node) => errors.get(node.value)?.source === node ? errors.get(node.value)?.message : void 0
76
+ };
77
+ }
78
+ export {
79
+ useHierarchy
80
+ };
@@ -0,0 +1,17 @@
1
+ import type { ContextMenuItem } from "./menuTypes";
2
+ export type MenuLayer = {
3
+ key: string;
4
+ level: number;
5
+ items: ContextMenuItem[];
6
+ anchor?: HTMLElement;
7
+ point: {
8
+ x: number;
9
+ y: number;
10
+ };
11
+ activeId?: string;
12
+ open: boolean;
13
+ };
14
+ export declare function useMenuLayers(desired: Omit<MenuLayer, "open">[]): {
15
+ layers: MenuLayer[];
16
+ exited: (key: string) => void;
17
+ };
@@ -0,0 +1,23 @@
1
+ import { useCallback, useLayoutEffect, useState } from "react";
2
+ function useMenuLayers(desired) {
3
+ const [layers, setLayers] = useState([]);
4
+ useLayoutEffect(() => {
5
+ setLayers((previous) => {
6
+ const keys = new Set(desired.map((layer) => layer.key));
7
+ return [
8
+ ...desired.map((layer) => ({ ...layer, open: true })),
9
+ ...previous.filter((layer) => !keys.has(layer.key)).map((layer) => ({ ...layer, open: false }))
10
+ ];
11
+ });
12
+ }, [desired]);
13
+ const exited = useCallback(
14
+ (key) => setLayers(
15
+ (previous) => previous.filter((layer) => layer.key !== key || layer.open)
16
+ ),
17
+ []
18
+ );
19
+ return { layers, exited };
20
+ }
21
+ export {
22
+ useMenuLayers
23
+ };
@@ -0,0 +1 @@
1
+ export declare function useModalScrollLock(active: boolean): void;
@@ -0,0 +1,18 @@
1
+ import { useEffect } from "react";
2
+ let locks = 0;
3
+ let previous = "";
4
+ function useModalScrollLock(active) {
5
+ useEffect(() => {
6
+ if (!active) return;
7
+ if (locks++ === 0) {
8
+ previous = document.body.style.overflow;
9
+ document.body.style.overflow = "hidden";
10
+ }
11
+ return () => {
12
+ if (--locks === 0) document.body.style.overflow = previous;
13
+ };
14
+ }, [active]);
15
+ }
16
+ export {
17
+ useModalScrollLock
18
+ };
@@ -0,0 +1,8 @@
1
+ export declare function usePopover<T extends HTMLElement = HTMLButtonElement>(blocked?: boolean): {
2
+ anchor: import("react").RefObject<T | null>;
3
+ open: boolean;
4
+ close: () => void;
5
+ closeAndFocus: () => void;
6
+ show: () => void;
7
+ toggle: () => void;
8
+ };
@@ -0,0 +1,22 @@
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+ function usePopover(blocked = false) {
3
+ const anchor = useRef(null), [open, setOpen] = useState(false);
4
+ const close = useCallback(() => setOpen(false), []);
5
+ const closeAndFocus = useCallback(() => {
6
+ close();
7
+ anchor.current?.focus({ preventScroll: true });
8
+ }, [close]);
9
+ const show = useCallback(() => {
10
+ if (!blocked) setOpen(true);
11
+ }, [blocked]);
12
+ const toggle = useCallback(() => {
13
+ if (!blocked) setOpen((value) => !value);
14
+ }, [blocked]);
15
+ useEffect(() => {
16
+ if (blocked) close();
17
+ }, [blocked, close]);
18
+ return { anchor, open: open && !blocked, close, closeAndFocus, show, toggle };
19
+ }
20
+ export {
21
+ usePopover
22
+ };
@@ -0,0 +1,12 @@
1
+ import { type KeyboardEvent } from "react";
2
+ export type TabOption<T extends string> = {
3
+ value: T;
4
+ label: React.ReactNode;
5
+ disabled?: boolean;
6
+ id?: string;
7
+ panelId?: string;
8
+ };
9
+ export declare function useTabIndicator<T extends string>(value: T, options: TabOption<T>[], onChange: (value: T) => void, orientation: "horizontal" | "vertical"): {
10
+ root: import("react").RefObject<HTMLDivElement | null>;
11
+ onKeyDown: (event: KeyboardEvent<HTMLDivElement>) => void;
12
+ };
@@ -0,0 +1,63 @@
1
+ import { useLayoutEffect, useRef } from "react";
2
+ function useTabIndicator(value, options, onChange, orientation) {
3
+ const root = useRef(null);
4
+ useLayoutEffect(() => {
5
+ const node = root.current;
6
+ const measure = () => {
7
+ const current = [
8
+ ...node.querySelectorAll('[role="tab"]')
9
+ ].find((el) => el.dataset.value === value);
10
+ if (!current) {
11
+ node.style.setProperty("--tab-opacity", "0");
12
+ return;
13
+ }
14
+ if (orientation === "vertical") {
15
+ const viewport = node.parentElement;
16
+ if (current.offsetTop < viewport.scrollTop)
17
+ viewport.scrollTop = current.offsetTop;
18
+ else if (current.offsetTop + current.offsetHeight > viewport.scrollTop + viewport.clientHeight)
19
+ viewport.scrollTop = current.offsetTop + current.offsetHeight - viewport.clientHeight;
20
+ }
21
+ if (orientation === "horizontal") {
22
+ const viewport = node.parentElement;
23
+ if (current.offsetLeft < viewport.scrollLeft)
24
+ viewport.scrollLeft = current.offsetLeft;
25
+ else if (current.offsetLeft + current.offsetWidth > viewport.scrollLeft + viewport.clientWidth)
26
+ viewport.scrollLeft = current.offsetLeft + current.offsetWidth - viewport.clientWidth;
27
+ }
28
+ node.style.setProperty("--tab-opacity", "1");
29
+ node.style.setProperty("--tab-x", current.offsetLeft + "px");
30
+ node.style.setProperty("--tab-y", current.offsetTop + "px");
31
+ node.style.setProperty("--tab-width", current.offsetWidth + "px");
32
+ node.style.setProperty("--tab-height", current.offsetHeight + "px");
33
+ if (!node.dataset.ready) {
34
+ node.getBoundingClientRect();
35
+ node.dataset.ready = "true";
36
+ }
37
+ };
38
+ measure();
39
+ const observer = new ResizeObserver(measure);
40
+ observer.observe(node);
41
+ node.querySelectorAll('[role="tab"]').forEach((el) => observer.observe(el));
42
+ return () => observer.disconnect();
43
+ }, [value, options, orientation]);
44
+ const onKeyDown = (event) => {
45
+ const enabled = options.filter((x) => !x.disabled), index = enabled.findIndex((x) => x.value === value);
46
+ let next = index;
47
+ if (event.key === (orientation === "vertical" ? "ArrowDown" : "ArrowRight"))
48
+ next = (index + 1) % enabled.length;
49
+ else if (event.key === (orientation === "vertical" ? "ArrowUp" : "ArrowLeft"))
50
+ next = (index - 1 + enabled.length) % enabled.length;
51
+ else if (event.key === "Home") next = 0;
52
+ else if (event.key === "End") next = enabled.length - 1;
53
+ else return;
54
+ if (!enabled[next]) return;
55
+ event.preventDefault();
56
+ onChange(enabled[next].value);
57
+ [...root.current.querySelectorAll('[role="tab"]')].find((el) => el.dataset.value === enabled[next].value)?.focus();
58
+ };
59
+ return { root, onKeyDown };
60
+ }
61
+ export {
62
+ useTabIndicator
63
+ };
@@ -0,0 +1,20 @@
1
+ import type { UploadFile, UploadRequest, UploadResult } from "./uploadTypes";
2
+ export declare function useUploadQueue({ value, defaultValue, onChange, request, autoUpload, concurrency, disabled, onSuccess, onError, }: {
3
+ value?: UploadFile[];
4
+ defaultValue?: UploadFile[];
5
+ onChange?(files: UploadFile[]): void;
6
+ request?: UploadRequest;
7
+ autoUpload?: boolean;
8
+ concurrency?: number;
9
+ disabled?: boolean;
10
+ onSuccess?(file: UploadFile, result: UploadResult | void): void;
11
+ onError?(file: UploadFile, error: unknown): void;
12
+ }): {
13
+ files: UploadFile[];
14
+ current: import("react").RefObject<UploadFile[]>;
15
+ add: (batch: File[]) => void;
16
+ start: (id: string) => void;
17
+ cancel: (id: string) => void;
18
+ remove: (id: string) => void;
19
+ retry: (id: string) => void;
20
+ };