allaw-ui 4.1.4 → 4.1.5

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.
@@ -11,6 +11,8 @@ export interface AvatarBubbleProps {
11
11
  alt?: string;
12
12
  className?: string;
13
13
  borderThick?: boolean;
14
+ showTooltip?: boolean;
15
+ tooltipId?: string;
14
16
  }
15
17
  declare const AvatarBubble: React.FC<AvatarBubbleProps>;
16
18
  export default AvatarBubble;
@@ -1,5 +1,17 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
1
12
  import React, { useState, useCallback } from "react";
2
13
  import Image from "next/image";
14
+ import { Tooltip } from "react-tooltip";
3
15
  import styles from "./avatarBubble.module.css";
4
16
  // Fonction de hash simple (DJB2)
5
17
  var hashString = function (str) {
@@ -24,13 +36,14 @@ var generateInitials = function (firstName, name) {
24
36
  return "".concat(firstInitial).concat(lastInitial);
25
37
  };
26
38
  var AvatarBubble = function (_a) {
27
- var firstName = _a.firstName, name = _a.name, src = _a.src, _b = _a.size, size = _b === void 0 ? 42.5 : _b, _c = _a.isSelected, isSelected = _c === void 0 ? false : _c, _d = _a.disabled, disabled = _d === void 0 ? false : _d, _e = _a.disableHoverAnimation, disableHoverAnimation = _e === void 0 ? false : _e, onClick = _a.onClick, alt = _a.alt, _f = _a.className, className = _f === void 0 ? "" : _f, _g = _a.borderThick, borderThick = _g === void 0 ? false : _g;
28
- var _h = useState(false), imageError = _h[0], setImageError = _h[1];
39
+ var firstName = _a.firstName, name = _a.name, src = _a.src, _b = _a.size, size = _b === void 0 ? 42.5 : _b, _c = _a.isSelected, isSelected = _c === void 0 ? false : _c, _d = _a.disabled, disabled = _d === void 0 ? false : _d, _e = _a.disableHoverAnimation, disableHoverAnimation = _e === void 0 ? false : _e, onClick = _a.onClick, alt = _a.alt, _f = _a.className, className = _f === void 0 ? "" : _f, _g = _a.borderThick, borderThick = _g === void 0 ? false : _g, _h = _a.showTooltip, showTooltip = _h === void 0 ? false : _h, _j = _a.tooltipId, tooltipId = _j === void 0 ? "avatar-tooltip" : _j;
40
+ var _k = useState(false), imageError = _k[0], setImageError = _k[1];
29
41
  var hasValidSrc = src && src.trim() !== "";
30
42
  var shouldShowInitials = !hasValidSrc || imageError;
31
43
  var backgroundColor = generateBackgroundColor(firstName, name);
32
44
  var initials = generateInitials(firstName, name);
33
45
  var displayAlt = alt || "".concat(firstName, " ").concat(name);
46
+ var fullName = "".concat(firstName, " ").concat(name);
34
47
  var ariaLabel = "".concat(firstName, " ").concat(name).concat(isSelected ? ", sélectionné(e)" : "");
35
48
  var handleImageError = useCallback(function () {
36
49
  setImageError(true);
@@ -54,19 +67,34 @@ var AvatarBubble = function (_a) {
54
67
  backgroundColor: backgroundColor,
55
68
  fontSize: "".concat(Math.max(12, size * 0.4), "px"),
56
69
  };
57
- return (React.createElement("div", { className: "".concat(styles.avatarBubble, " ").concat(className, " ") +
58
- (borderThick
59
- ? isSelected
60
- ? styles.selectedThick
61
- : styles.thick
62
- : isSelected
63
- ? styles.selectedThin
64
- : styles.thin), style: containerStyle, role: "button", "aria-label": ariaLabel, tabIndex: disabled ? -1 : 0, onClick: handleClick, onKeyDown: handleKeyDown, "data-selected": isSelected, "data-disabled": disabled, "data-disable-hover-animation": disableHoverAnimation }, shouldShowInitials ? (React.createElement("div", { className: styles.initials, style: initialsStyle, "aria-label": displayAlt }, initials)) : (React.createElement("div", { className: styles.imageContainer },
65
- React.createElement(Image, { src: src, alt: displayAlt, width: size, height: size, className: styles.image, onError: handleImageError, onLoad: function () { return setImageError(false); }, style: {
66
- objectFit: "cover",
67
- width: "100%",
68
- height: "100%",
69
- borderRadius: "50%",
70
- } })))));
70
+ return (React.createElement(React.Fragment, null,
71
+ React.createElement("div", __assign({ className: "".concat(styles.avatarBubble, " ").concat(className, " ") +
72
+ (borderThick
73
+ ? isSelected
74
+ ? styles.selectedThick
75
+ : styles.thick
76
+ : isSelected
77
+ ? styles.selectedThin
78
+ : styles.thin), style: containerStyle, role: "button", "aria-label": ariaLabel, tabIndex: disabled ? -1 : 0, onClick: handleClick, onKeyDown: handleKeyDown, "data-selected": isSelected, "data-disabled": disabled, "data-disable-hover-animation": disableHoverAnimation }, (showTooltip && {
79
+ "data-tooltip-id": tooltipId,
80
+ "data-tooltip-content": fullName,
81
+ })), shouldShowInitials ? (React.createElement("div", { className: styles.initials, style: initialsStyle, "aria-label": displayAlt }, initials)) : (React.createElement("div", { className: styles.imageContainer },
82
+ React.createElement(Image, { src: src, alt: displayAlt, width: size, height: size, className: styles.image, onError: handleImageError, onLoad: function () { return setImageError(false); }, style: {
83
+ objectFit: "cover",
84
+ width: "100%",
85
+ height: "100%",
86
+ borderRadius: "50%",
87
+ } })))),
88
+ showTooltip && (React.createElement(Tooltip, { id: tooltipId, place: "top", style: {
89
+ fontSize: "12px",
90
+ color: "#FFF",
91
+ background: "#171E25",
92
+ maxWidth: "400px",
93
+ whiteSpace: "wrap",
94
+ fontFamily: "'SF Pro Display', 'Source Sans Pro', 'Open Sans', sans-serif",
95
+ padding: "4px 8px",
96
+ margin: "0",
97
+ zIndex: 1000,
98
+ }, delayShow: 500, noArrow: true, opacity: 0.87 }))));
71
99
  };
72
100
  export default AvatarBubble;
@@ -54,17 +54,29 @@ declare namespace _default {
54
54
  let description_7: string;
55
55
  export { description_7 as description };
56
56
  }
57
- namespace onClick {
58
- export let action: string;
57
+ namespace showTooltip {
58
+ let control_8: string;
59
+ export { control_8 as control };
59
60
  let description_8: string;
60
61
  export { description_8 as description };
61
62
  }
62
- namespace alt {
63
- let control_8: string;
64
- export { control_8 as control };
63
+ namespace tooltipId {
64
+ let control_9: string;
65
+ export { control_9 as control };
65
66
  let description_9: string;
66
67
  export { description_9 as description };
67
68
  }
69
+ namespace onClick {
70
+ export let action: string;
71
+ let description_10: string;
72
+ export { description_10 as description };
73
+ }
74
+ namespace alt {
75
+ let control_10: string;
76
+ export { control_10 as control };
77
+ let description_11: string;
78
+ export { description_11 as description };
79
+ }
68
80
  }
69
81
  export namespace parameters {
70
82
  namespace backgrounds {
@@ -50,6 +50,14 @@ export default {
50
50
  control: "boolean",
51
51
  description: "Bordure épaisse (4px) autour de l'avatar si true, 2px sinon (défaut)",
52
52
  },
53
+ showTooltip: {
54
+ control: "boolean",
55
+ description: "Afficher le tooltip avec le nom complet au hover",
56
+ },
57
+ tooltipId: {
58
+ control: "text",
59
+ description: "ID personnalisé pour le tooltip",
60
+ },
53
61
  onClick: {
54
62
  action: "clicked",
55
63
  description: "Callback appelé au clic",
@@ -90,6 +98,8 @@ Default.args = {
90
98
  disabled: false,
91
99
  disableHoverAnimation: false,
92
100
  borderThick: false,
101
+ showTooltip: true,
102
+ tooltipId: "avatar-tooltip",
93
103
  };
94
104
  export var WithInitials = Template.bind({});
95
105
  WithInitials.args = {
@@ -101,6 +111,8 @@ WithInitials.args = {
101
111
  disabled: false,
102
112
  disableHoverAnimation: false,
103
113
  borderThick: false,
114
+ showTooltip: true,
115
+ tooltipId: "avatar-tooltip",
104
116
  };
105
117
  export var Selected = Template.bind({});
106
118
  Selected.args = {
@@ -112,6 +124,8 @@ Selected.args = {
112
124
  disabled: false,
113
125
  disableHoverAnimation: false,
114
126
  borderThick: false,
127
+ showTooltip: true,
128
+ tooltipId: "avatar-tooltip",
115
129
  };
116
130
  export var Disabled = Template.bind({});
117
131
  Disabled.args = {
@@ -123,6 +137,8 @@ Disabled.args = {
123
137
  disabled: true,
124
138
  disableHoverAnimation: false,
125
139
  borderThick: false,
140
+ showTooltip: true,
141
+ tooltipId: "avatar-tooltip",
126
142
  };
127
143
  export var Small = Template.bind({});
128
144
  Small.args = {
@@ -134,6 +150,8 @@ Small.args = {
134
150
  disabled: false,
135
151
  disableHoverAnimation: false,
136
152
  borderThick: false,
153
+ showTooltip: true,
154
+ tooltipId: "avatar-tooltip",
137
155
  };
138
156
  export var Large = Template.bind({});
139
157
  Large.args = {
@@ -145,6 +163,8 @@ Large.args = {
145
163
  disabled: false,
146
164
  disableHoverAnimation: false,
147
165
  borderThick: false,
166
+ showTooltip: true,
167
+ tooltipId: "avatar-tooltip",
148
168
  };
149
169
  export var WithoutHoverAnimation = Template.bind({});
150
170
  WithoutHoverAnimation.args = {
@@ -156,6 +176,8 @@ WithoutHoverAnimation.args = {
156
176
  disabled: false,
157
177
  disableHoverAnimation: true,
158
178
  borderThick: false,
179
+ showTooltip: true,
180
+ tooltipId: "avatar-tooltip",
159
181
  };
160
182
  export var SelectedWithoutHoverAnimation = Template.bind({});
161
183
  SelectedWithoutHoverAnimation.args = {
@@ -167,6 +189,8 @@ SelectedWithoutHoverAnimation.args = {
167
189
  disabled: false,
168
190
  disableHoverAnimation: true,
169
191
  borderThick: false,
192
+ showTooltip: true,
193
+ tooltipId: "avatar-tooltip",
170
194
  };
171
195
  export var MultipleSizes = function () {
172
196
  var _a = useState(0), selectedIndex = _a[0], setSelectedIndex = _a[1];
@@ -180,7 +204,7 @@ export var MultipleSizes = function () {
180
204
  display: "flex",
181
205
  gap: "20px",
182
206
  alignItems: "center",
183
- } }, avatars.map(function (avatar, index) { return (React.createElement(AvatarBubble, { key: index, firstName: avatar.firstName, name: avatar.name, size: avatar.size, isSelected: selectedIndex === index, onClick: function () { return setSelectedIndex(index); } })); })));
207
+ } }, avatars.map(function (avatar, index) { return (React.createElement(AvatarBubble, { key: index, firstName: avatar.firstName, name: avatar.name, size: avatar.size, isSelected: selectedIndex === index, onClick: function () { return setSelectedIndex(index); }, showTooltip: true, tooltipId: "multiple-sizes-tooltip" })); })));
184
208
  };
185
209
  export var ColorVariations = function () {
186
210
  var names = [
@@ -196,7 +220,7 @@ export var ColorVariations = function () {
196
220
  display: "flex",
197
221
  gap: "10px",
198
222
  flexWrap: "wrap",
199
- } }, names.map(function (name, index) { return (React.createElement(AvatarBubble, { key: index, firstName: name.firstName, name: name.name, size: 42.5, onClick: function () { return action("Clicked ".concat(name.firstName, " ").concat(name.name))(); } })); })));
223
+ } }, names.map(function (name, index) { return (React.createElement(AvatarBubble, { key: index, firstName: name.firstName, name: name.name, size: 42.5, onClick: function () { return action("Clicked ".concat(name.firstName, " ").concat(name.name))(); }, showTooltip: true, tooltipId: "color-variations-tooltip" })); })));
200
224
  };
201
225
  export var HoverAnimationComparison = function () {
202
226
  var _a = useState(0), selectedIndex = _a[0], setSelectedIndex = _a[1];
@@ -208,8 +232,8 @@ export var HoverAnimationComparison = function () {
208
232
  } },
209
233
  React.createElement("div", { style: { textAlign: "center" } },
210
234
  React.createElement("h4", { style: { marginBottom: "10px" } }, "Avec animation"),
211
- React.createElement(AvatarBubble, { firstName: "Jean", name: "Dupont", src: "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=150&h=150&fit=crop&crop=face", size: 42.5, isSelected: selectedIndex === 0, onClick: function () { return setSelectedIndex(0); } })),
235
+ React.createElement(AvatarBubble, { firstName: "Jean", name: "Dupont", src: "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=150&h=150&fit=crop&crop=face", size: 42.5, isSelected: selectedIndex === 0, onClick: function () { return setSelectedIndex(0); }, showTooltip: true, tooltipId: "hover-comparison-tooltip" })),
212
236
  React.createElement("div", { style: { textAlign: "center" } },
213
237
  React.createElement("h4", { style: { marginBottom: "10px" } }, "Sans animation"),
214
- React.createElement(AvatarBubble, { firstName: "Marie", name: "Martin", src: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=150&h=150&fit=crop&crop=face", size: 42.5, isSelected: selectedIndex === 1, onClick: function () { return setSelectedIndex(1); }, disableHoverAnimation: true }))));
238
+ React.createElement(AvatarBubble, { firstName: "Marie", name: "Martin", src: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=150&h=150&fit=crop&crop=face", size: 42.5, isSelected: selectedIndex === 1, onClick: function () { return setSelectedIndex(1); }, disableHoverAnimation: true, showTooltip: true, tooltipId: "hover-comparison-tooltip" }))));
215
239
  };
@@ -16,6 +16,8 @@ export interface AvatarToggleGroupProps {
16
16
  disabled?: boolean;
17
17
  onOpenPortal?: () => void;
18
18
  className?: string;
19
+ showTooltips?: boolean;
20
+ tooltipId?: string;
19
21
  }
20
22
  declare const AvatarToggleGroup: React.FC<AvatarToggleGroupProps>;
21
23
  export default AvatarToggleGroup;
@@ -9,12 +9,13 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
9
9
  };
10
10
  import React, { useState, useRef, useEffect, useCallback } from "react";
11
11
  import AvatarBubble from "./AvatarBubble";
12
+ import { Tooltip } from "react-tooltip";
12
13
  import styles from "./avatarToggleGroup.module.css";
13
14
  var AvatarToggleGroup = function (_a) {
14
- var pros = _a.pros, mode = _a.mode, selected = _a.selected, onSelect = _a.onSelect, maxVisible = _a.maxVisible, _b = _a.disabled, disabled = _b === void 0 ? false : _b, onOpenPortal = _a.onOpenPortal, _c = _a.className, className = _c === void 0 ? "" : _c;
15
+ var pros = _a.pros, mode = _a.mode, selected = _a.selected, onSelect = _a.onSelect, maxVisible = _a.maxVisible, _b = _a.disabled, disabled = _b === void 0 ? false : _b, onOpenPortal = _a.onOpenPortal, _c = _a.className, className = _c === void 0 ? "" : _c, _d = _a.showTooltips, showTooltips = _d === void 0 ? false : _d, _e = _a.tooltipId, tooltipId = _e === void 0 ? "avatar-toggle-tooltip" : _e;
15
16
  var containerRef = useRef(null);
16
- var _d = useState(maxVisible || 0), calculatedMaxVisible = _d[0], setCalculatedMaxVisible = _d[1];
17
- var _e = useState(-1), focusedIndex = _e[0], setFocusedIndex = _e[1];
17
+ var _f = useState(maxVisible || 0), calculatedMaxVisible = _f[0], setCalculatedMaxVisible = _f[1];
18
+ var _g = useState(-1), focusedIndex = _g[0], setFocusedIndex = _g[1];
18
19
  // Calcul dynamique de maxVisible
19
20
  var calculateMaxVisible = useCallback(function () {
20
21
  if (maxVisible !== undefined) {
@@ -69,6 +70,11 @@ var AvatarToggleGroup = function (_a) {
69
70
  // En mode multiple, on toggle
70
71
  var isCurrentlySelected = selected.includes(pro.proUserId);
71
72
  if (isCurrentlySelected) {
73
+ // Empêcher la désélection totale en mode multiple
74
+ if (selected.length === 1) {
75
+ // Garder la sélection actuelle
76
+ return;
77
+ }
72
78
  newSelected = selected.filter(function (id) { return id !== pro.proUserId; });
73
79
  }
74
80
  else {
@@ -141,10 +147,21 @@ var AvatarToggleGroup = function (_a) {
141
147
  zIndex: isSelected ? 100 : visiblePros.length - index,
142
148
  marginLeft: index === 0 ? 0 : -8,
143
149
  } },
144
- React.createElement(AvatarBubble, { firstName: pro.firstName, name: pro.name, src: pro.profilePictureLink, size: 42.5, isSelected: isSelected, disabled: disabled, onClick: function () { return handleAvatarClick(pro); }, alt: "".concat(pro.firstName, " ").concat(pro.name), className: focusedIndex === index ? styles.focused : "" })));
150
+ React.createElement(AvatarBubble, { firstName: pro.firstName, name: pro.name, src: pro.profilePictureLink, size: 42.5, isSelected: isSelected, disabled: disabled, onClick: function () { return handleAvatarClick(pro); }, alt: "".concat(pro.firstName, " ").concat(pro.name), className: focusedIndex === index ? styles.focused : "", showTooltip: showTooltips, tooltipId: tooltipId })));
145
151
  })),
146
152
  hasHiddenPros && (React.createElement("button", { className: styles.moreButton, onClick: onOpenPortal, onKeyDown: handleKeyDown, disabled: disabled, "aria-label": "Voir ".concat(pros.length, " professionnels"), tabIndex: disabled ? -1 : 0 },
147
153
  "+",
148
- hiddenCount))));
154
+ hiddenCount)),
155
+ showTooltips && (React.createElement(Tooltip, { id: tooltipId, place: "top", style: {
156
+ fontSize: "12px",
157
+ color: "#FFF",
158
+ background: "#171E25",
159
+ maxWidth: "400px",
160
+ whiteSpace: "wrap",
161
+ fontFamily: "'SF Pro Display', 'Source Sans Pro', 'Open Sans', sans-serif",
162
+ padding: "4px 8px",
163
+ margin: "0",
164
+ zIndex: 1000,
165
+ }, delayShow: 500, noArrow: true, opacity: 0.87 }))));
149
166
  };
