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,15 @@
1
+ :root {
2
+ --orange-0: #fff4e6;
3
+ --orange-1: #ffe8cc;
4
+ --orange-2: #ffd8a8;
5
+ --orange-3: #ffc078;
6
+ --orange-4: #ffa94d;
7
+ --orange-5: #ff922b;
8
+ --orange-6: #ff7400;
9
+ --orange-7: #f76707;
10
+ --orange-8: #e8590c;
11
+ --orange-9: #d9480f;
12
+ --orange-10: #bf400d;
13
+ --orange-11: #99330b;
14
+ --orange-12: #c23903;
15
+ }
@@ -0,0 +1,15 @@
1
+ :root {
2
+ --red-0: #fff5f5;
3
+ --red-1: #ffe3e3;
4
+ --red-2: #ffc9c9;
5
+ --red-3: #ffa8a8;
6
+ --red-4: #ff8787;
7
+ --red-5: #ff6b6b;
8
+ --red-6: #fa5252;
9
+ --red-7: #f03e3e;
10
+ --red-8: #e03131;
11
+ --red-9: #ff0b0b;
12
+ --red-10: #b02525;
13
+ --red-11: #962020;
14
+ --red-12: #cc0000;
15
+ }
@@ -0,0 +1,15 @@
1
+ :root {
2
+ --yellow-0: #fff9db;
3
+ --yellow-1: #fff3bf;
4
+ --yellow-2: #ffec99;
5
+ --yellow-3: #ffe066;
6
+ --yellow-4: #ffd43b;
7
+ --yellow-5: #fcc419;
8
+ --yellow-6: #fab005;
9
+ --yellow-7: #f59f00;
10
+ --yellow-8: #f08c00;
11
+ --yellow-9: #e67700;
12
+ --yellow-10: #b35c00;
13
+ --yellow-11: #804200;
14
+ --yellow-12: #663500;
15
+ }
@@ -0,0 +1,6 @@
1
+ @import './_red.css';
2
+ @import './_green.css';
3
+ @import './_blue.css';
4
+ @import './_orange.css';
5
+ @import './_gray.css';
6
+ @import './_yellow.css';
@@ -0,0 +1 @@
1
+ @import './colors/colors.css';
@@ -0,0 +1,38 @@
1
+ export const propValidators = {
2
+ size: ['x-small', 'small', 'normal', 'medium', 'large'],
3
+ weight: [
4
+ 'wght-100',
5
+ 'wght-200',
6
+ 'wght-300',
7
+ 'wght-400',
8
+ 'wght-500',
9
+ 'wght-600',
10
+ 'wght-700',
11
+ 'wght-800',
12
+ 'wght-900',
13
+ 'light',
14
+ 'normal',
15
+ 'bold',
16
+ 'fvs-wght-100',
17
+ 'fvs-wght-200',
18
+ 'fvs-wght-300',
19
+ 'fvs-wght-400',
20
+ 'fvs-wght-500',
21
+ 'fvs-wght-600',
22
+ 'fvs-wght-700',
23
+ 'fvs-wght-800',
24
+ 'fvs-wght-900',
25
+ ],
26
+ theme: ['primary', 'secondary', 'tertiary', 'ghost', 'error', 'success', 'warning', 'input-action', 'input-action-underlined'],
27
+ checkboxAppearance: [null, 'with-decorator'],
28
+ checkboxStyle: ['check', 'cross'],
29
+ radioAppearance: [null, 'with-decorator'],
30
+ optionsLayout: ['block', 'inline', 'equal-widths'],
31
+ labelWeight: ['normal', 'semi-bold', 'bold'],
32
+ inputVariant: ['normal', 'outlined', 'underlined'],
33
+ inputTypesButton: ['button', 'cancel', 'reset', 'submit'],
34
+ inputTypesText: ['text', 'email', 'password', 'number', 'tel', 'url'],
35
+ inputMode: ['text', 'email', 'tel', 'url', 'search', 'numeric', 'none', 'decimal'],
36
+ };
37
+
38
+ export default propValidators;
@@ -0,0 +1,14 @@
1
+ import type { InpuTextC12, IFormFieldC12, IFormData } from '@/types/types.forms';
2
+
3
+ const formFieldC12 = <IFormFieldC12>{
4
+ label: '',
5
+ placeholder: '',
6
+ errorMessage: '',
7
+ useCustomError: false,
8
+ customErrors: {},
9
+ isValid: false,
10
+ isDirty: false,
11
+ type: 'string',
12
+ };
13
+
14
+ export { formFieldC12 };
@@ -0,0 +1,172 @@
1
+ <template>
2
+ <div class="input-error-message" :id :class="[inputVariant, elementClasses, { show: showError }, { detached: isDetached }, { hide: !showError }]" :data-Testid>
3
+ <div class="inner" :class="[{ show: showError }]">
4
+ <div class="inner-content">
5
+ <div class="inner-icon">
6
+ <Icon name="radix-icons:circle-backslash" class="icon" />
7
+ </div>
8
+ <div class="message">
9
+ <ul v-if="isArray" class="message-list">
10
+ <li v-for="(message, index) in errorMessage" :key="index" class="message-list-item">{{ message }}</li>
11
+ </ul>
12
+ <span v-else class="message-single">
13
+ {{ errorMessage }}
14
+ </span>
15
+ </div>
16
+ </div>
17
+ </div>
18
+ </div>
19
+ </template>
20
+
21
+ <script setup lang="ts">
22
+ import propValidators from '../c12/prop-validators';
23
+
24
+ const props = defineProps({
25
+ dataTestid: {
26
+ type: String,
27
+ default: 'inputError',
28
+ },
29
+ errorMessage: {
30
+ type: [Array, Object, String],
31
+ required: true,
32
+ },
33
+ showError: {
34
+ type: Boolean,
35
+ required: true,
36
+ },
37
+ id: {
38
+ type: String,
39
+ required: true,
40
+ },
41
+ styleClassPassthrough: {
42
+ type: Array as PropType<string[]>,
43
+ default: () => [],
44
+ },
45
+ compact: {
46
+ type: Boolean,
47
+ value: false,
48
+ },
49
+ isDetached: {
50
+ type: Boolean,
51
+ required: true,
52
+ },
53
+ inputVariant: {
54
+ type: String as PropType<string>,
55
+ default: 'normal',
56
+ validator(value: string) {
57
+ return propValidators.inputVariant.includes(value);
58
+ },
59
+ },
60
+ });
61
+
62
+ const isArray = computed(() => {
63
+ return Array.isArray(props.errorMessage);
64
+ });
65
+
66
+ const { elementClasses, updateElementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
67
+ </script>
68
+
69
+ <style lang="css" scoped>
70
+ .input-error-message {
71
+ --_grid-template-rows: 0fr;
72
+ --_opacity-show: 1;
73
+ --_opacity-hide: 0;
74
+ --_opacity: var(--_opacity-hide);
75
+
76
+ --_border-radius: 0 0 0.4rem 0.4rem;
77
+ --_display-show: block;
78
+ --_display-hide: none;
79
+ --_display: var(--_display-hide);
80
+ --_gutter: 1.2rem;
81
+ --_gutter-block: 0;
82
+ --_gutter-inline: var(--_gutter);
83
+ --_transition-duration: 500ms;
84
+ --_transition-timing-function: linear;
85
+ --_padding-message: 1.2rem 1rem;
86
+
87
+ &.show {
88
+ --_grid-template-rows: 1fr;
89
+ --_opacity: var(--_opacity-show);
90
+ --_display: var(--_display-show);
91
+ --_gutter-block: var(--_gutter);
92
+ }
93
+
94
+ grid-row: 2;
95
+ grid-column: 1;
96
+ display: grid;
97
+ grid-template-rows: var(--_grid-template-rows);
98
+
99
+ color: var(--theme-error-text);
100
+ background-color: var(--theme-error-surface);
101
+ border-radius: var(--_border-radius);
102
+
103
+ transition-property: grid-template-rows;
104
+ transition-duration: var(--_transition-duration);
105
+ transition-timing-function: var(--_transition-timing-function);
106
+ transition-behavior: allow-discrete;
107
+
108
+ &.detached {
109
+ border-radius: var(--form-input-border-radius);
110
+ margin-block-start: 2rem;
111
+ }
112
+
113
+ &.outlined {
114
+ --_border-radius: 0;
115
+ }
116
+
117
+ &.underlined {
118
+ --_border-radius: 0;
119
+ }
120
+
121
+ .inner {
122
+ align-items: center;
123
+
124
+ overflow: hidden;
125
+ transition: opacity var(--_transition-duration) var(--_transition-timing-function), display var(--_transition-duration) var(--_transition-timing-function) allow-discrete;
126
+
127
+ .inner-content {
128
+ display: flex;
129
+ align-items: center;
130
+
131
+ .inner-icon {
132
+ display: inline-block;
133
+ padding-left: 1.2rem;
134
+
135
+ .icon {
136
+ color: white;
137
+ transform: translateY(3px);
138
+ }
139
+ }
140
+
141
+ .message {
142
+ display: inline-block;
143
+ flex-grow: 1;
144
+ font-family: var(--font-family);
145
+ font-size: 1.6rem;
146
+ font-weight: 500;
147
+ padding-block: var(--_padding-message);
148
+ padding-inline: var(--_gutter-inline);
149
+
150
+ .message-single {
151
+ color: white;
152
+ }
153
+
154
+ .message-list {
155
+ list-style-type: none;
156
+ padding-inline-start: 0;
157
+ margin-block-start: 0;
158
+ margin-block-end: 0;
159
+
160
+ .message-list-item {
161
+ color: white;
162
+ }
163
+
164
+ .message-list-item + .message-list-item {
165
+ margin-block-start: 0.6rem;
166
+ }
167
+ }
168
+ }
169
+ }
170
+ }
171
+ }
172
+ </style>
@@ -0,0 +1,67 @@
1
+ // https://nuxt.com/docs/getting-started/testing#unit-testing
2
+ import { describe, it, expect } from 'vitest';
3
+ import { VueWrapper } from '@vue/test-utils';
4
+ import { mountSuspended } from '@nuxt/test-utils/runtime';
5
+ import ComponentUnderTest from '../InputError.vue';
6
+
7
+ let initialPropsData = {
8
+ dataTestid: 'inputError',
9
+ errorMessage: 'Hello World',
10
+ showError: true,
11
+ id: 'testId',
12
+ styleClassPassthrough: ['testClass'],
13
+ compact: false,
14
+ isDetached: true,
15
+ };
16
+
17
+ let wrapper: VueWrapper<InstanceType<typeof ComponentUnderTest>>;
18
+ const wrapperFactory = (propsData = {}) => {
19
+ const mockPropsData = { ...initialPropsData, ...propsData };
20
+
21
+ return mountSuspended(ComponentUnderTest, {
22
+ props: mockPropsData,
23
+ });
24
+ };
25
+
26
+ describe('InputError Component', () => {
27
+ it('renders properly', async () => {
28
+ wrapper = await wrapperFactory();
29
+
30
+ // Check the value of the data-testid attribute
31
+ const dataTestIdValue = wrapper.attributes('data-testid');
32
+ expect(dataTestIdValue).toBe('inputError');
33
+
34
+ expect(wrapper.find('[data-testid]').classes()).toContain('testClass');
35
+ expect(wrapper.find('[data-testid]').classes()).toContain('show');
36
+ });
37
+
38
+ it('is not displayed by default', async () => {
39
+ const propData = {
40
+ showError: false,
41
+ };
42
+ wrapper = await wrapperFactory(propData);
43
+
44
+ expect(wrapper.find('[data-testid]').classes()).not.toContain('show');
45
+ });
46
+
47
+ it('is displays a single error message', async () => {
48
+ const propData = {
49
+ showError: true,
50
+ };
51
+ wrapper = await wrapperFactory(propData);
52
+
53
+ expect(wrapper.find('.message-list').exists()).toBe(false);
54
+ expect(wrapper.find('.message-single').text()).toContain('Hello World');
55
+ });
56
+
57
+ it('is displays a single error message', async () => {
58
+ const propData = {
59
+ errorMessage: ['Hello World', 'Hello World 2'],
60
+ };
61
+ wrapper = await wrapperFactory(propData);
62
+
63
+ expect(wrapper.find('.message-single').exists()).toBe(false);
64
+ expect(wrapper.find('.message-list .message-list-item:first-child').text()).toEqual('Hello World');
65
+ expect(wrapper.find('.message-list .message-list-item:last-child').text()).toEqual('Hello World 2');
66
+ });
67
+ });
@@ -0,0 +1,191 @@
1
+ <template>
2
+ <button
3
+ :type
4
+ :readonly
5
+ :aria-disabled="readonly"
6
+ :data-testid
7
+ :data-btn-theme="theme"
8
+ :data-size="size"
9
+ class="input-button-core"
10
+ :class="[`btn-${type}`, effectClass, elementClasses, { 'icon-only': isIconOnly }]"
11
+ >
12
+ <span v-if="useEffect && effect == 'fancy'" class="fancy"></span>
13
+ <template v-if="hasLeftContent && !isIconOnly">
14
+ <span class="btn-icon left">
15
+ <slot name="left"></slot>
16
+ </span>
17
+ </template>
18
+ <span class="btn-text" :class="[weight, { 'sr-only': isIconOnly }]">{{ buttonText }}</span>
19
+ <template v-if="hasRightContent && !isIconOnly">
20
+ <span class="btn-icon right">
21
+ <slot name="right"></slot>
22
+ </span>
23
+ </template>
24
+ <template v-if="isIconOnly">
25
+ <span class="btn-icon icon-only">
26
+ <slot name="iconOnly"></slot>
27
+ </span>
28
+ </template>
29
+ </button>
30
+ </template>
31
+
32
+ <script setup lang="ts">
33
+ import propValidators from '../c12/prop-validators';
34
+
35
+ const props = defineProps({
36
+ size: {
37
+ type: String as PropType<string>,
38
+ default: 'normal',
39
+ validator(value: string) {
40
+ return propValidators.size.includes(value);
41
+ },
42
+ },
43
+ weight: {
44
+ type: String as PropType<string>,
45
+ default: 'wght-400',
46
+ validator(value: string) {
47
+ return propValidators.weight.includes(value);
48
+ },
49
+ },
50
+ theme: {
51
+ type: String as PropType<string>,
52
+ default: 'primary',
53
+ validator(value: string) {
54
+ return propValidators.theme.includes(value);
55
+ },
56
+ },
57
+ type: {
58
+ type: String as PropType<'submit' | 'button' | 'reset'>,
59
+ default: 'button',
60
+ validator(value: string) {
61
+ return propValidators.inputTypesButton.includes(value);
62
+ },
63
+ },
64
+ buttonText: {
65
+ type: String,
66
+ required: true,
67
+ },
68
+ dataTestid: {
69
+ type: String,
70
+ default: '',
71
+ },
72
+ styleClassPassthrough: {
73
+ type: Array as PropType<string[]>,
74
+ default: () => [],
75
+ },
76
+ useEffect: {
77
+ type: Boolean,
78
+ default: false,
79
+ },
80
+ effect: {
81
+ type: String as PropType<string>,
82
+ default: 'fancy',
83
+ validator(value: string) {
84
+ return ['fancy', 'pulse'].includes(value);
85
+ },
86
+ },
87
+ isPending: {
88
+ type: Boolean,
89
+ default: false,
90
+ },
91
+ readonly: {
92
+ type: Boolean,
93
+ default: false,
94
+ },
95
+ });
96
+
97
+ const type = toRef(() => props.type);
98
+ const effectClass = computed(() => {
99
+ if (props.useEffect) {
100
+ return props.effect === 'fancy' ? '' : props.effect;
101
+ } else {
102
+ return '';
103
+ }
104
+ });
105
+
106
+ const slots = useSlots();
107
+ const hasLeftContent = computed(() => slots.left !== undefined);
108
+ const hasRightContent = computed(() => slots.right !== undefined);
109
+ const isIconOnly = computed(() => slots.iconOnly !== undefined);
110
+
111
+ const { elementClasses, updateElementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
112
+ </script>
113
+
114
+ <style lang="css">
115
+ .input-button-core {
116
+ align-items: center;
117
+ display: flex;
118
+ gap: var(--form-button-icon-gap);
119
+ justify-content: center;
120
+ border: none;
121
+ border-radius: var(--form-input-border-radius);
122
+ font-family: var(--font-family);
123
+
124
+ padding-inline: var(--form-button-padding-inline);
125
+ padding-block-start: var(--form-element-padding-block-start);
126
+ padding-block-end: var(--form-element-padding-block-end);
127
+
128
+ transition: all 0.2s ease-in-out;
129
+
130
+ box-shadow: var(--box-shadow-off);
131
+ background-color: var(--theme-btn-bg);
132
+ border: var(--form-element-border-width) solid var(--theme-btn-border);
133
+ color: var(--theme-btn-text);
134
+ outline: var(--form-element-outline-width) solid var(--theme-btn-outline);
135
+
136
+ /*
137
+ * States
138
+ **/
139
+ &:hover {
140
+ --theme-btn-bg: var(--theme-btn-bg-hover);
141
+ --theme-btn-border: var(--theme-btn-border-hover);
142
+ --theme-btn-text: var(--theme-btn-text-hover);
143
+ --theme-btn-outline: var(--theme-btn-outline-hover);
144
+ }
145
+
146
+ &:hover {
147
+ cursor: pointer;
148
+ }
149
+
150
+ &:focus-visible {
151
+ --theme-btn-bg: var(--theme-btn-bg-focus);
152
+ --theme-btn-border: var(--theme-btn-border-focus);
153
+ --theme-btn-text: var(--theme-btn-text-focus);
154
+ --theme-btn-outline: var(--theme-btn-outline-focus);
155
+ box-shadow: var(--box-shadow-on);
156
+ }
157
+
158
+ &[readonly] {
159
+ opacity: 0.5;
160
+ &:hover,
161
+ &:focus-visible {
162
+ cursor: not-allowed;
163
+ }
164
+ }
165
+
166
+ &.icon-only {
167
+ aspect-ratio: 1;
168
+ height: var(--form-icon-only-button-size);
169
+ width: var(--form-icon-only-button-size);
170
+ margin: 0 !important;
171
+ padding: 0 !important;
172
+ }
173
+
174
+ .btn-text {
175
+ display: inline-block;
176
+ white-space: nowrap;
177
+ font-size: var(--form-element-font-size);
178
+ line-height: var(--form-element-line-height);
179
+ }
180
+
181
+ .btn-icon {
182
+ display: flex;
183
+ .icon {
184
+ aspect-ratio: 1;
185
+ display: inline-block;
186
+ height: var(--form-icon-size);
187
+ width: var(--form-icon-size);
188
+ }
189
+ }
190
+ }
191
+ </style>
@@ -0,0 +1,66 @@
1
+ <template>
2
+ <InputButtonCore type="button" :use-effect :isPending :readonly :effect :data-testid :size :weight :button-text :style-class-passthrough :theme>
3
+ <template #left>
4
+ <Icon name="material-symbols:check-circle-outline" class="icon" />
5
+ </template>
6
+ </InputButtonCore>
7
+ </template>
8
+
9
+ <script setup lang="ts">
10
+ import propValidators from '../../c12/prop-validators';
11
+
12
+ defineProps({
13
+ size: {
14
+ type: String as PropType<string>,
15
+ default: 'normal',
16
+ validator(value: string) {
17
+ return propValidators.size.includes(value);
18
+ },
19
+ },
20
+ weight: {
21
+ type: String as PropType<string>,
22
+ default: 'wght-400',
23
+ validator(value: string) {
24
+ return propValidators.weight.includes(value);
25
+ },
26
+ },
27
+ theme: {
28
+ type: String as PropType<string>,
29
+ default: 'primary',
30
+ validator(value: string) {
31
+ return propValidators.theme.includes(value);
32
+ },
33
+ },
34
+ useEffect: {
35
+ type: Boolean,
36
+ default: false,
37
+ },
38
+ effect: {
39
+ type: String as PropType<string>,
40
+ default: 'fancy',
41
+ validator(value: string) {
42
+ return ['fancy', 'pulse'].includes(value);
43
+ },
44
+ },
45
+ buttonText: {
46
+ type: String,
47
+ required: true,
48
+ },
49
+ dataTestid: {
50
+ type: String,
51
+ default: '',
52
+ },
53
+ styleClassPassthrough: {
54
+ type: Array as PropType<string[]>,
55
+ default: () => [],
56
+ },
57
+ isPending: {
58
+ type: Boolean,
59
+ default: false,
60
+ },
61
+ readonly: {
62
+ type: Boolean,
63
+ default: false,
64
+ },
65
+ });
66
+ </script>
@@ -0,0 +1,62 @@
1
+ <template>
2
+ <InputButtonCore type="button" :use-effect :isPending :readonly :effect :data-testid :size :weight :button-text :style-class-passthrough :theme />
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ import propValidators from '../../c12/prop-validators';
7
+
8
+ defineProps({
9
+ size: {
10
+ type: String as PropType<string>,
11
+ default: 'normal',
12
+ validator(value: string) {
13
+ return propValidators.size.includes(value);
14
+ },
15
+ },
16
+ weight: {
17
+ type: String as PropType<string>,
18
+ default: 'wght-400',
19
+ validator(value: string) {
20
+ return propValidators.weight.includes(value);
21
+ },
22
+ },
23
+ theme: {
24
+ type: String as PropType<string>,
25
+ default: 'primary',
26
+ validator(value: string) {
27
+ return propValidators.theme.includes(value);
28
+ },
29
+ },
30
+ useEffect: {
31
+ type: Boolean,
32
+ default: false,
33
+ },
34
+ effect: {
35
+ type: String as PropType<string>,
36
+ default: 'fancy',
37
+ validator(value: string) {
38
+ return ['fancy', 'pulse'].includes(value);
39
+ },
40
+ },
41
+ buttonText: {
42
+ type: String,
43
+ required: true,
44
+ },
45
+ dataTestid: {
46
+ type: String,
47
+ default: '',
48
+ },
49
+ styleClassPassthrough: {
50
+ type: Array as PropType<string[]>,
51
+ default: () => [],
52
+ },
53
+ isPending: {
54
+ type: Boolean,
55
+ default: false,
56
+ },
57
+ readonly: {
58
+ type: Boolean,
59
+ default: false,
60
+ },
61
+ });
62
+ </script>