@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,69 @@
|
|
|
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
|
+
/** 选择的方式 */
|
|
5
|
+
export interface CalendarTypes {
|
|
6
|
+
/** 一天(默认) */
|
|
7
|
+
single: unknown;
|
|
8
|
+
/** 一段:先点开始,再点结束 */
|
|
9
|
+
range: unknown;
|
|
10
|
+
/** 几天:点一下选上,再点一下取消 */
|
|
11
|
+
multiple: unknown;
|
|
12
|
+
}
|
|
13
|
+
/** 日历的值:一天、一段 [开始, 结束]、几天 */
|
|
14
|
+
export type CalendarValue = Date | [Date, Date] | Date[];
|
|
15
|
+
/** 某一天的额外信息 */
|
|
16
|
+
export interface CalendarDayInfo {
|
|
17
|
+
/** 日子下面的小字(价格、节日) */
|
|
18
|
+
bottom?: VNodeChild;
|
|
19
|
+
/** 这一天不能选 */
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** 未声明的属性落到根元素(div)上 */
|
|
23
|
+
export interface CalendarProps extends Omit<PartProps<'div', 'title'>, 'onSelect'> {
|
|
24
|
+
/**
|
|
25
|
+
* 选择的方式
|
|
26
|
+
* @default 'single'
|
|
27
|
+
*/
|
|
28
|
+
type?: keyof CalendarTypes;
|
|
29
|
+
/** 选中的日期;双向绑定写 `_value={x}`(确认时写回) */
|
|
30
|
+
_value?: CalendarValue | null;
|
|
31
|
+
/** 最早可选的日子;默认今天 */
|
|
32
|
+
minDate?: Date;
|
|
33
|
+
/** 最晚可选的日子;默认半年后 */
|
|
34
|
+
maxDate?: Date;
|
|
35
|
+
/** 标题 */
|
|
36
|
+
title?: VNodeChild;
|
|
37
|
+
/**
|
|
38
|
+
* 下面显示确认按钮
|
|
39
|
+
* @default true
|
|
40
|
+
*/
|
|
41
|
+
showConfirm?: boolean;
|
|
42
|
+
/** 确认的文字;不给时用语言包 */
|
|
43
|
+
confirmText?: VNodeChild;
|
|
44
|
+
/** 每一天的额外信息 */
|
|
45
|
+
dayInfo?: (day: Date) => CalendarDayInfo | undefined;
|
|
46
|
+
/** 点了一天 */
|
|
47
|
+
onSelect?: (day: Date) => void;
|
|
48
|
+
/** 点了确认(或不显示确认按钮时选完了) */
|
|
49
|
+
onConfirm?: (value: CalendarValue) => void;
|
|
50
|
+
}
|
|
51
|
+
/** Calendar 的样式 */
|
|
52
|
+
export declare const calendarStyles: Readonly<{
|
|
53
|
+
body: css.CompiledStyles;
|
|
54
|
+
bottom: css.CompiledStyles;
|
|
55
|
+
day: css.CompiledStyles;
|
|
56
|
+
days: css.CompiledStyles;
|
|
57
|
+
footer: css.CompiledStyles;
|
|
58
|
+
middle: css.CompiledStyles;
|
|
59
|
+
month: css.CompiledStyles;
|
|
60
|
+
monthTitle: css.CompiledStyles;
|
|
61
|
+
rangeEnd: css.CompiledStyles;
|
|
62
|
+
rangeStart: css.CompiledStyles;
|
|
63
|
+
root: css.CompiledStyles;
|
|
64
|
+
selected: css.CompiledStyles;
|
|
65
|
+
title: css.CompiledStyles;
|
|
66
|
+
weekdays: css.CompiledStyles;
|
|
67
|
+
}>;
|
|
68
|
+
/** 日历(div > 标题 + 星期 + 各月 + 确认) */
|
|
69
|
+
export declare const Calendar: import("@zerodep-dev/vue-tsx-pro-tsx").TsxComponent<CalendarProps>;
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { useConfig } from "../config/context.js";
|
|
2
|
+
import { dataAttrs, hasContent, mergeAttrs } from "../utils/props.js";
|
|
3
|
+
import { Button } from "../base/Button.js";
|
|
4
|
+
import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
|
|
5
|
+
import { _component, bindable, mergeJsxProps, overridable, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
6
|
+
import { computed, createVNode } from "vue";
|
|
7
|
+
//#region src/picker/Calendar.tsx
|
|
8
|
+
/** 选择的方式 */
|
|
9
|
+
/** 日历的值:一天、一段 [开始, 结束]、几天 */
|
|
10
|
+
/** 某一天的额外信息 */
|
|
11
|
+
/** 未声明的属性落到根元素(div)上 */
|
|
12
|
+
/** Calendar 的样式 */
|
|
13
|
+
var calendarStyles = css.create({
|
|
14
|
+
root: {
|
|
15
|
+
display: "flex",
|
|
16
|
+
flexDirection: "column",
|
|
17
|
+
backgroundColor: "_surface",
|
|
18
|
+
userSelect: "none"
|
|
19
|
+
},
|
|
20
|
+
title: {
|
|
21
|
+
paddingBlock: "0.8em",
|
|
22
|
+
textAlign: "center",
|
|
23
|
+
fontSize: "_lg",
|
|
24
|
+
fontWeight: "_semibold",
|
|
25
|
+
color: "_text"
|
|
26
|
+
},
|
|
27
|
+
weekdays: {
|
|
28
|
+
display: "grid",
|
|
29
|
+
gridTemplateColumns: "repeat(7, 1fr)",
|
|
30
|
+
paddingBlock: "0.4em",
|
|
31
|
+
fontSize: "_xs",
|
|
32
|
+
color: "_textMuted",
|
|
33
|
+
textAlign: "center",
|
|
34
|
+
boxShadow: "_sm"
|
|
35
|
+
},
|
|
36
|
+
body: {
|
|
37
|
+
height: "22em",
|
|
38
|
+
overflowY: "auto"
|
|
39
|
+
},
|
|
40
|
+
month: { paddingBlockEnd: "_sm" },
|
|
41
|
+
monthTitle: {
|
|
42
|
+
paddingBlock: "0.7em",
|
|
43
|
+
textAlign: "center",
|
|
44
|
+
fontSize: "_md",
|
|
45
|
+
fontWeight: "_medium",
|
|
46
|
+
color: "_text"
|
|
47
|
+
},
|
|
48
|
+
days: {
|
|
49
|
+
display: "grid",
|
|
50
|
+
gridTemplateColumns: "repeat(7, 1fr)",
|
|
51
|
+
rowGap: "0.25em"
|
|
52
|
+
},
|
|
53
|
+
day: {
|
|
54
|
+
display: "flex",
|
|
55
|
+
flexDirection: "column",
|
|
56
|
+
alignItems: "center",
|
|
57
|
+
justifyContent: "center",
|
|
58
|
+
height: "3.4em",
|
|
59
|
+
fontSize: "_md",
|
|
60
|
+
color: {
|
|
61
|
+
default: "_text",
|
|
62
|
+
"[data-disabled]": "_textDisabled"
|
|
63
|
+
},
|
|
64
|
+
cursor: {
|
|
65
|
+
default: "pointer",
|
|
66
|
+
"[data-disabled]": "not-allowed"
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
middle: {
|
|
70
|
+
backgroundColor: "_accentSoft",
|
|
71
|
+
color: "_accentText"
|
|
72
|
+
},
|
|
73
|
+
selected: {
|
|
74
|
+
borderRadius: "_md",
|
|
75
|
+
backgroundColor: "_accent",
|
|
76
|
+
color: "_accentContrast"
|
|
77
|
+
},
|
|
78
|
+
rangeStart: {
|
|
79
|
+
borderStartEndRadius: 0,
|
|
80
|
+
borderEndEndRadius: 0
|
|
81
|
+
},
|
|
82
|
+
rangeEnd: {
|
|
83
|
+
borderStartStartRadius: 0,
|
|
84
|
+
borderEndStartRadius: 0
|
|
85
|
+
},
|
|
86
|
+
bottom: {
|
|
87
|
+
fontSize: "0.65em",
|
|
88
|
+
lineHeight: "1.2",
|
|
89
|
+
minHeight: "1.2em"
|
|
90
|
+
},
|
|
91
|
+
footer: {
|
|
92
|
+
paddingBlock: "_sm",
|
|
93
|
+
paddingInline: "_lg",
|
|
94
|
+
paddingBlockEnd: "calc(0.5em + env(safe-area-inset-bottom))"
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
/** 某天 0 点 */
|
|
98
|
+
var dayOf = (date) => new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
99
|
+
var sameDay = (a, b) => !!a && a.getTime() === dayOf(b).getTime();
|
|
100
|
+
/** 值 → 选中的日子列表(区间时是 [开始, 结束?]) */
|
|
101
|
+
function toDays(value) {
|
|
102
|
+
if (!value) return [];
|
|
103
|
+
return (Array.isArray(value) ? value : [value]).map(dayOf);
|
|
104
|
+
}
|
|
105
|
+
/** 日历(div > 标题 + 星期 + 各月 + 确认) */
|
|
106
|
+
var Calendar = /*#__PURE__*/ _component((_props, _ctx) => {
|
|
107
|
+
const type = readonlyProp(_props, "type", "single");
|
|
108
|
+
const value = bindable(_props, "_value", () => null, _ctx.emit);
|
|
109
|
+
const minDate = readonlyProp(_props, "minDate");
|
|
110
|
+
const maxDate = readonlyProp(_props, "maxDate");
|
|
111
|
+
const title = readonlyProp(_props, "title");
|
|
112
|
+
const showConfirm = readonlyProp(_props, "showConfirm", true);
|
|
113
|
+
const confirmText = readonlyProp(_props, "confirmText");
|
|
114
|
+
const dayInfo = readonlyProp(_props, "dayInfo");
|
|
115
|
+
const onSelect = readonlyProp(_props, "onSelect");
|
|
116
|
+
const onConfirm = readonlyProp(_props, "onConfirm");
|
|
117
|
+
const rest = restProps(_props, _ctx, true);
|
|
118
|
+
const config = useConfig();
|
|
119
|
+
const today = dayOf(/* @__PURE__ */ new Date());
|
|
120
|
+
const min = computed(() => dayOf(minDate.value ?? today));
|
|
121
|
+
const max = computed(() => dayOf(maxDate.value ?? new Date(today.getFullYear(), today.getMonth() + 6, today.getDate())));
|
|
122
|
+
let picked = overridable(() => toDays(value.value));
|
|
123
|
+
/** 各月:从 min 的月份到 max 的月份 */
|
|
124
|
+
const months = computed(() => {
|
|
125
|
+
const list = [];
|
|
126
|
+
for (let cursor = new Date(min.value.getFullYear(), min.value.getMonth(), 1); cursor <= max.value; cursor.setMonth(cursor.getMonth() + 1)) list.push({
|
|
127
|
+
year: cursor.getFullYear(),
|
|
128
|
+
month: cursor.getMonth()
|
|
129
|
+
});
|
|
130
|
+
return list;
|
|
131
|
+
});
|
|
132
|
+
const complete = () => type.value === "range" ? picked.value.length === 2 : picked.value.length > 0;
|
|
133
|
+
const result = () => type.value === "single" ? picked.value[0] : type.value === "range" ? [picked.value[0], picked.value[1]] : [...picked.value];
|
|
134
|
+
const commit = () => {
|
|
135
|
+
if (!complete()) return;
|
|
136
|
+
value.value = result();
|
|
137
|
+
onConfirm.value?.(value.value);
|
|
138
|
+
};
|
|
139
|
+
const choose = (day) => {
|
|
140
|
+
onSelect.value?.(day);
|
|
141
|
+
if (type.value === "single") picked.value = [day];
|
|
142
|
+
else if (type.value === "multiple") picked.value = picked.value.some((item) => sameDay(item, day)) ? picked.value.filter((item) => !sameDay(item, day)) : [...picked.value, day].sort((a, b) => a.getTime() - b.getTime());
|
|
143
|
+
else if (picked.value.length !== 1 || day < picked.value[0]) picked.value = [day];
|
|
144
|
+
else picked.value = [picked.value[0], day];
|
|
145
|
+
if (!showConfirm.value && complete()) commit();
|
|
146
|
+
};
|
|
147
|
+
const renderDay = (day) => {
|
|
148
|
+
const info = dayInfo.value?.(day);
|
|
149
|
+
const disabled = day < min.value || day > max.value || !!info?.disabled;
|
|
150
|
+
const [start, end] = picked.value;
|
|
151
|
+
const isStart = type.value === "range" && sameDay(start, day);
|
|
152
|
+
const isEnd = type.value === "range" && sameDay(end, day);
|
|
153
|
+
const selected = type.value === "range" ? isStart || isEnd : picked.value.some((item) => sameDay(item, day));
|
|
154
|
+
const middle = type.value === "range" && !!start && !!end && day > start && day < end;
|
|
155
|
+
const bottom = isStart ? config.lang.start : isEnd ? config.lang.end : info?.bottom;
|
|
156
|
+
return createVNode("div", mergeJsxProps(mergeAttrs({ sx: [
|
|
157
|
+
calendarStyles.day,
|
|
158
|
+
middle && calendarStyles.middle,
|
|
159
|
+
selected && calendarStyles.selected,
|
|
160
|
+
isStart && !!end && calendarStyles.rangeStart,
|
|
161
|
+
isEnd && calendarStyles.rangeEnd
|
|
162
|
+
] }), {
|
|
163
|
+
"role": "gridcell",
|
|
164
|
+
"aria-selected": selected ? "true" : void 0,
|
|
165
|
+
"aria-disabled": disabled ? "true" : void 0
|
|
166
|
+
}, dataAttrs({ "data-disabled": disabled }), { "onClick": () => !disabled && choose(day) }), [day.getDate(), createVNode("span", mergeAttrs({ sx: calendarStyles.bottom }), [hasContent(bottom) ? bottom : null])]);
|
|
167
|
+
};
|
|
168
|
+
return () => {
|
|
169
|
+
const first = config.lang.firstDayOfWeek;
|
|
170
|
+
const weekdays = [...config.lang.weekdays.slice(first), ...config.lang.weekdays.slice(0, first)];
|
|
171
|
+
return createVNode("div", mergeAttrs({ sx: calendarStyles.root }, rest), [
|
|
172
|
+
hasContent(title.value) && createVNode("div", mergeAttrs({ sx: calendarStyles.title }), [title.value]),
|
|
173
|
+
createVNode("div", mergeJsxProps(mergeAttrs({ sx: calendarStyles.weekdays }), { "aria-hidden": "true" }), [weekdays.map((name) => createVNode("span", null, [name]))]),
|
|
174
|
+
createVNode("div", mergeAttrs({ sx: calendarStyles.body }), [months.value.map(({ year, month }) => {
|
|
175
|
+
const count = new Date(year, month + 1, 0).getDate();
|
|
176
|
+
const offset = (new Date(year, month, 1).getDay() - first + 7) % 7;
|
|
177
|
+
return createVNode("div", mergeJsxProps(mergeAttrs({ sx: calendarStyles.month }), {
|
|
178
|
+
"role": "grid",
|
|
179
|
+
"aria-label": config.lang.monthTitle(year, month + 1)
|
|
180
|
+
}), [createVNode("div", mergeAttrs({ sx: calendarStyles.monthTitle }), [config.lang.monthTitle(year, month + 1)]), createVNode("div", mergeAttrs({ sx: calendarStyles.days }), [Array.from({ length: offset }, () => createVNode("span", null, null)), Array.from({ length: count }, (_, index) => renderDay(new Date(year, month, index + 1)))])]);
|
|
181
|
+
})]),
|
|
182
|
+
showConfirm.value && createVNode("div", mergeAttrs({ sx: calendarStyles.footer }), [createVNode(Button, {
|
|
183
|
+
"fullWidth": true,
|
|
184
|
+
"radius": "full",
|
|
185
|
+
"disabled": !complete(),
|
|
186
|
+
"onClick": commit,
|
|
187
|
+
"key": "__site0"
|
|
188
|
+
}, {
|
|
189
|
+
default: () => [confirmText.value ?? config.lang.confirm],
|
|
190
|
+
$stable: true
|
|
191
|
+
})])
|
|
192
|
+
]);
|
|
193
|
+
};
|
|
194
|
+
}, {
|
|
195
|
+
name: "Calendar",
|
|
196
|
+
props: [
|
|
197
|
+
"type",
|
|
198
|
+
"_value",
|
|
199
|
+
"onUpdate:_value",
|
|
200
|
+
"minDate",
|
|
201
|
+
"maxDate",
|
|
202
|
+
"title",
|
|
203
|
+
"showConfirm",
|
|
204
|
+
"confirmText",
|
|
205
|
+
"dayInfo",
|
|
206
|
+
"onSelect",
|
|
207
|
+
"onConfirm"
|
|
208
|
+
]
|
|
209
|
+
});
|
|
210
|
+
//#endregion
|
|
211
|
+
export { Calendar, calendarStyles };
|
|
212
|
+
|
|
213
|
+
//# sourceMappingURL=Calendar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Calendar.js","names":["_vtp_readonlyProp","_vtp_bindable","_vtp_restProps","_vue_computed","_vtp_overridable","_createVNode","_mergeProps"],"sources":["../../src/picker/Calendar.tsx"],"sourcesContent":["/**\n * 日历:按月排开的日期格子,选一天、选一段(入住到离店)、或选几天。常放在底部弹出层里,下面一个确认按钮。\n *\n * <Calendar _value={date} onConfirm={(day) => …} />\n * <Calendar type=\"range\" _value={stay} minDate={today} maxDate={inSixMonths} dayInfo={(day) => ({ bottom: '¥299' })} />\n * <Calendar type=\"multiple\" _value={days} />\n *\n * 选的过程在组件里,点了确认才写回 _value(showConfirm 为 false 时选完就写回)。一周从周几开始、星期的写法随语言包。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport type { VNodeChild } from 'vue';\nimport { Button } from '../base/Button';\nimport { useConfig } from '../config/context';\nimport { dataAttrs, hasContent, mergeAttrs, type PartProps } from '../utils/props';\n\n/** 选择的方式 */\nexport interface CalendarTypes {\n /** 一天(默认) */\n single: unknown;\n /** 一段:先点开始,再点结束 */\n range: unknown;\n /** 几天:点一下选上,再点一下取消 */\n multiple: unknown;\n}\n\n/** 日历的值:一天、一段 [开始, 结束]、几天 */\nexport type CalendarValue = Date | [Date, Date] | Date[];\n\n/** 某一天的额外信息 */\nexport interface CalendarDayInfo {\n /** 日子下面的小字(价格、节日) */\n bottom?: VNodeChild;\n /** 这一天不能选 */\n disabled?: boolean;\n}\n\n/** 未声明的属性落到根元素(div)上 */\nexport interface CalendarProps extends Omit<PartProps<'div', 'title'>, 'onSelect'> {\n /**\n * 选择的方式\n * @default 'single'\n */\n type?: keyof CalendarTypes;\n /** 选中的日期;双向绑定写 `_value={x}`(确认时写回) */\n _value?: CalendarValue | null;\n /** 最早可选的日子;默认今天 */\n minDate?: Date;\n /** 最晚可选的日子;默认半年后 */\n maxDate?: Date;\n /** 标题 */\n title?: VNodeChild;\n /**\n * 下面显示确认按钮\n * @default true\n */\n showConfirm?: boolean;\n /** 确认的文字;不给时用语言包 */\n confirmText?: VNodeChild;\n /** 每一天的额外信息 */\n dayInfo?: (day: Date) => CalendarDayInfo | undefined;\n /** 点了一天 */\n onSelect?: (day: Date) => void;\n /** 点了确认(或不显示确认按钮时选完了) */\n onConfirm?: (value: CalendarValue) => void;\n}\n\n/** Calendar 的样式 */\nexport const calendarStyles = css.create({\n root: {\n display: 'flex',\n flexDirection: 'column',\n backgroundColor: '_surface',\n userSelect: 'none',\n },\n title: {\n paddingBlock: '0.8em',\n textAlign: 'center',\n fontSize: '_lg',\n fontWeight: '_semibold',\n color: '_text',\n },\n weekdays: {\n display: 'grid',\n gridTemplateColumns: 'repeat(7, 1fr)',\n paddingBlock: '0.4em',\n fontSize: '_xs',\n color: '_textMuted',\n textAlign: 'center',\n boxShadow: '_sm',\n },\n body: { height: '22em', overflowY: 'auto' },\n month: { paddingBlockEnd: '_sm' },\n monthTitle: {\n paddingBlock: '0.7em',\n textAlign: 'center',\n fontSize: '_md',\n fontWeight: '_medium',\n color: '_text',\n },\n days: { display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', rowGap: '0.25em' },\n day: {\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n height: '3.4em',\n fontSize: '_md',\n color: { default: '_text', '[data-disabled]': '_textDisabled' },\n cursor: { default: 'pointer', '[data-disabled]': 'not-allowed' },\n },\n // 区间中间的几天:浅色底连成一条\n middle: { backgroundColor: '_accentSoft', color: '_accentText' },\n selected: { borderRadius: '_md', backgroundColor: '_accent', color: '_accentContrast' },\n rangeStart: { borderStartEndRadius: 0, borderEndEndRadius: 0 },\n rangeEnd: { borderStartStartRadius: 0, borderEndStartRadius: 0 },\n bottom: { fontSize: '0.65em', lineHeight: '1.2', minHeight: '1.2em' },\n footer: {\n paddingBlock: '_sm',\n paddingInline: '_lg',\n paddingBlockEnd: 'calc(0.5em + env(safe-area-inset-bottom))',\n },\n});\n\n/** 某天 0 点 */\nconst dayOf = (date: Date) => new Date(date.getFullYear(), date.getMonth(), date.getDate());\nconst sameDay = (a: Date | undefined, b: Date) => !!a && a.getTime() === dayOf(b).getTime();\n\n/** 值 → 选中的日子列表(区间时是 [开始, 结束?]) */\nfunction toDays(value: CalendarValue | null | undefined): Date[] {\n if (!value) return [];\n return (Array.isArray(value) ? value : [value]).map(dayOf);\n}\n\n/** 日历(div > 标题 + 星期 + 各月 + 确认) */\nexport const Calendar = _component(\n ({\n type = 'single',\n _value: value = _bindable<CalendarValue | null>(null),\n minDate,\n maxDate,\n title,\n showConfirm = true,\n confirmText,\n dayInfo,\n onSelect,\n onConfirm,\n ...rest\n }: CalendarProps) => {\n const config = useConfig();\n const today = dayOf(new Date());\n const min = _derived(dayOf(minDate ?? today));\n const max = _derived(\n dayOf(maxDate ?? new Date(today.getFullYear(), today.getMonth() + 6, today.getDate())),\n );\n // 选的过程:确认前不写回 _value(覆盖派生值);外面改了 _value 时重新跟随\n let picked = _derived(toDays(value));\n\n /** 各月:从 min 的月份到 max 的月份 */\n const months = _derived.by(() => {\n const list: { year: number; month: number }[] = [];\n for (\n let cursor = new Date(min.getFullYear(), min.getMonth(), 1);\n cursor <= max;\n cursor.setMonth(cursor.getMonth() + 1)\n )\n list.push({ year: cursor.getFullYear(), month: cursor.getMonth() });\n return list;\n });\n\n const complete = () => (type === 'range' ? picked.length === 2 : picked.length > 0);\n const result = (): CalendarValue =>\n type === 'single' ? picked[0]! : type === 'range' ? [picked[0]!, picked[1]!] : [...picked];\n const commit = () => {\n if (!complete()) return;\n value = result();\n onConfirm?.(value);\n };\n\n const choose = (day: Date) => {\n onSelect?.(day);\n if (type === 'single') picked = [day];\n else if (type === 'multiple')\n picked = picked.some((item) => sameDay(item, day))\n ? picked.filter((item) => !sameDay(item, day))\n : [...picked, day].sort((a, b) => a.getTime() - b.getTime());\n // 区间:没开始或已经选完时重新开始;点在开始之前时当成新的开始\n else if (picked.length !== 1 || day < picked[0]!) picked = [day];\n else picked = [picked[0]!, day];\n if (!showConfirm && complete()) commit();\n };\n\n const renderDay = (day: Date) => {\n const info = dayInfo?.(day);\n const disabled = day < min || day > max || !!info?.disabled;\n const [start, end] = picked;\n const isStart = type === 'range' && sameDay(start, day);\n const isEnd = type === 'range' && sameDay(end, day);\n const selected =\n type === 'range' ? isStart || isEnd : picked.some((item) => sameDay(item, day));\n const middle = type === 'range' && !!start && !!end && day > start && day < end;\n const bottom = isStart ? config.lang.start : isEnd ? config.lang.end : info?.bottom;\n return (\n <div\n {...mergeAttrs<'div'>({\n sx: [\n calendarStyles.day,\n middle && calendarStyles.middle,\n selected && calendarStyles.selected,\n isStart && !!end && calendarStyles.rangeStart,\n isEnd && calendarStyles.rangeEnd,\n ],\n })}\n role=\"gridcell\"\n aria-selected={selected ? 'true' : undefined}\n aria-disabled={disabled ? 'true' : undefined}\n {...dataAttrs({ 'data-disabled': disabled })}\n onClick={() => !disabled && choose(day)}\n >\n {day.getDate()}\n <span {...mergeAttrs<'span'>({ sx: calendarStyles.bottom })}>\n {hasContent(bottom) ? bottom : null}\n </span>\n </div>\n );\n };\n\n return () => {\n const first = config.lang.firstDayOfWeek;\n const weekdays = [\n ...config.lang.weekdays.slice(first),\n ...config.lang.weekdays.slice(0, first),\n ];\n return (\n <div {...mergeAttrs<'div'>({ sx: calendarStyles.root }, rest)}>\n {hasContent(title) && (\n <div {...mergeAttrs<'div'>({ sx: calendarStyles.title })}>{title}</div>\n )}\n <div {...mergeAttrs<'div'>({ sx: calendarStyles.weekdays })} aria-hidden=\"true\">\n {weekdays.map((name) => (\n <span>{name}</span>\n ))}\n </div>\n <div {...mergeAttrs<'div'>({ sx: calendarStyles.body })}>\n {months.map(({ year, month }) => {\n const count = new Date(year, month + 1, 0).getDate();\n // 第一天前面空几格\n const offset = (new Date(year, month, 1).getDay() - first + 7) % 7;\n return (\n <div\n {...mergeAttrs<'div'>({ sx: calendarStyles.month })}\n role=\"grid\"\n aria-label={config.lang.monthTitle(year, month + 1)}\n >\n <div {...mergeAttrs<'div'>({ sx: calendarStyles.monthTitle })}>\n {config.lang.monthTitle(year, month + 1)}\n </div>\n <div {...mergeAttrs<'div'>({ sx: calendarStyles.days })}>\n {Array.from({ length: offset }, () => (\n <span />\n ))}\n {Array.from({ length: count }, (_, index) =>\n renderDay(new Date(year, month, index + 1)),\n )}\n </div>\n </div>\n );\n })}\n </div>\n {showConfirm && (\n <div {...mergeAttrs<'div'>({ sx: calendarStyles.footer })}>\n <Button fullWidth radius=\"full\" disabled={!complete()} onClick={commit}>\n {confirmText ?? config.lang.confirm}\n </Button>\n </div>\n )}\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
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
|
+
/** 选择的结果 */
|
|
6
|
+
export interface CascaderResult {
|
|
7
|
+
/** 最后一级的值 */
|
|
8
|
+
value: string | number;
|
|
9
|
+
/** 一路选的各级选项 */
|
|
10
|
+
selectedOptions: PickerOption[];
|
|
11
|
+
}
|
|
12
|
+
/** 未声明的属性落到根元素(div)上 */
|
|
13
|
+
export interface CascaderProps extends Omit<PartProps<'div', 'title' | 'placeholder'>, 'onChange'> {
|
|
14
|
+
/** 选项树(选项带 children 时有下一级) */
|
|
15
|
+
options: PickerOption[];
|
|
16
|
+
/** 最后一级选中的值;双向绑定写 `_value={x}` */
|
|
17
|
+
_value?: string | number;
|
|
18
|
+
/** 标题 */
|
|
19
|
+
title?: VNodeChild;
|
|
20
|
+
/** 还没选的那一级标签上的文字;不给时用语言包的“请选择” */
|
|
21
|
+
placeholder?: VNodeChild;
|
|
22
|
+
/**
|
|
23
|
+
* 右上角的关闭按钮
|
|
24
|
+
* @default true
|
|
25
|
+
*/
|
|
26
|
+
closeable?: boolean;
|
|
27
|
+
/** 选了某一级的一项 */
|
|
28
|
+
onChange?: (result: CascaderResult & {
|
|
29
|
+
tabIndex: number;
|
|
30
|
+
}) => void;
|
|
31
|
+
/** 选到了最后一级 */
|
|
32
|
+
onFinish?: (result: CascaderResult) => void;
|
|
33
|
+
/** 点了关闭 */
|
|
34
|
+
onClose?: () => void;
|
|
35
|
+
}
|
|
36
|
+
/** Cascader 的样式 */
|
|
37
|
+
export declare const cascaderStyles: Readonly<{
|
|
38
|
+
close: css.CompiledStyles;
|
|
39
|
+
header: css.CompiledStyles;
|
|
40
|
+
list: css.CompiledStyles;
|
|
41
|
+
option: css.CompiledStyles;
|
|
42
|
+
root: css.CompiledStyles;
|
|
43
|
+
tab: css.CompiledStyles;
|
|
44
|
+
tabs: css.CompiledStyles;
|
|
45
|
+
title: css.CompiledStyles;
|
|
46
|
+
}>;
|
|
47
|
+
/** 在选项树里找到值为 value 的项,返回一路上的选项 */
|
|
48
|
+
export declare function findPath(options: PickerOption[], value: string | number | undefined): PickerOption[];
|
|
49
|
+
/** 级联选择(div > 标题栏 + 各级标签 + 当前一级的选项) */
|
|
50
|
+
export declare const Cascader: import("@zerodep-dev/vue-tsx-pro-tsx").TsxComponent<CascaderProps>;
|
|
@@ -0,0 +1,199 @@
|
|
|
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 { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
|
|
5
|
+
import { _component, bindable, mergeJsxProps, overridable, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
6
|
+
import { createVNode } from "vue";
|
|
7
|
+
import { Check, X } from "@lucide/icons";
|
|
8
|
+
//#region src/picker/Cascader.tsx
|
|
9
|
+
/**
|
|
10
|
+
* 级联选择:一级级往下选(省 → 市 → 区),上面一排标签显示每一级选了什么(点标签回到那一级重选),下面是当前这一级的选项。
|
|
11
|
+
* 选到没有下一级的项时完成。常放在底部弹出层里。
|
|
12
|
+
*
|
|
13
|
+
* <Cascader title="所在地区" options={areaOptions()} _value={code} onFinish={({ selectedOptions }) => …} onClose={…} />
|
|
14
|
+
*
|
|
15
|
+
* _value 是最后一级的值;给了时按它找回整条路径。
|
|
16
|
+
*/
|
|
17
|
+
/** 选择的结果 */
|
|
18
|
+
/** 未声明的属性落到根元素(div)上 */
|
|
19
|
+
/** Cascader 的样式 */
|
|
20
|
+
var cascaderStyles = css.create({
|
|
21
|
+
root: {
|
|
22
|
+
backgroundColor: "_surface",
|
|
23
|
+
userSelect: "none"
|
|
24
|
+
},
|
|
25
|
+
header: {
|
|
26
|
+
display: "flex",
|
|
27
|
+
alignItems: "center",
|
|
28
|
+
justifyContent: "space-between",
|
|
29
|
+
height: "3em",
|
|
30
|
+
paddingInline: "_lg"
|
|
31
|
+
},
|
|
32
|
+
title: {
|
|
33
|
+
fontSize: "_lg",
|
|
34
|
+
fontWeight: "_semibold",
|
|
35
|
+
color: "_text"
|
|
36
|
+
},
|
|
37
|
+
close: {
|
|
38
|
+
display: "inline-flex",
|
|
39
|
+
margin: 0,
|
|
40
|
+
padding: 0,
|
|
41
|
+
borderWidth: 0,
|
|
42
|
+
backgroundColor: "transparent",
|
|
43
|
+
color: "_textMuted",
|
|
44
|
+
fontSize: "_xl",
|
|
45
|
+
cursor: "pointer"
|
|
46
|
+
},
|
|
47
|
+
tabs: {
|
|
48
|
+
display: "flex",
|
|
49
|
+
gap: "_lg",
|
|
50
|
+
overflowX: "auto",
|
|
51
|
+
paddingInline: "_lg",
|
|
52
|
+
borderBlockEndWidth: "_hairline",
|
|
53
|
+
borderBlockEndStyle: "solid",
|
|
54
|
+
borderBlockEndColor: "_border",
|
|
55
|
+
scrollbarWidth: "none"
|
|
56
|
+
},
|
|
57
|
+
tab: {
|
|
58
|
+
position: "relative",
|
|
59
|
+
flex: "none",
|
|
60
|
+
maxWidth: "8em",
|
|
61
|
+
height: "2.6em",
|
|
62
|
+
margin: 0,
|
|
63
|
+
padding: 0,
|
|
64
|
+
borderWidth: 0,
|
|
65
|
+
backgroundColor: "transparent",
|
|
66
|
+
overflow: "hidden",
|
|
67
|
+
whiteSpace: "nowrap",
|
|
68
|
+
textOverflow: "ellipsis",
|
|
69
|
+
color: {
|
|
70
|
+
default: "_text",
|
|
71
|
+
"[data-empty]": "_textMuted"
|
|
72
|
+
},
|
|
73
|
+
fontFamily: "inherit",
|
|
74
|
+
fontSize: "_md",
|
|
75
|
+
fontWeight: {
|
|
76
|
+
default: "_normal",
|
|
77
|
+
"[aria-selected=\"true\"]": "_semibold"
|
|
78
|
+
},
|
|
79
|
+
cursor: "pointer",
|
|
80
|
+
backgroundImage: {
|
|
81
|
+
default: "none",
|
|
82
|
+
"[aria-selected=\"true\"]": "linear-gradient(currentColor, currentColor)"
|
|
83
|
+
},
|
|
84
|
+
backgroundSize: "1.6em 0.2em",
|
|
85
|
+
backgroundPosition: "center bottom",
|
|
86
|
+
backgroundRepeat: "no-repeat"
|
|
87
|
+
},
|
|
88
|
+
list: {
|
|
89
|
+
height: "22em",
|
|
90
|
+
overflowY: "auto",
|
|
91
|
+
paddingBlock: "_sm"
|
|
92
|
+
},
|
|
93
|
+
option: {
|
|
94
|
+
display: "flex",
|
|
95
|
+
alignItems: "center",
|
|
96
|
+
justifyContent: "space-between",
|
|
97
|
+
paddingBlock: "0.65em",
|
|
98
|
+
paddingInline: "_lg",
|
|
99
|
+
fontSize: "_md",
|
|
100
|
+
color: {
|
|
101
|
+
default: "_text",
|
|
102
|
+
"[aria-selected=\"true\"]": "_accentText",
|
|
103
|
+
"[data-disabled]": "_textDisabled"
|
|
104
|
+
},
|
|
105
|
+
backgroundColor: {
|
|
106
|
+
default: "transparent",
|
|
107
|
+
":active:not([data-disabled])": "_fillActive"
|
|
108
|
+
},
|
|
109
|
+
cursor: {
|
|
110
|
+
default: "pointer",
|
|
111
|
+
"[data-disabled]": "not-allowed"
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
/** 在选项树里找到值为 value 的项,返回一路上的选项 */
|
|
116
|
+
function findPath(options, value) {
|
|
117
|
+
if (value === void 0) return [];
|
|
118
|
+
for (const option of options) {
|
|
119
|
+
if (option.value === value) return [option];
|
|
120
|
+
const rest = findPath(option.children ?? [], value);
|
|
121
|
+
if (rest.length) return [option, ...rest];
|
|
122
|
+
}
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
/** 级联选择(div > 标题栏 + 各级标签 + 当前一级的选项) */
|
|
126
|
+
var Cascader = /*#__PURE__*/ _component((_props, _ctx) => {
|
|
127
|
+
const _cache = [];
|
|
128
|
+
const options = readonlyProp(_props, "options");
|
|
129
|
+
const value = bindable(_props, "_value", () => void 0, _ctx.emit);
|
|
130
|
+
const title = readonlyProp(_props, "title");
|
|
131
|
+
const placeholder = readonlyProp(_props, "placeholder");
|
|
132
|
+
const closeable = readonlyProp(_props, "closeable", true);
|
|
133
|
+
const onChange = readonlyProp(_props, "onChange");
|
|
134
|
+
const onFinish = readonlyProp(_props, "onFinish");
|
|
135
|
+
const onClose = readonlyProp(_props, "onClose");
|
|
136
|
+
const rest = restProps(_props, _ctx, true);
|
|
137
|
+
const config = useConfig();
|
|
138
|
+
let path = overridable(() => findPath(options.value, value.value));
|
|
139
|
+
let tab = overridable(() => Math.max(0, path.value.length - 1));
|
|
140
|
+
/** 第 level 级的选项 */
|
|
141
|
+
const levelOptions = (level) => level === 0 ? options.value : path.value[level - 1]?.children ?? [];
|
|
142
|
+
const choose = (level, option) => {
|
|
143
|
+
if (option.disabled) return;
|
|
144
|
+
path.value = [...path.value.slice(0, level), option];
|
|
145
|
+
const result = {
|
|
146
|
+
value: option.value,
|
|
147
|
+
selectedOptions: path.value
|
|
148
|
+
};
|
|
149
|
+
onChange.value?.({
|
|
150
|
+
...result,
|
|
151
|
+
tabIndex: level
|
|
152
|
+
});
|
|
153
|
+
if (option.children?.length) tab.value = level + 1;
|
|
154
|
+
else {
|
|
155
|
+
value.value = option.value;
|
|
156
|
+
onFinish.value?.(result);
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
return () => {
|
|
160
|
+
const levels = path.value.length + (path.value[path.value.length - 1]?.children?.length || !path.value.length ? 1 : 0);
|
|
161
|
+
return createVNode("div", mergeAttrs({ sx: cascaderStyles.root }, rest), [
|
|
162
|
+
createVNode("div", mergeAttrs({ sx: cascaderStyles.header }), [createVNode("span", mergeAttrs({ sx: cascaderStyles.title }), [hasContent(title.value) ? title.value : null]), closeable.value && createVNode("button", mergeJsxProps(mergeAttrs({ sx: cascaderStyles.close }), {
|
|
163
|
+
"type": "button",
|
|
164
|
+
"aria-label": config.lang.close,
|
|
165
|
+
"onClick": _cache[0] || (_cache[0] = () => onClose.value?.())
|
|
166
|
+
}), [createVNode(Icon, { "icon": X }, null)])]),
|
|
167
|
+
createVNode("div", mergeJsxProps(mergeAttrs({ sx: cascaderStyles.tabs }), { "role": "tablist" }), [Array.from({ length: levels }, (_, level) => createVNode("button", mergeJsxProps(mergeAttrs({ sx: cascaderStyles.tab }), {
|
|
168
|
+
"type": "button",
|
|
169
|
+
"role": "tab",
|
|
170
|
+
"aria-selected": level === tab.value ? "true" : "false"
|
|
171
|
+
}, dataAttrs({ "data-empty": !path.value[level] }), { "onClick": () => tab.value = level }), [path.value[level]?.text ?? placeholder.value ?? config.lang.select]))]),
|
|
172
|
+
createVNode("div", mergeJsxProps(mergeAttrs({ sx: cascaderStyles.list }), { "role": "listbox" }), [levelOptions(tab.value).map((option) => {
|
|
173
|
+
const selected = path.value[tab.value]?.value === option.value;
|
|
174
|
+
return createVNode("div", mergeJsxProps(mergeAttrs({ sx: cascaderStyles.option }), {
|
|
175
|
+
"role": "option",
|
|
176
|
+
"aria-selected": selected ? "true" : "false",
|
|
177
|
+
"aria-disabled": option.disabled ? "true" : void 0
|
|
178
|
+
}, dataAttrs({ "data-disabled": option.disabled }), { "onClick": () => choose(tab.value, option) }), [createVNode("span", null, [option.text]), selected && createVNode(Icon, { "icon": Check }, null)]);
|
|
179
|
+
})])
|
|
180
|
+
]);
|
|
181
|
+
};
|
|
182
|
+
}, {
|
|
183
|
+
name: "Cascader",
|
|
184
|
+
props: [
|
|
185
|
+
"options",
|
|
186
|
+
"_value",
|
|
187
|
+
"onUpdate:_value",
|
|
188
|
+
"title",
|
|
189
|
+
"placeholder",
|
|
190
|
+
"closeable",
|
|
191
|
+
"onChange",
|
|
192
|
+
"onFinish",
|
|
193
|
+
"onClose"
|
|
194
|
+
]
|
|
195
|
+
});
|
|
196
|
+
//#endregion
|
|
197
|
+
export { Cascader, cascaderStyles, findPath };
|
|
198
|
+
|
|
199
|
+
//# sourceMappingURL=Cascader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Cascader.js","names":["_vtp_readonlyProp","_vtp_bindable","_vtp_restProps","_vtp_overridable","_createVNode","_mergeProps"],"sources":["../../src/picker/Cascader.tsx"],"sourcesContent":["/**\n * 级联选择:一级级往下选(省 → 市 → 区),上面一排标签显示每一级选了什么(点标签回到那一级重选),下面是当前这一级的选项。\n * 选到没有下一级的项时完成。常放在底部弹出层里。\n *\n * <Cascader title=\"所在地区\" options={areaOptions()} _value={code} onFinish={({ selectedOptions }) => …} onClose={…} />\n *\n * _value 是最后一级的值;给了时按它找回整条路径。\n */\nimport { Check, X } from '@lucide/icons';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport type { VNodeChild } from 'vue';\nimport { Icon } from '../base/Icon';\nimport { useConfig } from '../config/context';\nimport { dataAttrs, hasContent, mergeAttrs, type PartProps } from '../utils/props';\nimport type { PickerOption } from './PickerColumn';\n\n/** 选择的结果 */\nexport interface CascaderResult {\n /** 最后一级的值 */\n value: string | number;\n /** 一路选的各级选项 */\n selectedOptions: PickerOption[];\n}\n\n/** 未声明的属性落到根元素(div)上 */\nexport interface CascaderProps extends Omit<PartProps<'div', 'title' | 'placeholder'>, 'onChange'> {\n /** 选项树(选项带 children 时有下一级) */\n options: PickerOption[];\n /** 最后一级选中的值;双向绑定写 `_value={x}` */\n _value?: string | number;\n /** 标题 */\n title?: VNodeChild;\n /** 还没选的那一级标签上的文字;不给时用语言包的“请选择” */\n placeholder?: VNodeChild;\n /**\n * 右上角的关闭按钮\n * @default true\n */\n closeable?: boolean;\n /** 选了某一级的一项 */\n onChange?: (result: CascaderResult & { tabIndex: number }) => void;\n /** 选到了最后一级 */\n onFinish?: (result: CascaderResult) => void;\n /** 点了关闭 */\n onClose?: () => void;\n}\n\n/** Cascader 的样式 */\nexport const cascaderStyles = css.create({\n root: { backgroundColor: '_surface', userSelect: 'none' },\n header: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n height: '3em',\n paddingInline: '_lg',\n },\n title: { fontSize: '_lg', fontWeight: '_semibold', color: '_text' },\n close: {\n display: 'inline-flex',\n margin: 0,\n padding: 0,\n borderWidth: 0,\n backgroundColor: 'transparent',\n color: '_textMuted',\n fontSize: '_xl',\n cursor: 'pointer',\n },\n tabs: {\n display: 'flex',\n gap: '_lg',\n overflowX: 'auto',\n paddingInline: '_lg',\n borderBlockEndWidth: '_hairline',\n borderBlockEndStyle: 'solid',\n borderBlockEndColor: '_border',\n scrollbarWidth: 'none',\n },\n tab: {\n position: 'relative',\n flex: 'none',\n maxWidth: '8em',\n height: '2.6em',\n margin: 0,\n padding: 0,\n borderWidth: 0,\n backgroundColor: 'transparent',\n overflow: 'hidden',\n whiteSpace: 'nowrap',\n textOverflow: 'ellipsis',\n color: { default: '_text', '[data-empty]': '_textMuted' },\n fontFamily: 'inherit',\n fontSize: '_md',\n fontWeight: { default: '_normal', '[aria-selected=\"true\"]': '_semibold' },\n cursor: 'pointer',\n // 当前一级的下划线(背景渐变画在底部,不用伪元素)\n backgroundImage: {\n default: 'none',\n '[aria-selected=\"true\"]': 'linear-gradient(currentColor, currentColor)',\n },\n backgroundSize: '1.6em 0.2em',\n backgroundPosition: 'center bottom',\n backgroundRepeat: 'no-repeat',\n },\n list: { height: '22em', overflowY: 'auto', paddingBlock: '_sm' },\n option: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n paddingBlock: '0.65em',\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/** 在选项树里找到值为 value 的项,返回一路上的选项 */\nexport function findPath(\n options: PickerOption[],\n value: string | number | undefined,\n): PickerOption[] {\n if (value === undefined) return [];\n for (const option of options) {\n if (option.value === value) return [option];\n const rest = findPath(option.children ?? [], value);\n if (rest.length) return [option, ...rest];\n }\n return [];\n}\n\n/** 级联选择(div > 标题栏 + 各级标签 + 当前一级的选项) */\nexport const Cascader = _component(\n ({\n options,\n _value: value = _bindable<string | number | undefined>(undefined),\n title,\n placeholder,\n closeable = true,\n onChange,\n onFinish,\n onClose,\n ...rest\n }: CascaderProps) => {\n const config = useConfig();\n // 一路选的项:按 _value 找回,选的过程中覆盖;外面改了 _value 时重新跟随\n let path = _derived(findPath(options, value));\n // 当前的一级:默认是最后选的那一级,点标签、选了有下一级的项时覆盖\n let tab = _derived(Math.max(0, path.length - 1));\n /** 第 level 级的选项 */\n const levelOptions = (level: number) =>\n level === 0 ? options : (path[level - 1]?.children ?? []);\n const choose = (level: number, option: PickerOption) => {\n if (option.disabled) return;\n path = [...path.slice(0, level), option];\n const result = { value: option.value, selectedOptions: path };\n onChange?.({ ...result, tabIndex: level });\n if (option.children?.length) tab = level + 1;\n else {\n value = option.value;\n onFinish?.(result);\n }\n };\n\n return () => {\n // 标签:选过的各级,加上还没选的下一级\n const levels =\n path.length + (path[path.length - 1]?.children?.length || !path.length ? 1 : 0);\n return (\n <div {...mergeAttrs<'div'>({ sx: cascaderStyles.root }, rest)}>\n <div {...mergeAttrs<'div'>({ sx: cascaderStyles.header })}>\n <span {...mergeAttrs<'span'>({ sx: cascaderStyles.title })}>\n {hasContent(title) ? title : null}\n </span>\n {closeable && (\n <button\n {...mergeAttrs<'button'>({ sx: cascaderStyles.close })}\n type=\"button\"\n aria-label={config.lang.close}\n onClick={() => onClose?.()}\n >\n <Icon icon={X} />\n </button>\n )}\n </div>\n <div {...mergeAttrs<'div'>({ sx: cascaderStyles.tabs })} role=\"tablist\">\n {Array.from({ length: levels }, (_, level) => (\n <button\n {...mergeAttrs<'button'>({ sx: cascaderStyles.tab })}\n type=\"button\"\n role=\"tab\"\n aria-selected={level === tab ? 'true' : 'false'}\n {...dataAttrs({ 'data-empty': !path[level] })}\n onClick={() => (tab = level)}\n >\n {path[level]?.text ?? placeholder ?? config.lang.select}\n </button>\n ))}\n </div>\n <div {...mergeAttrs<'div'>({ sx: cascaderStyles.list })} role=\"listbox\">\n {levelOptions(tab).map((option) => {\n const selected = path[tab]?.value === option.value;\n return (\n <div\n {...mergeAttrs<'div'>({ sx: cascaderStyles.option })}\n role=\"option\"\n aria-selected={selected ? 'true' : 'false'}\n aria-disabled={option.disabled ? 'true' : undefined}\n {...dataAttrs({ 'data-disabled': option.disabled })}\n onClick={() => choose(tab, option)}\n >\n <span>{option.text}</span>\n {selected && <Icon icon={Check} />}\n </div>\n );\n })}\n </div>\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { VNodeChild } from 'vue';
|
|
2
|
+
import type { PartProps } from '../utils/props';
|
|
3
|
+
/** 日期的列 */
|
|
4
|
+
export type DateColumn = 'year' | 'month' | 'day';
|
|
5
|
+
/** 共有的属性 */
|
|
6
|
+
interface PickerShellProps extends Omit<PartProps<'div', 'title'>, 'onChange'> {
|
|
7
|
+
/** 标题 */
|
|
8
|
+
title?: VNodeChild;
|
|
9
|
+
/** 点了取消 */
|
|
10
|
+
onCancel?: () => void;
|
|
11
|
+
/** 可见的行数 */
|
|
12
|
+
visibleItemCount?: number;
|
|
13
|
+
}
|
|
14
|
+
/** 未声明的属性落到选择器的根元素上 */
|
|
15
|
+
export interface DatePickerProps extends PickerShellProps {
|
|
16
|
+
/** 选中的日期;双向绑定写 `_value={x}`。不给时是今天(限在范围内) */
|
|
17
|
+
_value?: Date;
|
|
18
|
+
/** 最早的日期;默认十年前的 1 月 1 日 */
|
|
19
|
+
minDate?: Date;
|
|
20
|
+
/** 最晚的日期;默认十年后的 12 月 31 日 */
|
|
21
|
+
maxDate?: Date;
|
|
22
|
+
/**
|
|
23
|
+
* 显示哪几列
|
|
24
|
+
* @default ['year', 'month', 'day']
|
|
25
|
+
*/
|
|
26
|
+
columns?: DateColumn[];
|
|
27
|
+
/** 点了确认 */
|
|
28
|
+
onConfirm?: (date: Date) => void;
|
|
29
|
+
}
|
|
30
|
+
/** 日期选择器(Picker) */
|
|
31
|
+
export declare const DatePicker: import("@zerodep-dev/vue-tsx-pro-tsx").TsxComponent<DatePickerProps>;
|
|
32
|
+
/** 未声明的属性落到选择器的根元素上 */
|
|
33
|
+
export interface TimePickerProps extends PickerShellProps {
|
|
34
|
+
/** 选中的时间 "HH:mm";双向绑定写 `_value={x}`。不给时是 00:00 */
|
|
35
|
+
_value?: string;
|
|
36
|
+
/**
|
|
37
|
+
* 最小、最大的小时
|
|
38
|
+
* @default 0、23
|
|
39
|
+
*/
|
|
40
|
+
minHour?: number;
|
|
41
|
+
maxHour?: number;
|
|
42
|
+
/**
|
|
43
|
+
* 分钟的步长
|
|
44
|
+
* @default 1
|
|
45
|
+
*/
|
|
46
|
+
minuteStep?: number;
|
|
47
|
+
/** 点了确认 */
|
|
48
|
+
onConfirm?: (time: string) => void;
|
|
49
|
+
}
|
|
50
|
+
/** 时间选择器(Picker:时、分两列) */
|
|
51
|
+
export declare const TimePicker: import("@zerodep-dev/vue-tsx-pro-tsx").TsxComponent<TimePickerProps>;
|
|
52
|
+
export {};
|