150
167
  export default AvatarToggleGroup;
@@ -50,6 +50,18 @@ declare namespace _default {
50
50
  let description_6: string;
51
51
  export { description_6 as description };
52
52
  }
53
+ namespace showTooltips {
54
+ let control_5: string;
55
+ export { control_5 as control };
56
+ let description_7: string;
57
+ export { description_7 as description };
58
+ }
59
+ namespace tooltipId {
60
+ let control_6: string;
61
+ export { control_6 as control };
62
+ let description_8: string;
63
+ export { description_8 as description };
64
+ }
53
65
  }
54
66
  export namespace parameters {
55
67
  namespace backgrounds {
@@ -71,5 +83,6 @@ export const WithMaxVisible: any;
71
83
  export const SingleWithInitials: any;
72
84
  export function ResponsiveTest(): React.JSX.Element;
73
85
  export function InteractiveDemo(): React.JSX.Element;
86
+ export function TooltipTest(): React.JSX.Element;
74
87
  import AvatarToggleGroup from "./AvatarToggleGroup";
75
88
  import React from "react";
@@ -53,6 +53,14 @@ export default {
53
53
  action: "portal opened",
54
54
  description: "Callback appelé à l'ouverture de la modal",
55
55
  },
56
+ showTooltips: {
57
+ control: "boolean",
58
+ description: "Afficher les tooltips sur chaque avatar",
59
+ },
60
+ tooltipId: {
61
+ control: "text",
62
+ description: "ID personnalisé pour les tooltips",
63
+ },
56
64
  },
57
65
  parameters: {
58
66
  backgrounds: {
@@ -144,7 +152,12 @@ var Template = function (args) {
144
152
  React.createElement("div", { style: { marginTop: "20px", fontSize: "14px", color: "#666" } },
145
153
  React.createElement("strong", null, "S\u00E9lection actuelle :"),
146
154
  " ",
147
- selected.join(", ") || "Aucune")));
155
+ selected.join(", ") || "Aucune",
156
+ React.createElement("br", null),
157
+ React.createElement("small", null, "\uD83D\uDCA1 Testez le hover sur les avatars pour voir les tooltips"),
158
+ args.mode === "multiple" && (React.createElement(React.Fragment, null,
159
+ React.createElement("br", null),
160
+ React.createElement("small", null, "\uD83D\uDD12 En mode multiple, impossible de d\u00E9s\u00E9lectionner le dernier pro"))))));
148
161
  };
