orio-ui 1.18.1 → 1.20.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/README.md +5 -5
- package/dist/module.json +1 -1
- package/dist/runtime/components/AnimatedContainer.d.vue.ts +1 -1
- package/dist/runtime/components/AnimatedContainer.vue.d.ts +1 -1
- package/dist/runtime/components/Button.vue +2 -1
- package/dist/runtime/components/CheckBox.vue +6 -3
- package/dist/runtime/components/CheckboxGroup.vue +2 -1
- package/dist/runtime/components/ControlElement.d.vue.ts +5 -0
- package/dist/runtime/components/ControlElement.vue +19 -51
- package/dist/runtime/components/ControlElement.vue.d.ts +5 -0
- package/dist/runtime/components/Form.d.vue.ts +33 -0
- package/dist/runtime/components/Form.vue +102 -0
- package/dist/runtime/components/Form.vue.d.ts +33 -0
- package/dist/runtime/components/Input.vue +2 -1
- package/dist/runtime/components/ListItem.d.vue.ts +29 -0
- package/dist/runtime/components/ListItem.vue +72 -0
- package/dist/runtime/components/ListItem.vue.d.ts +29 -0
- package/dist/runtime/components/NavButton.vue +2 -1
- package/dist/runtime/components/NumberInput/Horizontal.vue +2 -1
- package/dist/runtime/components/NumberInput/Vertical.vue +2 -1
- package/dist/runtime/components/NumberInput/index.vue +2 -1
- package/dist/runtime/components/RadioButton.vue +2 -1
- package/dist/runtime/components/Selector.vue +14 -19
- package/dist/runtime/components/SwitchButton.vue +2 -1
- package/dist/runtime/components/Tag.d.vue.ts +3 -2
- package/dist/runtime/components/Tag.vue +1 -0
- package/dist/runtime/components/Tag.vue.d.ts +3 -2
- package/dist/runtime/components/TaggableSelector.d.vue.ts +16 -0
- package/dist/runtime/components/TaggableSelector.vue +35 -0
- package/dist/runtime/components/TaggableSelector.vue.d.ts +16 -0
- package/dist/runtime/components/Textarea.vue +2 -1
- package/dist/runtime/components/gallery/Carousel.vue +9 -9
- package/dist/runtime/composables/useControlSize.d.ts +9 -0
- package/dist/runtime/composables/useControlSize.js +67 -0
- package/dist/runtime/composables/useSound.d.ts +3 -1
- package/dist/runtime/composables/useSound.js +49 -9
- package/dist/runtime/index.d.ts +4 -1
- package/dist/runtime/index.js +4 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ A delightful, lightweight component library for Nuxt 3+ applications. Built with
|
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
|
-
✨ **
|
|
11
|
+
✨ **34 Components** - Beautiful, accessible components ready to use
|
|
12
12
|
🎨 **Themeable** - 5 built-in accent themes with light/dark mode support
|
|
13
13
|
🚀 **Auto-imported** - Works seamlessly with Nuxt's auto-import system
|
|
14
14
|
📦 **Tree-shakeable** - Only bundle what you use
|
|
@@ -66,7 +66,7 @@ function handleClick() {
|
|
|
66
66
|
|
|
67
67
|
## What's Included
|
|
68
68
|
|
|
69
|
-
### Components (
|
|
69
|
+
### Components (34)
|
|
70
70
|
|
|
71
71
|
#### Form Controls
|
|
72
72
|
|
|
@@ -112,7 +112,7 @@ function handleClick() {
|
|
|
112
112
|
|
|
113
113
|
- **Upload** - File upload component
|
|
114
114
|
|
|
115
|
-
### Composables (
|
|
115
|
+
### Composables (11)
|
|
116
116
|
|
|
117
117
|
- **useTheme** - Theme and color mode management
|
|
118
118
|
- **useModal** - Modal state with animation origin tracking
|
|
@@ -187,8 +187,8 @@ npm run docs:dev
|
|
|
187
187
|
orio-ui/
|
|
188
188
|
├── src/
|
|
189
189
|
│ ├── runtime/
|
|
190
|
-
│ │ ├── components/ #
|
|
191
|
-
│ │ ├── composables/ #
|
|
190
|
+
│ │ ├── components/ # 34 Vue components
|
|
191
|
+
│ │ ├── composables/ # 11 composables
|
|
192
192
|
│ │ ├── assets/css/ # Theme CSS files
|
|
193
193
|
│ │ └── utils/ # Icon registry
|
|
194
194
|
│ └── module.ts # Nuxt Module definition
|
package/dist/module.json
CHANGED
|
@@ -11,7 +11,8 @@ const props = defineProps({
|
|
|
11
11
|
id: { type: String, required: false },
|
|
12
12
|
label: { type: String, required: false },
|
|
13
13
|
layout: { type: String, required: false },
|
|
14
|
-
size: { type: String, required: false }
|
|
14
|
+
size: { type: String, required: false },
|
|
15
|
+
fill: { type: Boolean, required: false }
|
|
15
16
|
});
|
|
16
17
|
const { loading, disabled } = toRefs(props);
|
|
17
18
|
const slots = useSlots();
|
|
@@ -9,12 +9,13 @@ const props = defineProps({
|
|
|
9
9
|
id: { type: String, required: false },
|
|
10
10
|
label: { type: String, required: false },
|
|
11
11
|
layout: { type: String, required: false },
|
|
12
|
-
size: { type: String, required: false }
|
|
12
|
+
size: { type: String, required: false },
|
|
13
|
+
fill: { type: Boolean, required: false }
|
|
13
14
|
});
|
|
14
15
|
</script>
|
|
15
16
|
|
|
16
17
|
<template>
|
|
17
|
-
<orio-control-element v-bind="props" class="checkbox">
|
|
18
|
+
<orio-control-element v-bind="props" class="checkbox" fill>
|
|
18
19
|
<label class="checkbox-label">
|
|
19
20
|
<input
|
|
20
21
|
v-model="modelValue"
|
|
@@ -47,6 +48,9 @@ const props = defineProps({
|
|
|
47
48
|
.checkbox {
|
|
48
49
|
--box-size: var(--control-icon-size, 1rem);
|
|
49
50
|
}
|
|
51
|
+
.checkbox .checkbox-label {
|
|
52
|
+
vertical-align: baseline;
|
|
53
|
+
}
|
|
50
54
|
.checkbox-label {
|
|
51
55
|
position: relative;
|
|
52
56
|
user-select: none;
|
|
@@ -60,7 +64,6 @@ const props = defineProps({
|
|
|
60
64
|
position: absolute;
|
|
61
65
|
inset: 0;
|
|
62
66
|
width: var(--box-size);
|
|
63
|
-
height: 1rem;
|
|
64
67
|
margin: 0;
|
|
65
68
|
opacity: 0;
|
|
66
69
|
}
|
|
@@ -5,7 +5,8 @@ const props = defineProps({
|
|
|
5
5
|
error: { type: [String, null], required: false, default: null },
|
|
6
6
|
label: { type: String, required: false },
|
|
7
7
|
layout: { type: String, required: false, default: "vertical" },
|
|
8
|
-
size: { type: String, required: false, default: "md" }
|
|
8
|
+
size: { type: String, required: false, default: "md" },
|
|
9
|
+
fill: { type: Boolean, required: false }
|
|
9
10
|
});
|
|
10
11
|
const modelValue = defineModel({ type: Array, ...{ default: () => [] } });
|
|
11
12
|
function isChecked(value) {
|
|
@@ -31,6 +31,10 @@ export interface ControlProps {
|
|
|
31
31
|
* Size of the control and its inner elements
|
|
32
32
|
*/
|
|
33
33
|
size?: ControlSize;
|
|
34
|
+
/**
|
|
35
|
+
* Whether element should fill the container
|
|
36
|
+
*/
|
|
37
|
+
fill?: boolean;
|
|
34
38
|
}
|
|
35
39
|
declare var __VLS_7: {
|
|
36
40
|
id: string;
|
|
@@ -45,6 +49,7 @@ declare const __VLS_base: import("vue").DefineComponent<ControlProps, {}, {}, {}
|
|
|
45
49
|
id: string;
|
|
46
50
|
layout: ControlLayout;
|
|
47
51
|
size: ControlSize;
|
|
52
|
+
fill: boolean;
|
|
48
53
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
49
54
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
50
55
|
declare const _default: typeof __VLS_export;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { useId } from "vue";
|
|
2
|
+
import { computed, toRef, useId } from "vue";
|
|
3
|
+
import { provideControlSize, sizeTokens } from "../composables/useControlSize";
|
|
3
4
|
defineOptions({ inheritAttrs: false });
|
|
4
5
|
const props = defineProps({
|
|
5
6
|
appearance: { type: String, required: false, default: "normal" },
|
|
@@ -8,14 +9,23 @@ const props = defineProps({
|
|
|
8
9
|
id: { type: String, required: false, default: () => useId() },
|
|
9
10
|
label: { type: String, required: false },
|
|
10
11
|
layout: { type: String, required: false, default: "vertical" },
|
|
11
|
-
size: { type: String, required: false, default: "md" }
|
|
12
|
+
size: { type: String, required: false, default: "md" },
|
|
13
|
+
fill: { type: Boolean, required: false, default: false }
|
|
12
14
|
});
|
|
15
|
+
provideControlSize(toRef(props, "size"));
|
|
16
|
+
const sizeStyle = computed(() => sizeTokens[props.size]);
|
|
13
17
|
</script>
|
|
14
18
|
|
|
15
19
|
<template>
|
|
16
20
|
<div
|
|
17
21
|
class="control"
|
|
18
|
-
:class="[
|
|
22
|
+
:class="[
|
|
23
|
+
appearance,
|
|
24
|
+
layout,
|
|
25
|
+
`size-${size}`,
|
|
26
|
+
{ 'has-error': error, group, fill }
|
|
27
|
+
]"
|
|
28
|
+
:style="sizeStyle"
|
|
19
29
|
v-bind="{
|
|
20
30
|
...$attrs,
|
|
21
31
|
...group ? { role: 'group', ...label ? { 'aria-labelledby': id } : {} } : {}
|
|
@@ -39,54 +49,6 @@ const props = defineProps({
|
|
|
39
49
|
</template>
|
|
40
50
|
|
|
41
51
|
<style scoped>
|
|
42
|
-
.control {
|
|
43
|
-
--control-font-size: var(--font-md);
|
|
44
|
-
--control-label-font-size: var(--font-sm);
|
|
45
|
-
--control-py: 0.5rem;
|
|
46
|
-
--control-px: 0.75rem;
|
|
47
|
-
--control-gap: 0.5rem;
|
|
48
|
-
--control-radius: var(--border-radius-md);
|
|
49
|
-
--control-icon-size: 1rem;
|
|
50
|
-
--control-inner-block-start: 1.25rem;
|
|
51
|
-
--control-inner-block-end: 0.2rem;
|
|
52
|
-
--control-label-block-start: 0.25rem;
|
|
53
|
-
}
|
|
54
|
-
.control.size-sm {
|
|
55
|
-
--control-font-size: var(--font-sm);
|
|
56
|
-
--control-label-font-size: var(--font-xs);
|
|
57
|
-
--control-py: 0.25rem;
|
|
58
|
-
--control-px: 0.5rem;
|
|
59
|
-
--control-gap: 0.25rem;
|
|
60
|
-
--control-radius: var(--border-radius-sm);
|
|
61
|
-
--control-icon-size: 0.75rem;
|
|
62
|
-
--control-inner-block-start: 1rem;
|
|
63
|
-
--control-inner-block-end: 0.1rem;
|
|
64
|
-
--control-label-block-start: 0.2rem;
|
|
65
|
-
}
|
|
66
|
-
.control.size-lg {
|
|
67
|
-
--control-font-size: var(--font-lg);
|
|
68
|
-
--control-label-font-size: var(--font-md);
|
|
69
|
-
--control-py: 0.625rem;
|
|
70
|
-
--control-px: 1rem;
|
|
71
|
-
--control-gap: 0.5rem;
|
|
72
|
-
--control-radius: var(--border-radius-md);
|
|
73
|
-
--control-icon-size: 1.25rem;
|
|
74
|
-
--control-inner-block-start: 1.1rem;
|
|
75
|
-
--control-inner-block-end: 0.2rem;
|
|
76
|
-
--control-label-block-start: 0.25rem;
|
|
77
|
-
}
|
|
78
|
-
.control.size-xl {
|
|
79
|
-
--control-font-size: var(--font-xl);
|
|
80
|
-
--control-label-font-size: var(--font-lg);
|
|
81
|
-
--control-py: 0.75rem;
|
|
82
|
-
--control-px: 1.25rem;
|
|
83
|
-
--control-gap: 0.75rem;
|
|
84
|
-
--control-radius: var(--border-radius-lg);
|
|
85
|
-
--control-icon-size: 1.5rem;
|
|
86
|
-
--control-inner-block-start: 1.5rem;
|
|
87
|
-
--control-inner-block-end: 0;
|
|
88
|
-
--control-label-block-start: 0.25rem;
|
|
89
|
-
}
|
|
90
52
|
.control {
|
|
91
53
|
margin: 0.5rem;
|
|
92
54
|
display: flex;
|
|
@@ -104,6 +66,12 @@ const props = defineProps({
|
|
|
104
66
|
color: var(--color-danger);
|
|
105
67
|
font-size: var(--control-label-font-size);
|
|
106
68
|
}
|
|
69
|
+
.control.fill .slot-wrapper {
|
|
70
|
+
display: flex;
|
|
71
|
+
}
|
|
72
|
+
.control.fill .slot-wrapper > * {
|
|
73
|
+
flex: 1;
|
|
74
|
+
}
|
|
107
75
|
.control .slot-wrapper :deep(*) {
|
|
108
76
|
font-size: var(--control-font-size);
|
|
109
77
|
}
|
|
@@ -31,6 +31,10 @@ export interface ControlProps {
|
|
|
31
31
|
* Size of the control and its inner elements
|
|
32
32
|
*/
|
|
33
33
|
size?: ControlSize;
|
|
34
|
+
/**
|
|
35
|
+
* Whether element should fill the container
|
|
36
|
+
*/
|
|
37
|
+
fill?: boolean;
|
|
34
38
|
}
|
|
35
39
|
declare var __VLS_7: {
|
|
36
40
|
id: string;
|
|
@@ -45,6 +49,7 @@ declare const __VLS_base: import("vue").DefineComponent<ControlProps, {}, {}, {}
|
|
|
45
49
|
id: string;
|
|
46
50
|
layout: ControlLayout;
|
|
47
51
|
size: ControlSize;
|
|
52
|
+
fill: boolean;
|
|
48
53
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
49
54
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
50
55
|
declare const _default: typeof __VLS_export;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface FormProps {
|
|
2
|
+
/**
|
|
3
|
+
* Disables all form controls and the submit button
|
|
4
|
+
*/
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Shows a loading state (e.g. during async submission)
|
|
8
|
+
*/
|
|
9
|
+
loading?: boolean;
|
|
10
|
+
}
|
|
11
|
+
declare const __VLS_export: <T extends object>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
|
|
12
|
+
props: import("vue").PublicProps & __VLS_PrettifyLocal<(FormProps & {
|
|
13
|
+
modelValue?: T;
|
|
14
|
+
}) & {
|
|
15
|
+
"onUpdate:modelValue"?: ((value: T | undefined) => any) | undefined;
|
|
16
|
+
onSubmit?: (() => any) | undefined;
|
|
17
|
+
}> & (typeof globalThis extends {
|
|
18
|
+
__VLS_PROPS_FALLBACK: infer P;
|
|
19
|
+
} ? P : {});
|
|
20
|
+
expose: (exposed: {}) => void;
|
|
21
|
+
attrs: any;
|
|
22
|
+
slots: {};
|
|
23
|
+
emit: ((evt: "submit") => void) & ((event: "update:modelValue", value: T | undefined) => void);
|
|
24
|
+
}>) => import("vue").VNode & {
|
|
25
|
+
__ctx?: Awaited<typeof __VLS_setup>;
|
|
26
|
+
};
|
|
27
|
+
declare const _default: typeof __VLS_export;
|
|
28
|
+
export default _default;
|
|
29
|
+
type __VLS_PrettifyLocal<T> = (T extends any ? {
|
|
30
|
+
[K in keyof T]: T[K];
|
|
31
|
+
} : {
|
|
32
|
+
[K in keyof T as K]: T[K];
|
|
33
|
+
}) & {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { useSlots, cloneVNode } from "vue";
|
|
3
|
+
const { disabled = false, loading = false } = defineProps({
|
|
4
|
+
disabled: { type: Boolean, required: false },
|
|
5
|
+
loading: { type: Boolean, required: false }
|
|
6
|
+
});
|
|
7
|
+
const modelValue = defineModel({ type: null });
|
|
8
|
+
const emit = defineEmits(["submit"]);
|
|
9
|
+
const slots = useSlots();
|
|
10
|
+
function getByPath(obj, path) {
|
|
11
|
+
return path.split(".").reduce((current, key) => current?.[key], obj);
|
|
12
|
+
}
|
|
13
|
+
function setByPath(obj, path, value) {
|
|
14
|
+
const keys = path.split(".");
|
|
15
|
+
const lastKey = keys.pop();
|
|
16
|
+
const parent = keys.reduce((current, key) => current?.[key], obj);
|
|
17
|
+
if (parent) parent[lastKey] = value;
|
|
18
|
+
}
|
|
19
|
+
function wrapSlotFn(fn) {
|
|
20
|
+
return (...args) => bindFields(fn(...args));
|
|
21
|
+
}
|
|
22
|
+
function processChildren(children) {
|
|
23
|
+
if (Array.isArray(children)) {
|
|
24
|
+
return bindFields(children);
|
|
25
|
+
}
|
|
26
|
+
if (typeof children === "function") {
|
|
27
|
+
return wrapSlotFn(children);
|
|
28
|
+
}
|
|
29
|
+
if (children && typeof children === "object") {
|
|
30
|
+
const slotObj = children;
|
|
31
|
+
return Object.fromEntries(
|
|
32
|
+
Object.entries(slotObj).map(([key, fn]) => [key, wrapSlotFn(fn)])
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
return children;
|
|
36
|
+
}
|
|
37
|
+
function bindFields(vnodes) {
|
|
38
|
+
return vnodes.map((vnode) => {
|
|
39
|
+
const name = vnode.props?.name;
|
|
40
|
+
if (name && modelValue.value && getByPath(modelValue.value, name) !== void 0) {
|
|
41
|
+
return cloneVNode(vnode, {
|
|
42
|
+
modelValue: getByPath(modelValue.value, name),
|
|
43
|
+
"onUpdate:modelValue": (newValue) => {
|
|
44
|
+
setByPath(modelValue.value, name, newValue);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
if (vnode.children) {
|
|
49
|
+
const clone = cloneVNode(vnode);
|
|
50
|
+
clone.children = processChildren(vnode.children);
|
|
51
|
+
return clone;
|
|
52
|
+
}
|
|
53
|
+
return vnode;
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function renderSlot() {
|
|
57
|
+
const children = slots.default?.();
|
|
58
|
+
if (!children || !modelValue.value) return children;
|
|
59
|
+
return bindFields(children);
|
|
60
|
+
}
|
|
61
|
+
const slotRenderer = () => renderSlot();
|
|
62
|
+
function onSubmit(e) {
|
|
63
|
+
e.preventDefault();
|
|
64
|
+
if (disabled || loading) return;
|
|
65
|
+
emit("submit");
|
|
66
|
+
}
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<template>
|
|
70
|
+
<form
|
|
71
|
+
:class="{ disabled, loading }"
|
|
72
|
+
:aria-disabled="disabled || void 0"
|
|
73
|
+
:aria-busy="loading || void 0"
|
|
74
|
+
novalidate
|
|
75
|
+
@submit="onSubmit"
|
|
76
|
+
>
|
|
77
|
+
<fieldset v-if="disabled" disabled>
|
|
78
|
+
<component :is="slotRenderer" />
|
|
79
|
+
</fieldset>
|
|
80
|
+
<component :is="slotRenderer" v-else />
|
|
81
|
+
</form>
|
|
82
|
+
</template>
|
|
83
|
+
|
|
84
|
+
<style scoped>
|
|
85
|
+
form {
|
|
86
|
+
display: flex;
|
|
87
|
+
flex-direction: column;
|
|
88
|
+
width: 100%;
|
|
89
|
+
}
|
|
90
|
+
form.disabled {
|
|
91
|
+
opacity: 0.6;
|
|
92
|
+
}
|
|
93
|
+
form.loading {
|
|
94
|
+
pointer-events: none;
|
|
95
|
+
}
|
|
96
|
+
form fieldset {
|
|
97
|
+
display: contents;
|
|
98
|
+
border: none;
|
|
99
|
+
padding: 0;
|
|
100
|
+
margin: 0;
|
|
101
|
+
}
|
|
102
|
+
</style>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface FormProps {
|
|
2
|
+
/**
|
|
3
|
+
* Disables all form controls and the submit button
|
|
4
|
+
*/
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Shows a loading state (e.g. during async submission)
|
|
8
|
+
*/
|
|
9
|
+
loading?: boolean;
|
|
10
|
+
}
|
|
11
|
+
declare const __VLS_export: <T extends object>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
|
|
12
|
+
props: import("vue").PublicProps & __VLS_PrettifyLocal<(FormProps & {
|
|
13
|
+
modelValue?: T;
|
|
14
|
+
}) & {
|
|
15
|
+
"onUpdate:modelValue"?: ((value: T | undefined) => any) | undefined;
|
|
16
|
+
onSubmit?: (() => any) | undefined;
|
|
17
|
+
}> & (typeof globalThis extends {
|
|
18
|
+
__VLS_PROPS_FALLBACK: infer P;
|
|
19
|
+
} ? P : {});
|
|
20
|
+
expose: (exposed: {}) => void;
|
|
21
|
+
attrs: any;
|
|
22
|
+
slots: {};
|
|
23
|
+
emit: ((evt: "submit") => void) & ((event: "update:modelValue", value: T | undefined) => void);
|
|
24
|
+
}>) => import("vue").VNode & {
|
|
25
|
+
__ctx?: Awaited<typeof __VLS_setup>;
|
|
26
|
+
};
|
|
27
|
+
declare const _default: typeof __VLS_export;
|
|
28
|
+
export default _default;
|
|
29
|
+
type __VLS_PrettifyLocal<T> = (T extends any ? {
|
|
30
|
+
[K in keyof T]: T[K];
|
|
31
|
+
} : {
|
|
32
|
+
[K in keyof T as K]: T[K];
|
|
33
|
+
}) & {};
|
|
@@ -6,7 +6,8 @@ const props = defineProps({
|
|
|
6
6
|
group: { type: Boolean, required: false },
|
|
7
7
|
id: { type: String, required: false },
|
|
8
8
|
label: { type: String, required: false },
|
|
9
|
-
size: { type: String, required: false }
|
|
9
|
+
size: { type: String, required: false },
|
|
10
|
+
fill: { type: Boolean, required: false }
|
|
10
11
|
});
|
|
11
12
|
const modelValue = defineModel({ type: String, ...{ default: "" } });
|
|
12
13
|
</script>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface ListItemProps {
|
|
2
|
+
selectable?: boolean;
|
|
3
|
+
}
|
|
4
|
+
type __VLS_Props = ListItemProps;
|
|
5
|
+
type __VLS_ModelProps = {
|
|
6
|
+
"selected"?: boolean;
|
|
7
|
+
};
|
|
8
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
9
|
+
declare var __VLS_1: {}, __VLS_8: {}, __VLS_10: {};
|
|
10
|
+
type __VLS_Slots = {} & {
|
|
11
|
+
start?: (props: typeof __VLS_1) => any;
|
|
12
|
+
} & {
|
|
13
|
+
default?: (props: typeof __VLS_8) => any;
|
|
14
|
+
} & {
|
|
15
|
+
end?: (props: typeof __VLS_10) => any;
|
|
16
|
+
};
|
|
17
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
18
|
+
"update:selected": (value: boolean | undefined) => any;
|
|
19
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
20
|
+
"onUpdate:selected"?: ((value: boolean | undefined) => any) | undefined;
|
|
21
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
22
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
23
|
+
declare const _default: typeof __VLS_export;
|
|
24
|
+
export default _default;
|
|
25
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
26
|
+
new (): {
|
|
27
|
+
$slots: S;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { useSlots } from "vue";
|
|
3
|
+
const { selectable = false } = defineProps({
|
|
4
|
+
selectable: { type: Boolean, required: false }
|
|
5
|
+
});
|
|
6
|
+
const slots = useSlots();
|
|
7
|
+
const selected = defineModel("selected", { type: Boolean });
|
|
8
|
+
function toggle() {
|
|
9
|
+
if (!selectable) return;
|
|
10
|
+
selected.value = !selected.value;
|
|
11
|
+
}
|
|
12
|
+
function onKeydown(event) {
|
|
13
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
14
|
+
event.preventDefault();
|
|
15
|
+
toggle();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<li
|
|
22
|
+
class="list-item"
|
|
23
|
+
:class="{ selectable, selected }"
|
|
24
|
+
:tabindex="selectable ? 0 : void 0"
|
|
25
|
+
:role="selectable ? 'checkbox' : void 0"
|
|
26
|
+
:aria-checked="selectable ? selected : void 0"
|
|
27
|
+
@click="toggle"
|
|
28
|
+
@keydown="onKeydown"
|
|
29
|
+
>
|
|
30
|
+
<div v-if="!!slots.start || selectable" class="boundary">
|
|
31
|
+
<slot name="start">
|
|
32
|
+
<orio-check-box :model-value="selected" />
|
|
33
|
+
</slot>
|
|
34
|
+
</div>
|
|
35
|
+
<div class="content">
|
|
36
|
+
<slot />
|
|
37
|
+
</div>
|
|
38
|
+
<div v-if="!!slots.end" class="boundary">
|
|
39
|
+
<slot name="end" />
|
|
40
|
+
</div>
|
|
41
|
+
</li>
|
|
42
|
+
</template>
|
|
43
|
+
|
|
44
|
+
<style scoped>
|
|
45
|
+
.list-item {
|
|
46
|
+
width: 100%;
|
|
47
|
+
display: flex;
|
|
48
|
+
align-items: center;
|
|
49
|
+
gap: 0.5rem;
|
|
50
|
+
padding: 0.5rem;
|
|
51
|
+
user-select: none;
|
|
52
|
+
}
|
|
53
|
+
.list-item.selectable {
|
|
54
|
+
cursor: pointer;
|
|
55
|
+
}
|
|
56
|
+
.list-item {
|
|
57
|
+
transition: background-color 0.15s ease, color 0.15s ease;
|
|
58
|
+
}
|
|
59
|
+
.list-item.selected {
|
|
60
|
+
background-color: var(--color-accent);
|
|
61
|
+
color: var(--color-accent-soft-darker);
|
|
62
|
+
}
|
|
63
|
+
.list-item:hover:not(.selected) {
|
|
64
|
+
background-color: var(--color-surface);
|
|
65
|
+
}
|
|
66
|
+
.list-item .content {
|
|
67
|
+
flex-grow: 1;
|
|
68
|
+
}
|
|
69
|
+
.list-item .boundary {
|
|
70
|
+
display: flex;
|
|
71
|
+
}
|
|
72
|
+
</style>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface ListItemProps {
|
|
2
|
+
selectable?: boolean;
|
|
3
|
+
}
|
|
4
|
+
type __VLS_Props = ListItemProps;
|
|
5
|
+
type __VLS_ModelProps = {
|
|
6
|
+
"selected"?: boolean;
|
|
7
|
+
};
|
|
8
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
9
|
+
declare var __VLS_1: {}, __VLS_8: {}, __VLS_10: {};
|
|
10
|
+
type __VLS_Slots = {} & {
|
|
11
|
+
start?: (props: typeof __VLS_1) => any;
|
|
12
|
+
} & {
|
|
13
|
+
default?: (props: typeof __VLS_8) => any;
|
|
14
|
+
} & {
|
|
15
|
+
end?: (props: typeof __VLS_10) => any;
|
|
16
|
+
};
|
|
17
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
18
|
+
"update:selected": (value: boolean | undefined) => any;
|
|
19
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
20
|
+
"onUpdate:selected"?: ((value: boolean | undefined) => any) | undefined;
|
|
21
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
22
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
23
|
+
declare const _default: typeof __VLS_export;
|
|
24
|
+
export default _default;
|
|
25
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
26
|
+
new (): {
|
|
27
|
+
$slots: S;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
@@ -10,7 +10,8 @@ const props = defineProps({
|
|
|
10
10
|
id: { type: String, required: false },
|
|
11
11
|
label: { type: String, required: false },
|
|
12
12
|
layout: { type: String, required: false },
|
|
13
|
-
size: { type: String, required: false }
|
|
13
|
+
size: { type: String, required: false },
|
|
14
|
+
fill: { type: Boolean, required: false }
|
|
14
15
|
});
|
|
15
16
|
const { disabled, active } = toRefs(props);
|
|
16
17
|
const slots = useSlots();
|
|
@@ -12,7 +12,8 @@ defineProps({
|
|
|
12
12
|
group: { type: Boolean, required: false },
|
|
13
13
|
id: { type: String, required: false },
|
|
14
14
|
label: { type: String, required: false },
|
|
15
|
-
size: { type: String, required: false }
|
|
15
|
+
size: { type: String, required: false },
|
|
16
|
+
fill: { type: Boolean, required: false }
|
|
16
17
|
});
|
|
17
18
|
const modelValue = defineModel({ type: Number, ...{ default: 0 } });
|
|
18
19
|
const { pressAndHold, stop } = usePressAndHold();
|
|
@@ -12,7 +12,8 @@ defineProps({
|
|
|
12
12
|
group: { type: Boolean, required: false },
|
|
13
13
|
id: { type: String, required: false },
|
|
14
14
|
label: { type: String, required: false },
|
|
15
|
-
size: { type: String, required: false }
|
|
15
|
+
size: { type: String, required: false },
|
|
16
|
+
fill: { type: Boolean, required: false }
|
|
16
17
|
});
|
|
17
18
|
const modelValue = defineModel({ type: Number, ...{ default: 0 } });
|
|
18
19
|
const { pressAndHold, stop } = usePressAndHold();
|
|
@@ -12,7 +12,8 @@ const props = defineProps({
|
|
|
12
12
|
group: { type: Boolean, required: false },
|
|
13
13
|
id: { type: String, required: false },
|
|
14
14
|
label: { type: String, required: false },
|
|
15
|
-
size: { type: String, required: false }
|
|
15
|
+
size: { type: String, required: false },
|
|
16
|
+
fill: { type: Boolean, required: false }
|
|
16
17
|
});
|
|
17
18
|
const { min, max, step, decimalPlaces } = toRefs(props);
|
|
18
19
|
const modelValue = defineModel({ type: Number, ...{ default: 0 } });
|
|
@@ -11,7 +11,8 @@ const props = defineProps({
|
|
|
11
11
|
id: { type: String, required: false },
|
|
12
12
|
label: { type: String, required: false },
|
|
13
13
|
layout: { type: String, required: false },
|
|
14
|
-
size: { type: String, required: false }
|
|
14
|
+
size: { type: String, required: false },
|
|
15
|
+
fill: { type: Boolean, required: false }
|
|
15
16
|
});
|
|
16
17
|
</script>
|
|
17
18
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { computed, ref, toRefs } from "vue";
|
|
2
|
+
import { computed, ref, toRef, toRefs } from "vue";
|
|
3
|
+
import { useControlTokens } from "../composables/useControlSize";
|
|
3
4
|
import { useListKeyboard } from "../composables/useListKeyboard";
|
|
4
5
|
const props = defineProps({
|
|
5
6
|
options: { type: Array, required: true },
|
|
@@ -13,7 +14,8 @@ const props = defineProps({
|
|
|
13
14
|
id: { type: String, required: false },
|
|
14
15
|
label: { type: String, required: false },
|
|
15
16
|
layout: { type: String, required: false },
|
|
16
|
-
size: { type: String, required: false }
|
|
17
|
+
size: { type: String, required: false },
|
|
18
|
+
fill: { type: Boolean, required: false }
|
|
17
19
|
});
|
|
18
20
|
const { field, optionName, placeholder } = toRefs(props);
|
|
19
21
|
const modelValue = defineModel({ type: null, ...{
|
|
@@ -67,6 +69,7 @@ function getOptionKey(option) {
|
|
|
67
69
|
if (typeof option === "string") return option;
|
|
68
70
|
return String(option[key.value]);
|
|
69
71
|
}
|
|
72
|
+
const { tokens: controlTokens } = useControlTokens(toRef(props, "size"));
|
|
70
73
|
const controlProps = computed(() => {
|
|
71
74
|
const {
|
|
72
75
|
options: _options,
|
|
@@ -142,22 +145,21 @@ const {
|
|
|
142
145
|
</template>
|
|
143
146
|
|
|
144
147
|
<template #content="{ toggle }">
|
|
145
|
-
<div class="selector-content">
|
|
148
|
+
<div class="selector-content" :style="controlTokens">
|
|
146
149
|
<ul
|
|
147
150
|
v-if="options.length"
|
|
148
151
|
ref="listRef"
|
|
149
152
|
role="listbox"
|
|
150
153
|
:aria-multiselectable="multiple || void 0"
|
|
151
154
|
>
|
|
152
|
-
<
|
|
155
|
+
<orio-list-item
|
|
153
156
|
v-for="(option, index) in options"
|
|
154
157
|
:key="getOptionKey(option)"
|
|
158
|
+
:selectable="multiple"
|
|
159
|
+
:selected="isOptionSelected(option)"
|
|
155
160
|
role="option"
|
|
156
161
|
:aria-selected="isOptionSelected(option)"
|
|
157
|
-
:class="{
|
|
158
|
-
selected: isOptionSelected(option),
|
|
159
|
-
highlighted: index === highlightedIndex
|
|
160
|
-
}"
|
|
162
|
+
:class="{ highlighted: index === highlightedIndex }"
|
|
161
163
|
@click="toggleOption(option, toggle)"
|
|
162
164
|
@mouseenter="highlightedIndex = index"
|
|
163
165
|
>
|
|
@@ -170,7 +172,7 @@ const {
|
|
|
170
172
|
>
|
|
171
173
|
{{ getOptionLabel(option) }}
|
|
172
174
|
</slot>
|
|
173
|
-
</
|
|
175
|
+
</orio-list-item>
|
|
174
176
|
</ul>
|
|
175
177
|
<slot v-else name="no-options">
|
|
176
178
|
<orio-empty-state title="No options found" size="small" />
|
|
@@ -230,19 +232,12 @@ const {
|
|
|
230
232
|
padding: 0;
|
|
231
233
|
margin: 0;
|
|
232
234
|
}
|
|
233
|
-
.selector-content ul
|
|
235
|
+
.selector-content ul :deep(.list-item) {
|
|
234
236
|
padding: var(--control-py) var(--control-px);
|
|
235
237
|
cursor: pointer;
|
|
236
|
-
transition: background-color 0.15s ease, color 0.15s ease;
|
|
237
|
-
color: var(--color-text);
|
|
238
|
-
}
|
|
239
|
-
.selector-content ul li:hover, .selector-content ul li.highlighted {
|
|
240
|
-
background-color: var(--color-surface); /* neutral lift */
|
|
241
238
|
}
|
|
242
|
-
.selector-content ul
|
|
243
|
-
background-color: var(--color-
|
|
244
|
-
color: var(--color-accent-soft-darker);
|
|
245
|
-
font-weight: 400;
|
|
239
|
+
.selector-content ul :deep(.list-item).highlighted:not(.selected) {
|
|
240
|
+
background-color: var(--color-surface);
|
|
246
241
|
}
|
|
247
242
|
|
|
248
243
|
.trigger-content {
|
|
@@ -7,7 +7,8 @@ const props = defineProps({
|
|
|
7
7
|
id: { type: String, required: false },
|
|
8
8
|
label: { type: String, required: false },
|
|
9
9
|
layout: { type: String, required: false },
|
|
10
|
-
size: { type: String, required: false }
|
|
10
|
+
size: { type: String, required: false },
|
|
11
|
+
fill: { type: Boolean, required: false }
|
|
11
12
|
});
|
|
12
13
|
const modelValue = defineModel({ type: Boolean, ...{ required: false } });
|
|
13
14
|
function toggle() {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export type TagStyle = "neutral" | "accent";
|
|
2
|
-
interface
|
|
2
|
+
export interface TagProps {
|
|
3
3
|
text: string;
|
|
4
|
+
id?: string;
|
|
4
5
|
variant?: TagStyle;
|
|
5
6
|
}
|
|
6
|
-
declare const __VLS_export: import("vue").DefineComponent<
|
|
7
|
+
declare const __VLS_export: import("vue").DefineComponent<TagProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<TagProps> & Readonly<{}>, {
|
|
7
8
|
variant: TagStyle;
|
|
8
9
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
10
|
declare const _default: typeof __VLS_export;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export type TagStyle = "neutral" | "accent";
|
|
2
|
-
interface
|
|
2
|
+
export interface TagProps {
|
|
3
3
|
text: string;
|
|
4
|
+
id?: string;
|
|
4
5
|
variant?: TagStyle;
|
|
5
6
|
}
|
|
6
|
-
declare const __VLS_export: import("vue").DefineComponent<
|
|
7
|
+
declare const __VLS_export: import("vue").DefineComponent<TagProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<TagProps> & Readonly<{}>, {
|
|
7
8
|
variant: TagStyle;
|
|
8
9
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
10
|
declare const _default: typeof __VLS_export;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { SelectProps } from "./Selector.vue.js";
|
|
2
|
+
import type { TagProps } from "./Tag.vue.js";
|
|
3
|
+
type __VLS_Props = SelectProps;
|
|
4
|
+
type __VLS_ModelProps = {
|
|
5
|
+
modelValue?: TagProps[];
|
|
6
|
+
};
|
|
7
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
8
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
9
|
+
"update:modelValue": (value: TagProps[] | undefined) => any;
|
|
10
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
11
|
+
"onUpdate:modelValue"?: ((value: TagProps[] | undefined) => any) | undefined;
|
|
12
|
+
}>, {
|
|
13
|
+
optionName: string;
|
|
14
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
15
|
+
declare const _default: typeof __VLS_export;
|
|
16
|
+
export default _default;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
const props = defineProps({
|
|
3
|
+
options: { type: Array, required: true },
|
|
4
|
+
multiple: { type: Boolean, required: false },
|
|
5
|
+
field: { type: String, required: false },
|
|
6
|
+
optionName: { type: String, required: false, default: "text" },
|
|
7
|
+
placeholder: { type: String, 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 },
|
|
12
|
+
label: { type: String, required: false },
|
|
13
|
+
layout: { type: String, required: false },
|
|
14
|
+
size: { type: String, required: false },
|
|
15
|
+
fill: { type: Boolean, required: false }
|
|
16
|
+
});
|
|
17
|
+
const modelValue = defineModel({ type: Array });
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<orio-selector v-bind="props" v-model="modelValue" multiple>
|
|
22
|
+
<template #trigger-label>
|
|
23
|
+
<orio-tag
|
|
24
|
+
v-for="tag in modelValue"
|
|
25
|
+
:key="tag.id"
|
|
26
|
+
:text="tag.text"
|
|
27
|
+
:variant="tag.variant"
|
|
28
|
+
/>
|
|
29
|
+
</template>
|
|
30
|
+
</orio-selector>
|
|
31
|
+
</template>
|
|
32
|
+
|
|
33
|
+
<style scoped>
|
|
34
|
+
:deep(.trigger-content){display:flex;flex-wrap:wrap;gap:.5rem;text-align:left}
|
|
35
|
+
</style>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { SelectProps } from "./Selector.vue.js";
|
|
2
|
+
import type { TagProps } from "./Tag.vue.js";
|
|
3
|
+
type __VLS_Props = SelectProps;
|
|
4
|
+
type __VLS_ModelProps = {
|
|
5
|
+
modelValue?: TagProps[];
|
|
6
|
+
};
|
|
7
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
8
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
9
|
+
"update:modelValue": (value: TagProps[] | undefined) => any;
|
|
10
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
11
|
+
"onUpdate:modelValue"?: ((value: TagProps[] | undefined) => any) | undefined;
|
|
12
|
+
}>, {
|
|
13
|
+
optionName: string;
|
|
14
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
15
|
+
declare const _default: typeof __VLS_export;
|
|
16
|
+
export default _default;
|
|
@@ -7,7 +7,8 @@ const props = defineProps({
|
|
|
7
7
|
group: { type: Boolean, required: false },
|
|
8
8
|
id: { type: String, required: false },
|
|
9
9
|
label: { type: String, required: false },
|
|
10
|
-
size: { type: String, required: false }
|
|
10
|
+
size: { type: String, required: false },
|
|
11
|
+
fill: { type: Boolean, required: false }
|
|
11
12
|
});
|
|
12
13
|
</script>
|
|
13
14
|
|
|
@@ -25,23 +25,23 @@ const carousel = useTemplateRef("carousel");
|
|
|
25
25
|
const measureContainer = useTemplateRef("measureContainer");
|
|
26
26
|
const { width: carouselWidth } = useElementSize(carousel);
|
|
27
27
|
const { width: contentWidth, height: contentHeight } = useElementSize(measureContainer);
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
const measureWidth = computed(
|
|
29
|
+
() => isDynamicHeight.value ? `${rawSizes.value.width}px` : "max-content"
|
|
30
|
+
);
|
|
31
|
+
const measureHeight = computed(
|
|
32
|
+
() => isDynamicWidth.value ? `${rawSizes.value.height}px` : "max-content"
|
|
33
|
+
);
|
|
32
34
|
const calculatedSize = computed(() => {
|
|
33
35
|
const { width, height } = rawSizes.value;
|
|
34
36
|
if (isDynamicHeight.value) {
|
|
35
|
-
const dynamicHeight = contentAspectRatio.value ? width / contentAspectRatio.value : width;
|
|
36
37
|
return {
|
|
37
38
|
width: `${width}px`,
|
|
38
|
-
height: `${
|
|
39
|
+
height: contentHeight.value ? `${contentHeight.value}px` : `${width}px`
|
|
39
40
|
};
|
|
40
41
|
}
|
|
41
42
|
if (isDynamicWidth.value) {
|
|
42
|
-
const dynamicWidth = contentAspectRatio.value ? height * contentAspectRatio.value : height;
|
|
43
43
|
return {
|
|
44
|
-
width: `${
|
|
44
|
+
width: contentWidth.value ? `${contentWidth.value}px` : `${height}px`,
|
|
45
45
|
height: `${height}px`
|
|
46
46
|
};
|
|
47
47
|
}
|
|
@@ -157,5 +157,5 @@ onMounted(() => {
|
|
|
157
157
|
</template>
|
|
158
158
|
|
|
159
159
|
<style scoped>
|
|
160
|
-
.carousel-wrapper{display:block;
|
|
160
|
+
.carousel-wrapper{display:block;position:relative}.carousel-measure{height:v-bind(measureHeight);left:-9999px;pointer-events:none;position:fixed;visibility:hidden;width:v-bind(measureWidth)}.carousel-measure :deep(>*){display:block;height:100%;width:100%}.carousel{border:1px solid var(--color-border);border-radius:var(--border-radius-lg);height:v-bind("calculatedSize.height");max-height:v-bind(maxHeight);max-width:100%;overflow:hidden;transition:width .3s ease,height .3s ease;width:v-bind("calculatedSize.width")}.carousel-track{align-items:center;cursor:grab;display:flex;gap:.75rem;height:100%;position:relative;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:100%}.carousel-track:active{cursor:grabbing}.carousel-item{background:var(--color-surface);border-radius:var(--border-radius-sm);color:var(--color-text);height:100%;inset:0;opacity:0;overflow:hidden;padding:.5rem .75rem;pointer-events:none;position:absolute;transition:opacity .5s ease-in-out,transform .5s ease-in-out;white-space:nowrap;width:100%}.carousel-item.previous-image{transform:translateX(-100%)}.carousel-item.next-image{transform:translateX(100%)}.carousel-item.active-image{opacity:1;pointer-events:auto;transform:translateX(0)}.carousel-item :deep(>*){height:100%;-o-object-fit:v-bind(fit);object-fit:v-bind(fit);width:100%}.carousel-empty{color:var(--color-muted)}.switch-button{position:absolute}.switch-button :deep(button){background:transparent!important;border:none!important;color:transparent!important}.switch-button :deep(button:hover){color:transparent!important}.switch-button :deep(.orio-icon){color:#fff!important;fill:#fff!important;filter:drop-shadow(0 0 2px rgba(0,0,0,.8)) drop-shadow(0 0 4px rgba(0,0,0,.6))}@supports (mix-blend-mode:difference) and (not (-webkit-hyphens:none)){.switch-button :deep(.orio-icon){color:#000!important;fill:#000!important;filter:grayscale(1) contrast(9) invert(1) drop-shadow(0 0 1px black) drop-shadow(0 0 2px black);mix-blend-mode:difference}}.switch-button.previous-button{left:0}.switch-button.next-button{right:0}.carousel--minimal{background:none;border:none}.carousel--minimal .carousel-item{background:none}.carousel--minimal .switch-button{opacity:0;transition:opacity .2s ease}.carousel--minimal:hover .switch-button{opacity:1}
|
|
161
161
|
</style>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ComputedRef, type Ref } from "vue";
|
|
2
|
+
import type { ControlSize } from "../components/ControlElement.vue.js";
|
|
3
|
+
declare const sizeTokens: Record<ControlSize, Record<string, string>>;
|
|
4
|
+
export declare function provideControlSize(size: Ref<ControlSize> | ComputedRef<ControlSize>): void;
|
|
5
|
+
export declare function useControlTokens(explicit?: Ref<ControlSize | undefined> | ComputedRef<ControlSize | undefined>, fallback?: ControlSize): {
|
|
6
|
+
size: ComputedRef<ControlSize>;
|
|
7
|
+
tokens: ComputedRef<Record<string, string>>;
|
|
8
|
+
};
|
|
9
|
+
export { sizeTokens };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import {
|
|
2
|
+
computed,
|
|
3
|
+
inject,
|
|
4
|
+
provide,
|
|
5
|
+
ref
|
|
6
|
+
} from "vue";
|
|
7
|
+
const CONTROL_SIZE_KEY = Symbol("control-size");
|
|
8
|
+
const sizeTokens = {
|
|
9
|
+
sm: {
|
|
10
|
+
"--control-font-size": "var(--font-sm)",
|
|
11
|
+
"--control-label-font-size": "var(--font-xs)",
|
|
12
|
+
"--control-py": "0.25rem",
|
|
13
|
+
"--control-px": "0.5rem",
|
|
14
|
+
"--control-gap": "0.25rem",
|
|
15
|
+
"--control-radius": "var(--border-radius-sm)",
|
|
16
|
+
"--control-icon-size": "0.75rem",
|
|
17
|
+
"--control-inner-block-start": "1rem",
|
|
18
|
+
"--control-inner-block-end": "0.1rem",
|
|
19
|
+
"--control-label-block-start": "0.2rem"
|
|
20
|
+
},
|
|
21
|
+
md: {
|
|
22
|
+
"--control-font-size": "var(--font-md)",
|
|
23
|
+
"--control-label-font-size": "var(--font-sm)",
|
|
24
|
+
"--control-py": "0.5rem",
|
|
25
|
+
"--control-px": "0.75rem",
|
|
26
|
+
"--control-gap": "0.5rem",
|
|
27
|
+
"--control-radius": "var(--border-radius-md)",
|
|
28
|
+
"--control-icon-size": "1rem",
|
|
29
|
+
"--control-inner-block-start": "1.25rem",
|
|
30
|
+
"--control-inner-block-end": "0.2rem",
|
|
31
|
+
"--control-label-block-start": "0.25rem"
|
|
32
|
+
},
|
|
33
|
+
lg: {
|
|
34
|
+
"--control-font-size": "var(--font-lg)",
|
|
35
|
+
"--control-label-font-size": "var(--font-md)",
|
|
36
|
+
"--control-py": "0.625rem",
|
|
37
|
+
"--control-px": "1rem",
|
|
38
|
+
"--control-gap": "0.5rem",
|
|
39
|
+
"--control-radius": "var(--border-radius-md)",
|
|
40
|
+
"--control-icon-size": "1.25rem",
|
|
41
|
+
"--control-inner-block-start": "1.1rem",
|
|
42
|
+
"--control-inner-block-end": "0.2rem",
|
|
43
|
+
"--control-label-block-start": "0.25rem"
|
|
44
|
+
},
|
|
45
|
+
xl: {
|
|
46
|
+
"--control-font-size": "var(--font-xl)",
|
|
47
|
+
"--control-label-font-size": "var(--font-lg)",
|
|
48
|
+
"--control-py": "0.75rem",
|
|
49
|
+
"--control-px": "1.25rem",
|
|
50
|
+
"--control-gap": "0.75rem",
|
|
51
|
+
"--control-radius": "var(--border-radius-lg)",
|
|
52
|
+
"--control-icon-size": "1.5rem",
|
|
53
|
+
"--control-inner-block-start": "1.5rem",
|
|
54
|
+
"--control-inner-block-end": "0",
|
|
55
|
+
"--control-label-block-start": "0.25rem"
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
export function provideControlSize(size) {
|
|
59
|
+
provide(CONTROL_SIZE_KEY, size);
|
|
60
|
+
}
|
|
61
|
+
export function useControlTokens(explicit, fallback = "md") {
|
|
62
|
+
const injected = inject(CONTROL_SIZE_KEY, ref(fallback));
|
|
63
|
+
const size = computed(() => explicit?.value ?? injected.value);
|
|
64
|
+
const tokens = computed(() => sizeTokens[size.value]);
|
|
65
|
+
return { size, tokens };
|
|
66
|
+
}
|
|
67
|
+
export { sizeTokens };
|
|
@@ -1,13 +1,53 @@
|
|
|
1
1
|
const DEFAULT_SOUND = "https://cdn.jsdelivr.net/gh/oriondor/orio-ui@main/docs/public/sounds/mechanical-switch.wav";
|
|
2
|
+
let audioContext = null;
|
|
3
|
+
const bufferCache = /* @__PURE__ */ new Map();
|
|
4
|
+
function getAudioContext() {
|
|
5
|
+
if (typeof window === "undefined") return null;
|
|
6
|
+
if (audioContext) return audioContext;
|
|
7
|
+
const ContextClass = window.AudioContext ?? window.webkitAudioContext;
|
|
8
|
+
if (!ContextClass) return null;
|
|
9
|
+
try {
|
|
10
|
+
audioContext = new ContextClass();
|
|
11
|
+
} catch (e) {
|
|
12
|
+
console.error("[useSound] Failed to create AudioContext:", e);
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
return audioContext;
|
|
16
|
+
}
|
|
17
|
+
function fetchBuffer(ctx, src) {
|
|
18
|
+
const cached = bufferCache.get(src);
|
|
19
|
+
if (cached) return cached;
|
|
20
|
+
const promise = fetch(src).then((response) => response.arrayBuffer()).then((arrayBuffer) => ctx.decodeAudioData(arrayBuffer)).catch((e) => {
|
|
21
|
+
console.error(`[useSound] Failed to load sound "${src}":`, e);
|
|
22
|
+
bufferCache.delete(src);
|
|
23
|
+
return null;
|
|
24
|
+
});
|
|
25
|
+
bufferCache.set(src, promise);
|
|
26
|
+
return promise;
|
|
27
|
+
}
|
|
2
28
|
export function useSound(options = {}) {
|
|
3
|
-
const { src = DEFAULT_SOUND, volume = 0.3 } = options;
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
if (
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
29
|
+
const { src = DEFAULT_SOUND, volume = 0.3, prefetch = false } = options;
|
|
30
|
+
const warmUp = () => {
|
|
31
|
+
const ctx = getAudioContext();
|
|
32
|
+
if (ctx) fetchBuffer(ctx, src);
|
|
33
|
+
};
|
|
34
|
+
if (prefetch) warmUp();
|
|
35
|
+
const play = async () => {
|
|
36
|
+
const ctx = getAudioContext();
|
|
37
|
+
if (!ctx) return;
|
|
38
|
+
if (ctx.state === "suspended") {
|
|
39
|
+
await ctx.resume().catch(() => {
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
const buffer = await fetchBuffer(ctx, src);
|
|
43
|
+
if (!buffer) return;
|
|
44
|
+
const source = ctx.createBufferSource();
|
|
45
|
+
source.buffer = buffer;
|
|
46
|
+
const gainNode = ctx.createGain();
|
|
47
|
+
gainNode.gain.value = volume;
|
|
48
|
+
source.connect(gainNode);
|
|
49
|
+
gainNode.connect(ctx.destination);
|
|
50
|
+
source.start(0);
|
|
11
51
|
};
|
|
12
|
-
return { play };
|
|
52
|
+
return { play, prefetch: warmUp };
|
|
13
53
|
}
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { default as AnimatedContainer } from "./components/AnimatedContainer.vue.js";
|
|
2
2
|
export { default as Button } from "./components/Button.vue.js";
|
|
3
|
+
export { default as Form, type FormProps } from "./components/Form.vue.js";
|
|
3
4
|
export { default as NavButton } from "./components/NavButton.vue.js";
|
|
4
5
|
export { default as Input } from "./components/Input.vue.js";
|
|
5
6
|
export { default as NumberInput } from "./components/NumberInput/index.vue.js";
|
|
@@ -13,6 +14,7 @@ export { default as SwitchButton } from "./components/SwitchButton.vue.js";
|
|
|
13
14
|
export { default as DatePicker } from "./components/DatePicker.vue.js";
|
|
14
15
|
export { default as DateRangePicker } from "./components/DateRangePicker.vue.js";
|
|
15
16
|
export { default as Selector } from "./components/Selector.vue.js";
|
|
17
|
+
export { default as TaggableSelector } from "./components/TaggableSelector.vue.js";
|
|
16
18
|
export { default as Tag } from "./components/Tag.vue.js";
|
|
17
19
|
export { default as Badge } from "./components/Badge.vue.js";
|
|
18
20
|
export { default as Banner } from "./components/Banner.vue.js";
|
|
@@ -21,7 +23,7 @@ export { default as LoadingSpinner } from "./components/LoadingSpinner.vue.js";
|
|
|
21
23
|
export { default as Modal } from "./components/Modal.vue.js";
|
|
22
24
|
export { default as Popover } from "./components/Popover.vue.js";
|
|
23
25
|
export { default as Tooltip } from "./components/Tooltip.vue.js";
|
|
24
|
-
export { default as Upload } from "./components/
|
|
26
|
+
export { default as Upload } from "./components/upload/index.vue.js";
|
|
25
27
|
export { default as EmptyState } from "./components/EmptyState.vue.js";
|
|
26
28
|
export { default as DashedContainer } from "./components/DashedContainer.vue.js";
|
|
27
29
|
export { default as ControlElement } from "./components/ControlElement.vue.js";
|
|
@@ -29,6 +31,7 @@ export { default as GalleryCarousel } from "./components/gallery/Carousel.vue.js
|
|
|
29
31
|
export { default as ViewText } from "./components/view/Text.vue.js";
|
|
30
32
|
export { default as ViewDates } from "./components/view/Dates.vue.js";
|
|
31
33
|
export { default as ViewSeparator } from "./components/view/Separator.vue.js";
|
|
34
|
+
export { default as ListItem } from "./components/ListItem.vue.js";
|
|
32
35
|
export { useApi, type ApiOptions, type RequestBody, type RequestMethod, } from "./composables/useApi.js";
|
|
33
36
|
export { useFuzzySearch } from "./composables/useFuzzySearch.js";
|
|
34
37
|
export { useModal, type ModalProps, type OriginRect, } from "./composables/useModal.js";
|
package/dist/runtime/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { default as AnimatedContainer } from "./components/AnimatedContainer.vue";
|
|
2
2
|
export { default as Button } from "./components/Button.vue";
|
|
3
|
+
export { default as Form } from "./components/Form.vue";
|
|
3
4
|
export { default as NavButton } from "./components/NavButton.vue";
|
|
4
5
|
export { default as Input } from "./components/Input.vue";
|
|
5
6
|
export { default as NumberInput } from "./components/NumberInput/index.vue";
|
|
@@ -17,6 +18,7 @@ export { default as SwitchButton } from "./components/SwitchButton.vue";
|
|
|
17
18
|
export { default as DatePicker } from "./components/DatePicker.vue";
|
|
18
19
|
export { default as DateRangePicker } from "./components/DateRangePicker.vue";
|
|
19
20
|
export { default as Selector } from "./components/Selector.vue";
|
|
21
|
+
export { default as TaggableSelector } from "./components/TaggableSelector.vue";
|
|
20
22
|
export { default as Tag } from "./components/Tag.vue";
|
|
21
23
|
export { default as Badge } from "./components/Badge.vue";
|
|
22
24
|
export { default as Banner } from "./components/Banner.vue";
|
|
@@ -25,7 +27,7 @@ export { default as LoadingSpinner } from "./components/LoadingSpinner.vue";
|
|
|
25
27
|
export { default as Modal } from "./components/Modal.vue";
|
|
26
28
|
export { default as Popover } from "./components/Popover.vue";
|
|
27
29
|
export { default as Tooltip } from "./components/Tooltip.vue";
|
|
28
|
-
export { default as Upload } from "./components/
|
|
30
|
+
export { default as Upload } from "./components/upload/index.vue";
|
|
29
31
|
export { default as EmptyState } from "./components/EmptyState.vue";
|
|
30
32
|
export { default as DashedContainer } from "./components/DashedContainer.vue";
|
|
31
33
|
export { default as ControlElement } from "./components/ControlElement.vue";
|
|
@@ -33,6 +35,7 @@ export { default as GalleryCarousel } from "./components/gallery/Carousel.vue";
|
|
|
33
35
|
export { default as ViewText } from "./components/view/Text.vue";
|
|
34
36
|
export { default as ViewDates } from "./components/view/Dates.vue";
|
|
35
37
|
export { default as ViewSeparator } from "./components/view/Separator.vue";
|
|
38
|
+
export { default as ListItem } from "./components/ListItem.vue";
|
|
36
39
|
export {
|
|
37
40
|
useApi
|
|
38
41
|
} from "./composables/useApi.js";
|