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
@@ -1,135 +1,142 @@
1
1
  <template>
2
- <fieldset class="single-checkbox-fieldset" :class="[styleClassPassthrough, `theme-${theme}`, { error: fieldHasError }]">
2
+ <fieldset class="single-checkbox-fieldset" :class="[{ error: fieldHasError }]">
3
3
  <legend :class="[{ 'has-description': hasDescription }]">{{ legend }}</legend>
4
4
  <template v-if="hasDescription">
5
5
  <slot name="description"></slot>
6
6
  </template>
7
- <InputError :errorMessaging :fieldHasError :id="name" :isDetached="true" />
8
- <InputCheckboxWithLabel :id :name :required :c12 v-model="modelValue" :theme :size :checkboxAppearance :checkboxStyle />
7
+ <div class="single-checkbox-items" :class="[optionsLayout]">
8
+ <InputCheckboxWithLabel :id :name :required :label :fieldHasError v-model="modelValue" :trueValue :falseValue :size :checkboxAppearance :checkboxStyle :theme>
9
+ <template v-if="hasLabelContent" #labelContent>
10
+ <slot name="labelContent"></slot>
11
+ </template>
12
+ </InputCheckboxWithLabel>
13
+ </div>
14
+ <InputError :errorMessage :fieldHasError :id="name" :isDetached="true" :styleClassPassthrough="inputErrorStyles" />
9
15
  </fieldset>
10
16
  </template>
11
17
 
12
18
  <script setup lang="ts">
13
19
  import propValidators from '../../c12/prop-validators';
20
+ import type { IFormMultipleOptions } from '@/types/types.forms';
14
21
 
15
- import type { InpuTextC12, IFormFieldC12, IFormData } from '@/types/types.forms';
16
- // import { validationConfig } from '@/components/forms/c12/validation-patterns';
17
-
18
- const props = defineProps({
19
- id: {
20
- // type: String as PropType<string>,
21
- type: String,
22
- required: true,
23
- },
24
- name: {
25
- type: String,
26
- required: true,
27
- },
28
- legend: {
29
- type: String,
30
- required: true,
31
- },
32
- required: {
33
- type: Boolean,
34
- value: false,
35
- },
36
- c12: {
37
- type: Object as PropType<InpuTextC12>,
38
- required: true,
39
- },
40
- trueValue: {
41
- type: [String, Number, Boolean],
42
- default: true,
43
- },
44
- falseValue: {
45
- type: [String, Number, Boolean],
46
- default: false,
47
- },
48
- multipleOptions: {
49
- type: Boolean,
50
- default: false,
51
- },
52
- styleClassPassthrough: {
53
- type: String,
54
- default: '',
55
- },
56
- theme: {
57
- type: String as PropType<string>,
58
- default: 'primary',
59
- validator(value: string) {
60
- return propValidators.theme.includes(value);
61
- },
62
- },
63
- size: {
64
- type: String as PropType<string>,
65
- default: 'medium',
66
- validator(value: string) {
67
- return propValidators.size.includes(value);
68
- },
69
- },
70
- checkboxAppearance: {
71
- type: String as PropType<string>,
72
- default: null,
73
- validator(value: string) {
74
- return propValidators.checkboxAppearance.includes(value);
75
- },
76
- },
77
- checkboxStyle: {
78
- type: String as PropType<string>,
79
- default: 'check',
80
- validator(value: string) {
81
- return propValidators.checkboxStyle.includes(value);
82
- },
83
- },
84
- });
22
+ const { id, name, legend, label, required, fieldHasError, errorMessage, size, optionsLayout, equalCols, trueValue, falseValue, checkboxAppearance, checkboxStyle, styleClassPassthrough, theme } =
23
+ defineProps({
24
+ id: {
25
+ type: String,
26
+ required: true,
27
+ },
28
+ name: {
29
+ type: String,
30
+ required: true,
31
+ },
32
+ legend: {
33
+ type: String,
34
+ required: true,
35
+ },
36
+ label: {
37
+ type: String,
38
+ required: false,
39
+ default: '',
40
+ },
41
+ errorMessage: {
42
+ type: [Object, String],
43
+ required: true,
44
+ },
45
+ required: {
46
+ type: Boolean,
47
+ default: false,
48
+ },
49
+ fieldHasError: {
50
+ type: Boolean,
51
+ default: false,
52
+ },
53
+ multipleOptions: {
54
+ type: Boolean,
55
+ default: false,
56
+ },
57
+ size: {
58
+ type: String as PropType<string>,
59
+ default: 'medium',
60
+ validator(value: string) {
61
+ return propValidators.size.includes(value);
62
+ },
63
+ },
64
+ trueValue: {
65
+ type: [String, Number, Boolean],
66
+ default: true,
67
+ },
68
+ falseValue: {
69
+ type: [String, Number, Boolean],
70
+ default: false,
71
+ },
72
+ optionsLayout: {
73
+ type: String as PropType<string>,
74
+ default: 'equal-widths',
75
+ validator(value: string) {
76
+ return propValidators.optionsLayout.includes(value);
77
+ },
78
+ },
79
+ equalCols: {
80
+ type: Boolean,
81
+ default: true,
82
+ },
83
+ checkboxAppearance: {
84
+ type: String as PropType<string>,
85
+ default: null,
86
+ validator(value: string) {
87
+ return propValidators.checkboxAppearance.includes(value);
88
+ },
89
+ },
90
+ checkboxStyle: {
91
+ type: String as PropType<string>,
92
+ default: 'check',
93
+ validator(value: string) {
94
+ return propValidators.checkboxStyle.includes(value);
95
+ },
96
+ },
97
+ styleClassPassthrough: {
98
+ type: Array as PropType<string[]>,
99
+ default: () => [],
100
+ },
101
+ theme: {
102
+ type: String as PropType<string>,
103
+ default: 'primary',
104
+ validator(value: string) {
105
+ return propValidators.theme.includes(value);
106
+ },
107
+ },
108
+ });
85
109
 
