srcdev-nuxt-forms 5.1.0 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/README.md +16 -0
  2. package/app/assets/styles/extends-layer/srcdev-forms/components/_form-fieldset.css +38 -0
  3. package/app/assets/styles/extends-layer/srcdev-forms/components/_input-button.css +66 -0
  4. package/app/assets/styles/extends-layer/srcdev-forms/components/_input-checkbox-radio-core.css +66 -0
  5. package/app/assets/styles/extends-layer/srcdev-forms/components/_input-checkbox-radio-options-button.css +76 -0
  6. package/app/assets/styles/extends-layer/srcdev-forms/components/_input-error.css +54 -0
  7. package/app/assets/styles/extends-layer/srcdev-forms/components/_input-label.css +21 -0
  8. package/app/assets/styles/extends-layer/srcdev-forms/components/_input-select.css +140 -0
  9. package/app/assets/styles/extends-layer/srcdev-forms/components/_input-text.css +190 -0
  10. package/app/assets/styles/extends-layer/srcdev-forms/components/_input-textarea.css +96 -0
  11. package/{assets → app/assets}/styles/extends-layer/srcdev-forms/components/index.css +3 -4
  12. package/app/assets/styles/extends-layer/srcdev-forms/setup/_generic.css +21 -0
  13. package/app/assets/styles/extends-layer/srcdev-forms/setup/index.css +4 -0
  14. package/{assets → app/assets}/styles/extends-layer/srcdev-forms/setup/themes/_error.css +12 -12
  15. package/{assets → app/assets}/styles/extends-layer/srcdev-forms/setup/themes/_ghost.css +12 -12
  16. package/{assets → app/assets}/styles/extends-layer/srcdev-forms/setup/themes/_input-action-underlined.css +7 -7
  17. package/{assets → app/assets}/styles/extends-layer/srcdev-forms/setup/themes/_input-action.css +7 -7
  18. package/{assets → app/assets}/styles/extends-layer/srcdev-forms/setup/themes/_primary.css +12 -12
  19. package/{assets → app/assets}/styles/extends-layer/srcdev-forms/setup/themes/_secondary.css +12 -12
  20. package/{assets → app/assets}/styles/extends-layer/srcdev-forms/setup/themes/_success.css +12 -12
  21. package/{assets → app/assets}/styles/extends-layer/srcdev-forms/setup/themes/_tertiary.css +12 -12
  22. package/{assets → app/assets}/styles/extends-layer/srcdev-forms/setup/themes/_warning.css +12 -12
  23. package/app/assets/styles/extends-layer/srcdev-forms/setup/variables/_a11y.css +7 -0
  24. package/app/assets/styles/extends-layer/srcdev-forms/setup/variables/index.css +1 -0
  25. package/app/assets/styles/extends-layer/srcdev-forms/setup/variants/_normal.css +48 -0
  26. package/{assets → app/assets}/styles/extends-layer/srcdev-forms/setup/variants/_underlined.css +12 -12
  27. package/app/assets/styles/extends-layer/srcdev-forms/setup/variants/index.css +3 -0
  28. package/app/assets/styles/extends-layer/srcdev-forms/setup/variants/sizes/_default.css +13 -0
  29. package/app/assets/styles/extends-layer/srcdev-forms/setup/variants/sizes/_large.css +12 -0
  30. package/app/assets/styles/extends-layer/srcdev-forms/setup/variants/sizes/_medium.css +12 -0
  31. package/app/assets/styles/extends-layer/srcdev-forms/setup/variants/sizes/_small.css +12 -0
  32. package/app/assets/styles/extends-layer/srcdev-forms/setup/variants/sizes/_x-small.css +11 -0
  33. package/{assets/styles/extends-layer/srcdev-forms/setup → app/assets/styles/extends-layer/srcdev-forms/setup/variants}/sizes/index.css +2 -0
  34. package/app/assets/styles/setup/_head.css +36 -0
  35. package/app/assets/styles/setup/index.css +5 -0
  36. package/{assets/styles/setup/variables → app/assets/styles/setup/theming}/colors/_blue.css +1 -1
  37. package/{assets/styles/setup/variables → app/assets/styles/setup/theming}/index.css +1 -0
  38. package/app/assets/styles/setup/theming/themes/_default.css +66 -0
  39. package/app/assets/styles/setup/theming/themes/_error.css +66 -0
  40. package/app/assets/styles/setup/theming/themes/_ghost.css +31 -0
  41. package/app/assets/styles/setup/theming/themes/_info.css +31 -0
  42. package/app/assets/styles/setup/theming/themes/_primary.css +41 -0
  43. package/app/assets/styles/setup/theming/themes/_secondary.css +66 -0
  44. package/app/assets/styles/setup/theming/themes/_success.css +66 -0
  45. package/app/assets/styles/setup/theming/themes/_tertiary.css +31 -0
  46. package/app/assets/styles/setup/theming/themes/_warning.css +68 -0
  47. package/app/assets/styles/setup/theming/themes/index.css +9 -0
  48. package/app/assets/styles/setup/typography/index.css +2 -0
  49. package/app/assets/styles/setup/typography/utility-classes/_generic-font-classes.css +217 -0
  50. package/app/assets/styles/setup/typography/utility-classes/_generic-font-variation-settings.css +29 -0
  51. package/app/assets/styles/setup/typography/utility-classes/_generic-font-weights.css +39 -0
  52. package/app/assets/styles/setup/typography/vars/_colors.css +14 -0
  53. package/app/assets/styles/setup/typography/vars/_reponsive-font-sizes.css +12 -0
  54. package/{assets → app/assets}/styles/setup/typography/vars/index.css +1 -0
  55. package/app/assets/styles/setup/utility-classes/_fluid-spacing.css +13 -0
  56. package/app/assets/styles/setup/utility-classes/animations/_auto-rotate.css +13 -0
  57. package/app/assets/styles/setup/utility-classes/animations/_entry-exit-blur.css +16 -0
  58. package/app/assets/styles/setup/utility-classes/animations/_entry-slide-in.css +15 -0
  59. package/app/assets/styles/setup/utility-classes/animations/_entry-zoom-reveal.css +15 -0
  60. package/app/assets/styles/setup/utility-classes/animations/index.css +4 -0
  61. package/app/assets/styles/setup/utility-classes/index.css +2 -0
  62. package/app/assets/styles/setup/variables/index.css +1 -0
  63. package/{components → app/components}/forms/form-errors/InputError.vue +32 -49
  64. package/{components → app/components}/forms/form-fieldset/FormFieldset.vue +9 -9
  65. package/{components → app/components}/forms/input-button/InputButtonCore.vue +20 -18
  66. package/{components → app/components}/forms/input-button/variants/InputButtonConfirm.vue +1 -1
  67. package/app/components/forms/input-checkbox-radio/InputCheckboxRadioButton.vue +204 -0
  68. package/{components → app/components}/forms/input-checkbox-radio/InputCheckboxRadioCore.vue +29 -17
  69. package/{components → app/components}/forms/input-checkbox-radio/InputCheckboxRadioWithLabel.vue +1 -0
  70. package/{components → app/components}/forms/input-label/InputLabel.vue +26 -7
  71. package/{components → app/components}/forms/input-number/InputNumberCore.vue +7 -6
  72. package/{components → app/components}/forms/input-number/variants/InputNumberDefault.vue +5 -6
  73. package/{components → app/components}/forms/input-range/InputRangeCore.vue +1 -1
  74. package/{components → app/components}/forms/input-range/variants/InputRangeDefault.vue +5 -2
  75. package/{components → app/components}/forms/input-range-fancy/InputRangeFancyCore.vue +1 -1
  76. package/{components → app/components}/forms/input-range-fancy/InputRangeFancyWithLabel.vue +1 -1
  77. package/{components → app/components}/forms/input-select/InputSelectCore.vue +23 -21
  78. package/{components → app/components}/forms/input-select/variants/InputSelectWithLabel.vue +1 -1
  79. package/app/components/forms/input-text/InputTextCore.vue +341 -0
  80. package/{components → app/components}/forms/input-text/variants/InputPasswordWithLabel.vue +1 -1
  81. package/{components → app/components}/forms/input-text/variants/InputTextAsNumberWithLabel.vue +4 -2
  82. package/app/components/forms/input-text/variants/InputTextWithLabel.vue +158 -0
  83. package/{components → app/components}/forms/input-textarea/InputTextareaCore.vue +10 -131
  84. package/app/components/forms/input-textarea/variants/InputTextareaWithLabel.vue +125 -0
  85. package/{components → app/components}/forms/toggle-switch/ToggleSwitchCore.vue +1 -1
  86. package/{components → app/components}/forms/toggle-switch/ToggleSwitchCoreOld.vue +1 -1
  87. package/{components → app/components}/forms/toggle-switch/variants/ToggleSwitchWithLabel.vue +5 -2
  88. package/{components → app/components}/forms/toggle-switch/variants/ToggleSwitchWithLabelInline.vue +5 -2
  89. package/{components → app/components}/utils/colour-scheme-select/ColourSchemeSelect.vue +1 -1
  90. package/{components → app/components}/utils/colour-scheme-select/ColourSchemeSelectOld.vue +1 -1
  91. package/nuxt.config.ts +5 -2
  92. package/package.json +9 -11
  93. package/assets/styles/extends-layer/srcdev-forms/components/_form-core.css +0 -8
  94. package/assets/styles/extends-layer/srcdev-forms/components/_form-fieldset.css +0 -16
  95. package/assets/styles/extends-layer/srcdev-forms/components/_input-checkbox-radio-options-button.css +0 -59
  96. package/assets/styles/extends-layer/srcdev-forms/components/_input-checkbox.css +0 -72
  97. package/assets/styles/extends-layer/srcdev-forms/components/_input-error.css +0 -55
  98. package/assets/styles/extends-layer/srcdev-forms/components/_input-label.css +0 -18
  99. package/assets/styles/extends-layer/srcdev-forms/components/_input-radio.css +0 -68
  100. package/assets/styles/extends-layer/srcdev-forms/components/_input-select.css +0 -18
  101. package/assets/styles/extends-layer/srcdev-forms/components/_input-text-as-number.css +0 -22
  102. package/assets/styles/extends-layer/srcdev-forms/components/_input-textarea.css +0 -5
  103. package/assets/styles/extends-layer/srcdev-forms/setup/_generic.css +0 -7
  104. package/assets/styles/extends-layer/srcdev-forms/setup/index.css +0 -4
  105. package/assets/styles/extends-layer/srcdev-forms/setup/sizes/_default.css +0 -12
  106. package/assets/styles/extends-layer/srcdev-forms/setup/sizes/_large.css +0 -12
  107. package/assets/styles/extends-layer/srcdev-forms/setup/sizes/_medium.css +0 -12
  108. package/assets/styles/extends-layer/srcdev-forms/setup/sizes/_small.css +0 -12
  109. package/assets/styles/extends-layer/srcdev-forms/setup/sizes/_x-small.css +0 -11
  110. package/assets/styles/extends-layer/srcdev-forms/setup/variants/_normal.css +0 -48
  111. package/assets/styles/extends-layer/srcdev-forms/setup/variants/index.css +0 -2
  112. package/assets/styles/setup/_head.css +0 -5
  113. package/assets/styles/setup/index.css +0 -5
  114. package/assets/styles/setup/typography/index.css +0 -2
  115. package/assets/styles/setup/typography/utility-classes/_generic-font-classes.css +0 -192
  116. package/assets/styles/setup/typography/utility-classes/_generic-font-variation-settings.css +0 -29
  117. package/assets/styles/setup/typography/utility-classes/_generic-font-weights.css +0 -41
  118. package/assets/styles/setup/typography/vars/_reponsive-font-sizes.css +0 -10
  119. package/assets/styles/setup/utility-classes/_margin-helpers.css +0 -334
  120. package/assets/styles/setup/utility-classes/_padding-helpers.css +0 -308
  121. package/assets/styles/setup/utility-classes/_page.css +0 -49
  122. package/assets/styles/setup/utility-classes/index.css +0 -3
  123. package/components/forms/input-checkbox-radio/InputCheckboxRadioButton.vue +0 -218
  124. package/components/forms/input-text/InputTextCore.vue +0 -390
  125. package/components/forms/input-text/variants/InputTextWithLabel.vue +0 -300
  126. package/components/forms/input-textarea/variants/InputTextareaWithLabel.vue +0 -269
  127. package/{assets → app/assets}/styles/extends-layer/srcdev-forms/index.css +0 -0
  128. package/{assets → app/assets}/styles/extends-layer/srcdev-forms/setup/themes/index.css +0 -0
  129. package/{assets → app/assets}/styles/main.css +0 -0
  130. package/{assets → app/assets}/styles/setup/a11y/_utils.css +0 -0
  131. package/{assets → app/assets}/styles/setup/a11y/_variables.css +0 -0
  132. package/{assets → app/assets}/styles/setup/a11y/index.css +0 -0
  133. package/{assets/styles/setup/variables → app/assets/styles/setup/theming}/colors/_gray.css +0 -0
  134. package/{assets/styles/setup/variables → app/assets/styles/setup/theming}/colors/_green.css +0 -0
  135. package/{assets/styles/setup/variables → app/assets/styles/setup/theming}/colors/_orange.css +0 -0
  136. package/{assets/styles/setup/variables → app/assets/styles/setup/theming}/colors/_red.css +0 -0
  137. package/{assets/styles/setup/variables → app/assets/styles/setup/theming}/colors/_yellow.css +0 -0
  138. package/{assets/styles/setup/variables → app/assets/styles/setup/theming}/colors/index.css +3 -3
  139. package/{assets → app/assets}/styles/setup/typography/utility-classes/index.css +1 -1
  140. /package/{components → app/components}/forms/c12/prop-validators/index.ts +0 -0
  141. /package/{components → app/components}/forms/c12/utils.ts +0 -0
  142. /package/{components → app/components}/forms/form-errors/tests/InputError.spec.ts +0 -0
  143. /package/{components → app/components}/forms/input-button/variants/InputButtonSubmit.vue +0 -0
  144. /package/{components → app/components}/forms/input-checkbox/MultipleCheckboxes.vue +0 -0
  145. /package/{components → app/components}/forms/input-checkbox/SingleCheckbox.vue +0 -0
  146. /package/{components → app/components}/forms/input-checkbox/tests/MultipleCheckboxes.spec.ts +0 -0
  147. /package/{components → app/components}/forms/input-checkbox/tests/data/tags.json +0 -0
  148. /package/{components → app/components}/forms/input-radio/MultipleRadiobuttons.vue +0 -0
  149. /package/{components → app/components}/forms/input-radio/tests/MultipleRadioButtons.spec.ts +0 -0
  150. /package/{components → app/components}/forms/input-radio/tests/data/tags.json +0 -0
  151. /package/{components → app/components}/forms/ui/FormField.vue +0 -0
  152. /package/{components → app/components}/forms/ui/FormWrapper.vue +0 -0
  153. /package/{components → app/components}/utils/dark-mode-switcher/DarkModeSwitcher.vue +0 -0
  154. /package/{composables → app/composables}/useApiRequest.ts +0 -0
  155. /package/{composables → app/composables}/useColourScheme.ts +0 -0
  156. /package/{composables → app/composables}/useErrorMessages.ts +0 -0
  157. /package/{composables → app/composables}/useFormControl.ts +0 -0
  158. /package/{composables → app/composables}/useSleep.ts +0 -0
  159. /package/{composables → app/composables}/useStyleClassPassthrough.ts +0 -0
  160. /package/{composables → app/composables}/useZodValidation.ts +0 -0
  161. /package/{types → app/types}/types.forms.ts +0 -0
  162. /package/{types → app/types}/types.zodFormControl.ts +0 -0
