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.
@@ -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(data_1.cityData)) {
24
- for (const item of data_1.cityData[letter]) {
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
- const letters = (0, react_1.useMemo)(() => Object.keys(data_1.cityData), []);
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
- return keyword.trim() ? (0, search_1.searchCity)(keyword) : null;
87
- }, [keyword, composing]);
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() }), data_1.cityData[k].map((item) => ((0, jsx_runtime_1.jsx)(Clickable_1.Clickable, { css: style.item, onClick: () => handleSelect(item), children: item.name }, item.code)))] }, k));
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
- // iOS 风格设计变量
9
- const textPrimary = "#000000";
10
- const textSecondary = "#3c3c43"; // iOS secondaryLabel
11
- const textTertiary = "#8e8e93"; // iOS tertiaryLabel / placeholder
8
+ // 设计变量
9
+ const textPrimary = "#1f2328";
10
+ const textSecondary = "#6b7280";
11
+ const textTertiary = "#9ca3af";
12
12
  const bgPage = "#ffffff";
13
- const bgSubtle = "rgba(120,120,128,.12)"; // iOS quaternary fill
14
- const bgGrouped = "#f2f2f7"; // iOS systemGroupedBackground
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: "0 .3rem .3rem",
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: ".12rem .3rem .06rem",
167
+ padding: ".08rem .3rem",
166
168
  fontSize: ".22rem",
167
- fontWeight: 500,
168
- color: textTertiary,
169
+ fontWeight: 600,
170
+ color: textSecondary,
169
171
  letterSpacing: ".02rem",
170
172
  textTransform: "uppercase",
171
- backgroundColor: bgGrouped,
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
- // iOS 风格设计变量
9
- const textPrimary = "#000000";
10
- const textSecondary = "#3c3c43"; // iOS secondaryLabel
11
- const textTertiary = "#8e8e93"; // iOS tertiaryLabel
8
+ // CitySelect 一致的设计变量(带线条风格)
9
+ const textPrimary = "#1f2328";
10
+ const textSecondary = "#6b7280";
11
+ const textTertiary = "#9ca3af";
12
12
  const bgPage = "#ffffff";
13
- const bgSubtle = "rgba(120,120,128,.12)"; // iOS quaternary fill
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 ? ".28rem" : "0";
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
- // iOS 风标题栏:底部 hairline 与下方 body 做轻量区块分隔
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: "1px solid rgba(60,60,67,.18)",
43
+ borderBottom: `1px solid ${border}`,
43
44
  }),
44
45
  title: (0, react_1.css)({
45
46
  flex: 1,
46
47
  textAlign: "center",
47
- fontSize: ".32rem",
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: ".3rem",
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: 600,
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
- // iOS 风选中背景:柔和的 quaternary fill、充足圆角
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: textPrimary,
122
- fontWeight: 500,
124
+ color: primary,
125
+ fontWeight: 600,
123
126
  }),
124
127
  spacer: (0, react_1.css)({
125
128
  height: `${exports.ITEM_HEIGHT_REM * 2}rem`,