clxx 3.0.0 → 3.0.2
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/README.md +6 -3
- package/build/CitySelect/data.d.ts +1 -1
- package/build/CitySelect/data.js +2277 -1674
- package/build/CitySelect/index.d.ts +2 -1
- package/build/CitySelect/index.js +35 -9
- package/build/CitySelect/style.js +15 -12
- package/build/DatePicker/style.js +17 -14
- package/build/RegionPicker/data.js +974 -992
- package/build/RegionPicker/index.d.ts +3 -2
- package/build/RegionPicker/index.js +29 -10
- package/build/RegionPicker/style.js +25 -21
- package/build/utils/createApp.d.ts +16 -2
- package/build/utils/createApp.js +142 -109
- package/package.json +1 -1
- package/test/src/city-select/index.jsx +28 -15
- package/test/src/region-picker/index.jsx +29 -21
|
@@ -12,6 +12,7 @@ export interface CitySelectProps {
|
|
|
12
12
|
onLetterChange?: (letter: string) => void;
|
|
13
13
|
getLocation?: () => string | null | undefined | Promise<string | null | undefined>;
|
|
14
14
|
primary?: string;
|
|
15
|
+
taiwanHKMacau?: boolean;
|
|
15
16
|
}
|
|
16
17
|
export declare function CitySelect(props: CitySelectProps): import("@emotion/react/jsx-runtime").JSX.Element;
|
|
17
|
-
export declare function showCitySelect(options?: Pick<CitySelectProps, "onSelect" | "onLetterChange" | "getLocation" | "primary">): void;
|
|
18
|
+
export declare function showCitySelect(options?: Pick<CitySelectProps, "onSelect" | "onLetterChange" | "getLocation" | "primary" | "taiwanHKMacau">): void;
|
|
@@ -11,17 +11,23 @@ const style_1 = require("./style");
|
|
|
11
11
|
const Col_1 = require("../Flex/Col");
|
|
12
12
|
const Row_1 = require("../Flex/Row");
|
|
13
13
|
const Clickable_1 = require("../Clickable");
|
|
14
|
+
// 港澳台对应的省份 code(台湾、香港、澳门)
|
|
15
|
+
const HK_MO_TW_PCODES = new Set([
|
|
16
|
+
"710000",
|
|
17
|
+
"810000",
|
|
18
|
+
"820000",
|
|
19
|
+
]);
|
|
14
20
|
// 在 cityData 中按 code 或 name 查找城市
|
|
15
21
|
// name 匹配时允许省略末尾的"市",如"北京" 匹配 "北京市"
|
|
16
|
-
function findCity(key) {
|
|
22
|
+
function findCity(source, key) {
|
|
17
23
|
if (!key)
|
|
18
24
|
return null;
|
|
19
25
|
const k = key.trim();
|
|
20
26
|
if (!k)
|
|
21
27
|
return null;
|
|
22
28
|
const kNoCity = k.endsWith("市") ? k.slice(0, -1) : k;
|
|
23
|
-
for (const letter of Object.keys(
|
|
24
|
-
for (const item of
|
|
29
|
+
for (const letter of Object.keys(source)) {
|
|
30
|
+
for (const item of source[letter]) {
|
|
25
31
|
if (item.code === k)
|
|
26
32
|
return item;
|
|
27
33
|
const nameNoCity = item.name.endsWith("市")
|
|
@@ -35,14 +41,29 @@ function findCity(key) {
|
|
|
35
41
|
}
|
|
36
42
|
// 弹出与滑入/滑出动画由 showDialog (pullLeft) 接管
|
|
37
43
|
function CitySelect(props) {
|
|
38
|
-
const { onClose, onSelect, onLetterChange, getLocation, primary = style_1.DEFAULT_PRIMARY, } = props;
|
|
44
|
+
const { onClose, onSelect, onLetterChange, getLocation, primary = style_1.DEFAULT_PRIMARY, taiwanHKMacau = false, } = props;
|
|
39
45
|
const style = (0, react_1.useMemo)(() => (0, style_1.createStyle)(primary), [primary]);
|
|
40
|
-
|
|
46
|
+
// 过滤后的城市数据:当 taiwanHKMacau=false 时排除港澳台;
|
|
47
|
+
// 过滤后为空的字母档位会从指引中移除。仅在 taiwanHKMacau 变化时重建。
|
|
48
|
+
const filteredCityData = (0, react_1.useMemo)(() => {
|
|
49
|
+
if (taiwanHKMacau)
|
|
50
|
+
return data_1.cityData;
|
|
51
|
+
const out = {};
|
|
52
|
+
for (const letter of Object.keys(data_1.cityData)) {
|
|
53
|
+
const arr = data_1.cityData[letter].filter((it) => !HK_MO_TW_PCODES.has(it.pcode));
|
|
54
|
+
if (arr.length > 0)
|
|
55
|
+
out[letter] = arr;
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
58
|
+
}, [taiwanHKMacau]);
|
|
59
|
+
const letters = (0, react_1.useMemo)(() => Object.keys(filteredCityData), [filteredCityData]);
|
|
41
60
|
// 定位解析结果:null 表示尚未解析或失败/未匹配;非空时展示快捷入口
|
|
42
61
|
const [locatedCity, setLocatedCity] = (0, react_1.useState)(null);
|
|
43
62
|
// 首次挂载时调用一次外部定位;异步失败或匹配不到均保持不展示
|
|
44
63
|
const getLocationRef = (0, react_1.useRef)(getLocation);
|
|
45
64
|
getLocationRef.current = getLocation;
|
|
65
|
+
const filteredCityDataRef = (0, react_1.useRef)(filteredCityData);
|
|
66
|
+
filteredCityDataRef.current = filteredCityData;
|
|
46
67
|
(0, react_1.useEffect)(() => {
|
|
47
68
|
const fn = getLocationRef.current;
|
|
48
69
|
if (!fn)
|
|
@@ -53,7 +74,7 @@ function CitySelect(props) {
|
|
|
53
74
|
.then((key) => {
|
|
54
75
|
if (cancelled)
|
|
55
76
|
return;
|
|
56
|
-
const city = findCity(key !== null && key !== void 0 ? key : undefined);
|
|
77
|
+
const city = findCity(filteredCityDataRef.current, key !== null && key !== void 0 ? key : undefined);
|
|
57
78
|
if (city)
|
|
58
79
|
setLocatedCity(city);
|
|
59
80
|
})
|
|
@@ -83,8 +104,13 @@ function CitySelect(props) {
|
|
|
83
104
|
const searchResult = (0, react_1.useMemo)(() => {
|
|
84
105
|
if (composing)
|
|
85
106
|
return null;
|
|
86
|
-
|
|
87
|
-
|
|
107
|
+
if (!keyword.trim())
|
|
108
|
+
return null;
|
|
109
|
+
const list = (0, search_1.searchCity)(keyword);
|
|
110
|
+
if (taiwanHKMacau)
|
|
111
|
+
return list;
|
|
112
|
+
return list.filter((it) => !HK_MO_TW_PCODES.has(it.pcode));
|
|
113
|
+
}, [keyword, composing, taiwanHKMacau]);
|
|
88
114
|
const isSearching = searchResult !== null;
|
|
89
115
|
// 用 ref 保存最新值,避免 effect 依赖变化而反复解绑/绑定
|
|
90
116
|
const lettersRef = (0, react_1.useRef)(letters);
|
|
@@ -287,7 +313,7 @@ function CitySelect(props) {
|
|
|
287
313
|
// 每个字母对应一个区块,包含该字母开头的城市列表
|
|
288
314
|
(0, jsx_runtime_1.jsxs)("div", { ref: (el) => {
|
|
289
315
|
sectionRefs.current[k] = el;
|
|
290
|
-
}, children: [(0, jsx_runtime_1.jsx)("div", { css: style.title, children: k.toUpperCase() }),
|
|
316
|
+
}, children: [(0, jsx_runtime_1.jsx)("div", { css: style.title, children: k.toUpperCase() }), filteredCityData[k].map((item) => ((0, jsx_runtime_1.jsx)(Clickable_1.Clickable, { css: style.item, onClick: () => handleSelect(item), children: item.name }, item.code)))] }, k));
|
|
291
317
|
}) }))] }), !isSearching && ((0, jsx_runtime_1.jsx)("div", { ref: sidebarRef, css: style.sidebar, children: letters.map((k) => ((0, jsx_runtime_1.jsx)("div", { css: [style.letter, activeLetter === k && style.letterActive], children: k.toUpperCase() }, k))) })), touching && activeLetter && !isSearching && ((0, jsx_runtime_1.jsx)("div", { css: style.bigLetter, children: activeLetter.toUpperCase() }))] }));
|
|
292
318
|
}
|
|
293
319
|
function showCitySelect(options = {}) {
|
|
@@ -5,13 +5,13 @@ exports.createStyle = createStyle;
|
|
|
5
5
|
const react_1 = require("@emotion/react");
|
|
6
6
|
const color_1 = require("../utils/color");
|
|
7
7
|
const theme_1 = require("../utils/theme");
|
|
8
|
-
//
|
|
9
|
-
const textPrimary = "#
|
|
10
|
-
const textSecondary = "#
|
|
11
|
-
const textTertiary = "#
|
|
8
|
+
// 设计变量
|
|
9
|
+
const textPrimary = "#1f2328";
|
|
10
|
+
const textSecondary = "#6b7280";
|
|
11
|
+
const textTertiary = "#9ca3af";
|
|
12
12
|
const bgPage = "#ffffff";
|
|
13
|
-
const bgSubtle = "
|
|
14
|
-
const
|
|
13
|
+
const bgSubtle = "#f5f6f8";
|
|
14
|
+
const border = "#e5e7eb";
|
|
15
15
|
// 根据 primary 色值生成一整套样式;primaryActive 由 primary 派生
|
|
16
16
|
function createStyle(primary) {
|
|
17
17
|
const primaryActive = (0, color_1.darken)(primary, 0.15);
|
|
@@ -81,7 +81,8 @@ function createStyle(primary) {
|
|
|
81
81
|
backgroundColor: bgPage,
|
|
82
82
|
}),
|
|
83
83
|
top: (0, react_1.css)({
|
|
84
|
-
padding: ".3rem",
|
|
84
|
+
padding: ".24rem .3rem",
|
|
85
|
+
borderBottom: `1px solid ${border}`,
|
|
85
86
|
"& > div": {
|
|
86
87
|
height: ".72rem",
|
|
87
88
|
backgroundColor: bgSubtle,
|
|
@@ -137,7 +138,8 @@ function createStyle(primary) {
|
|
|
137
138
|
locate: (0, react_1.css)({
|
|
138
139
|
display: "flex",
|
|
139
140
|
alignItems: "center",
|
|
140
|
-
padding: "
|
|
141
|
+
padding: ".2rem .23rem",
|
|
142
|
+
borderBottom: `1px solid ${border}`,
|
|
141
143
|
backgroundColor: bgPage,
|
|
142
144
|
transition: "background-color .12s",
|
|
143
145
|
"&:active": {
|
|
@@ -162,13 +164,13 @@ function createStyle(primary) {
|
|
|
162
164
|
color: primary,
|
|
163
165
|
}),
|
|
164
166
|
title: (0, react_1.css)({
|
|
165
|
-
padding: ".
|
|
167
|
+
padding: ".08rem .3rem",
|
|
166
168
|
fontSize: ".22rem",
|
|
167
|
-
fontWeight:
|
|
168
|
-
color:
|
|
169
|
+
fontWeight: 600,
|
|
170
|
+
color: textSecondary,
|
|
169
171
|
letterSpacing: ".02rem",
|
|
170
172
|
textTransform: "uppercase",
|
|
171
|
-
backgroundColor:
|
|
173
|
+
backgroundColor: bgSubtle,
|
|
172
174
|
position: "sticky",
|
|
173
175
|
top: 0,
|
|
174
176
|
zIndex: 1,
|
|
@@ -177,6 +179,7 @@ function createStyle(primary) {
|
|
|
177
179
|
padding: ".24rem .3rem",
|
|
178
180
|
fontSize: ".3rem",
|
|
179
181
|
color: textPrimary,
|
|
182
|
+
borderBottom: `1px solid ${border}`,
|
|
180
183
|
backgroundColor: bgPage,
|
|
181
184
|
transition: "background-color .12s",
|
|
182
185
|
"&:active": {
|
|
@@ -5,18 +5,19 @@ exports.createStyle = createStyle;
|
|
|
5
5
|
const react_1 = require("@emotion/react");
|
|
6
6
|
const color_1 = require("../utils/color");
|
|
7
7
|
const theme_1 = require("../utils/theme");
|
|
8
|
-
//
|
|
9
|
-
const textPrimary = "#
|
|
10
|
-
const textSecondary = "#
|
|
11
|
-
const textTertiary = "#
|
|
8
|
+
// 与 CitySelect 一致的设计变量(带线条风格)
|
|
9
|
+
const textPrimary = "#1f2328";
|
|
10
|
+
const textSecondary = "#6b7280";
|
|
11
|
+
const textTertiary = "#9ca3af";
|
|
12
12
|
const bgPage = "#ffffff";
|
|
13
|
-
const bgSubtle = "
|
|
13
|
+
const bgSubtle = "#f5f6f8";
|
|
14
|
+
const border = "#e5e7eb";
|
|
14
15
|
// 可见行数 = 5,单元高度 = .8rem
|
|
15
16
|
exports.ITEM_HEIGHT_REM = 0.8;
|
|
16
17
|
exports.VISIBLE_ROWS = 5;
|
|
17
18
|
function createStyle(primary, rounded = true) {
|
|
18
19
|
const primaryActive = (0, color_1.darken)(primary, 0.15);
|
|
19
|
-
const sheetRadius = rounded ? ".
|
|
20
|
+
const sheetRadius = rounded ? ".24rem" : "0";
|
|
20
21
|
const indicatorRadius = rounded ? ".12rem" : "0";
|
|
21
22
|
return {
|
|
22
23
|
// 内容容器:动画/全屏/居中由 Dialog 提供,这里只保留视觉与排版
|
|
@@ -32,19 +33,19 @@ function createStyle(primary, rounded = true) {
|
|
|
32
33
|
WebkitFontSmoothing: "antialiased",
|
|
33
34
|
MozOsxFontSmoothing: "grayscale",
|
|
34
35
|
}),
|
|
35
|
-
//
|
|
36
|
+
// 标题栏:底部 hairline 与 body 区分
|
|
36
37
|
header: (0, react_1.css)({
|
|
37
38
|
height: ".92rem",
|
|
38
39
|
display: "flex",
|
|
39
40
|
alignItems: "center",
|
|
40
41
|
justifyContent: "space-between",
|
|
41
42
|
padding: "0 .16rem",
|
|
42
|
-
borderBottom:
|
|
43
|
+
borderBottom: `1px solid ${border}`,
|
|
43
44
|
}),
|
|
44
45
|
title: (0, react_1.css)({
|
|
45
46
|
flex: 1,
|
|
46
47
|
textAlign: "center",
|
|
47
|
-
fontSize: ".
|
|
48
|
+
fontSize: ".3rem",
|
|
48
49
|
fontWeight: 600,
|
|
49
50
|
color: textPrimary,
|
|
50
51
|
letterSpacing: ".01rem",
|
|
@@ -52,7 +53,7 @@ function createStyle(primary, rounded = true) {
|
|
|
52
53
|
btn: (0, react_1.css)({
|
|
53
54
|
minWidth: "1.1rem",
|
|
54
55
|
padding: "0 .08rem",
|
|
55
|
-
fontSize: ".
|
|
56
|
+
fontSize: ".28rem",
|
|
56
57
|
fontWeight: 400,
|
|
57
58
|
lineHeight: ".92rem",
|
|
58
59
|
cursor: "pointer",
|
|
@@ -65,7 +66,7 @@ function createStyle(primary, rounded = true) {
|
|
|
65
66
|
}),
|
|
66
67
|
btnConfirm: (0, react_1.css)({
|
|
67
68
|
textAlign: "right",
|
|
68
|
-
fontWeight:
|
|
69
|
+
fontWeight: 500,
|
|
69
70
|
color: primary,
|
|
70
71
|
"&:active": { color: primaryActive, opacity: 0.65 },
|
|
71
72
|
}),
|
|
@@ -75,7 +76,7 @@ function createStyle(primary, rounded = true) {
|
|
|
75
76
|
height: `${exports.ITEM_HEIGHT_REM * exports.VISIBLE_ROWS}rem`,
|
|
76
77
|
padding: "0 .16rem .12rem",
|
|
77
78
|
}),
|
|
78
|
-
//
|
|
79
|
+
// 选中条:浅灰底 + 上下 hairline,与 CitySelect 列表观感一致
|
|
79
80
|
indicator: (0, react_1.css)({
|
|
80
81
|
position: "absolute",
|
|
81
82
|
left: ".16rem",
|
|
@@ -84,6 +85,8 @@ function createStyle(primary, rounded = true) {
|
|
|
84
85
|
height: `${exports.ITEM_HEIGHT_REM}rem`,
|
|
85
86
|
pointerEvents: "none",
|
|
86
87
|
backgroundColor: bgSubtle,
|
|
88
|
+
borderTop: `1px solid ${border}`,
|
|
89
|
+
borderBottom: `1px solid ${border}`,
|
|
87
90
|
borderRadius: indicatorRadius,
|
|
88
91
|
}),
|
|
89
92
|
column: (0, react_1.css)({
|
|
@@ -118,8 +121,8 @@ function createStyle(primary, rounded = true) {
|
|
|
118
121
|
transition: "color .18s ease",
|
|
119
122
|
}),
|
|
120
123
|
itemActive: (0, react_1.css)({
|
|
121
|
-
color:
|
|
122
|
-
fontWeight:
|
|
124
|
+
color: primary,
|
|
125
|
+
fontWeight: 600,
|
|
123
126
|
}),
|
|
124
127
|
spacer: (0, react_1.css)({
|
|
125
128
|
height: `${exports.ITEM_HEIGHT_REM * 2}rem`,
|