@udixio/ui-react 2.8.4 → 2.9.3

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 (44) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/dist/index.cjs +7 -2
  3. package/dist/index.js +2307 -1818
  4. package/dist/lib/components/Button.d.ts.map +1 -1
  5. package/dist/lib/components/Chip.d.ts +9 -0
  6. package/dist/lib/components/Chip.d.ts.map +1 -0
  7. package/dist/lib/components/Chips.d.ts +4 -0
  8. package/dist/lib/components/Chips.d.ts.map +1 -0
  9. package/dist/lib/components/IconButton.d.ts.map +1 -1
  10. package/dist/lib/components/index.d.ts +2 -0
  11. package/dist/lib/components/index.d.ts.map +1 -1
  12. package/dist/lib/effects/block-scroll.effect.d.ts +6 -0
  13. package/dist/lib/effects/block-scroll.effect.d.ts.map +1 -1
  14. package/dist/lib/effects/smooth-scroll.effect.d.ts +5 -0
  15. package/dist/lib/effects/smooth-scroll.effect.d.ts.map +1 -1
  16. package/dist/lib/icon/icon.d.ts.map +1 -1
  17. package/dist/lib/interfaces/chip.interface.d.ts +76 -0
  18. package/dist/lib/interfaces/chip.interface.d.ts.map +1 -0
  19. package/dist/lib/interfaces/chips.interface.d.ts +29 -0
  20. package/dist/lib/interfaces/chips.interface.d.ts.map +1 -0
  21. package/dist/lib/interfaces/index.d.ts +2 -0
  22. package/dist/lib/interfaces/index.d.ts.map +1 -1
  23. package/dist/lib/styles/chip.style.d.ts +111 -0
  24. package/dist/lib/styles/chip.style.d.ts.map +1 -0
  25. package/dist/lib/styles/chips.style.d.ts +55 -0
  26. package/dist/lib/styles/chips.style.d.ts.map +1 -0
  27. package/dist/lib/styles/index.d.ts +2 -0
  28. package/dist/lib/styles/index.d.ts.map +1 -1
  29. package/dist/lib/styles/text-field.style.d.ts +2 -2
  30. package/package.json +4 -4
  31. package/src/lib/components/Button.tsx +11 -20
  32. package/src/lib/components/Chip.tsx +333 -0
  33. package/src/lib/components/Chips.tsx +280 -0
  34. package/src/lib/components/IconButton.tsx +11 -19
  35. package/src/lib/components/index.ts +2 -0
  36. package/src/lib/effects/block-scroll.effect.tsx +89 -11
  37. package/src/lib/effects/smooth-scroll.effect.tsx +5 -0
  38. package/src/lib/icon/icon.tsx +7 -1
  39. package/src/lib/interfaces/chip.interface.ts +97 -0
  40. package/src/lib/interfaces/chips.interface.ts +37 -0
  41. package/src/lib/interfaces/index.ts +2 -0
  42. package/src/lib/styles/chip.style.ts +62 -0
  43. package/src/lib/styles/chips.style.ts +20 -0
  44. package/src/lib/styles/index.ts +2 -0
