@tipp/ui 1.4.20 → 1.4.22

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 (47) hide show
  1. package/dist/atoms/button.d.cts +1 -1
  2. package/dist/atoms/button.d.ts +1 -1
  3. package/dist/atoms/field-error-wrapper.js +2 -2
  4. package/dist/atoms/index.js +53 -53
  5. package/dist/atoms/pagination.js +2 -2
  6. package/dist/chunk-23P5I2JR.js +192 -0
  7. package/dist/chunk-23P5I2JR.js.map +1 -0
  8. package/dist/chunk-52V6NWNP.js +350 -0
  9. package/dist/chunk-52V6NWNP.js.map +1 -0
  10. package/dist/chunk-6XAYAEHG.js +360 -0
  11. package/dist/chunk-6XAYAEHG.js.map +1 -0
  12. package/dist/chunk-IYEPU2SQ.js +350 -0
  13. package/dist/chunk-IYEPU2SQ.js.map +1 -0
  14. package/dist/chunk-P42HAVOT.js +359 -0
  15. package/dist/chunk-P42HAVOT.js.map +1 -0
  16. package/dist/chunk-SQ7HPPKD.js +360 -0
  17. package/dist/chunk-SQ7HPPKD.js.map +1 -0
  18. package/dist/chunk-WNYDAKKK.js +350 -0
  19. package/dist/chunk-WNYDAKKK.js.map +1 -0
  20. package/dist/chunk-WWQSL5XC.js +357 -0
  21. package/dist/chunk-WWQSL5XC.js.map +1 -0
  22. package/dist/chunk-ZCAMAL6P.js +360 -0
  23. package/dist/chunk-ZCAMAL6P.js.map +1 -0
  24. package/dist/chunk-ZRCNIT7C.js +357 -0
  25. package/dist/chunk-ZRCNIT7C.js.map +1 -0
  26. package/dist/index.cjs +20 -17
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.css +5 -1
  29. package/dist/index.css.map +1 -1
  30. package/dist/index.js +64 -64
  31. package/dist/molecules/date-picker/index.js +2 -2
  32. package/dist/molecules/expand-table/index.js +27 -27
  33. package/dist/molecules/expand-table/row.js +24 -24
  34. package/dist/molecules/form.js +2 -2
  35. package/dist/molecules/index.cjs +20 -17
  36. package/dist/molecules/index.cjs.map +1 -1
  37. package/dist/molecules/index.js +33 -33
  38. package/dist/molecules/learning-post.js +4 -4
  39. package/dist/molecules/navigation.js +25 -25
  40. package/dist/molecules/stepper.js +2 -2
  41. package/dist/molecules/tag-selector.cjs +20 -17
  42. package/dist/molecules/tag-selector.cjs.map +1 -1
  43. package/dist/molecules/tag-selector.d.cts +1 -0
  44. package/dist/molecules/tag-selector.d.ts +1 -0
  45. package/dist/molecules/tag-selector.js +25 -25
  46. package/package.json +1 -1
  47. package/src/molecules/tag-selector.tsx +20 -20
@@ -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
@@ -1729,11 +1729,13 @@ function TagSelector(props) {
1729
1729
  placeholder,
1730
1730
  maxCount = 0,
1731
1731
  DropdownContainer = DefaultDropdownContainer,
1732
- onChange,
1733
1732
  size = "medium",
1734
- readOnly
1733
+ readOnly,
1734
+ error
1735
1735
  } = props;
1736
- const [selected, setSelected] = (0, import_react26.useState)(props.selected || []);
1736
+ const [_selected, _setSelected] = (0, import_react26.useState)(props.selected || []);
1737
+ const selected = props.selected || _selected;
1738
+ const setSelected = props.onChange || _setSelected;
1737
1739
  const [value, setValue] = (0, import_react26.useState)("");
1738
1740
  const [focusIndex, setFocusIndex] = (0, import_react26.useState)(null);
1739
1741
  const [open, setOpen] = (0, import_react26.useState)(false);
