@portnet/ui 6.0.1 → 6.0.2

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 (158) hide show
  1. package/CHANGELOG.md +85 -0
  2. package/dist/esm/index.js +18 -0
  3. package/dist/esm/index.js.map +1 -1
  4. package/dist/esm/v2/__tests__/FieldError.test.js +0 -1
  5. package/dist/esm/v2/__tests__/FieldError.test.js.map +1 -1
  6. package/dist/esm/v2/__tests__/FieldWidth.test.js +146 -0
  7. package/dist/esm/v2/__tests__/FieldWidth.test.js.map +1 -0
  8. package/dist/esm/v2/__tests__/FileCard.test.js +0 -1
  9. package/dist/esm/v2/__tests__/FileCard.test.js.map +1 -1
  10. package/dist/esm/v2/__tests__/FormikCheckbox.test.js +265 -0
  11. package/dist/esm/v2/__tests__/FormikCheckbox.test.js.map +1 -0
  12. package/dist/esm/v2/__tests__/FormikDateTimePicker.test.js +248 -0
  13. package/dist/esm/v2/__tests__/FormikDateTimePicker.test.js.map +1 -0
  14. package/dist/esm/v2/__tests__/FormikRadioGroup.test.js +380 -0
  15. package/dist/esm/v2/__tests__/FormikRadioGroup.test.js.map +1 -0
  16. package/dist/esm/v2/__tests__/MobileRowCard.test.js +0 -1
  17. package/dist/esm/v2/__tests__/MobileRowCard.test.js.map +1 -1
  18. package/dist/esm/v2/__tests__/SectionErrorBoundary.test.js.map +1 -1
  19. package/dist/esm/v2/__tests__/labels-merge.test.js +0 -1
  20. package/dist/esm/v2/__tests__/labels-merge.test.js.map +1 -1
  21. package/dist/esm/v2/components/DateTimePicker.js +37 -4
  22. package/dist/esm/v2/components/DateTimePicker.js.map +1 -1
  23. package/dist/esm/v2/components/Field.js +63 -1
  24. package/dist/esm/v2/components/Field.js.map +1 -1
  25. package/dist/esm/v2/components/index.js +27 -0
  26. package/dist/esm/v2/components/index.js.map +1 -1
  27. package/dist/esm/v2/index.js +12 -1
  28. package/dist/esm/v2/index.js.map +1 -1
  29. package/dist/esm/v2/patterns/FavoriteColumn.js +14 -61
  30. package/dist/esm/v2/patterns/FavoriteColumn.js.map +1 -1
  31. package/dist/esm/v2/patterns/FormikCheckbox.js +140 -0
  32. package/dist/esm/v2/patterns/FormikCheckbox.js.map +1 -0
  33. package/dist/esm/v2/patterns/FormikCombobox.js +5 -2
  34. package/dist/esm/v2/patterns/FormikCombobox.js.map +1 -1
  35. package/dist/esm/v2/patterns/FormikDatePicker.js +13 -47
  36. package/dist/esm/v2/patterns/FormikDatePicker.js.map +1 -1
  37. package/dist/esm/v2/patterns/FormikDateTimePicker.js +150 -0
  38. package/dist/esm/v2/patterns/FormikDateTimePicker.js.map +1 -0
  39. package/dist/esm/v2/patterns/FormikInput.js +5 -2
  40. package/dist/esm/v2/patterns/FormikInput.js.map +1 -1
  41. package/dist/esm/v2/patterns/FormikRadioGroup.js +141 -0
  42. package/dist/esm/v2/patterns/FormikRadioGroup.js.map +1 -0
  43. package/dist/esm/v2/patterns/FormikSelect.js +5 -2
  44. package/dist/esm/v2/patterns/FormikSelect.js.map +1 -1
  45. package/dist/esm/v2/patterns/FormikTextarea.js +5 -2
  46. package/dist/esm/v2/patterns/FormikTextarea.js.map +1 -1
  47. package/dist/esm/v2/patterns/KeyboardShortcutsHelp.js +25 -8
  48. package/dist/esm/v2/patterns/KeyboardShortcutsHelp.js.map +1 -1
  49. package/dist/esm/v2/patterns/RowFavoriteToggle.js +122 -0
  50. package/dist/esm/v2/patterns/RowFavoriteToggle.js.map +1 -0
  51. package/dist/esm/v2/patterns/_pickerSerialisation.js +74 -0
  52. package/dist/esm/v2/patterns/_pickerSerialisation.js.map +1 -0
  53. package/dist/esm/v2/patterns/index.js +83 -0
  54. package/dist/esm/v2/patterns/index.js.map +1 -1
  55. package/dist/esm/v2/personalization/capabilities/gridPreferences.js +209 -0
  56. package/dist/esm/v2/personalization/capabilities/gridPreferences.js.map +1 -0
  57. package/dist/esm/v2/personalization/capabilities/index.js +5 -0
  58. package/dist/esm/v2/personalization/capabilities/index.js.map +1 -1
  59. package/dist/esm/v2/personalization/index.js +18 -0
  60. package/dist/esm/v2/personalization/index.js.map +1 -1
  61. package/dist/index.d.ts +2 -0
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +14 -0
  64. package/dist/index.js.map +1 -1
  65. package/dist/v2/__tests__/FieldError.test.js +26 -30
  66. package/dist/v2/__tests__/FieldError.test.js.map +1 -1
  67. package/dist/v2/__tests__/FieldWidth.test.js +150 -0
  68. package/dist/v2/__tests__/FieldWidth.test.js.map +1 -0
  69. package/dist/v2/__tests__/FileCard.test.js +25 -29
  70. package/dist/v2/__tests__/FileCard.test.js.map +1 -1
  71. package/dist/v2/__tests__/FormikCheckbox.test.js +268 -0
  72. package/dist/v2/__tests__/FormikCheckbox.test.js.map +1 -0
  73. package/dist/v2/__tests__/FormikDateTimePicker.test.js +247 -0
  74. package/dist/v2/__tests__/FormikDateTimePicker.test.js.map +1 -0
  75. package/dist/v2/__tests__/FormikRadioGroup.test.js +381 -0
  76. package/dist/v2/__tests__/FormikRadioGroup.test.js.map +1 -0
  77. package/dist/v2/__tests__/MobileRowCard.test.js +52 -56
  78. package/dist/v2/__tests__/MobileRowCard.test.js.map +1 -1
  79. package/dist/v2/__tests__/SectionErrorBoundary.test.js.map +1 -1
  80. package/dist/v2/__tests__/labels-merge.test.js +20 -24
  81. package/dist/v2/__tests__/labels-merge.test.js.map +1 -1
  82. package/dist/v2/components/DateTimePicker.d.ts.map +1 -1
  83. package/dist/v2/components/DateTimePicker.js +37 -4
  84. package/dist/v2/components/DateTimePicker.js.map +1 -1
  85. package/dist/v2/components/Field.d.ts +59 -1
  86. package/dist/v2/components/Field.d.ts.map +1 -1
  87. package/dist/v2/components/Field.js +62 -2
  88. package/dist/v2/components/Field.js.map +1 -1
  89. package/dist/v2/components/index.d.ts +27 -0
  90. package/dist/v2/components/index.d.ts.map +1 -1
  91. package/dist/v2/components/index.js.map +1 -1
  92. package/dist/v2/index.d.ts.map +1 -1
  93. package/dist/v2/index.js.map +1 -1
  94. package/dist/v2/patterns/FavoriteColumn.d.ts +9 -9
  95. package/dist/v2/patterns/FavoriteColumn.d.ts.map +1 -1
  96. package/dist/v2/patterns/FavoriteColumn.js +14 -61
  97. package/dist/v2/patterns/FavoriteColumn.js.map +1 -1
  98. package/dist/v2/patterns/FormikCheckbox.d.ts +77 -0
  99. package/dist/v2/patterns/FormikCheckbox.d.ts.map +1 -0
  100. package/dist/v2/patterns/FormikCheckbox.js +147 -0
  101. package/dist/v2/patterns/FormikCheckbox.js.map +1 -0
  102. package/dist/v2/patterns/FormikCombobox.d.ts +7 -1
  103. package/dist/v2/patterns/FormikCombobox.d.ts.map +1 -1
  104. package/dist/v2/patterns/FormikCombobox.js +5 -2
  105. package/dist/v2/patterns/FormikCombobox.js.map +1 -1
  106. package/dist/v2/patterns/FormikDatePicker.d.ts +13 -1
  107. package/dist/v2/patterns/FormikDatePicker.d.ts.map +1 -1
  108. package/dist/v2/patterns/FormikDatePicker.js +33 -66
  109. package/dist/v2/patterns/FormikDatePicker.js.map +1 -1
  110. package/dist/v2/patterns/FormikDateTimePicker.d.ts +111 -0
  111. package/dist/v2/patterns/FormikDateTimePicker.d.ts.map +1 -0
  112. package/dist/v2/patterns/FormikDateTimePicker.js +158 -0
  113. package/dist/v2/patterns/FormikDateTimePicker.js.map +1 -0
  114. package/dist/v2/patterns/FormikInput.d.ts +11 -1
  115. package/dist/v2/patterns/FormikInput.d.ts.map +1 -1
  116. package/dist/v2/patterns/FormikInput.js +5 -2
  117. package/dist/v2/patterns/FormikInput.js.map +1 -1
  118. package/dist/v2/patterns/FormikRadioGroup.d.ts +80 -0
  119. package/dist/v2/patterns/FormikRadioGroup.d.ts.map +1 -0
  120. package/dist/v2/patterns/FormikRadioGroup.js +148 -0
  121. package/dist/v2/patterns/FormikRadioGroup.js.map +1 -0
  122. package/dist/v2/patterns/FormikSelect.d.ts +9 -1
  123. package/dist/v2/patterns/FormikSelect.d.ts.map +1 -1
  124. package/dist/v2/patterns/FormikSelect.js +5 -2
  125. package/dist/v2/patterns/FormikSelect.js.map +1 -1
  126. package/dist/v2/patterns/FormikTextarea.d.ts +9 -1
  127. package/dist/v2/patterns/FormikTextarea.d.ts.map +1 -1
  128. package/dist/v2/patterns/FormikTextarea.js +5 -2
  129. package/dist/v2/patterns/FormikTextarea.js.map +1 -1
  130. package/dist/v2/patterns/KeyboardShortcutsHelp.d.ts +14 -1
  131. package/dist/v2/patterns/KeyboardShortcutsHelp.d.ts.map +1 -1
  132. package/dist/v2/patterns/KeyboardShortcutsHelp.js +25 -8
  133. package/dist/v2/patterns/KeyboardShortcutsHelp.js.map +1 -1
  134. package/dist/v2/patterns/RowFavoriteToggle.d.ts +92 -0
  135. package/dist/v2/patterns/RowFavoriteToggle.d.ts.map +1 -0
  136. package/dist/v2/patterns/RowFavoriteToggle.js +127 -0
  137. package/dist/v2/patterns/RowFavoriteToggle.js.map +1 -0
  138. package/dist/v2/patterns/_pickerSerialisation.d.ts +44 -0
  139. package/dist/v2/patterns/_pickerSerialisation.d.ts.map +1 -0
  140. package/dist/v2/patterns/_pickerSerialisation.js +81 -0
  141. package/dist/v2/patterns/_pickerSerialisation.js.map +1 -0
  142. package/dist/v2/patterns/index.d.ts +87 -0
  143. package/dist/v2/patterns/index.d.ts.map +1 -1
  144. package/dist/v2/patterns/index.js +34 -0
  145. package/dist/v2/patterns/index.js.map +1 -1
  146. package/dist/v2/personalization/capabilities/gridPreferences.d.ts +100 -0
  147. package/dist/v2/personalization/capabilities/gridPreferences.d.ts.map +1 -0
  148. package/dist/v2/personalization/capabilities/gridPreferences.js +215 -0
  149. package/dist/v2/personalization/capabilities/gridPreferences.js.map +1 -0
  150. package/dist/v2/personalization/capabilities/index.d.ts +6 -0
  151. package/dist/v2/personalization/capabilities/index.d.ts.map +1 -1
  152. package/dist/v2/personalization/capabilities/index.js +13 -0
  153. package/dist/v2/personalization/capabilities/index.js.map +1 -1
  154. package/dist/v2/personalization/index.d.ts +18 -0
  155. package/dist/v2/personalization/index.d.ts.map +1 -1
  156. package/dist/v2/personalization/index.js +13 -0
  157. package/dist/v2/personalization/index.js.map +1 -1
  158. package/package.json +1 -1
