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,47 @@
1
+ .overflow-auto {
2
+ overflow: auto;
3
+ }
4
+
5
+ .overflow-hidden {
6
+ overflow: hidden;
7
+ }
8
+
9
+ .overflow-scroll {
10
+ overflow: scroll;
11
+ }
12
+
13
+ .overflow-visible {
14
+ overflow: visible;
15
+ }
16
+
17
+ .overflow-x-auto {
18
+ overflow-x: auto;
19
+ }
20
+
21
+ .overflow-x-hidden {
22
+ overflow-x: hidden;
23
+ }
24
+
25
+ .overflow-x-scroll {
26
+ overflow-x: scroll;
27
+ }
28
+
29
+ .overflow-x-visible {
30
+ overflow-x: visible;
31
+ }
32
+
33
+ .overflow-y-auto {
34
+ overflow-y: auto;
35
+ }
36
+
37
+ .overflow-y-hidden {
38
+ overflow-y: hidden;
39
+ }
40
+
41
+ .overflow-y-scroll {
42
+ overflow-y: scroll;
43
+ }
44
+
45
+ .overflow-y-visible {
46
+ overflow-y: visible;
47
+ }
@@ -0,0 +1,58 @@
1
+ .static {
2
+ position: static;
3
+ }
4
+
5
+ .relative {
6
+ position: relative;
7
+ }
8
+
9
+ .fixed {
10
+ position: fixed;
11
+ }
12
+
13
+ .absolute {
14
+ position: absolute;
15
+ }
16
+
17
+ .sticky {
18
+ position: sticky;
19
+ }
20
+
21
+ .position-t {
22
+ top: 0;
23
+ }
24
+
25
+ .position-l {
26
+ left: 0;
27
+ }
28
+
29
+ .position-b {
30
+ bottom: 0;
31
+ }
32
+
33
+ .position-r {
34
+ right: 0;
35
+ }
36
+
37
+ .position-center {
38
+ left: 50%;
39
+ top: 50%;
40
+ transform: translate(-50%, -50%);
41
+ }
42
+
43
+ .position-x-center {
44
+ left: 50%;
45
+ transform: translateX(-50%);
46
+ }
47
+
48
+ .position-y-center {
49
+ top: 50%;
50
+ transform: translateY(-50%);
51
+ }
52
+
53
+ .position-fill {
54
+ top: 0;
55
+ left: 0;
56
+ width: 100%;
57
+ height: 100%;
58
+ }
package/css/base.css ADDED
@@ -0,0 +1,16 @@
1
+ img {
2
+ -webkit-user-drag: none;
3
+ user-drag: none;
4
+ }
5
+
6
+ /* 隐藏滚动条 */
7
+ .scrollbar-hidden {
8
+ scrollbar-width: none;
9
+ }
10
+
11
+ /* Chrome/Safari/Opera */
12
+ .scrollbar-hidden::-webkit-scrollbar {
13
+ display: none;
14
+ width: 0;
15
+ height: 0;
16
+ }
@@ -0,0 +1,46 @@
1
+ .carousel {
2
+ display: flex;
3
+ overflow: hidden;
4
+ user-select: none;
5
+ }
6
+
7
+ .carousel-backward,
8
+ .carousel-forward {
9
+ display: block;
10
+ position: absolute;
11
+ top: 50%;
12
+ transform: translateY(-50%);
13
+ width: 36px;
14
+ height: 36px;
15
+ border-radius: 36px;
16
+ padding: 8px;
17
+ background: rgba(255, 255, 255, 0.1);
18
+ cursor: pointer;
19
+ }
20
+
21
+ .carousel-backward {
22
+ left: 12px;
23
+ }
24
+
25
+ .carousel-forward {
26
+ right: 12px;
27
+ }
28
+
29
+ .le-800 .carousel-backward,
30
+ .le-800 .carousel-forward {
31
+ display: none;
32
+ }
33
+
34
+ .carousel-dot {
35
+ display: inline-block;
36
+ width: 6px;
37
+ height: 6px;
38
+ border-radius: 10px;
39
+ margin: 0 2px;
40
+ background: rgba(65, 72, 90, 1);
41
+ }
42
+
43
+ .carousel-dot.selected {
44
+ width: 16px;
45
+ background: white;
46
+ }
@@ -0,0 +1,58 @@
1
+ .combobox {
2
+ position: relative;
3
+ width: 100px;
4
+ height: 32px;
5
+ border: 1px solid silver;
6
+ background: white;
7
+ overflow: visible;
8
+ }
9
+
10
+ .combobox-host {
11
+ display: flex;
12
+ justify-content: center;
13
+ align-items: center;
14
+ width: 100%;
15
+ height: 100%;
16
+ }
17
+
18
+ .combobox-host > input {
19
+ flex: auto;
20
+ width: 100%;
21
+ height: 100%;
22
+ outline: none;
23
+ padding: 0 4px;
24
+ background: inherit;
25
+ color: inherit;
26
+ vertical-align: top;
27
+ font-size: inherit;
28
+ }
29
+
30
+ .combobox-host > svg {
31
+ display: flex;
32
+ justify-items: center;
33
+ align-items: center;
34
+ padding: 0 3px;
35
+ stroke: inherit;
36
+ fill: inherit;
37
+ cursor: pointer;
38
+ }
39
+
40
+ .combobox-popup {
41
+ position: absolute;
42
+ top: calc(100% + 4px);
43
+ left: 0;
44
+ width: auto;
45
+ z-index: 100;
46
+ will-change: height;
47
+ transition: height 0.2s linear;
48
+ }
49
+
50
+ .combobox-popup-top {
51
+ top: auto;
52
+ bottom: calc(100% + 4px);
53
+ }
54
+
55
+ .combobox-popup-right {
56
+ left: auto;
57
+ right: 0;
58
+ }
package/css/icon.css ADDED
@@ -0,0 +1,7 @@
1
+ .icon {
2
+ display: inline-flex;
3
+ justify-items: center;
4
+ align-items: center;
5
+ box-sizing: content-box;
6
+ user-select: none;
7
+ }
@@ -0,0 +1,3 @@
1
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M8.7793 2.22668L4.97596 5.78516C4.5268 6.20541 4.5268 6.89309 4.97596 7.31334L8.7793 10.8718" stroke="white" stroke-width="2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M0.750078 11.3565L11.3567 0.749922M11.3567 11.3565L0.750078 0.749922" stroke="#8693B6" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M12.5573 6.03015L8.44707 10.4231C7.96166 10.942 7.16737 10.942 6.68196 10.4231L2.57178 6.03015" stroke="#8693B6" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M5.2207 2.22668L9.02404 5.78516C9.4732 6.20541 9.4732 6.89309 9.02404 7.31334L5.2207 10.8718" stroke="white" stroke-width="2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg viewBox="0 0 10 6" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M9.14515 0.5L5.58667 4.30333C5.16642 4.7525 4.47873 4.7525 4.05848 4.30333L0.5 0.5" stroke="white" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
3
+ </svg>
package/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './src';
@@ -0,0 +1 @@
1
+ export * from './src/jsx';
package/package.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "china-diff",
3
+ "version": "1.0.1",
4
+ "type": "module",
5
+ "main": "index.ts",
6
+ "scripts": {},
7
+ "dependencies": {},
8
+ "devDependencies": {
9
+ "solid-js": "^1.9.10",
10
+ "typescript": "~5.6.2",
11
+ "vite-plugin-solid": "^2.11.10"
12
+ }
13
+ }
@@ -0,0 +1,65 @@
1
+ export const animateScrollTo = (container: HTMLElement, x?: number, y?: number, duration?: number): Promise<void> => {
2
+ if (x < 0) {
3
+ x = 0;
4
+ }
5
+
6
+ if (y < 0) {
7
+ y = 0;
8
+ }
9
+
10
+ return new Promise((resolve) => {
11
+ const startTime = Date.now();
12
+ const scrollLeft = container.scrollLeft;
13
+ const scrollTop = container.scrollTop;
14
+ const distanceX = x != null ? x - scrollLeft : 0;
15
+ const distanceY = y != null ? y - scrollTop : 0;
16
+
17
+ duration = duration > 0 ? duration : 200;
18
+
19
+ const step = () => {
20
+ let elapsed = Date.now() - startTime;
21
+
22
+ if (elapsed < duration) {
23
+ let scale = elapsed / duration;
24
+
25
+ container.scrollTo((scrollLeft + scale * distanceX) | 0, (scrollTop + scale * distanceY) | 0);
26
+ requestAnimationFrame(step);
27
+ } else {
28
+ container.scrollTo(x, y);
29
+ resolve();
30
+ }
31
+ };
32
+
33
+ requestAnimationFrame(step);
34
+ });
35
+ };
36
+
37
+ export const animateScrollBy = (
38
+ container: HTMLElement,
39
+ offsetX?: number,
40
+ offsetY?: number,
41
+ duration?: number,
42
+ ): Promise<void> => {
43
+ return animateScrollTo(
44
+ container,
45
+ container.scrollLeft + (offsetX || 0),
46
+ container.scrollTop + (offsetY || 0),
47
+ duration,
48
+ );
49
+ };
50
+
51
+ export const animateScrollIntoView = (
52
+ container: HTMLElement,
53
+ element: HTMLElement,
54
+ duration?: number,
55
+ ): Promise<void> => {
56
+ let rect1 = container.getBoundingClientRect();
57
+ let rect2 = element.getBoundingClientRect();
58
+
59
+ return animateScrollTo(
60
+ container,
61
+ container.scrollLeft + rect2.left - rect1.left,
62
+ container.scrollTop + rect2.top - rect1.top,
63
+ duration,
64
+ );
65
+ };
@@ -0,0 +1,299 @@
1
+ import { createEffect, createMemo, createSignal, For, onCleanup, onMount, splitProps } from 'solid-js';
2
+
3
+ import { JSX } from '../jsx';
4
+ import { isBrowser } from '../dom';
5
+ import { animateScrollIntoView } from '../animate-scroll-to';
6
+ import { defineProperty } from '../reactive';
7
+ import { Icon } from './Icon';
8
+
9
+ const CLASS_NAME = 'carousel-vertical';
10
+
11
+ const EVENT_OPTIONS = { passive: true, capture: true };
12
+
13
+ const DOTS = new Array(100).join('0').split('');
14
+
15
+ /**
16
+ * 填充数据项
17
+ */
18
+ const fillItems = <T extends unknown>(items: readonly T[]) => {
19
+ return [...items, ...items.slice(0, -1)];
20
+ };
21
+
22
+ /**
23
+ * 是否正在调整大小
24
+ */
25
+ let resizing = false;
26
+
27
+ if (isBrowser) {
28
+ let resizeTimer: any;
29
+
30
+ window.addEventListener(
31
+ 'resize',
32
+ () => {
33
+ resizing = true;
34
+
35
+ clearTimeout(resizeTimer);
36
+ resizeTimer = setTimeout(() => (resizing = false), 500);
37
+ },
38
+ true,
39
+ );
40
+ }
41
+
42
+ /**
43
+ * 轮播组件外部调用接口
44
+ */
45
+ export interface CarouselApi {
46
+ /**
47
+ * 当前索引
48
+ */
49
+ get index(): number;
50
+ /**
51
+ * 后退方法
52
+ */
53
+ backward: () => void;
54
+ /**
55
+ * 前进方法
56
+ */
57
+ forward: () => void;
58
+ }
59
+
60
+ /**
61
+ * 轮播组件
62
+ */
63
+ export const Carousel = <T, U extends JSX.Element>(
64
+ props?: Omit<JSX.HTMLAttributes<never>, 'children'> & {
65
+ /**
66
+ * 要循环的数据集合
67
+ */
68
+ each: readonly T[];
69
+ /**
70
+ * 子节点
71
+ *
72
+ * @param item 数据项
73
+ * @param index 索引
74
+ * @returns JSX.Element
75
+ */
76
+ children: (item: T, index: () => number) => U;
77
+ /**
78
+ * 是否自动播放
79
+ */
80
+ autoplay?: boolean;
81
+ /**
82
+ * 间隔时间
83
+ */
84
+ interval?: number;
85
+ /**
86
+ * 是否竖直滚动
87
+ */
88
+ vertical?: boolean;
89
+ /**
90
+ * 外部调用接口
91
+ */
92
+ api?: (api: CarouselApi) => void;
93
+ },
94
+ ) => {
95
+ let [thisProps, restProps] = splitProps(props, [
96
+ 'class',
97
+ 'each',
98
+ 'children',
99
+ 'autoplay',
100
+ 'interval',
101
+ 'vertical',
102
+ 'api',
103
+ ]);
104
+ let [currentIndex, setCurrentIndex] = createSignal(0);
105
+
106
+ let ref: HTMLElement;
107
+ // 开始按下位置
108
+ let pressdown = -1;
109
+ // 按下时的滚动位置
110
+ let pressdownScroll: number;
111
+ // 自动滚动计时器
112
+ let autoplayTimer: any;
113
+
114
+ // 获取滚动方向
115
+ const scrollType = createMemo(() => (thisProps.vertical ? 'scrollTop' : 'scrollLeft'));
116
+ const offsetType = createMemo(() => (thisProps.vertical ? 'offsetTop' : 'offsetLeft'));
117
+ const screenType = createMemo(() => (thisProps.vertical ? 'screenY' : 'screenX'));
118
+
119
+ // 滚动到指定索引
120
+ const scrollTo = (index: number) => {
121
+ let children = ref.children;
122
+ let length = children.length;
123
+ let count = thisProps.each.length; // 真实的子项数量
124
+
125
+ if (index < 0) {
126
+ index += count;
127
+ }
128
+
129
+ // 重新开启自动播放
130
+ autoplay();
131
+
132
+ // 滚动到指定子节点
133
+ animateScrollIntoView(ref, children[index % length] as HTMLElement).then(() => {
134
+ if (index >= count) {
135
+ // 滚动到对应节点
136
+ ref[scrollType()] = (children[index - count] as HTMLElement)[offsetType()];
137
+ // 调整到指定节点
138
+ index -= count;
139
+ }
140
+
141
+ setCurrentIndex(index);
142
+ });
143
+ };
144
+
145
+ const checkFirstIndex = () => {
146
+ let index = currentIndex();
147
+
148
+ if (index <= 0) {
149
+ // 真实的子项数量
150
+ let count = thisProps.each.length;
151
+
152
+ // 先滚动到对应节点的填充节点
153
+ ref[scrollType()] = (ref.children[index + count] as HTMLElement)[offsetType()];
154
+ // 调整到指定节点
155
+ index += count;
156
+ }
157
+
158
+ return index;
159
+ };
160
+
161
+ // 后退
162
+ const backward = () => {
163
+ scrollTo(checkFirstIndex() - 1);
164
+ };
165
+
166
+ // 前进
167
+ const forward = () => {
168
+ scrollTo(currentIndex() + 1);
169
+ };
170
+
171
+ const ontouchstart = (event: TouchEvent) => {
172
+ checkFirstIndex();
173
+
174
+ // 记录按下时状态
175
+ pressdown = (event.changedTouches[0] || event.touches[0])[screenType()];
176
+ pressdownScroll = ref[scrollType()];
177
+
178
+ // 取消自动播放
179
+ clearTimeout(autoplayTimer);
180
+ };
181
+
182
+ const ontouchmove = (event: TouchEvent) => {
183
+ if (pressdown >= 0) {
184
+ ref[scrollType()] = pressdownScroll - ((event.changedTouches[0] || event.touches[0])[screenType()] - pressdown);
185
+ }
186
+ };
187
+
188
+ const ontouchend = (event: TouchEvent) => {
189
+ let distance = (event.changedTouches[0] || event.touches[0])[screenType()] - pressdown;
190
+ let index = currentIndex();
191
+
192
+ // 清除按下状态
193
+ pressdown = -1;
194
+
195
+ // 往前滚
196
+ if (distance > 20) {
197
+ scrollTo(index - 1);
198
+ } else if (distance < -20) {
199
+ // 如果是第一个位置,则恢复滚动位置
200
+ if (index === 0) {
201
+ ref[scrollType()] = ref.children[offsetType()];
202
+ }
203
+
204
+ scrollTo(index + 1);
205
+ } else {
206
+ animateScrollIntoView(ref, ref.children[index % ref.children.length] as HTMLElement);
207
+ }
208
+ };
209
+
210
+ const autoplay = () => {
211
+ clearTimeout(autoplayTimer);
212
+
213
+ if (thisProps.autoplay !== false) {
214
+ autoplayTimer = setTimeout(
215
+ () => {
216
+ if (!resizing) {
217
+ let rect = ref.getBoundingClientRect();
218
+ let top = rect.top;
219
+
220
+ if (top + rect.height > 10 && top - 10 < window.innerHeight) {
221
+ forward();
222
+ }
223
+ }
224
+
225
+ autoplay();
226
+ },
227
+ thisProps.interval > 3000 ? thisProps.interval : 3000,
228
+ );
229
+ }
230
+ };
231
+
232
+ // 初始化外部访问接口
233
+ thisProps.api &&
234
+ thisProps.api(
235
+ defineProperty(
236
+ {
237
+ backward,
238
+ forward,
239
+ },
240
+ 'index',
241
+ { get: currentIndex },
242
+ ) as CarouselApi,
243
+ );
244
+
245
+ createEffect(() => {
246
+ let classList = ref.classList;
247
+
248
+ if (props.vertical) {
249
+ if (!classList.contains(CLASS_NAME)) {
250
+ classList.add();
251
+ }
252
+ } else {
253
+ classList.remove(CLASS_NAME);
254
+ }
255
+ });
256
+
257
+ createEffect(autoplay);
258
+
259
+ onMount(() => {
260
+ ref.addEventListener('touchstart', ontouchstart, EVENT_OPTIONS);
261
+ ref.addEventListener('touchmove', ontouchmove, EVENT_OPTIONS);
262
+ ref.addEventListener('touchend', ontouchend, EVENT_OPTIONS);
263
+
264
+ onCleanup(() => {
265
+ ref.removeEventListener('touchstart', ontouchstart, EVENT_OPTIONS);
266
+ ref.removeEventListener('touchmove', ontouchmove, EVENT_OPTIONS);
267
+ ref.removeEventListener('touchend', ontouchend, EVENT_OPTIONS);
268
+ });
269
+ });
270
+
271
+ return (
272
+ <div ref={ref as any} class={'carousel scrollbar-hidden ' + (thisProps.class || '')} {...restProps}>
273
+ <For each={fillItems(thisProps.each)}>{thisProps.children}</For>
274
+ </div>
275
+ );
276
+ };
277
+
278
+ /**
279
+ * 轮播按钮
280
+ */
281
+ export const CarouselButtons = (props: { carousel: CarouselApi }) => {
282
+ return (
283
+ <>
284
+ <Icon class="carousel-backward" name="backward" onclick={() => props.carousel.backward()}></Icon>
285
+ <Icon class="carousel-forward" name="forward" onclick={() => props.carousel.forward()}></Icon>
286
+ </>
287
+ );
288
+ };
289
+
290
+ /**
291
+ * 轮播页码点
292
+ */
293
+ export const CarouselDots = <T extends unknown>(props: { each: readonly T[]; carousel: CarouselApi }) => {
294
+ return (
295
+ <For each={DOTS.slice(0, props.each.length)}>
296
+ {(_, index) => <span class={'carousel-dot' + (props.carousel.index === index() ? ' selected' : '')}></span>}
297
+ </For>
298
+ );
299
+ };