@weni/unnnic-system 3.2.9-alpha.1 → 3.2.9-alpha.3
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/DateFilter/DateFilter.vue.d.ts +60 -93
- package/dist/components/Input/BaseInput.vue.d.ts +18 -0
- package/dist/components/Input/BaseInput.vue.d.ts.map +1 -1
- package/dist/components/Input/Input.vue.d.ts +60 -93
- package/dist/components/Input/Input.vue.d.ts.map +1 -1
- package/dist/components/Input/TextInput.vue.d.ts +36 -0
- package/dist/components/Input/TextInput.vue.d.ts.map +1 -1
- package/dist/components/InputDatePicker/InputDatePicker.vue.d.ts +60 -93
- package/dist/components/InputNext/InputNext.vue.d.ts +1 -1
- package/dist/components/Label/Label.vue.d.ts +2 -2
- package/dist/components/Label/Label.vue.d.ts.map +1 -1
- package/dist/components/ModalNext/ModalNext.vue.d.ts +60 -93
- package/dist/components/SelectSmart/SelectSmart.vue.d.ts +36 -0
- package/dist/components/SelectTime/index.vue.d.ts +36 -0
- package/dist/components/index.d.ts +486 -750
- package/dist/components/index.d.ts.map +1 -1
- package/dist/{es-2735a8fb.js → es-6e7b12d4.js} +1 -1
- package/dist/{index-e012fa52.js → index-531ad3f6.js} +2715 -2696
- package/dist/locales/en.json.d.ts +2 -1
- package/dist/locales/es.json.d.ts +2 -1
- package/dist/locales/pt_br.json.d.ts +2 -1
- package/dist/{pt-br-f38a8b9c.js → pt-br-9c8a0c50.js} +1 -1
- package/dist/style.css +1 -1
- package/dist/unnnic.js +1 -1
- package/dist/unnnic.umd.cjs +32 -32
- package/package.json +1 -1
- package/src/components/Input/BaseInput.vue +12 -2
- package/src/components/Input/Input.scss +2 -1
- package/src/components/Input/Input.vue +17 -29
- package/src/components/Input/TextInput.vue +11 -1
- package/src/components/Input/__test__/__snapshots__/Input.spec.js.snap +2 -2
- package/src/components/Label/Label.vue +2 -2
- package/src/components/Popover/__tests__/Popover.spec.js +147 -0
- package/src/components/Popover/__tests__/__snapshots__/Popover.spec.js.snap +8 -0
- package/src/components/Popover/index.vue +146 -0
- package/src/components/Select/SelectOption.vue +57 -0
- package/src/components/Select/__tests__/Select.spec.js +412 -0
- package/src/components/Select/__tests__/SelectItem.spec.js +330 -0
- package/src/components/Select/__tests__/SelectOption.spec.js +174 -0
- package/src/components/Select/__tests__/__snapshots__/Select.spec.js.snap +93 -0
- package/src/components/Select/__tests__/__snapshots__/SelectItem.spec.js.snap +15 -0
- package/src/components/Select/__tests__/__snapshots__/SelectOption.spec.js.snap +25 -0
- package/src/components/Select/index.vue +187 -0
- package/src/locales/en.json +2 -1
- package/src/locales/es.json +2 -1
- package/src/locales/pt_br.json +2 -1
- package/src/stories/Popover.stories.js +39 -0
- package/src/stories/Select.stories.js +91 -0
package/package.json
CHANGED
|
@@ -4,16 +4,18 @@
|
|
|
4
4
|
v-mask="mask"
|
|
5
5
|
v-bind="attributes"
|
|
6
6
|
:value="fullySanitize(modelValue)"
|
|
7
|
-
:class="classes"
|
|
7
|
+
:class="[classes, { focus: forceActiveStatus }]"
|
|
8
8
|
:type="nativeType"
|
|
9
|
+
:readonly="readonly"
|
|
9
10
|
/>
|
|
10
11
|
<input
|
|
11
12
|
v-else
|
|
12
13
|
v-bind="attributes"
|
|
13
14
|
:value="fullySanitize(modelValue)"
|
|
14
|
-
:class="classes"
|
|
15
|
+
:class="[classes, { focus: forceActiveStatus }]"
|
|
15
16
|
:type="nativeType"
|
|
16
17
|
:maxlength="maxlength"
|
|
18
|
+
:readonly="readonly"
|
|
17
19
|
/>
|
|
18
20
|
</template>
|
|
19
21
|
|
|
@@ -53,6 +55,14 @@ export default {
|
|
|
53
55
|
type: Number,
|
|
54
56
|
default: null,
|
|
55
57
|
},
|
|
58
|
+
readonly: {
|
|
59
|
+
type: Boolean,
|
|
60
|
+
default: false,
|
|
61
|
+
},
|
|
62
|
+
forceActiveStatus: {
|
|
63
|
+
type: Boolean,
|
|
64
|
+
default: false,
|
|
65
|
+
},
|
|
56
66
|
},
|
|
57
67
|
emits: ['update:modelValue'],
|
|
58
68
|
data() {
|
|
@@ -6,30 +6,19 @@
|
|
|
6
6
|
>
|
|
7
7
|
<slot name="label" />
|
|
8
8
|
</p>
|
|
9
|
-
|
|
9
|
+
|
|
10
|
+
<UnnnicLabel
|
|
10
11
|
v-else-if="label"
|
|
11
12
|
class="unnnic-form__label"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
</p>
|
|
16
|
-
<UnnnicToolTip
|
|
17
|
-
v-if="tooltip"
|
|
18
|
-
enabled
|
|
19
|
-
:text="tooltip"
|
|
20
|
-
>
|
|
21
|
-
<UnnnicIcon
|
|
22
|
-
icon="help"
|
|
23
|
-
size="sm"
|
|
24
|
-
scheme="fg-base"
|
|
25
|
-
/>
|
|
26
|
-
</UnnnicToolTip>
|
|
27
|
-
</section>
|
|
13
|
+
:label="label"
|
|
14
|
+
:tooltip="tooltip"
|
|
15
|
+
/>
|
|
28
16
|
|
|
29
17
|
<TextInput
|
|
30
18
|
v-bind="$attrs"
|
|
31
19
|
v-model="val"
|
|
32
20
|
class="unnnic-form-input"
|
|
21
|
+
:forceActiveStatus="forceActiveStatus"
|
|
33
22
|
:placeholder="placeholder"
|
|
34
23
|
:iconLeft="iconLeft"
|
|
35
24
|
:iconRight="iconRight"
|
|
@@ -42,6 +31,7 @@
|
|
|
42
31
|
:nativeType="nativeType"
|
|
43
32
|
:maxlength="maxlength"
|
|
44
33
|
:disabled="disabled"
|
|
34
|
+
:readonly="readonly"
|
|
45
35
|
/>
|
|
46
36
|
|
|
47
37
|
<section class="unnnic-form__hints-container">
|
|
@@ -69,12 +59,11 @@
|
|
|
69
59
|
<script>
|
|
70
60
|
import { fullySanitize } from '../../utils/sanitize';
|
|
71
61
|
import TextInput from './TextInput.vue';
|
|
72
|
-
import
|
|
73
|
-
import UnnnicIcon from '../Icon.vue';
|
|
62
|
+
import UnnnicLabel from '../Label/Label.vue';
|
|
74
63
|
|
|
75
64
|
export default {
|
|
76
65
|
name: 'UnnnicInput',
|
|
77
|
-
components: { TextInput,
|
|
66
|
+
components: { TextInput, UnnnicLabel },
|
|
78
67
|
props: {
|
|
79
68
|
placeholder: {
|
|
80
69
|
type: String,
|
|
@@ -155,6 +144,14 @@ export default {
|
|
|
155
144
|
type: Boolean,
|
|
156
145
|
default: false,
|
|
157
146
|
},
|
|
147
|
+
readonly: {
|
|
148
|
+
type: Boolean,
|
|
149
|
+
default: false,
|
|
150
|
+
},
|
|
151
|
+
forceActiveStatus: {
|
|
152
|
+
type: Boolean,
|
|
153
|
+
default: false,
|
|
154
|
+
},
|
|
158
155
|
},
|
|
159
156
|
emits: ['update:modelValue'],
|
|
160
157
|
data() {
|
|
@@ -203,16 +200,7 @@ export default {
|
|
|
203
200
|
}
|
|
204
201
|
|
|
205
202
|
&__label {
|
|
206
|
-
font: $unnnic-font-body;
|
|
207
|
-
color: $unnnic-color-neutral-cloudy;
|
|
208
203
|
margin-bottom: $unnnic-space-1;
|
|
209
|
-
display: flex;
|
|
210
|
-
align-items: center;
|
|
211
|
-
gap: $unnnic-space-2;
|
|
212
|
-
|
|
213
|
-
:deep(.unnnic-tooltip) {
|
|
214
|
-
display: flex;
|
|
215
|
-
}
|
|
216
204
|
}
|
|
217
205
|
|
|
218
206
|
&__hints-container {
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
:hasIconLeft="!!iconLeft"
|
|
14
14
|
:hasIconRight="!!iconRight || allowTogglePassword"
|
|
15
15
|
:maxlength="maxlength"
|
|
16
|
+
:readonly="readonly"
|
|
17
|
+
:forceActiveStatus="forceActiveStatus"
|
|
16
18
|
@focus="onFocus"
|
|
17
19
|
@blur="onBlur"
|
|
18
20
|
/>
|
|
@@ -107,6 +109,14 @@ export default {
|
|
|
107
109
|
type: Boolean,
|
|
108
110
|
default: false,
|
|
109
111
|
},
|
|
112
|
+
readonly: {
|
|
113
|
+
type: Boolean,
|
|
114
|
+
default: false,
|
|
115
|
+
},
|
|
116
|
+
forceActiveStatus: {
|
|
117
|
+
type: Boolean,
|
|
118
|
+
default: false,
|
|
119
|
+
},
|
|
110
120
|
},
|
|
111
121
|
emits: ['icon-left-click', 'icon-right-click'],
|
|
112
122
|
data() {
|
|
@@ -137,7 +147,7 @@ export default {
|
|
|
137
147
|
return 'fg-muted';
|
|
138
148
|
}
|
|
139
149
|
|
|
140
|
-
if (this.modelValue || this.isFocused) {
|
|
150
|
+
if (this.modelValue || this.isFocused || this.forceActiveStatus) {
|
|
141
151
|
return 'color-gray-700';
|
|
142
152
|
}
|
|
143
153
|
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
exports[`Input.vue > matches the snapshot 1`] = `
|
|
4
4
|
"<div data-v-d890ad85="" class="unnnic-form md">
|
|
5
|
-
<section data-v-d890ad85="" class="unnnic-form__label">
|
|
6
|
-
<p data-v-
|
|
5
|
+
<section data-v-7f222291="" data-v-d890ad85="" class="unnnic-label unnnic-form__label">
|
|
6
|
+
<p data-v-7f222291="" class="unnnic-label__label">Sample Label</p>
|
|
7
7
|
<!--v-if-->
|
|
8
8
|
</section>
|
|
9
9
|
<div data-v-a0d36167="" data-v-d890ad85="" class="text-input size--md unnnic-form-input" mask="####-####"><input data-v-86533b41="" data-v-a0d36167="" class="unnnic-form-input input-itself input size-md normal input--has-icon-left input--has-icon-right unnnic-form-input input-itself" placeholder="Enter text" iconleft="search" iconright="clear" iconleftclickable="true" iconrightclickable="true" hascloudycolor="false" type="text" value=""><span data-v-26446d8e="" data-v-a0d36167="" class="material-symbols-rounded unnnic-icon-scheme--fg-base unnnic-icon-size--ant unnnic--clickable icon-left clickable" data-testid="material-icon" translate="no">search</span><span data-v-26446d8e="" data-v-a0d36167="" class="material-symbols-rounded unnnic-icon-scheme--fg-base unnnic-icon-size--ant unnnic--clickable icon-right clickable" data-testid="material-icon" translate="no">clear</span></div>
|
|
@@ -26,13 +26,13 @@ defineOptions({
|
|
|
26
26
|
name: 'UnnnicLabel',
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
-
interface
|
|
29
|
+
export interface LabelProps {
|
|
30
30
|
label?: string;
|
|
31
31
|
tooltip?: string;
|
|
32
32
|
useHtmlTooltip?: boolean;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
const props = withDefaults(defineProps<
|
|
35
|
+
const props = withDefaults(defineProps<LabelProps>(), {
|
|
36
36
|
label: '',
|
|
37
37
|
tooltip: '',
|
|
38
38
|
useHtmlTooltip: false,
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { beforeEach, describe, expect, afterEach, test, vi } from 'vitest';
|
|
3
|
+
import UnnnicPopover from '@/components/Popover/index.vue';
|
|
4
|
+
|
|
5
|
+
vi.mock('@vueuse/core', () => ({
|
|
6
|
+
onClickOutside: vi.fn(),
|
|
7
|
+
useResizeObserver: vi.fn(),
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
describe('UnnnicPopover.vue', () => {
|
|
11
|
+
let wrapper;
|
|
12
|
+
|
|
13
|
+
const defaultSlots = {
|
|
14
|
+
trigger: '<button data-testid="trigger-button">Click me</button>',
|
|
15
|
+
content: '<div data-testid="popover-content">Popover content</div>',
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const mountWrapper = (props) => {
|
|
19
|
+
return mount(UnnnicPopover, {
|
|
20
|
+
slots: defaultSlots,
|
|
21
|
+
props: {
|
|
22
|
+
...props,
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
wrapper = mountWrapper();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
afterEach(() => {
|
|
32
|
+
wrapper?.unmount();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('renders correctly', () => {
|
|
36
|
+
expect(wrapper.exists()).toBe(true);
|
|
37
|
+
expect(wrapper.find('.unnnic-popover').exists()).toBe(true);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('renders trigger slot', () => {
|
|
41
|
+
const trigger = wrapper.find('[data-testid="popover-trigger"]');
|
|
42
|
+
const triggerButton = wrapper.find('[data-testid="trigger-button"]');
|
|
43
|
+
|
|
44
|
+
expect(trigger.exists()).toBe(true);
|
|
45
|
+
expect(triggerButton.exists()).toBe(true);
|
|
46
|
+
expect(triggerButton.text()).toBe('Click me');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('renders content slot inside balloon', async () => {
|
|
50
|
+
wrapper.vm.open = true;
|
|
51
|
+
await wrapper.vm.$nextTick();
|
|
52
|
+
const balloon = wrapper.find('[data-testid="popover-balloon"]');
|
|
53
|
+
const content = wrapper.find('[data-testid="popover-content"]');
|
|
54
|
+
|
|
55
|
+
expect(balloon.exists()).toBe(true);
|
|
56
|
+
expect(content.exists()).toBe(true);
|
|
57
|
+
expect(content.text()).toBe('Popover content');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('balloon is hidden by default', () => {
|
|
61
|
+
const balloon = wrapper.find('[data-testid="popover-balloon"]');
|
|
62
|
+
expect(balloon.exists()).toBe(false);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('toggles balloon visibility when trigger is clicked', async () => {
|
|
66
|
+
const trigger = wrapper.find('[data-testid="popover-trigger"]');
|
|
67
|
+
|
|
68
|
+
let balloon = wrapper.find('[data-testid="popover-balloon"]');
|
|
69
|
+
|
|
70
|
+
expect(balloon.exists()).toBe(false);
|
|
71
|
+
|
|
72
|
+
await trigger.trigger('click');
|
|
73
|
+
await wrapper.vm.$nextTick();
|
|
74
|
+
|
|
75
|
+
balloon = wrapper.find('[data-testid="popover-balloon"]');
|
|
76
|
+
|
|
77
|
+
expect(balloon.exists()).toBe(true);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test('uses modelValue when provided', async () => {
|
|
81
|
+
const wrapper = mountWrapper({ modelValue: true });
|
|
82
|
+
const balloon = wrapper.find('[data-testid="popover-balloon"]');
|
|
83
|
+
expect(balloon.isVisible()).toBe(true);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test('emits update:modelValue when open state changes', async () => {
|
|
87
|
+
await wrapper.setProps({ modelValue: false });
|
|
88
|
+
|
|
89
|
+
const trigger = wrapper.find('[data-testid="popover-trigger"]');
|
|
90
|
+
await trigger.trigger('click');
|
|
91
|
+
|
|
92
|
+
expect(wrapper.emitted('update:modelValue')).toBeTruthy();
|
|
93
|
+
expect(wrapper.emitted('update:modelValue')[0]).toEqual([true]);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test('does not emit update:modelValue when modelValue is undefined', async () => {
|
|
97
|
+
const trigger = wrapper.find('[data-testid="popover-trigger"]');
|
|
98
|
+
await trigger.trigger('click');
|
|
99
|
+
|
|
100
|
+
expect(wrapper.emitted('update:modelValue')).toBeFalsy();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('exposes open ref', () => {
|
|
104
|
+
expect(wrapper.vm.open).toBeDefined();
|
|
105
|
+
expect(typeof wrapper.vm.open).toBe('boolean');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test('open ref can be controlled programmatically', async () => {
|
|
109
|
+
wrapper.vm.open = true;
|
|
110
|
+
await wrapper.vm.$nextTick();
|
|
111
|
+
|
|
112
|
+
const balloon = wrapper.find('[data-testid="popover-balloon"]');
|
|
113
|
+
expect(balloon.isVisible()).toBe(true);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test('persistent prop prevents closing on outside click', async () => {
|
|
117
|
+
await wrapper.setProps({ persistent: true });
|
|
118
|
+
|
|
119
|
+
const { onClickOutside } = await import('@vueuse/core');
|
|
120
|
+
const mockOnClickOutside = vi.mocked(onClickOutside);
|
|
121
|
+
|
|
122
|
+
const callback = mockOnClickOutside.mock.calls[0][1];
|
|
123
|
+
|
|
124
|
+
wrapper.vm.open = true;
|
|
125
|
+
await wrapper.vm.$nextTick();
|
|
126
|
+
|
|
127
|
+
callback();
|
|
128
|
+
|
|
129
|
+
const balloon = wrapper.find('[data-testid="popover-balloon"]');
|
|
130
|
+
expect(balloon.isVisible()).toBe(true);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test('applies correct CSS classes', async () => {
|
|
134
|
+
wrapper.vm.open = true;
|
|
135
|
+
await wrapper.vm.$nextTick();
|
|
136
|
+
|
|
137
|
+
const popover = wrapper.find('.unnnic-popover');
|
|
138
|
+
const balloon = wrapper.find('.unnnic-popover__balloon');
|
|
139
|
+
|
|
140
|
+
expect(popover.exists()).toBe(true);
|
|
141
|
+
expect(balloon.exists()).toBe(true);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test('matches the snapshot', () => {
|
|
145
|
+
expect(wrapper.html()).toMatchSnapshot();
|
|
146
|
+
});
|
|
147
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`UnnnicPopover.vue > matches the snapshot 1`] = `
|
|
4
|
+
"<section data-v-5a3125ac="" class="unnnic-popover">
|
|
5
|
+
<div data-v-5a3125ac="" class="unnnic-popover__trigger" data-testid="popover-trigger"><button data-testid="trigger-button">Click me</button></div>
|
|
6
|
+
<!--v-if-->
|
|
7
|
+
</section>"
|
|
8
|
+
`;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<section
|
|
3
|
+
class="unnnic-popover"
|
|
4
|
+
ref="popover"
|
|
5
|
+
>
|
|
6
|
+
<div
|
|
7
|
+
class="unnnic-popover__trigger"
|
|
8
|
+
data-testid="popover-trigger"
|
|
9
|
+
@click="toggleOpen()"
|
|
10
|
+
>
|
|
11
|
+
<slot name="trigger" />
|
|
12
|
+
</div>
|
|
13
|
+
<div
|
|
14
|
+
v-if="open"
|
|
15
|
+
class="unnnic-popover__balloon"
|
|
16
|
+
data-testid="popover-balloon"
|
|
17
|
+
>
|
|
18
|
+
<slot name="content" />
|
|
19
|
+
</div>
|
|
20
|
+
</section>
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<script setup lang="ts">
|
|
24
|
+
import { computed, onMounted, ref, useTemplateRef, watch } from 'vue';
|
|
25
|
+
import { onClickOutside, useResizeObserver } from '@vueuse/core';
|
|
26
|
+
|
|
27
|
+
const target = useTemplateRef<HTMLDivElement>('popover');
|
|
28
|
+
|
|
29
|
+
const popoverWidth = ref<string>('');
|
|
30
|
+
|
|
31
|
+
useResizeObserver(target, (entries) => {
|
|
32
|
+
const entry = entries[0];
|
|
33
|
+
const { width } = entry.contentRect;
|
|
34
|
+
popoverWidth.value = `${width}px`;
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
onClickOutside(target, () => {
|
|
38
|
+
if (props.persistent) return;
|
|
39
|
+
open.value = false;
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
defineOptions({
|
|
43
|
+
name: 'UnnnicPopover',
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
interface PopoverBalloonProps {
|
|
47
|
+
width?: string;
|
|
48
|
+
height?: string;
|
|
49
|
+
maxHeight?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface PopoverProps {
|
|
53
|
+
modelValue?: boolean;
|
|
54
|
+
persistent?: boolean;
|
|
55
|
+
popoverBalloonProps?: PopoverBalloonProps;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const props = withDefaults(defineProps<PopoverProps>(), {
|
|
59
|
+
modelValue: undefined,
|
|
60
|
+
persistent: false,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const emit = defineEmits<{
|
|
64
|
+
'update:modelValue': [value: boolean];
|
|
65
|
+
}>();
|
|
66
|
+
|
|
67
|
+
const useModelValue = computed(() => props.modelValue !== undefined);
|
|
68
|
+
|
|
69
|
+
const open = ref<boolean>(
|
|
70
|
+
useModelValue.value ? Boolean(props.modelValue) : false,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
const toggleOpen = () => {
|
|
74
|
+
open.value = !open.value;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const calculatedPopoverWidth = computed(() => {
|
|
78
|
+
return props.popoverBalloonProps?.width || popoverWidth.value;
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const popoverHeight = computed(() => {
|
|
82
|
+
return props.popoverBalloonProps?.height || 'unset';
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const popoverMaxHeight = computed(() => {
|
|
86
|
+
return props.popoverBalloonProps?.maxHeight || 'unset';
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
onMounted(() => {
|
|
90
|
+
if (useModelValue.value) {
|
|
91
|
+
open.value = Boolean(props.modelValue);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
watch(open, (value) => {
|
|
96
|
+
if (useModelValue.value) {
|
|
97
|
+
emit('update:modelValue', value);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
watch(
|
|
102
|
+
() => props.modelValue,
|
|
103
|
+
(value) => {
|
|
104
|
+
open.value = !!value;
|
|
105
|
+
},
|
|
106
|
+
);
|
|
107
|
+
</script>
|
|
108
|
+
|
|
109
|
+
<style lang="scss" scoped>
|
|
110
|
+
@use '@/assets/scss/unnnic' as *;
|
|
111
|
+
|
|
112
|
+
* {
|
|
113
|
+
margin: 0;
|
|
114
|
+
padding: 0;
|
|
115
|
+
box-sizing: border-box;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.unnnic-popover {
|
|
119
|
+
&__balloon {
|
|
120
|
+
border-radius: $unnnic-radius-2;
|
|
121
|
+
padding: $unnnic-space-4;
|
|
122
|
+
background: $unnnic-color-bg-base;
|
|
123
|
+
box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.16);
|
|
124
|
+
// margin-top: $unnnic-space-1;
|
|
125
|
+
position: fixed;
|
|
126
|
+
width: v-bind(calculatedPopoverWidth);
|
|
127
|
+
height: v-bind(popoverHeight);
|
|
128
|
+
max-height: v-bind(popoverMaxHeight);
|
|
129
|
+
overflow: auto;
|
|
130
|
+
|
|
131
|
+
&::-webkit-scrollbar {
|
|
132
|
+
width: $unnnic-spacing-inline-nano;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
&::-webkit-scrollbar-thumb {
|
|
136
|
+
background: $unnnic-color-neutral-cleanest;
|
|
137
|
+
border-radius: $unnnic-border-radius-pill;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
&::-webkit-scrollbar-track {
|
|
141
|
+
background: $unnnic-color-neutral-soft;
|
|
142
|
+
border-radius: $unnnic-border-radius-pill;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
</style>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
:class="[
|
|
4
|
+
'unnnic-select-option',
|
|
5
|
+
{
|
|
6
|
+
'unnnic-select-option--disabled': props.disabled,
|
|
7
|
+
'unnnic-select-option--active': props.active,
|
|
8
|
+
},
|
|
9
|
+
]"
|
|
10
|
+
>
|
|
11
|
+
<p class="unnnic-select-option__label">{{ props.label }}</p>
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script setup lang="ts">
|
|
16
|
+
defineOptions({
|
|
17
|
+
name: 'UnnnicSelectOption',
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
interface SelectOptionProps {
|
|
21
|
+
label: string;
|
|
22
|
+
disabled?: boolean;
|
|
23
|
+
active?: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const props = withDefaults(defineProps<SelectOptionProps>(), {
|
|
27
|
+
disabled: false,
|
|
28
|
+
active: false,
|
|
29
|
+
});
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<style lang="scss" scoped>
|
|
33
|
+
@use '@/assets/scss/unnnic' as *;
|
|
34
|
+
* {
|
|
35
|
+
margin: 0;
|
|
36
|
+
padding: 0;
|
|
37
|
+
box-sizing: border-box;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.unnnic-select-option {
|
|
41
|
+
cursor: pointer;
|
|
42
|
+
border-radius: $unnnic-radius-1;
|
|
43
|
+
padding: $unnnic-space-2 $unnnic-space-4;
|
|
44
|
+
font: $unnnic-font-emphasis;
|
|
45
|
+
|
|
46
|
+
&--active {
|
|
47
|
+
background-color: $unnnic-color-bg-active;
|
|
48
|
+
color: $unnnic-color-fg-inverted;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
&--disabled {
|
|
52
|
+
color: $unnnic-color-fg-muted;
|
|
53
|
+
background-color: $unnnic-color-bg-muted;
|
|
54
|
+
cursor: not-allowed;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
</style>
|