@sparklingopinions/sparkling-ui 0.5.0 → 0.7.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 +1 -1
- package/dist/aliases.d.ts +176 -26
- package/dist/components/Avatar/Avatar.js.map +1 -1
- package/dist/components/Avatar/Avatar.vue.d.ts +3 -2
- package/dist/components/Avatar/Avatar.vue_vue_type_script_setup_true_lang.js +20 -14
- package/dist/components/Avatar/Avatar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/Button/Button.js.map +1 -1
- package/dist/components/Button/Button.vue.d.ts +1 -1
- package/dist/components/Button/Button.vue_vue_type_script_setup_true_lang.js +4 -2
- package/dist/components/Button/Button.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/ContextMenu/ContextMenu.js +7 -0
- package/dist/components/ContextMenu/ContextMenu.js.map +1 -0
- package/dist/components/ContextMenu/ContextMenu.vue.d.ts +44 -0
- package/dist/components/ContextMenu/ContextMenu.vue_vue_type_script_setup_true_lang.js +84 -0
- package/dist/components/ContextMenu/ContextMenu.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/ContextMenu/index.d.ts +2 -0
- package/dist/components/DataList/DataList.js.map +1 -1
- package/dist/components/DataList/DataList.vue.d.ts +8 -0
- package/dist/components/DataList/DataList.vue_vue_type_script_setup_true_lang.js +71 -52
- package/dist/components/DataList/DataList.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/DataList/types.d.ts +5 -1
- package/dist/components/Dialog/Dialog.js.map +1 -1
- package/dist/components/Dialog/Dialog.vue.d.ts +22 -6
- package/dist/components/Dialog/Dialog.vue_vue_type_script_setup_true_lang.js +174 -72
- package/dist/components/Dialog/Dialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/Dialog/useSheetDrag.d.ts +16 -0
- package/dist/components/Dialog/useSheetDrag.js +37 -0
- package/dist/components/Dialog/useSheetDrag.js.map +1 -0
- package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.vue.d.ts +6 -30
- package/dist/components/DropdownMenu/DropdownMenu.vue_vue_type_script_setup_true_lang.js +54 -74
- package/dist/components/DropdownMenu/DropdownMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/EmptyState/EmptyState.js.map +1 -1
- package/dist/components/EmptyState/EmptyState.vue.d.ts +9 -3
- package/dist/components/EmptyState/EmptyState.vue_vue_type_script_setup_true_lang.js +35 -7
- package/dist/components/EmptyState/EmptyState.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/Filters/FilterMenu.js.map +1 -1
- package/dist/components/Filters/FilterMenu.vue.d.ts +20 -1
- package/dist/components/Filters/FilterMenu.vue_vue_type_script_setup_true_lang.js +78 -56
- package/dist/components/Filters/FilterMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/Filters/SortMenu.js.map +1 -1
- package/dist/components/Filters/SortMenu.vue.d.ts +21 -1
- package/dist/components/Filters/SortMenu.vue_vue_type_script_setup_true_lang.js +90 -67
- package/dist/components/Filters/SortMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/Filters/index.d.ts +1 -0
- package/dist/components/Filters/trigger.d.ts +17 -0
- package/dist/components/Filters/trigger.js +33 -0
- package/dist/components/Filters/trigger.js.map +1 -0
- package/dist/components/FormField/FormField.js.map +1 -1
- package/dist/components/FormField/FormField.vue.d.ts +10 -0
- package/dist/components/FormField/FormField.vue_vue_type_script_setup_true_lang.js +31 -20
- package/dist/components/FormField/FormField.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/Icon/iconSet.js +25 -1
- package/dist/components/Icon/iconSet.js.map +1 -1
- package/dist/components/SegmentedControl/SegmentedControl.js.map +1 -1
- package/dist/components/SegmentedControl/SegmentedControl.vue.d.ts +6 -3
- package/dist/components/SegmentedControl/SegmentedControl.vue_vue_type_script_setup_true_lang.js +20 -17
- package/dist/components/SegmentedControl/SegmentedControl.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/SegmentedControl/index.d.ts +1 -1
- package/dist/components/Table/Table.js.map +1 -1
- package/dist/components/Table/Table.vue.d.ts +4 -0
- package/dist/components/Table/Table.vue_vue_type_script_setup_true_lang.js +65 -56
- 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 +16 -3
- package/dist/components/Tag/Tag.vue_vue_type_script_setup_true_lang.js +42 -19
- package/dist/components/Tag/Tag.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/Toast/ToastMessage.js.map +1 -1
- package/dist/components/Toast/ToastMessage.vue.d.ts +13 -1
- package/dist/components/Toast/ToastMessage.vue_vue_type_script_setup_true_lang.js +58 -23
- package/dist/components/Toast/ToastMessage.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 +7 -3
- package/dist/components/Toast/Toaster.vue_vue_type_script_setup_true_lang.js +50 -21
- package/dist/components/Toast/Toaster.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/internal/MenuItemContent.js +7 -0
- package/dist/components/internal/MenuItemContent.js.map +1 -0
- package/dist/components/internal/MenuItemContent.vue.d.ts +7 -0
- package/dist/components/internal/MenuItemContent.vue_vue_type_script_setup_true_lang.js +26 -0
- package/dist/components/internal/MenuItemContent.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/internal/menu.d.ts +46 -0
- package/dist/components/internal/menu.js +33 -0
- package/dist/components/internal/menu.js.map +1 -0
- package/dist/composables/toast.d.ts +20 -5
- package/dist/composables/toast.js +28 -20
- package/dist/composables/toast.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +34 -33
- package/package.json +1 -1
- package/src/styles/tailwind.css +29 -0
|
@@ -1,110 +1,90 @@
|
|
|
1
1
|
import e from "../Button/Button.js";
|
|
2
2
|
import t from "../Icon/Icon.js";
|
|
3
3
|
import n from "../Tooltip/Tooltip.js";
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import r from "../internal/MenuItemContent.js";
|
|
5
|
+
import { menuConfirmDefaults as i, menuContentClass as a, menuItemClass as o, menuSeparatorClass as s, useMenuSelect as c } from "../internal/menu.js";
|
|
6
|
+
import { Fragment as l, createBlock as u, createCommentVNode as d, createElementBlock as f, createVNode as p, defineComponent as m, mergeDefaults as h, normalizeClass as g, openBlock as _, ref as v, renderList as y, renderSlot as b, toDisplayString as x, unref as S, withCtx as C, withModifiers as w } from "vue";
|
|
7
|
+
import { DropdownMenuContent as T, DropdownMenuItem as E, DropdownMenuPortal as D, DropdownMenuRoot as O, DropdownMenuSeparator as k, DropdownMenuTrigger as A } from "reka-ui";
|
|
7
8
|
//#region src/components/DropdownMenu/DropdownMenu.vue?vue&type=script&setup=true&lang.ts
|
|
8
|
-
var
|
|
9
|
-
key: 1,
|
|
10
|
-
class: "text-11 text-sui-ink-muted"
|
|
11
|
-
}, k = /*@__PURE__*/ u({
|
|
9
|
+
var j = { key: 0 }, M = /*@__PURE__*/ m({
|
|
12
10
|
__name: "DropdownMenu",
|
|
13
|
-
props: {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
confirmTitle: {
|
|
21
|
-
confirmMessage: {
|
|
22
|
-
confirmLabel: {
|
|
23
|
-
deleteLabel: {
|
|
24
|
-
cancelLabel: {
|
|
25
|
-
},
|
|
11
|
+
props: /*@__PURE__*/ h({
|
|
12
|
+
items: {},
|
|
13
|
+
buttonIcon: {},
|
|
14
|
+
buttonLabel: {},
|
|
15
|
+
tooltip: {},
|
|
16
|
+
align: {},
|
|
17
|
+
id: {},
|
|
18
|
+
confirmTitle: {},
|
|
19
|
+
confirmMessage: {},
|
|
20
|
+
confirmLabel: {},
|
|
21
|
+
deleteLabel: {},
|
|
22
|
+
cancelLabel: {}
|
|
23
|
+
}, {
|
|
24
|
+
...i,
|
|
25
|
+
items: () => [],
|
|
26
|
+
buttonIcon: "more-vertical",
|
|
27
|
+
buttonLabel: void 0,
|
|
28
|
+
tooltip: "More actions",
|
|
29
|
+
align: "start"
|
|
30
|
+
}),
|
|
26
31
|
emits: [
|
|
27
32
|
"click-item",
|
|
28
33
|
"show",
|
|
29
34
|
"hide"
|
|
30
35
|
],
|
|
31
|
-
setup(
|
|
32
|
-
let
|
|
33
|
-
async function P(e) {
|
|
34
|
-
if (e.confirm || e.confirmed) {
|
|
35
|
-
let t = e.variant === "danger" || e.action === "delete";
|
|
36
|
-
if (!await N({
|
|
37
|
-
title: e.confirm?.title ?? A.confirmTitle,
|
|
38
|
-
message: e.confirm?.message ?? A.confirmMessage,
|
|
39
|
-
cancelLabel: A.cancelLabel,
|
|
40
|
-
confirmLabel: e.confirm?.acceptLabel ?? (e.action === "delete" ? A.deleteLabel : A.confirmLabel),
|
|
41
|
-
confirmVariant: t ? "danger" : "primary"
|
|
42
|
-
})) return;
|
|
43
|
-
}
|
|
44
|
-
j("click-item", {
|
|
45
|
-
id: A.id,
|
|
46
|
-
...e
|
|
47
|
-
});
|
|
48
|
-
}
|
|
36
|
+
setup(i, { emit: m }) {
|
|
37
|
+
let h = i, M = m, N = v(!1), P = c(h, (e) => M("click-item", e));
|
|
49
38
|
function F(e) {
|
|
50
|
-
|
|
39
|
+
N.value = e, M(e ? "show" : "hide");
|
|
51
40
|
}
|
|
52
|
-
return (
|
|
41
|
+
return (c, m) => (_(), f("div", null, [p(S(O), {
|
|
53
42
|
modal: !1,
|
|
54
|
-
open:
|
|
43
|
+
open: N.value,
|
|
55
44
|
"onUpdate:open": F
|
|
56
45
|
}, {
|
|
57
|
-
default:
|
|
58
|
-
default:
|
|
59
|
-
disabled: !
|
|
60
|
-
text:
|
|
46
|
+
default: C(() => [p(S(A), { "as-child": "" }, {
|
|
47
|
+
default: C(() => [p(n, {
|
|
48
|
+
disabled: !i.tooltip || N.value,
|
|
49
|
+
text: i.tooltip ?? void 0
|
|
61
50
|
}, {
|
|
62
|
-
default:
|
|
63
|
-
"aria-label":
|
|
64
|
-
"icon-only": !
|
|
51
|
+
default: C(() => [b(c.$slots, "trigger", { open: N.value }, () => [p(e, {
|
|
52
|
+
"aria-label": i.buttonLabel ? void 0 : i.tooltip ?? void 0,
|
|
53
|
+
"icon-only": !i.buttonLabel,
|
|
65
54
|
size: "sm",
|
|
66
55
|
type: "button",
|
|
67
56
|
variant: "ghost",
|
|
68
|
-
onClick:
|
|
57
|
+
onClick: m[0] ||= w(() => {}, ["stop"])
|
|
69
58
|
}, {
|
|
70
|
-
default:
|
|
59
|
+
default: C(() => [i.buttonLabel ? (_(), f("span", j, x(i.buttonLabel), 1)) : d("", !0), i.buttonIcon ? (_(), u(t, {
|
|
71
60
|
key: 1,
|
|
72
61
|
color: "ink-subtle",
|
|
73
|
-
name:
|
|
74
|
-
}, null, 8, ["name"])) :
|
|
62
|
+
name: i.buttonIcon
|
|
63
|
+
}, null, 8, ["name"])) : d("", !0)]),
|
|
75
64
|
_: 1
|
|
76
65
|
}, 8, ["aria-label", "icon-only"])])]),
|
|
77
66
|
_: 3
|
|
78
67
|
}, 8, ["disabled", "text"])]),
|
|
79
68
|
_: 3
|
|
80
|
-
}),
|
|
81
|
-
default:
|
|
82
|
-
align:
|
|
83
|
-
class:
|
|
69
|
+
}), p(S(D), null, {
|
|
70
|
+
default: C(() => [p(S(T), {
|
|
71
|
+
align: i.align,
|
|
72
|
+
class: g([S(a), "min-w-[max(12rem,var(--reka-dropdown-menu-trigger-width))]"]),
|
|
84
73
|
side: "bottom"
|
|
85
74
|
}, {
|
|
86
|
-
default:
|
|
75
|
+
default: C(() => [(_(!0), f(l, null, y(i.items, (e, t) => (_(), f(l, { key: t }, [e.type === "separator" ? (_(), u(S(k), {
|
|
87
76
|
key: 0,
|
|
88
|
-
class:
|
|
89
|
-
})) : (
|
|
77
|
+
class: g(S(s))
|
|
78
|
+
}, null, 8, ["class"])) : (_(), u(S(E), {
|
|
90
79
|
key: 1,
|
|
91
|
-
class:
|
|
92
|
-
onSelect: (t) => P(e)
|
|
80
|
+
class: g(S(o)),
|
|
81
|
+
onSelect: (t) => S(P)(e)
|
|
93
82
|
}, {
|
|
94
|
-
default:
|
|
95
|
-
e.icon ? (f(), a(t, {
|
|
96
|
-
key: 0,
|
|
97
|
-
class: "h-4 w-4 shrink-0",
|
|
98
|
-
color: e.variant === "danger" ? "danger" : "ink-muted",
|
|
99
|
-
name: e.icon
|
|
100
|
-
}, null, 8, ["color", "name"])) : o("", !0),
|
|
101
|
-
c("span", D, g(e.label), 1),
|
|
102
|
-
e.shortcut ? (f(), s("span", O, g(e.shortcut), 1)) : o("", !0)
|
|
103
|
-
], 2)]),
|
|
83
|
+
default: C(() => [p(r, { item: e }, null, 8, ["item"])]),
|
|
104
84
|
_: 2
|
|
105
|
-
}, 1032, ["onSelect"]))], 64))), 128))]),
|
|
85
|
+
}, 1032, ["class", "onSelect"]))], 64))), 128))]),
|
|
106
86
|
_: 1
|
|
107
|
-
}, 8, ["align"])]),
|
|
87
|
+
}, 8, ["align", "class"])]),
|
|
108
88
|
_: 1
|
|
109
89
|
})]),
|
|
110
90
|
_: 3
|
|
@@ -112,6 +92,6 @@ var E = { key: 0 }, D = { class: "flex-1 text-13" }, O = {
|
|
|
112
92
|
}
|
|
113
93
|
});
|
|
114
94
|
//#endregion
|
|
115
|
-
export {
|
|
95
|
+
export { M as default };
|
|
116
96
|
|
|
117
97
|
//# sourceMappingURL=DropdownMenu.vue_vue_type_script_setup_true_lang.js.map
|
package/dist/components/DropdownMenu/DropdownMenu.vue_vue_type_script_setup_true_lang.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DropdownMenu.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_createVNode","_unref","_withCtx","Tooltip","_renderSlot","Button","_withModifiers","_toDisplayString","_createCommentVNode","_createBlock","Icon","
|
|
1
|
+
{"version":3,"file":"DropdownMenu.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_createVNode","_unref","_withCtx","Tooltip","_renderSlot","Button","_withModifiers","_toDisplayString","_createCommentVNode","_createBlock","Icon","_normalizeClass","_Fragment","_renderList","MenuItemContent","Button_default","Icon_default","Tooltip_default","MenuItemContent_default","_hoisted_1","DropdownMenu_vue_vue_type_script_setup_true_lang_default","menuConfirmDefaults","__emit","props","__props","emit","open","ref","select","useMenuSelect","item","onOpenChange","value","openBlock","createElementBlock","createVNode","unref","DropdownMenuRoot","withCtx","DropdownMenuTrigger","renderSlot","_ctx","_cache","withModifiers","toDisplayString","createCommentVNode","createBlock","DropdownMenuPortal","DropdownMenuContent","normalizeClass","menuContentClass","Fragment","renderList","index","DropdownMenuSeparator","menuSeparatorClass","DropdownMenuItem","menuItemClass"],"sources":["../../../src/components/DropdownMenu/DropdownMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref } from 'vue'\n\nimport {\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuPortal,\n DropdownMenuRoot,\n DropdownMenuSeparator,\n DropdownMenuTrigger\n} from 'reka-ui'\n\nimport Button from '../Button/Button.vue'\nimport Icon from '../Icon/Icon.vue'\nimport Tooltip from '../Tooltip/Tooltip.vue'\nimport MenuItemContent from '../internal/MenuItemContent.vue'\nimport {\n type DropdownMenuAction,\n type DropdownMenuEntry,\n type MenuConfirmLabels,\n menuConfirmDefaults,\n menuContentClass,\n menuItemClass,\n menuSeparatorClass,\n useMenuSelect\n} from '../internal/menu'\n\nexport type { DropdownMenuAction, DropdownMenuEntry }\n\nexport interface DropdownMenuProps extends MenuConfirmLabels {\n items?: DropdownMenuEntry[]\n buttonIcon?: string\n /** A label beside the icon; without one the button is icon-only, named by the tooltip. */\n buttonLabel?: string\n /** The trigger's tooltip and name; null for none. */\n tooltip?: string | null\n /** Lines the menu up with the trigger's start or end edge. */\n align?: 'start' | 'end'\n}\n\nconst props = withDefaults(defineProps<DropdownMenuProps>(), {\n ...menuConfirmDefaults,\n items: () => [],\n buttonIcon: 'more-vertical',\n buttonLabel: undefined,\n tooltip: 'More actions',\n align: 'start'\n})\n\nconst emit = defineEmits<{ 'click-item': [item: DropdownMenuAction & { id?: string }]; show: []; hide: [] }>()\n\nconst open = ref(false)\nconst select = useMenuSelect(props, (item) => emit('click-item', item))\n\nfunction onOpenChange(value: boolean) {\n open.value = value\n if (value) emit('show')\n else emit('hide')\n}\n</script>\n\n<template>\n <div>\n <!-- Not modal: the page stays live (hover, scroll) while it's open. -->\n <DropdownMenuRoot :modal=\"false\" :open=\"open\" @update:open=\"onOpenChange\">\n <!-- The tooltip inside the menu's trigger: Reka's anchors attach to the nearest popper, which must be the menu's. -->\n <DropdownMenuTrigger as-child>\n <Tooltip :disabled=\"!tooltip || open\" :text=\"tooltip ?? undefined\">\n <slot name=\"trigger\" :open=\"open\">\n <Button\n :aria-label=\"buttonLabel ? undefined : (tooltip ?? undefined)\"\n :icon-only=\"!buttonLabel\"\n size=\"sm\"\n type=\"button\"\n variant=\"ghost\"\n @click.stop\n >\n <span v-if=\"buttonLabel\">{{ buttonLabel }}</span>\n <Icon v-if=\"buttonIcon\" color=\"ink-subtle\" :name=\"buttonIcon\" />\n </Button>\n </slot>\n </Tooltip>\n </DropdownMenuTrigger>\n <DropdownMenuPortal>\n <DropdownMenuContent\n :align=\"align\"\n :class=\"[menuContentClass, 'min-w-[max(12rem,var(--reka-dropdown-menu-trigger-width))]']\"\n side=\"bottom\"\n >\n <template v-for=\"(item, index) in items\" :key=\"index\">\n <DropdownMenuSeparator v-if=\"item.type === 'separator'\" :class=\"menuSeparatorClass\" />\n <DropdownMenuItem v-else :class=\"menuItemClass\" @select=\"select(item)\">\n <MenuItemContent :item=\"item\" />\n </DropdownMenuItem>\n </template>\n </DropdownMenuContent>\n </DropdownMenuPortal>\n </DropdownMenuRoot>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwCA,IAAMyB,IAAQC,GASRC,IAAOH,GAEPI,IAAOC,EAAI,EAAK,GAChBC,IAASC,EAAcN,IAAQ,MAASE,EAAK,cAAcK,CAAI,CAAC;EAEtE,SAASC,EAAa,GAAgB;GAEpC,AADA,EAAK,QAAQC,GACFP,EAAPO,IAAY,SACN,MAAM;EAClB;E,kBAIElC,EAAA,GAAAC,EAoCM,OAAA,MAAA,CAlCJC,EAiCmBC,EAAAoC,CAAA,GAAA;GAjCA,OAAO;GAAQ,MAAMX,EAAA;GAAO,iBAAaK;;GAE1D,SAAA7B,QAgBsB,CAhBtBF,EAgBsBC,EAAAsC,CAAA,GAAA,EAhBD,YAAA,GAAQ,GAAA;IAC3B,SAAArC,QAcU,CAdVF,EAcUG,GAAA;KAdA,UAAQ,CAAGqB,EAAA,WAAWE,EAAA;KAAO,MAAMF,EAAA,WAAW,KAAA;;KACtD,SAAAtB,QAYO,CAZPE,EAYOqC,EAAA,QAAA,WAAA,EAZe,MAAMf,EAAA,MAAI,SAYzB,CAXL1B,EAUSK,GAAA;MATN,cAAYmB,EAAA,cAAc,KAAA,IAAaA,EAAA,WAAW,KAAA;MAClD,aAAS,CAAGA,EAAA;MACb,MAAK;MACL,MAAK;MACL,SAAQ;MACP,SAAK,AAAAkB,EAAA,OAAApC,QAAN,CAAA,GAAW,CAAA,MAAA,CAAA;;MAEX,SAAAJ,QAAiD,CAArCsB,EAAA,eAAZ1B,EAAA,GAAAC,EAAiD,QAAAoB,GAAAZ,EAArBiB,EAAA,WAAW,GAAA,CAAA,K,WAC3BA,EAAA,cAAZ1B,EAAA,GAAAW,EAAgEC,GAAA;;OAAxC,OAAM;OAAc,MAAMc,EAAA;;;;;;;G,IAK1DxB,EAaqBC,EAAA8C,CAAA,GAAA,MAAA;IAZnB,SAAA7C,QAWsB,CAXtBF,EAWsBC,EAAA+C,CAAA,GAAA;KAVnB,OAAOxB,EAAA;KACP,OAAKb,EAAA,CAAGV,EAAAiD,CAAA,GAAgB,4DAAA,CAAA;KACzB,MAAK;;KAEK,SAAAhD,QAA8B,EAAxCJ,EAAA,EAAA,GAAAC,EAKWa,GAAA,MAAAC,EALuBW,EAAA,QAAhB,GAAM,OAAuB1B,EAAA,GAAAC,EAAAa,GAAA,EAAA,KAAAyC,EAAK,GAAA,CACrBvB,EAAK,SAAI,eAAtChC,EAAA,GAAAW,EAAsFR,EAAAqD,CAAA,GAAA;;MAA7B,OAAK3C,EAAEV,EAAAsD,CAAA,CAAkB;K,2BAClFzD,EAAA,GAAAW,EAEmBR,EAAAuD,CAAA,GAAA;;MAFO,OAAK7C,EAAEV,EAAAwD,CAAA,CAAa;MAAG,WAAM,MAAExD,EAAA2B,CAAA,CAAM,CAACE,CAAI;;MAClE,SAAA5B,QAAgC,CAAhCF,EAAgCc,GAAA,EAAR,QAAI,GAAA,MAAA,GAAA,CAAA,MAAA,CAAA,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmptyState.js","names":["_sfc_main","EmptyState_vue_vue_type_script_setup_true_lang_default","EmptyState_default"],"sources":["../../../src/components/EmptyState/EmptyState.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport Button from '../Button/Button.vue'\nimport Icon from '../Icon/Icon.vue'\n\nexport interface EmptyStateProps {\n title: string\n /** Plain text; for anything richer, use the `description` slot. */\n description?: string\n /** What the list holds, as an icon name (users, inbox, search for no matches), in a tile above the title. Decorative. */\n icon?: string\n /** `accent` for a list waiting to be filled; `neutral` for no matches or a filtered view. */\n tone?: 'accent' | 'neutral'\n /** Shows a primary button with this label, which emits `action`. Or put your own in the `action` slot. */\n actionLabel?: string\n actionIcon?: string\n /** The title's heading level, to fit the page's outline. */\n headingLevel?: 1 | 2 | 3 | 4 | 5 | 6\n}\n\nwithDefaults(defineProps<EmptyStateProps>(), {\n description: undefined,\n icon: undefined,\n tone: 'accent',\n actionLabel: undefined,\n actionIcon: 'plus',\n headingLevel: 2\n})\n\ndefineEmits<{ action: [] }>()\n</script>\n\n<template>\n <div class=\"flex flex-col items-center justify-center px-6 py-16 text-center\">\n <div\n v-if=\"icon\"\n aria-hidden=\"true\"\n class=\"mb-4 flex size-12 items-center justify-center rounded-xl ring-1 ring-inset\"\n :class=\"tone === 'accent' ? 'bg-sui-accent-wash ring-sui-accent-line' : 'bg-sui-sunken ring-sui-line-subtle'\"\n >\n <Icon class=\"size-6\" :color=\"tone === 'accent' ? 'accent' : 'ink-muted'\" :name=\"icon\" />\n </div>\n <component :is=\"`h${headingLevel}`\" class=\"m-0 mb-1.5 text-base font-semibold text-sui-ink\">{{ title }}</component>\n <div class=\"max-w-xs text-sm leading-relaxed text-sui-ink-muted\">\n <slot name=\"description\">{{ description }}</slot>\n </div>\n <slot name=\"action\">\n <Button v-if=\"actionLabel\" class=\"mt-4\" variant=\"primary\" @click=\"$emit('action')\">\n <Icon v-if=\"actionIcon\" :name=\"actionIcon\" />\n {{ actionLabel }}\n </Button>\n </slot>\n </div>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"EmptyState.js","names":["_sfc_main","EmptyState_vue_vue_type_script_setup_true_lang_default","EmptyState_default"],"sources":["../../../src/components/EmptyState/EmptyState.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport Button from '../Button/Button.vue'\nimport Icon from '../Icon/Icon.vue'\n\nexport interface EmptyStateProps {\n title: string\n /** Plain text; for anything richer, use the `description` slot. */\n description?: string\n /** What the list holds, as an icon name (users, inbox, search for no matches), in a tile above the title. Decorative. */\n icon?: string\n /** `accent` for a list waiting to be filled; `neutral` for no matches or a filtered view. */\n tone?: 'accent' | 'neutral'\n /** Shows a primary button with this label, which emits `action`. Or put your own in the `action` slot. */\n actionLabel?: string\n actionIcon?: string\n /** The title's heading level, to fit the page's outline. */\n headingLevel?: 1 | 2 | 3 | 4 | 5 | 6\n /** sm, for an empty card in settings or a tray: an optional 16px icon, the title as one muted line of text (not a\n * heading), a small secondary action. No description. */\n size?: 'md' | 'sm'\n}\n\nwithDefaults(defineProps<EmptyStateProps>(), {\n description: undefined,\n icon: undefined,\n tone: 'accent',\n actionLabel: undefined,\n actionIcon: 'plus',\n headingLevel: 2,\n size: 'md'\n})\n\ndefineEmits<{ action: [] }>()\n</script>\n\n<template>\n <div v-if=\"size === 'sm'\" class=\"flex flex-col items-center justify-center gap-2 px-4 py-5 text-center\">\n <Icon v-if=\"icon\" class=\"size-4\" color=\"ink-muted\" :name=\"icon\" />\n <p class=\"m-0 max-w-full text-13 leading-5 text-sui-ink-muted\">{{ title }}</p>\n <slot name=\"action\">\n <Button v-if=\"actionLabel\" class=\"mt-1\" size=\"sm\" variant=\"secondary\" @click=\"$emit('action')\">\n <Icon v-if=\"actionIcon\" :name=\"actionIcon\" />\n {{ actionLabel }}\n </Button>\n </slot>\n </div>\n <div v-else class=\"flex flex-col items-center justify-center px-6 py-16 text-center\">\n <div\n v-if=\"icon\"\n aria-hidden=\"true\"\n class=\"mb-4 flex size-12 items-center justify-center rounded-xl ring-1 ring-inset\"\n :class=\"tone === 'accent' ? 'bg-sui-accent-wash ring-sui-accent-line' : 'bg-sui-sunken ring-sui-line-subtle'\"\n >\n <Icon class=\"size-6\" :color=\"tone === 'accent' ? 'accent' : 'ink-muted'\" :name=\"icon\" />\n </div>\n <component :is=\"`h${headingLevel}`\" class=\"m-0 mb-1.5 text-base font-semibold text-sui-ink\">{{ title }}</component>\n <div class=\"max-w-xs text-sm leading-relaxed text-sui-ink-muted\">\n <slot name=\"description\">{{ description }}</slot>\n </div>\n <slot name=\"action\">\n <Button v-if=\"actionLabel\" class=\"mt-4\" variant=\"primary\" @click=\"$emit('action')\">\n <Icon v-if=\"actionIcon\" :name=\"actionIcon\" />\n {{ actionLabel }}\n </Button>\n </slot>\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -11,18 +11,24 @@ export interface EmptyStateProps {
|
|
|
11
11
|
actionIcon?: string;
|
|
12
12
|
/** The title's heading level, to fit the page's outline. */
|
|
13
13
|
headingLevel?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
14
|
+
/** sm, for an empty card in settings or a tray: an optional 16px icon, the title as one muted line of text (not a
|
|
15
|
+
* heading), a small secondary action. No description. */
|
|
16
|
+
size?: 'md' | 'sm';
|
|
14
17
|
}
|
|
15
|
-
declare var
|
|
18
|
+
declare var __VLS_6: {}, __VLS_32: {}, __VLS_34: {};
|
|
16
19
|
type __VLS_Slots = {} & {
|
|
17
|
-
|
|
20
|
+
action?: (props: typeof __VLS_6) => any;
|
|
18
21
|
} & {
|
|
19
|
-
|
|
22
|
+
description?: (props: typeof __VLS_32) => any;
|
|
23
|
+
} & {
|
|
24
|
+
action?: (props: typeof __VLS_34) => any;
|
|
20
25
|
};
|
|
21
26
|
declare const __VLS_base: import("vue").DefineComponent<EmptyStateProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
22
27
|
action: () => any;
|
|
23
28
|
}, string, import("vue").PublicProps, Readonly<EmptyStateProps> & Readonly<{
|
|
24
29
|
onAction?: (() => any) | undefined;
|
|
25
30
|
}>, {
|
|
31
|
+
size: "sm" | "md";
|
|
26
32
|
icon: string;
|
|
27
33
|
tone: "accent" | "neutral";
|
|
28
34
|
headingLevel: 1 | 2 | 3 | 4 | 5 | 6;
|
|
@@ -2,7 +2,13 @@ import e from "../Button/Button.js";
|
|
|
2
2
|
import t from "../Icon/Icon.js";
|
|
3
3
|
import { createBlock as n, createCommentVNode as r, createElementBlock as i, createElementVNode as a, createTextVNode as o, createVNode as s, defineComponent as c, normalizeClass as l, openBlock as u, renderSlot as d, resolveDynamicComponent as f, toDisplayString as p, withCtx as m } from "vue";
|
|
4
4
|
//#region src/components/EmptyState/EmptyState.vue?vue&type=script&setup=true&lang.ts
|
|
5
|
-
var h = {
|
|
5
|
+
var h = {
|
|
6
|
+
key: 0,
|
|
7
|
+
class: "flex flex-col items-center justify-center gap-2 px-4 py-5 text-center"
|
|
8
|
+
}, g = { class: "m-0 max-w-full text-13 leading-5 text-sui-ink-muted" }, _ = {
|
|
9
|
+
key: 1,
|
|
10
|
+
class: "flex flex-col items-center justify-center px-6 py-16 text-center"
|
|
11
|
+
}, v = { class: "max-w-xs text-sm leading-relaxed text-sui-ink-muted" }, y = /*@__PURE__*/ c({
|
|
6
12
|
__name: "EmptyState",
|
|
7
13
|
props: {
|
|
8
14
|
title: {},
|
|
@@ -11,11 +17,33 @@ var h = { class: "flex flex-col items-center justify-center px-6 py-16 text-cent
|
|
|
11
17
|
tone: { default: "accent" },
|
|
12
18
|
actionLabel: { default: void 0 },
|
|
13
19
|
actionIcon: { default: "plus" },
|
|
14
|
-
headingLevel: { default: 2 }
|
|
20
|
+
headingLevel: { default: 2 },
|
|
21
|
+
size: { default: "md" }
|
|
15
22
|
},
|
|
16
23
|
emits: ["action"],
|
|
17
24
|
setup(c) {
|
|
18
|
-
return (
|
|
25
|
+
return (y, b) => c.size === "sm" ? (u(), i("div", h, [
|
|
26
|
+
c.icon ? (u(), n(t, {
|
|
27
|
+
key: 0,
|
|
28
|
+
class: "size-4",
|
|
29
|
+
color: "ink-muted",
|
|
30
|
+
name: c.icon
|
|
31
|
+
}, null, 8, ["name"])) : r("", !0),
|
|
32
|
+
a("p", g, p(c.title), 1),
|
|
33
|
+
d(y.$slots, "action", {}, () => [c.actionLabel ? (u(), n(e, {
|
|
34
|
+
key: 0,
|
|
35
|
+
class: "mt-1",
|
|
36
|
+
size: "sm",
|
|
37
|
+
variant: "secondary",
|
|
38
|
+
onClick: b[0] ||= (e) => y.$emit("action")
|
|
39
|
+
}, {
|
|
40
|
+
default: m(() => [c.actionIcon ? (u(), n(t, {
|
|
41
|
+
key: 0,
|
|
42
|
+
name: c.actionIcon
|
|
43
|
+
}, null, 8, ["name"])) : r("", !0), o(" " + p(c.actionLabel), 1)]),
|
|
44
|
+
_: 1
|
|
45
|
+
})) : r("", !0)])
|
|
46
|
+
])) : (u(), i("div", _, [
|
|
19
47
|
c.icon ? (u(), i("div", {
|
|
20
48
|
key: 0,
|
|
21
49
|
"aria-hidden": "true",
|
|
@@ -29,12 +57,12 @@ var h = { class: "flex flex-col items-center justify-center px-6 py-16 text-cent
|
|
|
29
57
|
default: m(() => [o(p(c.title), 1)]),
|
|
30
58
|
_: 1
|
|
31
59
|
})),
|
|
32
|
-
a("div",
|
|
33
|
-
d(
|
|
60
|
+
a("div", v, [d(y.$slots, "description", {}, () => [o(p(c.description), 1)])]),
|
|
61
|
+
d(y.$slots, "action", {}, () => [c.actionLabel ? (u(), n(e, {
|
|
34
62
|
key: 0,
|
|
35
63
|
class: "mt-4",
|
|
36
64
|
variant: "primary",
|
|
37
|
-
onClick:
|
|
65
|
+
onClick: b[1] ||= (e) => y.$emit("action")
|
|
38
66
|
}, {
|
|
39
67
|
default: m(() => [c.actionIcon ? (u(), n(t, {
|
|
40
68
|
key: 0,
|
|
@@ -46,6 +74,6 @@ var h = { class: "flex flex-col items-center justify-center px-6 py-16 text-cent
|
|
|
46
74
|
}
|
|
47
75
|
});
|
|
48
76
|
//#endregion
|
|
49
|
-
export {
|
|
77
|
+
export { y as default };
|
|
50
78
|
|
|
51
79
|
//# sourceMappingURL=EmptyState.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmptyState.vue_vue_type_script_setup_true_lang.js","names":["$emit","_openBlock","_createElementBlock","
|
|
1
|
+
{"version":3,"file":"EmptyState.vue_vue_type_script_setup_true_lang.js","names":["$emit","_openBlock","_createElementBlock","_createBlock","Icon","_createCommentVNode","_createElementVNode","_toDisplayString","_renderSlot","Button","_withCtx","_createTextVNode","_normalizeClass","_createVNode","_resolveDynamicComponent","Button_default","Icon_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","EmptyState_vue_vue_type_script_setup_true_lang_default","__props","openBlock","createElementBlock","createBlock","createCommentVNode","createElementVNode","toDisplayString","renderSlot","_ctx","_cache","withCtx","createTextVNode","normalizeClass","createVNode","resolveDynamicComponent"],"sources":["../../../src/components/EmptyState/EmptyState.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport Button from '../Button/Button.vue'\nimport Icon from '../Icon/Icon.vue'\n\nexport interface EmptyStateProps {\n title: string\n /** Plain text; for anything richer, use the `description` slot. */\n description?: string\n /** What the list holds, as an icon name (users, inbox, search for no matches), in a tile above the title. Decorative. */\n icon?: string\n /** `accent` for a list waiting to be filled; `neutral` for no matches or a filtered view. */\n tone?: 'accent' | 'neutral'\n /** Shows a primary button with this label, which emits `action`. Or put your own in the `action` slot. */\n actionLabel?: string\n actionIcon?: string\n /** The title's heading level, to fit the page's outline. */\n headingLevel?: 1 | 2 | 3 | 4 | 5 | 6\n /** sm, for an empty card in settings or a tray: an optional 16px icon, the title as one muted line of text (not a\n * heading), a small secondary action. No description. */\n size?: 'md' | 'sm'\n}\n\nwithDefaults(defineProps<EmptyStateProps>(), {\n description: undefined,\n icon: undefined,\n tone: 'accent',\n actionLabel: undefined,\n actionIcon: 'plus',\n headingLevel: 2,\n size: 'md'\n})\n\ndefineEmits<{ action: [] }>()\n</script>\n\n<template>\n <div v-if=\"size === 'sm'\" class=\"flex flex-col items-center justify-center gap-2 px-4 py-5 text-center\">\n <Icon v-if=\"icon\" class=\"size-4\" color=\"ink-muted\" :name=\"icon\" />\n <p class=\"m-0 max-w-full text-13 leading-5 text-sui-ink-muted\">{{ title }}</p>\n <slot name=\"action\">\n <Button v-if=\"actionLabel\" class=\"mt-1\" size=\"sm\" variant=\"secondary\" @click=\"$emit('action')\">\n <Icon v-if=\"actionIcon\" :name=\"actionIcon\" />\n {{ actionLabel }}\n </Button>\n </slot>\n </div>\n <div v-else class=\"flex flex-col items-center justify-center px-6 py-16 text-center\">\n <div\n v-if=\"icon\"\n aria-hidden=\"true\"\n class=\"mb-4 flex size-12 items-center justify-center rounded-xl ring-1 ring-inset\"\n :class=\"tone === 'accent' ? 'bg-sui-accent-wash ring-sui-accent-line' : 'bg-sui-sunken ring-sui-line-subtle'\"\n >\n <Icon class=\"size-6\" :color=\"tone === 'accent' ? 'accent' : 'ink-muted'\" :name=\"icon\" />\n </div>\n <component :is=\"`h${headingLevel}`\" class=\"m-0 mb-1.5 text-base font-semibold text-sui-ink\">{{ title }}</component>\n <div class=\"max-w-xs text-sm leading-relaxed text-sui-ink-muted\">\n <slot name=\"description\">{{ description }}</slot>\n </div>\n <slot name=\"action\">\n <Button v-if=\"actionLabel\" class=\"mt-4\" variant=\"primary\" @click=\"$emit('action')\">\n <Icon v-if=\"actionIcon\" :name=\"actionIcon\" />\n {{ actionLabel }}\n </Button>\n </slot>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;E,iBAoCasB,EAAA,SAAI,QAAfrB,EAAA,GAAAC,EASM,OATNe,GASM;GARQK,EAAA,QAAZrB,EAAA,GAAAE,EAAkEC,GAAA;;IAAhD,OAAM;IAAS,OAAM;IAAa,MAAMkB,EAAA;;GAC1DhB,EAA8E,KAA9EY,GAA8EX,EAAZe,EAAA,KAAK,GAAA,CAAA;GACvEd,EAKOsB,EAAA,QAAA,UAAA,CAAA,SAAA,CAJSR,EAAA,eAAdrB,EAAA,GAAAE,EAGSM,GAAA;;IAHkB,OAAM;IAAO,MAAK;IAAK,SAAQ;IAAa,SAAK,AAAAsB,EAAA,QAAA,MAAE/B,EAAAA,MAAK,QAAA;;IACjF,SAAAU,QAA6C,CAAjCY,EAAA,cAAZrB,EAAA,GAAAE,EAA6CC,GAAA;;KAApB,MAAMkB,EAAA;I,oCAAcX,EAAA,MAC7CJ,EAAGe,EAAA,WAAW,GAAA,CAAA,C;;;E,OAIpBrB,EAAA,GAAAC,EAmBM,OAnBNiB,GAmBM;GAjBIG,EAAA,QADRrB,EAAA,GAAAC,EAOM,OAAA;;IALJ,eAAY;IACZ,OAAKU,EAAA,CAAC,8EACEU,EAAA,SAAI,WAAA,4CAAA,oCAAA,CAAA;G,IAEZT,EAAwFT,GAAA;IAAlF,OAAM;IAAU,OAAOkB,EAAA,SAAI,WAAA,WAAA;IAAyC,MAAMA,EAAA;;IAElFrB,EAAA,GAAAE,EAAmHW,EAAA,IAA/FQ,EAAA,cAAY,GAAA,EAAI,OAAM,kDAAiD,GAAA;IAAC,SAAAZ,QAAW,CAARC,EAAAJ,EAAAe,EAAA,KAAK,GAAA,CAAA,C;;;GACpGhB,EAEM,OAFNc,GAEM,CADJZ,EAAiDsB,EAAA,QAAA,eAAA,CAAA,SAAA,CAArBnB,EAAAJ,EAAAe,EAAA,WAAW,GAAA,CAAA,C;GAEzCd,EAKOsB,EAAA,QAAA,UAAA,CAAA,SAAA,CAJSR,EAAA,eAAdrB,EAAA,GAAAE,EAGSM,GAAA;;IAHkB,OAAM;IAAO,SAAQ;IAAW,SAAK,AAAAsB,EAAA,QAAA,MAAE/B,EAAAA,MAAK,QAAA;;IACrE,SAAAU,QAA6C,CAAjCY,EAAA,cAAZrB,EAAA,GAAAE,EAA6CC,GAAA;;KAApB,MAAMkB,EAAA;I,oCAAcX,EAAA,MAC7CJ,EAAGe,EAAA,WAAW,GAAA,CAAA,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FilterMenu.js","names":["_sfc_main","FilterMenu_vue_vue_type_script_setup_true_lang_default","FilterMenu_default"],"sources":["../../../src/components/Filters/FilterMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, useAttrs } from 'vue'\n\nimport {\n ListboxContent,\n ListboxFilter,\n ListboxGroup,\n ListboxGroupLabel,\n ListboxItem,\n ListboxRoot,\n PopoverContent,\n PopoverPortal,\n PopoverRoot,\n PopoverTrigger\n} from 'reka-ui'\n\nimport Button from '../Button/Button.vue'\nimport FilterFrame from './FilterFrame.vue'\nimport FilterGlyph from './FilterGlyph.vue'\nimport type { FilterField } from './types'\n\nexport interface FilterMenuProps {\n fields: FilterField[]\n /** Fields already filtering, marked \"In use\"; picking one should open its chip, not add a second. */\n inUse?: string[]\n /** chip: the dashed \"+ Filter\" in the view bar. button: the page header's Filters button, tinted while filters are in use. */\n as?: 'chip' | 'button'\n /** The footer's status; \"{count} fields\" by default. */\n status?: string\n label?: string\n buttonLabel?: string\n searchPlaceholder?: string\n inUseLabel?: string\n addLabel?: string\n closeLabel?: string\n /** `{count}` is the number of fields. */\n fieldsLabel?: string\n /** `{query}` is what was typed. */\n noMatchLabel?: string\n}\n\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<FilterMenuProps>(), {\n inUse: () => [],\n as: 'chip',\n status: undefined,\n label: 'Filter',\n buttonLabel: 'Filters',\n searchPlaceholder: 'Filter by…',\n inUseLabel: 'In use',\n addLabel: 'Add',\n closeLabel: 'Close',\n fieldsLabel: '{count} fields',\n noMatchLabel: 'No field matches “{query}”.'\n})\n\nconst emit = defineEmits<{ pick: [name: string] }>()\n\nconst open = defineModel<boolean>('open', { default: false })\n\nconst attrs = useAttrs()\nconst query = ref('')\n// Only the keyboard's highlight gets the focus ring; the pointer's is just a tint.\nconst keyboard = ref(false)\n\nconst groups = computed(() => {\n const q = query.value.trim().toLowerCase()\n const shown = props.fields.filter((f) => !q || f.label.toLowerCase().includes(q))\n return [...new Set(shown.map((f) => f.group ?? ''))].map((name) => ({\n name,\n fields: shown.filter((f) => (f.group ?? '') === name)\n }))\n})\n\nfunction pick(name: unknown) {\n if (typeof name !== 'string') return\n open.value = false\n query.value = ''\n emit('pick', name)\n}\n\nfunction onOpen(isOpen: boolean) {\n if (!isOpen) query.value = ''\n}\n\nfunction onKeydown(event: KeyboardEvent) {\n if (['ArrowUp', 'ArrowDown', 'Home', 'End'].includes(event.key)) keyboard.value = true\n}\n</script>\n\n<!-- The field list behind \"+ Filter\": search, fields grouped with their type, and which are already filtering. -->\n<template>\n <PopoverRoot v-model:open=\"open\" @update:open=\"onOpen\">\n <PopoverTrigger v-if=\"as === 'button'\" as-child>\n <Button v-bind=\"attrs\" :variant=\"inUse.length ? 'tinted' : 'secondary'\">\n <svg\n aria-hidden=\"true\"\n class=\"size-4 fill-none stroke-current\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 16 16\"\n >\n <path d=\"M2.5 3.5h11l-4.25 5v4l-2.5 1v-5z\" />\n </svg>\n {{ buttonLabel }}\n </Button>\n </PopoverTrigger>\n <PopoverTrigger\n v-else\n v-bind=\"attrs\"\n class=\"inline-flex h-7.5 items-center gap-1.5 rounded-lg border border-dashed border-sui-line-strong px-2 text-13 font-medium whitespace-nowrap text-sui-ink-muted outline-hidden transition-[border-color,box-shadow] duration-150 hover:border-sui-ink-muted hover:text-sui-ink-body focus-visible:sui-ring data-[state=open]:border-solid data-[state=open]:border-sui-accent-solid data-[state=open]:text-sui-accent data-[state=open]:shadow-[0_0_0_3px_rgb(var(--sui-focus-ring))]\"\n >\n <FilterGlyph name=\"plus\" />\n {{ label }}\n </PopoverTrigger>\n <PopoverPortal>\n <PopoverContent\n align=\"start\"\n class=\"z-[1100] w-85 max-w-[calc(100vw-2rem)] origin-(--reka-popover-content-transform-origin) rounded-xl border border-sui-line bg-sui-surface text-sui-ink shadow-lg data-[state=open]:animate-sui-overlay-in\"\n :side-offset=\"8\"\n @keydown=\"onKeydown\"\n @pointermove=\"keyboard = false\"\n >\n <ListboxRoot highlight-on-hover @update:model-value=\"pick\">\n <FilterFrame\n :close-label=\"closeLabel\"\n :enter-label=\"addLabel\"\n :status=\"status ?? fieldsLabel.replace('{count}', String(fields.length))\"\n >\n <div class=\"flex h-11 items-center gap-2 border-b border-sui-line-subtle px-3.5 text-sui-ink-muted\">\n <FilterGlyph class=\"size-4\" name=\"search\" />\n <ListboxFilter\n v-model=\"query\"\n :aria-label=\"searchPlaceholder\"\n auto-focus\n class=\"h-full min-w-0 flex-1 border-none bg-transparent p-0 text-sm text-sui-ink shadow-none outline-hidden placeholder:text-sui-ink-faint focus:border-none focus:shadow-none focus:ring-0 focus:outline-hidden\"\n :placeholder=\"searchPlaceholder\"\n />\n </div>\n <ListboxContent\n :aria-label=\"searchPlaceholder\"\n class=\"group/list max-h-64 overflow-auto px-1.5 pt-1 pb-1.5 outline-hidden\"\n :data-keyboard=\"keyboard || undefined\"\n >\n <ListboxGroup v-for=\"group in groups\" :key=\"group.name\">\n <ListboxGroupLabel\n v-if=\"group.name\"\n class=\"m-0 px-2 pt-2.5 pb-1 text-11 font-semibold tracking-caps text-sui-ink-muted uppercase\"\n >\n {{ group.name }}\n </ListboxGroupLabel>\n <ListboxItem\n v-for=\"field in group.fields\"\n :key=\"field.name\"\n class=\"flex min-h-8 cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1 text-13.5 text-sui-ink outline-hidden select-none data-highlighted:bg-sui-sunken group-data-keyboard/list:data-highlighted:sui-ring-inset\"\n :value=\"field.name\"\n >\n <span\n class=\"flex size-6 shrink-0 items-center justify-center rounded-md bg-sui-sunken text-sui-ink-body\"\n >\n <FilterGlyph :name=\"field.type\" />\n </span>\n <span class=\"min-w-0 flex-1 truncate\">{{ field.label }}</span>\n <span\n v-if=\"inUse.includes(field.name)\"\n class=\"inline-flex items-center gap-1.5 text-xs font-medium text-sui-accent\"\n >\n <span class=\"size-1.5 rounded-full bg-sui-accent-solid\" />\n {{ inUseLabel }}\n </span>\n </ListboxItem>\n </ListboxGroup>\n <p v-if=\"!groups.length\" class=\"m-0 px-2 py-3 text-13 text-sui-ink-body\">\n {{ noMatchLabel.replace('{query}', query) }}\n </p>\n </ListboxContent>\n </FilterFrame>\n </ListboxRoot>\n </PopoverContent>\n </PopoverPortal>\n </PopoverRoot>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"FilterMenu.js","names":["_sfc_main","FilterMenu_vue_vue_type_script_setup_true_lang_default","FilterMenu_default"],"sources":["../../../src/components/Filters/FilterMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, useAttrs } from 'vue'\n\nimport {\n ListboxContent,\n ListboxFilter,\n ListboxGroup,\n ListboxGroupLabel,\n ListboxItem,\n ListboxRoot,\n PopoverAnchor,\n PopoverContent,\n PopoverPortal,\n PopoverRoot,\n PopoverTrigger\n} from 'reka-ui'\n\nimport Button from '../Button/Button.vue'\nimport FilterFrame from './FilterFrame.vue'\nimport FilterGlyph from './FilterGlyph.vue'\nimport { type FilterTriggerProps, useCustomTrigger } from './trigger'\nimport type { FilterField } from './types'\n\nexport interface FilterMenuProps {\n fields: FilterField[]\n /** Fields already filtering, marked \"In use\"; picking one should open its chip, not add a second. */\n inUse?: string[]\n /** chip: the dashed \"+ Filter\" in the view bar. button: the page header's Filters button, tinted while filters are in use. */\n as?: 'chip' | 'button'\n /** as=\"button\" only: ghost for a page header. Secondary by default, tinted while filters are in use. */\n variant?: 'secondary' | 'ghost' | 'tinted'\n /** The footer's status; \"{count} fields\" by default. */\n status?: string\n label?: string\n buttonLabel?: string\n searchPlaceholder?: string\n inUseLabel?: string\n addLabel?: string\n closeLabel?: string\n /** `{count}` is the number of fields. */\n fieldsLabel?: string\n /** `{query}` is what was typed. */\n noMatchLabel?: string\n}\n\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<FilterMenuProps>(), {\n inUse: () => [],\n as: 'chip',\n variant: undefined,\n status: undefined,\n label: 'Filter',\n buttonLabel: 'Filters',\n searchPlaceholder: 'Filter by…',\n inUseLabel: 'In use',\n addLabel: 'Add',\n closeLabel: 'Close',\n fieldsLabel: '{count} fields',\n noMatchLabel: 'No field matches “{query}”.'\n})\n\nconst emit = defineEmits<{ pick: [name: string] }>()\n\nconst open = defineModel<boolean>('open', { default: false })\n\ndefineSlots<{\n /** Your own opener in place of the chip or button: spread `props` on it. `count` is the filters in use. */\n trigger?: (props: { open: boolean; toggle: () => void; count: number; props: FilterTriggerProps }) => unknown\n}>()\n\nconst attrs = useAttrs()\nconst custom = useCustomTrigger(open)\nconst query = ref('')\n// Only the keyboard's highlight gets the focus ring; the pointer's is just a tint.\nconst keyboard = ref(false)\n\nconst groups = computed(() => {\n const q = query.value.trim().toLowerCase()\n const shown = props.fields.filter((f) => !q || f.label.toLowerCase().includes(q))\n return [...new Set(shown.map((f) => f.group ?? ''))].map((name) => ({\n name,\n fields: shown.filter((f) => (f.group ?? '') === name)\n }))\n})\n\nfunction pick(name: unknown) {\n if (typeof name !== 'string') return\n open.value = false\n query.value = ''\n emit('pick', name)\n}\n\nfunction onOpen(isOpen: boolean) {\n if (!isOpen) query.value = ''\n}\n\nfunction onKeydown(event: KeyboardEvent) {\n if (['ArrowUp', 'ArrowDown', 'Home', 'End'].includes(event.key)) keyboard.value = true\n}\n</script>\n\n<!-- The field list behind \"+ Filter\": search, fields grouped with their type, and which are already filtering. -->\n<template>\n <PopoverRoot v-model:open=\"open\" @update:open=\"onOpen\">\n <PopoverAnchor v-if=\"$slots.trigger\" as-child>\n <slot :count=\"inUse.length\" name=\"trigger\" :open=\"open\" :props=\"custom.props.value\" :toggle=\"custom.toggle\" />\n </PopoverAnchor>\n <PopoverTrigger v-else-if=\"as === 'button'\" as-child>\n <Button v-bind=\"attrs\" :variant=\"variant ?? (inUse.length ? 'tinted' : 'secondary')\">\n <svg\n aria-hidden=\"true\"\n class=\"size-4 fill-none stroke-current\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 16 16\"\n >\n <path d=\"M2.5 3.5h11l-4.25 5v4l-2.5 1v-5z\" />\n </svg>\n {{ buttonLabel }}\n </Button>\n </PopoverTrigger>\n <PopoverTrigger\n v-else\n v-bind=\"attrs\"\n class=\"inline-flex h-7.5 items-center gap-1.5 rounded-lg border border-dashed border-sui-line-strong px-2 text-13 font-medium whitespace-nowrap text-sui-ink-muted outline-hidden transition-[border-color,box-shadow] duration-150 hover:border-sui-ink-muted hover:text-sui-ink-body focus-visible:sui-ring data-[state=open]:border-solid data-[state=open]:border-sui-accent-solid data-[state=open]:text-sui-accent data-[state=open]:shadow-[0_0_0_3px_rgb(var(--sui-focus-ring))]\"\n >\n <FilterGlyph name=\"plus\" />\n {{ label }}\n </PopoverTrigger>\n <PopoverPortal>\n <PopoverContent\n align=\"start\"\n :aria-label=\"$slots.trigger ? searchPlaceholder : undefined\"\n class=\"z-[1100] w-85 max-w-[calc(100vw-2rem)] origin-(--reka-popover-content-transform-origin) rounded-xl border border-sui-line bg-sui-surface text-sui-ink shadow-lg data-[state=open]:animate-sui-overlay-in\"\n :data-sui-panel=\"custom.panelKey\"\n :side-offset=\"8\"\n @close-auto-focus=\"custom.returnFocus\"\n @interact-outside=\"custom.ignoreTrigger\"\n @keydown=\"onKeydown\"\n @pointermove=\"keyboard = false\"\n >\n <ListboxRoot highlight-on-hover @update:model-value=\"pick\">\n <FilterFrame\n :close-label=\"closeLabel\"\n :enter-label=\"addLabel\"\n :status=\"status ?? fieldsLabel.replace('{count}', String(fields.length))\"\n >\n <div class=\"flex h-11 items-center gap-2 border-b border-sui-line-subtle px-3.5 text-sui-ink-muted\">\n <FilterGlyph class=\"size-4\" name=\"search\" />\n <ListboxFilter\n v-model=\"query\"\n :aria-label=\"searchPlaceholder\"\n auto-focus\n class=\"h-full min-w-0 flex-1 border-none bg-transparent p-0 text-sm text-sui-ink shadow-none outline-hidden placeholder:text-sui-ink-faint focus:border-none focus:shadow-none focus:ring-0 focus:outline-hidden\"\n :placeholder=\"searchPlaceholder\"\n />\n </div>\n <ListboxContent\n :aria-label=\"searchPlaceholder\"\n class=\"group/list max-h-64 overflow-auto px-1.5 pt-1 pb-1.5 outline-hidden\"\n :data-keyboard=\"keyboard || undefined\"\n >\n <ListboxGroup v-for=\"group in groups\" :key=\"group.name\">\n <ListboxGroupLabel\n v-if=\"group.name\"\n class=\"m-0 px-2 pt-2.5 pb-1 text-11 font-semibold tracking-caps text-sui-ink-muted uppercase\"\n >\n {{ group.name }}\n </ListboxGroupLabel>\n <ListboxItem\n v-for=\"field in group.fields\"\n :key=\"field.name\"\n class=\"flex min-h-8 cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1 text-13.5 text-sui-ink outline-hidden select-none data-highlighted:bg-sui-sunken group-data-keyboard/list:data-highlighted:sui-ring-inset\"\n :value=\"field.name\"\n >\n <span\n class=\"flex size-6 shrink-0 items-center justify-center rounded-md bg-sui-sunken text-sui-ink-body\"\n >\n <FilterGlyph :name=\"field.type\" />\n </span>\n <span class=\"min-w-0 flex-1 truncate\">{{ field.label }}</span>\n <span\n v-if=\"inUse.includes(field.name)\"\n class=\"inline-flex items-center gap-1.5 text-xs font-medium text-sui-accent\"\n >\n <span class=\"size-1.5 rounded-full bg-sui-accent-solid\" />\n {{ inUseLabel }}\n </span>\n </ListboxItem>\n </ListboxGroup>\n <p v-if=\"!groups.length\" class=\"m-0 px-2 py-3 text-13 text-sui-ink-body\">\n {{ noMatchLabel.replace('{query}', query) }}\n </p>\n </ListboxContent>\n </FilterFrame>\n </ListboxRoot>\n </PopoverContent>\n </PopoverPortal>\n </PopoverRoot>\n</template>\n"],"mappings":""}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type FilterTriggerProps } from './trigger';
|
|
1
2
|
import type { FilterField } from './types';
|
|
2
3
|
export interface FilterMenuProps {
|
|
3
4
|
fields: FilterField[];
|
|
@@ -5,6 +6,8 @@ export interface FilterMenuProps {
|
|
|
5
6
|
inUse?: string[];
|
|
6
7
|
/** chip: the dashed "+ Filter" in the view bar. button: the page header's Filters button, tinted while filters are in use. */
|
|
7
8
|
as?: 'chip' | 'button';
|
|
9
|
+
/** as="button" only: ghost for a page header. Secondary by default, tinted while filters are in use. */
|
|
10
|
+
variant?: 'secondary' | 'ghost' | 'tinted';
|
|
8
11
|
/** The footer's status; "{count} fields" by default. */
|
|
9
12
|
status?: string;
|
|
10
13
|
label?: string;
|
|
@@ -19,17 +22,27 @@ export interface FilterMenuProps {
|
|
|
19
22
|
noMatchLabel?: string;
|
|
20
23
|
}
|
|
21
24
|
type __VLS_Props = FilterMenuProps;
|
|
25
|
+
type __VLS_Slots = {
|
|
26
|
+
/** Your own opener in place of the chip or button: spread `props` on it. `count` is the filters in use. */
|
|
27
|
+
trigger?: (props: {
|
|
28
|
+
open: boolean;
|
|
29
|
+
toggle: () => void;
|
|
30
|
+
count: number;
|
|
31
|
+
props: FilterTriggerProps;
|
|
32
|
+
}) => unknown;
|
|
33
|
+
};
|
|
22
34
|
type __VLS_ModelProps = {
|
|
23
35
|
'open'?: boolean;
|
|
24
36
|
};
|
|
25
37
|
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
26
|
-
declare const
|
|
38
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
27
39
|
pick: (name: string) => any;
|
|
28
40
|
"update:open": (value: boolean) => any;
|
|
29
41
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
30
42
|
onPick?: ((name: string) => any) | undefined;
|
|
31
43
|
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
32
44
|
}>, {
|
|
45
|
+
variant: "secondary" | "tinted" | "ghost";
|
|
33
46
|
as: "button" | "chip";
|
|
34
47
|
label: string;
|
|
35
48
|
closeLabel: string;
|
|
@@ -42,5 +55,11 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
42
55
|
fieldsLabel: string;
|
|
43
56
|
noMatchLabel: string;
|
|
44
57
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
58
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
45
59
|
declare const _default: typeof __VLS_export;
|
|
46
60
|
export default _default;
|
|
61
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
62
|
+
new (): {
|
|
63
|
+
$slots: S;
|
|
64
|
+
};
|
|
65
|
+
};
|