@auronui/vue 1.0.22 → 1.0.23
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/cjs/index.cjs +393 -366
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/components/date-time-picker/DateTimePicker.js.map +1 -1
- package/dist/components/date-time-picker/DateTimePicker.vue_vue_type_script_setup_true_lang.js +69 -149
- package/dist/components/date-time-picker/DateTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/date-time-picker/DateTimePickerTimeScroller.js.map +1 -1
- package/dist/components/date-time-picker/DateTimePickerTimeScroller.vue_vue_type_script_setup_true_lang.js +49 -54
- package/dist/components/date-time-picker/DateTimePickerTimeScroller.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/list-box/ListBox.context.js.map +1 -1
- package/dist/components/list-box/ListBox.js.map +1 -1
- package/dist/components/list-box/ListBox.vue_vue_type_script_setup_true_lang.js +138 -32
- package/dist/components/list-box/ListBox.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/list-box/ListBoxItem.js.map +1 -1
- package/dist/components/list-box/ListBoxItem.vue_vue_type_script_setup_true_lang.js +11 -4
- package/dist/components/list-box/ListBoxItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/index.d.ts +149 -7
- package/package.json +4 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Fragment, computed, createElementBlock, defineComponent,
|
|
1
|
+
import { Fragment, computed, createElementBlock, defineComponent, normalizeClass, onMounted, openBlock, ref, renderList, toDisplayString } from "vue";
|
|
2
2
|
//#region src/components/date-time-picker/DateTimePickerTimeScroller.vue?vue&type=script&setup=true&lang.ts
|
|
3
3
|
var _hoisted_1 = ["aria-label", "onScrollPassive"];
|
|
4
4
|
var _hoisted_2 = [
|
|
@@ -6,6 +6,7 @@ var _hoisted_2 = [
|
|
|
6
6
|
"aria-selected",
|
|
7
7
|
"onClick"
|
|
8
8
|
];
|
|
9
|
+
var REPEAT = 3;
|
|
9
10
|
var ITEM_H = 40;
|
|
10
11
|
var DateTimePickerTimeScroller_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
|
|
11
12
|
__name: "DateTimePickerTimeScroller",
|
|
@@ -28,51 +29,62 @@ var DateTimePickerTimeScroller_vue_vue_type_script_setup_true_lang_default = /*
|
|
|
28
29
|
const columns = computed(() => {
|
|
29
30
|
const cols = [{
|
|
30
31
|
key: "hour",
|
|
31
|
-
items: hourItems.value
|
|
32
|
+
items: hourItems.value,
|
|
33
|
+
loop: true
|
|
32
34
|
}, {
|
|
33
35
|
key: "minute",
|
|
34
|
-
items: minutes
|
|
36
|
+
items: minutes,
|
|
37
|
+
loop: true
|
|
35
38
|
}];
|
|
36
39
|
if (props.granularity === "second") cols.push({
|
|
37
40
|
key: "second",
|
|
38
|
-
items: seconds
|
|
41
|
+
items: seconds,
|
|
42
|
+
loop: true
|
|
39
43
|
});
|
|
40
44
|
if (props.hourCycle === 12) cols.push({
|
|
41
45
|
key: "ampm",
|
|
42
|
-
items: ampm
|
|
46
|
+
items: ampm,
|
|
47
|
+
loop: false
|
|
43
48
|
});
|
|
44
49
|
return cols;
|
|
45
50
|
});
|
|
46
|
-
function currentIndexFor(key) {
|
|
47
|
-
const v = props.modelValue;
|
|
48
|
-
if (key === "hour") {
|
|
49
|
-
if (props.hourCycle === 12) {
|
|
50
|
-
const h12 = v.hour % 12 === 0 ? 12 : v.hour % 12;
|
|
51
|
-
return hours12.indexOf(h12);
|
|
52
|
-
}
|
|
53
|
-
return v.hour;
|
|
54
|
-
}
|
|
55
|
-
if (key === "minute") return v.minute;
|
|
56
|
-
if (key === "second") return v.second ?? 0;
|
|
57
|
-
if (key === "ampm") return v.hour >= 12 ? 1 : 0;
|
|
58
|
-
return 0;
|
|
59
|
-
}
|
|
60
51
|
const columnRefs = ref([]);
|
|
61
|
-
function
|
|
62
|
-
|
|
52
|
+
function renderItems(col) {
|
|
53
|
+
if (!col.loop) return col.items;
|
|
54
|
+
const out = [];
|
|
55
|
+
for (let r = 0; r < REPEAT; r++) out.push(...col.items);
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
function cycleHeight(col) {
|
|
59
|
+
return col.items.length * ITEM_H;
|
|
63
60
|
}
|
|
64
|
-
function
|
|
61
|
+
function onColumnScroll(i, colEl) {
|
|
62
|
+
const col = columns.value[i];
|
|
63
|
+
if (!col.loop) return;
|
|
64
|
+
const cycle = cycleHeight(col);
|
|
65
|
+
const total = cycle * REPEAT;
|
|
66
|
+
const recenter = (REPEAT - 2) * cycle;
|
|
67
|
+
if (colEl.scrollTop < cycle) colEl.scrollTop += recenter;
|
|
68
|
+
else if (colEl.scrollTop >= total - cycle) colEl.scrollTop -= recenter;
|
|
69
|
+
}
|
|
70
|
+
onMounted(() => {
|
|
65
71
|
columns.value.forEach((col, i) => {
|
|
66
72
|
const el = columnRefs.value[i];
|
|
67
|
-
if (el)
|
|
73
|
+
if (el && col.loop) el.scrollTop = cycleHeight(col) * Math.floor(REPEAT / 2);
|
|
68
74
|
});
|
|
75
|
+
});
|
|
76
|
+
function isSelected(key, item) {
|
|
77
|
+
const v = props.modelValue;
|
|
78
|
+
if (key === "hour") {
|
|
79
|
+
if (props.hourCycle === 12) return item === (v.hour % 12 === 0 ? 12 : v.hour % 12);
|
|
80
|
+
return item === v.hour;
|
|
81
|
+
}
|
|
82
|
+
if (key === "minute") return item === v.minute;
|
|
83
|
+
if (key === "second") return item === (v.second ?? 0);
|
|
84
|
+
if (key === "ampm") return item === (v.hour >= 12 ? "PM" : "AM");
|
|
85
|
+
return false;
|
|
69
86
|
}
|
|
70
|
-
|
|
71
|
-
watch(() => props.modelValue, () => nextTick(syncScrollPositions));
|
|
72
|
-
function onColumnScroll(key, colEl) {
|
|
73
|
-
const idx = Math.round(colEl.scrollTop / ITEM_H);
|
|
74
|
-
const item = columns.value.find((c) => c.key === key).items[idx];
|
|
75
|
-
if (item === void 0) return;
|
|
87
|
+
function onItemClick(key, item) {
|
|
76
88
|
const v = props.modelValue;
|
|
77
89
|
if (key === "hour") {
|
|
78
90
|
let newHour;
|
|
@@ -89,35 +101,19 @@ var DateTimePickerTimeScroller_vue_vue_type_script_setup_true_lang_default = /*
|
|
|
89
101
|
if (isPm !== v.hour >= 12) emit("update:modelValue", v.set({ hour: isPm ? v.hour + 12 : v.hour - 12 }));
|
|
90
102
|
}
|
|
91
103
|
}
|
|
92
|
-
function onKeyDown(e, colEl) {
|
|
93
|
-
if (e.key === "ArrowDown") {
|
|
94
|
-
e.preventDefault();
|
|
95
|
-
colEl.scrollTop += ITEM_H;
|
|
96
|
-
} else if (e.key === "ArrowUp") {
|
|
97
|
-
e.preventDefault();
|
|
98
|
-
colEl.scrollTop -= ITEM_H;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
function onItemClick(colEl, idx) {
|
|
102
|
-
colEl.scrollTo({
|
|
103
|
-
top: idx * ITEM_H,
|
|
104
|
-
behavior: "smooth"
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
104
|
function columnLabel(key) {
|
|
108
105
|
if (key === "hour") return "Hour";
|
|
109
106
|
if (key === "minute") return "Minute";
|
|
110
107
|
if (key === "second") return "Second";
|
|
111
108
|
return "AM/PM";
|
|
112
109
|
}
|
|
113
|
-
function itemLabel(
|
|
110
|
+
function itemLabel(item) {
|
|
114
111
|
if (typeof item === "string") return item;
|
|
115
112
|
return String(item).padStart(2, "0");
|
|
116
113
|
}
|
|
117
114
|
__expose({
|
|
118
115
|
columnRefs,
|
|
119
|
-
columns
|
|
120
|
-
currentIndexFor
|
|
116
|
+
columns
|
|
121
117
|
});
|
|
122
118
|
return (_ctx, _cache) => {
|
|
123
119
|
return openBlock(), createElementBlock("div", {
|
|
@@ -135,17 +131,16 @@ var DateTimePickerTimeScroller_vue_vue_type_script_setup_true_lang_default = /*
|
|
|
135
131
|
"data-slot": "scroller-column",
|
|
136
132
|
role: "listbox",
|
|
137
133
|
tabindex: "0",
|
|
138
|
-
onScrollPassive: ($event) => onColumnScroll(
|
|
139
|
-
|
|
140
|
-
}, [(openBlock(true), createElementBlock(Fragment, null, renderList(col.items, (item, idx) => {
|
|
134
|
+
onScrollPassive: ($event) => onColumnScroll(i, $event.currentTarget)
|
|
135
|
+
}, [(openBlock(true), createElementBlock(Fragment, null, renderList(renderItems(col), (item, idx) => {
|
|
141
136
|
return openBlock(), createElementBlock("div", {
|
|
142
137
|
key: idx,
|
|
143
138
|
class: "date-time-picker__scroller-item",
|
|
144
|
-
"data-selected":
|
|
145
|
-
"aria-selected":
|
|
139
|
+
"data-selected": isSelected(col.key, item) ? "true" : void 0,
|
|
140
|
+
"aria-selected": isSelected(col.key, item),
|
|
146
141
|
role: "option",
|
|
147
|
-
onClick: ($event) => onItemClick(
|
|
148
|
-
}, toDisplayString(itemLabel(
|
|
142
|
+
onClick: ($event) => onItemClick(col.key, item)
|
|
143
|
+
}, toDisplayString(itemLabel(item)), 9, _hoisted_2);
|
|
149
144
|
}), 128))], 40, _hoisted_1);
|
|
150
145
|
}), 128))], 2);
|
|
151
146
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DateTimePickerTimeScroller.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/date-time-picker/DateTimePickerTimeScroller.vue"],"sourcesContent":["<!-- packages/vue/src/components/date-time-picker/DateTimePickerTimeScroller.vue -->\n<script setup lang=\"ts\">\nimport { computed,
|
|
1
|
+
{"version":3,"file":"DateTimePickerTimeScroller.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/date-time-picker/DateTimePickerTimeScroller.vue"],"sourcesContent":["<!-- packages/vue/src/components/date-time-picker/DateTimePickerTimeScroller.vue -->\n<script setup lang=\"ts\">\nimport { computed, onMounted, ref } from 'vue'\nimport { CalendarDateTime } from '@internationalized/date'\n\nconst props = withDefaults(defineProps<{\n modelValue: CalendarDateTime\n granularity?: 'minute' | 'second'\n hourCycle?: 12 | 24\n class?: string\n}>(), {\n granularity: 'minute',\n hourCycle: 24,\n class: undefined,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: CalendarDateTime]\n}>()\n\n// ─── Column data ─────────────────────────────────────────────────────────\n\nconst hours24 = Array.from({ length: 24 }, (_, i) => i)\nconst hours12 = [12, ...Array.from({ length: 11 }, (_, i) => i + 1)] // 12,1..11\nconst minutes = Array.from({ length: 60 }, (_, i) => i)\nconst seconds = Array.from({ length: 60 }, (_, i) => i)\nconst ampm = ['AM', 'PM']\n\nconst hourItems = computed(() =>\n props.hourCycle === 12 ? hours12 : hours24,\n)\n\ntype Column = { key: string; items: (number | string)[]; loop: boolean }\n\nconst columns = computed<Column[]>(() => {\n const cols: Column[] = [\n { key: 'hour', items: hourItems.value, loop: true },\n { key: 'minute', items: minutes, loop: true },\n ]\n if (props.granularity === 'second') cols.push({ key: 'second', items: seconds, loop: true })\n // AM/PM is a short, finite column — it does not loop.\n if (props.hourCycle === 12) cols.push({ key: 'ampm', items: ampm, loop: false })\n return cols\n})\n\n// ─── Infinite circular scroll ─────────────────────────────────────────────\n// Numeric columns repeat their list REPEAT times and start in the middle copy.\n// On scroll, whenever the position drifts out of the middle band we jump it\n// back by whole cycles — invisible because the content is identical — so the\n// wheel can be dragged endlessly in either direction.\n\n// Three copies is the minimum for a seamless loop: a buffer copy at each end\n// plus the middle copy the user actually sits in. More copies = needless DOM.\nconst REPEAT = 3\nconst ITEM_H = 40 // 2.5rem at 16px base\nconst columnRefs = ref<HTMLElement[]>([])\n\nfunction renderItems(col: Column): (number | string)[] {\n if (!col.loop) return col.items\n const out: (number | string)[] = []\n for (let r = 0; r < REPEAT; r++) out.push(...col.items)\n return out\n}\n\nfunction cycleHeight(col: Column): number {\n return col.items.length * ITEM_H\n}\n\n// Keep the scroll position inside the inner copies [cycle, total-cycle); when it\n// drifts into the first or last buffer copy, jump it by (REPEAT-2) cycles. The\n// content is identical, so the jump is invisible and the wheel feels endless.\nfunction onColumnScroll(i: number, colEl: HTMLElement) {\n const col = columns.value[i]\n if (!col.loop) return\n const cycle = cycleHeight(col)\n const total = cycle * REPEAT\n const recenter = (REPEAT - 2) * cycle\n if (colEl.scrollTop < cycle) {\n colEl.scrollTop += recenter\n } else if (colEl.scrollTop >= total - cycle) {\n colEl.scrollTop -= recenter\n }\n}\n\nonMounted(() => {\n columns.value.forEach((col, i) => {\n const el = columnRefs.value[i]\n if (el && col.loop) el.scrollTop = cycleHeight(col) * Math.floor(REPEAT / 2)\n })\n})\n\n// ─── Selection (tap to select) ─────────────────────────────────────────────\n// Selection is by VALUE, so every repeated copy of the chosen number highlights.\n\nfunction isSelected(key: string, item: number | string): boolean {\n const v = props.modelValue\n if (key === 'hour') {\n if (props.hourCycle === 12) {\n const h12 = v.hour % 12 === 0 ? 12 : v.hour % 12\n return item === h12\n }\n return item === v.hour\n }\n if (key === 'minute') return item === v.minute\n if (key === 'second') return item === (v.second ?? 0)\n if (key === 'ampm') return item === (v.hour >= 12 ? 'PM' : 'AM')\n return false\n}\n\nfunction onItemClick(key: string, item: number | string) {\n const v = props.modelValue\n if (key === 'hour') {\n let newHour: number\n if (props.hourCycle === 12) {\n const isPm = v.hour >= 12\n const h12 = item as number\n newHour = h12 === 12 ? (isPm ? 12 : 0) : isPm ? h12 + 12 : h12\n } else {\n newHour = item as number\n }\n emit('update:modelValue', v.set({ hour: newHour }))\n } else if (key === 'minute') {\n emit('update:modelValue', v.set({ minute: item as number }))\n } else if (key === 'second') {\n emit('update:modelValue', v.set({ second: item as number }))\n } else if (key === 'ampm') {\n const isPm = item === 'PM'\n const currentPm = v.hour >= 12\n if (isPm !== currentPm) {\n emit('update:modelValue', v.set({ hour: isPm ? v.hour + 12 : v.hour - 12 }))\n }\n }\n}\n\n// ─── Label helpers ───────────────────────────────────────────────────────\n\nfunction columnLabel(key: string): string {\n if (key === 'hour') return 'Hour'\n if (key === 'minute') return 'Minute'\n if (key === 'second') return 'Second'\n return 'AM/PM'\n}\n\nfunction itemLabel(item: number | string): string {\n if (typeof item === 'string') return item\n return String(item).padStart(2, '0')\n}\n\n// expose for testing\ndefineExpose({ columnRefs, columns })\n</script>\n\n<template>\n <div\n :class=\"['date-time-picker__scroller-wrap', props.class]\"\n data-slot=\"time-scroller\"\n >\n <div\n v-for=\"(col, i) in columns\"\n :key=\"col.key\"\n :ref=\"(el) => { if (el) columnRefs[i] = el as HTMLElement }\"\n class=\"date-time-picker__scroller-column\"\n :aria-label=\"columnLabel(col.key)\"\n data-slot=\"scroller-column\"\n role=\"listbox\"\n tabindex=\"0\"\n @scroll.passive=\"onColumnScroll(i, ($event.currentTarget as HTMLElement))\"\n >\n <div\n v-for=\"(item, idx) in renderItems(col)\"\n :key=\"idx\"\n class=\"date-time-picker__scroller-item\"\n :data-selected=\"isSelected(col.key, item) ? 'true' : undefined\"\n :aria-selected=\"isSelected(col.key, item)\"\n role=\"option\"\n @click=\"onItemClick(col.key, item)\"\n >\n {{ itemLabel(item) }}\n </div>\n </div>\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ListBox.context.js","names":[],"sources":["../../../src/components/list-box/ListBox.context.ts"],"sourcesContent":["import { createContext } from '../../utils/context'\nimport type { Ref } from 'vue'\nimport type { ListBoxVariants } from '@auronui/styles'\nimport type { ListBoxItemVariants } from '@auronui/styles'\n\nexport interface ListBoxContext {\n variant: Ref<ListBoxVariants['variant']>\n itemVariant: Ref<ListBoxItemVariants['variant']>\n isDisabled: Ref<boolean>\n}\n\nexport const {\n useProvide: useListBoxProvide,\n useInject: useListBoxInject,\n key: listBoxContextKey,\n} = createContext<ListBoxContext>('ListBox')\n"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"ListBox.context.js","names":[],"sources":["../../../src/components/list-box/ListBox.context.ts"],"sourcesContent":["import { createContext } from '../../utils/context'\nimport type { Ref } from 'vue'\nimport type { ListBoxVariants } from '@auronui/styles'\nimport type { ListBoxItemVariants } from '@auronui/styles'\n\nexport interface ListBoxContext {\n variant: Ref<ListBoxVariants['variant']>\n itemVariant: Ref<ListBoxItemVariants['variant']>\n isDisabled: Ref<boolean>\n hideSelectedIcon: Ref<boolean>\n}\n\nexport const {\n useProvide: useListBoxProvide,\n useInject: useListBoxInject,\n key: listBoxContextKey,\n} = createContext<ListBoxContext>('ListBox')\n"],"mappings":";;AAYA,IAAa,EACX,YAAY,mBACZ,WAAW,kBACX,KAAK,sBACH,cAA8B,UAAU"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ListBox.js","names":[],"sources":["../../../src/components/list-box/ListBox.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, toRef, useAttrs } from 'vue'\nimport { ListboxRoot, ListboxContent } from 'reka-ui'\nimport { listboxVariants, type ListBoxVariants } from '@auronui/styles'\nimport { composeClassName , type ClassValue} from '../../utils/composeClassName'\nimport { useListBoxProvide } from './ListBox.context'\nimport ListBoxItem from './ListBoxItem.vue'\n\ntype ListBoxShorthandItem = { value: string; label?: string; disabled?: boolean; textValue?: string }\n\n// Disable Vue attribute fallthrough — we manually forward ARIA attrs to ListboxContent\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<{\n modelValue?: string | string[]\n defaultValue?: string | string[]\n selectionMode?: 'single' | 'multiple'\n variant?: ListBoxVariants['variant']\n isDisabled?: boolean\n class?: ClassValue\n /**\n * Per-slot class overrides. Each key maps to a named slot in the anatomy;\n * the value is merged with the generated variant classes via `composeClassName`.\n */\n classNames?: Partial<{\n base: ClassValue\n }>\n /** Shorthand API: render list items from an array instead of the compound slot API */\n items?: ListBoxShorthandItem[]\n /** Allow selecting multiple values (alias for selectionMode=\"multiple\"). */\n multiple?: boolean\n /** Orientation of the listbox for keyboard navigation. */\n orientation?: 'horizontal' | 'vertical'\n /** Reading direction for the component. */\n dir?: 'ltr' | 'rtl'\n /** Selection behavior when multiple is true. */\n selectionBehavior?: 'toggle' | 'replace'\n /** Highlight item on hover. */\n highlightOnHover?: boolean\n /** Key used to compare items for equality. */\n by?: string\n /** Render as a different element or component. */\n as?: string\n /** Merge props onto child element instead of rendering a wrapper. */\n asChild?: boolean\n /** Form field name for native form submission. */\n name?: string\n /** Mark the field as required. */\n required?: boolean\n /** Render the ListboxContent as a different element. */\n contentAs?: string\n /** Merge content props onto child element. */\n contentAsChild?: boolean\n}>(), {\n modelValue: undefined,\n defaultValue: undefined,\n selectionMode: 'single',\n variant: 'default',\n isDisabled: false,\n class: undefined,\n multiple: undefined,\n orientation: undefined,\n dir: undefined,\n selectionBehavior: undefined,\n highlightOnHover: undefined,\n by: undefined,\n as: undefined,\n asChild: false,\n name: undefined,\n required: undefined,\n contentAs: undefined,\n contentAsChild: false,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | string[] | undefined]\n 'highlight': [context: unknown]\n 'entry-focus': [event: Event]\n 'leave': [event: Event]\n}>()\n\nconst attrs = useAttrs()\n\n// Provide context for ListBoxItem and ListBoxSection children\nuseListBoxProvide({\n variant: toRef(props, 'variant'),\n itemVariant: toRef(props, 'variant'),\n isDisabled: toRef(props, 'isDisabled'),\n})\n\nconst slotFns = computed(() =>\n listboxVariants({ variant: props.variant })\n)\n</script>\n\n<template>\n <!-- ListboxRoot is an invisible wrapper that manages state; ListboxContent carries role=\"listbox\" -->\n <!-- We forward attrs (aria-label, aria-labelledby, etc.) to ListboxContent, not the root -->\n <ListboxRoot\n :model-value=\"props.modelValue == null ? undefined : ([] as string[]).concat(props.modelValue)\"\n :default-value=\"props.defaultValue == null ? undefined : ([] as string[]).concat(props.defaultValue)\"\n :multiple=\"props.multiple ?? props.selectionMode === 'multiple'\"\n :selection-behavior=\"props.selectionBehavior ?? (props.selectionMode === 'multiple' ? 'toggle' : 'replace')\"\n :disabled=\"props.isDisabled\"\n :orientation=\"props.orientation\"\n :dir=\"props.dir\"\n :highlight-on-hover=\"props.highlightOnHover\"\n :by=\"props.by\"\n :as=\"props.as\"\n :as-child=\"props.asChild\"\n :name=\"props.name\"\n :required=\"props.required\"\n @update:model-value=\"emit('update:modelValue', props.selectionMode === 'single' ? (Array.isArray($event) ? ($event as string[])[0] : $event as string) : $event as string[])\"\n @highlight=\"emit('highlight', $event)\"\n @entry-focus=\"emit('entry-focus', $event)\"\n @leave=\"emit('leave', $event)\"\n >\n <ListboxContent\n v-bind=\"attrs\"\n :as=\"props.contentAs\"\n :as-child=\"props.contentAsChild\"\n :class=\"composeClassName(slotFns, props.class, props.classNames?.base)\"\n >\n <template v-if=\"props.items\">\n <ListBoxItem\n v-for=\"item in props.items\"\n :key=\"item.value\"\n :value=\"item.value\"\n :is-disabled=\"item.disabled\"\n :text-value=\"item.textValue\"\n >{{ item.label ?? item.value }}</ListBoxItem>\n </template>\n <slot v-else />\n </ListboxContent>\n </ListboxRoot>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"ListBox.js","names":[],"sources":["../../../src/components/list-box/ListBox.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, toRef, useAttrs, useTemplateRef } from 'vue'\nimport { useInfiniteScroll } from '@vueuse/core'\nimport { ListboxRoot, ListboxContent, ListboxVirtualizer } from 'reka-ui'\nimport { listboxVariants, type ListBoxVariants } from '@auronui/styles'\nimport { composeClassName , type ClassValue} from '../../utils/composeClassName'\nimport { useListBoxProvide } from './ListBox.context'\nimport ListBoxItem from './ListBoxItem.vue'\nimport Button from '../button/Button.vue'\n\ntype ListBoxShorthandItem = { value: string; label?: string; disabled?: boolean; textValue?: string }\n\n// Disable Vue attribute fallthrough — we manually forward ARIA attrs to ListboxContent\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<{\n modelValue?: string | string[]\n defaultValue?: string | string[]\n selectionMode?: 'single' | 'multiple'\n variant?: ListBoxVariants['variant']\n isDisabled?: boolean\n class?: ClassValue\n /**\n * Per-slot class overrides. Each key maps to a named slot in the anatomy;\n * the value is merged with the generated variant classes via `composeClassName`.\n */\n classNames?: Partial<{\n base: ClassValue\n }>\n /** Shorthand API: render list items from an array instead of the compound slot API */\n items?: ListBoxShorthandItem[]\n /** Allow selecting multiple values (alias for selectionMode=\"multiple\"). */\n multiple?: boolean\n /** Orientation of the listbox for keyboard navigation. */\n orientation?: 'horizontal' | 'vertical'\n /** Reading direction for the component. */\n dir?: 'ltr' | 'rtl'\n /** Selection behavior when multiple is true. */\n selectionBehavior?: 'toggle' | 'replace'\n /** Highlight item on hover. */\n highlightOnHover?: boolean\n /** Key used to compare items for equality. */\n by?: string\n /** Render as a different element or component. */\n as?: string\n /** Merge props onto child element instead of rendering a wrapper. */\n asChild?: boolean\n /** Form field name for native form submission. */\n name?: string\n /** Mark the field as required. */\n required?: boolean\n /** Render the ListboxContent as a different element. */\n contentAs?: string\n /** Merge content props onto child element. */\n contentAsChild?: boolean\n /** Hide the selected checkmark on all items (forwarded via context). */\n hideSelectedIcon?: boolean\n /** Enable windowed rendering (opt-in). Renders from `items`. */\n virtualized?: boolean\n /** Estimated row height in px (or per-index fn) for the virtualizer. */\n estimateSize?: number | ((index: number) => number)\n /** Rows rendered outside the visible area. */\n overscan?: number\n /** Scroll-viewport height for the content when scrolling is active. */\n maxHeight?: string | number\n /** Whether more pages remain to load (gates load-more). */\n hasMore?: boolean\n /** A page is currently loading (gates load-more; drives #loading slot). */\n isLoading?: boolean\n /** Distance in px from the bottom that triggers load-more. */\n loadMoreDistance?: number\n /** How the next page is requested: auto on scroll, or a manual button. */\n loadMode?: 'scroll' | 'button'\n /** Label for the manual load-more button (loadMode=\"button\"). */\n loadMoreLabel?: string\n}>(), {\n modelValue: undefined,\n defaultValue: undefined,\n selectionMode: 'single',\n variant: 'default',\n isDisabled: false,\n class: undefined,\n multiple: undefined,\n orientation: undefined,\n dir: undefined,\n selectionBehavior: undefined,\n highlightOnHover: undefined,\n by: undefined,\n as: undefined,\n asChild: false,\n name: undefined,\n required: undefined,\n contentAs: undefined,\n contentAsChild: false,\n hideSelectedIcon: false,\n virtualized: false,\n estimateSize: 36,\n overscan: 12,\n maxHeight: '16rem',\n hasMore: false,\n isLoading: false,\n loadMoreDistance: 120,\n loadMode: 'scroll',\n loadMoreLabel: 'Load more',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | string[] | undefined]\n 'highlight': [context: unknown]\n 'entry-focus': [event: Event]\n 'leave': [event: Event]\n 'load-more': []\n}>()\n\nconst attrs = useAttrs()\n\n// Provide context for ListBoxItem and ListBoxSection children\nuseListBoxProvide({\n variant: toRef(props, 'variant'),\n itemVariant: toRef(props, 'variant'),\n isDisabled: toRef(props, 'isDisabled'),\n hideSelectedIcon: toRef(props, 'hideSelectedIcon'),\n})\n\nconst slotFns = computed(() =>\n listboxVariants({ variant: props.variant })\n)\n\n// Bounded scroll viewport only when the content actually needs to scroll, so\n// default (non-virtualized) ListBoxes are visually unchanged.\n// useTemplateRef on a Reka component resolves to its instance; useInfiniteScroll's\n// internal unrefElement reads `.$el` to get the scroll DOM node.\nconst contentRef = useTemplateRef<HTMLElement>('content')\n\n// Re-arm latch. useInfiniteScroll keeps re-invoking onLoadMore while the scroll\n// element stays at the bottom and canLoadMore is true. Emitting `load-more` does\n// not itself flip hasMore/isLoading, so without this guard it fires in a tight\n// loop (unbounded emits → hang). We record the item count at the moment we ask\n// for a page and refuse to ask again until the dataset actually grows — i.e.\n// until the consumer has appended the next page.\nconst lastRequestedCount = ref(-1)\nuseInfiniteScroll(\n contentRef,\n () => {\n lastRequestedCount.value = props.items?.length ?? 0\n emit('load-more')\n },\n {\n // Read once at setup: useScroll consumes `offset.bottom` as a raw number\n // (no toValue), so a getter/ref here would break arrival math. Hot-swapping\n // loadMoreDistance after mount is not supported (not a real use case).\n distance: props.loadMoreDistance,\n canLoadMore: () =>\n props.loadMode === 'scroll'\n && props.hasMore\n && !props.isLoading\n && (props.items?.length ?? 0) !== lastRequestedCount.value,\n },\n)\n\n// Manual load-more (loadMode=\"button\"). User-driven, so no re-arm latch needed —\n// the hasMore/isLoading gate is enough (and the button is disabled while loading).\nfunction requestLoadMore() {\n if (props.hasMore && !props.isLoading) emit('load-more')\n}\n\nconst needsScroll = computed(() => props.virtualized)\nconst contentStyle = computed(() =>\n needsScroll.value\n ? { maxHeight: typeof props.maxHeight === 'number' ? `${props.maxHeight}px` : props.maxHeight, overflowY: 'auto' as const }\n : undefined,\n)\n\n// Stable array references for Reka. Building a fresh array inline on every render\n// would retrigger Reka's `watch(modelValue)`, which re-highlights and\n// scrollIntoView's the selected/first item — making the list jump to the top on\n// any unrelated re-render (e.g. when isLoading toggles during load-more). A\n// computed is cached, so the reference only changes when the value really does.\nconst rekaModelValue = computed(() =>\n props.modelValue == null ? undefined : ([] as string[]).concat(props.modelValue),\n)\nconst rekaDefaultValue = computed(() =>\n props.defaultValue == null ? undefined : ([] as string[]).concat(props.defaultValue),\n)\n</script>\n\n<template>\n <!-- ListboxRoot is an invisible wrapper that manages state; ListboxContent carries role=\"listbox\" -->\n <!-- We forward attrs (aria-label, aria-labelledby, etc.) to ListboxContent, not the root -->\n <ListboxRoot\n :model-value=\"rekaModelValue\"\n :default-value=\"rekaDefaultValue\"\n :multiple=\"props.multiple ?? props.selectionMode === 'multiple'\"\n :selection-behavior=\"props.selectionBehavior ?? (props.selectionMode === 'multiple' ? 'toggle' : 'replace')\"\n :disabled=\"props.isDisabled\"\n :orientation=\"props.orientation\"\n :dir=\"props.dir\"\n :highlight-on-hover=\"props.highlightOnHover\"\n :by=\"props.by\"\n :as=\"props.as\"\n :as-child=\"props.asChild\"\n :name=\"props.name\"\n :required=\"props.required\"\n @update:model-value=\"emit('update:modelValue', props.selectionMode === 'single' ? (Array.isArray($event) ? ($event as string[])[0] : $event as string) : $event as string[])\"\n @highlight=\"emit('highlight', $event)\"\n @entry-focus=\"emit('entry-focus', $event)\"\n @leave=\"emit('leave', $event)\"\n >\n <ListboxContent\n ref=\"content\"\n v-bind=\"attrs\"\n :as=\"props.contentAs\"\n :as-child=\"props.contentAsChild\"\n :style=\"contentStyle\"\n :class=\"composeClassName(slotFns, props.class, props.classNames?.base)\"\n >\n <ListboxVirtualizer\n v-if=\"props.virtualized && props.items\"\n :options=\"props.items\"\n :estimate-size=\"props.estimateSize\"\n :overscan=\"props.overscan\"\n :text-content=\"(o) => (o.label ?? o.value)\"\n >\n <template #default=\"{ option, virtualItem }\">\n <slot name=\"item\" :item=\"option\" :index=\"virtualItem.index\">\n <ListBoxItem\n :value=\"option.value\"\n :is-disabled=\"option.disabled\"\n :text-value=\"option.textValue\"\n >{{ option.label ?? option.value }}</ListBoxItem>\n </slot>\n </template>\n </ListboxVirtualizer>\n\n <template v-else-if=\"props.items\">\n <ListBoxItem\n v-for=\"item in props.items\"\n :key=\"item.value\"\n :value=\"item.value\"\n :is-disabled=\"item.disabled\"\n :text-value=\"item.textValue\"\n >{{ item.label ?? item.value }}</ListBoxItem>\n </template>\n\n <slot v-else />\n </ListboxContent>\n\n <!-- Bottom area, rendered outside role=\"listbox\" so it does not violate\n aria-required-children. Scroll mode shows a loading row; button mode\n shows a manual \"Load more\" button (which conveys its own loading state). -->\n <div\n v-if=\"props.loadMode === 'scroll' && props.isLoading\"\n data-slot=\"list-box-loading\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <slot name=\"loading\">Loading…</slot>\n </div>\n\n <div\n v-if=\"props.loadMode === 'button' && props.hasMore\"\n class=\"flex justify-center p-2\"\n data-slot=\"list-box-load-more\"\n >\n <slot\n name=\"loadMore\"\n :load-more=\"requestLoadMore\"\n :is-loading=\"props.isLoading\"\n :has-more=\"props.hasMore\"\n >\n <Button\n size=\"sm\"\n :is-loading=\"props.isLoading\"\n :disabled=\"props.isLoading\"\n data-slot=\"load-more-button\"\n @click=\"requestLoadMore\"\n >\n {{ props.loadMoreLabel }}\n </Button>\n </slot>\n </div>\n </ListboxRoot>\n</template>\n"],"mappings":""}
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
import { composeClassName } from "../../utils/composeClassName.js";
|
|
2
|
+
import Button_default from "../button/Button.js";
|
|
2
3
|
import { useListBoxProvide } from "./ListBox.context.js";
|
|
3
4
|
import ListBoxItem_default from "./ListBoxItem.js";
|
|
4
|
-
import { Fragment, computed, createBlock, createElementBlock, createTextVNode, createVNode, defineComponent, mergeProps, openBlock, renderList, renderSlot, toDisplayString, toRef, unref, useAttrs, withCtx } from "vue";
|
|
5
|
+
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createTextVNode, createVNode, defineComponent, mergeProps, openBlock, ref, renderList, renderSlot, toDisplayString, toRef, unref, useAttrs, useTemplateRef, withCtx } from "vue";
|
|
6
|
+
import { useInfiniteScroll } from "@vueuse/core";
|
|
5
7
|
import { listboxVariants } from "@auronui/styles";
|
|
6
|
-
import { ListboxContent, ListboxRoot } from "reka-ui";
|
|
8
|
+
import { ListboxContent, ListboxRoot, ListboxVirtualizer } from "reka-ui";
|
|
7
9
|
//#region src/components/list-box/ListBox.vue?vue&type=script&setup=true&lang.ts
|
|
10
|
+
var _hoisted_1 = {
|
|
11
|
+
key: 0,
|
|
12
|
+
"data-slot": "list-box-loading",
|
|
13
|
+
role: "status",
|
|
14
|
+
"aria-live": "polite"
|
|
15
|
+
};
|
|
16
|
+
var _hoisted_2 = {
|
|
17
|
+
key: 1,
|
|
18
|
+
class: "flex justify-center p-2",
|
|
19
|
+
"data-slot": "list-box-load-more"
|
|
20
|
+
};
|
|
8
21
|
var ListBox_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
|
|
9
22
|
inheritAttrs: false,
|
|
10
23
|
__name: "ListBox",
|
|
@@ -55,13 +68,39 @@ var ListBox_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ define
|
|
|
55
68
|
contentAsChild: {
|
|
56
69
|
type: Boolean,
|
|
57
70
|
default: false
|
|
58
|
-
}
|
|
71
|
+
},
|
|
72
|
+
hideSelectedIcon: {
|
|
73
|
+
type: Boolean,
|
|
74
|
+
default: false
|
|
75
|
+
},
|
|
76
|
+
virtualized: {
|
|
77
|
+
type: Boolean,
|
|
78
|
+
default: false
|
|
79
|
+
},
|
|
80
|
+
estimateSize: {
|
|
81
|
+
type: [Number, Function],
|
|
82
|
+
default: 36
|
|
83
|
+
},
|
|
84
|
+
overscan: { default: 12 },
|
|
85
|
+
maxHeight: { default: "16rem" },
|
|
86
|
+
hasMore: {
|
|
87
|
+
type: Boolean,
|
|
88
|
+
default: false
|
|
89
|
+
},
|
|
90
|
+
isLoading: {
|
|
91
|
+
type: Boolean,
|
|
92
|
+
default: false
|
|
93
|
+
},
|
|
94
|
+
loadMoreDistance: { default: 120 },
|
|
95
|
+
loadMode: { default: "scroll" },
|
|
96
|
+
loadMoreLabel: { default: "Load more" }
|
|
59
97
|
},
|
|
60
98
|
emits: [
|
|
61
99
|
"update:modelValue",
|
|
62
100
|
"highlight",
|
|
63
101
|
"entry-focus",
|
|
64
|
-
"leave"
|
|
102
|
+
"leave",
|
|
103
|
+
"load-more"
|
|
65
104
|
],
|
|
66
105
|
setup(__props, { emit: __emit }) {
|
|
67
106
|
const props = __props;
|
|
@@ -70,13 +109,33 @@ var ListBox_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ define
|
|
|
70
109
|
useListBoxProvide({
|
|
71
110
|
variant: toRef(props, "variant"),
|
|
72
111
|
itemVariant: toRef(props, "variant"),
|
|
73
|
-
isDisabled: toRef(props, "isDisabled")
|
|
112
|
+
isDisabled: toRef(props, "isDisabled"),
|
|
113
|
+
hideSelectedIcon: toRef(props, "hideSelectedIcon")
|
|
74
114
|
});
|
|
75
115
|
const slotFns = computed(() => listboxVariants({ variant: props.variant }));
|
|
116
|
+
const contentRef = useTemplateRef("content");
|
|
117
|
+
const lastRequestedCount = ref(-1);
|
|
118
|
+
useInfiniteScroll(contentRef, () => {
|
|
119
|
+
lastRequestedCount.value = props.items?.length ?? 0;
|
|
120
|
+
emit("load-more");
|
|
121
|
+
}, {
|
|
122
|
+
distance: props.loadMoreDistance,
|
|
123
|
+
canLoadMore: () => props.loadMode === "scroll" && props.hasMore && !props.isLoading && (props.items?.length ?? 0) !== lastRequestedCount.value
|
|
124
|
+
});
|
|
125
|
+
function requestLoadMore() {
|
|
126
|
+
if (props.hasMore && !props.isLoading) emit("load-more");
|
|
127
|
+
}
|
|
128
|
+
const needsScroll = computed(() => props.virtualized);
|
|
129
|
+
const contentStyle = computed(() => needsScroll.value ? {
|
|
130
|
+
maxHeight: typeof props.maxHeight === "number" ? `${props.maxHeight}px` : props.maxHeight,
|
|
131
|
+
overflowY: "auto"
|
|
132
|
+
} : void 0);
|
|
133
|
+
const rekaModelValue = computed(() => props.modelValue == null ? void 0 : [].concat(props.modelValue));
|
|
134
|
+
const rekaDefaultValue = computed(() => props.defaultValue == null ? void 0 : [].concat(props.defaultValue));
|
|
76
135
|
return (_ctx, _cache) => {
|
|
77
136
|
return openBlock(), createBlock(unref(ListboxRoot), {
|
|
78
|
-
"model-value":
|
|
79
|
-
"default-value":
|
|
137
|
+
"model-value": rekaModelValue.value,
|
|
138
|
+
"default-value": rekaDefaultValue.value,
|
|
80
139
|
multiple: props.multiple ?? props.selectionMode === "multiple",
|
|
81
140
|
"selection-behavior": props.selectionBehavior ?? (props.selectionMode === "multiple" ? "toggle" : "replace"),
|
|
82
141
|
disabled: props.isDisabled,
|
|
@@ -93,32 +152,79 @@ var ListBox_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ define
|
|
|
93
152
|
onEntryFocus: _cache[2] || (_cache[2] = ($event) => emit("entry-focus", $event)),
|
|
94
153
|
onLeave: _cache[3] || (_cache[3] = ($event) => emit("leave", $event))
|
|
95
154
|
}, {
|
|
96
|
-
default: withCtx(() => [
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
"
|
|
155
|
+
default: withCtx(() => [
|
|
156
|
+
createVNode(unref(ListboxContent), mergeProps({ ref: "content" }, unref(attrs), {
|
|
157
|
+
as: props.contentAs,
|
|
158
|
+
"as-child": props.contentAsChild,
|
|
159
|
+
style: contentStyle.value,
|
|
160
|
+
class: unref(composeClassName)(slotFns.value, props.class, props.classNames?.base)
|
|
161
|
+
}), {
|
|
162
|
+
default: withCtx(() => [props.virtualized && props.items ? (openBlock(), createBlock(unref(ListboxVirtualizer), {
|
|
163
|
+
key: 0,
|
|
164
|
+
options: props.items,
|
|
165
|
+
"estimate-size": props.estimateSize,
|
|
166
|
+
overscan: props.overscan,
|
|
167
|
+
"text-content": (o) => o.label ?? o.value
|
|
107
168
|
}, {
|
|
108
|
-
default: withCtx(() => [
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
169
|
+
default: withCtx(({ option, virtualItem }) => [renderSlot(_ctx.$slots, "item", {
|
|
170
|
+
item: option,
|
|
171
|
+
index: virtualItem.index
|
|
172
|
+
}, () => [createVNode(ListBoxItem_default, {
|
|
173
|
+
value: option.value,
|
|
174
|
+
"is-disabled": option.disabled,
|
|
175
|
+
"text-value": option.textValue
|
|
176
|
+
}, {
|
|
177
|
+
default: withCtx(() => [createTextVNode(toDisplayString(option.label ?? option.value), 1)]),
|
|
178
|
+
_: 2
|
|
179
|
+
}, 1032, [
|
|
180
|
+
"value",
|
|
181
|
+
"is-disabled",
|
|
182
|
+
"text-value"
|
|
183
|
+
])])]),
|
|
184
|
+
_: 3
|
|
185
|
+
}, 8, [
|
|
186
|
+
"options",
|
|
187
|
+
"estimate-size",
|
|
188
|
+
"overscan",
|
|
189
|
+
"text-content"
|
|
190
|
+
])) : props.items ? (openBlock(true), createElementBlock(Fragment, { key: 1 }, renderList(props.items, (item) => {
|
|
191
|
+
return openBlock(), createBlock(ListBoxItem_default, {
|
|
192
|
+
key: item.value,
|
|
193
|
+
value: item.value,
|
|
194
|
+
"is-disabled": item.disabled,
|
|
195
|
+
"text-value": item.textValue
|
|
196
|
+
}, {
|
|
197
|
+
default: withCtx(() => [createTextVNode(toDisplayString(item.label ?? item.value), 1)]),
|
|
198
|
+
_: 2
|
|
199
|
+
}, 1032, [
|
|
200
|
+
"value",
|
|
201
|
+
"is-disabled",
|
|
202
|
+
"text-value"
|
|
203
|
+
]);
|
|
204
|
+
}), 128)) : renderSlot(_ctx.$slots, "default", { key: 2 })]),
|
|
205
|
+
_: 3
|
|
206
|
+
}, 16, [
|
|
207
|
+
"as",
|
|
208
|
+
"as-child",
|
|
209
|
+
"style",
|
|
210
|
+
"class"
|
|
211
|
+
]),
|
|
212
|
+
props.loadMode === "scroll" && props.isLoading ? (openBlock(), createElementBlock("div", _hoisted_1, [renderSlot(_ctx.$slots, "loading", {}, () => [_cache[4] || (_cache[4] = createTextVNode("Loading…", -1))])])) : createCommentVNode("", true),
|
|
213
|
+
props.loadMode === "button" && props.hasMore ? (openBlock(), createElementBlock("div", _hoisted_2, [renderSlot(_ctx.$slots, "loadMore", {
|
|
214
|
+
loadMore: requestLoadMore,
|
|
215
|
+
isLoading: props.isLoading,
|
|
216
|
+
hasMore: props.hasMore
|
|
217
|
+
}, () => [createVNode(Button_default, {
|
|
218
|
+
size: "sm",
|
|
219
|
+
"is-loading": props.isLoading,
|
|
220
|
+
disabled: props.isLoading,
|
|
221
|
+
"data-slot": "load-more-button",
|
|
222
|
+
onClick: requestLoadMore
|
|
223
|
+
}, {
|
|
224
|
+
default: withCtx(() => [createTextVNode(toDisplayString(props.loadMoreLabel), 1)]),
|
|
225
|
+
_: 1
|
|
226
|
+
}, 8, ["is-loading", "disabled"])])])) : createCommentVNode("", true)
|
|
227
|
+
]),
|
|
122
228
|
_: 3
|
|
123
229
|
}, 8, [
|
|
124
230
|
"model-value",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ListBox.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/list-box/ListBox.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, toRef, useAttrs } from 'vue'\nimport { ListboxRoot, ListboxContent } from 'reka-ui'\nimport { listboxVariants, type ListBoxVariants } from '@auronui/styles'\nimport { composeClassName , type ClassValue} from '../../utils/composeClassName'\nimport { useListBoxProvide } from './ListBox.context'\nimport ListBoxItem from './ListBoxItem.vue'\n\ntype ListBoxShorthandItem = { value: string; label?: string; disabled?: boolean; textValue?: string }\n\n// Disable Vue attribute fallthrough — we manually forward ARIA attrs to ListboxContent\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<{\n modelValue?: string | string[]\n defaultValue?: string | string[]\n selectionMode?: 'single' | 'multiple'\n variant?: ListBoxVariants['variant']\n isDisabled?: boolean\n class?: ClassValue\n /**\n * Per-slot class overrides. Each key maps to a named slot in the anatomy;\n * the value is merged with the generated variant classes via `composeClassName`.\n */\n classNames?: Partial<{\n base: ClassValue\n }>\n /** Shorthand API: render list items from an array instead of the compound slot API */\n items?: ListBoxShorthandItem[]\n /** Allow selecting multiple values (alias for selectionMode=\"multiple\"). */\n multiple?: boolean\n /** Orientation of the listbox for keyboard navigation. */\n orientation?: 'horizontal' | 'vertical'\n /** Reading direction for the component. */\n dir?: 'ltr' | 'rtl'\n /** Selection behavior when multiple is true. */\n selectionBehavior?: 'toggle' | 'replace'\n /** Highlight item on hover. */\n highlightOnHover?: boolean\n /** Key used to compare items for equality. */\n by?: string\n /** Render as a different element or component. */\n as?: string\n /** Merge props onto child element instead of rendering a wrapper. */\n asChild?: boolean\n /** Form field name for native form submission. */\n name?: string\n /** Mark the field as required. */\n required?: boolean\n /** Render the ListboxContent as a different element. */\n contentAs?: string\n /** Merge content props onto child element. */\n contentAsChild?: boolean\n}>(), {\n modelValue: undefined,\n defaultValue: undefined,\n selectionMode: 'single',\n variant: 'default',\n isDisabled: false,\n class: undefined,\n multiple: undefined,\n orientation: undefined,\n dir: undefined,\n selectionBehavior: undefined,\n highlightOnHover: undefined,\n by: undefined,\n as: undefined,\n asChild: false,\n name: undefined,\n required: undefined,\n contentAs: undefined,\n contentAsChild: false,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | string[] | undefined]\n 'highlight': [context: unknown]\n 'entry-focus': [event: Event]\n 'leave': [event: Event]\n}>()\n\nconst attrs = useAttrs()\n\n// Provide context for ListBoxItem and ListBoxSection children\nuseListBoxProvide({\n variant: toRef(props, 'variant'),\n itemVariant: toRef(props, 'variant'),\n isDisabled: toRef(props, 'isDisabled'),\n})\n\nconst slotFns = computed(() =>\n listboxVariants({ variant: props.variant })\n)\n</script>\n\n<template>\n <!-- ListboxRoot is an invisible wrapper that manages state; ListboxContent carries role=\"listbox\" -->\n <!-- We forward attrs (aria-label, aria-labelledby, etc.) to ListboxContent, not the root -->\n <ListboxRoot\n :model-value=\"props.modelValue == null ? undefined : ([] as string[]).concat(props.modelValue)\"\n :default-value=\"props.defaultValue == null ? undefined : ([] as string[]).concat(props.defaultValue)\"\n :multiple=\"props.multiple ?? props.selectionMode === 'multiple'\"\n :selection-behavior=\"props.selectionBehavior ?? (props.selectionMode === 'multiple' ? 'toggle' : 'replace')\"\n :disabled=\"props.isDisabled\"\n :orientation=\"props.orientation\"\n :dir=\"props.dir\"\n :highlight-on-hover=\"props.highlightOnHover\"\n :by=\"props.by\"\n :as=\"props.as\"\n :as-child=\"props.asChild\"\n :name=\"props.name\"\n :required=\"props.required\"\n @update:model-value=\"emit('update:modelValue', props.selectionMode === 'single' ? (Array.isArray($event) ? ($event as string[])[0] : $event as string) : $event as string[])\"\n @highlight=\"emit('highlight', $event)\"\n @entry-focus=\"emit('entry-focus', $event)\"\n @leave=\"emit('leave', $event)\"\n >\n <ListboxContent\n v-bind=\"attrs\"\n :as=\"props.contentAs\"\n :as-child=\"props.contentAsChild\"\n :class=\"composeClassName(slotFns, props.class, props.classNames?.base)\"\n >\n <template v-if=\"props.items\">\n <ListBoxItem\n v-for=\"item in props.items\"\n :key=\"item.value\"\n :value=\"item.value\"\n :is-disabled=\"item.disabled\"\n :text-value=\"item.textValue\"\n >{{ item.label ?? item.value }}</ListBoxItem>\n </template>\n <slot v-else />\n </ListboxContent>\n </ListboxRoot>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAaA,MAAM,QAAQ;EA6Dd,MAAM,OAAO;EAOb,MAAM,QAAQ,UAAS;AAGvB,oBAAkB;GAChB,SAAS,MAAM,OAAO,UAAU;GAChC,aAAa,MAAM,OAAO,UAAU;GACpC,YAAY,MAAM,OAAO,aAAa;GACvC,CAAA;EAED,MAAM,UAAU,eACd,gBAAgB,EAAE,SAAS,MAAM,SAAS,CAAA,CAC5C;;uBAME,YAoCc,MAAA,YAAA,EAAA;IAnCX,eAAa,MAAM,cAAU,OAAW,KAAA,IAAS,EAAA,CAAoB,OAAO,MAAM,WAAU;IAC5F,iBAAe,MAAM,gBAAY,OAAW,KAAA,IAAS,EAAA,CAAoB,OAAO,MAAM,aAAY;IAClG,UAAU,MAAM,YAAY,MAAM,kBAAa;IAC/C,sBAAoB,MAAM,sBAAsB,MAAM,kBAAa,aAAA,WAAA;IACnE,UAAU,MAAM;IAChB,aAAa,MAAM;IACnB,KAAK,MAAM;IACX,sBAAoB,MAAM;IAC1B,IAAI,MAAM;IACV,IAAI,MAAM;IACV,YAAU,MAAM;IAChB,MAAM,MAAM;IACZ,UAAU,MAAM;IAChB,uBAAkB,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,qBAAsB,MAAM,kBAAa,WAAiB,MAAM,QAAQ,OAAM,GAAK,OAAM,KAAmB,SAAoB,OAAM;IAC9J,aAAS,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,aAAc,OAAM;IACnC,cAAW,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,eAAgB,OAAM;IACvC,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,SAAU,OAAM;;2BAkBX,CAhBjB,YAgBiB,MAAA,eAAA,EAhBjB,WACU,MAeO,MAfF,EAAA;KACZ,IAAI,MAAM;KACV,YAAU,MAAM;KAChB,OAAO,MAAA,iBAAgB,CAAC,QAAA,OAAS,MAAM,OAAO,MAAM,YAAY,KAAI;;4BAU1D,CARK,MAAM,SAAA,UAAA,KAAA,EACpB,mBAM6C,UAAA,EAAA,KAAA,GAAA,EAAA,WAL5B,MAAM,QAAd,SAAI;0BADb,YAM6C,qBAAA;OAJ1C,KAAK,KAAK;OACV,OAAO,KAAK;OACZ,eAAa,KAAK;OAClB,cAAY,KAAK;;8BACW,CAAA,gBAAA,gBAA3B,KAAK,SAAS,KAAK,MAAK,EAAA,EAAA,CAAA,CAAA;;;;;;;iBAE9B,WAAe,KAAA,QAAA,WAAA,EAAA,KAAA,GAAA,CAAA,CAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"ListBox.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/list-box/ListBox.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, toRef, useAttrs, useTemplateRef } from 'vue'\nimport { useInfiniteScroll } from '@vueuse/core'\nimport { ListboxRoot, ListboxContent, ListboxVirtualizer } from 'reka-ui'\nimport { listboxVariants, type ListBoxVariants } from '@auronui/styles'\nimport { composeClassName , type ClassValue} from '../../utils/composeClassName'\nimport { useListBoxProvide } from './ListBox.context'\nimport ListBoxItem from './ListBoxItem.vue'\nimport Button from '../button/Button.vue'\n\ntype ListBoxShorthandItem = { value: string; label?: string; disabled?: boolean; textValue?: string }\n\n// Disable Vue attribute fallthrough — we manually forward ARIA attrs to ListboxContent\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<{\n modelValue?: string | string[]\n defaultValue?: string | string[]\n selectionMode?: 'single' | 'multiple'\n variant?: ListBoxVariants['variant']\n isDisabled?: boolean\n class?: ClassValue\n /**\n * Per-slot class overrides. Each key maps to a named slot in the anatomy;\n * the value is merged with the generated variant classes via `composeClassName`.\n */\n classNames?: Partial<{\n base: ClassValue\n }>\n /** Shorthand API: render list items from an array instead of the compound slot API */\n items?: ListBoxShorthandItem[]\n /** Allow selecting multiple values (alias for selectionMode=\"multiple\"). */\n multiple?: boolean\n /** Orientation of the listbox for keyboard navigation. */\n orientation?: 'horizontal' | 'vertical'\n /** Reading direction for the component. */\n dir?: 'ltr' | 'rtl'\n /** Selection behavior when multiple is true. */\n selectionBehavior?: 'toggle' | 'replace'\n /** Highlight item on hover. */\n highlightOnHover?: boolean\n /** Key used to compare items for equality. */\n by?: string\n /** Render as a different element or component. */\n as?: string\n /** Merge props onto child element instead of rendering a wrapper. */\n asChild?: boolean\n /** Form field name for native form submission. */\n name?: string\n /** Mark the field as required. */\n required?: boolean\n /** Render the ListboxContent as a different element. */\n contentAs?: string\n /** Merge content props onto child element. */\n contentAsChild?: boolean\n /** Hide the selected checkmark on all items (forwarded via context). */\n hideSelectedIcon?: boolean\n /** Enable windowed rendering (opt-in). Renders from `items`. */\n virtualized?: boolean\n /** Estimated row height in px (or per-index fn) for the virtualizer. */\n estimateSize?: number | ((index: number) => number)\n /** Rows rendered outside the visible area. */\n overscan?: number\n /** Scroll-viewport height for the content when scrolling is active. */\n maxHeight?: string | number\n /** Whether more pages remain to load (gates load-more). */\n hasMore?: boolean\n /** A page is currently loading (gates load-more; drives #loading slot). */\n isLoading?: boolean\n /** Distance in px from the bottom that triggers load-more. */\n loadMoreDistance?: number\n /** How the next page is requested: auto on scroll, or a manual button. */\n loadMode?: 'scroll' | 'button'\n /** Label for the manual load-more button (loadMode=\"button\"). */\n loadMoreLabel?: string\n}>(), {\n modelValue: undefined,\n defaultValue: undefined,\n selectionMode: 'single',\n variant: 'default',\n isDisabled: false,\n class: undefined,\n multiple: undefined,\n orientation: undefined,\n dir: undefined,\n selectionBehavior: undefined,\n highlightOnHover: undefined,\n by: undefined,\n as: undefined,\n asChild: false,\n name: undefined,\n required: undefined,\n contentAs: undefined,\n contentAsChild: false,\n hideSelectedIcon: false,\n virtualized: false,\n estimateSize: 36,\n overscan: 12,\n maxHeight: '16rem',\n hasMore: false,\n isLoading: false,\n loadMoreDistance: 120,\n loadMode: 'scroll',\n loadMoreLabel: 'Load more',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | string[] | undefined]\n 'highlight': [context: unknown]\n 'entry-focus': [event: Event]\n 'leave': [event: Event]\n 'load-more': []\n}>()\n\nconst attrs = useAttrs()\n\n// Provide context for ListBoxItem and ListBoxSection children\nuseListBoxProvide({\n variant: toRef(props, 'variant'),\n itemVariant: toRef(props, 'variant'),\n isDisabled: toRef(props, 'isDisabled'),\n hideSelectedIcon: toRef(props, 'hideSelectedIcon'),\n})\n\nconst slotFns = computed(() =>\n listboxVariants({ variant: props.variant })\n)\n\n// Bounded scroll viewport only when the content actually needs to scroll, so\n// default (non-virtualized) ListBoxes are visually unchanged.\n// useTemplateRef on a Reka component resolves to its instance; useInfiniteScroll's\n// internal unrefElement reads `.$el` to get the scroll DOM node.\nconst contentRef = useTemplateRef<HTMLElement>('content')\n\n// Re-arm latch. useInfiniteScroll keeps re-invoking onLoadMore while the scroll\n// element stays at the bottom and canLoadMore is true. Emitting `load-more` does\n// not itself flip hasMore/isLoading, so without this guard it fires in a tight\n// loop (unbounded emits → hang). We record the item count at the moment we ask\n// for a page and refuse to ask again until the dataset actually grows — i.e.\n// until the consumer has appended the next page.\nconst lastRequestedCount = ref(-1)\nuseInfiniteScroll(\n contentRef,\n () => {\n lastRequestedCount.value = props.items?.length ?? 0\n emit('load-more')\n },\n {\n // Read once at setup: useScroll consumes `offset.bottom` as a raw number\n // (no toValue), so a getter/ref here would break arrival math. Hot-swapping\n // loadMoreDistance after mount is not supported (not a real use case).\n distance: props.loadMoreDistance,\n canLoadMore: () =>\n props.loadMode === 'scroll'\n && props.hasMore\n && !props.isLoading\n && (props.items?.length ?? 0) !== lastRequestedCount.value,\n },\n)\n\n// Manual load-more (loadMode=\"button\"). User-driven, so no re-arm latch needed —\n// the hasMore/isLoading gate is enough (and the button is disabled while loading).\nfunction requestLoadMore() {\n if (props.hasMore && !props.isLoading) emit('load-more')\n}\n\nconst needsScroll = computed(() => props.virtualized)\nconst contentStyle = computed(() =>\n needsScroll.value\n ? { maxHeight: typeof props.maxHeight === 'number' ? `${props.maxHeight}px` : props.maxHeight, overflowY: 'auto' as const }\n : undefined,\n)\n\n// Stable array references for Reka. Building a fresh array inline on every render\n// would retrigger Reka's `watch(modelValue)`, which re-highlights and\n// scrollIntoView's the selected/first item — making the list jump to the top on\n// any unrelated re-render (e.g. when isLoading toggles during load-more). A\n// computed is cached, so the reference only changes when the value really does.\nconst rekaModelValue = computed(() =>\n props.modelValue == null ? undefined : ([] as string[]).concat(props.modelValue),\n)\nconst rekaDefaultValue = computed(() =>\n props.defaultValue == null ? undefined : ([] as string[]).concat(props.defaultValue),\n)\n</script>\n\n<template>\n <!-- ListboxRoot is an invisible wrapper that manages state; ListboxContent carries role=\"listbox\" -->\n <!-- We forward attrs (aria-label, aria-labelledby, etc.) to ListboxContent, not the root -->\n <ListboxRoot\n :model-value=\"rekaModelValue\"\n :default-value=\"rekaDefaultValue\"\n :multiple=\"props.multiple ?? props.selectionMode === 'multiple'\"\n :selection-behavior=\"props.selectionBehavior ?? (props.selectionMode === 'multiple' ? 'toggle' : 'replace')\"\n :disabled=\"props.isDisabled\"\n :orientation=\"props.orientation\"\n :dir=\"props.dir\"\n :highlight-on-hover=\"props.highlightOnHover\"\n :by=\"props.by\"\n :as=\"props.as\"\n :as-child=\"props.asChild\"\n :name=\"props.name\"\n :required=\"props.required\"\n @update:model-value=\"emit('update:modelValue', props.selectionMode === 'single' ? (Array.isArray($event) ? ($event as string[])[0] : $event as string) : $event as string[])\"\n @highlight=\"emit('highlight', $event)\"\n @entry-focus=\"emit('entry-focus', $event)\"\n @leave=\"emit('leave', $event)\"\n >\n <ListboxContent\n ref=\"content\"\n v-bind=\"attrs\"\n :as=\"props.contentAs\"\n :as-child=\"props.contentAsChild\"\n :style=\"contentStyle\"\n :class=\"composeClassName(slotFns, props.class, props.classNames?.base)\"\n >\n <ListboxVirtualizer\n v-if=\"props.virtualized && props.items\"\n :options=\"props.items\"\n :estimate-size=\"props.estimateSize\"\n :overscan=\"props.overscan\"\n :text-content=\"(o) => (o.label ?? o.value)\"\n >\n <template #default=\"{ option, virtualItem }\">\n <slot name=\"item\" :item=\"option\" :index=\"virtualItem.index\">\n <ListBoxItem\n :value=\"option.value\"\n :is-disabled=\"option.disabled\"\n :text-value=\"option.textValue\"\n >{{ option.label ?? option.value }}</ListBoxItem>\n </slot>\n </template>\n </ListboxVirtualizer>\n\n <template v-else-if=\"props.items\">\n <ListBoxItem\n v-for=\"item in props.items\"\n :key=\"item.value\"\n :value=\"item.value\"\n :is-disabled=\"item.disabled\"\n :text-value=\"item.textValue\"\n >{{ item.label ?? item.value }}</ListBoxItem>\n </template>\n\n <slot v-else />\n </ListboxContent>\n\n <!-- Bottom area, rendered outside role=\"listbox\" so it does not violate\n aria-required-children. Scroll mode shows a loading row; button mode\n shows a manual \"Load more\" button (which conveys its own loading state). -->\n <div\n v-if=\"props.loadMode === 'scroll' && props.isLoading\"\n data-slot=\"list-box-loading\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <slot name=\"loading\">Loading…</slot>\n </div>\n\n <div\n v-if=\"props.loadMode === 'button' && props.hasMore\"\n class=\"flex justify-center p-2\"\n data-slot=\"list-box-load-more\"\n >\n <slot\n name=\"loadMore\"\n :load-more=\"requestLoadMore\"\n :is-loading=\"props.isLoading\"\n :has-more=\"props.hasMore\"\n >\n <Button\n size=\"sm\"\n :is-loading=\"props.isLoading\"\n :disabled=\"props.isLoading\"\n data-slot=\"load-more-button\"\n @click=\"requestLoadMore\"\n >\n {{ props.loadMoreLabel }}\n </Button>\n </slot>\n </div>\n </ListboxRoot>\n</template>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ListBoxItem.js","names":[],"sources":["../../../src/components/list-box/ListBoxItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport { ListboxItem, ListboxItemIndicator } from 'reka-ui'\nimport { listboxItemVariants, type ListBoxItemVariants } from '@auronui/styles'\nimport { composeClassName , type ClassValue} from '../../utils/composeClassName'\nimport { useListBoxInject } from './ListBox.context'\n\nconst props = withDefaults(defineProps<{\n value: string\n textValue?: string\n isDisabled?: boolean\n variant?: ListBoxItemVariants['variant']\n class?: ClassValue\n /** Override classes for individual slots */\n classNames?: Partial<{\n item: ClassValue\n indicator: ClassValue\n }>\n /** Whether the item is disabled. Alias for isDisabled. */\n disabled?: boolean\n /** Render as a different element or component. */\n as?: string\n /** Merge props onto child element instead of rendering a wrapper. */\n asChild?: boolean\n /** Render the ListboxItemIndicator as a different element. */\n indicatorAs?: string\n /** Merge indicator props onto child element. */\n indicatorAsChild?: boolean\n}>(), {\n textValue: undefined,\n isDisabled: false,\n variant: undefined,\n class: undefined,\n classNames: undefined,\n disabled: undefined,\n as: undefined,\n asChild: false,\n indicatorAs: undefined,\n indicatorAsChild: false,\n})\n\nconst emit = defineEmits<{\n 'select': [event: Event]\n}>()\n\n// Inject context with fallback (standalone usage)\nconst ctx = useListBoxInject({\n variant: ref('default'),\n itemVariant: ref('default'),\n isDisabled: ref(false),\n})\n\nconst finalVariant = computed(() => props.variant ?? ctx.itemVariant.value)\nconst finalDisabled = computed(() => ctx.isDisabled.value || props.isDisabled)\n\nconst slotFns = computed(() =>\n listboxItemVariants({ variant: finalVariant.value as ListBoxItemVariants['variant'] })\n)\n</script>\n\n<template>\n <ListboxItem\n :value=\"props.value\"\n :disabled=\"props.disabled ?? finalDisabled\"\n :text-value=\"props.textValue ?? props.value\"\n :as=\"props.as\"\n :as-child=\"props.asChild\"\n :class=\"composeClassName(slotFns.item(), props.class, props.classNames?.item)\"\n @select=\"emit('select', $event)\"\n >\n <slot name=\"startContent\" />\n <slot />\n <slot name=\"endContent\" />\n <ListboxItemIndicator\n :as=\"props.indicatorAs\"\n :as-child=\"props.indicatorAsChild\"\n :class=\"composeClassName(slotFns.indicator(), props.classNames?.indicator)\"\n >\n <slot name=\"selectedIcon\">\n <!-- Default check icon -->\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n data-slot=\"list-box-item-indicator--checkmark\"\n aria-hidden=\"true\"\n >\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n </slot>\n </ListboxItemIndicator>\n </ListboxItem>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"ListBoxItem.js","names":[],"sources":["../../../src/components/list-box/ListBoxItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport { ListboxItem, ListboxItemIndicator } from 'reka-ui'\nimport { listboxItemVariants, type ListBoxItemVariants } from '@auronui/styles'\nimport { composeClassName , type ClassValue} from '../../utils/composeClassName'\nimport { useListBoxInject } from './ListBox.context'\n\nconst props = withDefaults(defineProps<{\n value: string\n textValue?: string\n isDisabled?: boolean\n variant?: ListBoxItemVariants['variant']\n class?: ClassValue\n /** Override classes for individual slots */\n classNames?: Partial<{\n item: ClassValue\n indicator: ClassValue\n }>\n /** Whether the item is disabled. Alias for isDisabled. */\n disabled?: boolean\n /** Render as a different element or component. */\n as?: string\n /** Merge props onto child element instead of rendering a wrapper. */\n asChild?: boolean\n /** Render the ListboxItemIndicator as a different element. */\n indicatorAs?: string\n /** Merge indicator props onto child element. */\n indicatorAsChild?: boolean\n /** Hide this item's selected indicator. Falls back to the ListBox setting. */\n hideSelectedIcon?: boolean\n}>(), {\n textValue: undefined,\n isDisabled: false,\n variant: undefined,\n class: undefined,\n classNames: undefined,\n disabled: undefined,\n as: undefined,\n asChild: false,\n indicatorAs: undefined,\n indicatorAsChild: false,\n hideSelectedIcon: undefined,\n})\n\nconst emit = defineEmits<{\n 'select': [event: Event]\n}>()\n\n// Inject context with fallback (standalone usage)\nconst ctx = useListBoxInject({\n variant: ref('default'),\n itemVariant: ref('default'),\n isDisabled: ref(false),\n hideSelectedIcon: ref(false),\n})\n\nconst finalVariant = computed(() => props.variant ?? ctx.itemVariant.value)\nconst finalDisabled = computed(() => ctx.isDisabled.value || props.isDisabled)\nconst finalHideSelectedIcon = computed(\n () => props.hideSelectedIcon ?? ctx.hideSelectedIcon.value,\n)\n\nconst slotFns = computed(() =>\n listboxItemVariants({ variant: finalVariant.value as ListBoxItemVariants['variant'] })\n)\n</script>\n\n<template>\n <ListboxItem\n :value=\"props.value\"\n :disabled=\"props.disabled ?? finalDisabled\"\n :text-value=\"props.textValue ?? props.value\"\n :as=\"props.as\"\n :as-child=\"props.asChild\"\n :class=\"composeClassName(slotFns.item(), props.class, props.classNames?.item)\"\n @select=\"emit('select', $event)\"\n >\n <slot name=\"startContent\" />\n <slot />\n <slot name=\"endContent\" />\n <ListboxItemIndicator\n v-if=\"!finalHideSelectedIcon\"\n :as=\"props.indicatorAs\"\n :as-child=\"props.indicatorAsChild\"\n :class=\"composeClassName(slotFns.indicator(), props.classNames?.indicator)\"\n >\n <slot name=\"selectedIcon\">\n <!-- Default check icon -->\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n data-slot=\"list-box-item-indicator--checkmark\"\n aria-hidden=\"true\"\n >\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n </slot>\n </ListboxItemIndicator>\n </ListboxItem>\n</template>\n"],"mappings":""}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { composeClassName } from "../../utils/composeClassName.js";
|
|
2
2
|
import { useListBoxInject } from "./ListBox.context.js";
|
|
3
|
-
import { computed, createBlock,
|
|
3
|
+
import { computed, createBlock, createCommentVNode, createElementVNode, defineComponent, normalizeClass, openBlock, ref, renderSlot, unref, withCtx } from "vue";
|
|
4
4
|
import { listboxItemVariants } from "@auronui/styles";
|
|
5
5
|
import { ListboxItem, ListboxItemIndicator } from "reka-ui";
|
|
6
6
|
//#region src/components/list-box/ListBoxItem.vue?vue&type=script&setup=true&lang.ts
|
|
@@ -38,6 +38,10 @@ var ListBoxItem_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ de
|
|
|
38
38
|
indicatorAsChild: {
|
|
39
39
|
type: Boolean,
|
|
40
40
|
default: false
|
|
41
|
+
},
|
|
42
|
+
hideSelectedIcon: {
|
|
43
|
+
type: Boolean,
|
|
44
|
+
default: void 0
|
|
41
45
|
}
|
|
42
46
|
},
|
|
43
47
|
emits: ["select"],
|
|
@@ -47,10 +51,12 @@ var ListBoxItem_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ de
|
|
|
47
51
|
const ctx = useListBoxInject({
|
|
48
52
|
variant: ref("default"),
|
|
49
53
|
itemVariant: ref("default"),
|
|
50
|
-
isDisabled: ref(false)
|
|
54
|
+
isDisabled: ref(false),
|
|
55
|
+
hideSelectedIcon: ref(false)
|
|
51
56
|
});
|
|
52
57
|
const finalVariant = computed(() => props.variant ?? ctx.itemVariant.value);
|
|
53
58
|
const finalDisabled = computed(() => ctx.isDisabled.value || props.isDisabled);
|
|
59
|
+
const finalHideSelectedIcon = computed(() => props.hideSelectedIcon ?? ctx.hideSelectedIcon.value);
|
|
54
60
|
const slotFns = computed(() => listboxItemVariants({ variant: finalVariant.value }));
|
|
55
61
|
return (_ctx, _cache) => {
|
|
56
62
|
return openBlock(), createBlock(unref(ListboxItem), {
|
|
@@ -66,7 +72,8 @@ var ListBoxItem_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ de
|
|
|
66
72
|
renderSlot(_ctx.$slots, "startContent"),
|
|
67
73
|
renderSlot(_ctx.$slots, "default"),
|
|
68
74
|
renderSlot(_ctx.$slots, "endContent"),
|
|
69
|
-
|
|
75
|
+
!finalHideSelectedIcon.value ? (openBlock(), createBlock(unref(ListboxItemIndicator), {
|
|
76
|
+
key: 0,
|
|
70
77
|
as: props.indicatorAs,
|
|
71
78
|
"as-child": props.indicatorAsChild,
|
|
72
79
|
class: normalizeClass(unref(composeClassName)(slotFns.value.indicator(), props.classNames?.indicator))
|
|
@@ -89,7 +96,7 @@ var ListBoxItem_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ de
|
|
|
89
96
|
"as",
|
|
90
97
|
"as-child",
|
|
91
98
|
"class"
|
|
92
|
-
])
|
|
99
|
+
])) : createCommentVNode("", true)
|
|
93
100
|
]),
|
|
94
101
|
_: 3
|
|
95
102
|
}, 8, [
|