@solidpb/ui-kit 0.1.1 → 0.3.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 (138) hide show
  1. package/README.md +17 -0
  2. package/dist/components/ActivityFeed/ActivityFeed.d.ts +16 -0
  3. package/dist/components/ActivityFeed/ActivityFeed.jsx +54 -0
  4. package/dist/components/ActivityFeed/index.d.ts +1 -0
  5. package/dist/components/ActivityFeed/index.js +1 -0
  6. package/dist/components/AlertDialog/AlertDialog.d.ts +27 -0
  7. package/dist/components/AlertDialog/AlertDialog.jsx +62 -0
  8. package/dist/components/AlertDialog/alertDialogContext.d.ts +9 -0
  9. package/dist/components/AlertDialog/alertDialogContext.js +2 -0
  10. package/dist/components/AlertDialog/index.d.ts +1 -0
  11. package/dist/components/AlertDialog/index.js +1 -0
  12. package/dist/components/Avatar/Avatar.d.ts +10 -0
  13. package/dist/components/Avatar/Avatar.jsx +30 -0
  14. package/dist/components/Avatar/index.d.ts +1 -0
  15. package/dist/components/Avatar/index.js +1 -0
  16. package/dist/components/BreadCrumbs/BreadCrumbs.d.ts +12 -0
  17. package/dist/components/BreadCrumbs/BreadCrumbs.jsx +26 -0
  18. package/dist/components/BreadCrumbs/index.d.ts +1 -0
  19. package/dist/components/BreadCrumbs/index.js +1 -0
  20. package/dist/components/Button/Button.d.ts +3 -3
  21. package/dist/components/Button/Button.jsx +1 -6
  22. package/dist/components/Card/Card.d.ts +1 -0
  23. package/dist/components/Card/Card.jsx +5 -2
  24. package/dist/components/Checkbox/Checkbox.d.ts +6 -7
  25. package/dist/components/Checkbox/Checkbox.jsx +39 -22
  26. package/dist/components/ColorPicker/ColorPicker.d.ts +10 -0
  27. package/dist/components/ColorPicker/ColorPicker.jsx +61 -0
  28. package/dist/components/ColorPicker/index.d.ts +1 -0
  29. package/dist/components/ColorPicker/index.js +1 -0
  30. package/dist/components/Container/Container.d.ts +0 -1
  31. package/dist/components/Container/Container.jsx +2 -8
  32. package/dist/components/DateInput/DateInput.d.ts +5 -0
  33. package/dist/components/DateInput/DateInput.jsx +29 -8
  34. package/dist/components/Drawer/Drawer.d.ts +33 -0
  35. package/dist/components/Drawer/Drawer.jsx +49 -0
  36. package/dist/components/Drawer/drawerContext.d.ts +6 -0
  37. package/dist/components/Drawer/drawerContext.js +9 -0
  38. package/dist/components/Drawer/index.d.ts +1 -0
  39. package/dist/components/Drawer/index.js +1 -0
  40. package/dist/components/DropdownMenu/DropdownMenu.d.ts +23 -7
  41. package/dist/components/DropdownMenu/DropdownMenu.jsx +41 -15
  42. package/dist/components/FileInput/FileInput.d.ts +7 -3
  43. package/dist/components/FileInput/FileInput.jsx +35 -9
  44. package/dist/components/FilterBar/AddFilter.d.ts +9 -0
  45. package/dist/components/FilterBar/AddFilter.jsx +14 -0
  46. package/dist/components/FilterBar/AddSortingDropdown.d.ts +9 -0
  47. package/dist/components/FilterBar/AddSortingDropdown.jsx +67 -0
  48. package/dist/components/FilterBar/EditFilters.d.ts +10 -0
  49. package/dist/components/FilterBar/EditFilters.jsx +12 -0
  50. package/dist/components/FilterBar/FilterBar.d.ts +54 -0
  51. package/dist/components/FilterBar/FilterBar.jsx +234 -0
  52. package/dist/components/FilterBar/FilterChip.d.ts +23 -0
  53. package/dist/components/FilterBar/FilterChip.jsx +220 -0
  54. package/dist/components/FilterBar/FilterEdit.d.ts +13 -0
  55. package/dist/components/FilterBar/FilterEdit.jsx +159 -0
  56. package/dist/components/FilterBar/FiltersEdit.d.ts +13 -0
  57. package/dist/components/FilterBar/FiltersEdit.jsx +45 -0
  58. package/dist/components/FilterBar/index.d.ts +1 -0
  59. package/dist/components/FilterBar/index.js +1 -0
  60. package/dist/components/Form/Form.d.ts +37 -2
  61. package/dist/components/Form/Form.jsx +102 -3
  62. package/dist/components/Form/formContext.d.ts +2 -0
  63. package/dist/components/Form/formContext.js +9 -0
  64. package/dist/components/Image/Image.d.ts +6 -7
  65. package/dist/components/Image/Image.jsx +74 -7
  66. package/dist/components/Input/Input.d.ts +4 -4
  67. package/dist/components/Input/Input.jsx +9 -35
  68. package/dist/components/Kanban/Kanban.d.ts +19 -0
  69. package/dist/components/Kanban/Kanban.jsx +68 -0
  70. package/dist/components/Kanban/KanbanCard.d.ts +11 -0
  71. package/dist/components/Kanban/KanbanCard.jsx +94 -0
  72. package/dist/components/Kanban/KanbanColumn.d.ts +18 -0
  73. package/dist/components/Kanban/KanbanColumn.jsx +251 -0
  74. package/dist/components/Kanban/index.d.ts +1 -0
  75. package/dist/components/Kanban/index.js +1 -0
  76. package/dist/components/Link/Link.d.ts +8 -6
  77. package/dist/components/Link/Link.jsx +17 -5
  78. package/dist/components/Modal/Modal.d.ts +17 -8
  79. package/dist/components/Modal/Modal.jsx +32 -39
  80. package/dist/components/Modal/modalContext.d.ts +2 -3
  81. package/dist/components/Navbar/Navbar.d.ts +26 -0
  82. package/dist/components/Navbar/Navbar.jsx +40 -0
  83. package/dist/components/Navbar/index.d.ts +1 -0
  84. package/dist/components/Navbar/index.js +1 -0
  85. package/dist/components/NumberInput/NumberInput.d.ts +8 -6
  86. package/dist/components/NumberInput/NumberInput.jsx +52 -7
  87. package/dist/components/Pagination/Pagination.d.ts +15 -0
  88. package/dist/components/Pagination/Pagination.jsx +67 -0
  89. package/dist/components/Pagination/index.d.ts +1 -0
  90. package/dist/components/Pagination/index.js +1 -0
  91. package/dist/components/SearchInput/SearchInput.d.ts +3 -0
  92. package/dist/components/SearchInput/SearchInput.jsx +38 -3
  93. package/dist/components/Select/Select.d.ts +13 -11
  94. package/dist/components/Select/Select.jsx +78 -32
  95. package/dist/components/Slider/Slider.d.ts +16 -0
  96. package/dist/components/Slider/Slider.jsx +60 -0
  97. package/dist/components/Slider/index.d.ts +1 -0
  98. package/dist/components/Slider/index.js +1 -0
  99. package/dist/components/Switch/Switch.d.ts +6 -8
  100. package/dist/components/Switch/Switch.jsx +38 -19
  101. package/dist/components/Table/Table.d.ts +27 -0
  102. package/dist/components/Table/Table.jsx +193 -0
  103. package/dist/components/Table/index.d.ts +1 -0
  104. package/dist/components/Table/index.js +1 -0
  105. package/dist/components/Tabs/Tabs.d.ts +25 -1
  106. package/dist/components/Tabs/Tabs.jsx +42 -1
  107. package/dist/components/Tabs/tabContext.d.ts +9 -0
  108. package/dist/components/Tabs/tabContext.js +2 -0
  109. package/dist/components/Tag/Tag.d.ts +7 -5
  110. package/dist/components/Tag/Tag.jsx +40 -14
  111. package/dist/components/TagArea/TagArea.d.ts +6 -2
  112. package/dist/components/TagArea/TagArea.jsx +89 -35
  113. package/dist/components/TextArea/TextArea.d.ts +9 -8
  114. package/dist/components/TextArea/TextArea.jsx +54 -18
  115. package/dist/components/ThemeSwitch/ThemeSwitch.d.ts +11 -0
  116. package/dist/components/ThemeSwitch/ThemeSwitch.jsx +49 -0
  117. package/dist/components/ThemeSwitch/index.d.ts +1 -0
  118. package/dist/components/ThemeSwitch/index.js +1 -0
  119. package/dist/components/Toast/Toast.d.ts +1 -1
  120. package/dist/components/Toast/Toast.jsx +13 -10
  121. package/dist/components/Toast/Toaster.jsx +1 -2
  122. package/dist/components/Tooltip/Tooltip.d.ts +4 -3
  123. package/dist/components/Tooltip/Tooltip.jsx +19 -8
  124. package/dist/constants.d.ts +8 -0
  125. package/dist/constants.js +8 -0
  126. package/dist/index.d.ts +14 -2
  127. package/dist/index.js +14 -2
  128. package/dist/methods/triggerFlash.d.ts +1 -0
  129. package/dist/methods/triggerFlash.js +7 -0
  130. package/package.json +3 -2
  131. package/dist/components/List/List.d.ts +0 -26
  132. package/dist/components/List/List.jsx +0 -120
  133. package/dist/components/List/index.d.ts +0 -1
  134. package/dist/components/List/index.js +0 -1
  135. package/dist/components/RelationPicker/RelationPicker.d.ts +0 -11
  136. package/dist/components/RelationPicker/RelationPicker.jsx +0 -13
  137. package/dist/components/RelationPicker/index.d.ts +0 -1
  138. package/dist/components/RelationPicker/index.js +0 -1
