@byyuurin/ui 0.2.0 → 0.4.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.
Files changed (137) hide show
  1. package/README.md +5 -3
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +2 -2
  4. package/dist/runtime/components/Accordion.vue +2 -2
  5. package/dist/runtime/components/Accordion.vue.d.ts +11 -7
  6. package/dist/runtime/components/Alert.vue +2 -1
  7. package/dist/runtime/components/Alert.vue.d.ts +4 -4
  8. package/dist/runtime/components/App.vue +2 -1
  9. package/dist/runtime/components/App.vue.d.ts +11 -7
  10. package/dist/runtime/components/Avatar.vue +2 -1
  11. package/dist/runtime/components/Avatar.vue.d.ts +4 -3
  12. package/dist/runtime/components/AvatarGroup.vue +2 -1
  13. package/dist/runtime/components/AvatarGroup.vue.d.ts +1 -1
  14. package/dist/runtime/components/Badge.vue +4 -3
  15. package/dist/runtime/components/Badge.vue.d.ts +2 -2
  16. package/dist/runtime/components/Breadcrumb.vue +2 -2
  17. package/dist/runtime/components/Breadcrumb.vue.d.ts +10 -6
  18. package/dist/runtime/components/Button.vue +8 -8
  19. package/dist/runtime/components/Button.vue.d.ts +1 -1
  20. package/dist/runtime/components/Calendar.vue +2 -1
  21. package/dist/runtime/components/Calendar.vue.d.ts +16 -12
  22. package/dist/runtime/components/Card.vue +2 -1
  23. package/dist/runtime/components/Card.vue.d.ts +1 -1
  24. package/dist/runtime/components/Carousel.vue +2 -1
  25. package/dist/runtime/components/Carousel.vue.d.ts +14 -10
  26. package/dist/runtime/components/Checkbox.vue +4 -2
  27. package/dist/runtime/components/Checkbox.vue.d.ts +4 -3
  28. package/dist/runtime/components/CheckboxGroup.vue +4 -3
  29. package/dist/runtime/components/CheckboxGroup.vue.d.ts +11 -7
  30. package/dist/runtime/components/Chip.vue +5 -1
  31. package/dist/runtime/components/Chip.vue.d.ts +2 -2
  32. package/dist/runtime/components/Collapsible.vue +2 -1
  33. package/dist/runtime/components/Collapsible.vue.d.ts +2 -2
  34. package/dist/runtime/components/Drawer.vue +2 -1
  35. package/dist/runtime/components/Drawer.vue.d.ts +6 -6
  36. package/dist/runtime/components/DropdownMenu.vue +3 -3
  37. package/dist/runtime/components/DropdownMenu.vue.d.ts +17 -9
  38. package/dist/runtime/components/DropdownMenuContent.vue +11 -12
  39. package/dist/runtime/components/DropdownMenuContent.vue.d.ts +11 -7
  40. package/dist/runtime/components/FieldGroup.vue +2 -1
  41. package/dist/runtime/components/FieldGroup.vue.d.ts +2 -2
  42. package/dist/runtime/components/FileUpload.vue +267 -0
  43. package/dist/runtime/components/FileUpload.vue.d.ts +178 -0
  44. package/dist/runtime/components/Form.vue +2 -1
  45. package/dist/runtime/components/Form.vue.d.ts +13 -8
  46. package/dist/runtime/components/FormField.vue +6 -4
  47. package/dist/runtime/components/FormField.vue.d.ts +7 -2
  48. package/dist/runtime/components/Icon.vue.d.ts +1 -1
  49. package/dist/runtime/components/Input.vue +4 -4
  50. package/dist/runtime/components/Input.vue.d.ts +16 -12
  51. package/dist/runtime/components/InputNumber.vue +3 -2
  52. package/dist/runtime/components/InputNumber.vue.d.ts +128 -124
  53. package/dist/runtime/components/InputTags.vue +2 -1
  54. package/dist/runtime/components/InputTags.vue.d.ts +16 -11
  55. package/dist/runtime/components/Kbd.vue +2 -1
  56. package/dist/runtime/components/Kbd.vue.d.ts +2 -2
  57. package/dist/runtime/components/Link.vue +5 -3
  58. package/dist/runtime/components/Link.vue.d.ts +16 -6
  59. package/dist/runtime/components/LinkBase.vue.d.ts +2 -2
  60. package/dist/runtime/components/Marquee.vue +2 -1
  61. package/dist/runtime/components/Marquee.vue.d.ts +3 -3
  62. package/dist/runtime/components/Modal.vue +3 -2
  63. package/dist/runtime/components/Modal.vue.d.ts +6 -6
  64. package/dist/runtime/components/NavigationMenu.vue +2 -2
  65. package/dist/runtime/components/NavigationMenu.vue.d.ts +11 -7
  66. package/dist/runtime/components/Pagination.vue +2 -1
  67. package/dist/runtime/components/Pagination.vue.d.ts +4 -4
  68. package/dist/runtime/components/PinInput.vue +4 -4
  69. package/dist/runtime/components/PinInput.vue.d.ts +14 -10
  70. package/dist/runtime/components/Popover.vue +1 -1
  71. package/dist/runtime/components/Popover.vue.d.ts +11 -7
  72. package/dist/runtime/components/Progress.vue +2 -1
  73. package/dist/runtime/components/Progress.vue.d.ts +2 -2
  74. package/dist/runtime/components/RadioGroup.vue +3 -3
  75. package/dist/runtime/components/RadioGroup.vue.d.ts +11 -7
  76. package/dist/runtime/components/ScrollArea.vue +2 -1
  77. package/dist/runtime/components/ScrollArea.vue.d.ts +2 -2
  78. package/dist/runtime/components/Select.vue +282 -131
  79. package/dist/runtime/components/Select.vue.d.ts +103 -123
  80. package/dist/runtime/components/Separator.vue +2 -1
  81. package/dist/runtime/components/Separator.vue.d.ts +2 -2
  82. package/dist/runtime/components/Skeleton.vue +2 -1
  83. package/dist/runtime/components/Skeleton.vue.d.ts +2 -2
  84. package/dist/runtime/components/Slider.vue +2 -1
  85. package/dist/runtime/components/Slider.vue.d.ts +11 -7
  86. package/dist/runtime/components/Stepper.vue +117 -0
  87. package/dist/runtime/components/Stepper.vue.d.ts +83 -0
  88. package/dist/runtime/components/Switch.vue +3 -4
  89. package/dist/runtime/components/Switch.vue.d.ts +4 -3
  90. package/dist/runtime/components/Table.vue +2 -1
  91. package/dist/runtime/components/Table.vue.d.ts +13 -8
  92. package/dist/runtime/components/Tabs.vue +2 -2
  93. package/dist/runtime/components/Tabs.vue.d.ts +12 -8
  94. package/dist/runtime/components/Textarea.vue +3 -3
  95. package/dist/runtime/components/Textarea.vue.d.ts +16 -11
  96. package/dist/runtime/components/Timeline.vue +2 -1
  97. package/dist/runtime/components/Timeline.vue.d.ts +11 -7
  98. package/dist/runtime/components/Toast.vue +2 -1
  99. package/dist/runtime/components/Toast.vue.d.ts +5 -5
  100. package/dist/runtime/components/ToastProvider.vue +2 -2
  101. package/dist/runtime/components/ToastProvider.vue.d.ts +3 -3
  102. package/dist/runtime/components/Tooltip.vue +4 -4
  103. package/dist/runtime/components/Tooltip.vue.d.ts +2 -2
  104. package/dist/runtime/components/Tree.vue +241 -0
  105. package/dist/runtime/components/Tree.vue.d.ts +121 -0
  106. package/dist/runtime/composables/defineShortcuts.d.ts +1 -0
  107. package/dist/runtime/composables/defineShortcuts.js +44 -8
  108. package/dist/runtime/composables/useFileUpload.d.ts +19 -0
  109. package/dist/runtime/composables/useFileUpload.js +79 -0
  110. package/dist/runtime/composables/useLocale.d.ts +18 -0
  111. package/dist/runtime/locale/en.d.ts +9 -0
  112. package/dist/runtime/locale/en.js +9 -0
  113. package/dist/runtime/locale/zh_tw.d.ts +9 -0
  114. package/dist/runtime/locale/zh_tw.js +9 -0
  115. package/dist/runtime/types/html.d.ts +8 -0
  116. package/dist/runtime/types/html.js +0 -0
  117. package/dist/runtime/types/index.d.ts +3 -0
  118. package/dist/runtime/types/index.js +3 -0
  119. package/dist/runtime/types/input.d.ts +5 -5
  120. package/dist/runtime/types/locale.d.ts +9 -0
  121. package/dist/runtime/types/utils.d.ts +4 -4
  122. package/dist/runtime/utils/index.d.ts +3 -3
  123. package/dist/runtime/utils/link.d.ts +2 -1
  124. package/dist/runtime/utils/link.js +40 -29
  125. package/dist/runtime/vue/components/Icon.vue.d.ts +1 -1
  126. package/dist/runtime/vue/components/Link.vue +7 -12
  127. package/dist/runtime/vue/components/Link.vue.d.ts +11 -40
  128. package/dist/setup.d.mts +1 -1
  129. package/dist/shared/{ui.DpbffTXs.d.mts → ui.CGCKYv7g.d.mts} +6 -2
  130. package/dist/shared/{ui.CzIlLITK.mjs → ui.DYMXCXO6.mjs} +9 -5
  131. package/dist/shared/{ui.DLOxhmP0.mjs → ui.DcEKQd0n.mjs} +490 -20
  132. package/dist/unocss.mjs +1 -1
  133. package/dist/unplugin.d.mts +1 -1
  134. package/dist/unplugin.mjs +2 -2
  135. package/dist/vite.d.mts +1 -1
  136. package/dist/vite.mjs +2 -2
  137. package/package.json +31 -31