@@ -0,0 +1,341 @@
1
+ <template>
2
+ <div
3
+ class="input-text-wrapper"
4
+ :data-theme="formTheme"
5
+ :data-size="size"
6
+ :data-inputmode="inputmode"
7
+ :class="[inputVariant, { dirty: isDirty }, { active: isActive }, { error: fieldHasError }, { 'has-left-slot': hasLeftSlot }, { 'has-right-slot': hasRightSlot }]"
8
+ >
9
+ <span v-if="hasLeftSlot" class="slot left-slot">
10
+ <slot name="left"></slot>
11
+ </span>
12
+
13
+ <input
14
+ :type
15
+ :placeholder
16
+ :id
17
+ :name
18
+ :required
19
+ :maxlength
20
+ :class="['input-text-core', elementClasses, { dirty: isDirty }, { active: isActive }]"
21
+ v-model="modelValue"
22
+ ref="inputField"
23
+ :aria-invalid="fieldHasError"
24
+ :aria-describedby
25
+ :pattern="inputPattern"
26
+ :inputmode
27
+ @focusin="updateFocus(true)"
28
+ @focusout="updateFocus(false)"
29
+ />
30
+
31
+ <span v-if="hasRightSlot" class="slot right-slot">
32
+ <slot name="right"></slot>
33
+ </span>
34
+ </div>
35
+ </template>
36
+
37
+ <script setup lang="ts">
38
+ import propValidators from '../c12/prop-validators';
39
+
40
+ const props = defineProps({
41
+ type: {
42
+ type: String as PropType<'text' | 'email' | 'password' | 'number' | 'tel' | 'url'>,
43
+ // type: String,
44
+ default: 'text',
45
+ validator(value: string) {
46
+ return propValidators.inputTypesText.includes(value);
47
+ },
48
+ },
49
+ inputmode: {
50
+ type: String as PropType<'text' | 'email' | 'tel' | 'url' | 'search' | 'numeric' | 'none' | 'decimal'>,
51
+ default: 'text',
52
+ validator(value: string) {
53
+ return propValidators.inputMode.includes(value);
54
+ },
55
+ },
56
+ maxlength: {
57
+ type: Number,
58
+ default: 255,
59
+ },
60
+ id: {
61
+ type: String,
62
+ required: true,
63
+ },
64
+ name: {
65
+ type: String,
66
+ required: true,
67
+ },
68
+ required: {
69
+ type: Boolean,
70
+ default: false,
71
+ },
72
+ placeholder: {
73
+ type: String,
74
+ default: '',
75
+ },
76
+ fieldHasError: {
77
+ type: Boolean,
78
+ default: false,
79
+ },
80
+ styleClassPassthrough: {
81
+ type: Array as PropType<string[]>,
82
+ default: () => [],
83
+ },
84
+ theme: {
85
+ type: String as PropType<string>,
86
+ default: 'primary',
87
+ validator(value: string) {
88
+ return propValidators.theme.includes(value);
89
+ },
90
+ },
91
+ ariaDescribedby: {
92
+ type: String,
93
+ default: null,
94
+ },
95
+ size: {
96
+ type: String as PropType<string>,
97
+ default: 'default',
98
+ validator(value: string) {
99
+ return propValidators.size.includes(value);
100
+ },
101
+ },
102
+ inputVariant: {
103
+ type: String as PropType<string>,
104
+ default: 'normal',
105
+ validator(value: string) {
106
+ return propValidators.inputVariant.includes(value);
107
+ },
108
+ },
109
+ });
110
+
111
+ const slots = useSlots();
112
+ const hasLeftSlot = computed(() => slots.left !== undefined);
113
+ const hasRightSlot = computed(() => slots.right !== undefined);
114
+
115
+ const formTheme = computed(() => {
116
+ return props.fieldHasError ? 'error' : props.theme;
117
+ });
118
+
119
+ const modelValue = defineModel();
120
+ const isDirty = defineModel('isDirty');
121
+ const isActive = defineModel('isActive');
122
+
123
+ const inputPattern = computed(() => {
124
+ return props.inputmode === 'numeric' ? '[0-9]+' : undefined;
125
+ });
126
+
127
+ const updateFocus = (isFocused: boolean) => {
128
+ isActive.value = isFocused;
129
+ };
130
+
131
+ const inputField = ref<HTMLInputElement | null>(null);
132
+
133
+ const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
134
+
135
+ // TODO: Move this to a utility function to allow removeEventListener on unmounted
136
+ // Leaving like this could lead to memory leaks
137
+ const validateInput = () => {
138
+ if (inputField.value !== null) {
139
+ inputField.value.addEventListener('beforeinput', (event: any) => {
140
+ let beforeValue = modelValue.value;
141
+ event.target.addEventListener(
142
+ 'input',
143
+ () => {
144
+ if (inputField.value !== null && inputField.value.validity.patternMismatch) {
145
+ inputField.value.value = beforeValue as string;
146
+ }
147
+ },
148
+ { once: true }
149
+ );
150
+ });
151
+ }
152
+ };
153
+
154
+ onMounted(() => {
155
+ if (props.inputmode === 'numeric') validateInput();
156
+ });
157
+ </script>
158
+
159
+ <style lang="css">
160
+ .input-text-wrapper {
161
+ display: flex;
162
+ align-items: center;
163
+ gap: 12px;
164
+ background-color: var(--theme-input-surface);
165
+
166
+ &:hover {
167
+ background-color: var(--theme-input-surface-hover);
168
+ }
169
+
170
+ &:focus-within {
171
+ background-color: var(--theme-input-surface-hover);
172
+ outline: var(--theme-focus-visible-outline);
173
+ box-shadow: var(--theme-focus-visible-shadow);
174
+ }
175
+
176
+ &.normal {
177
+ outline: var(--form-element-outline-width) solid var(--theme-input-outline);
178
+
179
+ border-top-left-radius: var(--form-input-border-radius);
180
+ border-top-right-radius: var(--form-input-border-radius);
181
+ border-bottom-left-radius: var(--form-input-border-radius);
182
+ border-bottom-right-radius: var(--form-input-border-radius);
183
+
184
+ border-top: var(--form-element-border-width) solid var(--theme-input-border);
185
+ border-right: var(--form-element-border-width) solid var(--theme-input-border);
186
+ border-bottom: var(--form-element-border-width) solid var(--theme-input-border);
187
+ border-left: var(--form-element-border-width) solid var(--theme-input-border);
188
+
189
+ padding-inline: 1rem;
190
+
191
+ &.error {
192
+ border-color: var(--theme-error-surface);
193
+ }
194
+
195
+ .slot {
196
+ display: flex;
197
+ place-items: center;
198
+ background-clip: padding-box;
199
+
200
+ &.left-slot:not([data-theme='input-action']) {
201
+ .icon {
202
+ width: 2.2rem;
203
+ height: 2.2rem;
204
+ }
205
+
206
+ [data-theme='input-action'] {
207
+ width: initial;
208
+ height: initial;
209
+ padding: 0.5rem;
210
+
211
+ .icon {
212
+ width: 1.8rem;
213
+ height: 1.8rem;
214
+ }
215
+ }
216
+ }
217
+ &.right-slot:not([data-theme='input-action']) {
218
+ .icon {
219
+ width: 2.2rem;
220
+ height: 2.2rem;
221
+ }
222
+
223
+ [data-theme='input-action'] {
224
+ width: initial;
225
+ height: initial;
226
+ padding: 0.5rem;
227
+
228
+ .icon {
229
+ width: 1.8rem;
230
+ height: 1.8rem;
231
+ }
232
+ }
233
+ }
234
+ }
235
+
236
+ &[data-inputmode='numeric'] {
237
+ padding-block: 0rem;
238
+ padding-inline: 0.75rem;
239
+
240
+ .slot {
241
+ [data-theme='input-action'] {
242
+ width: initial;
243
+ height: initial;
244
+ padding: 0.5rem;
245
+
246
+ .icon {
247
+ width: 1.8rem;
248
+ height: 1.8rem;
249
+ }
250
+ }
251
+ }
252
+ }
253
+ }
254
+
255
+ &.underlined {
256
+ margin-block-start: 0;
257
+ padding-block: 0;
258
+ padding-inline: 1rem;
259
+
260
+ border-radius: 0;
261
+
262
+ border-top: none;
263
+ border-right: none;
264
+ border-bottom: var(--form-element-border-width-underlined) solid var(--theme-input-border);
265
+ border-left: none;
266
+
267
+ overflow: hidden;
268
+
269
+ &.error {
270
+ border-bottom-right-radius: 0;
271
+ border-bottom-left-radius: 0;
272
+
273
+ border-top: var(--form-element-border-width) solid var(--theme-error-surface);
274
+ border-right: var(--form-element-border-width) solid var(--theme-error-surface);
275
+ border-bottom: var(--form-element-border-width) solid var(--theme-error-surface);
276
+ border-left: var(--form-element-border-width) solid var(--theme-error-surface);
277
+ }
278
+
279
+ .slot {
280
+ display: flex;
281
+ place-items: center;
282
+ background-clip: padding-box;
283
+
284
+ &.left-slot:not([data-theme='input-action-underlined']) {
285
+ .icon {
286
+ width: 2.2rem;
287
+ height: 2.2rem;
288
+ }
289
+
290
+ [data-theme='input-action-underlined'] {
291
+ width: initial;
292
+ height: initial;
293
+ padding: 0.5rem;
294
+
295
+ .icon {
296
+ width: 1.8rem;
297
+ height: 1.8rem;
298
+ }
299
+ }
300
+ }
301
+ &.right-slot:not([data-theme='input-action-underlined']) {
302
+ .icon {
303
+ width: 2.2rem;
304
+ height: 2.2rem;
305
+ }
306
+
307
+ [data-theme='input-action-underlined'] {
308
+ width: initial;
309
+ height: initial;
310
+ padding: 0.5rem;
311
+
312
+ .icon {
313
+ width: 1.8rem;
314
+ height: 1.8rem;
315
+ }
316
+ }
317
+ }
318
+ }
319
+ }
320
+
321
+ .input-text-core {
322
+ all: unset;
323
+ touch-action: manipulation;
324
+ flex-grow: 1;
325
+
326
+ font-family: var(--font-family);
327
+ font-size: var(--form-element-font-size);
328
+ line-height: var(--form-element-line-height);
329
+ padding-block: var(--input-element-padding-block);
330
+ padding-inline: 1rem;
331
+
332
+ &::placeholder {
333
+ color: var(--theme-input-placeholder);
334
+ font-size: var(--theme-input-placeholder-font-size);
335
+ font-style: italic;
336
+ line-height: 1;
337
+ font-weight: normal;
338
+ }
339
+ }
340
+ }
341
+ </style>
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <InputTextWithLabel
3
3
  v-model="modelValue"
