@milaboratories/uikit 2.2.66 → 2.2.68
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/CHANGELOG.md +12 -0
- package/dist/pl-uikit.js +4852 -4475
- package/dist/pl-uikit.js.map +1 -1
- package/dist/pl-uikit.umd.cjs +10 -10
- package/dist/pl-uikit.umd.cjs.map +1 -1
- package/dist/src/components/PlAutocomplete/PlAutocomplete.vue.d.ts +85 -0
- package/dist/src/components/PlAutocomplete/PlAutocomplete.vue.d.ts.map +1 -0
- package/dist/src/components/PlAutocomplete/__tests__/PlAutocomplete.spec.d.ts +2 -0
- package/dist/src/components/PlAutocomplete/__tests__/PlAutocomplete.spec.d.ts.map +1 -0
- package/dist/src/components/PlAutocomplete/index.d.ts +2 -0
- package/dist/src/components/PlAutocomplete/index.d.ts.map +1 -0
- package/dist/src/components/PlDropdown/PlDropdown.vue.d.ts.map +1 -1
- package/dist/src/components/PlDropdownMulti/PlDropdownMulti.vue.d.ts.map +1 -1
- package/dist/src/components/PlRadio/PlRadio.vue.d.ts +33 -0
- package/dist/src/components/PlRadio/PlRadio.vue.d.ts.map +1 -0
- package/dist/src/components/PlRadio/PlRadioGroup.vue.d.ts +50 -0
- package/dist/src/components/PlRadio/PlRadioGroup.vue.d.ts.map +1 -0
- package/dist/src/components/PlRadio/__tests__/PlRadioGroup.spec.d.ts +2 -0
- package/dist/src/components/PlRadio/__tests__/PlRadioGroup.spec.d.ts.map +1 -0
- package/dist/src/components/PlRadio/index.d.ts +3 -0
- package/dist/src/components/PlRadio/index.d.ts.map +1 -0
- package/dist/src/components/PlRadio/keys.d.ts +4 -0
- package/dist/src/components/PlRadio/keys.d.ts.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/style.css +1 -1
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/assets/base.scss +0 -2
- package/src/assets/variables.scss +3 -3
- package/src/components/PlAutocomplete/PlAutocomplete.vue +413 -0
- package/src/components/PlAutocomplete/__tests__/PlAutocomplete.spec.ts +41 -0
- package/src/components/PlAutocomplete/index.ts +1 -0
- package/src/components/PlAutocomplete/pl-autocomplete.scss +277 -0
- package/src/components/PlDropdown/PlDropdown.vue +13 -6
- package/src/components/PlDropdown/pl-dropdown.scss +13 -3
- package/src/components/PlDropdownMulti/PlDropdownMulti.vue +14 -6
- package/src/components/PlDropdownMulti/pl-dropdown-multi.scss +39 -25
- package/src/components/PlRadio/PlRadio.vue +92 -0
- package/src/components/PlRadio/PlRadioGroup.vue +74 -0
- package/src/components/PlRadio/__tests__/PlRadioGroup.spec.ts +168 -0
- package/src/components/PlRadio/index.ts +2 -0
- package/src/components/PlRadio/keys.ts +4 -0
- package/src/index.ts +3 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import type { VueWrapper } from '@vue/test-utils';
|
|
3
|
+
import { mount } from '@vue/test-utils';
|
|
4
|
+
import PlRadio from '../PlRadio.vue';
|
|
5
|
+
import PlRadioGroup from '../PlRadioGroup.vue';
|
|
6
|
+
import { h } from 'vue';
|
|
7
|
+
|
|
8
|
+
// --- Use objects as values ---
|
|
9
|
+
const VALUE_1 = { id: 1, name: 'one' };
|
|
10
|
+
const VALUE_2 = { id: 2, name: 'two' };
|
|
11
|
+
const VALUE_3 = { id: 3, name: 'three' };
|
|
12
|
+
const VALUE_A = { id: 'a', name: 'A' };
|
|
13
|
+
const VALUE_B = { id: 'b', name: 'B' };
|
|
14
|
+
const VALUE_4 = { id: 4, name: 'four' };
|
|
15
|
+
|
|
16
|
+
const OPTIONS = [
|
|
17
|
+
{ label: 'Option 1', value: VALUE_1 },
|
|
18
|
+
{ label: 'Option 2', value: VALUE_2 },
|
|
19
|
+
{ label: 'Option 3', value: VALUE_3, disabled: true },
|
|
20
|
+
];
|
|
21
|
+
// --- ---
|
|
22
|
+
|
|
23
|
+
describe('PlRadioGroup', () => {
|
|
24
|
+
it('renders options correctly', () => {
|
|
25
|
+
const wrapper = mount(PlRadioGroup, {
|
|
26
|
+
props: {
|
|
27
|
+
options: OPTIONS,
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Simplify type casting for now, as InstanceType was problematic
|
|
32
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
33
|
+
const radios = wrapper.findAllComponents(PlRadio) as unknown as VueWrapper<any>[];
|
|
34
|
+
|
|
35
|
+
expect(radios.length).toBe(OPTIONS.length);
|
|
36
|
+
|
|
37
|
+
radios.forEach((radioWrapper, index) => {
|
|
38
|
+
expect(radioWrapper.text()).toBe(OPTIONS[index].label);
|
|
39
|
+
// Use toEqual for object comparison
|
|
40
|
+
expect(radioWrapper.props('value')).toEqual(OPTIONS[index].value);
|
|
41
|
+
expect(radioWrapper.props('disabled') ?? false).toBe(OPTIONS[index].disabled ?? false);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('handles v-model with options prop', async () => {
|
|
46
|
+
const wrapper = mount(PlRadioGroup, {
|
|
47
|
+
props: {
|
|
48
|
+
'modelValue': VALUE_1, // Initial value is an object
|
|
49
|
+
'onUpdate:modelValue': (e) => wrapper.setProps({ modelValue: e }),
|
|
50
|
+
'options': OPTIONS,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const radioInputs = wrapper.findAll('input[type="radio"]');
|
|
55
|
+
expect(radioInputs.length).toBe(OPTIONS.length);
|
|
56
|
+
|
|
57
|
+
// Check initial state
|
|
58
|
+
expect((radioInputs[0].element as HTMLInputElement).checked).toBe(true);
|
|
59
|
+
expect((radioInputs[1].element as HTMLInputElement).checked).toBe(false);
|
|
60
|
+
|
|
61
|
+
// Click the second option
|
|
62
|
+
await radioInputs[1].setValue(true); // Use setValue for radio inputs
|
|
63
|
+
|
|
64
|
+
// Check updated state - use toEqual for objects
|
|
65
|
+
expect(wrapper.props('modelValue')).toEqual(VALUE_2);
|
|
66
|
+
expect((radioInputs[0].element as HTMLInputElement).checked).toBe(false);
|
|
67
|
+
expect((radioInputs[1].element as HTMLInputElement).checked).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// TODO: fix this test
|
|
71
|
+
it.skip('respects disabled options', async () => {
|
|
72
|
+
const wrapper = mount(PlRadioGroup, {
|
|
73
|
+
props: {
|
|
74
|
+
'modelValue': VALUE_1, // Initial value is an object
|
|
75
|
+
'onUpdate:modelValue': (e) => wrapper.setProps({ modelValue: e }),
|
|
76
|
+
'options': OPTIONS,
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const radioInputs = wrapper.findAll<HTMLInputElement>('input[type="radio"]');
|
|
81
|
+
expect((radioInputs[2].element as HTMLInputElement).disabled).toBe(true);
|
|
82
|
+
|
|
83
|
+
// Try clicking the disabled option
|
|
84
|
+
await radioInputs[2].setValue(true);
|
|
85
|
+
|
|
86
|
+
// Model value should not change - use toEqual
|
|
87
|
+
expect(wrapper.props('modelValue')).toEqual(VALUE_1);
|
|
88
|
+
expect((radioInputs[0].element).checked ?? false).toBe(true);
|
|
89
|
+
expect((radioInputs[2].element).checked ?? false).toBe(false);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('assigns the name attribute correctly', () => {
|
|
93
|
+
const groupName = 'test-group';
|
|
94
|
+
const wrapper = mount(PlRadioGroup, {
|
|
95
|
+
props: {
|
|
96
|
+
name: groupName,
|
|
97
|
+
options: OPTIONS,
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const radioInputs = wrapper.findAll('input[type="radio"]');
|
|
102
|
+
radioInputs.forEach((input) => {
|
|
103
|
+
expect(input.attributes('name')).toBe(groupName);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('renders default slot content', async () => {
|
|
108
|
+
const wrapper = mount(PlRadioGroup, {
|
|
109
|
+
props: {
|
|
110
|
+
'modelValue': VALUE_A, // Initial value is an object
|
|
111
|
+
'onUpdate:modelValue': (e) => wrapper.setProps({ modelValue: e }),
|
|
112
|
+
},
|
|
113
|
+
slots: {
|
|
114
|
+
default: () => [
|
|
115
|
+
// Use object values in slots
|
|
116
|
+
h(PlRadio, { value: VALUE_A }, { default: () => 'Slot Option A' }),
|
|
117
|
+
h(PlRadio, { value: VALUE_B }, { default: () => 'Slot Option B' }),
|
|
118
|
+
],
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const radios = wrapper.findAllComponents(PlRadio);
|
|
123
|
+
expect(radios.length).toBe(2);
|
|
124
|
+
expect(radios[0].text()).toBe('Slot Option A');
|
|
125
|
+
expect(radios[1].text()).toBe('Slot Option B');
|
|
126
|
+
|
|
127
|
+
const radioInputs = wrapper.findAll('input[type="radio"]');
|
|
128
|
+
expect((radioInputs[0].element as HTMLInputElement).checked).toBe(true);
|
|
129
|
+
|
|
130
|
+
await radioInputs[1].setValue(true);
|
|
131
|
+
// Use toEqual for object comparison
|
|
132
|
+
expect(wrapper.props('modelValue')).toEqual(VALUE_B);
|
|
133
|
+
expect((radioInputs[1].element as HTMLInputElement).checked).toBe(true);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('renders label slot content', () => {
|
|
137
|
+
const labelText = 'My Radio Group Label';
|
|
138
|
+
const wrapper = mount(PlRadioGroup, {
|
|
139
|
+
slots: {
|
|
140
|
+
label: () => labelText,
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const legend = wrapper.find('legend');
|
|
145
|
+
expect(legend.exists()).toBe(true);
|
|
146
|
+
expect(legend.text()).toBe(labelText);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('combines options prop and default slot', () => {
|
|
150
|
+
const wrapper = mount(PlRadioGroup, {
|
|
151
|
+
props: {
|
|
152
|
+
options: OPTIONS,
|
|
153
|
+
},
|
|
154
|
+
slots: {
|
|
155
|
+
// Use object value in slot
|
|
156
|
+
default: () => h(PlRadio, { value: VALUE_4 }, { default: () => 'Slot Option 4' }),
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
161
|
+
const radiosCombined = wrapper.findAllComponents(PlRadio) as unknown as VueWrapper<any>[];
|
|
162
|
+
expect(radiosCombined.length).toBe(OPTIONS.length + 1);
|
|
163
|
+
// Use toEqual for object comparison
|
|
164
|
+
expect(radiosCombined[0].props('value')).toEqual(OPTIONS[0].value);
|
|
165
|
+
expect(radiosCombined[OPTIONS.length].props('value')).toEqual(VALUE_4);
|
|
166
|
+
expect(radiosCombined[OPTIONS.length].text()).toBe('Slot Option 4');
|
|
167
|
+
});
|
|
168
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -53,6 +53,7 @@ export * from './components/PlStatusTag';
|
|
|
53
53
|
export * from './components/PlLoaderCircular';
|
|
54
54
|
export * from './components/PlSplash';
|
|
55
55
|
export * from './components/PlProgressCell';
|
|
56
|
+
export * from './components/PlAutocomplete';
|
|
56
57
|
|
|
57
58
|
export * from './components/PlFileDialog';
|
|
58
59
|
export * from './components/PlFileInput';
|
|
@@ -66,6 +67,8 @@ export * from './components/PlIcon24';
|
|
|
66
67
|
export * from './components/PlChartStackedBar';
|
|
67
68
|
export * from './components/PlChartHistogram';
|
|
68
69
|
|
|
70
|
+
export * from './components/PlRadio';
|
|
71
|
+
|
|
69
72
|
export * from './colors';
|
|
70
73
|
|
|
71
74
|
// @TODO review (may be private)
|