allaw-ui 4.1.1 → 4.1.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.
@@ -12,6 +12,11 @@ export type StepConfig = {
12
12
  title: string;
13
13
  description?: string;
14
14
  fields: StepField[];
15
+ layout?: number;
16
+ validate?: (values: Record<string, any>) => true | string;
17
+ disableNextUntilValid?: boolean;
18
+ hidePrevButton?: boolean;
19
+ nextLabel?: string;
15
20
  };
16
21
  export type StepperProps = {
17
22
  config: StepConfig[];
@@ -75,7 +75,7 @@ var FieldRenderer = function (_a) {
75
75
  }
76
76
  };
77
77
  // Ajout/ajustement du style CSS-in-JS pour le layout 2 colonnes et plus de spacing
78
- var stepperStyle = "\n.stepper-allaw {\n background: var(--pure-white, #fff);\n border: 1px solid var(--grey-venom, #e6edf5);\n border-radius: 16px;\n box-shadow: 0 2px 8px rgba(37, 190, 235, 0.06);\n padding: 32px;\n max-width: 600px;\n min-width: 100%;\n width: 700px;\n margin: 0 auto;\n font-family: 'Inter', 'Open Sans', Arial, sans-serif;\n}\n.stepper-progress-bar {\n width: 100%;\n height: 6px;\n background: var(--grey-light, #f6fcfe);\n border-radius: 8px;\n margin-bottom: 24px;\n overflow: hidden;\n}\n.stepper-progress-inner {\n height: 100%;\n background: var(--bleu-allaw, #25beeb);\n border-radius: 8px;\n transition: width 0.3s;\n}\n.stepper-title {\n color: var(--noir, #171e25);\n font-family: 'Poppins', Arial, sans-serif;\n font-size: 1.5rem;\n font-weight: 600;\n margin-bottom: 8px;\n}\n.stepper-desc {\n color: var(--mid-grey, #728ea7);\n font-family: 'Open Sans', Arial, sans-serif;\n font-size: 1rem;\n margin-bottom: 42px;\n}\n.stepper-fields-grid {\n display: grid;\n grid-template-columns: 1fr;\n gap: 24px 24px;\n margin-bottom: 42px;\n}\n@media (min-width: 600px) {\n .stepper-fields-grid {\n grid-template-columns: 1fr 1fr;\n }\n}\n.stepper-field {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: 8px;\n margin-bottom: 0;\n}\n.stepper-label {\n color: var(--dark-grey, #456073);\n font-size: 1rem;\n font-weight: 500;\n margin-bottom: 2px;\n min-width: 0;\n flex-shrink: 1;\n}\n.stepper-input, .stepper-select, .stepper-datalist {\n border: 1px solid var(--grey-venom, #e6edf5);\n border-radius: 8px;\n padding: 10px 12px;\n font-size: 1rem;\n font-family: inherit;\n background: var(--pure-white, #fff);\n color: var(--noir, #171e25);\n outline: none;\n transition: border-color 0.2s;\n flex: 1 1 0%;\n}\n.stepper-input:focus, .stepper-select:focus, .stepper-datalist:focus {\n border-color: var(--bleu-allaw, #25beeb);\n}\n.stepper-btn-row {\n display: flex;\n gap: 12px;\n margin-top: 24px;\n}\n@media (max-width: 599px) {\n .stepper-btn-row {\n flex-direction: column;\n gap: 12px;\n }\n}\n.stepper-btn {\n background: var(--bleu-allaw, #25beeb);\n color: var(--pure-white, #fff);\n border: none;\n border-radius: 8px;\n padding: 8px 16px;\n font-size: 1rem;\n font-weight: 600;\n cursor: pointer;\n transition: background 0.2s;\n flex: 1 1 0%;\n width: 100%;\n min-width: 0;\n}\n.stepper-btn:disabled {\n background: var(--grey-venom, #e6edf5);\n color: var(--mid-grey, #728ea7);\n cursor: not-allowed;\n}\n.stepper-btn:not(:disabled):hover {\n background: #1ca6d4;\n}\n.stepper-btn-secondary {\n background: var(--grey-light, #f6fcfe);\n color: var(--bleu-allaw, #25beeb);\n border: 1px solid var(--bleu-allaw, #25beeb);\n margin-right: 8px;\n}\n.stepper-modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n background: rgba(0, 0, 0, 0.6);\n z-index: 1000;\n display: flex;\n align-items: center;\n justify-content: center;\n pointer-events: all;\n}\n.stepper-modal-center {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n z-index: 1001;\n max-height: 90vh;\n overflow-y: auto;\n box-shadow: 0 8px 32px rgba(23, 30, 37, 0.18);\n pointer-events: all;\n}\n.stepper-modal-close {\n position: absolute;\n top: 18px;\n right: 18px;\n background: none;\n border: none;\n color: var(--mid-grey, #728ea7);\n font-size: 2rem;\n cursor: pointer;\n z-index: 1002;\n transition: color 0.2s;\n}\n.stepper-modal-close:hover {\n color: var(--noir, #171e25);\n}\n";
78
+ var stepperStyle = "\n.stepper-allaw {\n background: var(--pure-white, #fff);\n border: 1px solid var(--grey-venom, #e6edf5);\n border-radius: 16px;\n box-shadow: 0 2px 8px rgba(37, 190, 235, 0.06);\n padding: 32px;\n max-width: 100vw;\n min-width: 100%;\n width: 700px;\n margin: 0 auto;\n font-family: 'Inter', 'Open Sans', Arial, sans-serif;\n}\n.stepper-progress-bar {\n width: 100%;\n height: 6px;\n background: var(--grey-light, #f6fcfe);\n border-radius: 8px;\n\n overflow: hidden;\n}\n.stepper-progress-inner {\n height: 100%;\n background: var(--bleu-allaw, #25beeb);\n border-radius: 8px;\n transition: width 0.3s;\n}\n.stepper-title {\n color: var(--noir, #171e25);\n font-family: 'Poppins', Arial, sans-serif;\n font-size: 1.5rem;\n font-weight: 600;\n margin-bottom: 8px;\n}\n.stepper-desc {\n color: var(--mid-grey, #728ea7);\n font-family: 'Open Sans', Arial, sans-serif;\n font-size: 1rem;\n margin-bottom: 42px;\n}\n.stepper-fields-grid {\n display: grid;\n grid-template-columns: 1fr;\n gap: 24px 24px;\n margin-bottom: 42px;\n}\n@media (min-width: 600px) {\n .stepper-fields-grid {\n grid-template-columns: 1fr 1fr !important;\n }\n}\n.stepper-field {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: 8px;\n margin-bottom: 0;\n}\n.stepper-label {\n color: var(--dark-grey, #456073);\n font-size: 1rem;\n font-weight: 500;\n margin-bottom: 2px;\n min-width: 0;\n flex-shrink: 1;\n}\n.stepper-input, .stepper-select, .stepper-datalist {\n border: 1px solid var(--grey-venom, #e6edf5);\n border-radius: 8px;\n padding: 10px 12px;\n font-size: 1rem;\n font-family: inherit;\n background: var(--pure-white, #fff);\n color: var(--noir, #171e25);\n outline: none;\n transition: border-color 0.2s;\n flex: 1 1 0%;\n}\n.stepper-input:focus, .stepper-select:focus, .stepper-datalist:focus {\n border-color: var(--bleu-allaw, #25beeb);\n}\n.stepper-btn-row {\n display: flex;\n gap: 12px;\n margin-top: 32px;\n}\n@media (max-width: 599px) {\n .stepper-btn-row {\n flex-direction: column;\n gap: 12px;\n }\n}\n.stepper-btn {\n background: var(--bleu-allaw, #25beeb);\n color: var(--pure-white, #fff);\n border: none;\n border-radius: 8px;\n padding: 8px 16px;\n font-size: 1rem;\n font-weight: 600;\n cursor: pointer;\n transition: background 0.2s;\n flex: 1 1 0%;\n width: 100%;\n min-width: 0;\n}\n.stepper-btn:disabled {\n background: var(--grey-venom, #e6edf5);\n color: var(--mid-grey, #728ea7);\n cursor: not-allowed;\n}\n.stepper-btn:not(:disabled):hover {\n background: #1ca6d4;\n}\n.stepper-btn-secondary {\n background: var(--grey-light, #f6fcfe);\n color: var(--bleu-allaw, #25beeb);\n border: 1px solid var(--bleu-allaw, #25beeb);\n margin-right: 8px;\n}\n.stepper-modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n background: rgba(0, 0, 0, 0.6);\n z-index: 1000;\n display: flex;\n align-items: center;\n justify-content: center;\n pointer-events: all;\n}\n.stepper-modal-center {\n position: fixed;\n\n z-index: 1001;\n max-height: 98vh;\n overflow-y: auto;\n box-shadow: 0 8px 32px rgba(23, 30, 37, 0.18);\n pointer-events: all;\n}\n\n@media (max-width: 600px) {\n .stepper-allaw {\n height: 100%;\n }\n .stepper-modal-center {\n bottom: 0;\n right: 0;\n left: 0;\n width: 100vw;\n height: 98vh;\n transform: translate(0, 0);\n }\n}\n.stepper-modal-close {\n position: absolute;\n top: 18px;\n right: 18px;\n background: none;\n border: none;\n color: var(--mid-grey, #728ea7);\n font-size: 2rem;\n cursor: pointer;\n z-index: 1002;\n transition: color 0.2s;\n}\n.stepper-modal-close:hover {\n color: var(--noir, #171e25);\n}\n";
79
79
  if (typeof window !== 'undefined' && !document.getElementById('stepper-allaw-style')) {
80
80
  var style = document.createElement('style');
81
81
  style.id = 'stepper-allaw-style';
@@ -104,10 +104,21 @@ var CloseButton = function (_a) {
104
104
  React.createElement("path", { d: "M5 5L13 13M13 5L5 13", stroke: "#171e25", strokeWidth: "2", strokeLinecap: "round" }))));
