srcdev-nuxt-forms 0.2.0 → 1.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 (77) hide show
  1. package/assets/styles/brand/_brand.css +150 -0
  2. package/assets/styles/brand/_brand_dark.css +152 -0
  3. package/assets/styles/brand/_palette_dark.css +148 -0
  4. package/assets/styles/brand/_palette_light.css +148 -0
  5. package/assets/styles/brand/_typography.css +176 -0
  6. package/assets/styles/brand/index.css +1 -0
  7. package/assets/styles/forms/index.css +1 -2
  8. package/assets/styles/forms/themes/_default.css +3 -0
  9. package/assets/styles/forms/themes/_error.css +45 -11
  10. package/assets/styles/forms/themes/_ghost.css +42 -10
  11. package/assets/styles/forms/themes/_primary.css +42 -12
  12. package/assets/styles/forms/themes/_secondary.css +42 -12
  13. package/assets/styles/forms/themes/_success.css +42 -11
  14. package/assets/styles/forms/themes/_tertiary.css +42 -10
  15. package/assets/styles/forms/themes/_warning.css +42 -10
  16. package/assets/styles/forms/themes/index.css +1 -0
  17. package/assets/styles/forms/variables/_palette.css +104 -0
  18. package/assets/styles/forms/variables/_theme.css +1 -1
  19. package/assets/styles/forms/variables/index.css +2 -0
  20. package/assets/styles/main.css +2 -0
  21. package/assets/styles/scaffolding/_margin-helpers.css +308 -0
  22. package/assets/styles/scaffolding/_padding-helpers.css +308 -0
  23. package/assets/styles/scaffolding/_page.css +23 -0
  24. package/assets/styles/scaffolding/index.css +3 -0
  25. package/assets/styles/variables/colors/_blue.css +2 -2
  26. package/assets/styles/variables/colors/_gray.css +1 -1
  27. package/assets/styles/variables/colors/_green.css +2 -2
  28. package/assets/styles/variables/colors/_orange.css +2 -2
  29. package/assets/styles/variables/colors/_red.css +2 -2
  30. package/assets/styles/variables/colors/_yellow.css +1 -1
  31. package/components/forms/form-errors/InputError.vue +82 -37
  32. package/components/forms/input-button/InputButtonCore.vue +25 -104
  33. package/components/forms/input-checkbox/InputCheckboxCore.vue +37 -181
  34. package/components/forms/input-checkbox/InputCheckboxWithLabel.vue +42 -51
  35. package/components/forms/input-checkbox/variants/MultipleCheckboxes.vue +42 -69
  36. package/components/forms/input-checkbox/variants/SingleCheckbox.vue +126 -111
  37. package/components/forms/input-number/InputNumberCore.vue +184 -0
  38. package/components/forms/input-number/variants/InputNumberDefault.vue +155 -0
  39. package/components/forms/input-radio/InputRadiobuttonCore.vue +212 -0
  40. package/components/forms/input-radio/InputRadiobuttonWithLabel.vue +103 -0
  41. package/components/forms/input-radio/variants/MultipleRadiobuttons.vue +166 -0
  42. package/components/forms/input-range/InputRangeCore.vue +70 -88
  43. package/components/forms/input-range/variants/InputRangeDefault.vue +74 -46
  44. package/components/forms/input-text/InputTextCore.vue +141 -109
  45. package/components/forms/input-text/variants/material/InputPasswordWithLabel.vue +99 -0
  46. package/components/forms/input-text/variants/material/InputTextAsNumberWithLabel.vue +142 -0
  47. package/components/forms/input-text/variants/material/InputTextWithLabel.vue +125 -0
  48. package/components/forms/input-textarea/InputTextareaCore.vue +96 -105
  49. package/components/forms/input-textarea/variants/InputTextareaWithLabel.vue +106 -0
  50. package/components/scaffolding/footer/NavFooter.vue +62 -0
  51. package/composables/useApiRequest.ts +25 -0
  52. package/composables/useFormControl.ts +2 -0
  53. package/composables/useSleep.ts +2 -2
  54. package/composables/useStyleClassPassthrough.ts +30 -0
  55. package/composables/useZodValidation.ts +120 -0
  56. package/layouts/default.vue +21 -5
  57. package/package.json +13 -9
  58. package/pages/forms/examples/material/cssbattle.vue +60 -0
  59. package/pages/forms/examples/material/text-fields.vue +375 -153
  60. package/pages/index.vue +2 -2
  61. package/pages/typography.vue +83 -0
  62. package/server/data/places/cities.json +7 -1
  63. package/types/types.forms.ts +102 -0
  64. package/types/types.zodFormControl.ts +21 -0
  65. package/assets/styles/forms/utils/_a11y.css +0 -5
  66. package/assets/styles/forms/utils/index.css +0 -1
  67. package/components/forms/input-radio/InputRadioCore.vue +0 -226
  68. package/components/forms/input-radio/InputRadioWithLabel.vue +0 -118
  69. package/components/forms/input-radio/variants/MultipleRadio.vue +0 -183
  70. package/components/forms/input-radio/variants/SingleRadio.vue +0 -131
  71. package/components/forms/input-text/variants/material/InputEmailMaterial.vue +0 -72
  72. package/components/forms/input-text/variants/material/InputPasswordMaterial.vue +0 -114
  73. package/components/forms/input-text/variants/material/InputTextMaterial.vue +0 -68
  74. package/components/forms/input-text/variants/material/InputTextMaterialCore.vue +0 -313
  75. package/components/forms/input-textarea/variants/material/InputTextareaMaterial.vue +0 -75
  76. package/components/forms/input-textarea/variants/material/InputTextareaMaterialCore.vue +0 -290
  77. package/composables/useUpdateStyleClassPassthrough.ts +0 -29