149
162
  export var Default = Template.bind({});
150
163
  Default.args = {
@@ -152,6 +165,8 @@ Default.args = {
152
165
  mode: "single",
153
166
  selected: ["1"],
154
167
  disabled: false,
168
+ showTooltips: true,
169
+ tooltipId: "avatar-toggle-tooltip",
155
170
  };
156
171
  export var Multiple = Template.bind({});
157
172
  Multiple.args = {
@@ -159,6 +174,8 @@ Multiple.args = {
159
174
  mode: "multiple",
160
175
  selected: ["1", "3"],
161
176
  disabled: false,
177
+ showTooltips: true,
178
+ tooltipId: "avatar-toggle-tooltip",
162
179
  };
163
180
  export var WithManyPros = Template.bind({});
164
181
  WithManyPros.args = {
@@ -166,6 +183,8 @@ WithManyPros.args = {
166
183
  mode: "multiple",
167
184
  selected: ["1", "3", "5"],
168
185
  disabled: false,
186
+ showTooltips: true,
187
+ tooltipId: "avatar-toggle-tooltip",
169
188
  };
170
189
  export var Disabled = Template.bind({});
171
190
  Disabled.args = {
@@ -173,6 +192,8 @@ Disabled.args = {
173
192
  mode: "single",
174
193
  selected: ["1"],
175
194
  disabled: true,
195
+ showTooltips: true,
196
+ tooltipId: "avatar-toggle-tooltip",
176
197
  };
177
198
  export var WithMaxVisible = Template.bind({});
178
199
  WithMaxVisible.args = {
@@ -181,6 +202,8 @@ WithMaxVisible.args = {
181
202
  selected: ["1", "2"],
182
203
  maxVisible: 3,
183
204
  disabled: false,
205
+ showTooltips: true,
206
+ tooltipId: "avatar-toggle-tooltip",
184
207
  };
185
208
  export var SingleWithInitials = Template.bind({});
186
209
  SingleWithInitials.args = {
@@ -213,6 +236,8 @@ SingleWithInitials.args = {
213
236
  mode: "single",
214
237
  selected: ["1"],
215
238
  disabled: false,
239
+ showTooltips: true,
240
+ tooltipId: "avatar-toggle-tooltip",
216
241
  };
217
242
  export var ResponsiveTest = function () {
218
243
  var _a = useState(["1"]), selected = _a[0], setSelected = _a[1];
@@ -229,7 +254,7 @@ export var ResponsiveTest = function () {
229
254
  maxWidth: "100%",
230
255
  overflow: "hidden",
231
256
  } },
232
- React.createElement(AvatarToggleGroup, { pros: samplePros, mode: "multiple", selected: selected, onSelect: handleSelect, onOpenPortal: function () { return action("Portal opened")(); } })),
257
+ React.createElement(AvatarToggleGroup, { pros: samplePros, mode: "multiple", selected: selected, onSelect: handleSelect, onOpenPortal: function () { return action("Portal opened")(); }, showTooltips: true, tooltipId: "responsive-test-tooltip" })),
233
258
  React.createElement("div", { style: { fontSize: "14px", color: "#666" } },
234
259
  React.createElement("strong", null, "S\u00E9lection :"),
235
260
  " ",
@@ -264,7 +289,7 @@ export var InteractiveDemo = function () {
264
289
  padding: "20px",
265
290
  marginBottom: "20px",
266
291
  } },
267
- React.createElement(AvatarToggleGroup, { pros: samplePros.slice(0, 5), mode: mode, selected: selected, onSelect: handleSelect, disabled: disabled, onOpenPortal: function () { return action("Portal opened")(); } })),
292
+ React.createElement(AvatarToggleGroup, { pros: samplePros.slice(0, 5), mode: mode, selected: selected, onSelect: handleSelect, disabled: disabled, onOpenPortal: function () { return action("Portal opened")(); }, showTooltips: true, tooltipId: "interactive-demo-tooltip" })),
268
293
  React.createElement("div", { style: { fontSize: "14px", color: "#666" } },
269
294
  React.createElement("strong", null, "Mode :"),
270
295
  " ",
@@ -272,5 +297,32 @@ export var InteractiveDemo = function () {
272
297
  " | ",
273
298
  React.createElement("strong", null, "S\u00E9lection :"),
274
299
  " ",
275
- selected.join(", ") || "Aucune")));
300
+ selected.join(", ") || "Aucune",
301
+ React.createElement("br", null),
302
+ "\uD83D\uDCA1 Survolez les avatars pour voir les tooltips",
303
+ mode === "multiple" && (React.createElement(React.Fragment, null,
304
+ React.createElement("br", null),
305
+ "\uD83D\uDD12 En mode multiple, impossible de d\u00E9s\u00E9lectionner le dernier pro")))));
306
+ };
307
+ export var TooltipTest = function () {
308
+ var _a = useState(["1"]), selected = _a[0], setSelected = _a[1];
309
+ var handleSelect = function (selectedPros) {
310
+ setSelected(selectedPros.map(function (pro) { return pro.proUserId; }));
311
+ action("onSelect")(selectedPros);
312
+ };
313
+ return (React.createElement("div", { style: { padding: "20px" } },
314
+ React.createElement("h3", { style: { marginBottom: "10px" } }, "Test des Tooltips"),
315
+ React.createElement("p", { style: { marginBottom: "20px", fontSize: "14px", color: "#666" } }, "\uD83D\uDCA1 Survolez chaque avatar pour voir le tooltip avec le nom complet"),
316
+ React.createElement("div", { style: {
317
+ border: "1px solid #ccc",
318
+ padding: "20px",
319
+ marginBottom: "20px",
320
+ } },
321
+ React.createElement(AvatarToggleGroup, { pros: samplePros.slice(0, 6), mode: "multiple", selected: selected, onSelect: handleSelect, showTooltips: true, tooltipId: "tooltip-test" })),
322
+ React.createElement("div", { style: { fontSize: "14px", color: "#666" } },
323
+ React.createElement("strong", null, "S\u00E9lection :"),
324
+ " ",
325
+ selected.join(", ") || "Aucune",
326
+ React.createElement("br", null),
327
+ React.createElement("small", null, "\u2705 Tooltips activ\u00E9s sur tous les avatars"))));
276
328
  };
