@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.
- package/README.md +439 -424
- package/dist/auth-layout-M8K8_q5R.mjs +181 -0
- package/dist/auth-layout-M8K8_q5R.mjs.map +1 -0
- package/dist/bulk-upload-dialog-h7zXD78Y.mjs +274 -0
- package/dist/bulk-upload-dialog-h7zXD78Y.mjs.map +1 -0
- package/dist/{components/ui/card.mjs → card-BKHjBQfw.mjs} +8 -8
- package/dist/card-BKHjBQfw.mjs.map +1 -0
- package/dist/client/styles/index.css +434 -0
- package/dist/client-BCGpkAz6.mjs +22635 -0
- package/dist/client-BCGpkAz6.mjs.map +1 -0
- package/dist/client-CcWZbkBP.d.mts +13585 -0
- package/dist/client-CcWZbkBP.d.mts.map +1 -0
- package/dist/client.d.mts +3 -0
- package/dist/client.mjs +14 -0
- package/dist/content-locales-provider-BXvuIgfg.mjs +1650 -0
- package/dist/content-locales-provider-BXvuIgfg.mjs.map +1 -0
- package/dist/dashboard-page-B4PGEdc2.mjs +2500 -0
- package/dist/dashboard-page-B4PGEdc2.mjs.map +1 -0
- package/dist/dashboard-page-CVlyR40m.mjs +6 -0
- package/dist/dropzone-Do3awXKd.mjs +634 -0
- package/dist/dropzone-Do3awXKd.mjs.map +1 -0
- package/dist/{views/auth/forgot-password-form.mjs → forgot-password-page-Bcp-An4Y.mjs} +87 -14
- package/dist/forgot-password-page-Bcp-An4Y.mjs.map +1 -0
- package/dist/forgot-password-page-CIILVhfo.mjs +7 -0
- package/dist/index-B9Xwk4hi.d.mts +2753 -0
- package/dist/index-B9Xwk4hi.d.mts.map +1 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.mjs +14 -0
- package/dist/login-page-8K7fo0qK.mjs +7 -0
- package/dist/login-page-CP4gA-dl.mjs +298 -0
- package/dist/login-page-CP4gA-dl.mjs.map +1 -0
- package/dist/preview-utils-BKQ9-TMa.mjs +65 -0
- package/dist/preview-utils-BKQ9-TMa.mjs.map +1 -0
- package/dist/{views/auth/reset-password-form.mjs → reset-password-page-BqfDmLxA.mjs} +111 -14
- package/dist/reset-password-page-BqfDmLxA.mjs.map +1 -0
- package/dist/reset-password-page-DLATv0xQ.mjs +7 -0
- package/dist/runtime-6VZM878K.mjs +69 -0
- package/dist/runtime-6VZM878K.mjs.map +1 -0
- package/dist/saved-views.types-BMsz5mCy.d.mts +42 -0
- package/dist/saved-views.types-BMsz5mCy.d.mts.map +1 -0
- package/dist/server.d.mts +250 -0
- package/dist/server.d.mts.map +1 -0
- package/dist/server.mjs +832 -0
- package/dist/server.mjs.map +1 -0
- package/dist/setup-page-CMZ5P_OE.mjs +6 -0
- package/dist/setup-page-YAP_fzqh.mjs +264 -0
- package/dist/setup-page-YAP_fzqh.mjs.map +1 -0
- package/dist/shared.d.mts +57 -0
- package/dist/shared.d.mts.map +1 -0
- package/dist/shared.mjs +3 -0
- package/dist/{hooks/use-auth.mjs → use-auth-BoLmWtmU.mjs} +42 -30
- package/dist/use-auth-BoLmWtmU.mjs.map +1 -0
- package/package.json +48 -197
- package/.turbo/turbo-build.log +0 -108
- package/CHANGELOG.md +0 -10
- package/STATUS.md +0 -917
- package/VALIDATION.md +0 -602
- package/components.json +0 -24
- package/dist/__tests__/setup.mjs +0 -38
- package/dist/__tests__/test-utils.mjs +0 -45
- package/dist/__tests__/vitest.d.mjs +0 -3
- package/dist/components/admin-app.mjs +0 -69
- package/dist/components/fields/array-field.mjs +0 -190
- package/dist/components/fields/checkbox-field.mjs +0 -34
- package/dist/components/fields/custom-field.mjs +0 -32
- package/dist/components/fields/date-field.mjs +0 -41
- package/dist/components/fields/datetime-field.mjs +0 -42
- package/dist/components/fields/email-field.mjs +0 -37
- package/dist/components/fields/embedded-collection.mjs +0 -253
- package/dist/components/fields/field-types.mjs +0 -1
- package/dist/components/fields/field-utils.mjs +0 -10
- package/dist/components/fields/field-wrapper.mjs +0 -34
- package/dist/components/fields/index.mjs +0 -23
- package/dist/components/fields/json-field.mjs +0 -243
- package/dist/components/fields/locale-badge.mjs +0 -16
- package/dist/components/fields/number-field.mjs +0 -39
- package/dist/components/fields/password-field.mjs +0 -37
- package/dist/components/fields/relation-field.mjs +0 -104
- package/dist/components/fields/relation-picker.mjs +0 -229
- package/dist/components/fields/relation-select.mjs +0 -188
- package/dist/components/fields/rich-text-editor/index.mjs +0 -897
- package/dist/components/fields/select-field.mjs +0 -41
- package/dist/components/fields/switch-field.mjs +0 -34
- package/dist/components/fields/text-field.mjs +0 -38
- package/dist/components/fields/textarea-field.mjs +0 -38
- package/dist/components/index.mjs +0 -59
- package/dist/components/primitives/checkbox-input.mjs +0 -127
- package/dist/components/primitives/date-input.mjs +0 -303
- package/dist/components/primitives/index.mjs +0 -12
- package/dist/components/primitives/number-input.mjs +0 -104
- package/dist/components/primitives/select-input.mjs +0 -177
- package/dist/components/primitives/tag-input.mjs +0 -135
- package/dist/components/primitives/text-input.mjs +0 -39
- package/dist/components/primitives/textarea-input.mjs +0 -37
- package/dist/components/primitives/toggle-input.mjs +0 -31
- package/dist/components/primitives/types.mjs +0 -12
- package/dist/components/ui/accordion.mjs +0 -55
- package/dist/components/ui/avatar.mjs +0 -54
- package/dist/components/ui/badge.mjs +0 -34
- package/dist/components/ui/button.mjs +0 -48
- package/dist/components/ui/checkbox.mjs +0 -21
- package/dist/components/ui/combobox.mjs +0 -163
- package/dist/components/ui/dialog.mjs +0 -95
- package/dist/components/ui/dropdown-menu.mjs +0 -138
- package/dist/components/ui/field.mjs +0 -113
- package/dist/components/ui/input-group.mjs +0 -82
- package/dist/components/ui/input.mjs +0 -17
- package/dist/components/ui/label.mjs +0 -15
- package/dist/components/ui/popover.mjs +0 -56
- package/dist/components/ui/scroll-area.mjs +0 -38
- package/dist/components/ui/select.mjs +0 -100
- package/dist/components/ui/separator.mjs +0 -16
- package/dist/components/ui/sheet.mjs +0 -90
- package/dist/components/ui/sidebar.mjs +0 -387
- package/dist/components/ui/skeleton.mjs +0 -14
- package/dist/components/ui/spinner.mjs +0 -16
- package/dist/components/ui/switch.mjs +0 -22
- package/dist/components/ui/table.mjs +0 -68
- package/dist/components/ui/tabs.mjs +0 -48
- package/dist/components/ui/textarea.mjs +0 -15
- package/dist/components/ui/tooltip.mjs +0 -44
- package/dist/config/component-registry.mjs +0 -38
- package/dist/config/index.mjs +0 -129
- package/dist/hooks/admin-provider.mjs +0 -70
- package/dist/hooks/index.mjs +0 -7
- package/dist/hooks/store.mjs +0 -178
- package/dist/hooks/use-collection-db.mjs +0 -146
- package/dist/hooks/use-collection.mjs +0 -112
- package/dist/hooks/use-global.mjs +0 -46
- package/dist/hooks/use-mobile.mjs +0 -20
- package/dist/lib/utils.mjs +0 -10
- package/dist/styles/index.css +0 -336
- package/dist/styles/index.mjs +0 -1
- package/dist/utils/index.mjs +0 -9
- package/dist/views/auth/auth-layout.mjs +0 -52
- package/dist/views/auth/index.mjs +0 -6
- package/dist/views/auth/login-form.mjs +0 -156
- package/dist/views/collection/auto-form-fields.mjs +0 -525
- package/dist/views/collection/collection-form.mjs +0 -91
- package/dist/views/collection/collection-list.mjs +0 -76
- package/dist/views/collection/form-field.mjs +0 -42
- package/dist/views/collection/index.mjs +0 -6
- package/dist/views/common/index.mjs +0 -4
- package/dist/views/common/locale-switcher.mjs +0 -39
- package/dist/views/common/version-history.mjs +0 -272
- package/dist/views/index.mjs +0 -9
- package/dist/views/layout/admin-layout.mjs +0 -40
- package/dist/views/layout/admin-router.mjs +0 -95
- package/dist/views/layout/admin-sidebar.mjs +0 -63
- package/dist/views/layout/index.mjs +0 -5
- package/src/__tests__/setup.ts +0 -44
- package/src/__tests__/test-utils.tsx +0 -49
- package/src/__tests__/vitest.d.ts +0 -9
- package/src/components/admin-app.tsx +0 -221
- package/src/components/fields/array-field.tsx +0 -237
- package/src/components/fields/checkbox-field.tsx +0 -47
- package/src/components/fields/custom-field.tsx +0 -50
- package/src/components/fields/date-field.tsx +0 -65
- package/src/components/fields/datetime-field.tsx +0 -67
- package/src/components/fields/email-field.tsx +0 -51
- package/src/components/fields/embedded-collection.tsx +0 -315
- package/src/components/fields/field-types.ts +0 -162
- package/src/components/fields/field-utils.ts +0 -6
- package/src/components/fields/field-wrapper.tsx +0 -52
- package/src/components/fields/index.ts +0 -66
- package/src/components/fields/json-field.tsx +0 -440
- package/src/components/fields/locale-badge.tsx +0 -15
- package/src/components/fields/number-field.tsx +0 -57
- package/src/components/fields/password-field.tsx +0 -51
- package/src/components/fields/relation-field.tsx +0 -243
- package/src/components/fields/relation-picker.tsx +0 -402
- package/src/components/fields/relation-select.tsx +0 -327
- package/src/components/fields/rich-text-editor/index.tsx +0 -1337
- package/src/components/fields/select-field.tsx +0 -61
- package/src/components/fields/switch-field.tsx +0 -47
- package/src/components/fields/text-field.tsx +0 -55
- package/src/components/fields/textarea-field.tsx +0 -55
- package/src/components/index.ts +0 -40
- package/src/components/primitives/checkbox-input.tsx +0 -193
- package/src/components/primitives/date-input.tsx +0 -401
- package/src/components/primitives/index.ts +0 -24
- package/src/components/primitives/number-input.tsx +0 -132
- package/src/components/primitives/select-input.tsx +0 -296
- package/src/components/primitives/tag-input.tsx +0 -200
- package/src/components/primitives/text-input.tsx +0 -49
- package/src/components/primitives/textarea-input.tsx +0 -46
- package/src/components/primitives/toggle-input.tsx +0 -36
- package/src/components/primitives/types.ts +0 -235
- package/src/components/ui/accordion.tsx +0 -72
- package/src/components/ui/avatar.tsx +0 -106
- package/src/components/ui/badge.tsx +0 -48
- package/src/components/ui/button.tsx +0 -53
- package/src/components/ui/card.tsx +0 -94
- package/src/components/ui/checkbox.tsx +0 -27
- package/src/components/ui/combobox.tsx +0 -290
- package/src/components/ui/dialog.tsx +0 -151
- package/src/components/ui/dropdown-menu.tsx +0 -254
- package/src/components/ui/field.tsx +0 -227
- package/src/components/ui/input-group.tsx +0 -149
- package/src/components/ui/input.tsx +0 -20
- package/src/components/ui/label.tsx +0 -18
- package/src/components/ui/popover.tsx +0 -88
- package/src/components/ui/scroll-area.tsx +0 -53
- package/src/components/ui/select.tsx +0 -192
- package/src/components/ui/separator.tsx +0 -23
- package/src/components/ui/sheet.tsx +0 -127
- package/src/components/ui/sidebar.tsx +0 -723
- package/src/components/ui/skeleton.tsx +0 -13
- package/src/components/ui/spinner.tsx +0 -10
- package/src/components/ui/switch.tsx +0 -32
- package/src/components/ui/table.tsx +0 -99
- package/src/components/ui/tabs.tsx +0 -82
- package/src/components/ui/textarea.tsx +0 -18
- package/src/components/ui/tooltip.tsx +0 -70
- package/src/config/component-registry.ts +0 -190
- package/src/config/index.ts +0 -1099
- package/src/hooks/README.md +0 -269
- package/src/hooks/admin-provider.tsx +0 -110
- package/src/hooks/index.ts +0 -41
- package/src/hooks/store.ts +0 -248
- package/src/hooks/use-auth.ts +0 -168
- package/src/hooks/use-collection-db.ts +0 -209
- package/src/hooks/use-collection.ts +0 -156
- package/src/hooks/use-global.ts +0 -69
- package/src/hooks/use-mobile.ts +0 -21
- package/src/lib/utils.ts +0 -6
- package/src/styles/index.css +0 -340
- package/src/utils/index.ts +0 -6
- package/src/views/auth/auth-layout.tsx +0 -77
- package/src/views/auth/forgot-password-form.tsx +0 -192
- package/src/views/auth/index.ts +0 -21
- package/src/views/auth/login-form.tsx +0 -229
- package/src/views/auth/reset-password-form.tsx +0 -232
- package/src/views/collection/auto-form-fields.tsx +0 -982
- package/src/views/collection/collection-form.tsx +0 -186
- package/src/views/collection/collection-list.tsx +0 -223
- package/src/views/collection/form-field.tsx +0 -52
- package/src/views/collection/index.ts +0 -15
- package/src/views/common/index.ts +0 -8
- package/src/views/common/locale-switcher.tsx +0 -45
- package/src/views/common/version-history.tsx +0 -406
- package/src/views/index.ts +0 -25
- package/src/views/layout/admin-layout.tsx +0 -117
- package/src/views/layout/admin-router.tsx +0 -206
- package/src/views/layout/admin-sidebar.tsx +0 -185
- package/src/views/layout/index.ts +0 -12
- package/tsconfig.json +0 -13
- package/tsconfig.tsbuildinfo +0 -1
- package/tsdown.config.ts +0 -13
- 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 };
|