@solidpb/ui-kit 0.4.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/RelationPicker.d.ts +3 -2
- package/dist/components/RelationPicker.jsx +18 -3
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/package.json +1 -1
- package/dist/components/TagArea/TagArea.d.ts +0 -15
- package/dist/components/TagArea/TagArea.jsx +0 -116
- package/dist/components/TagArea/index.d.ts +0 -1
- package/dist/components/TagArea/index.js +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { JSXElement } from "solid-js";
|
|
1
|
+
import { JSX, JSXElement } from "solid-js";
|
|
2
2
|
export interface RelationPickerProps<T> {
|
|
3
3
|
value: T | T[] | null;
|
|
4
4
|
options: T[];
|
|
@@ -19,6 +19,7 @@ export interface RelationPickerProps<T> {
|
|
|
19
19
|
defaultFilter?: (option: T[] | Exclude<NonNullable<T>, null>, filter: string) => boolean;
|
|
20
20
|
onLinkClick?: (value: T) => void;
|
|
21
21
|
href?: string;
|
|
22
|
+
onCreateInline?: (text: string) => Promise<T | undefined>;
|
|
22
23
|
}
|
|
23
|
-
export declare const RelationPicker: <T>(props: RelationPickerProps<T>) =>
|
|
24
|
+
export declare const RelationPicker: <T extends object>(props: RelationPickerProps<T>) => JSX.Element;
|
|
24
25
|
export default RelationPicker;
|
|
@@ -72,6 +72,21 @@ export const RelationPicker = (props) => {
|
|
|
72
72
|
];
|
|
73
73
|
return props.options;
|
|
74
74
|
};
|
|
75
|
+
const handleKeyDown = async (e) => {
|
|
76
|
+
if (e.key === "Enter" && props.onCreateInline) {
|
|
77
|
+
e.preventDefault();
|
|
78
|
+
e.stopPropagation();
|
|
79
|
+
const newValue = await props.onCreateInline(inputRef.value);
|
|
80
|
+
if (newValue) {
|
|
81
|
+
if (props.multi) {
|
|
82
|
+
props.onChange([...(Array.isArray(props.value) ? props.value : []), newValue]);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
props.onChange(newValue);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
};
|
|
75
90
|
return (<div class="floating-label">
|
|
76
91
|
{props.label && <span>{props.label}</span>}
|
|
77
92
|
<Combobox disabled={props.disabled} multiple={props.multi} value={values()} onChange={props.onChange} options={options()}
|
|
@@ -113,15 +128,15 @@ export const RelationPicker = (props) => {
|
|
|
113
128
|
else {
|
|
114
129
|
e.currentTarget.value = String(state.selectedOptions()[0][props.labelKey]);
|
|
115
130
|
}
|
|
116
|
-
}} ref={inputRef} onInput={(e) => props.onTextInputChange?.(e.currentTarget.value)}/>
|
|
131
|
+
}} ref={inputRef} onInput={(e) => props.onTextInputChange?.(e.currentTarget.value)} onKeyDown={handleKeyDown}/>
|
|
117
132
|
</>}>
|
|
118
133
|
<div class="flex flex-wrap gap-1 w-full">
|
|
119
134
|
<For each={state.selectedOptions()}>
|
|
120
135
|
{(option) => (<span onPointerDown={(e) => e.stopPropagation()}>
|
|
121
|
-
<Tag appearance="neutral" variant="soft" title={String(option[props.labelKey])} onDelete={() => state.remove(option)}/>
|
|
136
|
+
<Tag appearance="neutral" variant="soft" title={String(option[props.labelKey])} onDelete={() => state.remove(option)} colorHex={"colorHex" in option ? option.colorHex : undefined}/>
|
|
122
137
|
</span>)}
|
|
123
138
|
</For>
|
|
124
|
-
<Combobox.Input class="w-[unset]" onBlur={(e) => (e.currentTarget.value = "")} ref={inputRef} onInput={(e) => props.onTextInputChange?.(e.currentTarget.value)}/>
|
|
139
|
+
<Combobox.Input class="w-[unset]" onBlur={(e) => (e.currentTarget.value = "")} ref={inputRef} onInput={(e) => props.onTextInputChange?.(e.currentTarget.value)} onKeyDown={handleKeyDown}/>
|
|
125
140
|
</div>
|
|
126
141
|
</Show>
|
|
127
142
|
</div>
|
package/dist/index.d.ts
CHANGED
|
@@ -28,7 +28,6 @@ export * from "./components/Switch";
|
|
|
28
28
|
export * from "./components/Table";
|
|
29
29
|
export * from "./components/Tabs";
|
|
30
30
|
export * from "./components/Tag";
|
|
31
|
-
export * from "./components/TagArea";
|
|
32
31
|
export * from "./components/TextArea";
|
|
33
32
|
export * from "./components/ThemeSwitch";
|
|
34
33
|
export * from "./components/Toast";
|
package/dist/index.js
CHANGED
|
@@ -28,7 +28,6 @@ export * from "./components/Switch";
|
|
|
28
28
|
export * from "./components/Table";
|
|
29
29
|
export * from "./components/Tabs";
|
|
30
30
|
export * from "./components/Tag";
|
|
31
|
-
export * from "./components/TagArea";
|
|
32
31
|
export * from "./components/TextArea";
|
|
33
32
|
export * from "./components/ThemeSwitch";
|
|
34
33
|
export * from "./components/Toast";
|
package/package.json
CHANGED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { JSX, JSXElement } from "solid-js";
|
|
2
|
-
interface TagAreaProps<T extends Tag = Tag> {
|
|
3
|
-
tags: T[];
|
|
4
|
-
setTags: (tags: T[]) => void;
|
|
5
|
-
onCreateTag: (name: string) => Promise<T | undefined>;
|
|
6
|
-
onDeleteTag: (tag: T) => Promise<void>;
|
|
7
|
-
suggestions?: T[];
|
|
8
|
-
noSuggestionsPlaceholder?: string;
|
|
9
|
-
dropDownAction?: JSXElement;
|
|
10
|
-
placeholder?: string;
|
|
11
|
-
editable?: boolean;
|
|
12
|
-
size?: "xs" | "sm" | "md" | "lg" | "xl";
|
|
13
|
-
}
|
|
14
|
-
export declare const TagArea: <T extends Tag = Tag>(props: TagAreaProps<T>) => JSX.Element;
|
|
15
|
-
export default TagArea;
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { createSignal, For, Show, createMemo } from "solid-js";
|
|
2
|
-
import { TextField } from "@kobalte/core/text-field";
|
|
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
|
-
});
|
|
29
|
-
export const TagArea = (props) => {
|
|
30
|
-
const [tagInput, setTagInput] = createSignal("");
|
|
31
|
-
const [showSuggestions, setShowSuggestions] = createSignal(false);
|
|
32
|
-
const [editing, setEditing] = createSignal(false);
|
|
33
|
-
let inputRef;
|
|
34
|
-
const filteredSuggestions = createMemo(() => (props.suggestions || []).filter((s) => s.name.toLowerCase().includes(tagInput().toLowerCase()) && !props.tags.some((t) => t.id === s.id)));
|
|
35
|
-
const handleTagInput = async (e) => {
|
|
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);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
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
|
-
}
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
const handleSuggestionClick = (tag) => {
|
|
66
|
-
props.setTags([...props.tags, tag]);
|
|
67
|
-
setTagInput("");
|
|
68
|
-
setShowSuggestions(false);
|
|
69
|
-
};
|
|
70
|
-
const deleteTag = async (t) => {
|
|
71
|
-
await props.onDeleteTag(t);
|
|
72
|
-
props.setTags((props.tags || []).filter((tag) => tag.id !== t.id));
|
|
73
|
-
};
|
|
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">
|
|
82
|
-
<For each={props.tags || []}>
|
|
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}/>)}
|
|
89
|
-
</For>
|
|
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>)}
|
|
113
|
-
</div>
|
|
114
|
-
</div>);
|
|
115
|
-
};
|
|
116
|
-
export default TagArea;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./TagArea";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./TagArea";
|