china-diff 1.0.1

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.
Files changed (52) hide show
  1. package/.gitattributes +1 -0
  2. package/.prettierignore +2 -0
  3. package/.prettierrc +5 -0
  4. package/README.md +1 -0
  5. package/build/css.ts +293 -0
  6. package/build/icons.ts +108 -0
  7. package/css/all.css +8 -0
  8. package/css/atomic/align.css +35 -0
  9. package/css/atomic/all.css +13 -0
  10. package/css/atomic/cursor.css +7 -0
  11. package/css/atomic/display.css +11 -0
  12. package/css/atomic/flex.css +124 -0
  13. package/css/atomic/grid.css +0 -0
  14. package/css/atomic/hidden.css +37 -0
  15. package/css/atomic/other.css +23 -0
  16. package/css/atomic/overflow.css +47 -0
  17. package/css/atomic/position.css +58 -0
  18. package/css/base.css +16 -0
  19. package/css/carousel.css +46 -0
  20. package/css/combobox.css +58 -0
  21. package/css/icon.css +7 -0
  22. package/icons/backward.svg +3 -0
  23. package/icons/close.svg +3 -0
  24. package/icons/dropdown.svg +3 -0
  25. package/icons/forward.svg +3 -0
  26. package/icons/toggle.svg +3 -0
  27. package/index.ts +1 -0
  28. package/jsx-runtime.d.ts +1 -0
  29. package/package.json +13 -0
  30. package/src/animate-scroll-to.ts +65 -0
  31. package/src/components/Carousel.tsx +299 -0
  32. package/src/components/CollapsiblePanel.tsx +139 -0
  33. package/src/components/ComboBox.tsx +163 -0
  34. package/src/components/Dialog.tsx +36 -0
  35. package/src/components/For.tsx +26 -0
  36. package/src/components/Icon.tsx +39 -0
  37. package/src/components/If.tsx +14 -0
  38. package/src/components/KeepAlive.tsx +26 -0
  39. package/src/components/Pulldown.tsx +157 -0
  40. package/src/components/Switch.tsx +49 -0
  41. package/src/dom.ts +137 -0
  42. package/src/http.ts +282 -0
  43. package/src/index.ts +68 -0
  44. package/src/jsx.ts +2 -0
  45. package/src/language.ts +34 -0
  46. package/src/layout.ts +89 -0
  47. package/src/location.ts +133 -0
  48. package/src/message.ts +290 -0
  49. package/src/reactive.ts +211 -0
  50. package/src/template.ts +23 -0
  51. package/tsconfig.json +16 -0
  52. package/vite-plugin.js +4 -0
