@udixio/ui-react 2.8.4 → 2.9.4
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/CHANGELOG.md +65 -0
- package/dist/index.cjs +7 -2
- package/dist/index.js +2189 -1693
- package/dist/lib/components/Button.d.ts.map +1 -1
- package/dist/lib/components/Chip.d.ts +9 -0
- package/dist/lib/components/Chip.d.ts.map +1 -0
- package/dist/lib/components/Chips.d.ts +4 -0
- package/dist/lib/components/Chips.d.ts.map +1 -0
- package/dist/lib/components/IconButton.d.ts.map +1 -1
- package/dist/lib/components/ToolTip.d.ts +1 -1
- package/dist/lib/components/ToolTip.d.ts.map +1 -1
- package/dist/lib/components/index.d.ts +2 -0
- package/dist/lib/components/index.d.ts.map +1 -1
- package/dist/lib/effects/block-scroll.effect.d.ts +6 -0
- package/dist/lib/effects/block-scroll.effect.d.ts.map +1 -1
- package/dist/lib/effects/smooth-scroll.effect.d.ts +5 -0
- package/dist/lib/effects/smooth-scroll.effect.d.ts.map +1 -1
- package/dist/lib/icon/icon.d.ts.map +1 -1
- package/dist/lib/interfaces/chip.interface.d.ts +76 -0
- package/dist/lib/interfaces/chip.interface.d.ts.map +1 -0
- package/dist/lib/interfaces/chips.interface.d.ts +29 -0
- package/dist/lib/interfaces/chips.interface.d.ts.map +1 -0
- package/dist/lib/interfaces/index.d.ts +2 -0
- package/dist/lib/interfaces/index.d.ts.map +1 -1
- package/dist/lib/interfaces/tooltip.interface.d.ts +2 -0
- package/dist/lib/interfaces/tooltip.interface.d.ts.map +1 -1
- package/dist/lib/styles/chip.style.d.ts +111 -0
- package/dist/lib/styles/chip.style.d.ts.map +1 -0
- package/dist/lib/styles/chips.style.d.ts +55 -0
- package/dist/lib/styles/chips.style.d.ts.map +1 -0
- package/dist/lib/styles/fab-menu.style.d.ts.map +1 -1
- package/dist/lib/styles/index.d.ts +2 -0
- package/dist/lib/styles/index.d.ts.map +1 -1
- package/dist/lib/styles/text-field.style.d.ts +2 -2
- package/dist/lib/styles/tooltip.style.d.ts +4 -0
- package/dist/lib/styles/tooltip.style.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/lib/components/Button.tsx +11 -20
- package/src/lib/components/Chip.tsx +333 -0
- package/src/lib/components/Chips.tsx +280 -0
- package/src/lib/components/IconButton.tsx +11 -19
- package/src/lib/components/ToolTip.tsx +33 -15
- package/src/lib/components/index.ts +2 -0
- package/src/lib/effects/block-scroll.effect.tsx +89 -11
- package/src/lib/effects/smooth-scroll.effect.tsx +5 -0
- package/src/lib/icon/icon.tsx +7 -1
- package/src/lib/interfaces/chip.interface.ts +97 -0
- package/src/lib/interfaces/chips.interface.ts +37 -0
- package/src/lib/interfaces/index.ts +2 -0
- package/src/lib/interfaces/tooltip.interface.ts +2 -0
- package/src/lib/styles/chip.style.ts +62 -0
- package/src/lib/styles/chips.style.ts +20 -0
- package/src/lib/styles/fab-menu.style.ts +1 -0
- package/src/lib/styles/index.ts +2 -0
- package/src/lib/styles/tooltip.style.ts +5 -4
|
@@ -29,8 +29,11 @@ export const ToolTip = ({
|
|
|
29
29
|
targetRef,
|
|
30
30
|
ref,
|
|
31
31
|
trigger = ['hover', 'focus'],
|
|
32
|
+
transition,
|
|
32
33
|
...props
|
|
33
34
|
}: MotionProps<ToolTipInterface>) => {
|
|
35
|
+
transition = { duration: 0.3, delay: 0.4, ...transition };
|
|
36
|
+
|
|
34
37
|
if (!children && !targetRef) {
|
|
35
38
|
throw new Error('ToolTip must have a child or a targetRef');
|
|
36
39
|
}
|
|
@@ -50,6 +53,7 @@ export const ToolTip = ({
|
|
|
50
53
|
const [isVisible, setIsVisible] = useState(false);
|
|
51
54
|
|
|
52
55
|
const timeout = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
56
|
+
const showTimeout = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
53
57
|
|
|
54
58
|
useEffect(() => {
|
|
55
59
|
const handleUpdate = (event: CustomEvent) => {
|
|
@@ -67,9 +71,19 @@ export const ToolTip = ({
|
|
|
67
71
|
|
|
68
72
|
useEffect(() => {
|
|
69
73
|
if (timeout.current) clearTimeout(timeout.current);
|
|
74
|
+
if (showTimeout.current) clearTimeout(showTimeout.current);
|
|
70
75
|
|
|
71
76
|
if (currentToolTipId) {
|
|
72
|
-
|
|
77
|
+
if (currentToolTipId === id) {
|
|
78
|
+
showTimeout.current = setTimeout(
|
|
79
|
+
() => {
|
|
80
|
+
setIsVisible(true);
|
|
81
|
+
},
|
|
82
|
+
(transition?.delay ?? 0) * 1000,
|
|
83
|
+
);
|
|
84
|
+
} else {
|
|
85
|
+
setIsVisible(false);
|
|
86
|
+
}
|
|
73
87
|
} else {
|
|
74
88
|
timeout.current = setTimeout(() => {
|
|
75
89
|
setIsVisible(false);
|
|
@@ -188,6 +202,17 @@ export const ToolTip = ({
|
|
|
188
202
|
children: children as any,
|
|
189
203
|
});
|
|
190
204
|
|
|
205
|
+
const variants = {
|
|
206
|
+
open: {
|
|
207
|
+
opacity: 1,
|
|
208
|
+
height: 'auto',
|
|
209
|
+
},
|
|
210
|
+
close: {
|
|
211
|
+
opacity: 0,
|
|
212
|
+
height: 16,
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
|
|
191
216
|
return (
|
|
192
217
|
<>
|
|
193
218
|
{enhancedChildren}
|
|
@@ -195,24 +220,17 @@ export const ToolTip = ({
|
|
|
195
220
|
{isVisible && (
|
|
196
221
|
<SyncedFixedWrapper targetRef={resolvedRef}>
|
|
197
222
|
<motion.div
|
|
198
|
-
initial={
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
223
|
+
initial={'close'}
|
|
224
|
+
variants={variants}
|
|
225
|
+
animate={'open'}
|
|
226
|
+
transition={{ duration: transition.duration }}
|
|
227
|
+
exit={'close'}
|
|
202
228
|
className={styles.toolTip}
|
|
203
229
|
{...props}
|
|
204
230
|
onMouseEnter={handleMouseEnter}
|
|
205
231
|
onMouseLeave={handleMouseLeave}
|
|
206
232
|
>
|
|
207
|
-
<
|
|
208
|
-
className={styles.container}
|
|
209
|
-
layoutId={'tool-tip'}
|
|
210
|
-
transition={{
|
|
211
|
-
type: 'spring',
|
|
212
|
-
stiffness: 200,
|
|
213
|
-
damping: 20,
|
|
214
|
-
}}
|
|
215
|
-
>
|
|
233
|
+
<div className={styles.container}>
|
|
216
234
|
{title && <div className={styles.subHead}>{title}</div>}
|
|
217
235
|
<div className={styles.supportingText}>{text}</div>
|
|
218
236
|
{buttons && (
|
|
@@ -228,7 +246,7 @@ export const ToolTip = ({
|
|
|
228
246
|
))}
|
|
229
247
|
</div>
|
|
230
248
|
)}
|
|
231
|
-
</
|
|
249
|
+
</div>
|
|
232
250
|
</motion.div>
|
|
233
251
|
</SyncedFixedWrapper>
|
|
234
252
|
)}
|
|
@@ -22,6 +22,12 @@ type BlockScrollProps = {
|
|
|
22
22
|
el: HTMLElement;
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* @deprecated Potentially blocks scroll events unintentionally (wheel/touch/keyboard)
|
|
27
|
+
* and may interfere with internal scrollable areas (modals, lists, overflow containers).
|
|
28
|
+
* This API will be removed soon. Avoid using it and migrate to native behaviors
|
|
29
|
+
* or to local scroll handling at the component level.
|
|
30
|
+
*/
|
|
25
31
|
export const BlockScroll: React.FC<BlockScrollProps> = ({
|
|
26
32
|
onScroll,
|
|
27
33
|
el,
|
|
@@ -143,11 +149,73 @@ export const BlockScroll: React.FC<BlockScrollProps> = ({
|
|
|
143
149
|
lastTouch.current = null;
|
|
144
150
|
};
|
|
145
151
|
|
|
152
|
+
const interactiveRoles = new Set([
|
|
153
|
+
'textbox',
|
|
154
|
+
'listbox',
|
|
155
|
+
'menu',
|
|
156
|
+
'menubar',
|
|
157
|
+
'grid',
|
|
158
|
+
'tree',
|
|
159
|
+
'tablist',
|
|
160
|
+
'toolbar',
|
|
161
|
+
'radiogroup',
|
|
162
|
+
'combobox',
|
|
163
|
+
'spinbutton',
|
|
164
|
+
'slider',
|
|
165
|
+
]);
|
|
166
|
+
|
|
167
|
+
const isEditableOrInteractive = (node: HTMLElement | null) => {
|
|
168
|
+
if (!node) return false;
|
|
169
|
+
const tag = node.tagName.toLowerCase();
|
|
170
|
+
if (tag === 'input' || tag === 'textarea' || tag === 'select')
|
|
171
|
+
return true;
|
|
172
|
+
if ((node as HTMLInputElement).isContentEditable) return true;
|
|
173
|
+
if (tag === 'button') return true;
|
|
174
|
+
if (tag === 'a' && (node as HTMLAnchorElement).href) return true;
|
|
175
|
+
const role = node.getAttribute('role');
|
|
176
|
+
if (role && interactiveRoles.has(role)) return true;
|
|
177
|
+
return false;
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const hasInteractiveAncestor = (el: HTMLElement | null) => {
|
|
181
|
+
let n: HTMLElement | null = el;
|
|
182
|
+
while (n && n !== document.body && n !== document.documentElement) {
|
|
183
|
+
if (isEditableOrInteractive(n)) return true;
|
|
184
|
+
n = n.parentElement;
|
|
185
|
+
}
|
|
186
|
+
return false;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const canAncestorScroll = (start: HTMLElement | null, dy: number) => {
|
|
190
|
+
let n: HTMLElement | null = start;
|
|
191
|
+
while (n && n !== el) {
|
|
192
|
+
const style = window.getComputedStyle(n);
|
|
193
|
+
const overflowY = style.overflowY || style.overflow;
|
|
194
|
+
const canScrollY =
|
|
195
|
+
(overflowY === 'auto' || overflowY === 'scroll') &&
|
|
196
|
+
n.scrollHeight > n.clientHeight;
|
|
197
|
+
if (canScrollY) {
|
|
198
|
+
const canDown = n.scrollTop < n.scrollHeight - n.clientHeight;
|
|
199
|
+
const canUp = n.scrollTop > 0;
|
|
200
|
+
if ((dy > 0 && canDown) || (dy < 0 && canUp)) return true;
|
|
201
|
+
}
|
|
202
|
+
n = n.parentElement;
|
|
203
|
+
}
|
|
204
|
+
return false;
|
|
205
|
+
};
|
|
206
|
+
|
|
146
207
|
const onKeyDown = (e: KeyboardEvent) => {
|
|
208
|
+
if (e.defaultPrevented) return;
|
|
209
|
+
|
|
210
|
+
// Garder les comportements natifs pour les éléments interactifs
|
|
211
|
+
const target = e.target as HTMLElement | null;
|
|
212
|
+
if (isEditableOrInteractive(target) || hasInteractiveAncestor(target)) {
|
|
213
|
+
return; // ne pas empêcher
|
|
214
|
+
}
|
|
215
|
+
|
|
147
216
|
const line = 40;
|
|
148
217
|
const page = el.clientHeight * 0.9;
|
|
149
|
-
let
|
|
150
|
-
dy = 0;
|
|
218
|
+
let dy = 0;
|
|
151
219
|
|
|
152
220
|
switch (e.key) {
|
|
153
221
|
case 'ArrowDown':
|
|
@@ -156,12 +224,6 @@ export const BlockScroll: React.FC<BlockScrollProps> = ({
|
|
|
156
224
|
case 'ArrowUp':
|
|
157
225
|
dy = -line;
|
|
158
226
|
break;
|
|
159
|
-
case 'ArrowRight':
|
|
160
|
-
dx = line;
|
|
161
|
-
break;
|
|
162
|
-
case 'ArrowLeft':
|
|
163
|
-
dx = -line;
|
|
164
|
-
break;
|
|
165
227
|
case 'PageDown':
|
|
166
228
|
dy = page;
|
|
167
229
|
break;
|
|
@@ -174,17 +236,33 @@ export const BlockScroll: React.FC<BlockScrollProps> = ({
|
|
|
174
236
|
case 'End':
|
|
175
237
|
dy = Number.POSITIVE_INFINITY;
|
|
176
238
|
break;
|
|
177
|
-
case ' ':
|
|
239
|
+
case ' ': {
|
|
240
|
+
// Espace: laisser passer sur boutons/inputs/etc. déjà filtrés ci-dessus
|
|
178
241
|
dy = e.shiftKey ? -page : page;
|
|
179
242
|
break;
|
|
243
|
+
}
|
|
180
244
|
default:
|
|
181
|
-
return;
|
|
245
|
+
return; // ne pas gérer, laisser natif
|
|
182
246
|
}
|
|
247
|
+
|
|
248
|
+
// Si un ancêtre (≠ el) peut scroller dans ce sens, laisser le natif
|
|
249
|
+
if (canAncestorScroll(target, dy)) return;
|
|
250
|
+
|
|
251
|
+
// Ne gérer que si focus est sur body/html ou dans el
|
|
252
|
+
const ae = document.activeElement as HTMLElement | null;
|
|
253
|
+
const focusInsideEl =
|
|
254
|
+
ae &&
|
|
255
|
+
(ae === document.body ||
|
|
256
|
+
ae === document.documentElement ||
|
|
257
|
+
el.contains(ae));
|
|
258
|
+
if (!focusInsideEl) return;
|
|
259
|
+
|
|
260
|
+
// OK on prend en charge: empêcher le natif et émettre l’intention
|
|
183
261
|
e.preventDefault();
|
|
184
262
|
emitIntent({
|
|
185
263
|
type: 'intent',
|
|
186
264
|
source: 'keyboard',
|
|
187
|
-
deltaX:
|
|
265
|
+
deltaX: 0,
|
|
188
266
|
deltaY: dy,
|
|
189
267
|
originalEvent: e,
|
|
190
268
|
});
|
|
@@ -4,6 +4,11 @@ import { ReactProps } from '../utils';
|
|
|
4
4
|
import { BlockScroll } from './block-scroll.effect';
|
|
5
5
|
import { animate, AnimationPlaybackControls } from 'motion';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* WARNING: using this component is not recommended for now.
|
|
9
|
+
* It may block or alter certain scroll events (wheel/touch/keyboard) depending on the context.
|
|
10
|
+
* Rework it later (e.g., via Lenis or another solution) before using it in production.
|
|
11
|
+
*/
|
|
7
12
|
export const SmoothScroll = ({
|
|
8
13
|
transition,
|
|
9
14
|
orientation = 'vertical',
|
package/src/lib/icon/icon.tsx
CHANGED
|
@@ -17,7 +17,12 @@ interface Props {
|
|
|
17
17
|
className?: string;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export const Icon: React.FC<Props> = ({
|
|
20
|
+
export const Icon: React.FC<Props> = ({
|
|
21
|
+
icon,
|
|
22
|
+
colors = [],
|
|
23
|
+
className,
|
|
24
|
+
...restProps
|
|
25
|
+
}) => {
|
|
21
26
|
// Si c'est une chaîne de caractères (SVG raw)
|
|
22
27
|
if (typeof icon === 'string') {
|
|
23
28
|
// Modifier la couleur du SVG en remplaçant les attributs fill/stroke
|
|
@@ -98,6 +103,7 @@ export const Icon: React.FC<Props> = ({ icon, colors = [], className }) => {
|
|
|
98
103
|
viewBox={`0 0 ${width} ${height}`}
|
|
99
104
|
role="img"
|
|
100
105
|
aria-hidden="true"
|
|
106
|
+
{...restProps}
|
|
101
107
|
>
|
|
102
108
|
{typeof svgPathData === 'string' ? (
|
|
103
109
|
<path className={'fill-current'} d={svgPathData} />
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { ActionOrLink } from '../utils';
|
|
2
|
+
import { Transition } from 'motion';
|
|
3
|
+
import { Icon } from '../icon';
|
|
4
|
+
|
|
5
|
+
type ChipVariant = 'outlined' | 'elevated';
|
|
6
|
+
|
|
7
|
+
export type ChipProps = {
|
|
8
|
+
/**
|
|
9
|
+
* The label is the text that is displayed on the chip.
|
|
10
|
+
*/
|
|
11
|
+
label?: string;
|
|
12
|
+
|
|
13
|
+
children?: string;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The chip variant determines the style.
|
|
17
|
+
*/
|
|
18
|
+
variant?: ChipVariant;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Disables the chip if set to true.
|
|
22
|
+
*/
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* An optional icon to display in the chip.
|
|
27
|
+
*/
|
|
28
|
+
icon?: Icon;
|
|
29
|
+
|
|
30
|
+
transition?: Transition;
|
|
31
|
+
|
|
32
|
+
onToggle?: (isActive: boolean) => void;
|
|
33
|
+
|
|
34
|
+
activated?: boolean;
|
|
35
|
+
|
|
36
|
+
onRemove?: () => void;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Enable native HTML drag and drop on the chip.
|
|
40
|
+
*/
|
|
41
|
+
draggable?: boolean;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Called when drag starts (composed with internal handler that sets isDragging).
|
|
45
|
+
*/
|
|
46
|
+
onDragStart?: (e: React.DragEvent) => void;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Called when drag ends (composed with internal handler that clears isDragging).
|
|
50
|
+
*/
|
|
51
|
+
onDragEnd?: (e: React.DragEvent) => void;
|
|
52
|
+
} & (
|
|
53
|
+
| {
|
|
54
|
+
editable?: false;
|
|
55
|
+
editing?: never;
|
|
56
|
+
onEditStart?: never;
|
|
57
|
+
onEditCommit: never;
|
|
58
|
+
onEditCancel?: never;
|
|
59
|
+
onChange?: never;
|
|
60
|
+
}
|
|
61
|
+
| {
|
|
62
|
+
/** Enable label inline edition for this chip (used by Chips variant="input"). */
|
|
63
|
+
editable?: true;
|
|
64
|
+
|
|
65
|
+
/** Affirms that the chip is currently being edited. */
|
|
66
|
+
editing?: boolean;
|
|
67
|
+
|
|
68
|
+
/** Request to start editing (e.g., double-click, Enter/F2). */
|
|
69
|
+
onEditStart?: () => void;
|
|
70
|
+
|
|
71
|
+
/** Commit edition with the new label. */
|
|
72
|
+
onEditCommit: (nextLabel: string) => void;
|
|
73
|
+
|
|
74
|
+
/** Cancel edition and restore previous label. */
|
|
75
|
+
onEditCancel?: () => void;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Fired on each edit keystroke when content changes (only while editing).
|
|
79
|
+
* Useful for live formatting, suggestions, validation, etc.
|
|
80
|
+
*/
|
|
81
|
+
onChange?: (nextLabel: string) => void;
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
type Elements = ['chip', 'stateLayer', 'leadingIcon', 'trailingIcon', 'label'];
|
|
86
|
+
|
|
87
|
+
export type ChipInterface = ActionOrLink<ChipProps> & {
|
|
88
|
+
elements: Elements;
|
|
89
|
+
states: {
|
|
90
|
+
isActive: boolean;
|
|
91
|
+
trailingIcon?: boolean;
|
|
92
|
+
isFocused: boolean;
|
|
93
|
+
isInteractive: boolean;
|
|
94
|
+
isDragging?: boolean;
|
|
95
|
+
isEditing?: boolean;
|
|
96
|
+
};
|
|
97
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ActionOrLink } from '../utils';
|
|
2
|
+
import type { Icon } from '../icon';
|
|
3
|
+
|
|
4
|
+
// Ce que Chips a besoin de connaître pour (re)construire un Chip
|
|
5
|
+
export type ChipItem = {
|
|
6
|
+
label: string;
|
|
7
|
+
icon?: Icon;
|
|
8
|
+
activated?: boolean;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
variant?: 'outlined' | 'elevated';
|
|
11
|
+
href?: string; // si tu utilises ActionOrLink côté Chip
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
type ChipsVariant = 'input';
|
|
15
|
+
|
|
16
|
+
type Props = {
|
|
17
|
+
/** Style du conteneur de chips */
|
|
18
|
+
variant?: ChipsVariant;
|
|
19
|
+
|
|
20
|
+
/** Active/masse un comportement de container (si utile) */
|
|
21
|
+
scrollable?: boolean;
|
|
22
|
+
|
|
23
|
+
draggable?: boolean; // optionnel
|
|
24
|
+
|
|
25
|
+
/** Mode contrôlé: la source de vérité */
|
|
26
|
+
items?: ChipItem[];
|
|
27
|
+
|
|
28
|
+
/** Notifie toute modification de la liste (remove, toggle, etc.) */
|
|
29
|
+
onItemsChange?: (next: ChipItem[]) => void;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
type Elements = ['chips'];
|
|
33
|
+
|
|
34
|
+
export type ChipsInterface = ActionOrLink<Props> & {
|
|
35
|
+
elements: Elements;
|
|
36
|
+
states: {};
|
|
37
|
+
};
|
|
@@ -2,6 +2,8 @@ export * from './button.interface';
|
|
|
2
2
|
export * from './card.interface';
|
|
3
3
|
export * from './carousel-item.interface';
|
|
4
4
|
export * from './carousel.interface';
|
|
5
|
+
export * from './chip.interface';
|
|
6
|
+
export * from './chips.interface';
|
|
5
7
|
export * from './divider.interface';
|
|
6
8
|
export * from './fab.interface';
|
|
7
9
|
export * from './fab-menu.interface';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ReactProps } from '../utils';
|
|
2
2
|
import { ButtonInterface } from './button.interface';
|
|
3
3
|
import { ReactNode, RefObject } from 'react';
|
|
4
|
+
import { Transition } from 'motion';
|
|
4
5
|
|
|
5
6
|
type Trigger = 'hover' | 'click' | 'focus' | null;
|
|
6
7
|
|
|
@@ -21,6 +22,7 @@ export type ToolTipInterface<T extends HTMLElement = any> = {
|
|
|
21
22
|
| 'bottom-left'
|
|
22
23
|
| 'bottom-right';
|
|
23
24
|
trigger?: Trigger | Trigger[];
|
|
25
|
+
transition?: Transition;
|
|
24
26
|
} & (
|
|
25
27
|
| {
|
|
26
28
|
children?: never;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { ClassNameComponent } from '../utils';
|
|
2
|
+
import { classNames, createUseClassNames, defaultClassNames } from '../utils';
|
|
3
|
+
import { ChipInterface } from '../interfaces';
|
|
4
|
+
|
|
5
|
+
const chipConfig: ClassNameComponent<ChipInterface> = ({
|
|
6
|
+
variant,
|
|
7
|
+
|
|
8
|
+
disabled,
|
|
9
|
+
trailingIcon,
|
|
10
|
+
icon,
|
|
11
|
+
isActive,
|
|
12
|
+
isInteractive,
|
|
13
|
+
activated,
|
|
14
|
+
isFocused,
|
|
15
|
+
isDragging,
|
|
16
|
+
isEditing,
|
|
17
|
+
}) => ({
|
|
18
|
+
chip: classNames(
|
|
19
|
+
' group/chip px-3 py-1.5 rounded-lg flex items-center gap-2 outline-none',
|
|
20
|
+
{
|
|
21
|
+
'pl-2': icon,
|
|
22
|
+
'pr-2': trailingIcon,
|
|
23
|
+
'cursor-pointer': !disabled && isInteractive,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
' text-on-surface-variant': (!activated && !isFocused) || isEditing,
|
|
27
|
+
'bg-secondary-container text-on-secondary-container':
|
|
28
|
+
(activated || isFocused) && !isEditing,
|
|
29
|
+
},
|
|
30
|
+
// Dragging feedback
|
|
31
|
+
isDragging && ['opacity-100 cursor-grabbing shadow-3'],
|
|
32
|
+
variant === 'outlined' && [
|
|
33
|
+
'border border-outline-variant',
|
|
34
|
+
{
|
|
35
|
+
'border-transparent': isEditing,
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
variant === 'elevated' &&
|
|
39
|
+
!isEditing && [
|
|
40
|
+
'shadow-1 bg-surface-container-low',
|
|
41
|
+
'border border-outline-variant',
|
|
42
|
+
],
|
|
43
|
+
),
|
|
44
|
+
|
|
45
|
+
stateLayer: classNames('rounded-lg overflow-hidden', {}),
|
|
46
|
+
label: classNames('outline-none text-nowrap', {
|
|
47
|
+
'opacity-[0.38]': disabled,
|
|
48
|
+
}),
|
|
49
|
+
leadingIcon: classNames('text-primary size-[18px]', {
|
|
50
|
+
'opacity-[0.38]': disabled,
|
|
51
|
+
}),
|
|
52
|
+
trailingIcon: classNames('cursor-pointer size-[18px]', {
|
|
53
|
+
'opacity-[0.38]': disabled,
|
|
54
|
+
}),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
export const chipStyle = defaultClassNames<ChipInterface>('chip', chipConfig);
|
|
58
|
+
|
|
59
|
+
export const useChipStyle = createUseClassNames<ChipInterface>(
|
|
60
|
+
'chip',
|
|
61
|
+
chipConfig,
|
|
62
|
+
);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ClassNameComponent } from '../utils';
|
|
2
|
+
import { classNames, createUseClassNames, defaultClassNames } from '../utils';
|
|
3
|
+
import { ChipsInterface } from '../interfaces';
|
|
4
|
+
|
|
5
|
+
const chipsConfig: ClassNameComponent<ChipsInterface> = ({ scrollable }) => ({
|
|
6
|
+
chips: classNames(' flex gap-3 outline-none', {
|
|
7
|
+
'flex-wrap': !scrollable,
|
|
8
|
+
'overflow-x-auto': scrollable,
|
|
9
|
+
}),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export const chipsStyle = defaultClassNames<ChipsInterface>(
|
|
13
|
+
'chips',
|
|
14
|
+
chipsConfig,
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
export const useChipsStyle = createUseClassNames<ChipsInterface>(
|
|
18
|
+
'chips',
|
|
19
|
+
chipsConfig,
|
|
20
|
+
);
|
|
@@ -15,6 +15,7 @@ const fabMenuConfig: ClassNameComponent<FabMenuInterface> = ({
|
|
|
15
15
|
actions: classNames(
|
|
16
16
|
'flex flex-col gap-1 items-end absolute bottom-[calc(100%_+_8px)] right-0',
|
|
17
17
|
),
|
|
18
|
+
label: classNames('text-nowrap'),
|
|
18
19
|
});
|
|
19
20
|
|
|
20
21
|
export const fabMenuStyle = defaultClassNames<FabMenuInterface>(
|
package/src/lib/styles/index.ts
CHANGED
|
@@ -2,6 +2,8 @@ export * from './button.style';
|
|
|
2
2
|
export * from './card.style';
|
|
3
3
|
export * from './carousel-item.style';
|
|
4
4
|
export * from './carousel.style';
|
|
5
|
+
export * from './chip.style';
|
|
6
|
+
export * from './chips.style';
|
|
5
7
|
export * from './divider.style';
|
|
6
8
|
export * from './fab.style';
|
|
7
9
|
export * from './fab-menu.style';
|
|
@@ -12,6 +12,9 @@ const toolTipConfig: ClassNameComponent<ToolTipInterface> = ({
|
|
|
12
12
|
}) => ({
|
|
13
13
|
toolTip: classNames(
|
|
14
14
|
' pointer-events-auto w-max z-10 absolute m-1 w-max-content max-w-[312px]',
|
|
15
|
+
variant == 'rich' &&
|
|
16
|
+
'bg-surface-container rounded-2xl text-on-surface-container shadow-2',
|
|
17
|
+
variant == 'plain' && 'bg-inverse-surface rounded text-inverse-on-surface ',
|
|
15
18
|
{
|
|
16
19
|
'bottom-full left-1/2 -translate-x-1/2': position == 'top',
|
|
17
20
|
'top-full left-1/2 -translate-x-1/2': position == 'bottom',
|
|
@@ -25,10 +28,8 @@ const toolTipConfig: ClassNameComponent<ToolTipInterface> = ({
|
|
|
25
28
|
),
|
|
26
29
|
container: classNames(
|
|
27
30
|
'pb-2',
|
|
28
|
-
variant == 'rich' &&
|
|
29
|
-
|
|
30
|
-
variant == 'plain' &&
|
|
31
|
-
'bg-inverse-surface rounded text-inverse-on-surface px-2 py-1',
|
|
31
|
+
variant == 'rich' && 'px-4 pt-3 ',
|
|
32
|
+
variant == 'plain' && 'px-2 py-1',
|
|
32
33
|
),
|
|
33
34
|
actions: classNames('flex gap-10 px-1 mt-2', variant == 'plain' && 'hidden'),
|
|
34
35
|
subHead: classNames('text-title-small mb-1', variant == 'plain' && 'hidden'),
|