@zerodep-dev/vue-tsx-pro-mobile 0.0.0-stage → 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.
- package/LICENSE +21 -0
- package/README.md +29 -2
- package/dist/area/data.d.ts +10 -0
- package/dist/area/data.js +3899 -0
- package/dist/area/data.js.map +1 -0
- package/dist/area/index.d.ts +22 -0
- package/dist/area/index.js +41 -0
- package/dist/area/index.js.map +1 -0
- package/dist/base/Button.d.ts +170 -0
- package/dist/base/Button.js +537 -0
- package/dist/base/Button.js.map +1 -0
- package/dist/base/Icon.d.ts +38 -0
- package/dist/base/Icon.js +65 -0
- package/dist/base/Icon.js.map +1 -0
- package/dist/capability/PrivacyPrompt.d.ts +1 -0
- package/dist/capability/PrivacyPrompt.js +73 -0
- package/dist/capability/PrivacyPrompt.js.map +1 -0
- package/dist/capability/types.d.ts +92 -0
- package/dist/capability/usePermission.d.ts +23 -0
- package/dist/capability/usePermission.js +52 -0
- package/dist/capability/usePermission.js.map +1 -0
- package/dist/capability/useStorage.d.ts +8 -0
- package/dist/capability/useStorage.js +19 -0
- package/dist/capability/useStorage.js.map +1 -0
- package/dist/capability/web.d.ts +18 -0
- package/dist/capability/web.js +109 -0
- package/dist/capability/web.js.map +1 -0
- package/dist/capacitor/index.d.ts +9 -0
- package/dist/capacitor/index.js +143 -0
- package/dist/capacitor/index.js.map +1 -0
- package/dist/config/ConfigProvider.d.ts +37 -0
- package/dist/config/ConfigProvider.js +64 -0
- package/dist/config/ConfigProvider.js.map +1 -0
- package/dist/config/context.d.ts +16 -0
- package/dist/config/context.js +20 -0
- package/dist/config/context.js.map +1 -0
- package/dist/config/lang.d.ts +85 -0
- package/dist/config/lang.js +138 -0
- package/dist/config/lang.js.map +1 -0
- package/dist/display/Badge.d.ts +39 -0
- package/dist/display/Badge.js +108 -0
- package/dist/display/Badge.js.map +1 -0
- package/dist/display/Cell.d.ts +92 -0
- package/dist/display/Cell.js +204 -0
- package/dist/display/Cell.js.map +1 -0
- package/dist/display/Collapse.d.ts +47 -0
- package/dist/display/Collapse.js +173 -0
- package/dist/display/Collapse.js.map +1 -0
- package/dist/display/Empty.d.ts +42 -0
- package/dist/display/Empty.js +79 -0
- package/dist/display/Empty.js.map +1 -0
- package/dist/display/Grid.d.ts +49 -0
- package/dist/display/Grid.js +136 -0
- package/dist/display/Grid.js.map +1 -0
- package/dist/display/Image.d.ts +70 -0
- package/dist/display/Image.js +138 -0
- package/dist/display/Image.js.map +1 -0
- package/dist/display/IndexBar.d.ts +34 -0
- package/dist/display/IndexBar.js +158 -0
- package/dist/display/IndexBar.js.map +1 -0
- package/dist/display/List.d.ts +34 -0
- package/dist/display/List.js +105 -0
- package/dist/display/List.js.map +1 -0
- package/dist/display/NoticeBar.d.ts +57 -0
- package/dist/display/NoticeBar.js +172 -0
- package/dist/display/NoticeBar.js.map +1 -0
- package/dist/display/Steps.d.ts +59 -0
- package/dist/display/Steps.js +158 -0
- package/dist/display/Steps.js.map +1 -0
- package/dist/display/SwipeCell.d.ts +37 -0
- package/dist/display/SwipeCell.js +147 -0
- package/dist/display/SwipeCell.js.map +1 -0
- package/dist/display/Swiper.d.ts +47 -0
- package/dist/display/Swiper.js +173 -0
- package/dist/display/Swiper.js.map +1 -0
- package/dist/display/Tag.d.ts +99 -0
- package/dist/display/Tag.js +320 -0
- package/dist/display/Tag.js.map +1 -0
- package/dist/feedback/Dialog.d.ts +79 -0
- package/dist/feedback/Dialog.js +186 -0
- package/dist/feedback/Dialog.js.map +1 -0
- package/dist/feedback/FeedbackOutlet.d.ts +2 -0
- package/dist/feedback/FeedbackOutlet.js +31 -0
- package/dist/feedback/FeedbackOutlet.js.map +1 -0
- package/dist/feedback/Loading.d.ts +26 -0
- package/dist/feedback/Loading.js +68 -0
- package/dist/feedback/Loading.js.map +1 -0
- package/dist/feedback/Notify.d.ts +48 -0
- package/dist/feedback/Notify.js +116 -0
- package/dist/feedback/Notify.js.map +1 -0
- package/dist/feedback/PullRefresh.d.ts +58 -0
- package/dist/feedback/PullRefresh.js +178 -0
- package/dist/feedback/PullRefresh.js.map +1 -0
- package/dist/feedback/Skeleton.d.ts +56 -0
- package/dist/feedback/Skeleton.js +99 -0
- package/dist/feedback/Skeleton.js.map +1 -0
- package/dist/feedback/Toast.d.ts +89 -0
- package/dist/feedback/Toast.js +186 -0
- package/dist/feedback/Toast.js.map +1 -0
- package/dist/form/Checkbox.d.ts +52 -0
- package/dist/form/Checkbox.js +107 -0
- package/dist/form/Checkbox.js.map +1 -0
- package/dist/form/Field.d.ts +91 -0
- package/dist/form/Field.js +296 -0
- package/dist/form/Field.js.map +1 -0
- package/dist/form/Form.d.ts +50 -0
- package/dist/form/Form.js +96 -0
- package/dist/form/Form.js.map +1 -0
- package/dist/form/FormItem.d.ts +57 -0
- package/dist/form/FormItem.js +142 -0
- package/dist/form/FormItem.js.map +1 -0
- package/dist/form/Radio.d.ts +41 -0
- package/dist/form/Radio.js +85 -0
- package/dist/form/Radio.js.map +1 -0
- package/dist/form/Rate.d.ts +45 -0
- package/dist/form/Rate.js +162 -0
- package/dist/form/Rate.js.map +1 -0
- package/dist/form/Search.d.ts +50 -0
- package/dist/form/Search.js +152 -0
- package/dist/form/Search.js.map +1 -0
- package/dist/form/Slider.d.ts +43 -0
- package/dist/form/Slider.js +213 -0
- package/dist/form/Slider.js.map +1 -0
- package/dist/form/Stepper.d.ts +61 -0
- package/dist/form/Stepper.js +222 -0
- package/dist/form/Stepper.js.map +1 -0
- package/dist/form/Switch.d.ts +33 -0
- package/dist/form/Switch.js +116 -0
- package/dist/form/Switch.js.map +1 -0
- package/dist/form/Uploader.d.ts +67 -0
- package/dist/form/Uploader.js +207 -0
- package/dist/form/Uploader.js.map +1 -0
- package/dist/form/choice.d.ts +42 -0
- package/dist/form/choice.js +109 -0
- package/dist/form/choice.js.map +1 -0
- package/dist/form/context.d.ts +83 -0
- package/dist/form/context.js +89 -0
- package/dist/form/context.js.map +1 -0
- package/dist/index.d.ts +66 -0
- package/dist/index.js +59 -0
- package/dist/layout/Divider.d.ts +34 -0
- package/dist/layout/Divider.js +55 -0
- package/dist/layout/Divider.js.map +1 -0
- package/dist/layout/Space.d.ts +66 -0
- package/dist/layout/Space.js +65 -0
- package/dist/layout/Space.js.map +1 -0
- package/dist/navigation/BackTop.d.ts +29 -0
- package/dist/navigation/BackTop.js +89 -0
- package/dist/navigation/BackTop.js.map +1 -0
- package/dist/navigation/NavBar.d.ts +46 -0
- package/dist/navigation/NavBar.js +141 -0
- package/dist/navigation/NavBar.js.map +1 -0
- package/dist/navigation/Sticky.d.ts +19 -0
- package/dist/navigation/Sticky.js +28 -0
- package/dist/navigation/Sticky.js.map +1 -0
- package/dist/navigation/TabBar.d.ts +54 -0
- package/dist/navigation/TabBar.js +138 -0
- package/dist/navigation/TabBar.js.map +1 -0
- package/dist/navigation/Tabs.d.ts +45 -0
- package/dist/navigation/Tabs.js +206 -0
- package/dist/navigation/Tabs.js.map +1 -0
- package/dist/overlay/ActionSheet.d.ts +80 -0
- package/dist/overlay/ActionSheet.js +164 -0
- package/dist/overlay/ActionSheet.js.map +1 -0
- package/dist/overlay/Overlay.d.ts +35 -0
- package/dist/overlay/Overlay.js +85 -0
- package/dist/overlay/Overlay.js.map +1 -0
- package/dist/overlay/Popup.d.ts +76 -0
- package/dist/overlay/Popup.js +191 -0
- package/dist/overlay/Popup.js.map +1 -0
- package/dist/picker/Calendar.d.ts +69 -0
- package/dist/picker/Calendar.js +213 -0
- package/dist/picker/Calendar.js.map +1 -0
- package/dist/picker/Cascader.d.ts +50 -0
- package/dist/picker/Cascader.js +199 -0
- package/dist/picker/Cascader.js.map +1 -0
- package/dist/picker/DatePicker.d.ts +52 -0
- package/dist/picker/DatePicker.js +135 -0
- package/dist/picker/DatePicker.js.map +1 -0
- package/dist/picker/DropdownMenu.d.ts +39 -0
- package/dist/picker/DropdownMenu.js +242 -0
- package/dist/picker/DropdownMenu.js.map +1 -0
- package/dist/picker/Picker.d.ts +67 -0
- package/dist/picker/Picker.js +185 -0
- package/dist/picker/Picker.js.map +1 -0
- package/dist/picker/PickerColumn.d.ts +36 -0
- package/dist/picker/PickerColumn.js +175 -0
- package/dist/picker/PickerColumn.js.map +1 -0
- package/dist/theme/dark.d.ts +121 -0
- package/dist/theme/dark.js +77 -0
- package/dist/theme/dark.js.map +1 -0
- package/dist/theme/divider.d.ts +6 -0
- package/dist/theme/divider.js +18 -0
- package/dist/theme/divider.js.map +1 -0
- package/dist/theme/token-names.d.ts +1389 -0
- package/dist/theme/tokens.d.ts +549 -0
- package/dist/theme/tokens.js +312 -0
- package/dist/theme/tokens.js.map +1 -0
- package/dist/utils/host.d.ts +97 -0
- package/dist/utils/host.js +98 -0
- package/dist/utils/host.js.map +1 -0
- package/dist/utils/presence.d.ts +11 -0
- package/dist/utils/presence.js +34 -0
- package/dist/utils/presence.js.map +1 -0
- package/dist/utils/props.d.ts +38 -0
- package/dist/utils/props.js +115 -0
- package/dist/utils/props.js.map +1 -0
- package/dist/utils/scales.d.ts +48 -0
- package/package.json +106 -3
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { useConfig } from "../config/context.js";
|
|
2
|
+
import { Picker } from "./Picker.js";
|
|
3
|
+
import { _component, bindable, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
4
|
+
import { computed, createVNode } from "vue";
|
|
5
|
+
//#region src/picker/DatePicker.tsx
|
|
6
|
+
/** 日期的列 */
|
|
7
|
+
/** 共有的属性 */
|
|
8
|
+
/** 未声明的属性落到选择器的根元素上 */
|
|
9
|
+
var daysIn = (year, month) => new Date(year, month, 0).getDate();
|
|
10
|
+
var range = (from, to) => Array.from({ length: to - from + 1 }, (_, index) => from + index);
|
|
11
|
+
var pad = (value) => String(value).padStart(2, "0");
|
|
12
|
+
/** 日期选择器(Picker) */
|
|
13
|
+
var DatePicker = /*#__PURE__*/ _component((_props, _ctx) => {
|
|
14
|
+
const _cache = [];
|
|
15
|
+
const value = bindable(_props, "_value", () => void 0, _ctx.emit);
|
|
16
|
+
const minDate = readonlyProp(_props, "minDate");
|
|
17
|
+
const maxDate = readonlyProp(_props, "maxDate");
|
|
18
|
+
const columns = readonlyProp(_props, "columns", () => [
|
|
19
|
+
"year",
|
|
20
|
+
"month",
|
|
21
|
+
"day"
|
|
22
|
+
]);
|
|
23
|
+
const onConfirm = readonlyProp(_props, "onConfirm");
|
|
24
|
+
const rest = restProps(_props, _ctx, true);
|
|
25
|
+
const config = useConfig();
|
|
26
|
+
const now = /* @__PURE__ */ new Date();
|
|
27
|
+
const min = computed(() => minDate.value ?? new Date(now.getFullYear() - 10, 0, 1));
|
|
28
|
+
const max = computed(() => maxDate.value ?? new Date(now.getFullYear() + 10, 11, 31));
|
|
29
|
+
/** 把日期限在范围内(只看年月日) */
|
|
30
|
+
const clamp = (date) => {
|
|
31
|
+
const day = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
32
|
+
if (day < min.value) return new Date(min.value.getFullYear(), min.value.getMonth(), min.value.getDate());
|
|
33
|
+
if (day > max.value) return new Date(max.value.getFullYear(), max.value.getMonth(), max.value.getDate());
|
|
34
|
+
return day;
|
|
35
|
+
};
|
|
36
|
+
const current = computed(() => clamp(value.value ?? now));
|
|
37
|
+
/** 各列的选项:月份、日子按当前的年月与范围裁剪 */
|
|
38
|
+
const lists = computed(() => {
|
|
39
|
+
const year = current.value.getFullYear();
|
|
40
|
+
const month = current.value.getMonth() + 1;
|
|
41
|
+
const atMin = (unit) => year === min.value.getFullYear() && (unit === "year" || month === min.value.getMonth() + 1);
|
|
42
|
+
const atMax = (unit) => year === max.value.getFullYear() && (unit === "year" || month === max.value.getMonth() + 1);
|
|
43
|
+
const units = config.lang.dateUnits;
|
|
44
|
+
const all = {
|
|
45
|
+
year: range(min.value.getFullYear(), max.value.getFullYear()).map((n) => ({
|
|
46
|
+
text: `${n}${units.year}`,
|
|
47
|
+
value: n
|
|
48
|
+
})),
|
|
49
|
+
month: range(atMin("year") ? min.value.getMonth() + 1 : 1, atMax("year") ? max.value.getMonth() + 1 : 12).map((n) => ({
|
|
50
|
+
text: `${pad(n)}${units.month}`,
|
|
51
|
+
value: n
|
|
52
|
+
})),
|
|
53
|
+
day: range(atMin("month") ? min.value.getDate() : 1, atMax("month") ? max.value.getDate() : daysIn(year, month)).map((n) => ({
|
|
54
|
+
text: `${pad(n)}${units.day}`,
|
|
55
|
+
value: n
|
|
56
|
+
}))
|
|
57
|
+
};
|
|
58
|
+
return columns.value.map((column) => all[column]);
|
|
59
|
+
});
|
|
60
|
+
const valuesOf = (date) => columns.value.map((column) => column === "year" ? date.getFullYear() : column === "month" ? date.getMonth() + 1 : date.getDate());
|
|
61
|
+
/** 各列的值 → 日期:缺的列取当前的,日子按月份的天数修正 */
|
|
62
|
+
const dateOf = (values) => {
|
|
63
|
+
const pick = (column, fallback) => {
|
|
64
|
+
const position = columns.value.indexOf(column);
|
|
65
|
+
return position >= 0 ? Number(values[position]) : fallback;
|
|
66
|
+
};
|
|
67
|
+
const year = pick("year", current.value.getFullYear());
|
|
68
|
+
const month = pick("month", current.value.getMonth() + 1);
|
|
69
|
+
const day = Math.min(pick("day", current.value.getDate()), daysIn(year, month));
|
|
70
|
+
return clamp(new Date(year, month - 1, day));
|
|
71
|
+
};
|
|
72
|
+
return () => createVNode(Picker, mergeJsxProps(rest, {
|
|
73
|
+
"columns": lists.value,
|
|
74
|
+
"_value": valuesOf(current.value),
|
|
75
|
+
"onChange": _cache[0] || (_cache[0] = ({ values }) => value.value = dateOf(values)),
|
|
76
|
+
"onConfirm": _cache[1] || (_cache[1] = ({ values }) => onConfirm.value?.(dateOf(values)))
|
|
77
|
+
}), null);
|
|
78
|
+
}, {
|
|
79
|
+
name: "DatePicker",
|
|
80
|
+
props: [
|
|
81
|
+
"_value",
|
|
82
|
+
"onUpdate:_value",
|
|
83
|
+
"minDate",
|
|
84
|
+
"maxDate",
|
|
85
|
+
"columns",
|
|
86
|
+
"onConfirm"
|
|
87
|
+
]
|
|
88
|
+
});
|
|
89
|
+
/** 未声明的属性落到选择器的根元素上 */
|
|
90
|
+
/** 时间选择器(Picker:时、分两列) */
|
|
91
|
+
var TimePicker = /*#__PURE__*/ _component((_props2, _ctx2) => {
|
|
92
|
+
const _cache2 = [];
|
|
93
|
+
const value = bindable(_props2, "_value", () => "00:00", _ctx2.emit);
|
|
94
|
+
const minHour = readonlyProp(_props2, "minHour", 0);
|
|
95
|
+
const maxHour = readonlyProp(_props2, "maxHour", 23);
|
|
96
|
+
const minuteStep = readonlyProp(_props2, "minuteStep", 1);
|
|
97
|
+
const onConfirm = readonlyProp(_props2, "onConfirm");
|
|
98
|
+
const rest = restProps(_props2, _ctx2, true);
|
|
99
|
+
const config = useConfig();
|
|
100
|
+
const lists = computed(() => {
|
|
101
|
+
const units = config.lang.dateUnits;
|
|
102
|
+
return [range(minHour.value, maxHour.value).map((n) => ({
|
|
103
|
+
text: `${pad(n)}${units.hour}`,
|
|
104
|
+
value: n
|
|
105
|
+
})), range(0, Math.floor(59 / minuteStep.value)).map((n) => ({
|
|
106
|
+
text: `${pad(n * minuteStep.value)}${units.minute}`,
|
|
107
|
+
value: n * minuteStep.value
|
|
108
|
+
}))];
|
|
109
|
+
});
|
|
110
|
+
const parts = () => {
|
|
111
|
+
const [hour = "0", minute = "0"] = value.value.split(":");
|
|
112
|
+
return [Number(hour), Math.round(Number(minute) / minuteStep.value) * minuteStep.value];
|
|
113
|
+
};
|
|
114
|
+
const format = (values) => values.map((n) => pad(Number(n))).join(":");
|
|
115
|
+
return () => createVNode(Picker, mergeJsxProps(rest, {
|
|
116
|
+
"columns": lists.value,
|
|
117
|
+
"_value": parts(),
|
|
118
|
+
"onChange": _cache2[0] || (_cache2[0] = ({ values }) => value.value = format(values)),
|
|
119
|
+
"onConfirm": _cache2[1] || (_cache2[1] = ({ values }) => onConfirm.value?.(format(values)))
|
|
120
|
+
}), null);
|
|
121
|
+
}, {
|
|
122
|
+
name: "TimePicker",
|
|
123
|
+
props: [
|
|
124
|
+
"_value",
|
|
125
|
+
"onUpdate:_value",
|
|
126
|
+
"minHour",
|
|
127
|
+
"maxHour",
|
|
128
|
+
"minuteStep",
|
|
129
|
+
"onConfirm"
|
|
130
|
+
]
|
|
131
|
+
});
|
|
132
|
+
//#endregion
|
|
133
|
+
export { DatePicker, TimePicker };
|
|
134
|
+
|
|
135
|
+
//# sourceMappingURL=DatePicker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DatePicker.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_restProps","_vue_computed","_createVNode","_mergeProps"],"sources":["../../src/picker/DatePicker.tsx"],"sourcesContent":["/**\n * 日期选择器与时间选择器:滚轮选年月日(可以只要年月)、选时分(分钟可以按步长)。建在 Picker 上,常放在底部弹出层里。\n *\n * <DatePicker _value={birthday} minDate={new Date(1950, 0, 1)} maxDate={new Date()} onConfirm={(date) => …} />\n * <DatePicker _value={month} columns={['year', 'month']} />\n * <TimePicker _value={time} minuteStep={15} /> time 是 \"09:30\"\n *\n * 换了年月时日子按那个月的天数修正(3 月 31 日换到 2 月是 2 月 28 / 29 日),超出 minDate、maxDate 的项不出现。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport type { VNodeChild } from 'vue';\nimport { useConfig } from '../config/context';\nimport type { PartProps } from '../utils/props';\nimport { Picker, type PickerOption } from './Picker';\n\n/** 日期的列 */\nexport type DateColumn = 'year' | 'month' | 'day';\n\n/** 共有的属性 */\ninterface PickerShellProps extends Omit<PartProps<'div', 'title'>, 'onChange'> {\n /** 标题 */\n title?: VNodeChild;\n /** 点了取消 */\n onCancel?: () => void;\n /** 可见的行数 */\n visibleItemCount?: number;\n}\n\n/** 未声明的属性落到选择器的根元素上 */\nexport interface DatePickerProps extends PickerShellProps {\n /** 选中的日期;双向绑定写 `_value={x}`。不给时是今天(限在范围内) */\n _value?: Date;\n /** 最早的日期;默认十年前的 1 月 1 日 */\n minDate?: Date;\n /** 最晚的日期;默认十年后的 12 月 31 日 */\n maxDate?: Date;\n /**\n * 显示哪几列\n * @default ['year', 'month', 'day']\n */\n columns?: DateColumn[];\n /** 点了确认 */\n onConfirm?: (date: Date) => void;\n}\n\nconst daysIn = (year: number, month: number) => new Date(year, month, 0).getDate();\nconst range = (from: number, to: number) =>\n Array.from({ length: to - from + 1 }, (_, index) => from + index);\nconst pad = (value: number) => String(value).padStart(2, '0');\n\n/** 日期选择器(Picker) */\nexport const DatePicker = _component(\n ({\n _value: value = _bindable<Date | undefined>(undefined),\n minDate,\n maxDate,\n columns = ['year', 'month', 'day'],\n onConfirm,\n ...rest\n }: DatePickerProps) => {\n const config = useConfig();\n const now = new Date();\n const min = _derived(minDate ?? new Date(now.getFullYear() - 10, 0, 1));\n const max = _derived(maxDate ?? new Date(now.getFullYear() + 10, 11, 31));\n /** 把日期限在范围内(只看年月日) */\n const clamp = (date: Date) => {\n const day = new Date(date.getFullYear(), date.getMonth(), date.getDate());\n if (day < min) return new Date(min.getFullYear(), min.getMonth(), min.getDate());\n if (day > max) return new Date(max.getFullYear(), max.getMonth(), max.getDate());\n return day;\n };\n const current = _derived(clamp(value ?? now));\n\n /** 各列的选项:月份、日子按当前的年月与范围裁剪 */\n const lists = _derived.by(() => {\n const year = current.getFullYear();\n const month = current.getMonth() + 1;\n const atMin = (unit: 'year' | 'month') =>\n year === min.getFullYear() && (unit === 'year' || month === min.getMonth() + 1);\n const atMax = (unit: 'year' | 'month') =>\n year === max.getFullYear() && (unit === 'year' || month === max.getMonth() + 1);\n const units = config.lang.dateUnits;\n const all: Record<DateColumn, PickerOption[]> = {\n year: range(min.getFullYear(), max.getFullYear()).map((n) => ({\n text: `${n}${units.year}`,\n value: n,\n })),\n month: range(\n atMin('year') ? min.getMonth() + 1 : 1,\n atMax('year') ? max.getMonth() + 1 : 12,\n ).map((n) => ({ text: `${pad(n)}${units.month}`, value: n })),\n day: range(\n atMin('month') ? min.getDate() : 1,\n atMax('month') ? max.getDate() : daysIn(year, month),\n ).map((n) => ({ text: `${pad(n)}${units.day}`, value: n })),\n };\n return columns.map((column) => all[column]);\n });\n\n const valuesOf = (date: Date) =>\n columns.map((column) =>\n column === 'year'\n ? date.getFullYear()\n : column === 'month'\n ? date.getMonth() + 1\n : date.getDate(),\n );\n /** 各列的值 → 日期:缺的列取当前的,日子按月份的天数修正 */\n const dateOf = (values: (string | number)[]) => {\n const pick = (column: DateColumn, fallback: number) => {\n const position = columns.indexOf(column);\n return position >= 0 ? Number(values[position]) : fallback;\n };\n const year = pick('year', current.getFullYear());\n const month = pick('month', current.getMonth() + 1);\n const day = Math.min(pick('day', current.getDate()), daysIn(year, month));\n return clamp(new Date(year, month - 1, day));\n };\n\n return () => (\n <Picker\n {...rest}\n columns={lists}\n _value={valuesOf(current)}\n onChange={({ values }) => (value = dateOf(values))}\n onConfirm={({ values }) => onConfirm?.(dateOf(values))}\n />\n );\n },\n);\n\n/** 未声明的属性落到选择器的根元素上 */\nexport interface TimePickerProps extends PickerShellProps {\n /** 选中的时间 \"HH:mm\";双向绑定写 `_value={x}`。不给时是 00:00 */\n _value?: string;\n /**\n * 最小、最大的小时\n * @default 0、23\n */\n minHour?: number;\n maxHour?: number;\n /**\n * 分钟的步长\n * @default 1\n */\n minuteStep?: number;\n /** 点了确认 */\n onConfirm?: (time: string) => void;\n}\n\n/** 时间选择器(Picker:时、分两列) */\nexport const TimePicker = _component(\n ({\n _value: value = _bindable('00:00'),\n minHour = 0,\n maxHour = 23,\n minuteStep = 1,\n onConfirm,\n ...rest\n }: TimePickerProps) => {\n const config = useConfig();\n const lists = _derived.by(() => {\n const units = config.lang.dateUnits;\n return [\n range(minHour, maxHour).map((n) => ({ text: `${pad(n)}${units.hour}`, value: n })),\n range(0, Math.floor(59 / minuteStep)).map((n) => ({\n text: `${pad(n * minuteStep)}${units.minute}`,\n value: n * minuteStep,\n })),\n ];\n });\n const parts = () => {\n const [hour = '0', minute = '0'] = value.split(':');\n return [Number(hour), Math.round(Number(minute) / minuteStep) * minuteStep];\n };\n const format = (values: (string | number)[]) => values.map((n) => pad(Number(n))).join(':');\n return () => (\n <Picker\n {...rest}\n columns={lists}\n _value={parts()}\n onChange={({ values }) => (value = format(values))}\n onConfirm={({ values }) => onConfirm?.(format(values))}\n />\n );\n },\n);\n"],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';
|
|
2
|
+
import { type VNodeChild } from 'vue';
|
|
3
|
+
import { type PartProps } from '../utils/props';
|
|
4
|
+
import type { PickerOption } from './PickerColumn';
|
|
5
|
+
/** 未声明的属性落到菜单这一排(div)上 */
|
|
6
|
+
export interface DropdownMenuProps extends PartProps<'div', 'role'> {
|
|
7
|
+
/** 各个 DropdownItem */
|
|
8
|
+
children?: VNodeChild;
|
|
9
|
+
}
|
|
10
|
+
/** DropdownMenu、DropdownItem 的样式 */
|
|
11
|
+
export declare const dropdownStyles: Readonly<{
|
|
12
|
+
arrow: css.CompiledStyles;
|
|
13
|
+
bar: css.CompiledStyles;
|
|
14
|
+
clip: css.CompiledStyles;
|
|
15
|
+
option: css.CompiledStyles;
|
|
16
|
+
overlay: css.CompiledStyles;
|
|
17
|
+
panel: css.CompiledStyles;
|
|
18
|
+
title: css.CompiledStyles;
|
|
19
|
+
titleText: css.CompiledStyles;
|
|
20
|
+
}>;
|
|
21
|
+
/** 下拉菜单(div > 各项的标题;展开的面板在浮层根) */
|
|
22
|
+
export declare const DropdownMenu: import("@zerodep-dev/vue-tsx-pro-tsx").TsxComponent<DropdownMenuProps>;
|
|
23
|
+
/** 未声明的属性落到面板(div)上 */
|
|
24
|
+
export interface DropdownItemProps extends Omit<PartProps<'div', 'title' | 'role'>, 'onChange'> {
|
|
25
|
+
/** 选中的值;双向绑定写 `_value={x}` */
|
|
26
|
+
_value?: string | number;
|
|
27
|
+
/** 选项(与 children 二选一) */
|
|
28
|
+
options?: PickerOption[];
|
|
29
|
+
/** 标题;不给时显示选中的选项 */
|
|
30
|
+
title?: VNodeChild;
|
|
31
|
+
/** 不能展开 */
|
|
32
|
+
disabled?: boolean;
|
|
33
|
+
/** 选了另一项 */
|
|
34
|
+
onChange?: (value: string | number) => void;
|
|
35
|
+
/** 自定义的面板内容(代替选项) */
|
|
36
|
+
children?: VNodeChild;
|
|
37
|
+
}
|
|
38
|
+
/** 下拉菜单的一项:标题由菜单画,这里画展开的面板 */
|
|
39
|
+
export declare const DropdownItem: import("@zerodep-dev/vue-tsx-pro-tsx").TsxComponent<DropdownItemProps>;
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { useConfig } from "../config/context.js";
|
|
2
|
+
import { dataAttrs, hasContent, mergeAttrs } from "../utils/props.js";
|
|
3
|
+
import { Icon } from "../base/Icon.js";
|
|
4
|
+
import { useHost } from "../utils/host.js";
|
|
5
|
+
import { usePresence } from "../utils/presence.js";
|
|
6
|
+
import { useLockScroll } from "../overlay/Overlay.js";
|
|
7
|
+
import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
|
|
8
|
+
import { _component, bindable, childrenProp, createContext, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
9
|
+
import { Teleport, computed, createVNode, onBeforeUnmount, ref, shallowReactive } from "vue";
|
|
10
|
+
import { Check, ChevronDown } from "@lucide/icons";
|
|
11
|
+
//#region src/picker/DropdownMenu.tsx
|
|
12
|
+
/**
|
|
13
|
+
* 下拉菜单:列表上方的一排筛选(排序、分类、价格),点一项从这一排下面展开选项,选了就收起;同一时间只展开一个。
|
|
14
|
+
*
|
|
15
|
+
* <DropdownMenu>
|
|
16
|
+
* <DropdownItem _value={sort} options={[{ text: '综合排序', value: 'default' }, { text: '销量优先', value: 'sales' }]} />
|
|
17
|
+
* <DropdownItem title="筛选">…自定义内容(开关、按钮)…</DropdownItem>
|
|
18
|
+
* </DropdownMenu>
|
|
19
|
+
*
|
|
20
|
+
* 展开的面板与遮罩渲染到浮层根,从这一排的下沿开始(宿主量它的位置),遮罩只盖住下面的部分。
|
|
21
|
+
*/
|
|
22
|
+
/** 一项登记给菜单的 */
|
|
23
|
+
/** 菜单提供给各项的 */
|
|
24
|
+
var DropdownContext = createContext("DropdownMenu");
|
|
25
|
+
/** 未声明的属性落到菜单这一排(div)上 */
|
|
26
|
+
/** DropdownMenu、DropdownItem 的样式 */
|
|
27
|
+
var dropdownStyles = css.create({
|
|
28
|
+
bar: {
|
|
29
|
+
position: "relative",
|
|
30
|
+
zIndex: 10,
|
|
31
|
+
display: "flex",
|
|
32
|
+
height: "3em",
|
|
33
|
+
backgroundColor: "_surface",
|
|
34
|
+
boxShadow: "_sm"
|
|
35
|
+
},
|
|
36
|
+
title: {
|
|
37
|
+
flex: "1 1 0",
|
|
38
|
+
minWidth: 0,
|
|
39
|
+
display: "inline-flex",
|
|
40
|
+
alignItems: "center",
|
|
41
|
+
justifyContent: "center",
|
|
42
|
+
gap: "0.2em",
|
|
43
|
+
margin: 0,
|
|
44
|
+
paddingInline: "_sm",
|
|
45
|
+
borderWidth: 0,
|
|
46
|
+
backgroundColor: "transparent",
|
|
47
|
+
color: {
|
|
48
|
+
default: "_text",
|
|
49
|
+
"[aria-expanded=\"true\"]": "_accentText",
|
|
50
|
+
"[disabled]": "_textDisabled"
|
|
51
|
+
},
|
|
52
|
+
fontFamily: "inherit",
|
|
53
|
+
fontSize: "_md",
|
|
54
|
+
whiteSpace: "nowrap",
|
|
55
|
+
cursor: {
|
|
56
|
+
default: "pointer",
|
|
57
|
+
"[disabled]": "not-allowed"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
titleText: {
|
|
61
|
+
overflow: "hidden",
|
|
62
|
+
textOverflow: "ellipsis"
|
|
63
|
+
},
|
|
64
|
+
arrow: {
|
|
65
|
+
flex: "none",
|
|
66
|
+
fontSize: "0.9em",
|
|
67
|
+
transform: {
|
|
68
|
+
default: "none",
|
|
69
|
+
"[data-open]": "rotate(180deg)"
|
|
70
|
+
},
|
|
71
|
+
transitionProperty: "transform",
|
|
72
|
+
transitionDuration: "_md"
|
|
73
|
+
},
|
|
74
|
+
overlay: {
|
|
75
|
+
position: "fixed",
|
|
76
|
+
insetInline: 0,
|
|
77
|
+
insetBlockEnd: 0,
|
|
78
|
+
zIndex: 2e3,
|
|
79
|
+
backgroundColor: "_overlay",
|
|
80
|
+
opacity: {
|
|
81
|
+
default: 0,
|
|
82
|
+
"[data-state=\"open\"]": 1
|
|
83
|
+
},
|
|
84
|
+
transitionProperty: "opacity",
|
|
85
|
+
transitionDuration: "_md"
|
|
86
|
+
},
|
|
87
|
+
clip: {
|
|
88
|
+
position: "fixed",
|
|
89
|
+
insetInline: 0,
|
|
90
|
+
zIndex: 2001,
|
|
91
|
+
overflow: "hidden"
|
|
92
|
+
},
|
|
93
|
+
panel: {
|
|
94
|
+
maxHeight: "60vh",
|
|
95
|
+
overflowY: "auto",
|
|
96
|
+
backgroundColor: "_surface",
|
|
97
|
+
borderEndStartRadius: "_lg",
|
|
98
|
+
borderEndEndRadius: "_lg",
|
|
99
|
+
transform: {
|
|
100
|
+
default: "translateY(-100%)",
|
|
101
|
+
"[data-state=\"open\"]": "none"
|
|
102
|
+
},
|
|
103
|
+
transitionProperty: "transform",
|
|
104
|
+
transitionDuration: "_md",
|
|
105
|
+
transitionTimingFunction: "_standard"
|
|
106
|
+
},
|
|
107
|
+
option: {
|
|
108
|
+
display: "flex",
|
|
109
|
+
alignItems: "center",
|
|
110
|
+
justifyContent: "space-between",
|
|
111
|
+
minHeight: "_control",
|
|
112
|
+
paddingInline: "_lg",
|
|
113
|
+
fontSize: "_md",
|
|
114
|
+
color: {
|
|
115
|
+
default: "_text",
|
|
116
|
+
"[aria-selected=\"true\"]": "_accentText",
|
|
117
|
+
"[data-disabled]": "_textDisabled"
|
|
118
|
+
},
|
|
119
|
+
backgroundColor: {
|
|
120
|
+
default: "transparent",
|
|
121
|
+
":active:not([data-disabled])": "_fillActive"
|
|
122
|
+
},
|
|
123
|
+
cursor: {
|
|
124
|
+
default: "pointer",
|
|
125
|
+
"[data-disabled]": "not-allowed"
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
/** 下拉菜单(div > 各项的标题;展开的面板在浮层根) */
|
|
130
|
+
var DropdownMenu = /*#__PURE__*/ _component((_props, _ctx) => {
|
|
131
|
+
const _cache = [];
|
|
132
|
+
const children = childrenProp(_props);
|
|
133
|
+
const rest = restProps(_props, _ctx, false);
|
|
134
|
+
const host = useHost();
|
|
135
|
+
const entries = shallowReactive([]);
|
|
136
|
+
let open = ref(-1);
|
|
137
|
+
let top = ref(0);
|
|
138
|
+
let bar = null;
|
|
139
|
+
const toggle = async (index) => {
|
|
140
|
+
if (open.value === index) return void (open.value = -1);
|
|
141
|
+
const rect = await host.measure(bar);
|
|
142
|
+
top.value = rect ? rect.top + rect.height : 0;
|
|
143
|
+
open.value = index;
|
|
144
|
+
};
|
|
145
|
+
DropdownContext.provide({
|
|
146
|
+
get open() {
|
|
147
|
+
return open.value;
|
|
148
|
+
},
|
|
149
|
+
get top() {
|
|
150
|
+
return top.value;
|
|
151
|
+
},
|
|
152
|
+
register(entry) {
|
|
153
|
+
entries.push(entry);
|
|
154
|
+
return {
|
|
155
|
+
index: () => entries.indexOf(entry),
|
|
156
|
+
unregister: () => void entries.splice(entries.indexOf(entry), 1)
|
|
157
|
+
};
|
|
158
|
+
},
|
|
159
|
+
close: () => open.value = -1
|
|
160
|
+
});
|
|
161
|
+
return () => createVNode("div", mergeJsxProps(mergeAttrs({ sx: dropdownStyles.bar }, rest, { role: "menubar" }), { "ref": _cache[0] || (_cache[0] = (node) => bar = node) }), [entries.map((entry, index) => createVNode("button", mergeJsxProps(mergeAttrs({ sx: dropdownStyles.title }), {
|
|
162
|
+
"type": "button",
|
|
163
|
+
"aria-expanded": open.value === index ? "true" : "false",
|
|
164
|
+
"aria-haspopup": "true",
|
|
165
|
+
"disabled": entry.disabled,
|
|
166
|
+
"onClick": () => void toggle(index)
|
|
167
|
+
}), [createVNode("span", mergeAttrs({ sx: dropdownStyles.titleText }), [entry.title]), createVNode(Icon, mergeJsxProps({
|
|
168
|
+
"icon": ChevronDown,
|
|
169
|
+
"sx": dropdownStyles.arrow
|
|
170
|
+
}, dataAttrs({ "data-open": open.value === index })), null)])), children.value]);
|
|
171
|
+
}, { name: "DropdownMenu" });
|
|
172
|
+
/** 未声明的属性落到面板(div)上 */
|
|
173
|
+
/** 下拉菜单的一项:标题由菜单画,这里画展开的面板 */
|
|
174
|
+
var DropdownItem = /*#__PURE__*/ _component((_props2, _ctx2) => {
|
|
175
|
+
const _cache2 = [];
|
|
176
|
+
const value = bindable(_props2, "_value", () => void 0, _ctx2.emit);
|
|
177
|
+
const options = readonlyProp(_props2, "options", () => []);
|
|
178
|
+
const title = readonlyProp(_props2, "title");
|
|
179
|
+
const disabled = readonlyProp(_props2, "disabled", false);
|
|
180
|
+
const onChange = readonlyProp(_props2, "onChange");
|
|
181
|
+
const children = childrenProp(_props2);
|
|
182
|
+
const rest = restProps(_props2, _ctx2, false);
|
|
183
|
+
const menu = DropdownContext.inject();
|
|
184
|
+
const host = useHost();
|
|
185
|
+
const config = useConfig();
|
|
186
|
+
const label = computed(() => title.value ?? options.value.find((option) => option.value === value.value)?.text ?? options.value[0]?.text);
|
|
187
|
+
const handle = menu.register({
|
|
188
|
+
get title() {
|
|
189
|
+
return label.value;
|
|
190
|
+
},
|
|
191
|
+
get disabled() {
|
|
192
|
+
return disabled.value;
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
onBeforeUnmount(handle.unregister);
|
|
196
|
+
const isOpen = () => menu.open === handle.index();
|
|
197
|
+
const presence = usePresence(isOpen);
|
|
198
|
+
useLockScroll(isOpen);
|
|
199
|
+
const choose = (option) => {
|
|
200
|
+
if (option.disabled) return;
|
|
201
|
+
if (option.value !== value.value) {
|
|
202
|
+
value.value = option.value;
|
|
203
|
+
onChange.value?.(option.value);
|
|
204
|
+
}
|
|
205
|
+
menu.close();
|
|
206
|
+
};
|
|
207
|
+
return () => {
|
|
208
|
+
if (!presence.mounted) return null;
|
|
209
|
+
const state = dataAttrs({ "data-state": presence.visible ? "open" : "closed" });
|
|
210
|
+
return createVNode(Teleport, { "to": host.overlayRoot() }, { default: () => [createVNode("div", mergeJsxProps(mergeAttrs({
|
|
211
|
+
sx: [config.rootSx, dropdownStyles.overlay],
|
|
212
|
+
style: { insetBlockStart: `${menu.top}px` }
|
|
213
|
+
}, state), { "onClick": _cache2[0] || (_cache2[0] = () => menu.close()) }, dataAttrs({ "data-scroll-lock": true })), null), createVNode("div", mergeAttrs({
|
|
214
|
+
sx: [config.rootSx, dropdownStyles.clip],
|
|
215
|
+
style: { insetBlockStart: `${menu.top}px` }
|
|
216
|
+
}), [createVNode("div", mergeAttrs({ sx: dropdownStyles.panel }, rest, {
|
|
217
|
+
role: "menu",
|
|
218
|
+
...state
|
|
219
|
+
}), [hasContent(children.value) ? children.value : options.value.map((option) => {
|
|
220
|
+
const selected = option.value === value.value;
|
|
221
|
+
return createVNode("div", mergeJsxProps(mergeAttrs({ sx: dropdownStyles.option }), {
|
|
222
|
+
"role": "menuitemradio",
|
|
223
|
+
"aria-checked": selected ? "true" : "false",
|
|
224
|
+
"aria-selected": selected ? "true" : "false"
|
|
225
|
+
}, dataAttrs({ "data-disabled": option.disabled }), { "onClick": () => choose(option) }), [createVNode("span", null, [option.text]), selected && createVNode(Icon, { "icon": Check }, null)]);
|
|
226
|
+
})])])] });
|
|
227
|
+
};
|
|
228
|
+
}, {
|
|
229
|
+
name: "DropdownItem",
|
|
230
|
+
props: [
|
|
231
|
+
"_value",
|
|
232
|
+
"onUpdate:_value",
|
|
233
|
+
"options",
|
|
234
|
+
"title",
|
|
235
|
+
"disabled",
|
|
236
|
+
"onChange"
|
|
237
|
+
]
|
|
238
|
+
});
|
|
239
|
+
//#endregion
|
|
240
|
+
export { DropdownItem, DropdownMenu, dropdownStyles };
|
|
241
|
+
|
|
242
|
+
//# sourceMappingURL=DropdownMenu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DropdownMenu.js","names":["_vtp_childrenProp","_vtp_restProps","_vue_ref","_createVNode","_mergeProps","_vtp_bindable","_vtp_readonlyProp","_vue_computed"],"sources":["../../src/picker/DropdownMenu.tsx"],"sourcesContent":["/**\n * 下拉菜单:列表上方的一排筛选(排序、分类、价格),点一项从这一排下面展开选项,选了就收起;同一时间只展开一个。\n *\n * <DropdownMenu>\n * <DropdownItem _value={sort} options={[{ text: '综合排序', value: 'default' }, { text: '销量优先', value: 'sales' }]} />\n * <DropdownItem title=\"筛选\">…自定义内容(开关、按钮)…</DropdownItem>\n * </DropdownMenu>\n *\n * 展开的面板与遮罩渲染到浮层根,从这一排的下沿开始(宿主量它的位置),遮罩只盖住下面的部分。\n */\nimport { Check, ChevronDown } from '@lucide/icons';\nimport { _component, createContext } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { Teleport, onBeforeUnmount, shallowReactive, type VNodeChild } from 'vue';\nimport { Icon } from '../base/Icon';\nimport { useConfig } from '../config/context';\nimport { useLockScroll } from '../overlay/Overlay';\nimport { useHost } from '../utils/host';\nimport { usePresence } from '../utils/presence';\nimport { dataAttrs, hasContent, mergeAttrs, type PartProps } from '../utils/props';\nimport type { PickerOption } from './PickerColumn';\n\n/** 一项登记给菜单的 */\ninterface DropdownEntry {\n readonly title: VNodeChild;\n readonly disabled: boolean;\n}\n\n/** 菜单提供给各项的 */\ninterface DropdownState {\n /** 展开的是第几项;-1 是都收着 */\n readonly open: number;\n /** 面板的上沿(px,菜单这一排的下沿) */\n readonly top: number;\n register(entry: DropdownEntry): { index: () => number; unregister: () => void };\n close(): void;\n}\n\nconst DropdownContext = createContext<DropdownState>('DropdownMenu');\n\n/** 未声明的属性落到菜单这一排(div)上 */\nexport interface DropdownMenuProps extends PartProps<'div', 'role'> {\n /** 各个 DropdownItem */\n children?: VNodeChild;\n}\n\n/** DropdownMenu、DropdownItem 的样式 */\nexport const dropdownStyles = css.create({\n bar: {\n position: 'relative',\n zIndex: 10,\n display: 'flex',\n height: '3em',\n backgroundColor: '_surface',\n boxShadow: '_sm',\n },\n title: {\n flex: '1 1 0',\n minWidth: 0,\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '0.2em',\n margin: 0,\n paddingInline: '_sm',\n borderWidth: 0,\n backgroundColor: 'transparent',\n color: {\n default: '_text',\n '[aria-expanded=\"true\"]': '_accentText',\n '[disabled]': '_textDisabled',\n },\n fontFamily: 'inherit',\n fontSize: '_md',\n whiteSpace: 'nowrap',\n cursor: { default: 'pointer', '[disabled]': 'not-allowed' },\n },\n titleText: { overflow: 'hidden', textOverflow: 'ellipsis' },\n arrow: {\n flex: 'none',\n fontSize: '0.9em',\n transform: { default: 'none', '[data-open]': 'rotate(180deg)' },\n transitionProperty: 'transform',\n transitionDuration: '_md',\n },\n overlay: {\n position: 'fixed',\n insetInline: 0,\n insetBlockEnd: 0,\n zIndex: 2000,\n backgroundColor: '_overlay',\n opacity: { default: 0, '[data-state=\"open\"]': 1 },\n transitionProperty: 'opacity',\n transitionDuration: '_md',\n },\n // 面板外面一层裁掉面板滑出来之前的部分\n clip: { position: 'fixed', insetInline: 0, zIndex: 2001, overflow: 'hidden' },\n panel: {\n maxHeight: '60vh',\n overflowY: 'auto',\n backgroundColor: '_surface',\n borderEndStartRadius: '_lg',\n borderEndEndRadius: '_lg',\n transform: { default: 'translateY(-100%)', '[data-state=\"open\"]': 'none' },\n transitionProperty: 'transform',\n transitionDuration: '_md',\n transitionTimingFunction: '_standard',\n },\n option: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n minHeight: '_control',\n paddingInline: '_lg',\n fontSize: '_md',\n color: {\n default: '_text',\n '[aria-selected=\"true\"]': '_accentText',\n '[data-disabled]': '_textDisabled',\n },\n backgroundColor: { default: 'transparent', ':active:not([data-disabled])': '_fillActive' },\n cursor: { default: 'pointer', '[data-disabled]': 'not-allowed' },\n },\n});\n\n/** 下拉菜单(div > 各项的标题;展开的面板在浮层根) */\nexport const DropdownMenu = _component(({ children, ...rest }: DropdownMenuProps) => {\n const host = useHost();\n const entries = shallowReactive<DropdownEntry[]>([]);\n let open = _state(-1);\n let top = _state(0);\n let bar: unknown = null;\n const toggle = async (index: number) => {\n if (open === index) return void (open = -1);\n const rect = await host.measure(bar);\n top = rect ? rect.top + rect.height : 0;\n open = index;\n };\n DropdownContext.provide({\n get open() {\n return open;\n },\n get top() {\n return top;\n },\n register(entry) {\n entries.push(entry);\n return {\n index: () => entries.indexOf(entry),\n unregister: () => void entries.splice(entries.indexOf(entry), 1),\n };\n },\n close: () => (open = -1),\n });\n return () => (\n <div\n {...mergeAttrs<'div'>({ sx: dropdownStyles.bar }, rest, { role: 'menubar' })}\n ref={(node: unknown) => (bar = node)}\n >\n {entries.map((entry, index) => (\n <button\n {...mergeAttrs<'button'>({ sx: dropdownStyles.title })}\n type=\"button\"\n aria-expanded={open === index ? 'true' : 'false'}\n aria-haspopup=\"true\"\n disabled={entry.disabled}\n onClick={() => void toggle(index)}\n >\n <span {...mergeAttrs<'span'>({ sx: dropdownStyles.titleText })}>{entry.title}</span>\n <Icon\n icon={ChevronDown}\n sx={dropdownStyles.arrow}\n {...dataAttrs({ 'data-open': open === index })}\n />\n </button>\n ))}\n {children}\n </div>\n );\n});\n\n/** 未声明的属性落到面板(div)上 */\nexport interface DropdownItemProps extends Omit<PartProps<'div', 'title' | 'role'>, 'onChange'> {\n /** 选中的值;双向绑定写 `_value={x}` */\n _value?: string | number;\n /** 选项(与 children 二选一) */\n options?: PickerOption[];\n /** 标题;不给时显示选中的选项 */\n title?: VNodeChild;\n /** 不能展开 */\n disabled?: boolean;\n /** 选了另一项 */\n onChange?: (value: string | number) => void;\n /** 自定义的面板内容(代替选项) */\n children?: VNodeChild;\n}\n\n/** 下拉菜单的一项:标题由菜单画,这里画展开的面板 */\nexport const DropdownItem = _component(\n ({\n _value: value = _bindable<string | number | undefined>(undefined),\n options = [],\n title,\n disabled = false,\n onChange,\n children,\n ...rest\n }: DropdownItemProps) => {\n const menu = DropdownContext.inject();\n const host = useHost();\n const config = useConfig();\n // 标题在这里算好:菜单的渲染只读这个派生值,不去读这一项可双向绑定的 _value\n const label = _derived(\n title ?? options.find((option) => option.value === value)?.text ?? options[0]?.text,\n );\n const handle = menu.register({\n get title() {\n return label;\n },\n get disabled() {\n return disabled;\n },\n });\n onBeforeUnmount(handle.unregister);\n const isOpen = () => menu.open === handle.index();\n const presence = usePresence(isOpen);\n useLockScroll(isOpen);\n\n const choose = (option: PickerOption) => {\n if (option.disabled) return;\n if (option.value !== value) {\n value = option.value;\n onChange?.(option.value);\n }\n menu.close();\n };\n\n return () => {\n if (!presence.mounted) return null;\n const state = dataAttrs({ 'data-state': presence.visible ? 'open' : 'closed' });\n return (\n <Teleport to={host.overlayRoot() as never}>\n <div\n {...mergeAttrs<'div'>(\n {\n sx: [config.rootSx, dropdownStyles.overlay],\n style: { insetBlockStart: `${menu.top}px` },\n },\n state,\n )}\n onClick={() => menu.close()}\n {...dataAttrs({ 'data-scroll-lock': true })}\n />\n <div\n {...mergeAttrs<'div'>({\n sx: [config.rootSx, dropdownStyles.clip],\n style: { insetBlockStart: `${menu.top}px` },\n })}\n >\n <div\n {...mergeAttrs<'div'>({ sx: dropdownStyles.panel }, rest, { role: 'menu', ...state })}\n >\n {hasContent(children)\n ? children\n : options.map((option) => {\n const selected = option.value === value;\n return (\n <div\n {...mergeAttrs<'div'>({ sx: dropdownStyles.option })}\n role=\"menuitemradio\"\n aria-checked={selected ? 'true' : 'false'}\n aria-selected={selected ? 'true' : 'false'}\n {...dataAttrs({ 'data-disabled': option.disabled })}\n onClick={() => choose(option)}\n >\n <span>{option.text}</span>\n {selected && <Icon icon={Check} />}\n </div>\n );\n })}\n </div>\n </div>\n </Teleport>\n );\n };\n },\n);\n"],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';
|
|
2
|
+
import type { VNodeChild } from 'vue';
|
|
3
|
+
import { type PartProps } from '../utils/props';
|
|
4
|
+
import { type PickerOption } from './PickerColumn';
|
|
5
|
+
export type { PickerOption } from './PickerColumn';
|
|
6
|
+
/** 选项的值 */
|
|
7
|
+
export type PickerValue = string | number;
|
|
8
|
+
/** 确认、变化时给出的 */
|
|
9
|
+
export interface PickerResult {
|
|
10
|
+
/** 各列选中的值 */
|
|
11
|
+
values: PickerValue[];
|
|
12
|
+
/** 各列选中的选项 */
|
|
13
|
+
options: PickerOption[];
|
|
14
|
+
}
|
|
15
|
+
/** 未声明的属性落到根元素(div)上 */
|
|
16
|
+
export interface PickerProps extends Omit<PartProps<'div', 'title'>, 'onChange'> {
|
|
17
|
+
/** 选项:一列、几列(数组的数组)、联动(选项带 children) */
|
|
18
|
+
columns: PickerOption[] | PickerOption[][];
|
|
19
|
+
/** 各列选中的值;双向绑定写 `_value={x}`(滚动时就写回,确认时 onConfirm) */
|
|
20
|
+
_value?: PickerValue[];
|
|
21
|
+
/** 标题 */
|
|
22
|
+
title?: VNodeChild;
|
|
23
|
+
/**
|
|
24
|
+
* 显示标题栏
|
|
25
|
+
* @default true
|
|
26
|
+
*/
|
|
27
|
+
showToolbar?: boolean;
|
|
28
|
+
/** 确认的文字;不给时用语言包 */
|
|
29
|
+
confirmText?: VNodeChild;
|
|
30
|
+
/** 取消的文字;不给时用语言包 */
|
|
31
|
+
cancelText?: VNodeChild;
|
|
32
|
+
/**
|
|
33
|
+
* 可见的行数(奇数)
|
|
34
|
+
* @default 5
|
|
35
|
+
*/
|
|
36
|
+
visibleItemCount?: number;
|
|
37
|
+
/** 点了确认 */
|
|
38
|
+
onConfirm?: (result: PickerResult) => void;
|
|
39
|
+
/** 点了取消 */
|
|
40
|
+
onCancel?: () => void;
|
|
41
|
+
/** 滚到另一项 */
|
|
42
|
+
onChange?: (result: PickerResult & {
|
|
43
|
+
columnIndex: number;
|
|
44
|
+
}) => void;
|
|
45
|
+
/** 各列的读屏名称 */
|
|
46
|
+
columnLabels?: string[];
|
|
47
|
+
}
|
|
48
|
+
/** Picker 的样式:root、toolbar、title、action、confirm、columns、mask、indicator */
|
|
49
|
+
export declare const pickerStyles: Readonly<{
|
|
50
|
+
action: css.CompiledStyles;
|
|
51
|
+
columns: css.CompiledStyles;
|
|
52
|
+
confirm: css.CompiledStyles;
|
|
53
|
+
indicator: css.CompiledStyles;
|
|
54
|
+
mask: css.CompiledStyles;
|
|
55
|
+
root: css.CompiledStyles;
|
|
56
|
+
title: css.CompiledStyles;
|
|
57
|
+
toolbar: css.CompiledStyles;
|
|
58
|
+
}>;
|
|
59
|
+
/** 按选中的值算出各列(联动时跟着上一列的选择往下展开)与各列选中的序号 */
|
|
60
|
+
export declare function resolveColumns(columns: PickerOption[] | PickerOption[][], values: PickerValue[]): {
|
|
61
|
+
lists: PickerOption[][];
|
|
62
|
+
indexes: number[];
|
|
63
|
+
options: PickerOption[];
|
|
64
|
+
values: (string | number)[];
|
|
65
|
+
};
|
|
66
|
+
/** 选择器(div > 标题栏 + 各列滚轮) */
|
|
67
|
+
export declare const Picker: import("@zerodep-dev/vue-tsx-pro-tsx").TsxComponent<PickerProps>;
|