@praxisui/list 1.0.0-beta.30 → 1.0.0-beta.38
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 +164 -8
- package/fesm2022/praxisui-list.mjs +3178 -1821
- package/fesm2022/praxisui-list.mjs.map +1 -1
- package/index.d.ts +545 -27
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -20,6 +20,7 @@ Peers (install in your app):
|
|
|
20
20
|
- `rxjs` (>=7 <9)
|
|
21
21
|
- `@praxisui/core` (icons, config storage, CRUD service)
|
|
22
22
|
- Optional: `@praxisui/settings-panel` (to open the in-app list configuration editor)
|
|
23
|
+
- Optional: `@praxisui/dynamic-fields` (color picker used by the in-app editor)
|
|
23
24
|
|
|
24
25
|
## Quick Start
|
|
25
26
|
|
|
@@ -33,6 +34,7 @@ import { PraxisList } from '@praxisui/list';
|
|
|
33
34
|
imports: [PraxisList],
|
|
34
35
|
template: `
|
|
35
36
|
<praxis-list
|
|
37
|
+
listId="products-list"
|
|
36
38
|
[config]="config"
|
|
37
39
|
(itemClick)="onItem($event)"
|
|
38
40
|
(actionClick)="onAction($event)"
|
|
@@ -71,12 +73,85 @@ export class ListDemoComponent {
|
|
|
71
73
|
}
|
|
72
74
|
```
|
|
73
75
|
|
|
76
|
+
## Runtime Contract (Data Mode and Precedence)
|
|
77
|
+
|
|
78
|
+
Effective data mode resolution follows `ListDataService.stream()`:
|
|
79
|
+
|
|
80
|
+
1. if `dataSource.data` exists, local mode is used;
|
|
81
|
+
2. else if `dataSource.resourcePath` exists and `GenericCrudService` is available, remote mode is used;
|
|
82
|
+
3. otherwise, empty mode is used.
|
|
83
|
+
|
|
84
|
+
Critical rule:
|
|
85
|
+
- local data has precedence over remote when both `dataSource.data` and `dataSource.resourcePath` are present.
|
|
86
|
+
|
|
87
|
+
Decision matrix (runtime today):
|
|
88
|
+
|
|
89
|
+
| `dataSource.data` | `dataSource.resourcePath` | Resolved mode | Data pipeline | Main surface |
|
|
90
|
+
| --- | --- | --- | --- | --- |
|
|
91
|
+
| array | any value | local | local array only | list/cards/tiles |
|
|
92
|
+
| missing/null | filled | remote | `/filter` with fallback `getAll()` on failure | list/cards/tiles + remote controls |
|
|
93
|
+
| missing/null | missing/empty | empty | none | empty state |
|
|
94
|
+
|
|
95
|
+
Important behavior:
|
|
96
|
+
- pagination/search/sort controls from `ui.*` are rendered only when `dataSource.resourcePath` is defined.
|
|
97
|
+
- remote mode uses `GenericCrudService.filter(query, pageable)` and falls back to `getAll()` when `/filter` fails.
|
|
98
|
+
|
|
99
|
+
## Runtime Status Matrix (High-Impact Paths)
|
|
100
|
+
|
|
101
|
+
| JSON path | Runtime status | Notes |
|
|
102
|
+
| --- | --- | --- |
|
|
103
|
+
| `dataSource.data` | Active | Local mode source. |
|
|
104
|
+
| `dataSource.resourcePath` | Active | Remote mode source. |
|
|
105
|
+
| `layout.virtualScroll` | Declared-only | Accepted in config/editor but no runtime binding yet. |
|
|
106
|
+
| `layout.stickySectionHeader` | Declared-only | Accepted in config/editor but no runtime sticky behavior yet. |
|
|
107
|
+
| `actions[].emitPayload` | Declared-only | Authoring field only; `actionClick` payload shape is fixed. |
|
|
108
|
+
| `events.*` | Declared-only | Declarative mapping only; no dynamic event router in runtime. |
|
|
109
|
+
| `a11y.highContrast` / `a11y.reduceMotion` | Declared-only | No visual/runtime enforcement yet. |
|
|
110
|
+
|
|
111
|
+
## Pagina de documentacao viva (showcase completo)
|
|
112
|
+
|
|
113
|
+
Para documentar o componente com exemplos live (layout, templating, selecao, acoes, skins e snippets),
|
|
114
|
+
use o componente `praxis-list-doc-page`:
|
|
115
|
+
|
|
116
|
+
```html
|
|
117
|
+
<praxis-list-doc-page></praxis-list-doc-page>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
import { Component } from '@angular/core';
|
|
122
|
+
import { PraxisListDocPageComponent } from '@praxisui/list';
|
|
123
|
+
|
|
124
|
+
@Component({
|
|
125
|
+
selector: 'app-list-doc-host',
|
|
126
|
+
standalone: true,
|
|
127
|
+
imports: [PraxisListDocPageComponent],
|
|
128
|
+
template: `<praxis-list-doc-page />`,
|
|
129
|
+
})
|
|
130
|
+
export class ListDocHostComponent {}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Cobertura da pagina:
|
|
134
|
+
- Variantes `list`, `cards`, `tiles`.
|
|
135
|
+
- `density`, `lines`, `model`, `groupBy`, `dividers`.
|
|
136
|
+
- Slots `leading`, `primary`, `secondary`, `meta`, `trailing`, `sectionHeader`, `emptyState`.
|
|
137
|
+
- Tipos de template `text`, `icon`, `image`, `chip`, `rating`, `currency`, `date`, `html`.
|
|
138
|
+
- Selecao (`none`, `single`, `multiple`) com `FormControl` externo.
|
|
139
|
+
- Acoes com `showIf`, estilos `icon/button` e log de eventos.
|
|
140
|
+
- Skins `elevated`, `pill-soft`, `glass`, `gradient-tile`, `custom`.
|
|
141
|
+
- Snippets para host, config JSON e contrato remoto com `resourcePath`.
|
|
142
|
+
|
|
143
|
+
## Persistência
|
|
144
|
+
|
|
145
|
+
- `listId` é obrigatório para salvar/carregar configurações.
|
|
146
|
+
- A chave usada no storage é `praxis-list-config-<component_id>` (via `ComponentKeyService`).
|
|
147
|
+
- Use `componentInstanceId` quando houver múltiplas listas com o mesmo `listId` na mesma rota.
|
|
148
|
+
|
|
74
149
|
## Remote Data (resourcePath)
|
|
75
150
|
|
|
76
151
|
Provide `dataSource.resourcePath` to fetch data and (optionally) infer templating from backend schema.
|
|
77
152
|
|
|
78
153
|
```html
|
|
79
|
-
<praxis-list [config]="{
|
|
154
|
+
<praxis-list listId="employees" [config]="{
|
|
80
155
|
id: 'employees',
|
|
81
156
|
dataSource: { resourcePath: 'employees', sort: ['name,asc'] },
|
|
82
157
|
layout: { variant: 'list', lines: 2, groupBy: 'department' },
|
|
@@ -90,25 +165,51 @@ The component uses `GenericCrudService` from `@praxisui/core` when `resourcePath
|
|
|
90
165
|
|
|
91
166
|
- `list` (default): Material list with optional selection and dividers.
|
|
92
167
|
- `cards`: Card grid layout with the same templating slots.
|
|
168
|
+
- `tiles`: Modern grid layout (image + title + meta), ideal for catalogs.
|
|
93
169
|
|
|
94
170
|
Layout options (`config.layout`):
|
|
95
171
|
- `lines`: 1 | 2 | 3 controls visible text lines.
|
|
96
172
|
- `dividers`: 'none' | 'between' | 'all'.
|
|
97
173
|
- `groupBy`: string key to group items; section headers can be templated via `templating.sectionHeader`.
|
|
98
|
-
- `pageSize`, `
|
|
174
|
+
- `pageSize`, `density`, `model` are runtime-active.
|
|
175
|
+
- `virtualScroll` and `stickySectionHeader` are currently declared-only (no runtime binding yet).
|
|
176
|
+
|
|
177
|
+
## Config Merging Behavior
|
|
178
|
+
Be aware that `applyConfigFromAdapter` replaces the entire `config` object. It does not perform a deep merge. Any local runtime overrides must be re-applied or managed carefully.
|
|
99
179
|
|
|
100
180
|
## Templating Slots
|
|
101
181
|
|
|
102
182
|
Every slot accepts a `TemplateDef` with `type`, `expr`, optional `class` and `style`.
|
|
103
|
-
- `leading`: 'icon' | 'image' with optional `badge`.
|
|
104
|
-
- `primary`: 'text' | 'html' | 'date' | 'currency'
|
|
183
|
+
- `leading`: 'icon' | 'image' | 'text' | 'chip' | 'rating' | 'html' with optional `badge`.
|
|
184
|
+
- `primary`: 'text' | 'html' | 'date' | 'currency'.
|
|
105
185
|
- `secondary`: same as primary; shown when `lines > 1`.
|
|
106
|
-
- `meta`: small text or chip/rating rendered inline or on the side (`metaPlacement`).
|
|
107
|
-
- `trailing`: optional trailing text/chip.
|
|
186
|
+
- `meta`: small text or chip/rating/icon/image rendered inline or on the side (`metaPlacement`).
|
|
187
|
+
- `trailing`: optional trailing text/chip/icon/image.
|
|
108
188
|
- `features`: array of `{ icon?, expr }` rendered below primary/secondary; control with `featuresVisible` and `featuresMode` ('icons+labels' | 'icons-only' | 'labels-only').
|
|
109
189
|
|
|
110
190
|
Expressions use `${...}` to read from `item` (e.g., `${item.name}`). For `currency`, you may pass code/locale as `|:USD` or `|:USD:en-US`.
|
|
111
191
|
|
|
192
|
+
### Rating props
|
|
193
|
+
|
|
194
|
+
```json
|
|
195
|
+
{
|
|
196
|
+
"templating": {
|
|
197
|
+
"meta": {
|
|
198
|
+
"type": "rating",
|
|
199
|
+
"expr": "${item.rating}",
|
|
200
|
+
"props": { "rating": { "max": 5, "size": 16, "color": "primary" } }
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Colors
|
|
207
|
+
|
|
208
|
+
`color` accepts:
|
|
209
|
+
- theme colors (`primary`, `accent`, `warn`)
|
|
210
|
+
- M3 tokens (`var(--md-sys-color-*)`)
|
|
211
|
+
- custom colors (hex/rgb). The in-app editor offers a color picker.
|
|
212
|
+
|
|
112
213
|
## Actions
|
|
113
214
|
|
|
114
215
|
Configure contextual item actions via `config.actions`:
|
|
@@ -122,8 +223,44 @@ actions: [
|
|
|
122
223
|
```
|
|
123
224
|
|
|
124
225
|
- `kind`: 'icon' (default) or 'button'.
|
|
125
|
-
- `showIf`: simple equality check is supported
|
|
126
|
-
- `emitPayload`:
|
|
226
|
+
- `showIf`: simple equality check is supported. Syntax: `"${item.field} == 'value'"`. Left side must be an interpolation expression.
|
|
227
|
+
- `emitPayload`: authoring field in the config/editor; current runtime `actionClick` emission does not change shape based on this field.
|
|
228
|
+
|
|
229
|
+
### Global actions (command)
|
|
230
|
+
|
|
231
|
+
```ts
|
|
232
|
+
actions: [
|
|
233
|
+
{
|
|
234
|
+
id: 'favorite',
|
|
235
|
+
icon: 'favorite',
|
|
236
|
+
label: 'Favorite',
|
|
237
|
+
command: 'global:api.post',
|
|
238
|
+
globalPayload: { url: '/api/favorite', body: { id: '${item.id}' } }
|
|
239
|
+
}
|
|
240
|
+
]
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
When `command` is set, `actionClick` is **not emitted** by default. Use `emitLocal: true` to emit both.
|
|
244
|
+
|
|
245
|
+
### Confirmation and loading
|
|
246
|
+
|
|
247
|
+
```ts
|
|
248
|
+
actions: [
|
|
249
|
+
{
|
|
250
|
+
id: 'delete',
|
|
251
|
+
icon: 'delete',
|
|
252
|
+
label: 'Delete',
|
|
253
|
+
command: 'global:api.patch',
|
|
254
|
+
showLoading: true,
|
|
255
|
+
confirmation: {
|
|
256
|
+
title: 'Confirm deletion',
|
|
257
|
+
message: 'Are you sure you want to delete this item?',
|
|
258
|
+
type: 'danger',
|
|
259
|
+
},
|
|
260
|
+
globalPayload: { url: '/api/items/${item.id}', body: { active: false } },
|
|
261
|
+
}
|
|
262
|
+
]
|
|
263
|
+
```
|
|
127
264
|
|
|
128
265
|
## Selection and Events
|
|
129
266
|
|
|
@@ -138,6 +275,25 @@ Outputs:
|
|
|
138
275
|
- `(actionClick)`: `{ actionId, item, index }`
|
|
139
276
|
- `(selectionChange)`: `{ mode, value, items, ids? }`
|
|
140
277
|
|
|
278
|
+
## Known limitations and mismatches
|
|
279
|
+
|
|
280
|
+
1. `layout.virtualScroll` and `layout.stickySectionHeader` exist in the contract/editor, but have no runtime implementation.
|
|
281
|
+
2. `actions[].emitPayload` is accepted in config/editor, but does not change current `actionClick` payload format.
|
|
282
|
+
3. `events.*` is declarative-only (no runtime dynamic routing).
|
|
283
|
+
4. `a11y.highContrast` and `a11y.reduceMotion` are declarative-only at this stage.
|
|
284
|
+
5. In remote mode, `/filter -> getAll()` fallback can increase network cost on large datasets.
|
|
285
|
+
|
|
286
|
+
## Source of truth
|
|
287
|
+
|
|
288
|
+
- Canonical contract: `projects/praxis-list/src/lib/praxis-list.json-api.md`
|
|
289
|
+
- Runtime implementation:
|
|
290
|
+
- `projects/praxis-list/src/lib/components/praxis-list.component.ts`
|
|
291
|
+
- `projects/praxis-list/src/lib/components/praxis-list.component.html`
|
|
292
|
+
- `projects/praxis-list/src/lib/services/list-data.service.ts`
|
|
293
|
+
- Runtime specs:
|
|
294
|
+
- `projects/praxis-list/src/lib/components/praxis-list.component.spec.ts`
|
|
295
|
+
- `projects/praxis-list/src/lib/services/list-data.service.spec.ts`
|
|
296
|
+
|
|
141
297
|
## License
|
|
142
298
|
|
|
143
299
|
Apache-2.0 — see `LICENSE` in this package or the repository root.
|