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,23 @@
1
+ /**
2
+ * # CView Form Dialog
3
+ *
4
+ * 显示一个表单
5
+ */
6
+
7
+ import { PreferenceListView, PreferenceSection } from "../static-preference-listview";
8
+ import { DialogSheet } from "./dialog-sheet";
9
+
10
+
11
+ export function formDialog({ sections, title }: { sections: PreferenceSection[]; title: string }) {
12
+ const view = new PreferenceListView({ sections });
13
+ const sheet = new DialogSheet({
14
+ title,
15
+ bgcolor: $color("insetGroupedBackground"),
16
+ cview: view,
17
+ doneHandler: () => view.values
18
+ });
19
+ return new Promise((resolve, reject) => {
20
+ sheet.promisify(resolve, reject);
21
+ sheet.present();
22
+ });
23
+ }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * # CView List Dialog
3
+ *
4
+ * 显示一个列表以供选择
5
+ */
6
+
7
+ import { DialogSheet } from './dialog-sheet';
8
+ import { List } from '../single-views';
9
+
10
+ export function listDialog({ items, multiSelectEnabled, value, values = [], title }: {
11
+ items: string[];
12
+ multiSelectEnabled?: boolean;
13
+ value?: number;
14
+ values?: number[];
15
+ title: string;
16
+ }) {
17
+ if (value) values = [value]
18
+ const listView = new List({
19
+ props: {
20
+ style: 2,
21
+ data: items.map((n, i) => {
22
+ return {
23
+ label: { text: n },
24
+ image: { hidden: !values.includes(i) }
25
+ };
26
+ }),
27
+ template: {
28
+ views: [
29
+ {
30
+ type: "label",
31
+ props: {
32
+ id: "label"
33
+ },
34
+ layout: (make, view) => {
35
+ make.top.bottom.inset(0);
36
+ make.left.inset(20);
37
+ make.right.inset(50);
38
+ }
39
+ },
40
+ {
41
+ type: "image",
42
+ props: {
43
+ id: "image",
44
+ symbol: "checkmark",
45
+ contentMode: 1,
46
+ tintColor: $color("systemLink")
47
+ },
48
+ layout: (make, view) => {
49
+ make.top.bottom.right.inset(10);
50
+ make.width.equalTo(30);
51
+ }
52
+ }
53
+ ]
54
+ }
55
+ },
56
+ events: {
57
+ didSelect: (sender, indexPath) => {
58
+ const data = sender.data;
59
+ if (multiSelectEnabled) {
60
+ data[indexPath.item].image.hidden = !data[indexPath.item].image
61
+ .hidden;
62
+ } else {
63
+ data.forEach((n, i) => {
64
+ n.image.hidden = i !== indexPath.item;
65
+ });
66
+ }
67
+ sender.data = data;
68
+ }
69
+ }
70
+ })
71
+ const sheet = new DialogSheet({
72
+ title,
73
+ bgcolor: $color("insetGroupedBackground"),
74
+ cview: listView,
75
+ doneHandler: () => {
76
+ const filtered = listView.view.data
77
+ .map((n, i) => (n.image.hidden ? -1 : i))
78
+ .filter(n => n !== -1);
79
+ if (multiSelectEnabled) return filtered;
80
+ else return filtered[0];
81
+ }
82
+ });
83
+ return new Promise((resolve, reject) => {
84
+ sheet.promisify(resolve, reject);
85
+ sheet.present();
86
+ });
87
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * # CView Text Dialog
3
+ *
4
+ * 返回一个Promise用于输入文本
5
+ */
6
+
7
+ import { Text } from "../single-views";
8
+ import { DialogSheet } from "./dialog-sheet";
9
+
10
+ export function textDialog({ title, text = "", placeholder = "" }: {
11
+ title: string;
12
+ text?: string;
13
+ placeholder?: string;
14
+ }) {
15
+ const textView = new Text({
16
+ props: {
17
+ text,
18
+ placeholder
19
+ },
20
+ events: {
21
+ ready: sender => sender.focus()
22
+ }
23
+ });
24
+
25
+ const sheet = new DialogSheet({
26
+ title,
27
+ cview: textView,
28
+ doneHandler: () => textView.view.text
29
+ });
30
+ return new Promise((resolve, reject) => {
31
+ sheet.promisify(resolve, reject);
32
+ sheet.present();
33
+ });
34
+ }
@@ -0,0 +1,190 @@
1
+ /**
2
+ * # CView Dynamic ItemSize Matrix
3
+ *
4
+ * 此组件是为了解决让 Matrix 的 ItemSize 跟随重新布局而动态变化的问题
5
+ *
6
+ * 动态的改变自己的 itemSize,从而使得 spacing 被优先满足。
7
+ * 思路为在 matrix 上层套一个 superView,在旋转的时候 superView 会调用 matrix.relayout() 和 matrix.reload()
8
+ * 从而触发 itemSize 事件
9
+ *
10
+ * 此视图的高度可以自动调整,需要 dynamicHeightEnabled 设为 true,且 layout 中要有关于 height 的约束
11
+ *
12
+ * 其排布逻辑是这样的:
13
+ *
14
+ * 1. 由 minItemWidth,spacing,maxColumns 这三个参数决定 cloumns,并结合 totalWidth 确定 itemSize.width
15
+ * 2. 确定 itemHeight 有两种方法:
16
+ * - fixedItemHeight 固定高度,优先级第二
17
+ * - event: itemHeight(width) => height 通过 width 动态计算,优先级最高
18
+ *
19
+ * props:
20
+ *
21
+ * 可以使用 matrix 的全部属性
22
+ *
23
+ * 特殊属性:
24
+ *
25
+ * - fixedItemHeight 固定 itemSize 高度
26
+ * - minItemWidth 最小的 itemSize 宽度
27
+ * - maxColumns 最大列数
28
+ * - spacing
29
+ * - dynamicHeightEnabled 此项为 true,那么 scrollEnabled 自动设为 false,且高度可以自动调整
30
+ *
31
+ * events:
32
+ *
33
+ * 可以使用 matrix 除 itemSize 以外的全部事件
34
+ *
35
+ * 其他特殊事件:
36
+ *
37
+ * - itemHeight: width => height 通过 itemWidth 动态计算 itemHeight
38
+ *
39
+ *
40
+ * 方法:
41
+ * - heightToWidth(width) 计算特定width时的应有的高度
42
+ */
43
+
44
+ import { Base } from './base';
45
+ import { Matrix } from "./single-views";
46
+
47
+ interface DynamicItemSizeMatrixProps extends UiTypes.MatrixProps {
48
+ fixedItemHeight: number;
49
+ minItemWidth: number;
50
+ maxColumns: number;
51
+ spacing: number;
52
+ maxTotalWidth: number;
53
+ dynamicHeightEnabled?: boolean;
54
+ }
55
+
56
+ interface DynamicItemSizeMatrixEvents extends UiTypes.MatrixEvents {
57
+ itemHeight?: (width: number) => number;
58
+ heightChanged?: (sender: DynamicItemSizeMatrix, height: number) => void;
59
+ }
60
+
61
+ interface DynamicItemSizeMatrixPropsPartial extends UiTypes.MatrixProps {
62
+ fixedItemHeight?: number;
63
+ minItemWidth?: number;
64
+ maxColumns?: number;
65
+ spacing?: number;
66
+ dynamicHeightEnabled?: boolean;
67
+ }
68
+
69
+ export class DynamicItemSizeMatrix extends Base<UIView, UiTypes.ViewOptions> {
70
+ private _props: DynamicItemSizeMatrixProps;
71
+ private _events: DynamicItemSizeMatrixEvents;
72
+ private _itemSizeWidth: number;
73
+ private _itemSizeHeight: number;
74
+ matrix: Matrix;
75
+ _defineView: () => UiTypes.ViewOptions;
76
+
77
+ constructor({ props, layout, events = {} }: {
78
+ props: DynamicItemSizeMatrixPropsPartial;
79
+ layout: (make: MASConstraintMaker, view: UIView) => void;
80
+ events: DynamicItemSizeMatrixEvents;
81
+
82
+ }) {
83
+ super();
84
+ this._props = {
85
+ fixedItemHeight: 40,
86
+ minItemWidth: 96,
87
+ maxColumns: 5,
88
+ spacing: 6,
89
+ maxTotalWidth: 0,
90
+ ...props
91
+ };
92
+ this._events = events;
93
+ const { itemHeight, heightChanged, ...rest } = this._events;
94
+ const _matrixEvents = rest;
95
+ this._itemSizeWidth = 0;
96
+ this._itemSizeHeight = 0;
97
+ this.matrix = new Matrix({
98
+ props: {
99
+ ...this._props,
100
+ scrollEnabled: !this._props.dynamicHeightEnabled
101
+ },
102
+ layout: this._props.maxTotalWidth
103
+ ? (make, view) => {
104
+ make.center.equalTo(view.super);
105
+ make.width.lessThanOrEqualTo(this._props.maxTotalWidth);
106
+ make.width.equalTo(view.super).priority(999);
107
+ make.height.equalTo(view.super);
108
+ }
109
+ : $layout.fill,
110
+ events: {
111
+ ..._matrixEvents,
112
+ itemSize: sender => $size(this._itemSizeWidth, this._itemSizeHeight)
113
+ }
114
+ });
115
+ this._defineView = () => {
116
+ return {
117
+ type: "view",
118
+ props: {
119
+ bgcolor: this._props.bgcolor,
120
+ id: this.id
121
+ },
122
+ layout,
123
+ events: {
124
+ layoutSubviews: sender => {
125
+ sender.relayout();
126
+ const { itemSizeWidth } = this._getColumnsAndItemSizeWidth(
127
+ sender.frame.width,
128
+ this._props.maxTotalWidth,
129
+ this._props.minItemWidth,
130
+ this._props.maxColumns,
131
+ this._props.spacing
132
+ );
133
+
134
+ this._itemSizeWidth = itemSizeWidth;
135
+ this._itemSizeHeight = this._events.itemHeight
136
+ ? this._events.itemHeight(this._itemSizeWidth)
137
+ : this._props.fixedItemHeight;
138
+ this.matrix.view.reload();
139
+ if (this._props.dynamicHeightEnabled) {
140
+ const height = this.heightToWidth(sender.frame.width);
141
+ sender.updateLayout(make => make.height.equalTo(height));
142
+ if (this._events.heightChanged)
143
+ this._events.heightChanged(this, height);
144
+ }
145
+ }
146
+ },
147
+ views: [this.matrix.definition]
148
+ };
149
+ }
150
+ }
151
+
152
+ // 此为纯函数
153
+ _getColumnsAndItemSizeWidth(
154
+ containerWidth: number,
155
+ maxTotalWidth: number,
156
+ minItemWidth: number,
157
+ maxColumns: number,
158
+ spacing: number
159
+ ) {
160
+ const totalWidth = maxTotalWidth
161
+ ? Math.min(maxTotalWidth, containerWidth)
162
+ : containerWidth;
163
+ const columns = Math.max(
164
+ Math.min(
165
+ Math.floor((totalWidth - spacing) / (minItemWidth + spacing)),
166
+ maxColumns
167
+ ),
168
+ 1
169
+ );
170
+ return {
171
+ columns,
172
+ itemSizeWidth: Math.floor((totalWidth - spacing * (columns + 1)) / columns)
173
+ };
174
+ }
175
+
176
+ heightToWidth(width: number) {
177
+ const { columns, itemSizeWidth } = this._getColumnsAndItemSizeWidth(
178
+ width,
179
+ this._props.maxTotalWidth,
180
+ this._props.minItemWidth,
181
+ this._props.maxColumns,
182
+ this._props.spacing
183
+ );
184
+ const rows = Math.ceil(this._props.data.length / columns);
185
+ const itemSizeHeight = this._events.itemHeight
186
+ ? this._events.itemHeight(itemSizeWidth)
187
+ : this._props.fixedItemHeight;
188
+ return rows * itemSizeHeight + (rows + 1) * this._props.spacing;
189
+ }
190
+ }