@@ -11,6 +11,8 @@ interface ProSwitchProps {
11
11
  onOpenPortal?: () => void;
12
12
  onClosePortal?: () => void;
13
13
  className?: string;
14
+ showTooltips?: boolean;
15
+ tooltipId?: string;
14
16
  }
15
17
  declare const ProSwitch: React.FC<ProSwitchProps>;
16
18
  export default ProSwitch;
@@ -13,11 +13,11 @@ import ProSwitchModal from "./ProSwitchModal";
13
13
  import styles from "./proSwitch.module.css";
14
14
  var LOCALSTORAGE_KEY = "allaw.proSwitch.order";
15
15
  var ProSwitch = function (_a) {
16
- var _b = _a.pros, pros = _b === void 0 ? [] : _b, _c = _a.selected, selected = _c === void 0 ? [] : _c, mode = _a.mode, _d = _a.disabled, disabled = _d === void 0 ? false : _d, maxVisible = _a.maxVisible, onSelect = _a.onSelect, onOrderChange = _a.onOrderChange, onOpenPortal = _a.onOpenPortal, onClosePortal = _a.onClosePortal, _e = _a.className, className = _e === void 0 ? "" : _e;
16
+ var _b = _a.pros, pros = _b === void 0 ? [] : _b, _c = _a.selected, selected = _c === void 0 ? [] : _c, mode = _a.mode, _d = _a.disabled, disabled = _d === void 0 ? false : _d, maxVisible = _a.maxVisible, onSelect = _a.onSelect, onOrderChange = _a.onOrderChange, onOpenPortal = _a.onOpenPortal, onClosePortal = _a.onClosePortal, _e = _a.className, className = _e === void 0 ? "" : _e, _f = _a.showTooltips, showTooltips = _f === void 0 ? false : _f, _g = _a.tooltipId, tooltipId = _g === void 0 ? "pro-switch-tooltip" : _g;
17
17
  var containerRef = useRef(null);
18
- var _f = useState([]), order = _f[0], setOrder = _f[1];
19
- var _g = useState(selected), selectedIds = _g[0], setSelectedIds = _g[1];
20
- var _h = useState(false), modalOpen = _h[0], setModalOpen = _h[1];
18
+ var _h = useState([]), order = _h[0], setOrder = _h[1];
19
+ var _j = useState(selected), selectedIds = _j[0], setSelectedIds = _j[1];
20
+ var _k = useState(false), modalOpen = _k[0], setModalOpen = _k[1];
21
21
  // Initialisation de l'ordre depuis localStorage ou props
22
22
  useEffect(function () {
23
23
  var initialOrder = pros.map(function (p) { return p.proUserId; });
@@ -44,10 +44,18 @@ var ProSwitch = function (_a) {
44
44
  }, [selected]);
45
45
  // Gestion de la sélection
46
46
  var handleSelect = useCallback(function (selectedPros) {
47
- setSelectedIds(selectedPros.map(function (p) { return p.proUserId; }));
47
+ var newSelectedIds = selectedPros.map(function (p) { return p.proUserId; });
48
+ // Empêcher la désélection totale en mode multiple
49
+ if (mode === "multiple" &&
50
+ newSelectedIds.length === 0 &&
51
+ selectedIds.length > 0) {
52
+ // Garder la sélection actuelle
53
+ return;
54
+ }
55
+ setSelectedIds(newSelectedIds);
48
56
  if (onSelect)
49
57
  onSelect(selectedPros);
50
- }, [onSelect]);
58
+ }, [mode, selectedIds, onSelect]);
51
59
  // Gestion de l'ouverture de la modal