@@ -0,0 +1,141 @@
1
+ function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
2
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
3
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
4
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
5
+ function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
6
+ function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
7
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
8
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
9
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
10
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
11
+ function _iterableToArrayLimit(arr, i) { var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"]; if (null != _i) { var _s, _e, _x, _r, _arr = [], _n = !0, _d = !1; try { if (_x = (_i = _i.call(arr)).next, 0 === i) { if (Object(_i) !== _i) return; _n = !1; } else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0) { ; } } catch (err) { _d = !0, _e = err; } finally { try { if (!_n && null != _i["return"] && (_r = _i["return"](), Object(_r) !== _r)) return; } finally { if (_d) throw _e; } } return _arr; } }
12
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
13
+ /**
14
+ * FormikRadioGroup — bridge between Formik state and v2.Field +
15
+ * v2.RadioGroup.
16
+ *
17
+ * ── WHY (gap G-C) ────────────────────────────────────────────────────
18
+ *
19
+ * R-Sel.2 is a MUST: 2–3 options → Radio or Segmented, never a Select. So any
20
+ * form with a two-way business question has to reach for `RadioGroup` — and
21
+ * until now there was no Formik bridge for it, while `FormikCheckboxGroup`,
22
+ * `FormikSelect`, `FormikCombobox`, `FormikDatePicker`, `FormikTextarea`,
23
+ * `FormikFile` and `FormikInput` all exist. Every host therefore re-wired
24
+ * `useField` + `RadioGroup` by hand, which is the duplication R-2.1 forbids
25
+ * and, worse, the shape in which validation messages go missing: a hand-rolled
26
+ * bridge renders the control but forgets `FieldError`.
27
+ *
28
+ * Reported from refonte-frontend (lot 5), where ONE form carried two such
29
+ * groups (`usageHorsMetrologique`, `certificat`).
30
+ *
31
+ * ── THE VALUE IS WRITTEN BACK AS DECLARED, NOT AS THE DOM SAW IT ─────
32
+ *
33
+ * This is the contract that matters, and it is invisible.
34
+ *
35
+ * A native `<input type="radio">` only ever reports a STRING. A host whose
36
+ * options are numbers — `{ value: 1 }`, `{ value: 2 }` — and whose payload
37
+ * declares a number would silently start sending `"1"` after the user picks.
38
+ * The API accepts it or rejects it days later; nothing in the UI tells anyone.
39
+ *
40
+ * So `onChange` matches the DOM string back against the option list and writes
41
+ * the ORIGINAL option value. Numbers stay numbers, strings stay strings. Only
42
+ * when no option matches (a host mutating its list mid-flight) does the raw DOM
43
+ * string go through, because dropping the user's click would be worse.
44
+ *
45
+ * Symmetrically, the group's `value` is compared as a string, so a field
46
+ * holding a boolean `false` selects the option declared `"false"`, and a field
47
+ * holding the number `2` selects `{ value: 2 }`. The STORED value is never
48
+ * coerced by this — only the comparison is.
49
+ *
50
+ * Usage:
51
+ *
52
+ * <FormikRadioGroup
53
+ * name="importateur.certificat"
54
+ * label="Modèle déjà approuvé"
55
+ * required
56
+ * row
57
+ * options={[
58
+ * { value: "true", label: "Oui" },
59
+ * { value: "false", label: "Non" },
60
+ * ]}
61
+ * />
62
+ *
63
+ * ── ERRORS APPEAR ON PICK, NOT ON BLUR ──────────────────────────────
64
+ *
65
+ * A radio group has no meaningful blur-before-change: the first interaction IS
66
+ * the answer. Waiting for a blur keeps a required-group message hidden while
67
+ * the user clicks around. Picking marks the field touched — same rule as
68
+ * `FormikCheckbox` and `FormikCheckboxGroup`.
69
+ *
70
+ * `required` is expressed on the FIELD, not on the options: `Field` renders the
71
+ * asterisk on the group label and injects `aria-required`, which — unlike the
72
+ * single-checkbox case — is valid on `role="radiogroup"` and forwarded by
73
+ * `RadioGroup`.
74
+ *
75
+ * Charter §03 · R-Sel.2, R-I.2, R-I.3, R-4.1. Peer dependency: formik >= 2.x.
76
+ */
77
+
78
+ import * as React from "react";
79
+ import { useField, useFormikContext } from "formik";
80
+ import Field from "../components/Field";
81
+ import { RadioGroup } from "../components/Radio";
82
+ import { jsx as _jsx } from "react/jsx-runtime";
83
+ /** Declared value of an option, whatever its shape. */
84
+ function valeurOption(option) {
85
+ return typeof option === "string" ? option : option.value;
86
+ }
87
+ var FormikRadioGroup = function FormikRadioGroup(_ref) {
88
+ var name = _ref.name,
89
+ label = _ref.label,
90
+ _ref$options = _ref.options,
91
+ options = _ref$options === void 0 ? [] : _ref$options,
92
+ required = _ref.required,
93
+ disabled = _ref.disabled,
94
+ hint = _ref.hint,
95
+ row = _ref.row;
96
+ var _useField = useField(name),
97
+ _useField2 = _slicedToArray(_useField, 2),
98
+ field = _useField2[0],
99
+ meta = _useField2[1];
100
+ var _useFormikContext = useFormikContext(),
101
+ setFieldValue = _useFormikContext.setFieldValue,
102
+ setFieldTouched = _useFormikContext.setFieldTouched;
103
+ var hasError = Boolean(meta.touched && meta.error);
104
+
105
+ /* Comparison only — the stored value is left untouched. A field holding
106
+ * boolean `false` therefore selects the option declared "false". */
107
+ var selection = field.value === null || field.value === undefined ? "" : String(field.value);
108
+ var handleChange = function handleChange(_event, valeurDom) {
109
+ var correspondante = options.find(function (option) {
110
+ return String(valeurOption(option)) === valeurDom;
111
+ });
112
+ /* Write back the DECLARED value — see the note above. The raw DOM string
113
+ * is the fallback, not the norm. */
114
+ void setFieldValue(name, correspondante === undefined ? valeurDom : valeurOption(correspondante));
115
+ void setFieldTouched(name, true, false);
116
+ };
117
+ return /*#__PURE__*/_jsx(Field, _objectSpread(_objectSpread(_objectSpread(_objectSpread({}, label !== undefined ? {
118
+ label: label
119
+ } : {}), {}, {
120
+ error: hasError ? meta.error : null,
121
+ hint: !hasError ? hint : undefined,
122
+ group: true
123
+ }, required !== undefined ? {
124
+ required: required
125
+ } : {}), disabled !== undefined ? {
126
+ disabled: disabled
127
+ } : {}), {}, {
128
+ children: /*#__PURE__*/_jsx(RadioGroup, _objectSpread(_objectSpread({
129
+ name: name,
130
+ value: selection,
131
+ options: options,
132
+ onChange: handleChange
133
+ }, row !== undefined ? {
134
+ row: row
135
+ } : {}), disabled !== undefined ? {
136
+ disabled: disabled
137
+ } : {}))
138
+ }));
139
+ };
140
+ export default FormikRadioGroup;
141
+ //# sourceMappingURL=FormikRadioGroup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FormikRadioGroup.js","names":["React","useField","useFormikContext","Field","RadioGroup","jsx","_jsx","valeurOption","option","value","FormikRadioGroup","_ref","name","label","_ref$options","options","required","disabled","hint","row","_useField","_useField2","_slicedToArray","field","meta","_useFormikContext","setFieldValue","setFieldTouched","hasError","Boolean","touched","error","selection","undefined","String","handleChange","_event","valeurDom","correspondante","find","_objectSpread","group","children","onChange"],"sources":["../../../../src/lib/v2/patterns/FormikRadioGroup.tsx"],"sourcesContent":["/**\r\n * FormikRadioGroup — bridge between Formik state and v2.Field +\r\n * v2.RadioGroup.\r\n *\r\n * ── WHY (gap G-C) ────────────────────────────────────────────────────\r\n *\r\n * R-Sel.2 is a MUST: 2–3 options → Radio or Segmented, never a Select. So any\r\n * form with a two-way business question has to reach for `RadioGroup` — and\r\n * until now there was no Formik bridge for it, while `FormikCheckboxGroup`,\r\n * `FormikSelect`, `FormikCombobox`, `FormikDatePicker`, `FormikTextarea`,\r\n * `FormikFile` and `FormikInput` all exist. Every host therefore re-wired\r\n * `useField` + `RadioGroup` by hand, which is the duplication R-2.1 forbids\r\n * and, worse, the shape in which validation messages go missing: a hand-rolled\r\n * bridge renders the control but forgets `FieldError`.\r\n *\r\n * Reported from refonte-frontend (lot 5), where ONE form carried two such\r\n * groups (`usageHorsMetrologique`, `certificat`).\r\n *\r\n * ── THE VALUE IS WRITTEN BACK AS DECLARED, NOT AS THE DOM SAW IT ─────\r\n *\r\n * This is the contract that matters, and it is invisible.\r\n *\r\n * A native `<input type=\"radio\">` only ever reports a STRING. A host whose\r\n * options are numbers — `{ value: 1 }`, `{ value: 2 }` — and whose payload\r\n * declares a number would silently start sending `\"1\"` after the user picks.\r\n * The API accepts it or rejects it days later; nothing in the UI tells anyone.\r\n *\r\n * So `onChange` matches the DOM string back against the option list and writes\r\n * the ORIGINAL option value. Numbers stay numbers, strings stay strings. Only\r\n * when no option matches (a host mutating its list mid-flight) does the raw DOM\r\n * string go through, because dropping the user's click would be worse.\r\n *\r\n * Symmetrically, the group's `value` is compared as a string, so a field\r\n * holding a boolean `false` selects the option declared `\"false\"`, and a field\r\n * holding the number `2` selects `{ value: 2 }`. The STORED value is never\r\n * coerced by this — only the comparison is.\r\n *\r\n * Usage:\r\n *\r\n * <FormikRadioGroup\r\n * name=\"importateur.certificat\"\r\n * label=\"Modèle déjà approuvé\"\r\n * required\r\n * row\r\n * options={[\r\n * { value: \"true\", label: \"Oui\" },\r\n * { value: \"false\", label: \"Non\" },\r\n * ]}\r\n * />\r\n *\r\n * ── ERRORS APPEAR ON PICK, NOT ON BLUR ──────────────────────────────\r\n *\r\n * A radio group has no meaningful blur-before-change: the first interaction IS\r\n * the answer. Waiting for a blur keeps a required-group message hidden while\r\n * the user clicks around. Picking marks the field touched — same rule as\r\n * `FormikCheckbox` and `FormikCheckboxGroup`.\r\n *\r\n * `required` is expressed on the FIELD, not on the options: `Field` renders the\r\n * asterisk on the group label and injects `aria-required`, which — unlike the\r\n * single-checkbox case — is valid on `role=\"radiogroup\"` and forwarded by\r\n * `RadioGroup`.\r\n *\r\n * Charter §03 · R-Sel.2, R-I.2, R-I.3, R-4.1. Peer dependency: formik >= 2.x.\r\n */\r\n\r\nimport * as React from \"react\";\r\nimport { useField, useFormikContext } from \"formik\";\r\nimport Field from \"../components/Field\";\r\nimport { RadioGroup } from \"../components/Radio\";\r\nimport type { RadioGroupOption } from \"../components/Radio\";\r\n\r\nexport interface FormikRadioGroupProps {\r\n name: string;\r\n /** Group label — rendered by `Field` above the options. */\r\n label?: React.ReactNode | undefined;\r\n options?: RadioGroupOption[] | undefined;\r\n required?: boolean | undefined;\r\n disabled?: boolean | undefined;\r\n hint?: React.ReactNode | undefined;\r\n /** Horizontal layout. Use only with short labels. */\r\n row?: boolean | undefined;\r\n}\r\n\r\n/** Declared value of an option, whatever its shape. */\r\nfunction valeurOption(option: RadioGroupOption): string | number {\r\n return typeof option === \"string\" ? option : option.value;\r\n}\r\n\r\nconst FormikRadioGroup = ({\r\n name,\r\n label,\r\n options = [],\r\n required,\r\n disabled,\r\n hint,\r\n row,\r\n}: FormikRadioGroupProps) => {\r\n const [field, meta] = useField(name);\r\n const { setFieldValue, setFieldTouched } = useFormikContext();\r\n const hasError = Boolean(meta.touched && meta.error);\r\n\r\n /* Comparison only — the stored value is left untouched. A field holding\r\n * boolean `false` therefore selects the option declared \"false\". */\r\n const selection =\r\n field.value === null || field.value === undefined\r\n ? \"\"\r\n : String(field.value);\r\n\r\n const handleChange = (\r\n _event: React.ChangeEvent<HTMLInputElement>,\r\n valeurDom: string\r\n ) => {\r\n const correspondante = options.find(\r\n (option) => String(valeurOption(option)) === valeurDom\r\n );\r\n /* Write back the DECLARED value — see the note above. The raw DOM string\r\n * is the fallback, not the norm. */\r\n void setFieldValue(\r\n name,\r\n correspondante === undefined ? valeurDom : valeurOption(correspondante)\r\n );\r\n void setFieldTouched(name, true, false);\r\n };\r\n\r\n return (\r\n <Field\r\n {...(label !== undefined ? { label } : {})}\r\n error={hasError ? meta.error : null}\r\n hint={!hasError ? hint : undefined}\r\n group\r\n {...(required !== undefined ? { required } : {})}\r\n {...(disabled !== undefined ? { disabled } : {})}\r\n >\r\n <RadioGroup\r\n name={name}\r\n value={selection}\r\n options={options}\r\n onChange={handleChange}\r\n {...(row !== undefined ? { row } : {})}\r\n {...(disabled !== undefined ? { disabled } : {})}\r\n />\r\n </Field>\r\n );\r\n};\r\n\r\nexport default FormikRadioGroup;\r\n"],"mappings":"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","ignoreList":[]}
@@ -1,4 +1,4 @@
1
- var _excluded = ["name", "label", "required", "hint", "options", "getOptionValue", "getOptionLabel", "loading", "disabled", "readOnly", "mono", "placeholder", "htmlFor", "onSelectionChange"];
1
+ var _excluded = ["name", "label", "required", "hint", "options", "getOptionValue", "getOptionLabel", "loading", "disabled", "readOnly", "mono", "placeholder", "htmlFor", "width", "onSelectionChange"];
2
2
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
3
3
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
4
4
  function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
@@ -81,6 +81,7 @@ var FormikSelect = function FormikSelect(_ref) {
81
81
  mono = _ref.mono,
82
82
  placeholder = _ref.placeholder,
83
83
  htmlFor = _ref.htmlFor,
84
+ width = _ref.width,
84
85
  onSelectionChange = _ref.onSelectionChange,
85
86
  rest = _objectWithoutProperties(_ref, _excluded);
86
87
  var _useField = useField(name),
@@ -135,7 +136,7 @@ var FormikSelect = function FormikSelect(_ref) {
135
136
  }
136
137
  }));
