@tipp/ui 1.4.19 → 1.4.21

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.
@@ -0,0 +1,357 @@
1
+ import {
2
+ ScrollArea
3
+ } from "./chunk-ZKZDVS7G.js";
4
+ import {
5
+ Popover
6
+ } from "./chunk-5AVBYDPB.js";
7
+ import {
8
+ Typo
9
+ } from "./chunk-52MVZ6AN.js";
10
+ import {
11
+ Flex
12
+ } from "./chunk-25HMMI7R.js";
13
+ import {
14
+ Grid
15
+ } from "./chunk-EGEQY3KT.js";
16
+ import {
17
+ Badge
18
+ } from "./chunk-EWD4AO5N.js";
19
+ import {
20
+ Button
21
+ } from "./chunk-U7JPP7WJ.js";
22
+ import {
23
+ CheckIcon
24
+ } from "./chunk-F77ES5Y3.js";
25
+ import {
26
+ AutoSizingInput
27
+ } from "./chunk-YJCCE5WP.js";
28
+
29
+ // src/molecules/tag-selector.tsx
30
+ import {
31
+ useCallback,
32
+ useEffect,
33
+ useMemo,
34
+ useRef,
35
+ useState
36
+ } from "react";
37
+ import {
38
+ ChevronRightIcon,
39
+ Cross1Icon,
40
+ MagnifyingGlassIcon
41
+ } from "@radix-ui/react-icons";
42
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
43
+ var OPTION_HEIGHT = 32;
44
+ var DefaultDropdownContainer = (props) => {
45
+ return props.children;
46
+ };
47
+ function TagSelector(props) {
48
+ const {
49
+ options = [],
50
+ tagRender,
51
+ placeholder,
52
+ maxCount = 0,
53
+ DropdownContainer = DefaultDropdownContainer,
54
+ onChange,
55
+ size = "medium",
56
+ readOnly
57
+ } = props;
58
+ const [selected, setSelected] = useState(props.selected || []);
59
+ const [value, setValue] = useState("");
60
+ const [focusIndex, setFocusIndex] = useState(null);
61
+ const [open, setOpen] = useState(false);
62
+ const [focus, setFocus] = useState(false);
63
+ const isInit = useRef(true);
64
+ const fieldRef = useRef(null);
65
+ const scrollRef = useRef(null);
66
+ const closeRef = useRef();
67
+ const onFocus = useCallback(() => {
68
+ clearTimeout(closeRef.current);
69
+ setFocus(true);
70
+ setOpen(true);
71
+ }, []);
72
+ const onBlur = useCallback(() => {
73
+ closeRef.current = setTimeout(() => {
74
+ setFocus(false);
75
+ setOpen(false);
76
+ setTimeout(() => {
77
+ setValue("");
78
+ }, 100);
79
+ }, 300);
80
+ }, []);
81
+ const onChangeValue = useCallback(
82
+ (e) => {
83
+ setValue(e.target.value);
84
+ },
85
+ []
86
+ );
87
+ const filteredOptions = useMemo(() => {
88
+ return options.filter((option) => {
89
+ return option.name.includes(value);
90
+ });
91
+ }, [options, value]);
92
+ const selectedItem = useMemo(() => {
93
+ const result = [];
94
+ selected.forEach((id) => {
95
+ const maybeItem = options.find((option) => option.id === id);
96
+ if (maybeItem)
97
+ result.push(maybeItem);
98
+ });
99
+ return result;
100
+ }, [options, selected]);
101
+ const onDelete = useCallback((id) => {
102
+ setSelected((prev) => prev.filter((el) => el !== id));
103
+ }, []);
104
+ const onSelect = useCallback(
105
+ (id) => {
106
+ if (maxCount && selected.length + 1 > maxCount)
107
+ return;
108
+ setSelected((prev) => [...prev, id]);
109
+ },
110
+ [maxCount, selected]
111
+ );
112
+ const toggleItem = useCallback(
113
+ (id) => {
114
+ if (selected.includes(id)) {
115
+ onDelete(id);
116
+ } else {
117
+ onSelect(id);
118
+ }
119
+ },
120
+ [onDelete, onSelect, selected]
121
+ );
122
+ const setScroll = useCallback((index) => {
123
+ if (scrollRef.current) {
124
+ const scrollTop = scrollRef.current.scrollTop;
125
+ const clientHeight = scrollRef.current.clientHeight;
126
+ const focusTop = index * OPTION_HEIGHT;
127
+ if (focusTop < scrollTop) {
128
+ scrollRef.current.scrollTop = focusTop;
129
+ } else if (focusTop + OPTION_HEIGHT > scrollTop + clientHeight) {
130
+ scrollRef.current.scrollTop = focusTop + OPTION_HEIGHT - clientHeight;
131
+ }
132
+ }
133
+ }, []);
134
+ const handleKeyDown = useCallback(
135
+ (e) => {
136
+ var _a;
137
+ const key = e.key;
138
+ switch (key) {
139
+ case "ArrowDown": {
140
+ e.preventDefault();
141
+ let newFocus = 0;
142
+ if (typeof focusIndex === "number") {
143
+ newFocus = focusIndex + 1 >= options.length ? 0 : focusIndex + 1;
144
+ }
145
+ setFocusIndex(newFocus);
146
+ setScroll(newFocus);
147
+ break;
148
+ }
149
+ case "ArrowUp": {
150
+ e.preventDefault();
151
+ let newFocus = 0;
152
+ if (typeof focusIndex === "number") {
153
+ newFocus = focusIndex - 1 < 0 ? options.length - 1 : focusIndex - 1;
154
+ }
155
+ setFocusIndex(newFocus);
156
+ setScroll(newFocus);
157
+ break;
158
+ }
159
+ case "Enter":
160
+ setValue("");
161
+ if (focusIndex !== null) {
162
+ toggleItem((_a = filteredOptions[focusIndex]) == null ? void 0 : _a.id);
163
+ }
164
+ break;
165
+ case "Backspace":
166
+ if (value.length === 0) {
167
+ setSelected((prev) => prev.slice(0, -1));
168
+ }
169
+ break;
170
+ case "Escape":
171
+ setOpen(false);
172
+ break;
173
+ }
174
+ },
175
+ [
176
+ focusIndex,
177
+ value.length,
178
+ setScroll,
179
+ options.length,
180
+ toggleItem,
181
+ filteredOptions
182
+ ]
183
+ );
184
+ const placeholderVisible = useMemo(() => {
185
+ if (selectedItem.length)
186
+ return false;
187
+ if (value)
188
+ return false;
189
+ if (focus)
190
+ return false;
191
+ return true;
192
+ }, [focus, selectedItem.length, value]);
193
+ useEffect(() => {
194
+ if (isInit.current) {
195
+ return;
196
+ }
197
+ onChange == null ? void 0 : onChange(selected);
198
+ }, [[...selected].sort().join(",")]);
199
+ useEffect(() => {
200
+ if (isInit.current) {
201
+ return;
202
+ }
203
+ setSelected(props.selected || []);
204
+ }, [[...props.selected || []].sort().join(",")]);
205
+ useEffect(() => {
206
+ setFocusIndex(null);
207
+ }, [open]);
208
+ useEffect(() => {
209
+ setFocusIndex(0);
210
+ }, [filteredOptions]);
211
+ useEffect(() => {
212
+ isInit.current = false;
213
+ }, []);
214
+ const badgeSize = useMemo(() => {
215
+ switch (size) {
216
+ case "large":
217
+ return "large";
218
+ case "medium":
219
+ case "small":
220
+ default:
221
+ return "small";
222
+ }
223
+ }, [size]);
224
+ const placeholderVariant = useMemo(() => {
225
+ switch (size) {
226
+ case "large":
227
+ return "subtitle";
228
+ case "medium":
229
+ default:
230
+ return "body";
231
+ }
232
+ }, [size]);
233
+ const focusClassName = focus ? " focused" : "";
234
+ const readOnlyClassName = readOnly ? " read-only" : "";
235
+ const readonlyContent = /* @__PURE__ */ jsx(Flex, { gap: "1", children: selectedItem.map((item) => {
236
+ return tagRender ? tagRender(item) : /* @__PURE__ */ jsx(Badge, { size: badgeSize, children: item.name }, item.id);
237
+ }) });
238
+ const editContent = /* @__PURE__ */ jsxs(Fragment, { children: [
239
+ /* @__PURE__ */ jsxs(
240
+ Flex,
241
+ {
242
+ align: "center",
243
+ gap: "1",
244
+ maxWidth: "100%",
245
+ overflow: "hidden",
246
+ wrap: "wrap",
247
+ children: [
248
+ selectedItem.map((item) => {
249
+ return tagRender ? tagRender(item) : /* @__PURE__ */ jsxs(Badge, { size: badgeSize, children: [
250
+ item.name,
251
+ /* @__PURE__ */ jsx(
252
+ Button,
253
+ {
254
+ onClick: () => {
255
+ onDelete(item.id);
256
+ },
257
+ variant: "transparent",
258
+ children: /* @__PURE__ */ jsx(Cross1Icon, {})
259
+ }
260
+ )
261
+ ] }, item.id);
262
+ }),
263
+ placeholderVisible ? /* @__PURE__ */ jsx(Typo, { color: "gray", variant: placeholderVariant, children: placeholder }) : null,
264
+ /* @__PURE__ */ jsx(
265
+ AutoSizingInput,
266
+ {
267
+ onBlur,
268
+ onChange: onChangeValue,
269
+ onFocus,
270
+ onKeyDown: handleKeyDown,
271
+ ref: fieldRef,
272
+ value
273
+ }
274
+ )
275
+ ]
276
+ }
277
+ ),
278
+ focus ? /* @__PURE__ */ jsx(MagnifyingGlassIcon, {}) : /* @__PURE__ */ jsx(ChevronRightIcon, {})
279
+ ] });
280
+ return /* @__PURE__ */ jsxs(Popover.Root, { open: Boolean(filteredOptions.length) && open, children: [
281
+ /* @__PURE__ */ jsx(Popover.Trigger, { style: { position: "relative" }, children: /* @__PURE__ */ jsx(
282
+ Grid,
283
+ {
284
+ align: "center",
285
+ className: `tag-selector ${size} ${focusClassName}${readOnlyClassName}`,
286
+ columns: "1fr auto",
287
+ gap: "1",
288
+ onClick: () => {
289
+ var _a;
290
+ return !readOnly && ((_a = fieldRef.current) == null ? void 0 : _a.focus());
291
+ },
292
+ children: readOnly ? readonlyContent : editContent
293
+ }
294
+ ) }),
295
+ /* @__PURE__ */ jsx(
296
+ Popover.Content,
297
+ {
298
+ onOpenAutoFocus: (e) => {
299
+ e.preventDefault();
300
+ },
301
+ children: /* @__PURE__ */ jsx(
302
+ DropdownContainer,
303
+ {
304
+ currentItem: filteredOptions[focusIndex || 0],
305
+ items: filteredOptions,
306
+ children: /* @__PURE__ */ jsx(
307
+ ScrollArea,
308
+ {
309
+ ref: scrollRef,
310
+ scrollbars: "vertical",
311
+ style: { height: OPTION_HEIGHT * 8 },
312
+ type: "auto",
313
+ children: /* @__PURE__ */ jsx(Flex, { direction: "column", children: filteredOptions.map((item, i) => {
314
+ const isSelected = Boolean(
315
+ selected.find((el) => el === item.id)
316
+ );
317
+ const isFocus = i === focusIndex;
318
+ return /* @__PURE__ */ jsx(
319
+ Button,
320
+ {
321
+ onClick: () => {
322
+ var _a;
323
+ toggleItem(item.id);
324
+ (_a = fieldRef.current) == null ? void 0 : _a.focus();
325
+ },
326
+ onMouseEnter: () => {
327
+ setFocusIndex(i);
328
+ },
329
+ style: {
330
+ width: "100%",
331
+ background: isFocus ? "var(--accent-a3)" : void 0,
332
+ color: "var(--gray-12)",
333
+ fontWeight: 400,
334
+ boxShadow: "none"
335
+ },
336
+ variant: isSelected ? "soft" : "outline",
337
+ children: /* @__PURE__ */ jsxs(Flex, { justify: "between", width: "100%", children: [
338
+ item.name,
339
+ isSelected ? /* @__PURE__ */ jsx(CheckIcon, {}) : null
340
+ ] })
341
+ },
342
+ item.id
343
+ );
344
+ }) })
345
+ }
346
+ )
347
+ }
348
+ )
349
+ }
350
+ )
351
+ ] });
352
+ }
353
+
354
+ export {
355
+ TagSelector
356
+ };
357
+ //# sourceMappingURL=chunk-ZRCNIT7C.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/molecules/tag-selector.tsx"],"sourcesContent":["import React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n ChevronRightIcon,\n Cross1Icon,\n MagnifyingGlassIcon,\n} from '@radix-ui/react-icons';\nimport { Popover } from '../atoms/popover';\nimport { Flex } from '../atoms/flex';\nimport { Button } from '../atoms/button';\nimport type { BadgeProps } from '../atoms/badge';\nimport { Badge } from '../atoms/badge';\nimport { CheckIcon } from '../icon';\nimport { ScrollArea } from '../atoms/scroll-area';\nimport { Grid } from '../atoms/grid';\nimport type { TypoProps } from '../atoms';\nimport { AutoSizingInput, Typo } from '../atoms';\n\ntype ID = string;\ninterface Item {\n name: string;\n id: ID;\n}\n\nconst OPTION_HEIGHT = 32;\n\nexport interface TagSelectorProps<T extends Item> {\n options?: T[];\n selected?: ID[];\n placeholder?: string;\n disabled?: boolean;\n maxCount?: number;\n style?: React.CSSProperties;\n size?: 'large' | 'medium' | 'small';\n readOnly?: boolean;\n error?: boolean;\n\n onChange?: (selected: ID[]) => void;\n tagRender?: (item: T) => React.ReactElement;\n DropdownContainer?: DropdownContainer<T>;\n}\ntype DropdownContainer<T> = (props: {\n items: T[];\n children: React.ReactElement;\n currentItem?: T;\n}) => React.ReactElement;\n\nconst DefaultDropdownContainer = (props: {\n children: React.ReactElement;\n}): React.ReactElement => {\n return props.children;\n};\n\nexport function TagSelector<T extends Item>(\n props: TagSelectorProps<T>\n): React.ReactElement {\n const {\n options = [],\n tagRender,\n placeholder,\n maxCount = 0,\n DropdownContainer = DefaultDropdownContainer,\n onChange,\n size = 'medium',\n readOnly,\n } = props;\n const [selected, setSelected] = useState<string[]>(props.selected || []);\n const [value, setValue] = useState<string>('');\n const [focusIndex, setFocusIndex] = useState<number | null>(null);\n const [open, setOpen] = useState(false);\n const [focus, setFocus] = useState(false);\n const isInit = useRef(true);\n\n const fieldRef = useRef<HTMLInputElement>(null);\n const scrollRef = useRef<HTMLDivElement>(null);\n\n const closeRef = useRef<ReturnType<typeof setTimeout>>();\n\n const onFocus = useCallback(() => {\n clearTimeout(closeRef.current);\n setFocus(true);\n setOpen(true);\n }, []);\n\n const onBlur = useCallback(() => {\n closeRef.current = setTimeout(() => {\n setFocus(false);\n setOpen(false);\n setTimeout(() => {\n setValue('');\n }, 100);\n }, 300);\n }, []);\n\n const onChangeValue = useCallback<React.ChangeEventHandler<HTMLInputElement>>(\n (e) => {\n setValue(e.target.value);\n },\n []\n );\n\n const filteredOptions = useMemo<T[]>(() => {\n return options.filter((option) => {\n return option.name.includes(value);\n });\n }, [options, value]);\n\n const selectedItem = useMemo<T[]>(() => {\n const result = [] as T[];\n selected.forEach((id) => {\n const maybeItem = options.find((option) => option.id === id);\n if (maybeItem) result.push(maybeItem);\n });\n return result;\n }, [options, selected]);\n\n const onDelete = useCallback((id: string) => {\n setSelected((prev) => prev.filter((el) => el !== id));\n }, []);\n\n const onSelect = useCallback(\n (id: string) => {\n if (maxCount && selected.length + 1 > maxCount) return;\n setSelected((prev) => [...prev, id]);\n },\n [maxCount, selected]\n );\n\n const toggleItem = useCallback(\n (id: string) => {\n if (selected.includes(id)) {\n onDelete(id);\n } else {\n onSelect(id);\n }\n },\n [onDelete, onSelect, selected]\n );\n\n const setScroll = useCallback((index: number): void => {\n if (scrollRef.current) {\n const scrollTop = scrollRef.current.scrollTop;\n const clientHeight = scrollRef.current.clientHeight;\n const focusTop = index * OPTION_HEIGHT;\n if (focusTop < scrollTop) {\n scrollRef.current.scrollTop = focusTop;\n } else if (focusTop + OPTION_HEIGHT > scrollTop + clientHeight) {\n scrollRef.current.scrollTop = focusTop + OPTION_HEIGHT - clientHeight;\n }\n }\n }, []);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n const key = e.key;\n\n switch (key) {\n case 'ArrowDown': {\n e.preventDefault();\n let newFocus = 0;\n if (typeof focusIndex === 'number') {\n newFocus = focusIndex + 1 >= options.length ? 0 : focusIndex + 1;\n }\n setFocusIndex(newFocus);\n setScroll(newFocus);\n break;\n }\n\n case 'ArrowUp': {\n e.preventDefault();\n let newFocus = 0;\n if (typeof focusIndex === 'number') {\n newFocus = focusIndex - 1 < 0 ? options.length - 1 : focusIndex - 1;\n }\n setFocusIndex(newFocus);\n setScroll(newFocus);\n break;\n }\n\n case 'Enter':\n setValue('');\n if (focusIndex !== null) {\n toggleItem(filteredOptions[focusIndex]?.id);\n }\n break;\n\n case 'Backspace':\n if (value.length === 0) {\n setSelected((prev) => prev.slice(0, -1));\n }\n break;\n\n case 'Escape':\n setOpen(false);\n break;\n }\n },\n [\n focusIndex,\n value.length,\n setScroll,\n options.length,\n toggleItem,\n filteredOptions,\n ]\n );\n\n const placeholderVisible = useMemo(() => {\n if (selectedItem.length) return false;\n if (value) return false;\n if (focus) return false;\n return true;\n }, [focus, selectedItem.length, value]);\n\n useEffect(() => {\n if (isInit.current) {\n return;\n }\n onChange?.(selected);\n // eslint-disable-next-line react-hooks/exhaustive-deps -- 주소값 변경 방지\n }, [[...selected].sort().join(',')]);\n\n useEffect(() => {\n if (isInit.current) {\n return;\n }\n setSelected(props.selected || []);\n // eslint-disable-next-line react-hooks/exhaustive-deps -- 주소값 변경 방지\n }, [[...(props.selected || [])].sort().join(',')]);\n\n useEffect(() => {\n setFocusIndex(null);\n }, [open]);\n\n useEffect(() => {\n setFocusIndex(0);\n }, [filteredOptions]);\n\n useEffect(() => {\n isInit.current = false;\n }, []);\n\n const badgeSize = useMemo<BadgeProps['size']>(() => {\n switch (size) {\n case 'large':\n return 'large';\n case 'medium':\n case 'small':\n default:\n return 'small';\n }\n }, [size]);\n\n const placeholderVariant = useMemo<TypoProps['variant']>(() => {\n switch (size) {\n case 'large':\n return 'subtitle';\n case 'medium':\n default:\n return 'body';\n }\n }, [size]);\n\n const focusClassName = focus ? ' focused' : '';\n const readOnlyClassName = readOnly ? ' read-only' : '';\n\n const readonlyContent = (\n <Flex gap=\"1\">\n {selectedItem.map((item) => {\n return tagRender ? (\n tagRender(item)\n ) : (\n <Badge key={item.id} size={badgeSize}>\n {item.name}\n </Badge>\n );\n })}\n </Flex>\n );\n\n const editContent = (\n <>\n <Flex\n align=\"center\"\n gap=\"1\"\n maxWidth=\"100%\"\n overflow=\"hidden\"\n wrap=\"wrap\"\n >\n {selectedItem.map((item) => {\n return tagRender ? (\n tagRender(item)\n ) : (\n <Badge key={item.id} size={badgeSize}>\n {item.name}\n <Button\n onClick={() => {\n onDelete(item.id);\n }}\n variant=\"transparent\"\n >\n <Cross1Icon />\n </Button>\n </Badge>\n );\n })}\n {placeholderVisible ? (\n <Typo color=\"gray\" variant={placeholderVariant}>\n {placeholder}\n </Typo>\n ) : null}\n <AutoSizingInput\n onBlur={onBlur}\n onChange={onChangeValue}\n onFocus={onFocus}\n onKeyDown={handleKeyDown}\n ref={fieldRef}\n value={value}\n />\n </Flex>\n {focus ? <MagnifyingGlassIcon /> : <ChevronRightIcon />}\n </>\n );\n return (\n <Popover.Root open={Boolean(filteredOptions.length) && open}>\n <Popover.Trigger style={{ position: 'relative' }}>\n <Grid\n align=\"center\"\n className={`tag-selector ${size} ${focusClassName}${readOnlyClassName}`}\n columns=\"1fr auto\"\n gap=\"1\"\n onClick={() => !readOnly && fieldRef.current?.focus()}\n >\n {readOnly ? readonlyContent : editContent}\n </Grid>\n </Popover.Trigger>\n\n <Popover.Content\n onOpenAutoFocus={(e) => {\n e.preventDefault();\n }}\n >\n <DropdownContainer\n currentItem={filteredOptions[focusIndex || 0]}\n items={filteredOptions}\n >\n <ScrollArea\n ref={scrollRef}\n scrollbars=\"vertical\"\n style={{ height: OPTION_HEIGHT * 8 }}\n type=\"auto\"\n >\n <Flex direction=\"column\">\n {filteredOptions.map((item, i) => {\n const isSelected = Boolean(\n selected.find((el) => el === item.id)\n );\n const isFocus = i === focusIndex;\n\n return (\n <Button\n key={item.id}\n onClick={() => {\n toggleItem(item.id);\n fieldRef.current?.focus();\n }}\n onMouseEnter={() => {\n setFocusIndex(i);\n }}\n style={{\n width: '100%',\n background: isFocus ? 'var(--accent-a3)' : undefined,\n color: 'var(--gray-12)',\n fontWeight: 400,\n boxShadow: 'none',\n }}\n variant={isSelected ? 'soft' : 'outline'}\n >\n <Flex justify=\"between\" width=\"100%\">\n {item.name}\n {isSelected ? <CheckIcon /> : null}\n </Flex>\n </Button>\n );\n })}\n </Flex>\n </ScrollArea>\n </DropdownContainer>\n </Popover.Content>\n </Popover.Root>\n );\n}\n"],"mappings":"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","names":[]}
package/dist/index.cjs CHANGED
@@ -1731,13 +1731,15 @@ function TagSelector(props) {
1731
1731
  DropdownContainer = DefaultDropdownContainer,
1732
1732
  onChange,
1733
1733
  size = "medium",
1734
- readOnly
1734
+ readOnly,
1735
+ error
1735
1736
  } = props;