105
105
  };
106
106
  export var Stepper = function (_a) {
107
- var config = _a.config, onSubmit = _a.onSubmit, _b = _a.isOpen, isOpen = _b === void 0 ? true : _b, onClose = _a.onClose;
108
- var _c = useState(0), step = _c[0], setStep = _c[1];
109
- var _d = useState({}), values = _d[0], setValues = _d[1];
107
+ var _b;
108
+ var config = _a.config, onSubmit = _a.onSubmit, _c = _a.isOpen, isOpen = _c === void 0 ? true : _c, onClose = _a.onClose;
109
+ var _d = useState(0), step = _d[0], setStep = _d[1];
110
+ var _e = useState({}), values = _e[0], setValues = _e[1];
111
+ var _f = useState(null), error = _f[0], setError = _f[1];
110
112
  var currentStep = config[step];
113
+ // Responsive: force 1 colonne si largeur < 600px
114
+ var _g = React.useState(undefined), windowWidth = _g[0], setWindowWidth = _g[1];
115
+ React.useEffect(function () {
116
+ var handleResize = function () { return setWindowWidth(window.innerWidth); };
117
+ handleResize();
118
+ window.addEventListener('resize', handleResize);
119
+ return function () { return window.removeEventListener('resize', handleResize); };
120
+ }, []);
121
+ var columns = windowWidth !== undefined && windowWidth < 600 ? 1 : ((_b = currentStep.layout) !== null && _b !== void 0 ? _b : 2);
111
122
  // Filtrer les champs à afficher selon showIf
112
123
  var visibleFields = useMemo(function () {
113
124
  return currentStep.fields.filter(function (field) { return !field.showIf || field.showIf(values); });
@@ -119,6 +130,14 @@ export var Stepper = function (_a) {
119
130
  });
120
131
  };
121
132
  var handleNext = function () {
133
+ if (currentStep.validate) {
134
+ var result = currentStep.validate(values);
135
+ if (result !== true) {
136
+ setError(typeof result === 'string' ? result : 'Erreur de validation');
137
+ return;
138
+ }
139
+ }
140
+ setError(null);
122
141
  if (step < config.length - 1) {
123
142
  setStep(step + 1);
124
143
  }
@@ -132,31 +151,41 @@ export var Stepper = function (_a) {
132
151
  };
133
152
  // Barre de progression simple
134
153
  var progress = ((step + 1) / config.length) * 100;
154
+ // Calcul de la validité du step courant si disableNextUntilValid est activé
155
+ var isStepValid = !currentStep.validate || currentStep.validate(values) === true;
135
156
  if (!isOpen)
136
157
  return null;
137
158
  return (React.createElement(React.Fragment, null,
138
159
  React.createElement("div", { className: "stepper-modal-backdrop" },
139
160
  React.createElement("div", { className: "stepper-modal-center" },
140
- React.createElement("div", { style: { position: "relative" } },
161
+ React.createElement("div", { style: { position: "relative", height: "100%" } },
141
162
  React.createElement("div", { className: "stepper-allaw" },
142
- React.createElement("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", gap: 12 } },
163
+ React.createElement("div", { style: { display: "flex", alignItems: "center", marginBottom: "24px", justifyContent: "center", gap: 12 } },
143
164
  React.createElement("div", { className: "stepper-progress-bar", style: { flex: 1, height: 8, minWidth: 0 } },
144
165
  React.createElement("div", { className: "stepper-progress-inner", style: { width: progress + "%", height: 8 } })),
145
166
  React.createElement(CloseButton, { onClick: function () { return onClose && onClose(); } })),
146
167
  React.createElement("div", { className: "stepper-title" }, currentStep.title),
147
168
  currentStep.description && React.createElement("div", { className: "stepper-desc" }, currentStep.description),
169
+ error && (React.createElement("div", { style: { color: 'red', marginBottom: 16 } }, error)),
148
170
  React.createElement("form", { onSubmit: function (e) {
149
171
  e.preventDefault();
150
172
  handleNext();
151
173
  } },
152
- React.createElement("div", { className: "stepper-fields-grid" }, visibleFields.map(function (field) {
174
+ React.createElement("div", { className: "stepper-fields-grid", style: {
175
+ display: 'grid',
176
+ gridTemplateColumns: "repeat(".concat(columns, ", 1fr)"),
177
+ gap: 24,
178
+ marginBottom: 42,
179
+ } }, visibleFields.map(function (field) {
153
180
  // On affiche le label au-dessus uniquement pour certains types
154
- var showLabelAbove = ["select", "date", "checkbox", "radio", "custom"].includes(field.type);
181
+ var showLabelAbove = ["select", "date", "radio", "custom"].includes(field.type);
155
182
  return (React.createElement("div", { key: field.name, className: "stepper-field" },
156
183
  showLabelAbove && (React.createElement(Paragraph, { variant: "medium", color: "noir", text: field.label, className: "stepper-label" })),
157
184
  React.createElement(FieldRenderer, { field: field, value: values[field.name], onChange: function (val) { return handleFieldChange(field.name, val); }, values: values })));
158
185
  })),
159
186
  React.createElement("div", { className: "stepper-btn-row" },
160
- React.createElement("button", { type: "button", className: "stepper-btn stepper-btn-secondary", onClick: handlePrev, disabled: step === 0 }, "Pr\u00E9c\u00E9dent"),
161
- React.createElement("button", { type: "submit", className: "stepper-btn" }, step === config.length - 1 ? "Valider" : "Suivant")))))))));
187
+ !currentStep.hidePrevButton && (React.createElement("button", { type: "button", className: "stepper-btn stepper-btn-secondary", onClick: handlePrev, disabled: step === 0 }, "Pr\u00E9c\u00E9dent")),
188
+ React.createElement("button", { type: "submit", className: "stepper-btn", disabled: currentStep.disableNextUntilValid && !isStepValid }, step === config.length - 1
189
+ ? (currentStep.nextLabel || "Valider")
190
+ : (currentStep.nextLabel || "Suivant"))))))))));
162
191
  };
@@ -61,6 +61,7 @@ var config = [
61
61
  {
62
62
  title: "Informations personnelles",
63
63
  description: "Merci de renseigner vos infos.",
64
+ layout: 2,
64
65
  fields: [
65
66
  { name: "firstName", label: "Prénom", type: "text" },
66
67
  { name: "lastName", label: "Nom", type: "text" },
@@ -206,4 +207,6 @@ export var GrandExemple = function () { return (React.createElement("div", { sty
206
207
  // eslint-disable-next-line no-alert
207
208
  alert("Données soumises : " + JSON.stringify(values, null, 2));
208
209
  console.log(values);
210
+ }, onClose: function () {
211
+ return alert("Données soumises : ");
209
212
  } }))); };
@@ -12,7 +12,6 @@
12
12
  align-items: stretch;
13
13
  align-self: stretch;
14
14
  border-radius: 16px;
15
- min-height: 147px;
16
15
  }
17
16
 
18
17
  .actionsContainer {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "allaw-ui",
3
- "version": "4.1.1",
3
+ "version": "4.1.3",
4
4
  "description": "Composants UI pour l'application Allaw",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",