@mgdis/mg-components 6.27.0 → 6.28.0

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 (65) hide show
  1. package/dist/cjs/loader.cjs.js +1 -1
  2. package/dist/cjs/mg-action-more_36.cjs.entry.js +365 -77
  3. package/dist/cjs/mg-components.cjs.js +1 -1
  4. package/dist/cjs/mg-input-combobox.cjs.entry.js +36 -2
  5. package/dist/cjs/mg-input-file.cjs.entry.js +25 -2
  6. package/dist/cjs/mg-input-rich-text-editor.cjs.entry.js +717 -504
  7. package/dist/collection/assets/jodit/jodit.css +1 -1
  8. package/dist/collection/components/atoms/mg-button/mg-button.js +86 -13
  9. package/dist/collection/components/molecules/inputs/mg-input-checkbox/mg-input-checkbox.js +24 -1
  10. package/dist/collection/components/molecules/inputs/mg-input-combobox/mg-input-combobox.js +36 -2
  11. package/dist/collection/components/molecules/inputs/mg-input-date/mg-input-date.js +25 -9
  12. package/dist/collection/components/molecules/inputs/mg-input-file/mg-input-file.js +25 -2
  13. package/dist/collection/components/molecules/inputs/mg-input-numeric/mg-input-numeric.js +24 -6
  14. package/dist/collection/components/molecules/inputs/mg-input-password/mg-input-password.js +24 -5
  15. package/dist/collection/components/molecules/inputs/mg-input-radio/mg-input-radio.js +64 -16
  16. package/dist/collection/components/molecules/inputs/mg-input-select/mg-input-select.js +32 -10
  17. package/dist/collection/components/molecules/inputs/mg-input-text/mg-input-text.js +24 -5
  18. package/dist/collection/components/molecules/inputs/mg-input-textarea/mg-input-textarea.js +24 -6
  19. package/dist/collection/components/molecules/mg-form/mg-form.js +74 -8
  20. package/dist/components/mg-button2.js +1 -1
  21. package/dist/components/mg-form.js +1 -1
  22. package/dist/components/mg-input-checkbox.js +1 -1
  23. package/dist/components/mg-input-combobox.js +1 -1
  24. package/dist/components/mg-input-date.js +1 -1
  25. package/dist/components/mg-input-file.js +1 -1
  26. package/dist/components/mg-input-numeric.js +1 -1
  27. package/dist/components/mg-input-password.js +1 -1
  28. package/dist/components/mg-input-radio.js +1 -1
  29. package/dist/components/mg-input-rich-text-editor.js +262 -262
  30. package/dist/components/mg-input-select2.js +1 -1
  31. package/dist/components/mg-input-text2.js +1 -1
  32. package/dist/components/mg-input-textarea.js +1 -1
  33. package/dist/components/mg-modal.js +1 -1
  34. package/dist/custom-elements.json +12 -2
  35. package/dist/esm/loader.js +1 -1
  36. package/dist/esm/mg-action-more_36.entry.js +366 -78
  37. package/dist/esm/mg-components.js +1 -1
  38. package/dist/esm/mg-input-combobox.entry.js +36 -2
  39. package/dist/esm/mg-input-file.entry.js +25 -2
  40. package/dist/esm/mg-input-rich-text-editor.entry.js +717 -504
  41. package/dist/mg-components/mg-components.esm.js +1 -1
  42. package/dist/mg-components/p-2198f145.entry.js +1 -0
  43. package/dist/mg-components/p-d4a4eb78.entry.js +1 -0
  44. package/dist/mg-components/{p-6f492676.entry.js → p-e8b5e8d8.entry.js} +261 -261
  45. package/dist/mg-components/p-fdcce8d5.entry.js +1 -0
  46. package/dist/types/components/atoms/mg-button/mg-button.d.ts +41 -2
  47. package/dist/types/components/molecules/inputs/mg-input/mg-input.conf.d.ts +1 -0
  48. package/dist/types/components/molecules/inputs/mg-input-checkbox/mg-input-checkbox.d.ts +9 -0
  49. package/dist/types/components/molecules/inputs/mg-input-combobox/mg-input-combobox.d.ts +10 -1
  50. package/dist/types/components/molecules/inputs/mg-input-date/mg-input-date.d.ts +9 -0
  51. package/dist/types/components/molecules/inputs/mg-input-file/mg-input-file.d.ts +9 -0
  52. package/dist/types/components/molecules/inputs/mg-input-numeric/mg-input-numeric.d.ts +9 -0
  53. package/dist/types/components/molecules/inputs/mg-input-password/mg-input-password.d.ts +9 -0
  54. package/dist/types/components/molecules/inputs/mg-input-radio/mg-input-radio.d.ts +29 -2
  55. package/dist/types/components/molecules/inputs/mg-input-select/mg-input-select.d.ts +10 -1
  56. package/dist/types/components/molecules/inputs/mg-input-text/mg-input-text.d.ts +9 -0
  57. package/dist/types/components/molecules/inputs/mg-input-textarea/mg-input-textarea.d.ts +9 -0
  58. package/dist/types/components/molecules/mg-form/mg-form.d.ts +18 -0
  59. package/dist/types/components.d.ts +10 -2
  60. package/ide/intellij/web-types.json +4 -4
  61. package/ide/vscode/html-custom-data.json +3 -3
  62. package/package.json +19 -19
  63. package/dist/mg-components/p-32a55ddb.entry.js +0 -1
  64. package/dist/mg-components/p-813d69c7.entry.js +0 -1
  65. package/dist/mg-components/p-a2445605.entry.js +0 -1
@@ -16,12 +16,12 @@ export class MgInputRadio {
16
16
  /************
17
17
  * Internal *
18
18
  ************/
19
- // HTML selector
20
- this.inputs = [];
21
19
  // classes
22
20
  this.classVerticalList = 'mg-c-input--vertical-list';
23
21
  // hasDisplayedError (triggered by blur event)
24
22
  this.hasDisplayedError = false;
23
+ // raised when `value` or `items` changed, so componentDidUpdate revalidates once the DOM is in sync
24
+ this.validityCheckPending = false;
25
25
  this.customErrorMessage = { lock: false };
26
26
  /**
27
27
  * Input name
@@ -65,7 +65,6 @@ export class MgInputRadio {
65
65
  * @param event - input event
66
66
  */
67
67
  this.handleInput = (event) => {
68
- this.checkValidity();
69
68
  this.value = this.options[event.target.value].value;
70
69
  };
71
70
  /**
@@ -78,11 +77,23 @@ export class MgInputRadio {
78
77
  // reset guard
79
78
  this.handlerInProgress = undefined;
80
79
  };
80
+ /**
81
+ * Check if the required constraint is fulfilled
82
+ * The native group validity cannot answer it: a browser keeps the checked member a group had, even
83
+ * once that input is removed from the DOM. Options that cannot be selected are ignored.
84
+ * @returns required constraint is fulfilled
85
+ */
86
+ this.validateRequired = () => {
87
+ const selectableOptions = this.options.filter((option) => !option.disabled);
88
+ return (!this.required ||
89
+ selectableOptions.length < 1 ||
90
+ selectableOptions.some((option) => this.isSelectedValue(option.value)));
91
+ };
81
92
  /**
82
93
  * Check if input is valid
83
94
  */
84
95
  this.checkValidity = () => {
85
- this.setValidity(this.readonly || this.disabled || this.getInvalidElement() === undefined);
96
+ this.setValidity(this.readonly || this.disabled || (this.getInvalidElement() === undefined && this.validateRequired()));
86
97
  };
87
98
  /**
88
99
  * Set input error message
@@ -98,7 +109,7 @@ export class MgInputRadio {
98
109
  this.errorMessage = this.customErrorMessage.message;
99
110
  }
100
111
  // required
101
- else if (invalidElement.validity.valueMissing) {
112
+ else if (invalidElement === undefined || invalidElement.validity.valueMissing) {
102
113
  this.errorMessage = this.messages.errors.required;
103
114
  }
104
115
  }
@@ -107,11 +118,24 @@ export class MgInputRadio {
107
118
  * get invalid element
108
119
  * @returns element
109
120
  */
110
- this.getInvalidElement = () => this.inputs.find((input) => !input.disabled && !input.readOnly && !input.checkValidity());
121
+ this.getInvalidElement = () => this.getInputs().find((input) => !input.disabled && !input.readOnly && !input.checkValidity());
122
+ /**
123
+ * Get the rendered radio inputs
124
+ * Read from the DOM: references kept from a render would outlive the inputs they point to.
125
+ * @returns rendered radio inputs
126
+ */
127
+ this.getInputs = () => Array.from(this.element.shadowRoot.querySelectorAll('input[type="radio"]'));
128
+ /**
129
+ * Check if a value is the selected one
130
+ * @param optionValue - option value to compare to the component value
131
+ * @returns option value is the selected one
132
+ */
133
+ this.isSelectedValue = (optionValue) => JSON.stringify(this.value) === JSON.stringify(optionValue);
111
134
  }
