@solidpb/ui-kit 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) 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 +7 -6
  21. package/dist/components/Button/Button.jsx +36 -55
  22. package/dist/components/Card/Card.d.ts +11 -1
  23. package/dist/components/Card/Card.jsx +25 -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.jsx +11 -1
  31. package/dist/components/DateInput/DateInput.d.ts +5 -0
  32. package/dist/components/DateInput/DateInput.jsx +29 -8
  33. package/dist/components/Drawer/Drawer.d.ts +33 -0
  34. package/dist/components/Drawer/Drawer.jsx +49 -0
  35. package/dist/components/Drawer/drawerContext.d.ts +6 -0
  36. package/dist/components/Drawer/drawerContext.js +9 -0
  37. package/dist/components/Drawer/index.d.ts +1 -0
  38. package/dist/components/Drawer/index.js +1 -0
  39. package/dist/components/DropdownMenu/DropdownMenu.d.ts +23 -7
  40. package/dist/components/DropdownMenu/DropdownMenu.jsx +41 -15
  41. package/dist/components/FileInput/FileInput.d.ts +7 -3
  42. package/dist/components/FileInput/FileInput.jsx +35 -9
  43. package/dist/components/FilterBar/AddFilter.d.ts +9 -0
  44. package/dist/components/FilterBar/AddFilter.jsx +14 -0
  45. package/dist/components/FilterBar/AddSortingDropdown.d.ts +9 -0
  46. package/dist/components/FilterBar/AddSortingDropdown.jsx +67 -0
  47. package/dist/components/FilterBar/EditFilters.d.ts +10 -0
  48. package/dist/components/FilterBar/EditFilters.jsx +12 -0
  49. package/dist/components/FilterBar/FilterBar.d.ts +56 -0
  50. package/dist/components/FilterBar/FilterBar.jsx +234 -0
  51. package/dist/components/FilterBar/FilterChip.d.ts +23 -0
  52. package/dist/components/FilterBar/FilterChip.jsx +220 -0
  53. package/dist/components/FilterBar/FilterEdit.d.ts +13 -0
  54. package/dist/components/FilterBar/FilterEdit.jsx +159 -0
  55. package/dist/components/FilterBar/FiltersEdit.d.ts +13 -0
  56. package/dist/components/FilterBar/FiltersEdit.jsx +45 -0
  57. package/dist/components/FilterBar/index.d.ts +1 -0
  58. package/dist/components/FilterBar/index.js +1 -0
  59. package/dist/components/Form/Form.d.ts +36 -2
  60. package/dist/components/Form/Form.jsx +98 -3
  61. package/dist/components/Form/formContext.d.ts +2 -0
  62. package/dist/components/Form/formContext.js +9 -0
  63. package/dist/components/Image/Image.d.ts +6 -7
  64. package/dist/components/Image/Image.jsx +56 -7
  65. package/dist/components/Input/Input.d.ts +4 -4
  66. package/dist/components/Input/Input.jsx +10 -27
  67. package/dist/components/Kanban/Kanban.d.ts +19 -0
  68. package/dist/components/Kanban/Kanban.jsx +66 -0
  69. package/dist/components/Kanban/KanbanCard.d.ts +11 -0
  70. package/dist/components/Kanban/KanbanCard.jsx +94 -0
  71. package/dist/components/Kanban/KanbanColumn.d.ts +18 -0
  72. package/dist/components/Kanban/KanbanColumn.jsx +256 -0
  73. package/dist/components/Kanban/index.d.ts +1 -0
  74. package/dist/components/Kanban/index.js +1 -0
  75. package/dist/components/Link/Link.d.ts +8 -6
  76. package/dist/components/Link/Link.jsx +17 -5
  77. package/dist/components/Modal/Modal.d.ts +17 -8
  78. package/dist/components/Modal/Modal.jsx +32 -39
  79. package/dist/components/Modal/modalContext.d.ts +2 -3
  80. package/dist/components/Navbar/Navbar.d.ts +22 -0
  81. package/dist/components/Navbar/Navbar.jsx +38 -0
  82. package/dist/components/Navbar/index.d.ts +1 -0
  83. package/dist/components/Navbar/index.js +1 -0
  84. package/dist/components/NumberInput/NumberInput.d.ts +8 -6
  85. package/dist/components/NumberInput/NumberInput.jsx +52 -7
  86. package/dist/components/Pagination/Pagination.d.ts +15 -0
  87. package/dist/components/Pagination/Pagination.jsx +67 -0
  88. package/dist/components/Pagination/index.d.ts +1 -0
  89. package/dist/components/Pagination/index.js +1 -0
  90. package/dist/components/SearchInput/SearchInput.d.ts +3 -0
  91. package/dist/components/SearchInput/SearchInput.jsx +38 -3
  92. package/dist/components/Select/Select.d.ts +13 -11
  93. package/dist/components/Select/Select.jsx +78 -32
  94. package/dist/components/Slider/Slider.d.ts +16 -0
  95. package/dist/components/Slider/Slider.jsx +60 -0
  96. package/dist/components/Slider/index.d.ts +1 -0
  97. package/dist/components/Slider/index.js +1 -0
  98. package/dist/components/Switch/Switch.d.ts +6 -8
  99. package/dist/components/Switch/Switch.jsx +38 -19
  100. package/dist/components/{List/List.d.ts → Table/Table.d.ts} +13 -12
  101. package/dist/components/Table/Table.jsx +193 -0
  102. package/dist/components/Table/index.d.ts +1 -0
  103. package/dist/components/Table/index.js +1 -0
  104. package/dist/components/Tabs/Tabs.d.ts +25 -1
  105. package/dist/components/Tabs/Tabs.jsx +42 -1
  106. package/dist/components/Tabs/tabContext.d.ts +9 -0
  107. package/dist/components/Tabs/tabContext.js +2 -0
  108. package/dist/components/Tag/Tag.d.ts +7 -5
  109. package/dist/components/Tag/Tag.jsx +40 -14
  110. package/dist/components/TagArea/TagArea.d.ts +8 -4
  111. package/dist/components/TagArea/TagArea.jsx +89 -35
  112. package/dist/components/TextArea/TextArea.d.ts +9 -8
  113. package/dist/components/TextArea/TextArea.jsx +54 -18
  114. package/dist/components/ThemeSwitch/ThemeSwitch.d.ts +2 -0
  115. package/dist/components/ThemeSwitch/ThemeSwitch.jsx +72 -0
  116. package/dist/components/ThemeSwitch/index.d.ts +1 -0
  117. package/dist/components/ThemeSwitch/index.js +1 -0
  118. package/dist/components/Toast/Toast.d.ts +1 -1
  119. package/dist/components/Toast/Toast.jsx +13 -10
  120. package/dist/components/Toast/Toaster.jsx +1 -2
  121. package/dist/components/Tooltip/Tooltip.d.ts +4 -3
  122. package/dist/components/Tooltip/Tooltip.jsx +19 -8
  123. package/dist/constants.d.ts +7 -0
  124. package/dist/constants.js +7 -0
  125. package/dist/index.d.ts +14 -4
  126. package/dist/index.js +14 -4
  127. package/dist/methods/triggerFlash.d.ts +1 -0
  128. package/dist/methods/triggerFlash.js +7 -0
  129. package/package.json +4 -3
  130. package/dist/components/Heading/Heading.d.ts +0 -7
  131. package/dist/components/Heading/Heading.jsx +0 -29
  132. package/dist/components/Heading/index.d.ts +0 -1
  133. package/dist/components/Heading/index.js +0 -1
  134. package/dist/components/List/List.jsx +0 -120
  135. package/dist/components/List/index.d.ts +0 -1
  136. package/dist/components/List/index.js +0 -1
  137. package/dist/components/RelationPicker/RelationPicker.d.ts +0 -11
  138. package/dist/components/RelationPicker/RelationPicker.jsx +0 -13
  139. package/dist/components/RelationPicker/index.d.ts +0 -1
  140. package/dist/components/RelationPicker/index.js +0 -1
  141. package/dist/components/Text/Text.d.ts +0 -9
  142. package/dist/components/Text/Text.jsx +0 -25
  143. package/dist/components/Text/index.d.ts +0 -1
  144. package/dist/components/Text/index.js +0 -1