1736
1737
  const [selected, setSelected] = (0, import_react26.useState)(props.selected || []);
1737
1738
  const [value, setValue] = (0, import_react26.useState)("");
1738
1739
  const [focusIndex, setFocusIndex] = (0, import_react26.useState)(null);
1739
1740
  const [open, setOpen] = (0, import_react26.useState)(false);
1740
1741
  const [focus, setFocus] = (0, import_react26.useState)(false);
1742
+ const isInit = (0, import_react26.useRef)(true);
1741
1743
  const fieldRef = (0, import_react26.useRef)(null);
1742
1744
  const scrollRef = (0, import_react26.useRef)(null);
1743
1745
  const closeRef = (0, import_react26.useRef)();
@@ -1868,9 +1870,15 @@ function TagSelector(props) {
1868
1870
  return true;
1869
1871
  }, [focus, selectedItem.length, value]);
1870
1872
  (0, import_react26.useEffect)(() => {
1873
+ if (isInit.current) {
1874
+ return;
1875
+ }
1871
1876
  onChange == null ? void 0 : onChange(selected);
1872
1877
  }, [[...selected].sort().join(",")]);
1873
1878
  (0, import_react26.useEffect)(() => {
1879
+ if (isInit.current) {
1880
+ return;
1881
+ }
1874
1882
  setSelected(props.selected || []);
1875
1883
  }, [[...props.selected || []].sort().join(",")]);
