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.
- package/LICENSE +21 -0
- package/README.md +19 -0
- package/components/alert/input-alert.ts +73 -0
- package/components/alert/login-alert.ts +75 -0
- package/components/alert/plain-alert.ts +49 -0
- package/components/alert/uialert.ts +110 -0
- package/components/artificial-flowlayout.ts +321 -0
- package/components/base.ts +47 -0
- package/components/custom-navigation-bar.ts +570 -0
- package/components/dialogs/dialog-sheet.ts +87 -0
- package/components/dialogs/form-dialog.ts +23 -0
- package/components/dialogs/list-dialog.ts +87 -0
- package/components/dialogs/text-dialog.ts +34 -0
- package/components/dynamic-itemsize-matrix.ts +190 -0
- package/components/dynamic-preference-listview.ts +691 -0
- package/components/dynamic-rowheight-list.ts +62 -0
- package/components/enhanced-imageview.ts +128 -0
- package/components/image-pager.ts +177 -0
- package/components/page-control.ts +91 -0
- package/components/pageviewer-titlebar.ts +170 -0
- package/components/pageviewer.ts +124 -0
- package/components/rotating-view.ts +126 -0
- package/components/searchbar.ts +373 -0
- package/components/sheet.ts +113 -0
- package/components/single-views.ts +828 -0
- package/components/spinners/loading-double-rings.ts +121 -0
- package/components/spinners/loading-dual-ring.ts +90 -0
- package/components/spinners/loading-wedges.ts +112 -0
- package/components/spinners/spinner-androidstyle.ts +264 -0
- package/components/static-preference-listview.ts +991 -0
- package/components/symbol-button.ts +105 -0
- package/components/tabbar.ts +451 -0
- package/controller/base-controller.ts +216 -0
- package/controller/controller-router.ts +74 -0
- package/controller/pageviewer-controller.ts +86 -0
- package/controller/presented-page-controller.ts +57 -0
- package/controller/splitview-controller.ts +323 -0
- package/controller/tabbar-controller.ts +99 -0
- package/package.json +23 -0
- package/test.ts +0 -0
- package/tsconfig.json +121 -0
- package/utils/colors.ts +13 -0
- package/utils/cvid.ts +34 -0
- package/utils/l10n.ts +42 -0
- package/utils/path.ts +100 -0
- package/utils/rect.ts +67 -0
- 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
|
+
}
|