srcdev-nuxt-forms 3.0.0 → 4.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 (86) hide show
  1. package/assets/styles/ally/_utils.css +20 -0
  2. package/assets/styles/ally/_variables.css +8 -0
  3. package/assets/styles/ally/index.css +2 -0
  4. package/assets/styles/forms/index.css +2 -0
  5. package/assets/styles/forms/themes/_error.css +85 -0
  6. package/assets/styles/forms/themes/_ghost.css +85 -0
  7. package/assets/styles/forms/themes/_input-action-underlined.css +20 -0
  8. package/assets/styles/forms/themes/_input-action.css +20 -0
  9. package/assets/styles/forms/themes/_primary.css +92 -0
  10. package/assets/styles/forms/themes/_secondary.css +85 -0
  11. package/assets/styles/forms/themes/_success.css +85 -0
  12. package/assets/styles/forms/themes/_tertiary.css +85 -0
  13. package/assets/styles/forms/themes/_warning.css +85 -0
  14. package/assets/styles/forms/themes/index.css +9 -0
  15. package/assets/styles/forms/variables/_sizes.css +71 -0
  16. package/assets/styles/forms/variables/_theme.css +11 -0
  17. package/assets/styles/forms/variables/index.css +2 -0
  18. package/assets/styles/main.css +5 -0
  19. package/assets/styles/typography/index.css +2 -0
  20. package/assets/styles/typography/utils/_font-classes.css +190 -0
  21. package/assets/styles/typography/utils/_weights.css +69 -0
  22. package/assets/styles/typography/utils/index.css +2 -0
  23. package/assets/styles/typography/variables/_colors.css +14 -0
  24. package/assets/styles/typography/variables/_reponsive-font-size.css +10 -0
  25. package/assets/styles/typography/variables/index.css +2 -0
  26. package/assets/styles/utils/_margin-helpers.css +334 -0
  27. package/assets/styles/utils/_padding-helpers.css +308 -0
  28. package/assets/styles/utils/_page.css +49 -0
  29. package/assets/styles/utils/index.css +3 -0
  30. package/assets/styles/variables/colors/_blue.css +15 -0
  31. package/assets/styles/variables/colors/_gray.css +16 -0
  32. package/assets/styles/variables/colors/_green.css +15 -0
  33. package/assets/styles/variables/colors/_orange.css +15 -0
  34. package/assets/styles/variables/colors/_red.css +15 -0
  35. package/assets/styles/variables/colors/_yellow.css +15 -0
  36. package/assets/styles/variables/colors/colors.css +6 -0
  37. package/assets/styles/variables/index.css +1 -0
  38. package/components/forms/c12/prop-validators/index.ts +38 -0
  39. package/components/forms/c12/utils.ts +14 -0
  40. package/components/forms/form-errors/InputError.vue +172 -0
  41. package/components/forms/form-errors/tests/InputError.spec.ts +67 -0
  42. package/components/forms/input-button/InputButtonCore.vue +191 -0
  43. package/components/forms/input-button/variants/InputButtonConfirm.vue +66 -0
  44. package/components/forms/input-button/variants/InputButtonSubmit.vue +62 -0
  45. package/components/forms/input-checkbox/MultipleCheckboxes.vue +203 -0
  46. package/components/forms/input-checkbox/SingleCheckbox.vue +169 -0
  47. package/components/forms/input-checkbox/tests/MultipleCheckboxes.spec.ts +98 -0
  48. package/components/forms/input-checkbox/tests/data/tags.json +67 -0
  49. package/components/forms/input-checkbox-radio/InputCheckboxRadioButton.vue +214 -0
  50. package/components/forms/input-checkbox-radio/InputCheckboxRadioCore.vue +191 -0
  51. package/components/forms/input-checkbox-radio/InputCheckboxRadioWithLabel.vue +111 -0
  52. package/components/forms/input-number/InputNumberCore.vue +203 -0
  53. package/components/forms/input-number/variants/InputNumberDefault.vue +154 -0
  54. package/components/forms/input-radio/MultipleRadiobuttons.vue +201 -0
  55. package/components/forms/input-radio/tests/MultipleRadioButtons.spec.ts +89 -0
  56. package/components/forms/input-radio/tests/data/tags.json +67 -0
  57. package/components/forms/input-range/InputRangeCore.vue +274 -0
  58. package/components/forms/input-range/variants/InputRangeDefault.vue +156 -0
  59. package/components/forms/input-range-fancy/InputRangeFancyCore.vue +450 -0
  60. package/components/forms/input-range-fancy/InputRangeFancyWithLabel.vue +124 -0
  61. package/components/forms/input-text/InputTextCore.vue +331 -0
  62. package/components/forms/input-text/variants/InputPasswordWithLabel.vue +130 -0
  63. package/components/forms/input-text/variants/InputTextAsNumberWithLabel.vue +187 -0
  64. package/components/forms/input-text/variants/InputTextWithLabel.vue +298 -0
  65. package/components/forms/input-textarea/InputTextareaCore.vue +234 -0
  66. package/components/forms/input-textarea/variants/InputTextareaWithLabel.vue +267 -0
  67. package/components/forms/toggle-switch/ToggleSwitchCore.vue +198 -0
  68. package/components/forms/toggle-switch/ToggleSwitchCoreOld.vue +216 -0
  69. package/components/forms/toggle-switch/variants/ToggleSwitchWithLabel.vue +105 -0
  70. package/components/forms/toggle-switch/variants/ToggleSwitchWithLabelInline.vue +102 -0
  71. package/components/forms/ui/FormField.vue +78 -0
  72. package/components/forms/ui/FormWrapper.vue +35 -0
  73. package/components/utils/colour-scheme-select/ColourSchemeSelect.vue +270 -0
  74. package/components/utils/colour-scheme-select/ColourSchemeSelectOld.vue +225 -0
  75. package/components/utils/dark-mode-switcher/DarkModeSwitcher.vue +47 -0
  76. package/composables/useApiRequest.ts +25 -0
  77. package/composables/useColourScheme.ts +25 -0
  78. package/composables/useErrorMessages.ts +59 -0
  79. package/composables/useFormControl.ts +248 -0
  80. package/composables/useSleep.ts +5 -0
  81. package/composables/useStyleClassPassthrough.ts +30 -0
  82. package/composables/useZodValidation.ts +148 -0
  83. package/nuxt.config.ts +0 -3
  84. package/package.json +1 -1
  85. package/types/types.forms.ts +216 -0
  86. package/types/types.zodFormControl.ts +21 -0
