@ticatec/uniface-element 5.0.4 → 5.0.5
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/README.md +10 -10
- package/README_CN.md +13 -12
- package/dist/base-calendar/DateContext.d.ts +1 -0
- package/dist/base-calendar/DateContext.js +5 -8
- package/dist/composite/pagination_panel/PaginationPanel.svelte +5 -2
- package/dist/composite/transfer/Transfer.svelte +0 -1
- package/dist/data_table/DataTable.svelte +31 -1
- package/dist/data_table/DataTable.svelte.d.ts +7 -0
- package/dist/data_table/lib/virtualWindow.d.ts +37 -0
- package/dist/data_table/lib/virtualWindow.js +41 -0
- package/dist/data_table/parts/ActionsPanel.svelte +17 -2
- package/dist/data_table/parts/ActionsPanel.svelte.d.ts +3 -0
- package/dist/data_table/parts/ContentPanel.svelte +26 -1
- package/dist/data_table/parts/ContentPanel.svelte.d.ts +6 -1
- package/dist/data_table/parts/FixedColumnsPanel.svelte +17 -1
- package/dist/data_table/parts/FixedColumnsPanel.svelte.d.ts +4 -1
- package/dist/data_table/parts/FixedHeaderPanel.svelte +1 -2
- package/dist/form/attachment_files/FileUploadBar.svelte +3 -3
- package/dist/form/attachment_files/FileUploadPanel.svelte +1 -1
- package/dist/form/color_picker/ColorPickerPanel.svelte +1 -1
- package/dist/form/date_picker/DateTimePicker.svelte +1 -1
- package/dist/form/options_select/OptionsSelect.svelte +2 -2
- package/dist/i18nRes/i18nRes.d.ts +41 -2
- package/dist/i18nRes/i18nRes.js +2 -1
- package/dist/overlay/dialog/CommonDialog.svelte +1 -1
- package/dist/overlay/dialog/Dialog.svelte +1 -1
- package/dist/overlay/message-box/MessageBox.svelte.js +3 -3
- package/package.json +1 -1
- package/dist/layout/flex/FlexBlock.svelte +0 -17
- package/dist/layout/flex/FlexBlock.svelte.d.ts +0 -38
- package/dist/layout/flex/README.md +0 -148
- package/dist/layout/flex/README_CN.md +0 -148
- package/dist/layout/flex/index.d.ts +0 -2
- package/dist/layout/flex/index.js +0 -2
- package/dist/layout/index.d.ts +0 -0
- package/dist/layout/index.js +0 -1
package/README.md
CHANGED
|
@@ -185,9 +185,9 @@ The library uses CSS custom properties for theming. You can customize the appear
|
|
|
185
185
|
|
|
186
186
|
The library includes built-in internationalization support:
|
|
187
187
|
|
|
188
|
-
default language is
|
|
188
|
+
The default language is English. Other languages are loaded dynamically at runtime, so adding a new language never requires a code change.
|
|
189
189
|
|
|
190
|
-
|
|
190
|
+
Create a language resource json file in the static web directory, example: `/assets/uniface_zh-CN.json` (this is the complete key list):
|
|
191
191
|
```json
|
|
192
192
|
{
|
|
193
193
|
"uniface": {
|
|
@@ -195,7 +195,9 @@ create a language resource json file in the static web directory, example: `/ass
|
|
|
195
195
|
"btnClose": "关闭",
|
|
196
196
|
"btnCancel": "取消",
|
|
197
197
|
"btnConfirm": "确定",
|
|
198
|
-
"textMore": "加载更多"
|
|
198
|
+
"textMore": "加载更多",
|
|
199
|
+
"filterPlaceholder": "搜索...",
|
|
200
|
+
"noResultsText": "无匹配结果..."
|
|
199
201
|
},
|
|
200
202
|
"colorPicker": "选择颜色",
|
|
201
203
|
"calendar": {
|
|
@@ -218,14 +220,12 @@ create a language resource json file in the static web directory, example: `/ass
|
|
|
218
220
|
"btnRemove": "删除",
|
|
219
221
|
"btnPickup": "选择文件"
|
|
220
222
|
},
|
|
221
|
-
"propertyEditor": {
|
|
222
|
-
"colName": "属性",
|
|
223
|
-
"colValue": "值"
|
|
224
|
-
},
|
|
225
223
|
"dataTable": {
|
|
226
224
|
"rowNo": "#",
|
|
227
225
|
"actions": "操作",
|
|
228
|
-
"emptyDataSet": "暂无数据"
|
|
226
|
+
"emptyDataSet": "暂无数据",
|
|
227
|
+
"totalInfo": "共 <b>{{total}}</b> 条",
|
|
228
|
+
"rowsPerPage": "行/页"
|
|
229
229
|
},
|
|
230
230
|
"transfer": {
|
|
231
231
|
"selectIndicator": "已选择: {{selected}}/{{total}}"
|
|
@@ -234,14 +234,14 @@ create a language resource json file in the static web directory, example: `/ass
|
|
|
234
234
|
}
|
|
235
235
|
```
|
|
236
236
|
|
|
237
|
-
|
|
237
|
+
Load the resource file in `+page.svelte` or another startup page:
|
|
238
238
|
|
|
239
239
|
```typescript
|
|
240
240
|
import i18n, {i18nUtils} from "@ticatec/i18n";
|
|
241
241
|
|
|
242
242
|
// 设置语言
|
|
243
243
|
i18n.setLanguage('zh-CN'); // 或 'en'
|
|
244
|
-
i18nUtils.loadResources('/assets/uniface.json'); //the language code will insert before .json
|
|
244
|
+
i18nUtils.loadResources('/assets/uniface.json'); // the language code will insert before .json => /assets/uniface_zh-CN.json
|
|
245
245
|
```
|
|
246
246
|
|
|
247
247
|
## Available Imports
|
package/README_CN.md
CHANGED
|
@@ -261,10 +261,11 @@ await messageBox.showInfo("操作完成", { title: "提示" });
|
|
|
261
261
|
|
|
262
262
|
## 国际化
|
|
263
263
|
|
|
264
|
-
|
|
264
|
+
组件库内置国际化支持:
|
|
265
265
|
|
|
266
|
-
|
|
267
|
-
|
|
266
|
+
默认语言为英文。其他语言在运行时动态加载,未来新增语言无需修改代码。
|
|
267
|
+
|
|
268
|
+
在静态资源目录下创建语言资源 json 文件,例如 `/assets/uniface_zh-CN.json`(以下为完整键列表):
|
|
268
269
|
```json
|
|
269
270
|
{
|
|
270
271
|
"uniface": {
|
|
@@ -272,7 +273,9 @@ await messageBox.showInfo("操作完成", { title: "提示" });
|
|
|
272
273
|
"btnClose": "关闭",
|
|
273
274
|
"btnCancel": "取消",
|
|
274
275
|
"btnConfirm": "确定",
|
|
275
|
-
"textMore": "加载更多"
|
|
276
|
+
"textMore": "加载更多",
|
|
277
|
+
"filterPlaceholder": "搜索...",
|
|
278
|
+
"noResultsText": "无匹配结果..."
|
|
276
279
|
},
|
|
277
280
|
"colorPicker": "选择颜色",
|
|
278
281
|
"calendar": {
|
|
@@ -295,14 +298,12 @@ await messageBox.showInfo("操作完成", { title: "提示" });
|
|
|
295
298
|
"btnRemove": "删除",
|
|
296
299
|
"btnPickup": "选择文件"
|
|
297
300
|
},
|
|
298
|
-
"propertyEditor": {
|
|
299
|
-
"colName": "属性",
|
|
300
|
-
"colValue": "值"
|
|
301
|
-
},
|
|
302
301
|
"dataTable": {
|
|
303
302
|
"rowNo": "#",
|
|
304
303
|
"actions": "操作",
|
|
305
|
-
"emptyDataSet": "暂无数据"
|
|
304
|
+
"emptyDataSet": "暂无数据",
|
|
305
|
+
"totalInfo": "共 <b>{{total}}</b> 条",
|
|
306
|
+
"rowsPerPage": "行/页"
|
|
306
307
|
},
|
|
307
308
|
"transfer": {
|
|
308
309
|
"selectIndicator": "已选择: {{selected}}/{{total}}"
|
|
@@ -311,16 +312,16 @@ await messageBox.showInfo("操作完成", { title: "提示" });
|
|
|
311
312
|
}
|
|
312
313
|
```
|
|
313
314
|
|
|
315
|
+
在 `+page.svelte` 或其他启动页加载资源文件:
|
|
316
|
+
|
|
314
317
|
```typescript
|
|
315
318
|
import i18n, {i18nUtils} from "@ticatec/i18n";
|
|
316
319
|
|
|
317
320
|
// 设置语言
|
|
318
321
|
i18n.setLanguage('zh-CN'); // 或 'en'
|
|
319
|
-
i18nUtils.loadResources('/assets/uniface.json');
|
|
322
|
+
i18nUtils.loadResources('/assets/uniface.json'); // 语言代码会插入到 .json 之前 => /assets/uniface_zh-CN.json
|
|
320
323
|
```
|
|
321
324
|
|
|
322
|
-
|
|
323
|
-
|
|
324
325
|
## 可用导入
|
|
325
326
|
|
|
326
327
|
### 模块化导入
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import i18nRes from "../i18nRes";
|
|
2
1
|
import i18n from "@ticatec/i18n";
|
|
2
|
+
import "../i18nRes"; // side effect: seeds the uniface namespace defaults used by i18n.get() below
|
|
3
3
|
export default class DateContext {
|
|
4
4
|
_weekBegin = 1;
|
|
5
5
|
_dateFmt = "YYYY-MM-DD";
|
|
@@ -14,19 +14,16 @@ export default class DateContext {
|
|
|
14
14
|
return DateContext.instance;
|
|
15
15
|
}
|
|
16
16
|
get months() {
|
|
17
|
-
return
|
|
17
|
+
return i18n.get('uniface.calendar.months');
|
|
18
18
|
}
|
|
19
19
|
get monthsAbbr() {
|
|
20
|
-
return
|
|
21
|
-
;
|
|
20
|
+
return i18n.get('uniface.calendar.monthsAbbr');
|
|
22
21
|
}
|
|
23
22
|
get weekTitle() {
|
|
24
|
-
return
|
|
25
|
-
;
|
|
23
|
+
return i18n.get('uniface.calendar.weekTitle');
|
|
26
24
|
}
|
|
27
25
|
get weekTitleAbbr() {
|
|
28
|
-
return
|
|
29
|
-
;
|
|
26
|
+
return i18n.get('uniface.calendar.weekTitleAbbr');
|
|
30
27
|
}
|
|
31
28
|
set weekBegin(value) {
|
|
32
29
|
if (value < 0 || value > 6) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import Pagination from "../../navigation/pagination";
|
|
3
3
|
import OptionsSelect from "../../form/options_select";
|
|
4
|
+
import i18nRes from "../../i18nRes";
|
|
4
5
|
import type {GenerateTotalInfo, OnPageChange, OnPageSizeChange} from "../../types";
|
|
5
6
|
|
|
6
7
|
interface Props {
|
|
@@ -29,7 +30,7 @@
|
|
|
29
30
|
total = 0,
|
|
30
31
|
generateInfo,
|
|
31
32
|
rowCount = $bindable(25),
|
|
32
|
-
rowCountLabel =
|
|
33
|
+
rowCountLabel = i18nRes.dataTable.rowsPerPage(),
|
|
33
34
|
align = '',
|
|
34
35
|
onPageSizeChange,
|
|
35
36
|
onchange,
|
|
@@ -40,10 +41,12 @@
|
|
|
40
41
|
);
|
|
41
42
|
// Rendered via {@html} below: generateInfo is a trusted, caller-supplied
|
|
42
43
|
// renderer (not user input) — same opt-in-HTML boundary as DataColumn#renderHTML.
|
|
44
|
+
// The default text comes from the i18n resources (dataTable.totalInfo), so it
|
|
45
|
+
// follows the active language instead of being hardcoded English.
|
|
43
46
|
let totalText = $derived(
|
|
44
47
|
generateInfo
|
|
45
48
|
? generateInfo(total, pageCount, pageNo, rowCount)
|
|
46
|
-
:
|
|
49
|
+
: i18nRes.dataTable.totalInfo({total})
|
|
47
50
|
);
|
|
48
51
|
|
|
49
52
|
const handleRowCountChange = () => {
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import { OrderDirection } from "./lib/OrderDirection";
|
|
12
12
|
import type { CompareFunction } from "./lib/CompareFunction";
|
|
13
13
|
import type { GetRowFontStyle } from "../types";
|
|
14
|
+
import { computeVirtualWindow } from "./lib/virtualWindow";
|
|
14
15
|
|
|
15
16
|
interface Props {
|
|
16
17
|
columns: Array<DataColumn>;
|
|
@@ -26,6 +27,13 @@
|
|
|
26
27
|
emptyIndicator?: string;
|
|
27
28
|
getRowFontStyle?: GetRowFontStyle<T>;
|
|
28
29
|
style?: string;
|
|
30
|
+
/**
|
|
31
|
+
* 行虚拟化(窗口化渲染):仅渲染可视区域附近的行,大数据集(数千行以上)
|
|
32
|
+
* 建议开启。要求所有行高度一致(即统一的 rowHeight),因此默认关闭。
|
|
33
|
+
*/
|
|
34
|
+
virtual?: boolean;
|
|
35
|
+
/** 虚拟化时可视区上下额外渲染的行数。 */
|
|
36
|
+
overscan?: number;
|
|
29
37
|
}
|
|
30
38
|
|
|
31
39
|
let {
|
|
@@ -42,6 +50,8 @@
|
|
|
42
50
|
emptyIndicator = undefined,
|
|
43
51
|
getRowFontStyle = undefined,
|
|
44
52
|
style = '',
|
|
53
|
+
virtual = false,
|
|
54
|
+
overscan = 8,
|
|
45
55
|
}: Props = $props();
|
|
46
56
|
|
|
47
57
|
const id: string = Math.round(new Date().getTime() + Math.random() * 1000).toString(36);
|
|
@@ -59,6 +69,23 @@
|
|
|
59
69
|
let scrollTop = $state(0);
|
|
60
70
|
let inlineComponent = $state<any>(null);
|
|
61
71
|
|
|
72
|
+
// Measured by ContentPanel (its scrollable data area); drives the virtual window.
|
|
73
|
+
let viewportHeight = $state(0);
|
|
74
|
+
let expandIndex = $derived(expandRow ? rows.indexOf(expandRow) : -1);
|
|
75
|
+
// One shared window for all three panels (frozen / content / actions), so the
|
|
76
|
+
// slices they render always cover the same absolute row indices.
|
|
77
|
+
let vwindow = $derived(virtual
|
|
78
|
+
? computeVirtualWindow({
|
|
79
|
+
scrollTop,
|
|
80
|
+
viewportHeight,
|
|
81
|
+
rowHeight,
|
|
82
|
+
count: rows.length,
|
|
83
|
+
overscan,
|
|
84
|
+
expandIndex,
|
|
85
|
+
inlineRowHeight
|
|
86
|
+
})
|
|
87
|
+
: null);
|
|
88
|
+
|
|
62
89
|
let orderColumn = $state<DataColumn | null>(null);
|
|
63
90
|
let orderDirection = $state<OrderDirection>(OrderDirection.Ascending);
|
|
64
91
|
|
|
@@ -162,6 +189,7 @@
|
|
|
162
189
|
{handleWidthChange}
|
|
163
190
|
width={frozenWidth}
|
|
164
191
|
bind:scrollTop
|
|
192
|
+
{vwindow}
|
|
165
193
|
/>
|
|
166
194
|
{/if}
|
|
167
195
|
|
|
@@ -185,10 +213,12 @@
|
|
|
185
213
|
displayHorizontalScroll={actionsColumn != null || indicatorColumn != null || fixedCols.length > 0}
|
|
186
214
|
showVerticalScroll={actionsColumn == null}
|
|
187
215
|
{getRowFontStyle}
|
|
216
|
+
{vwindow}
|
|
217
|
+
bind:viewportHeight
|
|
188
218
|
/>
|
|
189
219
|
{/if}
|
|
190
220
|
|
|
191
221
|
{#if actionsColumn}
|
|
192
|
-
<ActionPanel {expandRow} {rowHeight} {headerHeight} {actionsColumn} {rows} {inlineRowHeight} bind:scrollTop />
|
|
222
|
+
<ActionPanel {expandRow} {rowHeight} {headerHeight} {actionsColumn} {rows} {inlineRowHeight} bind:scrollTop {vwindow} />
|
|
193
223
|
{/if}
|
|
194
224
|
</div>
|
|
@@ -17,6 +17,13 @@ declare function $$render<T = any>(): {
|
|
|
17
17
|
emptyIndicator?: string;
|
|
18
18
|
getRowFontStyle?: GetRowFontStyle<T>;
|
|
19
19
|
style?: string;
|
|
20
|
+
/**
|
|
21
|
+
* 行虚拟化(窗口化渲染):仅渲染可视区域附近的行,大数据集(数千行以上)
|
|
22
|
+
* 建议开启。要求所有行高度一致(即统一的 rowHeight),因此默认关闭。
|
|
23
|
+
*/
|
|
24
|
+
virtual?: boolean;
|
|
25
|
+
/** 虚拟化时可视区上下额外渲染的行数。 */
|
|
26
|
+
overscan?: number;
|
|
20
27
|
};
|
|
21
28
|
exports: {};
|
|
22
29
|
bindings: "inlineRowHeight" | "selectedRows";
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Row-windowing math for the DataTable's opt-in virtual scrolling.
|
|
3
|
+
*
|
|
4
|
+
* The table renders three vertically synced panels (frozen columns, data
|
|
5
|
+
* content, actions). Each panel renders only the rows inside the computed
|
|
6
|
+
* window, with a top and bottom spacer so the scroll container keeps its
|
|
7
|
+
* full natural scrollHeight (the native scrollbar and the existing
|
|
8
|
+
* wheel/scroll sync logic keep working unchanged).
|
|
9
|
+
*
|
|
10
|
+
* All rows share one fixed `rowHeight`; at most one row (`expandIndex`) has
|
|
11
|
+
* an inline expansion panel of `inlineRowHeight` rendered directly below it.
|
|
12
|
+
*/
|
|
13
|
+
export interface VirtualWindow {
|
|
14
|
+
/** Index of the first rendered row (inclusive). */
|
|
15
|
+
start: number;
|
|
16
|
+
/** Index just past the last rendered row (exclusive). */
|
|
17
|
+
end: number;
|
|
18
|
+
/** Height (px) of the spacer above the rendered rows. */
|
|
19
|
+
topPad: number;
|
|
20
|
+
/** Height (px) of the spacer below the rendered rows. */
|
|
21
|
+
bottomPad: number;
|
|
22
|
+
}
|
|
23
|
+
export interface VirtualWindowInput {
|
|
24
|
+
scrollTop: number;
|
|
25
|
+
/** Height (px) of the scrollable viewport. 0 is tolerated (renders overscan only). */
|
|
26
|
+
viewportHeight: number;
|
|
27
|
+
rowHeight: number;
|
|
28
|
+
/** Total number of rows. */
|
|
29
|
+
count: number;
|
|
30
|
+
/** Extra rows rendered above and below the visible range. */
|
|
31
|
+
overscan?: number;
|
|
32
|
+
/** Index of the expanded row, or -1 when none. */
|
|
33
|
+
expandIndex?: number;
|
|
34
|
+
/** Height (px) of the inline expansion panel below the expanded row. */
|
|
35
|
+
inlineRowHeight?: number;
|
|
36
|
+
}
|
|
37
|
+
export declare function computeVirtualWindow(input: VirtualWindowInput): VirtualWindow;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Row-windowing math for the DataTable's opt-in virtual scrolling.
|
|
3
|
+
*
|
|
4
|
+
* The table renders three vertically synced panels (frozen columns, data
|
|
5
|
+
* content, actions). Each panel renders only the rows inside the computed
|
|
6
|
+
* window, with a top and bottom spacer so the scroll container keeps its
|
|
7
|
+
* full natural scrollHeight (the native scrollbar and the existing
|
|
8
|
+
* wheel/scroll sync logic keep working unchanged).
|
|
9
|
+
*
|
|
10
|
+
* All rows share one fixed `rowHeight`; at most one row (`expandIndex`) has
|
|
11
|
+
* an inline expansion panel of `inlineRowHeight` rendered directly below it.
|
|
12
|
+
*/
|
|
13
|
+
/** Top offset (px) of row `i`, accounting for an expansion panel above it. */
|
|
14
|
+
const rowTop = (i, rowHeight, expandIndex, inlineRowHeight) => i * rowHeight + (expandIndex >= 0 && i > expandIndex ? inlineRowHeight : 0);
|
|
15
|
+
export function computeVirtualWindow(input) {
|
|
16
|
+
const { scrollTop, viewportHeight, rowHeight, count } = input;
|
|
17
|
+
const overscan = input.overscan ?? 8;
|
|
18
|
+
const expandIndex = input.expandIndex ?? -1;
|
|
19
|
+
const inlineRowHeight = expandIndex >= 0 ? (input.inlineRowHeight ?? 0) : 0;
|
|
20
|
+
if (count === 0 || rowHeight <= 0) {
|
|
21
|
+
return { start: 0, end: 0, topPad: 0, bottomPad: 0 };
|
|
22
|
+
}
|
|
23
|
+
const st = Math.max(0, scrollTop);
|
|
24
|
+
// First row whose bottom edge is below the viewport top.
|
|
25
|
+
let start = Math.floor(st / rowHeight);
|
|
26
|
+
if (expandIndex >= 0 && start > expandIndex) {
|
|
27
|
+
// The viewport top sits below the expanded row: shift the estimate by the
|
|
28
|
+
// expansion panel's height. Clamping to expandIndex keeps the expanded
|
|
29
|
+
// row (and with it the inline panel, which is rendered inside the #each
|
|
30
|
+
// body next to its row) in the window while any part of the panel is
|
|
31
|
+
// visible.
|
|
32
|
+
start = Math.max(expandIndex, Math.floor((st - inlineRowHeight) / rowHeight));
|
|
33
|
+
}
|
|
34
|
+
start = Math.max(0, Math.min(start, count - 1) - overscan);
|
|
35
|
+
const visibleCount = Math.ceil(viewportHeight / rowHeight) + 1;
|
|
36
|
+
let end = Math.min(count, start + visibleCount + overscan * 2);
|
|
37
|
+
const totalHeight = count * rowHeight + inlineRowHeight;
|
|
38
|
+
const topPad = rowTop(start, rowHeight, expandIndex, inlineRowHeight);
|
|
39
|
+
const bottomPad = totalHeight - rowTop(end, rowHeight, expandIndex, inlineRowHeight);
|
|
40
|
+
return { start, end, topPad, bottomPad };
|
|
41
|
+
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import type TableRow from "./TableRow";
|
|
5
5
|
import { onDestroy, onMount } from "svelte";
|
|
6
6
|
import i18nRes from "../../i18nRes";
|
|
7
|
+
import type { VirtualWindow } from "../lib/virtualWindow";
|
|
7
8
|
|
|
8
9
|
interface Props {
|
|
9
10
|
actionsColumn: ActionsColumn;
|
|
@@ -13,6 +14,8 @@
|
|
|
13
14
|
expandRow?: TableRow | null;
|
|
14
15
|
rowHeight?: number;
|
|
15
16
|
headerHeight?: number;
|
|
17
|
+
/** Row window when virtual scrolling is on; null renders every row. */
|
|
18
|
+
vwindow?: VirtualWindow | null;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
let {
|
|
@@ -23,8 +26,13 @@
|
|
|
23
26
|
expandRow = null,
|
|
24
27
|
rowHeight,
|
|
25
28
|
headerHeight,
|
|
29
|
+
vwindow = null,
|
|
26
30
|
}: Props = $props();
|
|
27
31
|
|
|
32
|
+
// Virtual scrolling: same shared window as the other panels.
|
|
33
|
+
let visibleRows = $derived(vwindow ? rows.slice(vwindow.start, vwindow.end) : rows);
|
|
34
|
+
let startIndex = $derived(vwindow ? vwindow.start : 0);
|
|
35
|
+
|
|
28
36
|
const handleActionPanelScroll = (e: Event) => {
|
|
29
37
|
const target = e.target as HTMLDivElement;
|
|
30
38
|
scrollTop = target.scrollTop;
|
|
@@ -54,7 +62,7 @@
|
|
|
54
62
|
resizeObserver?.disconnect();
|
|
55
63
|
});
|
|
56
64
|
|
|
57
|
-
let actionText = i18nRes.dataTable.actions;
|
|
65
|
+
let actionText = i18nRes.dataTable.actions();
|
|
58
66
|
</script>
|
|
59
67
|
|
|
60
68
|
<div class="action-panel" bind:this={panel} style="user-select: none; width: {actionsColumn.width}px;">
|
|
@@ -65,7 +73,11 @@
|
|
|
65
73
|
</div>
|
|
66
74
|
<div bind:this={scrollPanel} class="rows-container" style="overflow-y: auto" onscroll={handleActionPanelScroll}>
|
|
67
75
|
<div>
|
|
68
|
-
{#
|
|
76
|
+
{#if vwindow}
|
|
77
|
+
<div style="height: {vwindow.topPad}px"></div>
|
|
78
|
+
{/if}
|
|
79
|
+
{#each visibleRows as row, i (startIndex + i)}
|
|
80
|
+
{@const idx = startIndex + i}
|
|
69
81
|
<ActionsRow
|
|
70
82
|
{row}
|
|
71
83
|
{rowHeight}
|
|
@@ -79,6 +91,9 @@
|
|
|
79
91
|
<div class="inline-panel" style="height: {inlineRowHeight ?? 0}px"> </div>
|
|
80
92
|
{/if}
|
|
81
93
|
{/each}
|
|
94
|
+
{#if vwindow}
|
|
95
|
+
<div style="height: {vwindow.bottomPad}px"></div>
|
|
96
|
+
{/if}
|
|
82
97
|
</div>
|
|
83
98
|
</div>
|
|
84
99
|
<div class="bottom-mask-overlay">
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type ActionsColumn from "../lib/ActionsColumn";
|
|
2
2
|
import type TableRow from "./TableRow";
|
|
3
|
+
import type { VirtualWindow } from "../lib/virtualWindow";
|
|
3
4
|
interface Props {
|
|
4
5
|
actionsColumn: ActionsColumn;
|
|
5
6
|
scrollTop?: number;
|
|
@@ -8,6 +9,8 @@ interface Props {
|
|
|
8
9
|
expandRow?: TableRow | null;
|
|
9
10
|
rowHeight?: number;
|
|
10
11
|
headerHeight?: number;
|
|
12
|
+
/** Row window when virtual scrolling is on; null renders every row. */
|
|
13
|
+
vwindow?: VirtualWindow | null;
|
|
11
14
|
}
|
|
12
15
|
declare const ActionsPanel: import("svelte").Component<Props, {}, "scrollTop">;
|
|
13
16
|
type ActionsPanel = ReturnType<typeof ActionsPanel>;
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import UniDataTable, { type TableEventHandler } from "../UniDataTable";
|
|
8
8
|
import { OrderDirection } from "../lib/OrderDirection";
|
|
9
9
|
import type { GetRowFontStyle } from "../../types";
|
|
10
|
+
import type { VirtualWindow } from "../lib/virtualWindow";
|
|
10
11
|
|
|
11
12
|
interface Props {
|
|
12
13
|
columns: Array<DataColumn>;
|
|
@@ -28,6 +29,10 @@
|
|
|
28
29
|
handleWidthChange?: TableEventHandler;
|
|
29
30
|
handleCellClick?: (col: DataColumn) => any;
|
|
30
31
|
tabWidth: number;
|
|
32
|
+
/** Row window when virtual scrolling is on; null renders every row. */
|
|
33
|
+
vwindow?: VirtualWindow | null;
|
|
34
|
+
/** Measured height of the scrollable data area (drives the virtual window). */
|
|
35
|
+
viewportHeight?: number;
|
|
31
36
|
}
|
|
32
37
|
|
|
33
38
|
let {
|
|
@@ -50,6 +55,8 @@
|
|
|
50
55
|
handleWidthChange,
|
|
51
56
|
handleCellClick,
|
|
52
57
|
tabWidth = $bindable(0),
|
|
58
|
+
vwindow = null,
|
|
59
|
+
viewportHeight = $bindable(0),
|
|
53
60
|
}: Props = $props();
|
|
54
61
|
|
|
55
62
|
let scrollLeft = $state(0);
|
|
@@ -62,8 +69,13 @@
|
|
|
62
69
|
onMount(() => {
|
|
63
70
|
resizeObserver = new ResizeObserver(() => {
|
|
64
71
|
viewWidth = Math.round(viewPanel?.clientWidth) - 1;
|
|
72
|
+
viewportHeight = dataPanel?.clientHeight ?? 0;
|
|
65
73
|
});
|
|
66
74
|
resizeObserver.observe(viewPanel);
|
|
75
|
+
if (dataPanel) {
|
|
76
|
+
resizeObserver.observe(dataPanel);
|
|
77
|
+
viewportHeight = dataPanel.clientHeight ?? 0;
|
|
78
|
+
}
|
|
67
79
|
});
|
|
68
80
|
|
|
69
81
|
onDestroy(() => {
|
|
@@ -117,6 +129,12 @@
|
|
|
117
129
|
|
|
118
130
|
let rowWidth = $derived(Math.max(viewWidth, tabWidth));
|
|
119
131
|
let hasWhitespace = $derived(viewWidth > tabWidth);
|
|
132
|
+
|
|
133
|
+
// Virtual scrolling: render only the windowed slice, padded by spacers so the
|
|
134
|
+
// scroll container keeps its full natural scrollHeight. `startIndex` keeps the
|
|
135
|
+
// rendered rows' absolute indices (striping, keys) stable while scrolling.
|
|
136
|
+
let visibleRows = $derived(vwindow ? rows.slice(vwindow.start, vwindow.end) : rows);
|
|
137
|
+
let startIndex = $derived(vwindow ? vwindow.start : 0);
|
|
120
138
|
</script>
|
|
121
139
|
|
|
122
140
|
<div class="data-content-panel" bind:this={viewPanel}>
|
|
@@ -140,7 +158,11 @@
|
|
|
140
158
|
>
|
|
141
159
|
{#if rows && rows.length > 0}
|
|
142
160
|
<div style="box-sizing: border-box; width: {rowWidth}px; top: 0px">
|
|
143
|
-
{#
|
|
161
|
+
{#if vwindow}
|
|
162
|
+
<div style="height: {vwindow.topPad}px"></div>
|
|
163
|
+
{/if}
|
|
164
|
+
{#each visibleRows as row, i (startIndex + i)}
|
|
165
|
+
{@const idx = startIndex + i}
|
|
144
166
|
<DataRow
|
|
145
167
|
fontStyle={getRowFontStyle?.(row.data)}
|
|
146
168
|
{rowHeight}
|
|
@@ -161,6 +183,9 @@
|
|
|
161
183
|
</div>
|
|
162
184
|
{/if}
|
|
163
185
|
{/each}
|
|
186
|
+
{#if vwindow}
|
|
187
|
+
<div style="height: {vwindow.bottomPad}px"></div>
|
|
188
|
+
{/if}
|
|
164
189
|
</div>
|
|
165
190
|
{:else}
|
|
166
191
|
<div class="empty-content-board" style="width: 100%">
|
|
@@ -3,6 +3,7 @@ import type TableRow from "./TableRow";
|
|
|
3
3
|
import UniDataTable, { type TableEventHandler } from "../UniDataTable";
|
|
4
4
|
import { OrderDirection } from "../lib/OrderDirection";
|
|
5
5
|
import type { GetRowFontStyle } from "../../types";
|
|
6
|
+
import type { VirtualWindow } from "../lib/virtualWindow";
|
|
6
7
|
interface Props {
|
|
7
8
|
columns: Array<DataColumn>;
|
|
8
9
|
rows: Array<TableRow>;
|
|
@@ -23,7 +24,11 @@ interface Props {
|
|
|
23
24
|
handleWidthChange?: TableEventHandler;
|
|
24
25
|
handleCellClick?: (col: DataColumn) => any;
|
|
25
26
|
tabWidth: number;
|
|
27
|
+
/** Row window when virtual scrolling is on; null renders every row. */
|
|
28
|
+
vwindow?: VirtualWindow | null;
|
|
29
|
+
/** Measured height of the scrollable data area (drives the virtual window). */
|
|
30
|
+
viewportHeight?: number;
|
|
26
31
|
}
|
|
27
|
-
declare const ContentPanel: import("svelte").Component<Props, {}, "
|
|
32
|
+
declare const ContentPanel: import("svelte").Component<Props, {}, "scrollTop" | "viewportHeight" | "rows" | "inlineRowHeight" | "tabWidth">;
|
|
28
33
|
type ContentPanel = ReturnType<typeof ContentPanel>;
|
|
29
34
|
export default ContentPanel;
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import type DataColumn from "../lib/DataColumn";
|
|
11
11
|
import FixedHeaderPanel from "./FixedHeaderPanel.svelte";
|
|
12
12
|
import { OrderDirection } from "../lib/OrderDirection";
|
|
13
|
+
import type { VirtualWindow } from "../lib/virtualWindow";
|
|
13
14
|
|
|
14
15
|
interface Props {
|
|
15
16
|
fixedCols?: Array<DataColumn>;
|
|
@@ -27,6 +28,8 @@
|
|
|
27
28
|
rowHeight?: number;
|
|
28
29
|
headerHeight?: number;
|
|
29
30
|
inlineRowHeight?: number;
|
|
31
|
+
/** Row window when virtual scrolling is on; null renders every row. */
|
|
32
|
+
vwindow?: VirtualWindow | null;
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
let {
|
|
@@ -45,8 +48,14 @@
|
|
|
45
48
|
rowHeight,
|
|
46
49
|
headerHeight,
|
|
47
50
|
inlineRowHeight = 0,
|
|
51
|
+
vwindow = null,
|
|
48
52
|
}: Props = $props();
|
|
49
53
|
|
|
54
|
+
// Virtual scrolling: same shared window as the other panels, so all three
|
|
55
|
+
// render the same absolute row indices (selection state and striping use them).
|
|
56
|
+
let visibleRows = $derived(vwindow ? (rows ?? []).slice(vwindow.start, vwindow.end) : (rows ?? []));
|
|
57
|
+
let startIndex = $derived(vwindow ? vwindow.start : 0);
|
|
58
|
+
|
|
50
59
|
let selectionMode = $state<SelectionMode>(SelectionMode.None);
|
|
51
60
|
|
|
52
61
|
let selectable = $derived(indicatorColumn?.selectable == true);
|
|
@@ -133,7 +142,11 @@
|
|
|
133
142
|
/>
|
|
134
143
|
<div class="rows-container" bind:this={viewPanel} onwheel={handleWheelEvent}>
|
|
135
144
|
<div>
|
|
136
|
-
{#
|
|
145
|
+
{#if vwindow}
|
|
146
|
+
<div style="height: {vwindow.topPad}px"></div>
|
|
147
|
+
{/if}
|
|
148
|
+
{#each visibleRows as row, i (startIndex + i)}
|
|
149
|
+
{@const idx = startIndex + i}
|
|
137
150
|
<FixedRow
|
|
138
151
|
rowNo={idx + 1}
|
|
139
152
|
{row}
|
|
@@ -153,6 +166,9 @@
|
|
|
153
166
|
<div class="inline-panel" style="height: {inlineRowHeight}px"> </div>
|
|
154
167
|
{/if}
|
|
155
168
|
{/each}
|
|
169
|
+
{#if vwindow}
|
|
170
|
+
<div style="height: {vwindow.bottomPad}px"></div>
|
|
171
|
+
{/if}
|
|
156
172
|
</div>
|
|
157
173
|
</div>
|
|
158
174
|
<div class="bottom-mask-overlay">
|
|
@@ -3,6 +3,7 @@ import type { IndicatorColumn } from "..";
|
|
|
3
3
|
import { type RowEventHandler, type TableEventHandler } from "../UniDataTable";
|
|
4
4
|
import type DataColumn from "../lib/DataColumn";
|
|
5
5
|
import { OrderDirection } from "../lib/OrderDirection";
|
|
6
|
+
import type { VirtualWindow } from "../lib/virtualWindow";
|
|
6
7
|
interface Props {
|
|
7
8
|
fixedCols?: Array<DataColumn>;
|
|
8
9
|
indicatorColumn?: IndicatorColumn | null;
|
|
@@ -19,7 +20,9 @@ interface Props {
|
|
|
19
20
|
rowHeight?: number;
|
|
20
21
|
headerHeight?: number;
|
|
21
22
|
inlineRowHeight?: number;
|
|
23
|
+
/** Row window when virtual scrolling is on; null renders every row. */
|
|
24
|
+
vwindow?: VirtualWindow | null;
|
|
22
25
|
}
|
|
23
|
-
declare const FixedColumnsPanel: import("svelte").Component<Props, {}, "
|
|
26
|
+
declare const FixedColumnsPanel: import("svelte").Component<Props, {}, "scrollTop" | "expandRow" | "selectedRows">;
|
|
24
27
|
type FixedColumnsPanel = ReturnType<typeof FixedColumnsPanel>;
|
|
25
28
|
export default FixedColumnsPanel;
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import type DataColumn from "../lib/DataColumn";
|
|
3
3
|
import type { IndicatorColumn } from "..";
|
|
4
4
|
import { type SelectionEventHandler, SelectionMode, type TableEventHandler } from "../UniDataTable";
|
|
5
|
-
import utils from "../../overlay/common/utils";
|
|
6
5
|
import { OrderDirection } from "../lib/OrderDirection";
|
|
7
6
|
import i18nRes from "../../i18nRes";
|
|
8
7
|
|
|
@@ -107,7 +106,7 @@
|
|
|
107
106
|
{:else}
|
|
108
107
|
<div style="text-align: center" class="vertical-center">
|
|
109
108
|
{#if indicatorColumn.displayNo}
|
|
110
|
-
<span>{i18nRes.dataTable.rowNo}</span>
|
|
109
|
+
<span>{i18nRes.dataTable.rowNo()}</span>
|
|
111
110
|
{/if}
|
|
112
111
|
</div>
|
|
113
112
|
{/if}
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
let status: ProgressStatus = $state(getInitialStatus());
|
|
19
19
|
let progress: number = $state(0);
|
|
20
20
|
|
|
21
|
-
let cancelLabel: string = i18nRes.common.btnCancel
|
|
22
|
-
let retryLabel: string = i18nRes.upload.btnRetry
|
|
23
|
-
let removeLabel: string = i18nRes.upload.btnRemove
|
|
21
|
+
let cancelLabel: string = i18nRes.common.btnCancel();
|
|
22
|
+
let retryLabel: string = i18nRes.upload.btnRetry();
|
|
23
|
+
let removeLabel: string = i18nRes.upload.btnRemove();
|
|
24
24
|
|
|
25
25
|
const cancelUpload = async () => {
|
|
26
26
|
if (await file.cancel()) {
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
};
|
|
45
45
|
|
|
46
46
|
const format = $derived(dateFmts[precision]);
|
|
47
|
-
const confirmText = $derived(i18nRes.calendar.confirmText
|
|
47
|
+
const confirmText = $derived(i18nRes.calendar.confirmText());
|
|
48
48
|
|
|
49
49
|
let isOpen = $state(false);
|
|
50
50
|
let currentValue = $state<dayjs.Dayjs>(dayjs());
|
|
@@ -42,9 +42,9 @@
|
|
|
42
42
|
onchange,
|
|
43
43
|
onfocus,
|
|
44
44
|
onblur,
|
|
45
|
-
filterPlaceholder = i18nRes.common.filterPlaceholder
|
|
45
|
+
filterPlaceholder = i18nRes.common.filterPlaceholder(),
|
|
46
46
|
filterFunction,
|
|
47
|
-
noResultsText = i18nRes.common.noResultsText
|
|
47
|
+
noResultsText = i18nRes.common.noResultsText(),
|
|
48
48
|
itemRender,
|
|
49
49
|
}: Props = $props();
|
|
50
50
|
|
|
@@ -1,3 +1,42 @@
|
|
|
1
|
-
import {
|
|
2
|
-
declare const
|
|
1
|
+
import type { ResourceProxy } from "@ticatec/i18n";
|
|
2
|
+
declare const langRes: {
|
|
3
|
+
common: {
|
|
4
|
+
btnClose: string;
|
|
5
|
+
btnCancel: string;
|
|
6
|
+
btnConfirm: string;
|
|
7
|
+
textMore: string;
|
|
8
|
+
filterPlaceholder: string;
|
|
9
|
+
noResultsText: string;
|
|
10
|
+
};
|
|
11
|
+
colorPicker: string;
|
|
12
|
+
calendar: {
|
|
13
|
+
months: string[];
|
|
14
|
+
monthsAbbr: string[];
|
|
15
|
+
weekTitle: string[];
|
|
16
|
+
weekTitleAbbr: string[];
|
|
17
|
+
confirmText: string;
|
|
18
|
+
};
|
|
19
|
+
upload: {
|
|
20
|
+
btnRetry: string;
|
|
21
|
+
btnRemove: string;
|
|
22
|
+
btnPickup: string;
|
|
23
|
+
};
|
|
24
|
+
dataTable: {
|
|
25
|
+
rowNo: string;
|
|
26
|
+
actions: string;
|
|
27
|
+
emptyDataSet: string;
|
|
28
|
+
totalInfo: string;
|
|
29
|
+
rowsPerPage: string;
|
|
30
|
+
};
|
|
31
|
+
transfer: {
|
|
32
|
+
selectIndicator: string;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* The shape of this package's translation resources. A language resource file
|
|
37
|
+
* loaded at runtime (e.g. /assets/uniface_zh-CN.json) should provide every key
|
|
38
|
+
* of this structure, wrapped in the `uniface` namespace.
|
|
39
|
+
*/
|
|
40
|
+
export type UnifaceLangRes = typeof langRes;
|
|
41
|
+
declare const i18nRes: ResourceProxy<UnifaceLangRes>;
|
|
3
42
|
export default i18nRes;
|
package/dist/i18nRes/i18nRes.js
CHANGED
|
@@ -33,7 +33,8 @@ const langRes = {
|
|
|
33
33
|
rowNo: "#",
|
|
34
34
|
actions: "Actions",
|
|
35
35
|
emptyDataSet: 'Empty dataset',
|
|
36
|
-
totalInfo: "Total: <b>{{total}}</b>"
|
|
36
|
+
totalInfo: "Total: <b>{{total}}</b>",
|
|
37
|
+
rowsPerPage: "Rows/Page"
|
|
37
38
|
},
|
|
38
39
|
transfer: {
|
|
39
40
|
selectIndicator: "Selected: {{selected}}/{{total}}"
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
let dialog: Dialog;
|
|
36
36
|
|
|
37
37
|
const confirmAction = $derived<ButtonAction>({
|
|
38
|
-
label: confirmText ?? i18nRes.common.btnConfirm
|
|
38
|
+
label: confirmText ?? i18nRes.common.btnConfirm(),
|
|
39
39
|
type: "primary",
|
|
40
40
|
disabled: confirmHandler == null || !enableConfirm,
|
|
41
41
|
handler: async () => {
|
|
@@ -43,14 +43,14 @@ class MessageBoxController {
|
|
|
43
43
|
}
|
|
44
44
|
showInfo = (_message, options = { type: 'info' }) => {
|
|
45
45
|
const infoButtons = [
|
|
46
|
-
{ label: i18nRes.common.btnClose, type: 'primary', result: ModalResult.MR_OK }
|
|
46
|
+
{ label: i18nRes.common.btnClose(), type: 'primary', result: ModalResult.MR_OK }
|
|
47
47
|
];
|
|
48
48
|
return this.showMessageBox(_message, infoButtons, options);
|
|
49
49
|
};
|
|
50
50
|
showConfirm = (_message, options = { type: 'question' }) => {
|
|
51
51
|
const confirmButtons = [
|
|
52
|
-
{ label: i18nRes.common.btnConfirm, type: 'primary', result: ModalResult.MR_OK },
|
|
53
|
-
{ label: i18nRes.common.btnCancel, type: 'secondary', result: ModalResult.MR_CANCEL }
|
|
52
|
+
{ label: i18nRes.common.btnConfirm(), type: 'primary', result: ModalResult.MR_OK },
|
|
53
|
+
{ label: i18nRes.common.btnCancel(), type: 'secondary', result: ModalResult.MR_CANCEL }
|
|
54
54
|
];
|
|
55
55
|
return this.showMessageBox(_message, confirmButtons, options);
|
|
56
56
|
};
|
package/package.json
CHANGED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
export let fixed: boolean = false;
|
|
4
|
-
export let style: string = '';
|
|
5
|
-
export {className as class };
|
|
6
|
-
export let direction: 'horizontal' | 'vertical' = 'horizontal';
|
|
7
|
-
export let flex: boolean = false;
|
|
8
|
-
export let autoFit: boolean = false;
|
|
9
|
-
export let grow: boolean = false;
|
|
10
|
-
export let shrink: boolean = false;
|
|
11
|
-
|
|
12
|
-
let className:string = '';
|
|
13
|
-
|
|
14
|
-
</script>
|
|
15
|
-
<div class:flex class="flex-block {className} {flex ? direction : ''}" class:fixed class:grow class:shrink class:auto_fit={autoFit} {style}>
|
|
16
|
-
<slot/>
|
|
17
|
-
</div>
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
2
|
-
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
3
|
-
$$bindings?: Bindings;
|
|
4
|
-
} & Exports;
|
|
5
|
-
(internal: unknown, props: Props & {
|
|
6
|
-
$$events?: Events;
|
|
7
|
-
$$slots?: Slots;
|
|
8
|
-
}): Exports & {
|
|
9
|
-
$set?: any;
|
|
10
|
-
$on?: any;
|
|
11
|
-
};
|
|
12
|
-
z_$$bindings?: Bindings;
|
|
13
|
-
}
|
|
14
|
-
type $$__sveltets_2_PropsWithChildren<Props, Slots> = Props & (Slots extends {
|
|
15
|
-
default: any;
|
|
16
|
-
} ? Props extends Record<string, never> ? any : {
|
|
17
|
-
children?: any;
|
|
18
|
-
} : {});
|
|
19
|
-
declare const FlexBlock: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<{
|
|
20
|
-
fixed?: boolean;
|
|
21
|
-
style?: string;
|
|
22
|
-
class?: string;
|
|
23
|
-
direction?: "horizontal" | "vertical";
|
|
24
|
-
flex?: boolean;
|
|
25
|
-
autoFit?: boolean;
|
|
26
|
-
grow?: boolean;
|
|
27
|
-
shrink?: boolean;
|
|
28
|
-
}, {
|
|
29
|
-
default: {};
|
|
30
|
-
}>, {
|
|
31
|
-
[evt: string]: CustomEvent<any>;
|
|
32
|
-
}, {
|
|
33
|
-
default: {};
|
|
34
|
-
}, {
|
|
35
|
-
class: string;
|
|
36
|
-
}, string>;
|
|
37
|
-
type FlexBlock = InstanceType<typeof FlexBlock>;
|
|
38
|
-
export default FlexBlock;
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
# FlexBlock
|
|
2
|
-
|
|
3
|
-
A flexible flexbox layout component with support for horizontal/vertical directions, resizing, and growth/shrink options.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install @ticatec/uniface-element
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Import
|
|
12
|
-
|
|
13
|
-
```typescript
|
|
14
|
-
import FlexBlock from '@ticatec/uniface-element/FlexBlock';
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Basic Usage
|
|
18
|
-
|
|
19
|
-
```svelte
|
|
20
|
-
<script>
|
|
21
|
-
import FlexBlock from '@ticatec/uniface-element/FlexBlock';
|
|
22
|
-
</script>
|
|
23
|
-
|
|
24
|
-
<FlexBlock>
|
|
25
|
-
<div>Item 1</div>
|
|
26
|
-
<div>Item 2</div>
|
|
27
|
-
<div>Item 3</div>
|
|
28
|
-
</FlexBlock>
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Props
|
|
32
|
-
|
|
33
|
-
| Prop | Type | Default | Description |
|
|
34
|
-
|------|------|---------|-------------|
|
|
35
|
-
| `direction` | `'horizontal' \| 'vertical'` | `'horizontal'` | Flex direction |
|
|
36
|
-
| `flex` | `boolean` | `false` | Apply flex styling based on direction |
|
|
37
|
-
| `fixed` | `boolean` | `false` | Enable fixed positioning |
|
|
38
|
-
| `grow` | `boolean` | `false` | Enable flex-grow |
|
|
39
|
-
| `shrink` | `boolean` | `false` | Enable flex-shrink |
|
|
40
|
-
| `autoFit` | `boolean` | `false` | Enable auto-fit to content |
|
|
41
|
-
| `style` | `string` | `''` | Custom CSS styles for the container |
|
|
42
|
-
| `class` | `string` | `''` | Custom CSS class name |
|
|
43
|
-
|
|
44
|
-
## Slots
|
|
45
|
-
|
|
46
|
-
| Slot | Description |
|
|
47
|
-
|------|-------------|
|
|
48
|
-
| `default` | Main content area |
|
|
49
|
-
|
|
50
|
-
## Events
|
|
51
|
-
|
|
52
|
-
No custom events.
|
|
53
|
-
|
|
54
|
-
## Examples
|
|
55
|
-
|
|
56
|
-
### Horizontal Layout
|
|
57
|
-
|
|
58
|
-
```svelte
|
|
59
|
-
<script>
|
|
60
|
-
import FlexBlock from '@ticatec/uniface-element/FlexBlock';
|
|
61
|
-
</script>
|
|
62
|
-
|
|
63
|
-
<FlexBlock direction="horizontal" style="gap: 16px;">
|
|
64
|
-
<div>Item 1</div>
|
|
65
|
-
<div>Item 2</div>
|
|
66
|
-
<div>Item 3</div>
|
|
67
|
-
</FlexBlock>
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### Vertical Layout
|
|
71
|
-
|
|
72
|
-
```svelte
|
|
73
|
-
<script>
|
|
74
|
-
import FlexBlock from '@ticatec/uniface-element/FlexBlock';
|
|
75
|
-
</script>
|
|
76
|
-
|
|
77
|
-
<FlexBlock direction="vertical" style="gap: 16px;">
|
|
78
|
-
<div>Header</div>
|
|
79
|
-
<div>Main Content</div>
|
|
80
|
-
<div>Footer</div>
|
|
81
|
-
</FlexBlock>
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
### Flex Grow and Shrink
|
|
85
|
-
|
|
86
|
-
```svelte
|
|
87
|
-
<script>
|
|
88
|
-
import FlexBlock from '@ticatec/uniface-element/FlexBlock';
|
|
89
|
-
</script>
|
|
90
|
-
|
|
91
|
-
<FlexBlock direction="horizontal" flex grow shrink>
|
|
92
|
-
<div style="flex: 1;">Flexible Item</div>
|
|
93
|
-
<div style="width: 200px;">Fixed Item</div>
|
|
94
|
-
</FlexBlock>
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
### Auto-Fit Layout
|
|
98
|
-
|
|
99
|
-
```svelte
|
|
100
|
-
<script>
|
|
101
|
-
import FlexBlock from '@ticatec/uniface-element/FlexBlock';
|
|
102
|
-
</script>
|
|
103
|
-
|
|
104
|
-
<FlexBlock autoFit>
|
|
105
|
-
{#each items as item}
|
|
106
|
-
<div>{item}</div>
|
|
107
|
-
{/each}
|
|
108
|
-
</FlexBlock>
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
### Card Grid
|
|
112
|
-
|
|
113
|
-
```svelte
|
|
114
|
-
<script>
|
|
115
|
-
import FlexBlock from '@ticatec/uniface-element/FlexBlock';
|
|
116
|
-
</script>
|
|
117
|
-
|
|
118
|
-
<FlexBlock direction="horizontal" autoFit style="gap: 16px;">
|
|
119
|
-
{#each cards as card}
|
|
120
|
-
<div style="border: 1px solid #ddd; padding: 16px; border-radius: 8px;">
|
|
121
|
-
<h3>{card.title}</h3>
|
|
122
|
-
<p>{card.description}</p>
|
|
123
|
-
</div>
|
|
124
|
-
{/each}
|
|
125
|
-
</FlexBlock>
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### Fixed Positioning
|
|
129
|
-
|
|
130
|
-
```svelte
|
|
131
|
-
<script>
|
|
132
|
-
import FlexBlock from '@ticatec/uniface-element/FlexBlock';
|
|
133
|
-
</script>
|
|
134
|
-
|
|
135
|
-
<FlexBlock fixed direction="vertical" style="position: fixed; top: 0; left: 0; right: 0; height: 100vh;">
|
|
136
|
-
<div style="height: 60px;">Header</div>
|
|
137
|
-
<div style="flex: 1; overflow: auto;">Main Content</div>
|
|
138
|
-
<div style="height: 40px;">Footer</div>
|
|
139
|
-
</FlexBlock>
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
## Best Practices
|
|
143
|
-
|
|
144
|
-
1. **Use direction prop** - Choose horizontal or vertical based on your layout needs
|
|
145
|
-
2. **Combine with flex** - Use `flex` prop for responsive layouts that adapt to container size
|
|
146
|
-
3. **Use autoFit** - Enable auto-fit for dynamic content that should wrap
|
|
147
|
-
4. **Use grow/shrink** - Control how items expand or contract within the flex container
|
|
148
|
-
5. **Fixed positioning** - Use `fixed` for sticky layouts that don't scroll with content
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
# FlexBlock 弹性布局组件
|
|
2
|
-
|
|
3
|
-
一个灵活的 flexbox 布局组件,支持水平/垂直方向、调整大小和增长/收缩选项。
|
|
4
|
-
|
|
5
|
-
## 安装
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install @ticatec/uniface-element
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## 导入
|
|
12
|
-
|
|
13
|
-
```typescript
|
|
14
|
-
import FlexBlock from '@ticatec/uniface-element/FlexBlock';
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## 基本用法
|
|
18
|
-
|
|
19
|
-
```svelte
|
|
20
|
-
<script>
|
|
21
|
-
import FlexBlock from '@ticatec/uniface-element/FlexBlock';
|
|
22
|
-
</script>
|
|
23
|
-
|
|
24
|
-
<FlexBlock>
|
|
25
|
-
<div>项目 1</div>
|
|
26
|
-
<div>项目 2</div>
|
|
27
|
-
<div>项目 3</div>
|
|
28
|
-
</FlexBlock>
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## 属性
|
|
32
|
-
|
|
33
|
-
| 属性 | 类型 | 默认值 | 说明 |
|
|
34
|
-
|------|------|---------|------|
|
|
35
|
-
| `direction` | `'horizontal' \| 'vertical'` | `'horizontal'` | Flex 方向 |
|
|
36
|
-
| `flex` | `boolean` | `false` | 根据方向应用 flex 样式 |
|
|
37
|
-
| `fixed` | `boolean` | `false` | 启用固定定位 |
|
|
38
|
-
| `grow` | `boolean` | `false` | 启用 flex-grow |
|
|
39
|
-
| `shrink` | `boolean` | `false` | 启用 flex-shrink |
|
|
40
|
-
| `autoFit` | `boolean` | `false` | 启用自动适应内容 |
|
|
41
|
-
| `style` | `string` | `''` | 容器的自定义 CSS 样式 |
|
|
42
|
-
| `class` | `string` | `''` | 自定义 CSS 类名 |
|
|
43
|
-
|
|
44
|
-
## 插槽
|
|
45
|
-
|
|
46
|
-
| 插槽 | 说明 |
|
|
47
|
-
|------|------|
|
|
48
|
-
| `default` | 主要内容区域 |
|
|
49
|
-
|
|
50
|
-
## 事件
|
|
51
|
-
|
|
52
|
-
无自定义事件。
|
|
53
|
-
|
|
54
|
-
## 示例
|
|
55
|
-
|
|
56
|
-
### 水平布局
|
|
57
|
-
|
|
58
|
-
```svelte
|
|
59
|
-
<script>
|
|
60
|
-
import FlexBlock from '@ticatec/uniface-element/FlexBlock';
|
|
61
|
-
</script>
|
|
62
|
-
|
|
63
|
-
<FlexBlock direction="horizontal" style="gap: 16px;">
|
|
64
|
-
<div>项目 1</div>
|
|
65
|
-
<div>项目 2</div>
|
|
66
|
-
<div>项目 3</div>
|
|
67
|
-
</FlexBlock>
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### 垂直布局
|
|
71
|
-
|
|
72
|
-
```svelte
|
|
73
|
-
<script>
|
|
74
|
-
import FlexBlock from '@ticatec/uniface-element/FlexBlock';
|
|
75
|
-
</script>
|
|
76
|
-
|
|
77
|
-
<FlexBlock direction="vertical" style="gap: 16px;">
|
|
78
|
-
<div>头部</div>
|
|
79
|
-
<div>主要内容</div>
|
|
80
|
-
<div>页脚</div>
|
|
81
|
-
</FlexBlock>
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
### 弹性增长和收缩
|
|
85
|
-
|
|
86
|
-
```svelte
|
|
87
|
-
<script>
|
|
88
|
-
import FlexBlock from '@ticatec/uniface-element/FlexBlock';
|
|
89
|
-
</script>
|
|
90
|
-
|
|
91
|
-
<FlexBlock direction="horizontal" flex grow shrink>
|
|
92
|
-
<div style="flex: 1;">弹性项目</div>
|
|
93
|
-
<div style="width: 200px;">固定项目</div>
|
|
94
|
-
</FlexBlock>
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
### 自动适应布局
|
|
98
|
-
|
|
99
|
-
```svelte
|
|
100
|
-
<script>
|
|
101
|
-
import FlexBlock from '@ticatec/uniface-element/FlexBlock';
|
|
102
|
-
</script>
|
|
103
|
-
|
|
104
|
-
<FlexBlock autoFit>
|
|
105
|
-
{#each items as item}
|
|
106
|
-
<div>{item}</div>
|
|
107
|
-
{/each}
|
|
108
|
-
</FlexBlock>
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
### 卡片网格
|
|
112
|
-
|
|
113
|
-
```svelte
|
|
114
|
-
<script>
|
|
115
|
-
import FlexBlock from '@ticatec/uniface-element/FlexBlock';
|
|
116
|
-
</script>
|
|
117
|
-
|
|
118
|
-
<FlexBlock direction="horizontal" autoFit style="gap: 16px;">
|
|
119
|
-
{#each cards as card}
|
|
120
|
-
<div style="border: 1px solid #ddd; padding: 16px; border-radius: 8px;">
|
|
121
|
-
<h3>{card.title}</h3>
|
|
122
|
-
<p>{card.description}</p>
|
|
123
|
-
</div>
|
|
124
|
-
{/each}
|
|
125
|
-
</FlexBlock>
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### 固定定位
|
|
129
|
-
|
|
130
|
-
```svelte
|
|
131
|
-
<script>
|
|
132
|
-
import FlexBlock from '@ticatec/uniface-element/FlexBlock';
|
|
133
|
-
</script>
|
|
134
|
-
|
|
135
|
-
<FlexBlock fixed direction="vertical" style="position: fixed; top: 0; left: 0; right: 0; height: 100vh;">
|
|
136
|
-
<div style="height: 60px;">头部</div>
|
|
137
|
-
<div style="flex: 1; overflow: auto;">主要内容</div>
|
|
138
|
-
<div style="height: 40px;">页脚</div>
|
|
139
|
-
</FlexBlock>
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
## 最佳实践
|
|
143
|
-
|
|
144
|
-
1. **使用 direction 属性** - 根据布局需求选择水平或垂直方向
|
|
145
|
-
2. **结合 flex 使用** - 使用 `flex` 属性实现响应式布局,适应容器大小
|
|
146
|
-
3. **使用 autoFit** - 动态内容启用自动适应换行
|
|
147
|
-
4. **使用 grow/shrink** - 控制项目在 flex 容器中的扩展或收缩
|
|
148
|
-
5. **固定定位** - 使用 `fixed` 实现不随内容滚动的粘性布局
|
package/dist/layout/index.d.ts
DELETED
|
File without changes
|
package/dist/layout/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";
|