jsbox-cview 1.0.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.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +19 -0
  3. package/components/alert/input-alert.ts +73 -0
  4. package/components/alert/login-alert.ts +75 -0
  5. package/components/alert/plain-alert.ts +49 -0
  6. package/components/alert/uialert.ts +110 -0
  7. package/components/artificial-flowlayout.ts +321 -0
  8. package/components/base.ts +47 -0
  9. package/components/custom-navigation-bar.ts +570 -0
  10. package/components/dialogs/dialog-sheet.ts +87 -0
  11. package/components/dialogs/form-dialog.ts +23 -0
  12. package/components/dialogs/list-dialog.ts +87 -0
  13. package/components/dialogs/text-dialog.ts +34 -0
  14. package/components/dynamic-itemsize-matrix.ts +190 -0
  15. package/components/dynamic-preference-listview.ts +691 -0
  16. package/components/dynamic-rowheight-list.ts +62 -0
  17. package/components/enhanced-imageview.ts +128 -0
  18. package/components/image-pager.ts +177 -0
  19. package/components/page-control.ts +91 -0
  20. package/components/pageviewer-titlebar.ts +170 -0
  21. package/components/pageviewer.ts +124 -0
  22. package/components/rotating-view.ts +126 -0
  23. package/components/searchbar.ts +373 -0
  24. package/components/sheet.ts +113 -0
  25. package/components/single-views.ts +828 -0
  26. package/components/spinners/loading-double-rings.ts +121 -0
  27. package/components/spinners/loading-dual-ring.ts +90 -0
  28. package/components/spinners/loading-wedges.ts +112 -0
  29. package/components/spinners/spinner-androidstyle.ts +264 -0
  30. package/components/static-preference-listview.ts +991 -0
  31. package/components/symbol-button.ts +105 -0
  32. package/components/tabbar.ts +451 -0
  33. package/controller/base-controller.ts +216 -0
  34. package/controller/controller-router.ts +74 -0
  35. package/controller/pageviewer-controller.ts +86 -0
  36. package/controller/presented-page-controller.ts +57 -0
  37. package/controller/splitview-controller.ts +323 -0
  38. package/controller/tabbar-controller.ts +99 -0
  39. package/package.json +23 -0
  40. package/test.ts +0 -0
  41. package/tsconfig.json +121 -0
  42. package/utils/colors.ts +13 -0
  43. package/utils/cvid.ts +34 -0
  44. package/utils/l10n.ts +42 -0
  45. package/utils/path.ts +100 -0
  46. package/utils/rect.ts +67 -0
  47. package/utils/uitools.ts +117 -0