52
60
  var handleOpenModal = useCallback(function () {
53
61
  setModalOpen(true);
@@ -80,7 +88,7 @@ var ProSwitch = function (_a) {
80
88
  return (React.createElement("div", { className: styles.proSwitchEmpty }, "Aucun professionnel disponible"));
81
89
  }
82
90
  return (React.createElement("div", { className: "".concat(styles.proSwitchContainer, " ").concat(className), ref: containerRef },
83
- React.createElement(AvatarToggleGroup, { pros: orderedPros, mode: mode, selected: selectedIds, onSelect: handleSelect, onOpenPortal: handleOpenModal, disabled: disabled, maxVisible: maxVisible, className: styles.avatarToggleGroup }),
91
+ React.createElement(AvatarToggleGroup, { pros: orderedPros, mode: mode, selected: selectedIds, onSelect: handleSelect, onOpenPortal: handleOpenModal, disabled: disabled, maxVisible: maxVisible, className: styles.avatarToggleGroup, showTooltips: showTooltips, tooltipId: tooltipId }),
84
92
  modalOpen && (React.createElement(ProSwitchModal, { open: modalOpen, pros: orderedPros, selected: selectedIds, mode: mode, onClosePortal: handleCloseModal, onOpenPortal: onOpenPortal, onOrderChange: handleOrderChange, onSelect: handleSelect }))));
85
93
  };
86
94
  export default ProSwitch;
@@ -129,16 +129,24 @@ var samplePros = [
129
129
  ];
130
130
  export var SingleSelect = function () {
131
131
  var _a = useState(["1"]), selected = _a[0], setSelected = _a[1];
132
- return (React.createElement(ProSwitch, { pros: samplePros.slice(0, 15), selected: selected, mode: "single", onSelect: function (pros) {
133
- setSelected(pros.map(function (p) { return p.proUserId; }));
134
- action("onSelect")(pros);
135
- }, onOrderChange: action("onOrderChange") }));
132
+ return (React.createElement("div", { style: { padding: "20px" } },
133
+ React.createElement("h3", { style: { marginBottom: "10px" } }, "Mode Single avec Tooltips"),
134
+ React.createElement(ProSwitch, { pros: samplePros.slice(0, 15), selected: selected, mode: "single", onSelect: function (pros) {
135
+ setSelected(pros.map(function (p) { return p.proUserId; }));
136
+ action("onSelect")(pros);
137
+ }, onOrderChange: action("onOrderChange"), showTooltips: true, tooltipId: "single-select-tooltip" }),
138
+ React.createElement("div", { style: { marginTop: "10px", fontSize: "12px", color: "#666" } }, "\uD83D\uDCA1 Survolez les avatars pour voir les tooltips")));
136
139
  };
137
140
  export var MultiSelectOverflow = function () {
138
141
  var _a = useState(["1", "2"]), selected = _a[0], setSelected = _a[1];
139
- return (React.createElement("div", { style: { width: 200 } },
142
+ return (React.createElement("div", { style: { width: 200, padding: "20px" } },
143
+ React.createElement("h3", { style: { marginBottom: "10px" } }, "Mode Multiple avec Blocage"),
140
144
  React.createElement(ProSwitch, { pros: samplePros, selected: selected, mode: "multiple", onSelect: function (pros) {
141
145
  setSelected(pros.map(function (p) { return p.proUserId; }));
142
146
  action("onSelect")(pros);
143
- }, onOrderChange: action("onOrderChange") })));
147
+ }, onOrderChange: action("onOrderChange"), showTooltips: true, tooltipId: "multi-select-tooltip" }),
148
+ React.createElement("div", { style: { marginTop: "10px", fontSize: "12px", color: "#666" } },
149
+ "\uD83D\uDCA1 Survolez les avatars pour voir les tooltips",
150
+ React.createElement("br", null),
151
+ "\uD83D\uDD12 Essayez de d\u00E9s\u00E9lectionner le dernier pro (impossible)")));
144
152
  };
