@witchcraft/ui 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.cjs +5 -0
- package/dist/module.d.ts +36 -0
- package/dist/module.json +2 -2
- package/dist/module.mjs +2 -1
- package/dist/runtime/assets/utils.css +1 -1
- package/dist/runtime/components/Aria/Aria.vue +9 -5
- package/dist/runtime/components/Focus.stories.d.ts +11 -0
- package/dist/runtime/components/Focus.stories.js +53 -0
- package/dist/runtime/components/Icon/Icon.vue +30 -10
- package/dist/runtime/components/LibButton/LibButton.stories.d.ts +12 -0
- package/dist/runtime/components/LibButton/LibButton.stories.js +94 -0
- package/dist/runtime/components/LibButton/LibButton.vue +72 -58
- package/dist/runtime/components/LibCheckbox/LibCheckbox.stories.d.ts +14 -0
- package/dist/runtime/components/LibCheckbox/LibCheckbox.stories.js +29 -0
- package/dist/runtime/components/LibCheckbox/LibCheckbox.vue +74 -48
- package/dist/runtime/components/LibColorInput/LibColorInput.stories.d.ts +7 -0
- package/dist/runtime/components/LibColorInput/LibColorInput.stories.js +58 -0
- package/dist/runtime/components/LibColorInput/LibColorInput.vue +107 -63
- package/dist/runtime/components/LibColorPicker/LibColorPicker.stories.d.ts +9 -0
- package/dist/runtime/components/LibColorPicker/LibColorPicker.stories.js +68 -0
- package/dist/runtime/components/LibColorPicker/LibColorPicker.vue +352 -271
- package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.stories.d.ts +7 -0
- package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.stories.js +36 -0
- package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.vue +56 -32
- package/dist/runtime/components/LibDatePicker/LibDatePicker.stories.d.ts +11 -0
- package/dist/runtime/components/LibDatePicker/LibDatePicker.stories.js +98 -0
- package/dist/runtime/components/LibDatePicker/LibDatePicker.vue +38 -17
- package/dist/runtime/components/LibDatePicker/LibRangeDatePicker.vue +82 -53
- package/dist/runtime/components/LibDatePicker/LibSingleDatePicker.vue +67 -50
- package/dist/runtime/components/LibDatePicker/LibTimeZonePicker.vue +8 -7
- package/dist/runtime/components/LibDebug/LibDebug.stories.d.ts +9 -0
- package/dist/runtime/components/LibDebug/LibDebug.stories.js +46 -0
- package/dist/runtime/components/LibDebug/LibDebug.vue +70 -42
- package/dist/runtime/components/LibDevOnly/LibDevOnly.vue +31 -18
- package/dist/runtime/components/LibFileInput/LibFileInput.stories.d.ts +10 -0
- package/dist/runtime/components/LibFileInput/LibFileInput.stories.js +63 -0
- package/dist/runtime/components/LibFileInput/LibFileInput.vue +156 -113
- package/dist/runtime/components/LibInputDeprecated/LibInputDeprecated.stories.d.ts +33 -0
- package/dist/runtime/components/LibInputDeprecated/LibInputDeprecated.stories.js +384 -0
- package/dist/runtime/components/LibInputDeprecated/LibInputDeprecated.vue +241 -215
- package/dist/runtime/components/LibLabel/LibLabel.stories.d.ts +6 -0
- package/dist/runtime/components/LibLabel/LibLabel.stories.js +25 -0
- package/dist/runtime/components/LibLabel/LibLabel.vue +46 -30
- package/dist/runtime/components/LibMultiValues/LibMultiValues.stories.d.ts +23 -0
- package/dist/runtime/components/LibMultiValues/LibMultiValues.stories.js +61 -0
- package/dist/runtime/components/LibMultiValues/LibMultiValues.vue +58 -44
- package/dist/runtime/components/LibNotifications/LibNotification.stories.d.ts +15 -0
- package/dist/runtime/components/LibNotifications/LibNotification.stories.js +126 -0
- package/dist/runtime/components/LibNotifications/LibNotification.vue +48 -32
- package/dist/runtime/components/LibNotifications/LibNotifications.stories.d.ts +6 -0
- package/dist/runtime/components/LibNotifications/LibNotifications.stories.js +109 -0
- package/dist/runtime/components/LibNotifications/LibNotifications.vue +83 -63
- package/dist/runtime/components/LibPagination/LibPagination.stories.d.ts +6 -0
- package/dist/runtime/components/LibPagination/LibPagination.stories.js +40 -0
- package/dist/runtime/components/LibPagination/LibPagination.vue +111 -67
- package/dist/runtime/components/LibPalette/LibPalette.stories.d.ts +6 -0
- package/dist/runtime/components/LibPalette/LibPalette.stories.js +20 -0
- package/dist/runtime/components/LibPalette/LibPalette.vue +23 -20
- package/dist/runtime/components/LibPopup/LibPopup.stories.d.ts +14 -0
- package/dist/runtime/components/LibPopup/LibPopup.stories.js +147 -0
- package/dist/runtime/components/LibPopup/LibPopup.vue +351 -314
- package/dist/runtime/components/LibProgressBar/LibProgressBar.stories.d.ts +10 -0
- package/dist/runtime/components/LibProgressBar/LibProgressBar.stories.js +81 -0
- package/dist/runtime/components/LibProgressBar/LibProgressBar.vue +91 -70
- package/dist/runtime/components/LibRecorder/LibRecorder.stories.d.ts +19 -0
- package/dist/runtime/components/LibRecorder/LibRecorder.stories.js +63 -0
- package/dist/runtime/components/LibRecorder/LibRecorder.vue +177 -133
- package/dist/runtime/components/LibRoot/LibRoot.vue +100 -73
- package/dist/runtime/components/LibSimpleInput/LibSimpleInput.stories.d.ts +26 -0
- package/dist/runtime/components/LibSimpleInput/LibSimpleInput.stories.js +78 -0
- package/dist/runtime/components/LibSimpleInput/LibSimpleInput.vue +77 -49
- package/dist/runtime/components/LibSuggestions/LibSuggestions.stories.d.ts +27 -0
- package/dist/runtime/components/LibSuggestions/LibSuggestions.stories.js +112 -0
- package/dist/runtime/components/LibSuggestions/LibSuggestions.vue +156 -123
- package/dist/runtime/components/LibTable/LibTable.stories.d.ts +16 -0
- package/dist/runtime/components/LibTable/LibTable.stories.js +156 -0
- package/dist/runtime/components/LibTable/LibTable.vue +99 -63
- package/dist/runtime/components/Reset.stories.d.ts +5 -0
- package/dist/runtime/components/Reset.stories.js +19 -0
- package/dist/runtime/components/Scrolling.stories.d.ts +6 -0
- package/dist/runtime/components/Scrolling.stories.js +44 -0
- package/dist/runtime/components/Template/NAME.vue +36 -15
- package/dist/runtime/components/TestControls/TestControls.vue +9 -6
- package/dist/runtime/composables/useScrollNearContainerEdges.stories.d.ts +7 -0
- package/dist/runtime/composables/useScrollNearContainerEdges.stories.js +85 -0
- package/dist/types.d.mts +6 -2
- package/dist/types.d.ts +7 -0
- package/package.json +11 -5
- package/src/module.ts +2 -1
- package/src/runtime/assets/utils.css +5 -5
- package/src/runtime/components/LibButton/LibButton.vue +2 -6
- package/src/runtime/nuxt/plugins/vue-plugin.ts +1 -1
- package/dist/runtime/components/Aria/Aria.vue.d.ts +0 -5
- package/dist/runtime/components/Icon/Icon.vue.d.ts +0 -21
- package/dist/runtime/components/LibButton/LibButton.vue.d.ts +0 -36
- package/dist/runtime/components/LibCheckbox/LibCheckbox.vue.d.ts +0 -42
- package/dist/runtime/components/LibColorInput/LibColorInput.vue.d.ts +0 -63
- package/dist/runtime/components/LibColorPicker/LibColorPicker.vue.d.ts +0 -61
- package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.vue.d.ts +0 -22
- package/dist/runtime/components/LibDatePicker/LibDatePicker.vue.d.ts +0 -40
- package/dist/runtime/components/LibDatePicker/LibRangeDatePicker.vue.d.ts +0 -34
- package/dist/runtime/components/LibDatePicker/LibSingleDatePicker.vue.d.ts +0 -34
- package/dist/runtime/components/LibDatePicker/LibTimeZonePicker.vue.d.ts +0 -22
- package/dist/runtime/components/LibDebug/LibDebug.vue.d.ts +0 -32
- package/dist/runtime/components/LibDevOnly/LibDevOnly.vue.d.ts +0 -22
- package/dist/runtime/components/LibFileInput/LibFileInput.vue.d.ts +0 -43
- package/dist/runtime/components/LibInputDeprecated/LibInputDeprecated.vue.d.ts +0 -165
- package/dist/runtime/components/LibLabel/LibLabel.vue.d.ts +0 -27
- package/dist/runtime/components/LibMultiValues/LibMultiValues.vue.d.ts +0 -29
- package/dist/runtime/components/LibNotifications/LibNotification.vue.d.ts +0 -17
- package/dist/runtime/components/LibNotifications/LibNotifications.vue.d.ts +0 -13
- package/dist/runtime/components/LibPagination/LibPagination.vue.d.ts +0 -104
- package/dist/runtime/components/LibPalette/LibPalette.vue.d.ts +0 -14
- package/dist/runtime/components/LibPopup/LibPopup.vue.d.ts +0 -46
- package/dist/runtime/components/LibProgressBar/LibProgressBar.vue.d.ts +0 -41
- package/dist/runtime/components/LibRecorder/LibRecorder.vue.d.ts +0 -77
- package/dist/runtime/components/LibRoot/LibRoot.vue.d.ts +0 -41
- package/dist/runtime/components/LibSimpleInput/LibSimpleInput.vue.d.ts +0 -35
- package/dist/runtime/components/LibSuggestions/LibSuggestions.vue.d.ts +0 -94
- package/dist/runtime/components/LibTable/LibTable.vue.d.ts +0 -45
- package/dist/runtime/components/Template/NAME.vue.d.ts +0 -17
- package/dist/runtime/components/TestControls/TestControls.vue.d.ts +0 -5
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { reactive, ref } from "vue";
|
|
2
|
+
import LibNotifications from "./LibNotifications.vue";
|
|
3
|
+
import { NotificationHandler } from "../../helpers/NotificationHandler.js";
|
|
4
|
+
import * as components from "../index.js";
|
|
5
|
+
const meta = {
|
|
6
|
+
component: LibNotifications,
|
|
7
|
+
title: "Components/Notifications",
|
|
8
|
+
args: {
|
|
9
|
+
// @ts-expect-error story only arg
|
|
10
|
+
withTitle: true
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
export default meta;
|
|
14
|
+
export const Primary = {
|
|
15
|
+
render: (args) => ({
|
|
16
|
+
components,
|
|
17
|
+
setup() {
|
|
18
|
+
const handler = reactive(new NotificationHandler());
|
|
19
|
+
let count = 0;
|
|
20
|
+
const withTitle = ref(args.withTitle);
|
|
21
|
+
const disableTimeout = ref(false);
|
|
22
|
+
const notifyRequiresAction = () => {
|
|
23
|
+
count++;
|
|
24
|
+
void handler.notify({
|
|
25
|
+
title: withTitle.value ? `Notification(${count})` : void 0,
|
|
26
|
+
message: `This is a notification that requires action. Pick an option:`,
|
|
27
|
+
requiresAction: true,
|
|
28
|
+
options: ["Ok", "Default Answer", "Cancel"],
|
|
29
|
+
default: "Default Answer"
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
const notifyWithDangerousOption = () => {
|
|
33
|
+
count++;
|
|
34
|
+
void handler.notify({
|
|
35
|
+
title: withTitle.value ? `Notification(${count})` : void 0,
|
|
36
|
+
message: `This is a notification that has a dangerous option. Pick an option:`,
|
|
37
|
+
options: ["Ok", "Default Answer", "Dangerous Option", "Cancel"],
|
|
38
|
+
default: "Default Answer",
|
|
39
|
+
dangerous: ["Dangerous Option"]
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
const notifyNonCancellable = () => {
|
|
43
|
+
count++;
|
|
44
|
+
void handler.notify({
|
|
45
|
+
title: withTitle.value ? `Notification(${count})` : void 0,
|
|
46
|
+
message: `This is a non-cancellable notification. Pick an option:`,
|
|
47
|
+
options: ["Ok", "Default Answer"],
|
|
48
|
+
default: "Default Answer",
|
|
49
|
+
cancellable: false
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
const notifyNonCancellableRequiresAction = () => {
|
|
53
|
+
count++;
|
|
54
|
+
void handler.notify({
|
|
55
|
+
title: withTitle.value ? `Notification(${count})` : void 0,
|
|
56
|
+
message: `This is a non-cancellable notification. Pick an option:`,
|
|
57
|
+
requiresAction: true,
|
|
58
|
+
options: ["Ok", "Default Answer"],
|
|
59
|
+
default: "Default Answer",
|
|
60
|
+
cancellable: false
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
const notifyTimeoutable = () => {
|
|
64
|
+
count++;
|
|
65
|
+
void handler.notify({
|
|
66
|
+
title: withTitle.value ? `Notification(${count})` : void 0,
|
|
67
|
+
message: `This is a notification. No action required.`,
|
|
68
|
+
timeout: disableTimeout.value ? false : 2e3
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
return {
|
|
72
|
+
notifyRequiresAction,
|
|
73
|
+
notifyTimeoutable,
|
|
74
|
+
notifyNonCancellable,
|
|
75
|
+
notifyWithDangerousOption,
|
|
76
|
+
notifyNonCancellableRequiresAction,
|
|
77
|
+
handler,
|
|
78
|
+
withTitle,
|
|
79
|
+
disableTimeout,
|
|
80
|
+
args: {
|
|
81
|
+
outline: false,
|
|
82
|
+
...args
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
},
|
|
86
|
+
backgrounds: { disable: true },
|
|
87
|
+
// <lib-debug>{{args.handler}}</lib-debug>
|
|
88
|
+
template: `
|
|
89
|
+
<lib-root :outline="args.outline">
|
|
90
|
+
<lib-button :label="'Notify Timeoutable'" @click="notifyTimeoutable()"></lib-button>
|
|
91
|
+
<lib-button :label="'Notify RequiresAction'" @click="notifyRequiresAction()"></lib-button>
|
|
92
|
+
<lib-button :label="'Notify Non-Cancellable that RequiresAction'" @click="notifyNonCancellableRequiresAction()"></lib-button>
|
|
93
|
+
<lib-button :label="'Notify With Dangerous Option'" @click="notifyWithDangerousOption()"></lib-button>
|
|
94
|
+
<lib-button :label="'Notify Non-Cancellable'" @click="notifyNonCancellable()"></lib-button>
|
|
95
|
+
<input type="checkbox" v-model="withTitle"/> With Title
|
|
96
|
+
<input type="checkbox" v-model="disableTimeout"/> Disable Timeout
|
|
97
|
+
<lib-notifications :handler="handler" />
|
|
98
|
+
History:
|
|
99
|
+
<lib-debug>
|
|
100
|
+
<template v-for="entry in handler.history">
|
|
101
|
+
Message: {{entry.message}}
|
|
102
|
+
Resolution: {{entry.resolution}}
|
|
103
|
+
<br>
|
|
104
|
+
</template>
|
|
105
|
+
</lib-debug>
|
|
106
|
+
</lib-root>
|
|
107
|
+
`
|
|
108
|
+
})
|
|
109
|
+
};
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
pointer-events-none
|
|
11
11
|
overflow-hidden
|
|
12
12
|
flex flex-col
|
|
13
|
-
`, $attrs.class)"
|
|
14
|
-
v-bind="{ ...$attrs, class:
|
|
13
|
+
`, ($attrs as any).class)"
|
|
14
|
+
v-bind="{ ...$attrs, class: undefined }"
|
|
15
15
|
>
|
|
16
16
|
<lib-notification class="pointer-events-auto"
|
|
17
17
|
:handler="handler"
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
<Transition>
|
|
25
25
|
<div
|
|
26
26
|
v-show="topNotifications.length > 0"
|
|
27
|
-
:class="twMerge(`notifications--none`, $attrs.class)"
|
|
27
|
+
:class="twMerge(`notifications--none`, ($attrs as any).class)"
|
|
28
28
|
/>
|
|
29
29
|
</Transition>
|
|
30
30
|
<Transition>
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
p-0
|
|
36
36
|
backdrop:bg-black/50
|
|
37
37
|
backdrop:p-5
|
|
38
|
-
`, $attrs.class)"
|
|
38
|
+
`, ($attrs as any).class)"
|
|
39
39
|
ref="dialogEl"
|
|
40
40
|
@click.self.prevent="topNotifications[0] && NotificationHandler.dismiss(topNotifications[0])"
|
|
41
41
|
>
|
|
@@ -50,72 +50,92 @@
|
|
|
50
50
|
</dialog>
|
|
51
51
|
</Transition>
|
|
52
52
|
</template>
|
|
53
|
+
<script setup lang="ts">
|
|
54
|
+
import { removeIfIn } from "@alanscodelog/utils/removeIfIn.js"
|
|
55
|
+
import { type HTMLAttributes,nextTick, onBeforeUnmount, ref,shallowReactive, Transition, TransitionGroup } from "vue"
|
|
56
|
+
|
|
57
|
+
import LibNotification from "./LibNotification.vue"
|
|
58
|
+
|
|
59
|
+
import { useNotificationHandler } from "../../composables/useNotificationHandler.js"
|
|
60
|
+
import { type NotificationEntry, NotificationHandler } from "../../helpers/NotificationHandler.js"
|
|
61
|
+
import { twMerge } from "../../utils/twMerge.js"
|
|
62
|
+
import type { LinkableByIdProps, TailwindClassProp } from "../shared/props.js"
|
|
53
63
|
|
|
54
|
-
<script setup>
|
|
55
|
-
import { removeIfIn } from "@alanscodelog/utils/removeIfIn.js";
|
|
56
|
-
import { nextTick, onBeforeUnmount, ref, shallowReactive, Transition, TransitionGroup } from "vue";
|
|
57
|
-
import LibNotification from "./LibNotification.vue";
|
|
58
|
-
import { useNotificationHandler } from "../../composables/useNotificationHandler.js";
|
|
59
|
-
import { NotificationHandler } from "../../helpers/NotificationHandler.js";
|
|
60
|
-
import { twMerge } from "../../utils/twMerge.js";
|
|
61
64
|
defineOptions({
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const dialogEl = ref(null)
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
const
|
|
65
|
+
name: "lib-notifications",
|
|
66
|
+
inheritAttrs: false,
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
const props = defineProps<Props>()
|
|
71
|
+
|
|
72
|
+
const dialogEl = ref<HTMLDialogElement | null>(null)
|
|
73
|
+
|
|
74
|
+
const isOpen = ref(false)
|
|
75
|
+
const notifications = shallowReactive<NotificationEntry[]>([])
|
|
76
|
+
const topNotifications = shallowReactive<NotificationEntry[]>([])
|
|
73
77
|
const open = () => {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
78
|
+
if (!isOpen.value) {
|
|
79
|
+
void nextTick(() => {
|
|
80
|
+
dialogEl.value!.showModal()
|
|
81
|
+
isOpen.value = true
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
}
|
|
81
85
|
const close = () => {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
handler.addNotificationListener(notificationListener);
|
|
111
|
-
for (const entry of handler.queue) {
|
|
112
|
-
addNotification(entry);
|
|
86
|
+
if (isOpen.value && topNotifications.length === 0) {
|
|
87
|
+
dialogEl.value!.close()
|
|
88
|
+
isOpen.value = false
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const addNotification = (entry: NotificationEntry) => {
|
|
93
|
+
if (entry.resolution === undefined) {
|
|
94
|
+
if (entry.requiresAction) {
|
|
95
|
+
topNotifications.push(entry)
|
|
96
|
+
open()
|
|
97
|
+
entry.promise.then(() => {
|
|
98
|
+
removeIfIn(topNotifications, entry)
|
|
99
|
+
close()
|
|
100
|
+
})
|
|
101
|
+
} else {
|
|
102
|
+
notifications.splice(0, 0, entry)
|
|
103
|
+
entry.promise.then(() => {
|
|
104
|
+
removeIfIn(notifications, entry)
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const notificationListener = (entry: NotificationEntry, type: "added" | "resolved" | "deleted"): void => {
|
|
111
|
+
if (type === "added") {
|
|
112
|
+
addNotification(entry)
|
|
113
|
+
}
|
|
113
114
|
}
|
|
115
|
+
|
|
116
|
+
const handler = props.handler ?? useNotificationHandler()
|
|
117
|
+
|
|
118
|
+
handler.addNotificationListener(notificationListener)
|
|
119
|
+
|
|
120
|
+
for (const entry of handler.queue) { addNotification(entry) }
|
|
114
121
|
onBeforeUnmount(() => {
|
|
115
|
-
|
|
116
|
-
})
|
|
122
|
+
handler.removeNotificationListener(notificationListener)
|
|
123
|
+
})
|
|
124
|
+
|
|
117
125
|
</script>
|
|
126
|
+
<script lang="ts">
|
|
118
127
|
|
|
119
|
-
|
|
128
|
+
type RealProps =
|
|
129
|
+
& LinkableByIdProps
|
|
130
|
+
& {
|
|
131
|
+
/** If not provided, uses the global handler (this requires useNotificationHandler be called and configured). */
|
|
132
|
+
handler?: NotificationHandler
|
|
133
|
+
}
|
|
120
134
|
|
|
135
|
+
interface Props
|
|
136
|
+
extends
|
|
137
|
+
/** @vue-ignore */
|
|
138
|
+
Partial<Omit<HTMLAttributes,"class"> & TailwindClassProp>,
|
|
139
|
+
RealProps
|
|
140
|
+
{}
|
|
121
141
|
</script>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ref } from "vue";
|
|
2
|
+
import LibPagination from "./LibPagination.vue";
|
|
3
|
+
import * as components from "../index.js";
|
|
4
|
+
const meta = {
|
|
5
|
+
component: LibPagination,
|
|
6
|
+
title: "Components/Pagination",
|
|
7
|
+
args: {
|
|
8
|
+
total: 10
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
export default meta;
|
|
12
|
+
export const Primary = {
|
|
13
|
+
render: (args) => ({
|
|
14
|
+
components,
|
|
15
|
+
setup() {
|
|
16
|
+
const num = ref(1);
|
|
17
|
+
const changePage = ($event, i) => {
|
|
18
|
+
$event.preventDefault();
|
|
19
|
+
if (i >= 10) num.value = 10;
|
|
20
|
+
if (i <= 1) num.value = 1;
|
|
21
|
+
num.value = i;
|
|
22
|
+
};
|
|
23
|
+
return {
|
|
24
|
+
changePage,
|
|
25
|
+
args,
|
|
26
|
+
num
|
|
27
|
+
};
|
|
28
|
+
},
|
|
29
|
+
template: `
|
|
30
|
+
<lib-pagination v-bind="{...args, current: num, route:'#'}">
|
|
31
|
+
<template #link="linkProps">
|
|
32
|
+
<a v-bind="linkProps" @click="changePage($event, linkProps.i)">{{ linkProps.text ?? linkProps.i }}</a>
|
|
33
|
+
</template>
|
|
34
|
+
</lib-pagination>
|
|
35
|
+
<lib-simple-input :label="'Change Page'" :modelValue="num.toString()" @update:modelValue="num = parseInt($event)" type="number" min="0" :max="args.total">
|
|
36
|
+
|
|
37
|
+
</lib-simple-input>
|
|
38
|
+
`
|
|
39
|
+
})
|
|
40
|
+
};
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
:class="twMerge(`
|
|
4
4
|
pagination--wrapper
|
|
5
5
|
flex flex-wrap items-center justify-center gap-2
|
|
6
|
-
`, $attrs.class)"
|
|
6
|
+
`, ($attrs as any).class)"
|
|
7
7
|
role="navigation"
|
|
8
8
|
:aria-label="t('pagination.aria')"
|
|
9
9
|
>
|
|
@@ -12,13 +12,13 @@
|
|
|
12
12
|
:i="prevLink.i"
|
|
13
13
|
:href="prevLink.href"
|
|
14
14
|
:text="t('pagination.previous-page')"
|
|
15
|
-
:aria-label="t('pagination.aria.go-to-previous-page',
|
|
15
|
+
:aria-label=" t('pagination.aria.go-to-previous-page',{count:prevLink.i})"
|
|
16
16
|
:class="`pagination--link ${pageClasses}`"
|
|
17
17
|
>
|
|
18
18
|
<a
|
|
19
19
|
:class="`pagination--link ${pageClasses}`"
|
|
20
20
|
:href="prevLink.href"
|
|
21
|
-
:aria-label="t('pagination.aria.go-to-previous-page', {
|
|
21
|
+
:aria-label=" t('pagination.aria.go-to-previous-page', {count:prevLink.i})"
|
|
22
22
|
/>
|
|
23
23
|
</slot>
|
|
24
24
|
<div class="pagination--spacer flex-1"/>
|
|
@@ -27,14 +27,14 @@
|
|
|
27
27
|
:i="0"
|
|
28
28
|
:href="firstLink.href"
|
|
29
29
|
:text="firstLink.i"
|
|
30
|
-
:aria-label="t('pagination.aria.go-to-page', {
|
|
30
|
+
:aria-label="t('pagination.aria.go-to-page', {count:firstLink.i})"
|
|
31
31
|
:class="`pagination--link pagination--first-link ${pageClasses}`"
|
|
32
32
|
>
|
|
33
33
|
{{ firstLink.href }}
|
|
34
34
|
<a
|
|
35
35
|
:class="`pagination--link pagination--first-link ${pageClasses}`"
|
|
36
36
|
:href="firstLink.href"
|
|
37
|
-
:aria-label="t('pagination.aria.go-to-page', {
|
|
37
|
+
:aria-label="t('pagination.aria.go-to-page', {count:firstLink.i})"
|
|
38
38
|
>
|
|
39
39
|
{{ firstLink.i }}
|
|
40
40
|
</a>
|
|
@@ -50,12 +50,12 @@
|
|
|
50
50
|
:class="`pagination--link ${pageClasses}`"
|
|
51
51
|
:i="entry.i"
|
|
52
52
|
:href="entry.href"
|
|
53
|
-
:aria-label="t('pagination.aria.go-to-page', {
|
|
53
|
+
:aria-label="t('pagination.aria.go-to-page', {count:entry.i})"
|
|
54
54
|
>
|
|
55
55
|
<a
|
|
56
56
|
:class="`pagination--link ${pageClasses}`"
|
|
57
57
|
:href="entry.href"
|
|
58
|
-
:aria-label="t('pagination.aria.go-to-page', {
|
|
58
|
+
:aria-label="t('pagination.aria.go-to-page', {count:entry.i})"
|
|
59
59
|
>
|
|
60
60
|
{{ entry.i }}
|
|
61
61
|
</a>
|
|
@@ -65,12 +65,12 @@
|
|
|
65
65
|
:class="`pagination--link ${currentPageClasses}`"
|
|
66
66
|
tabindex="0"
|
|
67
67
|
:i="currentLink.i"
|
|
68
|
-
:aria-label="t('pagination.aria.current-page', {
|
|
68
|
+
:aria-label="t('pagination.aria.current-page', {count:currentLink.i})"
|
|
69
69
|
:aria_current="true"
|
|
70
70
|
>
|
|
71
71
|
<div :class="`pagination--current-page a ${currentPageClasses}`"
|
|
72
72
|
tabindex="0"
|
|
73
|
-
:aria-label="t('pagination.aria.current-page', {
|
|
73
|
+
:aria-label="t('pagination.aria.current-page', {count:currentLink.i})"
|
|
74
74
|
aria-current="true"
|
|
75
75
|
@click="$event.preventDefault()"
|
|
76
76
|
>
|
|
@@ -85,12 +85,12 @@
|
|
|
85
85
|
:class="`pagination--link ${pageClasses}`"
|
|
86
86
|
:i="entry.i"
|
|
87
87
|
:href="entry.href"
|
|
88
|
-
:aria-label="t('pagination.aria.go-to-page', {
|
|
88
|
+
:aria-label="t('pagination.aria.go-to-page', {count:entry.i})"
|
|
89
89
|
>
|
|
90
90
|
<a
|
|
91
91
|
:class="`pagination--link ${pageClasses}`"
|
|
92
92
|
:href="entry.href"
|
|
93
|
-
:aria-label="t('pagination.aria.go-to-page', {
|
|
93
|
+
:aria-label="t('pagination.aria.go-to-page', {count:entry.i})"
|
|
94
94
|
>
|
|
95
95
|
{{ entry.i }}
|
|
96
96
|
</a>
|
|
@@ -105,12 +105,12 @@
|
|
|
105
105
|
:i="lastLink.i"
|
|
106
106
|
:href="lastLink.href"
|
|
107
107
|
:text="total"
|
|
108
|
-
:aria-label="t('pagination.aria.go-to-page', {
|
|
108
|
+
:aria-label="t('pagination.aria.go-to-page', {count:lastLink.i})"
|
|
109
109
|
>
|
|
110
110
|
<a
|
|
111
111
|
:class="`pagination--link ${pageClasses}`"
|
|
112
112
|
:href="lastLink.href"
|
|
113
|
-
:aria-label="t('pagination.aria.go-to-page', {
|
|
113
|
+
:aria-label="t('pagination.aria.go-to-page', {count:lastLink.i})"
|
|
114
114
|
>
|
|
115
115
|
{{ total }}
|
|
116
116
|
</a>
|
|
@@ -123,25 +123,27 @@
|
|
|
123
123
|
:i="nextLink.i"
|
|
124
124
|
:href="nextLink.href"
|
|
125
125
|
:text="t('pagination.next-page')"
|
|
126
|
-
:aria-label="t('pagination.aria.go-to-next-page', {
|
|
126
|
+
:aria-label="t('pagination.aria.go-to-next-page', {count:nextLink.i})"
|
|
127
127
|
>
|
|
128
128
|
<a
|
|
129
129
|
:class="`pagination--link ${pageClasses}`"
|
|
130
130
|
:href="nextLink.href"
|
|
131
|
-
:aria-label="t('pagination.aria.go-to-next-page', {
|
|
131
|
+
:aria-label="t('pagination.aria.go-to-next-page', {count:nextLink.i})"
|
|
132
132
|
>
|
|
133
133
|
Next
|
|
134
134
|
</a>
|
|
135
135
|
</slot>
|
|
136
136
|
</nav>
|
|
137
137
|
</template>
|
|
138
|
+
<script setup lang="ts">
|
|
139
|
+
import { computed, type HTMLAttributes,useAttrs,watch } from "vue"
|
|
140
|
+
|
|
141
|
+
import { useInjectedI18n } from "../../composables/useInjectedI18n.js"
|
|
142
|
+
import { twMerge } from "../../utils/twMerge.js"
|
|
143
|
+
import { type TailwindClassProp } from "../shared/props.js"
|
|
144
|
+
|
|
145
|
+
const t = useInjectedI18n()
|
|
138
146
|
|
|
139
|
-
<script setup>
|
|
140
|
-
import { computed, useAttrs, watch } from "vue";
|
|
141
|
-
import { useInjectedI18n } from "../../composables/useInjectedI18n.js";
|
|
142
|
-
import { twMerge } from "../../utils/twMerge.js";
|
|
143
|
-
import {} from "../shared/props.js";
|
|
144
|
-
const t = useInjectedI18n();
|
|
145
147
|
const commonClasses = `
|
|
146
148
|
block
|
|
147
149
|
focus-outline
|
|
@@ -149,68 +151,110 @@ const commonClasses = `
|
|
|
149
151
|
border-transparent
|
|
150
152
|
transition-all
|
|
151
153
|
outlined:rounded-sm
|
|
152
|
-
|
|
154
|
+
`
|
|
153
155
|
const pageClasses = `
|
|
154
156
|
${commonClasses}
|
|
155
157
|
focus-outline
|
|
156
158
|
hover:text-accent-600
|
|
157
159
|
hover:border-b-accent-500
|
|
158
160
|
hover:scale-125
|
|
159
|
-
|
|
161
|
+
`
|
|
162
|
+
|
|
160
163
|
const currentPageClasses = `
|
|
161
164
|
${commonClasses}
|
|
162
165
|
border-b-accent-500
|
|
163
166
|
scale-125
|
|
164
|
-
|
|
167
|
+
`
|
|
165
168
|
defineOptions({
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const
|
|
183
|
-
const
|
|
184
|
-
|
|
169
|
+
name: "lib-pagination",
|
|
170
|
+
inheritAttrs: false,
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
174
|
+
customRoute: (route: string, i: number) => {
|
|
175
|
+
if (i === 0 || i === 1) {
|
|
176
|
+
const num = 1
|
|
177
|
+
return { href: route, i: num }
|
|
178
|
+
}
|
|
179
|
+
return { href: route + i.toString(), i }
|
|
180
|
+
},
|
|
181
|
+
extraPages: 3,
|
|
182
|
+
})
|
|
183
|
+
const $attrs = useAttrs()
|
|
184
|
+
|
|
185
|
+
const currentLink = computed(() => props.customRoute(props.route, props.current))
|
|
186
|
+
const currentIsInvalid = computed(() => currentLink.value.i < 0 || currentLink.value.i > props.total)
|
|
187
|
+
|
|
185
188
|
watch(() => currentIsInvalid.value, () => {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
})
|
|
190
|
-
|
|
189
|
+
if (currentIsInvalid.value) {
|
|
190
|
+
throw new Error(`Current page is out of range: 0 - ${props.total}`)
|
|
191
|
+
}
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
const prevLink = computed(() => props.customRoute(props.route, props.current - 1))
|
|
195
|
+
|
|
191
196
|
const nextLink = computed(() => {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
})
|
|
198
|
-
|
|
199
|
-
const
|
|
197
|
+
const maybeNextLink = props.customRoute(props.route, props.current + 1)
|
|
198
|
+
if (maybeNextLink.i === currentLink.value.i) {
|
|
199
|
+
return props.customRoute(props.route, props.current + 2)
|
|
200
|
+
}
|
|
201
|
+
return maybeNextLink
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
const firstLink = computed(() => props.customRoute(props.route, 0))
|
|
205
|
+
const lastLink = computed(() => props.customRoute(props.route, props.total))
|
|
206
|
+
|
|
207
|
+
type HrefInfo = { href: string, i: number }
|
|
200
208
|
const extraPagesPrev = computed(() => [...Array(props.extraPages)].map((_, _i) => {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
}).filter(
|
|
209
|
+
const num = currentLink.value.i - (props.extraPages - _i)
|
|
210
|
+
if (num <= firstLink.value.i || num >= lastLink.value.i || num >= currentLink.value.i) return undefined
|
|
211
|
+
return props.customRoute(props.route, num)
|
|
212
|
+
}).filter(entry => entry !== undefined) as HrefInfo[])
|
|
213
|
+
|
|
205
214
|
const extraPagesNext = computed(() => [...Array(props.extraPages + 1)].map((_, i) => {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}).filter(
|
|
215
|
+
const num = currentLink.value.i + i
|
|
216
|
+
if (num <= firstLink.value.i || num >= lastLink.value.i || num <= currentLink.value.i) return undefined
|
|
217
|
+
return props.customRoute(props.route, num)
|
|
218
|
+
}).filter(entry => entry !== undefined).slice(0, props.extraPages) as HrefInfo[])
|
|
219
|
+
|
|
210
220
|
</script>
|
|
221
|
+
<script lang="ts">
|
|
211
222
|
|
|
212
|
-
|
|
223
|
+
/**
|
|
224
|
+
* Pagination component.
|
|
225
|
+
*
|
|
226
|
+
* Can be passed a slot like so to use a custom link element (like NuxtLink):
|
|
227
|
+
* ```vue
|
|
228
|
+
* <template #link="{ href, i, text, ariaLabel, ariaCurrent}">
|
|
229
|
+
* <NuxtLink :to="href" :aria-label="ariaLabel" :aria-current="ariaCurrent ?? false">{{ text ?? i }}</NuxtLink>
|
|
230
|
+
* </template>
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
213
233
|
export default {
|
|
214
|
-
|
|
215
|
-
}
|
|
234
|
+
name: "lib-pagination",
|
|
235
|
+
}
|
|
236
|
+
type RealProps = {
|
|
237
|
+
/** The total number of pages. */
|
|
238
|
+
total: number
|
|
239
|
+
/** The number of the current page. It must be valid, between 0 - total or the component will throw an error. */
|
|
240
|
+
current: number
|
|
241
|
+
/** The base route/link path for the page. Should end with a forward slash `/`. */
|
|
242
|
+
route: string
|
|
243
|
+
/**
|
|
244
|
+
* A function to customize the output href and page link number. By default, page 0 is page 1, page 1 is 1, then everything else is normal.
|
|
245
|
+
*
|
|
246
|
+
* This is because usually we have routes like: `/page/1`, `/page/2`, not `/page/0`.
|
|
247
|
+
*
|
|
248
|
+
* You can use this function to customize things further. For example, make `/page/1` just `/`
|
|
249
|
+
*/
|
|
250
|
+
customRoute?: (route: string, i: number) => { i: number, href: string }
|
|
251
|
+
/** How many extra pages to show to each side of the current page. */
|
|
252
|
+
extraPages?: number
|
|
253
|
+
}
|
|
254
|
+
interface Props
|
|
255
|
+
extends
|
|
256
|
+
/** @vue-ignore */
|
|
257
|
+
Partial<Omit<HTMLAttributes,"class"> & TailwindClassProp>,
|
|
258
|
+
RealProps
|
|
259
|
+
{}
|
|
216
260
|
</script>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import LibPalette from "./LibPalette.vue";
|
|
2
|
+
import { theme } from "../../theme.js";
|
|
3
|
+
import * as components from "../index.js";
|
|
4
|
+
const meta = {
|
|
5
|
+
component: LibPalette,
|
|
6
|
+
title: "Components/Palette",
|
|
7
|
+
args: {
|
|
8
|
+
// theme,
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
export default meta;
|
|
12
|
+
export const Primary = {
|
|
13
|
+
render: (args) => ({
|
|
14
|
+
components: { ...components, LibPalette },
|
|
15
|
+
setup: () => ({ args: { ...args, theme } }),
|
|
16
|
+
template: `
|
|
17
|
+
<LibPalette v-bind="{...args}">{{args.value}}</LibPalette>
|
|
18
|
+
`
|
|
19
|
+
})
|
|
20
|
+
};
|