@@ -0,0 +1,241 @@
1
+ <script>
2
+ import theme from "#build/ui/tree";
3
+ </script>
4
+
5
+ <script setup>
6
+ import { createReusableTemplate, reactivePick } from "@vueuse/core";
7
+ import { defu } from "defu";
8
+ import { TreeItem, TreeRoot, useForwardPropsEmits } from "reka-ui";
9
+ import { computed, shallowRef } from "vue";
10
+ import { useAppConfig } from "#imports";
11
+ import { get, pick } from "../utils";
12
+ import { cv, merge } from "../utils/style";
13
+ import Icon from "./Icon.vue";
14
+ defineOptions({ inheritAttrs: false });
15
+ const props = defineProps({
16
+ as: { type: null, required: false },
17
+ color: { type: null, required: false },
18
+ size: { type: null, required: false },
19
+ getKey: { type: Function, required: false },
20
+ labelKey: { type: null, required: false, default: "label" },
21
+ trailingIcon: { type: [String, Object], required: false },
22
+ expandedIcon: { type: [String, Object], required: false },
23
+ collapsedIcon: { type: [String, Object], required: false },
24
+ items: { type: null, required: false },
25
+ modelValue: { type: null, required: false },
26
+ defaultValue: { type: null, required: false },
27
+ multiple: { type: Boolean, required: false },
28
+ nested: { type: Boolean, required: false, default: true },
29
+ onSelect: { type: Function, required: false },
30
+ onToggle: { type: Function, required: false },
31
+ ui: { type: null, required: false },
32
+ class: { type: [Object, String, Number, Boolean, null, Array], required: false, skipCheck: true },
33
+ expanded: { type: Array, required: false },
34
+ defaultExpanded: { type: Array, required: false },
35
+ selectionBehavior: { type: String, required: false },
36
+ propagateSelect: { type: Boolean, required: false },
37
+ disabled: { type: Boolean, required: false },
38
+ bubbleSelect: { type: Boolean, required: false }
39
+ });
40
+ const emit = defineEmits(["update:modelValue", "update:expanded"]);
41
+ const slots = defineSlots();
42
+ const rootProps = useForwardPropsEmits(reactivePick(props, "items", "expanded", "disabled", "propagateSelect", "bubbleSelect"), emit);
43
+ const as = computed(() => {
44
+ if (typeof props.as === "string" || props.as && "render" in props.as && typeof props.as?.render === "function")
45
+ return { root: props.as, link: "button" };
46
+ return defu(props.as, { root: "ul", link: "button" });
47
+ });
48
+ const flattenedPaddingFormula = computed(() => {
49
+ const sizeConfig = {
50
+ xs: { base: 2, perLevel: 5.5 },
51
+ // px-2, ms-4 + ps-1.5
52
+ sm: { base: 2.5, perLevel: 6 },
53
+ // px-2.5, ms-4.5 + ps-1.5
54
+ md: { base: 2.5, perLevel: 6.5 },
55
+ // px-2.5, ms-5 + ps-1.5
56
+ lg: { base: 3, perLevel: 7 },
57
+ // px-3, ms-5.5 + ps-1.5
58
+ xl: { base: 3, perLevel: 7.5 }
59
+ // px-3, ms-6 + ps-1.5
60
+ };
61
+ const config = sizeConfig[props.size || "md"];
62
+ return (level) => `calc(var(--spacing) * ${(level - 1) * config.perLevel + config.base})`;
63
+ });
64
+ const { define: DefineTreeTemplate, reuse: ReuseTreeTemplate } = createReusableTemplate();
65
+ const { define: DefineItemTemplate, reuse: ReuseItemTemplate } = createReusableTemplate({
66
+ props: {
67
+ item: {
68
+ type: Object,
69
+ required: true
70
+ },
71
+ index: {
72
+ type: Number,
73
+ required: true
74
+ },
75
+ level: {
76
+ type: Number,
77
+ required: true
78
+ }
79
+ }
80
+ });
81
+ const rootRef = shallowRef();
82
+ function getItemLabel(item) {
83
+ return get(item, props.labelKey);
84
+ }
85
+ function getItemKey(item) {
86
+ return props.getKey ? props.getKey(item) || getItemLabel(item) : getItemLabel(item);
87
+ }
88
+ function getDefaultOpenedItems(item) {
89
+ const currentItem = item.defaultExpanded ? getItemKey(item) : null;
90
+ const childItems = item.children?.flatMap((child) => getDefaultOpenedItems(child)) ?? [];
91
+ return [currentItem, ...childItems].filter(Boolean);
92
+ }
93
+ const appConfig = useAppConfig();
94
+ const ui = computed(() => {
95
+ const styler = cv(merge(theme, appConfig.ui.tree));
96
+ return styler(pick(props, ["color", "size"]));
97
+ });
98
+ const defaultExpanded = computed(() => props.defaultExpanded ?? props.items?.flatMap((item) => getDefaultOpenedItems(item)));
99
+ defineExpose({
100
+ get $el() {
101
+ return rootRef.value?.$el;
102
+ }
103
+ });
104
+ function onUpdate(value) {
105
+ emit("update:modelValue", props.multiple && !Array.isArray(value) ? [value] : value);
106
+ }
107
+ </script>
108
+
109
+ <template>
110
+ <DefineItemTemplate v-slot="{ item, index, level }">
111
+ <li
112
+ role="presentation"
113
+ :class="props.nested && level > 1 ? ui.itemWithChildren({ class: [props.ui?.itemWithChildren, item.ui?.itemWithChildren] }) : ui.item({ class: [props.ui?.item, item.ui?.item] })"
114
+ :data-part="props.nested && level > 1 ? 'itemWithChildren' : 'item'"
115
+ >
116
+ <TreeItem
117
+ v-slot="{ isExpanded, isSelected, isIndeterminate, handleSelect, handleToggle }"
118
+ :level="level"
119
+ :value="item"
120
+ as-child
121
+ @toggle="(item.onToggle ?? props.onToggle)?.($event, item)"
122
+ @select="(item.onSelect ?? props.onSelect)?.($event, item)"
123
+ >
124
+ <slot
125
+ :name="`${item.slot ?? 'item'}-wrapper`"
126
+ v-bind="{ index, level, expanded: isExpanded, selected: isSelected, indeterminate: isIndeterminate, handleSelect, handleToggle, ui }"
127
+ :item="item"
128
+ >
129
+ <component
130
+ :is="as.link"
131
+ :type="as.link === 'button' ? 'button' : void 0"
132
+ :disabled="item.disabled || props.disabled"
133
+ :class="ui.link({ class: [props.ui?.link, item.ui?.link, item.class], selected: isSelected, disabled: item.disabled || props.disabled })"
134
+ data-part="link"
135
+ :style="!props.nested && level > 1 ? { paddingLeft: flattenedPaddingFormula(level) } : void 0"
136
+ >
137
+ <slot
138
+ :name="item.slot || 'item'"
139
+ v-bind="{ index, level, expanded: isExpanded, selected: isSelected, indeterminate: isIndeterminate, handleSelect, handleToggle, ui }"
140
+ :item="item"
141
+ >
142
+ <slot
143
+ :name="`${item.slot || 'item'}-leading`"
144
+ v-bind="{ index, level, expanded: isExpanded, selected: isSelected, indeterminate: isIndeterminate, handleSelect, handleToggle, ui }"
145
+ :item="item"
146
+ >
147
+ <Icon
148
+ v-if="item.icon"
149
+ :name="item.icon"
150
+ :class="ui.linkLeadingIcon({ class: [props.ui?.linkLeadingIcon, item.ui?.linkLeadingIcon] })"
151
+ data-part="linkLeadingIcon"
152
+ />
153
+ <Icon
154
+ v-else-if="item.children?.length"
155
+ :name="isExpanded ? props.expandedIcon ?? appConfig.ui.icons.folderOpen : props.collapsedIcon ?? appConfig.ui.icons.folder"
156
+ :class="ui.linkLeadingIcon({ class: [props.ui?.linkLeadingIcon, item.ui?.linkLeadingIcon] })"
157
+ data-part="linkLeadingIcon"
158
+ />
159
+ </slot>
160
+
161
+ <span v-if="getItemLabel(item) || slots[`${item.slot || 'item'}-label`]" :class="ui.linkLabel({ class: [props.ui?.linkLabel, item.ui?.linkLabel] })" data-part="linkLabel">
162
+ <slot
163
+ :name="`${item.slot || 'item'}-label`"
164
+ v-bind="{ index, level, expanded: isExpanded, selected: isSelected, indeterminate: isIndeterminate, handleSelect, handleToggle, ui }"
165
+ :item="item"
166
+ >
167
+ {{ getItemLabel(item) }}
168
+ </slot>
169
+ </span>
170
+
171
+ <span
172
+ v-if="item.trailingIcon || item.children?.length || slots[`${item.slot || 'item'}-trailing`]"
173
+ :class="ui.linkTrailing({ class: [props.ui?.linkTrailing, item.ui?.linkTrailing] })"
174
+ data-part="linkTrailing"
175
+ >
176
+ <slot
177
+ :name="`${item.slot || 'item'}-trailing`"
178
+ v-bind="{ index, level, expanded: isExpanded, selected: isSelected, indeterminate: isIndeterminate, handleSelect, handleToggle, ui }"
179
+ :item="item"
180
+ >
181
+ <Icon
182
+ v-if="item.trailingIcon"
183
+ :name="item.trailingIcon"
184
+ :class="ui.linkTrailingIcon({ class: [props.trailingIcon, item.ui?.linkTrailingIcon] })"
185
+ data-part="linkTrailingIcon"
186
+ />
187
+ <Icon
188
+ v-else-if="item.children?.length"
189
+ :name="props.trailingIcon ?? appConfig.ui.icons.chevronDown"
190
+ :class="ui.linkTrailingIcon({ class: [props.ui?.linkTrailingIcon, item.ui?.linkTrailingIcon] })"
191
+ data-part="linkTrailingIcon"
192
+ />
193
+ </slot>
194
+ </span>
195
+ </slot>
196
+ </component>
197
+ </slot>
198
+
199
+ <ul
200
+ v-if="props.nested && item.children?.length && isExpanded"
201
+ role="group"
202
+ :class="ui.listWithChildren({ class: [props.ui?.listWithChildren, item.ui?.listWithChildren] })"
203
+ data-part="listWithChildren"
204
+ >
205
+ <ReuseTreeTemplate :items="item.children" :level="level + 1" />
206
+ </ul>
207
+ </TreeItem>
208
+ </li>
209
+ </DefineItemTemplate>
210
+
211
+ <DefineTreeTemplate v-slot="{ items, level }">
212
+ <ReuseItemTemplate v-for="(item, index) in items" :key="`${level}-${index}`" :item="item" :index="index" :level="level" />
213
+ </DefineTreeTemplate>
214
+
215
+ <TreeRoot
216
+ ref="rootRef"
217
+ v-slot="{ flattenItems }"
218
+ v-bind="{ ...rootProps, ...$attrs }"
219
+ :as="as.root"
220
+ :model-value="props.modelValue"
221
+ :default-value="props.defaultValue"
222
+ :get-key="getItemKey"
223
+ :default-expanded="defaultExpanded"
224
+ :selection-behavior="props.selectionBehavior"
225
+ :multiple="props.multiple"
226
+ :class="ui.root({ class: [props.ui?.root, props.class] })"
227
+ data-part="root"
228
+ @update:model-value="onUpdate"
229
+ >
230
+ <template v-if="!props.nested">
231
+ <ReuseItemTemplate
232
+ v-for="(item, index) in flattenItems"
233
+ :key="item._id"
234
+ :item="item.value"
235
+ :index="index"
236
+ :level="item.level"
237
+ />
238
+ </template>
239
+ <ReuseTreeTemplate v-else :items="props.items" :level="1" />
240
+ </TreeRoot>
241
+ </template>
@@ -0,0 +1,121 @@
1
+ import type { VariantProps } from '@byyuurin/ui-kit';
2
+ import type { TreeItemProps, TreeItemSelectEvent, TreeItemToggleEvent, TreeRootEmits, TreeRootProps } from 'reka-ui';
3
+ import theme from '#build/ui/tree';
4
+ import type { ComponentBaseProps, ComponentStyler, ComponentUIProps, IconProps } from '../types';
5
+ import type { DynamicSlots, GetItemKeys, StaticSlot } from '../types/utils';
6
+ export interface TreeItem extends ComponentBaseProps {
7
+ icon?: IconProps['name'];
8
+ label?: string;
9
+ trailingIcon?: IconProps['name'];
10
+ defaultExpanded?: boolean;
11
+ disabled?: boolean;
12
+ slot?: string;
13
+ children?: TreeItem[];
14
+ onToggle?: (e: TreeItemToggleEvent<TreeItem>) => void;
15
+ onSelect?: (e: TreeItemSelectEvent<TreeItem>) => void;
16
+ ui?: Pick<ComponentUIProps<typeof theme>, 'item' | 'itemWithChildren' | 'link' | 'linkLeadingIcon' | 'linkLabel' | 'linkTrailing' | 'linkTrailingIcon' | 'listWithChildren'>;
17
+ [key: string]: any;
18
+ }
19
+ type ThemeVariants = VariantProps<typeof theme>;
20
+ export interface TreeProps<T extends TreeItem[] = TreeItem[], M extends boolean = false> extends ComponentBaseProps, Pick<TreeRootProps<T>, 'expanded' | 'defaultExpanded' | 'selectionBehavior' | 'propagateSelect' | 'disabled' | 'bubbleSelect'> {
21
+ /**
22
+ * The element or component this component should render as.
23
+ * @default "ul"
24
+ */
25
+ as?: TreeRootProps<T>['as'] | {
26
+ root?: TreeRootProps<T>['as'];
27
+ link: TreeItemProps<T>['as'];
28
+ };
29
+ /** @default "primary" */
30
+ color?: ThemeVariants['color'];
31
+ /** @default "md" */
32
+ size?: ThemeVariants['size'];
33
+ /** This function is passed the index of each item and should return a unique key for that item */
34
+ getKey?: (val: T[number]) => string;
35
+ /**
36
+ * The key used to get the label from the item.
37
+ * @default "label"
38
+ */
39
+ labelKey?: GetItemKeys<T>;
40
+ /**
41
+ * The icon displayed on the right side of a parent node.
42
+ * @default app.icons.chevronDown
43
+ */
44
+ trailingIcon?: IconProps['name'];
45
+ /**
46
+ * The icon displayed when a parent node is expanded.
47
+ * @default app.icons.folderOpen
48
+ */
49
+ expandedIcon?: IconProps['name'];
50
+ /**
51
+ * The icon displayed when a parent node is collapsed.
52
+ * @default app.icons.folder
53
+ */
54
+ collapsedIcon?: IconProps['name'];
55
+ items?: T;
56
+ /** The controlled value of the Tree. Can be bind as `v-model`. */
57
+ modelValue?: M extends true ? T[number][] : T[number];
58
+ /** The value of the Tree when initially rendered. Use when you do not need to control the state of the Tree. */
59
+ defaultValue?: M extends true ? T[number][] : T[number];
60
+ /** Whether multiple options can be selected or not. */
61
+ multiple?: M & boolean;
62
+ /**
63
+ * Use nested DOM structure (children inside parents) vs flattened structure (all items at same level).
64
+ * @default true
65
+ */
66
+ nested?: boolean;
67
+ onSelect?: (e: TreeItemSelectEvent<T[number]>, item: T[number]) => void;
68
+ onToggle?: (e: TreeItemToggleEvent<T[number]>, item: T[number]) => void;
69
+ ui?: ComponentUIProps<typeof theme>;
70
+ }
71
+ export type TreeEmits<T extends TreeItem[] = TreeItem[], M extends boolean = false> = TreeRootEmits<T[number], M>;
72
+ type SlotProps<T extends TreeItem> = StaticSlot<{
73
+ item: T;
74
+ index: number;
75
+ level: number;
76
+ expanded: boolean;
77
+ selected: boolean;
78
+ indeterminate: boolean | undefined;
79
+ handleSelect: () => void;
80
+ handleToggle: () => void;
81
+ ui: ComponentStyler<typeof theme>;
82
+ }>;
83
+ export type TreeSlots<T extends TreeItem[] = TreeItem[]> = {
84
+ 'item-wrapper': SlotProps<T[number]>;
85
+ 'item': SlotProps<T[number]>;
86
+ 'item-leading': SlotProps<T[number]>;
87
+ 'item-label': SlotProps<T[number]>;
88
+ 'item-trailing': SlotProps<T[number]>;
89
+ } & DynamicSlots<T[number], undefined, {
90
+ index: number;
91
+ level: number;
92
+ expanded: boolean;
93
+ ui: ComponentStyler<typeof theme>;
94
+ selected: boolean;
95
+ indeterminate: boolean | undefined;
96
+ handleSelect: () => void;
97
+ handleToggle: () => void;
98
+ }>;
99
+ declare const _default: typeof __VLS_export;
100
+ export default _default;
101
+ declare const __VLS_export: <T extends TreeItem[], M extends boolean = false>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
102
+ props: import("vue").PublicProps & __VLS_PrettifyLocal<TreeProps<T, M> & {
103
+ "onUpdate:modelValue"?: ((val: M extends true ? T[number][] : T[number]) => any) | undefined;
104
+ "onUpdate:expanded"?: ((val: string[]) => any) | undefined;
105
+ }> & (typeof globalThis extends {
106
+ __VLS_PROPS_FALLBACK: infer P;
107
+ } ? P : {});
108
+ expose: (exposed: import("vue").ShallowUnwrapRef<{
109
+ readonly $el: HTMLElement;
110
+ }>) => void;
111
+ attrs: any;
112
+ slots: TreeSlots<T>;
113
+ emit: ((evt: "update:modelValue", val: M extends true ? T[number][] : T[number]) => void) & ((evt: "update:expanded", val: string[]) => void);
114
+ }>) => import("vue").VNode & {
115
+ __ctx?: Awaited<typeof __VLS_setup>;
116
+ };
117
+ type __VLS_PrettifyLocal<T> = (T extends any ? {
118
+ [K in keyof T]: T[K];
119
+ } : {
120
+ [K in keyof T as K]: T[K];
121
+ }) & {};
@@ -10,6 +10,7 @@ export interface ShortcutsConfig {
10
10
  }