4
- :data-form-theme="formTheme"
4
+ :data-theme="formTheme"
5
5
  :type="inputType"
6
6
  :maxlength
7
7
  :name
@@ -1,6 +1,8 @@
1
1
  <template>
2
- <div class="input-text-with-label" :data-form-theme="formTheme" :class="[inputVariant, elementClasses, { dirty: isDirty }, { active: isActive }]">
3
- <label :for="id" class="input-text-label body-normal-bold">{{ label }}</label>
2
+ <div class="input-text-with-label" :data-theme="formTheme" :class="[inputVariant, elementClasses, { dirty: isDirty }, { active: isActive }]">
3
+ <InputLabel :for="id" :id :theme :name :input-variant :field-has-error :style-class-passthrough="['input-text-label', 'body-normal-bold']">
4
+ <template #textLabel>{{ label }}</template>
5
+ </InputLabel>
4
6
 
5
7
  <div v-if="hasDescriptionSlot" :id="`${id}-description`">
6
8
  <slot name="description"></slot>
@@ -0,0 +1,158 @@
1
+ <template>
2
+ <div>
3
+ <div class="input-text-with-label" :data-theme="formTheme" :class="[elementClasses, inputVariant, { dirty: isDirty }, { active: isActive }]">
4
+ <InputLabel :for="id" :id :theme :name :input-variant :field-has-error :style-class-passthrough="['input-text-label']">
5
+ <template #textLabel>{{ label }}</template>
6
+ </InputLabel>
7
+
8
+ <div v-if="inputVariant === 'normal' && hasDescriptionSlot" :id="`${id}-description`">
9
+ <slot name="description"></slot>
10
+ </div>
11
+
12
+ <InputTextCore
13
+ v-model="modelValue"
14
+ v-model:isDirty="isDirty"
15
+ v-model:isActive="isActive"
16
+ :type
17
+ :inputmode
18
+ :maxlength
19
+ :id
20
+ :name
21
+ :placeholder
22
+ :label
23
+ :errorMessage
24
+ :fieldHasError
25
+ :required
26
+ :styleClassPassthrough
27
+ :theme
28
+ :ariaDescribedby
29
+ :size
30
+ :inputVariant
31
+ >
32
+ <template v-if="hasLeftSlot" #left>
33
+ <slot name="left"></slot>
34
+ </template>
35
+ <template v-if="hasRightSlot" #right>
36
+ <slot name="right"></slot>
37
+ </template>
38
+ </InputTextCore>
39
+
40
+ <InputError :errorMessage :showError="fieldHasError" :id="errorId" :isDetached="false" :inputVariant />
41
+ </div>
42
+
43
+ <div v-if="inputVariant !== 'normal' && hasDescriptionSlot" :id="`${id}-description`">
44
+ <slot name="description"></slot>
45
+ </div>
46
+ </div>
47
+ </template>
48
+
49
+ <script setup lang="ts">
50
+ import propValidators from '../../c12/prop-validators';
51
+ const props = defineProps({
52
+ maxlength: {
53
+ type: Number,
54
+ default: 255,
55
+ },
56
+ type: {
57
+ type: String as PropType<'text' | 'email' | 'password' | 'number' | 'tel' | 'url'>,
58
+ required: true,
59
+ },
60
+ inputmode: {
61
+ type: String as PropType<'text' | 'email' | 'tel' | 'url' | 'search' | 'numeric' | 'none' | 'decimal'>,
62
+ default: 'text',
63
+ validator(value: string) {
64
+ return propValidators.inputMode.includes(value);
65
+ },
66
+ },
67
+ name: {
68
+ type: String,
69
+ required: true,
70
+ },
71
+ placeholder: {
72
+ type: String,
73
+ default: '',
74
+ },
75
+ label: {
76
+ type: String,
77
+ required: true,
78
+ },
79
+ errorMessage: {
80
+ type: [Object, String],
81
+ required: true,
82
+ },
83
+ fieldHasError: {
84
+ type: Boolean,
85
+ default: false,
86
+ },
87
+ required: {
88
+ type: Boolean,
89
+ default: false,
90
+ },
91
+ styleClassPassthrough: {
92
+ type: Array as PropType<string[]>,
93
+ default: () => [],
94
+ },
95
+ theme: {
96
+ type: String as PropType<string>,
97
+ default: 'primary',
98
+ validator(value: string) {
99
+ return propValidators.theme.includes(value);
100
+ },
101
+ },
102
+ size: {
103
+ type: String as PropType<string>,
104
+ default: 'default',
105
+ validator(value: string) {
106
+ return propValidators.size.includes(value);
107
+ },
108
+ },
109
+ inputVariant: {
110
+ type: String as PropType<string>,
111
+ default: 'normal',
112
+ validator(value: string) {
113
+ return propValidators.inputVariant.includes(value);
114
+ },
115
+ },
116
+ });
117
+
118
+ const slots = useSlots();
119
+ const hasDescriptionSlot = computed(() => slots.description !== undefined);
120
+ const hasLeftSlot = computed(() => slots.left !== undefined);
121
+ const hasRightSlot = computed(() => slots.right !== undefined);
122
+
123
+ const formTheme = computed(() => {
124
+ return props.fieldHasError ? 'error' : props.theme;
125
+ });
126
+
127
+ const id = `${props.name}-${useId()}`;
128
+ const errorId = `${id}-error-message`;
129
+ const ariaDescribedby = computed(() => {
130
+ const ariaDescribedbyId = hasDescriptionSlot.value ? `${id}-description` : undefined;
131
+ return props.fieldHasError ? errorId : ariaDescribedbyId;
132
+ });
133
+
134
+ const modelValue = defineModel();
135
+ const isActive = ref<boolean>(false);
136
+ const isDirty = ref<boolean>(false);
137
+
138
+ const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
139
+
140
+ const testDirty = () => {
141
+ const watchValue = modelValue.value ?? '';
142
+
143
+ if (!isDirty.value && typeof watchValue === 'string' && watchValue.length > 0) {
144
+ isDirty.value = true;
145
+ }
146
+ };
147
+
148
+ onMounted(() => {
149
+ testDirty();
150
+ });
151
+
152
+ watch(
153
+ () => modelValue.value,
154
+ () => {
155
+ testDirty();
156
+ }
157
+ );
158
+ </script>
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <div
3
3
  class="input-textarea-wrapper"
