srcdev-nuxt-components 9.6.8 → 9.6.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 (109) hide show
  1. package/.claude/skills/component-compliance-checklist.md +28 -1
  2. package/.claude/skills/component-inline-action-button.md +1 -1
  3. package/.claude/skills/component-local-style-override.md +1 -1
  4. package/.claude/skills/component-naming.md +17 -12
  5. package/.claude/skills/components/container-glow.md +2 -2
  6. package/.claude/skills/components/form-field.md +2 -2
  7. package/.claude/skills/components/form-wrapper.md +1 -1
  8. package/.claude/skills/components/glowing-border.md +1 -1
  9. package/.claude/skills/components/input-description.md +7 -7
  10. package/.claude/skills/components/input-error.md +3 -3
  11. package/.claude/skills/components/input-label.md +7 -8
  12. package/.claude/skills/components/input-number.md +17 -17
  13. package/.claude/skills/components/input-select.md +153 -0
  14. package/.claude/skills/components/input-text.md +220 -0
  15. package/.claude/skills/components/input-textarea.md +147 -0
  16. package/.claude/skills/components/select-menu.md +4 -4
  17. package/.claude/skills/components/toggle-switch.md +143 -0
  18. package/.claude/skills/composable-zod-validation.md +1 -1
  19. package/.claude/skills/css-nesting-conventions.md +22 -1
  20. package/.claude/skills/icon-sets.md +1 -1
  21. package/.claude/skills/icon-sizing.md +1 -1
  22. package/.claude/skills/index.md +5 -5
  23. package/.claude/skills/storybook-add-story.md +1 -1
  24. package/.claude/skills/theming-component-token-pattern.md +8 -8
  25. package/.claude/skills/theming-form-geometry-tokens.md +1 -1
  26. package/.vscode/srcdev-component-input-select.code-snippets +20 -14
  27. package/.vscode/srcdev-component-input-text.code-snippets +46 -40
  28. package/.vscode/srcdev-component-input-textarea.code-snippets +19 -14
  29. package/.vscode/srcdev-component-toggle-switch.code-snippets +19 -29
  30. package/app/assets/styles/setup/04.elements/forms/00.element-defaults.css +2 -2
  31. package/app/assets/styles/setup/04.elements/forms/06.button-geometry.css +1 -1
  32. package/app/components/01.atoms/animations/glowing-border/CONSUMER-STYLING.md +2 -2
  33. package/app/components/01.atoms/animations/glowing-border/stories/GlowingBorder.stories.ts +4 -4
  34. package/app/components/02.molecules/progress-tracker/stories/ProgressTracker.stories.ts +4 -4
  35. package/app/components/05.forms/form-errors/CONSUMER-STYLING.md +1 -1
  36. package/app/components/05.forms/form-field/CONSUMER-STYLING.md +2 -2
  37. package/app/components/05.forms/input-button/stories/InputButton.stories.ts +3 -3
  38. package/app/components/05.forms/input-description/CONSUMER-STYLING.md +6 -6
  39. package/app/components/05.forms/input-label/CONSUMER-STYLING.md +7 -7
  40. package/app/components/05.forms/input-number/CONSUMER-STYLING.md +9 -5
  41. package/app/components/05.forms/input-number/InputNumber.vue +2 -2
  42. package/app/components/05.forms/input-select/CONSUMER-STYLING.md +80 -10
  43. package/app/components/05.forms/input-select/InputSelect.vue +198 -0
  44. package/app/components/05.forms/input-select/InputSelectField.vue +130 -0
  45. package/app/components/05.forms/input-select/stories/InputSelect.stories.ts +184 -0
  46. package/app/components/05.forms/input-select/stories/InputSelectField.stories.ts +187 -0
  47. package/app/components/05.forms/input-select/tests/{InputSelectCore.spec.ts → InputSelect.spec.ts} +75 -12
  48. package/app/components/05.forms/input-select/tests/InputSelectField.spec.ts +121 -0
  49. package/app/components/05.forms/input-text/CONSUMER-STYLING.md +85 -15
  50. package/app/components/05.forms/input-text/{InputPasswordWithLabel.vue → InputPasswordField.vue} +16 -19
  51. package/app/components/05.forms/input-text/{InputTextCore.vue → InputText.vue} +42 -78
  52. package/app/components/05.forms/input-text/{InputTextAsNumberWithLabel.vue → InputTextAsNumberField.vue} +66 -62
  53. package/app/components/05.forms/input-text/InputTextField.vue +168 -0
  54. package/app/components/05.forms/input-text/stories/InputPasswordField.stories.ts +163 -0
  55. package/app/components/05.forms/input-text/stories/InputText.stories.ts +194 -0
  56. package/app/components/05.forms/input-text/stories/InputTextAsNumberField.stories.ts +182 -0
  57. package/app/components/05.forms/input-text/stories/InputTextField.stories.ts +206 -0
  58. package/app/components/05.forms/input-text/tests/{InputPasswordWithLabel.spec.ts → InputPasswordField.spec.ts} +42 -3
  59. package/app/components/05.forms/input-text/tests/InputText.spec.ts +166 -0
  60. package/app/components/05.forms/input-text/tests/InputTextAsNumberField.spec.ts +135 -0
  61. package/app/components/05.forms/input-text/tests/InputTextField.spec.ts +130 -0
  62. package/app/components/05.forms/input-textarea/CONSUMER-STYLING.md +94 -12
  63. package/app/components/05.forms/input-textarea/InputTextarea.vue +165 -0
  64. package/app/components/05.forms/input-textarea/InputTextareaField.vue +159 -0
  65. package/app/components/05.forms/input-textarea/stories/InputTextarea.stories.ts +198 -0
  66. package/app/components/05.forms/input-textarea/stories/InputTextareaField.stories.ts +161 -0
  67. package/app/components/05.forms/input-textarea/tests/InputTextarea.spec.ts +149 -0
  68. package/app/components/05.forms/input-textarea/tests/InputTextareaField.spec.ts +122 -0
  69. package/app/components/05.forms/patterns/stories/ContactForm.stories.ts +13 -13
  70. package/app/components/05.forms/patterns/stories/LoginForm.stories.ts +6 -6
  71. package/app/components/05.forms/patterns/stories/MigratedFieldsForm.stories.ts +30 -32
  72. package/app/components/05.forms/toggle-switch/CONSUMER-STYLING.md +71 -50
  73. package/app/components/05.forms/toggle-switch/{ToggleSwitchCore.vue → ToggleSwitch.vue} +58 -73
  74. package/app/components/05.forms/toggle-switch/{ToggleSwitchWithLabel.vue → ToggleSwitchField.vue} +65 -19
  75. package/app/components/05.forms/toggle-switch/stories/ToggleSwitch.stories.ts +148 -0
  76. package/app/components/05.forms/toggle-switch/stories/ToggleSwitchField.stories.ts +176 -0
  77. package/app/components/05.forms/toggle-switch/tests/ToggleSwitch.spec.ts +145 -0
  78. package/app/components/05.forms/toggle-switch/tests/ToggleSwitchField.spec.ts +155 -0
  79. package/package.json +1 -1
  80. package/.claude/skills/components/input-select-core.md +0 -151
  81. package/.claude/skills/components/input-text-core.md +0 -204
  82. package/.claude/skills/components/input-textarea-core.md +0 -154
  83. package/.claude/skills/components/toggle-switch-core.md +0 -169
  84. package/app/components/05.forms/input-select/InputSelectCore.vue +0 -188
  85. package/app/components/05.forms/input-select/InputSelectWithLabel.vue +0 -118
  86. package/app/components/05.forms/input-select/stories/InputSelectCore.stories.ts +0 -69
  87. package/app/components/05.forms/input-select/stories/InputSelectWithLabel.stories.ts +0 -115
  88. package/app/components/05.forms/input-select/tests/InputSelectWithLabel.spec.ts +0 -87
  89. package/app/components/05.forms/input-text/InputTextWithLabel.vue +0 -154
  90. package/app/components/05.forms/input-text/stories/InputPasswordWithLabel.stories.ts +0 -368
  91. package/app/components/05.forms/input-text/stories/InputTextAsNumberWithLabel.stories.ts +0 -480
  92. package/app/components/05.forms/input-text/stories/InputTextCore.stories.ts +0 -267
  93. package/app/components/05.forms/input-text/stories/InputTextWithLabel.stories.ts +0 -319
  94. package/app/components/05.forms/input-text/tests/InputTextAsNumberWithLabel.spec.ts +0 -75
  95. package/app/components/05.forms/input-text/tests/InputTextCore.spec.ts +0 -60
  96. package/app/components/05.forms/input-text/tests/InputTextWithLabel.spec.ts +0 -71
  97. package/app/components/05.forms/input-textarea/InputTextareaCore.vue +0 -159
  98. package/app/components/05.forms/input-textarea/InputTextareaWithLabel.vue +0 -136
  99. package/app/components/05.forms/input-textarea/stories/InputTextareaCore.stories.ts +0 -247
  100. package/app/components/05.forms/input-textarea/stories/InputTextareaWithLabel.stories.ts +0 -458
  101. package/app/components/05.forms/input-textarea/tests/InputTextareaCore.spec.ts +0 -119
  102. package/app/components/05.forms/input-textarea/tests/InputTextareaWithLabel.spec.ts +0 -93
  103. package/app/components/05.forms/toggle-switch/ToggleSwitchWithLabelInline.vue +0 -81
  104. package/app/components/05.forms/toggle-switch/stories/ToggleSwitchCore.stories.ts +0 -251
  105. package/app/components/05.forms/toggle-switch/stories/ToggleSwitchWithLabel.stories.ts +0 -251
  106. package/app/components/05.forms/toggle-switch/stories/ToggleSwitchWithLabelInline.stories.ts +0 -283
  107. package/app/components/05.forms/toggle-switch/tests/ToggleSwitchCore.spec.ts +0 -101
  108. package/app/components/05.forms/toggle-switch/tests/ToggleSwitchWithLabel.spec.ts +0 -133
  109. package/app/components/05.forms/toggle-switch/tests/ToggleSwitchWithLabelInline.spec.ts +0 -66