@@ -0,0 +1,212 @@
1
+ <template>
2
+ <div class="input-radiobutton-wrapper" :data-form-theme="formTheme" :class="[size, checkboxAppearance, { error: fieldHasError }]">
3
+ <input
4
+ type="radio"
5
+ :true-value="trueValue"
6
+ :false-value="falseValue"
7
+ :id
8
+ :name
9
+ :required="required && !multipleOptions"
10
+ :value="trueValue"
11
+ :class="['input-radiobutton-core', size, checkboxAppearance, { error: fieldHasError }]"
12
+ v-model="modelValue"
13
+ ref="inputField"
14
+ />
15
+ <div v-if="checkboxAppearance === 'with-decorator'" :class="['input-radiobutton-decorator', size, checkboxStyle]">
16
+ <div v-if="checkboxStyle === 'check' || checkboxStyle === 'cross'" :class="[checkboxStyle, { checked: isChecked }]"></div>
17
+ </div>
18
+ </div>
19
+ </template>
20
+
21
+ <script setup lang="ts">
22
+ import propValidators from '../c12/prop-validators';
23
+ const { id, name, required, trueValue, falseValue, multipleOptions, theme, styleClassPassthrough, size, checkboxAppearance, checkboxStyle, fieldHasError } = defineProps({
24
+ id: {
25
+ type: String,
26
+ required: true,
27
+ },
28
+ name: {
29
+ type: String,
30
+ required: true,
31
+ },
32
+ required: {
33
+ type: Boolean,
34
+ value: false,
35
+ },
36
+ trueValue: {
37
+ type: [String, Number, Boolean],
38
+ default: true,
39
+ },
40
+ falseValue: {
41
+ type: [String, Number, Boolean],
42
+ default: false,
43
+ },
44
+ multipleOptions: {
45
+ type: Boolean,
46
+ default: false,
47
+ },
48
+ theme: {
49
+ type: String as PropType<string>,
50
+ default: 'primary',
51
+ validator(value: string) {
52
+ return propValidators.theme.includes(value);
53
+ },
54
+ },
55
+ size: {
56
+ type: String as PropType<string>,
57
+ default: 'medium',
58
+ validator(value: string) {
59
+ return propValidators.size.includes(value);
60
+ },
61
+ },
62
+ checkboxAppearance: {
63
+ type: String as PropType<string>,
64
+ default: null,
65
+ validator(value: string) {
66
+ return propValidators.checkboxAppearance.includes(value);
67
+ },
68
+ },
69
+ checkboxStyle: {
70
+ type: String as PropType<string>,
71
+ default: 'check',
72
+ validator(value: string) {
73
+ return propValidators.checkboxStyle.includes(value);
74
+ },
75
+ },
76
+ fieldHasError: {
77
+ type: Boolean,
78
+ default: false,
79
+ },
80
+ styleClassPassthrough: {
81
+ type: Array as PropType<string[]>,
82
+ default: () => [],
83
+ },
84
+ });
85
+
86
+ const slots = useSlots();
87
+ const hasLeftContent = computed(() => slots.left !== undefined);
88
+ const hasRightContent = computed(() => slots.right !== undefined);
89
+ const { elementClasses, updateElementClasses } = useStyleClassPassthrough(styleClassPassthrough);
90
+
91
+ const formTheme = computed(() => {
92
+ return fieldHasError ? 'error' : theme;
93
+ });
94
+
95
+ const modelValue = defineModel<any>();
96
+
97
+ const inputField = ref<HTMLInputElement | null>(null);
98
+
99
+ const isArray = Array.isArray(modelValue.value);
100
+
101
+ const isChecked = computed(() => {
102
+ if (isArray) {
103
+ return modelValue.value.indexOf(trueValue) > -1;
104
+ } else {
105
+ return modelValue.value === trueValue;
106
+ }
107
+ });
108
+ </script>
109
+
110
+ <style scoped lang="css">
111
+ .input-radiobutton-wrapper {
112
+ --_checkbox-size: initial;
113
+ --_outline-width: var(--input-outline-width-thin);
114
+ --_border-width: var(--input-border-width-thin);
115
+
116
+ display: grid;
117
+ grid-template-areas: 'element-stack';
118
+
119
+ &.with-decorator {
120
+ border-radius: 50%;
121
+ border: var(--_border-width) solid var(--theme-form-input-border);
122
+ height: var(--_checkbox-size);
123
+ width: var(--_checkbox-size);
124
+ overflow: hidden;
125
+
126
+ &:has(.input-radiobutton-core:focus-visible) {
127
+ border: var(--_border-width) solid var(--theme-form-input-border-focus);
128
+ outline: var(--_outline-width) solid hsl(from var(--theme-form-input-outline-focus) h s 50%);
129
+ box-shadow: var(--theme-form-focus-box-shadow);
130
+ }
131
+ }
132
+
133
+ /* Sizes */
134
+ &.x-small {
135
+ --_checkbox-size: 20px;
136
+ }
137
+ &.small {
138
+ --_checkbox-size: 24px;
139
+ }
140
+ &.normal {
141
+ --_checkbox-size: 30px;
142
+ }
143
+ &.medium {
144
+ --_checkbox-size: 40px;
145
+ }
146
+ &.large {
147
+ --_checkbox-size: 44px;
148
+ }
149
+
150
+ .input-radiobutton-decorator {
151
+ --_padding: 5px;
152
+ display: grid;
153
+ grid-area: element-stack;
154
+ background-color: var(--theme-form-checkbox-bg);
155
+
156
+ place-content: center;
157
+ position: relative;
158
+ z-index: -1;
159
+
160
+ div {
161
+ grid-area: stack;
162
+ background-color: hsl(from var(--theme-form-radio-symbol) h s 50%);
163
+ width: calc(var(--_checkbox-size) - (var(--_padding) * 2));
164
+ height: calc(var(--_checkbox-size) - var(--_padding) * 2);
165
+ border: 1px solid var(--theme-form-input-border);
166
+ border-radius: 50%;
167
+ opacity: 0;
168
+ transition: opacity 0.2s ease-in-out;
169
+
170
+ &.checked {
171
+ opacity: 1;
172
+ }
173
+ }
174
+ }
175
+
176
+ .input-radiobutton-core {
177
+ grid-area: element-stack;
178
+ border: var(--_border-width) solid var(--theme-form-input-border);
179
+ height: var(--_checkbox-size);
180
+ width: var(--_checkbox-size);
181
+
182
+ transition: all 0.2s ease-in-out;
183
+
184
+ &.with-decorator {
185
+ appearance: none;
186
+ margin: 0;
187
+ overflow: hidden;
188
+ opacity: 0;
189
+ }
190
+
191
+ &:hover {
192
+ cursor: pointer;
193
+ }
194
+
195
+ /* &:focus-visible {
196
+ border-radius: var(--input-border-radius);
197
+ } */
198
+
199
+ &:focus {
200
+ border: var(--_border-width) solid var(--theme-form-input-border);
201
+ outline: var(--_outline-width) solid hsl(from var(--theme-form-input-outline) h s 50%);
202
+ }
203
+
204
+ &:checked::after {
205
+ display: grid;
206
+ font-family: var(--font-family);
207
+ place-content: center;
208
+ font-size: calc(var(--_checkbox-size) * 0.75);
209
+ }
210
+ }
211
+ }
212
+ </style>
@@ -0,0 +1,103 @@
1
+ <template>
2
+ <div class="input-radiobutton-with-label" :class="[elementClasses, { error: fieldHasError }]">
3
+ <InputRadiobuttonCore :id :name :required v-model="modelValue" :size :trueValue :falseValue :checkboxAppearance :checkboxStyle :fieldHasError :theme />
4
+ <label v-if="hasLabelContent" class="input-radiobutton-label body-normal" :for="id">
5
+ <slot name="labelContent"></slot>
6
+ </label>
7
+ <label v-else class="input-radiobutton-label body-normal-semibold" :for="id">{{ label }}</label>
8
+ </div>
9
+ </template>
10
+
11
+ <script setup lang="ts">
12
+ import propValidators from '../c12/prop-validators';
13
+
14
+ const { id, name, label, required, fieldHasError, trueValue, falseValue, size, checkboxAppearance, checkboxStyle, styleClassPassthrough, theme } = defineProps({
15
+ id: {
16
+ type: String,
17
+ required: true,
18
+ },
19
+ name: {
20
+ type: String,
21
+ required: true,
22
+ },
23
+ label: {
24
+ type: String,
25
+ required: true,
26
+ },
27
+ required: {
28
+ type: Boolean,
29
+ default: false,
30
+ },
31
+ fieldHasError: {
32
+ type: Boolean,
33
+ default: false,
34
+ },
35
+ trueValue: {
36
+ type: [String, Number, Boolean],
37
+ default: true,
38
+ },
39
+ falseValue: {
40
+ type: [String, Number, Boolean],
41
+ default: false,
42
+ },
43
+ size: {
44
+ type: String as PropType<string>,
45
+ default: 'medium',
46
+ validator(value: string) {
47
+ return propValidators.size.includes(value);
48
+ },
49
+ },
50
+ checkboxAppearance: {
51
+ type: String as PropType<string>,
52
+ default: null,
53
+ validator(value: string) {
54
+ return propValidators.checkboxAppearance.includes(value);
55
+ },
56
+ },
57
+ checkboxStyle: {
58
+ type: String as PropType<string>,
59
+ default: 'check',
60
+ validator(value: string) {
61
+ return propValidators.checkboxStyle.includes(value);
62
+ },
63
+ },
64
+ styleClassPassthrough: {
65
+ type: Array as PropType<string[]>,
66
+ default: () => [],
67
+ },
68
+ theme: {
69
+ type: String as PropType<string>,
70
+ default: 'primary',
71
+ validator(value: string) {
72
+ return propValidators.theme.includes(value);
73
+ },
74
+ },
75
+ });
76
+
77
+ const slots = useSlots();
78
+ const hasLabelContent = computed(() => slots.labelContent !== undefined);
79
+ const { elementClasses, updateElementClasses } = useStyleClassPassthrough(styleClassPassthrough);
80
+
81
+ const modelValue = defineModel();
82
+ </script>
83
+
84
+ <style lang="css">
85
+ .input-radiobutton-with-label {
86
+ display: grid;
87
+ align-items: center;
88
+ grid-template-columns: auto 1fr;
89
+
90
+ .input-radiobutton-label {
91
+ display: flex;
92
+ width: 100%;
93
+ height: 100%;
94
+ align-items: center;
95
+ margin-block: 8px;
96
+ padding-inline: 8px;
97
+
98
+ &:hover {
99
+ cursor: pointer;
100
+ }
101
+ }
102
+ }
103
+ </style>
@@ -0,0 +1,166 @@
1
+ <template>
2
+ <fieldset class="multiple-radiobuttons-fieldset" :class="[{ error: fieldHasError }]">
3
+ <legend :class="[{ 'has-description': hasDescription }]">{{ legend }}</legend>
4
+ <template v-if="hasDescription">
5
+ <slot name="description"></slot>
6
+ </template>
7
+ <div class="multiple-radiobuttons-items" :class="[optionsLayout]">
8
+ <template v-for="item in fieldData.data" :key="item.id">
9
+ <InputRadiobuttonWithLabel
10
+ :id="item.value"
11
+ :name="item.name"
12
+ :required
13
+ :label="item.label"
14
+ :fieldHasError
15
+ v-model="modelValue"
16
+ :true-value="item.value"
17
+ :size
18
+ :checkboxAppearance
19
+ :checkboxStyle
20
+ :theme
21
+ />
22
+ </template>
23
+ </div>
24
+ <InputError :errorMessage="errorMessage" :fieldHasError :id="name" :isDetached="true" />
25
+ </fieldset>
26
+ </template>
27
+
28
+ <script setup lang="ts">
29
+ import propValidators from '../../c12/prop-validators';
30
+ import type { IOptionsConfig, IFormMultipleOptions } from '@/types/types.forms';
31
+
32
+ import type { C12nMultipleCheckboxes, IFormFieldC12, IFormData } from '@/types/types.forms';
33
+
34
+ const { id, name, legend, label, required, fieldHasError, placeholder, errorMessage, size, optionsLayout, equalCols, checkboxAppearance, checkboxStyle, styleClassPassthrough, theme } = defineProps({
35
+ id: {
36
+ type: String,
37
+ required: true,
38
+ },
39
+ name: {
40
+ type: String,
41
+ required: true,
42
+ },
43
+ legend: {
44
+ type: String,
45
+ required: true,
46
+ },
47
+ label: {
48
+ type: String,
49
+ required: true,
50
+ },
51
+ placeholder: {
52
+ type: String,
53
+ default: '',
54
+ },
55
+ errorMessage: {
56
+ type: [Object, String],
57
+ required: true,
58
+ },
59
+ required: {
60
+ type: Boolean,
61
+ default: false,
62
+ },
63
+ fieldHasError: {
64
+ type: Boolean,
65
+ default: false,
66
+ },
67
+ multipleOptions: {
68
+ type: Boolean,
69
+ default: false,
70
+ },
71
+ size: {
72
+ type: String as PropType<string>,
73
+ default: 'medium',
74
+ validator(value: string) {
75
+ return propValidators.size.includes(value);
76
+ },
77
+ },
78
+ optionsLayout: {
79
+ type: String as PropType<string>,
80
+ default: 'equal-widths',
81
+ validator(value: string) {
82
+ return propValidators.optionsLayout.includes(value);
83
+ },
84
+ },
85
+ equalCols: {
86
+ type: Boolean,
87
+ default: true,
88
+ },
89
+ checkboxAppearance: {
90
+ type: String as PropType<string>,
91
+ default: null,
92
+ validator(value: string) {
93
+ return propValidators.checkboxAppearance.includes(value);
94
+ },
95
+ },
96
+ checkboxStyle: {
97
+ type: String as PropType<string>,
98
+ default: 'check',
99
+ validator(value: string) {
100
+ return propValidators.checkboxStyle.includes(value);
101
+ },
102
+ },
103
+ styleClassPassthrough: {
104
+ type: Array as PropType<string[]>,
105
+ default: () => [],
106
+ },
107
+ theme: {
108
+ type: String as PropType<string>,
109
+ default: 'primary',
110
+ validator(value: string) {
111
+ return propValidators.theme.includes(value);
112
+ },
113
+ },
114
+ });
115
+
116
+ const slots = useSlots();
117
+ const hasDescription = computed(() => slots.description !== undefined);
118
+ const { elementClasses, updateElementClasses } = useStyleClassPassthrough(styleClassPassthrough);
119
+
120
+ const modelValue = defineModel();
121
+ const fieldData = defineModel('fieldData') as Ref<IFormMultipleOptions>;
122
+ </script>
123
+
124
+ <style lang="css">
125
+ .multiple-radiobuttons-fieldset {
126
+ margin: 0;
127
+ padding: 0;
128
+ border: 0;
129
+
130
+ legend {
131
+ font-family: var(--font-family);
132
+ font-size: 16px;
133
+ font-weight: 500;
134
+
135
+ &.has-description {
136
+ margin-bottom: 0;
137
+ }
138
+ }
139
+
140
+ .label-description {
141
+ font-family: var(--font-family);
142
+ font-size: 16px;
143
+ margin-top: 12px;
144
+ }
145
+ }
146
+
147
+ .multiple-radiobuttons-items {
148
+ display: flex;
149
+ gap: 12px;
150
+ margin-top: 12px;
151
+
152
+ &.inline {
153
+ flex-direction: row;
154
+ flex-wrap: wrap;
155
+ }
156
+
157
+ &.block {
158
+ flex-direction: column;
159
+ }
160
+
161
+ &.equal-widths {
162
+ display: grid;
163
+ grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
164
+ }
165
+ }
166
+ </style>
@@ -1,21 +1,28 @@
1
1
  <template>