4
- :data-form-theme="formTheme"
4
+ :data-theme="formTheme"
5
5
  :data-size="size"
6
6
  :class="[inputVariant, { dirty: isDirty }, { active: isActive }, { error: fieldHasError }, { 'has-left-slot': hasLeftSlot }, { 'has-right-slot': hasRightSlot }]"
7
7
  >
@@ -107,8 +107,8 @@ const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
107
107
 
108
108
  <style lang="css">
109
109
  .input-textarea-wrapper {
110
- background-color: var(--element-decorator-background-color);
111
- outline: var(--element-decorator-outline-default);
110
+ background-color: var(--theme-input-surface);
111
+ outline: var(--form-element-outline-width) solid var(--theme-input-outline);
112
112
 
113
113
  border-top-left-radius: var(--element-decorator-border-top-left-radius);
114
114
  border-top-right-radius: var(--element-decorator-border-top-right-radius);
@@ -124,7 +124,11 @@ const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
124
124
 
125
125
  &:hover {
126
126
  /* background-color: lab(89.6502 -0.829279 -2.45323 / 0.1); */
127
- background-color: var(--form-core-background-color-hover);
127
+ background-color: var(--theme-input-surface-hover);
128
+ }
129
+
130
+ &:focus-within {
131
+ outline: var(--element-decorator-outline-focus);
128
132
  }
129
133
 
130
134
  display: flex;
@@ -146,6 +150,7 @@ const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
146
150
 
147
151
  .input-textarea-core {
148
152
  all: unset;
153
+ touch-action: manipulation;
149
154
  flex-grow: 1;
150
155
  field-sizing: content;
151
156
 
@@ -155,7 +160,7 @@ const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
155
160
  padding-block: var(--input-element-padding-block);
156
161
  padding-inline: var(--input-element-padding-inline);
157
162
 
158
- min-height: var(--input-textarea-min-height);
163
+ min-height: 4rem;
159
164
 
160
165
  &::placeholder {
161
166
  color: var(--input-placeholder-color);
@@ -166,130 +171,4 @@ const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
166
171
  }
167
172
  }
168
173
  }