@@ -1,154 +0,0 @@
1
- <template>
2
- <div>
3
- <div
4
- class="input-text-with-label"
5
- :data-theme="theme"
6
- :data-invalid="fieldHasError ? '' : null"
7
- :class="[elementClasses, inputVariant, { dirty: isDirty }, { active: isActive }]"
8
- >
9
- <InputLabel
10
- :id
11
- :required
12
- :input-variant
13
- :field-has-error
14
- :style-class-passthrough="['input-text-label']"
15
- >
16
- <template #textLabel>{{ label }}</template>
17
- </InputLabel>
18
-
19
- <InputDescription
20
- v-if="inputVariant !== 'outlined'"
21
- :description-id
22
- :input-variant
23
- :field-has-error="fieldHasError"
24
- :style-class-passthrough="['input-text-description']"
25
- >
26
- <template v-if="slots.descriptionHtml" #descriptionHtml>
27
- <slot name="descriptionHtml"></slot>
28
- </template>
29
- <template v-if="slots.descriptionText" #descriptionText>
30
- <slot name="descriptionText"></slot>
31
- </template>
32
- </InputDescription>
33
-
34
- <InputTextCore
35
- :id
36
- v-model="modelValue"
37
- v-model:is-dirty="isDirty"
38
- v-model:is-active="isActive"
39
- :type
40
- :inputmode
41
- :maxlength
42
- :min
43
- :max
44
- :name
45
- :placeholder
46
- :label
47
- :error-message
48
- :field-has-error
49
- :required
50
- :style-class-passthrough
51
- :theme
52
- :aria-describedby="ariaDescribedby()"
53
- :input-variant
54
- >
55
- <template v-if="slots.left" #left>
56
- <slot name="left"></slot>
57
- </template>
58
- <template v-if="slots.right" #right>
59
- <slot name="right"></slot>
60
- </template>
61
- </InputTextCore>
62
-
63
- <InputError :id="errorId" :error-message :show-error="fieldHasError" :is-detached="false" :input-variant />
64
- </div>
65
-
66
- <InputDescription
67
- v-if="inputVariant === 'outlined'"
68
- :description-id
69
- :input-variant
70
- :field-has-error="fieldHasError"
71
- :style-class-passthrough="['input-text-description']"
72
- >
73
- <template v-if="slots.descriptionHtml" #descriptionHtml>
74
- <slot name="descriptionHtml"></slot>
75
- </template>
76
- <template v-if="slots.descriptionText" #descriptionText>
77
- <slot name="descriptionText"></slot>
78
- </template>
79
- </InputDescription>
80
- </div>
81
- </template>
82
-
83
- <script setup lang="ts">
84
- import type { InputTypesText, FormUiTheme, InputUiVariant, InputMode } from "~/types/forms/types.forms";
85
-
86
- interface Props {
87
- maxlength?: number;
88
- /** Passed straight through to the native input — meaningful for type="date"/"number" etc. */
89
- min?: string | number;
90
- /** Passed straight through to the native input — meaningful for type="date"/"number" etc. */
91
- max?: string | number;
92
- type: InputTypesText;
93
- inputmode?: InputMode;
94
- name: string;
95
- placeholder?: string;
96
- label: string;
97
- errorMessage: object | string;
98
- fieldHasError?: boolean;
99
- required?: boolean;
100
- styleClassPassthrough?: string | string[];
101
- theme?: FormUiTheme;
102
- inputVariant?: InputUiVariant;
103
- }
104
-
105
- const props = withDefaults(defineProps<Props>(), {
106
- maxlength: 255,
107
- min: undefined,
108
- max: undefined,
109
- inputmode: "text",
110
- placeholder: "",
111
- fieldHasError: false,
112
- required: false,
113
- styleClassPassthrough: () => [],
114
- theme: "default",
115
- inputVariant: "normal",
116
- });
117
-
118
- const slots = useSlots();
119
-
120
- const FormUiTheme = computed(() => {
121
- return props.fieldHasError ? "error" : props.theme;
122
- });
123
-
124
- const { id, errorId, descriptionId, ariaDescribedby } = useAriaDescribedById(
125
- props.name,
126
- toRef(props, "fieldHasError"),
127
- slots
128
- );
129
-
130
- const modelValue = defineModel<string>({ required: true });
131
- const isActive = ref<boolean>(false);
132
- const isDirty = ref<boolean>(false);
133
-
134
- const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
135
-
136
- const testDirty = () => {
137
- const watchValue = modelValue.value ?? "";
138
-
139
- if (!isDirty.value && typeof watchValue === "string" && watchValue.length > 0) {
140
- isDirty.value = true;
141
- }
142
- };
143
-
144
- onMounted(() => {
145
- testDirty();
146
- });
147
-
148
- watch(
149
- () => modelValue.value,
150
- () => {
151
- testDirty();
152
- }
153
- );
154
- </script>
@@ -1,368 +0,0 @@
1
- import type { Meta, StoryFn } from "@nuxtjs/storybook";
2
- import { computed } from "vue";
3
- import StorybookComponent from "../InputPasswordWithLabel.vue";
4
- import type { FormUiTheme, InputUiVariant } from "~/types/forms/types.forms.d";
5
-
6
- interface InputPasswordWithLabelStoryArgs {
7
- modelValue: string;
8
- maxlength: number;
9
- name: string;
10
- placeholder: string;
11
- label: string;
12
- errorMessage: string;
13
- fieldHasError: boolean;
14
- required: boolean;
15
- theme: FormUiTheme;
16
- inputVariant: InputUiVariant;
17
- styleClassPassthrough: string[];
18
- useDescriptionSlot: boolean;
19
- useDescriptionHtmlSlot: boolean;
20
- descriptionContent: string;
21
- descriptionHtmlContent: string;
22
- showPasswordText: string;
23
- hidePasswordText: string;
24
- }
25
-
26
- export default {
27
- title: "Components/Forms/Input Text/InputPasswordWithLabel",
28
- component: StorybookComponent,
29
- argTypes: {
30
- // Model
31
- modelValue: {
32
- control: "text",
33
- description: "The password value",
34
- table: {
35
- category: "Model",
36
- },
37
- },
38
-
39
- // Basic Configuration
40
- maxlength: {
41
- control: { type: "number", min: 1, max: 1000 },
42
- description: "Maximum length of password",
43
- table: {
44
- category: "Basic",
45
- },
46
- },
47
- name: {
48
- control: "text",
49
- description: "Input name attribute",
50
- table: {
51
- category: "Basic",
52
- },
53
- },
54
- placeholder: {
55
- control: "text",
56
- description: "Placeholder text",
57
- table: {
58
- category: "Basic",
59
- },
60
- },
61
- label: {
62
- control: "text",
63
- description: "Input label",
64
- table: {
65
- category: "Basic",
66
- },
67
- },
68
-
69
- // Validation
70
- errorMessage: {
71
- control: "text",
72
- description: "Error message to display",
73
- table: {
74
- category: "Validation",
75
- },
76
- },
77
- fieldHasError: {
78
- control: "boolean",
79
- description: "Whether field has validation error",
80
- table: {
81
- category: "Validation",
82
- },
83
- },
84
- required: {
85
- control: "boolean",
86
- description: "Whether field is required",
87
- table: {
88
- category: "Validation",
89
- },
90
- },
91
-
92
- // Styling
93
- theme: {
94
- control: { type: "select" },
95
- options: ["primary", "secondary", "tertiary", "ghost", "error", "success", "warning"],
96
- description: "Theme for styling",
97
- table: {
98
- category: "Styling",
99
- },
100
- },
101
- inputVariant: {
102
- control: { type: "select" },
103
- options: ["normal", "outlined", "underlined"],
104
- description: "Input variant style",
105
- table: {
106
- category: "Styling",
107
- },
108
- },
109
- styleClassPassthrough: {
110
- control: "object",
111
- description: "Additional CSS classes",
112
- table: {
113
- category: "Styling",
114
- },
115
- },
116
-
117
- // Slots
118
- useDescriptionSlot: {
119
- control: "boolean",
120
- description: "Use description slot",
121
- table: {
122
- category: "Slots",
123
- },
124
- },
125
- useDescriptionHtmlSlot: {
126
- control: "boolean",
127
- description: "Use description HTML slot",
128
- table: {
129
- category: "Slots",
130
- },
131
- },
132
- descriptionContent: {
133
- control: "text",
134
- description: "Content for description slot",
135
- table: {
136
- category: "Slots",
137
- },
138
- },
139
- descriptionHtmlContent: {
140
- control: "text",
141
- description: "HTML content for description slot",
142
- table: {
143
- category: "Slots",
144
- },
145
- },
146
-
147
- // Localisation
148
- showPasswordText: {
149
- control: "text",
150
- description: "Accessible name for the toggle button while the password is hidden",
151
- table: {
152
- category: "Localisation",
153
- },
154
- },
155
- hidePasswordText: {
156
- control: "text",
157
- description: "Accessible name for the toggle button while the password is visible",
158
- table: {
159
- category: "Localisation",
160
- },
161
- },
162
- },
163
- args: {
164
- modelValue: "",
165
- maxlength: 255,
166
- name: "password-input",
167
- placeholder: "Enter your password...",
168
- label: "Password",
169
- errorMessage: "",
170
- fieldHasError: false,
171
- required: false,
172
- theme: "default",
173
- inputVariant: "normal",
174
- styleClassPassthrough: [],
175
- useDescriptionSlot: false,
176
- useDescriptionHtmlSlot: false,
177
- descriptionContent: "Password should be at least 8 characters long",
178
- descriptionHtmlContent:
179
- "Password must contain: <strong>8+ characters</strong>, <em>uppercase</em>, <em>lowercase</em>, <em>numbers</em>",
180
- showPasswordText: "Show password",
181
- hidePasswordText: "Hide password",
182
- },
183
- } as Meta<typeof StorybookComponent>;
184
-
185
- // `args` is Storybook's own reactive object — bind to it directly (`args.x`) rather than
186
- // destructuring it into local variables/refs, which would snapshot the values once at setup()
187
- // and stop reflecting later Controls-panel changes. `componentArgs` strips the non-prop
188
- // slot-toggle args so they don't leak onto the component as unknown attributes.
189
- const Template: StoryFn<InputPasswordWithLabelStoryArgs> = (args) => ({
190
- components: { StorybookComponent },
191
- setup() {
192
- const componentArgs = computed(() => {
193
- const { useDescriptionSlot, useDescriptionHtmlSlot, descriptionContent, descriptionHtmlContent, ...rest } = args;
194
- return rest;
195
- });
196
-
197
- return { args, componentArgs };
198
- },
199
- template: `
200
- <StorybookComponent
201
- v-model="args.modelValue"
202
- v-bind="componentArgs"
203
- >
204
- <template v-if="args.useDescriptionSlot" #description>{{ args.descriptionContent }}</template>
205
- <template v-if="args.useDescriptionHtmlSlot" #descriptionHtml v-html="args.descriptionHtmlContent"></template>
206
- </StorybookComponent>
207
- <div class="mt-4 text-sm text-gray-600">
208
- Current value: {{ args.modelValue ? '•'.repeat(args.modelValue.length) : 'Empty' }}
209
- </div>
210
- `,
211
- });
212
-
213
- export const Default = Template.bind({});
214
- Default.args = {};
215
-
216
- export const WithDescription = Template.bind({});
217
- WithDescription.args = {
218
- useDescriptionSlot: true,
219
- label: "Account Password",
220
- placeholder: "Create a secure password",
221
- };
222
-
223
- export const WithHtmlDescription = Template.bind({});
224
- WithHtmlDescription.args = {
225
- useDescriptionHtmlSlot: true,
226
- label: "New Password",
227
- placeholder: "Enter new password",
228
- };
229
-
230
- export const Required = Template.bind({});
231
- Required.args = {
232
- required: true,
233
- label: "Login Password",
234
- placeholder: "Enter your password",
235
- useDescriptionSlot: true,
236
- descriptionContent: "This field is required for login",
237
- };
238
-
239
- export const WithError = Template.bind({});
240
- WithError.args = {
241
- fieldHasError: true,
242
- errorMessage: "Password must be at least 8 characters long",
243
- theme: "error",
244
- label: "Password",
245
- placeholder: "Enter password",
246
- modelValue: "123", // Short password to show error
247
- };
248
-
249
- export const PasswordTooShort = Template.bind({});
250
- PasswordTooShort.args = {
251
- fieldHasError: true,
252
- errorMessage: "Password is too weak",
253
- theme: "error",
254
- label: "Strong Password",
255
- placeholder: "Enter a strong password",
256
- modelValue: "weak",
257
- useDescriptionHtmlSlot: true,
258
- };
259
-
260
- export const Outlined = Template.bind({});
261
- Outlined.args = {
262
- inputVariant: "outlined",
263
- label: "Confirm Password",
264
- placeholder: "Confirm your password",
265
- };
266
-
267
- export const Underlined = Template.bind({});
268
- Underlined.args = {
269
- inputVariant: "underlined",
270
- label: "Master Password",
271
- placeholder: "Enter master password",
272
- };
273
-
274
- export const LocalisedToggleText = Template.bind({});
275
- LocalisedToggleText.storyName = "Localised Toggle Text";
276
- LocalisedToggleText.args = {
277
- label: "Mot de passe",
278
- placeholder: "Saisissez votre mot de passe",
279
- showPasswordText: "Afficher le mot de passe",
280
- hidePasswordText: "Masquer le mot de passe",
281
- };
282
-
283
- export const AllVariants = Template.bind({});
284
- AllVariants.storyName = "All Input Variants";
285
- AllVariants.render = (args) => ({
286
- components: { StorybookComponent },
287
- setup() {
288
- const variants: InputUiVariant[] = ["normal", "outlined", "underlined"];
289
- const passwordValues = reactive(
290
- variants.reduce(
291
- (acc, variant) => ({
292
- ...acc,
293
- [variant]: "",
294
- }),
295
- {} as Record<string, string>
296
- )
297
- );
298
-
299
- return {
300
- variants,
301
- passwordValues,
302
- args,
303
- };
304
- },
305
- template: `
306
- <div class="space-y-6">
307
- <div v-for="variant in variants" :key="variant" class="space-y-2">
308
- <h3 class="text-lg font-semibold capitalize">{{ variant }} Variant</h3>
309
- <StorybookComponent
310
- v-model="passwordValues[variant]"
311
- v-bind="{ ...args, inputVariant: variant, label: variant + ' Password', name: variant + '-password' }"
312
- />
313
- </div>
314
- </div>
315
- `,
316
- });
317
-
318
- export const SecurityFeatures = Template.bind({});
319
- SecurityFeatures.storyName = "Password Security Demo";
320
- SecurityFeatures.render = (args) => ({
321
- components: { StorybookComponent },
322
- setup() {
323
- const passwords = reactive({
324
- weak: "123",
325
- medium: "password123",
326
- strong: "MyStr0ng!Pass",
327
- });
328
-
329
- const getStrengthColor = (password: string) => {
330
- if (password.length < 6) return "error";
331
- if (password.length < 10) return "warning";
332
- return "success";
333
- };
334
-
335
- return {
336
- passwords,
337
- getStrengthColor,
338
- args,
339
- };
340
- },
341
- template: `
342
- <div class="space-y-6">
343
- <div class="space-y-2">
344
- <h3 class="text-lg font-semibold">Weak Password (Error State)</h3>
345
- <StorybookComponent
346
- v-model="passwords.weak"
347
- v-bind="{ ...args, theme: getStrengthColor(passwords.weak), fieldHasError: passwords.weak.length < 6, errorMessage: 'Password too short', label: 'Weak Password', name: 'weak-password' }"
348
- />
349
- </div>
350
-
351
- <div class="space-y-2">
352
- <h3 class="text-lg font-semibold">Medium Password (Warning State)</h3>
353
- <StorybookComponent
354
- v-model="passwords.medium"
355
- v-bind="{ ...args, theme: getStrengthColor(passwords.medium), label: 'Medium Password', name: 'medium-password' }"
356
- />
357
- </div>
358
-
359
- <div class="space-y-2">
360
- <h3 class="text-lg font-semibold">Strong Password (Success State)</h3>
361
- <StorybookComponent
362
- v-model="passwords.strong"
363
- v-bind="{ ...args, theme: getStrengthColor(passwords.strong), label: 'Strong Password', name: 'strong-password' }"
364
- />
365
- </div>
366
- </div>
367
- `,
368
- });