art-bd-ui 1.0.2 → 1.0.4

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 (25) hide show
  1. package/dist/cjs/components/forms/form/form-control.js +17 -0
  2. package/dist/cjs/components/forms/form/form.js +68 -0
  3. package/dist/cjs/components/selectors/multiselect/components/badge-list.js +1 -5
  4. package/dist/cjs/components/selectors/multiselect/multiselect.js +12 -48
  5. package/dist/cjs/components/selectors/shared/input-container.js +17 -0
  6. package/dist/cjs/components/selectors/shared/options-list.js +14 -0
  7. package/dist/cjs/components/selectors/shared/utils.js +37 -0
  8. package/dist/cjs/components/selectors/single-select/single-select.js +81 -0
  9. package/dist/cjs/components/ui/card/card.js +54 -0
  10. package/dist/cjs/index.js +21 -0
  11. package/dist/esm/components/forms/form/form-control.js +15 -0
  12. package/dist/esm/components/forms/form/form.js +59 -0
  13. package/dist/esm/components/selectors/multiselect/components/badge-list.js +1 -5
  14. package/dist/esm/components/selectors/multiselect/multiselect.js +9 -45
  15. package/dist/esm/components/selectors/shared/input-container.js +15 -0
  16. package/dist/esm/components/selectors/shared/options-list.js +12 -0
  17. package/dist/esm/components/selectors/shared/utils.js +34 -0
  18. package/dist/esm/components/selectors/single-select/single-select.js +79 -0
  19. package/dist/esm/components/ui/card/card.js +46 -0
  20. package/dist/esm/index.js +4 -0
  21. package/dist/styles.css +67 -5
  22. package/dist/types/index.d.ts +61 -11
  23. package/package.json +7 -4
  24. package/dist/cjs/components/selectors/multiselect/components/options.js +0 -14
  25. package/dist/esm/components/selectors/multiselect/components/options.js +0 -12
