@skewedaspect/sleekspace-ui 0.9.1 → 0.10.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.
- package/dist/components/Accordion/context.d.ts +4 -0
- package/dist/components/Autocomplete/SkAutocomplete.vue.d.ts +87 -0
- package/dist/components/Autocomplete/SkAutocompleteEmpty.vue.d.ts +17 -0
- package/dist/components/Autocomplete/SkAutocompleteGroup.vue.d.ts +17 -0
- package/dist/components/Autocomplete/SkAutocompleteGroupLabel.vue.d.ts +17 -0
- package/dist/components/Autocomplete/SkAutocompleteItem.vue.d.ts +39 -0
- package/dist/components/Autocomplete/SkAutocompleteSeparator.vue.d.ts +2 -0
- package/dist/components/Autocomplete/index.d.ts +7 -0
- package/dist/components/Autocomplete/types.d.ts +3 -0
- package/dist/components/Breadcrumbs/context.d.ts +4 -0
- package/dist/components/Button/SkButton.vue.d.ts +8 -1
- package/dist/components/Button/types.d.ts +2 -0
- package/dist/components/Card/SkCard.vue.d.ts +1 -1
- package/dist/components/ContextMenu/context.d.ts +3 -0
- package/dist/components/Dropdown/SkDropdown.vue.d.ts +1 -1
- package/dist/components/Dropdown/context.d.ts +3 -0
- package/dist/components/Field/SkField.vue.d.ts +7 -6
- package/dist/components/Input/SkInput.vue.d.ts +9 -2
- package/dist/components/Input/types.d.ts +2 -0
- package/dist/components/InputGroup/SkInputGroup.vue.d.ts +23 -0
- package/dist/components/InputGroup/SkInputGroupAddon.vue.d.ts +33 -0
- package/dist/components/InputGroup/types.d.ts +13 -0
- package/dist/components/NumberInput/SkNumberInput.vue.d.ts +7 -1
- package/dist/components/NumberInput/types.d.ts +2 -0
- package/dist/components/Pagination/context.d.ts +5 -0
- package/dist/components/Panel/SkPanel.vue.d.ts +1 -1
- package/dist/components/Panel/types.d.ts +2 -1
- package/dist/components/Radio/context.d.ts +4 -0
- package/dist/components/Select/SkSelect.vue.d.ts +7 -1
- package/dist/components/Select/types.d.ts +2 -0
- package/dist/components/Sidebar/SkSidebar.vue.d.ts +1 -1
- package/dist/components/Tabs/context.d.ts +6 -0
- package/dist/components/Textarea/SkTextarea.vue.d.ts +1 -1
- package/dist/components/Tooltip/SkTooltip.vue.d.ts +1 -1
- package/dist/composables/injectionKeys.d.ts +9 -0
- package/dist/global.d.ts +4 -0
- package/dist/index.d.ts +18 -0
- package/dist/sleekspace-ui.css +831 -277
- package/dist/sleekspace-ui.es.js +3693 -2514
- package/dist/sleekspace-ui.umd.js +3700 -2513
- package/dist/static/components/alert.d.ts +2 -1
- package/dist/static/components/avatar.d.ts +2 -1
- package/dist/static/components/breadcrumbs.d.ts +2 -1
- package/dist/static/components/button.d.ts +4 -2
- package/dist/static/components/card.d.ts +2 -1
- package/dist/static/components/checkbox.d.ts +2 -1
- package/dist/static/components/colorPicker.d.ts +2 -1
- package/dist/static/components/divider.d.ts +2 -1
- package/dist/static/components/dropdown.d.ts +2 -1
- package/dist/static/components/field.d.ts +2 -1
- package/dist/static/components/group.d.ts +2 -1
- package/dist/static/components/input.d.ts +4 -2
- package/dist/static/components/inputGroup.d.ts +8 -0
- package/dist/static/components/inputGroupAddon.d.ts +7 -0
- package/dist/static/components/navBar.d.ts +2 -1
- package/dist/static/components/numberInput.d.ts +4 -2
- package/dist/static/components/page.d.ts +2 -1
- package/dist/static/components/pagination.d.ts +2 -1
- package/dist/static/components/panel.d.ts +2 -1
- package/dist/static/components/progress.d.ts +2 -1
- package/dist/static/components/radio.d.ts +2 -1
- package/dist/static/components/select.d.ts +4 -2
- package/dist/static/components/sidebar.d.ts +2 -1
- package/dist/static/components/skeleton.d.ts +2 -1
- package/dist/static/components/slider.d.ts +2 -1
- package/dist/static/components/spinner.d.ts +2 -1
- package/dist/static/components/switchInput.d.ts +2 -1
- package/dist/static/components/table.d.ts +2 -1
- package/dist/static/components/tag.d.ts +2 -1
- package/dist/static/components/tagsInput.d.ts +2 -1
- package/dist/static/components/textarea.d.ts +2 -1
- package/dist/static/components/toolbar.d.ts +2 -1
- package/dist/static/components/tooltip.d.ts +2 -1
- package/dist/static/h.d.ts +2 -0
- package/dist/static/index.cjs.js +1 -1
- package/dist/static/index.d.ts +6 -0
- package/dist/static/index.es.js +366 -216
- package/dist/static/render.d.ts +2 -1
- package/dist/static/stringH.d.ts +2 -0
- package/dist/static/types.d.ts +5 -0
- package/dist/tailwind.css +222 -0
- package/dist/tokens.css +0 -223
- package/dist/types/corners.d.ts +1 -0
- package/llms-full.txt +14 -9
- package/package.json +6 -3
- package/src/components/Accordion/SkAccordion.vue +5 -2
- package/src/components/Accordion/SkAccordionItem.vue +7 -4
- package/src/components/Accordion/context.ts +23 -0
- package/src/components/Autocomplete/SkAutocomplete.test.ts +83 -0
- package/src/components/Autocomplete/SkAutocomplete.vue +305 -0
- package/src/components/Autocomplete/SkAutocompleteEmpty.vue +39 -0
- package/src/components/Autocomplete/SkAutocompleteGroup.vue +46 -0
- package/src/components/Autocomplete/SkAutocompleteGroupLabel.vue +39 -0
- package/src/components/Autocomplete/SkAutocompleteItem.vue +85 -0
- package/src/components/Autocomplete/SkAutocompleteSeparator.vue +39 -0
- package/src/components/Autocomplete/index.ts +13 -0
- package/src/components/Autocomplete/types.ts +10 -0
- package/src/components/Breadcrumbs/SkBreadcrumbItem.vue +8 -3
- package/src/components/Breadcrumbs/SkBreadcrumbSeparator.vue +8 -2
- package/src/components/Breadcrumbs/SkBreadcrumbs.vue +5 -2
- package/src/components/Breadcrumbs/context.ts +20 -0
- package/src/components/Button/SkButton.vue +46 -6
- package/src/components/Button/types.ts +6 -0
- package/src/components/ColorPicker/SkColorPicker.vue +27 -5
- package/src/components/ContextMenu/SkContextMenu.vue +4 -1
- package/src/components/ContextMenu/SkContextMenuSubmenu.vue +5 -2
- package/src/components/ContextMenu/context.ts +17 -0
- package/src/components/Dropdown/SkDropdown.vue +2 -1
- package/src/components/Dropdown/SkDropdownSubmenu.vue +4 -3
- package/src/components/Dropdown/context.ts +16 -0
- package/src/components/Field/SkField.test.ts +88 -0
- package/src/components/Field/SkField.vue +15 -7
- package/src/components/Input/SkInput.test.ts +61 -0
- package/src/components/Input/SkInput.vue +42 -7
- package/src/components/Input/types.ts +2 -0
- package/src/components/InputGroup/SkInputGroup.test.ts +171 -0
- package/src/components/InputGroup/SkInputGroup.vue +131 -0
- package/src/components/InputGroup/SkInputGroupAddon.test.ts +104 -0
- package/src/components/InputGroup/SkInputGroupAddon.vue +107 -0
- package/src/components/InputGroup/types.ts +27 -0
- package/src/components/Listbox/SkListbox.vue +27 -6
- package/src/components/NumberInput/SkNumberInput.vue +39 -7
- package/src/components/NumberInput/types.ts +2 -0
- package/src/components/Pagination/SkPagination.vue +6 -3
- package/src/components/Pagination/SkPaginationItem.vue +8 -5
- package/src/components/Pagination/context.ts +19 -0
- package/src/components/Panel/types.ts +3 -2
- package/src/components/Radio/SkRadio.vue +6 -3
- package/src/components/Radio/SkRadioGroup.vue +4 -2
- package/src/components/Radio/context.ts +17 -0
- package/src/components/Select/SkSelect.vue +39 -7
- package/src/components/Select/types.ts +2 -0
- package/src/components/Tabs/SkTab.vue +4 -2
- package/src/components/Tabs/SkTabList.vue +4 -2
- package/src/components/Tabs/SkTabs.vue +5 -3
- package/src/components/Tabs/context.ts +19 -0
- package/src/components/TagsInput/SkTagsInput.vue +28 -7
- package/src/components/Textarea/SkTextarea.vue +27 -6
- package/src/composables/injectionKeys.ts +52 -0
- package/src/index.ts +28 -0
- package/src/static/__tests__/parity.test.ts +2 -1
- package/src/static/__tests__/parityHarness.ts +5 -2
- package/src/static/components/__tests__/helpers.test.ts +191 -99
- package/src/static/components/alert.ts +12 -11
- package/src/static/components/avatar.ts +15 -16
- package/src/static/components/breadcrumbs.ts +3 -2
- package/src/static/components/button.ts +23 -27
- package/src/static/components/card.ts +3 -2
- package/src/static/components/checkbox.ts +11 -14
- package/src/static/components/colorPicker.ts +7 -9
- package/src/static/components/divider.ts +4 -3
- package/src/static/components/dropdown.ts +15 -6
- package/src/static/components/field.ts +32 -15
- package/src/static/components/group.ts +3 -2
- package/src/static/components/input.ts +20 -15
- package/src/static/components/inputGroup.ts +30 -0
- package/src/static/components/inputGroupAddon.ts +29 -0
- package/src/static/components/navBar.ts +30 -17
- package/src/static/components/numberInput.ts +17 -17
- package/src/static/components/page.ts +3 -2
- package/src/static/components/pagination.ts +3 -2
- package/src/static/components/panel.ts +3 -2
- package/src/static/components/progress.ts +3 -2
- package/src/static/components/radio.ts +14 -20
- package/src/static/components/select.ts +18 -15
- package/src/static/components/sidebar.ts +9 -13
- package/src/static/components/skeleton.ts +7 -10
- package/src/static/components/slider.ts +7 -9
- package/src/static/components/spinner.ts +22 -22
- package/src/static/components/switchInput.ts +12 -14
- package/src/static/components/table.ts +8 -10
- package/src/static/components/tag.ts +17 -11
- package/src/static/components/tagsInput.ts +3 -3
- package/src/static/components/textarea.ts +8 -13
- package/src/static/components/toolbar.ts +7 -10
- package/src/static/components/tooltip.ts +3 -2
- package/src/static/generated/defaults.ts +24 -9
- package/src/static/generated/propTypes.ts +18 -2
- package/src/static/h.ts +16 -0
- package/src/static/index.ts +8 -0
- package/src/static/render.test.ts +14 -10
- package/src/static/render.ts +33 -18
- package/src/static/specs.test.ts +1 -0
- package/src/static/specs.ts +22 -2
- package/src/static/stringH.ts +104 -0
- package/src/static/types.ts +25 -0
- package/src/styles/components/_autocomplete.scss +498 -0
- package/src/styles/components/_button.scss +55 -6
- package/src/styles/components/_index.scss +2 -0
- package/src/styles/components/_input-group.scss +292 -0
- package/src/styles/components/_input.scss +57 -9
- package/src/styles/components/_number-input.scss +84 -18
- package/src/styles/components/_select.scss +56 -9
- package/src/styles/mixins/_cut-border.scss +83 -0
- package/src/styles/tailwind.scss +262 -0
- package/src/styles/tokens.scss +8 -255
- package/src/types/corners.ts +10 -0
- package/src/utils/slots.test.ts +89 -0
- package/src/utils/slots.ts +6 -1
- package/web-types.json +382 -12
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
2
|
+
// SkInput — input-group-size inject tests
|
|
3
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
4
|
+
|
|
5
|
+
import { mount } from '@vue/test-utils';
|
|
6
|
+
import { computed, defineComponent, h, provide } from 'vue';
|
|
7
|
+
import { describe, expect, it } from 'vitest';
|
|
8
|
+
|
|
9
|
+
import { inputGroupSizeKey } from '@/composables/injectionKeys';
|
|
10
|
+
|
|
11
|
+
import SkInput from './SkInput.vue';
|
|
12
|
+
|
|
13
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
describe('SkInput input-group-size inject', () =>
|
|
16
|
+
{
|
|
17
|
+
it('uses injected size when no explicit size prop is set', () =>
|
|
18
|
+
{
|
|
19
|
+
const Provider = defineComponent({
|
|
20
|
+
setup(_, { slots })
|
|
21
|
+
{
|
|
22
|
+
provide(inputGroupSizeKey, computed(() => 'lg'));
|
|
23
|
+
return () => h('div', slots.default ? slots.default() : []);
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const wrapper = mount(Provider, {
|
|
28
|
+
slots: { default: () => h(SkInput) },
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const input = wrapper.find('input.sk-input');
|
|
32
|
+
expect(input.classes()).toContain('sk-lg');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('explicit size prop overrides injected size', () =>
|
|
36
|
+
{
|
|
37
|
+
const Provider = defineComponent({
|
|
38
|
+
setup(_, { slots })
|
|
39
|
+
{
|
|
40
|
+
provide(inputGroupSizeKey, computed(() => 'lg'));
|
|
41
|
+
return () => h('div', slots.default ? slots.default() : []);
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const wrapper = mount(Provider, {
|
|
46
|
+
slots: { default: () => h(SkInput, { size: 'sm' }) },
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const input = wrapper.find('input.sk-input');
|
|
50
|
+
expect(input.classes()).toContain('sk-sm');
|
|
51
|
+
expect(input.classes()).not.toContain('sk-lg');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('falls back to md when neither prop nor inject is set', () =>
|
|
55
|
+
{
|
|
56
|
+
const wrapper = mount(SkInput);
|
|
57
|
+
expect(wrapper.classes()).toContain('sk-md');
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
@@ -43,13 +43,20 @@
|
|
|
43
43
|
* ```
|
|
44
44
|
*/
|
|
45
45
|
|
|
46
|
-
import {
|
|
46
|
+
import { computed, inject, toRef } from 'vue';
|
|
47
47
|
|
|
48
48
|
// Types
|
|
49
49
|
import type { ComponentCustomColors } from '@/types';
|
|
50
|
-
import type { SkInputKind, SkInputSize, SkInputType } from './types';
|
|
50
|
+
import type { SkInputCorner, SkInputKind, SkInputSize, SkInputType } from './types';
|
|
51
51
|
|
|
52
52
|
// Composables
|
|
53
|
+
import {
|
|
54
|
+
NO_KIND,
|
|
55
|
+
NO_SIZE,
|
|
56
|
+
inheritedKindKey,
|
|
57
|
+
inputGroupSizeKey,
|
|
58
|
+
validationKindKey,
|
|
59
|
+
} from '@/composables/injectionKeys';
|
|
53
60
|
import { useCustomColors } from '@/composables/useCustomColors';
|
|
54
61
|
|
|
55
62
|
//------------------------------------------------------------------------------------------------------------------
|
|
@@ -79,6 +86,13 @@
|
|
|
79
86
|
*/
|
|
80
87
|
size ?: SkInputSize;
|
|
81
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Which corners receive the beveled cut. Pass an empty array for square corners.
|
|
91
|
+
* When omitted, defaults to the input's standalone visual (`top-right` only).
|
|
92
|
+
* @default undefined (renders as ['top-right'])
|
|
93
|
+
*/
|
|
94
|
+
corners ?: SkInputCorner[];
|
|
95
|
+
|
|
82
96
|
/**
|
|
83
97
|
* Placeholder text displayed when the input is empty. Use to provide hints about expected
|
|
84
98
|
* input format or example values. The placeholder disappears when the user begins typing.
|
|
@@ -131,7 +145,8 @@
|
|
|
131
145
|
const props = withDefaults(defineProps<SkInputComponentProps>(), {
|
|
132
146
|
type: 'text',
|
|
133
147
|
kind: undefined,
|
|
134
|
-
size:
|
|
148
|
+
size: undefined,
|
|
149
|
+
corners: undefined,
|
|
135
150
|
placeholder: undefined,
|
|
136
151
|
disabled: false,
|
|
137
152
|
readonly: false,
|
|
@@ -151,20 +166,40 @@
|
|
|
151
166
|
|
|
152
167
|
//------------------------------------------------------------------------------------------------------------------
|
|
153
168
|
|
|
154
|
-
//
|
|
155
|
-
|
|
169
|
+
// Validation override (SkField with `state` set) always wins. Inherited kind (an ambient
|
|
170
|
+
// provider like SkInputGroup) is the default when the dev didn't set `kind` themselves.
|
|
171
|
+
const validationKind = inject(validationKindKey, NO_KIND);
|
|
172
|
+
const inheritedKind = inject(inheritedKindKey, NO_KIND);
|
|
173
|
+
const inputGroupSize = inject(inputGroupSizeKey, NO_SIZE);
|
|
156
174
|
|
|
157
175
|
//------------------------------------------------------------------------------------------------------------------
|
|
158
176
|
|
|
159
|
-
const effectiveKind = computed(() =>
|
|
177
|
+
const effectiveKind = computed<SkInputKind>(() =>
|
|
178
|
+
{
|
|
179
|
+
if(validationKind.value !== undefined) { return validationKind.value; }
|
|
180
|
+
if(props.kind !== undefined) { return props.kind; }
|
|
181
|
+
if(inheritedKind.value !== undefined) { return inheritedKind.value; }
|
|
182
|
+
return 'neutral';
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
const effectiveSize = computed<SkInputSize>(() =>
|
|
186
|
+
{
|
|
187
|
+
if(props.size !== undefined) { return props.size; }
|
|
188
|
+
if(inputGroupSize.value !== undefined) { return inputGroupSize.value; }
|
|
189
|
+
return 'md';
|
|
190
|
+
});
|
|
160
191
|
|
|
161
192
|
//------------------------------------------------------------------------------------------------------------------
|
|
162
193
|
|
|
163
194
|
const classes = computed(() => ({
|
|
164
195
|
'sk-input': true,
|
|
165
196
|
[`sk-${ effectiveKind.value }`]: true,
|
|
166
|
-
[`sk-${
|
|
197
|
+
[`sk-${ effectiveSize.value }`]: true,
|
|
167
198
|
'sk-readonly': props.readonly,
|
|
199
|
+
'sk-cut-top-left': props.corners?.includes('top-left') ?? false,
|
|
200
|
+
'sk-cut-top-right': props.corners?.includes('top-right') ?? false,
|
|
201
|
+
'sk-cut-bottom-right': props.corners?.includes('bottom-right') ?? false,
|
|
202
|
+
'sk-cut-bottom-left': props.corners?.includes('bottom-left') ?? false,
|
|
168
203
|
}));
|
|
169
204
|
|
|
170
205
|
//------------------------------------------------------------------------------------------------------------------
|
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
//----------------------------------------------------------------------------------------------------------------------
|
|
4
4
|
|
|
5
5
|
import type { ComponentKind, ComponentSize } from '@/types';
|
|
6
|
+
import type { SkCorner } from '@/types/corners';
|
|
6
7
|
|
|
7
8
|
export type SkInputKind = ComponentKind;
|
|
8
9
|
export type SkInputSize = ComponentSize;
|
|
9
10
|
export type SkInputType = 'text' | 'email' | 'password' | 'url' | 'tel' | 'search' | 'number';
|
|
11
|
+
export type SkInputCorner = SkCorner;
|
|
10
12
|
|
|
11
13
|
//----------------------------------------------------------------------------------------------------------------------
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
2
|
+
// SkInputGroup Tests
|
|
3
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
4
|
+
|
|
5
|
+
import { computed, defineComponent, h, inject, provide } from 'vue';
|
|
6
|
+
import { mount } from '@vue/test-utils';
|
|
7
|
+
import { describe, expect, it } from 'vitest';
|
|
8
|
+
|
|
9
|
+
import { inheritedKindKey, validationKindKey } from '@/composables/injectionKeys';
|
|
10
|
+
|
|
11
|
+
import SkInputGroup from './SkInputGroup.vue';
|
|
12
|
+
import SkInputGroupAddon from './SkInputGroupAddon.vue';
|
|
13
|
+
|
|
14
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
describe('SkInputGroup', () =>
|
|
17
|
+
{
|
|
18
|
+
it('renders a div with the group class and default classes', () =>
|
|
19
|
+
{
|
|
20
|
+
const wrapper = mount(SkInputGroup);
|
|
21
|
+
const div = wrapper.find('div.sk-input-group');
|
|
22
|
+
expect(div.exists()).toBe(true);
|
|
23
|
+
expect(div.classes()).toContain('sk-md');
|
|
24
|
+
expect(div.classes()).toContain('sk-neutral');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('applies corner classes from corners prop', () =>
|
|
28
|
+
{
|
|
29
|
+
const wrapper = mount(SkInputGroup, {
|
|
30
|
+
props: { corners: [ 'top-left', 'bottom-right' ] },
|
|
31
|
+
});
|
|
32
|
+
const div = wrapper.find('div.sk-input-group');
|
|
33
|
+
expect(div.classes()).toContain('sk-cut-top-left');
|
|
34
|
+
expect(div.classes()).toContain('sk-cut-bottom-right');
|
|
35
|
+
expect(div.classes()).not.toContain('sk-cut-top-right');
|
|
36
|
+
expect(div.classes()).not.toContain('sk-cut-bottom-left');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('provides input-group-size to children', () =>
|
|
40
|
+
{
|
|
41
|
+
const wrapper = mount(SkInputGroup, {
|
|
42
|
+
props: { size: 'lg' },
|
|
43
|
+
slots: { default: () => h(SkInputGroupAddon, null, { default: () => '$' }) },
|
|
44
|
+
});
|
|
45
|
+
const addon = wrapper.find('span.sk-input-group-addon');
|
|
46
|
+
expect(addon.classes()).toContain('sk-lg');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('provides inherited-kind to children', () =>
|
|
50
|
+
{
|
|
51
|
+
const wrapper = mount(SkInputGroup, {
|
|
52
|
+
props: { kind: 'primary' },
|
|
53
|
+
slots: { default: () => h(SkInputGroupAddon, null, { default: () => '$' }) },
|
|
54
|
+
});
|
|
55
|
+
const addon = wrapper.find('span.sk-input-group-addon');
|
|
56
|
+
expect(addon.classes()).toContain('sk-primary');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('inherits ambient kind from a parent inherited-kind provider', () =>
|
|
60
|
+
{
|
|
61
|
+
const AmbientStub = defineComponent({
|
|
62
|
+
setup(_, { slots })
|
|
63
|
+
{
|
|
64
|
+
provide(inheritedKindKey, computed(() => 'accent'));
|
|
65
|
+
return () => h('div', slots.default ? slots.default() : []);
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const wrapper = mount(AmbientStub, {
|
|
70
|
+
slots: {
|
|
71
|
+
default: () => h(SkInputGroup, null, {
|
|
72
|
+
default: () => h(SkInputGroupAddon, null, { default: () => '$' }),
|
|
73
|
+
}),
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const group = wrapper.find('div.sk-input-group');
|
|
78
|
+
const addon = wrapper.find('span.sk-input-group-addon');
|
|
79
|
+
expect(group.classes()).toContain('sk-accent');
|
|
80
|
+
expect(addon.classes()).toContain('sk-accent');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('explicit kind prop wins over ambient inherited-kind', () =>
|
|
84
|
+
{
|
|
85
|
+
const AmbientStub = defineComponent({
|
|
86
|
+
setup(_, { slots })
|
|
87
|
+
{
|
|
88
|
+
provide(inheritedKindKey, computed(() => 'accent'));
|
|
89
|
+
return () => h('div', slots.default ? slots.default() : []);
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const wrapper = mount(AmbientStub, {
|
|
94
|
+
slots: {
|
|
95
|
+
default: () => h(SkInputGroup, { kind: 'success' }, {
|
|
96
|
+
default: () => h(SkInputGroupAddon, null, { default: () => '$' }),
|
|
97
|
+
}),
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const group = wrapper.find('div.sk-input-group');
|
|
102
|
+
const addon = wrapper.find('span.sk-input-group-addon');
|
|
103
|
+
expect(group.classes()).toContain('sk-success');
|
|
104
|
+
expect(addon.classes()).toContain('sk-success');
|
|
105
|
+
expect(addon.classes()).not.toContain('sk-accent');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('parent validation-kind always wins over explicit kind', () =>
|
|
109
|
+
{
|
|
110
|
+
const FieldStub = defineComponent({
|
|
111
|
+
setup(_, { slots })
|
|
112
|
+
{
|
|
113
|
+
provide(validationKindKey, computed(() => 'danger'));
|
|
114
|
+
return () => h('div', slots.default ? slots.default() : []);
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const wrapper = mount(FieldStub, {
|
|
119
|
+
slots: {
|
|
120
|
+
default: () => h(SkInputGroup, { kind: 'success' }, {
|
|
121
|
+
default: () => h(SkInputGroupAddon, null, { default: () => '$' }),
|
|
122
|
+
}),
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const group = wrapper.find('div.sk-input-group');
|
|
127
|
+
const addon = wrapper.find('span.sk-input-group-addon');
|
|
128
|
+
expect(group.classes()).toContain('sk-danger');
|
|
129
|
+
expect(addon.classes()).toContain('sk-danger');
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('re-provides inherited-kind from props.kind, not the validation-resolved kind', () =>
|
|
133
|
+
{
|
|
134
|
+
// The property under test: SkInputGroup's `inherited-kind` re-provide must use props.kind
|
|
135
|
+
// (or the parent's inherited-kind), NOT the validation-overridden effectiveKind. Otherwise
|
|
136
|
+
// a parent SkField's validation override would leak onto the inherited-kind channel and
|
|
137
|
+
// clobber descendants that consult only inherited-kind.
|
|
138
|
+
//
|
|
139
|
+
// To observe what the InputGroup actually puts on inherited-kind, we mount a synthetic
|
|
140
|
+
// probe inside the group that injects ONLY inherited-kind (no validation-kind) and
|
|
141
|
+
// surfaces the resolved value as a data attribute.
|
|
142
|
+
const Probe = defineComponent({
|
|
143
|
+
setup()
|
|
144
|
+
{
|
|
145
|
+
const seen = inject(inheritedKindKey, computed(() => 'NONE'));
|
|
146
|
+
return () => h('div', { 'data-seen': seen.value });
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const FieldStub = defineComponent({
|
|
151
|
+
setup(_, { slots })
|
|
152
|
+
{
|
|
153
|
+
provide(validationKindKey, computed(() => 'danger'));
|
|
154
|
+
return () => h('div', slots.default ? slots.default() : []);
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
const wrapper = mount(FieldStub, {
|
|
159
|
+
slots: {
|
|
160
|
+
default: () => h(SkInputGroup, { kind: 'primary' }, {
|
|
161
|
+
default: () => h(Probe),
|
|
162
|
+
}),
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// The probe sees 'primary' (props.kind), not 'danger' (validation override).
|
|
167
|
+
expect(wrapper.find('[data-seen]').attributes('data-seen')).toBe('primary');
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
<!----------------------------------------------------------------------------------------------------------------------
|
|
2
|
+
- InputGroup Component
|
|
3
|
+
--------------------------------------------------------------------------------------------------------------------->
|
|
4
|
+
|
|
5
|
+
<template>
|
|
6
|
+
<div :class="classes" :style="customColorStyles">
|
|
7
|
+
<slot />
|
|
8
|
+
</div>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<!--------------------------------------------------------------------------------------------------------------------->
|
|
12
|
+
|
|
13
|
+
<style lang="scss" scoped>
|
|
14
|
+
// Component styles are implemented in /src/styles/components/_input-group.scss
|
|
15
|
+
</style>
|
|
16
|
+
|
|
17
|
+
<!--------------------------------------------------------------------------------------------------------------------->
|
|
18
|
+
|
|
19
|
+
<script setup lang="ts">
|
|
20
|
+
/**
|
|
21
|
+
* @component SkInputGroup
|
|
22
|
+
* @description Wraps form inputs, buttons, selects, and SkInputGroupAddon children into a
|
|
23
|
+
* single visually unified control. Bevels appear only on the group's outer corners; interior
|
|
24
|
+
* joins are clean. Cascades kind and size to Vue children via provide/inject — size on the
|
|
25
|
+
* `input-group-size` channel, kind on the `inherited-kind` ambient-default channel. A
|
|
26
|
+
* parent SkField's validation override (the `validation-kind` channel) takes precedence over
|
|
27
|
+
* both the group's own kind and the descendants' kinds.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```vue
|
|
31
|
+
* <SkInputGroup :corners="['top-left', 'bottom-right']" size="md" kind="primary">
|
|
32
|
+
* <SkInputGroupAddon>$</SkInputGroupAddon>
|
|
33
|
+
* <SkInput v-model="amount" />
|
|
34
|
+
* <SkButton>Submit</SkButton>
|
|
35
|
+
* </SkInputGroup>
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @slot default - Form components, SkButton, and SkInputGroupAddon children in left-to-right order.
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
import { computed, inject, provide, toRef } from 'vue';
|
|
42
|
+
|
|
43
|
+
// Types
|
|
44
|
+
import type {
|
|
45
|
+
SkInputGroupBaseProps,
|
|
46
|
+
SkInputGroupCorner,
|
|
47
|
+
SkInputGroupKind,
|
|
48
|
+
SkInputGroupSize,
|
|
49
|
+
} from './types';
|
|
50
|
+
|
|
51
|
+
export type { SkInputGroupComponentProps } from './types';
|
|
52
|
+
|
|
53
|
+
// Composables
|
|
54
|
+
import {
|
|
55
|
+
NO_KIND,
|
|
56
|
+
NO_SIZE,
|
|
57
|
+
inheritedKindKey,
|
|
58
|
+
inputGroupSizeKey,
|
|
59
|
+
validationKindKey,
|
|
60
|
+
} from '@/composables/injectionKeys';
|
|
61
|
+
import { useCustomColors } from '@/composables/useCustomColors';
|
|
62
|
+
|
|
63
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
64
|
+
|
|
65
|
+
const props = withDefaults(defineProps<SkInputGroupBaseProps>(), {
|
|
66
|
+
kind: undefined,
|
|
67
|
+
size: 'md',
|
|
68
|
+
corners: () => [ 'top-left', 'bottom-right' ],
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
72
|
+
|
|
73
|
+
// Same resolution rule as the leaf form components: validation override (from a parent
|
|
74
|
+
// SkField with `state` set) wins, then explicit prop, then ambient inherited-kind, then
|
|
75
|
+
// 'neutral'. Validation-kind passes through to descendants on its own channel — we never
|
|
76
|
+
// re-provide it.
|
|
77
|
+
const validationKind = inject(validationKindKey, NO_KIND);
|
|
78
|
+
const inheritedKind = inject(inheritedKindKey, NO_KIND);
|
|
79
|
+
|
|
80
|
+
const effectiveKind = computed<SkInputGroupKind>(() =>
|
|
81
|
+
{
|
|
82
|
+
if(validationKind.value !== undefined) { return validationKind.value; }
|
|
83
|
+
if(props.kind !== undefined) { return props.kind; }
|
|
84
|
+
if(inheritedKind.value !== undefined) { return inheritedKind.value; }
|
|
85
|
+
return 'neutral';
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
89
|
+
|
|
90
|
+
// Re-provide on the inherited-kind channel so descendants pick up the group's prop-driven
|
|
91
|
+
// kind as their default. Use the prop directly (not the resolved value) so a parent SkField's
|
|
92
|
+
// validation override doesn't propagate as the group's "ambient default" and clobber children
|
|
93
|
+
// that have their own explicit kind.
|
|
94
|
+
const ambientKind = computed<SkInputGroupKind | undefined>(() =>
|
|
95
|
+
{
|
|
96
|
+
if(props.kind !== undefined) { return props.kind; }
|
|
97
|
+
return inheritedKind.value;
|
|
98
|
+
});
|
|
99
|
+
provide(inheritedKindKey, ambientKind);
|
|
100
|
+
|
|
101
|
+
// Size passes straight through to the input-group-size channel — no resolution to do.
|
|
102
|
+
const sizeRef = toRef(props, 'size');
|
|
103
|
+
provide(inputGroupSizeKey, sizeRef);
|
|
104
|
+
|
|
105
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
106
|
+
|
|
107
|
+
function hasCorner(corner : SkInputGroupCorner) : boolean
|
|
108
|
+
{
|
|
109
|
+
return props.corners.includes(corner);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const classes = computed<Record<string, boolean>>(() => ({
|
|
113
|
+
'sk-input-group': true,
|
|
114
|
+
[`sk-${ effectiveKind.value }`]: true,
|
|
115
|
+
[`sk-${ sizeRef.value }`]: true,
|
|
116
|
+
'sk-cut-top-left': hasCorner('top-left'),
|
|
117
|
+
'sk-cut-top-right': hasCorner('top-right'),
|
|
118
|
+
'sk-cut-bottom-right': hasCorner('bottom-right'),
|
|
119
|
+
'sk-cut-bottom-left': hasCorner('bottom-left'),
|
|
120
|
+
}));
|
|
121
|
+
|
|
122
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
123
|
+
|
|
124
|
+
const customColorStyles = useCustomColors(
|
|
125
|
+
'input-group',
|
|
126
|
+
toRef(() => props.baseColor),
|
|
127
|
+
toRef(() => props.textColor)
|
|
128
|
+
);
|
|
129
|
+
</script>
|
|
130
|
+
|
|
131
|
+
<!--------------------------------------------------------------------------------------------------------------------->
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { type InjectionKey, computed, defineComponent, h, provide } from 'vue';
|
|
2
|
+
import { mount } from '@vue/test-utils';
|
|
3
|
+
import { describe, expect, it } from 'vitest';
|
|
4
|
+
|
|
5
|
+
import { inheritedKindKey, inputGroupSizeKey, validationKindKey } from '@/composables/injectionKeys';
|
|
6
|
+
|
|
7
|
+
import SkInputGroupAddon from './SkInputGroupAddon.vue';
|
|
8
|
+
|
|
9
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
function withProvides(
|
|
12
|
+
children : () => ReturnType<typeof h>,
|
|
13
|
+
provides : Map<InjectionKey<unknown>, unknown> = new Map<InjectionKey<unknown>, unknown>()
|
|
14
|
+
) : ReturnType<typeof defineComponent>
|
|
15
|
+
{
|
|
16
|
+
return defineComponent({
|
|
17
|
+
setup()
|
|
18
|
+
{
|
|
19
|
+
for(const [ key, value ] of provides)
|
|
20
|
+
{
|
|
21
|
+
provide(key, value);
|
|
22
|
+
}
|
|
23
|
+
return () => h('div', children());
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
describe('SkInputGroupAddon', () =>
|
|
31
|
+
{
|
|
32
|
+
it('renders a span with the addon class', () =>
|
|
33
|
+
{
|
|
34
|
+
const wrapper = mount(SkInputGroupAddon, { slots: { default: '$' } });
|
|
35
|
+
const span = wrapper.find('span.sk-input-group-addon');
|
|
36
|
+
expect(span.exists()).toBe(true);
|
|
37
|
+
expect(span.text()).toBe('$');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('uses injected input-group-size when no explicit size is set', () =>
|
|
41
|
+
{
|
|
42
|
+
const Provider = withProvides(
|
|
43
|
+
() => h(SkInputGroupAddon, null, { default: () => '$' }),
|
|
44
|
+
new Map<InjectionKey<unknown>, unknown>([ [ inputGroupSizeKey, computed(() => 'lg') ] ])
|
|
45
|
+
);
|
|
46
|
+
const wrapper = mount(Provider);
|
|
47
|
+
const span = wrapper.find('span.sk-input-group-addon');
|
|
48
|
+
expect(span.classes()).toContain('sk-lg');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('uses injected inherited-kind when no explicit kind is set', () =>
|
|
52
|
+
{
|
|
53
|
+
const Provider = withProvides(
|
|
54
|
+
() => h(SkInputGroupAddon, null, { default: () => '$' }),
|
|
55
|
+
new Map<InjectionKey<unknown>, unknown>([ [ inheritedKindKey, computed(() => 'primary') ] ])
|
|
56
|
+
);
|
|
57
|
+
const wrapper = mount(Provider);
|
|
58
|
+
const span = wrapper.find('span.sk-input-group-addon');
|
|
59
|
+
expect(span.classes()).toContain('sk-primary');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('validation-kind always wins over explicit kind and inherited-kind', () =>
|
|
63
|
+
{
|
|
64
|
+
const Provider = withProvides(
|
|
65
|
+
() => h(SkInputGroupAddon, { kind: 'success' }, { default: () => '$' }),
|
|
66
|
+
new Map<InjectionKey<unknown>, unknown>([
|
|
67
|
+
[ validationKindKey, computed(() => 'danger') ],
|
|
68
|
+
[ inheritedKindKey, computed(() => 'primary') ],
|
|
69
|
+
])
|
|
70
|
+
);
|
|
71
|
+
const wrapper = mount(Provider);
|
|
72
|
+
const span = wrapper.find('span.sk-input-group-addon');
|
|
73
|
+
expect(span.classes()).toContain('sk-danger');
|
|
74
|
+
expect(span.classes()).not.toContain('sk-success');
|
|
75
|
+
expect(span.classes()).not.toContain('sk-primary');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('explicit props override inherited-kind and input-group-size', () =>
|
|
79
|
+
{
|
|
80
|
+
const Provider = withProvides(
|
|
81
|
+
() => h(SkInputGroupAddon, { size: 'sm', kind: 'danger' }, { default: () => '$' }),
|
|
82
|
+
new Map<InjectionKey<unknown>, unknown>([
|
|
83
|
+
[ inputGroupSizeKey, computed(() => 'lg') ],
|
|
84
|
+
[ inheritedKindKey, computed(() => 'primary') ],
|
|
85
|
+
])
|
|
86
|
+
);
|
|
87
|
+
const wrapper = mount(Provider);
|
|
88
|
+
const span = wrapper.find('span.sk-input-group-addon');
|
|
89
|
+
expect(span.classes()).toContain('sk-sm');
|
|
90
|
+
expect(span.classes()).toContain('sk-danger');
|
|
91
|
+
expect(span.classes()).not.toContain('sk-lg');
|
|
92
|
+
expect(span.classes()).not.toContain('sk-primary');
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('defaults to md/neutral when nothing is provided', () =>
|
|
96
|
+
{
|
|
97
|
+
const wrapper = mount(SkInputGroupAddon);
|
|
98
|
+
const span = wrapper.find('span.sk-input-group-addon');
|
|
99
|
+
expect(span.classes()).toContain('sk-md');
|
|
100
|
+
expect(span.classes()).toContain('sk-neutral');
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
<!----------------------------------------------------------------------------------------------------------------------
|
|
2
|
+
- InputGroup Addon Component
|
|
3
|
+
--------------------------------------------------------------------------------------------------------------------->
|
|
4
|
+
|
|
5
|
+
<template>
|
|
6
|
+
<span :class="classes">
|
|
7
|
+
<slot />
|
|
8
|
+
</span>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<!--------------------------------------------------------------------------------------------------------------------->
|
|
12
|
+
|
|
13
|
+
<style lang="scss" scoped>
|
|
14
|
+
// Component styles are implemented in /src/styles/components/_input-group.scss
|
|
15
|
+
</style>
|
|
16
|
+
|
|
17
|
+
<!--------------------------------------------------------------------------------------------------------------------->
|
|
18
|
+
|
|
19
|
+
<script setup lang="ts">
|
|
20
|
+
/**
|
|
21
|
+
* @component SkInputGroupAddon
|
|
22
|
+
* @description Styled wrapper for non-component content (text, icons, plain HTML) inside an
|
|
23
|
+
* SkInputGroup. Renders as a span with the addon background, border, and font sizing matching
|
|
24
|
+
* the surrounding group. Inherits size and kind from the parent SkInputGroup via inject.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```vue
|
|
28
|
+
* <SkInputGroup>
|
|
29
|
+
* <SkInputGroupAddon>$</SkInputGroupAddon>
|
|
30
|
+
* <SkInput v-model="amount" />
|
|
31
|
+
* </SkInputGroup>
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @slot default - Addon content. Text, icons, or any inline element.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
import { computed, inject } from 'vue';
|
|
38
|
+
|
|
39
|
+
// Types
|
|
40
|
+
import type { SkInputGroupAddonKind, SkInputGroupAddonSize } from './types';
|
|
41
|
+
|
|
42
|
+
// Composables
|
|
43
|
+
import {
|
|
44
|
+
NO_KIND,
|
|
45
|
+
NO_SIZE,
|
|
46
|
+
inheritedKindKey,
|
|
47
|
+
inputGroupSizeKey,
|
|
48
|
+
validationKindKey,
|
|
49
|
+
} from '@/composables/injectionKeys';
|
|
50
|
+
|
|
51
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
export interface SkInputGroupAddonComponentProps
|
|
54
|
+
{
|
|
55
|
+
/**
|
|
56
|
+
* Semantic color kind. Inherits from a parent SkInputGroup or SkField when not set.
|
|
57
|
+
* @default inherited or 'neutral'
|
|
58
|
+
*/
|
|
59
|
+
kind ?: SkInputGroupAddonKind;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Size of the addon. Inherits from a parent SkInputGroup when not set.
|
|
63
|
+
* @default inherited or 'md'
|
|
64
|
+
*/
|
|
65
|
+
size ?: SkInputGroupAddonSize;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
69
|
+
|
|
70
|
+
const props = withDefaults(defineProps<SkInputGroupAddonComponentProps>(), {
|
|
71
|
+
kind: undefined,
|
|
72
|
+
size: undefined,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
76
|
+
|
|
77
|
+
const validationKind = inject(validationKindKey, NO_KIND);
|
|
78
|
+
const inheritedKind = inject(inheritedKindKey, NO_KIND);
|
|
79
|
+
const inputGroupSize = inject(inputGroupSizeKey, NO_SIZE);
|
|
80
|
+
|
|
81
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
82
|
+
|
|
83
|
+
const effectiveKind = computed<SkInputGroupAddonKind>(() =>
|
|
84
|
+
{
|
|
85
|
+
if(validationKind.value !== undefined) { return validationKind.value; }
|
|
86
|
+
if(props.kind !== undefined) { return props.kind; }
|
|
87
|
+
if(inheritedKind.value !== undefined) { return inheritedKind.value; }
|
|
88
|
+
return 'neutral';
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const effectiveSize = computed<SkInputGroupAddonSize>(() =>
|
|
92
|
+
{
|
|
93
|
+
if(props.size !== undefined) { return props.size; }
|
|
94
|
+
if(inputGroupSize.value !== undefined) { return inputGroupSize.value; }
|
|
95
|
+
return 'md';
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
99
|
+
|
|
100
|
+
const classes = computed<Record<string, boolean>>(() => ({
|
|
101
|
+
'sk-input-group-addon': true,
|
|
102
|
+
[`sk-${ effectiveKind.value }`]: true,
|
|
103
|
+
[`sk-${ effectiveSize.value }`]: true,
|
|
104
|
+
}));
|
|
105
|
+
</script>
|
|
106
|
+
|
|
107
|
+
<!--------------------------------------------------------------------------------------------------------------------->
|