srcdev-nuxt-components 9.6.7 → 9.6.9

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 (152) hide show
  1. package/.claude/rules/consumer/ids-from-useid.md +14 -0
  2. package/.claude/skills/component-compliance-checklist.md +18 -1
  3. package/.claude/skills/component-inline-action-button.md +1 -1
  4. package/.claude/skills/component-local-style-override.md +1 -1
  5. package/.claude/skills/component-naming.md +13 -13
  6. package/.claude/skills/components/container-glow.md +2 -2
  7. package/.claude/skills/components/form-field.md +2 -2
  8. package/.claude/skills/components/form-wrapper.md +1 -1
  9. package/.claude/skills/components/glowing-border.md +1 -1
  10. package/.claude/skills/components/input-checkbox-radio.md +19 -3
  11. package/.claude/skills/components/input-checkbox.md +14 -3
  12. package/.claude/skills/components/input-description.md +7 -7
  13. package/.claude/skills/components/input-error.md +3 -3
  14. package/.claude/skills/components/input-label.md +7 -8
  15. package/.claude/skills/components/input-number.md +60 -29
  16. package/.claude/skills/components/input-radio.md +15 -1
  17. package/.claude/skills/components/{input-range-core.md → input-range.md} +53 -18
  18. package/.claude/skills/components/input-select.md +153 -0
  19. package/.claude/skills/components/input-text.md +220 -0
  20. package/.claude/skills/components/input-textarea.md +147 -0
  21. package/.claude/skills/components/select-menu.md +4 -4
  22. package/.claude/skills/components/toggle-switch.md +143 -0
  23. package/.claude/skills/composable-zod-validation.md +1 -1
  24. package/.claude/skills/icon-sets.md +1 -1
  25. package/.claude/skills/icon-sizing.md +1 -1
  26. package/.claude/skills/index.md +10 -10
  27. package/.claude/skills/storybook-add-story.md +1 -1
  28. package/.claude/skills/testing-add-unit-test.md +17 -0
  29. package/.claude/skills/theming-component-token-pattern.md +8 -8
  30. package/.claude/skills/theming-form-geometry-tokens.md +1 -1
  31. package/.vscode/srcdev-component-input-checkbox-radio.code-snippets +0 -1
  32. package/.vscode/srcdev-component-input-range.code-snippets +38 -18
  33. package/.vscode/srcdev-component-input-select.code-snippets +20 -14
  34. package/.vscode/srcdev-component-input-text.code-snippets +46 -40
  35. package/.vscode/srcdev-component-input-textarea.code-snippets +19 -14
  36. package/.vscode/srcdev-component-toggle-switch.code-snippets +19 -29
  37. package/app/assets/styles/setup/04.elements/forms/00.element-defaults.css +2 -2
  38. package/app/assets/styles/setup/04.elements/forms/06.button-geometry.css +1 -1
  39. package/app/components/01.atoms/animations/glowing-border/CONSUMER-STYLING.md +2 -2
  40. package/app/components/01.atoms/animations/glowing-border/stories/GlowingBorder.stories.ts +4 -4
  41. package/app/components/02.molecules/progress-tracker/stories/ProgressTracker.stories.ts +4 -4
  42. package/app/components/05.forms/form-errors/CONSUMER-STYLING.md +1 -1
  43. package/app/components/05.forms/form-field/CONSUMER-STYLING.md +2 -2
  44. package/app/components/05.forms/input-button/stories/InputButton.stories.ts +3 -3
  45. package/app/components/05.forms/input-checkbox/CONSUMER-STYLING.md +10 -0
  46. package/app/components/05.forms/input-checkbox/MultipleCheckboxes.vue +18 -4
  47. package/app/components/05.forms/input-checkbox/SingleCheckbox.vue +14 -2
  48. package/app/components/05.forms/input-checkbox/stories/MultipleCheckboxes.stories.ts +146 -37
  49. package/app/components/05.forms/input-checkbox/stories/SingleCheckbox.stories.ts +107 -30
  50. package/app/components/05.forms/input-checkbox/tests/MultipleCheckboxes.spec.ts +38 -4
  51. package/app/components/05.forms/input-checkbox/tests/SingleCheckbox.spec.ts +5 -0
  52. package/app/components/05.forms/input-checkbox-radio/CONSUMER-STYLING.md +10 -3
  53. package/app/components/05.forms/input-checkbox-radio/InputCheckboxRadio.vue +1 -0
  54. package/app/components/05.forms/input-checkbox-radio/InputCheckboxRadioButton.vue +11 -10
  55. package/app/components/05.forms/input-checkbox-radio/InputCheckboxRadioField.vue +3 -0
  56. package/app/components/05.forms/input-checkbox-radio/stories/InputCheckboxRadio.stories.ts +44 -17
  57. package/app/components/05.forms/input-checkbox-radio/stories/InputCheckboxRadioButton.stories.ts +164 -58
  58. package/app/components/05.forms/input-checkbox-radio/stories/InputCheckboxRadioField.stories.ts +94 -21
  59. package/app/components/05.forms/input-checkbox-radio/tests/InputCheckboxRadio.spec.ts +14 -3
  60. package/app/components/05.forms/input-checkbox-radio/tests/InputCheckboxRadioButton.spec.ts +38 -3
  61. package/app/components/05.forms/input-checkbox-radio/tests/InputCheckboxRadioField.spec.ts +14 -3
  62. package/app/components/05.forms/input-description/CONSUMER-STYLING.md +7 -7
  63. package/app/components/05.forms/input-label/CONSUMER-STYLING.md +6 -6
  64. package/app/components/05.forms/input-number/CONSUMER-STYLING.md +50 -6
  65. package/app/components/05.forms/input-number/InputNumber.vue +39 -27
  66. package/app/components/05.forms/input-number/InputNumberField.vue +29 -16
  67. package/app/components/05.forms/input-number/stories/InputNumber.stories.ts +76 -25
  68. package/app/components/05.forms/input-number/stories/InputNumberField.stories.ts +116 -50
  69. package/app/components/05.forms/input-number/tests/InputNumber.spec.ts +49 -13
  70. package/app/components/05.forms/input-number/tests/InputNumberField.spec.ts +59 -5
  71. package/app/components/05.forms/input-radio/CONSUMER-STYLING.md +11 -0
  72. package/app/components/05.forms/input-radio/MultipleRadiobuttons.vue +14 -3
  73. package/app/components/05.forms/input-radio/stories/MultipleRadiobuttons.stories.ts +138 -38
  74. package/app/components/05.forms/input-radio/tests/MultipleRadioButtons.spec.ts +50 -3
  75. package/app/components/05.forms/input-range/CONSUMER-STYLING.md +68 -26
  76. package/app/components/05.forms/input-range/InputRange.vue +247 -0
  77. package/app/components/05.forms/input-range/{InputRangeDefault.vue → InputRangeField.vue} +41 -18
  78. package/app/components/05.forms/input-range/stories/InputRange.stories.ts +187 -0
  79. package/app/components/05.forms/input-range/stories/InputRangeField.stories.ts +196 -0
  80. package/app/components/05.forms/input-range/tests/{InputRangeCore.spec.ts → InputRange.spec.ts} +39 -15
  81. package/app/components/05.forms/input-range/tests/{InputRangeDefault.spec.ts → InputRangeField.spec.ts} +71 -7
  82. package/app/components/05.forms/input-select/CONSUMER-STYLING.md +80 -10
  83. package/app/components/05.forms/input-select/InputSelect.vue +198 -0
  84. package/app/components/05.forms/input-select/InputSelectField.vue +130 -0
  85. package/app/components/05.forms/input-select/stories/InputSelect.stories.ts +184 -0
  86. package/app/components/05.forms/input-select/stories/InputSelectField.stories.ts +187 -0
  87. package/app/components/05.forms/input-select/tests/{InputSelectCore.spec.ts → InputSelect.spec.ts} +75 -12
  88. package/app/components/05.forms/input-select/tests/InputSelectField.spec.ts +121 -0
  89. package/app/components/05.forms/input-text/CONSUMER-STYLING.md +85 -15
  90. package/app/components/05.forms/input-text/{InputPasswordWithLabel.vue → InputPasswordField.vue} +16 -19
  91. package/app/components/05.forms/input-text/{InputTextCore.vue → InputText.vue} +42 -78
  92. package/app/components/05.forms/input-text/{InputTextAsNumberWithLabel.vue → InputTextAsNumberField.vue} +66 -62
  93. package/app/components/05.forms/input-text/InputTextField.vue +168 -0
  94. package/app/components/05.forms/input-text/stories/InputPasswordField.stories.ts +163 -0
  95. package/app/components/05.forms/input-text/stories/InputText.stories.ts +194 -0
  96. package/app/components/05.forms/input-text/stories/InputTextAsNumberField.stories.ts +182 -0
  97. package/app/components/05.forms/input-text/stories/InputTextField.stories.ts +206 -0
  98. package/app/components/05.forms/input-text/tests/{InputPasswordWithLabel.spec.ts → InputPasswordField.spec.ts} +42 -3
  99. package/app/components/05.forms/input-text/tests/InputText.spec.ts +166 -0
  100. package/app/components/05.forms/input-text/tests/InputTextAsNumberField.spec.ts +135 -0
  101. package/app/components/05.forms/input-text/tests/InputTextField.spec.ts +130 -0
  102. package/app/components/05.forms/input-textarea/CONSUMER-STYLING.md +94 -12
  103. package/app/components/05.forms/input-textarea/InputTextarea.vue +165 -0
  104. package/app/components/05.forms/input-textarea/InputTextareaField.vue +159 -0
  105. package/app/components/05.forms/input-textarea/stories/InputTextarea.stories.ts +198 -0
  106. package/app/components/05.forms/input-textarea/stories/InputTextareaField.stories.ts +161 -0
  107. package/app/components/05.forms/input-textarea/tests/InputTextarea.spec.ts +149 -0
  108. package/app/components/05.forms/input-textarea/tests/InputTextareaField.spec.ts +122 -0
  109. package/app/components/05.forms/patterns/stories/ContactForm.stories.ts +13 -13
  110. package/app/components/05.forms/patterns/stories/LoginForm.stories.ts +6 -6
  111. package/app/components/05.forms/patterns/stories/MigratedFieldsForm.stories.ts +34 -36
  112. package/app/components/05.forms/toggle-switch/CONSUMER-STYLING.md +71 -50
  113. package/app/components/05.forms/toggle-switch/{ToggleSwitchCore.vue → ToggleSwitch.vue} +58 -73
  114. package/app/components/05.forms/toggle-switch/{ToggleSwitchWithLabel.vue → ToggleSwitchField.vue} +65 -19
  115. package/app/components/05.forms/toggle-switch/stories/ToggleSwitch.stories.ts +148 -0
  116. package/app/components/05.forms/toggle-switch/stories/ToggleSwitchField.stories.ts +176 -0
  117. package/app/components/05.forms/toggle-switch/tests/ToggleSwitch.spec.ts +145 -0
  118. package/app/components/05.forms/toggle-switch/tests/ToggleSwitchField.spec.ts +155 -0
  119. package/package.json +1 -1
  120. package/.claude/skills/components/input-select-core.md +0 -151
  121. package/.claude/skills/components/input-text-core.md +0 -204
  122. package/.claude/skills/components/input-textarea-core.md +0 -154
  123. package/.claude/skills/components/toggle-switch-core.md +0 -169
  124. package/app/components/05.forms/input-range/InputRangeCore.vue +0 -169
  125. package/app/components/05.forms/input-range/stories/InputRangeCore.stories.ts +0 -126
  126. package/app/components/05.forms/input-range/stories/InputRangeDefault.stories.ts +0 -108
  127. package/app/components/05.forms/input-select/InputSelectCore.vue +0 -188
  128. package/app/components/05.forms/input-select/InputSelectWithLabel.vue +0 -118
  129. package/app/components/05.forms/input-select/stories/InputSelectCore.stories.ts +0 -69
  130. package/app/components/05.forms/input-select/stories/InputSelectWithLabel.stories.ts +0 -115
  131. package/app/components/05.forms/input-select/tests/InputSelectWithLabel.spec.ts +0 -87
  132. package/app/components/05.forms/input-text/InputTextWithLabel.vue +0 -154
  133. package/app/components/05.forms/input-text/stories/InputPasswordWithLabel.stories.ts +0 -368
  134. package/app/components/05.forms/input-text/stories/InputTextAsNumberWithLabel.stories.ts +0 -480
  135. package/app/components/05.forms/input-text/stories/InputTextCore.stories.ts +0 -267
  136. package/app/components/05.forms/input-text/stories/InputTextWithLabel.stories.ts +0 -319
  137. package/app/components/05.forms/input-text/tests/InputTextAsNumberWithLabel.spec.ts +0 -75
  138. package/app/components/05.forms/input-text/tests/InputTextCore.spec.ts +0 -60
  139. package/app/components/05.forms/input-text/tests/InputTextWithLabel.spec.ts +0 -71
  140. package/app/components/05.forms/input-textarea/InputTextareaCore.vue +0 -159
  141. package/app/components/05.forms/input-textarea/InputTextareaWithLabel.vue +0 -136
  142. package/app/components/05.forms/input-textarea/stories/InputTextareaCore.stories.ts +0 -247
  143. package/app/components/05.forms/input-textarea/stories/InputTextareaWithLabel.stories.ts +0 -458
  144. package/app/components/05.forms/input-textarea/tests/InputTextareaCore.spec.ts +0 -119
  145. package/app/components/05.forms/input-textarea/tests/InputTextareaWithLabel.spec.ts +0 -93
  146. package/app/components/05.forms/toggle-switch/ToggleSwitchWithLabelInline.vue +0 -81
  147. package/app/components/05.forms/toggle-switch/stories/ToggleSwitchCore.stories.ts +0 -251
  148. package/app/components/05.forms/toggle-switch/stories/ToggleSwitchWithLabel.stories.ts +0 -251
  149. package/app/components/05.forms/toggle-switch/stories/ToggleSwitchWithLabelInline.stories.ts +0 -283
  150. package/app/components/05.forms/toggle-switch/tests/ToggleSwitchCore.spec.ts +0 -101
  151. package/app/components/05.forms/toggle-switch/tests/ToggleSwitchWithLabel.spec.ts +0 -133
  152. package/app/components/05.forms/toggle-switch/tests/ToggleSwitchWithLabelInline.spec.ts +0 -66
