@sparklingopinions/sparkling-ui 0.7.0 → 0.8.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 +2 -2
- package/dist/aliases.d.ts +23 -2
- package/dist/components/Button/Button.js.map +1 -1
- package/dist/components/Button/Button.vue.d.ts +4 -0
- package/dist/components/Button/Button.vue_vue_type_script_setup_true_lang.js +21 -11
- package/dist/components/Button/Button.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
- package/dist/components/ContextMenu/ContextMenu.vue_vue_type_script_setup_true_lang.js +29 -20
- package/dist/components/ContextMenu/ContextMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/DataList/DataList.js.map +1 -1
- package/dist/components/DataList/DataList.vue.d.ts +30 -3
- package/dist/components/DataList/DataList.vue_vue_type_script_setup_true_lang.js +188 -100
- package/dist/components/DataList/DataList.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/DataList/types.d.ts +2 -0
- package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.vue_vue_type_script_setup_true_lang.js +32 -23
- package/dist/components/DropdownMenu/DropdownMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/Icon/iconSet.js +1 -0
- package/dist/components/Icon/iconSet.js.map +1 -1
- package/dist/components/Popover/PopoverDialog.js +7 -0
- package/dist/components/Popover/PopoverDialog.js.map +1 -0
- package/dist/components/Popover/PopoverDialog.vue.d.ts +56 -0
- package/dist/components/Popover/PopoverDialog.vue_vue_type_script_setup_true_lang.js +158 -0
- package/dist/components/Popover/PopoverDialog.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/Popover/index.d.ts +2 -0
- package/dist/components/Table/Table.js.map +1 -1
- package/dist/components/Table/Table.vue.d.ts +2 -0
- package/dist/components/Table/Table.vue_vue_type_script_setup_true_lang.js +5 -1
- package/dist/components/Table/Table.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/Tag/Tag.js.map +1 -1
- package/dist/components/Tag/Tag.vue.d.ts +3 -0
- package/dist/components/Tag/Tag.vue_vue_type_script_setup_true_lang.js +3 -2
- package/dist/components/Tag/Tag.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/Toast/Toaster.js.map +1 -1
- package/dist/components/Toast/Toaster.vue.d.ts +4 -0
- package/dist/components/Toast/Toaster.vue_vue_type_script_setup_true_lang.js +49 -32
- package/dist/components/Toast/Toaster.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/Toolbar/Toolbar.js +7 -0
- package/dist/components/Toolbar/Toolbar.js.map +1 -0
- package/dist/components/Toolbar/Toolbar.vue.d.ts +23 -0
- package/dist/components/Toolbar/Toolbar.vue_vue_type_script_setup_true_lang.js +52 -0
- package/dist/components/Toolbar/Toolbar.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/Toolbar/index.d.ts +2 -0
- package/dist/components/internal/MenuItemContent.js.map +1 -1
- package/dist/components/internal/MenuItemContent.vue.d.ts +1 -0
- package/dist/components/internal/MenuItemContent.vue_vue_type_script_setup_true_lang.js +30 -14
- package/dist/components/internal/MenuItemContent.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/internal/menu.d.ts +5 -1
- package/dist/components/internal/menu.js +17 -14
- package/dist/components/internal/menu.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +18 -16
- package/package.json +1 -1
- package/src/styles/tailwind.css +22 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import e from "../Button/Button.js";
|
|
2
|
+
import t from "../Dialog/Dialog.js";
|
|
3
|
+
import { useCustomTrigger as n } from "../Filters/trigger.js";
|
|
4
|
+
import { Fragment as r, computed as i, createBlock as a, createCommentVNode as o, createElementBlock as s, createElementVNode as c, createSlots as l, createTextVNode as u, createVNode as d, defineComponent as f, mergeModels as p, normalizeStyle as m, onBeforeUnmount as h, openBlock as g, ref as _, renderSlot as v, shallowRef as y, toDisplayString as b, toValue as x, unref as S, useModel as C, useSlots as w, watch as T, withCtx as E, withKeys as D, withModifiers as O } from "vue";
|
|
5
|
+
import { PopoverAnchor as k, PopoverContent as A, PopoverPortal as j, PopoverRoot as M } from "reka-ui";
|
|
6
|
+
//#region src/components/Popover/PopoverDialog.vue?vue&type=script&setup=true&lang.ts
|
|
7
|
+
var N = { class: "m-0 text-sm font-semibold text-sui-ink" }, P = {
|
|
8
|
+
key: 0,
|
|
9
|
+
class: "flex items-center justify-end gap-2 pt-0.5"
|
|
10
|
+
}, F = /*@__PURE__*/ f({
|
|
11
|
+
__name: "PopoverDialog",
|
|
12
|
+
props: /*@__PURE__*/ p({
|
|
13
|
+
title: {},
|
|
14
|
+
anchor: { default: void 0 },
|
|
15
|
+
width: { default: 320 },
|
|
16
|
+
confirmLabel: { default: void 0 },
|
|
17
|
+
confirmDisabled: { type: Boolean },
|
|
18
|
+
cancelLabel: { default: "Cancel" },
|
|
19
|
+
closeLabel: { default: "Close" },
|
|
20
|
+
sheetBelow: { default: 640 }
|
|
21
|
+
}, {
|
|
22
|
+
open: {
|
|
23
|
+
type: Boolean,
|
|
24
|
+
default: !1
|
|
25
|
+
},
|
|
26
|
+
openModifiers: {}
|
|
27
|
+
}),
|
|
28
|
+
emits: /*@__PURE__*/ p(["confirm", "cancel"], ["update:open"]),
|
|
29
|
+
setup(f, { emit: p }) {
|
|
30
|
+
let F = f, I = p, L = C(f, "open"), R = w(), z = n(L), B = y(null), V = i(() => ({
|
|
31
|
+
...z.props.value,
|
|
32
|
+
ref: (e) => {
|
|
33
|
+
z.props.value.ref(e), B.value = e instanceof Element ? e : e?.$el ?? null;
|
|
34
|
+
}
|
|
35
|
+
})), H = i(() => {
|
|
36
|
+
let e = x(F.anchor);
|
|
37
|
+
return e instanceof Element ? e : e?.$el ?? B.value ?? void 0;
|
|
38
|
+
}), U = _(!1), W, G = () => U.value = !!W?.matches;
|
|
39
|
+
T(() => F.sheetBelow, (e) => {
|
|
40
|
+
W?.removeEventListener("change", G), W = typeof window < "u" && window.matchMedia ? window.matchMedia(`(max-width: ${e - .02}px)`) : void 0, W?.addEventListener("change", G), G();
|
|
41
|
+
}, { immediate: !0 }), h(() => W?.removeEventListener("change", G));
|
|
42
|
+
let K = i(() => U.value ? "sheet" : H.value ? "popover" : "dialog"), q = null, J = !1;
|
|
43
|
+
T(L, (e) => {
|
|
44
|
+
if (!e) return;
|
|
45
|
+
let t = document.activeElement;
|
|
46
|
+
q = t && t !== document.body ? t : null, J = !1;
|
|
47
|
+
});
|
|
48
|
+
function Y() {
|
|
49
|
+
I("cancel"), L.value = !1;
|
|
50
|
+
}
|
|
51
|
+
function X(e) {
|
|
52
|
+
e.preventDefault();
|
|
53
|
+
let t = e.target.querySelector("[role=\"dialog\"]") ?? e.target;
|
|
54
|
+
(t.querySelector("[autofocus]") ?? t).focus();
|
|
55
|
+
}
|
|
56
|
+
function Z(e) {
|
|
57
|
+
e.preventDefault(), !J && (q?.isConnected ? q : H.value)?.focus();
|
|
58
|
+
}
|
|
59
|
+
function Q(e) {
|
|
60
|
+
let t = e.detail.originalEvent.target;
|
|
61
|
+
t instanceof Node && B.value?.contains(t) ? e.preventDefault() : (J = !0, I("cancel"));
|
|
62
|
+
}
|
|
63
|
+
function $(e) {
|
|
64
|
+
(e.metaKey || e.ctrlKey) && (e.preventDefault(), F.confirmLabel && !F.confirmDisabled && I("confirm"));
|
|
65
|
+
}
|
|
66
|
+
let ee = i(() => typeof F.width == "number" ? `${F.width}px` : F.width);
|
|
67
|
+
return (n, i) => (g(), s(r, null, [S(R).trigger ? v(n.$slots, "trigger", {
|
|
68
|
+
open: L.value,
|
|
69
|
+
props: V.value
|
|
70
|
+
}, void 0, void 0, 0) : o("", !0), K.value === "popover" ? (g(), a(S(M), {
|
|
71
|
+
key: 1,
|
|
72
|
+
open: L.value,
|
|
73
|
+
"onUpdate:open": i[3] ||= (e) => L.value = e
|
|
74
|
+
}, {
|
|
75
|
+
default: E(() => [d(S(k), { reference: H.value }, null, 8, ["reference"]), d(S(j), null, {
|
|
76
|
+
default: E(() => [d(S(A), {
|
|
77
|
+
align: "start",
|
|
78
|
+
"aria-label": f.title,
|
|
79
|
+
class: "z-[1100] flex max-h-(--reka-popover-content-available-height) flex-col gap-2.5 overflow-y-auto rounded-lg border border-sui-line-subtle bg-sui-surface px-4 py-3.5 text-sm text-sui-ink shadow-xl outline-hidden data-[state=closed]:animate-sui-overlay-out data-[state=open]:animate-sui-overlay-in",
|
|
80
|
+
"collision-padding": 8,
|
|
81
|
+
"data-sui-panel": S(z).panelKey,
|
|
82
|
+
role: "dialog",
|
|
83
|
+
side: "bottom",
|
|
84
|
+
"side-offset": 4,
|
|
85
|
+
style: m({ width: ee.value }),
|
|
86
|
+
onCloseAutoFocus: Z,
|
|
87
|
+
onEscapeKeyDown: i[1] ||= (e) => I("cancel"),
|
|
88
|
+
onFocusOutside: i[2] ||= O(() => {}, ["prevent"]),
|
|
89
|
+
onKeydown: D($, ["enter"]),
|
|
90
|
+
onOpenAutoFocus: X,
|
|
91
|
+
onPointerDownOutside: Q
|
|
92
|
+
}, {
|
|
93
|
+
default: E(() => [
|
|
94
|
+
c("h2", N, b(f.title), 1),
|
|
95
|
+
v(n.$slots, "default"),
|
|
96
|
+
n.$slots.footer || f.confirmLabel ? (g(), s("div", P, [v(n.$slots, "footer", {}, () => [d(e, {
|
|
97
|
+
size: "sm",
|
|
98
|
+
type: "button",
|
|
99
|
+
variant: "ghost",
|
|
100
|
+
onClick: Y
|
|
101
|
+
}, {
|
|
102
|
+
default: E(() => [u(b(f.cancelLabel), 1)]),
|
|
103
|
+
_: 1
|
|
104
|
+
}), d(e, {
|
|
105
|
+
disabled: f.confirmDisabled,
|
|
106
|
+
size: "sm",
|
|
107
|
+
type: "button",
|
|
108
|
+
variant: "primary",
|
|
109
|
+
onClick: i[0] ||= (e) => I("confirm")
|
|
110
|
+
}, {
|
|
111
|
+
default: E(() => [u(b(f.confirmLabel), 1)]),
|
|
112
|
+
_: 1
|
|
113
|
+
}, 8, ["disabled"])])])) : o("", !0)
|
|
114
|
+
]),
|
|
115
|
+
_: 3
|
|
116
|
+
}, 8, [
|
|
117
|
+
"aria-label",
|
|
118
|
+
"data-sui-panel",
|
|
119
|
+
"style"
|
|
120
|
+
])]),
|
|
121
|
+
_: 3
|
|
122
|
+
})]),
|
|
123
|
+
_: 3
|
|
124
|
+
}, 8, ["open"])) : (g(), a(t, {
|
|
125
|
+
key: 2,
|
|
126
|
+
open: L.value,
|
|
127
|
+
"onUpdate:open": i[4] ||= (e) => L.value = e,
|
|
128
|
+
"cancel-label": f.cancelLabel,
|
|
129
|
+
"close-label": f.closeLabel,
|
|
130
|
+
"confirm-disabled": f.confirmDisabled,
|
|
131
|
+
"confirm-label": f.confirmLabel,
|
|
132
|
+
presentation: K.value === "sheet" ? "sheet" : "dialog",
|
|
133
|
+
size: "sm",
|
|
134
|
+
title: f.title,
|
|
135
|
+
onCancel: i[5] ||= (e) => I("cancel"),
|
|
136
|
+
onConfirm: i[6] ||= (e) => I("confirm")
|
|
137
|
+
}, l({
|
|
138
|
+
default: E(() => [v(n.$slots, "default")]),
|
|
139
|
+
_: 2
|
|
140
|
+
}, [n.$slots.footer ? {
|
|
141
|
+
name: "footer",
|
|
142
|
+
fn: E(() => [v(n.$slots, "footer")]),
|
|
143
|
+
key: "0"
|
|
144
|
+
} : void 0]), 1032, [
|
|
145
|
+
"open",
|
|
146
|
+
"cancel-label",
|
|
147
|
+
"close-label",
|
|
148
|
+
"confirm-disabled",
|
|
149
|
+
"confirm-label",
|
|
150
|
+
"presentation",
|
|
151
|
+
"title"
|
|
152
|
+
]))], 64));
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
//#endregion
|
|
156
|
+
export { F as default };
|
|
157
|
+
|
|
158
|
+
//# sourceMappingURL=PopoverDialog.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PopoverDialog.vue_vue_type_script_setup_true_lang.js","names":["$slots","_useModel","_openBlock","_createElementBlock","_Fragment","_unref","_renderSlot","_createCommentVNode","_createBlock","_withCtx","_createVNode","_normalizeStyle","_withModifiers","_withKeys","_createElementVNode","_toDisplayString","Button","_createTextVNode","Dialog","_createSlots","Button_default","Dialog_default","_hoisted_1","_hoisted_2","PopoverDialog_vue_vue_type_script_setup_true_lang_default","\"open\"","\"openModifiers\"","__emit","props","__props","emit","open","useModel","slots","useSlots","trigger","useCustomTrigger","triggerElement","shallowRef","triggerProps","computed","node","anchorElement","value","toValue","narrow","ref","query","onQuery","watch","below","onBeforeUnmount","presentation","returnTo","pressedOutside","isOpen","active","cancel","onOpenAutoFocus","panel","event","onCloseAutoFocus","onPointerDownOutside","target","confirmFromKeyboard","panelWidth","openBlock","createElementBlock","Fragment","unref","renderSlot","_ctx","createCommentVNode","createBlock","PopoverRoot","_cache","$event","withCtx","createVNode","PopoverAnchor","PopoverPortal","PopoverContent","normalizeStyle","withModifiers","withKeys","createElementVNode","toDisplayString","createTextVNode","createSlots"],"sources":["../../../src/components/Popover/PopoverDialog.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n type ComponentPublicInstance,\n type MaybeRef,\n computed,\n onBeforeUnmount,\n ref,\n shallowRef,\n toValue,\n useSlots,\n watch\n} from 'vue'\n\nimport { PopoverAnchor, PopoverContent, PopoverPortal, PopoverRoot } from 'reka-ui'\n\nimport Button from '../Button/Button.vue'\nimport Dialog from '../Dialog/Dialog.vue'\nimport { type FilterTriggerProps, useCustomTrigger } from '../Filters/trigger'\n\nexport type PopoverDialogTriggerProps = FilterTriggerProps\n\nexport interface PopoverDialogProps {\n title: string\n /** What it opens under on the desktop: an element, a component, or a ref to one. Without it, the `trigger` slot. */\n anchor?: MaybeRef<HTMLElement | ComponentPublicInstance | null | undefined>\n /** The popover's width in px, or a CSS width. */\n width?: number | string\n /** Shows Cancel and this confirm button in the footer; it emits `confirm`, as ⌘ or Ctrl Enter does. */\n confirmLabel?: string\n confirmDisabled?: boolean\n cancelLabel?: string\n closeLabel?: string\n /** The viewport width in px below which it's a bottom sheet. */\n sheetBelow?: number\n}\n\nconst props = withDefaults(defineProps<PopoverDialogProps>(), {\n anchor: undefined,\n width: 320,\n confirmLabel: undefined,\n cancelLabel: 'Cancel',\n closeLabel: 'Close',\n sheetBelow: 640\n})\n\nconst emit = defineEmits<{ confirm: []; cancel: [] }>()\n\nconst open = defineModel<boolean>('open', { default: false })\n\ndefineSlots<{\n default?: () => unknown\n /** Replaces Cancel and the confirm button. */\n footer?: () => unknown\n /** The opener, when there's no `anchor`: spread `props` on your button. */\n trigger?: (props: { props: PopoverDialogTriggerProps; open: boolean }) => unknown\n}>()\n\nconst slots = useSlots()\nconst trigger = useCustomTrigger(open)\nconst triggerElement = shallowRef<HTMLElement | null>(null)\nconst triggerProps = computed<PopoverDialogTriggerProps>(() => ({\n ...trigger.props.value,\n ref: (node) => {\n trigger.props.value.ref(node)\n triggerElement.value = node instanceof Element ? (node as HTMLElement) : ((node?.$el as HTMLElement) ?? null)\n }\n}))\n\nconst anchorElement = computed(() => {\n const value = toValue(props.anchor)\n if (value instanceof Element) return value as HTMLElement\n return (value?.$el as HTMLElement | undefined) ?? triggerElement.value ?? undefined\n})\n\nconst narrow = ref(false)\nlet query: MediaQueryList | undefined\nconst onQuery = () => (narrow.value = !!query?.matches)\nwatch(\n () => props.sheetBelow,\n (below) => {\n query?.removeEventListener('change', onQuery)\n query =\n typeof window !== 'undefined' && window.matchMedia\n ? window.matchMedia(`(max-width: ${below - 0.02}px)`)\n : undefined\n query?.addEventListener('change', onQuery)\n onQuery()\n },\n { immediate: true }\n)\nonBeforeUnmount(() => query?.removeEventListener('change', onQuery))\n\n// A popover needs something to sit under; without one it's a small dialog, and on a phone always a sheet.\nconst presentation = computed(() => (narrow.value ? 'sheet' : anchorElement.value ? 'popover' : 'dialog'))\n\n// Focus goes back to what had it when it opened (a row opened by a shortcut, a button), else the anchor; a press\n// outside leaves it where it landed.\nlet returnTo: HTMLElement | null = null\nlet pressedOutside = false\nwatch(open, (isOpen) => {\n if (!isOpen) return\n const active = document.activeElement as HTMLElement | null\n returnTo = active && active !== document.body ? active : null\n pressedOutside = false\n})\n\nfunction cancel() {\n emit('cancel')\n open.value = false\n}\n\nfunction onOpenAutoFocus(event: Event) {\n event.preventDefault()\n const panel =\n (event.target as HTMLElement).querySelector<HTMLElement>('[role=\"dialog\"]') ?? (event.target as HTMLElement)\n ;(panel.querySelector<HTMLElement>('[autofocus]') ?? panel).focus()\n}\n\nfunction onCloseAutoFocus(event: Event) {\n event.preventDefault()\n if (pressedOutside) return\n const target = returnTo?.isConnected ? returnTo : anchorElement.value\n target?.focus()\n}\n\nfunction onPointerDownOutside(event: CustomEvent<{ originalEvent: PointerEvent }>) {\n const target = event.detail.originalEvent.target\n if (target instanceof Node && triggerElement.value?.contains(target)) {\n event.preventDefault()\n return\n }\n pressedOutside = true\n emit('cancel')\n}\n\nfunction confirmFromKeyboard(event: KeyboardEvent) {\n if (!event.metaKey && !event.ctrlKey) return\n event.preventDefault()\n if (props.confirmLabel && !props.confirmDisabled) emit('confirm')\n}\n\nconst panelWidth = computed(() => (typeof props.width === 'number' ? `${props.width}px` : props.width))\n</script>\n\n<!-- A small decision: a popover under its anchor on the desktop, a bottom sheet on the phone. -->\n<template>\n <slot v-if=\"slots.trigger\" name=\"trigger\" :open=\"open\" :props=\"triggerProps\" />\n <PopoverRoot v-if=\"presentation === 'popover'\" v-model:open=\"open\">\n <PopoverAnchor :reference=\"anchorElement\" />\n <PopoverPortal>\n <PopoverContent\n align=\"start\"\n :aria-label=\"title\"\n class=\"z-[1100] flex max-h-(--reka-popover-content-available-height) flex-col gap-2.5 overflow-y-auto rounded-lg border border-sui-line-subtle bg-sui-surface px-4 py-3.5 text-sm text-sui-ink shadow-xl outline-hidden data-[state=closed]:animate-sui-overlay-out data-[state=open]:animate-sui-overlay-in\"\n :collision-padding=\"8\"\n :data-sui-panel=\"trigger.panelKey\"\n role=\"dialog\"\n side=\"bottom\"\n :side-offset=\"4\"\n :style=\"{ width: panelWidth }\"\n @close-auto-focus=\"onCloseAutoFocus\"\n @escape-key-down=\"emit('cancel')\"\n @focus-outside.prevent\n @keydown.enter=\"confirmFromKeyboard\"\n @open-auto-focus=\"onOpenAutoFocus\"\n @pointer-down-outside=\"onPointerDownOutside\"\n >\n <h2 class=\"m-0 text-sm font-semibold text-sui-ink\">{{ title }}</h2>\n <slot />\n <div v-if=\"$slots.footer || confirmLabel\" class=\"flex items-center justify-end gap-2 pt-0.5\">\n <slot name=\"footer\">\n <Button size=\"sm\" type=\"button\" variant=\"ghost\" @click=\"cancel\">{{ cancelLabel }}</Button>\n <Button :disabled=\"confirmDisabled\" size=\"sm\" type=\"button\" variant=\"primary\" @click=\"emit('confirm')\">\n {{ confirmLabel }}\n </Button>\n </slot>\n </div>\n </PopoverContent>\n </PopoverPortal>\n </PopoverRoot>\n <Dialog\n v-else\n v-model:open=\"open\"\n :cancel-label=\"cancelLabel\"\n :close-label=\"closeLabel\"\n :confirm-disabled=\"confirmDisabled\"\n :confirm-label=\"confirmLabel\"\n :presentation=\"presentation === 'sheet' ? 'sheet' : 'dialog'\"\n size=\"sm\"\n :title=\"title\"\n @cancel=\"emit('cancel')\"\n @confirm=\"emit('confirm')\"\n >\n <slot />\n <template v-if=\"$slots.footer\" #footer><slot name=\"footer\" /></template>\n </Dialog>\n</template>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Table.js","names":["_sfc_main","Table_vue_vue_type_script_setup_true_lang_default","Table_default"],"sources":["../../../src/components/Table/Table.vue"],"sourcesContent":["<script setup lang=\"ts\" generic=\"T extends Record<string, any>\">\nimport { computed } from 'vue'\n\nimport Checkbox from '../Checkbox/Checkbox.vue'\nimport Skeleton from '../Skeleton/Skeleton.vue'\nimport type { TableColumn, TableSort } from './types'\n\nexport interface TableProps<T> {\n columns: TableColumn[]\n rows: T[]\n /** The row field that identifies it. */\n rowKey?: keyof T & string\n /** A checkbox column bound to `v-model:selected`; selected rows tint accent-wash. */\n selectable?: boolean\n /** Skeleton rows in place of the body. */\n loading?: boolean\n loadingRows?: number\n /** md: 57px rows. sm: 40px, for dense lists. */\n size?: 'md' | 'sm'\n /** A row height in px between the sizes, such as 44, for body and header rows; sets `--sui-table-row`. */\n rowHeight?: number\n /** canvas lays the header on the page colour, for a table directly on the canvas. */\n headerTone?: 'sunken' | 'canvas'\n /** The table's name for screen readers. */\n caption?: string\n selectAllLabel?: string\n selectRowLabel?: string\n /** Makes rows clickable (`@row-click`), e.g. to open the record. */\n onRowClick?: (row: T) => void\n}\n\nconst props = withDefaults(defineProps<TableProps<T>>(), {\n rowKey: 'id' as never,\n loadingRows: 5,\n size: 'md',\n rowHeight: undefined,\n headerTone: 'sunken',\n caption: undefined,\n selectAllLabel: 'Select all rows',\n selectRowLabel: 'Select row',\n onRowClick: undefined\n})\n\nconst sort = defineModel<TableSort | null>('sort', { default: null })\nconst selected = defineModel<unknown[]>('selected', { default: () => [] })\n\nconst slots = defineSlots<\n {\n /** Shown in place of the body when there are no rows, e.g. an EmptyState. */\n empty?: () => unknown\n /** Replaces the body when given, e.g. an inset danger Alert with a retry. */\n error?: () => unknown\n /** A canvas strip under the rows: a rows-per-page Select, the range, Pagination. */\n footer?: () => unknown\n } & {\n [K in `cell-${string}`]?: (props: { row: T; value: unknown }) => unknown\n }\n>()\n\nconst idOf = (row: T): unknown => row[props.rowKey ?? 'id']\nconst ids = computed(() => props.rows.map(idOf))\nconst allSelected = computed(() => ids.value.length > 0 && ids.value.every((id) => selected.value.includes(id)))\nconst someSelected = computed(() => !allSelected.value && ids.value.some((id) => selected.value.includes(id)))\n\nfunction toggleAll() {\n selected.value = allSelected.value\n ? selected.value.filter((id) => !ids.value.includes(id))\n : [...new Set([...selected.value, ...ids.value])]\n}\n\nfunction toggle(id: unknown) {\n selected.value = selected.value.includes(id) ? selected.value.filter((x) => x !== id) : [...selected.value, id]\n}\n\n// Sorting a column cycles ascending, descending, unsorted.\nfunction sortBy(key: string) {\n const dir = sort.value?.key === key ? sort.value.dir : null\n const next = dir === null ? 'asc' : dir === 'asc' ? 'desc' : null\n sort.value = next ? { key, dir: next } : null\n}\n\nfunction dirOf(key: string) {\n return sort.value?.key === key ? sort.value.dir : null\n}\n\nfunction ariaSort(column: TableColumn) {\n const dir = dirOf(column.key)\n if (dir) return dir === 'asc' ? 'ascending' : 'descending'\n return column.sortable ? 'none' : undefined\n}\n\nconst state = computed(() => {\n if (slots.error) return 'error'\n if (props.loading) return 'loading'\n return props.rows.length === 0 && slots.empty ? 'empty' : 'rows'\n})\n\nconst columnCount = computed(() => props.columns.length + (props.selectable ? 1 : 0))\nconst alignClass = { left: 'text-left', center: 'text-center', right: 'text-right' }\nconst skeletonWidths = ['60%', '45%', '70%', '35%', '55%']\n\nconst sm = computed(() => props.size === 'sm')\nconst fixed = computed(() => props.rowHeight !== undefined)\nconst rowStyle = computed(() => (fixed.value ? { '--sui-table-row': `${props.rowHeight}px` } : undefined))\nconst th = computed(() => [\n 'border-b border-sui-line-subtle text-13 font-medium whitespace-nowrap',\n sm.value ? 'h-[var(--sui-table-row,2.25rem)]' : 'h-[var(--sui-table-row,2.75rem)]'\n])\nconst td = computed(() => [\n 'border-b border-sui-line-subtle align-middle text-sui-ink-body group-last/row:border-b-0',\n sm.value ? 'h-[var(--sui-table-row,2.5rem)]' : 'h-[var(--sui-table-row,3.5625rem)]'\n])\n// A set row height takes the cells' vertical padding with it.\nconst pad = computed(() => [sm.value ? 'px-3' : 'px-4', !fixed.value && (sm.value ? 'py-1.5' : 'py-3')])\nconst headTone = computed(() => (props.headerTone === 'canvas' ? 'bg-sui-canvas' : 'bg-sui-sunken'))\nconst headPad = computed(() => (sm.value ? 'px-3' : 'px-4'))\nconst checkCell = 'w-12 pl-4'\n</script>\n\n<!-- A data table: sunken header strip, sortable headers, selection, loading, empty and error states, a footer. -->\n<template>\n <div\n class=\"overflow-hidden rounded-xl border border-sui-line-subtle bg-sui-surface text-sm text-sui-ink\"\n :style=\"rowStyle\"\n >\n <div class=\"overflow-x-auto\">\n <table class=\"w-full min-w-[var(--sui-table-min,720px)] table-fixed border-collapse\">\n <caption v-if=\"caption\" class=\"sr-only\">\n {{\n caption\n }}\n </caption>\n <colgroup>\n <col v-if=\"selectable\" class=\"w-12\" />\n <col\n v-for=\"column in columns\"\n :key=\"column.key\"\n :style=\"{ width: typeof column.width === 'number' ? `${column.width}px` : column.width }\"\n />\n </colgroup>\n <thead>\n <tr>\n <th v-if=\"selectable\" :class=\"[th, checkCell, headTone]\">\n <Checkbox\n :aria-label=\"selectAllLabel\"\n :disabled=\"loading || rows.length === 0\"\n :indeterminate=\"someSelected\"\n :model-value=\"allSelected\"\n @update:model-value=\"toggleAll\"\n />\n </th>\n <component\n :is=\"column.label ? 'th' : 'td'\"\n v-for=\"column in columns\"\n :key=\"column.key\"\n :aria-sort=\"ariaSort(column)\"\n :class=\"[\n th,\n headPad,\n alignClass[column.align ?? 'left'],\n dirOf(column.key) ? 'bg-sui-accent-wash text-sui-accent' : [headTone, 'text-sui-ink-subtle']\n ]\"\n :scope=\"column.label ? 'col' : undefined\"\n >\n <button\n v-if=\"column.sortable\"\n class=\"inline-flex h-full w-full items-center gap-1.5 rounded-md outline-hidden focus-visible:sui-ring-inset\"\n :class=\"[\n column.align === 'right' && 'justify-end',\n column.align === 'center' && 'justify-center',\n !dirOf(column.key) && 'hover:text-sui-ink'\n ]\"\n type=\"button\"\n @click=\"sortBy(column.key)\"\n >\n {{ column.label }}\n <svg\n aria-hidden=\"true\"\n class=\"size-3 shrink-0 fill-none stroke-current\"\n :class=\"!dirOf(column.key) && 'opacity-50'\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 12 12\"\n >\n <path v-if=\"dirOf(column.key) === 'asc'\" d=\"M3 7.5 6 4.5l3 3\" />\n <path v-else-if=\"dirOf(column.key) === 'desc'\" d=\"M3 4.5 6 7.5l3-3\" />\n <path v-else d=\"M3.5 4.5 6 2l2.5 2.5M3.5 7.5 6 10l2.5-2.5\" />\n </svg>\n </button>\n <template v-else>{{ column.label }}</template>\n </component>\n </tr>\n </thead>\n <tbody :aria-busy=\"loading || undefined\">\n <tr v-if=\"state === 'error' || state === 'empty'\">\n <td class=\"p-0\" :colspan=\"columnCount\">\n <slot :name=\"state\" />\n </td>\n </tr>\n <template v-else-if=\"state === 'loading'\">\n <tr v-for=\"i in loadingRows\" :key=\"i\" aria-hidden=\"true\" class=\"group/row\">\n <td v-if=\"selectable\" :class=\"[td, checkCell]\"><Skeleton size=\"1rem\" /></td>\n <td v-for=\"(column, j) in columns\" :key=\"column.key\" :class=\"[td, pad]\">\n <Skeleton height=\"0.75rem\" :width=\"skeletonWidths[(i + j) % 5]\" />\n </td>\n </tr>\n </template>\n <template v-else>\n <tr\n v-for=\"row in rows\"\n :key=\"idOf(row) as PropertyKey\"\n :aria-selected=\"selectable ? selected.includes(idOf(row)) : undefined\"\n class=\"group/row transition-colors duration-150\"\n :class=\"[\n selected.includes(idOf(row)) ? 'bg-sui-accent-wash' : 'hover:bg-sui-sunken',\n onRowClick && 'cursor-pointer'\n ]\"\n @click=\"onRowClick?.(row)\"\n >\n <td v-if=\"selectable\" :class=\"[td, checkCell]\" @click.stop>\n <Checkbox\n :aria-label=\"selectRowLabel\"\n :model-value=\"selected.includes(idOf(row))\"\n @update:model-value=\"toggle(idOf(row))\"\n />\n </td>\n <td\n v-for=\"column in columns\"\n :key=\"column.key\"\n :class=\"[\n td,\n pad,\n alignClass[column.align ?? 'left'],\n column.wrap ? 'break-words whitespace-normal' : 'truncate'\n ]\"\n >\n <slot :name=\"`cell-${column.key}`\" :row=\"row\" :value=\"row[column.key]\">\n <template v-if=\"row[column.key] != null && row[column.key] !== ''\">{{ row[column.key] }}</template>\n <span v-else class=\"text-sui-ink-muted\">–</span>\n </slot>\n </td>\n </tr>\n </template>\n </tbody>\n </table>\n </div>\n <div\n v-if=\"$slots.footer\"\n class=\"flex flex-wrap items-center justify-between gap-3 border-t border-sui-line-subtle bg-sui-canvas py-2 pr-3 pl-4 text-13 text-sui-ink-muted\"\n >\n <slot name=\"footer\" />\n </div>\n </div>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"Table.js","names":["_sfc_main","Table_vue_vue_type_script_setup_true_lang_default","Table_default"],"sources":["../../../src/components/Table/Table.vue"],"sourcesContent":["<script setup lang=\"ts\" generic=\"T extends Record<string, any>\">\nimport { computed } from 'vue'\n\nimport Checkbox from '../Checkbox/Checkbox.vue'\nimport Skeleton from '../Skeleton/Skeleton.vue'\nimport type { TableColumn, TableSort } from './types'\n\nexport interface TableProps<T> {\n columns: TableColumn[]\n rows: T[]\n /** The row field that identifies it. */\n rowKey?: keyof T & string\n /** A checkbox column bound to `v-model:selected`; selected rows tint accent-wash. */\n selectable?: boolean\n /** Skeleton rows in place of the body. */\n loading?: boolean\n loadingRows?: number\n /** md: 57px rows. sm: 40px, for dense lists. */\n size?: 'md' | 'sm'\n /** A row height in px between the sizes, such as 44, for body and header rows; sets `--sui-table-row`. */\n rowHeight?: number\n /** The header row's height in px, e.g. 36 over 44px rows; sets `--sui-table-header`. Defaults to the row height. */\n headerHeight?: number\n /** canvas lays the header on the page colour, for a table directly on the canvas. */\n headerTone?: 'sunken' | 'canvas'\n /** The table's name for screen readers. */\n caption?: string\n selectAllLabel?: string\n selectRowLabel?: string\n /** Makes rows clickable (`@row-click`), e.g. to open the record. */\n onRowClick?: (row: T) => void\n}\n\nconst props = withDefaults(defineProps<TableProps<T>>(), {\n rowKey: 'id' as never,\n loadingRows: 5,\n size: 'md',\n rowHeight: undefined,\n headerHeight: undefined,\n headerTone: 'sunken',\n caption: undefined,\n selectAllLabel: 'Select all rows',\n selectRowLabel: 'Select row',\n onRowClick: undefined\n})\n\nconst sort = defineModel<TableSort | null>('sort', { default: null })\nconst selected = defineModel<unknown[]>('selected', { default: () => [] })\n\nconst slots = defineSlots<\n {\n /** Shown in place of the body when there are no rows, e.g. an EmptyState. */\n empty?: () => unknown\n /** Replaces the body when given, e.g. an inset danger Alert with a retry. */\n error?: () => unknown\n /** A canvas strip under the rows: a rows-per-page Select, the range, Pagination. */\n footer?: () => unknown\n } & {\n [K in `cell-${string}`]?: (props: { row: T; value: unknown }) => unknown\n }\n>()\n\nconst idOf = (row: T): unknown => row[props.rowKey ?? 'id']\nconst ids = computed(() => props.rows.map(idOf))\nconst allSelected = computed(() => ids.value.length > 0 && ids.value.every((id) => selected.value.includes(id)))\nconst someSelected = computed(() => !allSelected.value && ids.value.some((id) => selected.value.includes(id)))\n\nfunction toggleAll() {\n selected.value = allSelected.value\n ? selected.value.filter((id) => !ids.value.includes(id))\n : [...new Set([...selected.value, ...ids.value])]\n}\n\nfunction toggle(id: unknown) {\n selected.value = selected.value.includes(id) ? selected.value.filter((x) => x !== id) : [...selected.value, id]\n}\n\n// Sorting a column cycles ascending, descending, unsorted.\nfunction sortBy(key: string) {\n const dir = sort.value?.key === key ? sort.value.dir : null\n const next = dir === null ? 'asc' : dir === 'asc' ? 'desc' : null\n sort.value = next ? { key, dir: next } : null\n}\n\nfunction dirOf(key: string) {\n return sort.value?.key === key ? sort.value.dir : null\n}\n\nfunction ariaSort(column: TableColumn) {\n const dir = dirOf(column.key)\n if (dir) return dir === 'asc' ? 'ascending' : 'descending'\n return column.sortable ? 'none' : undefined\n}\n\nconst state = computed(() => {\n if (slots.error) return 'error'\n if (props.loading) return 'loading'\n return props.rows.length === 0 && slots.empty ? 'empty' : 'rows'\n})\n\nconst columnCount = computed(() => props.columns.length + (props.selectable ? 1 : 0))\nconst alignClass = { left: 'text-left', center: 'text-center', right: 'text-right' }\nconst skeletonWidths = ['60%', '45%', '70%', '35%', '55%']\n\nconst sm = computed(() => props.size === 'sm')\nconst fixed = computed(() => props.rowHeight !== undefined)\nconst rowStyle = computed(() => {\n const style: Record<string, string> = {}\n if (fixed.value) style['--sui-table-row'] = `${props.rowHeight}px`\n if (props.headerHeight !== undefined) style['--sui-table-header'] = `${props.headerHeight}px`\n return Object.keys(style).length ? style : undefined\n})\nconst th = computed(() => [\n 'border-b border-sui-line-subtle text-13 font-medium whitespace-nowrap',\n sm.value\n ? 'h-[var(--sui-table-header,var(--sui-table-row,2.25rem))]'\n : 'h-[var(--sui-table-header,var(--sui-table-row,2.75rem))]'\n])\nconst td = computed(() => [\n 'border-b border-sui-line-subtle align-middle text-sui-ink-body group-last/row:border-b-0',\n sm.value ? 'h-[var(--sui-table-row,2.5rem)]' : 'h-[var(--sui-table-row,3.5625rem)]'\n])\n// A set row height takes the cells' vertical padding with it.\nconst pad = computed(() => [sm.value ? 'px-3' : 'px-4', !fixed.value && (sm.value ? 'py-1.5' : 'py-3')])\nconst headTone = computed(() => (props.headerTone === 'canvas' ? 'bg-sui-canvas' : 'bg-sui-sunken'))\nconst headPad = computed(() => (sm.value ? 'px-3' : 'px-4'))\nconst checkCell = 'w-12 pl-4'\n</script>\n\n<!-- A data table: sunken header strip, sortable headers, selection, loading, empty and error states, a footer. -->\n<template>\n <div\n class=\"overflow-hidden rounded-xl border border-sui-line-subtle bg-sui-surface text-sm text-sui-ink\"\n :style=\"rowStyle\"\n >\n <div class=\"overflow-x-auto\">\n <table class=\"w-full min-w-[var(--sui-table-min,720px)] table-fixed border-collapse\">\n <caption v-if=\"caption\" class=\"sr-only\">\n {{\n caption\n }}\n </caption>\n <colgroup>\n <col v-if=\"selectable\" class=\"w-12\" />\n <col\n v-for=\"column in columns\"\n :key=\"column.key\"\n :style=\"{ width: typeof column.width === 'number' ? `${column.width}px` : column.width }\"\n />\n </colgroup>\n <thead>\n <tr>\n <th v-if=\"selectable\" :class=\"[th, checkCell, headTone]\">\n <Checkbox\n :aria-label=\"selectAllLabel\"\n :disabled=\"loading || rows.length === 0\"\n :indeterminate=\"someSelected\"\n :model-value=\"allSelected\"\n @update:model-value=\"toggleAll\"\n />\n </th>\n <component\n :is=\"column.label ? 'th' : 'td'\"\n v-for=\"column in columns\"\n :key=\"column.key\"\n :aria-sort=\"ariaSort(column)\"\n :class=\"[\n th,\n headPad,\n alignClass[column.align ?? 'left'],\n dirOf(column.key) ? 'bg-sui-accent-wash text-sui-accent' : [headTone, 'text-sui-ink-subtle']\n ]\"\n :scope=\"column.label ? 'col' : undefined\"\n >\n <button\n v-if=\"column.sortable\"\n class=\"inline-flex h-full w-full items-center gap-1.5 rounded-md outline-hidden focus-visible:sui-ring-inset\"\n :class=\"[\n column.align === 'right' && 'justify-end',\n column.align === 'center' && 'justify-center',\n !dirOf(column.key) && 'hover:text-sui-ink'\n ]\"\n type=\"button\"\n @click=\"sortBy(column.key)\"\n >\n {{ column.label }}\n <svg\n aria-hidden=\"true\"\n class=\"size-3 shrink-0 fill-none stroke-current\"\n :class=\"!dirOf(column.key) && 'opacity-50'\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 12 12\"\n >\n <path v-if=\"dirOf(column.key) === 'asc'\" d=\"M3 7.5 6 4.5l3 3\" />\n <path v-else-if=\"dirOf(column.key) === 'desc'\" d=\"M3 4.5 6 7.5l3-3\" />\n <path v-else d=\"M3.5 4.5 6 2l2.5 2.5M3.5 7.5 6 10l2.5-2.5\" />\n </svg>\n </button>\n <template v-else>{{ column.label }}</template>\n </component>\n </tr>\n </thead>\n <tbody :aria-busy=\"loading || undefined\">\n <tr v-if=\"state === 'error' || state === 'empty'\">\n <td class=\"p-0\" :colspan=\"columnCount\">\n <slot :name=\"state\" />\n </td>\n </tr>\n <template v-else-if=\"state === 'loading'\">\n <tr v-for=\"i in loadingRows\" :key=\"i\" aria-hidden=\"true\" class=\"group/row\">\n <td v-if=\"selectable\" :class=\"[td, checkCell]\"><Skeleton size=\"1rem\" /></td>\n <td v-for=\"(column, j) in columns\" :key=\"column.key\" :class=\"[td, pad]\">\n <Skeleton height=\"0.75rem\" :width=\"skeletonWidths[(i + j) % 5]\" />\n </td>\n </tr>\n </template>\n <template v-else>\n <tr\n v-for=\"row in rows\"\n :key=\"idOf(row) as PropertyKey\"\n :aria-selected=\"selectable ? selected.includes(idOf(row)) : undefined\"\n class=\"group/row transition-colors duration-150\"\n :class=\"[\n selected.includes(idOf(row)) ? 'bg-sui-accent-wash' : 'hover:bg-sui-sunken',\n onRowClick && 'cursor-pointer'\n ]\"\n @click=\"onRowClick?.(row)\"\n >\n <td v-if=\"selectable\" :class=\"[td, checkCell]\" @click.stop>\n <Checkbox\n :aria-label=\"selectRowLabel\"\n :model-value=\"selected.includes(idOf(row))\"\n @update:model-value=\"toggle(idOf(row))\"\n />\n </td>\n <td\n v-for=\"column in columns\"\n :key=\"column.key\"\n :class=\"[\n td,\n pad,\n alignClass[column.align ?? 'left'],\n column.wrap ? 'break-words whitespace-normal' : 'truncate'\n ]\"\n >\n <slot :name=\"`cell-${column.key}`\" :row=\"row\" :value=\"row[column.key]\">\n <template v-if=\"row[column.key] != null && row[column.key] !== ''\">{{ row[column.key] }}</template>\n <span v-else class=\"text-sui-ink-muted\">–</span>\n </slot>\n </td>\n </tr>\n </template>\n </tbody>\n </table>\n </div>\n <div\n v-if=\"$slots.footer\"\n class=\"flex flex-wrap items-center justify-between gap-3 border-t border-sui-line-subtle bg-sui-canvas py-2 pr-3 pl-4 text-13 text-sui-ink-muted\"\n >\n <slot name=\"footer\" />\n </div>\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -13,6 +13,8 @@ export interface TableProps<T> {
|
|
|
13
13
|
size?: 'md' | 'sm';
|
|
14
14
|
/** A row height in px between the sizes, such as 44, for body and header rows; sets `--sui-table-row`. */
|
|
15
15
|
rowHeight?: number;
|
|
16
|
+
/** The header row's height in px, e.g. 36 over 44px rows; sets `--sui-table-header`. Defaults to the row height. */
|
|
17
|
+
headerHeight?: number;
|
|
16
18
|
/** canvas lays the header on the page colour, for a table directly on the canvas. */
|
|
17
19
|
headerTone?: 'sunken' | 'canvas';
|
|
18
20
|
/** The table's name for screen readers. */
|
|
@@ -34,6 +34,7 @@ var C = { class: "overflow-x-auto" }, w = { class: "w-full min-w-[var(--sui-tabl
|
|
|
34
34
|
loadingRows: { default: 5 },
|
|
35
35
|
size: { default: "md" },
|
|
36
36
|
rowHeight: { default: void 0 },
|
|
37
|
+
headerHeight: { default: void 0 },
|
|
37
38
|
headerTone: { default: "sunken" },
|
|
38
39
|
caption: { default: void 0 },
|
|
39
40
|
selectAllLabel: { default: "Select all rows" },
|
|
@@ -81,7 +82,10 @@ var C = { class: "overflow-x-auto" }, w = { class: "w-full min-w-[var(--sui-tabl
|
|
|
81
82
|
"70%",
|
|
82
83
|
"35%",
|
|
83
84
|
"55%"
|
|
84
|
-
], J = r(() => d.size === "sm"), Y = r(() => d.rowHeight !== void 0), oe = r(() =>
|
|
85
|
+
], J = r(() => d.size === "sm"), Y = r(() => d.rowHeight !== void 0), oe = r(() => {
|
|
86
|
+
let e = {};
|
|
87
|
+
return Y.value && (e["--sui-table-row"] = `${d.rowHeight}px`), d.headerHeight !== void 0 && (e["--sui-table-header"] = `${d.headerHeight}px`), Object.keys(e).length ? e : void 0;
|
|
88
|
+
}), X = r(() => ["border-b border-sui-line-subtle text-13 font-medium whitespace-nowrap", J.value ? "h-[var(--sui-table-header,var(--sui-table-row,2.25rem))]" : "h-[var(--sui-table-header,var(--sui-table-row,2.75rem))]"]), Z = r(() => ["border-b border-sui-line-subtle align-middle text-sui-ink-body group-last/row:border-b-0", J.value ? "h-[var(--sui-table-row,2.5rem)]" : "h-[var(--sui-table-row,3.5625rem)]"]), Q = r(() => [J.value ? "px-3" : "px-4", !Y.value && (J.value ? "py-1.5" : "py-3")]), $ = r(() => d.headerTone === "canvas" ? "bg-sui-canvas" : "bg-sui-sunken"), se = r(() => J.value ? "px-3" : "px-4");
|
|
85
89
|
return (r, d) => (m(), o("div", {
|
|
86
90
|
class: "overflow-hidden rounded-xl border border-sui-line-subtle bg-sui-surface text-sm text-sui-ink",
|
|
87
91
|
style: p(oe.value)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Table.vue_vue_type_script_setup_true_lang.js","names":["$slots","_useModel","_useSlots","_openBlock","_createElementBlock","_normalizeStyle","_createElementVNode","_toDisplayString","_createCommentVNode","_Fragment","_renderList","_normalizeClass","_createVNode","Checkbox","_createBlock","_resolveDynamicComponent","_withCtx","_createTextVNode","_renderSlot","Skeleton","_withModifiers","Skeleton_default","Checkbox_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","checkCell","Table_vue_vue_type_script_setup_true_lang_default","\"sort\"","\"sortModifiers\"","\"selected\"","\"selectedModifiers\"","props","__props","sort","useModel","selected","slots","useSlots","idOf","row","ids","computed","allSelected","id","someSelected","toggleAll","toggle","x","sortBy","dir","key","next","dirOf","ariaSort","column","state","columnCount","alignClass","skeletonWidths","sm","fixed","rowStyle","th","td","pad","headTone","headPad","openBlock","createElementBlock","normalizeStyle","createElementVNode","toDisplayString","createCommentVNode","Fragment","renderList","normalizeClass","createVNode","createBlock","resolveDynamicComponent","withCtx","createTextVNode","renderSlot","_ctx","i","j","_cache","withModifiers"],"sources":["../../../src/components/Table/Table.vue"],"sourcesContent":["<script setup lang=\"ts\" generic=\"T extends Record<string, any>\">\nimport { computed } from 'vue'\n\nimport Checkbox from '../Checkbox/Checkbox.vue'\nimport Skeleton from '../Skeleton/Skeleton.vue'\nimport type { TableColumn, TableSort } from './types'\n\nexport interface TableProps<T> {\n columns: TableColumn[]\n rows: T[]\n /** The row field that identifies it. */\n rowKey?: keyof T & string\n /** A checkbox column bound to `v-model:selected`; selected rows tint accent-wash. */\n selectable?: boolean\n /** Skeleton rows in place of the body. */\n loading?: boolean\n loadingRows?: number\n /** md: 57px rows. sm: 40px, for dense lists. */\n size?: 'md' | 'sm'\n /** A row height in px between the sizes, such as 44, for body and header rows; sets `--sui-table-row`. */\n rowHeight?: number\n /** canvas lays the header on the page colour, for a table directly on the canvas. */\n headerTone?: 'sunken' | 'canvas'\n /** The table's name for screen readers. */\n caption?: string\n selectAllLabel?: string\n selectRowLabel?: string\n /** Makes rows clickable (`@row-click`), e.g. to open the record. */\n onRowClick?: (row: T) => void\n}\n\nconst props = withDefaults(defineProps<TableProps<T>>(), {\n rowKey: 'id' as never,\n loadingRows: 5,\n size: 'md',\n rowHeight: undefined,\n headerTone: 'sunken',\n caption: undefined,\n selectAllLabel: 'Select all rows',\n selectRowLabel: 'Select row',\n onRowClick: undefined\n})\n\nconst sort = defineModel<TableSort | null>('sort', { default: null })\nconst selected = defineModel<unknown[]>('selected', { default: () => [] })\n\nconst slots = defineSlots<\n {\n /** Shown in place of the body when there are no rows, e.g. an EmptyState. */\n empty?: () => unknown\n /** Replaces the body when given, e.g. an inset danger Alert with a retry. */\n error?: () => unknown\n /** A canvas strip under the rows: a rows-per-page Select, the range, Pagination. */\n footer?: () => unknown\n } & {\n [K in `cell-${string}`]?: (props: { row: T; value: unknown }) => unknown\n }\n>()\n\nconst idOf = (row: T): unknown => row[props.rowKey ?? 'id']\nconst ids = computed(() => props.rows.map(idOf))\nconst allSelected = computed(() => ids.value.length > 0 && ids.value.every((id) => selected.value.includes(id)))\nconst someSelected = computed(() => !allSelected.value && ids.value.some((id) => selected.value.includes(id)))\n\nfunction toggleAll() {\n selected.value = allSelected.value\n ? selected.value.filter((id) => !ids.value.includes(id))\n : [...new Set([...selected.value, ...ids.value])]\n}\n\nfunction toggle(id: unknown) {\n selected.value = selected.value.includes(id) ? selected.value.filter((x) => x !== id) : [...selected.value, id]\n}\n\n// Sorting a column cycles ascending, descending, unsorted.\nfunction sortBy(key: string) {\n const dir = sort.value?.key === key ? sort.value.dir : null\n const next = dir === null ? 'asc' : dir === 'asc' ? 'desc' : null\n sort.value = next ? { key, dir: next } : null\n}\n\nfunction dirOf(key: string) {\n return sort.value?.key === key ? sort.value.dir : null\n}\n\nfunction ariaSort(column: TableColumn) {\n const dir = dirOf(column.key)\n if (dir) return dir === 'asc' ? 'ascending' : 'descending'\n return column.sortable ? 'none' : undefined\n}\n\nconst state = computed(() => {\n if (slots.error) return 'error'\n if (props.loading) return 'loading'\n return props.rows.length === 0 && slots.empty ? 'empty' : 'rows'\n})\n\nconst columnCount = computed(() => props.columns.length + (props.selectable ? 1 : 0))\nconst alignClass = { left: 'text-left', center: 'text-center', right: 'text-right' }\nconst skeletonWidths = ['60%', '45%', '70%', '35%', '55%']\n\nconst sm = computed(() => props.size === 'sm')\nconst fixed = computed(() => props.rowHeight !== undefined)\nconst rowStyle = computed(() => (fixed.value ? { '--sui-table-row': `${props.rowHeight}px` } : undefined))\nconst th = computed(() => [\n 'border-b border-sui-line-subtle text-13 font-medium whitespace-nowrap',\n sm.value ? 'h-[var(--sui-table-row,2.25rem)]' : 'h-[var(--sui-table-row,2.75rem)]'\n])\nconst td = computed(() => [\n 'border-b border-sui-line-subtle align-middle text-sui-ink-body group-last/row:border-b-0',\n sm.value ? 'h-[var(--sui-table-row,2.5rem)]' : 'h-[var(--sui-table-row,3.5625rem)]'\n])\n// A set row height takes the cells' vertical padding with it.\nconst pad = computed(() => [sm.value ? 'px-3' : 'px-4', !fixed.value && (sm.value ? 'py-1.5' : 'py-3')])\nconst headTone = computed(() => (props.headerTone === 'canvas' ? 'bg-sui-canvas' : 'bg-sui-sunken'))\nconst headPad = computed(() => (sm.value ? 'px-3' : 'px-4'))\nconst checkCell = 'w-12 pl-4'\n</script>\n\n<!-- A data table: sunken header strip, sortable headers, selection, loading, empty and error states, a footer. -->\n<template>\n <div\n class=\"overflow-hidden rounded-xl border border-sui-line-subtle bg-sui-surface text-sm text-sui-ink\"\n :style=\"rowStyle\"\n >\n <div class=\"overflow-x-auto\">\n <table class=\"w-full min-w-[var(--sui-table-min,720px)] table-fixed border-collapse\">\n <caption v-if=\"caption\" class=\"sr-only\">\n {{\n caption\n }}\n </caption>\n <colgroup>\n <col v-if=\"selectable\" class=\"w-12\" />\n <col\n v-for=\"column in columns\"\n :key=\"column.key\"\n :style=\"{ width: typeof column.width === 'number' ? `${column.width}px` : column.width }\"\n />\n </colgroup>\n <thead>\n <tr>\n <th v-if=\"selectable\" :class=\"[th, checkCell, headTone]\">\n <Checkbox\n :aria-label=\"selectAllLabel\"\n :disabled=\"loading || rows.length === 0\"\n :indeterminate=\"someSelected\"\n :model-value=\"allSelected\"\n @update:model-value=\"toggleAll\"\n />\n </th>\n <component\n :is=\"column.label ? 'th' : 'td'\"\n v-for=\"column in columns\"\n :key=\"column.key\"\n :aria-sort=\"ariaSort(column)\"\n :class=\"[\n th,\n headPad,\n alignClass[column.align ?? 'left'],\n dirOf(column.key) ? 'bg-sui-accent-wash text-sui-accent' : [headTone, 'text-sui-ink-subtle']\n ]\"\n :scope=\"column.label ? 'col' : undefined\"\n >\n <button\n v-if=\"column.sortable\"\n class=\"inline-flex h-full w-full items-center gap-1.5 rounded-md outline-hidden focus-visible:sui-ring-inset\"\n :class=\"[\n column.align === 'right' && 'justify-end',\n column.align === 'center' && 'justify-center',\n !dirOf(column.key) && 'hover:text-sui-ink'\n ]\"\n type=\"button\"\n @click=\"sortBy(column.key)\"\n >\n {{ column.label }}\n <svg\n aria-hidden=\"true\"\n class=\"size-3 shrink-0 fill-none stroke-current\"\n :class=\"!dirOf(column.key) && 'opacity-50'\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 12 12\"\n >\n <path v-if=\"dirOf(column.key) === 'asc'\" d=\"M3 7.5 6 4.5l3 3\" />\n <path v-else-if=\"dirOf(column.key) === 'desc'\" d=\"M3 4.5 6 7.5l3-3\" />\n <path v-else d=\"M3.5 4.5 6 2l2.5 2.5M3.5 7.5 6 10l2.5-2.5\" />\n </svg>\n </button>\n <template v-else>{{ column.label }}</template>\n </component>\n </tr>\n </thead>\n <tbody :aria-busy=\"loading || undefined\">\n <tr v-if=\"state === 'error' || state === 'empty'\">\n <td class=\"p-0\" :colspan=\"columnCount\">\n <slot :name=\"state\" />\n </td>\n </tr>\n <template v-else-if=\"state === 'loading'\">\n <tr v-for=\"i in loadingRows\" :key=\"i\" aria-hidden=\"true\" class=\"group/row\">\n <td v-if=\"selectable\" :class=\"[td, checkCell]\"><Skeleton size=\"1rem\" /></td>\n <td v-for=\"(column, j) in columns\" :key=\"column.key\" :class=\"[td, pad]\">\n <Skeleton height=\"0.75rem\" :width=\"skeletonWidths[(i + j) % 5]\" />\n </td>\n </tr>\n </template>\n <template v-else>\n <tr\n v-for=\"row in rows\"\n :key=\"idOf(row) as PropertyKey\"\n :aria-selected=\"selectable ? selected.includes(idOf(row)) : undefined\"\n class=\"group/row transition-colors duration-150\"\n :class=\"[\n selected.includes(idOf(row)) ? 'bg-sui-accent-wash' : 'hover:bg-sui-sunken',\n onRowClick && 'cursor-pointer'\n ]\"\n @click=\"onRowClick?.(row)\"\n >\n <td v-if=\"selectable\" :class=\"[td, checkCell]\" @click.stop>\n <Checkbox\n :aria-label=\"selectRowLabel\"\n :model-value=\"selected.includes(idOf(row))\"\n @update:model-value=\"toggle(idOf(row))\"\n />\n </td>\n <td\n v-for=\"column in columns\"\n :key=\"column.key\"\n :class=\"[\n td,\n pad,\n alignClass[column.align ?? 'left'],\n column.wrap ? 'break-words whitespace-normal' : 'truncate'\n ]\"\n >\n <slot :name=\"`cell-${column.key}`\" :row=\"row\" :value=\"row[column.key]\">\n <template v-if=\"row[column.key] != null && row[column.key] !== ''\">{{ row[column.key] }}</template>\n <span v-else class=\"text-sui-ink-muted\">–</span>\n </slot>\n </td>\n </tr>\n </template>\n </tbody>\n </table>\n </div>\n <div\n v-if=\"$slots.footer\"\n class=\"flex flex-wrap items-center justify-between gap-3 border-t border-sui-line-subtle bg-sui-canvas py-2 pr-3 pl-4 text-13 text-sui-ink-muted\"\n >\n <slot name=\"footer\" />\n </div>\n </div>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Table.vue_vue_type_script_setup_true_lang.js","names":["$slots","_useModel","_useSlots","_openBlock","_createElementBlock","_normalizeStyle","_createElementVNode","_toDisplayString","_createCommentVNode","_Fragment","_renderList","_normalizeClass","_createVNode","Checkbox","_createBlock","_resolveDynamicComponent","_withCtx","_createTextVNode","_renderSlot","Skeleton","_withModifiers","Skeleton_default","Checkbox_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","checkCell","Table_vue_vue_type_script_setup_true_lang_default","\"sort\"","\"sortModifiers\"","\"selected\"","\"selectedModifiers\"","props","__props","sort","useModel","selected","slots","useSlots","idOf","row","ids","computed","allSelected","id","someSelected","toggleAll","toggle","x","sortBy","dir","key","next","dirOf","ariaSort","column","state","columnCount","alignClass","skeletonWidths","sm","fixed","rowStyle","style","th","td","pad","headTone","headPad","openBlock","createElementBlock","normalizeStyle","createElementVNode","toDisplayString","createCommentVNode","Fragment","renderList","normalizeClass","createVNode","createBlock","resolveDynamicComponent","withCtx","createTextVNode","renderSlot","_ctx","i","j","_cache","withModifiers"],"sources":["../../../src/components/Table/Table.vue"],"sourcesContent":["<script setup lang=\"ts\" generic=\"T extends Record<string, any>\">\nimport { computed } from 'vue'\n\nimport Checkbox from '../Checkbox/Checkbox.vue'\nimport Skeleton from '../Skeleton/Skeleton.vue'\nimport type { TableColumn, TableSort } from './types'\n\nexport interface TableProps<T> {\n columns: TableColumn[]\n rows: T[]\n /** The row field that identifies it. */\n rowKey?: keyof T & string\n /** A checkbox column bound to `v-model:selected`; selected rows tint accent-wash. */\n selectable?: boolean\n /** Skeleton rows in place of the body. */\n loading?: boolean\n loadingRows?: number\n /** md: 57px rows. sm: 40px, for dense lists. */\n size?: 'md' | 'sm'\n /** A row height in px between the sizes, such as 44, for body and header rows; sets `--sui-table-row`. */\n rowHeight?: number\n /** The header row's height in px, e.g. 36 over 44px rows; sets `--sui-table-header`. Defaults to the row height. */\n headerHeight?: number\n /** canvas lays the header on the page colour, for a table directly on the canvas. */\n headerTone?: 'sunken' | 'canvas'\n /** The table's name for screen readers. */\n caption?: string\n selectAllLabel?: string\n selectRowLabel?: string\n /** Makes rows clickable (`@row-click`), e.g. to open the record. */\n onRowClick?: (row: T) => void\n}\n\nconst props = withDefaults(defineProps<TableProps<T>>(), {\n rowKey: 'id' as never,\n loadingRows: 5,\n size: 'md',\n rowHeight: undefined,\n headerHeight: undefined,\n headerTone: 'sunken',\n caption: undefined,\n selectAllLabel: 'Select all rows',\n selectRowLabel: 'Select row',\n onRowClick: undefined\n})\n\nconst sort = defineModel<TableSort | null>('sort', { default: null })\nconst selected = defineModel<unknown[]>('selected', { default: () => [] })\n\nconst slots = defineSlots<\n {\n /** Shown in place of the body when there are no rows, e.g. an EmptyState. */\n empty?: () => unknown\n /** Replaces the body when given, e.g. an inset danger Alert with a retry. */\n error?: () => unknown\n /** A canvas strip under the rows: a rows-per-page Select, the range, Pagination. */\n footer?: () => unknown\n } & {\n [K in `cell-${string}`]?: (props: { row: T; value: unknown }) => unknown\n }\n>()\n\nconst idOf = (row: T): unknown => row[props.rowKey ?? 'id']\nconst ids = computed(() => props.rows.map(idOf))\nconst allSelected = computed(() => ids.value.length > 0 && ids.value.every((id) => selected.value.includes(id)))\nconst someSelected = computed(() => !allSelected.value && ids.value.some((id) => selected.value.includes(id)))\n\nfunction toggleAll() {\n selected.value = allSelected.value\n ? selected.value.filter((id) => !ids.value.includes(id))\n : [...new Set([...selected.value, ...ids.value])]\n}\n\nfunction toggle(id: unknown) {\n selected.value = selected.value.includes(id) ? selected.value.filter((x) => x !== id) : [...selected.value, id]\n}\n\n// Sorting a column cycles ascending, descending, unsorted.\nfunction sortBy(key: string) {\n const dir = sort.value?.key === key ? sort.value.dir : null\n const next = dir === null ? 'asc' : dir === 'asc' ? 'desc' : null\n sort.value = next ? { key, dir: next } : null\n}\n\nfunction dirOf(key: string) {\n return sort.value?.key === key ? sort.value.dir : null\n}\n\nfunction ariaSort(column: TableColumn) {\n const dir = dirOf(column.key)\n if (dir) return dir === 'asc' ? 'ascending' : 'descending'\n return column.sortable ? 'none' : undefined\n}\n\nconst state = computed(() => {\n if (slots.error) return 'error'\n if (props.loading) return 'loading'\n return props.rows.length === 0 && slots.empty ? 'empty' : 'rows'\n})\n\nconst columnCount = computed(() => props.columns.length + (props.selectable ? 1 : 0))\nconst alignClass = { left: 'text-left', center: 'text-center', right: 'text-right' }\nconst skeletonWidths = ['60%', '45%', '70%', '35%', '55%']\n\nconst sm = computed(() => props.size === 'sm')\nconst fixed = computed(() => props.rowHeight !== undefined)\nconst rowStyle = computed(() => {\n const style: Record<string, string> = {}\n if (fixed.value) style['--sui-table-row'] = `${props.rowHeight}px`\n if (props.headerHeight !== undefined) style['--sui-table-header'] = `${props.headerHeight}px`\n return Object.keys(style).length ? style : undefined\n})\nconst th = computed(() => [\n 'border-b border-sui-line-subtle text-13 font-medium whitespace-nowrap',\n sm.value\n ? 'h-[var(--sui-table-header,var(--sui-table-row,2.25rem))]'\n : 'h-[var(--sui-table-header,var(--sui-table-row,2.75rem))]'\n])\nconst td = computed(() => [\n 'border-b border-sui-line-subtle align-middle text-sui-ink-body group-last/row:border-b-0',\n sm.value ? 'h-[var(--sui-table-row,2.5rem)]' : 'h-[var(--sui-table-row,3.5625rem)]'\n])\n// A set row height takes the cells' vertical padding with it.\nconst pad = computed(() => [sm.value ? 'px-3' : 'px-4', !fixed.value && (sm.value ? 'py-1.5' : 'py-3')])\nconst headTone = computed(() => (props.headerTone === 'canvas' ? 'bg-sui-canvas' : 'bg-sui-sunken'))\nconst headPad = computed(() => (sm.value ? 'px-3' : 'px-4'))\nconst checkCell = 'w-12 pl-4'\n</script>\n\n<!-- A data table: sunken header strip, sortable headers, selection, loading, empty and error states, a footer. -->\n<template>\n <div\n class=\"overflow-hidden rounded-xl border border-sui-line-subtle bg-sui-surface text-sm text-sui-ink\"\n :style=\"rowStyle\"\n >\n <div class=\"overflow-x-auto\">\n <table class=\"w-full min-w-[var(--sui-table-min,720px)] table-fixed border-collapse\">\n <caption v-if=\"caption\" class=\"sr-only\">\n {{\n caption\n }}\n </caption>\n <colgroup>\n <col v-if=\"selectable\" class=\"w-12\" />\n <col\n v-for=\"column in columns\"\n :key=\"column.key\"\n :style=\"{ width: typeof column.width === 'number' ? `${column.width}px` : column.width }\"\n />\n </colgroup>\n <thead>\n <tr>\n <th v-if=\"selectable\" :class=\"[th, checkCell, headTone]\">\n <Checkbox\n :aria-label=\"selectAllLabel\"\n :disabled=\"loading || rows.length === 0\"\n :indeterminate=\"someSelected\"\n :model-value=\"allSelected\"\n @update:model-value=\"toggleAll\"\n />\n </th>\n <component\n :is=\"column.label ? 'th' : 'td'\"\n v-for=\"column in columns\"\n :key=\"column.key\"\n :aria-sort=\"ariaSort(column)\"\n :class=\"[\n th,\n headPad,\n alignClass[column.align ?? 'left'],\n dirOf(column.key) ? 'bg-sui-accent-wash text-sui-accent' : [headTone, 'text-sui-ink-subtle']\n ]\"\n :scope=\"column.label ? 'col' : undefined\"\n >\n <button\n v-if=\"column.sortable\"\n class=\"inline-flex h-full w-full items-center gap-1.5 rounded-md outline-hidden focus-visible:sui-ring-inset\"\n :class=\"[\n column.align === 'right' && 'justify-end',\n column.align === 'center' && 'justify-center',\n !dirOf(column.key) && 'hover:text-sui-ink'\n ]\"\n type=\"button\"\n @click=\"sortBy(column.key)\"\n >\n {{ column.label }}\n <svg\n aria-hidden=\"true\"\n class=\"size-3 shrink-0 fill-none stroke-current\"\n :class=\"!dirOf(column.key) && 'opacity-50'\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 12 12\"\n >\n <path v-if=\"dirOf(column.key) === 'asc'\" d=\"M3 7.5 6 4.5l3 3\" />\n <path v-else-if=\"dirOf(column.key) === 'desc'\" d=\"M3 4.5 6 7.5l3-3\" />\n <path v-else d=\"M3.5 4.5 6 2l2.5 2.5M3.5 7.5 6 10l2.5-2.5\" />\n </svg>\n </button>\n <template v-else>{{ column.label }}</template>\n </component>\n </tr>\n </thead>\n <tbody :aria-busy=\"loading || undefined\">\n <tr v-if=\"state === 'error' || state === 'empty'\">\n <td class=\"p-0\" :colspan=\"columnCount\">\n <slot :name=\"state\" />\n </td>\n </tr>\n <template v-else-if=\"state === 'loading'\">\n <tr v-for=\"i in loadingRows\" :key=\"i\" aria-hidden=\"true\" class=\"group/row\">\n <td v-if=\"selectable\" :class=\"[td, checkCell]\"><Skeleton size=\"1rem\" /></td>\n <td v-for=\"(column, j) in columns\" :key=\"column.key\" :class=\"[td, pad]\">\n <Skeleton height=\"0.75rem\" :width=\"skeletonWidths[(i + j) % 5]\" />\n </td>\n </tr>\n </template>\n <template v-else>\n <tr\n v-for=\"row in rows\"\n :key=\"idOf(row) as PropertyKey\"\n :aria-selected=\"selectable ? selected.includes(idOf(row)) : undefined\"\n class=\"group/row transition-colors duration-150\"\n :class=\"[\n selected.includes(idOf(row)) ? 'bg-sui-accent-wash' : 'hover:bg-sui-sunken',\n onRowClick && 'cursor-pointer'\n ]\"\n @click=\"onRowClick?.(row)\"\n >\n <td v-if=\"selectable\" :class=\"[td, checkCell]\" @click.stop>\n <Checkbox\n :aria-label=\"selectRowLabel\"\n :model-value=\"selected.includes(idOf(row))\"\n @update:model-value=\"toggle(idOf(row))\"\n />\n </td>\n <td\n v-for=\"column in columns\"\n :key=\"column.key\"\n :class=\"[\n td,\n pad,\n alignClass[column.align ?? 'left'],\n column.wrap ? 'break-words whitespace-normal' : 'truncate'\n ]\"\n >\n <slot :name=\"`cell-${column.key}`\" :row=\"row\" :value=\"row[column.key]\">\n <template v-if=\"row[column.key] != null && row[column.key] !== ''\">{{ row[column.key] }}</template>\n <span v-else class=\"text-sui-ink-muted\">–</span>\n </slot>\n </td>\n </tr>\n </template>\n </tbody>\n </table>\n </div>\n <div\n v-if=\"$slots.footer\"\n class=\"flex flex-wrap items-center justify-between gap-3 border-t border-sui-line-subtle bg-sui-canvas py-2 pr-3 pl-4 text-13 text-sui-ink-muted\"\n >\n <slot name=\"footer\" />\n </div>\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tag.js","names":["_sfc_main","Tag_vue_vue_type_script_setup_true_lang_default","Tag_default"],"sources":["../../../src/components/Tag/Tag.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { Hue } from '../../utils/hues'\nimport CloseSmallIcon from '../internal/CloseSmallIcon.vue'\n\nexport interface TagProps {\n /** The text; or use the default slot. */\n name?: string\n /** soft: a label people create, with an optional hue dot, removable. outline: a value from a fixed set (a stage, a status). */\n variant?: 'soft' | 'outline'\n /** soft only: a dot of the tag's own hue, on a neutral chip. */\n color?: Hue\n /** outline only: the quieter, superseded side, e.g. the \"from\" of a stage change. */\n muted?: boolean\n /** soft only. */\n removable?: boolean\n /** The remove button's accessible name. */\n removeLabel?: string\n /** A toggle button for quick choices, bound to `v-model:pressed`. Group several in a `role=\"group\"` with a label. */\n pressable?: boolean\n /** pressable only. */\n disabled?: boolean\n}\n\nwithDefaults(defineProps<TagProps>(), {\n name: undefined,\n variant: 'soft',\n color: undefined,\n removeLabel: 'Remove tag'\n})\n\ndefineEmits<{ remove: [] }>()\n\nconst pressed = defineModel<boolean>('pressed', { default: false })\n\nconst dots: Record<Hue, string> = {\n blue: 'bg-sui-hue-blue-ink',\n green: 'bg-sui-hue-green-ink',\n orange: 'bg-sui-hue-orange-ink',\n pink: 'bg-sui-hue-pink-ink',\n purple: 'bg-sui-hue-purple-ink',\n slate: 'bg-sui-hue-slate-ink',\n red: 'bg-sui-hue-red-ink',\n amber: 'bg-sui-hue-amber-ink',\n gray: 'bg-sui-ink'\n}\n</script>\n\n<!-- A label: soft for the ones people create, outline for a value from a fixed set; or, pressable, a toggle chip. -->\n<template>\n <button\n v-if=\"pressable\"\n :aria-pressed=\"pressed\"\n class=\"inline-flex
|
|
1
|
+
{"version":3,"file":"Tag.js","names":["_sfc_main","Tag_vue_vue_type_script_setup_true_lang_default","Tag_default"],"sources":["../../../src/components/Tag/Tag.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { Hue } from '../../utils/hues'\nimport CloseSmallIcon from '../internal/CloseSmallIcon.vue'\n\nexport interface TagProps {\n /** The text; or use the default slot. */\n name?: string\n /** soft: a label people create, with an optional hue dot, removable. outline: a value from a fixed set (a stage, a status). */\n variant?: 'soft' | 'outline'\n /** soft only: a dot of the tag's own hue, on a neutral chip. */\n color?: Hue\n /** outline only: the quieter, superseded side, e.g. the \"from\" of a stage change. */\n muted?: boolean\n /** soft only. */\n removable?: boolean\n /** The remove button's accessible name. */\n removeLabel?: string\n /** A toggle button for quick choices, bound to `v-model:pressed`. Group several in a `role=\"group\"` with a label. */\n pressable?: boolean\n /** pressable only. */\n disabled?: boolean\n /** pressable only: md is 28px, sm 22px for a dense row of filters. */\n size?: 'sm' | 'md'\n}\n\nwithDefaults(defineProps<TagProps>(), {\n name: undefined,\n variant: 'soft',\n color: undefined,\n removeLabel: 'Remove tag',\n size: 'md'\n})\n\ndefineEmits<{ remove: [] }>()\n\nconst pressed = defineModel<boolean>('pressed', { default: false })\n\nconst dots: Record<Hue, string> = {\n blue: 'bg-sui-hue-blue-ink',\n green: 'bg-sui-hue-green-ink',\n orange: 'bg-sui-hue-orange-ink',\n pink: 'bg-sui-hue-pink-ink',\n purple: 'bg-sui-hue-purple-ink',\n slate: 'bg-sui-hue-slate-ink',\n red: 'bg-sui-hue-red-ink',\n amber: 'bg-sui-hue-amber-ink',\n gray: 'bg-sui-ink'\n}\n</script>\n\n<!-- A label: soft for the ones people create, outline for a value from a fixed set; or, pressable, a toggle chip. -->\n<template>\n <button\n v-if=\"pressable\"\n :aria-pressed=\"pressed\"\n class=\"inline-flex cursor-pointer items-center rounded-md border leading-none font-medium whitespace-nowrap transition-colors duration-150 outline-hidden focus-visible:sui-ring disabled:cursor-default disabled:opacity-50\"\n :class=\"[\n size === 'sm' ? 'h-5.5 gap-1 px-2 text-xs' : 'h-7 gap-1.5 px-3 text-13',\n pressed\n ? 'border-sui-accent-line bg-sui-accent-wash text-sui-accent enabled:hover:border-sui-accent-bright enabled:hover:bg-sui-accent-soft enabled:active:border-sui-accent-solid enabled:active:bg-sui-accent-soft'\n : 'border-sui-line bg-sui-surface text-sui-ink-body enabled:hover:border-sui-line-strong enabled:hover:bg-sui-canvas enabled:hover:text-sui-ink enabled:active:bg-sui-sunken'\n ]\"\n :disabled=\"disabled\"\n type=\"button\"\n @click=\"pressed = !pressed\"\n >\n <svg\n v-if=\"pressed\"\n aria-hidden=\"true\"\n class=\"-ml-0.5 size-3 shrink-0 fill-none stroke-current\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.75\"\n viewBox=\"0 0 16 16\"\n >\n <path d=\"M3.5 8.25l3 3 6-6.5\" />\n </svg>\n <slot>{{ name }}</slot>\n </button>\n <span\n v-else-if=\"variant === 'outline'\"\n class=\"inline-flex items-center gap-1.5 rounded-md border px-2 py-1 text-xs whitespace-nowrap\"\n :class=\"\n muted ? 'border-sui-line-subtle text-sui-ink-muted' : 'border-sui-line bg-sui-sunken font-medium text-sui-ink'\n \"\n >\n <slot>{{ name }}</slot>\n </span>\n <div\n v-else\n class=\"inline-flex items-center gap-1.5 rounded-md bg-sui-sunken px-2 py-0.5 text-xs font-medium text-sui-ink-body\"\n >\n <span v-if=\"color\" class=\"h-1.5 w-1.5 shrink-0 rounded-full\" :class=\"dots[color]\" />\n <span class=\"truncate\"\n ><slot>{{ name }}</slot></span\n >\n <button\n v-if=\"removable\"\n :aria-label=\"removeLabel\"\n class=\"-mr-0.5 inline-flex h-3.5 w-3.5 items-center justify-center rounded-full transition-colors hover:bg-sui-line focus-visible:sui-ring\"\n type=\"button\"\n @click=\"$emit('remove')\"\n >\n <CloseSmallIcon class=\"fill-sui-ink-muted stroke-sui-ink-muted\" />\n </button>\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -16,6 +16,8 @@ export interface TagProps {
|
|
|
16
16
|
pressable?: boolean;
|
|
17
17
|
/** pressable only. */
|
|
18
18
|
disabled?: boolean;
|
|
19
|
+
/** pressable only: md is 28px, sm 22px for a dense row of filters. */
|
|
20
|
+
size?: 'sm' | 'md';
|
|
19
21
|
}
|
|
20
22
|
type __VLS_Props = TagProps;
|
|
21
23
|
type __VLS_ModelProps = {
|
|
@@ -38,6 +40,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
|
|
|
38
40
|
"onUpdate:pressed"?: ((value: boolean) => any) | undefined;
|
|
39
41
|
}>, {
|
|
40
42
|
variant: "soft" | "outline";
|
|
43
|
+
size: "sm" | "md";
|
|
41
44
|
name: string;
|
|
42
45
|
color: Hue;
|
|
43
46
|
removeLabel: string;
|
|
@@ -22,7 +22,8 @@ var p = ["aria-pressed", "disabled"], m = {
|
|
|
22
22
|
removable: { type: Boolean },
|
|
23
23
|
removeLabel: { default: "Remove tag" },
|
|
24
24
|
pressable: { type: Boolean },
|
|
25
|
-
disabled: { type: Boolean }
|
|
25
|
+
disabled: { type: Boolean },
|
|
26
|
+
size: { default: "md" }
|
|
26
27
|
}, {
|
|
27
28
|
pressed: {
|
|
28
29
|
type: Boolean,
|
|
@@ -46,7 +47,7 @@ var p = ["aria-pressed", "disabled"], m = {
|
|
|
46
47
|
return (f, y) => o.pressable ? (l(), n("button", {
|
|
47
48
|
key: 0,
|
|
48
49
|
"aria-pressed": s.value,
|
|
49
|
-
class: c(["inline-flex
|
|
50
|
+
class: c(["inline-flex cursor-pointer items-center rounded-md border leading-none font-medium whitespace-nowrap transition-colors duration-150 outline-hidden focus-visible:sui-ring disabled:cursor-default disabled:opacity-50", [o.size === "sm" ? "h-5.5 gap-1 px-2 text-xs" : "h-7 gap-1.5 px-3 text-13", s.value ? "border-sui-accent-line bg-sui-accent-wash text-sui-accent enabled:hover:border-sui-accent-bright enabled:hover:bg-sui-accent-soft enabled:active:border-sui-accent-solid enabled:active:bg-sui-accent-soft" : "border-sui-line bg-sui-surface text-sui-ink-body enabled:hover:border-sui-line-strong enabled:hover:bg-sui-canvas enabled:hover:text-sui-ink enabled:active:bg-sui-sunken"]]),
|
|
50
51
|
disabled: o.disabled,
|
|
51
52
|
type: "button",
|
|
52
53
|
onClick: y[0] ||= (e) => s.value = !s.value
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tag.vue_vue_type_script_setup_true_lang.js","names":["$emit","_useModel","_openBlock","_createElementBlock","_normalizeClass","_createElementVNode","_createCommentVNode","_renderSlot","_createTextVNode","_toDisplayString","_createVNode","CloseSmallIcon","CloseSmallIcon_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","Tag_vue_vue_type_script_setup_true_lang_default","\"pressed\"","\"pressedModifiers\"","pressed","useModel","__props","dots","openBlock","createElementBlock","normalizeClass","_cache","createElementVNode","createCommentVNode","renderSlot","_ctx","createTextVNode","toDisplayString","createVNode"],"sources":["../../../src/components/Tag/Tag.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { Hue } from '../../utils/hues'\nimport CloseSmallIcon from '../internal/CloseSmallIcon.vue'\n\nexport interface TagProps {\n /** The text; or use the default slot. */\n name?: string\n /** soft: a label people create, with an optional hue dot, removable. outline: a value from a fixed set (a stage, a status). */\n variant?: 'soft' | 'outline'\n /** soft only: a dot of the tag's own hue, on a neutral chip. */\n color?: Hue\n /** outline only: the quieter, superseded side, e.g. the \"from\" of a stage change. */\n muted?: boolean\n /** soft only. */\n removable?: boolean\n /** The remove button's accessible name. */\n removeLabel?: string\n /** A toggle button for quick choices, bound to `v-model:pressed`. Group several in a `role=\"group\"` with a label. */\n pressable?: boolean\n /** pressable only. */\n disabled?: boolean\n}\n\nwithDefaults(defineProps<TagProps>(), {\n name: undefined,\n variant: 'soft',\n color: undefined,\n removeLabel: 'Remove tag'\n})\n\ndefineEmits<{ remove: [] }>()\n\nconst pressed = defineModel<boolean>('pressed', { default: false })\n\nconst dots: Record<Hue, string> = {\n blue: 'bg-sui-hue-blue-ink',\n green: 'bg-sui-hue-green-ink',\n orange: 'bg-sui-hue-orange-ink',\n pink: 'bg-sui-hue-pink-ink',\n purple: 'bg-sui-hue-purple-ink',\n slate: 'bg-sui-hue-slate-ink',\n red: 'bg-sui-hue-red-ink',\n amber: 'bg-sui-hue-amber-ink',\n gray: 'bg-sui-ink'\n}\n</script>\n\n<!-- A label: soft for the ones people create, outline for a value from a fixed set; or, pressable, a toggle chip. -->\n<template>\n <button\n v-if=\"pressable\"\n :aria-pressed=\"pressed\"\n class=\"inline-flex
|
|
1
|
+
{"version":3,"file":"Tag.vue_vue_type_script_setup_true_lang.js","names":["$emit","_useModel","_openBlock","_createElementBlock","_normalizeClass","_createElementVNode","_createCommentVNode","_renderSlot","_createTextVNode","_toDisplayString","_createVNode","CloseSmallIcon","CloseSmallIcon_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","Tag_vue_vue_type_script_setup_true_lang_default","\"pressed\"","\"pressedModifiers\"","pressed","useModel","__props","dots","openBlock","createElementBlock","normalizeClass","_cache","createElementVNode","createCommentVNode","renderSlot","_ctx","createTextVNode","toDisplayString","createVNode"],"sources":["../../../src/components/Tag/Tag.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { Hue } from '../../utils/hues'\nimport CloseSmallIcon from '../internal/CloseSmallIcon.vue'\n\nexport interface TagProps {\n /** The text; or use the default slot. */\n name?: string\n /** soft: a label people create, with an optional hue dot, removable. outline: a value from a fixed set (a stage, a status). */\n variant?: 'soft' | 'outline'\n /** soft only: a dot of the tag's own hue, on a neutral chip. */\n color?: Hue\n /** outline only: the quieter, superseded side, e.g. the \"from\" of a stage change. */\n muted?: boolean\n /** soft only. */\n removable?: boolean\n /** The remove button's accessible name. */\n removeLabel?: string\n /** A toggle button for quick choices, bound to `v-model:pressed`. Group several in a `role=\"group\"` with a label. */\n pressable?: boolean\n /** pressable only. */\n disabled?: boolean\n /** pressable only: md is 28px, sm 22px for a dense row of filters. */\n size?: 'sm' | 'md'\n}\n\nwithDefaults(defineProps<TagProps>(), {\n name: undefined,\n variant: 'soft',\n color: undefined,\n removeLabel: 'Remove tag',\n size: 'md'\n})\n\ndefineEmits<{ remove: [] }>()\n\nconst pressed = defineModel<boolean>('pressed', { default: false })\n\nconst dots: Record<Hue, string> = {\n blue: 'bg-sui-hue-blue-ink',\n green: 'bg-sui-hue-green-ink',\n orange: 'bg-sui-hue-orange-ink',\n pink: 'bg-sui-hue-pink-ink',\n purple: 'bg-sui-hue-purple-ink',\n slate: 'bg-sui-hue-slate-ink',\n red: 'bg-sui-hue-red-ink',\n amber: 'bg-sui-hue-amber-ink',\n gray: 'bg-sui-ink'\n}\n</script>\n\n<!-- A label: soft for the ones people create, outline for a value from a fixed set; or, pressable, a toggle chip. -->\n<template>\n <button\n v-if=\"pressable\"\n :aria-pressed=\"pressed\"\n class=\"inline-flex cursor-pointer items-center rounded-md border leading-none font-medium whitespace-nowrap transition-colors duration-150 outline-hidden focus-visible:sui-ring disabled:cursor-default disabled:opacity-50\"\n :class=\"[\n size === 'sm' ? 'h-5.5 gap-1 px-2 text-xs' : 'h-7 gap-1.5 px-3 text-13',\n pressed\n ? 'border-sui-accent-line bg-sui-accent-wash text-sui-accent enabled:hover:border-sui-accent-bright enabled:hover:bg-sui-accent-soft enabled:active:border-sui-accent-solid enabled:active:bg-sui-accent-soft'\n : 'border-sui-line bg-sui-surface text-sui-ink-body enabled:hover:border-sui-line-strong enabled:hover:bg-sui-canvas enabled:hover:text-sui-ink enabled:active:bg-sui-sunken'\n ]\"\n :disabled=\"disabled\"\n type=\"button\"\n @click=\"pressed = !pressed\"\n >\n <svg\n v-if=\"pressed\"\n aria-hidden=\"true\"\n class=\"-ml-0.5 size-3 shrink-0 fill-none stroke-current\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.75\"\n viewBox=\"0 0 16 16\"\n >\n <path d=\"M3.5 8.25l3 3 6-6.5\" />\n </svg>\n <slot>{{ name }}</slot>\n </button>\n <span\n v-else-if=\"variant === 'outline'\"\n class=\"inline-flex items-center gap-1.5 rounded-md border px-2 py-1 text-xs whitespace-nowrap\"\n :class=\"\n muted ? 'border-sui-line-subtle text-sui-ink-muted' : 'border-sui-line bg-sui-sunken font-medium text-sui-ink'\n \"\n >\n <slot>{{ name }}</slot>\n </span>\n <div\n v-else\n class=\"inline-flex items-center gap-1.5 rounded-md bg-sui-sunken px-2 py-0.5 text-xs font-medium text-sui-ink-body\"\n >\n <span v-if=\"color\" class=\"h-1.5 w-1.5 shrink-0 rounded-full\" :class=\"dots[color]\" />\n <span class=\"truncate\"\n ><slot>{{ name }}</slot></span\n >\n <button\n v-if=\"removable\"\n :aria-label=\"removeLabel\"\n class=\"-mr-0.5 inline-flex h-3.5 w-3.5 items-center justify-center rounded-full transition-colors hover:bg-sui-line focus-visible:sui-ring\"\n type=\"button\"\n @click=\"$emit('remove')\"\n >\n <CloseSmallIcon class=\"fill-sui-ink-muted stroke-sui-ink-muted\" />\n </button>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmCA,IAAMqB,IAAUpB,EAAoBsB,GAAC,SAA6B,GAE5DC,IAA4B;GAChC,MAAM;GACN,OAAO;GACP,QAAQ;GACR,MAAM;GACN,QAAQ;GACR,OAAO;GACP,KAAK;GACL,OAAO;GACP,MAAM;EACR;E,iBAMUD,EAAA,aADRrB,EAAA,GAAAC,EA0BS,UAAA;;GAxBN,gBAAckB,EAAA;GACf,OAAKjB,EAAA,CAAC,yNAAuN,CAC7MmB,EAAA,SAAI,OAAA,6BAAA,4BAA2EF,EAAA,Q;GAM9F,UAAUE,EAAA;GACX,MAAK;GACJ,SAAK,AAAAK,EAAA,QAAA,MAAE,EAAA,QAAO,CAAIP,EAAA;E,IAGXA,EAAA,SADRnB,EAAA,GAAAC,EAUM,OAVNW,GAUM,CAAA,GAAA,AAAAc,EAAA,OAAA,CADJvB,EAAgC,QAAA,EAA1B,GAAE,sBAAqB,GAAA,MAAA,EAAA,C,kBAE/BE,EAAuByB,EAAA,QAAA,WAAA,CAAA,SAAA,CAAdxB,EAAAC,EAAAc,EAAA,IAAI,GAAA,CAAA,C,eAGFA,EAAA,YAAO,aADpBrB,EAAA,GAAAC,EAQO,QAAA;;GANL,OAAKC,EAAA,CAAC,0FACSmB,EAAA,QAAK,8CAAA,wD;E,IAIpBhB,EAAuByB,EAAA,QAAA,WAAA,CAAA,SAAA,CAAdxB,EAAAC,EAAAc,EAAA,IAAI,GAAA,CAAA,C,YAEfrB,EAAA,GAAAC,EAiBM,OAjBNY,GAiBM;GAbQQ,EAAA,SAAZrB,EAAA,GAAAC,EAAoF,QAAA;;IAAjE,OAAKC,EAAA,CAAC,qCAA4CoB,EAAKD,EAAA,MAAK,CAAA;;GAC/ElB,EAEC,QAFDW,GAEC,CADET,EAAuByB,EAAA,QAAA,WAAA,CAAA,SAAA,CAAdxB,EAAAC,EAAAc,EAAA,IAAI,GAAA,CAAA,C;GAGRA,EAAA,aADRrB,EAAA,GAAAC,EAQS,UAAA;;IANN,cAAYoB,EAAA;IACb,OAAM;IACN,MAAK;IACJ,SAAK,AAAAK,EAAA,QAAA,MAAE5B,EAAAA,MAAK,QAAA;G,IAEbU,EAAkEC,GAAA,EAAlD,OAAM,0CAAyC,CAAA,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toaster.js","names":["_sfc_main","Toaster_vue_vue_type_script_setup_true_lang_default","Toaster_default"],"sources":["../../../src/components/Toast/Toaster.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { reactive } from 'vue'\n\nimport { ToastProvider, ToastRoot, ToastViewport } from 'reka-ui'\n\nimport {\n type ToastAction,\n type ToastDismissReason,\n type ToastSeverity,\n removeToast,\n toastActions,\n toasts\n} from '../../composables/toast'\nimport ToastMessage from './ToastMessage.vue'\n\nexport interface ToastPreview {\n /** Keeps its place as the list changes, so toasts animate in and out like live ones. Defaults to its index. */\n id?: string | number\n summary: string\n detail?: string\n severity?: ToastSeverity\n closable?: boolean\n action?: ToastAction\n actions?: ToastAction[]\n /** With actions, the countdown bar's length in ms; it emits `close` with `timeout` when it runs out. */\n life?: number\n}\n\nexport interface ToasterProps {\n /** The toast region's name for assistive tech; `{hotkey}` is F8, which focuses it. */\n label?: string\n closeLabel?: string\n /**\n * Toasts drawn in place, for docs, designs and demos, instead of the live ones fixed to the viewport. The list is\n * yours: add and remove items, and handle `close`.\n */\n preview?: ToastPreview[]\n}\n\
|
|
1
|
+
{"version":3,"file":"Toaster.js","names":["_sfc_main","Toaster_vue_vue_type_script_setup_true_lang_default","Toaster_default"],"sources":["../../../src/components/Toast/Toaster.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, reactive } from 'vue'\n\nimport { ToastProvider, ToastRoot, ToastViewport } from 'reka-ui'\n\nimport {\n type ToastAction,\n type ToastDismissReason,\n type ToastSeverity,\n removeToast,\n toastActions,\n toasts\n} from '../../composables/toast'\nimport ToastMessage from './ToastMessage.vue'\n\nexport interface ToastPreview {\n /** Keeps its place as the list changes, so toasts animate in and out like live ones. Defaults to its index. */\n id?: string | number\n summary: string\n detail?: string\n severity?: ToastSeverity\n closable?: boolean\n action?: ToastAction\n actions?: ToastAction[]\n /** With actions, the countdown bar's length in ms; it emits `close` with `timeout` when it runs out. */\n life?: number\n}\n\nexport type ToasterPosition = 'bottom-center' | 'bottom-left' | 'bottom-right' | 'top-center' | 'top-left' | 'top-right'\n\nexport interface ToasterProps {\n /** Where live toasts sit. Move them clear of the app's own chrome with the `--sui-toaster-inset-*` tokens. */\n position?: ToasterPosition\n /** The toast region's name for assistive tech; `{hotkey}` is F8, which focuses it. */\n label?: string\n closeLabel?: string\n /**\n * Toasts drawn in place, for docs, designs and demos, instead of the live ones fixed to the viewport. The list is\n * yours: add and remove items, and handle `close`.\n */\n preview?: ToastPreview[]\n}\n\nconst props = withDefaults(defineProps<ToasterProps>(), {\n position: 'bottom-center',\n label: 'Notifications ({hotkey})',\n closeLabel: 'Close',\n preview: undefined\n})\n\nconst emit = defineEmits<{\n /** A preview toast left, with its `id` (or index): its close button, one of its actions, or its countdown. */\n close: [id: string | number, reason: ToastDismissReason]\n}>()\n\n// Reka pauses every toast's timer while the region is hovered or focused, or the window is in the background; the\n// countdown bars follow it.\nconst paused = reactive(new Set<number>())\n\n// The region sits `--sui-toaster-margin` in from the viewport's edges plus the app's insets, and the safe area\n// beyond them; centred, it centres in what's left between the side insets.\nconst side = (edge: 'left' | 'right') => `calc(var(--sui-toaster-margin) + var(--sui-toaster-inset-${edge}))`\nconst placement = computed(() => {\n const [vertical, horizontal] = props.position.split('-') as ['top' | 'bottom', 'left' | 'center' | 'right']\n return {\n [vertical]: `calc(var(--sui-toaster-margin) + var(--sui-toaster-inset-${vertical}) + env(safe-area-inset-${vertical}))`,\n left: horizontal === 'right' ? 'auto' : side('left'),\n right: horizontal === 'left' ? 'auto' : side('right'),\n width: `min(var(--sui-toaster-width), 100vw - ${side('left')} - ${side('right')})`\n }\n})\nconst fromTop = computed(() => props.position.startsWith('top'))\n\nfunction runLive(id: number, action: ToastAction) {\n action.onClick()\n removeToast(id, 'action')\n}\n\nfunction runPreview(id: string | number, action: ToastAction) {\n action.onClick()\n emit('close', id, 'action')\n}\n</script>\n\n<!-- Mount once near the app root; `toast.info(...)` and friends show here. Swiping is off. -->\n<template>\n <TransitionGroup\n v-if=\"preview\"\n class=\"flex w-full max-w-96 flex-col\"\n enter-active-class=\"animate-sui-toast-in\"\n leave-active-class=\"animate-sui-toast-out overflow-hidden\"\n tag=\"div\"\n >\n <ToastMessage\n v-for=\"(item, index) in preview\"\n :key=\"item.id ?? index\"\n :actions=\"toastActions(item)\"\n :closable=\"item.closable\"\n :close-label=\"closeLabel\"\n :detail=\"item.detail\"\n :life=\"item.life\"\n :severity=\"item.severity\"\n :summary=\"item.summary\"\n @action=\"runPreview(item.id ?? index, $event)\"\n @close=\"emit('close', item.id ?? index, 'close')\"\n @expire=\"emit('close', item.id ?? index, 'timeout')\"\n />\n </TransitionGroup>\n <ToastProvider v-else :swipe-threshold=\"Number.POSITIVE_INFINITY\">\n <ToastRoot\n v-for=\"item in toasts\"\n :key=\"item.id\"\n as-child\n :duration=\"item.life || Number.POSITIVE_INFINITY\"\n :open=\"item.open\"\n :type=\"item.severity === 'error' ? 'foreground' : 'background'\"\n @escape-key-down=\"removeToast(item.id, 'close')\"\n @pause=\"paused.add(item.id)\"\n @resume=\"paused.delete(item.id)\"\n @update:open=\"(open) => !open && removeToast(item.id, 'timeout')\"\n >\n <ToastMessage\n :actions=\"item.actions\"\n class=\"pointer-events-auto data-[state=closed]:overflow-hidden data-[state=closed]:animate-sui-toast-out motion-reduce:data-[state=closed]:animate-sui-toast-fade\"\n :class=\"\n fromTop\n ? 'data-[state=open]:animate-sui-toast-in-top motion-reduce:data-[state=open]:animate-sui-fade-in'\n : 'data-[state=open]:animate-sui-toast-in motion-reduce:data-[state=open]:animate-sui-fade-in'\n \"\n :closable=\"item.closable\"\n :close-label=\"closeLabel\"\n :detail=\"item.detail\"\n :life=\"item.life\"\n :paused=\"paused.has(item.id)\"\n :severity=\"item.severity\"\n :summary=\"item.summary\"\n @action=\"runLive(item.id, $event)\"\n @close=\"removeToast(item.id, 'close')\"\n />\n </ToastRoot>\n <!-- A div, not Reka's default ol: the toasts are divs, so a page can draw one alone. From the top, the newest is\n nearest the edge, as it is at the bottom. -->\n <ToastViewport\n as=\"div\"\n class=\"pointer-events-none fixed z-[1200] mx-auto flex rounded-md outline-hidden\"\n :class=\"fromTop ? 'flex-col-reverse' : 'flex-col'\"\n :data-sui-position=\"position\"\n data-sui-toasts\n :label=\"label\"\n :style=\"placement\"\n />\n </ToastProvider>\n</template>\n"],"mappings":""}
|
|
@@ -11,7 +11,10 @@ export interface ToastPreview {
|
|
|
11
11
|
/** With actions, the countdown bar's length in ms; it emits `close` with `timeout` when it runs out. */
|
|
12
12
|
life?: number;
|
|
13
13
|
}
|
|
14
|
+
export type ToasterPosition = 'bottom-center' | 'bottom-left' | 'bottom-right' | 'top-center' | 'top-left' | 'top-right';
|
|
14
15
|
export interface ToasterProps {
|
|
16
|
+
/** Where live toasts sit. Move them clear of the app's own chrome with the `--sui-toaster-inset-*` tokens. */
|
|
17
|
+
position?: ToasterPosition;
|
|
15
18
|
/** The toast region's name for assistive tech; `{hotkey}` is F8, which focuses it. */
|
|
16
19
|
label?: string;
|
|
17
20
|
closeLabel?: string;
|
|
@@ -28,6 +31,7 @@ declare const __VLS_export: import("vue").DefineComponent<ToasterProps, {}, {},
|
|
|
28
31
|
}>, {
|
|
29
32
|
label: string;
|
|
30
33
|
closeLabel: string;
|
|
34
|
+
position: ToasterPosition;
|
|
31
35
|
preview: ToastPreview[];
|
|
32
36
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
33
37
|
declare const _default: typeof __VLS_export;
|