@revojs/ui 0.2.12 → 0.2.13
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/button.d.ts +1 -0
- package/dist/components/card.d.ts +8 -0
- package/dist/components/collection.d.ts +3 -0
- package/dist/components/container.d.ts +2 -3
- package/dist/components/dialog.d.ts +3 -2
- package/dist/components/entry.d.ts +6 -0
- package/dist/components/entry.js +1 -0
- package/dist/components/field.d.ts +2 -0
- package/dist/components/input.d.ts +1 -0
- package/dist/components/notification.d.ts +9 -0
- package/dist/components/notification.js +1 -0
- package/dist/components/pagination.d.ts +8 -0
- package/dist/components/pagination.js +1 -0
- package/dist/components/popover.d.ts +9 -1
- package/dist/components/select.d.ts +8 -5
- package/dist/components/sheet.d.ts +3 -2
- package/dist/components/shell.d.ts +6 -0
- package/dist/components/shell.js +1 -0
- package/dist/components/textarea.d.ts +13 -0
- package/dist/components/textarea.js +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/module/index.d.ts +8 -0
- package/dist/module/index.js +16 -0
- package/dist/style.css +8 -0
- package/dist/vue/components/breadcrumb.vue +6 -1
- package/dist/vue/components/button.vue +25 -3
- package/dist/vue/components/card.vue +22 -3
- package/dist/vue/components/collection.vue +22 -7
- package/dist/vue/components/container.vue +6 -2
- package/dist/vue/components/dialog.vue +52 -35
- package/dist/vue/components/entry.vue +52 -0
- package/dist/vue/components/field.vue +37 -7
- package/dist/vue/components/input.vue +22 -2
- package/dist/vue/components/navigate.vue +1 -0
- package/dist/vue/components/notification.vue +58 -0
- package/dist/vue/components/pagination.vue +24 -0
- package/dist/vue/components/popover.vue +39 -15
- package/dist/vue/components/select.vue +93 -15
- package/dist/vue/components/sheet.vue +55 -21
- package/dist/vue/components/shell.vue +38 -0
- package/dist/vue/components/textarea.vue +49 -0
- package/dist/vue/components/upload.vue +43 -24
- package/dist/vue/index.d.ts +5 -0
- package/dist/vue/index.js +6 -1
- package/dist/vue/utilities/use-control-attributes.d.ts +11 -0
- package/dist/vue/utilities/use-control-attributes.js +14 -0
- package/dist/vue/utilities/use-modal-dialog.d.ts +9 -0
- package/dist/vue/utilities/use-modal-dialog.js +48 -0
- package/package.json +1 -1
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<header class="z-10 shrink-0 border-b border-border bg-background" :class="sticky ? 'sticky top-0' : ''">
|
|
3
|
+
<Stack direction="horizontal" align="center" gap="1" padding="1">
|
|
4
|
+
<slot name="prefix" />
|
|
5
|
+
|
|
6
|
+
<h1 v-if="label || $slots.heading" class="min-w-0 flex-1 truncate p-3 text-sm font-semibold">
|
|
7
|
+
<slot name="heading">{{ label }}</slot>
|
|
8
|
+
</h1>
|
|
9
|
+
<template v-else-if="headingLabel">
|
|
10
|
+
<h1 class="sr-only">{{ headingLabel }}</h1>
|
|
11
|
+
|
|
12
|
+
<span aria-hidden="true" class="min-w-0 flex-1" />
|
|
13
|
+
</template>
|
|
14
|
+
<span v-else aria-hidden="true" class="min-w-0 flex-1" />
|
|
15
|
+
|
|
16
|
+
<slot name="actions"><slot /></slot>
|
|
17
|
+
</Stack>
|
|
18
|
+
|
|
19
|
+
<Stack
|
|
20
|
+
v-if="$slots.navigation"
|
|
21
|
+
is="nav"
|
|
22
|
+
:aria-label="navigationLabel"
|
|
23
|
+
direction="horizontal"
|
|
24
|
+
gap="1"
|
|
25
|
+
padding="1"
|
|
26
|
+
class="overflow-x-auto border-t border-border [scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
|
|
27
|
+
>
|
|
28
|
+
<slot name="navigation" />
|
|
29
|
+
</Stack>
|
|
30
|
+
</header>
|
|
31
|
+
</template>
|
|
32
|
+
|
|
33
|
+
<script setup lang="ts">
|
|
34
|
+
import type { ShellProps } from "../../components/shell";
|
|
35
|
+
import Stack from "./stack.vue";
|
|
36
|
+
|
|
37
|
+
const { label, headingLabel, sticky = true, navigationLabel = "Page navigation" } = defineProps<ShellProps>();
|
|
38
|
+
</script>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<textarea
|
|
3
|
+
ref="control"
|
|
4
|
+
class="block w-full min-w-0 rounded-ui outline-ring placeholder:opacity-50 focus-visible:outline-2 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-2 aria-invalid:ring-destructive"
|
|
5
|
+
:class="[texts[text], resizes[resize], variants[variant]]"
|
|
6
|
+
:value="modelValue"
|
|
7
|
+
:disabled="disabled"
|
|
8
|
+
:readonly="readonly"
|
|
9
|
+
:required="required"
|
|
10
|
+
:aria-invalid="invalid ?? ($attrs as HTMLAttributes)['aria-invalid']"
|
|
11
|
+
@input="$emit('update:modelValue', ($event.currentTarget as HTMLTextAreaElement).value)"
|
|
12
|
+
></textarea>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script setup lang="ts">
|
|
16
|
+
import { useTemplateRef, type HTMLAttributes } from "vue";
|
|
17
|
+
import type { TextareaProps, TextareaResize, TextareaText, TextareaVariant } from "../../components/textarea";
|
|
18
|
+
|
|
19
|
+
const {
|
|
20
|
+
modelValue = "",
|
|
21
|
+
text = "sm",
|
|
22
|
+
resize = "vertical",
|
|
23
|
+
variant = "default",
|
|
24
|
+
disabled = false,
|
|
25
|
+
readonly = false,
|
|
26
|
+
required = false,
|
|
27
|
+
invalid = undefined,
|
|
28
|
+
} = defineProps<TextareaProps>();
|
|
29
|
+
|
|
30
|
+
defineEmits<{ "update:modelValue": [value: string] }>();
|
|
31
|
+
|
|
32
|
+
const control = useTemplateRef("control");
|
|
33
|
+
|
|
34
|
+
defineExpose({ focus: () => control.value?.focus() });
|
|
35
|
+
|
|
36
|
+
const texts: Record<TextareaText, string> = { sm: "text-sm", md: "text-base" };
|
|
37
|
+
|
|
38
|
+
const resizes: Record<TextareaResize, string> = {
|
|
39
|
+
none: "resize-none",
|
|
40
|
+
vertical: "resize-y",
|
|
41
|
+
horizontal: "resize-x",
|
|
42
|
+
both: "resize",
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const variants: Record<TextareaVariant, string> = {
|
|
46
|
+
default: "bg-secondary p-3 ring-1 ring-input ring-inset",
|
|
47
|
+
plain: "bg-transparent p-0",
|
|
48
|
+
};
|
|
49
|
+
</script>
|
|
@@ -13,30 +13,34 @@
|
|
|
13
13
|
@dragleave="leave"
|
|
14
14
|
@drop.prevent="drop"
|
|
15
15
|
>
|
|
16
|
-
<
|
|
17
|
-
<
|
|
18
|
-
<span class="
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
<
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
16
|
+
<slot v-if="modelValue" name="file" :file="modelValue" :remove="remove" :disabled="disabled">
|
|
17
|
+
<Stack direction="horizontal" align="center" justify="between" gap="0">
|
|
18
|
+
<span class="min-w-0 flex-1 p-3">
|
|
19
|
+
<span class="block truncate px-1">{{
|
|
20
|
+
"name" in modelValue ? modelValue.name : "File selected"
|
|
21
|
+
}}</span>
|
|
22
|
+
</span>
|
|
23
|
+
|
|
24
|
+
<Button
|
|
25
|
+
size="icon"
|
|
26
|
+
variant="secondary"
|
|
27
|
+
:text="text"
|
|
28
|
+
:icon-prefix="CloseIcon"
|
|
29
|
+
aria-label="Remove file"
|
|
30
|
+
:disabled="disabled"
|
|
31
|
+
@click="remove"
|
|
32
|
+
/>
|
|
33
|
+
</Stack>
|
|
34
|
+
</slot>
|
|
35
|
+
<slot v-else name="empty" :browse="browse" :disabled="disabled" :dragging="isOver">
|
|
36
|
+
<Stack align="center" gap="3" padding="5" class="text-center">
|
|
37
|
+
<Icon :is="UploadIcon" :size="24" />
|
|
38
|
+
|
|
39
|
+
<span class="text-sm opacity-60"> Drag and drop a file here </span>
|
|
40
|
+
|
|
41
|
+
<Button label="Browse files" variant="outline" :disabled="disabled" @click="browse" />
|
|
42
|
+
</Stack>
|
|
43
|
+
</slot>
|
|
40
44
|
|
|
41
45
|
<input
|
|
42
46
|
ref="input"
|
|
@@ -84,6 +88,11 @@ const emit = defineEmits<{
|
|
|
84
88
|
"update:modelValue": [value?: Blob | File];
|
|
85
89
|
}>();
|
|
86
90
|
|
|
91
|
+
defineSlots<{
|
|
92
|
+
empty?: (props: { browse: () => void; disabled: boolean; dragging: boolean }) => unknown;
|
|
93
|
+
file?: (props: { file: Blob | File; remove: () => void; disabled: boolean }) => unknown;
|
|
94
|
+
}>();
|
|
95
|
+
|
|
87
96
|
const input = useTemplateRef("input");
|
|
88
97
|
|
|
89
98
|
const isOver = ref(false);
|
|
@@ -107,6 +116,12 @@ const texts: Record<UploadText, string> = {
|
|
|
107
116
|
md: "text-base",
|
|
108
117
|
};
|
|
109
118
|
|
|
119
|
+
function browse() {
|
|
120
|
+
if (!disabled) {
|
|
121
|
+
input.value?.click();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
110
125
|
function change() {
|
|
111
126
|
const file = input.value?.files?.item(0);
|
|
112
127
|
|
|
@@ -137,6 +152,10 @@ function leave(event: DragEvent) {
|
|
|
137
152
|
}
|
|
138
153
|
|
|
139
154
|
function remove() {
|
|
155
|
+
if (disabled) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
140
159
|
if (input.value) {
|
|
141
160
|
input.value.value = "";
|
|
142
161
|
}
|
package/dist/vue/index.d.ts
CHANGED
|
@@ -8,11 +8,15 @@ export { default as Counter } from "./components/counter.vue";
|
|
|
8
8
|
export { default as Dialog } from "./components/dialog.vue";
|
|
9
9
|
export { default as Field } from "./components/field.vue";
|
|
10
10
|
export { default as Heading } from "./components/heading.vue";
|
|
11
|
+
export { default as Shell } from "./components/shell.vue";
|
|
11
12
|
export { default as Icon } from "./components/icon.vue";
|
|
12
13
|
export { default as Input } from "./components/input.vue";
|
|
13
14
|
export { default as Link } from "./components/link.vue";
|
|
15
|
+
export { default as Entry } from "./components/entry.vue";
|
|
16
|
+
export { default as Notification } from "./components/notification.vue";
|
|
14
17
|
export { default as Navigate } from "./components/navigate.vue";
|
|
15
18
|
export { default as Popover } from "./components/popover.vue";
|
|
19
|
+
export { default as Pagination } from "./components/pagination.vue";
|
|
16
20
|
export { default as Progress } from "./components/progress.vue";
|
|
17
21
|
export { default as Radio } from "./components/radio.vue";
|
|
18
22
|
export { default as Range } from "./components/range.vue";
|
|
@@ -23,5 +27,6 @@ export { default as Sheet } from "./components/sheet.vue";
|
|
|
23
27
|
export { default as Stack } from "./components/stack.vue";
|
|
24
28
|
export { default as Switch } from "./components/switch.vue";
|
|
25
29
|
export { default as Upload } from "./components/upload.vue";
|
|
30
|
+
export { default as Textarea } from "./components/textarea.vue";
|
|
26
31
|
export { useFocusTrap } from "./utilities/use-focus-trap";
|
|
27
32
|
export { useScrollLock } from "./utilities/use-scroll-lock";
|
package/dist/vue/index.js
CHANGED
|
@@ -10,11 +10,15 @@ import Counter from "./components/counter.vue";
|
|
|
10
10
|
import Dialog from "./components/dialog.vue";
|
|
11
11
|
import Field from "./components/field.vue";
|
|
12
12
|
import Heading from "./components/heading.vue";
|
|
13
|
+
import Shell from "./components/shell.vue";
|
|
13
14
|
import Icon from "./components/icon.vue";
|
|
14
15
|
import Input from "./components/input.vue";
|
|
15
16
|
import Link from "./components/link.vue";
|
|
17
|
+
import Entry from "./components/entry.vue";
|
|
18
|
+
import Notification from "./components/notification.vue";
|
|
16
19
|
import Navigate from "./components/navigate.vue";
|
|
17
20
|
import Popover from "./components/popover.vue";
|
|
21
|
+
import Pagination from "./components/pagination.vue";
|
|
18
22
|
import Progress from "./components/progress.vue";
|
|
19
23
|
import Radio from "./components/radio.vue";
|
|
20
24
|
import Range from "./components/range.vue";
|
|
@@ -25,4 +29,5 @@ import Sheet from "./components/sheet.vue";
|
|
|
25
29
|
import Stack from "./components/stack.vue";
|
|
26
30
|
import Switch from "./components/switch.vue";
|
|
27
31
|
import Upload from "./components/upload.vue";
|
|
28
|
-
|
|
32
|
+
import Textarea from "./components/textarea.vue";
|
|
33
|
+
export { Breadcrumb, Button, Card, Checkbox, Collection, Container, Counter, Dialog, Entry, Field, Heading, Icon, Input, Link, Navigate, Notification, Pagination, Popover, Progress, Radio, Range, Rating, Select, Separator, Sheet, Shell, Stack, Switch, Textarea, Upload, useFocusTrap, useScrollLock };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type InputHTMLAttributes } from "vue";
|
|
2
|
+
export declare function useControlAttributes(): {
|
|
3
|
+
rootAttributes: Readonly<import("vue").Ref<{
|
|
4
|
+
class: import("vue").ClassValue;
|
|
5
|
+
style: import("vue").StyleValue;
|
|
6
|
+
}, {
|
|
7
|
+
class: import("vue").ClassValue;
|
|
8
|
+
style: import("vue").StyleValue;
|
|
9
|
+
}>>;
|
|
10
|
+
controlAttributes: Readonly<import("vue").Ref<InputHTMLAttributes, InputHTMLAttributes>>;
|
|
11
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { toRef, useAttrs } from "vue";
|
|
2
|
+
//#region src/vue/utilities/use-control-attributes.ts
|
|
3
|
+
function useControlAttributes() {
|
|
4
|
+
const attributes = useAttrs();
|
|
5
|
+
return {
|
|
6
|
+
rootAttributes: toRef(() => ({
|
|
7
|
+
class: attributes.class,
|
|
8
|
+
style: attributes.style
|
|
9
|
+
})),
|
|
10
|
+
controlAttributes: toRef(() => Object.fromEntries(Object.entries(attributes).filter(([key]) => key !== "class" && key !== "style")))
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { useControlAttributes };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type MaybeRefOrGetter, type Ref } from "vue";
|
|
2
|
+
export declare function useModalDialog(element: Ref<HTMLDialogElement | null>, modelValue: MaybeRefOrGetter<boolean | undefined>, update: (value: boolean) => void, dismissible: MaybeRefOrGetter<boolean>): {
|
|
3
|
+
isOpen: import("vue").ComputedRef<boolean>;
|
|
4
|
+
open: () => void;
|
|
5
|
+
close: () => void;
|
|
6
|
+
toggle: () => void;
|
|
7
|
+
dismiss: (event: Event) => void;
|
|
8
|
+
handleClose: () => void;
|
|
9
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { useScrollLock } from "./use-scroll-lock.js";
|
|
2
|
+
import { computed, ref, toValue, watchEffect } from "vue";
|
|
3
|
+
//#region src/vue/utilities/use-modal-dialog.ts
|
|
4
|
+
function useModalDialog(element, modelValue, update, dismissible) {
|
|
5
|
+
function open() {
|
|
6
|
+
internalOpen.value = true;
|
|
7
|
+
update(true);
|
|
8
|
+
}
|
|
9
|
+
function close() {
|
|
10
|
+
internalOpen.value = false;
|
|
11
|
+
element.value?.close();
|
|
12
|
+
update(false);
|
|
13
|
+
}
|
|
14
|
+
function toggle() {
|
|
15
|
+
if (isOpen.value) close();
|
|
16
|
+
else open();
|
|
17
|
+
}
|
|
18
|
+
function dismiss(event) {
|
|
19
|
+
if (!toValue(dismissible)) {
|
|
20
|
+
event.preventDefault();
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
close();
|
|
24
|
+
}
|
|
25
|
+
function handleClose() {
|
|
26
|
+
if (element.value?.open) return;
|
|
27
|
+
internalOpen.value = false;
|
|
28
|
+
if (isOpen.value) update(false);
|
|
29
|
+
}
|
|
30
|
+
const internalOpen = ref(false);
|
|
31
|
+
const isOpen = computed(() => toValue(modelValue) ?? internalOpen.value);
|
|
32
|
+
useScrollLock(isOpen);
|
|
33
|
+
watchEffect(() => {
|
|
34
|
+
if (!element.value?.isConnected) return;
|
|
35
|
+
if (isOpen.value && !element.value.open) element.value.showModal();
|
|
36
|
+
else if (!isOpen.value && element.value.open) element.value.close();
|
|
37
|
+
}, { flush: "post" });
|
|
38
|
+
return {
|
|
39
|
+
isOpen,
|
|
40
|
+
open,
|
|
41
|
+
close,
|
|
42
|
+
toggle,
|
|
43
|
+
dismiss,
|
|
44
|
+
handleClose
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//#endregion
|
|
48
|
+
export { useModalDialog };
|