@verbb/formie-browser 1.0.8 → 1.0.10

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 (85) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/chunks/_survey-presentations-RbSqcQph.js +4 -0
  3. package/dist/chunks/{address-state-BQ0xGV9n.js → address-state-BwE01m2_.js} +1 -1
  4. package/dist/chunks/{api-C8wyLC-s.js → api-BYe9YPko.js} +10 -3
  5. package/dist/chunks/{bpoint-CwSw_p7A.js → bpoint-C0VOftX9.js} +1 -1
  6. package/dist/chunks/{calculations-CeDgB9jt.js → calculations-HAZ8wUrT.js} +1 -1
  7. package/dist/chunks/checkbox-radio-BY2aTCOG.js +177 -0
  8. package/dist/chunks/{combobox-D-2b42wn.js → combobox-C0EuExSI.js} +1 -1
  9. package/dist/chunks/{conditions-B6_nzpeE.js → conditions-BiA_uANV.js} +1 -1
  10. package/dist/chunks/{dist-BQ4a9hmy.js → dist-BaHXfvBO.js} +1 -1
  11. package/dist/chunks/{eway-B30BMlDp.js → eway-CS6Y1Yvo.js} +1 -1
  12. package/dist/chunks/{file-upload-D49m8-DR.js → file-upload-rqfZNqlH.js} +1 -1
  13. package/dist/chunks/{go-cardless-BiF3iLel.js → go-cardless-BTPD668l.js} +1 -1
  14. package/dist/chunks/{mollie-D__SwtcH.js → mollie-CXgBwvo6.js} +1 -1
  15. package/dist/chunks/{moneris-KJS1BKx7.js → moneris-B6oLu7nj.js} +1 -1
  16. package/dist/chunks/{opayo-A_LIkc-v.js → opayo-DPUA5CKr.js} +1 -1
  17. package/dist/chunks/{paddle-BjbOOb0m.js → paddle-GRlsm5mm.js} +1 -1
  18. package/dist/chunks/password-validation-D5AirwUM.js +49 -0
  19. package/dist/chunks/{paypal-CyjHIV8v.js → paypal-CdcZnf6r.js} +2 -2
  20. package/dist/chunks/{payway-a_cyrr3j.js → payway-CfmYOS__.js} +2 -2
  21. package/dist/chunks/{repeater-B5leVxZU.js → repeater-BVnPUqTj.js} +1 -1
  22. package/dist/chunks/rich-text-Bg_--4TG.js +349 -0
  23. package/dist/chunks/{square-Bga6WXHV.js → square-BY--5M-X.js} +1 -1
  24. package/dist/chunks/{stripe-BlqVocl3.js → stripe-uusYjWty.js} +2 -2
  25. package/dist/chunks/{survey-likert-DmJ3klhP.js → survey-likert-DkE6bR7B.js} +1 -1
  26. package/dist/chunks/{survey-rank-DeUenftw.js → survey-rank-DN6x4IZM.js} +1 -1
  27. package/dist/chunks/{survey-rating-BPUYDgBJ.js → survey-rating-BnsNL9U5.js} +1 -1
  28. package/dist/chunks/{table-C-lkQN6I.js → table-CAjCJHrL.js} +1 -1
  29. package/dist/chunks/{text-limit-DbgEFHLO.js → text-limit-nSATKyhp.js} +1 -1
  30. package/dist/chunks/{upload-manager-BpqWSHmU.js → upload-manager-W-QDgxKD.js} +1 -1
  31. package/dist/css/theme/_tokens.css +10 -5
  32. package/dist/css/theme/fields/_check-radio.css +26 -1
  33. package/dist/css/theme/fields/_combobox.css +1 -1
  34. package/dist/css/theme/fields/_file.css +3 -3
  35. package/dist/css/theme/fields/_input.css +1 -1
  36. package/dist/css/theme/fields/_repeater.css +1 -1
  37. package/dist/css/theme/fields/_rich-text.css +1 -1
  38. package/dist/css/theme/fields/_select.css +1 -1
  39. package/dist/css/theme/fields/_survey-presentations.css +1 -1
  40. package/dist/css/theme/fields/_table.css +1 -1
  41. package/dist/css/theme/fields/_upload-manager.css +3 -3
  42. package/dist/css/theme/integrations/_paypal.css +1 -1
  43. package/dist/css/theme/integrations/_payway.css +1 -1
  44. package/dist/css/theme/integrations/_stripe.css +1 -1
  45. package/dist/index.js +520 -505
  46. package/dist/js/core/create-formie-client.d.ts.map +1 -1
  47. package/dist/js/core/submit-flow.d.ts.map +1 -1
  48. package/dist/js/core/submit-result-state.d.ts.map +1 -1
  49. package/dist/js/core/submit-result-ui.d.ts +1 -0
  50. package/dist/js/core/submit-result-ui.d.ts.map +1 -1
  51. package/dist/js/modules/fields/checkbox-radio.d.ts.map +1 -1
  52. package/dist/js/modules/fields/index.d.ts.map +1 -1
  53. package/dist/js/modules/fields/password-validation.d.ts +3 -0
  54. package/dist/js/modules/fields/password-validation.d.ts.map +1 -0
  55. package/dist/js/utils/fields.d.ts.map +1 -1
  56. package/dist/js/validation/rules/match.d.ts.map +1 -1
  57. package/package.json +2 -2
  58. package/src/css/theme/_tokens.css +10 -5
  59. package/src/css/theme/fields/_check-radio.css +26 -1
  60. package/src/css/theme/fields/_combobox.css +1 -1
  61. package/src/css/theme/fields/_file.css +3 -3
  62. package/src/css/theme/fields/_input.css +1 -1
  63. package/src/css/theme/fields/_repeater.css +1 -1
  64. package/src/css/theme/fields/_rich-text.css +1 -1
  65. package/src/css/theme/fields/_select.css +1 -1
  66. package/src/css/theme/fields/_survey-presentations.css +1 -1
  67. package/src/css/theme/fields/_table.css +1 -1
  68. package/src/css/theme/fields/_upload-manager.css +3 -3
  69. package/src/css/theme/integrations/_paypal.css +1 -1
  70. package/src/css/theme/integrations/_payway.css +1 -1
  71. package/src/css/theme/integrations/_stripe.css +1 -1
  72. package/src/js/core/create-formie-client.ts +9 -1
  73. package/src/js/core/submit-flow.ts +3 -1
  74. package/src/js/core/submit-result-state.ts +12 -0
  75. package/src/js/core/submit-result-ui.ts +47 -9
  76. package/src/js/modules/fields/checkbox-radio.ts +133 -4
  77. package/src/js/modules/fields/index.ts +1 -0
  78. package/src/js/modules/fields/password-validation.ts +132 -0
  79. package/src/js/utils/fields.ts +14 -2
  80. package/src/js/validation/rules/match.ts +5 -4
  81. package/src/js/validation/rules/minmax.ts +2 -2
  82. package/src/js/validation/rules/number.ts +1 -1
  83. package/dist/chunks/_survey-presentations-CFsgToRT.js +0 -4
  84. package/dist/chunks/checkbox-radio-DQ0H67Tj.js +0 -125
  85. package/dist/chunks/rich-text-D0sb8bmX.js +0 -349