@@ -195,6 +195,11 @@ var ProSwitchModal = function (_a) {
195
195
  }
196
196
  else {
197
197
  if (selected.includes(pro.proUserId)) {
198
+ // Empêcher la désélection totale en mode multiple
199
+ if (selected.length === 1) {
200
+ // Garder la sélection actuelle
201
+ return;
202
+ }
198
203
  newSelected = selected.filter(function (id) { return id !== pro.proUserId; });
199
204
  }
200
205
  else {
@@ -57,4 +57,6 @@ export const FallbackInitiales: any;
57
57
  export const Responsive: any;
58
58
  export const ResponsiveMobile: any;
59
59
  export const FewProfiles: any;
60
+ export function TestBlocking(): React.JSX.Element;
60
61
  import ProSwitchModal from "./ProSwitchModal";
62
+ import React from "react";
@@ -137,29 +137,71 @@ export var Default = Template.bind({});
137
137
  Default.args = {
138
138
  mode: "multiple",
139
139
  };
140
+ Default.parameters = {
141
+ docs: {
142
+ description: {
143
+ story: "Modal avec blocage de désélection en mode multiple. Essayez de désélectionner le dernier pro sélectionné.",
144
+ },
145
+ },
146
+ };
140
147
  export var Single = Template.bind({});
141
148
  Single.args = {
142
149
  mode: "single",
143
150
  };
151
+ Single.parameters = {
152
+ docs: {
153
+ description: {
154
+ story: "Modal en mode single.",
155
+ },
156
+ },
157
+ };
144
158
  export var Reorder = Template.bind({});
145
159
  Reorder.args = {
146
160
  mode: "multiple",
147
161
  };
162
+ Reorder.parameters = {
163
+ docs: {
164
+ description: {
165
+ story: "Modal avec réorganisation drag-and-drop. Testez la réorganisation.",
166
+ },
167
+ },
168
+ };
148
169
  export var Scroll = Template.bind({});
149
170
  Scroll.args = {
150
171
  mode: "multiple",
151
172
  pros: __spreadArray(__spreadArray(__spreadArray([], samplePros, true), samplePros.map(function (p, i) { return (__assign(__assign({}, p), { proUserId: "x" + (i + 1) })); }), true), samplePros.map(function (p, i) { return (__assign(__assign({}, p), { proUserId: "y" + (i + 1) })); }), true),
152
173
  };
174
+ Scroll.parameters = {
175
+ docs: {
176
+ description: {
177
+ story: "Modal avec beaucoup de pros et scroll. Testez le blocage de désélection.",
178
+ },
179
+ },
180
+ };
153
181
  export var FallbackInitiales = Template.bind({});
154
182
  FallbackInitiales.args = {
155
183
  mode: "multiple",
156
184
  pros: samplePros.map(function (p) { return (__assign(__assign({}, p), { profilePictureLink: "" })); }),
157
185
  };
186
+ FallbackInitiales.parameters = {
187
+ docs: {
188
+ description: {
189
+ story: "Modal avec fallback sur les initiales.",
190
+ },
191
+ },
192
+ };
158
193
  export var Responsive = Template.bind({});
159
194
  Responsive.args = {
160
195
  mode: "multiple",
161
196
  pros: samplePros,
162
197
  };
198
+ Responsive.parameters = {
199
+ docs: {
200
+ description: {
201
+ story: "Modal responsive. Redimensionnez la fenêtre pour tester la responsivité.",
202
+ },
203
+ },
204
+ };
163
205
  export var ResponsiveMobile = Template.bind({});
164
206
  ResponsiveMobile.args = {
165
207
  mode: "multiple",
@@ -169,6 +211,11 @@ ResponsiveMobile.parameters = {
169
211
  defaultViewport: "mobile1",
170
212
  },
171
213
  layout: "fullscreen",
214
+ docs: {
215
+ description: {
216
+ story: "Modal en mode mobile. Testez sur mobile ou redimensionnez la fenêtre.",
217
+ },
218
+ },
172
219
  };
173
220
  export var FewProfiles = Template.bind({});
174
221
  FewProfiles.args = {
@@ -192,3 +239,31 @@ FewProfiles.args = {
192
239
  },
193
240
  ],
194
241
  };
242
+ FewProfiles.parameters = {
243
+ docs: {
244
+ description: {
245
+ story: "Modal avec peu de profils. Testez le blocage de désélection.",
246
+ },
247
+ },
248
+ };
249
+ export var TestBlocking = function () {
250
+ var _a = useState(["1", "2"]), selected = _a[0], setSelected = _a[1];
251
+ var _b = useState(samplePros.map(function (p) { return p.proUserId; })), order = _b[0], setOrder = _b[1];
252
+ var handleOrderChange = function (newOrderPros) {
253
+ setOrder(newOrderPros.map(function (p) { return p.proUserId; }));
254
+ action("onOrderChange")(newOrderPros);
255
+ };
256
+ var handleSelect = function (selectedPros) {
257
+ setSelected(selectedPros.map(function (p) { return p.proUserId; }));
258
+ action("onSelect")(selectedPros);
259
+ };
260
+ return (React.createElement("div", { style: { padding: "20px" } },
261
+ React.createElement("h3", { style: { marginBottom: "10px" } }, "Test du Blocage de D\u00E9s\u00E9lection"),
262
+ React.createElement("p", { style: { marginBottom: "20px", fontSize: "14px", color: "#666" } }, "\uD83D\uDD12 En mode multiple, essayez de d\u00E9s\u00E9lectionner le dernier pro s\u00E9lectionn\u00E9. Cela devrait \u00EAtre impossible !"),
263
+ React.createElement("button", { onClick: function () { return setSelected(["1", "2"]); }, style: { marginBottom: "16px", padding: "8px 16px" } }, "Reset \u00E0 2 pros s\u00E9lectionn\u00E9s"),
264
+ React.createElement(ProSwitchModal, { open: true, pros: samplePros.filter(function (p) { return order.includes(p.proUserId); }), selected: selected, mode: "multiple", onOrderChange: handleOrderChange, onSelect: handleSelect, onClosePortal: function () { }, onOpenPortal: action("onOpenPortal") }),
265
+ React.createElement("div", { style: { marginTop: "10px", fontSize: "12px", color: "#666" } },
266
+ React.createElement("strong", null, "S\u00E9lection actuelle :"),
267
+ " ",
268
+ selected.join(", ") || "Aucune")));
269
+ };
package/dist/index.d.ts CHANGED
@@ -63,7 +63,7 @@ export { default as DocumentCard } from "./components/molecules/documentCard/Doc
63
63
  export type { DocumentCardProps } from "./components/molecules/documentCard/DocumentCard";
64
64
  export { default as EmployeeCard } from "./components/molecules/employeeCard/EmployeeCard";
65
65
  export { Stepper as DataStepper } from "./components/molecules/DataStepper";
66
- export type { StepField as DataStepField, StepConfig as DataStepConfig, StepperProps as DataStepperProps } from "./components/molecules/DataStepper";
66
+ export type { StepField as DataStepField, StepConfig as DataStepConfig, StepperProps as DataStepperProps, } from "./components/molecules/DataStepper";
67
67
  export { default as Stepper } from "./components/molecules/stepper/Stepper";
68
68
  export type { StepperProps } from "./components/molecules/stepper/Stepper";
69
69
  export { default as RangeSlider } from "./components/molecules/rangeSlider/RangeSlider";
@@ -107,6 +107,10 @@ export type { BlogHeaderProps } from "./components/molecules/blogHeader/BlogHead
107
107
  export { default as blogFooter } from "./components/molecules/blogFooter/BlogFooter";
108
108
  export type { BlogFooterProps } from "./components/molecules/blogFooter/BlogFooter";
109
109
  export { default as BlogCard } from "./components/molecules/blogCard/BlogCard";
110
+ export { default as ProSwitch } from "./components/molecules/proSwitch/ProSwitch";
111
+ export type { Pro } from "./components/molecules/proSwitch/AvatarToggleGroup";
112
+ export type { AvatarBubbleProps } from "./components/molecules/proSwitch/AvatarBubble";
113
+ export type { AvatarToggleGroupProps } from "./components/molecules/proSwitch/AvatarToggleGroup";
110
114
  export type { BlogCardProps } from "./components/molecules/blogCard/BlogCard";
111
115
  export { default as BlogText } from "./components/molecules/blogText/BlogText";
112
116
  export type { BlogTextProps } from "./components/molecules/blogText/BlogText";
package/dist/index.js CHANGED
@@ -108,6 +108,8 @@ export { default as Brands } from "./components/molecules/brands/Brands";
108
108
  export { default as BlogHeader } from "./components/molecules/blogHeader/BlogHeader";
109
109
  export { default as blogFooter } from "./components/molecules/blogFooter/BlogFooter";
110
110
  export { default as BlogCard } from "./components/molecules/blogCard/BlogCard";
111
+ // ProSwitch
112
+ export { default as ProSwitch } from "./components/molecules/proSwitch/ProSwitch";
111
113
  export { default as BlogText } from "./components/molecules/blogText/BlogText";
112
114
  export { default as blogTextImageBlock } from "./components/molecules/blogTextImageBlock/BlogTextImageBlock";
113
115
  // File Uploader
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "allaw-ui",
3
- "version": "4.1.4",
3
+ "version": "4.1.5",
4
4
  "description": "Composants UI pour l'application Allaw",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",
@@ -50,6 +50,7 @@
50
50
  "react-datepicker": "^7.5.0",
51
51
  "react-dom": "^17.0.0 || ^18.0.0",
52
52
  "react-hook-form": "^7.53.0",
53
+ "react-tooltip": "^5.29.1",
53
54
  "typeface-open-sans": "^1.1.13"
54
55
  },
55
56
  "devDependencies": {