@@ -0,0 +1,333 @@
1
+ import { classNames, ReactProps } from '../utils';
2
+ import { ChipInterface } from '../interfaces';
3
+ import { useChipStyle } from '../styles';
4
+ import { Icon } from '../icon';
5
+ import { State } from '../effects';
6
+ import React, { useEffect, useRef, useState } from 'react';
7
+ import { faCheck, faXmark } from '@fortawesome/free-solid-svg-icons';
8
+
9
+ /**
10
+ * Chips prompt most actions in a UI
11
+ * @status beta
12
+ * @category Action
13
+ */
14
+ export const Chip = ({
15
+ variant = 'outlined',
16
+ disabled = false,
17
+ icon,
18
+ href,
19
+ label,
20
+ className,
21
+ onClick,
22
+ onToggle,
23
+ activated,
24
+ ref,
25
+ onRemove,
26
+ editable,
27
+ onEditStart,
28
+ onEditCommit,
29
+ onEditCancel,
30
+ onChange,
31
+ transition,
32
+ children,
33
+ editing,
34
+ ...restProps
35
+ }: ReactProps<ChipInterface>) => {
36
+ if (children) label = children;
37
+ // Allow empty string when editable (newly created chips start empty)
38
+ if (label === undefined && !editable) {
39
+ throw new Error(
40
+ 'Chip component requires either a label prop or children content',
41
+ );
42
+ }
43
+
44
+ const ElementType = href ? 'a' : 'button';
45
+
46
+ const defaultRef = useRef<HTMLDivElement>(null);
47
+ const resolvedRef = ref || defaultRef;
48
+
49
+ const [isActive, setIsActive] = React.useState(activated);
50
+ const [isFocused, setIsFocused] = React.useState(false);
51
+ const [isEditing, setIsEditing] = useState(editing && editable);
52
+ const [isDragging, setIsDragging] = React.useState(false);
53
+ const [editValue, setEditValue] = React.useState<string>(
54
+ typeof label === 'string' ? label : '',
55
+ );
56
+ const editSpanRef = React.useRef<HTMLSpanElement>(null);
57
+ useEffect(() => {
58
+ setIsActive(activated);
59
+ }, [activated]);
60
+
61
+ useEffect(() => {
62
+ if (editing) {
63
+ setIsEditing(editing);
64
+ }
65
+ if (editable && isFocused) {
66
+ // Délai de 1 seconde avant d'activer l'édition
67
+ const timerId = setTimeout(() => {
68
+ // Ignore l'édition si draggable et en cours de dragging
69
+ if ((restProps as any)?.draggable && isDragging) {
70
+ return;
71
+ }
72
+ setIsEditing(true);
73
+ }, 1000);
74
+
75
+ // Cleanup: annule le timer si le focus est perdu avant 1 seconde
76
+ return () => clearTimeout(timerId);
77
+ } else if (!isFocused) {
78
+ // Désactive l'édition immédiatement si le focus est perdu
79
+ setIsEditing(false);
80
+ }
81
+ return;
82
+ }, [isFocused, editable, isDragging, restProps, editValue]);
83
+
84
+ // Sync edit value and focus caret when entering editing mode
85
+ useEffect(() => {
86
+ if (isEditing) {
87
+ setEditValue(typeof label === 'string' ? label : '');
88
+ // focus contenteditable span and move caret to end
89
+ const el =
90
+ (labelRef.current as unknown as HTMLSpanElement) || editSpanRef.current;
91
+ if (el) {
92
+ el.focus();
93
+ const range = document.createRange();
94
+ range.selectNodeContents(el);
95
+ range.collapse(false);
96
+ const sel = window.getSelection();
97
+ sel?.removeAllRanges();
98
+ sel?.addRange(range);
99
+ }
100
+ }
101
+ }, [isEditing]);
102
+
103
+ transition = { duration: 0.3, ...transition };
104
+
105
+ const handleClick = (e: React.MouseEvent<any, MouseEvent>) => {
106
+ if (disabled) {
107
+ e.preventDefault();
108
+ }
109
+ if (onToggle) {
110
+ setIsActive(!isActive);
111
+ onToggle(!isActive);
112
+ } else if (onClick) {
113
+ onClick(e);
114
+ }
115
+ };
116
+
117
+ const isInteractive = !!onToggle || !!onRemove || !!onClick || !!href;
118
+
119
+ if (activated) {
120
+ icon = faCheck;
121
+ }
122
+
123
+ // Extract potential onFocus/onBlur from rest props to compose handlers
124
+ const {
125
+ onFocus: restOnFocus,
126
+ onBlur: restOnBlur,
127
+ onKeyDown: restOnKeyDown,
128
+ onDragStart: restOnDragStart,
129
+ onDragEnd: restOnDragEnd,
130
+ onDoubleClick: restOnDoubleClick,
131
+ ...rest
132
+ } = (restProps as any) ?? {};
133
+
134
+ const styles = useChipStyle({
135
+ href,
136
+ disabled,
137
+ icon,
138
+ variant,
139
+ transition,
140
+ className,
141
+ isActive: isActive ?? false,
142
+ onToggle,
143
+ activated: isActive,
144
+ label,
145
+ isInteractive,
146
+ children: label,
147
+ isFocused: isFocused,
148
+ isDragging,
149
+ onEditCommit,
150
+ isEditing,
151
+ });
152
+
153
+ const labelRef = useRef(null);
154
+
155
+ const handleCommit = () => {
156
+ const trimmed = (editValue ?? '').trim();
157
+ if (!trimmed) {
158
+ if (onRemove) {
159
+ onRemove();
160
+ }
161
+ return;
162
+ }
163
+ onEditCommit?.(trimmed);
164
+ };
165
+
166
+ return (
167
+ <ElementType
168
+ contentEditable={false}
169
+ ref={resolvedRef}
170
+ href={href}
171
+ className={styles.chip}
172
+ {...(rest as any)}
173
+ onClick={(e: React.MouseEvent<any>) => {
174
+ if (!isEditing) handleClick(e);
175
+ }}
176
+ draggable={!disabled && !!(restProps as any)?.draggable}
177
+ onDragStart={(e: React.DragEvent<any>) => {
178
+ if (!disabled && (restProps as any)?.draggable) {
179
+ setIsDragging(true);
180
+ }
181
+ restOnDragStart?.(e);
182
+ }}
183
+ onDragEnd={(e: React.DragEvent<any>) => {
184
+ if ((restProps as any)?.draggable) {
185
+ setIsDragging(false);
186
+ }
187
+ restOnDragEnd?.(e);
188
+ }}
189
+ onDoubleClick={(e: React.MouseEvent<any>) => {
190
+ if (!disabled && editable && !isEditing) {
191
+ onEditStart?.();
192
+ e.preventDefault();
193
+ e.stopPropagation();
194
+ }
195
+ restOnDoubleClick?.(e);
196
+ }}
197
+ onFocus={(e: React.FocusEvent<any>) => {
198
+ if (isInteractive) {
199
+ setIsFocused(true);
200
+ }
201
+ restOnFocus?.(e);
202
+ }}
203
+ onBlur={(e: React.FocusEvent<any>) => {
204
+ setIsFocused(false);
205
+ restOnBlur?.(e);
206
+ }}
207
+ onKeyDown={(e: React.KeyboardEvent<any>) => {
208
+ const key = e.key;
209
+
210
+ // While editing: handle commit/cancel locally
211
+ if (!disabled && isEditing) {
212
+ if (key === 'Enter') {
213
+ e.preventDefault();
214
+ handleCommit();
215
+ } else if (key === 'Escape') {
216
+ e.preventDefault();
217
+ onEditCancel?.();
218
+ } else if (
219
+ onRemove &&
220
+ editValue?.trim() === '' &&
221
+ (key === 'Backspace' || key === 'Delete' || key === 'Del')
222
+ ) {
223
+ e.preventDefault();
224
+ e.stopPropagation();
225
+ onRemove();
226
+ }
227
+ return;
228
+ }
229
+
230
+ // Only handle keys when focused/selected and not disabled
231
+ if (!disabled && isFocused) {
232
+ // Start editing with F2 or Enter when editable and no toggle behavior
233
+ if (editable && !onToggle && (key === 'F2' || key === 'Enter')) {
234
+ e.preventDefault();
235
+ onEditStart?.();
236
+ return;
237
+ }
238
+
239
+ // Toggle active state on Enter or Space when togglable
240
+ if (
241
+ onToggle &&
242
+ (key === 'Enter' || key === ' ' || key === 'Spacebar')
243
+ ) {
244
+ e.preventDefault();
245
+ const next = !isActive;
246
+ setIsActive(next);
247
+ onToggle(next);
248
+ }
249
+
250
+ // Trigger remove on Backspace or Delete when removable
251
+ if (
252
+ onRemove &&
253
+ (key === 'Backspace' || key === 'Delete' || key === 'Del')
254
+ ) {
255
+ e.preventDefault();
256
+ e.stopPropagation();
257
+ onRemove();
258
+ }
259
+ }
260
+
261
+ // Delegate to user handler last
262
+ restOnKeyDown?.(e);
263
+ }}
264
+ disabled={disabled}
265
+ aria-pressed={onToggle ? isActive : undefined}
266
+ style={{ transition: transition.duration + 's' }}
267
+ >
268
+ {isInteractive && !disabled && !isEditing && (
269
+ <State
270
+ style={{ transition: transition.duration + 's' }}
271
+ className={styles.stateLayer}
272
+ colorName={classNames({
273
+ 'on-surface-variant': !isActive,
274
+ 'on-secondary-container': isActive,
275
+ })}
276
+ stateClassName={'state-ripple-group-[chip]'}
277
+ />
278
+ )}
279
+
280
+ {icon && <Icon icon={icon} className={styles.leadingIcon} />}
281
+ <span
282
+ ref={labelRef}
283
+ contentEditable={!!editable && !!isEditing}
284
+ suppressContentEditableWarning
285
+ className={styles.label}
286
+ role={editable ? 'textbox' : undefined}
287
+ spellCheck={false}
288
+ onInput={(e) => {
289
+ const text = (e.currentTarget as HTMLSpanElement).innerText;
290
+ setEditValue(text);
291
+ onChange?.(text);
292
+ }}
293
+ onBlur={(e) => {
294
+ if (editable && isEditing) {
295
+ handleCommit();
296
+ }
297
+ }}
298
+ onKeyDown={(e) => {
299
+ // prevent line breaks inside contenteditable
300
+ if (editable && isEditing && e.key === 'Enter') {
301
+ e.preventDefault();
302
+ e.stopPropagation();
303
+ handleCommit();
304
+ return;
305
+ }
306
+ if (editable && isEditing && e.key === 'Escape') {
307
+ e.preventDefault();
308
+ e.stopPropagation();
309
+ onEditCancel?.();
310
+ }
311
+ }}
312
+ >
313
+ {label}
314
+ </span>
315
+ {onRemove && !isEditing && (
316
+ <Icon
317
+ icon={faXmark}
318
+ className={styles.trailingIcon}
319
+ onMouseDown={(e) => {
320
+ e.preventDefault(); // ⬅️ clé
321
+ e.stopPropagation();
322
+ }}
323
+ onClick={(e: React.MouseEvent) => {
324
+ e.stopPropagation();
325
+ if (!disabled) {
326
+ onRemove();
327
+ }
328
+ }}
329
+ />
330
+ )}
331
+ </ElementType>
332
+ );
333
+ };
@@ -0,0 +1,280 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { ReactProps } from '../utils';
3
+ import { ChipItem, ChipsInterface } from '../interfaces';
4
+ import { useChipsStyle } from '../styles';
5
+ import { Chip } from './Chip';
6
+ import { Divider } from './Divider';
7
+ import { v4 } from 'uuid';
8
+
9
+ export const Chips = ({
10
+ variant = 'input',
11
+ className,
12
+ scrollable = true,
13
+ draggable = false,
14
+ items,
15
+ onItemsChange,
16
+ }: ReactProps<ChipsInterface>) => {
17
+ const list = items ?? [];
18
+
19
+ const ref = React.useRef<HTMLDivElement>(null);
20
+
21
+ const [isFocused, setIsFocused] = React.useState<boolean>(false);
22
+
23
+ // Internal stable ids per item object (since ChipItem no longer exposes id)
24
+ const idMapRef = React.useRef<WeakMap<ChipItem, string>>(new WeakMap());
25
+ const getInternalId = React.useCallback((it: ChipItem) => {
26
+ const map = idMapRef.current;
27
+ let id = map.get(it);
28
+ if (!id) {
29
+ id = v4();
30
+ map.set(it, id);
31
+ }
32
+ return id;
33
+ }, []);
34
+
35
+ React.useEffect(() => {
36
+ if (isFocused) {
37
+ ref.current?.focus();
38
+ }
39
+ }, [isFocused]);
40
+
41
+ const chipRefs = React.useRef<(HTMLElement | null)[]>([]);
42
+
43
+ const updateItems = React.useCallback(
44
+ (updater: (prev: ChipItem[]) => ChipItem[]) => {
45
+ onItemsChange?.(updater(list));
46
+ },
47
+ [onItemsChange, list],
48
+ );
49
+
50
+ const removeAt = React.useCallback(
51
+ (index: number) => {
52
+ updateItems((prev) => prev.filter((_, i) => i !== index));
53
+ },
54
+ [updateItems],
55
+ );
56
+
57
+ const styles = useChipsStyle({
58
+ scrollable,
59
+ className,
60
+ variant,
61
+ });
62
+
63
+ const createAndStartEdit = React.useCallback(
64
+ (seedLabel = '') => {
65
+ if (variant !== 'input') return;
66
+
67
+ const newItem: ChipItem = {
68
+ label: seedLabel,
69
+ } as ChipItem;
70
+
71
+ // Generate internal ID for the new item
72
+ const newId = getInternalId(newItem);
73
+
74
+ // Ask parent to add as well
75
+ const next = [...list, newItem];
76
+ onItemsChange?.(next);
77
+
78
+ requestAnimationFrame(() => {
79
+ setSelectedChip(newId);
80
+ });
81
+ },
82
+ [variant, onItemsChange, list, getInternalId],
83
+ );
84
+
85
+ const [selectedChip, setSelectedChip] = useState<string | null>(null);
86
+
87
+ useEffect(() => {
88
+ if (selectedChip) {
89
+ const index = list.findIndex(
90
+ (item) => getInternalId(item) === selectedChip,
91
+ );
92
+ if (index !== -1) {
93
+ const el = chipRefs.current[index] as any;
94
+ el?.focus?.();
95
+
96
+ const chipsEl = ref.current!;
97
+ const scrollLeft =
98
+ el.offsetLeft + el.offsetWidth / 2 - chipsEl.offsetWidth / 2;
99
+ chipsEl.scrollTo({ left: scrollLeft, behavior: 'smooth' });
100
+ }
101
+ }
102
+ }, [selectedChip, list, getInternalId]);
103
+
104
+ // MODE ITEMS (source de vérité locale ou contrôlée)
105
+ return (
106
+ <div
107
+ ref={ref}
108
+ role="list"
109
+ aria-label="Chips"
110
+ className={styles.chips}
111
+ tabIndex={variant === 'input' ? 0 : undefined}
112
+ onFocus={(e) => {
113
+ if (e.target === e.currentTarget) {
114
+ setIsFocused(true);
115
+ }
116
+ }}
117
+ onBlur={() => setIsFocused(false)}
118
+ onKeyDown={(e) => {
119
+ if (variant !== 'input') return;
120
+
121
+ const key = e.key;
122
+ const target = e.target as HTMLElement;
123
+ const isContainerFocused = target === e.currentTarget;
124
+
125
+ // If currently editing a chip, let the chip handle keys
126
+ if (!isFocused) return;
127
+
128
+ // Determine focused chip index if any
129
+ const activeEl = document.activeElement as HTMLElement | null;
130
+ const focusedIndex = chipRefs.current.findIndex(
131
+ (el) => el === activeEl,
132
+ );
133
+
134
+ if (key === 'ArrowLeft') {
135
+ e.preventDefault();
136
+ const nextIdx = focusedIndex > 0 ? focusedIndex - 1 : list.length - 1;
137
+ const elId = getInternalId(list[nextIdx]);
138
+ setSelectedChip(elId);
139
+ return;
140
+ }
141
+ if (key === 'ArrowRight') {
142
+ e.preventDefault();
143
+ const nextIdx =
144
+ focusedIndex >= 0
145
+ ? (focusedIndex + 1) % Math.max(1, list.length)
146
+ : 0;
147
+ const elId = getInternalId(list[nextIdx]);
148
+ setSelectedChip(elId);
149
+ return;
150
+ }
151
+ if (key === 'Home') {
152
+ e.preventDefault();
153
+ const elId = getInternalId(list[0]);
154
+ setSelectedChip(elId);
155
+ return;
156
+ }
157
+ if (key === 'End') {
158
+ e.preventDefault();
159
+ const elId = getInternalId(list[list.length - 1]);
160
+ setSelectedChip(elId);
161
+ return;
162
+ }
163
+
164
+ if (isContainerFocused) {
165
+ if (key === 'Enter') {
166
+ e.preventDefault();
167
+ createAndStartEdit('');
168
+ return;
169
+ }
170
+ if (key === 'Backspace') {
171
+ e.preventDefault();
172
+ // Focus last chip if any
173
+ if (list.length > 0) {
174
+ const el = chipRefs.current[list.length - 1] as any;
175
+ el?.focus?.();
176
+ }
177
+ return;
178
+ }
179
+ // Start creation when typing a printable character
180
+ if (key.length === 1 && !e.altKey && !e.ctrlKey && !e.metaKey) {
181
+ createAndStartEdit(key);
182
+ e.preventDefault();
183
+ return;
184
+ }
185
+ }
186
+ }}
187
+ >
188
+ {list.map((item, index) => {
189
+ const internalId = getInternalId(item);
190
+ const isInputVariant = variant === 'input';
191
+ const editProps = isInputVariant
192
+ ? {
193
+ editable: true,
194
+ editing: selectedChip === internalId,
195
+ onEditCommit: (next: string | undefined) => {
196
+ setIsFocused(true);
197
+ updateItems((prev) =>
198
+ prev.map((it, i) =>
199
+ i === index ? { ...it, label: next as any } : it,
200
+ ),
201
+ );
202
+ },
203
+ onEditCancel: () => {
204
+ setIsFocused(true);
205
+ },
206
+ onChange: (next: ChipItem[]) => {
207
+ if (chipRefs.current.length == index + 1) {
208
+ const el = ref.current!;
209
+ requestAnimationFrame(() => {
210
+ el.scrollTo({ left: el.scrollWidth, behavior: 'smooth' });
211
+ });
212
+ }
213
+ },
214
+ }
215
+ : {};
216
+
217
+ return (
218
+ <Chip
219
+ key={internalId}
220
+ ref={(el: any) => (chipRefs.current[index] = el)}
221
+ label={item.label ?? ''}
222
+ icon={item.icon}
223
+ activated={item.activated}
224
+ disabled={item.disabled}
225
+ variant={item.variant}
226
+ href={item.href}
227
+ draggable={draggable}
228
+ {...editProps}
229
+ onToggle={
230
+ item.activated === undefined
231
+ ? undefined
232
+ : (next) =>
233
+ updateItems((prev) =>
234
+ prev.map((it, i) =>
235
+ i === index ? { ...it, activated: next } : it,
236
+ ),
237
+ )
238
+ }
239
+ onBlur={() => {
240
+ if (selectedChip === internalId) {
241
+ setSelectedChip(null);
242
+ }
243
+ }}
244
+ onRemove={
245
+ isInputVariant
246
+ ? () => {
247
+ setIsFocused(true);
248
+ removeAt(index);
249
+ }
250
+ : undefined
251
+ }
252
+ />
253
+ );
254
+ })}
255
+ {isFocused && (
256
+ <>
257
+ <Divider
258
+ orientation="vertical"
259
+ className="animate-[var(--animate-blink)] border-outline"
260
+ style={
261
+ {
262
+ '--animate-blink':
263
+ 'blink 1s cubic-bezier(0.4, 0, 0.6, 1) infinite',
264
+ } as React.CSSProperties
265
+ }
266
+ />
267
+
268
+ <style>
269
+ {`
270
+ @keyframes blink {
271
+ 0%, 50% { opacity: 1; }
272
+ 50.01%, 100% { opacity: 0; }
273
+ }
274
+ `}
275
+ </style>
276
+ </>
277
+ )}
278
+ </div>
279
+ );
280
+ };
@@ -48,26 +48,18 @@ export const IconButton = ({
48
48
 
49
49
  const [isActive, setIsActive] = React.useState(activated);
50
50
 
51
- let handleClick;
52
- if (!onToggle) {
53
- handleClick = (e: React.MouseEvent<any, MouseEvent>) => {
54
- if (disabled) {
55
- e.preventDefault();
56
- }
57
- if (onClick) {
58
- onClick(e);
59
- }
60
- };
61
- } else if (onToggle) {
62
- handleClick = (e: React.MouseEvent<any, MouseEvent>) => {
63
- if (disabled) {
64
- e.preventDefault();
65
- }
51
+ const handleClick = (e: React.MouseEvent<any, MouseEvent>) => {
52
+ if (disabled) {
53
+ e.preventDefault();
54
+ }
55
+ if (onToggle) {
66
56
  setIsActive(!isActive);
67
- onToggle(Boolean(isActive));
68
- };
69
- icon = isActive ? (iconSelected ? iconSelected : icon) : icon;
70
- }
57
+ onToggle(!isActive);
58
+ } else if (onClick) {
59
+ onClick(e);
60
+ }
61
+ };
62
+
71
63
  useEffect(() => {
72
64
  setIsActive(activated);
73
65
  }, [activated]);
@@ -3,6 +3,8 @@ export * from './Card';
3
3
  export * from './Carousel';
4
4
  export * from './CarouselItem';
5
5
  export * from './CarouselItem';
6
+ export * from './Chip';
7
+ export * from './Chips';
6
8
  export * from './Divider';
7
9
  export * from './Fab';
8
10
  export * from './FabMenu';