@@ -0,0 +1,105 @@
1
+ <template>
2
+ <div class="toggle-switch-with-label" :class="[elementClasses]" :data-form-theme="formTheme">
3
+ <label class="toggle-switch-label input-text-label body-normal-bold" :for="`toggle-sitch-${id}`">{{ label }}</label>
4
+ <div v-if="hasDescriptionSlot" :id="`${id}-description`">
5
+ <slot name="description"></slot>
6
+ </div>
7
+ <ToggleSwitchCore v-model="modelValue" :id :name :required :field-has-error :true-value :false-value :theme :round :size :ariaDescribedby>
8
+ <template v-if="hasIconOnSlot" #iconOn>
9
+ <slot name="iconOn"></slot>
10
+ </template>
11
+
12
+ <template v-if="hasIconOffSlot" #iconOff>
13
+ <slot name="iconOff"></slot>
14
+ </template>
15
+ </ToggleSwitchCore>
16
+ <InputError :errorMessage :showError="fieldHasError" :id="errorId" :isDetached="true" />
17
+ </div>
18
+ </template>
19
+
20
+ <script setup lang="ts">
21
+ import propValidators from '../../c12/prop-validators';
22
+
23
+ const props = defineProps({
24
+ name: {
25
+ type: String,
26
+ required: true,
27
+ },
28
+ label: {
29
+ type: String,
30
+ required: true,
31
+ },
32
+ required: {
33
+ type: Boolean,
34
+ default: false,
35
+ },
36
+ errorMessage: {
37
+ type: [Object, String],
38
+ default: '',
39
+ required: false,
40
+ },
41
+ fieldHasError: {
42
+ type: Boolean,
43
+ default: false,
44
+ },
45
+ trueValue: {
46
+ type: [String, Number, Boolean],
47
+ default: true,
48
+ },
49
+ falseValue: {
50
+ type: [String, Number, Boolean],
51
+ default: false,
52
+ },
53
+ styleClassPassthrough: {
54
+ type: Array as PropType<string[]>,
55
+ default: () => [],
56
+ },
57
+ theme: {
58
+ type: String as PropType<string>,
59
+ default: 'primary',
60
+ validator(value: string) {
61
+ return propValidators.theme.includes(value);
62
+ },
63
+ },
64
+ round: {
65
+ type: Boolean,
66
+ default: true,
67
+ },
68
+ size: {
69
+ type: String as PropType<string>,
70
+ default: 'normal',
71
+ validator(value: string) {
72
+ return propValidators.size.includes(value);
73
+ },
74
+ },
75
+ });
76
+
77
+ const slots = useSlots();
78
+ const hasDescriptionSlot = computed(() => slots.description !== undefined);
79
+ const hasIconOnSlot = computed(() => slots.iconOn !== undefined);
80
+ const hasIconOffSlot = computed(() => slots.iconOff !== undefined);
81
+
82
+ const formTheme = computed(() => {
83
+ return props.fieldHasError ? 'error' : props.theme;
84
+ });
85
+
86
+ const id = useId();
87
+ const errorId = `${id}-error-message`;
88
+ const ariaDescribedby = computed(() => {
89
+ const ariaDescribedbyId = hasDescriptionSlot.value ? `${id}-description` : undefined;
90
+ return props.fieldHasError ? errorId : ariaDescribedbyId;
91
+ });
92
+
93
+ const modelValue = defineModel();
94
+ const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
95
+ </script>
96
+
97
+ <style lang="css">
98
+ .toggle-switch-with-label {
99
+ --_transition-duration: 0.4s;
100
+
101
+ .toggle-switch-label {
102
+ display: block;
103
+ }
104
+ }
105
+ </style>
@@ -0,0 +1,102 @@
1
+ <template>
2
+ <div class="toggle-switch-with-label-inline" :class="[elementClasses]" :data-form-theme="theme">
3
+ <label class="toggle-switch-label input-text-label" :class="labelWeightClass" :for="`toggle-sitch-${id}`">{{ label }}</label>
4
+ <ToggleSwitchCore v-model="modelValue" :id :name :true-value :false-value :theme :round :size>
5
+ <template v-if="hasIconOnSlot" #iconOn>
6
+ <slot name="iconOn"></slot>
7
+ </template>
8
+
9
+ <template v-if="hasIconOffSlot" #iconOff>
10
+ <slot name="iconOff"></slot>
11
+ </template>
12
+ </ToggleSwitchCore>
13
+ </div>
14
+ </template>
15
+
16
+ <script setup lang="ts">
17
+ import propValidators from '../../c12/prop-validators';
18
+
19
+ const props = defineProps({
20
+ name: {
21
+ type: String,
22
+ required: true,
23
+ },
24
+ label: {
25
+ type: String,
26
+ required: true,
27
+ },
28
+ labelWeight: {
29
+ type: String as PropType<string>,
30
+ default: 'semi-bold',
31
+ validator(value: string) {
32
+ return propValidators.labelWeight.includes(value);
33
+ },
34
+ },
35
+ trueValue: {
36
+ type: [String, Number, Boolean],
37
+ default: true,
38
+ },
39
+ falseValue: {
40
+ type: [String, Number, Boolean],
41
+ default: false,
42
+ },
43
+ styleClassPassthrough: {
44
+ type: Array as PropType<string[]>,
45
+ default: () => [],
46
+ },
47
+ theme: {
48
+ type: String as PropType<string>,
49
+ default: 'primary',
50
+ validator(value: string) {
51
+ return propValidators.theme.includes(value);
52
+ },
53
+ },
54
+ round: {
55
+ type: Boolean,
56
+ default: true,
57
+ },
58
+ size: {
59
+ type: String as PropType<string>,
60
+ default: 'normal',
61
+ validator(value: string) {
62
+ return propValidators.size.includes(value);
63
+ },
64
+ },
65
+ });
66
+
67
+ const slots = useSlots();
68
+ const hasIconOnSlot = computed(() => slots.iconOn !== undefined);
69
+ const hasIconOffSlot = computed(() => slots.iconOff !== undefined);
70
+
71
+ const id = useId();
72
+
73
+ const labelWeightClass = computed(() => {
74
+ switch (props.labelWeight) {
75
+ case 'bold':
76
+ return 'body-normal-bold';
77
+ case 'semi-bold':
78
+ return 'body-normal-semibold';
79
+ case 'normal':
80
+ return 'body-normal';
81
+ default:
82
+ return 'body-normal-semibold';
83
+ }
84
+ });
85
+
86
+ const modelValue = defineModel();
87
+ const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
88
+ </script>
89
+
90
+ <style lang="css">
91
+ .toggle-switch-with-label-inline {
92
+ --_transition-duration: 0.4s;
93
+ display: flex;
94
+ align-items: center;
95
+ gap: 12px;
96
+
97
+ .toggle-switch-label {
98
+ display: block;
99
+ white-space: nowrap;
100
+ }
101
+ }
102
+ </style>
@@ -0,0 +1,78 @@
1
+ <template>
2
+ <div class="form-field" :class="[width, styleClassPassthrough, { 'has-gutter': hasGutter }, { error: fieldHasError }]">
3
+ <div class="form-field-inner">
4
+ <slot name="default"></slot>
5
+ </div>
6
+ </div>
7
+ </template>
8
+
9
+ <script setup lang="ts">
10
+ defineProps({
11
+ width: {
12
+ type: String as PropType<string>,
13
+ default: 'narrow',
14
+ validator: (val: string) => ['narrow', 'medium', 'wide'].includes(val),
15
+ },
16
+ fieldHasError: {
17
+ type: Boolean as PropType<boolean>,
18
+ default: false,
19
+ },
20
+ hasGutter: {
21
+ type: Boolean as PropType<boolean>,
22
+ default: true,
23
+ },
24
+ styleClassPassthrough: {
25
+ type: String,
26
+ default: '',
27
+ },
28
+ });
29
+ </script>
30
+
31
+ <style lang="css">
32
+ .form-field {
33
+ --_gutter-width: 0rem;
34
+ --_max-width: 400px;
35
+ --_background-color: transparent;
36
+ --_border-radius: 0.4rem;
37
+
38
+ background-color: var(--_background-color);
39
+ border-radius: var(--_border-radius);
40
+ margin-inline: auto;
41
+ margin-block: 1lh;
42
+
43
+ width: min(100% - calc(2 * var(--_gutter-width)), var(--_max-width));
44
+ outline: 0rem solid var(--gray-5);
45
+
46
+ &.error {
47
+ background-color: var(--theme-error-surface);
48
+ }
49
+
50
+ &:has(.underline) {
51
+ --_background-color: var(--theme-form-input-bg-underlined);
52
+ }
53
+
54
+ .form-field-inner {
55
+ background-color: var(--_background-color);
56
+ border-radius: var(--_border-radius);
57
+ margin-inline-start: 0rem;
58
+ padding-inline-start: 0rem;
59
+ outline: 0 solid var(--gray-5);
60
+ }
61
+
62
+ &.has-gutter {
63
+ --_gutter-width: 1.6rem;
64
+ }
65
+
66
+ &.narrow {
67
+ max-width: 400px;
68
+ }
69
+
70
+ &.medium {
71
+ --_max-width: 800px;
72
+ }
73
+
74
+ &.wide {
75
+ --_max-width: 1200px;
76
+ }
77
+ }
78
+ </style>
@@ -0,0 +1,35 @@
1
+ <template>
2
+ <div class="form-wrapper" :class="width">
3
+ <slot name="default"></slot>
4
+ </div>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+ defineProps({
9
+ width: {
10
+ type: String as PropType<string>,
11
+ default: 'narrow',
12
+ validator: (val: string) => ['narrow', 'medium', 'wide'].includes(val),
13
+ },
14
+ });
15
+ </script>
16
+
17
+ <style lang="css">
18
+ .form-wrapper {
19
+ outline: 0rem solid var(--gray-12);
20
+ padding-bottom: 2rem;
21
+ margin-trim: block;
22
+
23
+ &.narrow {
24
+ max-width: 400px;
25
+ }
26
+
27
+ &.medium {
28
+ max-width: 800px;
29
+ }
30
+
31
+ &.wide {
32
+ max-width: 1200px;
33
+ }
34
+ }
35
+ </style>
@@ -0,0 +1,270 @@
1
+ <template>
2
+ <div class="colour-scheme-select" :data-size="size" :data-form-theme="theme">
3
+ <p>Color Scheme select</p>
4
+
5
+ <form class="colour-scheme-select-form mbe-20" ref="colourSchemeWrapper">
6
+ <div class="select-scheme-marker-wrapper">
7
+ <div class="select-scheme-marker" :class="[{ show: showMarker }]"></div>
8
+ </div>
9
+ <div class="select-scheme-group-wrapper">
10
+ <div class="select-scheme-group">
11
+ <LazyIcon name="material-symbols:night-sight-auto-sharp" class="scheme-icon" />
12
+ <input type="radio" id="auto" name="colour-scheme" class="scheme-input" v-model="currentColourScheme" value="auto" />
13
+ <label for="auto" class="sr-only">Auto</label>
14
+ </div>
15
+ <div class="select-scheme-group">
16
+ <LazyIcon name="radix-icons:sun" class="scheme-icon" />
17
+ <input type="radio" id="light" name="colour-scheme" class="scheme-input" v-model="currentColourScheme" value="light" />
18
+ <label for="light" class="sr-only">Light</label>
19
+ </div>
20
+ <div class="select-scheme-group">
21
+ <LazyIcon name="radix-icons:moon" class="scheme-icon" />
22
+ <input type="radio" id="dark" name="colour-scheme" class="scheme-input" v-model="currentColourScheme" value="dark" />
23
+ <label for="dark" class="sr-only">Dark</label>
24
+ </div>
25
+ </div>
26
+ </form>
27
+ </div>
28
+ </template>
29
+
30
+ <script setup lang="ts">
31
+ import propValidators from '../../forms/c12/prop-validators';
32
+
33
+ const props = defineProps({
34
+ name: {
35
+ type: String,
36
+ defaul: 'colour-scheme-select',
37
+ },
38
+ size: {
39
+ type: String as PropType<string>,
40
+ default: 'medium',
41
+ validator(value: string) {
42
+ return propValidators.size.includes(value);
43
+ },
44
+ },
45
+ theme: {
46
+ type: String as PropType<string>,
47
+ default: 'primary',
48
+ validator(value: string) {
49
+ return propValidators.theme.includes(value);
50
+ },
51
+ },
52
+ stepAnimationDuration: {
53
+ type: Number as PropType<number>,
54
+ default: 100,
55
+ },
56
+ styleClassPassthrough: {
57
+ type: Array as PropType<string[]>,
58
+ default: () => [],
59
+ },
60
+ });
61
+
62
+ const duration = ref(props.stepAnimationDuration);
63
+
64
+ const { currentColourScheme } = useColourScheme();
65
+
66
+ const colourSchemeWrapper = ref<HTMLFormElement | null>(null);
67
+ const colourSchemeGroupElements = ref<HTMLDivElement[]>([]);
68
+ const colourSchemeInputElements = ref<HTMLInputElement[]>([]);
69
+ const showMarker = ref(false);
70
+
71
+ const findIndexOfInputValueFromCurrentColourScheme = () => {
72
+ if (currentColourScheme.value === 'auto') return 1;
73
+ if (currentColourScheme.value === 'light') return 2;
74
+ if (currentColourScheme.value === 'dark') return 3;
75
+ return undefined;
76
+ };
77
+
78
+ const findIndexOfCheckedInput = () => {
79
+ return colourSchemeInputElements.value.findIndex((input) => input.checked);
80
+ };
81
+
82
+ const currentActiveIndex = ref(findIndexOfCheckedInput());
83
+
84
+ const setColourSchemeAttr = async () => {
85
+ const index = findIndexOfInputValueFromCurrentColourScheme() ?? 0;
86
+
87
+ await nextTick();
88
+ currentActiveIndex.value = findIndexOfCheckedInput();
89
+
90
+ const wrapperLeftPosition = colourSchemeWrapper.value?.getBoundingClientRect().left ?? 0;
91
+ const parentLeftPosition = colourSchemeWrapper.value?.parentElement?.getBoundingClientRect().left ?? 0;
92
+ const relativeLeftPosition = wrapperLeftPosition - parentLeftPosition;
93
+
94
+ colourSchemeWrapper.value?.style.setProperty('--_select-scheme-marker-step-animation-duration', colourSchemeGroupElements.value?.length * duration.value + 'ms');
95
+
96
+ colourSchemeWrapper.value?.style.setProperty('--_select-scheme-marker-position', index !== undefined ? index.toString() : '0');
97
+ colourSchemeWrapper.value?.style.setProperty('--_select-scheme-marker-left-offset', colourSchemeGroupElements.value?.[index - 1]?.offsetLeft - relativeLeftPosition + 'px');
98
+ colourSchemeWrapper.value?.style.setProperty('--_select-scheme-marker-width', colourSchemeGroupElements.value?.[index - 1]?.getBoundingClientRect().width + 'px');
99
+ };
100
+
101
+ const handleInputActiveClass = () => {
102
+ colourSchemeInputElements.value.forEach((element) => {
103
+ element.classList.remove('active');
104
+ });
105
+
106
+ setTimeout(() => {
107
+ colourSchemeInputElements.value?.[currentActiveIndex.value].classList.add('active');
108
+ }, duration.value);
109
+ };
110
+
111
+ onMounted(() => {
112
+ colourSchemeGroupElements.value = Array.from(colourSchemeWrapper.value?.querySelectorAll('.select-scheme-group') || []) as HTMLInputElement[];
113
+ colourSchemeInputElements.value = Array.from(colourSchemeWrapper.value?.querySelectorAll('.scheme-input') || []) as HTMLInputElement[];
114
+
115
+ if (colourSchemeWrapper.value !== null) {
116
+ setColourSchemeAttr();
117
+ setTimeout(() => {
118
+ showMarker.value = true;
119
+ handleInputActiveClass();
120
+ }, duration.value);
121
+ }
122
+ });
123
+
124
+ watch(currentColourScheme, () => {
125
+ setColourSchemeAttr();
126
+ });
127
+
128
+ watch(currentActiveIndex, () => {
129
+ handleInputActiveClass();
130
+ });
131
+ </script>
132
+
133
+ <style lang="css">
134
+ .colour-scheme-select {
135
+ --_form-background-color: var(--theme-form-checkbox-bg);
136
+ --_form-border-width: 0.1rem;
137
+ --_form-border-colour: var(--theme-form-radio-border);
138
+ --_form-outline-width: 0.1rem;
139
+
140
+ --_form-outline-colour: var(--theme-form-radio-outline);
141
+
142
+ --_form-border-radius: calc(
143
+ (var(--_scheme-icon-font-size) / 2) + var(--_form-border-width) + var(--_form-outline-width) + var(--_form-padding) + var(--_select-scheme-group-padding) + var(--_select-scheme-group-border-width) +
144
+ var(--_select-scheme-group-outline-width)
145
+ );
146
+
147
+ --_form-items-gap: 1rem;
148
+ --_form-padding: 0.6rem;
149
+
150
+ --_select-scheme-group-background-color: var(--theme-form-checkbox-bg);
151
+ --_select-scheme-group-padding: 0.5rem;
152
+ --_select-scheme-group-border-width: 0.2rem;
153
+ --_select-scheme-group-border-colour: transparent;
154
+ --_select-scheme-group-outline-width: 0.2rem;
155
+ --_select-scheme-group-outline-colour: transparent;
156
+ --_select-scheme-group-width: calc(
157
+ var(--_scheme-icon-font-size) + (var(--_select-scheme-group-padding) * 2) + (var(--_select-scheme-group-border-width) * 2) + (var(--_select-scheme-group-outline-width) * 2)
158
+ );
159
+
160
+ --_scheme-icon-font-size: 2rem;
161
+ --_scheme-icon-colour: black;
162
+
163
+ .colour-scheme-select-form {
164
+ display: inline-grid;
165
+ grid-template-areas: 'select-stack';
166
+ width: fit-content;
167
+
168
+ background-color: var(--_form-background-color);
169
+ border: var(--_form-border-width) solid var(--_form-border-colour);
170
+ outline: var(--_form-outline-width) solid var(--_form-outline-colour);
171
+ border-radius: var(--_form-border-radius);
172
+ padding: var(--_form-padding);
173
+
174
+ .select-scheme-marker-wrapper {
175
+ grid-area: select-stack;
176
+ z-index: 1;
177
+ display: flex;
178
+ align-items: center;
179
+ position: relative;
180
+
181
+ .select-scheme-marker {
182
+ aspect-ratio: 1;
183
+ width: var(--_select-scheme-group-width);
184
+ transition: all var(--_select-scheme-marker-step-animation-duration) ease-in-out;
185
+ background-color: var(--theme-form-radio-border);
186
+ border-radius: 50%;
187
+
188
+ position: absolute;
189
+ left: calc(var(--_select-scheme-marker-left-offset) - var(--_select-scheme-group-border-width));
190
+
191
+ opacity: 0;
192
+
193
+ &.show {
194
+ opacity: 1;
195
+ }
196
+ }
197
+ }
198
+
199
+ .select-scheme-group-wrapper {
200
+ display: grid;
201
+ grid-area: select-stack;
202
+ grid-template-columns: repeat(3, 1fr);
203
+ align-items: center;
204
+ width: fit-content;
205
+ z-index: 2;
206
+ gap: var(--_form-items-gap);
207
+ position: relative;
208
+
209
+ .select-scheme-group {
210
+ aspect-ratio: 1;
211
+ display: grid;
212
+ grid-template-areas: 'icon-stack';
213
+ place-content: center;
214
+ background: var(--_select-scheme-group-background-color);
215
+ border: var(--_select-scheme-group-border-width) solid var(--_select-scheme-group-border-colour);
216
+ outline: var(--_select-scheme-group-outline-width) solid var(--_select-scheme-group-outline-colour);
217
+ border-radius: 50%;
218
+ padding: var(--_select-scheme-group-padding);
219
+
220
+ transition: background calc(var(--_select-scheme-marker-step-animation-duration) / 3);
221
+
222
+ .scheme-icon {
223
+ grid-area: icon-stack;
224
+ display: block;
225
+ color: var(--_scheme-icon-colour);
226
+ font-size: var(--_scheme-icon-font-size);
227
+
228
+ &:hover {
229
+ cursor: pointer;
230
+ }
231
+ }
232
+
233
+ .scheme-input {
234
+ grid-area: icon-stack;
235
+ opacity: 0;
236
+
237
+ &:hover {
238
+ cursor: pointer;
239
+ }
240
+ }
241
+
242
+ &:has(input[value='auto']) {
243
+ &:has(.active) {
244
+ --_select-scheme-group-background-color: green;
245
+ --_scheme-icon-colour: white;
246
+ }
247
+ }
248
+
249
+ &:has(input[value='light']) {
250
+ &:has(.active) {
251
+ /* background: rgb(180, 58, 91);
252
+ background: linear-gradient(90deg, rgba(180, 58, 91, 1) 0%, rgba(253, 29, 29, 1) 50%, rgba(252, 176, 69, 1) 100%); */
253
+ --_select-scheme-group-background-color: radial-gradient(circle, rgba(180, 58, 91, 1) 0%, rgba(253, 29, 29, 1) 27%, rgba(252, 176, 69, 1) 100%);
254
+ /* --_select-scheme-group-background-color: radial-gradient(circle, rgba(63, 94, 251, 1) 70%, rgba(63, 94, 251, 0.5550814075630253) 90%, rgba(255, 255, 255, 0.42622986694677867) 100%); */
255
+
256
+ --_scheme-icon-colour: white;
257
+ }
258
+ }
259
+
260
+ &:has(input[value='dark']) {
261
+ &:has(.active) {
262
+ --_select-scheme-group-background-color: black;
263
+ --_scheme-icon-colour: white;
264
+ }
265
+ }
266
+ }
267
+ }
268
+ }
269
+ }
270
+ </style>