@questpie/admin 0.0.1 → 1.0.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 (250) hide show
  1. package/README.md +439 -424
  2. package/dist/auth-layout-M8K8_q5R.mjs +181 -0
  3. package/dist/auth-layout-M8K8_q5R.mjs.map +1 -0
  4. package/dist/bulk-upload-dialog-h7zXD78Y.mjs +274 -0
  5. package/dist/bulk-upload-dialog-h7zXD78Y.mjs.map +1 -0
  6. package/dist/{components/ui/card.mjs → card-BKHjBQfw.mjs} +8 -8
  7. package/dist/card-BKHjBQfw.mjs.map +1 -0
  8. package/dist/client/styles/index.css +434 -0
  9. package/dist/client-BCGpkAz6.mjs +22635 -0
  10. package/dist/client-BCGpkAz6.mjs.map +1 -0
  11. package/dist/client-CcWZbkBP.d.mts +13585 -0
  12. package/dist/client-CcWZbkBP.d.mts.map +1 -0
  13. package/dist/client.d.mts +3 -0
  14. package/dist/client.mjs +14 -0
  15. package/dist/content-locales-provider-BXvuIgfg.mjs +1650 -0
  16. package/dist/content-locales-provider-BXvuIgfg.mjs.map +1 -0
  17. package/dist/dashboard-page-B4PGEdc2.mjs +2500 -0
  18. package/dist/dashboard-page-B4PGEdc2.mjs.map +1 -0
  19. package/dist/dashboard-page-CVlyR40m.mjs +6 -0
  20. package/dist/dropzone-Do3awXKd.mjs +634 -0
  21. package/dist/dropzone-Do3awXKd.mjs.map +1 -0
  22. package/dist/{views/auth/forgot-password-form.mjs → forgot-password-page-Bcp-An4Y.mjs} +87 -14
  23. package/dist/forgot-password-page-Bcp-An4Y.mjs.map +1 -0
  24. package/dist/forgot-password-page-CIILVhfo.mjs +7 -0
  25. package/dist/index-B9Xwk4hi.d.mts +2753 -0
  26. package/dist/index-B9Xwk4hi.d.mts.map +1 -0
  27. package/dist/index.d.mts +3 -0
  28. package/dist/index.mjs +14 -0
  29. package/dist/login-page-8K7fo0qK.mjs +7 -0
  30. package/dist/login-page-CP4gA-dl.mjs +298 -0
  31. package/dist/login-page-CP4gA-dl.mjs.map +1 -0
  32. package/dist/preview-utils-BKQ9-TMa.mjs +65 -0
  33. package/dist/preview-utils-BKQ9-TMa.mjs.map +1 -0
  34. package/dist/{views/auth/reset-password-form.mjs → reset-password-page-BqfDmLxA.mjs} +111 -14
  35. package/dist/reset-password-page-BqfDmLxA.mjs.map +1 -0
  36. package/dist/reset-password-page-DLATv0xQ.mjs +7 -0
  37. package/dist/runtime-6VZM878K.mjs +69 -0
  38. package/dist/runtime-6VZM878K.mjs.map +1 -0
  39. package/dist/saved-views.types-BMsz5mCy.d.mts +42 -0
  40. package/dist/saved-views.types-BMsz5mCy.d.mts.map +1 -0
  41. package/dist/server.d.mts +250 -0
  42. package/dist/server.d.mts.map +1 -0
  43. package/dist/server.mjs +832 -0
  44. package/dist/server.mjs.map +1 -0
  45. package/dist/setup-page-CMZ5P_OE.mjs +6 -0
  46. package/dist/setup-page-YAP_fzqh.mjs +264 -0
  47. package/dist/setup-page-YAP_fzqh.mjs.map +1 -0
  48. package/dist/shared.d.mts +57 -0
  49. package/dist/shared.d.mts.map +1 -0
  50. package/dist/shared.mjs +3 -0
  51. package/dist/{hooks/use-auth.mjs → use-auth-BoLmWtmU.mjs} +42 -30
  52. package/dist/use-auth-BoLmWtmU.mjs.map +1 -0
  53. package/package.json +48 -197
  54. package/.turbo/turbo-build.log +0 -108
  55. package/CHANGELOG.md +0 -10
  56. package/STATUS.md +0 -917
  57. package/VALIDATION.md +0 -602
  58. package/components.json +0 -24
  59. package/dist/__tests__/setup.mjs +0 -38
  60. package/dist/__tests__/test-utils.mjs +0 -45
  61. package/dist/__tests__/vitest.d.mjs +0 -3
  62. package/dist/components/admin-app.mjs +0 -69
  63. package/dist/components/fields/array-field.mjs +0 -190
  64. package/dist/components/fields/checkbox-field.mjs +0 -34
  65. package/dist/components/fields/custom-field.mjs +0 -32
  66. package/dist/components/fields/date-field.mjs +0 -41
  67. package/dist/components/fields/datetime-field.mjs +0 -42
  68. package/dist/components/fields/email-field.mjs +0 -37
  69. package/dist/components/fields/embedded-collection.mjs +0 -253
  70. package/dist/components/fields/field-types.mjs +0 -1
  71. package/dist/components/fields/field-utils.mjs +0 -10
  72. package/dist/components/fields/field-wrapper.mjs +0 -34
  73. package/dist/components/fields/index.mjs +0 -23
  74. package/dist/components/fields/json-field.mjs +0 -243
  75. package/dist/components/fields/locale-badge.mjs +0 -16
  76. package/dist/components/fields/number-field.mjs +0 -39
  77. package/dist/components/fields/password-field.mjs +0 -37
  78. package/dist/components/fields/relation-field.mjs +0 -104
  79. package/dist/components/fields/relation-picker.mjs +0 -229
  80. package/dist/components/fields/relation-select.mjs +0 -188
  81. package/dist/components/fields/rich-text-editor/index.mjs +0 -897
  82. package/dist/components/fields/select-field.mjs +0 -41
  83. package/dist/components/fields/switch-field.mjs +0 -34
  84. package/dist/components/fields/text-field.mjs +0 -38
  85. package/dist/components/fields/textarea-field.mjs +0 -38
  86. package/dist/components/index.mjs +0 -59
  87. package/dist/components/primitives/checkbox-input.mjs +0 -127
  88. package/dist/components/primitives/date-input.mjs +0 -303
  89. package/dist/components/primitives/index.mjs +0 -12
  90. package/dist/components/primitives/number-input.mjs +0 -104
  91. package/dist/components/primitives/select-input.mjs +0 -177
  92. package/dist/components/primitives/tag-input.mjs +0 -135
  93. package/dist/components/primitives/text-input.mjs +0 -39
  94. package/dist/components/primitives/textarea-input.mjs +0 -37
  95. package/dist/components/primitives/toggle-input.mjs +0 -31
  96. package/dist/components/primitives/types.mjs +0 -12
  97. package/dist/components/ui/accordion.mjs +0 -55
  98. package/dist/components/ui/avatar.mjs +0 -54
  99. package/dist/components/ui/badge.mjs +0 -34
  100. package/dist/components/ui/button.mjs +0 -48
  101. package/dist/components/ui/checkbox.mjs +0 -21
  102. package/dist/components/ui/combobox.mjs +0 -163
  103. package/dist/components/ui/dialog.mjs +0 -95
  104. package/dist/components/ui/dropdown-menu.mjs +0 -138
  105. package/dist/components/ui/field.mjs +0 -113
  106. package/dist/components/ui/input-group.mjs +0 -82
  107. package/dist/components/ui/input.mjs +0 -17
  108. package/dist/components/ui/label.mjs +0 -15
  109. package/dist/components/ui/popover.mjs +0 -56
  110. package/dist/components/ui/scroll-area.mjs +0 -38
  111. package/dist/components/ui/select.mjs +0 -100
  112. package/dist/components/ui/separator.mjs +0 -16
  113. package/dist/components/ui/sheet.mjs +0 -90
  114. package/dist/components/ui/sidebar.mjs +0 -387
  115. package/dist/components/ui/skeleton.mjs +0 -14
  116. package/dist/components/ui/spinner.mjs +0 -16
  117. package/dist/components/ui/switch.mjs +0 -22
  118. package/dist/components/ui/table.mjs +0 -68
  119. package/dist/components/ui/tabs.mjs +0 -48
  120. package/dist/components/ui/textarea.mjs +0 -15
  121. package/dist/components/ui/tooltip.mjs +0 -44
  122. package/dist/config/component-registry.mjs +0 -38
  123. package/dist/config/index.mjs +0 -129
  124. package/dist/hooks/admin-provider.mjs +0 -70
  125. package/dist/hooks/index.mjs +0 -7
  126. package/dist/hooks/store.mjs +0 -178
  127. package/dist/hooks/use-collection-db.mjs +0 -146
  128. package/dist/hooks/use-collection.mjs +0 -112
  129. package/dist/hooks/use-global.mjs +0 -46
  130. package/dist/hooks/use-mobile.mjs +0 -20
  131. package/dist/lib/utils.mjs +0 -10
  132. package/dist/styles/index.css +0 -336
  133. package/dist/styles/index.mjs +0 -1
  134. package/dist/utils/index.mjs +0 -9
  135. package/dist/views/auth/auth-layout.mjs +0 -52
  136. package/dist/views/auth/index.mjs +0 -6
  137. package/dist/views/auth/login-form.mjs +0 -156
  138. package/dist/views/collection/auto-form-fields.mjs +0 -525
  139. package/dist/views/collection/collection-form.mjs +0 -91
  140. package/dist/views/collection/collection-list.mjs +0 -76
  141. package/dist/views/collection/form-field.mjs +0 -42
  142. package/dist/views/collection/index.mjs +0 -6
  143. package/dist/views/common/index.mjs +0 -4
  144. package/dist/views/common/locale-switcher.mjs +0 -39
  145. package/dist/views/common/version-history.mjs +0 -272
  146. package/dist/views/index.mjs +0 -9
  147. package/dist/views/layout/admin-layout.mjs +0 -40
  148. package/dist/views/layout/admin-router.mjs +0 -95
  149. package/dist/views/layout/admin-sidebar.mjs +0 -63
  150. package/dist/views/layout/index.mjs +0 -5
  151. package/src/__tests__/setup.ts +0 -44
  152. package/src/__tests__/test-utils.tsx +0 -49
  153. package/src/__tests__/vitest.d.ts +0 -9
  154. package/src/components/admin-app.tsx +0 -221
  155. package/src/components/fields/array-field.tsx +0 -237
  156. package/src/components/fields/checkbox-field.tsx +0 -47
  157. package/src/components/fields/custom-field.tsx +0 -50
  158. package/src/components/fields/date-field.tsx +0 -65
  159. package/src/components/fields/datetime-field.tsx +0 -67
  160. package/src/components/fields/email-field.tsx +0 -51
  161. package/src/components/fields/embedded-collection.tsx +0 -315
  162. package/src/components/fields/field-types.ts +0 -162
  163. package/src/components/fields/field-utils.ts +0 -6
  164. package/src/components/fields/field-wrapper.tsx +0 -52
  165. package/src/components/fields/index.ts +0 -66
  166. package/src/components/fields/json-field.tsx +0 -440
  167. package/src/components/fields/locale-badge.tsx +0 -15
  168. package/src/components/fields/number-field.tsx +0 -57
  169. package/src/components/fields/password-field.tsx +0 -51
  170. package/src/components/fields/relation-field.tsx +0 -243
  171. package/src/components/fields/relation-picker.tsx +0 -402
  172. package/src/components/fields/relation-select.tsx +0 -327
  173. package/src/components/fields/rich-text-editor/index.tsx +0 -1337
  174. package/src/components/fields/select-field.tsx +0 -61
  175. package/src/components/fields/switch-field.tsx +0 -47
  176. package/src/components/fields/text-field.tsx +0 -55
  177. package/src/components/fields/textarea-field.tsx +0 -55
  178. package/src/components/index.ts +0 -40
  179. package/src/components/primitives/checkbox-input.tsx +0 -193
  180. package/src/components/primitives/date-input.tsx +0 -401
  181. package/src/components/primitives/index.ts +0 -24
  182. package/src/components/primitives/number-input.tsx +0 -132
  183. package/src/components/primitives/select-input.tsx +0 -296
  184. package/src/components/primitives/tag-input.tsx +0 -200
  185. package/src/components/primitives/text-input.tsx +0 -49
  186. package/src/components/primitives/textarea-input.tsx +0 -46
  187. package/src/components/primitives/toggle-input.tsx +0 -36
  188. package/src/components/primitives/types.ts +0 -235
  189. package/src/components/ui/accordion.tsx +0 -72
  190. package/src/components/ui/avatar.tsx +0 -106
  191. package/src/components/ui/badge.tsx +0 -48
  192. package/src/components/ui/button.tsx +0 -53
  193. package/src/components/ui/card.tsx +0 -94
  194. package/src/components/ui/checkbox.tsx +0 -27
  195. package/src/components/ui/combobox.tsx +0 -290
  196. package/src/components/ui/dialog.tsx +0 -151
  197. package/src/components/ui/dropdown-menu.tsx +0 -254
  198. package/src/components/ui/field.tsx +0 -227
  199. package/src/components/ui/input-group.tsx +0 -149
  200. package/src/components/ui/input.tsx +0 -20
  201. package/src/components/ui/label.tsx +0 -18
  202. package/src/components/ui/popover.tsx +0 -88
  203. package/src/components/ui/scroll-area.tsx +0 -53
  204. package/src/components/ui/select.tsx +0 -192
  205. package/src/components/ui/separator.tsx +0 -23
  206. package/src/components/ui/sheet.tsx +0 -127
  207. package/src/components/ui/sidebar.tsx +0 -723
  208. package/src/components/ui/skeleton.tsx +0 -13
  209. package/src/components/ui/spinner.tsx +0 -10
  210. package/src/components/ui/switch.tsx +0 -32
  211. package/src/components/ui/table.tsx +0 -99
  212. package/src/components/ui/tabs.tsx +0 -82
  213. package/src/components/ui/textarea.tsx +0 -18
  214. package/src/components/ui/tooltip.tsx +0 -70
  215. package/src/config/component-registry.ts +0 -190
  216. package/src/config/index.ts +0 -1099
  217. package/src/hooks/README.md +0 -269
  218. package/src/hooks/admin-provider.tsx +0 -110
  219. package/src/hooks/index.ts +0 -41
  220. package/src/hooks/store.ts +0 -248
  221. package/src/hooks/use-auth.ts +0 -168
  222. package/src/hooks/use-collection-db.ts +0 -209
  223. package/src/hooks/use-collection.ts +0 -156
  224. package/src/hooks/use-global.ts +0 -69
  225. package/src/hooks/use-mobile.ts +0 -21
  226. package/src/lib/utils.ts +0 -6
  227. package/src/styles/index.css +0 -340
  228. package/src/utils/index.ts +0 -6
  229. package/src/views/auth/auth-layout.tsx +0 -77
  230. package/src/views/auth/forgot-password-form.tsx +0 -192
  231. package/src/views/auth/index.ts +0 -21
  232. package/src/views/auth/login-form.tsx +0 -229
  233. package/src/views/auth/reset-password-form.tsx +0 -232
  234. package/src/views/collection/auto-form-fields.tsx +0 -982
  235. package/src/views/collection/collection-form.tsx +0 -186
  236. package/src/views/collection/collection-list.tsx +0 -223
  237. package/src/views/collection/form-field.tsx +0 -52
  238. package/src/views/collection/index.ts +0 -15
  239. package/src/views/common/index.ts +0 -8
  240. package/src/views/common/locale-switcher.tsx +0 -45
  241. package/src/views/common/version-history.tsx +0 -406
  242. package/src/views/index.ts +0 -25
  243. package/src/views/layout/admin-layout.tsx +0 -117
  244. package/src/views/layout/admin-router.tsx +0 -206
  245. package/src/views/layout/admin-sidebar.tsx +0 -185
  246. package/src/views/layout/index.ts +0 -12
  247. package/tsconfig.json +0 -13
  248. package/tsconfig.tsbuildinfo +0 -1
  249. package/tsdown.config.ts +0 -13
  250. package/vitest.config.ts +0 -29