2
- <div class="input-range-wrapper">
2
+ <div class="input-range-wrapper" :data-form-theme="formTheme">
3
3
  <div v-if="hasLeftContent" class="slot left">
4
4
  <slot name="left"></slot>
5
5
  </div>
6
6
 
7
- <input
8
- type="range"
9
- :id
10
- :name
11
- :required
12
- :min
13
- :max
14
- :step
15
- :class="['input-range-core', `input-range--${theme}`, `input-range--${size}`, `input-range--${weight}`, styleClassPassthrough]"
16
- v-model="modelValue.data[name]"
17
- ref="inputField"
18
- />
7
+ <div class="input-range-container">
8
+ <input
9
+ type="range"
10
+ :id
11
+ :name
12
+ :required
13
+ :min
14
+ :max
15
+ :step
16
+ :list="hasDataList ? name + '-datalist' : ''"
17
+ :class="['input-range-core', `input-range--${size}`, `input-range--${weight}`, styleClassPassthrough]"
18
+ v-model="modelValue"
19
+ ref="inputField"
20
+ />
21
+
22
+ <template v-if="hasDataList">
23
+ <slot name="datalist"></slot>
24
+ </template>
25
+ </div>
19
26
  <div v-if="hasRightContent" class="slot right">
20
27
  <slot name="right"></slot>
