orio-ui 1.16.2 → 1.18.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/module.json +1 -1
- package/dist/runtime/assets/css/variables.css +1 -1
- package/dist/runtime/components/Badge.d.vue.ts +2 -0
- package/dist/runtime/components/Badge.vue +13 -4
- package/dist/runtime/components/Badge.vue.d.ts +2 -0
- package/dist/runtime/components/Button.d.vue.ts +2 -1
- package/dist/runtime/components/Button.vue +11 -5
- package/dist/runtime/components/Button.vue.d.ts +2 -1
- package/dist/runtime/components/CheckBox.d.vue.ts +2 -1
- package/dist/runtime/components/CheckBox.vue +11 -3
- package/dist/runtime/components/CheckBox.vue.d.ts +2 -1
- package/dist/runtime/components/ControlElement.vue +21 -11
- package/dist/runtime/components/Icon.d.vue.ts +0 -1
- package/dist/runtime/components/Icon.vue +7 -14
- package/dist/runtime/components/Icon.vue.d.ts +0 -1
- package/dist/runtime/components/Input.d.vue.ts +2 -2
- package/dist/runtime/components/Input.vue +14 -6
- package/dist/runtime/components/Input.vue.d.ts +2 -2
- package/dist/runtime/components/NavButton.d.vue.ts +2 -1
- package/dist/runtime/components/NavButton.vue +11 -5
- package/dist/runtime/components/NavButton.vue.d.ts +2 -1
- package/dist/runtime/components/NumberInput/Horizontal.d.vue.ts +1 -1
- package/dist/runtime/components/NumberInput/Horizontal.vue +7 -1
- package/dist/runtime/components/NumberInput/Horizontal.vue.d.ts +1 -1
- package/dist/runtime/components/NumberInput/Vertical.d.vue.ts +1 -1
- package/dist/runtime/components/NumberInput/Vertical.vue +7 -1
- package/dist/runtime/components/NumberInput/Vertical.vue.d.ts +1 -1
- package/dist/runtime/components/NumberInput/index.d.vue.ts +3 -2
- package/dist/runtime/components/NumberInput/index.vue +23 -3
- package/dist/runtime/components/NumberInput/index.vue.d.ts +3 -2
- package/dist/runtime/components/Popover.d.vue.ts +22 -51
- package/dist/runtime/components/Popover.vue +37 -65
- package/dist/runtime/components/Popover.vue.d.ts +22 -51
- package/dist/runtime/components/RadioButton.d.vue.ts +3 -2
- package/dist/runtime/components/RadioButton.vue +12 -5
- package/dist/runtime/components/RadioButton.vue.d.ts +3 -2
- package/dist/runtime/components/Selector.d.vue.ts +2 -1
- package/dist/runtime/components/Selector.vue +68 -10
- package/dist/runtime/components/Selector.vue.d.ts +2 -1
- package/dist/runtime/components/SwitchButton.d.vue.ts +2 -1
- package/dist/runtime/components/SwitchButton.vue +10 -2
- package/dist/runtime/components/SwitchButton.vue.d.ts +2 -1
- package/dist/runtime/components/Textarea.d.vue.ts +2 -1
- package/dist/runtime/components/Textarea.vue +10 -7
- package/dist/runtime/components/Textarea.vue.d.ts +2 -1
- package/dist/runtime/components/view/Text.d.vue.ts +1 -1
- package/dist/runtime/components/view/Text.vue.d.ts +1 -1
- package/dist/runtime/composables/useListKeyboard.d.ts +19 -0
- package/dist/runtime/composables/useListKeyboard.js +59 -0
- package/dist/runtime/composables/useValidation.d.ts +3 -3
- package/dist/runtime/composables/useValidation.js +5 -6
- package/package.json +1 -1
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
type PopoverPosition = "top" | "bottom" | "left" | "right" | "top-left" | "top-right" | "bottom-left" | "bottom-right" | "left-top" | "left-bottom" | "right-top" | "right-bottom";
|
|
2
|
+
interface PopoverProps {
|
|
3
|
+
/**
|
|
4
|
+
* Defines where the popover is placed relative to the trigger.
|
|
5
|
+
* Acceptable single values: 'top', 'bottom', 'left', 'right'
|
|
6
|
+
* Acceptable combos: 'top-left', 'top-right', 'bottom-left', 'bottom-right',
|
|
7
|
+
* 'left-top', 'left-bottom', 'right-top', 'right-bottom'
|
|
8
|
+
* If you only provide 'top', 'bottom', 'left', or 'right',
|
|
9
|
+
* it aligns center by default.
|
|
10
|
+
*/
|
|
11
|
+
position?: PopoverPosition;
|
|
12
|
+
/**
|
|
13
|
+
* Distance (in px) between the popover and the trigger element.
|
|
14
|
+
*/
|
|
15
|
+
offset?: number;
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
}
|
|
1
18
|
/**
|
|
2
19
|
* Toggles popover visibility.
|
|
3
20
|
* @param {boolean|null} force - If `true`/`false`, force that state; if `null`, toggle.
|
|
@@ -5,67 +22,21 @@
|
|
|
5
22
|
declare function togglePopover(force?: boolean | null): Promise<void>;
|
|
6
23
|
declare var __VLS_1: {
|
|
7
24
|
toggle: typeof togglePopover;
|
|
25
|
+
isOpen: boolean;
|
|
8
26
|
}, __VLS_15: {
|
|
9
27
|
toggle: typeof togglePopover;
|
|
28
|
+
isOpen: true;
|
|
10
29
|
};
|
|
11
30
|
type __VLS_Slots = {} & {
|
|
12
31
|
default?: (props: typeof __VLS_1) => any;
|
|
13
32
|
} & {
|
|
14
33
|
content?: (props: typeof __VLS_15) => any;
|
|
15
34
|
};
|
|
16
|
-
declare const __VLS_base: import("vue").DefineComponent<import("vue").
|
|
17
|
-
/**
|
|
18
|
-
* Defines where the popover is placed relative to the trigger.
|
|
19
|
-
* Acceptable single values: 'top', 'bottom', 'left', 'right'
|
|
20
|
-
* Acceptable combos: 'top-left', 'top-right', 'bottom-left', 'bottom-right',
|
|
21
|
-
* 'left-top', 'left-bottom', 'right-top', 'right-bottom'
|
|
22
|
-
* If you only provide 'top', 'bottom', 'left', or 'right',
|
|
23
|
-
* it aligns center by default.
|
|
24
|
-
*/
|
|
25
|
-
position: {
|
|
26
|
-
type: StringConstructor;
|
|
27
|
-
default: string;
|
|
28
|
-
};
|
|
29
|
-
/**
|
|
30
|
-
* Distance (in px) between the popover and the trigger element.
|
|
31
|
-
*/
|
|
32
|
-
offset: {
|
|
33
|
-
type: NumberConstructor;
|
|
34
|
-
default: number;
|
|
35
|
-
};
|
|
36
|
-
disabled: {
|
|
37
|
-
type: BooleanConstructor;
|
|
38
|
-
default: boolean;
|
|
39
|
-
};
|
|
40
|
-
}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
41
|
-
/**
|
|
42
|
-
* Defines where the popover is placed relative to the trigger.
|
|
43
|
-
* Acceptable single values: 'top', 'bottom', 'left', 'right'
|
|
44
|
-
* Acceptable combos: 'top-left', 'top-right', 'bottom-left', 'bottom-right',
|
|
45
|
-
* 'left-top', 'left-bottom', 'right-top', 'right-bottom'
|
|
46
|
-
* If you only provide 'top', 'bottom', 'left', or 'right',
|
|
47
|
-
* it aligns center by default.
|
|
48
|
-
*/
|
|
49
|
-
position: {
|
|
50
|
-
type: StringConstructor;
|
|
51
|
-
default: string;
|
|
52
|
-
};
|
|
53
|
-
/**
|
|
54
|
-
* Distance (in px) between the popover and the trigger element.
|
|
55
|
-
*/
|
|
56
|
-
offset: {
|
|
57
|
-
type: NumberConstructor;
|
|
58
|
-
default: number;
|
|
59
|
-
};
|
|
60
|
-
disabled: {
|
|
61
|
-
type: BooleanConstructor;
|
|
62
|
-
default: boolean;
|
|
63
|
-
};
|
|
64
|
-
}>> & Readonly<{}>, {
|
|
35
|
+
declare const __VLS_base: import("vue").DefineComponent<PopoverProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<PopoverProps> & Readonly<{}>, {
|
|
65
36
|
disabled: boolean;
|
|
66
|
-
position:
|
|
37
|
+
position: PopoverPosition;
|
|
67
38
|
offset: number;
|
|
68
|
-
}, {}, {}, {}, string, import("vue").ComponentProvideOptions,
|
|
39
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
69
40
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
70
41
|
declare const _default: typeof __VLS_export;
|
|
71
42
|
export default _default;
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
<div ref="
|
|
4
|
-
<slot :toggle="togglePopover" />
|
|
3
|
+
<div ref="triggerRef">
|
|
4
|
+
<slot :toggle="togglePopover" :is-open="showPopover" />
|
|
5
5
|
</div>
|
|
6
6
|
|
|
7
7
|
<Teleport to="body">
|
|
8
8
|
<Transition name="animate-fade-slide" appear>
|
|
9
9
|
<div
|
|
10
10
|
v-if="showPopover"
|
|
11
|
-
ref="
|
|
11
|
+
ref="containerRef"
|
|
12
12
|
class="popover"
|
|
13
13
|
:style="popoverStyle"
|
|
14
14
|
>
|
|
15
|
-
<slot name="content" :toggle="togglePopover" />
|
|
15
|
+
<slot name="content" :toggle="togglePopover" :is-open="showPopover" />
|
|
16
16
|
</div>
|
|
17
17
|
</Transition>
|
|
18
18
|
</Teleport>
|
|
@@ -20,43 +20,20 @@
|
|
|
20
20
|
</template>
|
|
21
21
|
|
|
22
22
|
<script setup>
|
|
23
|
+
import { ref, computed, nextTick, useTemplateRef, watch } from "vue";
|
|
23
24
|
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
onBeforeUnmount,
|
|
29
|
-
watch
|
|
30
|
-
} from "vue";
|
|
31
|
-
import { useElementBounding } from "@vueuse/core";
|
|
25
|
+
useElementBounding,
|
|
26
|
+
onClickOutside,
|
|
27
|
+
useEventListener
|
|
28
|
+
} from "@vueuse/core";
|
|
32
29
|
const props = defineProps({
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
* Acceptable combos: 'top-left', 'top-right', 'bottom-left', 'bottom-right',
|
|
37
|
-
* 'left-top', 'left-bottom', 'right-top', 'right-bottom'
|
|
38
|
-
* If you only provide 'top', 'bottom', 'left', or 'right',
|
|
39
|
-
* it aligns center by default.
|
|
40
|
-
*/
|
|
41
|
-
position: {
|
|
42
|
-
type: String,
|
|
43
|
-
default: "bottom-left"
|
|
44
|
-
},
|
|
45
|
-
/**
|
|
46
|
-
* Distance (in px) between the popover and the trigger element.
|
|
47
|
-
*/
|
|
48
|
-
offset: {
|
|
49
|
-
type: Number,
|
|
50
|
-
default: 10
|
|
51
|
-
},
|
|
52
|
-
disabled: {
|
|
53
|
-
type: Boolean,
|
|
54
|
-
default: false
|
|
55
|
-
}
|
|
30
|
+
position: { type: String, required: false, default: "bottom-left" },
|
|
31
|
+
offset: { type: Number, required: false, default: 10 },
|
|
32
|
+
disabled: { type: Boolean, required: false, default: false }
|
|
56
33
|
});
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
const { width: popoverWidth, height: popoverHeight } = useElementBounding(
|
|
34
|
+
const triggerRef = useTemplateRef("triggerRef");
|
|
35
|
+
const containerRef = useTemplateRef("containerRef");
|
|
36
|
+
const { width: popoverWidth, height: popoverHeight } = useElementBounding(containerRef);
|
|
60
37
|
const showPopover = ref(false);
|
|
61
38
|
const triggerRect = ref(null);
|
|
62
39
|
const popoverRect = ref(null);
|
|
@@ -96,7 +73,7 @@ const popoverStyle = computed(() => {
|
|
|
96
73
|
});
|
|
97
74
|
const currentPosition = ref(props.position);
|
|
98
75
|
const getFallbackPositions = (pos) => {
|
|
99
|
-
const [main, sub = "center"] = pos.split("-");
|
|
76
|
+
const [main = "", sub = "center"] = pos.split("-");
|
|
100
77
|
const opposites = {
|
|
101
78
|
top: "bottom",
|
|
102
79
|
bottom: "top",
|
|
@@ -107,15 +84,19 @@ const getFallbackPositions = (pos) => {
|
|
|
107
84
|
`${main}-${sub}`,
|
|
108
85
|
`${opposites[main]}-${sub}`,
|
|
109
86
|
`${main}-center`,
|
|
110
|
-
`${opposites[main]}-center
|
|
111
|
-
`${sub}-${main}`,
|
|
112
|
-
// e.g. left-top
|
|
113
|
-
`${sub}-${opposites[main]}`
|
|
87
|
+
`${opposites[main]}-center`
|
|
114
88
|
];
|
|
89
|
+
if (sub !== "center") {
|
|
90
|
+
allPositions.push(
|
|
91
|
+
`${sub}-${main}`,
|
|
92
|
+
// e.g. left-top
|
|
93
|
+
`${sub}-${opposites[main]}`
|
|
94
|
+
);
|
|
95
|
+
}
|
|
115
96
|
return [...new Set(allPositions)];
|
|
116
97
|
};
|
|
117
98
|
function checkIfFits(position, tRect, pRect, offset) {
|
|
118
|
-
const [main
|
|
99
|
+
const [main] = position.split("-");
|
|
119
100
|
const space = {
|
|
120
101
|
top: tRect.top,
|
|
121
102
|
bottom: window.innerHeight - tRect.bottom,
|
|
@@ -130,15 +111,14 @@ function checkIfFits(position, tRect, pRect, offset) {
|
|
|
130
111
|
}
|
|
131
112
|
async function updateRects() {
|
|
132
113
|
await nextTick();
|
|
133
|
-
const triggerEl =
|
|
134
|
-
const popoverEl =
|
|
114
|
+
const triggerEl = triggerRef.value;
|
|
115
|
+
const popoverEl = containerRef.value;
|
|
135
116
|
if (!triggerEl || !popoverEl) return;
|
|
136
117
|
const tRect = triggerEl.getBoundingClientRect();
|
|
137
118
|
triggerRect.value = tRect;
|
|
138
119
|
const fallbacks = getFallbackPositions(props.position);
|
|
120
|
+
popoverEl.style.visibility = "hidden";
|
|
139
121
|
for (const pos of fallbacks) {
|
|
140
|
-
popoverEl.style.visibility = "hidden";
|
|
141
|
-
popoverEl.style.display = "block";
|
|
142
122
|
const pRect = popoverEl.getBoundingClientRect();
|
|
143
123
|
const fits = checkIfFits(pos, tRect, pRect, props.offset);
|
|
144
124
|
if (fits) {
|
|
@@ -150,6 +130,7 @@ async function updateRects() {
|
|
|
150
130
|
}
|
|
151
131
|
popoverRect.value = popoverEl.getBoundingClientRect();
|
|
152
132
|
currentPosition.value = props.position;
|
|
133
|
+
popoverEl.style.visibility = "";
|
|
153
134
|
}
|
|
154
135
|
async function togglePopover(force = null) {
|
|
155
136
|
if (props.disabled) return;
|
|
@@ -158,29 +139,20 @@ async function togglePopover(force = null) {
|
|
|
158
139
|
await nextTick();
|
|
159
140
|
updateRects();
|
|
160
141
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const clickedInsidePopover = popover.value && popover.value.contains(e.target);
|
|
165
|
-
if (!clickedInsideTrigger && !clickedInsidePopover) {
|
|
142
|
+
onClickOutside(
|
|
143
|
+
containerRef,
|
|
144
|
+
() => {
|
|
166
145
|
showPopover.value = false;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
146
|
+
},
|
|
147
|
+
{ ignore: [triggerRef] }
|
|
148
|
+
);
|
|
169
149
|
function redrawPopover() {
|
|
170
150
|
if (!showPopover.value) return;
|
|
171
151
|
updateRects();
|
|
172
152
|
}
|
|
173
153
|
watch([popoverWidth, popoverHeight], redrawPopover);
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
window.addEventListener("scroll", redrawPopover, true);
|
|
177
|
-
window.addEventListener("resize", redrawPopover, true);
|
|
178
|
-
});
|
|
179
|
-
onBeforeUnmount(() => {
|
|
180
|
-
document.removeEventListener("click", handleDocumentClick);
|
|
181
|
-
window.removeEventListener("scroll", redrawPopover, true);
|
|
182
|
-
window.removeEventListener("resize", redrawPopover, true);
|
|
183
|
-
});
|
|
154
|
+
useEventListener(window, "scroll", redrawPopover, { capture: true });
|
|
155
|
+
useEventListener(window, "resize", redrawPopover, { capture: true });
|
|
184
156
|
</script>
|
|
185
157
|
|
|
186
158
|
<style scoped>
|
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
type PopoverPosition = "top" | "bottom" | "left" | "right" | "top-left" | "top-right" | "bottom-left" | "bottom-right" | "left-top" | "left-bottom" | "right-top" | "right-bottom";
|
|
2
|
+
interface PopoverProps {
|
|
3
|
+
/**
|
|
4
|
+
* Defines where the popover is placed relative to the trigger.
|
|
5
|
+
* Acceptable single values: 'top', 'bottom', 'left', 'right'
|
|
6
|
+
* Acceptable combos: 'top-left', 'top-right', 'bottom-left', 'bottom-right',
|
|
7
|
+
* 'left-top', 'left-bottom', 'right-top', 'right-bottom'
|
|
8
|
+
* If you only provide 'top', 'bottom', 'left', or 'right',
|
|
9
|
+
* it aligns center by default.
|
|
10
|
+
*/
|
|
11
|
+
position?: PopoverPosition;
|
|
12
|
+
/**
|
|
13
|
+
* Distance (in px) between the popover and the trigger element.
|
|
14
|
+
*/
|
|
15
|
+
offset?: number;
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
}
|
|
1
18
|
/**
|
|
2
19
|
* Toggles popover visibility.
|
|
3
20
|
* @param {boolean|null} force - If `true`/`false`, force that state; if `null`, toggle.
|
|
@@ -5,67 +22,21 @@
|
|
|
5
22
|
declare function togglePopover(force?: boolean | null): Promise<void>;
|
|
6
23
|
declare var __VLS_1: {
|
|
7
24
|
toggle: typeof togglePopover;
|
|
25
|
+
isOpen: boolean;
|
|
8
26
|
}, __VLS_15: {
|
|
9
27
|
toggle: typeof togglePopover;
|
|
28
|
+
isOpen: true;
|
|
10
29
|
};
|
|
11
30
|
type __VLS_Slots = {} & {
|
|
12
31
|
default?: (props: typeof __VLS_1) => any;
|
|
13
32
|
} & {
|
|
14
33
|
content?: (props: typeof __VLS_15) => any;
|
|
15
34
|
};
|
|
16
|
-
declare const __VLS_base: import("vue").DefineComponent<import("vue").
|
|
17
|
-
/**
|
|
18
|
-
* Defines where the popover is placed relative to the trigger.
|
|
19
|
-
* Acceptable single values: 'top', 'bottom', 'left', 'right'
|
|
20
|
-
* Acceptable combos: 'top-left', 'top-right', 'bottom-left', 'bottom-right',
|
|
21
|
-
* 'left-top', 'left-bottom', 'right-top', 'right-bottom'
|
|
22
|
-
* If you only provide 'top', 'bottom', 'left', or 'right',
|
|
23
|
-
* it aligns center by default.
|
|
24
|
-
*/
|
|
25
|
-
position: {
|
|
26
|
-
type: StringConstructor;
|
|
27
|
-
default: string;
|
|
28
|
-
};
|
|
29
|
-
/**
|
|
30
|
-
* Distance (in px) between the popover and the trigger element.
|
|
31
|
-
*/
|
|
32
|
-
offset: {
|
|
33
|
-
type: NumberConstructor;
|
|
34
|
-
default: number;
|
|
35
|
-
};
|
|
36
|
-
disabled: {
|
|
37
|
-
type: BooleanConstructor;
|
|
38
|
-
default: boolean;
|
|
39
|
-
};
|
|
40
|
-
}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
41
|
-
/**
|
|
42
|
-
* Defines where the popover is placed relative to the trigger.
|
|
43
|
-
* Acceptable single values: 'top', 'bottom', 'left', 'right'
|
|
44
|
-
* Acceptable combos: 'top-left', 'top-right', 'bottom-left', 'bottom-right',
|
|
45
|
-
* 'left-top', 'left-bottom', 'right-top', 'right-bottom'
|
|
46
|
-
* If you only provide 'top', 'bottom', 'left', or 'right',
|
|
47
|
-
* it aligns center by default.
|
|
48
|
-
*/
|
|
49
|
-
position: {
|
|
50
|
-
type: StringConstructor;
|
|
51
|
-
default: string;
|
|
52
|
-
};
|
|
53
|
-
/**
|
|
54
|
-
* Distance (in px) between the popover and the trigger element.
|
|
55
|
-
*/
|
|
56
|
-
offset: {
|
|
57
|
-
type: NumberConstructor;
|
|
58
|
-
default: number;
|
|
59
|
-
};
|
|
60
|
-
disabled: {
|
|
61
|
-
type: BooleanConstructor;
|
|
62
|
-
default: boolean;
|
|
63
|
-
};
|
|
64
|
-
}>> & Readonly<{}>, {
|
|
35
|
+
declare const __VLS_base: import("vue").DefineComponent<PopoverProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<PopoverProps> & Readonly<{}>, {
|
|
65
36
|
disabled: boolean;
|
|
66
|
-
position:
|
|
37
|
+
position: PopoverPosition;
|
|
67
38
|
offset: number;
|
|
68
|
-
}, {}, {}, {}, string, import("vue").ComponentProvideOptions,
|
|
39
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
69
40
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
70
41
|
declare const _default: typeof __VLS_export;
|
|
71
42
|
export default _default;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
import type { ControlProps } from "./ControlElement.vue.js";
|
|
2
|
+
export interface RadioButtonProps extends ControlProps {
|
|
2
3
|
/** The value this radio represents; compared to v-model to determine checked state */
|
|
3
4
|
value?: unknown;
|
|
4
5
|
/** HTML name attribute — groups radios together so only one is selected at a time */
|
|
5
6
|
name?: string;
|
|
6
7
|
/** Inline label text (alternative to default slot) */
|
|
7
|
-
|
|
8
|
+
text?: string;
|
|
8
9
|
/** Visually hides the label while keeping it accessible to SR (screen readers) */
|
|
9
10
|
hideLabel?: boolean;
|
|
10
11
|
}
|
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
const modelValue = defineModel({ type: null });
|
|
3
|
-
defineProps({
|
|
3
|
+
const props = defineProps({
|
|
4
4
|
value: { type: null, required: false },
|
|
5
5
|
name: { type: String, required: false },
|
|
6
|
+
text: { type: String, required: false },
|
|
7
|
+
hideLabel: { type: Boolean, required: false },
|
|
8
|
+
appearance: { type: String, required: false },
|
|
9
|
+
error: { type: [String, null], required: false },
|
|
10
|
+
group: { type: Boolean, required: false },
|
|
11
|
+
id: { type: String, required: false },
|
|
6
12
|
label: { type: String, required: false },
|
|
7
|
-
|
|
13
|
+
layout: { type: String, required: false },
|
|
14
|
+
size: { type: String, required: false }
|
|
8
15
|
});
|
|
9
16
|
</script>
|
|
10
17
|
|
|
11
18
|
<template>
|
|
12
|
-
<orio-control-element class="radio">
|
|
19
|
+
<orio-control-element v-bind="props" class="radio">
|
|
13
20
|
<label class="radio-label">
|
|
14
21
|
<input
|
|
15
22
|
v-model="modelValue"
|
|
@@ -21,11 +28,11 @@ defineProps({
|
|
|
21
28
|
/>
|
|
22
29
|
<span class="radio-box" />
|
|
23
30
|
<span
|
|
24
|
-
v-if="
|
|
31
|
+
v-if="text || $slots.default"
|
|
25
32
|
class="radio-text"
|
|
26
33
|
:class="{ 'sr-only': hideLabel }"
|
|
27
34
|
>
|
|
28
|
-
<slot>{{
|
|
35
|
+
<slot>{{ text }}</slot>
|
|
29
36
|
</span>
|
|
30
37
|
</label>
|
|
31
38
|
</orio-control-element>
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
import type { ControlProps } from "./ControlElement.vue.js";
|
|
2
|
+
export interface RadioButtonProps extends ControlProps {
|
|
2
3
|
/** The value this radio represents; compared to v-model to determine checked state */
|
|
3
4
|
value?: unknown;
|
|
4
5
|
/** HTML name attribute — groups radios together so only one is selected at a time */
|
|
5
6
|
name?: string;
|
|
6
7
|
/** Inline label text (alternative to default slot) */
|
|
7
|
-
|
|
8
|
+
text?: string;
|
|
8
9
|
/** Visually hides the label while keeping it accessible to SR (screen readers) */
|
|
9
10
|
hideLabel?: boolean;
|
|
10
11
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type { ControlProps } from "./ControlElement.vue.js";
|
|
1
2
|
export type SelectableOption<T extends object = object> = string | T;
|
|
2
|
-
export interface SelectProps<T extends object = object> {
|
|
3
|
+
export interface SelectProps<T extends object = object> extends ControlProps {
|
|
3
4
|
options: SelectableOption[];
|
|
4
5
|
multiple?: boolean;
|
|
5
6
|
field?: string;
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { computed, toRefs } from "vue";
|
|
2
|
+
import { computed, ref, toRefs } from "vue";
|
|
3
|
+
import { useListKeyboard } from "../composables/useListKeyboard";
|
|
3
4
|
const props = defineProps({
|
|
4
5
|
options: { type: Array, required: true },
|
|
5
6
|
multiple: { type: Boolean, required: false },
|
|
6
7
|
field: { type: String, required: false, default: "id" },
|
|
7
8
|
optionName: { type: String, required: false },
|
|
8
|
-
placeholder: { type: String, required: false, default: "Select an option" }
|
|
9
|
+
placeholder: { type: String, required: false, default: "Select an option" },
|
|
10
|
+
appearance: { type: String, required: false },
|
|
11
|
+
error: { type: [String, null], required: false },
|
|
12
|
+
group: { type: Boolean, required: false },
|
|
13
|
+
id: { type: String, required: false },
|
|
14
|
+
label: { type: String, required: false },
|
|
15
|
+
layout: { type: String, required: false },
|
|
16
|
+
size: { type: String, required: false }
|
|
9
17
|
});
|
|
10
18
|
const { field, optionName, placeholder } = toRefs(props);
|
|
11
19
|
const modelValue = defineModel({ type: null, ...{
|
|
@@ -59,15 +67,53 @@ function getOptionKey(option) {
|
|
|
59
67
|
if (typeof option === "string") return option;
|
|
60
68
|
return String(option[key.value]);
|
|
61
69
|
}
|
|
70
|
+
const controlProps = computed(() => {
|
|
71
|
+
const {
|
|
72
|
+
options: _options,
|
|
73
|
+
multiple: _multiple,
|
|
74
|
+
field: _field,
|
|
75
|
+
optionName: _optionName,
|
|
76
|
+
placeholder: _placeholder,
|
|
77
|
+
...rest
|
|
78
|
+
} = props;
|
|
79
|
+
return rest;
|
|
80
|
+
});
|
|
62
81
|
const selectorAttrs = computed(() => ({ getOptionKey, getOptionLabel }));
|
|
82
|
+
const popoverToggleRef = ref(() => {
|
|
83
|
+
});
|
|
84
|
+
const {
|
|
85
|
+
highlightedIndex,
|
|
86
|
+
listRef,
|
|
87
|
+
onKeydown,
|
|
88
|
+
reset: resetHighlight
|
|
89
|
+
} = useListKeyboard({
|
|
90
|
+
count: () => props.options.length,
|
|
91
|
+
onSelect: (index) => toggleOption(props.options[index], () => popoverToggleRef.value(false)),
|
|
92
|
+
onOpen: () => {
|
|
93
|
+
popoverToggleRef.value(true);
|
|
94
|
+
resetHighlight();
|
|
95
|
+
},
|
|
96
|
+
onClose: () => popoverToggleRef.value(false),
|
|
97
|
+
initialIndex: () => props.options.findIndex(isOptionSelected)
|
|
98
|
+
});
|
|
63
99
|
</script>
|
|
64
100
|
|
|
65
101
|
<template>
|
|
66
|
-
<orio-control-element>
|
|
102
|
+
<orio-control-element v-bind="controlProps">
|
|
67
103
|
<orio-popover position="bottom-right" :offset="5">
|
|
68
|
-
<template #default="{ toggle }">
|
|
104
|
+
<template #default="{ toggle, isOpen }">
|
|
69
105
|
<slot name="trigger" :toggle>
|
|
70
|
-
<
|
|
106
|
+
<button
|
|
107
|
+
:id="props.id"
|
|
108
|
+
type="button"
|
|
109
|
+
class="selector-trigger"
|
|
110
|
+
aria-haspopup="listbox"
|
|
111
|
+
:aria-expanded="isOpen"
|
|
112
|
+
@click="toggle();
|
|
113
|
+
!isOpen && resetHighlight()"
|
|
114
|
+
@keydown="popoverToggleRef = toggle;
|
|
115
|
+
onKeydown($event, isOpen)"
|
|
116
|
+
>
|
|
71
117
|
<slot
|
|
72
118
|
name="trigger-content"
|
|
73
119
|
:toggle
|
|
@@ -91,18 +137,29 @@ const selectorAttrs = computed(() => ({ getOptionKey, getOptionLabel }));
|
|
|
91
137
|
</div>
|
|
92
138
|
<orio-icon name="chevron-down" />
|
|
93
139
|
</slot>
|
|
94
|
-
</
|
|
140
|
+
</button>
|
|
95
141
|
</slot>
|
|
96
142
|
</template>
|
|
97
143
|
|
|
98
144
|
<template #content="{ toggle }">
|
|
99
145
|
<div class="selector-content">
|
|
100
|
-
<ul
|
|
146
|
+
<ul
|
|
147
|
+
v-if="options.length"
|
|
148
|
+
ref="listRef"
|
|
149
|
+
role="listbox"
|
|
150
|
+
:aria-multiselectable="multiple || void 0"
|
|
151
|
+
>
|
|
101
152
|
<li
|
|
102
|
-
v-for="option in options"
|
|
153
|
+
v-for="(option, index) in options"
|
|
103
154
|
:key="getOptionKey(option)"
|
|
104
|
-
|
|
155
|
+
role="option"
|
|
156
|
+
:aria-selected="isOptionSelected(option)"
|
|
157
|
+
:class="{
|
|
158
|
+
selected: isOptionSelected(option),
|
|
159
|
+
highlighted: index === highlightedIndex
|
|
160
|
+
}"
|
|
105
161
|
@click="toggleOption(option, toggle)"
|
|
162
|
+
@mouseenter="highlightedIndex = index"
|
|
106
163
|
>
|
|
107
164
|
<slot
|
|
108
165
|
name="option"
|
|
@@ -127,6 +184,7 @@ const selectorAttrs = computed(() => ({ getOptionKey, getOptionLabel }));
|
|
|
127
184
|
|
|
128
185
|
<style scoped>
|
|
129
186
|
.selector-trigger {
|
|
187
|
+
width: 100%;
|
|
130
188
|
z-index: 1;
|
|
131
189
|
min-height: 1.5rem;
|
|
132
190
|
user-select: none;
|
|
@@ -178,7 +236,7 @@ const selectorAttrs = computed(() => ({ getOptionKey, getOptionLabel }));
|
|
|
178
236
|
transition: background-color 0.15s ease, color 0.15s ease;
|
|
179
237
|
color: var(--color-text);
|
|
180
238
|
}
|
|
181
|
-
.selector-content ul li:hover {
|
|
239
|
+
.selector-content ul li:hover, .selector-content ul li.highlighted {
|
|
182
240
|
background-color: var(--color-surface); /* neutral lift */
|
|
183
241
|
}
|
|
184
242
|
.selector-content ul li.selected {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type { ControlProps } from "./ControlElement.vue.js";
|
|
1
2
|
export type SelectableOption<T extends object = object> = string | T;
|
|
2
|
-
export interface SelectProps<T extends object = object> {
|
|
3
|
+
export interface SelectProps<T extends object = object> extends ControlProps {
|
|
3
4
|
options: SelectableOption[];
|
|
4
5
|
multiple?: boolean;
|
|
5
6
|
field?: string;
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
const props = defineProps({
|
|
3
|
-
disabled: { type: Boolean, required: false, default: false }
|
|
3
|
+
disabled: { type: Boolean, required: false, default: false },
|
|
4
|
+
appearance: { type: String, required: false },
|
|
5
|
+
error: { type: [String, null], required: false },
|
|
6
|
+
group: { type: Boolean, required: false },
|
|
7
|
+
id: { type: String, required: false },
|
|
8
|
+
label: { type: String, required: false },
|
|
9
|
+
layout: { type: String, required: false },
|
|
10
|
+
size: { type: String, required: false }
|
|
4
11
|
});
|
|
5
12
|
const modelValue = defineModel({ type: Boolean, ...{ required: false } });
|
|
6
13
|
function toggle() {
|
|
@@ -10,9 +17,10 @@ function toggle() {
|
|
|
10
17
|
</script>
|
|
11
18
|
|
|
12
19
|
<template>
|
|
13
|
-
<orio-control-element v-slot="{ id }">
|
|
20
|
+
<orio-control-element v-slot="{ id }" v-bind="props">
|
|
14
21
|
<button
|
|
15
22
|
:id
|
|
23
|
+
v-bind="$attrs"
|
|
16
24
|
class="switch-button"
|
|
17
25
|
:class="{ active: modelValue, disabled }"
|
|
18
26
|
:disabled="disabled"
|
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { useAttrs } from "vue";
|
|
3
|
-
const attrs = useAttrs();
|
|
4
2
|
const modelValue = defineModel({ type: String, ...{ default: "" } });
|
|
5
|
-
defineProps({
|
|
6
|
-
layout: { type: String, required: false, default: "vertical" }
|
|
3
|
+
const props = defineProps({
|
|
4
|
+
layout: { type: String, required: false, default: "vertical" },
|
|
5
|
+
appearance: { type: String, required: false },
|
|
6
|
+
error: { type: [String, null], required: false },
|
|
7
|
+
group: { type: Boolean, required: false },
|
|
8
|
+
id: { type: String, required: false },
|
|
9
|
+
label: { type: String, required: false },
|
|
10
|
+
size: { type: String, required: false }
|
|
7
11
|
});
|
|
8
12
|
</script>
|
|
9
13
|
|
|
10
14
|
<template>
|
|
11
15
|
<orio-control-element
|
|
12
16
|
v-slot="{ id }"
|
|
13
|
-
v-bind="
|
|
17
|
+
v-bind="props"
|
|
14
18
|
:layout="layout === 'inner' ? 'vertical' : layout"
|
|
15
19
|
:class="{ inner: layout === 'inner' }"
|
|
16
20
|
>
|
|
17
|
-
<textarea
|
|
21
|
+
<textarea :id v-model="modelValue" rows="4" v-bind="$attrs" />
|
|
18
22
|
</orio-control-element>
|
|
19
23
|
</template>
|
|
20
24
|
|
|
@@ -67,7 +71,6 @@ textarea {
|
|
|
67
71
|
.inner :deep(.control-label) {
|
|
68
72
|
position: absolute;
|
|
69
73
|
z-index: 1;
|
|
70
|
-
pointer-events: none;
|
|
71
74
|
left: var(--control-px);
|
|
72
75
|
top: var(--control-label-block-start);
|
|
73
76
|
color: var(--color-muted);
|