@@ -0,0 +1,105 @@
1
+ /**
2
+ * #cview symbolButton
3
+ *
4
+ * 创建可以自动规范symbol大小的button,兼容image,可以设定insets
5
+ *
6
+ * props:
7
+ * - symbol
8
+ * - image
9
+ * - tintColor
10
+ * - insets
11
+ *
12
+ * events:
13
+ * - tapped
14
+ */
15
+
16
+ import { Base } from "./base";
17
+
18
+ interface CunstomProps extends UiTypes.ButtonProps {
19
+ insets: JBInsets
20
+ }
21
+
22
+ interface CunstomPropsOptional extends UiTypes.ButtonProps {
23
+ insets?: JBInsets
24
+ }
25
+ /**
26
+ * 创建可以自动规范symbol大小的button,兼容image,可以设定insets
27
+ * props:
28
+ * - symbol
29
+ * - image
30
+ * - tintColor
31
+ * - insets
32
+ * events:
33
+ * - tapped
34
+ */
35
+ export class SymbolButton extends Base<UIButtonView, UiTypes.ButtonOptions> {
36
+ _props: CunstomProps
37
+ _layout: (make: MASConstraintMaker, view: UIButtonView) => void
38
+ _events: UiTypes.BaseViewEvents<UIButtonView>
39
+ _defineView: () => UiTypes.ButtonOptions;
40
+ constructor({
41
+ props,
42
+ layout,
43
+ events = {}
44
+ }: {
45
+ props: CunstomPropsOptional;
46
+ layout: (make: MASConstraintMaker, view: UIButtonView) => void;
47
+ events?: UiTypes.BaseViewEvents<UIButtonView>;
48
+ }) {
49
+ super();
50
+ this._props = {
51
+ insets: $insets(12.5, 12.5, 12.5, 12.5),
52
+ tintColor: $color("primaryText"),
53
+ ...props
54
+ };
55
+ this._layout = layout;
56
+ this._events = events;
57
+ this._defineView = () => {
58
+ return {
59
+ type: "button",
60
+ props: {
61
+ radius: 0,
62
+ bgcolor: $color("clear"),
63
+ id: this.id
64
+ },
65
+ views: [
66
+ {
67
+ type: "image",
68
+ props: {
69
+ id: "image",
70
+ symbol: this._props.symbol,
71
+ image: this._props.image,
72
+ src: this._props.src,
73
+ tintColor: this._props.tintColor,
74
+ contentMode: 1
75
+ },
76
+ layout: (make, view: UIImageView) => {
77
+ make.edges.insets(this._props.insets);
78
+ make.centerX.equalTo(view.super);
79
+ make.width.equalTo(view.height);
80
+ }
81
+ }
82
+ ],
83
+ layout: this._layout,
84
+ events: {
85
+ ...this._events
86
+ }
87
+ };
88
+ }
89
+ }
90
+
91
+ set tintColor(tintColor: UIColor) {
92
+ const image = this.view.get("image") as UIImageView;
93
+ image.tintColor = tintColor;
94
+ }
95
+
96
+ set symbol(symbol) {
97
+ this._props.symbol = symbol;
98
+ const image = this.view.get("image") as UIImageView;
99
+ image.symbol = symbol;
100
+ }
101
+
102
+ get symbol() {
103
+ return this._props.symbol;
104
+ }
105
+ }
@@ -0,0 +1,451 @@
1
+ /**
2
+ * 本组件是为了仿制 UITabBar
3
+ * 本组件不能指定布局而是应该指定 height(如果需要的话)
4
+ * 典型的使用方式是添加在布局为$layout.fill的视图中,并指定 items
5
+ *
6
+ * props:
7
+ *
8
+ * - 只写 height: number = 50
9
+ * - 只写 items: {symbol?: string, image?:UIImage, title?: string}[]
10
+ * - 只写 bgcolor?: UIColor 如果不指定则背景使用blur(style 10),若指定则使用纯色视图
11
+ * - 读写 index: number = 0
12
+ * - 只写 selectedSegmentTintColor = $color("tintColor")
13
+ * - 只写 defaultSegmentTintColor = colors.footBarDefaultSegmentColor
14
+ *
15
+ * events:
16
+ *
17
+ * - changed: (cview, index) => void
18
+ * - doubleTapped: (cview, index) => void
19
+ *
20
+ * methods:
21
+ *
22
+ * - hide(animated=true) 隐藏
23
+ * - show(animated=true) 显示
24
+ */
25
+
26
+ import { footBarDefaultSegmentColor } from "../utils/colors";
27
+ import { Base } from "./base";
28
+
29
+ class ImageLabelCell extends Base<UIView, UiTypes.ViewOptions> {
30
+ _props: {
31
+ symbol?: string;
32
+ image?: UIImage;
33
+ text: string;
34
+ index: number;
35
+ selectedSegmentTintColor: UIColor;
36
+ defaultSegmentTintColor: UIColor;
37
+ selected?: boolean;
38
+ };
39
+ layouts: {
40
+ image_tightened: (make: MASConstraintMaker, view: AllUIView) => void;
41
+ label_tightened: (make: MASConstraintMaker, view: AllUIView) => void;
42
+ image_loosed: (make: MASConstraintMaker, view: AllUIView) => void;
43
+ label_loosed: (make: MASConstraintMaker, view: AllUIView) => void;
44
+ };
45
+ _defineView: () => UiTypes.ViewOptions;
46
+ constructor({ props, events = {} }: {
47
+ props: {
48
+ symbol?: string;
49
+ image?: UIImage;
50
+ text: string;
51
+ index: number;
52
+ selectedSegmentTintColor: UIColor;
53
+ defaultSegmentTintColor: UIColor;
54
+ selected?: boolean;
55
+ },
56
+ events: {
57
+ tapped?: (index: number) => void;
58
+ }
59
+ }) {
60
+ super();
61
+ this._props = props;
62
+ this.layouts = {
63
+ image_tightened: (make, view) => {
64
+ make.centerX.equalTo(view.super);
65
+ make.size.equalTo($size(25, 25));
66
+ make.top.inset(7);
67
+ },
68
+ label_tightened: (make, view) => {
69
+ make.centerX.equalTo(view.super);
70
+ make.top.equalTo(view.prev.bottom);
71
+ },
72
+ image_loosed: (make, view) => {
73
+ make.centerX.equalTo(view.super).offset(-35);
74
+ make.centerY.equalTo(view.super);
75
+ make.size.equalTo($size(25, 25));
76
+ },
77
+ label_loosed: (make, view) => {
78
+ make.left.equalTo(view.prev.right).inset(10);
79
+ make.centerY.equalTo(view.super);
80
+ }
81
+ };
82
+ this._defineView = () => {
83
+ return {
84
+ type: "view",
85
+ props: {
86
+ id: this.id,
87
+ userInteractionEnabled: true
88
+ },
89
+ views: [
90
+ {
91
+ type: "image",
92
+ props: {
93
+ id: "image",
94
+ symbol: this._props.symbol,
95
+ image: this._props.image,
96
+ contentMode: 1
97
+ }
98
+ },
99
+ {
100
+ type: "label",
101
+ props: {
102
+ id: "label",
103
+ text: this._props.text,
104
+ align: $align.center
105
+ }
106
+ }
107
+ ],
108
+ events: {
109
+ tapped: sender => {
110
+ if (events.tapped) events.tapped(this._props.index);
111
+ }
112
+ }
113
+ };
114
+ }
115
+ }
116
+
117
+ set selected(selected) {
118
+ this._props.selected = selected;
119
+ const color = selected
120
+ ? this._props.selectedSegmentTintColor
121
+ : this._props.defaultSegmentTintColor;
122
+ this.view.get("image").tintColor = color;
123
+ const label = this.view.get("label") as UILabelView;
124
+ label.textColor = color;
125
+ }
126
+
127
+ get selected() {
128
+ return this._props.selected;
129
+ }
130
+
131
+ _useTightenedLayout() {
132
+ this.view.get("image").remakeLayout(this.layouts.image_tightened);
133
+ this.view.get("label").remakeLayout(this.layouts.label_tightened);
134
+ const label = this.view.get("label") as UILabelView;
135
+ label.font = $font(10);
136
+ }
137
+
138
+ _useLoosedLayout() {
139
+ this.view.get("image").remakeLayout(this.layouts.image_loosed);
140
+ this.view.get("label").remakeLayout(this.layouts.label_loosed);
141
+ const label = this.view.get("label") as UILabelView;
142
+ label.font = $font(14);
143
+ }
144
+ }
145
+
146
+ class ImageCell extends Base<UIView, UiTypes.ViewOptions> {
147
+ _props: {
148
+ symbol?: string;
149
+ image?: UIImage;
150
+ index: number;
151
+ selectedSegmentTintColor: UIColor;
152
+ defaultSegmentTintColor: UIColor;
153
+ selected?: boolean;
154
+ };
155
+ layouts: {
156
+ image_tightened: (make: MASConstraintMaker, view: AllUIView) => void;
157
+ image_loosed: (make: MASConstraintMaker, view: AllUIView) => void;
158
+ };
159
+ _defineView: () => UiTypes.ViewOptions;
160
+ constructor({ props, events = {} }: {
161
+ props: {
162
+ symbol?: string;
163
+ image?: UIImage;
164
+ index: number;
165
+ selectedSegmentTintColor: UIColor;
166
+ defaultSegmentTintColor: UIColor;
167
+ selected?: boolean;
168
+ },
169
+ events: {
170
+ tapped?: (index: number) => void;
171
+ }
172
+ }) {
173
+ super();
174
+ this._props = props;
175
+ this.layouts = {
176
+ image_tightened: (make, view) => {
177
+ make.center.equalTo(view.super);
178
+ make.size.equalTo($size(30, 30));
179
+ },
180
+ image_loosed: (make, view) => {
181
+ make.center.equalTo(view.super);
182
+ make.size.equalTo($size(30, 30));
183
+ }
184
+ };
185
+ this._defineView = () => {
186
+ return {
187
+ type: "view",
188
+ props: {
189
+ id: this.id,
190
+ userInteractionEnabled: true
191
+ },
192
+ views: [
193
+ {
194
+ type: "image",
195
+ props: {
196
+ id: "image",
197
+ symbol: this._props.symbol,
198
+ image: this._props.image,
199
+ contentMode: 1
200
+ }
201
+ }
202
+ ],
203
+ events: {
204
+ tapped: sender => {
205
+ if (events.tapped) events.tapped(this._props.index);
206
+ }
207
+ }
208
+ };
209
+ }
210
+ }
211
+
212
+ set selected(selected) {
213
+ this._props.selected = selected;
214
+ const color = selected
215
+ ? this._props.selectedSegmentTintColor
216
+ : this._props.defaultSegmentTintColor;
217
+ this.view.get("image").tintColor = color;
218
+ }
219
+
220
+ get selected() {
221
+ return this._props.selected;
222
+ }
223
+
224
+ _useTightenedLayout() {
225
+ this.view.get("image").remakeLayout(this.layouts.image_tightened);
226
+ }
227
+
228
+ _useLoosedLayout() {
229
+ this.view.get("image").remakeLayout(this.layouts.image_loosed);
230
+ }
231
+ }
232
+
233
+ export class TabBar extends Base<UIView | UIBlurView, UiTypes.ViewOptions | UiTypes.BlurOptions> {
234
+ _props: {
235
+ height: number;
236
+ items: { symbol?: string; image?: UIImage; title?: string }[];
237
+ index: number;
238
+ selectedSegmentTintColor: UIColor;
239
+ defaultSegmentTintColor: UIColor;
240
+ bgcolor?: UIColor;
241
+ };
242
+ _index: number;
243
+ _cells: (ImageLabelCell | ImageCell)[];
244
+ _events: {
245
+ changed?: (cview: TabBar, index: number) => void;
246
+ doubleTapped?: (cview: TabBar, index: number) => void;
247
+ };
248
+ _defineView: () => UiTypes.ViewOptions | UiTypes.BlurOptions;
249
+ constructor({ props, events = {} }: {
250
+ props: {
251
+ height?: number;
252
+ items: { symbol?: string; image?: UIImage; title?: string }[];
253
+ index?: number;
254
+ selectedSegmentTintColor?: UIColor;
255
+ defaultSegmentTintColor?: UIColor;
256
+ bgcolor?: UIColor;
257
+ },
258
+ events: {
259
+ changed?: (cview: TabBar, index: number) => void;
260
+ doubleTapped?: (cview: TabBar, index: number) => void;
261
+ }
262
+ }) {
263
+ super();
264
+ this._props = {
265
+ height: 50,
266
+ index: 0,
267
+ selectedSegmentTintColor: $color("systemLink"),
268
+ defaultSegmentTintColor: footBarDefaultSegmentColor,
269
+ //bgcolor: $color("secondarySurface"),
270
+ ...props
271
+ };
272
+ this._index = this._props.index;
273
+ this._events = events;
274
+ this._cells = this._defineCells();
275
+ this._defineView = () => {
276
+ const stack: UiTypes.StackOptions = {
277
+ type: "stack",
278
+ props: {
279
+ axis: $stackViewAxis.horizontal,
280
+ distribution: $stackViewDistribution.fillEqually,
281
+ spacing: 0,
282
+ stack: {
283
+ views: this._cells.map(n => n.definition)
284
+ }
285
+ },
286
+ layout: (make, view) => {
287
+ make.height.equalTo(this._props.height - 0.5);
288
+ make.left.right.equalTo(view.super.safeArea);
289
+ make.top.equalTo(view.prev.bottom);
290
+ }
291
+ };
292
+ const line: UiTypes.ViewOptions = {
293
+ type: "view",
294
+ props: {
295
+ bgcolor: $color("separatorColor")
296
+ },
297
+ layout: (make, view) => {
298
+ make.top.left.right.inset(0);
299
+ make.height.equalTo(0.5);
300
+ }
301
+ };
302
+ if (this._props.bgcolor) {
303
+ return {
304
+ type: "view",
305
+ props: {
306
+ id: this.id,
307
+ bgcolor: this._props.bgcolor
308
+ },
309
+ layout: (make, view) => {
310
+ make.left.right.bottom.inset(0);
311
+ make.top.equalTo(view.super.safeAreaBottom).inset(-this._props.height);
312
+ },
313
+ views: [line, stack],
314
+ events: {
315
+ ready: sender => (this.index = this._index),
316
+ layoutSubviews: sender => {
317
+ const windowWidth = sender.frame.width;
318
+ if (windowWidth > 600) {
319
+ this._useLoosedLayout();
320
+ } else {
321
+ this._useTightenedLayout();
322
+ }
323
+ }
324
+ }
325
+ };
326
+ } else {
327
+ return {
328
+ type: "blur",
329
+ props: {
330
+ id: this.id,
331
+ style: 10
332
+ },
333
+ layout: (make, view) => {
334
+ make.left.right.bottom.inset(0);
335
+ make.top.equalTo(view.super.safeAreaBottom).inset(-this._props.height);
336
+ },
337
+ views: [line, stack],
338
+ events: {
339
+ ready: sender => (this.index = this._index),
340
+ layoutSubviews: sender => {
341
+ const windowWidth = sender.frame.width;
342
+ if (windowWidth > 600) {
343
+ this._useLoosedLayout();
344
+ } else {
345
+ this._useTightenedLayout();
346
+ }
347
+ }
348
+ }
349
+ };
350
+ }
351
+ }
352
+ }
353
+
354
+ _defineCells() {
355
+ return this._props.items.map((n, i) => {
356
+ if (n.title) {
357
+ return new ImageLabelCell({
358
+ props: {
359
+ symbol: n.symbol,
360
+ image: n.image ? n.image.alwaysTemplate : undefined,
361
+ text: n.title,
362
+ index: i,
363
+ selectedSegmentTintColor: this._props.selectedSegmentTintColor,
364
+ defaultSegmentTintColor: this._props.defaultSegmentTintColor
365
+ },
366
+ events: {
367
+ tapped: index => {
368
+ if (index !== this.index) {
369
+ this.index = index;
370
+ if (this._events.changed) this._events.changed(this, index);
371
+ } else {
372
+ if (this._events.doubleTapped)
373
+ this._events.doubleTapped(this, index);
374
+ }
375
+ }
376
+ }
377
+ });
378
+ } else {
379
+ return new ImageCell({
380
+ props: {
381
+ symbol: n.symbol,
382
+ image: n.image ? n.image.alwaysTemplate : undefined,
383
+ index: i,
384
+ selectedSegmentTintColor: this._props.selectedSegmentTintColor,
385
+ defaultSegmentTintColor: this._props.defaultSegmentTintColor
386
+ },
387
+ events: {
388
+ tapped: index => {
389
+ if (index !== this.index) {
390
+ this.index = index;
391
+ if (this._events.changed) this._events.changed(this, index);
392
+ } else {
393
+ if (this._events.doubleTapped)
394
+ this._events.doubleTapped(this, index);
395
+ }
396
+ }
397
+ }
398
+ });
399
+ }
400
+ });
401
+ }
402
+
403
+ get index() {
404
+ return this._index;
405
+ }
406
+
407
+ set index(index) {
408
+ this._index = index;
409
+ this._cells.forEach((n, i) => {
410
+ n.selected = i === this._index;
411
+ });
412
+ }
413
+
414
+ hide(animated = true) {
415
+ this.view.remakeLayout((make, view) => {
416
+ make.left.right.bottom.inset(0);
417
+ make.height.equalTo(0);
418
+ });
419
+ if (animated) {
420
+ $ui.animate({
421
+ duration: 0.3,
422
+ animation: () => this.view.relayout()
423
+ });
424
+ }
425
+ }
426
+
427
+ show(animated = true) {
428
+ this.view.remakeLayout((make, view) => {
429
+ make.left.right.bottom.inset(0);
430
+ make.top.equalTo(view.super.safeAreaBottom).inset(-this._props.height);
431
+ });
432
+ if (animated) {
433
+ $ui.animate({
434
+ duration: 0.3,
435
+ animation: () => this.view.relayout()
436
+ });
437
+ }
438
+ }
439
+
440
+ _useTightenedLayout() {
441
+ this._cells.forEach(n => {
442
+ n._useTightenedLayout();
443
+ });
444
+ }
445
+
446
+ _useLoosedLayout() {
447
+ this._cells.forEach(n => {
448
+ n._useLoosedLayout();
449
+ });
450
+ }
451
+ }