@@ -0,0 +1,45 @@
1
+ import { createMemo, createSignal, For, Show } from "solid-js";
2
+ import { Button } from "../Button";
3
+ import FilterEdit from "./FilterEdit";
4
+ import { createStore } from "solid-js/store";
5
+ export const FiltersEdit = (props) => {
6
+ const [filters, setFilters] = createStore(props.filters);
7
+ const [filtersReady, setFiltersReady] = createSignal(props.filters.map(() => props.filtersReady || false));
8
+ const allFiltersReady = createMemo(() => [...filtersReady()].every(Boolean));
9
+ const handleSaveFilters = () => {
10
+ if (allFiltersReady()) {
11
+ props.onSaveFilters(filters);
12
+ }
13
+ };
14
+ const addNewFilter = () => {
15
+ setFilters(filters.length, {});
16
+ setFiltersReady([...filtersReady(), false]);
17
+ };
18
+ const deleteFilter = (ind) => {
19
+ setFilters((prev) => prev.filter((_, i) => i !== ind));
20
+ setFiltersReady((prev) => prev.filter((_, i) => i !== ind));
21
+ };
22
+ return (<div class="flex flex-col gap-2 bg-base-200">
23
+ <For each={filters}>
24
+ {(f, i) => (<>
25
+ {i() > 0 && <span class="divider italic text-xs m-0">OR</span>}
26
+ <FilterEdit availableFields={props.availableFields} filter={f} setField={(field) => setFilters(i(), { ...filters[i()], field })} setOperator={(operator) => setFilters(i(), { ...filters[i()], operator })} setValue={(value) => setFilters(i(), { ...filters[i()], value })} setCanConfirm={(v) => setFiltersReady((prev) => {
27
+ const next = [...prev];
28
+ next[i()] = v;
29
+ return next;
30
+ })} size={props.size} onDelete={filters.length > 1 ? () => deleteFilter(i()) : undefined}/>
31
+ </>)}
32
+ </For>
33
+ <div class="w-full flex justify-end gap-1">
34
+ <Show when={props.addConditionTrigger !== undefined}>
35
+ <Button appearance="secondary" size="xs" onClick={addNewFilter}>
36
+ {props.addConditionTrigger}
37
+ </Button>
38
+ </Show>
39
+ <Button appearance="success" disabled={!allFiltersReady()} size="xs" onClick={handleSaveFilters}>
40
+ {props.saveTrigger}
41
+ </Button>
42
+ </div>
43
+ </div>);
44
+ };
45
+ export default FiltersEdit;
@@ -0,0 +1 @@
1
+ export * from "./FilterBar";
@@ -0,0 +1 @@
1
+ export * from "./FilterBar";
@@ -1,2 +1,37 @@
1
- import { ParentComponent } from "solid-js";
2
- export declare const Form: ParentComponent;
1
+ import { JSXElement } from "solid-js";
2
+ import { type SwitchProps } from "../Switch";
3
+ import { type SelectProps } from "../Select";
4
+ import { type InputRootProps } from "../Input";
5
+ import { type TextAreaRootProps } from "../TextArea";
6
+ import { type CheckboxProps } from "../Checkbox";
7
+ import { type NumberInputRootProps } from "../NumberInput";
8
+ import { type SliderProps } from "../Slider";
9
+ import { type ImageProps } from "../Image";
10
+ import { type FileInputProps } from "../FileInput";
11
+ export interface FormProps<T> {
12
+ data: T;
13
+ title?: string;
14
+ onSave?: (values: Partial<T>) => Promise<void>;
15
+ onCancel?: () => void;
16
+ children: JSXElement;
17
+ class?: string;
18
+ }
19
+ type BaseFieldProps<T> = {
20
+ field: keyof T;
21
+ };
22
+ export declare function createForm<T>(): {
23
+ (props: FormProps<T>): JSXElement;
24
+ TextField: (props: InputRootProps & BaseFieldProps<T>) => import("solid-js").JSX.Element;
25
+ NumberField: (props: NumberInputRootProps & BaseFieldProps<T>) => import("solid-js").JSX.Element;
26
+ CheckboxField: (props: CheckboxProps & BaseFieldProps<T>) => import("solid-js").JSX.Element;
27
+ SwitchField: (props: SwitchProps & BaseFieldProps<T>) => import("solid-js").JSX.Element;
28
+ TextAreaField: (props: TextAreaRootProps & BaseFieldProps<T>) => import("solid-js").JSX.Element;
29
+ SelectField: (props: SelectProps<{
30
+ label: string;
31
+ value: string;
32
+ }> & BaseFieldProps<T>) => import("solid-js").JSX.Element;
33
+ FileField: (props: FileInputProps & BaseFieldProps<T>) => import("solid-js").JSX.Element;
34
+ ImageField: (props: ImageProps & BaseFieldProps<T>) => import("solid-js").JSX.Element;
35
+ SliderField: (props: SliderProps & BaseFieldProps<T>) => import("solid-js").JSX.Element;
36
+ };
37
+ export {};
@@ -1,3 +1,102 @@
1
- export const Form = (props) => {
2
- return <div>{props.children}</div>;
3
- };
1
+ import { splitProps } from "solid-js";
2
+ import { createStore } from "solid-js/store";
3
+ import { InternalFormContext, useInternalFormContext } from "./formContext";
4
+ import { Switch } from "../Switch";
5
+ import { Select } from "../Select";
6
+ import { Input } from "../Input";
7
+ import { TextArea } from "../TextArea";
8
+ import { Checkbox } from "../Checkbox";
9
+ import { NumberInput } from "../NumberInput";
10
+ import { Slider } from "../Slider";
11
+ import { Image } from "../Image";
12
+ import { Button } from "../Button";
13
+ import { FileInput } from "../FileInput";
14
+ import { tv } from "tailwind-variants";
15
+ const formClass = tv({
16
+ base: "space-y-4 space-x-4",
17
+ });
18
+ export function createForm() {
19
+ const Form = (props) => {
20
+ const [values, setValues] = createStore({ ...props.data });
21
+ const setValue = (key, value) => {
22
+ setValues(key, value);
23
+ };
24
+ const getValue = (key) => {
25
+ return values[key];
26
+ };
27
+ const contextValue = { setValue, getValue, values };
28
+ const handleSubmit = (e) => {
29
+ e.preventDefault();
30
+ props.onSave?.(values);
31
+ };
32
+ return (<InternalFormContext.Provider value={contextValue}>
33
+ <form onSubmit={handleSubmit} class={formClass({ class: props.class })}>
34
+ {props.title && <h2 class="text-lg font-semibold">{props.title}</h2>}
35
+
36
+ {props.children}
37
+
38
+ <div class="flex justify-end gap-2">
39
+ {props.onCancel && (<Button appearance="neutral" onClick={props.onCancel} size="sm">
40
+ Cancel
41
+ </Button>)}
42
+ {props.onSave && (<Button appearance="success" type="submit" size="sm">
43
+ Save
44
+ </Button>)}
45
+ </div>
46
+ </form>
47
+ </InternalFormContext.Provider>);
48
+ };
49
+ const TextField = (props) => {
50
+ const form = useInternalFormContext();
51
+ return (<Input {...props} value={form.getValue(props.field)} onChange={(v) => form.setValue(props.field, v)}/>);
52
+ };
53
+ const NumberField = (props) => {
54
+ const form = useInternalFormContext();
55
+ return (<NumberInput {...props} rawValue={form.getValue(props.field)} onRawValueChange={(v) => form.setValue(props.field, v)}/>);
56
+ };
57
+ const CheckboxField = (props) => {
58
+ const form = useInternalFormContext();
59
+ return (<Checkbox {...props} checked={Boolean(form.getValue(props.field))} onChange={(v) => form.setValue(props.field, v)}/>);
60
+ };
61
+ const SwitchField = (props) => {
62
+ const form = useInternalFormContext();
63
+ return (<Switch {...props} checked={Boolean(form.getValue(props.field))} onChange={(v) => form.setValue(props.field, v)}/>);
64
+ };
65
+ const TextAreaField = (props) => {
66
+ const form = useInternalFormContext();
67
+ return (<TextArea {...props} value={form.getValue(props.field)} onChange={(v) => form.setValue(props.field, v)}/>);
68
+ };
69
+ const SelectField = (props) => {
70
+ const [local, others] = splitProps(props, ["onChange", "value"]);
71
+ const form = useInternalFormContext();
72
+ return (<Select {...others} labelKey="label" valueKey="value" value={local.value} onChange={(v) => {
73
+ local.onChange(v);
74
+ form.setValue(props.field, v?.value);
75
+ }}/>);
76
+ };
77
+ const FileField = (props) => {
78
+ const form = useInternalFormContext();
79
+ return <FileInput {...props} onChange={(files) => form.setValue(props.field, files)}/>;
80
+ };
81
+ const ImageField = (props) => {
82
+ const form = useInternalFormContext();
83
+ return (<Image {...props} editable src={form.getValue(props.field)} onChange={(file) => {
84
+ const fileURL = URL.createObjectURL(file);
85
+ form.setValue(props.field, fileURL);
86
+ }}/>);
87
+ };
88
+ const SliderField = (props) => {
89
+ const form = useInternalFormContext();
90
+ return (<Slider {...props} value={form.getValue(props.field)} onChange={(v) => form.setValue(props.field, v)}/>);
91
+ };
92
+ Form.TextField = TextField;
93
+ Form.NumberField = NumberField;
94
+ Form.CheckboxField = CheckboxField;
95
+ Form.SwitchField = SwitchField;
96
+ Form.TextAreaField = TextAreaField;
97
+ Form.SelectField = SelectField;
98
+ Form.FileField = FileField;
99
+ Form.ImageField = ImageField;
100
+ Form.SliderField = SliderField;
101
+ return Form;
102
+ }
@@ -0,0 +1,2 @@
1
+ export declare const InternalFormContext: import("solid-js").Context<any>;
2
+ export declare function useInternalFormContext(): any;
@@ -0,0 +1,9 @@
1
+ import { createContext, useContext } from "solid-js";
2
+ export const InternalFormContext = createContext();
3
+ export function useInternalFormContext() {
4
+ const ctx = useContext(InternalFormContext);
5
+ if (!ctx) {
6
+ throw new Error("useInternalFormContext must be used inside Form");
7
+ }
8
+ return ctx;
9
+ }
@@ -1,9 +1,8 @@
1
- import { Component } from "solid-js";
2
- interface ImageProps {
3
- src: string;
4
- alt?: string;
5
- class?: string;
6
- rounded?: boolean;
1
+ import type { Component, JSX } from "solid-js";
2
+ export interface ImageProps extends Omit<JSX.ImgHTMLAttributes<HTMLImageElement>, "onChange"> {
3
+ editable?: boolean;
4
+ onChange?: (file: File) => void;
5
+ size?: "xs" | "sm" | "md" | "lg" | "xl";
6
+ label?: string;
7
7
  }
8
8
  export declare const Image: Component<ImageProps>;
9
- export default Image;
@@ -1,15 +1,82 @@
1
+ import { Show, createSignal } from "solid-js";
1
2
  import { tv } from "tailwind-variants";
3
+ import Pencil from "lucide-solid/icons/pencil";
4
+ import ImageIcon from "lucide-solid/icons/image";
5
+ import { Button } from "../Button";
2
6
  const image = tv({
3
- base: "object-cover",
7
+ base: "rounded-box shadow object-cover",
4
8
  variants: {
5
- rounded: {
6
- true: "rounded-full",
7
- false: "rounded-none",
9
+ size: {
10
+ xs: "w-16 h-16",
11
+ sm: "w-24 h-24",
12
+ md: "w-32 h-32",
13
+ lg: "w-48 h-48",
14
+ xl: "w-64 h-64",
15
+ },
16
+ },
17
+ });
18
+ const placeholder = tv({
19
+ base: "rounded-box shadow flex items-center justify-center bg-base-200",
20
+ variants: {
21
+ size: {
22
+ xs: "w-16 h-16",
23
+ sm: "w-24 h-24",
24
+ md: "w-32 h-32",
25
+ lg: "w-48 h-48",
26
+ xl: "w-64 h-64",
27
+ },
28
+ },
29
+ });
30
+ const label = tv({
31
+ base: "label text-xs",
32
+ variants: {
33
+ size: {
34
+ xs: "text-xs",
35
+ sm: "text-xs",
36
+ md: "text-xs",
37
+ lg: "text-sm",
38
+ xl: "text-sm",
8
39
  },
9
40
  },
10
41
  defaultVariants: {
11
- rounded: false,
42
+ size: "sm",
12
43
  },
13
44
  });
14
- export const Image = (props) => (<img src={props.src} alt={props.alt} class={image({ rounded: props.rounded, class: props.class })}/>);
15
- export default Image;
45
+ export const Image = (props) => {
46
+ const [preview, setPreview] = createSignal(null);
47
+ let fileInputRef = null;
48
+ const handleEditClick = () => {
49
+ fileInputRef?.click();
50
+ };
51
+ const handleFileChange = (e) => {
52
+ const target = e.target;
53
+ const file = target.files?.[0];
54
+ if (file) {
55
+ setPreview(URL.createObjectURL(file));
56
+ props.onChange?.(file);
57
+ }
58
+ };
59
+ // Destructure onChange and editable so they are not passed to <img>
60
+ const { onChange, editable, ...imgProps } = props;
61
+ const currentSrc = () => preview() || props.src;
62
+ return (<label class="flex flex-col gap-1 w-fit">
63
+ <Show when={props.label}>
64
+ <span class={label({ size: props.size })}>{props.label}</span>
65
+ </Show>
66
+ <div class="relative inline-block group w-fit">
67
+ <Show when={currentSrc()} fallback={<div class={placeholder({ size: props.size, class: props.class })}>
68
+ <ImageIcon class="w-1/2 h-1/2 text-base-300"/>
69
+ </div>}>
70
+ <img {...imgProps} src={currentSrc()} alt={props.alt} class={image({ size: props.size, class: props.class })}/>
71
+ </Show>
72
+ <Show when={editable}>
73
+ <div class="absolute inset-0 flex items-center justify-center bg-black/10 opacity-0 group-hover:opacity-100 transition-opacity z-10 rounded-box">
74
+ <Button size="sm" modifier="square" variant="ghost" onClick={handleEditClick}>
75
+ <Pencil class="w-4 h-4"/>
76
+ </Button>
77
+ </div>
78
+ <input ref={(el) => (fileInputRef = el)} type="file" accept="image/*" class="hidden" onChange={handleFileChange}/>
79
+ </Show>
80
+ </div>
81
+ </label>);
82
+ };
@@ -1,15 +1,15 @@
1
1
  import { Component, ValidComponent } from "solid-js";
2
2
  import { type TextFieldInputProps, type TextFieldRootProps } from "@kobalte/core/text-field";
3
3
  import type { PolymorphicProps } from "@kobalte/core";
4
- type InputProps<T extends ValidComponent = "input"> = PolymorphicProps<T, TextFieldInputProps<T>>;
5
- interface ExtraProps {
4
+ export type InputProps<T extends ValidComponent = "input"> = PolymorphicProps<T, TextFieldInputProps<T>>;
5
+ export interface ExtraProps {
6
6
  label?: string;
7
- variant?: "ghost" | "none";
7
+ variant?: "ghost";
8
8
  appearance?: "neutral" | "primary" | "secondary" | "accent" | "info" | "success" | "warning" | "error";
9
9
  size?: "xs" | "sm" | "md" | "lg" | "xl";
10
10
  inputProps?: InputProps;
11
11
  saveFunc?: (v: string) => Promise<any>;
12
12
  }
13
- type InputRootProps<T extends ValidComponent = "div"> = ExtraProps & PolymorphicProps<T, TextFieldRootProps<T>>;
13
+ export type InputRootProps<T extends ValidComponent = "div"> = ExtraProps & PolymorphicProps<T, TextFieldRootProps<T>>;
14
14
  export declare const Input: Component<InputRootProps>;
15
15
  export default Input;
@@ -4,30 +4,6 @@ import { tv } from "tailwind-variants";
4
4
  import { debounce } from "../../methods/debounce";
5
5
  const inputRoot = tv({
6
6
  base: "relative flex flex-col gap-1",
7
- variants: {
8
- marginTop: {
9
- yes: "mt-2",
10
- no: "",
11
- },
12
- },
13
- defaultVariants: {
14
- marginTop: "no",
15
- },
16
- });
17
- const inputLabel = tv({
18
- base: "absolute left-3 px-1 font-medium pointer-events-none z-10 bg-base-100",
19
- variants: {
20
- size: {
21
- xs: "text-xs",
22
- sm: "text-xs",
23
- md: "text-sm",
24
- lg: "text-sm",
25
- xl: "text-md",
26
- },
27
- },
28
- defaultVariants: {
29
- size: "md",
30
- },
31
7
  });
32
8
  const inputField = tv({
33
9
  base: "input outline-offset-0",
@@ -55,9 +31,7 @@ const inputField = tv({
55
31
  },
56
32
  },
57
33
  defaultVariants: {
58
- variant: "none",
59
- size: "md",
60
- appearance: "neutral",
34
+ size: "sm",
61
35
  },
62
36
  });
63
37
  export const Input = (props) => {
@@ -76,19 +50,19 @@ export const Input = (props) => {
76
50
  local.onChange?.(v);
77
51
  debouncedSave()?.(v);
78
52
  };
79
- return (<TextField class={inputRoot({ class: local.class, marginTop: local.label ? "yes" : "no" })} {...others} onChange={handleChange}>
53
+ return (<TextField {...others} class={inputRoot({ class: local.class })} onChange={handleChange}>
80
54
  <div class="relative w-full">
81
- <Show when={local.label}>
82
- <TextField.Label class={inputLabel({ size: local.size })} style="transform: translateY(-50%);">
83
- {local.label}
84
- </TextField.Label>
85
- </Show>
86
- <TextField.Input class={inputField({
55
+ <TextField.Label class="floating-label">
56
+ <Show when={local.label}>
57
+ <span>{local.label}</span>
58
+ </Show>
59
+ <TextField.Input {...local.inputProps} class={inputField({
87
60
  appearance: local.appearance,
88
61
  variant: local.variant,
89
62
  size: local.size,
90
63
  class: local.inputProps?.class,
91
- })} {...local.inputProps}/>
64
+ })}/>
65
+ </TextField.Label>
92
66
  </div>
93
67
  </TextField>);
94
68
  };
@@ -0,0 +1,19 @@
1
+ import { JSXElement } from "solid-js";
2
+ export interface KanbanProps<T extends KanbanItem, K extends KanbanState> {
3
+ columns?: K[];
4
+ items: T[];
5
+ renderItem?: (item: T) => JSXElement;
6
+ onCardClick?: (item: T) => void;
7
+ containerClass?: string;
8
+ columnClass?: string;
9
+ cardClass?: string;
10
+ onCreateItem?: (title: string, state: string) => void;
11
+ onCollapseColumn?: (collapsed: boolean) => void;
12
+ onReorderCard?: (item: T, oldPos: number, newPos: number, oldState: string, newState: string) => void;
13
+ onReorderColumn?: (col: K, oldPos: number, newPos: number) => void;
14
+ itemStateKey?: keyof T;
15
+ itemPositionKey?: keyof T;
16
+ statePositionKey?: keyof K;
17
+ }
18
+ export declare const Kanban: <T extends KanbanItem, K extends KanbanState>(props: KanbanProps<T, K>) => import("solid-js").JSX.Element;
19
+ export default Kanban;
@@ -0,0 +1,68 @@
1
+ import { createEffect, createMemo, createSignal, For, onCleanup, Show } from "solid-js";
2
+ import { extractClosestEdge } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
3
+ import { monitorForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
4
+ import { tv } from "tailwind-variants";
5
+ import { KanbanColumn } from "./KanbanColumn";
6
+ const container = tv({
7
+ base: "flex gap-2 overflow-x-auto p-2",
8
+ });
9
+ export const Kanban = (props) => {
10
+ const sortedColumns = createMemo(() => {
11
+ const posKey = props.statePositionKey;
12
+ if (!posKey)
13
+ return props.columns;
14
+ return props.columns?.toSorted((a, b) => (Number(a[posKey]) ?? 0) - (Number(b[posKey]) ?? 0));
15
+ });
16
+ const colDragEnabled = () => !!props.statePositionKey;
17
+ const [flashedColId, setFlashedColId] = createSignal(null);
18
+ createEffect(() => {
19
+ if (!props.items.length || !colDragEnabled())
20
+ return;
21
+ const dispose = monitorForElements({
22
+ canMonitor({ source }) {
23
+ return (source.data.item.collectionId == props.items[0].collectionId &&
24
+ !!source.data.isKanbanColumn);
25
+ },
26
+ onDrop({ location, source }) {
27
+ const target = location.current.dropTargets[0];
28
+ if (!target) {
29
+ return;
30
+ }
31
+ const sourceData = source.data;
32
+ const targetData = target.data;
33
+ const sourceItem = sourceData.item;
34
+ const targetItem = targetData.item;
35
+ const posKey = props.statePositionKey;
36
+ if (!posKey)
37
+ return;
38
+ if (sourceItem.collectionId !== targetItem.collectionId && source.data.isKanbanColumn) {
39
+ return;
40
+ }
41
+ if ((Number(sourceItem[posKey]) || 0) < 0 || (Number(targetItem[posKey]) || 0) < 0) {
42
+ return;
43
+ }
44
+ const closestEdgeOfTarget = extractClosestEdge(targetData);
45
+ let newInd = closestEdgeOfTarget === "left"
46
+ ? Number(targetItem[posKey]) || 0
47
+ : (Number(targetItem[posKey]) || 0) + 1;
48
+ if (newInd > (Number(sourceItem[posKey]) || 0)) {
49
+ newInd--;
50
+ }
51
+ if ((Number(sourceItem[posKey]) || 0) !== newInd) {
52
+ setFlashedColId(sourceItem.id);
53
+ setTimeout(() => setFlashedColId(null), 10);
54
+ }
55
+ props.onReorderColumn?.(sourceItem, Number(sourceItem[posKey]) || 0, newInd);
56
+ },
57
+ });
58
+ onCleanup(dispose);
59
+ });
60
+ return (<div class={container({ class: props.containerClass })}>
61
+ <Show when={sortedColumns()?.length} fallback={<KanbanColumn dragEnabled={colDragEnabled} cardClass={props.cardClass} items={props.items} class={props.columnClass} onCardClick={props.onCardClick} renderItem={props.renderItem} onCreateItem={props.onCreateItem} onReorderCard={props.onReorderCard} onCollapse={props.onCollapseColumn} flashSignal={() => flashedColId()} itemPositionKey={props.itemPositionKey} itemStateKey={props.itemStateKey}/>}>
62
+ <For each={sortedColumns()}>
63
+ {(col) => (<KanbanColumn col={col} dragEnabled={colDragEnabled} cardClass={props.cardClass} items={props.items} class={props.columnClass} onCardClick={props.onCardClick} renderItem={props.renderItem} onCreateItem={props.onCreateItem} onReorderCard={props.onReorderCard} onCollapse={props.onCollapseColumn} flashSignal={() => flashedColId()} itemPositionKey={props.itemPositionKey} itemStateKey={props.itemStateKey}/>)}
64
+ </For>
65
+ </Show>
66
+ </div>);
67
+ };
68
+ export default Kanban;
@@ -0,0 +1,11 @@
1
+ import { Accessor, JSXElement } from "solid-js";
2
+ export interface KanbanCardProps<T extends KanbanItem> {
3
+ item: T;
4
+ dragEnabled: Accessor<boolean>;
5
+ flashSignal: Accessor<string | null>;
6
+ onCardClick?: () => void;
7
+ renderItem?: (item: T) => JSXElement;
8
+ class?: string;
9
+ }
10
+ export declare const KanbanCard: <T extends KanbanItem>(props: KanbanCardProps<T>) => import("solid-js").JSX.Element;
11
+ export default KanbanCard;
@@ -0,0 +1,94 @@
1
+ import { createSignal, createEffect, onCleanup } from "solid-js";
2
+ import { attachClosestEdge, extractClosestEdge, } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
3
+ import { dropTargetForElements, draggable } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
4
+ import invariant from "tiny-invariant";
5
+ import { tv } from "tailwind-variants";
6
+ import { triggerFlash } from "../../methods/triggerFlash";
7
+ const itemCard = tv({
8
+ base: "kanban-card card bg-base-100 p-2 rounded-md cursor-pointer hover:shadow-xs transition-shadow",
9
+ });
10
+ const itemTitle = tv({
11
+ base: "font-medium text-sm",
12
+ });
13
+ export const KanbanCard = (props) => {
14
+ let ref;
15
+ const [dragging, setDragging] = createSignal("idle");
16
+ const [closestEdge, setClosestEdge] = createSignal();
17
+ createEffect(() => {
18
+ if (props.flashSignal?.() === props.item.id && ref) {
19
+ triggerFlash(ref);
20
+ }
21
+ });
22
+ createEffect(() => {
23
+ if (!props.dragEnabled())
24
+ return;
25
+ const element = ref;
26
+ invariant(element);
27
+ const dispose = dropTargetForElements({
28
+ element,
29
+ canDrop({ source }) {
30
+ // not allowing dropping on yourself
31
+ if (source.element === element) {
32
+ return false;
33
+ }
34
+ if (!source.data.item) {
35
+ return false;
36
+ }
37
+ // only allowing same collection for now to be dropped on me
38
+ return source.data.item.collectionId == props.item.collectionId && !!source.data.isKanbanCard;
39
+ },
40
+ getData({ input }) {
41
+ return attachClosestEdge({
42
+ item: props.item,
43
+ isKanbanCard: true,
44
+ }, { element, input, allowedEdges: ["top", "bottom"] });
45
+ },
46
+ onDragEnter({ self }) {
47
+ const _closestEdge = extractClosestEdge(self.data);
48
+ setDragging("dragging-over");
49
+ setClosestEdge(_closestEdge);
50
+ },
51
+ onDrag({ self }) {
52
+ const _closestEdge = extractClosestEdge(self.data);
53
+ // Only need to update state if nothing has changed.
54
+ if (dragging() !== "dragging-over" || _closestEdge !== closestEdge()) {
55
+ setDragging("dragging-over");
56
+ setClosestEdge(_closestEdge);
57
+ }
58
+ },
59
+ onDragLeave() {
60
+ setDragging("idle");
61
+ },
62
+ onDrop() {
63
+ setDragging("idle");
64
+ },
65
+ });
66
+ onCleanup(dispose);
67
+ });
68
+ createEffect(() => {
69
+ if (!props.dragEnabled())
70
+ return;
71
+ const element = ref;
72
+ invariant(element);
73
+ const dispose = draggable({
74
+ element,
75
+ getInitialData() {
76
+ return {
77
+ item: props.item,
78
+ isKanbanCard: true,
79
+ };
80
+ },
81
+ onDragStart() {
82
+ setDragging("dragging");
83
+ },
84
+ onDrop() {
85
+ setDragging("idle");
86
+ },
87
+ });
88
+ onCleanup(dispose);
89
+ });
90
+ return (<div data-drop-edge={dragging() === "dragging-over" ? (closestEdge() ?? undefined) : undefined} style={{ opacity: dragging() == "dragging" ? 0.2 : 1 }} ref={ref} class={itemCard({ class: props.class })} onClick={props.onCardClick}>
91
+ {props.renderItem ? props.renderItem(props.item) : <div class={itemTitle()}>{props.item.title}</div>}
92
+ </div>);
93
+ };
94
+ export default KanbanCard;
@@ -0,0 +1,18 @@
1
+ import { Accessor, JSXElement } from "solid-js";
2
+ export interface KanbanColumnProps<T extends KanbanItem, K extends KanbanState> {
3
+ col?: K;
4
+ items: T[];
5
+ dragEnabled: Accessor<boolean>;
6
+ class?: string;
7
+ cardClass?: string;
8
+ onCardClick?: (item: T) => void;
9
+ renderItem?: (item: T) => JSXElement;
10
+ onCreateItem?: (title: string, state: string) => void;
11
+ onReorderCard?: (item: T, oldPos: number, newPos: number, oldState: string, newState: string) => void;
12
+ onCollapse?: (collapsed: boolean) => void;
13
+ flashSignal: Accessor<string | null>;
14
+ itemStateKey?: keyof T;
15
+ itemPositionKey?: keyof T;
16
+ }
17
+ export declare const KanbanColumn: <T extends KanbanItem, K extends KanbanState>(props: KanbanColumnProps<T, K>) => import("solid-js").JSX.Element;
18
+ export default KanbanColumn;