@sewadah/selaras 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.json +1 -1
- package/dist/module.mjs +14 -1
- package/dist/runtime/components/Autocomplete.vue +3 -1
- package/dist/runtime/components/Calendar.d.vue.ts +69 -0
- package/dist/runtime/components/Calendar.vue +163 -0
- package/dist/runtime/components/Calendar.vue.d.ts +69 -0
- package/dist/runtime/components/Callout.vue +12 -1
- package/dist/runtime/components/CodeGroup.vue +13 -3
- package/dist/runtime/components/CodeTree.d.vue.ts +2 -0
- package/dist/runtime/components/CodeTree.vue +52 -1
- package/dist/runtime/components/CodeTree.vue.d.ts +2 -0
- package/dist/runtime/components/ColorPicker.d.vue.ts +8 -0
- package/dist/runtime/components/ColorPicker.vue +66 -45
- package/dist/runtime/components/ColorPicker.vue.d.ts +8 -0
- package/dist/runtime/components/Column.js +1 -1
- package/dist/runtime/components/CommandPalette.d.vue.ts +3 -1
- package/dist/runtime/components/CommandPalette.vue +5 -0
- package/dist/runtime/components/CommandPalette.vue.d.ts +3 -1
- package/dist/runtime/components/ContentNavigation.d.vue.ts +8 -1
- package/dist/runtime/components/ContentNavigation.vue +9 -2
- package/dist/runtime/components/ContentNavigation.vue.d.ts +8 -1
- package/dist/runtime/components/ContextMenu.d.vue.ts +8 -1
- package/dist/runtime/components/ContextMenu.vue +16 -4
- package/dist/runtime/components/ContextMenu.vue.d.ts +8 -1
- package/dist/runtime/components/DatePicker.d.vue.ts +10 -3
- package/dist/runtime/components/DatePicker.vue +24 -16
- package/dist/runtime/components/DatePicker.vue.d.ts +10 -3
- package/dist/runtime/components/Dropdown.d.vue.ts +33 -6
- package/dist/runtime/components/Dropdown.vue +143 -11
- package/dist/runtime/components/Dropdown.vue.d.ts +33 -6
- package/dist/runtime/components/FileTree.d.vue.ts +2 -0
- package/dist/runtime/components/FileTree.vue +8 -4
- package/dist/runtime/components/FileTree.vue.d.ts +2 -0
- package/dist/runtime/components/FormField.d.vue.ts +4 -0
- package/dist/runtime/components/FormField.vue +19 -4
- package/dist/runtime/components/FormField.vue.d.ts +4 -0
- package/dist/runtime/components/Input.vue +3 -2
- package/dist/runtime/components/Kbd.vue +12 -2
- package/dist/runtime/components/NavigationMenu.d.vue.ts +10 -10
- package/dist/runtime/components/NavigationMenu.vue +13 -9
- package/dist/runtime/components/NavigationMenu.vue.d.ts +10 -10
- package/dist/runtime/components/NavigationMenuAccordionItem.vue +5 -1
- package/dist/runtime/components/NavigationMenuFlyoutList.vue +7 -4
- package/dist/runtime/components/Popover.d.vue.ts +8 -2
- package/dist/runtime/components/Popover.vue +9 -4
- package/dist/runtime/components/Popover.vue.d.ts +8 -2
- package/dist/runtime/components/ProsePre.d.vue.ts +2 -0
- package/dist/runtime/components/ProsePre.vue +2 -1
- package/dist/runtime/components/ProsePre.vue.d.ts +2 -0
- package/dist/runtime/components/Select.vue +3 -1
- package/dist/runtime/components/SplitterPanel.d.vue.ts +2 -2
- package/dist/runtime/components/SplitterPanel.vue.d.ts +2 -2
- package/dist/runtime/components/Table.vue +95 -26
- package/dist/runtime/components/Tabs.d.vue.ts +44 -4
- package/dist/runtime/components/Tabs.vue +171 -18
- package/dist/runtime/components/Tabs.vue.d.ts +44 -4
- package/dist/runtime/components/Textarea.vue +3 -2
- package/dist/runtime/components/Timeline.d.vue.ts +19 -0
- package/dist/runtime/components/Timeline.vue +99 -0
- package/dist/runtime/components/Timeline.vue.d.ts +19 -0
- package/dist/runtime/components/Toast.d.vue.ts +10 -1
- package/dist/runtime/components/Toast.vue +94 -8
- package/dist/runtime/components/Toast.vue.d.ts +10 -1
- package/dist/runtime/components/Tooltip.d.vue.ts +8 -2
- package/dist/runtime/components/Tooltip.vue +9 -4
- package/dist/runtime/components/Tooltip.vue.d.ts +8 -2
- package/dist/runtime/composables/use-form-field.d.ts +1 -0
- package/dist/runtime/composables/use-table.d.ts +3 -0
- package/dist/runtime/composables/use-table.js +10 -4
- package/dist/runtime/composables/use-toast.js +5 -1
- package/dist/runtime/directives/hotkey.d.ts +13 -0
- package/dist/runtime/directives/hotkey.js +107 -0
- package/dist/runtime/directives/index.d.ts +2 -0
- package/dist/runtime/directives/index.js +2 -0
- package/dist/runtime/directives/mask.d.ts +30 -0
- package/dist/runtime/directives/mask.js +165 -0
- package/dist/runtime/internal/ComboboxSelectBase.d.vue.ts +29 -25
- package/dist/runtime/internal/ComboboxSelectBase.vue +103 -19
- package/dist/runtime/internal/ComboboxSelectBase.vue.d.ts +29 -25
- package/dist/runtime/internal/ComboboxSelectBody.d.vue.ts +16 -11
- package/dist/runtime/internal/ComboboxSelectBody.vue +49 -10
- package/dist/runtime/internal/ComboboxSelectBody.vue.d.ts +16 -11
- package/dist/runtime/internal/DatePickerCalendarBody.vue +1 -1
- package/dist/runtime/internal/DatePickerRangeCalendarBody.vue +1 -1
- package/dist/runtime/internal/ShortcutHint.d.vue.ts +6 -0
- package/dist/runtime/internal/ShortcutHint.vue +13 -0
- package/dist/runtime/internal/ShortcutHint.vue.d.ts +6 -0
- package/dist/runtime/internal/ToastItemRenderer.d.vue.ts +9 -1
- package/dist/runtime/internal/ToastItemRenderer.vue +55 -8
- package/dist/runtime/internal/ToastItemRenderer.vue.d.ts +9 -1
- package/dist/runtime/internal/combobox-select.js +2 -1
- package/dist/runtime/internal/programmatic-services.d.ts +2 -0
- package/dist/runtime/internal/programmatic-services.js +8 -0
- package/dist/runtime/internal/toast-stack.d.ts +36 -0
- package/dist/runtime/internal/toast-stack.js +36 -0
- package/dist/runtime/structural.css +1 -1
- package/dist/runtime/table.d.ts +1 -1
- package/dist/runtime/theme/alert-dialog.js +1 -1
- package/dist/runtime/theme/calendar.d.ts +86 -0
- package/dist/runtime/theme/calendar.js +19 -0
- package/dist/runtime/theme/callout.d.ts +0 -12
- package/dist/runtime/theme/callout.js +8 -8
- package/dist/runtime/theme/code-tree.js +1 -1
- package/dist/runtime/theme/command-palette.js +1 -1
- package/dist/runtime/theme/content-navigation.d.ts +3 -0
- package/dist/runtime/theme/content-navigation.js +1 -0
- package/dist/runtime/theme/drawer.js +1 -1
- package/dist/runtime/theme/dropdown.d.ts +21 -0
- package/dist/runtime/theme/dropdown.js +15 -2
- package/dist/runtime/theme/file-tree.js +1 -1
- package/dist/runtime/theme/form-field.d.ts +18 -0
- package/dist/runtime/theme/form-field.js +6 -1
- package/dist/runtime/theme/modal.js +1 -1
- package/dist/runtime/theme/slideover.js +1 -1
- package/dist/runtime/theme/table.d.ts +27 -0
- package/dist/runtime/theme/table.js +11 -2
- package/dist/runtime/theme/tabs.d.ts +87 -3
- package/dist/runtime/theme/tabs.js +46 -22
- package/dist/runtime/theme/timeline.d.ts +251 -0
- package/dist/runtime/theme/timeline.js +84 -0
- package/dist/runtime/theme/toast.d.ts +92 -0
- package/dist/runtime/theme/toast.js +29 -7
- package/dist/runtime/theme-config.d.ts +12 -1
- package/dist/runtime/types/index.d.ts +6 -1
- package/dist/runtime/utils/arrow.d.ts +21 -0
- package/dist/runtime/utils/arrow.js +10 -0
- package/dist/runtime/utils/file-icons.js +2 -0
- package/dist/runtime/utils/icons.d.ts +2 -0
- package/dist/runtime/utils/icons.js +2 -0
- package/dist/runtime/utils/messages.d.ts +6 -0
- package/dist/runtime/utils/messages.js +6 -0
- package/dist/runtime/utils/navigation-menu.d.ts +7 -0
- package/dist/runtime/utils/navigation-menu.js +3 -0
- package/dist/runtime/utils/overlay.d.ts +17 -0
- package/dist/runtime/utils/overlay.js +7 -0
- package/dist/runtime/utils/select-contracts.d.ts +7 -1
- package/dist/runtime/utils/table-columns.js +1 -1
- package/dist/runtime/utils/table-contracts.d.ts +9 -1
- package/dist/runtime/utils/timeline-contracts.d.ts +42 -0
- package/dist/runtime/utils/timeline-contracts.js +0 -0
- package/package.json +2 -1
|
@@ -2,21 +2,26 @@
|
|
|
2
2
|
import { TooltipArrow, TooltipContent, TooltipPortal, TooltipRoot, TooltipTrigger } from "reka-ui";
|
|
3
3
|
import { computed } from "vue";
|
|
4
4
|
import { tooltipTheme } from "../theme/tooltip";
|
|
5
|
+
import { arrowContentProps, arrowElementProps } from "../utils/arrow";
|
|
6
|
+
import { overlayPortalProps } from "../utils/overlay";
|
|
5
7
|
import { resolveSlot, useComponentTheme, useThemeBindings } from "../utils/ui";
|
|
6
8
|
const props = defineProps({
|
|
7
9
|
text: { type: String, required: false },
|
|
8
10
|
side: { type: String, required: false, default: "top" },
|
|
11
|
+
positioning: { type: Object, required: false },
|
|
12
|
+
portal: { type: [Boolean, String], required: false, skipCheck: true, default: void 0 },
|
|
9
13
|
delayDuration: { type: Number, required: false, default: 200 },
|
|
10
14
|
kbds: { type: Array, required: false },
|
|
11
|
-
arrow: { type: Boolean, required: false, default: true },
|
|
15
|
+
arrow: { type: [Boolean, Object], required: false, default: true },
|
|
12
16
|
disabled: { type: Boolean, required: false },
|
|
13
17
|
ui: { type: Object, required: false }
|
|
14
18
|
});
|
|
15
19
|
const theme = useComponentTheme("tooltip", tooltipTheme);
|
|
16
20
|
const themeBindings = useThemeBindings();
|
|
17
21
|
const ui = computed(() => theme.value());
|
|
18
|
-
const contentProps = computed(() => resolveSlot(ui.value.content, props.ui?.content));
|
|
19
|
-
const
|
|
22
|
+
const contentProps = computed(() => ({ ...resolveSlot(ui.value.content, props.ui?.content), ...arrowContentProps(props.arrow), ...props.positioning }));
|
|
23
|
+
const portalProps = computed(() => overlayPortalProps(props.portal));
|
|
24
|
+
const arrowProps = computed(() => ({ ...resolveSlot(ui.value.arrow, props.ui?.arrow), ...arrowElementProps(props.arrow) }));
|
|
20
25
|
const kbdsProps = computed(() => resolveSlot(ui.value.kbds, props.ui?.kbds));
|
|
21
26
|
const kbdProps = computed(() => resolveSlot(ui.value.kbd, props.ui?.kbd));
|
|
22
27
|
</script>
|
|
@@ -26,7 +31,7 @@ const kbdProps = computed(() => resolveSlot(ui.value.kbd, props.ui?.kbd));
|
|
|
26
31
|
<TooltipTrigger as-child>
|
|
27
32
|
<slot />
|
|
28
33
|
</TooltipTrigger>
|
|
29
|
-
<TooltipPortal>
|
|
34
|
+
<TooltipPortal v-bind="portalProps">
|
|
30
35
|
<TooltipContent :side="side" :side-offset="6" :data-selaras-theme="themeBindings['data-selaras-theme']" :data-selaras-mode="themeBindings['data-selaras-mode']" :style="themeBindings.style" v-bind="contentProps">
|
|
31
36
|
<slot name="content">
|
|
32
37
|
{{ text }}
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import type { TooltipThemeSlots } from '../theme/tooltip.js';
|
|
2
|
+
import type { ArrowConfig } from '../utils/arrow.js';
|
|
3
|
+
import type { OverlayPortal, OverlayPositioning } from '../utils/overlay.js';
|
|
2
4
|
import type { UiProp } from '../utils/ui.js';
|
|
3
5
|
export interface TooltipProps {
|
|
4
6
|
text?: string;
|
|
5
7
|
side?: 'top' | 'right' | 'bottom' | 'left';
|
|
8
|
+
/** Anchored tooltip placement. Overrides `side` when supplied. */
|
|
9
|
+
positioning?: OverlayPositioning;
|
|
10
|
+
/** Teleport target, or `false` to render inline. Defaults to `body`. */
|
|
11
|
+
portal?: OverlayPortal;
|
|
6
12
|
delayDuration?: number;
|
|
7
13
|
/** Keyboard shortcut hint shown alongside the text, e.g. `['⌘', 'K']` - each entry renders as its own small key badge. Takes the literal display strings, not semantic key names - there's no platform-specific symbol mapping. */
|
|
8
14
|
kbds?: string[];
|
|
9
|
-
/** Set `false` to hide the
|
|
10
|
-
arrow?: boolean;
|
|
15
|
+
/** Set `false` to hide the pointer; an object configures its size and edge clearance. */
|
|
16
|
+
arrow?: boolean | ArrowConfig;
|
|
11
17
|
disabled?: boolean;
|
|
12
18
|
ui?: UiProp<TooltipThemeSlots>;
|
|
13
19
|
}
|
|
@@ -34,6 +34,7 @@ export type TableRowSelectionState = RowSelectionState;
|
|
|
34
34
|
export type TableExpandedState = ExpandedState;
|
|
35
35
|
export type TableColumnVisibilityState = ColumnVisibilityState;
|
|
36
36
|
export type TableGetRowId<TData extends RowData = RowData> = (row: TData, index: number) => string;
|
|
37
|
+
export type TableGetSubRows<TData extends RowData = RowData> = (row: TData, index: number) => readonly TData[] | undefined;
|
|
37
38
|
/** Creates TanStack v9 column definitions bound to STable's fixed feature set. */
|
|
38
39
|
export declare const createTableColumnHelper: <TData extends RowData>() => import("@tanstack/vue-table").AppColumnHelper<{
|
|
39
40
|
rowSortingFeature: import("@tanstack/vue-table").TableFeature;
|
|
@@ -68,6 +69,8 @@ interface UseTableProps<TData extends RowData> {
|
|
|
68
69
|
expanded?: TableExpandedState;
|
|
69
70
|
columnVisibility?: TableColumnVisibilityState;
|
|
70
71
|
getRowId?: TableGetRowId<TData>;
|
|
72
|
+
tree?: boolean;
|
|
73
|
+
getSubRows?: TableGetSubRows<TData>;
|
|
71
74
|
manualSorting?: boolean;
|
|
72
75
|
manualFiltering?: boolean;
|
|
73
76
|
manualPagination?: boolean;
|
|
@@ -89,12 +89,18 @@ export function useTable(props, emit, columns, columnPinning) {
|
|
|
89
89
|
const table = useAppTable({
|
|
90
90
|
data: computed(() => props.data),
|
|
91
91
|
columns,
|
|
92
|
+
// TanStack enables sorting by default for accessor columns. Selaras opts
|
|
93
|
+
// columns into sorting explicitly, matching the declarative SColumn API.
|
|
94
|
+
defaultColumn: { enableSorting: false },
|
|
92
95
|
enableRowSelection: computed(() => !!props.selectable),
|
|
93
96
|
getRowId: props.getRowId,
|
|
94
|
-
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
getRowCanExpand: () => true,
|
|
97
|
+
getSubRows: props.tree ? props.getSubRows ?? ((row) => row.subRows) : () => void 0,
|
|
98
|
+
// Tree rows expand when they have children; detail expansion remains
|
|
99
|
+
// available on every row when tree mode is off.
|
|
100
|
+
getRowCanExpand: (row) => props.tree ? !!row.subRows?.length : true,
|
|
101
|
+
// Paginate tree roots as a unit so expanding one root does not hide later
|
|
102
|
+
// roots simply because its children consume the page-size row count.
|
|
103
|
+
paginateExpandedRows: false,
|
|
98
104
|
// Opts out of the local sorted/filtered/paginated row models - state
|
|
99
105
|
// still lives here (sorting/globalFilter/pageIndex above, still
|
|
100
106
|
// emitting their own update:* events the normal way), only the row
|
|
@@ -5,9 +5,13 @@ export function useToast() {
|
|
|
5
5
|
const snapshotTheme = useProgrammaticThemeSnapshot();
|
|
6
6
|
function add(toast) {
|
|
7
7
|
if (import.meta.server)
|
|
8
|
-
|
|
8
|
+
return -1;
|
|
9
9
|
const id = service.nextId();
|
|
10
|
+
if (service.max.value <= 0)
|
|
11
|
+
return id;
|
|
10
12
|
service.toasts.value.push({ ...toast, id, _theme: snapshotTheme() });
|
|
13
|
+
if (service.toasts.value.length > service.max.value)
|
|
14
|
+
service.toasts.value.splice(0, service.toasts.value.length - service.max.value);
|
|
11
15
|
return id;
|
|
12
16
|
}
|
|
13
17
|
return { add, remove: service.remove };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Directive } from 'vue';
|
|
2
|
+
export interface HotkeyOptions<T extends HTMLElement = HTMLElement> {
|
|
3
|
+
/** A key chord such as `mod+k`, `ctrl+shift+p`, or `escape`. */
|
|
4
|
+
keys: string;
|
|
5
|
+
/** Runs instead of clicking the bound element. */
|
|
6
|
+
handler?: (event: KeyboardEvent) => void;
|
|
7
|
+
/** Gate activation on current application state. */
|
|
8
|
+
when?: boolean | ((element: T, event: KeyboardEvent) => boolean);
|
|
9
|
+
/** Allow shortcuts while focus is in an editable control. Defaults to false. */
|
|
10
|
+
allowInEditable?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export type HotkeyValue<T extends HTMLElement = HTMLElement> = string | HotkeyOptions<T> | false | null | undefined;
|
|
13
|
+
export declare const vHotkey: Directive<HTMLElement, HotkeyValue>;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
const aliases = {
|
|
2
|
+
esc: "escape",
|
|
3
|
+
return: "enter",
|
|
4
|
+
spacebar: " ",
|
|
5
|
+
space: " ",
|
|
6
|
+
up: "arrowup",
|
|
7
|
+
down: "arrowdown",
|
|
8
|
+
left: "arrowleft",
|
|
9
|
+
right: "arrowright",
|
|
10
|
+
del: "delete",
|
|
11
|
+
ctrl: "control",
|
|
12
|
+
cmd: "meta",
|
|
13
|
+
command: "meta",
|
|
14
|
+
option: "alt"
|
|
15
|
+
};
|
|
16
|
+
function isMacPlatform() {
|
|
17
|
+
if (typeof navigator === "undefined")
|
|
18
|
+
return false;
|
|
19
|
+
const platform = navigator.platform ?? "";
|
|
20
|
+
return /mac|iphone|ipad|ipod/i.test(platform);
|
|
21
|
+
}
|
|
22
|
+
function canonicalKey(key) {
|
|
23
|
+
const normalized = key.trim().toLowerCase();
|
|
24
|
+
return aliases[normalized] ?? normalized;
|
|
25
|
+
}
|
|
26
|
+
function parseHotkey(keys) {
|
|
27
|
+
const parts = keys.split("+").map(canonicalKey).filter(Boolean);
|
|
28
|
+
const key = parts.find((part) => !["control", "meta", "alt", "shift", "mod"].includes(part));
|
|
29
|
+
if (!key)
|
|
30
|
+
return void 0;
|
|
31
|
+
const hasMod = parts.includes("mod");
|
|
32
|
+
const mac = isMacPlatform();
|
|
33
|
+
return {
|
|
34
|
+
key,
|
|
35
|
+
ctrl: parts.includes("control") || hasMod && !mac,
|
|
36
|
+
meta: parts.includes("meta") || hasMod && mac,
|
|
37
|
+
alt: parts.includes("alt"),
|
|
38
|
+
shift: parts.includes("shift"),
|
|
39
|
+
focusScoped: key.length === 1 && !parts.some((part) => ["control", "meta", "alt", "shift", "mod"].includes(part))
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function isEditable(target) {
|
|
43
|
+
if (!(target instanceof Element))
|
|
44
|
+
return false;
|
|
45
|
+
return Boolean(target.closest('input, textarea, select, [contenteditable]:not([contenteditable="false"])'));
|
|
46
|
+
}
|
|
47
|
+
function physicalKey(code) {
|
|
48
|
+
return /^Key([A-Z])$/.exec(code)?.[1]?.toLowerCase() ?? /^Digit(\d)$/.exec(code)?.[1];
|
|
49
|
+
}
|
|
50
|
+
function matches(event, hotkey) {
|
|
51
|
+
const keyMatches = canonicalKey(event.key) === hotkey.key || event.altKey && physicalKey(event.code) === hotkey.key;
|
|
52
|
+
const symbol = hotkey.key.length === 1 && hotkey.key !== " " && !/[a-z0-9]/.test(hotkey.key);
|
|
53
|
+
return keyMatches && event.ctrlKey === hotkey.ctrl && event.metaKey === hotkey.meta && event.altKey === hotkey.alt && (symbol && !hotkey.shift ? true : event.shiftKey === hotkey.shift);
|
|
54
|
+
}
|
|
55
|
+
function normalizeBinding(value) {
|
|
56
|
+
if (value === false || value == null)
|
|
57
|
+
return void 0;
|
|
58
|
+
return typeof value === "string" ? { keys: value } : value;
|
|
59
|
+
}
|
|
60
|
+
function install(element, value) {
|
|
61
|
+
const options = normalizeBinding(value);
|
|
62
|
+
const parsed = options && parseHotkey(options.keys);
|
|
63
|
+
if (!options || !parsed)
|
|
64
|
+
return void 0;
|
|
65
|
+
const listener = (event) => {
|
|
66
|
+
if (event.defaultPrevented || !matches(event, parsed))
|
|
67
|
+
return;
|
|
68
|
+
if (typeof options.when === "boolean" && !options.when)
|
|
69
|
+
return;
|
|
70
|
+
if (typeof options.when === "function" && !options.when(element, event))
|
|
71
|
+
return;
|
|
72
|
+
const activeElement = element.ownerDocument.activeElement;
|
|
73
|
+
const eventTarget = event.target;
|
|
74
|
+
if (parsed.focusScoped && !element.contains(activeElement) && !(eventTarget && (eventTarget === element || element.contains(eventTarget)))) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (!options.allowInEditable && isEditable(event.target))
|
|
78
|
+
return;
|
|
79
|
+
event.preventDefault();
|
|
80
|
+
if (options.handler)
|
|
81
|
+
options.handler(event);
|
|
82
|
+
else
|
|
83
|
+
element.click();
|
|
84
|
+
};
|
|
85
|
+
document.addEventListener("keydown", listener);
|
|
86
|
+
return () => document.removeEventListener("keydown", listener);
|
|
87
|
+
}
|
|
88
|
+
export const vHotkey = {
|
|
89
|
+
mounted(element, binding) {
|
|
90
|
+
const cleanup = install(element, binding.value);
|
|
91
|
+
if (cleanup)
|
|
92
|
+
element.__selarasHotkeyCleanup = cleanup;
|
|
93
|
+
},
|
|
94
|
+
updated(element, binding) {
|
|
95
|
+
const host = element;
|
|
96
|
+
host.__selarasHotkeyCleanup?.();
|
|
97
|
+
delete host.__selarasHotkeyCleanup;
|
|
98
|
+
const cleanup = install(element, binding.value);
|
|
99
|
+
if (cleanup)
|
|
100
|
+
host.__selarasHotkeyCleanup = cleanup;
|
|
101
|
+
},
|
|
102
|
+
unmounted(element) {
|
|
103
|
+
const host = element;
|
|
104
|
+
host.__selarasHotkeyCleanup?.();
|
|
105
|
+
delete host.__selarasHotkeyCleanup;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Directive } from 'vue';
|
|
2
|
+
/** A mask placeholder character and the input characters it accepts. */
|
|
3
|
+
export interface MaskToken {
|
|
4
|
+
pattern: RegExp;
|
|
5
|
+
/** Rewrites an accepted character, e.g. to uppercase it. */
|
|
6
|
+
transform?: (char: string) => string;
|
|
7
|
+
}
|
|
8
|
+
/** Values reported by `v-mask` after each mask update. */
|
|
9
|
+
export interface MaskDetail {
|
|
10
|
+
/** The value without mask literals. This is also the value `v-model` receives. */
|
|
11
|
+
value: string;
|
|
12
|
+
/** The formatted value shown in the input. */
|
|
13
|
+
maskedValue: string;
|
|
14
|
+
/** Whether every placeholder in the mask has been filled. */
|
|
15
|
+
completed: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface MaskOptions {
|
|
18
|
+
mask: string;
|
|
19
|
+
/** Extra or overriding placeholder tokens, merged over the defaults (`#`, `@`, `*`). */
|
|
20
|
+
tokens?: Record<string, MaskToken>;
|
|
21
|
+
onMask?: (detail: MaskDetail) => void;
|
|
22
|
+
}
|
|
23
|
+
/** A mask pattern string, or options for custom tokens and the `onMask` callback. */
|
|
24
|
+
export type MaskValue = string | MaskOptions | null | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* Formats a native input or the input inside a single-input component.
|
|
27
|
+
* `v-model` receives the raw value; the field shows the formatted one. Use
|
|
28
|
+
* `onMask` (or the bubbling `mask` event) to also read the formatted value.
|
|
29
|
+
*/
|
|
30
|
+
export declare const vMask: Directive<HTMLElement, MaskValue>;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
const defaultMaskTokens = {
|
|
2
|
+
"#": { pattern: /\d/ },
|
|
3
|
+
"@": { pattern: /[a-z]/i },
|
|
4
|
+
"*": { pattern: /[\da-z]/i }
|
|
5
|
+
};
|
|
6
|
+
function formatMask(input, mask, tokens = defaultMaskTokens, raw = true) {
|
|
7
|
+
let masked = "";
|
|
8
|
+
let unmasked = "";
|
|
9
|
+
let inputIndex = 0;
|
|
10
|
+
let maskIndex = 0;
|
|
11
|
+
let skipped = 0;
|
|
12
|
+
const slotEnds = [];
|
|
13
|
+
while (maskIndex < mask.length && inputIndex < input.length) {
|
|
14
|
+
const maskChar = mask[maskIndex];
|
|
15
|
+
const token = tokens[maskChar];
|
|
16
|
+
const char = input[inputIndex];
|
|
17
|
+
if (token) {
|
|
18
|
+
if (token.pattern.test(char)) {
|
|
19
|
+
const accepted = token.transform ? token.transform(char) : char;
|
|
20
|
+
masked += accepted;
|
|
21
|
+
unmasked += accepted;
|
|
22
|
+
slotEnds.push(masked.length);
|
|
23
|
+
maskIndex++;
|
|
24
|
+
} else {
|
|
25
|
+
skipped++;
|
|
26
|
+
}
|
|
27
|
+
inputIndex++;
|
|
28
|
+
} else {
|
|
29
|
+
masked += maskChar;
|
|
30
|
+
if (!raw && char === maskChar && inputIndex - skipped === maskIndex)
|
|
31
|
+
inputIndex++;
|
|
32
|
+
maskIndex++;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
let slotCount = 0;
|
|
36
|
+
for (const char of mask) {
|
|
37
|
+
if (tokens[char])
|
|
38
|
+
slotCount++;
|
|
39
|
+
}
|
|
40
|
+
return { masked, unmasked, completed: slotEnds.length === slotCount, slotEnds };
|
|
41
|
+
}
|
|
42
|
+
const states = /* @__PURE__ */ new WeakMap();
|
|
43
|
+
let nativeDescriptor;
|
|
44
|
+
function nativeValue() {
|
|
45
|
+
return nativeDescriptor ??= Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value");
|
|
46
|
+
}
|
|
47
|
+
function readNative(input) {
|
|
48
|
+
return nativeValue().get.call(input);
|
|
49
|
+
}
|
|
50
|
+
function writeNative(input, value) {
|
|
51
|
+
if (readNative(input) !== value)
|
|
52
|
+
nativeValue().set.call(input, value);
|
|
53
|
+
}
|
|
54
|
+
function resolveInput(element) {
|
|
55
|
+
if (element instanceof HTMLInputElement)
|
|
56
|
+
return element;
|
|
57
|
+
return element.querySelector("input") ?? void 0;
|
|
58
|
+
}
|
|
59
|
+
function normalize(value) {
|
|
60
|
+
if (!value)
|
|
61
|
+
return void 0;
|
|
62
|
+
return typeof value === "string" ? { mask: value } : value.mask ? value : void 0;
|
|
63
|
+
}
|
|
64
|
+
function resolveTokens(options) {
|
|
65
|
+
return options.tokens ? { ...defaultMaskTokens, ...options.tokens } : defaultMaskTokens;
|
|
66
|
+
}
|
|
67
|
+
function commit(state, result) {
|
|
68
|
+
state.masked = result.masked;
|
|
69
|
+
state.unmasked = result.unmasked;
|
|
70
|
+
writeNative(state.input, result.masked);
|
|
71
|
+
if (state.reported === result.masked)
|
|
72
|
+
return;
|
|
73
|
+
state.reported = result.masked;
|
|
74
|
+
const detail = { value: result.unmasked, maskedValue: result.masked, completed: result.completed };
|
|
75
|
+
state.onMask?.(detail);
|
|
76
|
+
state.input.dispatchEvent(new CustomEvent("mask", { bubbles: true, detail }));
|
|
77
|
+
}
|
|
78
|
+
function handleInput(state, event) {
|
|
79
|
+
if (event.isComposing)
|
|
80
|
+
return;
|
|
81
|
+
const { input, mask, tokens } = state;
|
|
82
|
+
const current = readNative(input);
|
|
83
|
+
const caret = input.selectionStart ?? current.length;
|
|
84
|
+
const result = formatMask(current, mask, tokens, false);
|
|
85
|
+
const inputType = event.inputType ?? "";
|
|
86
|
+
if (inputType.startsWith("delete"))
|
|
87
|
+
result.masked = result.masked.slice(0, result.slotEnds.at(-1) ?? 0);
|
|
88
|
+
const position = Math.min(formatMask(current.slice(0, caret), mask, tokens, false).masked.length, result.masked.length);
|
|
89
|
+
commit(state, result);
|
|
90
|
+
if (document.activeElement === input)
|
|
91
|
+
input.setSelectionRange(position, position);
|
|
92
|
+
}
|
|
93
|
+
function install(element, input, options) {
|
|
94
|
+
const state = {
|
|
95
|
+
input,
|
|
96
|
+
mask: options.mask,
|
|
97
|
+
tokens: resolveTokens(options),
|
|
98
|
+
onMask: options.onMask,
|
|
99
|
+
masked: "",
|
|
100
|
+
unmasked: "",
|
|
101
|
+
onInput: (event) => handleInput(state, event)
|
|
102
|
+
};
|
|
103
|
+
Object.defineProperty(input, "value", {
|
|
104
|
+
configurable: true,
|
|
105
|
+
enumerable: nativeValue().enumerable,
|
|
106
|
+
get: () => {
|
|
107
|
+
const current = readNative(input);
|
|
108
|
+
return current === state.masked ? state.unmasked : formatMask(current, state.mask, state.tokens, false).unmasked;
|
|
109
|
+
},
|
|
110
|
+
set: (value) => {
|
|
111
|
+
commit(state, formatMask(value == null ? "" : String(value), state.mask, state.tokens));
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
input.addEventListener("input", state.onInput, true);
|
|
115
|
+
states.set(element, state);
|
|
116
|
+
commit(state, formatMask(readNative(input), state.mask, state.tokens));
|
|
117
|
+
}
|
|
118
|
+
function uninstall(element, state) {
|
|
119
|
+
state.input.removeEventListener("input", state.onInput, true);
|
|
120
|
+
Reflect.deleteProperty(state.input, "value");
|
|
121
|
+
states.delete(element);
|
|
122
|
+
}
|
|
123
|
+
function apply(element, value) {
|
|
124
|
+
const options = normalize(value);
|
|
125
|
+
const input = resolveInput(element);
|
|
126
|
+
const state = states.get(element);
|
|
127
|
+
if (state && (!options || state.input !== input))
|
|
128
|
+
uninstall(element, state);
|
|
129
|
+
if (!options || !input)
|
|
130
|
+
return;
|
|
131
|
+
const existing = states.get(element);
|
|
132
|
+
if (!existing) {
|
|
133
|
+
install(element, input, options);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
existing.onMask = options.onMask;
|
|
137
|
+
const tokens = resolveTokens(options);
|
|
138
|
+
if (existing.mask === options.mask && sameTokens(existing.tokens, tokens))
|
|
139
|
+
return;
|
|
140
|
+
existing.mask = options.mask;
|
|
141
|
+
existing.tokens = tokens;
|
|
142
|
+
commit(existing, formatMask(existing.unmasked, existing.mask, existing.tokens));
|
|
143
|
+
}
|
|
144
|
+
function sameTokens(left, right) {
|
|
145
|
+
if (left === right)
|
|
146
|
+
return true;
|
|
147
|
+
const keys = Object.keys(left);
|
|
148
|
+
return keys.length === Object.keys(right).length && keys.every((key) => right[key] && String(left[key].pattern) === String(right[key].pattern));
|
|
149
|
+
}
|
|
150
|
+
export const vMask = {
|
|
151
|
+
getSSRProps() {
|
|
152
|
+
return void 0;
|
|
153
|
+
},
|
|
154
|
+
mounted(element, binding) {
|
|
155
|
+
apply(element, binding.value);
|
|
156
|
+
},
|
|
157
|
+
updated(element, binding) {
|
|
158
|
+
apply(element, binding.value);
|
|
159
|
+
},
|
|
160
|
+
beforeUnmount(element) {
|
|
161
|
+
const state = states.get(element);
|
|
162
|
+
if (state)
|
|
163
|
+
uninstall(element, state);
|
|
164
|
+
}
|
|
165
|
+
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { VariantProps } from 'tailwind-variants';
|
|
2
2
|
import type { SelectThemeSlots } from '../theme/select.js';
|
|
3
|
+
import type { RoundedArrowConfig } from '../utils/arrow.js';
|
|
3
4
|
import type { ColorRole } from '../utils/color-registry.js';
|
|
5
|
+
import type { OverlayPortal, OverlayPositioning } from '../utils/overlay.js';
|
|
4
6
|
import type { UiProp } from '../utils/ui.js';
|
|
5
7
|
import type { SelectItems, SelectOption } from './combobox-select.js';
|
|
6
8
|
import { selectTheme } from '../theme/select.js';
|
|
@@ -43,7 +45,9 @@ export interface ComboboxSelectBaseProps {
|
|
|
43
45
|
resetSearchTermOnBlur?: boolean;
|
|
44
46
|
resetSearchTermOnSelect?: boolean;
|
|
45
47
|
/** Shows a small pointer triangle connecting the panel to its trigger. */
|
|
46
|
-
arrow?: boolean;
|
|
48
|
+
arrow?: boolean | RoundedArrowConfig;
|
|
49
|
+
positioning?: OverlayPositioning;
|
|
50
|
+
portal?: OverlayPortal;
|
|
47
51
|
/** Opts into the component's accessible small-screen presentation. */
|
|
48
52
|
adaptive?: boolean;
|
|
49
53
|
ui?: UiProp<SelectThemeSlots>;
|
|
@@ -55,57 +59,57 @@ export interface ComboboxSelectBaseEmits {
|
|
|
55
59
|
}
|
|
56
60
|
declare var __VLS_43: {
|
|
57
61
|
item: SelectOption<import("../utils/select-contracts.js").SelectValue>;
|
|
58
|
-
},
|
|
62
|
+
}, __VLS_98: {}, __VLS_105: {}, __VLS_120: {}, __VLS_144: {
|
|
59
63
|
item: SelectOption<import("../utils/select-contracts.js").SelectValue>;
|
|
60
|
-
},
|
|
64
|
+
}, __VLS_164: {
|
|
61
65
|
selected: import("./combobox-select.js").ResolvedOption | undefined;
|
|
62
|
-
},
|
|
66
|
+
}, __VLS_175: {}, __VLS_182: {}, __VLS_189: {}, __VLS_219: {}, __VLS_222: {}, __VLS_225: {}, __VLS_228: {}, __VLS_231: {
|
|
63
67
|
item: SelectOption<import("../utils/select-contracts.js").SelectValue>;
|
|
64
|
-
},
|
|
68
|
+
}, __VLS_234: {
|
|
65
69
|
group: import("./combobox-select.js").SelectOptionGroup<import("../utils/select-contracts.js").SelectValue>;
|
|
66
|
-
},
|
|
70
|
+
}, __VLS_237: {}, __VLS_273: string, __VLS_274: {}, __VLS_277: {
|
|
67
71
|
item: SelectOption<import("../utils/select-contracts.js").SelectValue>;
|
|
68
|
-
},
|
|
72
|
+
}, __VLS_280: {
|
|
69
73
|
group: import("./combobox-select.js").SelectOptionGroup<import("../utils/select-contracts.js").SelectValue>;
|
|
70
74
|
};
|
|
71
75
|
type __VLS_Slots = {} & {
|
|
72
|
-
[K in NonNullable<typeof
|
|
76
|
+
[K in NonNullable<typeof __VLS_273>]?: (props: typeof __VLS_274) => any;
|
|
73
77
|
} & {
|
|
74
78
|
item?: (props: typeof __VLS_43) => any;
|
|
75
79
|
} & {
|
|
76
|
-
'clear-icon'?: (props: typeof
|
|
80
|
+
'clear-icon'?: (props: typeof __VLS_98) => any;
|
|
77
81
|
} & {
|
|
78
|
-
'loading-icon'?: (props: typeof
|
|
82
|
+
'loading-icon'?: (props: typeof __VLS_105) => any;
|
|
79
83
|
} & {
|
|
80
|
-
'dropdown-icon'?: (props: typeof
|
|
84
|
+
'dropdown-icon'?: (props: typeof __VLS_120) => any;
|
|
81
85
|
} & {
|
|
82
|
-
item?: (props: typeof
|
|
86
|
+
item?: (props: typeof __VLS_144) => any;
|
|
83
87
|
} & {
|
|
84
|
-
value?: (props: typeof
|
|
88
|
+
value?: (props: typeof __VLS_164) => any;
|
|
85
89
|
} & {
|
|
86
|
-
'clear-icon'?: (props: typeof
|
|
90
|
+
'clear-icon'?: (props: typeof __VLS_175) => any;
|
|
87
91
|
} & {
|
|
88
|
-
'loading-icon'?: (props: typeof
|
|
92
|
+
'loading-icon'?: (props: typeof __VLS_182) => any;
|
|
89
93
|
} & {
|
|
90
|
-
'dropdown-icon'?: (props: typeof
|
|
94
|
+
'dropdown-icon'?: (props: typeof __VLS_189) => any;
|
|
91
95
|
} & {
|
|
92
|
-
header?: (props: typeof
|
|
96
|
+
header?: (props: typeof __VLS_219) => any;
|
|
93
97
|
} & {
|
|
94
|
-
'filter-icon'?: (props: typeof
|
|
98
|
+
'filter-icon'?: (props: typeof __VLS_222) => any;
|
|
95
99
|
} & {
|
|
96
|
-
empty?: (props: typeof
|
|
100
|
+
empty?: (props: typeof __VLS_225) => any;
|
|
97
101
|
} & {
|
|
98
|
-
'empty-filter'?: (props: typeof
|
|
102
|
+
'empty-filter'?: (props: typeof __VLS_228) => any;
|
|
99
103
|
} & {
|
|
100
|
-
item?: (props: typeof
|
|
104
|
+
item?: (props: typeof __VLS_231) => any;
|
|
101
105
|
} & {
|
|
102
|
-
group?: (props: typeof
|
|
106
|
+
group?: (props: typeof __VLS_234) => any;
|
|
103
107
|
} & {
|
|
104
|
-
footer?: (props: typeof
|
|
108
|
+
footer?: (props: typeof __VLS_237) => any;
|
|
105
109
|
} & {
|
|
106
|
-
item?: (props: typeof
|
|
110
|
+
item?: (props: typeof __VLS_277) => any;
|
|
107
111
|
} & {
|
|
108
|
-
group?: (props: typeof
|
|
112
|
+
group?: (props: typeof __VLS_280) => any;
|
|
109
113
|
};
|
|
110
114
|
declare const __VLS_base: import("vue").DefineComponent<ComboboxSelectBaseProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
111
115
|
"update:modelValue": (value: string | number | (string | number)[] | undefined) => any;
|