169
-
170
- .input-textarea-wrapper-XXX {
171
- --_focus-box-shadow: var(--box-shadow-off);
172
- --_input-textarea-core-color: var(--theme-form-input-text-color-normal);
173
-
174
- --_input-textarea-wrapper-background-color: var(--theme-form-input-bg-normal);
175
-
176
- --_input-textarea-wrapper-border: var(--form-element-border-width) solid var(--theme-form-input-border);
177
- --_input-textarea-wrapper-border-radius: var(--form-input-border-radius);
178
-
179
- --_input-textarea-wrapper-outline: var(--form-element-outline-width) solid var(--theme-form-input-outline);
180
- --_input-textarea-wrapper-opacity: 1;
181
- --_input-textarea-wrapper-box-shadow: var(--_focus-box-shadow);
182
- --_input-textarea-wrapper-margin-inline: 0;
183
- --_input-textarea-wrapper-padding-block: 0;
184
-
185
- &.underlined {
186
- --_input-textarea-core-color: var(--theme-form-input-text-color-underlined);
187
- --_input-textarea-wrapper-background-color: transparent;
188
- --_input-textarea-wrapper-padding-block: 0.5rem;
189
- }
190
-
191
- &.outlined {
192
- --_input-textarea-wrapper-margin-inline: 1px;
193
- --_input-textarea-wrapper-background-color: var(--theme-form-input-bg-outlined);
194
- }
195
-
196
- &.normal {
197
- &:focus-within {
198
- --_input-textarea-wrapper-box-shadow: var(--box-shadow-on);
199
- --_input-textarea-wrapper-outline: var(--form-element-outline-width) solid hsl(from var(--theme-form-input-outline-focus) h s 90%);
200
- }
201
- }
202
-
203
- &:not(.normal) {
204
- --_input-textarea-wrapper-border: none;
205
- --_input-textarea-wrapper-box-shadow: none;
206
- --_input-textarea-wrapper-outline: none;
207
- --_input-textarea-wrapper-opacity: 0;
208
-
209
- &:focus {
210
- --_input-textarea-wrapper-border: none;
211
- --_input-textarea-wrapper-box-shadow: none;
212
- --_input-textarea-wrapper-outline: none;
213
- --_input-textarea-wrapper-background-color: transparent;
214
- }
215
-
216
- &:focus-within {
217
- --_input-textarea-wrapper-border: none;
218
- --_input-textarea-wrapper-box-shadow: none;
219
- --_input-textarea-wrapper-outline: none;
220
- --_input-textarea-wrapper-background-color: transparent;
221
- }
222
-
223
- &.active,
224
- &.dirty {
225
- --_input-textarea-wrapper-border: none;
226
- --_input-textarea-wrapper-box-shadow: none;
227
- --_input-textarea-wrapper-outline: none;
228
- --_input-textarea-wrapper-background-color: transparent;
229
-
230
- --_input-textarea-wrapper-opacity: 1;
231
- }
232
- }
233
-
234
- display: flex;
235
- align-items: center;
236
-
237
- background-color: var(--_input-textarea-wrapper-background-color);
238
- border-radius: var(--_input-textarea-wrapper-border-radius);
239
- border: var(--_input-textarea-wrapper-border);
240
- outline: var(--_input-textarea-wrapper-outline);
241
- box-shadow: var(--_input-textarea-wrapper-box-shadow);
242
- opacity: var(--_input-textarea-wrapper-opacity);
243
-
244
- margin-inline: var(--_input-textarea-wrapper-margin-inline);
245
- padding-block: var(--_input-textarea-wrapper-padding-block);
246
-
247
- &:not(.normal) {
248
- transition: opacity 0.2s ease-in-out;
249
- }
250
-
251
- &.has-left-slot {
252
- .left-slot {
253
- display: flex;
254
- align-items: center;
255
- margin-inline-start: 1rem;
256
- }
257
- }
258
-
259
- &.has-right-slot {
260
- .right-slot {
261
- display: flex;
262
- align-items: center;
263
- margin-inline-end: 1rem;
264
- }
265
- }
266
-
267
- .input-textarea-core {
268
- background-color: transparent;
269
- border: none;
270
- outline: none;
271
- box-shadow: none;
272
- flex-grow: 1;
273
-
274
- min-height: 4lh;
275
- field-sizing: content;
276
-
277
- color: var(--_input-textarea-core-color);
278
- font-family: var(--font-family);
279
- font-size: var(--form-element-font-size);
280
- line-height: var(--form-element-line-height);
281
-
282
- padding-inline: var(--form-text-padding-inline);
283
- padding-block-start: var(--form-element-padding-block-start);
284
- padding-block-end: var(--form-element-padding-block-end);
285
-
286
- &::placeholder,
287
- &::-webkit-input-placeholder {
288
- font-family: var(--font-family);
289
- font-size: var(--form-element-font-size);
290
- font-style: italic;
291
- font-weight: 400;
292
- }
293
- }
294
- }
295
174
  </style>