11
11
  export interface ShortcutsOptions {
12
12
  chainDelay?: number;
13
+ layoutIndependent?: boolean;
13
14
  }
14
15
  export declare function extractShortcuts(items: any[] | any[][]): Record<string, Handler>;
15
16
  export declare function defineShortcuts(config: MaybeRef<ShortcutsConfig>, options?: ShortcutsOptions): import("@vueuse/core").Fn;
@@ -3,7 +3,28 @@ import { computed, ref, toValue } from "vue";
3
3
  import { useKbd } from "./useKbd.js";
4
4
  const chainedShortcutRegex = /^[^-]+.*-.*[^-]+$/;
5
5
  const combinedShortcutRegex = /^[^_]+.*_.*[^_]+$/;
6
- const shiftableKeys = /* @__PURE__ */ new Set(["arrowleft", "arrowright", "arrowup", "arrowright", "tab", "escape", "enter", "backspace"]);
6
+ const shiftableKeys = ["arrowleft", "arrowright", "arrowup", "arrowright", "tab", "escape", "enter", "backspace"];
7
+ function convertKeyToCode(key) {
8
+ if (/^[a-z]$/i.test(key))
9
+ return `Key${key.toUpperCase()}`;
10
+ if (/^\d$/.test(key))
11
+ return `Digit${key}`;
12
+ if (/^f\d+$/i.test(key))
13
+ return key.toUpperCase();
14
+ const specialKeys = {
15
+ space: "Space",
16
+ enter: "Enter",
17
+ escape: "Escape",
18
+ tab: "Tab",
19
+ backspace: "Backspace",
20
+ delete: "Delete",
21
+ arrowup: "ArrowUp",
22
+ arrowdown: "ArrowDown",
23
+ arrowleft: "ArrowLeft",
24
+ arrowright: "ArrowRight"
25
+ };
26
+ return specialKeys[key.toLowerCase()] || key;
27
+ }
7
28
  export function extractShortcuts(items) {
8
29
  const shortcuts = {};
9
30
  function traverse(items2) {
@@ -29,6 +50,8 @@ export function defineShortcuts(config, options = {}) {
29
50
  const debouncedClearChainedInput = useDebounceFn(clearChainedInput, options.chainDelay ?? 800);
30
51
  const { macOS } = useKbd();
31
52
  const activeElement = useActiveElement();
53
+ const layoutIndependent = options.layoutIndependent ?? false;
54
+ const shiftableCodes = new Set(shiftableKeys.map((k) => convertKeyToCode(k)));
32
55
  const usingInput = computed(() => {
33
56
  const tagName = activeElement.value?.tagName;
34
57
  const contentEditable = activeElement.value?.contentEditable;
@@ -48,8 +71,13 @@ export function defineShortcuts(config, options = {}) {
48
71
  console.trace(`[Shortcut] Invalid key: "${key}"`);
49
72
  const chained = key.includes("-") && key !== "-" && !key.includes("_");
50
73
  if (chained) {
74
+ let shortcutKey = key.toLowerCase();
75
+ if (layoutIndependent) {
76
+ const parts = key.split("-").map((p) => convertKeyToCode(p));
77
+ shortcutKey = parts.join("-");
78
+ }
51
79
  shortcut = {
52
- key: key.toLowerCase(),
80
+ key: shortcutKey,
53
81
  metaKey: false,
54
82
  ctrlKey: false,
55
83
  shiftKey: false,
@@ -57,8 +85,11 @@ export function defineShortcuts(config, options = {}) {
57
85
  };
58
86
  } else {
59
87
  const keySplit = key.toLowerCase().split("_").map((k) => k);
88
+ let baseKey = keySplit.filter((k) => !["meta", "command", "ctrl", "shift", "alt", "option"].includes(k)).join("_");
89
+ if (layoutIndependent)
90
+ baseKey = convertKeyToCode(baseKey);
60
91
  shortcut = {
61
- key: keySplit.filter((k) => !["meta", "command", "ctrl", "shift", "alt", "option"].includes(k)).join("_"),
92
+ key: baseKey,
62
93
  metaKey: keySplit.includes("meta") || keySplit.includes("command"),
63
94
  ctrlKey: keySplit.includes("ctrl"),
64
95
  shiftKey: keySplit.includes("shift"),
@@ -90,10 +121,10 @@ export function defineShortcuts(config, options = {}) {
90
121
  const onKeyDown = (e) => {
91
122
  if (!e.key)
92
123
  return;
93
- const alphabetKey = /^[a-z]{1}$/i.test(e.key);
94
- const shiftableKey = shiftableKeys.has(e.key.toLowerCase());
124
+ const alphabetKey = layoutIndependent ? /^Key[A-Z]$/i.test(e.code) : /^[a-z]{1}$/i.test(e.key);
125
+ const shiftableKey = layoutIndependent ? shiftableCodes.has(e.code) : shiftableKeys.includes(e.key.toLowerCase());
95
126
  let chainedKey;
96
- chainedInputs.value.push(e.key);
127
+ chainedInputs.value.push(layoutIndependent ? e.code : e.key);
97
128
  if (chainedInputs.value.length >= 2) {
98
129
  chainedKey = chainedInputs.value.slice(-2).join("-");
99
130
  for (const shortcut of shortcuts.value.filter((s) => s.chained)) {
@@ -108,8 +139,13 @@ export function defineShortcuts(config, options = {}) {
108
139
  }
109
140
  }
110
141
  for (const shortcut of shortcuts.value.filter((s) => !s.chained)) {
111
- if (e.key.toLowerCase() !== shortcut.key)
112
- continue;
142
+ if (layoutIndependent) {
143
+ if (e.code !== shortcut.key)
144
+ continue;
145
+ } else {
146
+ if (e.key.toLowerCase() !== shortcut.key)
147
+ continue;
148
+ }
113
149
  if (e.metaKey !== shortcut.metaKey)
114
150
  continue;
115
151
  if (e.ctrlKey !== shortcut.ctrlKey)
@@ -0,0 +1,19 @@
1
+ import type { ComponentPublicInstance, MaybeRef } from 'vue';
2
+ export interface UseFileUploadOptions {
3
+ /**
4
+ * Specifies the allowed file types. Provide a comma-separated list of MIME types or file extensions.
5
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/accept
6
+ * @default "*"
7
+ */
8
+ accept?: MaybeRef<string>;
9
+ reset?: boolean;
10
+ multiple?: MaybeRef<boolean>;
11
+ dropzone?: MaybeRef<boolean>;
12
+ onUpdate: (files: File[]) => void;
13
+ }
14
+ export declare function useFileUpload(options: UseFileUploadOptions): {
15
+ isDragging: import("vue").ShallowRef<boolean, boolean>;
16
+ open: () => void;
17
+ inputRef: import("vue").ShallowRef<ComponentPublicInstance | undefined, ComponentPublicInstance | undefined>;
18
+ dropzoneRef: import("vue").ShallowRef<HTMLDivElement | undefined, HTMLDivElement | undefined>;
19
+ };
@@ -0,0 +1,79 @@
1
+ import { useDropZone, useFileDialog } from "@vueuse/core";
2
+ import { computed, onMounted, reactive, shallowRef, unref, watch } from "vue";
3
+ function parseAcceptToDataTypes(accept) {
4
+ if (!accept || accept === "*")
5
+ return void 0;
6
+ const types = accept.split(",").map((type) => {
7
+ const trimmedType = type.trim();
8
+ if (trimmedType.includes("/") && trimmedType.endsWith("/*"))
9
+ return trimmedType.split("/")[0] || trimmedType;
10
+ return trimmedType;
11
+ }).filter((type) => {
12
+ return !type.startsWith(".");
13
+ });
14
+ return types.length > 0 ? types : void 0;
15
+ }
16
+ export function useFileUpload(options) {
17
+ const {
18
+ accept = "*",
19
+ reset = false,
20
+ multiple = false,
21
+ dropzone = true,
22
+ onUpdate
23
+ } = options;
24
+ const inputRef = shallowRef();
25
+ const dropzoneRef = shallowRef();
26
+ const dataTypes = computed(() => parseAcceptToDataTypes(unref(accept)));
27
+ const onDrop = (files, fromDropzone = false) => {
28
+ if (!files || files.length === 0)
29
+ return;
30
+ if (files instanceof FileList)
31
+ files = Array.from(files);
32
+ if (files.length > 1 && !unref(multiple))
33
+ files = [files[0]];
34
+ if (fromDropzone && inputRef.value?.$el) {
35
+ try {
36
+ const dt = new DataTransfer();
37
+ files.forEach((file) => dt.items.add(file));
38
+ inputRef.value.$el.files = dt.files;
39
+ } catch (e) {
40
+ console.warn("Could not sync files to input element:", e);
41
+ }
42
+ }
43
+ onUpdate(files);
44
+ };
45
+ const isDragging = shallowRef(false);
46
+ const fileDialog = reactive({
47
+ open: () => {
48
+ }
49
+ });
50
+ function open() {
51
+ fileDialog.open();
52
+ }
53
+ onMounted(() => {
54
+ const { isOverDropZone } = useDropZone(
55
+ () => unref(dropzone) ? dropzoneRef.value : void 0,
56
+ {
57
+ dataTypes: dataTypes.value,
58
+ onDrop: (files) => onDrop(files, true)
59
+ }
60
+ );
61
+ watch(isOverDropZone, (value) => {
62
+ isDragging.value = unref(dropzone) ? value : false;
63
+ });
64
+ const { onChange, open: open2 } = useFileDialog({
65
+ accept,
66
+ multiple,
67
+ input: unref(inputRef)?.$el,
68
+ reset
69
+ });
70
+ fileDialog.open = open2;
71
+ onChange((fileList) => onDrop(fileList, false));
72
+ });
73
+ return {
74
+ isDragging,
75
+ open,
76
+ inputRef,
77
+ dropzoneRef
78
+ };
79
+ }
@@ -19,6 +19,9 @@ declare function _useLocale(): {
19
19
  next: string;
20
20
  goto: string;
21
21
  };
22
+ fileUpload: {
23
+ removeFile: string;
24
+ };
22
25
  inputNumber: {
23
26
  increment: string;
24
27
  decrement: string;
@@ -26,6 +29,12 @@ declare function _useLocale(): {
26
29
  modal: {
27
30
  close: string;
28
31
  };
32
+ select: {
33
+ create: string;
34
+ noData: string;
35
+ noMatch: string;
36
+ search: string;
37
+ };
29
38
  table: {
30
39
  noData: string;
31
40
  };
@@ -52,6 +61,9 @@ declare function _useLocale(): {
52
61
  next: string;
53
62
  goto: string;
54
63
  };
64
+ fileUpload: {
65
+ removeFile: string;
66
+ };
55
67
  inputNumber: {
56
68
  increment: string;
57
69
  decrement: string;
@@ -59,6 +71,12 @@ declare function _useLocale(): {
59
71
  modal: {
60
72
  close: string;
61
73
  };
74
+ select: {
75
+ create: string;
76
+ noData: string;
77
+ noMatch: string;
78
+ search: string;
79
+ };
62
80
  table: {
63
81
  noData: string;
64
82
  };
@@ -14,6 +14,9 @@ declare const _default: Required<import("@byyuurin/ui-kit").Locale<{
14
14
  next: string;
15
15
  goto: string;
16
16
  };
17
+ fileUpload: {
18
+ removeFile: string;
19
+ };
17
20
  inputNumber: {
18
21
  increment: string;
19
22
  decrement: string;
@@ -21,6 +24,12 @@ declare const _default: Required<import("@byyuurin/ui-kit").Locale<{
21
24
  modal: {
22
25
  close: string;
23
26
  };
27
+ select: {
28
+ create: string;
29
+ noData: string;
30
+ noMatch: string;
31
+ search: string;
32
+ };
24
33
  table: {
25
34
  noData: string;
26
35
  };
@@ -18,6 +18,9 @@ export default defineLocale({
18
18
  next: "Next",
19
19
  goto: "Go to slide {page}"
20
20
  },
21
+ fileUpload: {
22
+ removeFile: "Remove {filename}"
23
+ },
21
24
  inputNumber: {
22
25
  increment: "Increment",
23
26
  decrement: "Decrement"
@@ -25,6 +28,12 @@ export default defineLocale({
25
28
  modal: {
26
29
  close: "Close"
27
30
  },
31
+ select: {
32
+ create: 'Create "{label}"',
33
+ noData: "No data",
34
+ noMatch: "No matching data",
35
+ search: "Search\u2026"
36
+ },
28
37
  table: {
29
38
  noData: "No data"
30
39
  },
@@ -14,6 +14,9 @@ declare const _default: Required<import("@byyuurin/ui-kit").Locale<{
14
14
  next: string;
15
15
  goto: string;
16
16
  };
17
+ fileUpload: {
18
+ removeFile: string;
19
+ };
17
20
  inputNumber: {
18
21
  increment: string;
19
22
  decrement: string;
@@ -21,6 +24,12 @@ declare const _default: Required<import("@byyuurin/ui-kit").Locale<{
21
24
  modal: {
22
25
  close: string;
23
26
  };
27
+ select: {
28
+ create: string;
29
+ noData: string;
30
+ noMatch: string;
31
+ search: string;
32
+ };
24
33
  table: {
25
34
  noData: string;
26
35
  };