@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,158 @@
|
|
|
1
|
+
import { dataAttrs, mergeAttrs } from "../utils/props.js";
|
|
2
|
+
import { useHost } from "../utils/host.js";
|
|
3
|
+
import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
|
|
4
|
+
import { _component, childrenProp, createContext, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
5
|
+
import { createVNode, nextTick, onBeforeUnmount, onMounted, ref, shallowReactive, watch } from "vue";
|
|
6
|
+
//#region src/display/IndexBar.tsx
|
|
7
|
+
/** 一组的标题登记给索引栏的 */
|
|
8
|
+
/** 索引栏提供给各组标题的 */
|
|
9
|
+
var IndexBarContext = createContext("IndexBar");
|
|
10
|
+
/** 未声明的属性落到根元素(div)上 */
|
|
11
|
+
/** IndexBar、IndexAnchor 的样式 */
|
|
12
|
+
var indexBarStyles = css.create({
|
|
13
|
+
sidebar: {
|
|
14
|
+
position: "fixed",
|
|
15
|
+
insetInlineEnd: 0,
|
|
16
|
+
insetBlockStart: "50%",
|
|
17
|
+
zIndex: 200,
|
|
18
|
+
display: "flex",
|
|
19
|
+
flexDirection: "column",
|
|
20
|
+
alignItems: "center",
|
|
21
|
+
paddingInline: "0.3em",
|
|
22
|
+
transform: "translateY(-50%)",
|
|
23
|
+
userSelect: "none"
|
|
24
|
+
},
|
|
25
|
+
letter: {
|
|
26
|
+
paddingBlock: "0.1em",
|
|
27
|
+
paddingInline: "0.4em",
|
|
28
|
+
fontSize: "0.7em",
|
|
29
|
+
fontWeight: "_medium",
|
|
30
|
+
lineHeight: "1.4",
|
|
31
|
+
color: {
|
|
32
|
+
default: "_textMuted",
|
|
33
|
+
"[data-active]": "_accentText"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
anchor: {
|
|
37
|
+
position: "sticky",
|
|
38
|
+
zIndex: 1,
|
|
39
|
+
paddingBlock: "0.3em",
|
|
40
|
+
paddingInline: "_lg",
|
|
41
|
+
fontSize: "_sm",
|
|
42
|
+
fontWeight: "_semibold",
|
|
43
|
+
color: {
|
|
44
|
+
default: "_textMuted",
|
|
45
|
+
"[data-active]": "_accentText"
|
|
46
|
+
},
|
|
47
|
+
backgroundColor: {
|
|
48
|
+
default: "_background",
|
|
49
|
+
"[data-active]": "_surface"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
/** 索引栏(div > 内容 + 右边的字母栏) */
|
|
54
|
+
var IndexBar = /*#__PURE__*/ _component((_props, _ctx) => {
|
|
55
|
+
const stickyOffsetTop = readonlyProp(_props, "stickyOffsetTop", "0px");
|
|
56
|
+
const onSelect = readonlyProp(_props, "onSelect");
|
|
57
|
+
const children = childrenProp(_props);
|
|
58
|
+
const propsSidebar = readonlyProp(_props, "propsSidebar");
|
|
59
|
+
const rest = restProps(_props, _ctx, false);
|
|
60
|
+
const host = useHost();
|
|
61
|
+
const anchors = shallowReactive([]);
|
|
62
|
+
let active = ref(void 0);
|
|
63
|
+
let offsets = [];
|
|
64
|
+
const measureAnchors = async () => {
|
|
65
|
+
const scrollTop = host.scrollTop();
|
|
66
|
+
const rects = await Promise.all(anchors.map((anchor) => host.measure(anchor.element)));
|
|
67
|
+
offsets = anchors.map((anchor, position) => ({
|
|
68
|
+
index: anchor.index,
|
|
69
|
+
top: (rects[position]?.top ?? 0) + scrollTop
|
|
70
|
+
})).sort((a, b) => a.top - b.top);
|
|
71
|
+
update(host.scrollTop());
|
|
72
|
+
};
|
|
73
|
+
/** 当前的组:页面顶部已经越过的最后一个标题(留几像素的余量) */
|
|
74
|
+
const update = (scrollTop) => {
|
|
75
|
+
let current = offsets[0]?.index;
|
|
76
|
+
for (const offset of offsets) if (offset.top <= scrollTop + 4) current = offset.index;
|
|
77
|
+
active.value = current;
|
|
78
|
+
};
|
|
79
|
+
onMounted(() => void nextTick(measureAnchors));
|
|
80
|
+
watch(() => anchors.length, () => void nextTick(measureAnchors));
|
|
81
|
+
const stop = host.onScroll(update);
|
|
82
|
+
onBeforeUnmount(stop);
|
|
83
|
+
IndexBarContext.provide({
|
|
84
|
+
get active() {
|
|
85
|
+
return active.value;
|
|
86
|
+
},
|
|
87
|
+
get stickyOffsetTop() {
|
|
88
|
+
return stickyOffsetTop.value;
|
|
89
|
+
},
|
|
90
|
+
register(entry) {
|
|
91
|
+
anchors.push(entry);
|
|
92
|
+
return () => anchors.splice(anchors.indexOf(entry), 1);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
const jump = (index) => {
|
|
96
|
+
const offset = offsets.find((item) => item.index === index);
|
|
97
|
+
if (!offset) return;
|
|
98
|
+
onSelect.value?.(index);
|
|
99
|
+
host.scrollTo(offset.top);
|
|
100
|
+
active.value = index;
|
|
101
|
+
};
|
|
102
|
+
let letters = [];
|
|
103
|
+
let letterRects = [];
|
|
104
|
+
let last;
|
|
105
|
+
const letterAt = (y) => anchors[letterRects.findIndex((rect) => rect !== null && y >= rect.top && y < rect.top + rect.height)]?.index;
|
|
106
|
+
const onTouchstart = () => {
|
|
107
|
+
last = void 0;
|
|
108
|
+
Promise.all(letters.slice(0, anchors.length).map((letter) => host.measure(letter))).then((rects) => letterRects = rects);
|
|
109
|
+
};
|
|
110
|
+
const onTouchmove = (event) => {
|
|
111
|
+
const index = letterAt(event.touches[0].clientY);
|
|
112
|
+
if (index && index !== last) jump(last = index);
|
|
113
|
+
};
|
|
114
|
+
return () => createVNode("div", mergeAttrs({}, rest), [children.value, createVNode("div", mergeAttrs({ sx: indexBarStyles.sidebar }, propsSidebar.value, {
|
|
115
|
+
onTouchstart,
|
|
116
|
+
onTouchmove,
|
|
117
|
+
...dataAttrs({ "data-touch-move": "catch" })
|
|
118
|
+
}), [anchors.map((anchor, position) => createVNode("span", mergeJsxProps(mergeAttrs({ sx: indexBarStyles.letter }, {
|
|
119
|
+
role: "button",
|
|
120
|
+
"aria-label": anchor.index,
|
|
121
|
+
onClick: () => jump(anchor.index),
|
|
122
|
+
...dataAttrs({ "data-active": anchor.index === active.value })
|
|
123
|
+
}), { "ref": (node) => letters[position] = node }), [anchor.index]))])]);
|
|
124
|
+
}, {
|
|
125
|
+
name: "IndexBar",
|
|
126
|
+
props: [
|
|
127
|
+
"stickyOffsetTop",
|
|
128
|
+
"onSelect",
|
|
129
|
+
"propsSidebar"
|
|
130
|
+
]
|
|
131
|
+
});
|
|
132
|
+
/** 未声明的属性落到标题(div)上 */
|
|
133
|
+
/** 一组的标题(div,吸顶) */
|
|
134
|
+
var IndexAnchor = /*#__PURE__*/ _component((_props2, _ctx2) => {
|
|
135
|
+
const _cache = [];
|
|
136
|
+
const index = readonlyProp(_props2, "index");
|
|
137
|
+
const children = childrenProp(_props2);
|
|
138
|
+
const rest = restProps(_props2, _ctx2, false);
|
|
139
|
+
const bar = IndexBarContext.inject();
|
|
140
|
+
const entry = {
|
|
141
|
+
get index() {
|
|
142
|
+
return index.value;
|
|
143
|
+
},
|
|
144
|
+
element: null
|
|
145
|
+
};
|
|
146
|
+
onBeforeUnmount(bar.register(entry));
|
|
147
|
+
return () => createVNode("div", mergeJsxProps(mergeAttrs({
|
|
148
|
+
sx: indexBarStyles.anchor,
|
|
149
|
+
style: { insetBlockStart: bar.stickyOffsetTop }
|
|
150
|
+
}, rest, dataAttrs({ "data-active": bar.active === index.value })), { "ref": _cache[0] || (_cache[0] = (node) => entry.element = node) }), [children.value ?? index.value]);
|
|
151
|
+
}, {
|
|
152
|
+
name: "IndexAnchor",
|
|
153
|
+
props: ["index"]
|
|
154
|
+
});
|
|
155
|
+
//#endregion
|
|
156
|
+
export { IndexAnchor, IndexBar, indexBarStyles };
|
|
157
|
+
|
|
158
|
+
//# sourceMappingURL=IndexBar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IndexBar.js","names":["_vtp_readonlyProp","_vtp_childrenProp","_vtp_restProps","_vue_ref","_createVNode","_mergeProps"],"sources":["../../src/display/IndexBar.tsx"],"sourcesContent":["/**\n * 索引栏:按首字母分组的长列表(城市、通讯录),右边一列字母,点或在上面滑动跳到那一组,各组的标题滚到顶部时吸住。\n *\n * <IndexBar>\n * <IndexAnchor index=\"A\" />\n * <Cell title=\"安庆\" />\n * <IndexAnchor index=\"B\" />\n * <Cell title=\"北京\" />\n * </IndexBar>\n *\n * 跳转与当前组都按页面滚动算:各组标题的位置在挂上时量一次(宿主的异步测量),之后滚动只比较数字。\n */\nimport { _component, createContext } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { nextTick, onBeforeUnmount, onMounted, shallowReactive, watch, type VNodeChild } from 'vue';\nimport { useHost, type HostRect } from '../utils/host';\nimport { dataAttrs, mergeAttrs, type PartProps } from '../utils/props';\n\n/** 一组的标题登记给索引栏的 */\ninterface AnchorEntry {\n readonly index: string;\n element: unknown;\n}\n\n/** 索引栏提供给各组标题的 */\ninterface IndexBarState {\n readonly active: string | undefined;\n readonly stickyOffsetTop: string;\n register(entry: AnchorEntry): () => void;\n}\n\nconst IndexBarContext = createContext<IndexBarState>('IndexBar');\n\n/** 未声明的属性落到根元素(div)上 */\nexport interface IndexBarProps extends Omit<PartProps<'div'>, 'onSelect'> {\n /**\n * 组标题吸住时离顶部多远(CSS 长度;页面顶部有固定的导航栏时写它的高度)\n * @default '0px'\n */\n stickyOffsetTop?: string;\n /** 点(或滑到)右边的一个字母 */\n onSelect?: (index: string) => void;\n /** 各组的 IndexAnchor 与内容 */\n children?: VNodeChild;\n /** 右边字母栏的部件属性 */\n propsSidebar?: PartProps<'div'>;\n}\n\n/** IndexBar、IndexAnchor 的样式 */\nexport const indexBarStyles = css.create({\n sidebar: {\n position: 'fixed',\n insetInlineEnd: 0,\n insetBlockStart: '50%',\n zIndex: 200,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n paddingInline: '0.3em',\n transform: 'translateY(-50%)',\n userSelect: 'none',\n },\n letter: {\n paddingBlock: '0.1em',\n paddingInline: '0.4em',\n fontSize: '0.7em',\n fontWeight: '_medium',\n lineHeight: '1.4',\n color: { default: '_textMuted', '[data-active]': '_accentText' },\n },\n anchor: {\n position: 'sticky',\n zIndex: 1,\n paddingBlock: '0.3em',\n paddingInline: '_lg',\n fontSize: '_sm',\n fontWeight: '_semibold',\n color: { default: '_textMuted', '[data-active]': '_accentText' },\n backgroundColor: { default: '_background', '[data-active]': '_surface' },\n },\n});\n\n/** 索引栏(div > 内容 + 右边的字母栏) */\nexport const IndexBar = _component(\n ({ stickyOffsetTop = '0px', onSelect, children, propsSidebar, ...rest }: IndexBarProps) => {\n const host = useHost();\n const anchors = shallowReactive<AnchorEntry[]>([]);\n let active = _state<string | undefined>(undefined);\n // 各组标题在页面里的位置(px,相对页面顶部),挂上时与组变化时量\n let offsets: { index: string; top: number }[] = [];\n const measureAnchors = async () => {\n const scrollTop = host.scrollTop();\n const rects = await Promise.all(anchors.map((anchor) => host.measure(anchor.element)));\n offsets = anchors\n .map((anchor, position) => ({\n index: anchor.index,\n top: (rects[position]?.top ?? 0) + scrollTop,\n }))\n .sort((a, b) => a.top - b.top);\n update(host.scrollTop());\n };\n /** 当前的组:页面顶部已经越过的最后一个标题(留几像素的余量) */\n const update = (scrollTop: number) => {\n let current = offsets[0]?.index;\n for (const offset of offsets) if (offset.top <= scrollTop + 4) current = offset.index;\n active = current;\n };\n onMounted(() => void nextTick(measureAnchors));\n watch(\n () => anchors.length,\n () => void nextTick(measureAnchors),\n );\n const stop = host.onScroll(update);\n onBeforeUnmount(stop);\n\n IndexBarContext.provide({\n get active() {\n return active;\n },\n get stickyOffsetTop() {\n return stickyOffsetTop;\n },\n register(entry) {\n anchors.push(entry);\n return () => anchors.splice(anchors.indexOf(entry), 1);\n },\n });\n\n // 跳到一组:按挂上时量的位置(吸住的标题量出来是吸住的位置,不是这一组开始的地方)\n const jump = (index: string) => {\n const offset = offsets.find((item) => item.index === index);\n if (!offset) return;\n onSelect?.(index);\n host.scrollTo(offset.top);\n active = index;\n };\n\n // 在字母栏上滑动:按下时量各字母的位置,移动时按纵坐标找字母\n let letters: unknown[] = [];\n let letterRects: (HostRect | null)[] = [];\n let last: string | undefined;\n const letterAt = (y: number) =>\n anchors[\n letterRects.findIndex(\n (rect) => rect !== null && y >= rect.top && y < rect.top + rect.height,\n )\n ]?.index;\n const onTouchstart = () => {\n last = undefined;\n void Promise.all(letters.slice(0, anchors.length).map((letter) => host.measure(letter))).then(\n (rects) => (letterRects = rects),\n );\n };\n const onTouchmove = (event: TouchEvent) => {\n const index = letterAt(event.touches[0]!.clientY);\n if (index && index !== last) jump((last = index));\n };\n\n return () => (\n <div {...mergeAttrs<'div'>({}, rest)}>\n {children}\n <div\n {...mergeAttrs<'div'>({ sx: indexBarStyles.sidebar }, propsSidebar, {\n onTouchstart,\n onTouchmove,\n // 小程序:在字母栏上滑动时页面不跟着滚\n ...dataAttrs({ 'data-touch-move': 'catch' }),\n })}\n >\n {anchors.map((anchor, position) => (\n <span\n {...mergeAttrs<'span'>(\n { sx: indexBarStyles.letter },\n {\n role: 'button',\n 'aria-label': anchor.index,\n onClick: () => jump(anchor.index),\n ...dataAttrs({ 'data-active': anchor.index === active }),\n },\n )}\n ref={(node: unknown) => (letters[position] = node)}\n >\n {anchor.index}\n </span>\n ))}\n </div>\n </div>\n );\n },\n);\n\n/** 未声明的属性落到标题(div)上 */\nexport interface IndexAnchorProps extends PartProps<'div'> {\n /** 这一组的字母(也是右边字母栏上的字) */\n index: string;\n /** 标题的内容;不给时显示 index */\n children?: VNodeChild;\n}\n\n/** 一组的标题(div,吸顶) */\nexport const IndexAnchor = _component(({ index, children, ...rest }: IndexAnchorProps) => {\n const bar = IndexBarContext.inject();\n const entry: AnchorEntry = {\n get index() {\n return index;\n },\n element: null,\n };\n onBeforeUnmount(bar.register(entry));\n return () => (\n <div\n {...mergeAttrs<'div'>(\n { sx: indexBarStyles.anchor, style: { insetBlockStart: bar.stickyOffsetTop } },\n rest,\n dataAttrs({ 'data-active': bar.active === index }),\n )}\n ref={(node: unknown) => (entry.element = node)}\n >\n {children ?? index}\n </div>\n );\n});\n"],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
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
|
+
/** 未声明的属性落到根元素(div)上 */
|
|
5
|
+
export interface ListProps extends Omit<PartProps<'div', 'role'>, 'onLoad'> {
|
|
6
|
+
/** 是否在加载;双向绑定写 `_loading={x}` */
|
|
7
|
+
_loading?: boolean;
|
|
8
|
+
/** 是否加载失败;双向绑定写 `_error={x}` */
|
|
9
|
+
_error?: boolean;
|
|
10
|
+
/** 已经加载完了(不再触发 onLoad) */
|
|
11
|
+
finished?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* 离底部多近(px)开始加载
|
|
14
|
+
* @default 300
|
|
15
|
+
*/
|
|
16
|
+
offset?: number;
|
|
17
|
+
/** 加载下一页;返回 Promise 时完成后自动结束加载中,抛错时显示失败 */
|
|
18
|
+
onLoad?: () => void | Promise<unknown>;
|
|
19
|
+
/** 加载完时底部的文字;不给时用语言包的“没有更多了”,null 不显示 */
|
|
20
|
+
finishedText?: VNodeChild;
|
|
21
|
+
/** 失败时底部的文字;不给时用语言包 */
|
|
22
|
+
errorText?: VNodeChild;
|
|
23
|
+
/** 列表的内容 */
|
|
24
|
+
children?: VNodeChild;
|
|
25
|
+
/** 底部状态栏的部件属性 */
|
|
26
|
+
propsFooter?: PartProps<'div'>;
|
|
27
|
+
}
|
|
28
|
+
/** List 的样式:footer、error */
|
|
29
|
+
export declare const listStyles: Readonly<{
|
|
30
|
+
error: css.CompiledStyles;
|
|
31
|
+
footer: css.CompiledStyles;
|
|
32
|
+
}>;
|
|
33
|
+
/** 列表(div[role=feed] > 内容 + 底部状态) */
|
|
34
|
+
export declare const List: import("@zerodep-dev/vue-tsx-pro-tsx").TsxComponent<ListProps>;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { useConfig } from "../config/context.js";
|
|
2
|
+
import { hasContent, mergeAttrs } from "../utils/props.js";
|
|
3
|
+
import { Loading } from "../feedback/Loading.js";
|
|
4
|
+
import { useHost } from "../utils/host.js";
|
|
5
|
+
import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
|
|
6
|
+
import { _component, bindable, childrenProp, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
7
|
+
import { createVNode, nextTick, onBeforeUnmount, onMounted, watch } from "vue";
|
|
8
|
+
//#region src/display/List.tsx
|
|
9
|
+
/** 未声明的属性落到根元素(div)上 */
|
|
10
|
+
/** List 的样式:footer、error */
|
|
11
|
+
var listStyles = css.create({
|
|
12
|
+
footer: {
|
|
13
|
+
display: "flex",
|
|
14
|
+
alignItems: "center",
|
|
15
|
+
justifyContent: "center",
|
|
16
|
+
minHeight: "3.2em",
|
|
17
|
+
fontSize: "_sm",
|
|
18
|
+
color: "_textMuted"
|
|
19
|
+
},
|
|
20
|
+
error: { cursor: "pointer" }
|
|
21
|
+
});
|
|
22
|
+
/** 列表(div[role=feed] > 内容 + 底部状态) */
|
|
23
|
+
var List = /*#__PURE__*/ _component((_props, _ctx) => {
|
|
24
|
+
const _cache = [];
|
|
25
|
+
const loading = bindable(_props, "_loading", () => false, _ctx.emit);
|
|
26
|
+
const error = bindable(_props, "_error", () => false, _ctx.emit);
|
|
27
|
+
const finished = readonlyProp(_props, "finished", false);
|
|
28
|
+
const offset = readonlyProp(_props, "offset", 300);
|
|
29
|
+
const onLoad = readonlyProp(_props, "onLoad");
|
|
30
|
+
const finishedText = readonlyProp(_props, "finishedText");
|
|
31
|
+
const errorText = readonlyProp(_props, "errorText");
|
|
32
|
+
const children = childrenProp(_props);
|
|
33
|
+
const propsFooter = readonlyProp(_props, "propsFooter");
|
|
34
|
+
const rest = restProps(_props, _ctx, false);
|
|
35
|
+
const host = useHost();
|
|
36
|
+
const config = useConfig();
|
|
37
|
+
let footer = null;
|
|
38
|
+
let checking = false;
|
|
39
|
+
const load = async () => {
|
|
40
|
+
loading.value = true;
|
|
41
|
+
const pending = onLoad.value?.();
|
|
42
|
+
if (!(pending instanceof Promise)) return;
|
|
43
|
+
try {
|
|
44
|
+
await pending;
|
|
45
|
+
} catch {
|
|
46
|
+
error.value = true;
|
|
47
|
+
} finally {
|
|
48
|
+
loading.value = false;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
/** 底部离可视区的下沿不到 offset 时加载 */
|
|
52
|
+
const check = async () => {
|
|
53
|
+
if (checking || loading.value || error.value || finished.value) return;
|
|
54
|
+
checking = true;
|
|
55
|
+
try {
|
|
56
|
+
const rect = await host.measure(footer);
|
|
57
|
+
if (rect && rect.top - host.window().height <= offset.value && !loading.value && !error.value && !finished.value) await load();
|
|
58
|
+
} finally {
|
|
59
|
+
checking = false;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
const stop = host.onScroll(() => void check());
|
|
63
|
+
onBeforeUnmount(stop);
|
|
64
|
+
onMounted(() => void check());
|
|
65
|
+
watch(() => [
|
|
66
|
+
loading.value,
|
|
67
|
+
finished.value,
|
|
68
|
+
error.value
|
|
69
|
+
], () => void nextTick(check));
|
|
70
|
+
const retry = () => {
|
|
71
|
+
error.value = false;
|
|
72
|
+
check();
|
|
73
|
+
};
|
|
74
|
+
return () => {
|
|
75
|
+
const status = error.value ? errorText.value ?? config.lang.loadFailed : loading.value ? createVNode(Loading, { "key": "__site0" }, {
|
|
76
|
+
default: () => [config.lang.loading],
|
|
77
|
+
$stable: true
|
|
78
|
+
}) : finished.value && finishedText.value !== null ? hasContent(finishedText.value) ? finishedText.value : config.lang.noMore : null;
|
|
79
|
+
return createVNode("div", mergeAttrs({}, rest, {
|
|
80
|
+
role: "feed",
|
|
81
|
+
"aria-busy": loading.value ? "true" : "false"
|
|
82
|
+
}), [children.value, createVNode("div", mergeJsxProps(mergeAttrs({ sx: [listStyles.footer, error.value && listStyles.error] }, propsFooter.value, error.value ? {
|
|
83
|
+
role: "button",
|
|
84
|
+
onClick: retry
|
|
85
|
+
} : {}), { "ref": _cache[0] || (_cache[0] = (node) => footer = node) }), [status])]);
|
|
86
|
+
};
|
|
87
|
+
}, {
|
|
88
|
+
name: "List",
|
|
89
|
+
props: [
|
|
90
|
+
"_loading",
|
|
91
|
+
"onUpdate:_loading",
|
|
92
|
+
"_error",
|
|
93
|
+
"onUpdate:_error",
|
|
94
|
+
"finished",
|
|
95
|
+
"offset",
|
|
96
|
+
"onLoad",
|
|
97
|
+
"finishedText",
|
|
98
|
+
"errorText",
|
|
99
|
+
"propsFooter"
|
|
100
|
+
]
|
|
101
|
+
});
|
|
102
|
+
//#endregion
|
|
103
|
+
export { List, listStyles };
|
|
104
|
+
|
|
105
|
+
//# sourceMappingURL=List.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"List.js","names":["_vtp_bindable","_vtp_readonlyProp","_vtp_childrenProp","_vtp_restProps","_createVNode","_mergeProps"],"sources":["../../src/display/List.tsx"],"sourcesContent":["/**\n * 列表:滚到离底部不远时自动加载下一页,底部显示加载中、没有更多了、加载失败(点了重试)。\n *\n * <List finished={done} onLoad={async () => { rows.push(...(await fetchPage(++page))); done = page >= last; }}>\n * {rows.map((row) => <Cell title={row.name} />)}\n * </List>\n *\n * onLoad 返回 Promise 时自动管理加载中与失败(抛错时显示“加载失败,点击重试”);不返回时由使用方改 _loading、_error。\n * 离底部多近用宿主量底部的位置判断:H5 与小程序都按页面滚动。\n */\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { nextTick, onBeforeUnmount, onMounted, watch, type VNodeChild } from 'vue';\nimport { useConfig } from '../config/context';\nimport { Loading } from '../feedback/Loading';\nimport { useHost } from '../utils/host';\nimport { hasContent, mergeAttrs, type PartProps } from '../utils/props';\n\n/** 未声明的属性落到根元素(div)上 */\nexport interface ListProps extends Omit<PartProps<'div', 'role'>, 'onLoad'> {\n /** 是否在加载;双向绑定写 `_loading={x}` */\n _loading?: boolean;\n /** 是否加载失败;双向绑定写 `_error={x}` */\n _error?: boolean;\n /** 已经加载完了(不再触发 onLoad) */\n finished?: boolean;\n /**\n * 离底部多近(px)开始加载\n * @default 300\n */\n offset?: number;\n /** 加载下一页;返回 Promise 时完成后自动结束加载中,抛错时显示失败 */\n onLoad?: () => void | Promise<unknown>;\n /** 加载完时底部的文字;不给时用语言包的“没有更多了”,null 不显示 */\n finishedText?: VNodeChild;\n /** 失败时底部的文字;不给时用语言包 */\n errorText?: VNodeChild;\n /** 列表的内容 */\n children?: VNodeChild;\n /** 底部状态栏的部件属性 */\n propsFooter?: PartProps<'div'>;\n}\n\n/** List 的样式:footer、error */\nexport const listStyles = css.create({\n footer: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: '3.2em',\n fontSize: '_sm',\n color: '_textMuted',\n },\n error: { cursor: 'pointer' },\n});\n\n/** 列表(div[role=feed] > 内容 + 底部状态) */\nexport const List = _component(\n ({\n _loading: loading = _bindable(false),\n _error: error = _bindable(false),\n finished = false,\n offset = 300,\n onLoad,\n finishedText,\n errorText,\n children,\n propsFooter,\n ...rest\n }: ListProps) => {\n const host = useHost();\n const config = useConfig();\n let footer: unknown = null;\n let checking = false;\n\n const load = async () => {\n loading = true;\n const pending = onLoad?.();\n if (!(pending instanceof Promise)) return;\n try {\n await pending;\n } catch {\n error = true;\n } finally {\n loading = false;\n }\n };\n /** 底部离可视区的下沿不到 offset 时加载 */\n const check = async () => {\n if (checking || loading || error || finished) return;\n checking = true;\n try {\n const rect = await host.measure(footer);\n if (rect && rect.top - host.window().height <= offset && !loading && !error && !finished)\n await load();\n } finally {\n checking = false;\n }\n };\n\n const stop = host.onScroll(() => void check());\n onBeforeUnmount(stop);\n onMounted(() => void check());\n // 一页加载完、内容还不满一屏时接着加载\n watch(\n () => [loading, finished, error],\n () => void nextTick(check),\n );\n\n const retry = () => {\n error = false;\n void check();\n };\n\n return () => {\n const status = error ? (\n (errorText ?? config.lang.loadFailed)\n ) : loading ? (\n <Loading>{config.lang.loading}</Loading>\n ) : finished && finishedText !== null ? (\n hasContent(finishedText) ? (\n finishedText\n ) : (\n config.lang.noMore\n )\n ) : null;\n return (\n <div\n {...mergeAttrs<'div'>({}, rest, {\n role: 'feed',\n 'aria-busy': loading ? 'true' : 'false',\n })}\n >\n {children}\n <div\n {...mergeAttrs<'div'>(\n { sx: [listStyles.footer, error && listStyles.error] },\n propsFooter,\n // 失败时整条可点:重试\n error ? { role: 'button', onClick: retry } : {},\n )}\n ref={(node: unknown) => (footer = node)}\n >\n {status}\n </div>\n </div>\n );\n };\n },\n);\n"],"mappings":";;;;;;;;;;AA4CA,IAAa,aAAa,IAAI,OAAO;CACnC,QAAQ;EACN,SAAS;EACT,YAAY;EACZ,gBAAgB;EAChB,WAAW;EACX,UAAU;EACV,OAAO;CACT;CACA,OAAO,EAAE,QAAQ,UAAU;AAC7B,CAAC;;AAGD,IAAa,OAAO,0BAClB,QAAA,SAWiB;CAAA,MAAA,SAAA,CAAA;CAAA,MAAA,UAAAA,SAAA,QAAA,kBAVe,OAAK,KAAA,IAAA;CAAA,MAAA,QAAAA,SAAA,QAAA,gBACT,OAAK,KAAA,IAAA;CAAA,MAAA,WAAAC,aAAA,QAAA,YACpB,KAAK;CAAA,MAAA,SAAAA,aAAA,QAAA,UACP,GAAG;CAAA,MAAA,SAAAA,aAAA,QAAA,QAAA;CAAA,MAAA,eAAAA,aAAA,QAAA,cAAA;CAAA,MAAA,YAAAA,aAAA,QAAA,WAAA;CAAA,MAAA,WAAAC,aAAA,MAAA;CAAA,MAAA,cAAAD,aAAA,QAAA,aAAA;CAAA,MAMT,OAAIE,UAAA,QAAA,MAAA,KAAA;CAEP,MAAM,OAAO,QAAQ;CACrB,MAAM,SAAS,UAAU;CACzB,IAAI,SAAkB;CACtB,IAAI,WAAW;CAEf,MAAM,OAAO,YAAY;EACvB,QAAA,QAAU;EACV,MAAM,UAAU,OAAA,QAAS;EACzB,IAAI,EAAE,mBAAmB,UAAU;EACnC,IAAI;GACF,MAAM;EACR,QAAQ;GACN,MAAA,QAAQ;EACV,UAAU;GACR,QAAA,QAAU;EACZ;CACF;;CAEA,MAAM,QAAQ,YAAY;EACxB,IAAI,YAAQ,QAAA,SAAW,MAAA,SAAS,SAAA,OAAc;EAC9C,WAAW;EACX,IAAI;GACF,MAAM,OAAO,MAAM,KAAK,QAAQ,MAAM;GACtC,IAAI,QAAQ,KAAK,MAAM,KAAK,OAAO,CAAC,CAAC,UAAM,OAAA,SAAc,CAAA,QAAA,SAAY,CAAA,MAAA,SAAU,CAAA,SAAA,OAC7E,MAAM,KAAK;EACf,UAAU;GACR,WAAW;EACb;CACF;CAEA,MAAM,OAAO,KAAK,eAAe,KAAK,MAAM,CAAC;CAC7C,gBAAgB,IAAI;CACpB,gBAAgB,KAAK,MAAM,CAAC;CAE5B,YACQ;EAAA,QAAA;EAAA,SAAA;EAAA,MAAA;CAAA,SACA,KAAK,SAAS,KAAK,CAC3B;CAEA,MAAM,cAAc;EAClB,MAAA,QAAQ;EACR,MAAW;CACb;CAEA,aAAa;EACX,MAAM,SAAS,MAAA,QACZ,UAAA,SAAa,OAAO,KAAK,aACxB,QAAA,QAAAC,YAAA,SAAA,EAAA,OAAA,UAAA,GAAA;GAAA,eAAA,CACQ,OAAO,KAAK,OAAO;GAAA,SAAA;EAAA,CAAA,IAC3B,SAAA,SAAY,aAAA,UAAiB,OAC/B,WAAU,aAAA,KAAa,IAAC,aAAA,QAGtB,OAAO,KAAK,SAEZ;EACJ,OAAAA,YAAA,OAEQ,WAAkB,CAAC,GAAG,MAAM;GAC9B,MAAM;GACN,aAAa,QAAA,QAAU,SAAS;EAClC,CAAC,GAAC,CAAA,SAAA,OAAAA,YAAA,OAAAC,cAII,WACF,EAAE,IAAI,CAAC,WAAW,QAAQ,MAAA,SAAS,WAAW,KAAK,EAAE,GAAC,YAAA,OAGtD,MAAA,QAAQ;GAAE,MAAM;GAAU,SAAS;EAAM,IAAI,CAAC,CAChD,GAAC,EAAA,OAAA,OAAA,OAAA,OAAA,MACK,SAAmB,SAAS,MAAK,CAAA,GAAA,CAEtC,MAAM,CAAA,CAAA,CAAA;CAIf;AACF,GAAC;CAAA,MAAA;CAAA,OAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;CAAA;AAAA,CACH"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';
|
|
2
|
+
import { type VNodeChild } from 'vue';
|
|
3
|
+
import { type IconData } from '../base/Icon';
|
|
4
|
+
import { type PartProps } from '../utils/props';
|
|
5
|
+
/** 右边的操作 */
|
|
6
|
+
export interface NoticeBarModes {
|
|
7
|
+
/** 关闭按钮 */
|
|
8
|
+
closeable: unknown;
|
|
9
|
+
/** 箭头:整条可点 */
|
|
10
|
+
link: unknown;
|
|
11
|
+
}
|
|
12
|
+
/** 未声明的属性落到根元素(div)上 */
|
|
13
|
+
export interface NoticeBarProps extends Omit<PartProps<'div', 'role'>, 'onClose'> {
|
|
14
|
+
/** 文字(与 children 二选一) */
|
|
15
|
+
text?: VNodeChild;
|
|
16
|
+
/** 右边的操作 */
|
|
17
|
+
mode?: keyof NoticeBarModes;
|
|
18
|
+
/**
|
|
19
|
+
* 色调
|
|
20
|
+
* @default 'warning'
|
|
21
|
+
*/
|
|
22
|
+
tone?: 'warning' | 'accent' | 'danger' | 'success';
|
|
23
|
+
/**
|
|
24
|
+
* 前面的图标;false 不显示
|
|
25
|
+
* @default Volume2
|
|
26
|
+
*/
|
|
27
|
+
icon?: IconData | false;
|
|
28
|
+
/** 多行显示,不滚动 */
|
|
29
|
+
wrapable?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* 滚动的速度(px/s)
|
|
32
|
+
* @default 60
|
|
33
|
+
*/
|
|
34
|
+
speed?: number;
|
|
35
|
+
/** 点了关闭(关闭后不再显示) */
|
|
36
|
+
onClose?: () => void;
|
|
37
|
+
/** 文字 */
|
|
38
|
+
children?: VNodeChild;
|
|
39
|
+
/** 文字那一栏的部件属性 */
|
|
40
|
+
propsContent?: PartProps<'div'>;
|
|
41
|
+
}
|
|
42
|
+
/** NoticeBar 的样式:root、各色调、icon、viewport、text、scrolling、wrap、action */
|
|
43
|
+
export declare const noticeBarStyles: Readonly<{
|
|
44
|
+
accent: css.CompiledStyles;
|
|
45
|
+
action: css.CompiledStyles;
|
|
46
|
+
danger: css.CompiledStyles;
|
|
47
|
+
icon: css.CompiledStyles;
|
|
48
|
+
root: css.CompiledStyles;
|
|
49
|
+
scrolling: css.CompiledStyles;
|
|
50
|
+
success: css.CompiledStyles;
|
|
51
|
+
text: css.CompiledStyles;
|
|
52
|
+
viewport: css.CompiledStyles;
|
|
53
|
+
warning: css.CompiledStyles;
|
|
54
|
+
wrap: css.CompiledStyles;
|
|
55
|
+
}>;
|
|
56
|
+
/** 通知栏(div[role=alert] > 图标 + 文字 + 操作) */
|
|
57
|
+
export declare const NoticeBar: import("@zerodep-dev/vue-tsx-pro-tsx").TsxComponent<NoticeBarProps>;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { useConfig } from "../config/context.js";
|
|
2
|
+
import { hasContent, mergeAttrs } from "../utils/props.js";
|
|
3
|
+
import { Icon } from "../base/Icon.js";
|
|
4
|
+
import { useHost } from "../utils/host.js";
|
|
5
|
+
import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
|
|
6
|
+
import { _component, childrenProp, mergeJsxProps, readonlyProp, restProps } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
7
|
+
import { createVNode, onMounted, onUpdated, ref } from "vue";
|
|
8
|
+
import { ChevronRight, Volume2, X } from "@lucide/icons";
|
|
9
|
+
//#region src/display/NoticeBar.tsx
|
|
10
|
+
/**
|
|
11
|
+
* 通知栏:页面顶部一条浅色的公告,前面一个喇叭;文字放不下时从右往左滚动,可关闭或带箭头点进详情。
|
|
12
|
+
*
|
|
13
|
+
* <NoticeBar>双十一活动 11 月 1 日开始,全场满 300 减 50</NoticeBar>
|
|
14
|
+
* <NoticeBar mode="closeable" tone="danger">账户存在风险,请尽快完善实名信息</NoticeBar>
|
|
15
|
+
* <NoticeBar wrapable>多行显示,不滚动……</NoticeBar>
|
|
16
|
+
*/
|
|
17
|
+
/** 右边的操作 */
|
|
18
|
+
/** 未声明的属性落到根元素(div)上 */
|
|
19
|
+
var marquee = css.keyframes({
|
|
20
|
+
from: { transform: "translateX(0)" },
|
|
21
|
+
to: { transform: "translateX(-100%)" }
|
|
22
|
+
});
|
|
23
|
+
/** NoticeBar 的样式:root、各色调、icon、viewport、text、scrolling、wrap、action */
|
|
24
|
+
var noticeBarStyles = css.create({
|
|
25
|
+
root: {
|
|
26
|
+
boxSizing: "border-box",
|
|
27
|
+
display: "flex",
|
|
28
|
+
alignItems: "center",
|
|
29
|
+
gap: "_sm",
|
|
30
|
+
minHeight: "2.6em",
|
|
31
|
+
paddingBlock: "0.4em",
|
|
32
|
+
paddingInline: "_lg",
|
|
33
|
+
fontSize: "_sm",
|
|
34
|
+
lineHeight: "1.5"
|
|
35
|
+
},
|
|
36
|
+
warning: {
|
|
37
|
+
color: "_warningText",
|
|
38
|
+
backgroundColor: "_warningSoft"
|
|
39
|
+
},
|
|
40
|
+
accent: {
|
|
41
|
+
color: "_accentText",
|
|
42
|
+
backgroundColor: "_accentSoft"
|
|
43
|
+
},
|
|
44
|
+
danger: {
|
|
45
|
+
color: "_dangerText",
|
|
46
|
+
backgroundColor: "_dangerSoft"
|
|
47
|
+
},
|
|
48
|
+
success: {
|
|
49
|
+
color: "_successText",
|
|
50
|
+
backgroundColor: "_successSoft"
|
|
51
|
+
},
|
|
52
|
+
icon: {
|
|
53
|
+
flex: "none",
|
|
54
|
+
fontSize: "1.15em"
|
|
55
|
+
},
|
|
56
|
+
viewport: {
|
|
57
|
+
position: "relative",
|
|
58
|
+
flex: "1 1 auto",
|
|
59
|
+
minWidth: 0,
|
|
60
|
+
overflow: "hidden"
|
|
61
|
+
},
|
|
62
|
+
text: {
|
|
63
|
+
display: "inline-block",
|
|
64
|
+
whiteSpace: "nowrap"
|
|
65
|
+
},
|
|
66
|
+
scrolling: {
|
|
67
|
+
animationName: marquee,
|
|
68
|
+
animationTimingFunction: "linear",
|
|
69
|
+
animationIterationCount: {
|
|
70
|
+
default: "infinite",
|
|
71
|
+
_reducedMotion: 0
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
wrap: {
|
|
75
|
+
whiteSpace: "normal",
|
|
76
|
+
overflowWrap: "anywhere"
|
|
77
|
+
},
|
|
78
|
+
action: {
|
|
79
|
+
flex: "none",
|
|
80
|
+
display: "inline-flex",
|
|
81
|
+
padding: 0,
|
|
82
|
+
margin: 0,
|
|
83
|
+
borderWidth: 0,
|
|
84
|
+
backgroundColor: "transparent",
|
|
85
|
+
color: "inherit",
|
|
86
|
+
fontSize: "1.15em",
|
|
87
|
+
cursor: "pointer"
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
/** 通知栏(div[role=alert] > 图标 + 文字 + 操作) */
|
|
91
|
+
var NoticeBar = /*#__PURE__*/ _component((_props, _ctx) => {
|
|
92
|
+
const _cache = [];
|
|
93
|
+
const text = readonlyProp(_props, "text");
|
|
94
|
+
const mode = readonlyProp(_props, "mode");
|
|
95
|
+
const tone = readonlyProp(_props, "tone", "warning");
|
|
96
|
+
const icon = readonlyProp(_props, "icon", () => Volume2);
|
|
97
|
+
const wrapable = readonlyProp(_props, "wrapable", false);
|
|
98
|
+
const speed = readonlyProp(_props, "speed", 60);
|
|
99
|
+
const onClose = readonlyProp(_props, "onClose");
|
|
100
|
+
const children = childrenProp(_props);
|
|
101
|
+
const propsContent = readonlyProp(_props, "propsContent");
|
|
102
|
+
const rest = restProps(_props, _ctx, false);
|
|
103
|
+
const config = useConfig();
|
|
104
|
+
const host = useHost();
|
|
105
|
+
let closed = ref(false);
|
|
106
|
+
let scroll = ref(null);
|
|
107
|
+
let viewport = null;
|
|
108
|
+
let content = null;
|
|
109
|
+
const measure = async () => {
|
|
110
|
+
if (closed.value) return;
|
|
111
|
+
if (wrapable.value) return void (scroll.value = null);
|
|
112
|
+
const [box, inner] = await Promise.all([host.measure(viewport), host.measure(content)]);
|
|
113
|
+
const width = (inner?.width ?? 0) - (scroll.value?.viewport ?? 0);
|
|
114
|
+
const next = box && width > box.width ? {
|
|
115
|
+
viewport: box.width,
|
|
116
|
+
text: width
|
|
117
|
+
} : null;
|
|
118
|
+
if (next?.viewport !== scroll.value?.viewport || next?.text !== scroll.value?.text) scroll.value = next;
|
|
119
|
+
};
|
|
120
|
+
onMounted(() => void measure());
|
|
121
|
+
onUpdated(() => void measure());
|
|
122
|
+
return () => {
|
|
123
|
+
if (closed.value) return null;
|
|
124
|
+
const body = text.value ?? children.value;
|
|
125
|
+
return createVNode("div", mergeAttrs({ sx: [noticeBarStyles.root, noticeBarStyles[tone.value]] }, rest, { role: "alert" }), [
|
|
126
|
+
icon.value && createVNode(Icon, {
|
|
127
|
+
"icon": icon.value,
|
|
128
|
+
"sx": noticeBarStyles.icon
|
|
129
|
+
}, null),
|
|
130
|
+
createVNode("div", mergeJsxProps(mergeAttrs({ sx: noticeBarStyles.viewport }, propsContent.value), { "ref": _cache[0] || (_cache[0] = (node) => viewport = node) }), [createVNode("span", mergeJsxProps(mergeAttrs({
|
|
131
|
+
sx: [
|
|
132
|
+
noticeBarStyles.text,
|
|
133
|
+
wrapable.value && noticeBarStyles.wrap,
|
|
134
|
+
scroll.value && noticeBarStyles.scrolling
|
|
135
|
+
],
|
|
136
|
+
style: scroll.value ? {
|
|
137
|
+
paddingInlineStart: `${scroll.value.viewport}px`,
|
|
138
|
+
animationDuration: `${(scroll.value.viewport + scroll.value.text) / speed.value}s`
|
|
139
|
+
} : void 0
|
|
140
|
+
}), { "ref": _cache[1] || (_cache[1] = (node) => content = node) }), [hasContent(body) ? body : null])]),
|
|
141
|
+
mode.value === "closeable" && createVNode("button", mergeJsxProps(mergeAttrs({ sx: noticeBarStyles.action }), {
|
|
142
|
+
"type": "button",
|
|
143
|
+
"aria-label": config.lang.close,
|
|
144
|
+
"onClick": _cache[2] || (_cache[2] = (event) => {
|
|
145
|
+
event.stopPropagation();
|
|
146
|
+
closed.value = true;
|
|
147
|
+
onClose.value?.();
|
|
148
|
+
})
|
|
149
|
+
}), [createVNode(Icon, { "icon": X }, null)]),
|
|
150
|
+
mode.value === "link" && createVNode(Icon, {
|
|
151
|
+
"icon": ChevronRight,
|
|
152
|
+
"sx": noticeBarStyles.icon
|
|
153
|
+
}, null)
|
|
154
|
+
]);
|
|
155
|
+
};
|
|
156
|
+
}, {
|
|
157
|
+
name: "NoticeBar",
|
|
158
|
+
props: [
|
|
159
|
+
"text",
|
|
160
|
+
"mode",
|
|
161
|
+
"tone",
|
|
162
|
+
"icon",
|
|
163
|
+
"wrapable",
|
|
164
|
+
"speed",
|
|
165
|
+
"onClose",
|
|
166
|
+
"propsContent"
|
|
167
|
+
]
|
|
168
|
+
});
|
|
169
|
+
//#endregion
|
|
170
|
+
export { NoticeBar, noticeBarStyles };
|
|
171
|
+
|
|
172
|
+
//# sourceMappingURL=NoticeBar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NoticeBar.js","names":["_vtp_readonlyProp","_vtp_childrenProp","_vtp_restProps","_vue_ref","_createVNode","_mergeProps"],"sources":["../../src/display/NoticeBar.tsx"],"sourcesContent":["/**\n * 通知栏:页面顶部一条浅色的公告,前面一个喇叭;文字放不下时从右往左滚动,可关闭或带箭头点进详情。\n *\n * <NoticeBar>双十一活动 11 月 1 日开始,全场满 300 减 50</NoticeBar>\n * <NoticeBar mode=\"closeable\" tone=\"danger\">账户存在风险,请尽快完善实名信息</NoticeBar>\n * <NoticeBar wrapable>多行显示,不滚动……</NoticeBar>\n */\nimport { ChevronRight, Volume2, X } from '@lucide/icons';\nimport { _component } from '@zerodep-dev/vue-tsx-pro-tsx';\nimport { css } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport { onMounted, onUpdated, type VNodeChild } from 'vue';\nimport { Icon, type IconData } from '../base/Icon';\nimport { useConfig } from '../config/context';\nimport { useHost } from '../utils/host';\nimport { hasContent, mergeAttrs, type PartProps } from '../utils/props';\n\n/** 右边的操作 */\nexport interface NoticeBarModes {\n /** 关闭按钮 */\n closeable: unknown;\n /** 箭头:整条可点 */\n link: unknown;\n}\n\n/** 未声明的属性落到根元素(div)上 */\nexport interface NoticeBarProps extends Omit<PartProps<'div', 'role'>, 'onClose'> {\n /** 文字(与 children 二选一) */\n text?: VNodeChild;\n /** 右边的操作 */\n mode?: keyof NoticeBarModes;\n /**\n * 色调\n * @default 'warning'\n */\n tone?: 'warning' | 'accent' | 'danger' | 'success';\n /**\n * 前面的图标;false 不显示\n * @default Volume2\n */\n icon?: IconData | false;\n /** 多行显示,不滚动 */\n wrapable?: boolean;\n /**\n * 滚动的速度(px/s)\n * @default 60\n */\n speed?: number;\n /** 点了关闭(关闭后不再显示) */\n onClose?: () => void;\n /** 文字 */\n children?: VNodeChild;\n /** 文字那一栏的部件属性 */\n propsContent?: PartProps<'div'>;\n}\n\nconst marquee = css.keyframes({\n from: { transform: 'translateX(0)' },\n to: { transform: 'translateX(-100%)' },\n});\n\n/** NoticeBar 的样式:root、各色调、icon、viewport、text、scrolling、wrap、action */\nexport const noticeBarStyles = css.create({\n root: {\n boxSizing: 'border-box',\n display: 'flex',\n alignItems: 'center',\n gap: '_sm',\n minHeight: '2.6em',\n paddingBlock: '0.4em',\n paddingInline: '_lg',\n fontSize: '_sm',\n lineHeight: '1.5',\n },\n warning: { color: '_warningText', backgroundColor: '_warningSoft' },\n accent: { color: '_accentText', backgroundColor: '_accentSoft' },\n danger: { color: '_dangerText', backgroundColor: '_dangerSoft' },\n success: { color: '_successText', backgroundColor: '_successSoft' },\n icon: { flex: 'none', fontSize: '1.15em' },\n viewport: { position: 'relative', flex: '1 1 auto', minWidth: 0, overflow: 'hidden' },\n text: { display: 'inline-block', whiteSpace: 'nowrap' },\n // 滚动时:左边留出整个可视宽度(从右边进来),动画移动自己的全部宽度\n scrolling: {\n animationName: marquee,\n animationTimingFunction: 'linear',\n animationIterationCount: { default: 'infinite', _reducedMotion: 0 },\n },\n wrap: { whiteSpace: 'normal', overflowWrap: 'anywhere' },\n action: {\n flex: 'none',\n display: 'inline-flex',\n padding: 0,\n margin: 0,\n borderWidth: 0,\n backgroundColor: 'transparent',\n color: 'inherit',\n fontSize: '1.15em',\n cursor: 'pointer',\n },\n});\n\n/** 通知栏(div[role=alert] > 图标 + 文字 + 操作) */\nexport const NoticeBar = _component(\n ({\n text,\n mode,\n tone = 'warning',\n icon = Volume2,\n wrapable = false,\n speed = 60,\n onClose,\n children,\n propsContent,\n ...rest\n }: NoticeBarProps) => {\n const config = useConfig();\n const host = useHost();\n let closed = _state(false);\n // 放不下时的滚动:可视宽度与文字宽度(px)\n let scroll = _state<{ viewport: number; text: number } | null>(null);\n let viewport: unknown = null;\n let content: unknown = null;\n const measure = async () => {\n // 关闭后节点已经卸掉,不再量\n if (closed) return;\n if (wrapable) return void (scroll = null);\n const [box, inner] = await Promise.all([host.measure(viewport), host.measure(content)]);\n // 滚动时文字左边加了可视宽度的内边距,量到的宽度要减掉\n const width = (inner?.width ?? 0) - (scroll?.viewport ?? 0);\n const next = box && width > box.width ? { viewport: box.width, text: width } : null;\n // 量出来没变就不赋值:否则又触发一次渲染、再量一次,停不下来\n if (next?.viewport !== scroll?.viewport || next?.text !== scroll?.text) scroll = next;\n };\n // 文字、children 换了都会重新渲染,渲染完再量(children 是插槽,不能在渲染函数外读)\n onMounted(() => void measure());\n onUpdated(() => void measure());\n\n return () => {\n if (closed) return null;\n const body = text ?? children;\n return (\n <div\n {...mergeAttrs<'div'>({ sx: [noticeBarStyles.root, noticeBarStyles[tone]] }, rest, {\n role: 'alert',\n })}\n >\n {icon && <Icon icon={icon} sx={noticeBarStyles.icon} />}\n <div\n {...mergeAttrs<'div'>({ sx: noticeBarStyles.viewport }, propsContent)}\n ref={(node: unknown) => (viewport = node)}\n >\n <span\n {...mergeAttrs<'span'>({\n sx: [\n noticeBarStyles.text,\n wrapable && noticeBarStyles.wrap,\n scroll && noticeBarStyles.scrolling,\n ],\n style: scroll\n ? {\n paddingInlineStart: `${scroll.viewport}px`,\n animationDuration: `${(scroll.viewport + scroll.text) / speed}s`,\n }\n : undefined,\n })}\n ref={(node: unknown) => (content = node)}\n >\n {hasContent(body) ? body : null}\n </span>\n </div>\n {mode === 'closeable' && (\n <button\n {...mergeAttrs<'button'>({ sx: noticeBarStyles.action })}\n type=\"button\"\n aria-label={config.lang.close}\n onClick={(event: Event) => {\n event.stopPropagation();\n closed = true;\n onClose?.();\n }}\n >\n <Icon icon={X} />\n </button>\n )}\n {mode === 'link' && <Icon icon={ChevronRight} sx={noticeBarStyles.icon} />}\n </div>\n );\n };\n },\n);\n"],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
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 StepStatuses {
|
|
6
|
+
/** 已完成:对勾 */
|
|
7
|
+
done: unknown;
|
|
8
|
+
/** 进行中:实心的主色圆点 */
|
|
9
|
+
process: unknown;
|
|
10
|
+
/** 未开始:灰色圆点 */
|
|
11
|
+
wait: unknown;
|
|
12
|
+
/** 出错:叉 */
|
|
13
|
+
error: unknown;
|
|
14
|
+
}
|
|
15
|
+
/** 一步 */
|
|
16
|
+
export interface StepItem {
|
|
17
|
+
/** 标题 */
|
|
18
|
+
title: VNodeChild;
|
|
19
|
+
/** 说明(竖排时显示在标题下面) */
|
|
20
|
+
description?: VNodeChild;
|
|
21
|
+
/** 状态;不给时按 active 算 */
|
|
22
|
+
status?: keyof StepStatuses;
|
|
23
|
+
}
|
|
24
|
+
/** 未声明的属性落到根元素(div)上 */
|
|
25
|
+
export interface StepsProps extends PartProps<'div', 'role'> {
|
|
26
|
+
/** 各步 */
|
|
27
|
+
items: StepItem[];
|
|
28
|
+
/**
|
|
29
|
+
* 当前是第几步(从 0 开始):之前的是已完成,这一步是进行中
|
|
30
|
+
* @default 0
|
|
31
|
+
*/
|
|
32
|
+
active?: number;
|
|
33
|
+
/**
|
|
34
|
+
* 方向
|
|
35
|
+
* @default 'horizontal'
|
|
36
|
+
*/
|
|
37
|
+
direction?: 'horizontal' | 'vertical';
|
|
38
|
+
/** 每一步的部件属性 */
|
|
39
|
+
propsItem?: PartProps<'div'>;
|
|
40
|
+
}
|
|
41
|
+
/** Steps 的样式 */
|
|
42
|
+
export declare const stepsStyles: Readonly<{
|
|
43
|
+
body: css.CompiledStyles;
|
|
44
|
+
description: css.CompiledStyles;
|
|
45
|
+
done: css.CompiledStyles;
|
|
46
|
+
dot: css.CompiledStyles;
|
|
47
|
+
error: css.CompiledStyles;
|
|
48
|
+
item: css.CompiledStyles;
|
|
49
|
+
itemVertical: css.CompiledStyles;
|
|
50
|
+
line: css.CompiledStyles;
|
|
51
|
+
lineVertical: css.CompiledStyles;
|
|
52
|
+
process: css.CompiledStyles;
|
|
53
|
+
root: css.CompiledStyles;
|
|
54
|
+
title: css.CompiledStyles;
|
|
55
|
+
vertical: css.CompiledStyles;
|
|
56
|
+
wait: css.CompiledStyles;
|
|
57
|
+
}>;
|
|
58
|
+
/** 步骤条(div[role=list] > 各步) */
|
|
59
|
+
export declare const Steps: import("@zerodep-dev/vue-tsx-pro-tsx").TsxComponent<StepsProps>;
|