@@ -4,6 +4,7 @@ import { createDebug } from '#utils/debug';
4
4
 
5
5
  const FIELD_SELECTOR = '[data-formie-checkboxes-field-layout], [data-formie-radio-field-layout]';
6
6
  const CHECKBOX_MINMAX_VALIDATOR = 'minmaxOptions';
7
+ const OTHER_OPTION_TEXT_VALIDATOR = 'otherOptionText';
7
8
  const MAX_DISABLED_ATTR = 'data-formie-checkbox-radio-max-disabled';
8
9
  const MODULE_ID = 'checkbox-radio';
9
10
  const VALIDATOR_SCOPE = 'checkbox-radio';
@@ -31,6 +32,94 @@ function getMinMaxRule(getRule: (rule: string) => unknown): { min: number | null
31
32
  };
32
33
  }
33
34
 
35
+ function isOtherOptionInput(input: HTMLInputElement): boolean {
36
+ return input.hasAttribute('data-formie-other-option')
37
+ || !!input.closest('[data-formie-other-option]');
38
+ }
39
+
40
+ function findOtherOptionGroups(field: HTMLElement): Array<{ choiceInput: HTMLInputElement; textInput: HTMLInputElement }> {
41
+ const groups: Array<{ choiceInput: HTMLInputElement; textInput: HTMLInputElement }> = [];
42
+
43
+ field.querySelectorAll('[data-formie-other-option-text]').forEach((node) => {
44
+ if (!(node instanceof HTMLInputElement)) {
45
+ return;
46
+ }
47
+
48
+ const container = node.closest('[data-formie-field-option]') ?? node.parentElement;
49
+
50
+ if (!container) {
51
+ return;
52
+ }
53
+
54
+ const choiceInput = container.querySelector('input[type="checkbox"][data-formie-other-option], input[type="radio"][data-formie-other-option]')
55
+ ?? container.querySelector('input[type="checkbox"], input[type="radio"]');
56
+
57
+ if (!(choiceInput instanceof HTMLInputElement)) {
58
+ return;
59
+ }
60
+
61
+ groups.push({ choiceInput, textInput: node });
62
+ });
63
+
64
+ return groups;
65
+ }
66
+
67
+ function syncOtherOptionField(field: HTMLElement): void {
68
+ findOtherOptionGroups(field).forEach(({ choiceInput, textInput }) => {
69
+ const showTextInput = choiceInput.checked;
70
+
71
+ textInput.disabled = !showTextInput;
72
+
73
+ if (!showTextInput) {
74
+ textInput.value = '';
75
+ }
76
+ });
77
+ }
78
+
79
+ function bindOtherOptionField(field: HTMLElement): () => void {
80
+ const otherOptionGroups = findOtherOptionGroups(field);
81
+
82
+ if (!otherOptionGroups.length) {
83
+ return () => {};
84
+ }
85
+
86
+ const listeners: Array<() => void> = [];
87
+
88
+ Array.from(field.querySelectorAll('input[type="checkbox"], input[type="radio"]')).filter((input): input is HTMLInputElement => {
89
+ return input instanceof HTMLInputElement && !isToggleCheckbox(input);
90
+ }).forEach((input) => {
91
+ const handler = () => {
92
+ syncOtherOptionField(field);
93
+ };
94
+
95
+ input.addEventListener('change', handler);
96
+ listeners.push(() => {
97
+ input.removeEventListener('change', handler);
98
+ });
99
+ });
100
+
101
+ otherOptionGroups.forEach(({ textInput }) => {
102
+ const handler = () => {
103
+ syncOtherOptionField(field);
104
+ };
105
+
106
+ textInput.addEventListener('input', handler);
107
+ textInput.addEventListener('change', handler);
108
+ listeners.push(() => {
109
+ textInput.removeEventListener('input', handler);
110
+ textInput.removeEventListener('change', handler);
111
+ });
112
+ });
113
+
114
+ syncOtherOptionField(field);
115
+
116
+ return () => {
117
+ listeners.forEach((unbind) => {
118
+ unbind();
119
+ });
120
+ };
121
+ }
122
+
34
123
  function getSelectedOptionCount(field: HTMLElement): number {
35
124
  return Array.from(field.querySelectorAll('input[type="checkbox"]')).filter((input): input is HTMLInputElement => {
36
125
  return input instanceof HTMLInputElement && !isToggleCheckbox(input);
@@ -43,6 +132,39 @@ function registerValidators(form: HTMLFormElement | null): void {
43
132
  // Several checkbox/radio module instances can exist in one form, but the
44
133
  // custom validator should only be registered once per form lifecycle.
45
134
  retainFormValidators(form, VALIDATOR_SCOPE, (validator) => {
135
+ validator.addValidator(
136
+ OTHER_OPTION_TEXT_VALIDATOR,
137
+ ({ field, getRule }) => {
138
+ if (!field || !getRule(OTHER_OPTION_TEXT_VALIDATOR)) {
139
+ return true;
140
+ }
141
+
142
+ return findOtherOptionGroups(field).every(({ choiceInput, textInput }) => {
143
+ if (!choiceInput.checked) {
144
+ return true;
145
+ }
146
+
147
+ return textInput.value.trim() !== '';
148
+ });
149
+ },
150
+ ({ field, label, t, getRule }) => {
151
+ if (!field || !getRule(OTHER_OPTION_TEXT_VALIDATOR)) {
152
+ return t('{label} is invalid.', { label });
153
+ }
154
+
155
+ const otherGroup = findOtherOptionGroups(field).find(({ choiceInput }) => {
156
+ return choiceInput.checked;
157
+ });
158
+ const otherLabel = otherGroup?.choiceInput.closest('[data-formie-field-option]')
159
+ ?.querySelector('[data-formie-field-option-label]')
160
+ ?.textContent
161
+ ?.trim()
162
+ ?? label;
163
+
164
+ return field.getAttribute('data-formie-validation-other-option-text-message')
165
+ ?? t('Please enter a value for “{label}”.', { label: otherLabel });
166
+ },
167
+ );
46
168
  validator.addValidator(
47
169
  CHECKBOX_MINMAX_VALIDATOR,
48
170
  ({ field, getRule }) => {
@@ -65,7 +187,7 @@ function registerValidators(form: HTMLFormElement | null): void {
65
187
  },
66
188
  ({ field, label, t, getRule }) => {
67
189
  if (!field) {
68
- return t('{label} has an invalid value.', { label });
190
+ return t('{label} is invalid.', { label });
69
191
  }
70
192
 
71
193
  const selected = getSelectedOptionCount(field);
@@ -81,14 +203,14 @@ function registerValidators(form: HTMLFormElement | null): void {
81
203
  ?? t('{label} should contain at most {max, number} {max, plural, one{option} other{options}}.', { label, max });
82
204
  }
83
205
 
84
- return t('{label} has an invalid value.', { label });
206
+ return t('{label} is invalid.', { label });
85
207
  },
86
208
  );
87
209
  });
88
210
  }
89
211
 
90
212
  function unregisterValidators(form: HTMLFormElement | null): void {
91
- releaseFormValidators(form, VALIDATOR_SCOPE, [CHECKBOX_MINMAX_VALIDATOR]);
213
+ releaseFormValidators(form, VALIDATOR_SCOPE, [CHECKBOX_MINMAX_VALIDATOR, OTHER_OPTION_TEXT_VALIDATOR]);
92
214
  }
93
215
 
94
216
  function syncCheckedAttribute(input: HTMLInputElement): void {
@@ -134,7 +256,7 @@ function enforceMaxOptions(field: HTMLElement): void {
134
256
  }
135
257
 
136
258
  const checkboxes = Array.from(field.querySelectorAll('input[type="checkbox"]')).filter((input): input is HTMLInputElement => {
137
- return input instanceof HTMLInputElement && !isToggleCheckbox(input);
259
+ return input instanceof HTMLInputElement && !isToggleCheckbox(input) && !isOtherOptionInput(input);
138
260
  });
139
261
 
140
262
  const checked = checkboxes.filter((input) => {
@@ -223,6 +345,9 @@ function bindField(field: HTMLElement): () => void {
223
345
 
224
346
  syncRequiredCheckboxes(field);
225
347
  enforceMaxOptions(field);
348
+ queueMicrotask(() => {
349
+ syncOtherOptionField(field);
350
+ });
226
351
  debug.log('Input interaction processed.', {
227
352
  inputName: input.name,
228
353
  inputType: input.type,
@@ -238,8 +363,11 @@ function bindField(field: HTMLElement): () => void {
238
363
  };
239
364
  });
240
365
 
366
+ const destroyOtherOptionBinding = bindOtherOptionField(field);
367
+
241
368
  syncRequiredCheckboxes(field);
242
369
  enforceMaxOptions(field);
370
+ syncOtherOptionField(field);
243
371
  dispatchFieldEvent(field, MODULE_ID, 'init', {
244
372
  checkboxRadio: field,
245
373
  });
@@ -248,6 +376,7 @@ function bindField(field: HTMLElement): () => void {
248
376
  listeners.forEach((unbind) => {
249
377
  unbind();
250
378
  });
379
+ destroyOtherOptionBinding();
251
380
  };
252
381
  }
253
382
 
@@ -15,6 +15,7 @@ export const builtinFieldModuleLoaders: Record<string, () => Promise<FormieModul
15
15
  'upload-manager': () => import('#modules/fields/upload-manager').then((module) => module.uploadManagerModule),
16
16
  'hidden': () => import('#modules/fields/hidden').then((module) => module.hiddenModule),
17
17
  'phone-country': () => import('#modules/fields/phone-country').then((module) => module.phoneCountryModule),
18
+ 'password-validation': () => import('#modules/fields/password-validation').then((module) => module.passwordValidationModule),
18
19
  'address-country': () => import('#modules/fields/address-country').then((module) => module.addressCountryModule),
19
20
  'address-state': () => import('#modules/fields/address-state').then((module) => module.addressStateModule),
20
21
  'repeater': () => import('#modules/fields/repeater').then((module) => module.repeaterModule),
@@ -0,0 +1,132 @@
1
+ import { getTextLimitMetrics } from '@verbb/formie-core';
2
+
3
+ import type { FormieModuleDefinition } from '#contracts/modules';
4
+ import { getModuleFieldTarget, releaseFormValidators, retainFormValidators } from '#modules/fields/shared';
5
+
6
+ const INPUT_SELECTOR = 'input[data-formie-password-input]';
7
+ const PASSWORD_VALIDATORS = [
8
+ 'passwordMinLength',
9
+ 'passwordUppercase',
10
+ 'passwordLowercase',
11
+ 'passwordSpecialCharacter',
12
+ ] as const;
13
+ const VALIDATOR_SCOPE = 'password-validation';
14
+
15
+ function isPasswordInput(input: Element): input is HTMLInputElement {
16
+ return input instanceof HTMLInputElement && input.matches(INPUT_SELECTOR);
17
+ }
18
+
19
+ function getMinLength(input: HTMLInputElement): number {
20
+ return parseInt(input.getAttribute('data-formie-password-min-length') || '', 10) || 0;
21
+ }
22
+
23
+ function hasAnyPasswordValidationAttributes(input: HTMLInputElement): boolean {
24
+ return input.hasAttribute('data-formie-password-min-length') ||
25
+ input.hasAttribute('data-formie-password-require-uppercase') ||
26
+ input.hasAttribute('data-formie-password-require-lowercase') ||
27
+ input.hasAttribute('data-formie-password-require-special-character');
28
+ }
29
+
30
+ function hasNoRawValue(input: HTMLInputElement): boolean {
31
+ return input.value === '';
32
+ }
33
+
34
+ function registerValidators(form: HTMLFormElement | null): void {
35
+ retainFormValidators(form, VALIDATOR_SCOPE, (validator) => {
36
+ validator.addValidator('passwordMinLength', ({ input }) => {
37
+ if (!isPasswordInput(input)) {
38
+ return true;
39
+ }
40
+
41
+ const limit = getMinLength(input);
42
+
43
+ if (!limit || hasNoRawValue(input)) {
44
+ return true;
45
+ }
46
+
47
+ return getTextLimitMetrics(input.value).graphemeCount >= limit;
48
+ }, ({ label, input, t: translate }) => {
49
+ return input.getAttribute('data-formie-validation-min-characters-message')
50
+ || translate('{label} must be no less than {min} characters.', {
51
+ label,
52
+ min: input.getAttribute('data-formie-password-min-length') || '',
53
+ });
54
+ });
55
+
56
+ validator.addValidator('passwordUppercase', ({ input }) => {
57
+ if (!isPasswordInput(input) || !input.hasAttribute('data-formie-password-require-uppercase')) {
58
+ return true;
59
+ }
60
+
61
+ if (hasNoRawValue(input)) {
62
+ return true;
63
+ }
64
+
65
+ return /[A-Z]/.test(input.value);
66
+ }, ({ label, input, t: translate }) => {
67
+ return input.getAttribute('data-formie-validation-password-uppercase-message')
68
+ || translate('{label} must contain at least one uppercase letter.', { label });
69
+ });
70
+
71
+ validator.addValidator('passwordLowercase', ({ input }) => {
72
+ if (!isPasswordInput(input) || !input.hasAttribute('data-formie-password-require-lowercase')) {
73
+ return true;
74
+ }
75
+
76
+ if (hasNoRawValue(input)) {
77
+ return true;
78
+ }
79
+
80
+ return /[a-z]/.test(input.value);
81
+ }, ({ label, input, t: translate }) => {
82
+ return input.getAttribute('data-formie-validation-password-lowercase-message')
83
+ || translate('{label} must contain at least one lowercase letter.', { label });
84
+ });
85
+
86
+ validator.addValidator('passwordSpecialCharacter', ({ input }) => {
87
+ if (!isPasswordInput(input) || !input.hasAttribute('data-formie-password-require-special-character')) {
88
+ return true;
89
+ }
90
+
91
+ if (hasNoRawValue(input)) {
92
+ return true;
93
+ }
94
+
95
+ return /[^a-zA-Z0-9]/.test(input.value);
96
+ }, ({ label, input, t: translate }) => {
97
+ return input.getAttribute('data-formie-validation-password-special-character-message')
98
+ || translate('{label} must contain at least one special character.', { label });
99
+ });
100
+ });
101
+ }
102
+
103
+ function unregisterValidators(form: HTMLFormElement | null): void {
104
+ releaseFormValidators(form, VALIDATOR_SCOPE, PASSWORD_VALIDATORS);
105
+ }
106
+
107
+ export const passwordValidationModule: FormieModuleDefinition = {
108
+ id: 'password-validation',
109
+ kind: 'field',
110
+ match: (ctx) => {
111
+ return !!ctx.target.querySelector(`${INPUT_SELECTOR}[data-formie-password-min-length], ${INPUT_SELECTOR}[data-formie-password-require-uppercase], ${INPUT_SELECTOR}[data-formie-password-require-lowercase], ${INPUT_SELECTOR}[data-formie-password-require-special-character]`);
112
+ },
113
+ setup: async (ctx) => {
114
+ const field = getModuleFieldTarget(ctx);
115
+ const inputs = Array.from((field || ctx.target).querySelectorAll(INPUT_SELECTOR)).filter((input): input is HTMLInputElement => {
116
+ return input instanceof HTMLInputElement && hasAnyPasswordValidationAttributes(input);
117
+ });
118
+
119
+ registerValidators(ctx.form);
120
+
121
+ await ctx.emit('formie:module:password-validation:init', {
122
+ count: inputs.length,
123
+ });
124
+
125
+ return {
126
+ destroy: () => {
127
+ unregisterValidators(ctx.form);
128
+ void ctx.emit('formie:module:password-validation:destroy', {});
129
+ },
130
+ };
131
+ },
132
+ };
@@ -47,9 +47,21 @@ export function currencyToFloat(currencyString: string): number {
47
47
  // Accept both "1,234.56" and "1.234,56" style inputs so calculations can
48
48
  // operate on locale-formatted values emitted by other field modules.
49
49
  if (hasComma && hasDot) {
50
- sanitized = sanitized.replace(/\./g, '').replace(/,/, '.');
50
+ if (sanitized.lastIndexOf(',') > sanitized.lastIndexOf('.')) {
51
+ // EU style: 1.234,56
52
+ sanitized = sanitized.replace(/\./g, '').replace(',', '.');
53
+ } else {
54
+ // US style: 1,234.56
55
+ sanitized = sanitized.replace(/,/g, '');
56
+ }
51
57
  } else if (hasComma && !hasDot) {
52
- sanitized = sanitized.replace(/,/, '.');
58
+ const parts = sanitized.split(',');
59
+
60
+ if (parts.length === 2 && parts[1].length === 3 && /^\d+$/.test(parts[0]) && /^\d+$/.test(parts[1])) {
61
+ sanitized = parts[0] + parts[1];
62
+ } else {
63
+ sanitized = sanitized.replace(',', '.');
64
+ }
53
65
  } else {
54
66
  sanitized = sanitized.replace(/,/g, '');
55
67
  }
@@ -16,10 +16,11 @@ const match: ValidationRuleDefinition = {
16
16
  const sourceField = sourceInput?.closest('[data-formie-field-handle]') as HTMLElement | null;
17
17
  const sourceLabel = getLabelText(sourceField);
18
18
 
19
- return ctx.t('{label} must match {value}.', {
20
- label: ctx.label,
21
- value: sourceLabel,
22
- });
19
+ return ctx.input.getAttribute('data-formie-validation-match-message')
20
+ ?? ctx.t('{label} must match {value}.', {
21
+ label: ctx.label,
22
+ value: sourceLabel,
23
+ });
23
24
  },
24
25
  };
25
26
 
@@ -29,7 +29,7 @@ const minmax: ValidationRuleDefinition = {
29
29
  const max = input.hasAttribute('max') ? parseFloat(input.getAttribute('max') || '') : null;
30
30
 
31
31
  if (min !== null && max !== null) {
32
- return t('{label} must be between {min} and {max}.', { label, min, max });
32
+ return t('{label} must be no less than {min}.', { label, min });
33
33
  }
34
34
 
35
35
  if (min !== null) {
@@ -40,7 +40,7 @@ const minmax: ValidationRuleDefinition = {
40
40
  return t('{label} must be no greater than {max}.', { label, max });
41
41
  }
42
42
 
43
- return t('{label} has an invalid value.', { label });
43
+ return t('{label} is not a valid number.', { label });
44
44
  },
45
45
  };
46
46
 
@@ -36,7 +36,7 @@ const number: ValidationRuleDefinition = {
36
36
 
37
37
  if (min !== null && max !== null) {
38
38
  return input.getAttribute('data-formie-validation-number-min-message')
39
- ?? t('{label} must be between {min} and {max}.', { label, min, max });
39
+ ?? t('{label} must be no less than {min}.', { label, min });
40
40
  }
41
41
 
42
42
  if (min !== null) {
@@ -1,4 +0,0 @@
1
- //#region src/css/theme/fields/_survey-presentations.css?inline
2
- var e = "@layer formie-theme{.formie-likert-field-layout{table-layout:fixed;border-collapse:collapse;border-spacing:0;width:100%;display:table}.formie-likert-field-layout thead{display:table-header-group}.formie-likert-field-layout tbody{display:table-row-group}.formie-likert-field-layout tr{display:table-row}.formie-likert-field-layout th,.formie-likert-field-layout td{display:table-cell}.formie-likert-column-label{text-align:center;color:var(--formie-survey-likert-label-color,var(--formie-color-heading));word-break:break-word;vertical-align:bottom;font-size:var(--formie-survey-likert-column-label-font-size,.875rem);padding:0 .35rem .5rem;line-height:1.3}[data-formie-field-control]:has(>[data-formie-likert-multiple-rows]){-webkit-overflow-scrolling:touch;overflow-x:auto}@media (width>=40rem){.formie-likert-field-layout[data-formie-likert-multiple-rows]{width:max-content;min-width:100%}.formie-likert-field-layout[data-formie-likert-multiple-rows] .formie-likert-column-label,.formie-likert-field-layout[data-formie-likert-multiple-rows] .formie-likert-option{min-width:var(--formie-survey-likert-column-min-width,5.5rem)}}.formie-likert-row-label-header,.formie-likert-row-label{text-align:left;color:var(--formie-survey-likert-label-color,var(--formie-color-heading));word-break:break-word;vertical-align:middle;font-weight:var(--formie-font-weight-medium);padding:.65rem .75rem .65rem 0}.formie-likert-row-label-header{font-weight:var(--formie-font-weight-normal);padding-bottom:.5rem}.formie-likert-field-layout[data-formie-likert-multiple-rows]{table-layout:auto}.formie-likert-field-layout[data-formie-likert-multiple-rows] .formie-likert-row-label-header,.formie-likert-field-layout[data-formie-likert-multiple-rows] .formie-likert-row-label{white-space:nowrap;width:1%;padding-right:1rem}.formie-likert-field-layout[data-formie-likert-multiple-rows] .formie-likert-inputs-row .formie-likert-row-label{border-top-left-radius:var(--formie-border-radius);border-bottom-left-radius:var(--formie-border-radius)}.formie-likert-field-layout[data-formie-likert-multiple-rows] .formie-likert-inputs-row .formie-likert-option:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.formie-likert-inputs-row--alt .formie-likert-row-label,.formie-likert-inputs-row--alt .formie-likert-option{background-color:var(--formie-survey-likert-option-background-alt,var(--formie-color-surface))}.formie-likert-option{text-align:center;vertical-align:middle;background-color:var(--formie-survey-likert-option-background,var(--formie-color-surface-muted));padding:.65rem .35rem}.formie-likert-inputs-row .formie-likert-option:first-child{border-top-left-radius:var(--formie-border-radius);border-bottom-left-radius:var(--formie-border-radius)}.formie-likert-inputs-row .formie-likert-option:last-child{border-top-right-radius:var(--formie-border-radius);border-bottom-right-radius:var(--formie-border-radius)}.formie-likert-option .formie-radio-option-label{width:var(--formie-check-size);height:var(--formie-check-size);line-height:var(--formie-check-size);padding-left:0;overflow:hidden}.formie-likert-option .formie-likert-option-label-text{display:none}.formie-likert-option .formie-radio-option-label:before{top:0;left:0}@media (width<=39.999rem){[data-formie-field-control]:has(>[data-formie-likert-field-layout]){overflow-x:visible}.formie-likert-field-layout{table-layout:auto;background-color:#0000;border-radius:0;width:100%;padding:0;display:block}.formie-likert-column-labels{clip:rect(0, 0, 0, 0);clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.formie-likert-field-layout thead,.formie-likert-field-layout tbody,.formie-likert-field-layout tr,.formie-likert-field-layout th,.formie-likert-field-layout td{width:100%;display:block}.formie-likert-inputs-row{margin:0 0 var(--formie-space-2);padding:var(--formie-space-2) var(--formie-space-3);border-radius:var(--formie-border-radius);background-color:var(--formie-survey-likert-option-background,var(--formie-color-surface-muted))}.formie-likert-inputs-row:last-child{margin-bottom:0}.formie-likert-inputs-row--alt{background-color:var(--formie-survey-likert-option-background-alt,var(--formie-color-surface))}.formie-likert-option{padding:var(--formie-space-2) 0;text-align:left;background-color:#0000;border-radius:0;min-width:0;display:block}.formie-likert-option:first-child{padding-top:0}.formie-likert-option:last-child{padding-bottom:0}.formie-likert-option .formie-radio-option-label{width:auto;height:auto;padding-left:var(--formie-check-label-padding-left);line-height:var(--formie-check-line-height);font-weight:var(--formie-font-weight-normal);color:var(--formie-color-text);overflow:visible}.formie-likert-option .formie-likert-option-label-text{display:inline}.formie-likert-field-layout[data-formie-likert-multiple-rows] .formie-likert-row-label{width:100%;padding:0 0 var(--formie-space-2);font-weight:var(--formie-font-weight-medium);white-space:normal;background-color:#0000;display:block}.formie-likert-field-layout[data-formie-likert-multiple-rows] .formie-likert-inputs-row{border-top:0}.formie-likert-field-layout[data-formie-likert-multiple-rows] .formie-likert-inputs-row .formie-likert-row-label,.formie-likert-field-layout[data-formie-likert-multiple-rows] .formie-likert-inputs-row .formie-likert-option:first-child,.formie-likert-field-layout[data-formie-likert-multiple-rows] .formie-likert-inputs-row .formie-likert-option:last-child{border-radius:0}}.formie-rank-field-layout{width:100%}.formie-rank-list,.formie-rank-field-layout .formie-rank-list.formie-field-options{margin:var(--formie-space-1) 0 0;gap:var(--formie-survey-rank-list-gap,var(--formie-space-2));flex-flow:column;padding:0;list-style:none;display:flex}.formie-rank-list[data-formie-rank-sorting=true]{-webkit-user-select:none;user-select:none}.formie-rank-item{align-items:center;gap:var(--formie-space-2);padding:var(--formie-space-2) var(--formie-space-3);border:var(--formie-border-width) solid var(--formie-survey-rank-item-border-color,var(--formie-color-border));border-radius:var(--formie-border-radius);background:var(--formie-survey-rank-item-background,var(--formie-color-surface));cursor:move;touch-action:none;margin:0;display:flex}.formie-rank-placeholder{box-sizing:border-box;background:0 0;border:0;margin:0;padding:0;list-style:none}.formie-rank-handle{width:.875rem;height:1.125rem;color:var(--formie-survey-rank-handle-color,var(--formie-color-text-muted));opacity:.6;cursor:move;pointer-events:none;background:0 0;border:0;flex-shrink:0;justify-content:center;align-items:center;padding:0;display:inline-flex}.formie-rank-handle:before{content:\"\";background:currentColor;width:13px;height:.875rem;display:block;-webkit-mask:url(\"data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 640'%3E%3Cpath d='M288 128C288 92.7 259.3 64 224 64C188.7 64 160 92.7 160 128C160 163.3 188.7 192 224 192C259.3 192 288 163.3 288 128zM288 320C288 284.7 259.3 256 224 256C188.7 256 160 284.7 160 320C160 355.3 188.7 384 224 384C259.3 384 288 355.3 288 320zM160 512C160 547.3 188.7 576 224 576C259.3 576 288 547.3 288 512C288 476.7 259.3 448 224 448C188.7 448 160 476.7 160 512zM480 128C480 92.7 451.3 64 416 64C380.7 64 352 92.7 352 128C352 163.3 380.7 192 416 192C451.3 192 480 163.3 480 128zM352 320C352 355.3 380.7 384 416 384C451.3 384 480 355.3 480 320C480 284.7 451.3 256 416 256C380.7 256 352 284.7 352 320zM480 512C480 476.7 451.3 448 416 448C380.7 448 352 476.7 352 512C352 547.3 380.7 576 416 576C451.3 576 480 547.3 480 512z'/%3E%3C/svg%3E\") 50%/contain no-repeat;mask:url(\"data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 640'%3E%3Cpath d='M288 128C288 92.7 259.3 64 224 64C188.7 64 160 92.7 160 128C160 163.3 188.7 192 224 192C259.3 192 288 163.3 288 128zM288 320C288 284.7 259.3 256 224 256C188.7 256 160 284.7 160 320C160 355.3 188.7 384 224 384C259.3 384 288 355.3 288 320zM160 512C160 547.3 188.7 576 224 576C259.3 576 288 547.3 288 512C288 476.7 259.3 448 224 448C188.7 448 160 476.7 160 512zM480 128C480 92.7 451.3 64 416 64C380.7 64 352 92.7 352 128C352 163.3 380.7 192 416 192C451.3 192 480 163.3 480 128zM352 320C352 355.3 380.7 384 416 384C451.3 384 480 355.3 480 320C480 284.7 451.3 256 416 256C380.7 256 352 284.7 352 320zM480 512C480 476.7 451.3 448 416 448C380.7 448 352 476.7 352 512C352 547.3 380.7 576 416 576C451.3 576 480 547.3 480 512z'/%3E%3C/svg%3E\") 50%/contain no-repeat}.formie-rank-option-label{font-size:var(--formie-check-font-size);line-height:var(--formie-check-line-height);flex:auto}.formie-rank-input{display:none}.formie-rating-field-layout{width:100%}.formie-rating-stars,.formie-rating-field-layout .formie-rating-stars.formie-field-options{padding:var(--formie-space-2) 0;--formie-survey-rating-star-size:26px;--formie-survey-rating-star-spacing:var(--formie-space-1);--formie-survey-rating-star-outline:url(data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2023%22%20fill%3D%22none%22%3E%3Cpath%20d%3D%22M22.2%208.05333L15.7466%207.49333L13.2266%201.56C12.7733%200.48%2011.2266%200.48%2010.7733%201.56L8.25331%207.50667L1.81331%208.05333C0.639975%208.14667%200.159975%209.61333%201.05331%2010.3867L5.94664%2014.6267L4.47998%2020.92C4.21331%2022.0667%205.45331%2022.9733%206.46664%2022.36L12%2019.0267L17.5333%2022.3733C18.5466%2022.9867%2019.7866%2022.08%2019.52%2020.9333L18.0533%2014.6267L22.9466%2010.3867C23.84%209.61333%2023.3733%208.14667%2022.2%208.05333ZM12%2016.5333L6.98664%2019.56L8.31998%2013.8533L3.89331%2010.0133L9.73331%209.50667L12%204.13333L14.28%209.52L20.12%2010.0267L15.6933%2013.8667L17.0266%2019.5733L12%2016.5333Z%22%20fill%3D%22%23E27730%22%2F%3E%3C%2Fsvg%3E);--formie-survey-rating-star-filled:url(data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2023%22%20fill%3D%22none%22%3E%3Cpath%20d%3D%22M12%2019.0267L17.5333%2022.3733C18.5466%2022.9867%2019.7866%2022.08%2019.52%2020.9333L18.0533%2014.64L22.9466%2010.4C23.84%209.62667%2023.36%208.16%2022.1866%208.06667L15.7466%207.52L13.2266%201.57334C12.7733%200.493336%2011.2266%200.493336%2010.7733%201.57334L8.25331%207.50667L1.81331%208.05334C0.639975%208.14667%200.159975%209.61334%201.05331%2010.3867L5.94664%2014.6267L4.47997%2020.92C4.21331%2022.0667%205.45331%2022.9733%206.46664%2022.36L12%2019.0267Z%22%20fill%3D%22%23E27730%22%2F%3E%3C%2Fsvg%3E);flex-wrap:nowrap;align-items:center;gap:0;display:inline-flex}.formie-rating-option{cursor:pointer;align-items:center;gap:0;margin:0;position:relative}.formie-rating-input{clip:rect(0, 0, 0, 0);clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.formie-rating-option-label{cursor:pointer;padding-inline:calc(var(--formie-survey-rating-star-spacing,var(--formie-space-1)) / 2);display:inline-flex}.formie-rating-star{width:var(--formie-survey-rating-star-size,26px);height:var(--formie-survey-rating-star-size,26px);background:50%/contain no-repeat;background-image:var(--formie-survey-rating-star-outline);display:block}.formie-rating-stars:not([data-formie-rating-hover])[data-formie-rating-value=\"1\"] .formie-rating-option:nth-child(-n+1) .formie-rating-star,.formie-rating-stars:not([data-formie-rating-hover])[data-formie-rating-value=\"2\"] .formie-rating-option:nth-child(-n+2) .formie-rating-star,.formie-rating-stars:not([data-formie-rating-hover])[data-formie-rating-value=\"3\"] .formie-rating-option:nth-child(-n+3) .formie-rating-star,.formie-rating-stars:not([data-formie-rating-hover])[data-formie-rating-value=\"4\"] .formie-rating-option:nth-child(-n+4) .formie-rating-star,.formie-rating-stars:not([data-formie-rating-hover])[data-formie-rating-value=\"5\"] .formie-rating-option:nth-child(-n+5) .formie-rating-star,.formie-rating-stars:not([data-formie-rating-hover])[data-formie-rating-value=\"6\"] .formie-rating-option:nth-child(-n+6) .formie-rating-star,.formie-rating-stars:not([data-formie-rating-hover])[data-formie-rating-value=\"7\"] .formie-rating-option:nth-child(-n+7) .formie-rating-star,.formie-rating-stars:not([data-formie-rating-hover])[data-formie-rating-value=\"8\"] .formie-rating-option:nth-child(-n+8) .formie-rating-star,.formie-rating-stars:not([data-formie-rating-hover])[data-formie-rating-value=\"9\"] .formie-rating-option:nth-child(-n+9) .formie-rating-star,.formie-rating-stars:not([data-formie-rating-hover])[data-formie-rating-value=\"10\"] .formie-rating-option:nth-child(-n+10) .formie-rating-star,.formie-rating-stars[data-formie-rating-hover=\"1\"] .formie-rating-option:nth-child(-n+1) .formie-rating-star,.formie-rating-stars[data-formie-rating-hover=\"2\"] .formie-rating-option:nth-child(-n+2) .formie-rating-star,.formie-rating-stars[data-formie-rating-hover=\"3\"] .formie-rating-option:nth-child(-n+3) .formie-rating-star,.formie-rating-stars[data-formie-rating-hover=\"4\"] .formie-rating-option:nth-child(-n+4) .formie-rating-star,.formie-rating-stars[data-formie-rating-hover=\"5\"] .formie-rating-option:nth-child(-n+5) .formie-rating-star,.formie-rating-stars[data-formie-rating-hover=\"6\"] .formie-rating-option:nth-child(-n+6) .formie-rating-star,.formie-rating-stars[data-formie-rating-hover=\"7\"] .formie-rating-option:nth-child(-n+7) .formie-rating-star,.formie-rating-stars[data-formie-rating-hover=\"8\"] .formie-rating-option:nth-child(-n+8) .formie-rating-star,.formie-rating-stars[data-formie-rating-hover=\"9\"] .formie-rating-option:nth-child(-n+9) .formie-rating-star,.formie-rating-stars[data-formie-rating-hover=\"10\"] .formie-rating-option:nth-child(-n+10) .formie-rating-star{background-image:var(--formie-survey-rating-star-filled)}.formie-rating-input:focus-visible+.formie-rating-option-label .formie-rating-star{outline:2px solid var(--formie-color-focus-ring);outline-offset:2px}}";
3
- //#endregion
4
- export { e as t };
@@ -1,125 +0,0 @@
1
- import { t as e } from "./debug-BV0DvdHx.js";
2
- import { c as t, l as n, n as r, t as i } from "./shared-Bx9s0i0P.js";
3
- //#region src/js/modules/fields/checkbox-radio.ts
4
- var a = "[data-formie-checkboxes-field-layout], [data-formie-radio-field-layout]", o = "minmaxOptions", s = "data-formie-checkbox-radio-max-disabled", c = "checkbox-radio", l = "checkbox-radio", u = e("fields", "checkbox-radio");
5
- function d(e) {
6
- return e.hasAttribute("data-checkbox-toggle") || e.hasAttribute("data-formie-checkbox-toggle");
7
- }
8
- function f(e) {
9
- let t = e(o);
10
- if (!t || t === !0 || typeof t != "object") return {
11
- min: null,
12
- max: null
13
- };
14
- let n = t;
15
- return {
16
- min: typeof n.min == "number" ? n.min : null,
17
- max: typeof n.max == "number" ? n.max : null
18
- };
19
- }
20
- function p(e) {
21
- return Array.from(e.querySelectorAll("input[type=\"checkbox\"]")).filter((e) => e instanceof HTMLInputElement && !d(e)).filter((e) => e.checked).length;
22
- }
23
- function m(e) {
24
- n(e, l, (e) => {
25
- e.addValidator(o, ({ field: e, getRule: t }) => {
26
- if (!e || !t(o)) return !0;
27
- let n = p(e), { min: r, max: i } = f(t);
28
- return !(r !== null && n < r || i !== null && n > i);
29
- }, ({ field: e, label: t, t: n, getRule: r }) => {
30
- if (!e) return n("{label} has an invalid value.", { label: t });
31
- let i = p(e), { min: a, max: o } = f(r);
32
- return a !== null && i < a ? e.getAttribute("data-formie-validation-min-options-message") ?? n("{label} should contain at least {min, number} {min, plural, one{option} other{options}}.", {
33
- label: t,
34
- min: a
35
- }) : o !== null && i > o ? e.getAttribute("data-formie-validation-max-options-message") ?? n("{label} should contain at most {max, number} {max, plural, one{option} other{options}}.", {
36
- label: t,
37
- max: o
38
- }) : n("{label} has an invalid value.", { label: t });
39
- });
40
- });
41
- }
42
- function h(e) {
43
- t(e, l, [o]);
44
- }
45
- function g(e) {
46
- e.checked ? e.setAttribute("checked", "") : e.removeAttribute("checked");
47
- }
48
- function _(e) {
49
- let t = Array.from(e.querySelectorAll("input[type=\"checkbox\"][required][data-formie-checkbox-input]")).filter((e) => e instanceof HTMLInputElement);
50
- if (!t.length) return;
51
- let n = t.some((e) => e.checked);
52
- t.forEach((e) => {
53
- if (n) {
54
- e.removeAttribute("required"), e.setAttribute("aria-required", "false");
55
- return;
56
- }
57
- e.setAttribute("required", "true"), e.setAttribute("aria-required", "true");
58
- });
59
- }
60
- function v(e) {
61
- let t = parseInt(e.closest("[data-formie-field-handle]")?.getAttribute("data-formie-max-options") || "", 10);
62
- if (!(t > 0)) return;
63
- let n = Array.from(e.querySelectorAll("input[type=\"checkbox\"]")).filter((e) => e instanceof HTMLInputElement && !d(e)), r = n.filter((e) => e.checked).length >= t;
64
- n.forEach((e) => {
65
- let t = r && !e.checked, n = e.hasAttribute(s);
66
- if (t) {
67
- e.disabled || (e.disabled = !0, e.setAttribute(s, "true"));
68
- return;
69
- }
70
- n && (e.disabled = !1, e.removeAttribute(s));
71
- });
72
- }
73
- function y(e, t) {
74
- Array.from(e.querySelectorAll("input[type=\"checkbox\"]")).filter((e) => e instanceof HTMLInputElement && e !== t && !d(e)).forEach((e) => {
75
- e.disabled && !e.checked || (e.checked = t.checked, g(e), e.dispatchEvent(new Event("change", { bubbles: !0 })), e.dispatchEvent(new Event("input", { bubbles: !0 })));
76
- });
77
- }
78
- function b(e, t) {
79
- if (!e.checked || !e.name) {
80
- g(e);
81
- return;
82
- }
83
- Array.from(t.querySelectorAll(`input[type="radio"][name="${r(e.name)}"]`)).filter((e) => e instanceof HTMLInputElement).forEach((e) => {
84
- g(e);
85
- });
86
- }
87
- function x(e) {
88
- let t = Array.from(e.querySelectorAll("input[type=\"checkbox\"], input[type=\"radio\"]")).filter((e) => e instanceof HTMLInputElement);
89
- if (!t.length) return u.log("No checkbox/radio inputs found for field."), () => {};
90
- let n = t.map((t) => {
91
- let n = t.type === "radio" ? "change" : "click", r = () => {
92
- g(t), t.type === "checkbox" && d(t) && y(e, t), t.type === "radio" && b(t, e), _(e), v(e), u.log("Input interaction processed.", {
93
- inputName: t.name,
94
- inputType: t.type,
95
- checked: t.checked
96
- });
97
- };
98
- return t.addEventListener(n, r), g(t), () => {
99
- t.removeEventListener(n, r);
100
- };
101
- });
102
- return _(e), v(e), i(e, c, "init", { checkboxRadio: e }), () => {
103
- n.forEach((e) => {
104
- e();
105
- });
106
- };
107
- }
108
- var S = {
109
- id: c,
110
- kind: "field",
111
- match: (e) => e.target instanceof HTMLElement && (e.target.matches(a) || !!e.target.querySelector(a)),
112
- setup: async (e) => {
113
- if (!(e.target instanceof HTMLElement)) return;
114
- let t = e.target.matches(a) ? [e.target] : Array.from(e.target.querySelectorAll(a)).filter((e) => e instanceof HTMLElement);
115
- m(e.form), u.log("Module setup.", { fieldCount: t.length });
116
- let n = t.map((e) => x(e));
117
- return await e.emit("formie:module:checkbox-radio:init", { count: t.length }), { destroy: () => {
118
- n.forEach((e) => {
119
- e();
120
- }), h(e.form), u.log("Module destroy.", { fieldCount: t.length }), e.emit("formie:module:checkbox-radio:destroy", {});
121
- } };
122
- }
123
- };
124
- //#endregion
125
- export { S as checkboxRadioModule };