@@ -0,0 +1,133 @@
1
+ import { isBrowser } from './dom';
2
+ import { reactive } from './reactive';
3
+
4
+ export interface Location {
5
+ /**
6
+ * 完整 URL
7
+ */
8
+ url: string;
9
+
10
+ /**
11
+ * 路径
12
+ */
13
+ path: string;
14
+
15
+ /**
16
+ * 查询参数
17
+ */
18
+ search: string;
19
+
20
+ /**
21
+ * hash
22
+ */
23
+ hash: string;
24
+
25
+ /**
26
+ * 参数
27
+ */
28
+ query: { readonly [key: string]: any };
29
+
30
+ /**
31
+ * 路径集合
32
+ */
33
+ paths: string[];
34
+
35
+ /**
36
+ * 路由到指定地址
37
+ *
38
+ * @param url 指定地址
39
+ * @param scrollTo 要滚动到的位置
40
+ */
41
+ routeTo(url: string, scrollTo?: [number, number]): void;
42
+ }
43
+
44
+ /**
45
+ * 当前地址
46
+ */
47
+ export const location: Location = reactive({
48
+ url: '',
49
+ path: '',
50
+ search: '',
51
+ hash: '',
52
+ query: {},
53
+ paths: [],
54
+ routeTo(url: string, scrollTo?: [number, number]) {
55
+ history.pushState(null, '', url || '');
56
+ routeTo();
57
+
58
+ if (isBrowser && scrollTo) {
59
+ window.scrollTo(scrollTo[0] | 0, scrollTo[1] | 0);
60
+ }
61
+ },
62
+ });
63
+
64
+ export const parseQuery = (search: string) => {
65
+ let query = {};
66
+ let items = search.slice(1).split('&');
67
+ let item;
68
+
69
+ for (let i = 0, l = items.length; i < l; i++) {
70
+ if ((item = items[i])) {
71
+ let index = item.indexOf('=');
72
+ let key = index > 0 ? item.slice(0, index) : item;
73
+ let value = index > 0 ? decodeURIComponent(item.slice(index + 1) || '') : '';
74
+ let oldValue = query[key];
75
+
76
+ if (oldValue === void 0) {
77
+ query[key] = value;
78
+ } else if (typeof oldValue !== 'string') {
79
+ oldValue.push(value);
80
+ } else {
81
+ query[key] = [oldValue, value];
82
+ }
83
+ }
84
+ }
85
+
86
+ return query;
87
+ };
88
+
89
+ /**
90
+ * 更新地址
91
+ *
92
+ * @param path 路径
93
+ * @param search 查询条件
94
+ * @param hash hash
95
+ */
96
+ export const updateURL = (path: string, search?: string, hash?: string) => {
97
+ location.url = path + (search || '') + (hash || '');
98
+ location.hash = hash;
99
+
100
+ if (location.path !== path || location.search !== search) {
101
+ location.path = path;
102
+ location.paths = path.match(/\/[^/]*/g) || [];
103
+ location.search = search;
104
+ location.query = search ? parseQuery(search) : {};
105
+ }
106
+ };
107
+
108
+ // 浏览器环境
109
+ const routeTo = isBrowser
110
+ ? (() => {
111
+ // 更新地址方法
112
+ const routeTo = () => {
113
+ let system = window.location;
114
+
115
+ updateURL(system.pathname, system.search, system.hash);
116
+ };
117
+
118
+ // 立即更新
119
+ routeTo();
120
+
121
+ // 侦听地址变化
122
+ window.addEventListener('popstate', () => routeTo(), true);
123
+ // window.addEventListener(
124
+ // 'hashchange',
125
+ // () => {
126
+ // location.hash = '';
127
+ // },
128
+ // true,
129
+ // );
130
+
131
+ return routeTo;
132
+ })()
133
+ : () => {};
package/src/message.ts ADDED
@@ -0,0 +1,290 @@
1
+ import { isBrowser } from './dom';
2
+
3
+ /**
4
+ * 订阅者集合
5
+ */
6
+ type SubscriberList = Array<[onmessage: (message: SubscribeMessage) => void, once?: boolean]>;
7
+
8
+ /**
9
+ * 返回结果方法名
10
+ */
11
+ const ONRETURN = Symbol('onreturn');
12
+
13
+ /**
14
+ * 复制对象
15
+ */
16
+ const assign = Object.assign;
17
+
18
+ /**
19
+ * 订阅集合
20
+ */
21
+ const subscribes: { [key: string]: SubscriberList } = Object.create(null);
22
+
23
+ /**
24
+ * 返回结果处理函数集合
25
+ */
26
+ const onreturnFns: Map<number, (result: unknown, error?: unknown) => void> = new Map();
27
+
28
+ /**
29
+ * 递增的回调 id
30
+ */
31
+ let returnIdInc = 1;
32
+
33
+ /**
34
+ * 分发消息
35
+ *
36
+ * @param event 消息事件
37
+ */
38
+ const dispatchMessage = (message: SubscribeMessage) => {
39
+ let list = subscribes[message.type];
40
+
41
+ // 发送消息
42
+ if (list) {
43
+ let length = list.length;
44
+ let index = -1;
45
+
46
+ for (let i = 0; i < length; i++) {
47
+ let item = list[i];
48
+
49
+ // 没有标记删除
50
+ if (item[0]) {
51
+ // 通知订阅者
52
+ item[0](message);
53
+
54
+ // 可多次执行
55
+ if (!item[1]) {
56
+ // 有删除
57
+ if (index >= 0) {
58
+ list[index++] = item;
59
+ }
60
+
61
+ continue;
62
+ }
63
+ }
64
+
65
+ // 记录第一个删除项
66
+ if (index < 0) {
67
+ index = i;
68
+ }
69
+ }
70
+
71
+ // 有删除的订阅
72
+ if (index >= 0 && index < length) {
73
+ list.splice(index);
74
+ }
75
+ }
76
+ };
77
+
78
+ /**
79
+ * 订阅消息
80
+ */
81
+ export interface SubscribeMessage<T = unknown, R = unknown> {
82
+ /**
83
+ * 消息类型
84
+ */
85
+ type: string;
86
+
87
+ /**
88
+ * 消息数据
89
+ */
90
+ data: T;
91
+
92
+ /**
93
+ * 发送消息窗口
94
+ */
95
+ source: Window;
96
+
97
+ /**
98
+ * 源地址(仅 sendMessageTo 有效)
99
+ */
100
+ origin: string;
101
+
102
+ /**
103
+ * 回调函数id(仅 sendMessageTo 有效)
104
+ */
105
+ returnId?: number;
106
+
107
+ /**
108
+ * 返回(仅 sendMessage 有效)
109
+ *
110
+ * @param result 返回结果
111
+ * @param error 错误信息
112
+ */
113
+ [ONRETURN]?: (result: R, error: string) => void;
114
+ }
115
+
116
+ /**
117
+ * 订阅消息
118
+ *
119
+ * @param type 消息类型
120
+ * @param onmessage 消息处理函数
121
+ * @param once 是否执行一次后自动注销
122
+ */
123
+ export const subscribe = <T = unknown, R = unknown>(
124
+ type: string,
125
+ onmessage: (message: SubscribeMessage<T, R>) => void,
126
+ once?: boolean
127
+ ) => {
128
+ let items = subscribes[type];
129
+
130
+ if (items) {
131
+ items.push([onmessage, once]);
132
+ } else {
133
+ subscribes[type] = [[onmessage, once]];
134
+ }
135
+ };
136
+
137
+ /**
138
+ * 取消订阅
139
+ *
140
+ * @param type 消息类型
141
+ * @param onmessage 消息处理函数
142
+ */
143
+ export const unsubscribe = <T = unknown, R = unknown>(
144
+ type: string,
145
+ onmessage: (message: SubscribeMessage<T, R>) => void
146
+ ) => {
147
+ let items = subscribes[type];
148
+
149
+ if (items) {
150
+ for (let i = items.length; i--; ) {
151
+ if (items[i][0] === onmessage) {
152
+ // 标记已删除
153
+ items[i][0] = null;
154
+ break;
155
+ }
156
+ }
157
+ }
158
+ };
159
+
160
+ /**
161
+ * 向当前窗口发送消息(同步执行)
162
+ *
163
+ * @param type 消息类型
164
+ * @param data 消息数据
165
+ * @param onreturn 返回结果处理函数(返回 true 时继续等待下一个返回结果,否则不再等待)
166
+ */
167
+ export const sendMessage = <T = unknown, R = unknown>(
168
+ type: string,
169
+ data: T,
170
+ onreturn?: (result: R, error?: string) => void | true
171
+ ) => {
172
+ let message = {
173
+ type,
174
+ data,
175
+ source: window,
176
+ origin: location.href,
177
+ } as SubscribeMessage;
178
+
179
+ if (onreturn) {
180
+ message[ONRETURN] = onreturn;
181
+ }
182
+
183
+ dispatchMessage(message);
184
+ };
185
+
186
+ /**
187
+ * 向指定窗口发送消息(使用 window.postMessage 发送,异步执行)
188
+ *
189
+ * @param window 目标窗口
190
+ * @param type 消息类型
191
+ * @param data 消息数据(要可序列化)
192
+ * @param onreturn 返回结果处理函数(返回 true 时继续等待下一个返回结果,否则不再等待)
193
+ */
194
+ export const sendMessageTo = <T = unknown, R = unknown>(
195
+ window: Window,
196
+ type: string,
197
+ data?: T,
198
+ onreturn?: (result: R, error?: string) => void | true
199
+ ) => {
200
+ let returnId;
201
+
202
+ if (typeof onreturn === 'function') {
203
+ // 添加到返回函数集合,Id 添加随机值防止猜测
204
+ onreturnFns.set((returnId = returnIdInc++ + Math.random()), onreturn);
205
+ }
206
+
207
+ window.postMessage(
208
+ {
209
+ type,
210
+ data,
211
+ returnId,
212
+ },
213
+ '*'
214
+ );
215
+ };
216
+
217
+ /**
218
+ * 返回消息结果
219
+ *
220
+ * @param message 订阅消息
221
+ * @param result 返回结果
222
+ * @param error 错误信息
223
+ */
224
+ export const returnMessageResult = <T = unknown, R = unknown>(
225
+ message: SubscribeMessage<T>,
226
+ result: R,
227
+ error?: string
228
+ ) => {
229
+ let returnId, onreturn;
230
+
231
+ if ((onreturn = message[ONRETURN])) {
232
+ try {
233
+ // 执行回调(返回 true 表示需要继续等待返回结果)
234
+ if (!onreturn(result, error)) {
235
+ message[ONRETURN] = void 0;
236
+ }
237
+ } catch {
238
+ // 出错时不再接收返回结果
239
+ message[ONRETURN] = void 0;
240
+ }
241
+ } else if ((returnId = message.returnId)) {
242
+ message.source.postMessage(
243
+ {
244
+ returnId,
245
+ result,
246
+ error,
247
+ },
248
+ '*'
249
+ );
250
+ }
251
+ };
252
+
253
+ /**
254
+ * 浏览器环境接收窗口消息
255
+ */
256
+ isBrowser &&
257
+ window.addEventListener(
258
+ 'message',
259
+ (event) => {
260
+ let message = event.data;
261
+ let returnId, onreturn;
262
+
263
+ // 有 type 字段才处理
264
+ if (message) {
265
+ if (message.type) {
266
+ // 需创建新的消息以免影响第三方消息处理
267
+ message = assign({}, message);
268
+ message.source = event.source;
269
+ message.origin = event.origin;
270
+
271
+ // 分发消息
272
+ dispatchMessage(message);
273
+ } else if ((returnId = message.returnId) && (onreturn = onreturnFns.get(returnId))) {
274
+ // 返回消息
275
+
276
+ try {
277
+ // 执行返回结果处理函数(返回 true 表示需要继续等待返回结果)
278
+ if (!onreturn(message.result, message.error)) {
279
+ // 删除返回结果处理函数
280
+ onreturnFns.delete(returnId);
281
+ }
282
+ } catch {
283
+ // 出错时不再接收返回结果
284
+ onreturnFns.delete(returnId);
285
+ }
286
+ }
287
+ }
288
+ },
289
+ true
290
+ );
@@ -0,0 +1,211 @@
1
+ import { Component, createEffect, createSignal, createUniqueId, lazy, untrack } from 'solid-js';
2
+
3
+ export const defineProperty = Object.defineProperty;
4
+ export const defineProperties = Object.defineProperties;
5
+ export const isArray = Array.isArray;
6
+
7
+ export interface ServerContext {
8
+ /**
9
+ * 异步等待集合
10
+ */
11
+ promises: Promise<any>[];
12
+ /**
13
+ * 已经获取的异步缓存
14
+ */
15
+ cache: Map<string, any>;
16
+ /**
17
+ * 需要 SSR 缓存的 key 集合
18
+ */
19
+ ssr: { [key: string]: any };
20
+ }
21
+
22
+ /**
23
+ * 当前服务端渲染上下文
24
+ */
25
+ let serverContext: ServerContext;
26
+
27
+ /**
28
+ * 设置当前服务端渲染上下文
29
+ *
30
+ * @param context 渲染上下文
31
+ */
32
+ export const setServerContext = (context: ServerContext) => {
33
+ serverContext = context;
34
+ };
35
+
36
+ class ReactiveArray {}
37
+
38
+ /**
39
+ * 创建响应式对象
40
+ *
41
+ * @param props 属性集
42
+ */
43
+ export const reactive = <T extends { [key: string]: any }>(props: T): T => {
44
+ let descriptors = Object.getOwnPropertyDescriptors(props);
45
+ let result = {};
46
+ let properties = {};
47
+
48
+ for (let name in descriptors) {
49
+ let descriptor = descriptors[name];
50
+ let get = descriptor.get;
51
+ let set = descriptor.set;
52
+
53
+ if (get) {
54
+ get = get.bind(result);
55
+
56
+ if (set) {
57
+ set = set.bind(result);
58
+ }
59
+ } else if (set) {
60
+ set = set.bind(result);
61
+ } else {
62
+ let value = props[name];
63
+
64
+ if (typeof value === 'object') {
65
+ if (isArray(value)) {
66
+ for (let i = value.length; i--; ) {
67
+ if (typeof value[i] === 'object') {
68
+ value[i] = reactive(value[i]);
69
+ }
70
+ }
71
+ } else {
72
+ value = reactive(value);
73
+ }
74
+ }
75
+
76
+ let signal = createSignal(value);
77
+
78
+ get = signal[0];
79
+ set = signal[1];
80
+ }
81
+
82
+ properties[name] = { get, set };
83
+ }
84
+
85
+ return defineProperties(result, properties) as T;
86
+ };
87
+
88
+ /**
89
+ * 观测响应式属性变化
90
+ *
91
+ * @param deps 依赖属性集
92
+ * @param callbackFn 变化时的回调函数
93
+ */
94
+ export const watch = <T extends unknown>(deps: () => T, callbackFn: (values: T) => void): void => {
95
+ let initialized;
96
+
97
+ createEffect(() => {
98
+ // 已经初始化
99
+ if (initialized) {
100
+ // 不收集依赖的情况下执行回调
101
+ untrack(() => callbackFn(deps()));
102
+ } else {
103
+ // 回集依赖
104
+ deps();
105
+ // 标记已经初始化
106
+ initialized = true;
107
+ }
108
+ });
109
+ };
110
+
111
+ /**
112
+ * 异步管理器结果
113
+ */
114
+ export interface FetcherResult<T> {
115
+ /**
116
+ * 异步状态
117
+ */
118
+ status: 'loading' | 'done' | 'fail';
119
+
120
+ /**
121
+ * 成功返回的结果数据
122
+ */
123
+ result?: T;
124
+
125
+ /**
126
+ * 错误信息
127
+ */
128
+ error?: any;
129
+ }
130
+
131
+ /**
132
+ * 创建异步获取器
133
+ *
134
+ * @param promise 异步对象
135
+ * @param ssr_cache 在服务端渲染的模式下是否缓存请求结果到 HTML 中
136
+ */
137
+ export const createFetcher = <T>(promise?: () => Promise<T>, ssr_cache?: string) => {
138
+ let [status, setStatus] = createSignal('loading');
139
+ let [result, setResult] = createSignal();
140
+ let [error, setError] = createSignal();
141
+ let data;
142
+
143
+ if (promise) {
144
+ if (import.meta.env.SSR) {
145
+ let id = createUniqueId();
146
+
147
+ if ((data = serverContext.cache.get(id))) {
148
+ setStatus('done');
149
+ setResult(data);
150
+ } else {
151
+ serverContext.promises.push(
152
+ promise().then((result) => {
153
+ serverContext.cache.set(id, result);
154
+
155
+ // 需要缓存到 HTML 中
156
+ if (ssr_cache) {
157
+ serverContext.ssr[ssr_cache] = result;
158
+ }
159
+ }),
160
+ );
161
+ }
162
+ } else {
163
+ if (ssr_cache && (data = (window as any).SSR) && (data = data[ssr_cache])) {
164
+ setStatus('done');
165
+ setResult(data);
166
+ } else {
167
+ promise().then(
168
+ (result) => {
169
+ setStatus('done');
170
+ setResult(result as any);
171
+ },
172
+ (error) => {
173
+ setStatus('fail');
174
+ setError(error);
175
+ },
176
+ );
177
+ }
178
+ }
179
+ }
180
+
181
+ return defineProperties(
182
+ {},
183
+ {
184
+ status: {
185
+ get: status,
186
+ set: setStatus,
187
+ },
188
+ result: {
189
+ get: result,
190
+ set: setResult,
191
+ },
192
+ error: {
193
+ get: error,
194
+ set: setError,
195
+ },
196
+ },
197
+ ) as FetcherResult<T>;
198
+ };
199
+
200
+ /**
201
+ * 延迟加载组件
202
+ *
203
+ * @param importFn 按需导入的组件 import('...')
204
+ */
205
+ export const LazyComponent = (
206
+ importFn: () => Promise<{
207
+ default: Component<any>;
208
+ }>,
209
+ ) => {
210
+ return lazy(importFn);
211
+ };
@@ -0,0 +1,23 @@
1
+ /**
2
+ * 替换模板字符串
3
+ *
4
+ * @param template 模板
5
+ * @param args 参数集合
6
+ *
7
+ * @example
8
+ * // 按索引替换
9
+ * replaceTemplate('...${0} ${1}...', 1, 2); // '...1 2...'
10
+ * // 按名称替换
11
+ * replaceTemplate('...${name} ${value}...', { name: 1, value: 2 }); // '...1 2...'
12
+ */
13
+ export const replaceTemplate = (template: string, ...args: unknown[]) => {
14
+ return template.replace(/\$\{([^}]+)\}/g, (_, token: string) => {
15
+ token = token.trim();
16
+
17
+ if (token[0] >= '0' && token[0] <= '9') {
18
+ return args[token];
19
+ }
20
+
21
+ return args[0] && args[0][token];
22
+ });
23
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @link https://www.typescriptlang.org/tsconfig
3
+ * @link https://cn.vuejs.org/guide/typescript/overview#configuring-tsconfig-json
4
+ * @link https://cn.vite.dev/guide/features#typescript-compiler-options
5
+ */
6
+ {
7
+ "compilerOptions": {
8
+ "target": "esnext",
9
+ "jsx": "preserve",
10
+ "jsxImportSource": "solid-js",
11
+ "moduleResolution": "bundler",
12
+ "module": "esnext",
13
+ "paths": {
14
+ }
15
+ }
16
+ }
package/vite-plugin.js ADDED
@@ -0,0 +1,4 @@
1
+ import VitePlugin from 'vite-plugin-solid';
2
+
3
+ export * from 'vite-plugin-solid';
4
+ export default VitePlugin;