@@ -1,22 +1,22 @@
1
1
  {
2
- "SRCDEV InputSelectCore Basic": {
3
- "description": "Basic InputSelectCore native select (no label/error wrapper)",
2
+ "SRCDEV InputSelect Basic": {
3
+ "description": "Basic InputSelect native select (no label/error wrapper)",
4
4
  "scope": "vue,html",
5
5
  "body": [
6
- "<InputSelectCore",
6
+ "<InputSelect",
7
7
  " id=\"$1fieldId\"",
8
- " name=\"$2fieldName\"",
9
- " v-model=\"$3fieldValue\"",
10
- " v-model:field-data=\"$4fieldOptions\"",
8
+ " v-model=\"$2fieldValue\"",
9
+ " v-model:field-data=\"$3fieldOptions\"",
10
+ " name=\"$4fieldName\"",
11
11
  " placeholder=\"$5Choose an option\"",
12
12
  "/>"
13
13
  ]
14
14
  },
15
- "SRCDEV InputSelectWithLabel Basic": {
16
- "description": "InputSelectWithLabel: labelled select with error/description support",
15
+ "SRCDEV InputSelectField Basic": {
16
+ "description": "InputSelectField: labelled select with description and error support",
17
17
  "scope": "vue,html",
18
18
  "body": [
19
- "<InputSelectWithLabel",
19
+ "<InputSelectField",
20
20
  " v-model=\"$1fieldValue\"",
21
21
  " v-model:field-data=\"$2fieldOptions\"",
22
22
  " name=\"$3fieldName\"",
@@ -24,17 +24,23 @@
24
24
  " placeholder=\"$5Choose an option\"",
25
25
  " :error-message=\"$6errors.fieldName\"",
26
26
  " :field-has-error=\"!!$6errors.fieldName\"",
27
- "/>"
27
+ ">",
28
+ " <template #descriptionText>$7</template>",
29
+ "</InputSelectField>"
28
30
  ]
29
31
  },
30
32
  "SRCDEV InputSelect CSS Override": {
31
- "description": "CSS override scaffold for InputSelectCore tokens",
33
+ "description": "CSS override scaffold for InputSelect tokens",
32
34
  "scope": "css",
33
35
  "body": [
34
36
  ".$1my-page {",
35
- " .input-select-wrapper {",
36
- " --input-select-surface: $2;",
37
- " --input-select-border: $3;",
37
+ " --input-select-surface: $2;",
38
+ " --input-select-text-color: $3;",
39
+ " --input-select-border: $4;",
40
+ " --input-select-border-focus: $5;",
41
+ "",
42
+ " .input-select-field[data-invalid] {",
43
+ " $0",
38
44
  " }",
39
45
  "}"
40
46
  ]
@@ -1,53 +1,54 @@
1
1
  {
2
- "SRCDEV InputTextCore Basic": {
3
- "description": "Basic InputTextCore native input (no label/error wrapper)",
2
+ "SRCDEV InputText Basic": {
3
+ "description": "Basic InputText native input (no label/error wrapper)",
4
4
  "scope": "vue,html",
5
5
  "body": [
6
- "<InputTextCore",
6
+ "<InputText",
7
7
  " id=\"$1fieldId\"",
8
- " name=\"$2fieldName\"",
9
- " v-model=\"$3fieldValue\"",
8
+ " v-model=\"$2fieldValue\"",
9
+ " name=\"$3fieldName\"",
10
10
  " type=\"$4text\"",
11
- " placeholder=\"$5Enter value...\"",
11
+ " placeholder=\"$5Enter value\"",
12
12
  "/>"
13
13
  ]
14
14
  },
15
- "SRCDEV InputTextCore Date with min/max": {
16
- "description": "InputTextCore date input constrained to a min/max range (e.g. no dates in the past)",
15
+ "SRCDEV InputText Date with min/max": {
16
+ "description": "InputText date input constrained to a min/max range (e.g. no dates in the past)",
17
17
  "scope": "vue,html",
18
18
  "body": [
19
- "<InputTextCore",
19
+ "<InputText",
20
20
  " id=\"$1appointment-date\"",
21
- " name=\"$2appointmentDate\"",
22
- " v-model=\"$3appointmentDate\"",
21
+ " v-model=\"$2appointmentDate\"",
22
+ " name=\"$3appointmentDate\"",
23
23
  " type=\"date\"",
24
24
  " :min=\"new Date().toISOString().split('T')[0]\"",
25
25
  " max=\"$42027-12-31\"",
26
26
  "/>"
27
27
  ]
28
28
  },
29
- "SRCDEV InputTextWithLabel Basic": {
30
- "description": "InputTextWithLabel: labelled text field with error/description support",
29
+ "SRCDEV InputTextField Basic": {
30
+ "description": "InputTextField: labelled text field with description and error support",
31
31
  "scope": "vue,html",
32
32
  "body": [
33
- "<InputTextWithLabel",
33
+ "<InputTextField",
34
34
  " v-model=\"$1fieldValue\"",
35
- " id=\"$2fieldId\"",
36
- " name=\"$3fieldName\"",
37
- " type=\"$4text\"",
38
- " label=\"$5Field label\"",
35
+ " name=\"$2fieldName\"",
36
+ " type=\"${3|text,email,tel,url,date,number|}\"",
37
+ " label=\"$4Field label\"",
38
+ " autocomplete=\"$5\"",
39
39
  " :error-message=\"$6errors.fieldName\"",
40
40
  " :field-has-error=\"!!$6errors.fieldName\"",
41
- "/>"
41
+ ">",
42
+ " <template #descriptionText>$7</template>",
43
+ "</InputTextField>"
42
44
  ]
43
45
  },
44
- "SRCDEV InputTextWithLabel Date with min/max": {
45
- "description": "InputTextWithLabel date field constrained to a min/max range",
46
+ "SRCDEV InputTextField Date with min/max": {
47
+ "description": "InputTextField date field constrained to a min/max range",
46
48
  "scope": "vue,html",
47
49
  "body": [
48
- "<InputTextWithLabel",
50
+ "<InputTextField",
49
51
  " v-model=\"$1appointmentDate\"",
50
- " id=\"$2appointment-date\"",
51
52
  " name=\"$2appointmentDate\"",
52
53
  " type=\"date\"",
53
54
  " label=\"$3Appointment date\"",
@@ -58,24 +59,27 @@
58
59
  "/>"
59
60
  ]
60
61
  },
61
- "SRCDEV InputPasswordWithLabel": {
62
- "description": "InputPasswordWithLabel with show/hide toggle",
62
+ "SRCDEV InputPasswordField": {
63
+ "description": "InputPasswordField with show/hide toggle",
63
64
  "scope": "vue,html",
64
65
  "body": [
65
- "<InputPasswordWithLabel",
66
+ "<InputPasswordField",
66
67
  " v-model=\"$1password\"",
67
68
  " name=\"$2password\"",
68
69
  " label=\"$3Password\"",
69
- " :error-message=\"$4errors.password\"",
70
- " :field-has-error=\"!!$4errors.password\"",
70
+ " autocomplete=\"${4|current-password,new-password|}\"",
71
+ " :error-message=\"$5errors.password\"",
72
+ " :field-has-error=\"!!$5errors.password\"",
73
+ " show-password-text=\"$6Show password\"",
74
+ " hide-password-text=\"$7Hide password\"",
71
75
  "/>"
72
76
  ]
73
77
  },
74
- "SRCDEV InputTextAsNumberWithLabel": {
75
- "description": "InputTextAsNumberWithLabel numeric stepper with min/max/step",
78
+ "SRCDEV InputTextAsNumberField": {
79
+ "description": "InputTextAsNumberField numeric stepper with min/max/step",
76
80
  "scope": "vue,html",
77
81
  "body": [
78
- "<InputTextAsNumberWithLabel",
82
+ "<InputTextAsNumberField",
79
83
  " v-model=\"$1quantity\"",
80
84
  " name=\"$2quantity\"",
81
85
  " label=\"$3Quantity\"",
@@ -85,21 +89,23 @@
85
89
  " :error-message=\"$7errors.quantity\"",
86
90
  " :field-has-error=\"!!$7errors.quantity\"",
87
91
  ">",
88
- " <template #left>−</template>",
89
- " <template #right>+</template>",
90
- "</InputTextAsNumberWithLabel>"
92
+ " <template #left><Icon name=\"mdi:minus\" /></template>",
93
+ " <template #right><Icon name=\"mdi:plus\" /></template>",
94
+ "</InputTextAsNumberField>"
91
95
  ]
92
96
  },
93
97
  "SRCDEV InputText CSS Override": {
94
- "description": "CSS override scaffold for InputTextCore tokens",
98
+ "description": "CSS override scaffold for InputText tokens",
95
99
  "scope": "css",
96
100
  "body": [
97
101
  ".$1my-page {",
98
- " .input-text-wrapper {",
99
- " --input-text-surface: $2;",
100
- " --input-text-border: $3;",
101
- " --input-text-border-focus: $4;",
102
- " --input-text-color: $5;",
102
+ " --input-text-surface: $2;",
103
+ " --input-text-border: $3;",
104
+ " --input-text-border-focus: $4;",
105
+ " --input-text-color: $5;",
106
+ "",
107
+ " .input-text-field[data-invalid] {",
108
+ " $0",
103
109
  " }",
104
110
  "}"
105
111
  ]
@@ -1,38 +1,43 @@
1
1
  {
2
- "SRCDEV InputTextareaCore Basic": {
3
- "description": "Basic InputTextareaCore native textarea (no label/error wrapper)",
2
+ "SRCDEV InputTextarea Basic": {
3
+ "description": "Basic InputTextarea native textarea (no label/error wrapper)",
4
4
  "scope": "vue,html",
5
5
  "body": [
6
- "<InputTextareaCore",
6
+ "<InputTextarea",
7
7
  " id=\"$1fieldId\"",
8
- " name=\"$2fieldName\"",
9
- " v-model=\"$3fieldValue\"",
8
+ " v-model=\"$2fieldValue\"",
9
+ " name=\"$3fieldName\"",
10
10
  " placeholder=\"$4Placeholder text\"",
11
11
  "/>"
12
12
  ]
13
13
  },
14
- "SRCDEV InputTextareaWithLabel Basic": {
15
- "description": "InputTextareaWithLabel: labelled textarea with error/description support",
14
+ "SRCDEV InputTextareaField Basic": {
15
+ "description": "InputTextareaField: labelled textarea with description and error support",
16
16
  "scope": "vue,html",
17
17
  "body": [
18
- "<InputTextareaWithLabel",
18
+ "<InputTextareaField",
19
19
  " v-model=\"$1fieldValue\"",
20
20
  " name=\"$2fieldName\"",
21
21
  " label=\"$3Field label\"",
22
- " placeholder=\"$4Placeholder text\"",
22
+ " :maxlength=\"${4:1000}\"",
23
23
  " :error-message=\"$5errors.fieldName\"",
24
24
  " :field-has-error=\"!!$5errors.fieldName\"",
25
- "/>"
25
+ ">",
26
+ " <template #descriptionText>$6</template>",
27
+ "</InputTextareaField>"
26
28
  ]
27
29
  },
28
30
  "SRCDEV InputTextarea CSS Override": {
29
- "description": "CSS override scaffold for InputTextareaCore tokens",
31
+ "description": "CSS override scaffold for InputTextarea tokens",
30
32
  "scope": "css",
31
33
  "body": [
32
34
  ".$1my-page {",
33
- " .input-textarea-wrapper {",
34
- " --input-textarea-surface: $2;",
35
- " --input-textarea-border: $3;",
35
+ " --input-textarea-surface: $2;",
36
+ " --input-textarea-border: $3;",
37
+ " --input-textarea-max-height: ${4:20lh};",
38
+ "",
39
+ " .input-textarea-field[data-invalid] {",
40
+ " $0",
36
41
  " }",
37
42
  "}"
38
43
  ]
@@ -1,50 +1,40 @@
1
1
  {
2
- "SRCDEV ToggleSwitchCore": {
3
- "description": "ToggleSwitchCore — bare toggle switch (no label, use ToggleSwitchWithLabel for that)",
2
+ "SRCDEV ToggleSwitch": {
3
+ "description": "ToggleSwitch: bare switch (pair with a label for=\"toggle-switch-{id}\", or use ToggleSwitchField)",
4
4
  "scope": "vue,html",
5
5
  "body": [
6
- "<ToggleSwitchCore",
7
- " v-model=\"$1modelValue\"",
8
- " id=\"$2toggle-id\"",
9
- " name=\"$3toggleName\"",
6
+ "<label for=\"toggle-switch-$1toggle-id\">$2Label</label>",
7
+ "<ToggleSwitch",
8
+ " id=\"$1toggle-id\"",
9
+ " v-model=\"$3modelValue\"",
10
+ " name=\"$4toggleName\"",
10
11
  "/>"
11
12
  ]
12
13
  },
13
- "SRCDEV ToggleSwitchWithLabel": {
14
- "description": "ToggleSwitchWithLabel: labelled toggle switch with description/error support",
14
+ "SRCDEV ToggleSwitchField": {
15
+ "description": "ToggleSwitchField: labelled switch with description and error support",
15
16
  "scope": "vue,html",
16
17
  "body": [
17
- "<ToggleSwitchWithLabel",
18
+ "<ToggleSwitchField",
18
19
  " v-model=\"$1fieldValue\"",
19
20
  " name=\"$2fieldName\"",
20
21
  " label=\"$3Field label\"",
21
- " :error-message=\"$4errors.fieldName\"",
22
- " :field-has-error=\"!!$4errors.fieldName\"",
22
+ " layout=\"${4|stacked,inline|}\"",
23
+ " :error-message=\"$5errors.fieldName\"",
24
+ " :field-has-error=\"!!$5errors.fieldName\"",
23
25
  ">",
24
- " <template #descriptionText>$5Help text</template>",
25
- "</ToggleSwitchWithLabel>"
26
- ]
27
- },
28
- "SRCDEV ToggleSwitchWithLabelInline": {
29
- "description": "ToggleSwitchWithLabelInline: compact label + toggle switch side by side, no error support",
30
- "scope": "vue,html",
31
- "body": [
32
- "<ToggleSwitchWithLabelInline",
33
- " v-model=\"$1fieldValue\"",
34
- " name=\"$2fieldName\"",
35
- " label=\"$3Field label\"",
36
- "/>"
26
+ " <template #descriptionText>$6Help text</template>",
27
+ "</ToggleSwitchField>"
37
28
  ]
38
29
  },
39
30
  "SRCDEV ToggleSwitch CSS Override": {
40
- "description": "CSS override scaffold for ToggleSwitchCore tokens",
31
+ "description": "CSS override scaffold for ToggleSwitch tokens",
41
32
  "scope": "css",
42
33
  "body": [
43
34
  ".$1my-page {",
44
- " .toggle-switch-wrapper {",
45
- " --toggle-switch-surface: $2;",
46
- " --toggle-switch-symbol-surface-on: $3;",
47
- " }",
35
+ " --toggle-switch-surface: $2;",
36
+ " --toggle-switch-symbol-surface-on: $3;",
37
+ " --input-toggle-symbol-size: ${4:2.4rem};",
48
38
  "}"
49
39
  ]
50
40
  }
@@ -11,9 +11,9 @@
11
11
  input:-webkit-autofill-and-obscured {
12
12
  background-color: var(--theme-surface) !important;
13
13
  background-image: none !important;
14
- color: var(--_input-text-core-color) !important;
14
+ color: var(--input-text-color, var(--theme-input-text-color-normal)) !important;
15
15
  -webkit-box-shadow: 0 0 0rem 1000px var(--theme-surface) inset;
16
- -webkit-text-fill-color: var(--_input-text-core-color);
16
+ -webkit-text-fill-color: var(--input-text-color, var(--theme-input-text-color-normal));
17
17
  transition: background-color 5000s ease-in-out 0s;
18
18
  }
19
19
  }
@@ -17,7 +17,7 @@
17
17
  box alone — .input-button keeps box-sizing: content-box (changing that risks shifting
18
18
  icon-only's aspect-ratio: 1 sizing), so its own padding-block and border have to be
19
19
  subtracted back out here, unlike --input-min-height itself which happens to need no such
20
- adjustment (InputTextCore has zero padding-block and no full border in its resting state).
20
+ adjustment (InputText has zero padding-block and no full border in its resting state).
21
21
  This is a floor, not a fixed height — icon-only/pill buttons or longer button-text can
22
22
  still grow past it. Textareas are the deliberate exception to this alignment entirely. */
23
23
  --button-min-height: calc(
@@ -86,7 +86,7 @@ For a single "special" button or input, wrap just the control so the glow become
86
86
  No changes to the control are needed:
87
87
 
88
88
  - `InputButton`'s border already defaults to its own surface colour, so it shows no edge of its own.
89
- - `InputTextCore` needs `--input-text-border: transparent`.
89
+ - `InputText` needs `--input-text-border: transparent`.
90
90
  - On the `GlowingBorder`: radius is the control's radius plus the glow width, surface
91
91
  `transparent`, overflow `visible` (so the control's hover and focus outlines aren't clipped),
92
92
  and an inline or shrink-to-fit display so it hugs the control.
@@ -97,7 +97,7 @@ No changes to the control are needed:
97
97
  </GlowingBorder>
98
98
 
99
99
  <GlowingBorder variant="vivid" style-class-passthrough="special-input">
100
- <InputTextCore id="email" v-model="email" type="email" name="email"></InputTextCore>
100
+ <InputText id="email" v-model="email" type="email" name="email"></InputText>
101
101
  </GlowingBorder>
102
102
  ```
103
103
 
@@ -1,7 +1,7 @@
1
1
  import type { Meta, StoryFn } from "@nuxtjs/storybook";
2
2
  import { computed, ref } from "vue";
3
3
  import StorybookComponent from "../GlowingBorder.vue";
4
- import InputTextCore from "../../../../05.forms/input-text/InputTextCore.vue";
4
+ import InputText from "../../../../05.forms/input-text/InputText.vue";
5
5
  import InputButton from "../../../../05.forms/input-button/InputButton.vue";
6
6
  import CanvasSwitcher from "../../../canvas-switcher/CanvasSwitcher.vue";
7
7
  import type { MediaCanvas } from "~/types/components";
@@ -194,7 +194,7 @@ CustomTokens.args = {
194
194
  };
195
195
 
196
196
  export const HighlightedControls: StoryFn<StoryArgs> = (args) => ({
197
- components: { StorybookComponent, InputTextCore, InputButton },
197
+ components: { StorybookComponent, InputText, InputButton },
198
198
  setup() {
199
199
  const { args: storyArgs, stageStyle } = useStorySetup(args);
200
200
  const glowStyle = (controlRadius: string) =>
@@ -224,13 +224,13 @@ export const HighlightedControls: StoryFn<StoryArgs> = (args) => ({
224
224
  <div style="display: grid; gap: 8px; inline-size: min(100%, 40rem);">
225
225
  <label for="highlighted-email">Early-access email</label>
226
226
  <StorybookComponent :variant="args.variant" :style="inputGlowStyle">
227
- <InputTextCore
227
+ <InputText
228
228
  id="highlighted-email"
229
229
  v-model="email"
230
230
  type="email"
231
231
  name="highlighted-email"
232
232
  placeholder="eg. jane@example.com"
233
- ></InputTextCore>
233
+ ></InputText>
234
234
  </StorybookComponent>
235
235
  </div>
236
236
  </div>
@@ -2,7 +2,7 @@ import { computed, reactive, ref } from "vue";
2
2
  import ProgressTracker from "../ProgressTracker.vue";
3
3
  import CanvasSwitcher from "../../../01.atoms/canvas-switcher/CanvasSwitcher.vue";
4
4
  import InputButton from "../../../05.forms/input-button/InputButton.vue";
5
- import InputTextWithLabel from "../../../05.forms/input-text/InputTextWithLabel.vue";
5
+ import InputTextField from "../../../05.forms/input-text/InputTextField.vue";
6
6
  import type { Meta, StoryObj } from "@nuxtjs/storybook";
7
7
  import type { MediaCanvas, ProgressTrackerStep } from "~/types/components";
8
8
 
@@ -217,7 +217,7 @@ export const Wizard: Story = {
217
217
  name: "Wizard (parent-owned forms)",
218
218
  args: { modelValue: 0, steps: wizardSteps },
219
219
  render: (args) => ({
220
- components: { ProgressTracker, InputButton, InputTextWithLabel },
220
+ components: { ProgressTracker, InputButton, InputTextField },
221
221
  setup() {
222
222
  const story = useStorySetup(args);
223
223
  const form = reactive({ name: "", email: "" });
@@ -254,7 +254,7 @@ export const Wizard: Story = {
254
254
  <ProgressTracker v-bind="componentArgs" v-model="args.modelValue" :steps="steps">
255
255
  <template #step-0="{ headingId }">
256
256
  <form :aria-labelledby="headingId" style="display: grid; gap: 1.6rem;" @submit.prevent="next('name')">
257
- <InputTextWithLabel
257
+ <InputTextField
258
258
  v-model="form.name"
259
259
  type="text"
260
260
  name="wizard-name"
@@ -270,7 +270,7 @@ export const Wizard: Story = {
270
270
  </template>
271
271
  <template #step-1="{ headingId }">
272
272
  <form :aria-labelledby="headingId" style="display: grid; gap: 1.6rem;" @submit.prevent="next('email')">
273
- <InputTextWithLabel
273
+ <InputTextField
274
274
  v-model="form.email"
275
275
  type="email"
276
276
  name="wizard-email"
@@ -1,7 +1,7 @@
1
1
  # InputError — Consumer Styling Guide
2
2
 
3
3
  `InputError` is the red error message strip rendered under a form control by every `*Field`
4
- wrapper (`InputTextWithLabel`, `InputNumberField`, `InputSelectWithLabel`, `SingleCheckbox`, ...).
4
+ wrapper (`InputTextField`, `InputNumberField`, `InputSelectField`, `SingleCheckbox`, ...).
5
5
  It animates open (`grid-template-rows: 0fr → 1fr` plus opacity) when the field is in error.
6
6
 
7
7
  ## Public token API
@@ -1,7 +1,7 @@
1
1
  # FormField — Consumer Styling Guide
2
2
 
3
3
  `FormField` is a layout wrapper for one form control (typically an `*Field` component such as
4
- `InputTextWithLabel` or `InputNumberField`). It caps the field's width, centres it, optionally
4
+ `InputTextField` or `InputNumberField`). It caps the field's width, centres it, optionally
5
5
  insets it from its container's edges with a gutter, and applies vertical spacing between fields.
6
6
 
7
7
  ## Public token API
@@ -65,7 +65,7 @@ Set the tokens above on an element you own (a page or section class, or a class
65
65
 
66
66
  ```vue
67
67
  <FormField width="wide" style="--form-field-background-color: var(--slate-01);">
68
- <InputTextWithLabel ... />
68
+ <InputTextField ... />
69
69
  </FormField>
70
70
  ```
71
71
 
@@ -1,7 +1,7 @@
1
1
  import type { Meta, StoryFn } from "@nuxtjs/storybook";
2
2
  import { ref } from "vue";
3
3
  import StorybookComponent from "../InputButton.vue";
4
- import InputTextCore from "../../input-text/InputTextCore.vue";
4
+ import InputText from "../../input-text/InputText.vue";
5
5
 
6
6
  interface InputButtonStoryArgs {
7
7
  type: "submit" | "button" | "reset";
@@ -314,11 +314,11 @@ NuxtIconOnlyComponent.args = {
314
314
  // most common "usual suspect" pairing (e.g. newsletter signup, search bar). Textareas are the
315
315
  // deliberate exception to this alignment and aren't part of this story.
316
316
  const InlineTemplate: StoryFn = () => ({
317
- components: { StorybookComponent, InputTextCore },
317
+ components: { StorybookComponent, InputText },
318
318
  template: `
319
319
  <div style="margin: 36px; max-width: 480px;">
320
320
  <div style="display: flex; align-items: flex-start; gap: 0.8rem;">
321
- <InputTextCore
321
+ <InputText
322
322
  id="inline-email"
323
323
  name="email"
324
324
  type="email"
@@ -29,6 +29,16 @@ columns need more room.
29
29
  | `--single-checkbox-margin-block-start` | `1.2rem` | Space between the legend/description and the checkbox |
30
30
  | `--single-checkbox-column-min-width` | `100px` | Grid column minimum width with `options-layout="equal-widths"` |
31
31
 
32
+ > **Changed 2026-10-16**: the equal-width column minimum is capped at `min(100%, ...)` so one long
33
+ > label can no longer push the grid wider than its container.
34
+
35
+ ### Root fieldset
36
+
37
+ `.multiple-checkboxes-fieldset` and `.single-checkbox-fieldset` set `min-inline-size: 0` and
38
+ `overflow-wrap: anywhere` (added 2026-10-16). The second inherits into the legend, description,
39
+ option labels and error, so long unbroken words and URLs wrap instead of overflowing. Neither is a
40
+ token; override `overflow-wrap` on your passthrough class if you need the old behaviour.
41
+
32
42
  ---
33
43
 
34
44
  ## State hooks
@@ -23,10 +23,10 @@
23
23
  </template>
24
24
  </InputDescription>
25
25
  <div ref="itemsContainer" class="multiple-checkboxes-items" :data-options-layout="optionsLayout">
26
- <template v-for="item in fieldData.data" :key="item.id">
26
+ <template v-for="(item, index) in fieldData.data" :key="item.id">
27
27
  <InputCheckboxRadioButton
28
28
  v-if="isButton"
29
- :id="`${name}-${item.value}`"
29
+ :id="`${optionIdPrefix}-${index}`"
30
30
  v-model="modelValue"
31
31
  type="checkbox"
32
32
  :name
@@ -119,7 +119,14 @@ const slots = useSlots();
119
119
  const modelValue = defineModel<(string | number | boolean)[] | string | number | boolean | undefined>({ required: true });
120
120
  const fieldData = defineModel<IFormMultipleOptions>("fieldData", { required: true });
121
121
 
122
- const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
122
+ const { elementClasses, resetElementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
123
+
124
+ watch(
125
+ () => props.styleClassPassthrough,
126
+ () => {
127
+ resetElementClasses(props.styleClassPassthrough);
128
+ }
129
+ );
123
130
 
124
131
  const { id, errorId, descriptionId, ariaDescribedby } = useAriaDescribedById(
125
132
  props.name,
@@ -127,6 +134,8 @@ const { id, errorId, descriptionId, ariaDescribedby } = useAriaDescribedById(
127
134
  slots
128
135
  );
129
136
 
137
+ const optionIdPrefix = useId();
138
+
130
139
  const { maxChildWidth, updateMaxChildWidth } = useMaxChildWidth(
131
140
  ".input-checkbox-radio-field-label, .input-checkbox-radio-field",
132
141
  "100px"
@@ -146,6 +155,11 @@ watch(
146
155
 
147
156
  <style lang="css">
148
157
  @layer components {
158
+ .multiple-checkboxes-fieldset {
159
+ min-inline-size: 0;
160
+ overflow-wrap: anywhere;
161
+ }
162
+
149
163
  .multiple-checkboxes-items {
150
164
  display: flex;
151
165
  gap: var(--multiple-checkboxes-gap, 1.2rem);
@@ -165,7 +179,7 @@ watch(
165
179
  grid-template-columns: repeat(
166
180
  auto-fit,
167
181
  minmax(
168
- calc(var(--input-checked-icon-gap) + (2 * var(--input-checkbox-label-padding-inline)) + v-bind(maxChildWidth)),
182
+ min(100%, calc(var(--input-checked-icon-gap) + (2 * var(--input-checkbox-label-padding-inline)) + v-bind(maxChildWidth))),
169
183
  1fr
170
184
  )
171
185
  );
@@ -84,7 +84,14 @@ const props = withDefaults(defineProps<Props>(), {
84
84
 
85
85
  const slots = useSlots();
86
86
  const modelValue = defineModel<(string | number | boolean)[] | string | number | boolean | undefined>({ required: true });
87
- const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
87
+ const { elementClasses, resetElementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
88
+
89
+ watch(
90
+ () => props.styleClassPassthrough,
91
+ () => {
92
+ resetElementClasses(props.styleClassPassthrough);
93
+ }
94
+ );
88
95
 
89
96
  const { id, errorId, descriptionId, ariaDescribedby } = useAriaDescribedById(
90
97
  props.name,
@@ -95,6 +102,11 @@ const { id, errorId, descriptionId, ariaDescribedby } = useAriaDescribedById(
95
102
 
96
103
  <style lang="css">
97
104
  @layer components {
105
+ .single-checkbox-fieldset {
106
+ min-inline-size: 0;
107
+ overflow-wrap: anywhere;
108
+ }
109
+
98
110
  .single-checkbox-items {
99
111
  display: flex;
100
112
  gap: var(--single-checkbox-gap, 1.2rem);
@@ -111,7 +123,7 @@ const { id, errorId, descriptionId, ariaDescribedby } = useAriaDescribedById(
111
123
 
112
124
  &[data-options-layout="equal-widths"] {
113
125
  display: grid;
114
- grid-template-columns: repeat(auto-fit, minmax(var(--single-checkbox-column-min-width, 100px), 1fr));
126
+ grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--single-checkbox-column-min-width, 100px)), 1fr));
115
127
  }
116
128
  }
117
129
  }