@ticatec/topside-elements 1.2.0 → 1.2.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.
- package/CHANGELOG.md +5 -0
- package/dist/data_display/list_box/ListBox.svelte +14 -4
- package/dist/data_display/list_box/ListBox.svelte.d.ts +6 -3
- package/dist/data_display/list_box/README.md +25 -3
- package/dist/data_display/list_box/README_CN.md +25 -3
- package/docs/NAMING.md +1 -1
- package/docs/NAMING_CN.md +1 -1
- package/docs/components/list-box/README.md +18 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.2.1
|
|
4
|
+
|
|
5
|
+
### 新增
|
|
6
|
+
- **ListBox 列表内置首尾项(`contentHeader` / `contentFooter` Snippet)**:在 `.listbox-content` 滚动容器内部的最上部与最下部分别新增 `contentHeader` 与 `contentFooter` 插槽。与外部固定不滚动的 `header` / `footer` 不同,这两个插槽的内容位于滚动视口内,跟随列表项一起滚动,适合呈现“全部/快捷选项”、“底部新增”或说明信息。
|
|
7
|
+
|
|
3
8
|
## 1.2.0
|
|
4
9
|
|
|
5
10
|
### 新增
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {tick, onDestroy, untrack} from "svelte";
|
|
2
|
+
import {tick, onDestroy, untrack, type Snippet} from "svelte";
|
|
3
3
|
import SearchBox from "../../form/search_box"
|
|
4
4
|
import type {FilterFn} from "../../types";
|
|
5
5
|
import type {ListLazyLoader} from "../../types";
|
|
@@ -29,9 +29,11 @@
|
|
|
29
29
|
title?: string;
|
|
30
30
|
round?: boolean;
|
|
31
31
|
filterText?: string;
|
|
32
|
-
header?: any;
|
|
33
|
-
footer?: any;
|
|
34
|
-
|
|
32
|
+
header?: Snippet | any;
|
|
33
|
+
footer?: Snippet | any;
|
|
34
|
+
contentHeader?: Snippet | any;
|
|
35
|
+
contentFooter?: Snippet | any;
|
|
36
|
+
loadMoreIndicator?: Snippet | any;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
let {
|
|
@@ -54,6 +56,8 @@
|
|
|
54
56
|
filterText,
|
|
55
57
|
header,
|
|
56
58
|
footer,
|
|
59
|
+
contentHeader,
|
|
60
|
+
contentFooter,
|
|
57
61
|
loadMoreIndicator
|
|
58
62
|
}: Props = $props();
|
|
59
63
|
|
|
@@ -293,6 +297,9 @@
|
|
|
293
297
|
{/if}
|
|
294
298
|
<div class="listbox-content" class:selectable={selectMode==='single'} bind:this={scrollElement} onscroll={handleScroll}
|
|
295
299
|
role="listbox" aria-multiselectable={selectMode === 'multiple' ? true : undefined}>
|
|
300
|
+
{#if contentHeader}
|
|
301
|
+
{@render contentHeader()}
|
|
302
|
+
{/if}
|
|
296
303
|
{#if filteredList && ItemRender}
|
|
297
304
|
{#each filteredList as item}
|
|
298
305
|
{#if selectMode === "multiple"}
|
|
@@ -319,6 +326,9 @@
|
|
|
319
326
|
{#if hasMore && loadMoreIndicator}
|
|
320
327
|
{@render loadMoreIndicator()}
|
|
321
328
|
{/if}
|
|
329
|
+
{#if contentFooter}
|
|
330
|
+
{@render contentFooter()}
|
|
331
|
+
{/if}
|
|
322
332
|
</div>
|
|
323
333
|
{#if footer}
|
|
324
334
|
<div class="box-footer flex-container">
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Snippet } from "svelte";
|
|
1
2
|
import type { FilterFn } from "../../types";
|
|
2
3
|
import type { ListLazyLoader } from "../../types";
|
|
3
4
|
type OnSelectChange = (item: any) => void;
|
|
@@ -22,9 +23,11 @@ interface Props {
|
|
|
22
23
|
title?: string;
|
|
23
24
|
round?: boolean;
|
|
24
25
|
filterText?: string;
|
|
25
|
-
header?: any;
|
|
26
|
-
footer?: any;
|
|
27
|
-
|
|
26
|
+
header?: Snippet | any;
|
|
27
|
+
footer?: Snippet | any;
|
|
28
|
+
contentHeader?: Snippet | any;
|
|
29
|
+
contentFooter?: Snippet | any;
|
|
30
|
+
loadMoreIndicator?: Snippet | any;
|
|
28
31
|
}
|
|
29
32
|
declare const ListBox: import("svelte").Component<Props, {}, "selectedItems">;
|
|
30
33
|
type ListBox = ReturnType<typeof ListBox>;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
A list component with optional header / footer snippets, built-in search, lazy loading, and single / multiple selection modes.
|
|
6
6
|
|
|
7
|
-
> Svelte 5 component. Custom header/footer/load-more
|
|
7
|
+
> Svelte 5 component. Custom header/footer/load-more/content snippets are passed as **Snippets** (`header`, `footer`, `contentHeader`, `contentFooter`, `loadMoreIndicator`).
|
|
8
8
|
|
|
9
9
|
## Installation
|
|
10
10
|
|
|
@@ -39,8 +39,10 @@ npm install @ticatec/topside-elements
|
|
|
39
39
|
| `round` | `boolean` | `false` | Adds a border radius (`--topside-radius`) |
|
|
40
40
|
| `class` | `string` | `undefined` | Extra class on the root |
|
|
41
41
|
| `style` | `string \| null` | `null` | Inline CSS on the root |
|
|
42
|
-
| `header` | `Snippet` | `undefined` | Custom header content (overrides `title
|
|
43
|
-
| `footer` | `Snippet` | `undefined` | Custom footer content |
|
|
42
|
+
| `header` | `Snippet` | `undefined` | Custom header content (overrides `title`, fixed above content) |
|
|
43
|
+
| `footer` | `Snippet` | `undefined` | Custom footer content (fixed below content) |
|
|
44
|
+
| `contentHeader` | `Snippet` | `undefined` | Custom snippet at the top inside `listbox-content` (scrolls with list items) |
|
|
45
|
+
| `contentFooter` | `Snippet` | `undefined` | Custom snippet at the bottom inside `listbox-content` (scrolls with list items) |
|
|
44
46
|
| `loadMoreIndicator` | `Snippet` | `undefined` | Custom "loading more" indicator shown at the bottom while `hasMore` |
|
|
45
47
|
| `onchange` | `(item: any) => void` | `undefined` | Single-mode: fires when the selected item changes (also fires with `null` when filter resets selection) |
|
|
46
48
|
| `onItemDblClick` | `(item: any) => void` | `undefined` | Single-mode only |
|
|
@@ -111,6 +113,26 @@ interface LoadResult {
|
|
|
111
113
|
<button disabled={selected.length === 0} onclick={() => console.log(selected)}>OK</button>
|
|
112
114
|
```
|
|
113
115
|
|
|
116
|
+
### Scrolling content header & footer (`contentHeader` & `contentFooter`)
|
|
117
|
+
|
|
118
|
+
Unlike `header` and `footer` which remain pinned outside the scroll viewport, `contentHeader` and `contentFooter` sit inside `.listbox-content` at the very top and bottom, scrolling alongside the list items:
|
|
119
|
+
|
|
120
|
+
```svelte
|
|
121
|
+
<ListBox list={users} itemRender={UserItem} selectMode="single" style="height: 300px;">
|
|
122
|
+
{#snippet contentHeader()}
|
|
123
|
+
<div style="padding: 8px 12px; background: #eef2ff; border-bottom: 1px solid #e0e7ff; cursor: pointer;">
|
|
124
|
+
All Users / Quick Actions (scrolls with list)
|
|
125
|
+
</div>
|
|
126
|
+
{/snippet}
|
|
127
|
+
|
|
128
|
+
{#snippet contentFooter()}
|
|
129
|
+
<div style="padding: 8px 12px; text-align: center; color: #64748b; border-top: 1px solid #f1f5f9;">
|
|
130
|
+
Bottom action or footer notice (scrolls with list)
|
|
131
|
+
</div>
|
|
132
|
+
{/snippet}
|
|
133
|
+
</ListBox>
|
|
134
|
+
```
|
|
135
|
+
|
|
114
136
|
### Lazy-loaded list with custom footer
|
|
115
137
|
|
|
116
138
|
```svelte
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
列表组件,可选 header / footer snippet、内置搜索框、懒加载、单选 / 多选。
|
|
6
6
|
|
|
7
|
-
> Svelte 5 组件。header / footer / 加载更多 通过 **Snippet** 传入(`header`、`footer`、`loadMoreIndicator`)。
|
|
7
|
+
> Svelte 5 组件。header / footer / contentHeader / contentFooter / 加载更多 通过 **Snippet** 传入(`header`、`footer`、`contentHeader`、`contentFooter`、`loadMoreIndicator`)。
|
|
8
8
|
|
|
9
9
|
## 安装
|
|
10
10
|
|
|
@@ -39,8 +39,10 @@ npm install @ticatec/topside-elements
|
|
|
39
39
|
| `round` | `boolean` | `false` | 加圆角(`--topside-radius`) |
|
|
40
40
|
| `class` | `string` | `undefined` | 根节点附加 class |
|
|
41
41
|
| `style` | `string \| null` | `null` | 根节点内联 CSS |
|
|
42
|
-
| `header` | `Snippet` | `undefined` | 自定义 header(覆盖 `title
|
|
43
|
-
| `footer` | `Snippet` | `undefined` | 自定义 footer |
|
|
42
|
+
| `header` | `Snippet` | `undefined` | 自定义 header(覆盖 `title`,固定在顶部不随列表滚动) |
|
|
43
|
+
| `footer` | `Snippet` | `undefined` | 自定义 footer(固定在底部不随列表滚动) |
|
|
44
|
+
| `contentHeader` | `Snippet` | `undefined` | 位于 `listbox-content` 最上部的自定义组件/片段(跟随列表滚动) |
|
|
45
|
+
| `contentFooter` | `Snippet` | `undefined` | 位于 `listbox-content` 最下部的自定义组件/片段(跟随列表滚动) |
|
|
44
46
|
| `loadMoreIndicator` | `Snippet` | `undefined` | 自定义"加载更多"指示器,`hasMore` 时显示在底部 |
|
|
45
47
|
| `onchange` | `(item: any) => void` | `undefined` | 单选模式:选中变化时触发(过滤重置时也会以 `null` 触发一次) |
|
|
46
48
|
| `onItemDblClick` | `(item: any) => void` | `undefined` | 仅单选模式 |
|
|
@@ -111,6 +113,26 @@ interface LoadResult {
|
|
|
111
113
|
<button disabled={selected.length === 0} onclick={() => console.log(selected)}>OK</button>
|
|
112
114
|
```
|
|
113
115
|
|
|
116
|
+
### 随列表滚动的内置首尾项 (`contentHeader` & `contentFooter`)
|
|
117
|
+
|
|
118
|
+
与 `header` 和 `footer`(固定在滚动容器外部、不随内容滚动)不同,`contentHeader` 与 `contentFooter` 位于 `.listbox-content` 滚动容器内部的最上部与最下部,跟随列表项一起滚动,适合放置“全部选项”、“快捷动作”或底部的“新增选项”等条目:
|
|
119
|
+
|
|
120
|
+
```svelte
|
|
121
|
+
<ListBox list={users} itemRender={UserItem} selectMode="single" style="height: 300px;">
|
|
122
|
+
{#snippet contentHeader()}
|
|
123
|
+
<div style="padding: 8px 12px; background: #eef2ff; border-bottom: 1px solid #e0e7ff; cursor: pointer;">
|
|
124
|
+
全部选项 / 快捷操作(跟随列表滚动)
|
|
125
|
+
</div>
|
|
126
|
+
{/snippet}
|
|
127
|
+
|
|
128
|
+
{#snippet contentFooter()}
|
|
129
|
+
<div style="padding: 8px 12px; text-align: center; color: #64748b; border-top: 1px solid #f1f5f9;">
|
|
130
|
+
底部操作或说明(跟随列表滚动)
|
|
131
|
+
</div>
|
|
132
|
+
{/snippet}
|
|
133
|
+
</ListBox>
|
|
134
|
+
```
|
|
135
|
+
|
|
114
136
|
### 懒加载 + 自定义 footer
|
|
115
137
|
|
|
116
138
|
```svelte
|
package/docs/NAMING.md
CHANGED
|
@@ -342,7 +342,7 @@ interface Action<T = any> {
|
|
|
342
342
|
**Events (notifications)**: `onchange` `onclick` `ondblclick` `onfocus` `onblur` `oninput` `onclose` `onselect` `ondelete` `onremove` `onrefresh` `onconfirm` `onaction` `ondownload` `onretry` `onkeydown` `onkeyup` `onkeypress` `oncontextmenu` `ontoggle` `onItemClick` `onRowClick` `onIconClick` `onPageSizeChange` `onFileUploaded` `onFileRejected` `onUploadError` `onPreview` `onResizeEnd`; between DataTable's internal panels: `onCellClick` `onWidthChange` `onRowExpand` `onRowSelectChange` `onToggleSelectAll`
|
|
343
343
|
**Hooks (veto)**: `beforeClose` `beforeRemove` `beforeChange` `beforeTransfer`
|
|
344
344
|
**Instance methods**: `focus()` `blur()` `clear()` `open()` `close()` `reset()` `push()` `pop()` `getElement()` `openFileDialog()`
|
|
345
|
-
**Snippets**: `children` `header` `headerExtra` `footer` `left` `right` `top` `bottom` `sidebar` `home` `leadingIcon` `trailingIcon` `popup` `item` `tab` `node` `chevronIcon` `nodeIcon` `from` `to`
|
|
345
|
+
**Snippets**: `children` `header` `headerExtra` `footer` `contentHeader` `contentFooter` `left` `right` `top` `bottom` `sidebar` `home` `leadingIcon` `trailingIcon` `popup` `item` `tab` `node` `chevronIcon` `nodeIcon` `from` `to`
|
|
346
346
|
|
|
347
347
|
---
|
|
348
348
|
|
package/docs/NAMING_CN.md
CHANGED
|
@@ -342,7 +342,7 @@ interface Action<T = any> {
|
|
|
342
342
|
**事件(通知)**:`onchange` `onclick` `ondblclick` `onfocus` `onblur` `oninput` `onclose` `onselect` `ondelete` `onremove` `onrefresh` `onconfirm` `onaction` `ondownload` `onretry` `onkeydown` `onkeyup` `onkeypress` `oncontextmenu` `ontoggle` `onItemClick` `onRowClick` `onIconClick` `onPageSizeChange` `onFileUploaded` `onFileRejected` `onUploadError` `onPreview` `onResizeEnd`;DataTable 内部面板间:`onCellClick` `onWidthChange` `onRowExpand` `onRowSelectChange` `onToggleSelectAll`
|
|
343
343
|
**钩子(否决)**:`beforeClose` `beforeRemove` `beforeChange` `beforeTransfer`
|
|
344
344
|
**实例方法**:`focus()` `blur()` `clear()` `open()` `close()` `reset()` `push()` `pop()` `getElement()` `openFileDialog()`
|
|
345
|
-
**Snippet**:`children` `header` `headerExtra` `footer` `left` `right` `top` `bottom` `sidebar` `home` `leadingIcon` `trailingIcon` `popup` `item` `tab` `node` `chevronIcon` `nodeIcon` `from` `to`
|
|
345
|
+
**Snippet**:`children` `header` `headerExtra` `footer` `contentHeader` `contentFooter` `left` `right` `top` `bottom` `sidebar` `home` `leadingIcon` `trailingIcon` `popup` `item` `tab` `node` `chevronIcon` `nodeIcon` `from` `to`
|
|
346
346
|
|
|
347
347
|
---
|
|
348
348
|
|
|
@@ -40,6 +40,8 @@ import ListBox from '@ticatec/topside-elements/ListBox';
|
|
|
40
40
|
| `filterText` | 是 | `string` | 否 | `undefined` | 否 | 过滤输入框的外部初始值或受控值,用于预设搜索条件。 |
|
|
41
41
|
| `header` | 否 | `any` | 否 | `undefined` | 否 | 可选配置,具体取值范围和数据结构见类型列。 |
|
|
42
42
|
| `footer` | 否 | `any` | 否 | `undefined` | 否 | 可选配置,具体取值范围和数据结构见类型列。 |
|
|
43
|
+
| `contentHeader` | 否 | `Snippet \| any` | 否 | `undefined` | 否 | 位于 listbox-content 最上部的自定义组件/片段(跟随列表滚动)。 |
|
|
44
|
+
| `contentFooter` | 否 | `Snippet \| any` | 否 | `undefined` | 否 | 位于 listbox-content 最下部的自定义组件/片段(跟随列表滚动)。 |
|
|
43
45
|
| `loadMoreIndicator` | 否 | `any` | 否 | `undefined` | 否 | 可选配置,具体取值范围和数据结构见类型列。 |
|
|
44
46
|
|
|
45
47
|
> 组件的“可绑定”表示源码使用了 Svelte 5 的 `$bindable`;服务的“响应式”表示成员使用了 `$state`。复杂类型请同时参考 TypeScript 自动补全。
|
|
@@ -121,6 +123,22 @@ import ListBox from '@ticatec/topside-elements/ListBox';
|
|
|
121
123
|
- 默认值:`undefined`
|
|
122
124
|
- 示例写法:`filterText="研发"`
|
|
123
125
|
|
|
126
|
+
### `contentHeader`
|
|
127
|
+
|
|
128
|
+
位于 `listbox-content` 滚动容器内部的最上部,在所有列表项之前渲染,**跟随列表一起滚动**(与固定的 `header` 区分)。可用于放置如“全部选项”、“快捷搜索”等类似选择项的内容。
|
|
129
|
+
|
|
130
|
+
- 类型:`Snippet | any`
|
|
131
|
+
- 默认值:`undefined`
|
|
132
|
+
- 示例写法:`{#snippet contentHeader()}<div>全部选项</div>{/snippet}`
|
|
133
|
+
|
|
134
|
+
### `contentFooter`
|
|
135
|
+
|
|
136
|
+
位于 `listbox-content` 滚动容器内部的最下部,在所有列表项(及加载更多指示器)之后渲染,**跟随列表一起滚动**(与固定的 `footer` 区分)。可用于放置如“新增选项”、“列表说明”等类似选择项的内容。
|
|
137
|
+
|
|
138
|
+
- 类型:`Snippet | any`
|
|
139
|
+
- 默认值:`undefined`
|
|
140
|
+
- 示例写法:`{#snippet contentFooter()}<div>新增选项</div>{/snippet}`
|
|
141
|
+
|
|
124
142
|
## 相关类型定义
|
|
125
143
|
|
|
126
144
|
以下定义帮助理解复杂属性的数据结构;其中部分辅助类型属于内部实现,不一定是独立导出入口。
|
package/package.json
CHANGED