@@ -0,0 +1,17 @@
1
+ 'use strict';
2
+
3
+ var tslib = require('tslib');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var reactHookForm = require('react-hook-form');
6
+ var form = require('./form.js');
7
+
8
+ function FormControl(_a) {
9
+ var { name, label, description, showMessage = true, children } = _a, props = tslib.__rest(_a, ["name", "label", "description", "showMessage", "children"]);
10
+ const form$1 = reactHookForm.useFormContext();
11
+ if (!form$1) {
12
+ throw new Error("FormControl must be used within a Form component");
13
+ }
14
+ return (jsxRuntime.jsx(form.FormField, { control: form$1.control, name: name, render: ({ field }) => (jsxRuntime.jsxs(form.FormItem, Object.assign({}, props, { children: [label && jsxRuntime.jsx(form.FormLabel, { children: label }), jsxRuntime.jsx(form.FormFieldControl, Object.assign({}, field, { children: children })), description && jsxRuntime.jsx(form.FormDescription, { children: description }), showMessage && jsxRuntime.jsx(form.FormMessage, {})] }))) }));
15
+ }
16
+
17
+ exports.FormControl = FormControl;
@@ -0,0 +1,68 @@
1
+ 'use strict';
2
+
3
+ var tslib = require('tslib');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var reactSlot = require('@radix-ui/react-slot');
6
+ var reactHookForm = require('react-hook-form');
7
+ var react = require('react');
8
+ var utils = require('../../../lib/utils.js');
9
+ var label = require('../label/label.js');
10
+
11
+ const Form = reactHookForm.FormProvider;
12
+ const FormFieldContext = react.createContext({});
13
+ const FormField = (_a) => {
14
+ var props = tslib.__rest(_a, []);
15
+ return (jsxRuntime.jsx(FormFieldContext.Provider, { value: { name: props.name }, children: jsxRuntime.jsx(reactHookForm.Controller, Object.assign({}, props)) }));
16
+ };
17
+ const FormItemContext = react.createContext({});
18
+ const useFormField = () => {
19
+ const fieldContext = react.useContext(FormFieldContext);
20
+ const itemContext = react.useContext(FormItemContext);
21
+ const { getFieldState } = reactHookForm.useFormContext();
22
+ const formState = reactHookForm.useFormState({ name: fieldContext.name });
23
+ const fieldState = getFieldState(fieldContext.name, formState);
24
+ if (!fieldContext) {
25
+ throw new Error("useFormField should be used within <FormField>");
26
+ }
27
+ const { id } = itemContext;
28
+ return Object.assign({ id, name: fieldContext.name, formItemId: `${id}-form-item`, formDescriptionId: `${id}-form-item-description`, formMessageId: `${id}-form-item-message` }, fieldState);
29
+ };
30
+ function FormItem(_a) {
31
+ var { className } = _a, props = tslib.__rest(_a, ["className"]);
32
+ const id = react.useId();
33
+ return (jsxRuntime.jsx(FormItemContext.Provider, { value: { id }, children: jsxRuntime.jsx("div", Object.assign({ "data-slot": "form-item", className: utils.cn("grid gap-2", className) }, props)) }));
34
+ }
35
+ function FormLabel(_a) {
36
+ var { className } = _a, props = tslib.__rest(_a, ["className"]);
37
+ const { error, formItemId } = useFormField();
38
+ return (jsxRuntime.jsx(label.Label, Object.assign({ "data-slot": "form-label", "data-error": !!error, className: utils.cn("data-[error=true]:text-destructive", className), htmlFor: formItemId }, props)));
39
+ }
40
+ function FormFieldControl(_a) {
41
+ var props = tslib.__rest(_a, []);
42
+ const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
43
+ return (jsxRuntime.jsx(reactSlot.Slot, Object.assign({ "data-slot": "form-control", id: formItemId, "aria-describedby": !error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`, "aria-invalid": !!error }, props)));
44
+ }
45
+ function FormDescription(_a) {
46
+ var { className } = _a, props = tslib.__rest(_a, ["className"]);
47
+ const { formDescriptionId } = useFormField();
48
+ return (jsxRuntime.jsx("p", Object.assign({ "data-slot": "form-description", id: formDescriptionId, className: utils.cn("text-muted-foreground text-sm", className) }, props)));
49
+ }
50
+ function FormMessage(_a) {
51
+ var _b;
52
+ var { className } = _a, props = tslib.__rest(_a, ["className"]);
53
+ const { error, formMessageId } = useFormField();
54
+ const body = error ? String((_b = error === null || error === void 0 ? void 0 : error.message) !== null && _b !== void 0 ? _b : "") : props.children;
55
+ if (!body) {
56
+ return null;
57
+ }
58
+ return (jsxRuntime.jsx("p", Object.assign({ "data-slot": "form-message", id: formMessageId, className: utils.cn("text-destructive text-sm", className) }, props, { children: body })));
59
+ }
60
+
61
+ exports.Form = Form;
62
+ exports.FormDescription = FormDescription;
63
+ exports.FormField = FormField;
64
+ exports.FormFieldControl = FormFieldControl;
65
+ exports.FormItem = FormItem;
66
+ exports.FormLabel = FormLabel;
67
+ exports.FormMessage = FormMessage;
68
+ exports.useFormField = useFormField;
@@ -13,11 +13,7 @@ const BadgeList = react.memo(({ options, disabled, onRemove }) => {
13
13
  if (disabled) {
14
14
  return;
15
15
  }
16
- if (e.key === "Enter" || e.key === " ") {
17
- e.preventDefault();
18
- onRemove(opt);
19
- }
20
- else if (e.key === "Backspace" || e.key === "Delete") {
16
+ if (e.key === "Enter" || e.key === " " || e.key === "Backspace" || e.key === "Delete") {
21
17
  e.preventDefault();
22
18
  onRemove(opt);
23
19
  const nextBadge = e.currentTarget.nextElementSibling || e.currentTarget.previousElementSibling;
@@ -4,69 +4,39 @@
4
4
  var tslib = require('tslib');
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
  var react = require('react');
7
- var options = require('./components/options.js');
7
+ var utils = require('../shared/utils.js');
8
+ var optionsList = require('../shared/options-list.js');
9
+ var inputContainer = require('../shared/input-container.js');
8
10
  var badgeList = require('./components/badge-list.js');
9
11
  var command = require('../../ui/command/command.js');
10
12
  var popover = require('../../popovers/popover/popover.js');
11
- var utils = require('../../../lib/utils.js');
12
13
  var useDebounce = require('../../../hooks/use-debounce.js');
13
14
  require('clsx');
14
15
  var toggle = require('../../../utils/toggle.js');
15
16
  var useUpdateEffect = require('../../../hooks/useUpdateEffect.js');
16
17
  require('lodash/throttle');
17
- var iconButton = require('../../buttons/icon-button/icon-button.js');
18
- var flex = require('../../layout/flex/flex.js');
19
18
 
20
- function isPromise(value) {
21
- return value instanceof Promise;
22
- }
23
- function getGroupedListOptions(options, groups = []) {
24
- const lookup = groups.reduce((acc, { value, label }) => {
25
- acc[value] = { value, label, children: [] };
26
- return acc;
27
- }, {});
28
- const ungrouped = [];
29
- for (const opt of options) {
30
- const node = {
31
- value: opt.value,
32
- label: opt.label,
33
- children: [],
34
- data: opt,
35
- };
36
- if (opt.group && lookup[opt.group]) {
37
- lookup[opt.group].children.push(node);
38
- }
39
- else {
40
- ungrouped.push(node);
41
- }
42
- }
43
- const result = [];
44
- for (const grp of groups) {
45
- const bucket = lookup[grp.value];
46
- if (bucket.children.length > 0) {
47
- result.push(bucket);
48
- }
49
- }
50
- return result.concat(ungrouped);
51
- }
52
19
  const defaultValue = [];
53
20
  const defaultOptions = [];
54
21
  const defaultGroups = [];
55
22
  const MultiSelect = (_a) => {
56
- var { value = defaultValue, onChange = () => { }, options: options$1 = defaultOptions, groups = defaultGroups, createable = false, onCreate = () => { }, onSearch, debounceDelay = 500, placeholder = "Select options...", disabled = false, clearable = false, className } = _a, props = tslib.__rest(_a, ["value", "onChange", "options", "groups", "createable", "onCreate", "onSearch", "debounceDelay", "placeholder", "disabled", "clearable", "className"]);
23
+ var { value = defaultValue, onChange = () => { }, options = defaultOptions, groups = defaultGroups, createable = false, onCreate = () => { }, onSearch, debounceDelay = 500, placeholder = "Select options...", disabled = false, clearable = false } = _a, props = tslib.__rest(_a, ["value", "onChange", "options", "groups", "createable", "onCreate", "onSearch", "debounceDelay", "placeholder", "disabled", "clearable"]);
57
24
  const [open, setOpen] = react.useState(false);
58
25
  const [loading, setLoading] = react.useState(false);
59
26
  const [searchQuery, setSearchQuery] = react.useState("");
60
27
  const debouncedSearch = useDebounce.useDebounce(searchQuery, debounceDelay);
61
- const [searchResults, setSearchResults] = react.useState(options$1);
28
+ const [searchResults, setSearchResults] = react.useState(options);
62
29
  useUpdateEffect.useUpdateEffect(() => {
63
- if (!onSearch || !debouncedSearch) {
30
+ if (!onSearch) {
64
31
  return;
65
32
  }
66
33
  const search = () => tslib.__awaiter(void 0, void 0, void 0, function* () {
67
34
  try {
35
+ if (!debouncedSearch) {
36
+ setSearchResults(options);
37
+ }
68
38
  const results = onSearch(debouncedSearch);
69
- if (isPromise(results)) {
39
+ if (utils.isPromise(results)) {
70
40
  setLoading(true);
71
41
  const options = yield results;
72
42
  setSearchResults(options);
@@ -90,7 +60,7 @@ const MultiSelect = (_a) => {
90
60
  }, [onChange, value]);
91
61
  const handleRemove = react.useCallback((opt) => onChange(value.filter((v) => v.value !== opt.value)), [onChange, value]);
92
62
  const handleClear = react.useCallback(() => onChange([]), [onChange]);
93
- const optionsList = react.useMemo(() => getGroupedListOptions(searchResults, groups), [searchResults, groups]);
63
+ const optionsList$1 = react.useMemo(() => utils.getGroupedListOptions(searchResults, groups), [searchResults, groups]);
94
64
  const selectedValues = react.useMemo(() => new Set(value.map((v) => v.value)), [value]);
95
65
  const handleTriggerKeyDown = react.useCallback((e) => {
96
66
  if (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") {
@@ -98,18 +68,12 @@ const MultiSelect = (_a) => {
98
68
  setOpen(true);
99
69
  }
100
70
  }, []);
101
- const handleClearKeyDown = react.useCallback((e) => {
102
- if (e.key === "Enter" || e.key === " ") {
103
- e.preventDefault();
104
- handleClear();
105
- }
106
- }, [handleClear]);
107
71
  const setPopoverVisibility = react.useCallback((open) => {
108
72
  if (!disabled) {
109
73
  setOpen(open);
110
74
  }
111
75
  }, [disabled]);
112
- return (jsxRuntime.jsxs(popover.Popover, { open: open, onOpenChange: setPopoverVisibility, children: [jsxRuntime.jsx(popover.PopoverTrigger, { asChild: true, children: jsxRuntime.jsxs("div", Object.assign({}, props, { tabIndex: disabled ? -1 : 0, role: "combobox", "aria-expanded": open, "aria-haspopup": "listbox", "aria-controls": "multiselect-options", "aria-label": placeholder, "aria-disabled": disabled, onKeyDown: handleTriggerKeyDown, className: utils.cn("flex min-h-10 w-full flex-wrap items-center gap-1 rounded-md border bg-background px-3 py-2", !disabled && "focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", disabled && "disabled:cursor-not-allowed disabled:opacity-50", className), children: [jsxRuntime.jsx(flex.Flex, { wrap: "wrap", gap: 1, align: "start", className: "flex-1", children: value.length > 0 ? (jsxRuntime.jsx(badgeList.BadgeList, { options: value, disabled: disabled, onRemove: handleRemove })) : (jsxRuntime.jsx("span", { className: "text-muted-foreground", children: placeholder })) }), clearable && !disabled && value.length > 0 && (jsxRuntime.jsx(iconButton.IconButton, { icon: "circle-x", radius: "full", variant: "ghost", className: "size-5 p-0.25 self-start shrink-0", onClick: handleClear, onKeyDown: handleClearKeyDown, disabled: disabled, tooltip: "Clear All", "aria-label": "Clear all selections" }))] })) }), jsxRuntime.jsx(popover.PopoverContent, { className: "p-0", align: "start", matchTriggerWidth: true, children: jsxRuntime.jsxs(command.Command, { id: "multiselect-options", role: "listbox", shouldFilter: !onSearch, children: [jsxRuntime.jsx(command.CommandInput, { placeholder: "Search...", value: searchQuery, onValueChange: setSearchQuery, disabled: disabled }), jsxRuntime.jsxs(command.CommandList, { children: [loading ? (jsxRuntime.jsx(command.CommandLoading, { children: "Searching\u2026" })) : optionsList.length > 0 ? (jsxRuntime.jsx(options.OptionsList, { options: optionsList, selectedValues: selectedValues, onSelect: handleSelect })) : (jsxRuntime.jsx(command.CommandEmpty, { children: "No results found." })), createable && !loading && searchQuery && debouncedSearch && (jsxRuntime.jsxs(command.CommandItem, { value: searchQuery, keywords: [searchQuery], onSelect: () => {
76
+ return (jsxRuntime.jsxs(popover.Popover, { open: open, onOpenChange: setPopoverVisibility, children: [jsxRuntime.jsx(popover.PopoverTrigger, { asChild: true, children: jsxRuntime.jsx(inputContainer.InputContainer, Object.assign({}, props, { disabled: disabled, placeholder: placeholder, clearable: clearable, onClear: handleClear, onKeyDown: handleTriggerKeyDown, children: value.length > 0 ? jsxRuntime.jsx(badgeList.BadgeList, { options: value, disabled: disabled, onRemove: handleRemove }) : null })) }), jsxRuntime.jsx(popover.PopoverContent, { className: "p-0", align: "start", matchTriggerWidth: true, children: jsxRuntime.jsxs(command.Command, { id: "multiselect-options", role: "listbox", shouldFilter: !onSearch, children: [jsxRuntime.jsx(command.CommandInput, { placeholder: "Search...", value: searchQuery, onValueChange: setSearchQuery, disabled: disabled }), jsxRuntime.jsxs(command.CommandList, { children: [loading ? (jsxRuntime.jsx(command.CommandLoading, { children: "Searching\u2026" })) : optionsList$1.length > 0 ? (jsxRuntime.jsx(optionsList.OptionsList, { options: optionsList$1, selectedValues: selectedValues, onSelect: handleSelect, showCheckbox: true })) : (jsxRuntime.jsx(command.CommandEmpty, { children: "No results found." })), createable && !loading && searchQuery && debouncedSearch && (jsxRuntime.jsxs(command.CommandItem, { value: searchQuery, keywords: [searchQuery], onSelect: () => {
113
77
  onCreate(searchQuery);
114
78
  setSearchQuery("");
115
79
  }, children: ["Create \"", searchQuery, "\""] }))] })] }) })] }));
@@ -0,0 +1,17 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var tslib = require('tslib');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+ var utils = require('../../../lib/utils.js');
7
+ var icon = require('../../media/icon/icon.js');
8
+ var iconButton = require('../../buttons/icon-button/icon-button.js');
9
+ var flex = require('../../layout/flex/flex.js');
10
+
11
+ const InputContainer = (_a) => {
12
+ var { disabled = false, placeholder = "Select...", clearable = false, onClear, children, className } = _a, props = tslib.__rest(_a, ["disabled", "placeholder", "clearable", "onClear", "children", "className"]);
13
+ return (jsxRuntime.jsxs("div", Object.assign({}, props, { tabIndex: disabled ? -1 : 0, role: "combobox", "aria-expanded": false, "aria-haspopup": "listbox", "aria-label": placeholder, "aria-disabled": disabled, className: utils.cn("flex min-h-9 w-full items-center gap-1 rounded-md border bg-background px-3 py-1", !disabled && "focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", disabled && "disabled:cursor-not-allowed disabled:opacity-50", className), children: [jsxRuntime.jsx(flex.Flex, { wrap: "wrap", gap: 1, align: "start", className: "flex-1", children: children !== null && children !== void 0 ? children : jsxRuntime.jsx("span", { className: "text-base md:text-sm text-muted-foreground", children: placeholder }) }), clearable && !disabled && onClear && (jsxRuntime.jsx(iconButton.IconButton, { icon: "circle-x", radius: "full", variant: "ghost", className: "size-6 p-1 shrink-0 self-start", onClick: onClear, disabled: disabled, tooltip: "Clear", "aria-label": "Clear selection" })), jsxRuntime.jsx(icon.Icon, { name: "chevron-down", className: "size-6 p-1 shrink-0 opacity-50 self-start" })] })));
14
+ };
15
+ InputContainer.displayName = "InputContainer";
16
+
17
+ exports.InputContainer = InputContainer;
@@ -0,0 +1,14 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var react = require('react');
6
+ var command = require('../../ui/command/command.js');
7
+ var checkbox = require('../../forms/checkbox/checkbox.js');
8
+
9
+ const OptionItem = react.memo(({ option, selected, onSelect, showCheckbox = false }) => (jsxRuntime.jsxs(command.CommandItem, { value: option.value, keywords: [option.label], onSelect: () => onSelect(option), className: "flex items-center gap-2", children: [showCheckbox && jsxRuntime.jsx(checkbox.Checkbox, { tabIndex: -1, checked: selected, size: "sm" }), option.label] })));
10
+ OptionItem.displayName = "OptionItem";
11
+ const OptionsList = react.memo(({ options, selectedValues, onSelect, showCheckbox = false }) => (jsxRuntime.jsx(jsxRuntime.Fragment, { children: options.map(({ value, label, children, data }) => children.length > 0 ? (jsxRuntime.jsx(command.CommandGroup, { heading: label, children: jsxRuntime.jsx(OptionsList, { options: children, selectedValues: selectedValues, onSelect: onSelect, showCheckbox: showCheckbox }) }, value)) : data ? (jsxRuntime.jsx(OptionItem, { option: data, selected: selectedValues.has(value), onSelect: onSelect, showCheckbox: showCheckbox }, value)) : null) })));
12
+ OptionsList.displayName = "OptionsList";
13
+
14
+ exports.OptionsList = OptionsList;
@@ -0,0 +1,37 @@
1
+ 'use strict';
2
+
3
+ function isPromise(value) {
4
+ return value instanceof Promise;
5
+ }
6
+ function getGroupedListOptions(options, groups = []) {
7
+ const lookup = groups.reduce((acc, { value, label }) => {
8
+ acc[value] = { value, label, children: [] };
9
+ return acc;
10
+ }, {});
11
+ const ungrouped = [];
12
+ for (const opt of options) {
13
+ const node = {
14
+ value: opt.value,
15
+ label: opt.label,
16
+ children: [],
17
+ data: opt,
18
+ };
19
+ if (opt.group && lookup[opt.group]) {
20
+ lookup[opt.group].children.push(node);
21
+ }
22
+ else {
23
+ ungrouped.push(node);
24
+ }
25
+ }
26
+ const result = [];
27
+ for (const grp of groups) {
28
+ const bucket = lookup[grp.value];
29
+ if (bucket.children.length > 0) {
30
+ result.push(bucket);
31
+ }
32
+ }
33
+ return result.concat(ungrouped);
34
+ }
35
+
36
+ exports.getGroupedListOptions = getGroupedListOptions;
37
+ exports.isPromise = isPromise;
@@ -0,0 +1,81 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var tslib = require('tslib');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+ var react = require('react');
7
+ var utils = require('../shared/utils.js');
8
+ var optionsList = require('../shared/options-list.js');
9
+ var inputContainer = require('../shared/input-container.js');
10
+ var command = require('../../ui/command/command.js');
11
+ var popover = require('../../popovers/popover/popover.js');
12
+ var useDebounce = require('../../../hooks/use-debounce.js');
13
+ var useUpdateEffect = require('../../../hooks/useUpdateEffect.js');
14
+ require('clsx');
15
+ require('lodash/throttle');
16
+
17
+ const defaultOption = undefined;
18
+ const defaultOptions = [];
19
+ const defaultGroups = [];
20
+ const SingleSelect = (_a) => {
21
+ var { value = defaultOption, onChange = () => { }, options = defaultOptions, groups = defaultGroups, createable = false, onCreate = () => { }, onSearch, debounceDelay = 500, placeholder = "Select an option...", disabled = false, clearable = false } = _a, props = tslib.__rest(_a, ["value", "onChange", "options", "groups", "createable", "onCreate", "onSearch", "debounceDelay", "placeholder", "disabled", "clearable"]);
22
+ const [open, setOpen] = react.useState(false);
23
+ const [loading, setLoading] = react.useState(false);
24
+ const [searchQuery, setSearchQuery] = react.useState("");
25
+ const debouncedSearch = useDebounce.useDebounce(searchQuery, debounceDelay);
26
+ const [searchResults, setSearchResults] = react.useState(options);
27
+ useUpdateEffect.useUpdateEffect(() => {
28
+ if (!onSearch) {
29
+ return;
30
+ }
31
+ const search = () => tslib.__awaiter(void 0, void 0, void 0, function* () {
32
+ try {
33
+ if (!debouncedSearch) {
34
+ setSearchResults(options);
35
+ }
36
+ const results = onSearch(debouncedSearch);
37
+ if (utils.isPromise(results)) {
38
+ setLoading(true);
39
+ const options = yield results;
40
+ setSearchResults(options);
41
+ }
42
+ else if (Array.isArray(results)) {
43
+ setSearchResults(results);
44
+ }
45
+ }
46
+ catch (error) {
47
+ console.error("Search failed:", error);
48
+ setSearchResults([]);
49
+ }
50
+ finally {
51
+ setLoading(false);
52
+ }
53
+ });
54
+ void search();
55
+ }, [debouncedSearch, onSearch]);
56
+ const handleSelect = react.useCallback((opt) => {
57
+ onChange(opt);
58
+ setOpen(false);
59
+ }, [onChange]);
60
+ const handleClear = react.useCallback(() => onChange(undefined), [onChange]);
61
+ const optionsList$1 = react.useMemo(() => utils.getGroupedListOptions(searchResults, groups), [searchResults, groups]);
62
+ const selectedValues = react.useMemo(() => new Set(value ? [value.value] : []), [value]);
63
+ const handleTriggerKeyDown = react.useCallback((e) => {
64
+ if (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") {
65
+ e.preventDefault();
66
+ setOpen(true);
67
+ }
68
+ }, []);
69
+ const setPopoverVisibility = react.useCallback((open) => {
70
+ if (!disabled) {
71
+ setOpen(open);
72
+ }
73
+ }, [disabled]);
74
+ return (jsxRuntime.jsxs(popover.Popover, { open: open, onOpenChange: setPopoverVisibility, children: [jsxRuntime.jsx(popover.PopoverTrigger, { asChild: true, children: jsxRuntime.jsx(inputContainer.InputContainer, Object.assign({}, props, { disabled: disabled, placeholder: placeholder, clearable: clearable, onClear: handleClear, onKeyDown: handleTriggerKeyDown, children: value && jsxRuntime.jsx("span", { className: "text-base md:text-sm", children: value.label }) })) }), jsxRuntime.jsx(popover.PopoverContent, { className: "p-0", align: "start", matchTriggerWidth: true, children: jsxRuntime.jsxs(command.Command, { id: "singleselect-options", role: "listbox", shouldFilter: !onSearch, children: [jsxRuntime.jsx(command.CommandInput, { placeholder: "Search...", value: searchQuery, onValueChange: setSearchQuery, disabled: disabled }), jsxRuntime.jsxs(command.CommandList, { children: [loading ? (jsxRuntime.jsx(command.CommandLoading, { children: "Searching\u2026" })) : optionsList$1.length > 0 ? (jsxRuntime.jsx(optionsList.OptionsList, { options: optionsList$1, selectedValues: selectedValues, onSelect: handleSelect })) : (jsxRuntime.jsx(command.CommandEmpty, { children: "No results found." })), createable && !loading && searchQuery && debouncedSearch && (jsxRuntime.jsxs(command.CommandItem, { value: searchQuery, keywords: [searchQuery], onSelect: () => {
75
+ onCreate(searchQuery);
76
+ setSearchQuery("");
77
+ }, children: ["Create \"", searchQuery, "\""] }))] })] }) })] }));
78
+ };
79
+ SingleSelect.displayName = "SingleSelect";
80
+
81
+ exports.SingleSelect = SingleSelect;
@@ -0,0 +1,54 @@
1
+ 'use strict';
2
+
3
+ var tslib = require('tslib');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var classVarianceAuthority = require('class-variance-authority');
6
+ var utils = require('../../../lib/utils.js');
7
+
8
+ const cardVariants = classVarianceAuthority.cva("bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm", {
9
+ variants: {
10
+ variant: {
11
+ default: "",
12
+ ghost: "border-none shadow-none",
13
+ },
14
+ },
15
+ defaultVariants: {
16
+ variant: "default",
17
+ },
18
+ });
19
+ function Card(_a) {
20
+ var { className, variant } = _a, props = tslib.__rest(_a, ["className", "variant"]);
21
+ return jsxRuntime.jsx("div", Object.assign({ "data-slot": "card", className: utils.cn(cardVariants({ variant }), className) }, props));
22
+ }
23
+ function CardHeader(_a) {
24
+ var { className } = _a, props = tslib.__rest(_a, ["className"]);
25
+ return (jsxRuntime.jsx("div", Object.assign({ "data-slot": "card-header", className: utils.cn("@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6", className) }, props)));
26
+ }
27
+ function CardTitle(_a) {
28
+ var { className } = _a, props = tslib.__rest(_a, ["className"]);
29
+ return jsxRuntime.jsx("div", Object.assign({ "data-slot": "card-title", className: utils.cn("leading-none font-semibold", className) }, props));
30
+ }
31
+ function CardDescription(_a) {
32
+ var { className } = _a, props = tslib.__rest(_a, ["className"]);
33
+ return jsxRuntime.jsx("div", Object.assign({ "data-slot": "card-description", className: utils.cn("text-muted-foreground text-sm", className) }, props));
34
+ }
35
+ function CardAction(_a) {
36
+ var { className } = _a, props = tslib.__rest(_a, ["className"]);
37
+ return (jsxRuntime.jsx("div", Object.assign({ "data-slot": "card-action", className: utils.cn("col-start-2 row-span-2 row-start-1 self-start justify-self-end", className) }, props)));
38
+ }
39
+ function CardContent(_a) {
40
+ var { className } = _a, props = tslib.__rest(_a, ["className"]);
41
+ return jsxRuntime.jsx("div", Object.assign({ "data-slot": "card-content", className: utils.cn("px-6", className) }, props));
42
+ }
43
+ function CardFooter(_a) {
44
+ var { className } = _a, props = tslib.__rest(_a, ["className"]);
45
+ return (jsxRuntime.jsx("div", Object.assign({ "data-slot": "card-footer", className: utils.cn("flex items-center px-6 [.border-t]:pt-6", className) }, props)));
46
+ }
47
+
48
+ exports.Card = Card;
49
+ exports.CardAction = CardAction;
50
+ exports.CardContent = CardContent;
51
+ exports.CardDescription = CardDescription;
52
+ exports.CardFooter = CardFooter;
53
+ exports.CardHeader = CardHeader;
54
+ exports.CardTitle = CardTitle;
package/dist/cjs/index.js CHANGED
@@ -14,7 +14,10 @@ var radio = require('./components/forms/radio/radio.js');
14
14
  var select = require('./components/forms/select/select.js');
15
15
  var _switch = require('./components/forms/switch/switch.js');
16
16
  var textarea = require('./components/forms/textarea/textarea.js');
17
+ var form = require('./components/forms/form/form.js');
18
+ var formControl = require('./components/forms/form/form-control.js');
17
19
  var multiselect = require('./components/selectors/multiselect/multiselect.js');
20
+ var singleSelect = require('./components/selectors/single-select/single-select.js');
18
21
  var icon = require('./components/media/icon/icon.js');
19
22
  var avatar = require('./components/media/avatar/avatar.js');
20
23
  var aspectRatio = require('./components/media/aspect-ratio/aspect-ratio.js');
@@ -39,6 +42,7 @@ var progress = require('./components/ui/progress/progress.js');
39
42
  var sidebar = require('./components/ui/sidebar/sidebar.js');
40
43
  var table = require('./components/ui/table/table.js');
41
44
  var tabs = require('./components/ui/tabs/tabs.js');
45
+ var card = require('./components/ui/card/card.js');
42
46
  var emptyState = require('./components/utility/empty-state/empty-state.js');
43
47
  var separator = require('./components/utility/separator/separator.js');
44
48
  var skeleton = require('./components/utility/skeleton/skeleton.js');
@@ -95,7 +99,17 @@ exports.SelectTrigger = select.SelectTrigger;
95
99
  exports.SelectValue = select.SelectValue;
96
100
  exports.Switch = _switch.Switch;
97
101
  exports.Textarea = textarea.Textarea;
102
+ exports.Form = form.Form;
103
+ exports.FormDescription = form.FormDescription;
104
+ exports.FormField = form.FormField;
105
+ exports.FormFieldControl = form.FormFieldControl;
106
+ exports.FormItem = form.FormItem;
107
+ exports.FormLabel = form.FormLabel;
108
+ exports.FormMessage = form.FormMessage;
109
+ exports.useFormField = form.useFormField;
110
+ exports.FormControl = formControl.FormControl;
98
111
  exports.MultiSelect = multiselect.MultiSelect;
112
+ exports.SingleSelect = singleSelect.SingleSelect;
99
113
  exports.Icon = icon.Icon;
100
114
  exports.Avatar = avatar.Avatar;
101
115
  exports.AvatarFallback = avatar.AvatarFallback;
@@ -212,6 +226,13 @@ exports.Tabs = tabs.Tabs;
212
226
  exports.TabsContent = tabs.TabsContent;
213
227
  exports.TabsList = tabs.TabsList;
214
228
  exports.TabsTrigger = tabs.TabsTrigger;
229
+ exports.Card = card.Card;
230
+ exports.CardAction = card.CardAction;
231
+ exports.CardContent = card.CardContent;
232
+ exports.CardDescription = card.CardDescription;
233
+ exports.CardFooter = card.CardFooter;
234
+ exports.CardHeader = card.CardHeader;
235
+ exports.CardTitle = card.CardTitle;
215
236
  exports.EmptyState = emptyState.EmptyState;
216
237
  exports.Separator = separator.Separator;
217
238
  exports.Skeleton = skeleton.Skeleton;
@@ -0,0 +1,15 @@
1
+ import { __rest } from 'tslib';
2
+ import { jsx, jsxs } from 'react/jsx-runtime';
3
+ import { useFormContext } from 'react-hook-form';
4
+ import { FormField, FormItem, FormLabel, FormFieldControl, FormDescription, FormMessage } from './form.js';
5
+
6
+ function FormControl(_a) {
7
+ var { name, label, description, showMessage = true, children } = _a, props = __rest(_a, ["name", "label", "description", "showMessage", "children"]);
8
+ const form = useFormContext();
9
+ if (!form) {
10
+ throw new Error("FormControl must be used within a Form component");
11
+ }
12
+ return (jsx(FormField, { control: form.control, name: name, render: ({ field }) => (jsxs(FormItem, Object.assign({}, props, { children: [label && jsx(FormLabel, { children: label }), jsx(FormFieldControl, Object.assign({}, field, { children: children })), description && jsx(FormDescription, { children: description }), showMessage && jsx(FormMessage, {})] }))) }));
13
+ }
14
+
15
+ export { FormControl };
@@ -0,0 +1,59 @@
1
+ import { __rest } from 'tslib';
2
+ import { jsx } from 'react/jsx-runtime';
3
+ import { Slot } from '@radix-ui/react-slot';
4
+ import { FormProvider, useFormContext, useFormState, Controller } from 'react-hook-form';
5
+ import { createContext, useContext, useId } from 'react';
6
+ import { cn } from '../../../lib/utils.js';
7
+ import { Label } from '../label/label.js';
8
+
9
+ const Form = FormProvider;
10
+ const FormFieldContext = createContext({});
11
+ const FormField = (_a) => {
12
+ var props = __rest(_a, []);
13
+ return (jsx(FormFieldContext.Provider, { value: { name: props.name }, children: jsx(Controller, Object.assign({}, props)) }));
14
+ };
15
+ const FormItemContext = createContext({});
16
+ const useFormField = () => {
17
+ const fieldContext = useContext(FormFieldContext);
18
+ const itemContext = useContext(FormItemContext);
19
+ const { getFieldState } = useFormContext();
20
+ const formState = useFormState({ name: fieldContext.name });
21
+ const fieldState = getFieldState(fieldContext.name, formState);
22
+ if (!fieldContext) {
23
+ throw new Error("useFormField should be used within <FormField>");
24
+ }
25
+ const { id } = itemContext;
26
+ return Object.assign({ id, name: fieldContext.name, formItemId: `${id}-form-item`, formDescriptionId: `${id}-form-item-description`, formMessageId: `${id}-form-item-message` }, fieldState);
27
+ };
28
+ function FormItem(_a) {
29
+ var { className } = _a, props = __rest(_a, ["className"]);
30
+ const id = useId();
31
+ return (jsx(FormItemContext.Provider, { value: { id }, children: jsx("div", Object.assign({ "data-slot": "form-item", className: cn("grid gap-2", className) }, props)) }));
32
+ }
33
+ function FormLabel(_a) {
34
+ var { className } = _a, props = __rest(_a, ["className"]);
35
+ const { error, formItemId } = useFormField();
36
+ return (jsx(Label, Object.assign({ "data-slot": "form-label", "data-error": !!error, className: cn("data-[error=true]:text-destructive", className), htmlFor: formItemId }, props)));
37
+ }
38
+ function FormFieldControl(_a) {
39
+ var props = __rest(_a, []);
40
+ const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
41
+ return (jsx(Slot, Object.assign({ "data-slot": "form-control", id: formItemId, "aria-describedby": !error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`, "aria-invalid": !!error }, props)));
42
+ }
43
+ function FormDescription(_a) {
44
+ var { className } = _a, props = __rest(_a, ["className"]);
45
+ const { formDescriptionId } = useFormField();
46
+ return (jsx("p", Object.assign({ "data-slot": "form-description", id: formDescriptionId, className: cn("text-muted-foreground text-sm", className) }, props)));
47
+ }
48
+ function FormMessage(_a) {
49
+ var _b;
50
+ var { className } = _a, props = __rest(_a, ["className"]);
51
+ const { error, formMessageId } = useFormField();
52
+ const body = error ? String((_b = error === null || error === void 0 ? void 0 : error.message) !== null && _b !== void 0 ? _b : "") : props.children;
53
+ if (!body) {
54
+ return null;
55
+ }
56
+ return (jsx("p", Object.assign({ "data-slot": "form-message", id: formMessageId, className: cn("text-destructive text-sm", className) }, props, { children: body })));
57
+ }
58
+
59
+ export { Form, FormDescription, FormField, FormFieldControl, FormItem, FormLabel, FormMessage, useFormField };
@@ -11,11 +11,7 @@ const BadgeList = memo(({ options, disabled, onRemove }) => {
11
11
  if (disabled) {
12
12
  return;
13
13
  }
14
- if (e.key === "Enter" || e.key === " ") {
15
- e.preventDefault();
16
- onRemove(opt);
17
- }
18
- else if (e.key === "Backspace" || e.key === "Delete") {
14
+ if (e.key === "Enter" || e.key === " " || e.key === "Backspace" || e.key === "Delete") {
19
15
  e.preventDefault();
20
16
  onRemove(opt);
21
17
  const nextBadge = e.currentTarget.nextElementSibling || e.currentTarget.previousElementSibling;