1876
1884
  (0, import_react26.useEffect)(() => {
@@ -1879,6 +1887,9 @@ function TagSelector(props) {
1879
1887
  (0, import_react26.useEffect)(() => {
1880
1888
  setFocusIndex(0);
1881
1889
  }, [filteredOptions]);
1890
+ (0, import_react26.useEffect)(() => {
1891
+ isInit.current = false;
1892
+ }, []);
1882
1893
  const badgeSize = (0, import_react26.useMemo)(() => {
1883
1894
  switch (size) {
1884
1895
  case "large":
@@ -1900,6 +1911,7 @@ function TagSelector(props) {
1900
1911
  }, [size]);
1901
1912
  const focusClassName = focus ? " focused" : "";
1902
1913
  const readOnlyClassName = readOnly ? " read-only" : "";
1914
+ const errorClassName = error ? " error" : "";
1903
1915
  const readonlyContent = /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_themes19.Flex, { gap: "1", children: selectedItem.map((item) => {
1904
1916
  return tagRender ? tagRender(item) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Badge, { size: badgeSize, children: item.name }, item.id);
1905
1917
  }) });
@@ -1950,7 +1962,7 @@ function TagSelector(props) {
1950
1962
  import_themes20.Grid,
1951
1963
  {
1952
1964
  align: "center",
1953
- className: `tag-selector ${size} ${focusClassName}${readOnlyClassName}`,
1965
+ className: `tag-selector ${size} ${focusClassName}${readOnlyClassName}${errorClassName}`,
1954
1966
  columns: "1fr auto",
1955
1967
  gap: "1",
1956
1968
  onClick: () => {
@@ -1986,6 +1998,7 @@ function TagSelector(props) {
1986
1998
  return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1987
1999
  Button,
1988
2000
  {
2001
+ className: `tag-selector-button ${isFocus ? "focus" : ""}`,
1989
2002
  onClick: () => {
1990
2003
  var _a;
1991
2004
  toggleItem(item.id);