137
138
  }
138
- return /*#__PURE__*/_jsx(Field, _objectSpread(_objectSpread({
139
+ return /*#__PURE__*/_jsx(Field, _objectSpread(_objectSpread(_objectSpread({
139
140
  label: label,
140
141
  error: hasError ? meta.error : null,
141
142
  hint: !hasError ? hint : undefined,
@@ -143,6 +144,8 @@ var FormikSelect = function FormikSelect(_ref) {
143
144
  disabled: disabled
144
145
  }, required !== undefined ? {
145
146
  required: required
147
+ } : {}), width !== undefined ? {
148
+ width: width
146
149
  } : {}), {}, {
147
150
  children: /*#__PURE__*/_jsx(Select, _objectSpread(_objectSpread({
148
151
  value: (_field$value = field.value) !== null && _field$value !== void 0 ? _field$value : "",
@@ -1 +1 @@
1
- {"version":3,"file":"FormikSelect.js","names":["React","useField","useFormikContext","Field","Select","FormikDisplay","labelFromValue","sameOptionValue","jsx","_jsx","defaultGetOptionValue","opt","_typeof","rec","undefined","defaultGetOptionLabel","String","FormikSelect","_ref","_field$value","name","label","required","hint","_ref$options","options","_ref$getOptionValue","getOptionValue","_ref$getOptionLabel","getOptionLabel","_ref$loading","loading","_ref$disabled","disabled","_ref$readOnly","readOnly","mono","placeholder","htmlFor","onSelectionChange","rest","_objectWithoutProperties","_excluded","_useField","_useField2","_slicedToArray","field","meta","_useFormikContext","setFieldValue","setFieldTouched","hasError","Boolean","touched","error","v2Options","map","raw","value","__raw","handleChange","e","next","target","found","find","o","picked","resolvedPlaceholder","_objectSpread","format","match","children","onChange","onBlur"],"sources":["../../../../src/lib/v2/patterns/FormikSelect.tsx"],"sourcesContent":["/**\r\n * FormikSelect — bridge between Formik state and v2.Field + v2.Select.\r\n *\r\n * Charter §03 · R-Sel.1 → R-Sel.5. Peer dependency: formik >= 2.x.\r\n *\r\n * Use for short / medium option lists. For large referential lists that\r\n * need free-text filtering, prefer FormikCombobox, or pass `searchThreshold`\r\n * straight through to the underlying v2.Select.\r\n *\r\n * Maps caller-supplied raw options to v2.Select's {value, label} shape and\r\n * exposes onSelectionChange(rawOption) for consumers that need cross-field\r\n * side effects on pick.\r\n *\r\n * <FormikSelect\r\n * name=\"bureau\"\r\n * label=\"Bureau douanier\"\r\n * options={bureaux}\r\n * getOptionValue={(b) => b.id}\r\n * getOptionLabel={(b) => b.libelle}\r\n * />\r\n */\r\n\r\nimport * as React from \"react\";\r\nimport { useField, useFormikContext } from \"formik\";\r\nimport Field from \"../components/Field\";\r\nimport Select from \"../components/Select\";\r\nimport FormikDisplay from \"../components/FormikDisplay\";\r\nimport { labelFromValue, sameOptionValue } from \"../components/Select\";\r\nimport type {\r\n SelectOptionValue,\r\n SelectProps,\r\n SelectValue,\r\n SelectChangeLike,\r\n} from \"../components/Select\";\r\n\r\nfunction defaultGetOptionValue(opt: unknown): SelectOptionValue {\r\n if (opt == null || typeof opt !== \"object\") return opt as SelectOptionValue;\r\n const rec = opt as Record<string, unknown>;\r\n if (rec[\"value\"] !== undefined && rec[\"value\"] !== null) return rec[\"value\"] as SelectOptionValue;\r\n if (rec[\"id\"] !== undefined && rec[\"id\"] !== null) return rec[\"id\"] as SelectOptionValue;\r\n // Unreachable for well-formed options: an object exposing neither value nor\r\n // id can never be a valid Select value/key, so collapse to empty selection.\r\n return \"\";\r\n}\r\n\r\nfunction defaultGetOptionLabel(opt: unknown): string {\r\n if (opt == null) return \"\";\r\n if (typeof opt !== \"object\") return String(opt);\r\n const rec = opt as Record<string, unknown>;\r\n if (rec[\"description\"]) return String(rec[\"description\"]);\r\n if (rec[\"label\"]) return String(rec[\"label\"]);\r\n if (rec[\"code\"]) return String(rec[\"code\"]);\r\n return String(opt);\r\n}\r\n\r\nexport interface FormikSelectProps<TOption = unknown>\r\n extends Omit<\r\n SelectProps,\r\n | \"value\"\r\n | \"onChange\"\r\n | \"onBlur\"\r\n | \"options\"\r\n | \"disabled\"\r\n | \"placeholder\"\r\n | \"label\"\r\n | \"required\"\r\n | \"error\"\r\n // SelectProps carries its own loosely-typed `ref` (Ref<unknown>, likely\r\n // inherited from its underlying MUI base) that isn't the real ref for\r\n // this wrapper. Excluding it here stops it leaking into ...rest below\r\n // and colliding with <Select>'s real RefAttributes<HTMLInputElement>.\r\n | \"ref\"\r\n > {\r\n name: string;\r\n label?: React.ReactNode | undefined;\r\n required?: boolean | undefined;\r\n hint?: React.ReactNode | undefined;\r\n options?: TOption[] | undefined;\r\n getOptionValue?: ((opt: TOption) => SelectOptionValue) | undefined;\r\n getOptionLabel?: ((opt: TOption) => React.ReactNode) | undefined;\r\n loading?: boolean | undefined;\r\n disabled?: boolean | undefined;\r\n /**\r\n * Render the RESOLVED OPTION LABEL as read-only text via FormikDisplay,\r\n * instead of a Select.\r\n *\r\n * Resolution matters here in a way it does not for FormikInput: the Formik\r\n * value is whatever `getOptionValue` produced — often a code, sometimes a\r\n * whole referentiel object — and printing it raw would show\r\n * \"DOMAIN_ACTIVITE_1\" where the user expects \"Domaine médical\". So the value is\r\n * matched back against `options` and `getOptionLabel` supplies the text.\r\n *\r\n * Matching goes through the same `sameOptionValue` the Select itself uses, so\r\n * a value seeded from an API payload still matches a separately-fetched\r\n * option (structural comparison, not reference identity). When nothing\r\n * matches, `labelFromValue` derives something readable from the value rather\r\n * than showing a code.\r\n *\r\n * `disabled` wins when both are passed — same rule as FormikInput.\r\n */\r\n readOnly?: boolean | undefined;\r\n /** Tabular-nums monospace in read-only mode. */\r\n mono?: boolean | undefined;\r\n placeholder?: string | undefined;\r\n htmlFor?: string | undefined;\r\n onSelectionChange?: ((picked: TOption | null) => void) | undefined;\r\n}\r\n\r\nconst FormikSelect = <TOption,>({\r\n name,\r\n label,\r\n required,\r\n hint,\r\n options = [],\r\n getOptionValue = defaultGetOptionValue,\r\n getOptionLabel = defaultGetOptionLabel,\r\n loading = false,\r\n disabled = false,\r\n readOnly = false,\r\n mono,\r\n placeholder,\r\n htmlFor,\r\n onSelectionChange,\r\n ...rest\r\n}: FormikSelectProps<TOption>) => {\r\n const [field, meta] = useField<SelectValue>(name);\r\n const { setFieldValue, setFieldTouched } = useFormikContext();\r\n const hasError = Boolean(meta.touched && meta.error);\r\n\r\n const v2Options = options.map(\r\n (opt): string | { value: SelectOptionValue; label: React.ReactNode; __raw: TOption } => {\r\n const raw: unknown = opt;\r\n if (raw == null || typeof raw !== \"object\") return raw as string;\r\n return {\r\n value: getOptionValue(opt),\r\n label: getOptionLabel(opt),\r\n __raw: opt,\r\n };\r\n },\r\n );\r\n\r\n const handleChange = (e: SelectChangeLike) => {\r\n const next = e && e.target ? e.target.value : e;\r\n setFieldValue(name, next === \"\" ? null : next);\r\n setFieldTouched(name, true, false);\r\n if (typeof onSelectionChange === \"function\") {\r\n const found = v2Options.find(\r\n (o) => typeof o === \"object\" && o !== null && o.value === next,\r\n );\r\n const picked = found && typeof found === \"object\" ? found.__raw : null;\r\n onSelectionChange(picked);\r\n }\r\n };\r\n\r\n const resolvedPlaceholder = loading ? \"Chargement…\" : placeholder;\r\n\r\n /* Lecture seule : on résout le libellé de l'option avant de déléguer, sinon\r\n * FormikDisplay afficherait la VALEUR brute (un code, ou un objet dont il ne\r\n * lirait que `.description`). */\r\n if (readOnly && !disabled) {\r\n return (\r\n <FormikDisplay\r\n name={name}\r\n label={label}\r\n {...(hint !== undefined ? { hint } : {})}\r\n {...(mono !== undefined ? { mono } : {})}\r\n format={(raw) => {\r\n const match = options.find((opt) =>\r\n sameOptionValue(getOptionValue(opt), raw),\r\n );\r\n if (match !== undefined) return getOptionLabel(match);\r\n return labelFromValue(raw);\r\n }}\r\n />\r\n );\r\n }\r\n\r\n return (\r\n <Field\r\n label={label}\r\n error={hasError ? meta.error : null}\r\n hint={!hasError ? hint : undefined}\r\n htmlFor={htmlFor || name}\r\n disabled={disabled}\r\n {...(required !== undefined ? { required } : {})}\r\n >\r\n <Select\r\n value={field.value ?? \"\"}\r\n onChange={handleChange}\r\n onBlur={field.onBlur}\r\n options={v2Options}\r\n disabled={Boolean(disabled || loading)}\r\n {...rest}\r\n {...(resolvedPlaceholder !== undefined ? { placeholder: resolvedPlaceholder } : {})}\r\n />\r\n </Field>\r\n );\r\n};\r\n\r\nexport default FormikSelect;\r\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"FormikSelect.js","names":["React","useField","useFormikContext","Field","Select","FormikDisplay","labelFromValue","sameOptionValue","jsx","_jsx","defaultGetOptionValue","opt","_typeof","rec","undefined","defaultGetOptionLabel","String","FormikSelect","_ref","_field$value","name","label","required","hint","_ref$options","options","_ref$getOptionValue","getOptionValue","_ref$getOptionLabel","getOptionLabel","_ref$loading","loading","_ref$disabled","disabled","_ref$readOnly","readOnly","mono","placeholder","htmlFor","width","onSelectionChange","rest","_objectWithoutProperties","_excluded","_useField","_useField2","_slicedToArray","field","meta","_useFormikContext","setFieldValue","setFieldTouched","hasError","Boolean","touched","error","v2Options","map","raw","value","__raw","handleChange","e","next","target","found","find","o","picked","resolvedPlaceholder","_objectSpread","format","match","children","onChange","onBlur"],"sources":["../../../../src/lib/v2/patterns/FormikSelect.tsx"],"sourcesContent":["/**\r\n * FormikSelect — bridge between Formik state and v2.Field + v2.Select.\r\n *\r\n * Charter §03 · R-Sel.1 → R-Sel.5. Peer dependency: formik >= 2.x.\r\n *\r\n * Use for short / medium option lists. For large referential lists that\r\n * need free-text filtering, prefer FormikCombobox, or pass `searchThreshold`\r\n * straight through to the underlying v2.Select.\r\n *\r\n * Maps caller-supplied raw options to v2.Select's {value, label} shape and\r\n * exposes onSelectionChange(rawOption) for consumers that need cross-field\r\n * side effects on pick.\r\n *\r\n * <FormikSelect\r\n * name=\"bureau\"\r\n * label=\"Bureau douanier\"\r\n * options={bureaux}\r\n * getOptionValue={(b) => b.id}\r\n * getOptionLabel={(b) => b.libelle}\r\n * />\r\n */\r\n\r\nimport * as React from \"react\";\r\nimport { useField, useFormikContext } from \"formik\";\r\nimport Field from \"../components/Field\";\r\nimport Select from \"../components/Select\";\r\nimport FormikDisplay from \"../components/FormikDisplay\";\r\nimport { labelFromValue, sameOptionValue } from \"../components/Select\";\r\nimport type { FieldWidth } from \"../components/Field\";\r\nimport type {\r\n SelectOptionValue,\r\n SelectProps,\r\n SelectValue,\r\n SelectChangeLike,\r\n} from \"../components/Select\";\r\n\r\nfunction defaultGetOptionValue(opt: unknown): SelectOptionValue {\r\n if (opt == null || typeof opt !== \"object\") return opt as SelectOptionValue;\r\n const rec = opt as Record<string, unknown>;\r\n if (rec[\"value\"] !== undefined && rec[\"value\"] !== null) return rec[\"value\"] as SelectOptionValue;\r\n if (rec[\"id\"] !== undefined && rec[\"id\"] !== null) return rec[\"id\"] as SelectOptionValue;\r\n // Unreachable for well-formed options: an object exposing neither value nor\r\n // id can never be a valid Select value/key, so collapse to empty selection.\r\n return \"\";\r\n}\r\n\r\nfunction defaultGetOptionLabel(opt: unknown): string {\r\n if (opt == null) return \"\";\r\n if (typeof opt !== \"object\") return String(opt);\r\n const rec = opt as Record<string, unknown>;\r\n if (rec[\"description\"]) return String(rec[\"description\"]);\r\n if (rec[\"label\"]) return String(rec[\"label\"]);\r\n if (rec[\"code\"]) return String(rec[\"code\"]);\r\n return String(opt);\r\n}\r\n\r\nexport interface FormikSelectProps<TOption = unknown>\r\n extends Omit<\r\n SelectProps,\r\n | \"value\"\r\n | \"onChange\"\r\n | \"onBlur\"\r\n | \"options\"\r\n | \"disabled\"\r\n | \"placeholder\"\r\n | \"label\"\r\n | \"required\"\r\n | \"error\"\r\n // SelectProps carries its own loosely-typed `ref` (Ref<unknown>, likely\r\n // inherited from its underlying MUI base) that isn't the real ref for\r\n // this wrapper. Excluding it here stops it leaking into ...rest below\r\n // and colliding with <Select>'s real RefAttributes<HTMLInputElement>.\r\n | \"ref\"\r\n > {\r\n name: string;\r\n label?: React.ReactNode | undefined;\r\n required?: boolean | undefined;\r\n hint?: React.ReactNode | undefined;\r\n options?: TOption[] | undefined;\r\n getOptionValue?: ((opt: TOption) => SelectOptionValue) | undefined;\r\n getOptionLabel?: ((opt: TOption) => React.ReactNode) | undefined;\r\n loading?: boolean | undefined;\r\n disabled?: boolean | undefined;\r\n /**\r\n * Render the RESOLVED OPTION LABEL as read-only text via FormikDisplay,\r\n * instead of a Select.\r\n *\r\n * Resolution matters here in a way it does not for FormikInput: the Formik\r\n * value is whatever `getOptionValue` produced — often a code, sometimes a\r\n * whole referentiel object — and printing it raw would show\r\n * \"DOMAIN_ACTIVITE_1\" where the user expects \"Domaine médical\". So the value is\r\n * matched back against `options` and `getOptionLabel` supplies the text.\r\n *\r\n * Matching goes through the same `sameOptionValue` the Select itself uses, so\r\n * a value seeded from an API payload still matches a separately-fetched\r\n * option (structural comparison, not reference identity). When nothing\r\n * matches, `labelFromValue` derives something readable from the value rather\r\n * than showing a code.\r\n *\r\n * `disabled` wins when both are passed — same rule as FormikInput.\r\n */\r\n readOnly?: boolean | undefined;\r\n /** Tabular-nums monospace in read-only mode. */\r\n mono?: boolean | undefined;\r\n placeholder?: string | undefined;\r\n htmlFor?: string | undefined;\r\n /**\r\n * Gabarit de largeur semantique (G-H). Sur un select, le gabarit se choisit\r\n * d'apres la longueur des LIBELLES d'options, pas d'une contrainte de\r\n * saisie : le standard range les « simple dropdowns » en `m` et les « long\r\n * dropdowns » en `l`. Ne s'applique pas en mode `readOnly`.\r\n */\r\n width?: FieldWidth | undefined;\r\n onSelectionChange?: ((picked: TOption | null) => void) | undefined;\r\n}\r\n\r\nconst FormikSelect = <TOption,>({\r\n name,\r\n label,\r\n required,\r\n hint,\r\n options = [],\r\n getOptionValue = defaultGetOptionValue,\r\n getOptionLabel = defaultGetOptionLabel,\r\n loading = false,\r\n disabled = false,\r\n readOnly = false,\r\n mono,\r\n placeholder,\r\n htmlFor,\r\n width,\r\n onSelectionChange,\r\n ...rest\r\n}: FormikSelectProps<TOption>) => {\r\n const [field, meta] = useField<SelectValue>(name);\r\n const { setFieldValue, setFieldTouched } = useFormikContext();\r\n const hasError = Boolean(meta.touched && meta.error);\r\n\r\n const v2Options = options.map(\r\n (opt): string | { value: SelectOptionValue; label: React.ReactNode; __raw: TOption } => {\r\n const raw: unknown = opt;\r\n if (raw == null || typeof raw !== \"object\") return raw as string;\r\n return {\r\n value: getOptionValue(opt),\r\n label: getOptionLabel(opt),\r\n __raw: opt,\r\n };\r\n },\r\n );\r\n\r\n const handleChange = (e: SelectChangeLike) => {\r\n const next = e && e.target ? e.target.value : e;\r\n setFieldValue(name, next === \"\" ? null : next);\r\n setFieldTouched(name, true, false);\r\n if (typeof onSelectionChange === \"function\") {\r\n const found = v2Options.find(\r\n (o) => typeof o === \"object\" && o !== null && o.value === next,\r\n );\r\n const picked = found && typeof found === \"object\" ? found.__raw : null;\r\n onSelectionChange(picked);\r\n }\r\n };\r\n\r\n const resolvedPlaceholder = loading ? \"Chargement…\" : placeholder;\r\n\r\n /* Lecture seule : on résout le libellé de l'option avant de déléguer, sinon\r\n * FormikDisplay afficherait la VALEUR brute (un code, ou un objet dont il ne\r\n * lirait que `.description`). */\r\n if (readOnly && !disabled) {\r\n return (\r\n <FormikDisplay\r\n name={name}\r\n label={label}\r\n {...(hint !== undefined ? { hint } : {})}\r\n {...(mono !== undefined ? { mono } : {})}\r\n format={(raw) => {\r\n const match = options.find((opt) =>\r\n sameOptionValue(getOptionValue(opt), raw),\r\n );\r\n if (match !== undefined) return getOptionLabel(match);\r\n return labelFromValue(raw);\r\n }}\r\n />\r\n );\r\n }\r\n\r\n return (\r\n <Field\r\n label={label}\r\n error={hasError ? meta.error : null}\r\n hint={!hasError ? hint : undefined}\r\n htmlFor={htmlFor || name}\r\n disabled={disabled}\r\n {...(required !== undefined ? { required } : {})}\r\n {...(width !== undefined ? { width } : {})}\r\n >\r\n <Select\r\n value={field.value ?? \"\"}\r\n onChange={handleChange}\r\n onBlur={field.onBlur}\r\n options={v2Options}\r\n disabled={Boolean(disabled || loading)}\r\n {...rest}\r\n {...(resolvedPlaceholder !== undefined ? { placeholder: resolvedPlaceholder } : {})}\r\n />\r\n </Field>\r\n );\r\n};\r\n\r\nexport default FormikSelect;\r\n"],"mappings":"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","ignoreList":[]}
@@ -1,5 +1,5 @@
1
1
  function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
2
- var _excluded = ["name", "label", "required", "rows", "htmlFor", "hint", "disabled"];
2
+ var _excluded = ["name", "label", "required", "rows", "htmlFor", "hint", "disabled", "width"];
3
3
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
4
4
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
5
5
  function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
@@ -47,13 +47,14 @@ var FormikTextarea = function FormikTextarea(_ref) {
47
47
  htmlFor = _ref.htmlFor,
48
48
  hint = _ref.hint,
49
49
  disabled = _ref.disabled,
50
+ width = _ref.width,
50
51
  rest = _objectWithoutProperties(_ref, _excluded);
51
52
  var _useField = useField(name),
52
53
  _useField2 = _slicedToArray(_useField, 2),
53
54
  field = _useField2[0],
54
55
  meta = _useField2[1];
55
56
  var hasError = Boolean(meta.touched && meta.error);
56
- return /*#__PURE__*/_jsx(Field, _objectSpread(_objectSpread(_objectSpread({
57
+ return /*#__PURE__*/_jsx(Field, _objectSpread(_objectSpread(_objectSpread(_objectSpread({
57
58
  label: label,
58
59
  error: hasError ? meta.error : null,
59
60
  hint: !hasError ? hint : undefined,
@@ -62,6 +63,8 @@ var FormikTextarea = function FormikTextarea(_ref) {
62
63
  required: required
63
64
  } : {}), disabled !== undefined ? {
64
65
  disabled: disabled
66
+ } : {}), width !== undefined ? {
67
+ width: width
65
68
  } : {}), {}, {
66
69
  children: /*#__PURE__*/_jsx(Textarea, _objectSpread({
67
70
  name: field.name,
@@ -1 +1 @@
1
- {"version":3,"file":"FormikTextarea.js","names":["React","useField","Field","Textarea","jsx","_jsx","FormikTextarea","_ref","_field$value","name","label","required","_ref$rows","rows","htmlFor","hint","disabled","rest","_objectWithoutProperties","_excluded","_useField","_useField2","_slicedToArray","field","meta","hasError","Boolean","touched","error","_objectSpread","undefined","children","value","onChange","onBlur"],"sources":["../../../../src/lib/v2/patterns/FormikTextarea.tsx"],"sourcesContent":["/**\r\n * FormikTextarea — bridge between Formik state and v2.Field + v2.Textarea.\r\n *\r\n * Default rows = 4 (matches the legacy Pui multiline default\r\n * across ms-ti-fe / addpe-fe usage).\r\n *\r\n * Usage:\r\n *\r\n * import { FormikTextarea } from \"@portnet/ui/lib/v2\";\r\n *\r\n * <FormikTextarea\r\n * name=\"observation\"\r\n * label=\"Observations\"\r\n * rows={4}\r\n * />\r\n *\r\n * Charter §03 / R-I.1 → R-I.6. Peer dependency: `formik` >= 2.x.\r\n */\r\n\r\nimport * as React from \"react\";\r\nimport { useField } from \"formik\";\r\nimport Field from \"../components/Field\";\r\nimport Textarea from \"../components/Textarea\";\r\nimport type { TextareaProps } from \"../components/Textarea\";\r\n\r\nexport interface FormikTextareaProps\r\n extends Omit<\r\n TextareaProps,\r\n \"name\" | \"value\" | \"onChange\" | \"onBlur\" | \"label\" | \"required\" | \"disabled\" | \"error\"\r\n > {\r\n name: string;\r\n label?: React.ReactNode | undefined;\r\n required?: boolean | undefined;\r\n disabled?: boolean | undefined;\r\n htmlFor?: string | undefined;\r\n hint?: React.ReactNode | undefined;\r\n}\r\n\r\nconst FormikTextarea = ({\r\n name,\r\n label,\r\n required,\r\n rows = 4,\r\n htmlFor,\r\n hint,\r\n disabled,\r\n ...rest\r\n}: FormikTextareaProps) => {\r\n const [field, meta] = useField<string>(name);\r\n const hasError = Boolean(meta.touched && meta.error);\r\n\r\n return (\r\n <Field\r\n label={label}\r\n error={hasError ? meta.error : null}\r\n hint={!hasError ? hint : undefined}\r\n htmlFor={htmlFor || name}\r\n {...(required !== undefined ? { required } : {})}\r\n {...(disabled !== undefined ? { disabled } : {})}\r\n >\r\n <Textarea\r\n name={field.name}\r\n value={field.value ?? \"\"}\r\n onChange={field.onChange}\r\n onBlur={field.onBlur}\r\n rows={rows}\r\n {...rest}\r\n />\r\n </Field>\r\n );\r\n};\r\n\r\nexport default FormikTextarea;\r\n"],"mappings":";;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAC9B,SAASC,QAAQ,QAAQ,QAAQ;AACjC,OAAOC,KAAK,MAAM,qBAAqB;AACvC,OAAOC,QAAQ,MAAM,wBAAwB;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAgB9C,IAAMC,cAAc,GAAG,SAAjBA,cAAcA,CAAAC,IAAA,EASO;EAAA,IAAAC,YAAA;EAAA,IARzBC,IAAI,GAAAF,IAAA,CAAJE,IAAI;IACJC,KAAK,GAAAH,IAAA,CAALG,KAAK;IACLC,QAAQ,GAAAJ,IAAA,CAARI,QAAQ;IAAAC,SAAA,GAAAL,IAAA,CACRM,IAAI;IAAJA,IAAI,GAAAD,SAAA,cAAG,CAAC,GAAAA,SAAA;IACRE,OAAO,GAAAP,IAAA,CAAPO,OAAO;IACPC,IAAI,GAAAR,IAAA,CAAJQ,IAAI;IACJC,QAAQ,GAAAT,IAAA,CAARS,QAAQ;IACLC,IAAI,GAAAC,wBAAA,CAAAX,IAAA,EAAAY,SAAA;EAEP,IAAAC,SAAA,GAAsBnB,QAAQ,CAASQ,IAAI,CAAC;IAAAY,UAAA,GAAAC,cAAA,CAAAF,SAAA;IAArCG,KAAK,GAAAF,UAAA;IAAEG,IAAI,GAAAH,UAAA;EAClB,IAAMI,QAAQ,GAAGC,OAAO,CAACF,IAAI,CAACG,OAAO,IAAIH,IAAI,CAACI,KAAK,CAAC;EAEpD,oBACEvB,IAAA,CAACH,KAAK,EAAA2B,aAAA,CAAAA,aAAA,CAAAA,aAAA;IACJnB,KAAK,EAAEA,KAAM;IACbkB,KAAK,EAAEH,QAAQ,GAAGD,IAAI,CAACI,KAAK,GAAG,IAAK;IACpCb,IAAI,EAAE,CAACU,QAAQ,GAAGV,IAAI,GAAGe,SAAU;IACnChB,OAAO,EAAEA,OAAO,IAAIL;EAAK,GACpBE,QAAQ,KAAKmB,SAAS,GAAG;IAAEnB,QAAQ,EAARA;EAAS,CAAC,GAAG,CAAC,CAAC,GAC1CK,QAAQ,KAAKc,SAAS,GAAG;IAAEd,QAAQ,EAARA;EAAS,CAAC,GAAG,CAAC,CAAC;IAAAe,QAAA,eAE/C1B,IAAA,CAACF,QAAQ,EAAA0B,aAAA;MACPpB,IAAI,EAAEc,KAAK,CAACd,IAAK;MACjBuB,KAAK,GAAAxB,YAAA,GAAEe,KAAK,CAACS,KAAK,cAAAxB,YAAA,cAAAA,YAAA,GAAI,EAAG;MACzByB,QAAQ,EAAEV,KAAK,CAACU,QAAS;MACzBC,MAAM,EAAEX,KAAK,CAACW,MAAO;MACrBrB,IAAI,EAAEA;IAAK,GACPI,IAAI,CACT;EAAC,EACG,CAAC;AAEZ,CAAC;AAED,eAAeX,cAAc","ignoreList":[]}
1
+ {"version":3,"file":"FormikTextarea.js","names":["React","useField","Field","Textarea","jsx","_jsx","FormikTextarea","_ref","_field$value","name","label","required","_ref$rows","rows","htmlFor","hint","disabled","width","rest","_objectWithoutProperties","_excluded","_useField","_useField2","_slicedToArray","field","meta","hasError","Boolean","touched","error","_objectSpread","undefined","children","value","onChange","onBlur"],"sources":["../../../../src/lib/v2/patterns/FormikTextarea.tsx"],"sourcesContent":["/**\r\n * FormikTextarea — bridge between Formik state and v2.Field + v2.Textarea.\r\n *\r\n * Default rows = 4 (matches the legacy Pui multiline default\r\n * across ms-ti-fe / addpe-fe usage).\r\n *\r\n * Usage:\r\n *\r\n * import { FormikTextarea } from \"@portnet/ui/lib/v2\";\r\n *\r\n * <FormikTextarea\r\n * name=\"observation\"\r\n * label=\"Observations\"\r\n * rows={4}\r\n * />\r\n *\r\n * Charter §03 / R-I.1 → R-I.6. Peer dependency: `formik` >= 2.x.\r\n */\r\n\r\nimport * as React from \"react\";\r\nimport { useField } from \"formik\";\r\nimport Field from \"../components/Field\";\r\nimport Textarea from \"../components/Textarea\";\r\nimport type { FieldWidth } from \"../components/Field\";\r\nimport type { TextareaProps } from \"../components/Textarea\";\r\n\r\nexport interface FormikTextareaProps\r\n extends Omit<\r\n TextareaProps,\r\n \"name\" | \"value\" | \"onChange\" | \"onBlur\" | \"label\" | \"required\" | \"disabled\" | \"error\"\r\n > {\r\n name: string;\r\n label?: React.ReactNode | undefined;\r\n required?: boolean | undefined;\r\n disabled?: boolean | undefined;\r\n htmlFor?: string | undefined;\r\n hint?: React.ReactNode | undefined;\r\n /**\r\n * Gabarit de largeur semantique (G-H). Sur une zone de texte, le standard\r\n * range les descriptions et les editeurs en `xl` (pleine largeur du bloc) :\r\n * c'est donc rarement autre chose, mais la prop existe pour les cas ou la\r\n * zone est courte et bornee.\r\n */\r\n width?: FieldWidth | undefined;\r\n}\r\n\r\nconst FormikTextarea = ({\r\n name,\r\n label,\r\n required,\r\n rows = 4,\r\n htmlFor,\r\n hint,\r\n disabled,\r\n width,\r\n ...rest\r\n}: FormikTextareaProps) => {\r\n const [field, meta] = useField<string>(name);\r\n const hasError = Boolean(meta.touched && meta.error);\r\n\r\n return (\r\n <Field\r\n label={label}\r\n error={hasError ? meta.error : null}\r\n hint={!hasError ? hint : undefined}\r\n htmlFor={htmlFor || name}\r\n {...(required !== undefined ? { required } : {})}\r\n {...(disabled !== undefined ? { disabled } : {})}\r\n {...(width !== undefined ? { width } : {})}\r\n >\r\n <Textarea\r\n name={field.name}\r\n value={field.value ?? \"\"}\r\n onChange={field.onChange}\r\n onBlur={field.onBlur}\r\n rows={rows}\r\n {...rest}\r\n />\r\n </Field>\r\n );\r\n};\r\n\r\nexport default FormikTextarea;\r\n"],"mappings":";;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAC9B,SAASC,QAAQ,QAAQ,QAAQ;AACjC,OAAOC,KAAK,MAAM,qBAAqB;AACvC,OAAOC,QAAQ,MAAM,wBAAwB;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAwB9C,IAAMC,cAAc,GAAG,SAAjBA,cAAcA,CAAAC,IAAA,EAUO;EAAA,IAAAC,YAAA;EAAA,IATzBC,IAAI,GAAAF,IAAA,CAAJE,IAAI;IACJC,KAAK,GAAAH,IAAA,CAALG,KAAK;IACLC,QAAQ,GAAAJ,IAAA,CAARI,QAAQ;IAAAC,SAAA,GAAAL,IAAA,CACRM,IAAI;IAAJA,IAAI,GAAAD,SAAA,cAAG,CAAC,GAAAA,SAAA;IACRE,OAAO,GAAAP,IAAA,CAAPO,OAAO;IACPC,IAAI,GAAAR,IAAA,CAAJQ,IAAI;IACJC,QAAQ,GAAAT,IAAA,CAARS,QAAQ;IACRC,KAAK,GAAAV,IAAA,CAALU,KAAK;IACFC,IAAI,GAAAC,wBAAA,CAAAZ,IAAA,EAAAa,SAAA;EAEP,IAAAC,SAAA,GAAsBpB,QAAQ,CAASQ,IAAI,CAAC;IAAAa,UAAA,GAAAC,cAAA,CAAAF,SAAA;IAArCG,KAAK,GAAAF,UAAA;IAAEG,IAAI,GAAAH,UAAA;EAClB,IAAMI,QAAQ,GAAGC,OAAO,CAACF,IAAI,CAACG,OAAO,IAAIH,IAAI,CAACI,KAAK,CAAC;EAEpD,oBACExB,IAAA,CAACH,KAAK,EAAA4B,aAAA,CAAAA,aAAA,CAAAA,aAAA,CAAAA,aAAA;IACJpB,KAAK,EAAEA,KAAM;IACbmB,KAAK,EAAEH,QAAQ,GAAGD,IAAI,CAACI,KAAK,GAAG,IAAK;IACpCd,IAAI,EAAE,CAACW,QAAQ,GAAGX,IAAI,GAAGgB,SAAU;IACnCjB,OAAO,EAAEA,OAAO,IAAIL;EAAK,GACpBE,QAAQ,KAAKoB,SAAS,GAAG;IAAEpB,QAAQ,EAARA;EAAS,CAAC,GAAG,CAAC,CAAC,GAC1CK,QAAQ,KAAKe,SAAS,GAAG;IAAEf,QAAQ,EAARA;EAAS,CAAC,GAAG,CAAC,CAAC,GAC1CC,KAAK,KAAKc,SAAS,GAAG;IAAEd,KAAK,EAALA;EAAM,CAAC,GAAG,CAAC,CAAC;IAAAe,QAAA,eAEzC3B,IAAA,CAACF,QAAQ,EAAA2B,aAAA;MACPrB,IAAI,EAAEe,KAAK,CAACf,IAAK;MACjBwB,KAAK,GAAAzB,YAAA,GAAEgB,KAAK,CAACS,KAAK,cAAAzB,YAAA,cAAAA,YAAA,GAAI,EAAG;MACzB0B,QAAQ,EAAEV,KAAK,CAACU,QAAS;MACzBC,MAAM,EAAEX,KAAK,CAACW,MAAO;MACrBtB,IAAI,EAAEA;IAAK,GACPK,IAAI,CACT;EAAC,EACG,CAAC;AAEZ,CAAC;AAED,eAAeZ,cAAc","ignoreList":[]}
@@ -112,12 +112,31 @@ function KeyboardShortcutsHelp(_ref2) {
112
112
  shortcuts = _ref2$shortcuts === void 0 ? [] : _ref2$shortcuts,
113
113
  _ref2$title = _ref2.title,
114
114
  title = _ref2$title === void 0 ? "Raccourcis clavier" : _ref2$title,
115
- labels = _ref2.labels;
115
+ labels = _ref2.labels,
116
+ open = _ref2.open,
117
+ onOpenChange = _ref2.onOpenChange;
116
118
  var _React$useState = React.useState(false),
117
119
  _React$useState2 = _slicedToArray(_React$useState, 2),
118
- isOpen = _React$useState2[0],
119
- setIsOpen = _React$useState2[1];
120
+ uncontrolledOpen = _React$useState2[0],
121
+ setUncontrolledOpen = _React$useState2[1];
122
+ var isControlled = open !== undefined;
123
+ var isOpen = isControlled ? open : uncontrolledOpen;
120
124
  var L = mergeLabels(DEFAULT_LABELS, labels);
125
+
126
+ /* Refs so the "?" listener can stay on a `[]` dependency list — it must not
127
+ * be torn down and re-added on every open/close, and in controlled mode there
128
+ * is no functional-update form to fall back on. */
129
+ var isOpenRef = React.useRef(isOpen);
130
+ isOpenRef.current = isOpen;
131
+ var onOpenChangeRef = React.useRef(onOpenChange);
132
+ onOpenChangeRef.current = onOpenChange;
133
+ var isControlledRef = React.useRef(isControlled);
134
+ isControlledRef.current = isControlled;
135
+ var requestOpen = React.useCallback(function (next) {
136
+ var _onOpenChangeRef$curr;
137
+ if (!isControlledRef.current) setUncontrolledOpen(next);
138
+ (_onOpenChangeRef$curr = onOpenChangeRef.current) === null || _onOpenChangeRef$curr === void 0 ? void 0 : _onOpenChangeRef$curr.call(onOpenChangeRef, next);
139
+ }, []);
121
140
  React.useEffect(function () {
122
141
  var handler = function handler(event) {
123
142
  // Only react to "?" (Shift+/ on US, AltGr+, on many AZERTY layouts).
@@ -130,15 +149,13 @@ function KeyboardShortcutsHelp(_ref2) {
130
149
  // User is typing in a text field — let "?" through.
131
150
  if (isFocusOnTextEntry()) return;
132
151
  event.preventDefault();
133
- setIsOpen(function (prev) {
134
- return !prev;
135
- });
152
+ requestOpen(!isOpenRef.current);
136
153
  };
137
154
  window.addEventListener("keydown", handler);
138
155
  return function () {
139
156
  return window.removeEventListener("keydown", handler);
140
157
  };
141
- }, []);
158
+ }, [requestOpen]);
142
159
  if (!Array.isArray(shortcuts) || shortcuts.length === 0) {
143
160
  return null;
144
161
  }
@@ -146,7 +163,7 @@ function KeyboardShortcutsHelp(_ref2) {
146
163
  open: isOpen,
147
164
  title: title,
148
165
  onClose: function onClose() {
149
- return setIsOpen(false);
166
+ return requestOpen(false);
150
167
  },
151
168
  size: "md",
152
169
  children: [/*#__PURE__*/_jsx("dl", {
@@ -1 +1 @@
1
- {"version":3,"file":"KeyboardShortcutsHelp.js","names":["React","Modal","mergeLabels","jsx","_jsx","jsxs","_jsxs","isFocusOnTextEntry","el","document","activeElement","tag","tagName","HTMLElement","isContentEditable","ShortcutKey","_ref","children","style","display","minWidth","padding","background","border","borderBottomColor","borderRadius","boxShadow","fontFamily","fontSize","textAlign","lineHeight","color","SHORTCUT_ROW_SX","gridTemplateColumns","gap","alignItems","borderBottom","SHORTCUT_KEYS_SX","flexWrap","HELP_FOOTNOTE_SX","marginTop","paddingTop","borderTop","DEFAULT_LABELS","Object","freeze","footnoteIntro","footnoteOutro","listAriaLabel","keyJoiner","KeyboardShortcutsHelp","_ref2","_ref2$shortcuts","shortcuts","_ref2$title","title","labels","_React$useState","useState","_React$useState2","_slicedToArray","isOpen","setIsOpen","L","useEffect","handler","event","key","ctrlKey","metaKey","altKey","preventDefault","prev","window","addEventListener","removeEventListener","Array","isArray","length","open","onClose","size","margin","map","sc","i","keys","k","j","Fragment","description"],"sources":["../../../../src/lib/v2/patterns/KeyboardShortcutsHelp.tsx"],"sourcesContent":["import * as React from \"react\";\r\nimport Modal from \"../components/Modal\";\r\nimport { mergeLabels } from \"../utils/mergeLabels\";\r\n\r\n/* ── Body-only focus guard ────────────────────────────────────────\r\n * The \"?\" key is a printable character. If a user types \"?\" inside an\r\n * Input / Textarea / contentEditable element we must NOT hijack the\r\n * keypress to open the help — they're trying to type a question mark.\r\n *\r\n * BUTTON / A focus is NOT blocking by design: when the user has tabbed\r\n * onto an interactive non-text element, hitting \"?\" makes sense as a\r\n * help affordance (navigation mode, not text-entry mode).\r\n */\r\nfunction isFocusOnTextEntry(): boolean {\r\n const el = typeof document !== \"undefined\" ? document.activeElement : null;\r\n if (!el) return false;\r\n const tag = el.tagName;\r\n if (tag === \"INPUT\" || tag === \"TEXTAREA\" || tag === \"SELECT\") return true;\r\n if (el instanceof HTMLElement && el.isContentEditable) return true;\r\n return false;\r\n}\r\n\r\nfunction ShortcutKey({ children }: { children?: React.ReactNode }) {\r\n return (\r\n <kbd\r\n style={{\r\n display: \"inline-block\",\r\n minWidth: \"1.75em\",\r\n padding: \"0.15em 0.5em\",\r\n background: \"var(--bg-subtle)\",\r\n border: \"1px solid var(--border)\",\r\n borderBottomColor: \"var(--border-strong, var(--border))\",\r\n borderRadius: \"var(--r-sm)\",\r\n boxShadow: \"inset 0 -1px 0 var(--border)\",\r\n fontFamily: \"var(--font-mono, monospace)\",\r\n fontSize: \"var(--text-sm)\",\r\n textAlign: \"center\",\r\n lineHeight: 1.4,\r\n color: \"var(--fg)\",\r\n }}\r\n >\r\n {children}\r\n </kbd>\r\n );\r\n}\r\n\r\nconst SHORTCUT_ROW_SX: React.CSSProperties = {\r\n display: \"grid\",\r\n gridTemplateColumns: \"auto 1fr\",\r\n gap: \"var(--s-4)\",\r\n alignItems: \"center\",\r\n padding: \"var(--s-2) 0\",\r\n borderBottom: \"1px solid var(--border-subtle, var(--border))\",\r\n};\r\n\r\nconst SHORTCUT_KEYS_SX: React.CSSProperties = {\r\n display: \"flex\",\r\n gap: \"var(--s-1)\",\r\n alignItems: \"center\",\r\n flexWrap: \"wrap\",\r\n};\r\n\r\nconst HELP_FOOTNOTE_SX: React.CSSProperties = {\r\n marginTop: \"var(--s-4)\",\r\n paddingTop: \"var(--s-3)\",\r\n borderTop: \"1px solid var(--border)\",\r\n fontSize: \"var(--text-xs)\",\r\n color: \"var(--fg-subtle)\",\r\n lineHeight: 1.5,\r\n};\r\n\r\nconst DEFAULT_LABELS = Object.freeze({\r\n /* Footnote rendered below the shortcut list. Split into two parts so the\r\n * keycap can be embedded in the middle without forcing the i18n string to\r\n * carry HTML tags. */\r\n footnoteIntro: \"Astuce : appuyez sur\",\r\n footnoteOutro:\r\n \"à tout moment pour ouvrir ou fermer cette aide. Les raccourcis s'activent uniquement quand votre curseur n'est pas dans un champ de saisie.\",\r\n /* aria-label on the <dl> listing every shortcut. */\r\n listAriaLabel: \"Liste des raccourcis clavier disponibles sur cette page\",\r\n /* Joiner rendered between alternative keys for the same shortcut. */\r\n keyJoiner: \"ou\",\r\n});\r\n\r\n/**\r\n * KeyboardShortcutsHelp — Portnet UI v2\r\n *\r\n * Charter §5.2 SHOULD — discoverable help overlay for page-level keyboard\r\n * shortcuts. Listens globally for \"?\" and opens a v2.Modal listing every\r\n * shortcut as <kbd> elements (WCAG 1.3.1 semantic).\r\n *\r\n * Self-contained: the host page only declares the shortcuts array and renders\r\n * <KeyboardShortcutsHelp shortcuts={…} /> once.\r\n *\r\n * Localisation (FR / EN / AR):\r\n * <KeyboardShortcutsHelp\r\n * title=\"Keyboard shortcuts\"\r\n * labels={{\r\n * footnoteIntro: \"Tip: press\",\r\n * footnoteOutro: \"anytime to toggle this help…\",\r\n * listAriaLabel: \"List of keyboard shortcuts available on this page\",\r\n * keyJoiner: \"or\",\r\n * }}\r\n * shortcuts={…}\r\n * />\r\n *\r\n * Charter §5.2 SHOULD + WCAG 1.3.1 (semantic <kbd>) + 2.1.1 (keyboard\r\n * reachable) + R-M.* (modal focus trap inherited from v2.Modal).\r\n */\r\n\r\nexport interface KeyboardShortcut {\r\n keys: string[];\r\n description: React.ReactNode;\r\n}\r\n\r\nexport interface KeyboardShortcutsHelpLabels {\r\n footnoteIntro?: string | undefined;\r\n footnoteOutro?: string | undefined;\r\n listAriaLabel?: string | undefined;\r\n keyJoiner?: string | undefined;\r\n}\r\n\r\nexport interface KeyboardShortcutsHelpProps {\r\n shortcuts?: KeyboardShortcut[] | undefined;\r\n title?: React.ReactNode | undefined;\r\n labels?: KeyboardShortcutsHelpLabels | undefined;\r\n}\r\n\r\nfunction KeyboardShortcutsHelp({\r\n shortcuts = [],\r\n title = \"Raccourcis clavier\",\r\n labels,\r\n}: KeyboardShortcutsHelpProps) {\r\n const [isOpen, setIsOpen] = React.useState(false);\r\n const L = mergeLabels(DEFAULT_LABELS, labels);\r\n\r\n React.useEffect(() => {\r\n const handler = (event: KeyboardEvent) => {\r\n // Only react to \"?\" (Shift+/ on US, AltGr+, on many AZERTY layouts).\r\n // event.key gives us the resolved character regardless of physical key.\r\n if (event.key !== \"?\") return;\r\n\r\n // Modifier keys (Ctrl, Meta, Alt) reserved for browser / OS shortcuts.\r\n if (event.ctrlKey || event.metaKey || event.altKey) return;\r\n\r\n // User is typing in a text field — let \"?\" through.\r\n if (isFocusOnTextEntry()) return;\r\n\r\n event.preventDefault();\r\n setIsOpen((prev) => !prev);\r\n };\r\n\r\n window.addEventListener(\"keydown\", handler);\r\n return () => window.removeEventListener(\"keydown\", handler);\r\n }, []);\r\n\r\n if (!Array.isArray(shortcuts) || shortcuts.length === 0) {\r\n return null;\r\n }\r\n\r\n return (\r\n <Modal open={isOpen} title={title} onClose={() => setIsOpen(false)} size=\"md\">\r\n <dl style={{ margin: 0, padding: 0 }} aria-label={L.listAriaLabel}>\r\n {shortcuts.map((sc, i) => (\r\n <div key={i} style={SHORTCUT_ROW_SX}>\r\n <dt style={SHORTCUT_KEYS_SX}>\r\n {sc.keys.map((k, j) => (\r\n <React.Fragment key={j}>\r\n <ShortcutKey>{k}</ShortcutKey>\r\n {j < sc.keys.length - 1 && (\r\n <span\r\n aria-hidden=\"true\"\r\n style={{\r\n color: \"var(--fg-subtle)\",\r\n fontSize: \"var(--text-xs)\",\r\n }}\r\n >\r\n {L.keyJoiner}\r\n </span>\r\n )}\r\n </React.Fragment>\r\n ))}\r\n </dt>\r\n <dd style={{ margin: 0, fontSize: \"var(--text-body)\" }}>\r\n {sc.description}\r\n </dd>\r\n </div>\r\n ))}\r\n </dl>\r\n <div style={HELP_FOOTNOTE_SX}>\r\n {L.footnoteIntro}{\" \"}\r\n <ShortcutKey>?</ShortcutKey>{\" \"}\r\n {L.footnoteOutro}\r\n </div>\r\n </Modal>\r\n );\r\n}\r\n\r\nexport default KeyboardShortcutsHelp;\r\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"KeyboardShortcutsHelp.js","names":["React","Modal","mergeLabels","jsx","_jsx","jsxs","_jsxs","isFocusOnTextEntry","el","document","activeElement","tag","tagName","HTMLElement","isContentEditable","ShortcutKey","_ref","children","style","display","minWidth","padding","background","border","borderBottomColor","borderRadius","boxShadow","fontFamily","fontSize","textAlign","lineHeight","color","SHORTCUT_ROW_SX","gridTemplateColumns","gap","alignItems","borderBottom","SHORTCUT_KEYS_SX","flexWrap","HELP_FOOTNOTE_SX","marginTop","paddingTop","borderTop","DEFAULT_LABELS","Object","freeze","footnoteIntro","footnoteOutro","listAriaLabel","keyJoiner","KeyboardShortcutsHelp","_ref2","_ref2$shortcuts","shortcuts","_ref2$title","title","labels","open","onOpenChange","_React$useState","useState","_React$useState2","_slicedToArray","uncontrolledOpen","setUncontrolledOpen","isControlled","undefined","isOpen","L","isOpenRef","useRef","current","onOpenChangeRef","isControlledRef","requestOpen","useCallback","next","_onOpenChangeRef$curr","call","useEffect","handler","event","key","ctrlKey","metaKey","altKey","preventDefault","window","addEventListener","removeEventListener","Array","isArray","length","onClose","size","margin","map","sc","i","keys","k","j","Fragment","description"],"sources":["../../../../src/lib/v2/patterns/KeyboardShortcutsHelp.tsx"],"sourcesContent":["import * as React from \"react\";\r\nimport Modal from \"../components/Modal\";\r\nimport { mergeLabels } from \"../utils/mergeLabels\";\r\n\r\n/* ── Body-only focus guard ────────────────────────────────────────\r\n * The \"?\" key is a printable character. If a user types \"?\" inside an\r\n * Input / Textarea / contentEditable element we must NOT hijack the\r\n * keypress to open the help — they're trying to type a question mark.\r\n *\r\n * BUTTON / A focus is NOT blocking by design: when the user has tabbed\r\n * onto an interactive non-text element, hitting \"?\" makes sense as a\r\n * help affordance (navigation mode, not text-entry mode).\r\n */\r\nfunction isFocusOnTextEntry(): boolean {\r\n const el = typeof document !== \"undefined\" ? document.activeElement : null;\r\n if (!el) return false;\r\n const tag = el.tagName;\r\n if (tag === \"INPUT\" || tag === \"TEXTAREA\" || tag === \"SELECT\") return true;\r\n if (el instanceof HTMLElement && el.isContentEditable) return true;\r\n return false;\r\n}\r\n\r\nfunction ShortcutKey({ children }: { children?: React.ReactNode }) {\r\n return (\r\n <kbd\r\n style={{\r\n display: \"inline-block\",\r\n minWidth: \"1.75em\",\r\n padding: \"0.15em 0.5em\",\r\n background: \"var(--bg-subtle)\",\r\n border: \"1px solid var(--border)\",\r\n borderBottomColor: \"var(--border-strong, var(--border))\",\r\n borderRadius: \"var(--r-sm)\",\r\n boxShadow: \"inset 0 -1px 0 var(--border)\",\r\n fontFamily: \"var(--font-mono, monospace)\",\r\n fontSize: \"var(--text-sm)\",\r\n textAlign: \"center\",\r\n lineHeight: 1.4,\r\n color: \"var(--fg)\",\r\n }}\r\n >\r\n {children}\r\n </kbd>\r\n );\r\n}\r\n\r\nconst SHORTCUT_ROW_SX: React.CSSProperties = {\r\n display: \"grid\",\r\n gridTemplateColumns: \"auto 1fr\",\r\n gap: \"var(--s-4)\",\r\n alignItems: \"center\",\r\n padding: \"var(--s-2) 0\",\r\n borderBottom: \"1px solid var(--border-subtle, var(--border))\",\r\n};\r\n\r\nconst SHORTCUT_KEYS_SX: React.CSSProperties = {\r\n display: \"flex\",\r\n gap: \"var(--s-1)\",\r\n alignItems: \"center\",\r\n flexWrap: \"wrap\",\r\n};\r\n\r\nconst HELP_FOOTNOTE_SX: React.CSSProperties = {\r\n marginTop: \"var(--s-4)\",\r\n paddingTop: \"var(--s-3)\",\r\n borderTop: \"1px solid var(--border)\",\r\n fontSize: \"var(--text-xs)\",\r\n color: \"var(--fg-subtle)\",\r\n lineHeight: 1.5,\r\n};\r\n\r\nconst DEFAULT_LABELS = Object.freeze({\r\n /* Footnote rendered below the shortcut list. Split into two parts so the\r\n * keycap can be embedded in the middle without forcing the i18n string to\r\n * carry HTML tags. */\r\n footnoteIntro: \"Astuce : appuyez sur\",\r\n footnoteOutro:\r\n \"à tout moment pour ouvrir ou fermer cette aide. Les raccourcis s'activent uniquement quand votre curseur n'est pas dans un champ de saisie.\",\r\n /* aria-label on the <dl> listing every shortcut. */\r\n listAriaLabel: \"Liste des raccourcis clavier disponibles sur cette page\",\r\n /* Joiner rendered between alternative keys for the same shortcut. */\r\n keyJoiner: \"ou\",\r\n});\r\n\r\n/**\r\n * KeyboardShortcutsHelp — Portnet UI v2\r\n *\r\n * Charter §5.2 SHOULD — discoverable help overlay for page-level keyboard\r\n * shortcuts. Listens globally for \"?\" and opens a v2.Modal listing every\r\n * shortcut as <kbd> elements (WCAG 1.3.1 semantic).\r\n *\r\n * Self-contained: the host page only declares the shortcuts array and renders\r\n * <KeyboardShortcutsHelp shortcuts={…} /> once.\r\n *\r\n * Localisation (FR / EN / AR):\r\n * <KeyboardShortcutsHelp\r\n * title=\"Keyboard shortcuts\"\r\n * labels={{\r\n * footnoteIntro: \"Tip: press\",\r\n * footnoteOutro: \"anytime to toggle this help…\",\r\n * listAriaLabel: \"List of keyboard shortcuts available on this page\",\r\n * keyJoiner: \"or\",\r\n * }}\r\n * shortcuts={…}\r\n * />\r\n *\r\n * Charter §5.2 SHOULD + WCAG 1.3.1 (semantic <kbd>) + 2.1.1 (keyboard\r\n * reachable) + R-M.* (modal focus trap inherited from v2.Modal).\r\n */\r\n\r\nexport interface KeyboardShortcut {\r\n keys: string[];\r\n description: React.ReactNode;\r\n}\r\n\r\nexport interface KeyboardShortcutsHelpLabels {\r\n footnoteIntro?: string | undefined;\r\n footnoteOutro?: string | undefined;\r\n listAriaLabel?: string | undefined;\r\n keyJoiner?: string | undefined;\r\n}\r\n\r\nexport interface KeyboardShortcutsHelpProps {\r\n shortcuts?: KeyboardShortcut[] | undefined;\r\n title?: React.ReactNode | undefined;\r\n labels?: KeyboardShortcutsHelpLabels | undefined;\r\n /**\r\n * Optional CONTROLLED open state. Omit for the original self-contained\r\n * behaviour (the \"?\" listener owns the state).\r\n *\r\n * Added because the panel had no trigger but the keystroke. Hosts wired it\r\n * correctly and users still reported the shortcuts \"missing\" — they are, in\r\n * every practical sense, if the only affordance is a key you have to already\r\n * know about. Charter §05.2 asks for DISCOVERABLE help, and a host cannot add\r\n * a menu item or button without being able to open this.\r\n */\r\n open?: boolean | undefined;\r\n /** Called with the requested next state, for both \"?\" and the close button. */\r\n onOpenChange?: ((open: boolean) => void) | undefined;\r\n}\r\n\r\nfunction KeyboardShortcutsHelp({\r\n shortcuts = [],\r\n title = \"Raccourcis clavier\",\r\n labels,\r\n open,\r\n onOpenChange,\r\n}: KeyboardShortcutsHelpProps) {\r\n const [uncontrolledOpen, setUncontrolledOpen] = React.useState(false);\r\n const isControlled = open !== undefined;\r\n const isOpen = isControlled ? open : uncontrolledOpen;\r\n const L = mergeLabels(DEFAULT_LABELS, labels);\r\n\r\n /* Refs so the \"?\" listener can stay on a `[]` dependency list — it must not\r\n * be torn down and re-added on every open/close, and in controlled mode there\r\n * is no functional-update form to fall back on. */\r\n const isOpenRef = React.useRef(isOpen);\r\n isOpenRef.current = isOpen;\r\n const onOpenChangeRef = React.useRef(onOpenChange);\r\n onOpenChangeRef.current = onOpenChange;\r\n const isControlledRef = React.useRef(isControlled);\r\n isControlledRef.current = isControlled;\r\n\r\n const requestOpen = React.useCallback((next: boolean) => {\r\n if (!isControlledRef.current) setUncontrolledOpen(next);\r\n onOpenChangeRef.current?.(next);\r\n }, []);\r\n\r\n React.useEffect(() => {\r\n const handler = (event: KeyboardEvent) => {\r\n // Only react to \"?\" (Shift+/ on US, AltGr+, on many AZERTY layouts).\r\n // event.key gives us the resolved character regardless of physical key.\r\n if (event.key !== \"?\") return;\r\n\r\n // Modifier keys (Ctrl, Meta, Alt) reserved for browser / OS shortcuts.\r\n if (event.ctrlKey || event.metaKey || event.altKey) return;\r\n\r\n // User is typing in a text field — let \"?\" through.\r\n if (isFocusOnTextEntry()) return;\r\n\r\n event.preventDefault();\r\n requestOpen(!isOpenRef.current);\r\n };\r\n\r\n window.addEventListener(\"keydown\", handler);\r\n return () => window.removeEventListener(\"keydown\", handler);\r\n }, [requestOpen]);\r\n\r\n if (!Array.isArray(shortcuts) || shortcuts.length === 0) {\r\n return null;\r\n }\r\n\r\n return (\r\n <Modal\r\n open={isOpen}\r\n title={title}\r\n onClose={() => requestOpen(false)}\r\n size=\"md\"\r\n >\r\n <dl style={{ margin: 0, padding: 0 }} aria-label={L.listAriaLabel}>\r\n {shortcuts.map((sc, i) => (\r\n <div key={i} style={SHORTCUT_ROW_SX}>\r\n <dt style={SHORTCUT_KEYS_SX}>\r\n {sc.keys.map((k, j) => (\r\n <React.Fragment key={j}>\r\n <ShortcutKey>{k}</ShortcutKey>\r\n {j < sc.keys.length - 1 && (\r\n <span\r\n aria-hidden=\"true\"\r\n style={{\r\n color: \"var(--fg-subtle)\",\r\n fontSize: \"var(--text-xs)\",\r\n }}\r\n >\r\n {L.keyJoiner}\r\n </span>\r\n )}\r\n </React.Fragment>\r\n ))}\r\n </dt>\r\n <dd style={{ margin: 0, fontSize: \"var(--text-body)\" }}>\r\n {sc.description}\r\n </dd>\r\n </div>\r\n ))}\r\n </dl>\r\n <div style={HELP_FOOTNOTE_SX}>\r\n {L.footnoteIntro}{\" \"}\r\n <ShortcutKey>?</ShortcutKey>{\" \"}\r\n {L.footnoteOutro}\r\n </div>\r\n </Modal>\r\n );\r\n}\r\n\r\nexport default KeyboardShortcutsHelp;\r\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,122 @@
1
+ function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
2
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
3
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
4
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
5
+ function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
6
+ function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
7
+ import * as React from "react";
8
+ import FavoriteToggle from "../components/FavoriteToggle";
9
+ import Tooltip from "../components/Tooltip";
10
+ import { useIsFavorite } from "../personalization/capabilities/favorites";
11
+
12
+ /**
13
+ * RowFavoriteToggle — Portnet UI v2 (pattern)
14
+ *
15
+ * A store-connected follow star for ONE row. Reads `useIsFavorite`, renders
16
+ * `FavoriteToggle`, and stops its own click/keydown from reaching the row's
17
+ * `onRowClick`.
18
+ *
19
+ * ─────────────────────────────────────────────────────────────────────────────
20
+ * WHY THIS BELONGS IN THE LIBRARY (capability gap G-36)
21
+ *
22
+ * This exact component already existed — as `FavoriteCell`, private inside
23
+ * `makeFavoriteColumn`. So the follow star was reachable in ONE context only:
24
+ * as a DataGrid column. Every other place a row appears had to rebuild it.
25
+ *
26
+ * The place that always appears is the MOBILE CARD. `DataGrid` swaps to
27
+ * `renderMobileCard` below its `mobileBreakpoint`, and `MobileRowCard` has a
28
+ * `leading` slot precisely for a per-row control — but a column definition
29
+ * cannot be rendered into a slot, so the host had to re-derive the star by
30
+ * hand. Observed in `onssa-export-fe` as a local `MobileFavoriteToggle`, and
31
+ * `ms-ti-fe` destructures the identical `MobileRowCard` + `FavoriteToggle` +
32
+ * `useIsFavorite` trio for the same reason.
33
+ *
34
+ * This is the same failure mode G-10 recorded for the card recipe welded
35
+ * inside `FormSection`: the library owned the behaviour but exposed it at only
36
+ * one composition point, so consumers reimplemented it at the others. And it
37
+ * was not a harmless copy — the local twin drifted on the part that matters
38
+ * least visibly and most to a screen-reader user. It labelled itself
39
+ * "Ajouter aux favoris" / "Retirer des favoris" while the grid column on the
40
+ * SAME page said "Suivre" / "Ne plus suivre", and it omitted the status
41
+ * Tooltip entirely. One list, one control, two accessible names, depending on
42
+ * viewport width — exactly what R-2.1 forbids.
43
+ *
44
+ * `makeFavoriteColumn` now renders this component, so the desktop column and
45
+ * the mobile card are guaranteed to agree by construction rather than by
46
+ * review.
47
+ * ─────────────────────────────────────────────────────────────────────────────
48
+ *
49
+ * Usage — mobile card `leading` slot:
50
+ *
51
+ * <MobileRowCard
52
+ * leading={
53
+ * <RowFavoriteToggle
54
+ * resourceKey="ti:list"
55
+ * rowId={row.reference}
56
+ * rowLabel={row.reference}
57
+ * />
58
+ * }
59
+ * title={row.reference}
60
+ * … />
61
+ *
62
+ * a11y. The accessible name is ACTION-oriented ("Suivre" / "Ne plus suivre",
63
+ * optionally enriched with `rowLabel`) because that is the toggle convention;
64
+ * `aria-pressed` — set by `FavoriteToggle` — carries the state. The visible
65
+ * status ("Suivi" / "Non suivi") is shown as a Tooltip on hover/focus. An
66
+ * `aria-label` is therefore ALWAYS supplied, which also stops Tooltip from
67
+ * mirroring its title onto the trigger and producing a doubled name.
68
+ *
69
+ * Requires a <UserPersonalizationProvider> ancestor (`useIsFavorite` throws
70
+ * otherwise). `rowId` MUST be the same id the grid uses, so the follow and the
71
+ * row agree.
72
+ */
73
+
74
+ /** `FavoriteToggle`'s own size union, re-derived rather than restated. */
75
+ import { jsx as _jsx } from "react/jsx-runtime";
76
+ export var DEFAULT_ROW_FAVORITE_LABELS = Object.freeze({
77
+ addFavorite: "Suivre",
78
+ removeFavorite: "Ne plus suivre",
79
+ statusFollowed: "Suivi",
80
+ statusNotFollowed: "Non suivi"
81
+ });
82
+ function RowFavoriteToggle(props) {
83
+ var resourceKey = props.resourceKey,
84
+ rowId = props.rowId,
85
+ rowLabel = props.rowLabel,
86
+ _props$size = props.size,
87
+ size = _props$size === void 0 ? "sm" : _props$size,
88
+ labels = props.labels;
89
+ var L = labels ? _objectSpread(_objectSpread({}, DEFAULT_ROW_FAVORITE_LABELS), labels) : DEFAULT_ROW_FAVORITE_LABELS;
90
+ var _useIsFavorite = useIsFavorite(resourceKey, rowId),
91
+ isFavorite = _useIsFavorite.isFavorite,
92
+ toggle = _useIsFavorite.toggle;
93
+ var action = isFavorite ? L.removeFavorite : L.addFavorite;
94
+ var ariaLabel = rowLabel ? action + " : " + rowLabel : action;
95
+ var statusLabel = isFavorite ? L.statusFollowed : L.statusNotFollowed;
96
+ var handleChange = function handleChange(_next, e) {
97
+ // Don't let the toggle's click bubble to the row's onRowClick.
98
+ if (e && typeof e.stopPropagation === "function") e.stopPropagation();
99
+ toggle();
100
+ };
101
+ var handleKeyDown = function handleKeyDown(e) {
102
+ // Prevent row-level Enter/Space (onRowClick) from also firing; the
103
+ // button's own native activation is unaffected.
104
+ e.stopPropagation();
105
+ };
106
+ return /*#__PURE__*/_jsx(Tooltip, {
107
+ title: statusLabel,
108
+ children: /*#__PURE__*/_jsx(FavoriteToggle, {
109
+ pressed: isFavorite,
110
+ onChange: handleChange,
111
+ onKeyDown: handleKeyDown,
112
+ size: size,
113
+ labels: {
114
+ addFavorite: L.addFavorite,
115
+ removeFavorite: L.removeFavorite
116
+ },
117
+ "aria-label": ariaLabel
118
+ })
119
+ });
120
+ }
121
+ export default RowFavoriteToggle;
122
+ //# sourceMappingURL=RowFavoriteToggle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RowFavoriteToggle.js","names":["React","FavoriteToggle","Tooltip","useIsFavorite","jsx","_jsx","DEFAULT_ROW_FAVORITE_LABELS","Object","freeze","addFavorite","removeFavorite","statusFollowed","statusNotFollowed","RowFavoriteToggle","props","resourceKey","rowId","rowLabel","_props$size","size","labels","L","_objectSpread","_useIsFavorite","isFavorite","toggle","action","ariaLabel","statusLabel","handleChange","_next","e","stopPropagation","handleKeyDown","title","children","pressed","onChange","onKeyDown"],"sources":["../../../../src/lib/v2/patterns/RowFavoriteToggle.tsx"],"sourcesContent":["import * as React from \"react\";\r\n\r\nimport FavoriteToggle from \"../components/FavoriteToggle\";\r\nimport Tooltip from \"../components/Tooltip\";\r\nimport { useIsFavorite } from \"../personalization/capabilities/favorites\";\r\nimport type { RowId } from \"../types/common\";\r\n\r\n/**\r\n * RowFavoriteToggle — Portnet UI v2 (pattern)\r\n *\r\n * A store-connected follow star for ONE row. Reads `useIsFavorite`, renders\r\n * `FavoriteToggle`, and stops its own click/keydown from reaching the row's\r\n * `onRowClick`.\r\n *\r\n * ─────────────────────────────────────────────────────────────────────────────\r\n * WHY THIS BELONGS IN THE LIBRARY (capability gap G-36)\r\n *\r\n * This exact component already existed — as `FavoriteCell`, private inside\r\n * `makeFavoriteColumn`. So the follow star was reachable in ONE context only:\r\n * as a DataGrid column. Every other place a row appears had to rebuild it.\r\n *\r\n * The place that always appears is the MOBILE CARD. `DataGrid` swaps to\r\n * `renderMobileCard` below its `mobileBreakpoint`, and `MobileRowCard` has a\r\n * `leading` slot precisely for a per-row control — but a column definition\r\n * cannot be rendered into a slot, so the host had to re-derive the star by\r\n * hand. Observed in `onssa-export-fe` as a local `MobileFavoriteToggle`, and\r\n * `ms-ti-fe` destructures the identical `MobileRowCard` + `FavoriteToggle` +\r\n * `useIsFavorite` trio for the same reason.\r\n *\r\n * This is the same failure mode G-10 recorded for the card recipe welded\r\n * inside `FormSection`: the library owned the behaviour but exposed it at only\r\n * one composition point, so consumers reimplemented it at the others. And it\r\n * was not a harmless copy — the local twin drifted on the part that matters\r\n * least visibly and most to a screen-reader user. It labelled itself\r\n * \"Ajouter aux favoris\" / \"Retirer des favoris\" while the grid column on the\r\n * SAME page said \"Suivre\" / \"Ne plus suivre\", and it omitted the status\r\n * Tooltip entirely. One list, one control, two accessible names, depending on\r\n * viewport width — exactly what R-2.1 forbids.\r\n *\r\n * `makeFavoriteColumn` now renders this component, so the desktop column and\r\n * the mobile card are guaranteed to agree by construction rather than by\r\n * review.\r\n * ─────────────────────────────────────────────────────────────────────────────\r\n *\r\n * Usage — mobile card `leading` slot:\r\n *\r\n * <MobileRowCard\r\n * leading={\r\n * <RowFavoriteToggle\r\n * resourceKey=\"ti:list\"\r\n * rowId={row.reference}\r\n * rowLabel={row.reference}\r\n * />\r\n * }\r\n * title={row.reference}\r\n * … />\r\n *\r\n * a11y. The accessible name is ACTION-oriented (\"Suivre\" / \"Ne plus suivre\",\r\n * optionally enriched with `rowLabel`) because that is the toggle convention;\r\n * `aria-pressed` — set by `FavoriteToggle` — carries the state. The visible\r\n * status (\"Suivi\" / \"Non suivi\") is shown as a Tooltip on hover/focus. An\r\n * `aria-label` is therefore ALWAYS supplied, which also stops Tooltip from\r\n * mirroring its title onto the trigger and producing a doubled name.\r\n *\r\n * Requires a <UserPersonalizationProvider> ancestor (`useIsFavorite` throws\r\n * otherwise). `rowId` MUST be the same id the grid uses, so the follow and the\r\n * row agree.\r\n */\r\n\r\n/** `FavoriteToggle`'s own size union, re-derived rather than restated. */\r\nexport type FavoriteToggleSize = NonNullable<\r\n React.ComponentProps<typeof FavoriteToggle>[\"size\"]\r\n>;\r\n\r\nexport interface RowFavoriteToggleLabels {\r\n addFavorite: string;\r\n removeFavorite: string;\r\n statusFollowed: string;\r\n statusNotFollowed: string;\r\n}\r\n\r\nexport const DEFAULT_ROW_FAVORITE_LABELS = Object.freeze({\r\n addFavorite: \"Suivre\",\r\n removeFavorite: \"Ne plus suivre\",\r\n statusFollowed: \"Suivi\",\r\n statusNotFollowed: \"Non suivi\",\r\n} satisfies RowFavoriteToggleLabels);\r\n\r\nexport interface RowFavoriteToggleProps {\r\n /** Follow namespace — must match the list's other personalization calls. */\r\n resourceKey: string;\r\n /** Business row id. MUST match the grid's `getRowId` for this row. */\r\n rowId: RowId;\r\n /** Enriches the per-row accessible name (\"Suivre : 2025-IM-0042\"). */\r\n rowLabel?: string | undefined;\r\n /** @default \"sm\" — fits dense rows and card leading slots. */\r\n size?: FavoriteToggleSize | undefined;\r\n labels?: Partial<RowFavoriteToggleLabels> | undefined;\r\n}\r\n\r\nfunction RowFavoriteToggle(props: RowFavoriteToggleProps): React.JSX.Element {\r\n const { resourceKey, rowId, rowLabel, size = \"sm\", labels } = props;\r\n const L: RowFavoriteToggleLabels = labels\r\n ? { ...DEFAULT_ROW_FAVORITE_LABELS, ...labels }\r\n : DEFAULT_ROW_FAVORITE_LABELS;\r\n\r\n const { isFavorite, toggle } = useIsFavorite(resourceKey, rowId);\r\n\r\n const action = isFavorite ? L.removeFavorite : L.addFavorite;\r\n const ariaLabel = rowLabel ? action + \" : \" + rowLabel : action;\r\n const statusLabel = isFavorite ? L.statusFollowed : L.statusNotFollowed;\r\n\r\n const handleChange: NonNullable<\r\n React.ComponentProps<typeof FavoriteToggle>[\"onChange\"]\r\n > = function handleChange(_next, e) {\r\n // Don't let the toggle's click bubble to the row's onRowClick.\r\n if (e && typeof e.stopPropagation === \"function\") e.stopPropagation();\r\n toggle();\r\n };\r\n const handleKeyDown: NonNullable<\r\n React.ComponentProps<typeof FavoriteToggle>[\"onKeyDown\"]\r\n > = function handleKeyDown(e) {\r\n // Prevent row-level Enter/Space (onRowClick) from also firing; the\r\n // button's own native activation is unaffected.\r\n e.stopPropagation();\r\n };\r\n\r\n return (\r\n <Tooltip title={statusLabel}>\r\n <FavoriteToggle\r\n pressed={isFavorite}\r\n onChange={handleChange}\r\n onKeyDown={handleKeyDown}\r\n size={size}\r\n labels={{ addFavorite: L.addFavorite, removeFavorite: L.removeFavorite }}\r\n aria-label={ariaLabel}\r\n />\r\n </Tooltip>\r\n );\r\n}\r\n\r\nexport default RowFavoriteToggle;\r\n"],"mappings":";;;;;;AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAE9B,OAAOC,cAAc,MAAM,8BAA8B;AACzD,OAAOC,OAAO,MAAM,uBAAuB;AAC3C,SAASC,aAAa,QAAQ,2CAA2C;;AAGzE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AAAA,SAAAC,GAAA,IAAAC,IAAA;AAYA,OAAO,IAAMC,2BAA2B,GAAGC,MAAM,CAACC,MAAM,CAAC;EACvDC,WAAW,EAAE,QAAQ;EACrBC,cAAc,EAAE,gBAAgB;EAChCC,cAAc,EAAE,OAAO;EACvBC,iBAAiB,EAAE;AACrB,CAAmC,CAAC;AAcpC,SAASC,iBAAiBA,CAACC,KAA6B,EAAqB;EAC3E,IAAQC,WAAW,GAA2CD,KAAK,CAA3DC,WAAW;IAAEC,KAAK,GAAoCF,KAAK,CAA9CE,KAAK;IAAEC,QAAQ,GAA0BH,KAAK,CAAvCG,QAAQ;IAAAC,WAAA,GAA0BJ,KAAK,CAA7BK,IAAI;IAAJA,IAAI,GAAAD,WAAA,cAAG,IAAI,GAAAA,WAAA;IAAEE,MAAM,GAAKN,KAAK,CAAhBM,MAAM;EACzD,IAAMC,CAA0B,GAAGD,MAAM,GAAAE,aAAA,CAAAA,aAAA,KAChChB,2BAA2B,GAAKc,MAAM,IAC3Cd,2BAA2B;EAE/B,IAAAiB,cAAA,GAA+BpB,aAAa,CAACY,WAAW,EAAEC,KAAK,CAAC;IAAxDQ,UAAU,GAAAD,cAAA,CAAVC,UAAU;IAAEC,MAAM,GAAAF,cAAA,CAANE,MAAM;EAE1B,IAAMC,MAAM,GAAGF,UAAU,GAAGH,CAAC,CAACX,cAAc,GAAGW,CAAC,CAACZ,WAAW;EAC5D,IAAMkB,SAAS,GAAGV,QAAQ,GAAGS,MAAM,GAAG,KAAK,GAAGT,QAAQ,GAAGS,MAAM;EAC/D,IAAME,WAAW,GAAGJ,UAAU,GAAGH,CAAC,CAACV,cAAc,GAAGU,CAAC,CAACT,iBAAiB;EAEvE,IAAMiB,YAEL,GAAG,SAASA,YAAYA,CAACC,KAAK,EAAEC,CAAC,EAAE;IAClC;IACA,IAAIA,CAAC,IAAI,OAAOA,CAAC,CAACC,eAAe,KAAK,UAAU,EAAED,CAAC,CAACC,eAAe,CAAC,CAAC;IACrEP,MAAM,CAAC,CAAC;EACV,CAAC;EACD,IAAMQ,aAEL,GAAG,SAASA,aAAaA,CAACF,CAAC,EAAE;IAC5B;IACA;IACAA,CAAC,CAACC,eAAe,CAAC,CAAC;EACrB,CAAC;EAED,oBACE3B,IAAA,CAACH,OAAO;IAACgC,KAAK,EAAEN,WAAY;IAAAO,QAAA,eAC1B9B,IAAA,CAACJ,cAAc;MACbmC,OAAO,EAAEZ,UAAW;MACpBa,QAAQ,EAAER,YAAa;MACvBS,SAAS,EAAEL,aAAc;MACzBd,IAAI,EAAEA,IAAK;MACXC,MAAM,EAAE;QAAEX,WAAW,EAAEY,CAAC,CAACZ,WAAW;QAAEC,cAAc,EAAEW,CAAC,CAACX;MAAe,CAAE;MACzE,cAAYiB;IAAU,CACvB;EAAC,CACK,CAAC;AAEd;AAEA,eAAed,iBAAiB","ignoreList":[]}