@@ -0,0 +1,193 @@
1
+ import { For, Show, createEffect, createMemo, createSignal, onCleanup } from "solid-js";
2
+ import { attachClosestEdge, extractClosestEdge, } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
3
+ import { monitorForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
4
+ import { draggable, dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
5
+ import invariant from "tiny-invariant";
6
+ import { createSolidTable, flexRender, getCoreRowModel } from "@tanstack/solid-table";
7
+ import { tv } from "tailwind-variants";
8
+ import Loader from "lucide-solid/icons/loader";
9
+ import GripVertical from "lucide-solid/icons/grip-vertical";
10
+ import { triggerFlash } from "../../methods/triggerFlash";
11
+ import { iconSize } from "../../constants";
12
+ const tableClass = tv({
13
+ base: "table table-pin-rows",
14
+ variants: {
15
+ size: {
16
+ xs: "table-xs",
17
+ sm: "table-sm",
18
+ md: "table-md",
19
+ lg: "table-lg",
20
+ xl: "table-xl",
21
+ },
22
+ },
23
+ defaultVariants: {
24
+ size: "sm",
25
+ },
26
+ });
27
+ const TableRow = (props) => {
28
+ let ref;
29
+ let handleRef;
30
+ const [dragging, setDragging] = createSignal("idle");
31
+ const [closestEdge, setClosestEdge] = createSignal();
32
+ createEffect(() => {
33
+ if (props.flashSignal?.() === props.row.original.id && ref) {
34
+ triggerFlash(ref);
35
+ }
36
+ });
37
+ createEffect(() => {
38
+ if (!props.dragEnabled())
39
+ return;
40
+ const element = ref;
41
+ invariant(element);
42
+ const dispose = dropTargetForElements({
43
+ element,
44
+ canDrop({ source }) {
45
+ // not allowing dropping on yourself
46
+ if (source.element === element) {
47
+ return false;
48
+ }
49
+ // only allowing same collection for now to be dropped on me
50
+ return source.data.collectionId == props.row.original.collectionId;
51
+ },
52
+ getData({ input }) {
53
+ return attachClosestEdge({ id: props.row.original.id, ind: props.row.index, collectionId: props.row.original.collectionId }, { element, input, allowedEdges: ["top", "bottom"] });
54
+ },
55
+ onDragEnter({ self }) {
56
+ const _closestEdge = extractClosestEdge(self.data);
57
+ setDragging("dragging-over");
58
+ setClosestEdge(_closestEdge);
59
+ },
60
+ onDrag({ self }) {
61
+ const _closestEdge = extractClosestEdge(self.data);
62
+ // Only need to update state if nothing has changed.
63
+ if (dragging() !== "dragging-over" || _closestEdge !== closestEdge()) {
64
+ setDragging("dragging-over");
65
+ setClosestEdge(_closestEdge);
66
+ }
67
+ },
68
+ onDragLeave() {
69
+ setDragging("idle");
70
+ },
71
+ onDrop() {
72
+ setDragging("idle");
73
+ },
74
+ });
75
+ onCleanup(dispose);
76
+ });
77
+ createEffect(() => {
78
+ if (!props.dragEnabled())
79
+ return;
80
+ const element = ref;
81
+ const elementHandle = handleRef;
82
+ invariant(element);
83
+ invariant(elementHandle);
84
+ const dispose = draggable({
85
+ element,
86
+ dragHandle: elementHandle,
87
+ getInitialData() {
88
+ return {
89
+ id: props.row.original.id,
90
+ ind: props.row.index,
91
+ collectionId: props.row.original.collectionId,
92
+ };
93
+ },
94
+ onDragStart() {
95
+ setDragging("dragging");
96
+ },
97
+ onDrop() {
98
+ setDragging("idle");
99
+ },
100
+ });
101
+ onCleanup(dispose);
102
+ });
103
+ return (<tr ref={ref} data-drop-edge={dragging() === "dragging-over" ? (closestEdge() ?? undefined) : undefined} class="row-hover relative" style={{ opacity: dragging() == "dragging" ? 0.2 : 1 }} onClick={() => props.onRowClick(props.row.original)}>
104
+ <Show when={props.row.original.tablePosition !== undefined}>
105
+ <th ref={handleRef} class="cursor-pointer">
106
+ <GripVertical size={iconSize[props.size ?? "md"]}/>
107
+ </th>
108
+ </Show>
109
+ <For each={props.row.getVisibleCells()}>
110
+ {(cell) => <td>{flexRender(cell.column.columnDef.cell, cell.getContext())}</td>}
111
+ </For>
112
+ </tr>);
113
+ };
114
+ export const Table = (props) => {
115
+ const table = createSolidTable({
116
+ get data() {
117
+ return props.data || [];
118
+ },
119
+ columns: props.columns(),
120
+ getCoreRowModel: getCoreRowModel(),
121
+ });
122
+ const rowCount = createMemo(() => table.getRowModel().rows.length);
123
+ const rows = createMemo(() => table.getRowModel().rows);
124
+ const dragEnabled = createMemo(() => {
125
+ return props.data.length > 0 && "tablePosition" in props.data[0];
126
+ });
127
+ const [flashedRowId, setFlashedRowId] = createSignal(null);
128
+ createEffect(() => {
129
+ if (!rows().length || !dragEnabled())
130
+ return;
131
+ const dispose = monitorForElements({
132
+ canMonitor({ source }) {
133
+ return source.data.collectionId == props.data[0].collectionId;
134
+ },
135
+ onDrop({ location, source }) {
136
+ const target = location.current.dropTargets[0];
137
+ if (!target) {
138
+ return;
139
+ }
140
+ const sourceData = source.data;
141
+ const targetData = target.data;
142
+ if (sourceData.collectionId !== targetData.collectionId) {
143
+ return;
144
+ }
145
+ if (sourceData.ind < 0 || targetData.ind < 0) {
146
+ return;
147
+ }
148
+ const closestEdgeOfTarget = extractClosestEdge(targetData);
149
+ let newInd = closestEdgeOfTarget === "top" ? targetData.ind : targetData.ind + 1;
150
+ if (newInd > sourceData.ind) {
151
+ newInd--;
152
+ }
153
+ if (sourceData.ind !== newInd) {
154
+ setFlashedRowId(sourceData.id);
155
+ setTimeout(() => setFlashedRowId(null), 10);
156
+ }
157
+ props.onReorderRow?.(props.data[sourceData.ind], sourceData.ind, newInd);
158
+ },
159
+ });
160
+ onCleanup(dispose);
161
+ });
162
+ return (<div class="overflow-x-auto">
163
+ <Show when={!props.loading} fallback={props.loadingFallback || (<div class="fixed inset-0 z-10 flex items-center justify-center">
164
+ <Loader class="w-9 h-9 animate-spin"/>
165
+ </div>)}>
166
+ <Show when={rowCount() > 0} fallback={props.emptyState || <div class="text-center py-4">No results found.</div>}>
167
+ <table class={tableClass({ class: props.class })}>
168
+ <Show when={props.headers}>
169
+ <thead>
170
+ <For each={table.getHeaderGroups()}>
171
+ {(headerGroup) => (<tr>
172
+ <Show when={dragEnabled()}>
173
+ <th></th>
174
+ </Show>
175
+ <For each={headerGroup.headers}>
176
+ {(header) => (<th>{flexRender(header.column.columnDef.header, header.getContext())}</th>)}
177
+ </For>
178
+ </tr>)}
179
+ </For>
180
+ </thead>
181
+ </Show>
182
+
183
+ <tbody>
184
+ <For each={rows()}>
185
+ {(row, ind) => (<TableRow row={row} ind={ind()} onRowClick={() => props.onRowClick(row.original)} dragEnabled={dragEnabled} flashSignal={() => flashedRowId()}/>)}
186
+ </For>
187
+ </tbody>
188
+ </table>
189
+ </Show>
190
+ </Show>
191
+ </div>);
192
+ };
193
+ export default Table;
@@ -0,0 +1 @@
1
+ export * from "./Table";
@@ -0,0 +1 @@
1
+ export * from "./Table";
@@ -1,3 +1,27 @@
1
1
  import { ParentComponent } from "solid-js";
2
- export declare const Tabs: ParentComponent;
2
+ export interface TabsProps {
3
+ defaultTab?: string;
4
+ size?: "xs" | "sm" | "md" | "lg" | "xl";
5
+ }
6
+ export interface TabsComponents {
7
+ Trigger: ParentComponent<{
8
+ value: string;
9
+ }>;
10
+ Content: ParentComponent<{
11
+ value: string;
12
+ }>;
13
+ List: ParentComponent<{
14
+ size?: "xs" | "sm" | "md" | "lg" | "xl";
15
+ }>;
16
+ }
17
+ export declare const Tabs: ParentComponent<TabsProps> & TabsComponents;
18
+ export declare const TabList: ParentComponent<{
19
+ size?: "xs" | "sm" | "md" | "lg" | "xl";
20
+ }>;
21
+ export declare const TabTrigger: ParentComponent<{
22
+ value: string;
23
+ }>;
24
+ export declare const TabContent: ParentComponent<{
25
+ value: string;
26
+ }>;
3
27
  export default Tabs;
@@ -1,4 +1,45 @@
1
+ import { Tabs as KTabs } from "@kobalte/core/tabs";
2
+ import { tv } from "tailwind-variants";
3
+ const tabs = tv({
4
+ base: "tabs tabs-box",
5
+ variants: {
6
+ size: {
7
+ xs: "tabs-xs",
8
+ sm: "tabs-sm",
9
+ md: "tabs-base",
10
+ lg: "tabs-lg",
11
+ xl: "tabs-xl",
12
+ },
13
+ },
14
+ defaultVariants: {
15
+ size: "sm",
16
+ },
17
+ });
18
+ const tab = tv({
19
+ base: "tab tab-lifted",
20
+ });
21
+ const tabContent = tv({
22
+ base: "card bg-base-100 border-base-300 p-3 w-full",
23
+ });
1
24
  export const Tabs = (props) => {
2
- return <div>{props.children}</div>;
25
+ return (<KTabs class={tabs({ size: props.size })} defaultValue={props.defaultTab}>
26
+ {props.children}
27
+ </KTabs>);
3
28
  };
29
+ export const TabList = (props) => {
30
+ return <KTabs.List class={tabs({ size: props.size })}>{props.children}</KTabs.List>;
31
+ };
32
+ export const TabTrigger = (props) => {
33
+ return (<KTabs.Trigger value={props.value} as={"a"} class={tab()}>
34
+ {props.children}
35
+ </KTabs.Trigger>);
36
+ };
37
+ export const TabContent = (props) => {
38
+ return (<KTabs.Content class={tabContent()} value={props.value}>
39
+ {props.children}
40
+ </KTabs.Content>);
41
+ };
42
+ Tabs.Trigger = TabTrigger;
43
+ Tabs.Content = TabContent;
44
+ Tabs.List = TabList;
4
45
  export default Tabs;
@@ -0,0 +1,9 @@
1
+ import { Accessor } from "solid-js";
2
+ type ModalContextType = {
3
+ id: string;
4
+ title?: string;
5
+ open: Accessor<boolean>;
6
+ setOpen: (v: boolean) => void;
7
+ };
8
+ export declare const ModalContext: import("solid-js").Context<ModalContextType | undefined>;
9
+ export {};
@@ -0,0 +1,2 @@
1
+ import { createContext } from "solid-js";
2
+ export const ModalContext = createContext();
@@ -1,10 +1,12 @@
1
1
  import { Component } from "solid-js";
2
- interface Props {
3
- onClick: () => void;
2
+ export interface TagProps {
4
3
  title: string;
5
- colorHex: string;
6
- size?: "xs" | "s" | "m";
4
+ colorHex?: string;
5
+ onDelete?: () => void;
6
+ variant?: "ghost" | "outline" | "dash" | "soft";
7
+ appearance?: "neutral" | "primary" | "secondary" | "accent" | "info" | "success" | "warning" | "error";
8
+ size?: "xs" | "sm" | "md" | "lg" | "xl";
7
9
  class?: string;
8
10
  }
9
- export declare const Tag: Component<Props>;
11
+ export declare const Tag: Component<TagProps>;
10
12
  export default Tag;
@@ -1,30 +1,56 @@
1
- import { createMemo } from "solid-js";
2
1
  import { Button as KobalteButton } from "@kobalte/core/button";
3
2
  import CloseIcon from "lucide-solid/icons/x";
4
3
  import { tv } from "tailwind-variants";
5
4
  const tag = tv({
6
- base: "flex items-center rounded-full select-none border-1 font-bold",
5
+ base: "badge rounded-full",
7
6
  variants: {
8
7
  size: {
9
- m: "text-sm px-2 py-1",
10
- s: "text-sm pl-1.5 pr-1 py-0.5",
11
- xs: "text-xs px-1",
8
+ xs: "badge-xs",
9
+ sm: "badge-sm",
10
+ md: "badge-md",
11
+ lg: "badge-lg",
12
+ xl: "badge-xl",
13
+ },
14
+ appearance: {
15
+ neutral: "badge-neutral",
16
+ primary: "badge-primary",
17
+ secondary: "badge-secondary",
18
+ accent: "badge-accent",
19
+ info: "badge-info",
20
+ success: "badge-success",
21
+ warning: "badge-warning",
22
+ error: "badge-error",
23
+ },
24
+ variant: {
25
+ ghost: "badge-ghost",
26
+ outline: "badge-outline",
27
+ dash: "badge-dash",
28
+ soft: "badge-soft",
29
+ none: "",
12
30
  },
13
31
  },
14
32
  defaultVariants: {
15
- size: "m",
33
+ size: "sm",
16
34
  },
17
35
  });
18
36
  export const Tag = (props) => {
19
- const classes = createMemo(() => tag({
20
- size: props.size,
21
- class: props.class,
22
- }));
23
- return (<div style={{ "background-color": `${props.colorHex}30`, color: `${props.colorHex}` }} class={classes()}>
37
+ const style = props.colorHex
38
+ ? {
39
+ "background-color": `${props.colorHex}40`,
40
+ color: `${props.colorHex}`,
41
+ "border-color": `${props.colorHex}`,
42
+ }
43
+ : {};
44
+ return (<div style={style} class={tag({
45
+ size: props.size,
46
+ class: props.class,
47
+ appearance: props.appearance,
48
+ variant: props.variant,
49
+ })}>
24
50
  <span>{props.title}</span>
25
- <KobalteButton onClick={props.onClick} class="pl-1 flex items-center justify-center">
26
- <CloseIcon size={14}/>
27
- </KobalteButton>
51
+ {props.onDelete && (<KobalteButton onClick={props.onDelete}>
52
+ <CloseIcon class="w-[1em] h-[1em]" stroke-width={4}/>
53
+ </KobalteButton>)}
28
54
  </div>);
29
55
  };
30
56
  export default Tag;
@@ -1,11 +1,15 @@
1
- import { JSX } from "solid-js";
2
- interface TagAreaProps<T extends TagRecord = TagRecord> {
1
+ import { JSX, JSXElement } from "solid-js";
2
+ interface TagAreaProps<T extends Tag = Tag> {
3
3
  tags: T[];
4
4
  setTags: (tags: T[]) => void;
5
- onCreateTag: (name: string) => Promise<T>;
5
+ onCreateTag: (name: string) => Promise<T | undefined>;
6
6
  onDeleteTag: (tag: T) => Promise<void>;
7
7
  suggestions?: T[];
8
+ noSuggestionsPlaceholder?: string;
9
+ dropDownAction?: JSXElement;
8
10
  placeholder?: string;
11
+ editable?: boolean;
12
+ size?: "xs" | "sm" | "md" | "lg" | "xl";
9
13
  }
10
- export declare const TagArea: <T extends TagRecord = TagRecord>(props: TagAreaProps<T>) => JSX.Element;
14
+ export declare const TagArea: <T extends Tag = Tag>(props: TagAreaProps<T>) => JSX.Element;
11
15
  export default TagArea;
@@ -1,25 +1,65 @@
1
1
  import { createSignal, For, Show, createMemo } from "solid-js";
2
- import { Input } from "../Input";
2
+ import { TextField } from "@kobalte/core/text-field";
3
3
  import Tag from "../Tag/Tag";
4
+ import { tv } from "tailwind-variants";
5
+ const tagArea = tv({
6
+ base: "textarea outline-offset-0 p-2 min-h-2",
7
+ variants: {
8
+ editing: {
9
+ true: "",
10
+ false: "cursor-pointer",
11
+ },
12
+ },
13
+ });
14
+ const menu = tv({
15
+ base: "dropdown-content bg-base-200 min-w-30 shadow-sm rounded-box menu absolute border border-base-200 gap-1",
16
+ variants: {
17
+ size: {
18
+ xs: "menu-xs",
19
+ sm: "menu-sm",
20
+ md: "menu-base",
21
+ lg: "menu-lg",
22
+ xl: "menu-xl",
23
+ },
24
+ },
25
+ defaultVariants: {
26
+ size: "sm",
27
+ },
28
+ });
4
29
  export const TagArea = (props) => {
5
30
  const [tagInput, setTagInput] = createSignal("");
6
31
  const [showSuggestions, setShowSuggestions] = createSignal(false);
32
+ const [editing, setEditing] = createSignal(false);
33
+ let inputRef;
7
34
  const filteredSuggestions = createMemo(() => (props.suggestions || []).filter((s) => s.name.toLowerCase().includes(tagInput().toLowerCase()) && !props.tags.some((t) => t.id === s.id)));
8
35
  const handleTagInput = async (e) => {
9
- if (e.key === "Enter" && tagInput().trim()) {
10
- e.preventDefault();
11
- const newTagName = tagInput().trim();
12
- if (!props.tags.map((t) => t.name).includes(newTagName)) {
13
- let newTag = undefined;
14
- newTag = await props.onCreateTag(newTagName);
15
- if (newTag)
16
- props.setTags([...props.tags, newTag]);
36
+ setShowSuggestions(true);
37
+ if (tagInput().trim()) {
38
+ if (e.key === "Enter") {
39
+ e.preventDefault();
40
+ e.stopPropagation();
41
+ const newTagName = tagInput().trim();
42
+ if (!props.tags.map((t) => t.name).includes(newTagName)) {
43
+ let newTag = undefined;
44
+ newTag = await props.onCreateTag(newTagName);
45
+ if (newTag)
46
+ props.setTags([...props.tags, newTag]);
47
+ }
48
+ setTagInput("");
49
+ setShowSuggestions(false);
50
+ }
51
+ else {
52
+ setShowSuggestions(true);
17
53
  }
18
- setTagInput("");
19
- setShowSuggestions(false);
20
54
  }
21
55
  else {
22
- setShowSuggestions(true);
56
+ if (e.key === "Delete" || e.key === "Backspace") {
57
+ if (props.tags.length > 0) {
58
+ const lastTag = props.tags[props.tags.length - 1];
59
+ await props.onDeleteTag(lastTag);
60
+ props.setTags(props.tags.slice(0, -1));
61
+ }
62
+ }
23
63
  }
24
64
  };
25
65
  const handleSuggestionClick = (tag) => {
@@ -31,31 +71,45 @@ export const TagArea = (props) => {
31
71
  await props.onDeleteTag(t);
32
72
  props.setTags((props.tags || []).filter((tag) => tag.id !== t.id));
33
73
  };
34
- return (<div class="rounded-md p-2 flex flex-col bg-[var(--color-light-surface)] dark:bg-[var(--color-dark-surface)]">
35
- <div class="flex flex-wrap gap-2">
74
+ return (<div class={tagArea({ editing: editing() })} onMouseDown={(e) => {
75
+ if (props.editable === false)
76
+ return;
77
+ e.preventDefault();
78
+ setEditing(true);
79
+ inputRef?.focus();
80
+ }}>
81
+ <div class="flex flex-wrap gap-1">
36
82
  <For each={props.tags || []}>
37
- {(t) => (<Tag title={t.name || ""} colorHex={t.colorHex || "#6b7280"} onClick={() => deleteTag(t)}/>)}
83
+ {(t) => (<Tag title={t.name || ""} colorHex={t.colorHex || "#6b7280"} onDelete={editing()
84
+ ? () => {
85
+ setShowSuggestions(false);
86
+ deleteTag(t);
87
+ }
88
+ : undefined} size={props.size}/>)}
38
89
  </For>
39
- <div class="relative flex-1 min-w-[120px]">
40
- <Input label="" value={tagInput()} onChange={(v) => {
41
- setTagInput(v);
42
- setShowSuggestions(true);
43
- }} inputProps={{
44
- onKeyDown: handleTagInput,
45
- placeholder: props.placeholder || "Add tags (press Enter)",
46
- onFocus: () => setShowSuggestions(true),
47
- onBlur: () => setTimeout(() => setShowSuggestions(false), 100),
48
- }} class="w-full"/>
49
- <Show when={showSuggestions() && filteredSuggestions().length > 0}>
50
- <div class="absolute z-10 mt-1 w-full bg-[var(--color-light-surface)] dark:bg-[var(--color-dark-surface)] border border-[var(--color-light-muted)] dark:border-[var(--color-dark-muted)] rounded shadow-lg max-h-40 overflow-auto">
51
- <For each={filteredSuggestions()}>
52
- {(s) => (<div class="px-3 py-2 cursor-pointer hover:bg-[var(--color-light-muted)] dark:hover:bg-[var(--color-dark-muted)]" onMouseDown={() => handleSuggestionClick(s)}>
53
- {s.name}
54
- </div>)}
55
- </For>
56
- </div>
57
- </Show>
58
- </div>
90
+ {editing() && props.editable !== false && (<div class="relative flex-1 min-w-30">
91
+ <TextField value={tagInput()} onChange={setTagInput}>
92
+ <TextField.Input ref={inputRef} onKeyDown={handleTagInput} placeholder={props.placeholder || ""} onBlur={() => {
93
+ setEditing(false);
94
+ setShowSuggestions(false);
95
+ setTagInput("");
96
+ }} class="w-full focus:outline-none"/>
97
+ </TextField>
98
+ <Show when={showSuggestions()}>
99
+ <div class={menu({ size: props.size })}>
100
+ <Show when={filteredSuggestions().length > 0} fallback={<p class="italic text-xs">{props.noSuggestionsPlaceholder ?? "No matches found"}</p>}>
101
+ <ul>
102
+ <For each={filteredSuggestions()}>
103
+ {(s) => (<li class="cursor-pointer rounded" onMouseDown={() => handleSuggestionClick(s)}>
104
+ <a>{s.name}</a>
105
+ </li>)}
106
+ </For>
107
+ </ul>
108
+ </Show>
109
+ <Show when={props.dropDownAction}>{props.dropDownAction}</Show>
110
+ </div>
111
+ </Show>
112
+ </div>)}
59
113
  </div>
60
114
  </div>);
61
115
  };
@@ -1,14 +1,15 @@
1
1
  import { Component, ValidComponent } from "solid-js";
2
- import { type TextFieldInputProps, type TextFieldRootProps } from "@kobalte/core/text-field";
2
+ import { type TextFieldTextAreaProps, type TextFieldRootProps } from "@kobalte/core/text-field";
3
3
  import type { PolymorphicProps } from "@kobalte/core";
4
- type InputProps<T extends ValidComponent = "textarea"> = PolymorphicProps<T, TextFieldInputProps<T>>;
5
- interface ExtraProps {
4
+ export type TextAreaProps<T extends ValidComponent = "textarea"> = PolymorphicProps<T, TextFieldTextAreaProps<T>>;
5
+ export interface TextAreaExtraProps {
6
6
  label?: string;
7
7
  saveFunc?: (v: string) => Promise<any>;
8
- inputProps?: InputProps;
9
- variant?: "bordered" | "none";
10
- size?: "sm" | "md";
8
+ textareaProps?: TextAreaProps;
9
+ variant?: "ghost";
10
+ size?: "xs" | "sm" | "md" | "lg" | "xl";
11
+ appearance?: "primary" | "secondary" | "success" | "warning" | "neutral" | "error" | "accent" | "info";
11
12
  }
12
- type InputRootProps<T extends ValidComponent = "div"> = ExtraProps & PolymorphicProps<T, TextFieldRootProps<T>>;
13
- export declare const TextArea: Component<InputRootProps>;
13
+ export type TextAreaRootProps<T extends ValidComponent = "div"> = TextAreaExtraProps & PolymorphicProps<T, TextFieldRootProps<T>>;
14
+ export declare const TextArea: Component<TextAreaRootProps>;
14
15
  export default TextArea;