@@ -1,104 +0,0 @@
1
- import { jsx, jsxs } from "react/jsx-runtime";
2
- import { Button } from "../ui/button";
3
- import { Input } from "../ui/input";
4
- import { cn } from "../../lib/utils";
5
- import { Minus, Plus } from "@phosphor-icons/react";
6
-
7
- //#region src/components/primitives/number-input.tsx
8
- /**
9
- * Number Input Primitive
10
- *
11
- * A number input with optional increment/decrement buttons.
12
- *
13
- * @example
14
- * ```tsx
15
- * <NumberInput
16
- * value={count}
17
- * onChange={setCount}
18
- * min={0}
19
- * max={100}
20
- * step={1}
21
- * showButtons
22
- * />
23
- * ```
24
- */
25
- function NumberInput({ value, onChange, min, max, step = 1, showButtons = false, placeholder, disabled, readOnly, className, id, "aria-invalid": ariaInvalid }) {
26
- const handleChange = (newValue) => {
27
- if (newValue === null) {
28
- onChange(null);
29
- return;
30
- }
31
- let clampedValue = newValue;
32
- if (min !== void 0 && clampedValue < min) clampedValue = min;
33
- if (max !== void 0 && clampedValue > max) clampedValue = max;
34
- onChange(clampedValue);
35
- };
36
- const increment = () => {
37
- handleChange((value ?? 0) + step);
38
- };
39
- const decrement = () => {
40
- handleChange((value ?? 0) - step);
41
- };
42
- if (showButtons) return /* @__PURE__ */ jsxs("div", {
43
- className: cn("flex items-center gap-1", className),
44
- children: [
45
- /* @__PURE__ */ jsx(Button, {
46
- type: "button",
47
- variant: "outline",
48
- size: "icon-sm",
49
- onClick: decrement,
50
- disabled: disabled || min !== void 0 && (value ?? 0) <= min,
51
- tabIndex: -1,
52
- children: /* @__PURE__ */ jsx(Minus, { className: "size-3" })
53
- }),
54
- /* @__PURE__ */ jsx(Input, {
55
- id,
56
- type: "number",
57
- value: value ?? "",
58
- onChange: (e) => {
59
- const val = e.target.value;
60
- if (val === "") handleChange(null);
61
- else handleChange(Number(val));
62
- },
63
- placeholder,
64
- disabled,
65
- readOnly,
66
- min,
67
- max,
68
- step,
69
- "aria-invalid": ariaInvalid,
70
- className: "text-center [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
71
- }),
72
- /* @__PURE__ */ jsx(Button, {
73
- type: "button",
74
- variant: "outline",
75
- size: "icon-sm",
76
- onClick: increment,
77
- disabled: disabled || max !== void 0 && (value ?? 0) >= max,
78
- tabIndex: -1,
79
- children: /* @__PURE__ */ jsx(Plus, { className: "size-3" })
80
- })
81
- ]
82
- });
83
- return /* @__PURE__ */ jsx(Input, {
84
- id,
85
- type: "number",
86
- value: value ?? "",
87
- onChange: (e) => {
88
- const val = e.target.value;
89
- if (val === "") handleChange(null);
90
- else handleChange(Number(val));
91
- },
92
- placeholder,
93
- disabled,
94
- readOnly,
95
- min,
96
- max,
97
- step,
98
- "aria-invalid": ariaInvalid,
99
- className: cn(className)
100
- });
101
- }
102
-
103
- //#endregion
104
- export { NumberInput };
@@ -1,177 +0,0 @@
1
- "use client";
2
-
3
- import { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
- import { jsx, jsxs } from "react/jsx-runtime";
5
- import { Combobox, ComboboxChip, ComboboxChips, ComboboxChipsInput, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxList, useComboboxAnchor } from "../ui/combobox";
6
- import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
7
- import { cn } from "../../lib/utils";
8
- import { Check, CircleNotch } from "@phosphor-icons/react";
9
- import { flattenOptions } from "./types";
10
-
11
- //#region src/components/primitives/select-input.tsx
12
- /**
13
- * Select Input Primitive
14
- *
15
- * A unified select component that supports:
16
- * - Single select (dropdown)
17
- * - Multi-select (chips)
18
- * - Static options
19
- * - Dynamic loading via loadOptions
20
- * - Search/filtering
21
- *
22
- * @example
23
- * ```tsx
24
- * // Single select with static options
25
- * <SelectInput
26
- * value={status}
27
- * onChange={setStatus}
28
- * options={[
29
- * { value: "active", label: "Active" },
30
- * { value: "inactive", label: "Inactive" },
31
- * ]}
32
- * />
33
- *
34
- * // Multi-select with dynamic loading
35
- * <SelectInput
36
- * value={selectedTags}
37
- * onChange={setSelectedTags}
38
- * multiple
39
- * loadOptions={async (search) => {
40
- * const res = await fetch(`/api/tags?search=${search}`)
41
- * return res.json()
42
- * }}
43
- * />
44
- * ```
45
- */
46
- function SelectInput({ value, onChange, options: staticOptions = [], loadOptions, multiple = false, clearable = true, maxSelections, debounceMs = 300, loading: externalLoading = false, emptyMessage = "No options found", placeholder = "Select...", disabled, className, id, "aria-invalid": ariaInvalid }) {
47
- const [search, setSearch] = useState("");
48
- const [dynamicOptions, setDynamicOptions] = useState([]);
49
- const [isLoading, setIsLoading] = useState(false);
50
- const debounceRef = useRef(null);
51
- const anchorRef = useComboboxAnchor();
52
- const flatStaticOptions = useMemo(() => flattenOptions(staticOptions), [staticOptions]);
53
- const allOptions = useMemo(() => {
54
- if (loadOptions) return dynamicOptions;
55
- return flatStaticOptions;
56
- }, [
57
- loadOptions,
58
- dynamicOptions,
59
- flatStaticOptions
60
- ]);
61
- const filteredOptions = useMemo(() => {
62
- if (loadOptions) return allOptions;
63
- if (!search) return allOptions;
64
- return allOptions.filter((opt) => opt.label.toLowerCase().includes(search.toLowerCase()));
65
- }, [
66
- allOptions,
67
- search,
68
- loadOptions
69
- ]);
70
- useEffect(() => {
71
- if (!loadOptions) return;
72
- if (debounceRef.current) clearTimeout(debounceRef.current);
73
- debounceRef.current = setTimeout(async () => {
74
- setIsLoading(true);
75
- try {
76
- setDynamicOptions(await loadOptions(search));
77
- } catch (error) {
78
- console.error("Failed to load options:", error);
79
- setDynamicOptions([]);
80
- } finally {
81
- setIsLoading(false);
82
- }
83
- }, debounceMs);
84
- return () => {
85
- if (debounceRef.current) clearTimeout(debounceRef.current);
86
- };
87
- }, [
88
- search,
89
- loadOptions,
90
- debounceMs
91
- ]);
92
- const getLabel = useCallback((val) => {
93
- return allOptions.find((opt) => opt.value === val)?.label ?? String(val);
94
- }, [allOptions]);
95
- const selectedValues = useMemo(() => {
96
- if (value === null || value === void 0) return [];
97
- return Array.isArray(value) ? value : [value];
98
- }, [value]);
99
- const handleMultiSelect = useCallback((selectedValue) => {
100
- const currentValues = selectedValues;
101
- if (currentValues.includes(selectedValue)) onChange(currentValues.filter((v) => v !== selectedValue));
102
- else {
103
- if (maxSelections && currentValues.length >= maxSelections) return;
104
- onChange([...currentValues, selectedValue]);
105
- }
106
- }, [
107
- selectedValues,
108
- onChange,
109
- maxSelections
110
- ]);
111
- useCallback((removedValue) => {
112
- onChange(selectedValues.filter((v) => v !== removedValue));
113
- }, [selectedValues, onChange]);
114
- const showLoading = isLoading || externalLoading;
115
- if (!multiple && !loadOptions) return /* @__PURE__ */ jsxs(Select, {
116
- value: selectedValues[0] ?? "",
117
- onValueChange: (val) => onChange(val),
118
- disabled,
119
- children: [/* @__PURE__ */ jsx(SelectTrigger, {
120
- id,
121
- className: cn("w-full", className),
122
- "aria-invalid": ariaInvalid,
123
- children: /* @__PURE__ */ jsx(SelectValue, { children: selectedValues[0] ? getLabel(selectedValues[0]) : placeholder })
124
- }), /* @__PURE__ */ jsx(SelectContent, { children: filteredOptions.map((option) => /* @__PURE__ */ jsxs(SelectItem, {
125
- value: String(option.value),
126
- disabled: option.disabled,
127
- children: [option.icon, option.label]
128
- }, String(option.value))) })]
129
- });
130
- return /* @__PURE__ */ jsxs(Combobox, {
131
- value: multiple ? void 0 : selectedValues[0] ?? null,
132
- onValueChange: (val) => {
133
- if (val !== null && val !== void 0) if (multiple) handleMultiSelect(val);
134
- else onChange(val);
135
- },
136
- disabled,
137
- children: [multiple ? /* @__PURE__ */ jsxs(ComboboxChips, {
138
- ref: anchorRef,
139
- className: cn(className),
140
- "aria-invalid": ariaInvalid,
141
- children: [selectedValues.map((val) => /* @__PURE__ */ jsx(ComboboxChip, { children: getLabel(val) }, String(val))), /* @__PURE__ */ jsx(ComboboxChipsInput, {
142
- placeholder: selectedValues.length === 0 ? placeholder : void 0,
143
- value: search,
144
- onChange: (e) => setSearch(e.target.value)
145
- })]
146
- }) : /* @__PURE__ */ jsx(ComboboxInput, {
147
- id,
148
- placeholder,
149
- value: search,
150
- onChange: (e) => setSearch(e.target.value),
151
- className: cn(className),
152
- "aria-invalid": ariaInvalid,
153
- showClear: clearable && selectedValues.length > 0
154
- }), /* @__PURE__ */ jsxs(ComboboxContent, {
155
- anchor: multiple ? anchorRef : void 0,
156
- children: [
157
- showLoading && /* @__PURE__ */ jsx("div", {
158
- className: "flex items-center justify-center py-4",
159
- children: /* @__PURE__ */ jsx(CircleNotch, { className: "size-4 animate-spin text-muted-foreground" })
160
- }),
161
- /* @__PURE__ */ jsx(ComboboxList, { children: filteredOptions.map((option) => /* @__PURE__ */ jsxs(ComboboxItem, {
162
- value: option.value,
163
- disabled: option.disabled,
164
- children: [
165
- option.icon,
166
- option.label,
167
- multiple && selectedValues.includes(option.value) && /* @__PURE__ */ jsx(Check, { className: "ml-auto size-3.5" })
168
- ]
169
- }, String(option.value))) }),
170
- /* @__PURE__ */ jsx(ComboboxEmpty, { children: emptyMessage })
171
- ]
172
- })]
173
- });
174
- }
175
-
176
- //#endregion
177
- export { SelectInput };
@@ -1,135 +0,0 @@
1
- "use client";
2
-
3
- import { useCallback, useState } from "react";
4
- import { jsx, jsxs } from "react/jsx-runtime";
5
- import { Badge } from "../ui/badge";
6
- import { cn } from "../../lib/utils";
7
- import { X } from "@phosphor-icons/react";
8
-
9
- //#region src/components/primitives/tag-input.tsx
10
- /**
11
- * Tag Input Primitive
12
- *
13
- * An input for creating and managing tags/chips.
14
- * Supports validation patterns, max tags, and autocomplete suggestions.
15
- *
16
- * @example
17
- * ```tsx
18
- * // Basic usage
19
- * <TagInput
20
- * value={tags}
21
- * onChange={setTags}
22
- * placeholder="Add tags..."
23
- * />
24
- *
25
- * // With suggestions and validation
26
- * <TagInput
27
- * value={emails}
28
- * onChange={setEmails}
29
- * suggestions={["user@example.com", "admin@example.com"]}
30
- * pattern={/^[^\s@]+@[^\s@]+\.[^\s@]+$/}
31
- * maxTags={5}
32
- * />
33
- * ```
34
- */
35
- function TagInput({ value, onChange, suggestions = [], maxTags, allowDuplicates = false, pattern, placeholder = "Type and press Enter...", disabled, className, id, "aria-invalid": ariaInvalid }) {
36
- const [inputValue, setInputValue] = useState("");
37
- const [showSuggestions, setShowSuggestions] = useState(false);
38
- const addTag = useCallback((tag) => {
39
- const trimmed = tag.trim();
40
- if (!trimmed) return;
41
- if (maxTags && value.length >= maxTags) return;
42
- if (!allowDuplicates && value.includes(trimmed)) return;
43
- if (pattern && !pattern.test(trimmed)) return;
44
- onChange([...value, trimmed]);
45
- setInputValue("");
46
- setShowSuggestions(false);
47
- }, [
48
- value,
49
- onChange,
50
- maxTags,
51
- allowDuplicates,
52
- pattern
53
- ]);
54
- const removeTag = useCallback((index) => {
55
- if (disabled) return;
56
- onChange(value.filter((_, i) => i !== index));
57
- }, [
58
- value,
59
- onChange,
60
- disabled
61
- ]);
62
- const handleKeyDown = useCallback((e) => {
63
- if (e.key === "Enter") {
64
- e.preventDefault();
65
- addTag(inputValue);
66
- } else if (e.key === "Backspace" && !inputValue && value.length > 0) removeTag(value.length - 1);
67
- else if (e.key === "Escape") setShowSuggestions(false);
68
- }, [
69
- inputValue,
70
- value,
71
- addTag,
72
- removeTag
73
- ]);
74
- const handleInputChange = useCallback((e) => {
75
- const newValue = e.target.value;
76
- setInputValue(newValue);
77
- setShowSuggestions(newValue.length > 0 && suggestions.length > 0);
78
- }, [suggestions]);
79
- const filteredSuggestions = suggestions.filter((suggestion) => suggestion.toLowerCase().includes(inputValue.toLowerCase()) && (allowDuplicates || !value.includes(suggestion)));
80
- const canAddMore = !maxTags || value.length < maxTags;
81
- return /* @__PURE__ */ jsxs("div", {
82
- className: cn("relative", className),
83
- children: [
84
- /* @__PURE__ */ jsxs("div", {
85
- className: cn("flex flex-wrap gap-1.5 min-h-9 w-full border border-input bg-background px-3 py-2", "focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2", ariaInvalid && "border-destructive ring-destructive/20", disabled && "cursor-not-allowed opacity-50"),
86
- children: [value.map((tag, index) => /* @__PURE__ */ jsxs(Badge, {
87
- variant: "secondary",
88
- className: "gap-1 pr-1",
89
- children: [tag, !disabled && /* @__PURE__ */ jsx("button", {
90
- type: "button",
91
- onClick: () => removeTag(index),
92
- className: "ml-1 rounded-full p-0.5 hover:bg-muted-foreground/20",
93
- "aria-label": `Remove ${tag}`,
94
- children: /* @__PURE__ */ jsx(X, { className: "size-3" })
95
- })]
96
- }, `${tag}-${index}`)), canAddMore && /* @__PURE__ */ jsx("input", {
97
- id,
98
- type: "text",
99
- value: inputValue,
100
- onChange: handleInputChange,
101
- onKeyDown: handleKeyDown,
102
- onFocus: () => setShowSuggestions(inputValue.length > 0 && suggestions.length > 0),
103
- onBlur: () => {
104
- setTimeout(() => setShowSuggestions(false), 150);
105
- },
106
- placeholder: value.length === 0 ? placeholder : void 0,
107
- disabled,
108
- "aria-invalid": ariaInvalid,
109
- className: cn("flex-1 min-w-[120px] bg-transparent text-sm outline-none placeholder:text-muted-foreground", "disabled:cursor-not-allowed")
110
- })]
111
- }),
112
- showSuggestions && filteredSuggestions.length > 0 && /* @__PURE__ */ jsx("div", {
113
- className: cn("absolute z-50 mt-1 w-full border border-input bg-popover shadow-md", "max-h-[200px] overflow-auto"),
114
- children: filteredSuggestions.map((suggestion, index) => /* @__PURE__ */ jsx("button", {
115
- type: "button",
116
- onClick: () => addTag(suggestion),
117
- className: cn("w-full px-3 py-2 text-left text-sm", "hover:bg-accent hover:text-accent-foreground", "focus:bg-accent focus:text-accent-foreground focus:outline-none"),
118
- children: suggestion
119
- }, suggestion))
120
- }),
121
- maxTags && /* @__PURE__ */ jsxs("p", {
122
- className: "mt-1 text-xs text-muted-foreground",
123
- children: [
124
- value.length,
125
- " / ",
126
- maxTags,
127
- " tags"
128
- ]
129
- })
130
- ]
131
- });
132
- }
133
-
134
- //#endregion
135
- export { TagInput };
@@ -1,39 +0,0 @@
1
- import { jsx } from "react/jsx-runtime";
2
- import { Input } from "../ui/input";
3
- import { cn } from "../../lib/utils";
4
-
5
- //#region src/components/primitives/text-input.tsx
6
- /**
7
- * Text Input Primitive
8
- *
9
- * A basic text input with value/onChange pattern.
10
- * Supports different input types: text, email, password, url, tel, search.
11
- *
12
- * @example
13
- * ```tsx
14
- * <TextInput
15
- * value={email}
16
- * onChange={setEmail}
17
- * type="email"
18
- * placeholder="Enter email"
19
- * />
20
- * ```
21
- */
22
- function TextInput({ value, onChange, type = "text", placeholder, disabled, readOnly, maxLength, autoComplete, className, id, "aria-invalid": ariaInvalid }) {
23
- return /* @__PURE__ */ jsx(Input, {
24
- id,
25
- type,
26
- value,
27
- onChange: (e) => onChange(e.target.value),
28
- placeholder,
29
- disabled,
30
- readOnly,
31
- maxLength,
32
- autoComplete,
33
- "aria-invalid": ariaInvalid,
34
- className: cn(className)
35
- });
36
- }
37
-
38
- //#endregion
39
- export { TextInput };
@@ -1,37 +0,0 @@
1
- import { jsx } from "react/jsx-runtime";
2
- import { Textarea } from "../ui/textarea";
3
- import { cn } from "../../lib/utils";
4
-
5
- //#region src/components/primitives/textarea-input.tsx
6
- /**
7
- * Textarea Input Primitive
8
- *
9
- * A multi-line text input.
10
- *
11
- * @example
12
- * ```tsx
13
- * <TextareaInput
14
- * value={description}
15
- * onChange={setDescription}
16
- * rows={4}
17
- * placeholder="Enter description..."
18
- * />
19
- * ```
20
- */
21
- function TextareaInput({ value, onChange, rows = 3, maxLength, placeholder, disabled, readOnly, className, id, "aria-invalid": ariaInvalid }) {
22
- return /* @__PURE__ */ jsx(Textarea, {
23
- id,
24
- value,
25
- onChange: (e) => onChange(e.target.value),
26
- rows,
27
- maxLength,
28
- placeholder,
29
- disabled,
30
- readOnly,
31
- "aria-invalid": ariaInvalid,
32
- className: cn(className)
33
- });
34
- }
35
-
36
- //#endregion
37
- export { TextareaInput };
@@ -1,31 +0,0 @@
1
- import { jsx } from "react/jsx-runtime";
2
- import { Switch } from "../ui/switch";
3
- import { cn } from "../../lib/utils";
4
-
5
- //#region src/components/primitives/toggle-input.tsx
6
- /**
7
- * Toggle Input Primitive
8
- *
9
- * A switch/toggle for boolean values.
10
- *
11
- * @example
12
- * ```tsx
13
- * <ToggleInput
14
- * value={isActive}
15
- * onChange={setIsActive}
16
- * />
17
- * ```
18
- */
19
- function ToggleInput({ value, onChange, disabled, className, id, "aria-invalid": ariaInvalid }) {
20
- return /* @__PURE__ */ jsx(Switch, {
21
- id,
22
- checked: value,
23
- onCheckedChange: onChange,
24
- disabled,
25
- "aria-invalid": ariaInvalid,
26
- className: cn(className)
27
- });
28
- }
29
-
30
- //#endregion
31
- export { ToggleInput };
@@ -1,12 +0,0 @@
1
- //#region src/components/primitives/types.ts
2
- /** Check if options are grouped */
3
- function isOptionGroup(option) {
4
- return "options" in option;
5
- }
6
- /** Flatten grouped options */
7
- function flattenOptions(options) {
8
- return options.flatMap((opt) => isOptionGroup(opt) ? opt.options : [opt]);
9
- }
10
-
11
- //#endregion
12
- export { flattenOptions, isOptionGroup };
@@ -1,55 +0,0 @@
1
- import { jsx, jsxs } from "react/jsx-runtime";
2
- import { cn } from "../../lib/utils";
3
- import { CaretDownIcon, CaretUpIcon } from "@phosphor-icons/react";
4
- import { Accordion as Accordion$1 } from "@base-ui/react/accordion";
5
-
6
- //#region src/components/ui/accordion.tsx
7
- function Accordion({ className, ...props }) {
8
- return /* @__PURE__ */ jsx(Accordion$1.Root, {
9
- "data-slot": "accordion",
10
- className: cn("overflow-hidden rounded-md border flex w-full flex-col", className),
11
- ...props
12
- });
13
- }
14
- function AccordionItem({ className, ...props }) {
15
- return /* @__PURE__ */ jsx(Accordion$1.Item, {
16
- "data-slot": "accordion-item",
17
- className: cn("data-open:bg-muted/50 not-last:border-b", className),
18
- ...props
19
- });
20
- }
21
- function AccordionTrigger({ className, children, ...props }) {
22
- return /* @__PURE__ */ jsx(Accordion$1.Header, {
23
- className: "flex",
24
- children: /* @__PURE__ */ jsxs(Accordion$1.Trigger, {
25
- "data-slot": "accordion-trigger",
26
- className: cn("**:data-[slot=accordion-trigger-icon]:text-muted-foreground gap-6 p-2 text-left text-xs/relaxed font-medium hover:underline **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 group/accordion-trigger relative flex flex-1 items-start justify-between border border-transparent transition-all outline-none disabled:pointer-events-none disabled:opacity-50", className),
27
- ...props,
28
- children: [
29
- children,
30
- /* @__PURE__ */ jsx(CaretDownIcon, {
31
- "data-slot": "accordion-trigger-icon",
32
- className: "pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden"
33
- }),
34
- /* @__PURE__ */ jsx(CaretUpIcon, {
35
- "data-slot": "accordion-trigger-icon",
36
- className: "pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline"
37
- })
38
- ]
39
- })
40
- });
41
- }
42
- function AccordionContent({ className, children, ...props }) {
43
- return /* @__PURE__ */ jsx(Accordion$1.Panel, {
44
- "data-slot": "accordion-content",
45
- className: "data-open:animate-accordion-down data-closed:animate-accordion-up px-2 text-xs/relaxed overflow-hidden",
46
- ...props,
47
- children: /* @__PURE__ */ jsx("div", {
48
- className: cn("pt-0 pb-4 [&_a]:hover:text-foreground h-(--accordion-panel-height) data-ending-style:h-0 data-starting-style:h-0 [&_a]:underline [&_a]:underline-offset-3 [&_p:not(:last-child)]:mb-4", className),
49
- children
50
- })
51
- });
52
- }
53
-
54
- //#endregion
55
- export { Accordion, AccordionContent, AccordionItem, AccordionTrigger };
@@ -1,54 +0,0 @@
1
- "use client";
2
-
3
- import "react";
4
- import { jsx } from "react/jsx-runtime";
5
- import { cn } from "../../lib/utils";
6
- import { Avatar as Avatar$1 } from "@base-ui/react/avatar";
7
-
8
- //#region src/components/ui/avatar.tsx
9
- function Avatar({ className, size = "default", ...props }) {
10
- return /* @__PURE__ */ jsx(Avatar$1.Root, {
11
- "data-slot": "avatar",
12
- "data-size": size,
13
- className: cn("size-8 rounded-full after:rounded-full data-[size=lg]:size-10 data-[size=sm]:size-6 after:border-border group/avatar relative flex shrink-0 select-none after:absolute after:inset-0 after:border after:mix-blend-darken dark:after:mix-blend-lighten", className),
14
- ...props
15
- });
16
- }
17
- function AvatarImage({ className, ...props }) {
18
- return /* @__PURE__ */ jsx(Avatar$1.Image, {
19
- "data-slot": "avatar-image",
20
- className: cn("rounded-full aspect-square size-full object-cover", className),
21
- ...props
22
- });
23
- }
24
- function AvatarFallback({ className, ...props }) {
25
- return /* @__PURE__ */ jsx(Avatar$1.Fallback, {
26
- "data-slot": "avatar-fallback",
27
- className: cn("bg-muted text-muted-foreground rounded-full flex size-full items-center justify-center text-sm group-data-[size=sm]/avatar:text-xs", className),
28
- ...props
29
- });
30
- }
31
- function AvatarBadge({ className, ...props }) {
32
- return /* @__PURE__ */ jsx("span", {
33
- "data-slot": "avatar-badge",
34
- className: cn("bg-primary text-primary-foreground ring-background absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-blend-color ring-2 select-none", "group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden", "group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2", "group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2", className),
35
- ...props
36
- });
37
- }
38
- function AvatarGroup({ className, ...props }) {
39
- return /* @__PURE__ */ jsx("div", {
40
- "data-slot": "avatar-group",
41
- className: cn("*:data-[slot=avatar]:ring-background group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2", className),
42
- ...props
43
- });
44
- }
45
- function AvatarGroupCount({ className, ...props }) {
46
- return /* @__PURE__ */ jsx("div", {
47
- "data-slot": "avatar-group-count",
48
- className: cn("bg-muted text-muted-foreground size-8 rounded-full text-xs/relaxed group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3 ring-background relative flex shrink-0 items-center justify-center ring-2", className),
49
- ...props
50
- });
51
- }
52
-
53
- //#endregion
54
- export { Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage };
@@ -1,34 +0,0 @@
1
- import { cn } from "../../lib/utils";
2
- import { mergeProps } from "@base-ui/react/merge-props";
3
- import { useRender } from "@base-ui/react/use-render";
4
- import { cva } from "class-variance-authority";
5
-
6
- //#region src/components/ui/badge.tsx
7
- const badgeVariants = cva("h-5 gap-1 rounded-full border border-transparent px-2 py-0.5 text-[0.625rem] font-medium transition-all has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&>svg]:size-2.5! inline-flex items-center justify-center w-fit whitespace-nowrap shrink-0 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-colors overflow-hidden group/badge", {
8
- variants: { variant: {
9
- default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
10
- secondary: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
11
- destructive: "bg-destructive/10 [a]:hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 text-destructive dark:bg-destructive/20",
12
- outline: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground bg-input/20 dark:bg-input/30",
13
- ghost: "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
14
- link: "text-primary underline-offset-4 hover:underline"
15
- } },
16
- defaultVariants: { variant: "default" }
17
- });
18
- function Badge({ className, variant = "default", render, ...props }) {
19
- return useRender({
20
- defaultTagName: "span",
21
- props: mergeProps({ className: cn(badgeVariants({
22
- className,
23
- variant
24
- })) }, props),
25
- render,
26
- state: {
27
- slot: "badge",
28
- variant
29
- }
30
- });
31
- }
32
-
33
- //#endregion
34
- export { Badge, badgeVariants };