@@ -1775,16 +1777,19 @@ function TagSelector(props) {
1775
1777
  });
1776
1778
  return result;
1777
1779
  }, [options, selected]);
1778
- const onDelete = (0, import_react26.useCallback)((id) => {
1779
- setSelected((prev) => prev.filter((el) => el !== id));
1780
- }, []);
1780
+ const onDelete = (0, import_react26.useCallback)(
1781
+ (id) => {
1782
+ setSelected(selected.filter((el) => el !== id));
1783
+ },
1784
+ [selected, setSelected]
1785
+ );
1781
1786
  const onSelect = (0, import_react26.useCallback)(
1782
1787
  (id) => {
1783
1788
  if (maxCount && selected.length + 1 > maxCount)
1784
1789
  return;
1785
- setSelected((prev) => [...prev, id]);
1790
+ setSelected([...selected, id]);
1786
1791
  },
1787
- [maxCount, selected]
1792
+ [maxCount, selected, setSelected]
1788
1793
  );
1789
1794
  const toggleItem = (0, import_react26.useCallback)(
1790
1795
  (id) => {
@@ -1841,7 +1846,7 @@ function TagSelector(props) {
1841
1846
  break;
1842
1847
  case "Backspace":
1843
1848
  if (value.length === 0) {
1844
- setSelected((prev) => prev.slice(0, -1));
1849
+ setSelected(selected.slice(0, -1));
1845
1850
  }
1846
1851
  break;
1847
1852
  case "Escape":
@@ -1855,7 +1860,9 @@ function TagSelector(props) {
1855
1860
  setScroll,
1856
1861
  options.length,
1857
1862
  toggleItem,
1858
- filteredOptions
1863
+ filteredOptions,
1864
+ setSelected,
1865
+ selected
1859
1866
  ]
1860
1867
  );
1861
1868
  const placeholderVisible = (0, import_react26.useMemo)(() => {
@@ -1867,12 +1874,6 @@ function TagSelector(props) {
1867
1874
  return false;
1868
1875
  return true;
1869
1876
  }, [focus, selectedItem.length, value]);
1870
- (0, import_react26.useEffect)(() => {
1871
- onChange == null ? void 0 : onChange(selected);
1872
- }, [[...selected].sort().join(",")]);
1873
- (0, import_react26.useEffect)(() => {
1874
- setSelected(props.selected || []);
1875
- }, [[...props.selected || []].sort().join(",")]);
1876
1877
  (0, import_react26.useEffect)(() => {
1877
1878
  setFocusIndex(null);
1878
1879
  }, [open]);
@@ -1900,6 +1901,7 @@ function TagSelector(props) {
1900
1901
  }, [size]);
1901
1902
  const focusClassName = focus ? " focused" : "";
1902
1903
  const readOnlyClassName = readOnly ? " read-only" : "";
1904
+ const errorClassName = error ? " error" : "";
1903
1905
  const readonlyContent = /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_themes19.Flex, { gap: "1", children: selectedItem.map((item) => {
1904
1906
  return tagRender ? tagRender(item) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Badge, { size: badgeSize, children: item.name }, item.id);
1905
1907
  }) });
@@ -1950,7 +1952,7 @@ function TagSelector(props) {
1950
1952
  import_themes20.Grid,
1951
1953
  {
1952
1954
  align: "center",
1953
- className: `tag-selector ${size} ${focusClassName}${readOnlyClassName}`,
1955
+ className: `tag-selector ${size} ${focusClassName}${readOnlyClassName}${errorClassName}`,
1954
1956
  columns: "1fr auto",
1955
1957
  gap: "1",
1956
1958
  onClick: () => {
@@ -1986,6 +1988,7 @@ function TagSelector(props) {
1986
1988
  return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1987
1989
  Button,
1988
1990
  {
1991
+ className: `tag-selector-button ${isFocus ? "focus" : ""}`,
1989
1992
  onClick: () => {
1990
1993
  var _a;
1991
1994
  toggleItem(item.id);