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.
- package/.claude/rules/consumer/ids-from-useid.md +14 -0
- package/.claude/skills/component-compliance-checklist.md +18 -1
- package/.claude/skills/component-inline-action-button.md +1 -1
- package/.claude/skills/component-local-style-override.md +1 -1
- package/.claude/skills/component-naming.md +13 -13
- package/.claude/skills/components/container-glow.md +2 -2
- package/.claude/skills/components/form-field.md +2 -2
- package/.claude/skills/components/form-wrapper.md +1 -1
- package/.claude/skills/components/glowing-border.md +1 -1
- package/.claude/skills/components/input-checkbox-radio.md +19 -3
- package/.claude/skills/components/input-checkbox.md +14 -3
- package/.claude/skills/components/input-description.md +7 -7
- package/.claude/skills/components/input-error.md +3 -3
- package/.claude/skills/components/input-label.md +7 -8
- package/.claude/skills/components/input-number.md +60 -29
- package/.claude/skills/components/input-radio.md +15 -1
- package/.claude/skills/components/{input-range-core.md → input-range.md} +53 -18
- package/.claude/skills/components/input-select.md +153 -0
- package/.claude/skills/components/input-text.md +220 -0
- package/.claude/skills/components/input-textarea.md +147 -0
- package/.claude/skills/components/select-menu.md +4 -4
- package/.claude/skills/components/toggle-switch.md +143 -0
- package/.claude/skills/composable-zod-validation.md +1 -1
- package/.claude/skills/icon-sets.md +1 -1
- package/.claude/skills/icon-sizing.md +1 -1
- package/.claude/skills/index.md +10 -10
- package/.claude/skills/storybook-add-story.md +1 -1
- package/.claude/skills/testing-add-unit-test.md +17 -0
- package/.claude/skills/theming-component-token-pattern.md +8 -8
- package/.claude/skills/theming-form-geometry-tokens.md +1 -1
- package/.vscode/srcdev-component-input-checkbox-radio.code-snippets +0 -1
- package/.vscode/srcdev-component-input-range.code-snippets +38 -18
- package/.vscode/srcdev-component-input-select.code-snippets +20 -14
- package/.vscode/srcdev-component-input-text.code-snippets +46 -40
- package/.vscode/srcdev-component-input-textarea.code-snippets +19 -14
- package/.vscode/srcdev-component-toggle-switch.code-snippets +19 -29
- package/app/assets/styles/setup/04.elements/forms/00.element-defaults.css +2 -2
- package/app/assets/styles/setup/04.elements/forms/06.button-geometry.css +1 -1
- package/app/components/01.atoms/animations/glowing-border/CONSUMER-STYLING.md +2 -2
- package/app/components/01.atoms/animations/glowing-border/stories/GlowingBorder.stories.ts +4 -4
- package/app/components/02.molecules/progress-tracker/stories/ProgressTracker.stories.ts +4 -4
- package/app/components/05.forms/form-errors/CONSUMER-STYLING.md +1 -1
- package/app/components/05.forms/form-field/CONSUMER-STYLING.md +2 -2
- package/app/components/05.forms/input-button/stories/InputButton.stories.ts +3 -3
- package/app/components/05.forms/input-checkbox/CONSUMER-STYLING.md +10 -0
- package/app/components/05.forms/input-checkbox/MultipleCheckboxes.vue +18 -4
- package/app/components/05.forms/input-checkbox/SingleCheckbox.vue +14 -2
- package/app/components/05.forms/input-checkbox/stories/MultipleCheckboxes.stories.ts +146 -37
- package/app/components/05.forms/input-checkbox/stories/SingleCheckbox.stories.ts +107 -30
- package/app/components/05.forms/input-checkbox/tests/MultipleCheckboxes.spec.ts +38 -4
- package/app/components/05.forms/input-checkbox/tests/SingleCheckbox.spec.ts +5 -0
- package/app/components/05.forms/input-checkbox-radio/CONSUMER-STYLING.md +10 -3
- package/app/components/05.forms/input-checkbox-radio/InputCheckboxRadio.vue +1 -0
- package/app/components/05.forms/input-checkbox-radio/InputCheckboxRadioButton.vue +11 -10
- package/app/components/05.forms/input-checkbox-radio/InputCheckboxRadioField.vue +3 -0
- package/app/components/05.forms/input-checkbox-radio/stories/InputCheckboxRadio.stories.ts +44 -17
- package/app/components/05.forms/input-checkbox-radio/stories/InputCheckboxRadioButton.stories.ts +164 -58
- package/app/components/05.forms/input-checkbox-radio/stories/InputCheckboxRadioField.stories.ts +94 -21
- package/app/components/05.forms/input-checkbox-radio/tests/InputCheckboxRadio.spec.ts +14 -3
- package/app/components/05.forms/input-checkbox-radio/tests/InputCheckboxRadioButton.spec.ts +38 -3
- package/app/components/05.forms/input-checkbox-radio/tests/InputCheckboxRadioField.spec.ts +14 -3
- package/app/components/05.forms/input-description/CONSUMER-STYLING.md +7 -7
- package/app/components/05.forms/input-label/CONSUMER-STYLING.md +6 -6
- package/app/components/05.forms/input-number/CONSUMER-STYLING.md +50 -6
- package/app/components/05.forms/input-number/InputNumber.vue +39 -27
- package/app/components/05.forms/input-number/InputNumberField.vue +29 -16
- package/app/components/05.forms/input-number/stories/InputNumber.stories.ts +76 -25
- package/app/components/05.forms/input-number/stories/InputNumberField.stories.ts +116 -50
- package/app/components/05.forms/input-number/tests/InputNumber.spec.ts +49 -13
- package/app/components/05.forms/input-number/tests/InputNumberField.spec.ts +59 -5
- package/app/components/05.forms/input-radio/CONSUMER-STYLING.md +11 -0
- package/app/components/05.forms/input-radio/MultipleRadiobuttons.vue +14 -3
- package/app/components/05.forms/input-radio/stories/MultipleRadiobuttons.stories.ts +138 -38
- package/app/components/05.forms/input-radio/tests/MultipleRadioButtons.spec.ts +50 -3
- package/app/components/05.forms/input-range/CONSUMER-STYLING.md +68 -26
- package/app/components/05.forms/input-range/InputRange.vue +247 -0
- package/app/components/05.forms/input-range/{InputRangeDefault.vue → InputRangeField.vue} +41 -18
- package/app/components/05.forms/input-range/stories/InputRange.stories.ts +187 -0
- package/app/components/05.forms/input-range/stories/InputRangeField.stories.ts +196 -0
- package/app/components/05.forms/input-range/tests/{InputRangeCore.spec.ts → InputRange.spec.ts} +39 -15
- package/app/components/05.forms/input-range/tests/{InputRangeDefault.spec.ts → InputRangeField.spec.ts} +71 -7
- package/app/components/05.forms/input-select/CONSUMER-STYLING.md +80 -10
- package/app/components/05.forms/input-select/InputSelect.vue +198 -0
- package/app/components/05.forms/input-select/InputSelectField.vue +130 -0
- package/app/components/05.forms/input-select/stories/InputSelect.stories.ts +184 -0
- package/app/components/05.forms/input-select/stories/InputSelectField.stories.ts +187 -0
- package/app/components/05.forms/input-select/tests/{InputSelectCore.spec.ts → InputSelect.spec.ts} +75 -12
- package/app/components/05.forms/input-select/tests/InputSelectField.spec.ts +121 -0
- package/app/components/05.forms/input-text/CONSUMER-STYLING.md +85 -15
- package/app/components/05.forms/input-text/{InputPasswordWithLabel.vue → InputPasswordField.vue} +16 -19
- package/app/components/05.forms/input-text/{InputTextCore.vue → InputText.vue} +42 -78
- package/app/components/05.forms/input-text/{InputTextAsNumberWithLabel.vue → InputTextAsNumberField.vue} +66 -62
- package/app/components/05.forms/input-text/InputTextField.vue +168 -0
- package/app/components/05.forms/input-text/stories/InputPasswordField.stories.ts +163 -0
- package/app/components/05.forms/input-text/stories/InputText.stories.ts +194 -0
- package/app/components/05.forms/input-text/stories/InputTextAsNumberField.stories.ts +182 -0
- package/app/components/05.forms/input-text/stories/InputTextField.stories.ts +206 -0
- package/app/components/05.forms/input-text/tests/{InputPasswordWithLabel.spec.ts → InputPasswordField.spec.ts} +42 -3
- package/app/components/05.forms/input-text/tests/InputText.spec.ts +166 -0
- package/app/components/05.forms/input-text/tests/InputTextAsNumberField.spec.ts +135 -0
- package/app/components/05.forms/input-text/tests/InputTextField.spec.ts +130 -0
- package/app/components/05.forms/input-textarea/CONSUMER-STYLING.md +94 -12
- package/app/components/05.forms/input-textarea/InputTextarea.vue +165 -0
- package/app/components/05.forms/input-textarea/InputTextareaField.vue +159 -0
- package/app/components/05.forms/input-textarea/stories/InputTextarea.stories.ts +198 -0
- package/app/components/05.forms/input-textarea/stories/InputTextareaField.stories.ts +161 -0
- package/app/components/05.forms/input-textarea/tests/InputTextarea.spec.ts +149 -0
- package/app/components/05.forms/input-textarea/tests/InputTextareaField.spec.ts +122 -0
- package/app/components/05.forms/patterns/stories/ContactForm.stories.ts +13 -13
- package/app/components/05.forms/patterns/stories/LoginForm.stories.ts +6 -6
- package/app/components/05.forms/patterns/stories/MigratedFieldsForm.stories.ts +34 -36
- package/app/components/05.forms/toggle-switch/CONSUMER-STYLING.md +71 -50
- package/app/components/05.forms/toggle-switch/{ToggleSwitchCore.vue → ToggleSwitch.vue} +58 -73
- package/app/components/05.forms/toggle-switch/{ToggleSwitchWithLabel.vue → ToggleSwitchField.vue} +65 -19
- package/app/components/05.forms/toggle-switch/stories/ToggleSwitch.stories.ts +148 -0
- package/app/components/05.forms/toggle-switch/stories/ToggleSwitchField.stories.ts +176 -0
- package/app/components/05.forms/toggle-switch/tests/ToggleSwitch.spec.ts +145 -0
- package/app/components/05.forms/toggle-switch/tests/ToggleSwitchField.spec.ts +155 -0
- package/package.json +1 -1
- package/.claude/skills/components/input-select-core.md +0 -151
- package/.claude/skills/components/input-text-core.md +0 -204
- package/.claude/skills/components/input-textarea-core.md +0 -154
- package/.claude/skills/components/toggle-switch-core.md +0 -169
- package/app/components/05.forms/input-range/InputRangeCore.vue +0 -169
- package/app/components/05.forms/input-range/stories/InputRangeCore.stories.ts +0 -126
- package/app/components/05.forms/input-range/stories/InputRangeDefault.stories.ts +0 -108
- package/app/components/05.forms/input-select/InputSelectCore.vue +0 -188
- package/app/components/05.forms/input-select/InputSelectWithLabel.vue +0 -118
- package/app/components/05.forms/input-select/stories/InputSelectCore.stories.ts +0 -69
- package/app/components/05.forms/input-select/stories/InputSelectWithLabel.stories.ts +0 -115
- package/app/components/05.forms/input-select/tests/InputSelectWithLabel.spec.ts +0 -87
- package/app/components/05.forms/input-text/InputTextWithLabel.vue +0 -154
- package/app/components/05.forms/input-text/stories/InputPasswordWithLabel.stories.ts +0 -368
- package/app/components/05.forms/input-text/stories/InputTextAsNumberWithLabel.stories.ts +0 -480
- package/app/components/05.forms/input-text/stories/InputTextCore.stories.ts +0 -267
- package/app/components/05.forms/input-text/stories/InputTextWithLabel.stories.ts +0 -319
- package/app/components/05.forms/input-text/tests/InputTextAsNumberWithLabel.spec.ts +0 -75
- package/app/components/05.forms/input-text/tests/InputTextCore.spec.ts +0 -60
- package/app/components/05.forms/input-text/tests/InputTextWithLabel.spec.ts +0 -71
- package/app/components/05.forms/input-textarea/InputTextareaCore.vue +0 -159
- package/app/components/05.forms/input-textarea/InputTextareaWithLabel.vue +0 -136
- package/app/components/05.forms/input-textarea/stories/InputTextareaCore.stories.ts +0 -247
- package/app/components/05.forms/input-textarea/stories/InputTextareaWithLabel.stories.ts +0 -458
- package/app/components/05.forms/input-textarea/tests/InputTextareaCore.spec.ts +0 -119
- package/app/components/05.forms/input-textarea/tests/InputTextareaWithLabel.spec.ts +0 -93
- package/app/components/05.forms/toggle-switch/ToggleSwitchWithLabelInline.vue +0 -81
- package/app/components/05.forms/toggle-switch/stories/ToggleSwitchCore.stories.ts +0 -251
- package/app/components/05.forms/toggle-switch/stories/ToggleSwitchWithLabel.stories.ts +0 -251
- package/app/components/05.forms/toggle-switch/stories/ToggleSwitchWithLabelInline.stories.ts +0 -283
- package/app/components/05.forms/toggle-switch/tests/ToggleSwitchCore.spec.ts +0 -101
- package/app/components/05.forms/toggle-switch/tests/ToggleSwitchWithLabel.spec.ts +0 -133
- package/app/components/05.forms/toggle-switch/tests/ToggleSwitchWithLabelInline.spec.ts +0 -66
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
{
|
|
2
|
-
"SRCDEV
|
|
3
|
-
"description": "Basic
|
|
2
|
+
"SRCDEV InputSelect Basic": {
|
|
3
|
+
"description": "Basic InputSelect native select (no label/error wrapper)",
|
|
4
4
|
"scope": "vue,html",
|
|
5
5
|
"body": [
|
|
6
|
-
"<
|
|
6
|
+
"<InputSelect",
|
|
7
7
|
" id=\"$1fieldId\"",
|
|
8
|
-
"
|
|
9
|
-
" v-model=\"$
|
|
10
|
-
"
|
|
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
|
|
16
|
-
"description": "
|
|
15
|
+
"SRCDEV InputSelectField Basic": {
|
|
16
|
+
"description": "InputSelectField: labelled select with description and error support",
|
|
17
17
|
"scope": "vue,html",
|
|
18
18
|
"body": [
|
|
19
|
-
"<
|
|
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
|
|
33
|
+
"description": "CSS override scaffold for InputSelect tokens",
|
|
32
34
|
"scope": "css",
|
|
33
35
|
"body": [
|
|
34
36
|
".$1my-page {",
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
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
|
|
3
|
-
"description": "Basic
|
|
2
|
+
"SRCDEV InputText Basic": {
|
|
3
|
+
"description": "Basic InputText native input (no label/error wrapper)",
|
|
4
4
|
"scope": "vue,html",
|
|
5
5
|
"body": [
|
|
6
|
-
"<
|
|
6
|
+
"<InputText",
|
|
7
7
|
" id=\"$1fieldId\"",
|
|
8
|
-
"
|
|
9
|
-
"
|
|
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
|
|
16
|
-
"description": "
|
|
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
|
-
"<
|
|
19
|
+
"<InputText",
|
|
20
20
|
" id=\"$1appointment-date\"",
|
|
21
|
-
"
|
|
22
|
-
"
|
|
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
|
|
30
|
-
"description": "
|
|
29
|
+
"SRCDEV InputTextField Basic": {
|
|
30
|
+
"description": "InputTextField: labelled text field with description and error support",
|
|
31
31
|
"scope": "vue,html",
|
|
32
32
|
"body": [
|
|
33
|
-
"<
|
|
33
|
+
"<InputTextField",
|
|
34
34
|
" v-model=\"$1fieldValue\"",
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
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
|
|
45
|
-
"description": "
|
|
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
|
-
"<
|
|
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
|
|
62
|
-
"description": "
|
|
62
|
+
"SRCDEV InputPasswordField": {
|
|
63
|
+
"description": "InputPasswordField with show/hide toggle",
|
|
63
64
|
"scope": "vue,html",
|
|
64
65
|
"body": [
|
|
65
|
-
"<
|
|
66
|
+
"<InputPasswordField",
|
|
66
67
|
" v-model=\"$1password\"",
|
|
67
68
|
" name=\"$2password\"",
|
|
68
69
|
" label=\"$3Password\"",
|
|
69
|
-
"
|
|
70
|
-
" :
|
|
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
|
|
75
|
-
"description": "
|
|
78
|
+
"SRCDEV InputTextAsNumberField": {
|
|
79
|
+
"description": "InputTextAsNumberField numeric stepper with min/max/step",
|
|
76
80
|
"scope": "vue,html",
|
|
77
81
|
"body": [
|
|
78
|
-
"<
|
|
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
|
|
89
|
-
" <template #right
|
|
90
|
-
"</
|
|
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
|
|
98
|
+
"description": "CSS override scaffold for InputText tokens",
|
|
95
99
|
"scope": "css",
|
|
96
100
|
"body": [
|
|
97
101
|
".$1my-page {",
|
|
98
|
-
"
|
|
99
|
-
"
|
|
100
|
-
"
|
|
101
|
-
"
|
|
102
|
-
"
|
|
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
|
|
3
|
-
"description": "Basic
|
|
2
|
+
"SRCDEV InputTextarea Basic": {
|
|
3
|
+
"description": "Basic InputTextarea native textarea (no label/error wrapper)",
|
|
4
4
|
"scope": "vue,html",
|
|
5
5
|
"body": [
|
|
6
|
-
"<
|
|
6
|
+
"<InputTextarea",
|
|
7
7
|
" id=\"$1fieldId\"",
|
|
8
|
-
"
|
|
9
|
-
"
|
|
8
|
+
" v-model=\"$2fieldValue\"",
|
|
9
|
+
" name=\"$3fieldName\"",
|
|
10
10
|
" placeholder=\"$4Placeholder text\"",
|
|
11
11
|
"/>"
|
|
12
12
|
]
|
|
13
13
|
},
|
|
14
|
-
"SRCDEV
|
|
15
|
-
"description": "
|
|
14
|
+
"SRCDEV InputTextareaField Basic": {
|
|
15
|
+
"description": "InputTextareaField: labelled textarea with description and error support",
|
|
16
16
|
"scope": "vue,html",
|
|
17
17
|
"body": [
|
|
18
|
-
"<
|
|
18
|
+
"<InputTextareaField",
|
|
19
19
|
" v-model=\"$1fieldValue\"",
|
|
20
20
|
" name=\"$2fieldName\"",
|
|
21
21
|
" label=\"$3Field label\"",
|
|
22
|
-
"
|
|
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
|
|
31
|
+
"description": "CSS override scaffold for InputTextarea tokens",
|
|
30
32
|
"scope": "css",
|
|
31
33
|
"body": [
|
|
32
34
|
".$1my-page {",
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
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
|
|
3
|
-
"description": "
|
|
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
|
-
"<
|
|
7
|
-
"
|
|
8
|
-
" id=\"$
|
|
9
|
-
"
|
|
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
|
|
14
|
-
"description": "
|
|
14
|
+
"SRCDEV ToggleSwitchField": {
|
|
15
|
+
"description": "ToggleSwitchField: labelled switch with description and error support",
|
|
15
16
|
"scope": "vue,html",
|
|
16
17
|
"body": [
|
|
17
|
-
"<
|
|
18
|
+
"<ToggleSwitchField",
|
|
18
19
|
" v-model=\"$1fieldValue\"",
|
|
19
20
|
" name=\"$2fieldName\"",
|
|
20
21
|
" label=\"$3Field label\"",
|
|
21
|
-
"
|
|
22
|
-
" :
|
|
22
|
+
" layout=\"${4|stacked,inline|}\"",
|
|
23
|
+
" :error-message=\"$5errors.fieldName\"",
|
|
24
|
+
" :field-has-error=\"!!$5errors.fieldName\"",
|
|
23
25
|
">",
|
|
24
|
-
" <template #descriptionText>$
|
|
25
|
-
"</
|
|
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
|
|
31
|
+
"description": "CSS override scaffold for ToggleSwitch tokens",
|
|
41
32
|
"scope": "css",
|
|
42
33
|
"body": [
|
|
43
34
|
".$1my-page {",
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
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(--
|
|
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(--
|
|
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 (
|
|
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
|
-
- `
|
|
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
|
-
<
|
|
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
|
|
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,
|
|
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
|
-
<
|
|
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
|
-
></
|
|
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
|
|
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,
|
|
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
|
-
<
|
|
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
|
-
<
|
|
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 (`
|
|
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
|
-
`
|
|
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
|
-
<
|
|
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
|
|
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,
|
|
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
|
-
<
|
|
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="`${
|
|
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
|
}
|