21
28
  </div>
@@ -25,10 +32,8 @@
25
32
  <script setup lang="ts">
26
33
  import propValidators from '../c12/prop-validators';
27
34
 
28
- import type { InpuTextC12, IFormFieldC12, IFormData } from '@/types/types.forms';
29
- const props = defineProps({
35
+ const { id, name, required, min, max, step, theme, size, weight, styleClassPassthrough, fieldHasError } = defineProps({
30
36
  id: {
31
- // type: String as PropType<string>,
32
37
  type: String,
33
38
  required: true,
34
39
  },
@@ -36,30 +41,26 @@ const props = defineProps({
36
41
  type: String,
37
42
  required: true,
38
43
  },
39
- required: {
40
- type: Boolean,
41
- value: false,
42
- },
43
44
  min: {
44
45
  type: Number,
45
- default: 0,
46
+ required: true,
46
47
  },
47
48
  max: {
48
49
  type: Number,
49
- default: 100,
50
+ required: true,
50
51
  },
51
52
  step: {
52
53
  type: Number,
53
54
  default: 1,
54
55
  },
55
- c12: {
56
- type: Object as PropType<InpuTextC12>,
57
- required: true,
58
- },
59
- styleClassPassthrough: {
56
+ placeholder: {
60
57
  type: String,
61
58
  default: '',
62
59
  },
60
+ required: {
61
+ type: Boolean,
62
+ default: false,
63
+ },
63
64
  theme: {
64
65
  type: String as PropType<string>,
65
66
  default: 'primary',
@@ -81,90 +82,71 @@ const props = defineProps({
81
82
  return propValidators.weight.includes(value);
82
83
  },
83
84
  },
85
+ fieldHasError: {
86
+ type: Boolean,
87
+ default: false,
88
+ },
89
+ styleClassPassthrough: {
90
+ type: String,
91
+ default: '',
92
+ },
84
93
  });
85
94
 
86
95
  const slots = useSlots();
96
+ const hasDataList = computed(() => slots.datalist !== undefined);
87
97
  const hasLeftContent = computed(() => slots.left !== undefined);
88
98
  const hasRightContent = computed(() => slots.right !== undefined);
89
99
 
90
- const modelValue = defineModel() as Ref<IFormData>;
91
-
92
- const name = computed(() => {
93
- return props.name !== null ? props.name : props.id;
94
- });
95
-
96
- const inputField = ref<HTMLInputElement | null>(null);
97
-
98
- const formFieldC12 = <IFormFieldC12>{
99
- label: props.c12.label,
100
- placeholder: props.c12.placeholder,
101
- errorMessage: props.c12.errorMessage,
102
- useCustomError: false,
103
- customErrors: {},
104
- isValid: false,
105
- isDirty: false,
106
- type: 'number',
107
- previousValue: null,
108
- };
109
- modelValue.value!.formFieldsC12[name.value] = formFieldC12;
110
-
111
- const { initFormFieldsC12 } = useFormControl();
112
- initFormFieldsC12(props.name, formFieldC12);
113
-
114
- const fieldValue = computed(() => {
115
- return modelValue.value.data[name.value];
116
- });
117
-
118
- watch(fieldValue, () => {
119
- if (!modelValue.value!.formFieldsC12[name.value].isDirty) {
120
- modelValue.value!.formFieldsC12[name.value].isDirty = modelValue.value.data[name.value] !== '';
121
- }
122
- modelValue.value!.formFieldsC12[name.value].isValid = inputField.value?.validity.valid ?? false;
123
- modelValue.value!.validityState[name.value] = inputField.value?.validity.valid ?? false;
124
-
125
- if (modelValue.value!.formFieldsC12[name.value].useCustomError && modelValue.value.data[props.name] === modelValue.value.formFieldsC12[props.name].previousValue) {
126
- modelValue.value!.validityState[name.value] = false;
127
- modelValue.value!.formFieldsC12[name.value].isValid = false;
128
- modelValue.value.displayErrorMessages = true;
129
- }
100
+ const formTheme = computed(() => {
101
+ return fieldHasError ? 'error' : theme;
130
102
  });
131
103
 
132
- const isValid = () => {
133
- setTimeout(() => {
134
- modelValue.value!.validityState[name.value] = inputField.value?.validity.valid ?? false;
135
- modelValue.value!.formFieldsC12[name.value].isValid = inputField.value?.validity.valid ?? false;
136
- if (!modelValue.value!.formFieldsC12[name.value].isDirty) {
137
- modelValue.value!.formFieldsC12[name.value].isDirty = modelValue.value.data[name.value] !== '';
138
- }
139
- }, 0);
140
- };
141
-
142
- onMounted(() => {
143
- isValid();
144
- });
104
+ const modelValue = defineModel<number | readonly number[]>();
145
105
  </script>
146
106
 
147
107
  <style lang="css">
148
108
  .input-range-wrapper {
149
- --_form-theme: var(--theme-form-primary);
150
- --_focus-colour: var(--theme-form-primary-focus);
151
109
  --_gutter: 12px;
152
110
  --_border-width: var(--input-border-width-thin);
153
- --_border-color: var(--_form-theme);
154
111
  --_outline-width: var(--input-outline-width-thin);
155
112
 
113
+ --_input-range-height: 24px;
114
+ --_slot-translate-y: calc(var(--_input-range-height) / 4);
115
+
156
116
  display: flex;
157
117
  align-items: center;
158
118
  justify-content: space-between;
159
119
  gap: 10px;
160
120
 
161
- .input-range-core {
121
+ .slot {
122
+ align-self: flex-start;
123
+ transform: translateY(-4px);
124
+ }
125
+
126
+ .input-range-container {
162
127
  flex-grow: 1;
163
- height: 24px;
128
+ .input-range-core {
129
+ height: var(--_input-range-height);
130
+ margin: 0;
131
+ width: 100%;
132
+
133
+ &:focus-visible {
134
+ box-shadow: var(--theme-form-focus-box-shadow);
135
+ }
136
+ }
164
137
 
165
- &:focus-visible {
166
- outline: var(--focus-visible-outline);
167
- box-shadow: var(--focus-visible-box-shadow);
138
+ .input-range-datalist {
139
+ display: flex;
140
+ flex-direction: column;
141
+ font-family: var(--font-family);
142
+ font-size: 14px;
143
+ font-weight: 500;
144
+ justify-content: space-between;
145
+ writing-mode: vertical-lr;
146
+ width: 100%;
147
+ option {
148
+ padding: 0;
149
+ }
168
150
  }
169
151
  }
170
152
  }