86
110
  const slots = useSlots();
87
111
  const hasDescription = computed(() => slots.description !== undefined);
112
+ const hasLabelContent = computed(() => slots.labelContent !== undefined);
88
113
 
89
- const modelValue = defineModel() as Ref<IFormData>;
90
- const name = computed(() => {
91
- return props.name !== null ? props.name : props.id;
92
- });
93
- const fieldHasError = computed(() => {
94
- return modelValue.value!.submitAttempted && !modelValue.value!.formFieldsC12[name.value].isValid;
95
- });
114
+ const { elementClasses, updateElementClasses } = useStyleClassPassthrough(styleClassPassthrough);
115
+
116
+ const modelValue = defineModel();
117
+ const fieldData = defineModel('fieldData') as Ref<IFormMultipleOptions>;
118
+
119
+ const inputErrorStyles = ref<string[]>(styleClassPassthrough);
96
120
 
97
- const errorMessaging = computed(() => {
98
- if (
99
- typeof modelValue.value!.formFieldsC12[props.name] !== 'undefined' &&
100
- modelValue.value!.formFieldsC12[props.name].useCustomError &&
101
- modelValue.value.data[props.name] === modelValue.value.formFieldsC12[props.name].previousValue
102
- ) {
103
- return modelValue.value.formFieldsC12[props.name]?.customErrors || [];
121
+ watchEffect(() => {
122
+ if (!hasDescription.value && fieldHasError) {
123
+ inputErrorStyles.value.push('mbs-12');
104
124
  } else {
105
- return props.c12.errorMessage;
125
+ inputErrorStyles.value = inputErrorStyles.value.filter((style) => style !== 'mbs-12');
106
126
  }
107
127
  });
108
128
  </script>
109
129
 
110
130
  <style lang="css">
111
131
  .single-checkbox-fieldset {
112
- --_form-theme: var(--theme-form-primary);
113
-
114
132
  margin: 0;
115
133
  padding: 0;
116
134
  border: 0;
117
135
 
118
- &.theme-secondary {
119
- --_form-theme: var(--theme-form-secondary);
120
- }
121
-
122
- &.error {
123
- --_form-theme: var(--theme-error);
124
- }
125
-
126
136
  legend {
127
- color: var(--_form-theme);
128
137
  font-family: var(--font-family);
129
- font-size: 18px;
138
+ font-size: 16px;
130
139
  font-weight: 500;
131
- margin-bottom: 12px;
132
- transition: color 0.2s;
133
140
 
134
141
  &.has-description {
135
142
  margin-bottom: 0;
@@ -140,18 +147,26 @@ const errorMessaging = computed(() => {
140
147
  font-family: var(--font-family);
141
148
  font-size: 16px;
142
149
  margin-top: 12px;
143
- color: var(--theme-form-secondary);
150
+ }
151
+ }
152
+
153
+ .single-checkbox-items {
154
+ display: flex;
155
+ gap: 12px;
156
+ margin-top: 12px;
157
+
158
+ &.inline {
159
+ flex-direction: row;
160
+ flex-wrap: wrap;
144
161
  }
145
162
 
146
- .input-checkbox-with-label {
147
- margin-block-start: 12px;
163
+ &.block {
164
+ flex-direction: column;
148
165
  }
149
166
 
150
- /* &:has(.input-error-message.show) {
151
- .input-checkbox-with-label {
152
- margin-block-start: 12px;
153
- transition: margin 500ms linear;
154
- }
155
- } */
167
+ &.equal-widths {
168
+ display: grid;
169
+ grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
170
+ }
156
171
  }
157
172
  </style>
@@ -0,0 +1,184 @@
1
+ <template>
2
+ <div class="input-number-wrapper" :data-form-theme="formTheme" :class="elementClasses">
3
+ <div v-if="hasLeftContent" class="slot left">
4
+ <slot name="left"></slot>
5
+ </div>
6
+
7
+ <div class="input-number-container">
8
+ <input
9
+ type="number"
10
+ :id
11
+ :name
12
+ :required
13
+ :min
14
+ :max
15
+ :step
16
+ :class="['input-number-core', `input-number--${theme}`, `input-number--${size}`, `input-number--${weight}`, styleClassPassthrough]"
17
+ v-model="modelValue"
18
+ ref="inputField"
19
+ inputmode="numeric"
20
+ pattern="[0-9]+"
21
+ />
22
+ </div>
23
+ <div v-if="hasRightContent" class="slot right">
24
+ <slot name="right"></slot>
25
+ </div>
26
+ </div>
27
+ </template>
28
+
29
+ <script setup lang="ts">
30
+ import propValidators from '../c12/prop-validators';
31
+
32
+ const { id, name, required, min, max, step, theme, size, weight, fieldHasError, styleClassPassthrough } = defineProps({
33
+ id: {
34
+ type: String,
35
+ required: true,
36
+ },
37
+ name: {
38
+ type: String,
39
+ required: true,
40
+ },
41
+ min: {
42
+ type: Number,
43
+ required: true,
44
+ },
45
+ max: {
46
+ type: Number,
47
+ required: true,
48
+ },
49
+ step: {
50
+ type: Number,
51
+ default: 1,
52
+ },
53
+ placeholder: {
54
+ type: String,
55
+ default: '',
56
+ },
57
+ required: {
58
+ type: Boolean,
59
+ default: false,
60
+ },
61
+ theme: {
62
+ type: String as PropType<string>,
63
+ default: 'primary',
64
+ validator(value: string) {
65
+ return propValidators.theme.includes(value);
66
+ },
67
+ },
68
+ size: {
69
+ type: String as PropType<string>,
70
+ default: 'medium',
71
+ validator(value: string) {
72
+ return propValidators.size.includes(value);
73
+ },
74
+ },
75
+ weight: {
76
+ type: String as PropType<string>,
77
+ default: 'wght-400',
78
+ validator(value: string) {
79
+ return propValidators.weight.includes(value);
80
+ },
81
+ },
82
+ fieldHasError: {
83
+ type: Boolean,
84
+ default: false,
85
+ },
86
+ styleClassPassthrough: {
87
+ type: Array as PropType<string[]>,
88
+ default: () => [],
89
+ },
90
+ });
91
+
92
+ const slots = useSlots();
93
+ const hasLeftContent = computed(() => slots.left !== undefined);
94
+ const hasRightContent = computed(() => slots.right !== undefined);
95
+
96
+ const formTheme = computed(() => {
97
+ return fieldHasError ? 'error' : theme;
98
+ });
99
+
100
+ const modelValue = defineModel<number | readonly number[]>();
101
+
102
+ const { elementClasses, updateElementClasses } = useStyleClassPassthrough(styleClassPassthrough);
103
+ const minLength = computed(() => `${max.toString().length + 3}ch`);
104
+
105
+ onMounted(() => {
106
+ updateElementClasses(['number-1']);
107
+ });
108
+ </script>
109
+
110
+ <style lang="css">
111
+ .input-number-wrapper {
112
+ --_gutter: 12px;
113
+ --_border-width: var(--input-border-width-thin);
114
+ --_min-width: v-bind(minLength);
115
+
116
+ display: flex;
117
+ align-items: center;
118
+
119
+ width: fit-content;
120
+
121
+ .slot {
122
+ display: inline-block;
123
+ padding-inline: 8px;
124
+
125
+ .icon {
126
+ font-weight: 900;
127
+ }
128
+ }
129
+
130
+ &.has-left-slot {
131
+ .left-slot {
132
+ display: flex;
133
+ align-items: center;
134
+ }
135
+ }
136
+
137
+ &.has-right-slot {
138
+ .right-slot {
139
+ display: flex;
140
+ align-items: center;
141
+ }
142
+ }
143
+
144
+ .input-number-core {
145
+ background-color: transparent;
146
+ border: none;
147
+ outline: none;
148
+ box-shadow: none;
149
+
150
+ background-color: var(--theme-form-input-bg);
151
+ border-radius: var(--input-border-width-default);
152
+ border: var(--_border-width) solid var(--theme-form-input-border);
153
+ outline: var(--_outline-width) solid var(--theme-form-input-outline);
154
+
155
+ /* color: var(--theme-form-input-text); */
156
+ font-family: var(--font-family);
157
+ font-size: var(--theme-form-button-font-size-normal);
158
+ line-height: var(--line-height);
159
+ padding: 4px 16px;
160
+ text-align: center;
161
+ min-width: var(--_min-width);
162
+
163
+ &:focus-visible {
164
+ border: var(--_border-width) solid var(--theme-form-input-border);
165
+ outline: var(--_outline-width) solid hsl(from var(--theme-form-input-outline-focus) h s 50%);
166
+ box-shadow: var(--theme-form-focus-box-shadow);
167
+ }
168
+
169
+ &::placeholder,
170
+ &::-webkit-input-placeholder {
171
+ font-family: var(--font-family);
172
+ font-size: var(--font-size);
173
+ font-style: italic;
174
+ font-weight: 400;
175
+ }
176
+ }
177
+ }
178
+
179
+ input[type='number']::-webkit-inner-spin-button,
180
+ input[type='number']::-webkit-outer-spin-button {
181
+ -webkit-appearance: none;
182
+ margin: 0;
183
+ }
184
+ </style>
@@ -0,0 +1,155 @@
1
+ <template>
2
+ <div class="input-number-with-label" :data-form-theme="formTheme" :class="[elementClasses, `theme-${theme}`, { error: fieldHasError }]">
3
+ <label class="input-number-label body-normal-bold" :for="id">{{ label }}</label>
4
+ <template v-if="hasDescription">
5
+ <slot name="description"></slot>
6
+ </template>
7
+
8
+ <InputNumberCore v-model="modelValue" :id :name :min :max :step :theme :required :size :weight :fieldHasError>
9
+ <template v-if="hasLeftContent" #left>
10
+ <InputButtonCore
11
+ type="button"
12
+ @click.stop.prevent="updateValue(-step, Number(modelValue) > min)"
13
+ :readonly="Number(modelValue) === min"
14
+ :is-pending="false"
15
+ buttonText="Step down"
16
+ theme="primary"
17
+ size="x-small"
18
+ >
19
+ <template #iconOnly>
20
+ <slot name="left"></slot>
21
+ </template>
22
+ </InputButtonCore>
23
+ </template>
24
+ <template v-if="hasRightContent" #right>
25
+ <InputButtonCore
26
+ type="button"
27
+ @click.stop.prevent="updateValue(step, Number(modelValue) < max)"
28
+ :readonly="Number(modelValue) === max"
29
+ :is-pending="false"
30
+ buttonText="Step up"
31
+ theme="primary"
32
+ size="x-small"
33
+ >
34
+ <template #iconOnly>
35
+ <slot name="right"></slot>
36
+ </template>
37
+ </InputButtonCore>
38
+ </template>
39
+ </InputNumberCore>
40
+ <InputError :errorMessage :fieldHasError :id :isDetached="true" />
41
+ </div>
42
+ </template>
43
+
44
+ <script setup lang="ts">
45
+ import propValidators from '../../c12/prop-validators';
46
+
47
+ const { id, name, label, required, min, max, step, theme, size, weight, styleClassPassthrough, errorMessage, fieldHasError } = defineProps({
48
+ id: {
49
+ type: String,
50
+ required: true,
51
+ },
52
+ name: {
53
+ type: String,
54
+ required: true,
55
+ },
56
+ label: {
57
+ type: String,
58
+ required: true,
59
+ },
60
+ min: {
61
+ type: Number,
62
+ required: true,
63
+ },
64
+ max: {
65
+ type: Number,
66
+ required: true,
67
+ },
68
+ step: {
69
+ type: Number,
70
+ default: 1,
71
+ },
72
+ placeholder: {
73
+ type: String,
74
+ default: '',
75
+ },
76
+ errorMessage: {
77
+ type: [Object, String],
78
+ required: true,
79
+ },
80
+ fieldHasError: {
81
+ type: Boolean,
82
+ default: false,
83
+ },
84
+ required: {
85
+ type: Boolean,
86
+ default: false,
87
+ },
88
+ theme: {
89
+ type: String as PropType<string>,
90
+ default: 'primary',
91
+ validator(value: string) {
92
+ return propValidators.theme.includes(value);
93
+ },
94
+ },
95
+ size: {
96
+ type: String as PropType<string>,
97
+ default: 'medium',
98
+ validator(value: string) {
99
+ return propValidators.size.includes(value);
100
+ },
101
+ },
102
+ weight: {
103
+ type: String as PropType<string>,
104
+ default: 'wght-400',
105
+ validator(value: string) {
106
+ return propValidators.weight.includes(value);
107
+ },
108
+ },
109
+ styleClassPassthrough: {
110
+ type: Array as PropType<string[]>,
111
+ default: () => [],
112
+ },
113
+ });
114
+
115
+ const slots = useSlots();
116
+ const hasDescription = computed(() => slots.description !== undefined);
117
+ const hasLeftContent = computed(() => slots.left !== undefined);
118
+ const hasRightContent = computed(() => slots.right !== undefined);
119
+ const { elementClasses, updateElementClasses } = useStyleClassPassthrough(styleClassPassthrough);
120
+
121
+ const formTheme = computed(() => {
122
+ return fieldHasError ? 'error' : theme;
123
+ });
124
+
125
+ const modelValue = defineModel<number | readonly number[]>();
126
+
127
+ const updateValue = (step: number, withinRangeLimit: boolean) => {
128
+ if (withinRangeLimit) {
129
+ modelValue.value = (Number(modelValue.value) + step) as number;
130
+ }
131
+ };
132
+ </script>
133
+
134
+ <style lang="css">
135
+ .input-number-with-label {
136
+ --_border-width: var(--input-border-width-default);
137
+ --_outline-width: var(--input-outline-width-thin);
138
+ --_label-padding-inline: 10px;
139
+
140
+ .input-number-label {
141
+ display: block;
142
+ margin-block: 8px;
143
+
144
+ &:hover {
145
+ cursor: pointer;
146
+ }
147
+ }
148
+
149
+ .label-description {
150
+ font-family: var(--font-family);
151
+ font-size: 16px;
152
+ margin-top: 12px;
153
+ }
154
+ }
155
+ </style>