112
135
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
113
136
  watchValue(newValue) {
114
137
  var _a;
138
+ this.validityCheckPending = true;
115
139
  if (allItemsAreString(this.items) && typeof newValue === 'string') {
116
140
  this.readonlyValue = newValue;
117
141
  }
@@ -123,7 +147,7 @@ export class MgInputRadio {
123
147
  }
124
148
  this.valueChange.emit(newValue);
125
149
  }
126
- validateItems(newValue) {
150
+ validateItems(newValue, oldValue) {
127
151
  // Validate if items have required min length
128
152
  if (typeof newValue === 'object' && newValue.length < 2) {
129
153
  throw new Error(`<mg-input-radio> prop "items" require at least 2 items. Passed value: ${toString(newValue)}.`);
@@ -139,6 +163,14 @@ export class MgInputRadio {
139
163
  else {
140
164
  throw new Error(`<mg-input-radio> prop "items" is required and all items must be the same type, string or RadioOption. Passed value: ${toString(newValue)}.`);
141
165
  }
166
+ // `oldValue` is undefined on init
167
+ if (oldValue !== undefined) {
168
+ // the options cannot display a value they no longer offer, drop it
169
+ if (this.value !== undefined && !this.options.some((option) => this.isSelectedValue(option.value))) {
170
+ this.value = undefined;
171
+ }
172
+ this.validityCheckPending = true;
173
+ }
142
174
  }
143
175
  watchInputVerticalList(newValue) {
144
176
  if (newValue)
@@ -153,7 +185,7 @@ export class MgInputRadio {
153
185
  this.classCollection.delete(classReadonly);
154
186
  }
155
187
  handleValidityChange(newValue, _oldValue, prop) {
156
- this.inputs.forEach((input) => {
188
+ this.getInputs().forEach((input) => {
157
189
  input[prop] = newValue;
158
190
  });
159
191
  this.checkValidity();
@@ -172,9 +204,8 @@ export class MgInputRadio {
172
204
  * Set focus on input.
173
205
  */
174
206
  async setFocus() {
175
- if (this.inputs.length > 0) {
176
- this.inputs[0].focus();
177
- }
207
+ var _a;
208
+ (_a = this.element.shadowRoot.querySelector('input')) === null || _a === void 0 ? void 0 : _a.focus();
178
209
  }
179
210
  /**
180
211
  * Display input error if it exists.
@@ -216,6 +247,8 @@ export class MgInputRadio {
216
247
  lock: valid ? false : errorMessageLock,
217
248
  message: valid ? undefined : errorMessage,
218
249
  };
250
+ // setError() states the validity explicitly, so drop any pending recomputation
251
+ this.validityCheckPending = false;
219
252
  this.setValidity(valid);
220
253
  this.setErrorMessage(true);
221
254
  this.hasDisplayedError = this.invalid;
@@ -281,20 +314,35 @@ export class MgInputRadio {
281
314
  // https://stenciljs.com/docs/component-lifecycle#componentwillload
282
315
  return setTimeout(() => {
283
316
  this.checkValidity();
317
+ // the initial check covers the initial value: nothing is pending yet
318
+ this.validityCheckPending = false;
284
319
  }, 0);
285
320
  }
321
+ /**
322
+ * Recompute validity once the DOM is in sync with `value`.
323
+ * `@Watch('value')` fires before Stencil re-renders, so the rendered control still holds the
324
+ * previous value at that point (visible with a programmatic value change, e.g. a `v-model`
325
+ * default value). The watcher therefore only raises a flag, and the check runs here, after the
326
+ * render. Renders unrelated to `value` leave the flag down and recompute nothing.
327
+ */
328
+ componentDidUpdate() {
329
+ if (this.validityCheckPending && this.getInputs().length > 0) {
330
+ this.validityCheckPending = false;
331
+ this.checkValidity();
332
+ if (this.hasDisplayedError) {
333
+ this.setErrorMessage();
334
+ }
335
+ }
336
+ }
286
337
  /**
287
338
  * Render
288
339
  * @returns HTML Element
289
340
  */
290
341
  render() {
291
- return (h("mg-input", { key: '763e021cdda0735dcbd62700f09cbc32c0de7377', label: this.label, identifier: this.identifier, class: this.classCollection.join(), labelOnTop: this.labelOnTop, labelHide: this.labelHide, required: this.required, tooltip: this.tooltip, tooltipPosition: this.readonly && !this.value ? 'label' : this.tooltipPosition, helpText: this.helpText, errorMessage: this.errorMessage }, this.readonly ? (this.readonlyValue && h("b", { class: "mg-c-input__readonly-value" }, this.readonlyValue)) : (h("div", { class: "mg-c-input__input-group-container" }, this.options.map((input, index) => (h("div", { key: input.title, class: {
342
+ return (h("mg-input", { key: '1fd4b600eb95f2ff5c753884c40b982e0552d576', label: this.label, identifier: this.identifier, class: this.classCollection.join(), labelOnTop: this.labelOnTop, labelHide: this.labelHide, required: this.required, tooltip: this.tooltip, tooltipPosition: this.readonly && !this.value ? 'label' : this.tooltipPosition, helpText: this.helpText, errorMessage: this.errorMessage }, this.readonly ? (this.readonlyValue && h("b", { class: "mg-c-input__readonly-value" }, this.readonlyValue)) : (h("div", { class: "mg-c-input__input-group-container" }, this.options.map((input, index) => (h("div", { key: input.title, class: {
292
343
  'mg-c-input__input-group': true,
293
344
  'mg-c-input__input-group--disabled': this.disabled || input.disabled,
294
- } }, h("input", { type: "radio", id: this.identifier + '_' + index, name: this.identifier, value: index, checked: JSON.stringify(this.value) === JSON.stringify(this.options[index].value), disabled: this.disabled || input.disabled, required: this.required, onBlur: this.handleBlur, onInput: this.handleInput, ref: (el) => {
295
- if (el !== null)
296
- this.inputs[index] = el;
297
- } }), h("label", { htmlFor: this.identifier + '_' + index }, input.title))))))));
345
+ } }, h("input", { type: "radio", id: this.identifier + '_' + index, name: this.identifier, value: index, checked: this.isSelectedValue(this.options[index].value), disabled: this.disabled || input.disabled, required: this.required, onBlur: this.handleBlur, onInput: this.handleInput }), h("label", { htmlFor: this.identifier + '_' + index }, input.title))))))));
298
346
  }
299
347
  static get is() { return "mg-input-radio"; }
300
348
  static get encapsulation() { return "shadow"; }
@@ -24,8 +24,9 @@ const isOptGroup = (optgroup) => typeof optgroup === 'object' &&
24
24
  typeof optgroup.group === 'string' &&
25
25
  allItemsAreOptions(optgroup.options);
26
26
  /**
27
- * Ensure options can be unambiguously differentiated by their title
27
+ * Report, without enforcing, options that cannot be unambiguously differentiated by their title
28
28
  * Two options can share the same title only when they belong to different groups
29
+ * An option is identified by its render index, so a duplicated title only harms readability: it is reported to the developer and the field still renders
29
30
  * @param items - select options to validate
30
31
  */
31
32
  const validateUniqueTitles = (items) => {
@@ -37,7 +38,7 @@ const validateUniqueTitles = (items) => {
37
38
  const titles = titlesByGroup.get(group);
38
39
  if (titles.has(title)) {
39
40
  const groupContext = group === undefined ? 'outside of a group' : `within the group "${group}"`;
40
- throw new Error(`<mg-input-select> prop "items" must not contain options with the same "title" ${groupContext}. Duplicated title: "${title}".`);
41
+ console.error(`<mg-input-select> prop "items" must not contain options with the same "title" ${groupContext}. Duplicated title: "${title}".`);
41
42
  }
42
43
  titles.add(title);
43
44
  });
@@ -70,6 +71,8 @@ export class MgInputSelect {
70
71
  constructor() {
71
72
  // hasDisplayedError (triggered by blur event)
72
73
  this.hasDisplayedError = false;
74
+ // raised when `value` or `items` changed, so componentDidUpdate revalidates once the DOM is in sync
75
+ this.validityCheckPending = false;
73
76
  this.customErrorMessage = { lock: false };
74
77
  /**
75
78
  * Input name
@@ -217,18 +220,14 @@ export class MgInputSelect {
217
220
  this.renderOption = (option, index) => (h("option", { key: index, value: `${index}`, selected: JSON.stringify(this.value) === JSON.stringify(option.value), disabled: option.disabled }, option.title));
218
221
  }
219
222
  validateValue(newValue) {
220
- setTimeout(() => {
221
- this.checkValidity();
222
- if (this.hasDisplayedError) {
223
- this.setErrorMessage();
224
- }
225
- }, 0);
223
+ this.validityCheckPending = true;
226
224
  this.valueChange.emit(newValue);
227
225
  }
228
- validateItems(newValue) {
226
+ validateItems(newValue, oldValue) {
229
227
  // Empty options
230
228
  if (newValue.length === 0) {
231
229
  this.options = [];
230
+ this.valueExist = false;
232
231
  }
233
232
  // String array
234
233
  else if (allItemsAreString(newValue)) {
@@ -254,6 +253,9 @@ export class MgInputSelect {
254
253
  else {
255
254
  throw new Error(`<mg-input-select> prop "items" is required, can be an empty Array or all items must be the same type: string or Option. Passed value: ${toString(newValue)}.`);
256
255
  }
256
+ // `oldValue` is undefined on init. The value is kept: an unmatched one renders the placeholder.
257
+ if (oldValue !== undefined)
258
+ this.validityCheckPending = true;
257
259
  }
258
260
  watchReadonly(newValue) {
259
261
  if (newValue)
@@ -333,6 +335,8 @@ export class MgInputSelect {
333
335
  lock: valid ? false : errorMessageLock,
334
336
  message: valid ? undefined : errorMessage,
335
337
  };
338
+ // setError() states the validity explicitly, so drop any pending recomputation
339
+ this.validityCheckPending = false;
336
340
  this.setValidity(valid);
337
341
  this.setErrorMessage(true);
338
342
  this.hasDisplayedError = this.invalid;
@@ -403,8 +407,26 @@ export class MgInputSelect {
403
407
  // https://stenciljs.com/docs/component-lifecycle#componentwillload
404
408
  return setTimeout(() => {
405
409
  this.checkValidity();
410
+ // the initial check covers the initial value: nothing is pending yet
411
+ this.validityCheckPending = false;
406
412
  }, 0);
407
413
  }
414
+ /**
415
+ * Recompute validity once the DOM is in sync with `value`.
416
+ * `@Watch('value')` fires before Stencil re-renders, so the rendered control still holds the
417
+ * previous value at that point (visible with a programmatic value change, e.g. a `v-model`
418
+ * default value). The watcher therefore only raises a flag, and the check runs here, after the
419
+ * render. Renders unrelated to `value` leave the flag down and recompute nothing.
420
+ */
421
+ componentDidUpdate() {
422
+ if (this.validityCheckPending && this.input !== undefined) {
423
+ this.validityCheckPending = false;
424
+ this.checkValidity();
425
+ if (this.hasDisplayedError) {
426
+ this.setErrorMessage();
427
+ }
428
+ }
429
+ }
408
430
  /**
409
431
  * Render
410
432
  * @returns HTML Element
@@ -413,7 +435,7 @@ export class MgInputSelect {
413
435
  const readonlyValue = this.getReadonlyValue();
414
436
  // Running index shared across groups, so each option gets a unique value matching its position in getOptions()
415
437
  let optionIndex = 0;
416
- return (h("mg-input", { key: 'aab8c17ced01c0afbec9114f280ee2b7fa73cdfc', label: this.label, identifier: this.identifier, class: this.classCollection.join(), labelOnTop: this.labelOnTop, labelHide: this.labelHide, required: this.required, tooltip: this.tooltip, tooltipPosition: this.readonly && readonlyValue === null ? 'label' : this.tooltipPosition, helpText: this.helpText, errorMessage: this.errorMessage }, this.readonly ? (readonlyValue && h("b", { class: "mg-c-input__readonly-value" }, readonlyValue)) : (h("select", { class: "mg-c-input__box", id: this.identifier, name: this.name, title: this.placeholder, disabled: this.disabled, required: this.required, "aria-invalid": (this.invalid === true).toString(), onInput: this.handleInput, onBlur: this.handleBlur, ref: (el) => {
438
+ return (h("mg-input", { key: 'ca4a3a1b95094505bff8bf062566a633a1b12d1a', label: this.label, identifier: this.identifier, class: this.classCollection.join(), labelOnTop: this.labelOnTop, labelHide: this.labelHide, required: this.required, tooltip: this.tooltip, tooltipPosition: this.readonly && readonlyValue === null ? 'label' : this.tooltipPosition, helpText: this.helpText, errorMessage: this.errorMessage }, this.readonly ? (readonlyValue && h("b", { class: "mg-c-input__readonly-value" }, readonlyValue)) : (h("select", { class: "mg-c-input__box", id: this.identifier, name: this.name, title: this.placeholder, disabled: this.disabled, required: this.required, "aria-invalid": (this.invalid === true).toString(), onInput: this.handleInput, onBlur: this.handleBlur, ref: (el) => {
417
439
  if (el !== null)
418
440
  this.input = el;
419
441
  } }, (!this.placeholderHide || !this.valueExist) && ( // In case passed value does not match any option we display the placeholder
@@ -34,6 +34,8 @@ export class MgInputText {
34
34
  // hasDisplayedError (triggered by blur event)
35
35
  this.hasDisplayedError = false;
36
36
  this.customErrorMessage = { lock: false };
37
+ // raised when `value` changed, so componentDidUpdate revalidates once the DOM is in sync
38
+ this.validityCheckPending = false;
37
39
  /**
38
40
  * Input name
39
41
  * If not set the value equals the identifier
@@ -98,10 +100,6 @@ export class MgInputText {
98
100
  * Handle input event
99
101
  */
100
102
  this.handleInput = () => {
101
- this.checkValidity();
102
- if (this.hasDisplayedError) {
103
- this.setErrorMessage();
104
- }
105
103
  this.value = this.input.value;
106
104
  };
107
105
  /**
@@ -182,6 +180,7 @@ export class MgInputText {
182
180
  }
183
181
  handleValue(newValue) {
184
182
  var _a, _b;
183
+ this.validityCheckPending = true;
185
184
  if ((_a = this.datalistoptions) === null || _a === void 0 ? void 0 : _a.every(isOption)) {
186
185
  this.valueChange.emit(((_b = this.datalistoptions.find((option) => option.title === newValue)) === null || _b === void 0 ? void 0 : _b.value) || newValue);
187
186
  }
@@ -301,6 +300,8 @@ export class MgInputText {
301
300
  lock: valid ? false : errorMessageLock,
302
301
  message: valid ? undefined : errorMessage,
303
302
  };
303
+ // setError() states the validity explicitly, so drop any pending recomputation
304
+ this.validityCheckPending = false;
304
305
  this.setValidity(valid);
305
306
  this.setErrorMessage(true);
306
307
  this.hasDisplayedError = this.invalid;
@@ -373,14 +374,32 @@ export class MgInputText {
373
374
  // https://stenciljs.com/docs/component-lifecycle#componentwillload
374
375
  return setTimeout(() => {
375
376
  this.checkValidity();
377
+ // the initial check covers the initial value: nothing is pending yet
378
+ this.validityCheckPending = false;
376
379
  }, 0);
377
380
  }
381
+ /**
382
+ * Recompute validity once the DOM is in sync with `value`.
383
+ * `@Watch('value')` fires before Stencil re-renders, so the rendered control still holds the
384
+ * previous value at that point (visible with a programmatic value change, e.g. a `v-model`
385
+ * default value). The watcher therefore only raises a flag, and the check runs here, after the
386
+ * render. Renders unrelated to `value` leave the flag down and recompute nothing.
387
+ */
388
+ componentDidUpdate() {
389
+ if (this.validityCheckPending && this.input !== undefined) {
390
+ this.validityCheckPending = false;
391
+ this.checkValidity();
392
+ if (this.hasDisplayedError) {
393
+ this.setErrorMessage();
394
+ }
395
+ }
396
+ }
378
397
  /**
379
398
  * Render
380
399
  * @returns HTML Element
381
400
  */
382
401
  render() {
383
- return (h("mg-input", { key: '3454b5f94af7b47a2c94b1416f59f840552ef70a', label: this.label, identifier: this.identifier, class: this.classCollection.join(), ariaDescribedbyIDs: this.characterLeftId, labelOnTop: this.labelOnTop, labelHide: this.labelHide, required: this.required, tooltip: this.tooltip, tooltipPosition: this.readonly && this.value === undefined ? 'label' : this.tooltipPosition, helpText: this.helpText, errorMessage: this.errorMessage }, this.readonly
402
+ return (h("mg-input", { key: '20a89d186c673936740cce348977cc0a8471fafb', label: this.label, identifier: this.identifier, class: this.classCollection.join(), ariaDescribedbyIDs: this.characterLeftId, labelOnTop: this.labelOnTop, labelHide: this.labelHide, required: this.required, tooltip: this.tooltip, tooltipPosition: this.readonly && this.value === undefined ? 'label' : this.tooltipPosition, helpText: this.helpText, errorMessage: this.errorMessage }, this.readonly
384
403
  ? this.value && this.renderReadonly()
385
404
  : [
386
405
  h("div", { key: "input", class: "mg-c-input__input-group-container", style: {
@@ -7,6 +7,8 @@ export class MgInputTextarea {
7
7
  constructor() {
8
8
  // hasDisplayedError (triggered by blur event)
9
9
  this.hasDisplayedError = false;
10
+ // raised when `value` changed, so componentDidUpdate revalidates once the DOM is in sync
11
+ this.validityCheckPending = false;
10
12
  this.customErrorMessage = { lock: false };
11
13
  /**
12
14
  * Input name
@@ -65,10 +67,6 @@ export class MgInputTextarea {
65
67
  * Handle input event
66
68
  */
67
69
  this.handleInput = () => {
68
- if (this.hasDisplayedError) {
69
- this.checkValidity();
70
- this.setErrorMessage();
71
- }
72
70
  this.value = this.input.value;
73
71
  };
74
72
  /**
@@ -118,7 +116,7 @@ export class MgInputTextarea {
118
116
  };
119
117
  }
120
118
  handleValue(newValue) {
121
- this.checkValidity();
119
+ this.validityCheckPending = true;
122
120
  this.valueChange.emit(newValue);
123
121
  }
124
122
  watchReadonly(newValue) {
@@ -212,6 +210,8 @@ export class MgInputTextarea {
212
210
  lock: valid ? false : errorMessageLock,
213
211
  message: valid ? undefined : errorMessage,
214
212
  };
213
+ // setError() states the validity explicitly, so drop any pending recomputation
214
+ this.validityCheckPending = false;
215
215
  this.setValidity(valid);
216
216
  this.setErrorMessage(true);
217
217
  this.hasDisplayedError = this.invalid;
@@ -279,14 +279,32 @@ export class MgInputTextarea {
279
279
  // https://stenciljs.com/docs/component-lifecycle#componentwillload
280
280
  return setTimeout(() => {
281
281
  this.checkValidity();
282
+ // the initial check covers the initial value: nothing is pending yet
283
+ this.validityCheckPending = false;
282
284
  }, 0);
283
285
  }
286
+ /**
287
+ * Recompute validity once the DOM is in sync with `value`.
288
+ * `@Watch('value')` fires before Stencil re-renders, so the rendered control still holds the
289
+ * previous value at that point (visible with a programmatic value change, e.g. a `v-model`
290
+ * default value). The watcher therefore only raises a flag, and the check runs here, after the
291
+ * render. Renders unrelated to `value` leave the flag down and recompute nothing.
292
+ */
293
+ componentDidUpdate() {
294
+ if (this.validityCheckPending && this.input !== undefined) {
295
+ this.validityCheckPending = false;
296
+ this.checkValidity();
297
+ if (this.hasDisplayedError) {
298
+ this.setErrorMessage();
299
+ }
300
+ }
301
+ }
284
302
  /**
285
303
  * Render
286
304
  * @returns HTML Element
287
305
  */
288
306
  render() {
289
- return (h("mg-input", { key: '36575f026a23722bb6d224aaeacf0e80d3e1bbfd', label: this.label, identifier: this.identifier, class: this.classCollection.join(), ariaDescribedbyIDs: this.characterLeftId, labelOnTop: this.labelOnTop, labelHide: this.labelHide, required: this.required, tooltip: this.tooltip, tooltipPosition: this.readonly && this.value === undefined ? 'label' : this.tooltipPosition, helpText: this.helpText, errorMessage: this.errorMessage }, this.readonly ? (this.value && h("b", { class: "mg-c-input__readonly-value" }, this.value)) : (h("div", { class: "mg-c-input__input-group-container" }, h("textarea", { class: {
307
+ return (h("mg-input", { key: 'e3bf8b4bbddccaf86a78f8517cc529aa41cc61d6', label: this.label, identifier: this.identifier, class: this.classCollection.join(), ariaDescribedbyIDs: this.characterLeftId, labelOnTop: this.labelOnTop, labelHide: this.labelHide, required: this.required, tooltip: this.tooltip, tooltipPosition: this.readonly && this.value === undefined ? 'label' : this.tooltipPosition, helpText: this.helpText, errorMessage: this.errorMessage }, this.readonly ? (this.value && h("b", { class: "mg-c-input__readonly-value" }, this.value)) : (h("div", { class: "mg-c-input__input-group-container" }, h("textarea", { class: {
290
308
  'mg-c-input__box': true,
291
309
  'mg-c-input__box--width': true,
292
310
  'mg-c-input__box--resizable': this.resizable === 'both',
@@ -1,5 +1,5 @@
1
1
  import { h } from "@stencil/core";
2
- import { ClassList, createID, isValideID, toString } from "@mgdis/core-ui-helpers/dist/utils";
2
+ import { ClassList, createID, isValideID, isValidString, toString } from "@mgdis/core-ui-helpers/dist/utils";
3
3
  import { normalizeBooleanAttributes } from "@mgdis/core-ui-helpers/dist/stencil";
4
4
  import { initLocales } from "../../../locales";
5
5
  import { isMgInputFile } from "../inputs/mg-input/mg-input.conf";
@@ -195,6 +195,38 @@ export class MgForm {
195
195
  this.formReset.emit(true);
196
196
  }
197
197
  }
198
+ /**
199
+ * Request the form submission: emit `form-submit`, whatever the inputs validity.
200
+ * This is what a `mg-button` associated with this form goes through, so that reaching the form
201
+ * needs no access to its shadow DOM. Unlike the native `requestSubmit()`, it runs no constraint
202
+ * validation: validity is the consumer's call here, as it is on submission from a nested button.
203
+ * Read `invalid`, or call `displayError()` / `focusFirstInvalidInput()`.
204
+ * Unlike `reset()`, a readonly form still submits: readonly fields do not block a native
205
+ * submission either, and a nested button has always submitted such a form.
206
+ */
207
+ async requestSubmit() {
208
+ this.formSubmit.emit();
209
+ }
210
+ /**
211
+ * **Experimental.** The signature may still change in a minor release.
212
+ *
213
+ * Display errors, then focus and scroll to the first invalid input. Focusing is what
214
+ * carries the information for assistive technologies, a scroll announces nothing.
215
+ * Read the `invalid` property to know whether the form had an invalid input.
216
+ */
217
+ async focusFirstInvalidInput() {
218
+ if (!this.readonly) {
219
+ await this.displayError();
220
+ // Inputs defer their displayError() to a requestAnimationFrame
221
+ await new Promise((resolve) => requestAnimationFrame(resolve));
222
+ // Read at call time: a MutationObserver rebuilds the list on content change
223
+ const firstInvalidInput = this.mgInputs.find((input) => input.invalid);
224
+ if (firstInvalidInput !== undefined) {
225
+ await firstInvalidInput.setFocus();
226
+ firstInvalidInput.scrollIntoView();
227
+ }
228
+ }
229
+ }
198
230
  /*************
199
231
  * Lifecycle *
200
232
  *************/
@@ -213,13 +245,13 @@ export class MgForm {
213
245
  this.hasActions = this.element.querySelector('[slot="actions"]') !== null;
214
246
  // Get slotted mgButtons
215
247
  this.mgButtons = Array.from(this.element.querySelectorAll('mg-button'));
216
- // Set button form identifier
248
+ // Announce the association: a slotted button then drives this form through its public API and
249
+ // handles its own submit and reset, which is why none is wired here. An id it already carries
250
+ // wins, read as property and attribute since frameworks pass the prop as one or the other.
217
251
  this.mgButtons.forEach((mgButton) => {
218
- mgButton.setAttribute('form', this.identifier);
219
- if (mgButton.type === 'reset') {
220
- mgButton.addEventListener('click', () => {
221
- this.reset();
222
- });
252
+ var _a;
253
+ if (!isValidString((_a = mgButton.form) !== null && _a !== void 0 ? _a : mgButton.getAttribute('form'))) {
254
+ mgButton.setAttribute('form', this.identifier);
223
255
  }
224
256
  });
225
257
  // Set mgInputs
@@ -254,7 +286,7 @@ export class MgForm {
254
286
  * @returns HTML Element
255
287
  */
256
288
  render() {
257
- return (h("form", { key: 'c851e6f19af32f28cad695daa1f42ddff10796a0', class: this.classCollection.join(), id: this.identifier, name: this.name, onSubmit: this.handleFormSubmit, role: this.ariaRole }, this.requiredMessageText && h("p", { key: '7f92b35872c938e87959acac8841937ad503d98f', innerHTML: this.requiredMessageText }), h("slot", { key: 'e75e90f1fe3076d93df82a7a426b17d82035e0cf' }), !this.readonly && !this.disabled && this.hasActions && (h("div", { key: 'a472cf024a61d6be1665d149749ce7d560a00473', class: "mg-c-form__actions" }, h("slot", { key: 'f9098c711cb2d2714057c4f14d6df295b75de774', name: "actions" })))));
289
+ return (h("form", { key: '0c23474cba5ae38a70162129641128cdd17224cb', class: this.classCollection.join(), id: this.identifier, name: this.name, onSubmit: this.handleFormSubmit, role: this.ariaRole }, this.requiredMessageText && h("p", { key: '8938192d2b2f4d1278f6e5037ed7f0f839c44861', innerHTML: this.requiredMessageText }), h("slot", { key: 'aefbcb13adbe2632b958c55c2c2c0174d5aaf471' }), !this.readonly && !this.disabled && this.hasActions && (h("div", { key: '30675225f5a910945f5b31fb044d3501c323acf9', class: "mg-c-form__actions" }, h("slot", { key: '6f5b871264d0237fc1eccfac5c454e61135b81c4', name: "actions" })))));
258
290
  }
259
291
  static get is() { return "mg-form"; }
260
292
  static get encapsulation() { return "shadow"; }
@@ -565,6 +597,40 @@ export class MgForm {
565
597
  "text": "Reset form inputs values, validity and error state",
566
598
  "tags": []
567
599
  }
600
+ },
601
+ "requestSubmit": {
602
+ "complexType": {
603
+ "signature": "() => Promise<void>",
604
+ "parameters": [],
605
+ "references": {
606
+ "Promise": {
607
+ "location": "global",
608
+ "id": "global::Promise"
609
+ }
610
+ },
611
+ "return": "Promise<void>"
612
+ },
613
+ "docs": {
614
+ "text": "Request the form submission: emit `form-submit`, whatever the inputs validity.\nThis is what a `mg-button` associated with this form goes through, so that reaching the form\nneeds no access to its shadow DOM. Unlike the native `requestSubmit()`, it runs no constraint\nvalidation: validity is the consumer's call here, as it is on submission from a nested button.\nRead `invalid`, or call `displayError()` / `focusFirstInvalidInput()`.\nUnlike `reset()`, a readonly form still submits: readonly fields do not block a native\nsubmission either, and a nested button has always submitted such a form.",
615
+ "tags": []
616
+ }
617
+ },
618
+ "focusFirstInvalidInput": {
619
+ "complexType": {
620
+ "signature": "() => Promise<void>",
621
+ "parameters": [],
622
+ "references": {
623
+ "Promise": {
624
+ "location": "global",
625
+ "id": "global::Promise"
626
+ }
627
+ },
628
+ "return": "Promise<void>"
629
+ },
630
+ "docs": {
631
+ "text": "**Experimental.** The signature may still change in a minor release.\n\nDisplay errors, then focus and scroll to the first invalid input. Focusing is what\ncarries the information for assistive technologies, a scroll announces nothing.\nRead the `invalid` property to know whether the form had an invalid input.",
632
+ "tags": []
633
+ }
568
634
  }
569
635
  };
570
636
  }
@@ -1 +1 @@
1
- import{transformTag as t,proxyCustomElement as o,HTMLElement as n,createEvent as r,h as i,Host as e}from"@stencil/core/internal/client";import{C as a,t as c,i as b,n as d}from"./index2.js";import{n as g}from"./index3.js";import{K as s}from"./events.utils.js";import{d as u}from"./mg-icon2.js";const m=["medium","large"],l=["primary","secondary","danger","danger-alt","info","flat","success","link"],h=o(class extends n{constructor(t){super(),!1!==t&&this.__registerHost(),this.__attachShadow(),this.disabledChange=r(this,"disabled-change",7),this.onClickElementFn=null,this.classDisabled="mg-c-button--disabled",this.classLoading="mg-c-button--loading",this.classFullWidth="mg-c-button--full-width",this.variant="primary",this.size="medium",this.fullWidth=!1,this.isIcon=!1,this.disableOnClick=!1,this.loading=!1,this.classCollection=new a(["mg-c-button"]),this.handleClick=t=>{this.disabled?t.stopPropagation():this.disableOnClick&&(this.loading=!0,this.disabled=!0)},this.handleKeydown=t=>{this.disabled||" "!==t.key?!this.disabled&&[s.ENTER,s.NUMPADENTER,s.SPACE].includes(t.key)&&(t.preventDefault(),this.element.dispatchEvent(new MouseEvent("click",{bubbles:!0}))):t.preventDefault()},this.handleKeyup=t=>{this.disabled||" "!==t.key||(t.preventDefault(),this.element.dispatchEvent(new MouseEvent("click",{bubbles:!0})))},this.setIconSize=()=>{var t,o;"medium"===this.size?null===(t=this.element.querySelector("mg-icon[size]"))||void 0===t||t.removeAttribute("size"):this.isIcon&&(null===(o=this.element.querySelector("mg-icon"))||void 0===o||o.setAttribute("size",this.size))}}validateVariant(t,o){if(!l.includes(t)){if(""===t)return void(this.variant=l[0]);throw new Error(`<mg-button> prop "variant" must be one of: ${l.join(", ")}. Passed value: ${c(t)}.`)}void 0!==o&&this.classCollection.delete(`mg-c-button--${o}`),this.classCollection.add(`mg-c-button--${t}`)}validateSize(t,o){if(!m.includes(t))throw new Error(`<mg-button> prop "size" must be one of: ${m.join(", ")}. Passed value: ${c(t)}.`);void 0!==o&&this.classCollection.delete(`mg-c-button--${o}`),this.classCollection.add(`mg-c-button--${t}`),this.setIconSize()}validateFullWidth(t){if(t&&this.isIcon)throw new Error('<mg-button> prop "fullWidth" cannot be used with prop "isIcon".');t?this.classCollection.add(this.classFullWidth):this.classCollection.delete(this.classFullWidth)}disabledHandler(t){!t&&this.disableOnClick&&(this.loading=!1),this.element.onclick=t?void 0:this.onClickElementFn,t?this.classCollection.add(this.classDisabled):this.classCollection.delete(this.classDisabled),this.disabledChange.emit(t)}watchIsIcon(t){if(t){if(this.classCollection.add("mg-c-button--icon"),!b(this.label))throw new Error('<mg-button> prop "label" is mandatory when prop "isIcon" is set to true.')}else this.classCollection.delete("mg-c-button--icon");this.setIconSize()}loadingHandler(t){t?this.classCollection.add(this.classLoading):this.classCollection.delete(this.classLoading)}componentWillLoad(){g(this),this.validateVariant(this.variant),this.validateFullWidth(this.fullWidth),this.validateSize(this.size),this.watchIsIcon(this.isIcon),this.onClickElementFn=this.element.onclick,this.disabledHandler(this.disabled)}componentDidLoad(){d((()=>{var t;const o=this.element.closest("form")||(null===(t=this.element.closest("mg-form"))||void 0===t?void 0:t.shadowRoot.querySelector("form"));o&&["submit",void 0].includes(this.type)&&this.element.addEventListener("click",(()=>{o.dispatchEvent(new SubmitEvent("submit",{bubbles:!0,cancelable:!0}))}))}))}render(){var t;return i(e,{key:"9efa9dbbcdb2965cb8fd301c86988d0b0d97b474",role:"button",tabIndex:this.element.getAttribute("tabindex")||0,type:this.type,form:this.form,"full-width":this.fullWidth,"aria-label":this.label,"aria-disabled":null===(t=this.disabled)||void 0===t?void 0:t.toString(),onClick:this.handleClick,onKeyup:this.handleKeyup,onKeydown:this.handleKeydown},i("div",{key:"36918b5b208a9e0a9650107f4418cac35ade1ed2",class:this.classCollection.join()},this.loading&&i("mg-icon",{key:"8ad3e911d273f69441f2a405f8040cc685a0a486",icon:"loader",spin:!0}),i("div",{key:"a6b199c669ef6b15bfc345c98192290ce11e65cb",class:"mg-c-button__content"},i("slot",{key:"b13d317001dbf66c945cdf9e97c06338ce073c12"}))))}get element(){return this}static get watchers(){return{variant:[{validateVariant:0}],size:[{validateSize:0}],fullWidth:[{validateFullWidth:0}],disabled:[{disabledHandler:0}],isIcon:[{watchIsIcon:0}],loading:[{loadingHandler:0}]}}static get style(){return":host{display:inline-block;max-width:100%;vertical-align:middle}:host(:hover) .mg-c-button--flat:not(.mg-c-button--disabled),:host([data-mg-popover-trigger][aria-expanded=true]) .mg-c-button--flat:not(.mg-c-button--disabled),.mg-c-button--flat:hover:not(.mg-c-button--disabled,:disabled,[aria-disabled=true]){background:color-mix(in srgb, var(--mg-b-color-dark), transparent 90%)}:host([full-width]){display:block}:host([disabled]),:host([aria-disabled=true]){pointer-events:none}.mg-c-button.mg-c-button--primary{border-color:var(--mg-c-button-color-border-primary);background:linear-gradient(to bottom, var(--mg-c-button-color-background-primary), var(--mg-c-button-color-gradient-primary));color:var(--mg-c-button-color-text-primary)}:host(:hover) .mg-c-button.mg-c-button--primary:not(.mg-c-button--disabled),:host([data-mg-popover-trigger][aria-expanded=true]) .mg-c-button.mg-c-button--primary:not(.mg-c-button--disabled),.mg-c-button.mg-c-button--primary:hover:not(.mg-c-button--disabled,:disabled,[aria-disabled=true]){background:var(--mg-c-button-color-background-primary)}.mg-c-button.mg-c-button--secondary{border-color:var(--mg-c-button-color-border-secondary);background:linear-gradient(to bottom, var(--mg-c-button-color-background-secondary), var(--mg-c-button-color-gradient-secondary));color:var(--mg-c-button-color-text-secondary)}:host(:hover) .mg-c-button.mg-c-button--secondary:not(.mg-c-button--disabled),:host([data-mg-popover-trigger][aria-expanded=true]) .mg-c-button.mg-c-button--secondary:not(.mg-c-button--disabled),.mg-c-button.mg-c-button--secondary:hover:not(.mg-c-button--disabled,:disabled,[aria-disabled=true]){background:var(--mg-c-button-color-background-secondary)}.mg-c-button.mg-c-button--danger{border-color:var(--mg-c-button-color-border-danger);background:linear-gradient(to bottom, var(--mg-c-button-color-background-danger), var(--mg-c-button-color-gradient-danger));color:var(--mg-c-button-color-text-danger)}:host(:hover) .mg-c-button.mg-c-button--danger:not(.mg-c-button--disabled),:host([data-mg-popover-trigger][aria-expanded=true]) .mg-c-button.mg-c-button--danger:not(.mg-c-button--disabled),.mg-c-button.mg-c-button--danger:hover:not(.mg-c-button--disabled,:disabled,[aria-disabled=true]){background:var(--mg-c-button-color-background-danger)}.mg-c-button.mg-c-button--info{border-color:var(--mg-c-button-color-border-info);background:linear-gradient(to bottom, var(--mg-c-button-color-background-info), var(--mg-c-button-color-gradient-info));color:var(--mg-c-button-color-text-info)}:host(:hover) .mg-c-button.mg-c-button--info:not(.mg-c-button--disabled),:host([data-mg-popover-trigger][aria-expanded=true]) .mg-c-button.mg-c-button--info:not(.mg-c-button--disabled),.mg-c-button.mg-c-button--info:hover:not(.mg-c-button--disabled,:disabled,[aria-disabled=true]){background:var(--mg-c-button-color-background-info)}.mg-c-button.mg-c-button--success{border-color:var(--mg-c-button-color-border-success);background:linear-gradient(to bottom, var(--mg-c-button-color-background-success), var(--mg-c-button-color-gradient-success));color:var(--mg-c-button-color-text-success)}:host(:hover) .mg-c-button.mg-c-button--success:not(.mg-c-button--disabled),:host([data-mg-popover-trigger][aria-expanded=true]) .mg-c-button.mg-c-button--success:not(.mg-c-button--disabled),.mg-c-button.mg-c-button--success:hover:not(.mg-c-button--disabled,:disabled,[aria-disabled=true]){background:var(--mg-c-button-color-background-success)}.mg-c-button.mg-c-button--warning{border-color:var(--mg-c-button-color-border-warning);background:linear-gradient(to bottom, var(--mg-c-button-color-background-warning), var(--mg-c-button-color-gradient-warning));color:var(--mg-c-button-color-text-warning)}:host(:hover) .mg-c-button.mg-c-button--warning:not(.mg-c-button--disabled),:host([data-mg-popover-trigger][aria-expanded=true]) .mg-c-button.mg-c-button--warning:not(.mg-c-button--disabled),.mg-c-button.mg-c-button--warning:hover:not(.mg-c-button--disabled,:disabled,[aria-disabled=true]){background:var(--mg-c-button-color-background-warning)}.mg-c-button.mg-c-button--danger-alt{border-color:var(--mg-c-button-color-border-danger-alt);background:linear-gradient(to bottom, var(--mg-c-button-color-background-danger-alt), var(--mg-c-button-color-gradient-danger-alt));color:var(--mg-c-button-color-text-danger-alt)}:host(:hover) .mg-c-button.mg-c-button--danger-alt:not(.mg-c-button--disabled),:host([data-mg-popover-trigger][aria-expanded=true]) .mg-c-button.mg-c-button--danger-alt:not(.mg-c-button--disabled),.mg-c-button.mg-c-button--danger-alt:hover:not(.mg-c-button--disabled,:disabled,[aria-disabled=true]){background:var(--mg-c-button-color-background-danger-alt)}.mg-c-button{position:relative;display:inline-flex;min-height:var(--mg-b-size-min-height);box-sizing:border-box;align-items:center;padding:calc((var(--mg-b-size-min-height) - 2*var(--mg-b-size-border) - var(--mg-b-font-size)*var(--mg-b-line-height))/2) var(--mg-b-size-12);border-width:var(--mg-c-button-border-top-width, var(--mg-b-size-border)) var(--mg-c-button-border-right-width, var(--mg-b-size-border)) var(--mg-c-button-border-bottom-width, var(--mg-b-size-border)) var(--mg-c-button-border-left-width, var(--mg-b-size-border));border-style:solid;border-radius:var(--mg-c-button-border-radius-top-left, var(--mg-c-button-border-radius)) var(--mg-c-button-border-radius-top-right, var(--mg-c-button-border-radius)) var(--mg-c-button-border-radius-bottom-right, var(--mg-c-button-border-radius)) var(--mg-c-button-border-radius-bottom-left, var(--mg-c-button-border-radius));background-image:none;color:inherit;column-gap:var(--mg-b-size-8);cursor:pointer;touch-action:manipulation;font-family:inherit;font-size:var(--mg-b-font-size);font-weight:var(--mg-c-button-font-weight, normal);text-align:left;text-decoration:none}.mg-c-button slot,.mg-c-button ::slotted(*:not(mg-icon)){font-family:inherit;font-size:var(--mg-b-font-size);font-weight:var(--mg-c-button-font-weight, normal);text-align:left;text-decoration:none;display:flex;align-items:center;column-gap:var(--mg-b-size-8)}.mg-c-button mg-icon:only-child,.mg-c-button ::slotted(mg-icon){display:inline-flex;flex-shrink:0;margin:auto 0;line-height:1}.mg-c-button.mg-c-button--disabled,.mg-c-button[aria-disabled=true],.mg-c-button:disabled{cursor:default;opacity:var(--mg-b-opacity-element-disabled);pointer-events:none}.mg-c-button.mg-c-button--flat{border:none;background:none}.mg-c-button.mg-c-button--link{min-height:unset;padding:unset;border:unset;border-radius:unset;background:unset;text-decoration:underline}.mg-c-button.mg-c-button--link slot{font-weight:600}.mg-c-button.mg-c-button--link:hover{text-decoration:none}.mg-c-button.mg-c-button--large{padding:calc(var(--mg-b-size-12) - var(--mg-b-size-border)) calc(var(--mg-b-size-24) - var(--mg-b-size-border))}.mg-c-button.mg-c-button--large:not(.mg-c-button--icon){line-height:var(--mg-b-size-24)}.mg-c-button.mg-c-button--large:not(.mg-c-button--icon) slot,.mg-c-button.mg-c-button--large:not(.mg-c-button--icon) ::slotted(*){font-size:var(--mg-b-size-16)}.mg-c-button.mg-c-button--icon{width:var(--mg-b-size-min-height);height:var(--mg-b-size-min-height);justify-content:center;padding:0;border-radius:var(--mg-c-button-border-radius-top-left, var(--mg-c-button-icon-border-radius)) var(--mg-c-button-border-radius-top-right, var(--mg-c-button-icon-border-radius)) var(--mg-c-button-border-radius-bottom-right, var(--mg-c-button-icon-border-radius)) var(--mg-c-button-border-radius-bottom-left, var(--mg-c-button-icon-border-radius));font-size:var(--mg-b-font-size);line-height:var(--mg-b-font-size)}.mg-c-button.mg-c-button--icon.mg-c-button--large{width:unset;height:unset;padding:calc(var(--mg-b-size-12) - var(--mg-b-size-border))}.mg-c-button.mg-c-button--icon.mg-c-button--large ::slotted(*){min-width:var(--mg-b-size-24);min-height:var(--mg-b-size-24);align-items:center;justify-content:center}.mg-c-button.mg-c-button--full-width{display:flex;width:100%;justify-content:center}.mg-c-button.mg-c-button--loading>mg-icon:first-of-type{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%)}.mg-c-button.mg-c-button--loading .mg-c-button__content{opacity:0}:host(:focus-visible),:host([data-focus-visible]){outline:0}:host(:focus-visible) .mg-c-button,:host([data-focus-visible]) .mg-c-button{outline-color:-webkit-focus-ring-color;outline-style:auto;outline-width:var(--mg-b-size-2)}.mg-c-button:focus-visible{outline-color:-webkit-focus-ring-color;outline-style:auto;outline-width:var(--mg-b-size-2)}"}},[257,"mg-button",{variant:[1025],label:[1],type:[1],size:[1],fullWidth:[4,"full-width"],form:[1],disabled:[1028],isIcon:[4,"is-icon"],disableOnClick:[4,"disable-on-click"],loading:[32],classCollection:[32]},void 0,{variant:[{validateVariant:0}],size:[{validateSize:0}],fullWidth:[{validateFullWidth:0}],disabled:[{disabledHandler:0}],isIcon:[{watchIsIcon:0}],loading:[{loadingHandler:0}]}]);function v(){"undefined"!=typeof customElements&&["mg-button","mg-icon"].forEach((o=>{switch(o){case"mg-button":customElements.get(t(o))||customElements.define(t(o),h);break;case"mg-icon":customElements.get(t(o))||u()}}))}v();export{h as M,v as d}
1
+ import{transformTag as t,proxyCustomElement as o,HTMLElement as n,createEvent as r,h as i,Host as e}from"@stencil/core/internal/client";import{C as a,i as c,t as b}from"./index2.js";import{n as s}from"./index3.js";import{K as g}from"./events.utils.js";import{d}from"./mg-icon2.js";const u=["medium","large"],m=["primary","secondary","danger","danger-alt","info","flat","success","link"],l=o(class extends n{constructor(t){super(),!1!==t&&this.__registerHost(),this.__attachShadow(),this.disabledChange=r(this,"disabled-change",7),this.onClickElementFn=null,this.classDisabled="mg-c-button--disabled",this.classLoading="mg-c-button--loading",this.classFullWidth="mg-c-button--full-width",this.variant="primary",this.size="medium",this.fullWidth=!1,this.isIcon=!1,this.disableOnClick=!1,this.loading=!1,this.classCollection=new a(["mg-c-button"]),this.handleClick=t=>{this.disabled?t.stopPropagation():this.disableOnClick&&(this.loading=!0,this.disabled=!0)},this.handleKeydown=t=>{this.disabled||" "!==t.key?!this.disabled&&[g.ENTER,g.NUMPADENTER,g.SPACE].includes(t.key)&&(t.preventDefault(),this.element.dispatchEvent(new MouseEvent("click",{bubbles:!0}))):t.preventDefault()},this.handleKeyup=t=>{this.disabled||" "!==t.key||(t.preventDefault(),this.element.dispatchEvent(new MouseEvent("click",{bubbles:!0})))},this.setIconSize=()=>{var t,o;"medium"===this.size?null===(t=this.element.querySelector("mg-icon[size]"))||void 0===t||t.removeAttribute("size"):this.isIcon&&(null===(o=this.element.querySelector("mg-icon"))||void 0===o||o.setAttribute("size",this.size))},this.dispatchSubmit=t=>{t.dispatchEvent(new SubmitEvent("submit",{bubbles:!0,cancelable:!0}))},this.mgFormActions=t=>({submit:()=>t.requestSubmit(),reset:()=>t.reset()}),this.nativeFormActions=t=>({submit:()=>this.dispatchSubmit(t),reset:()=>t.reset()}),this.resolveOwnerById=()=>{const t=this.element.closest("mg-form");if(null!==t&&t.identifier===this.form)return this.mgFormActions(t);const o=this.element.getRootNode(),n=o instanceof ShadowRoot?o:this.element.ownerDocument,r=Array.from(n.querySelectorAll("mg-form")).find((t=>t.identifier===this.form));if(void 0!==r)return this.mgFormActions(r);const i=n.getElementById(this.form);return i instanceof HTMLFormElement?this.nativeFormActions(i):null},this.resolveFormOwner=()=>{if(c(this.form)){const t=this.resolveOwnerById();if(null!==t)return t;console.error(`<mg-button> prop "form" matches no form in the button tree. Passed value: ${b(this.form)}.`)}const t=this.element.closest("form");if(null!==t)return this.nativeFormActions(t);const o=this.element.closest("mg-form");return null===o?null:this.mgFormActions(o)},this.handleFormClick=()=>{const t=["submit",void 0].includes(this.type),o="reset"===this.type&&c(this.form);if(!t&&!o)return;const n=this.resolveFormOwner();null!==n&&(t?n.submit():n.reset())}}validateVariant(t,o){if(!m.includes(t)){if(""===t)return void(this.variant=m[0]);throw new Error(`<mg-button> prop "variant" must be one of: ${m.join(", ")}. Passed value: ${b(t)}.`)}void 0!==o&&this.classCollection.delete(`mg-c-button--${o}`),this.classCollection.add(`mg-c-button--${t}`)}validateSize(t,o){if(!u.includes(t))throw new Error(`<mg-button> prop "size" must be one of: ${u.join(", ")}. Passed value: ${b(t)}.`);void 0!==o&&this.classCollection.delete(`mg-c-button--${o}`),this.classCollection.add(`mg-c-button--${t}`),this.setIconSize()}validateFullWidth(t){if(t&&this.isIcon)throw new Error('<mg-button> prop "fullWidth" cannot be used with prop "isIcon".');t?this.classCollection.add(this.classFullWidth):this.classCollection.delete(this.classFullWidth)}disabledHandler(t){!t&&this.disableOnClick&&(this.loading=!1),this.element.onclick=t?void 0:this.onClickElementFn,t?this.classCollection.add(this.classDisabled):this.classCollection.delete(this.classDisabled),this.disabledChange.emit(t)}watchIsIcon(t){if(t){if(this.classCollection.add("mg-c-button--icon"),!c(this.label))throw new Error('<mg-button> prop "label" is mandatory when prop "isIcon" is set to true.')}else this.classCollection.delete("mg-c-button--icon");this.setIconSize()}loadingHandler(t){t?this.classCollection.add(this.classLoading):this.classCollection.delete(this.classLoading)}componentWillLoad(){s(this),this.validateVariant(this.variant),this.validateFullWidth(this.fullWidth),this.validateSize(this.size),this.watchIsIcon(this.isIcon),this.onClickElementFn=this.element.onclick,this.disabledHandler(this.disabled)}componentDidLoad(){this.element.addEventListener("click",this.handleFormClick)}render(){var t;return i(e,{key:"815bedd3729c652a5faf06c3d451cbc67123ab63",role:"button",tabIndex:this.element.getAttribute("tabindex")||0,type:this.type,form:this.form,"full-width":this.fullWidth,"aria-label":this.label,"aria-disabled":null===(t=this.disabled)||void 0===t?void 0:t.toString(),onClick:this.handleClick,onKeyup:this.handleKeyup,onKeydown:this.handleKeydown},i("div",{key:"2a1c20c677294870958f01c4042e8f530bf0f89d",class:this.classCollection.join()},this.loading&&i("mg-icon",{key:"db3960249deed458f86bcba16b66bbeb9aac69c1",icon:"loader",spin:!0}),i("div",{key:"76a3af6c9a105b91b7f6055cc19bbb6f315be1a5",class:"mg-c-button__content"},i("slot",{key:"ca87921b6c58fbd055a83ea28f5ce58a618f16fe"}))))}get element(){return this}static get watchers(){return{variant:[{validateVariant:0}],size:[{validateSize:0}],fullWidth:[{validateFullWidth:0}],disabled:[{disabledHandler:0}],isIcon:[{watchIsIcon:0}],loading:[{loadingHandler:0}]}}static get style(){return":host{display:inline-block;max-width:100%;vertical-align:middle}:host(:hover) .mg-c-button--flat:not(.mg-c-button--disabled),:host([data-mg-popover-trigger][aria-expanded=true]) .mg-c-button--flat:not(.mg-c-button--disabled),.mg-c-button--flat:hover:not(.mg-c-button--disabled,:disabled,[aria-disabled=true]){background:color-mix(in srgb, var(--mg-b-color-dark), transparent 90%)}:host([full-width]){display:block}:host([disabled]),:host([aria-disabled=true]){pointer-events:none}.mg-c-button.mg-c-button--primary{border-color:var(--mg-c-button-color-border-primary);background:linear-gradient(to bottom, var(--mg-c-button-color-background-primary), var(--mg-c-button-color-gradient-primary));color:var(--mg-c-button-color-text-primary)}:host(:hover) .mg-c-button.mg-c-button--primary:not(.mg-c-button--disabled),:host([data-mg-popover-trigger][aria-expanded=true]) .mg-c-button.mg-c-button--primary:not(.mg-c-button--disabled),.mg-c-button.mg-c-button--primary:hover:not(.mg-c-button--disabled,:disabled,[aria-disabled=true]){background:var(--mg-c-button-color-background-primary)}.mg-c-button.mg-c-button--secondary{border-color:var(--mg-c-button-color-border-secondary);background:linear-gradient(to bottom, var(--mg-c-button-color-background-secondary), var(--mg-c-button-color-gradient-secondary));color:var(--mg-c-button-color-text-secondary)}:host(:hover) .mg-c-button.mg-c-button--secondary:not(.mg-c-button--disabled),:host([data-mg-popover-trigger][aria-expanded=true]) .mg-c-button.mg-c-button--secondary:not(.mg-c-button--disabled),.mg-c-button.mg-c-button--secondary:hover:not(.mg-c-button--disabled,:disabled,[aria-disabled=true]){background:var(--mg-c-button-color-background-secondary)}.mg-c-button.mg-c-button--danger{border-color:var(--mg-c-button-color-border-danger);background:linear-gradient(to bottom, var(--mg-c-button-color-background-danger), var(--mg-c-button-color-gradient-danger));color:var(--mg-c-button-color-text-danger)}:host(:hover) .mg-c-button.mg-c-button--danger:not(.mg-c-button--disabled),:host([data-mg-popover-trigger][aria-expanded=true]) .mg-c-button.mg-c-button--danger:not(.mg-c-button--disabled),.mg-c-button.mg-c-button--danger:hover:not(.mg-c-button--disabled,:disabled,[aria-disabled=true]){background:var(--mg-c-button-color-background-danger)}.mg-c-button.mg-c-button--info{border-color:var(--mg-c-button-color-border-info);background:linear-gradient(to bottom, var(--mg-c-button-color-background-info), var(--mg-c-button-color-gradient-info));color:var(--mg-c-button-color-text-info)}:host(:hover) .mg-c-button.mg-c-button--info:not(.mg-c-button--disabled),:host([data-mg-popover-trigger][aria-expanded=true]) .mg-c-button.mg-c-button--info:not(.mg-c-button--disabled),.mg-c-button.mg-c-button--info:hover:not(.mg-c-button--disabled,:disabled,[aria-disabled=true]){background:var(--mg-c-button-color-background-info)}.mg-c-button.mg-c-button--success{border-color:var(--mg-c-button-color-border-success);background:linear-gradient(to bottom, var(--mg-c-button-color-background-success), var(--mg-c-button-color-gradient-success));color:var(--mg-c-button-color-text-success)}:host(:hover) .mg-c-button.mg-c-button--success:not(.mg-c-button--disabled),:host([data-mg-popover-trigger][aria-expanded=true]) .mg-c-button.mg-c-button--success:not(.mg-c-button--disabled),.mg-c-button.mg-c-button--success:hover:not(.mg-c-button--disabled,:disabled,[aria-disabled=true]){background:var(--mg-c-button-color-background-success)}.mg-c-button.mg-c-button--warning{border-color:var(--mg-c-button-color-border-warning);background:linear-gradient(to bottom, var(--mg-c-button-color-background-warning), var(--mg-c-button-color-gradient-warning));color:var(--mg-c-button-color-text-warning)}:host(:hover) .mg-c-button.mg-c-button--warning:not(.mg-c-button--disabled),:host([data-mg-popover-trigger][aria-expanded=true]) .mg-c-button.mg-c-button--warning:not(.mg-c-button--disabled),.mg-c-button.mg-c-button--warning:hover:not(.mg-c-button--disabled,:disabled,[aria-disabled=true]){background:var(--mg-c-button-color-background-warning)}.mg-c-button.mg-c-button--danger-alt{border-color:var(--mg-c-button-color-border-danger-alt);background:linear-gradient(to bottom, var(--mg-c-button-color-background-danger-alt), var(--mg-c-button-color-gradient-danger-alt));color:var(--mg-c-button-color-text-danger-alt)}:host(:hover) .mg-c-button.mg-c-button--danger-alt:not(.mg-c-button--disabled),:host([data-mg-popover-trigger][aria-expanded=true]) .mg-c-button.mg-c-button--danger-alt:not(.mg-c-button--disabled),.mg-c-button.mg-c-button--danger-alt:hover:not(.mg-c-button--disabled,:disabled,[aria-disabled=true]){background:var(--mg-c-button-color-background-danger-alt)}.mg-c-button{position:relative;display:inline-flex;min-height:var(--mg-b-size-min-height);box-sizing:border-box;align-items:center;padding:calc((var(--mg-b-size-min-height) - 2*var(--mg-b-size-border) - var(--mg-b-font-size)*var(--mg-b-line-height))/2) var(--mg-b-size-12);border-width:var(--mg-c-button-border-top-width, var(--mg-b-size-border)) var(--mg-c-button-border-right-width, var(--mg-b-size-border)) var(--mg-c-button-border-bottom-width, var(--mg-b-size-border)) var(--mg-c-button-border-left-width, var(--mg-b-size-border));border-style:solid;border-radius:var(--mg-c-button-border-radius-top-left, var(--mg-c-button-border-radius)) var(--mg-c-button-border-radius-top-right, var(--mg-c-button-border-radius)) var(--mg-c-button-border-radius-bottom-right, var(--mg-c-button-border-radius)) var(--mg-c-button-border-radius-bottom-left, var(--mg-c-button-border-radius));background-image:none;color:inherit;column-gap:var(--mg-b-size-8);cursor:pointer;touch-action:manipulation;font-family:inherit;font-size:var(--mg-b-font-size);font-weight:var(--mg-c-button-font-weight, normal);text-align:left;text-decoration:none}.mg-c-button slot,.mg-c-button ::slotted(*:not(mg-icon)){font-family:inherit;font-size:var(--mg-b-font-size);font-weight:var(--mg-c-button-font-weight, normal);text-align:left;text-decoration:none;display:flex;align-items:center;column-gap:var(--mg-b-size-8)}.mg-c-button mg-icon:only-child,.mg-c-button ::slotted(mg-icon){display:inline-flex;flex-shrink:0;margin:auto 0;line-height:1}.mg-c-button.mg-c-button--disabled,.mg-c-button[aria-disabled=true],.mg-c-button:disabled{cursor:default;opacity:var(--mg-b-opacity-element-disabled);pointer-events:none}.mg-c-button.mg-c-button--flat{border:none;background:none}.mg-c-button.mg-c-button--link{min-height:unset;padding:unset;border:unset;border-radius:unset;background:unset;text-decoration:underline}.mg-c-button.mg-c-button--link slot{font-weight:600}.mg-c-button.mg-c-button--link:hover{text-decoration:none}.mg-c-button.mg-c-button--large{padding:calc(var(--mg-b-size-12) - var(--mg-b-size-border)) calc(var(--mg-b-size-24) - var(--mg-b-size-border))}.mg-c-button.mg-c-button--large:not(.mg-c-button--icon){line-height:var(--mg-b-size-24)}.mg-c-button.mg-c-button--large:not(.mg-c-button--icon) slot,.mg-c-button.mg-c-button--large:not(.mg-c-button--icon) ::slotted(*){font-size:var(--mg-b-size-16)}.mg-c-button.mg-c-button--icon{width:var(--mg-b-size-min-height);height:var(--mg-b-size-min-height);justify-content:center;padding:0;border-radius:var(--mg-c-button-border-radius-top-left, var(--mg-c-button-icon-border-radius)) var(--mg-c-button-border-radius-top-right, var(--mg-c-button-icon-border-radius)) var(--mg-c-button-border-radius-bottom-right, var(--mg-c-button-icon-border-radius)) var(--mg-c-button-border-radius-bottom-left, var(--mg-c-button-icon-border-radius));font-size:var(--mg-b-font-size);line-height:var(--mg-b-font-size)}.mg-c-button.mg-c-button--icon.mg-c-button--large{width:unset;height:unset;padding:calc(var(--mg-b-size-12) - var(--mg-b-size-border))}.mg-c-button.mg-c-button--icon.mg-c-button--large ::slotted(*){min-width:var(--mg-b-size-24);min-height:var(--mg-b-size-24);align-items:center;justify-content:center}.mg-c-button.mg-c-button--full-width{display:flex;width:100%;justify-content:center}.mg-c-button.mg-c-button--loading>mg-icon:first-of-type{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%)}.mg-c-button.mg-c-button--loading .mg-c-button__content{opacity:0}:host(:focus-visible),:host([data-focus-visible]){outline:0}:host(:focus-visible) .mg-c-button,:host([data-focus-visible]) .mg-c-button{outline-color:-webkit-focus-ring-color;outline-style:auto;outline-width:var(--mg-b-size-2)}.mg-c-button:focus-visible{outline-color:-webkit-focus-ring-color;outline-style:auto;outline-width:var(--mg-b-size-2)}"}},[257,"mg-button",{variant:[1025],label:[1],type:[1],size:[1],fullWidth:[4,"full-width"],form:[1],disabled:[1028],isIcon:[4,"is-icon"],disableOnClick:[4,"disable-on-click"],loading:[32],classCollection:[32]},void 0,{variant:[{validateVariant:0}],size:[{validateSize:0}],fullWidth:[{validateFullWidth:0}],disabled:[{disabledHandler:0}],isIcon:[{watchIsIcon:0}],loading:[{loadingHandler:0}]}]);function h(){"undefined"!=typeof customElements&&["mg-button","mg-icon"].forEach((o=>{switch(o){case"mg-button":customElements.get(t(o))||customElements.define(t(o),l);break;case"mg-icon":customElements.get(t(o))||d()}}))}h();export{l as M,h as d}