@cxtms/cx-schema 1.9.66 → 1.9.241

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 (81) hide show
  1. package/dist/cli.js +43 -9
  2. package/dist/cli.js.map +1 -1
  3. package/package.json +1 -1
  4. package/schemas/actions/all.json +5 -1
  5. package/schemas/actions/reload.json +17 -0
  6. package/schemas/actions/setSessionStorage.json +38 -0
  7. package/schemas/actions/sound.json +39 -0
  8. package/schemas/actions/vibrate.json +48 -0
  9. package/schemas/components/avatar.json +1 -0
  10. package/schemas/components/badge.json +79 -0
  11. package/schemas/components/barcodeScanner.json +28 -0
  12. package/schemas/components/camera.json +177 -0
  13. package/schemas/components/card.json +78 -0
  14. package/schemas/components/dashboard-widget.json +39 -0
  15. package/schemas/components/dashboard.json +46 -0
  16. package/schemas/components/dataGrid.json +15 -0
  17. package/schemas/components/field-collection.json +86 -2
  18. package/schemas/components/field.json +39 -4
  19. package/schemas/components/form.json +4 -0
  20. package/schemas/components/index.json +17 -1
  21. package/schemas/components/infoLine.json +1 -0
  22. package/schemas/components/map.json +167 -0
  23. package/schemas/components/module.json +32 -0
  24. package/schemas/components/planner.json +1 -0
  25. package/schemas/components/progressBar.json +1 -0
  26. package/schemas/components/timeline.json +216 -74
  27. package/schemas/components/timelineGrid.json +5 -1
  28. package/schemas/fields/autocomplete-googleplaces.json +2 -2
  29. package/schemas/fields/datetime.json +2 -2
  30. package/schemas/fields/index.json +4 -0
  31. package/schemas/fields/number-select.json +88 -0
  32. package/schemas/fields/rangedatetime.json +10 -2
  33. package/schemas/fields/select-async.json +2 -2
  34. package/schemas/fields/toggle.json +91 -0
  35. package/schemas/schema.graphql +11016 -12171
  36. package/schemas/schemas.json +131 -4
  37. package/schemas/workflows/flow/entity.json +3 -1
  38. package/schemas/workflows/input.json +1 -1
  39. package/schemas/workflows/output.json +1 -1
  40. package/schemas/workflows/tasks/all.json +9 -0
  41. package/schemas/workflows/tasks/commodity.json +8 -0
  42. package/schemas/workflows/tasks/contact-address.json +25 -0
  43. package/schemas/workflows/tasks/dispatch-routes.json +64 -0
  44. package/schemas/workflows/tasks/edi.json +15 -0
  45. package/schemas/workflows/tasks/export.json +21 -0
  46. package/schemas/workflows/tasks/httpRequest.json +4 -0
  47. package/schemas/workflows/tasks/import.json +5 -0
  48. package/schemas/workflows/tasks/order-move.json +38 -0
  49. package/schemas/workflows/tasks/order.json +6 -0
  50. package/schemas/workflows/tasks/organization-config.json +101 -0
  51. package/schemas/workflows/tasks/tracking-event.json +11 -3
  52. package/schemas/workflows/tasks/workflow-execute.json +4 -0
  53. package/schemas/workflows/variable.json +2 -2
  54. package/schemas/workflows/workflow.json +39 -2
  55. package/skills/cxtms-developer/SKILL.md +5 -2
  56. package/skills/cxtms-developer/ref-cli-auth.md +2 -0
  57. package/skills/cxtms-developer/ref-entity-commodity.md +41 -5
  58. package/skills/cxtms-developer/ref-entity-contact.md +46 -0
  59. package/skills/cxtms-developer/ref-entity-dispatch-routing.md +195 -0
  60. package/skills/cxtms-developer/ref-entity-geography.md +26 -1
  61. package/skills/cxtms-developer/ref-entity-job.md +6 -2
  62. package/skills/cxtms-developer/ref-entity-order-sub.md +1 -1
  63. package/skills/cxtms-developer/ref-entity-order.md +36 -3
  64. package/skills/cxtms-developer/ref-entity-organization.md +4 -2
  65. package/skills/cxtms-developer/ref-entity-shared.md +79 -3
  66. package/skills/cxtms-developer/ref-graphql-query.md +246 -4
  67. package/skills/cxtms-module-builder/SKILL.md +33 -6
  68. package/skills/cxtms-module-builder/ref-components-data.md +85 -0
  69. package/skills/cxtms-module-builder/ref-components-display.md +282 -8
  70. package/skills/cxtms-module-builder/ref-components-forms.md +386 -21
  71. package/skills/cxtms-module-builder/ref-components-interactive.md +2 -0
  72. package/skills/cxtms-module-builder/ref-components-layout.md +288 -29
  73. package/skills/cxtms-module-builder/ref-components-specialized.md +168 -20
  74. package/skills/cxtms-workflow-builder/SKILL.md +45 -6
  75. package/skills/cxtms-workflow-builder/ref-entity.md +100 -4
  76. package/skills/cxtms-workflow-builder/ref-expressions-ncalc.md +35 -2
  77. package/skills/cxtms-workflow-builder/ref-expressions-template.md +15 -1
  78. package/skills/cxtms-workflow-builder/ref-flow.md +6 -1
  79. package/skills/cxtms-workflow-builder/ref-query.md +16 -0
  80. package/skills/cxtms-workflow-builder/ref-utilities.md +32 -2
  81. package/templates/workflow-public-api.yaml +1 -0
@@ -20,6 +20,7 @@ Full-featured data table with views, filtering, sorting, pagination, and row act
20
20
  **Responsive layout:**
21
21
  - **Toolbar**: ViewSelector and search input stack full-width on mobile (`xs`), then collapse to auto-width on `sm` and above. Search input enforces a `20ch` minimum width on `sm+`.
22
22
  - **Filters**: Filter inputs use a responsive grid — 1 per row on `xs`/`sm`, 2 per row on `md`, 3 per row on `lg`, 4 per row on `xl`.
23
+ - **Pagination**: Below the MUI `sm` breakpoint, the pager tightens inline padding and narrows the page-size select so short pagers stay on one row inside dialogs. Do not add extra mobile-only wrapper padding around embedded grids unless the content needs it.
23
24
 
24
25
  **Props:**
25
26
  | Prop | Type | Description |
@@ -27,6 +28,8 @@ Full-featured data table with views, filtering, sorting, pagination, and row act
27
28
  | `toolbar` | `component[]` | Header toolbar components |
28
29
  | `dotsMenu` | `{items[]}` | Three-dot menu per row |
29
30
  | `dotsMenu.items[]` | `{label, icon, onClick, permission, isHidden, disabled}` | Menu item |
31
+
32
+ **Row-aware dots menu expressions:** `dotsMenu.items[].disabled` and `isHidden` are evaluated with component props plus the current row data. Reference row fields directly, e.g. `disabled: "{{ eval status !== 'Ready' || isLocked }}"`.
30
33
  | `views` | `ITableViewProps[]` | View definitions |
31
34
  | `enableSelect` | `Single \| Multiple` | Row selection mode |
32
35
  | `isInDialog` | `boolean` | Optimize for dialog (10 rows) |
@@ -38,6 +41,7 @@ Full-featured data table with views, filtering, sorting, pagination, and row act
38
41
  | `query` | `string` | — | **Required.** GraphQL entity name |
39
42
  | `rootEntityName` | `string` | — | **Required.** Entity name for dynamic grid |
40
43
  | `entityKeys` | `string[]` | — | **Required.** Primary key fields |
44
+ | `includeEntityKeysInExport` | `boolean` | `true` | Force `entityKeys`/primary keys into exports even when hidden, preserving ID-first re-import matching. Set `false` for id-less templates or cross-space copies. |
41
45
  | `navigationType` | `navigate \| dialog \| store` | — | **Required.** Row click behavior |
42
46
  | `enableDynamicGrid` | `boolean` | — | Enable dynamic columns |
43
47
  | `enableViews` | `boolean` | — | Show view selector |
@@ -53,10 +57,15 @@ Full-featured data table with views, filtering, sorting, pagination, and row act
53
57
  | `highlightNew` | `boolean` | `true` | Highlight newly added rows |
54
58
  | `highlightUpdated` | `boolean` | `true` | Highlight rows with updated values |
55
59
  | `highlightForRefreshes` | `number` | `1` | Per-row TTL — refresh cycles a highlight persists |
60
+ | `defaultExpandedRows` | `boolean` | `false` | Pre-expand parent rows once on first load when `childViews` exist; refreshes preserve user collapse/expand choices |
56
61
  | `onRowClick` | `action[]` | — | Default row click action |
57
62
  | `onDataLoad` | `action[]` | — | Action after data loads |
58
63
  | `items` | `any` | — | Static data (instead of query) |
59
64
 
65
+ **Pagination display:** when `totalCount` is `0`, DataGrid shows `Showing 0 to 0 of 0 entries` instead of starting at row `1`.
66
+
67
+ **Store navigation state:** with `navigationType: store`, DataGrid keeps `{gridName}_limit`, `{gridName}_offset`, and search state in the local UI context store, not URL variables. Use it for embedded/stateful grids where dialogs or parent re-renders must not reset pagination back to page 1.
68
+
60
69
  **View definition:**
61
70
  | Prop | Type | Description |
62
71
  |------|------|-------------|
@@ -64,20 +73,34 @@ Full-featured data table with views, filtering, sorting, pagination, and row act
64
73
  | `displayName` | `ILocalizeString` | View label |
65
74
  | `columns` | `IColumn[]` | Column definitions |
66
75
  | `filter` | `string` | View-level filter |
76
+ | `search` | `string` | Default search term seeded once on initial load; supports `{{ }}` templates; URL/user search wins |
67
77
  | `orderBy` | `{name, direction}[]` | Default sort |
78
+ | `paginationPosition` | `top \| bottom` | Place pagination controls above or below rows (`bottom` default) |
68
79
  | `onRowClick` | `action[]` | Per-view row click |
69
80
  | `enableSelect` | `Single \| Multiple` | Per-view selection |
81
+ | `includeEntityKeysInExport` | `boolean` | Per-view override for exporting entity keys |
82
+ | `stickyColumns` | `{left: string[], right: string[]}` | User-pinned columns for the view. Left-pinned columns render first, normal columns next, right-pinned columns last |
70
83
  | `childViews` | `object` | Expandable child views |
71
84
 
72
85
  **Column definition:**
73
86
  | Prop | Type | Description |
74
87
  |------|------|-------------|
75
- | `name` | `string` | Field name |
88
+ | `name` | `string` | Field name or resolver expression |
76
89
  | `label` | `ILocalizeString` | Column header |
77
- | `isHidden` | `boolean` | Hidden column |
78
- | `showAs` | `{component, props}` | Custom cell renderer |
90
+ | `description` | `ILocalizeString` | Header and column-picker tooltip; dynamic entity columns inherit the field description |
91
+ | `isHidden` | `boolean \| template` | Available in picker but hidden by default; also excluded from export when truthy |
92
+ | `isVisible` | `boolean \| template` | Inverse visibility flag; excluded from export when false |
93
+ | `showAs` | `{component, props, queries}` | Custom cell renderer |
79
94
  | `width` | `number` | Column width |
80
95
  | `sticky` | `left \| right` | Pin column |
96
+ | `enableEdit` | `boolean` | Enable inline editing (requires `editor`) |
97
+ | `editor` | `{component, props}` | Editor component (required with `enableEdit`) |
98
+ | `onEdit` | `action[]` | Action on edit commit. Variables: `changedValues`, `value`, `index`, + row data |
99
+ | `exportPath` | `string` | Export key/path override (top-level or `props.exportPath`). Fallback: `exportPath ?? path ?? name` |
100
+ | `exportTemplate` | `string` | Template expression for export-only formatted value (top-level or `props.exportTemplate`); exposed at `store.<gridName>.exportTemplates` |
101
+ | `path` | `string` | Data path for column value. Fallback for `exportPath` |
102
+ | `subQueries` | `string[]` | Extra GraphQL field paths to fetch without displaying them as columns |
103
+ | `excludeFromQuery` | `boolean` | Exclude from GraphQL query and CSV export |
81
104
 
82
105
  ```yaml
83
106
  component: dataGrid
@@ -101,13 +124,20 @@ props:
101
124
  views:
102
125
  - name: all
103
126
  displayName: { en-US: "All Orders" }
127
+ paginationPosition: top
104
128
  columns:
105
129
  - name: id
106
130
  isHidden: true
107
131
  - name: orderNumber
108
132
  label: { en-US: "Order #" }
133
+ subQueries:
134
+ - customer.name
109
135
  - name: customerName
110
136
  label: { en-US: "Customer" }
137
+ exportPath: customer.displayName
138
+ - name: totalAmount
139
+ label: { en-US: "Total" }
140
+ exportTemplate: "{{ formatCurrency totalAmount currencyCode }}"
111
141
  - name: status
112
142
  label: { en-US: "Status" }
113
143
  showAs:
@@ -124,6 +154,7 @@ props:
124
154
  - name: active
125
155
  displayName: { en-US: "Active" }
126
156
  filter: "status:Active"
157
+ search: "{{ inputs.customerName }}"
127
158
  columns:
128
159
  - name: id
129
160
  isHidden: true
@@ -143,6 +174,8 @@ props:
143
174
  enableColumns: true
144
175
  enableFilter: true
145
176
  defaultView: all
177
+ defaultExpandedRows: true
178
+ includeEntityKeysInExport: true
146
179
  onRowClick:
147
180
  - navigate: "orders/{{ id }}"
148
181
  toolbar:
@@ -156,6 +189,221 @@ props:
156
189
  - notification: { message: { en-US: "Exporting..." }, type: success }
157
190
  ```
158
191
 
192
+ ### Entity Fields & Column Visibility
193
+
194
+ When `rootEntityName` is set in datagrid options, the component fetches entity field definitions via GraphQL at runtime. Entity fields become "available columns" in the column picker — they are **not visible by default**. To make an entity field visible by default, add it to a view's `columns` array.
195
+
196
+ **Entity field properties** (in `entities[].fields[]`):
197
+
198
+ | Property | Location | Effect |
199
+ |----------|----------|--------|
200
+ | `allowOrderBy: false` | `props` (preferred) or top-level legacy | Disables sorting; runtime falls back to top-level `allowOrderBy` when `props.allowOrderBy` is absent |
201
+ | `allowFilter: false` | `props` | Hides from filter picker |
202
+ | `allowSelect: false` | `props` | Hides from standard column picker; filter picker still uses `allowFilter` |
203
+ | `filterByProperty` | `props` | Filter against a different field/path than the display column; nested filter paths honor parent `filterByProperty` values |
204
+ | `isInactive: true` | top-level | Marks field as inactive |
205
+ | `isCustomField: true` | top-level | Marks as custom field |
206
+ | `priority: <int>` | top-level | Resolves duplicate field definitions across app modules; highest active priority wins |
207
+
208
+ **Visibility rules:**
209
+
210
+ - Do **not** use `fieldType: select` for new entity fields. It is a legacy pattern that requires `props.showAs` to appear in the column picker and causes rendering conflicts on editable columns (see pitfalls below). Use the appropriate non-select fieldType instead (`text`, `number`, `date`, `enhanced-rangedatetime`, `checkbox`, etc.). All non-select types appear in the picker without needing `showAs`.
211
+ - `fieldType: Entity` is filtered out of the column picker entirely by the runtime — do not use it.
212
+ - `isHidden` is only valid on view columns, not entity field definitions.
213
+ - View column `name` must exactly match entity field `name`. If they differ (e.g., using a GraphQL alias prefix), the datagrid treats them as two separate columns — one always visible from the view, one hidden in the picker from the entity field.
214
+ - Saved database views override YAML definitions. User customizations take priority. If a user has saved a view, YAML visibility changes have no effect until the saved view is deleted.
215
+
216
+ **Correct pattern** (resolver column, sortable, filterable, in picker):
217
+
218
+ ```yaml
219
+ entities:
220
+ - name: MyEntity
221
+ entityKind: Order
222
+ fields:
223
+ - name: 'getTerminal(idPropertyName:"terminalId").name'
224
+ displayName: { en-US: Terminal }
225
+ description: { en-US: Terminal }
226
+ fieldType: text
227
+ isInactive: false
228
+ isCustomField: true
229
+ props:
230
+ orderByProperty: "customValues.terminalId->terminal.name"
231
+ filterByProperty: "customValues.terminalId"
232
+ filter:
233
+ component: Terminals/Select
234
+
235
+ views:
236
+ - name: all
237
+ columns:
238
+ - name: 'getTerminal(idPropertyName:"terminalId").name' # matches entity field exactly
239
+ label: { en-US: Terminal }
240
+ ```
241
+
242
+ ### Export + Re-import Keys
243
+
244
+ DataGrid export configuration now prepends missing `options.entityKeys` by default. This is intentional: import tasks can match by primary key first, so users can export a grid, edit business-key columns, and re-import without creating duplicate records.
245
+
246
+ Disable key injection only for clean/template exports:
247
+
248
+ ```yaml
249
+ props:
250
+ options:
251
+ entityKeys: [contactAddressId]
252
+ includeEntityKeysInExport: false
253
+ views:
254
+ - name: publicTemplate
255
+ includeEntityKeysInExport: false
256
+ ```
257
+
258
+ ### Inline Cell Editing
259
+
260
+ **Both `enableEdit: true` AND `editor` are required** for inline editing to activate.
261
+
262
+ Example with built-in field editor:
263
+
264
+ ```yaml
265
+ columns:
266
+ - name: trackingNumber
267
+ enableEdit: true
268
+ editor: { component: field }
269
+ onEdit:
270
+ - mutation:
271
+ variables:
272
+ trackingNumber: "{{ changedValues }}"
273
+ ```
274
+
275
+ Example with select-async editor — use `{{ value }}` in `onEdit`:
276
+
277
+ ```yaml
278
+ columns:
279
+ - name: customValues.returnLocation
280
+ enableEdit: true
281
+ editor:
282
+ component: Terminals/Select
283
+ onEdit:
284
+ - mutation:
285
+ variables:
286
+ input:
287
+ values:
288
+ customValues:
289
+ returnLocationId: "{{ number value }}"
290
+ ```
291
+
292
+ ### Entity Field Pitfalls
293
+
294
+ **Pitfall 1 — `fieldType: select` is legacy (do not use for new fields)**
295
+
296
+ `fieldType: select` requires `props.showAs` to appear in the column picker — without it, the column is invisible. Non-select types always appear.
297
+
298
+ When editing existing modules that use `fieldType: select` with inline editing: `showAs` changes how EditableCell renders in display mode. The cell goes through ComponentRender template evaluation instead of raw value display. This produces different visual output than the original grid column definition. Be aware of this dual behavior when maintaining legacy `select` fields.
299
+
300
+ **Pitfall 2 — Entity field `onEdit` must match grid column `onEdit` verbatim**
301
+
302
+ When a user re-adds an editable column from the picker, the entity field's `onEdit` replaces the grid column's `onEdit` entirely. If they differ (different mutation, different variable names, different `onSuccess`), the re-added column saves differently. Always copy `onEdit` from the grid view column definition into the entity field definition verbatim.
303
+
304
+ **Pitfall 3 — Edit properties go inside `props` in entity fields**
305
+
306
+ Unlike grid view columns where `enableEdit`, `editor`, and `onEdit` are top-level, entity field definitions must place them inside `props`. The runtime automatically promotes them to top-level when building available columns.
307
+
308
+ **Example — entity field with inline editing:**
309
+
310
+ ```yaml
311
+ entities:
312
+ - name: MyEntity
313
+ entityKind: Order
314
+ fields:
315
+ - name: 'getTerminal(idPropertyName:"terminalId").name'
316
+ displayName: { en-US: Terminal }
317
+ description: { en-US: Terminal }
318
+ fieldType: text
319
+ isInactive: false
320
+ isCustomField: true
321
+ props:
322
+ enableEdit: true # inside props, not top-level
323
+ editor:
324
+ component: Terminals/Select
325
+ onEdit: # must match grid column onEdit exactly
326
+ - mutation:
327
+ command: |
328
+ mutation UpdateOrderMutation($input: UpdateOrderInput!) {
329
+ updateOrder(input: $input) { order { orderId } }
330
+ }
331
+ variables:
332
+ input:
333
+ organizationId: "{{number organizationId}}"
334
+ orderId: "{{number orderId}}"
335
+ values:
336
+ customValues:
337
+ terminalId: "{{ number value }}"
338
+ onSuccess:
339
+ - refresh: orders
340
+ orderByProperty: "customValues.terminalId->terminal.name"
341
+ filterByProperty: "customValues.terminalId"
342
+ filter:
343
+ component: Terminals/Select
344
+ ```
345
+
346
+ ### Sorting Resolver Columns
347
+
348
+ Resolver columns (e.g., `getTerminal(idPropertyName:"terminalId").name`) cannot be sorted by default — the backend rejects them as invalid entity properties. Use `orderByProperty` in column `props` to override the sort field:
349
+
350
+ ```yaml
351
+ - name: 'getTerminal(idPropertyName:"terminalId").name'
352
+ label: { en-US: Terminal }
353
+ props:
354
+ orderByProperty: "customValues.terminalId->terminal.name"
355
+ ```
356
+
357
+ Join syntax format: `customValues.{idPropertyName}->{entityAlias}.{property}`
358
+
359
+ Single-level property access only (`terminal.name` works, `contact.address.city` does not).
360
+
361
+ Registered join entities: `contact`, `order`, `modeOfTransportation`, `country`, `terminal`, `contactAddress`.
362
+
363
+ Contact-address custom values can use the same override pattern, for example `customValues.deliveryLocationId->contactAddress.name` or `customValues.returnLocationId->contactAddress.name`.
364
+
365
+ Alternative: disable sorting with `allowOrderBy: false` in column props.
366
+
367
+ ### Hidden Query Dependencies
368
+
369
+ Use column-level `subQueries` when a column renderer, action, conditional style, or export needs related GraphQL fields that should not appear as visible columns. The runtime appends these paths to the query selection and preserves them when users add the column in view settings.
370
+
371
+ ```yaml
372
+ - name: orderNumber
373
+ label: { en-US: Order # }
374
+ subQueries:
375
+ - customer.name
376
+ - customer.primaryContact.email
377
+ showAs:
378
+ component: text
379
+ props:
380
+ value: "{{ orderNumber }} — {{ customer.name }}"
381
+ ```
382
+
383
+ ### CSV Export
384
+
385
+ `exportPath` controls the column key used for CSV export. Fallback chain: `exportPath ?? path ?? name`.
386
+
387
+ For resolver columns, `exportPath` must use the GraphQL response key **without arguments**:
388
+
389
+ ```yaml
390
+ # Correct — GraphQL response uses "getTerminal" as the key
391
+ - name: 'getTerminal(idPropertyName:"terminalId").name'
392
+ exportPath: "getTerminal.name"
393
+ label: { en-US: Terminal }
394
+
395
+ # Wrong — response key does not include arguments, CSV values will be empty
396
+ - name: 'getTerminal(idPropertyName:"terminalId").name'
397
+ exportPath: 'getTerminal(idPropertyName:"terminalId").name'
398
+ ```
399
+
400
+ For aliased resolver fields, use the alias as the response key:
401
+
402
+ ```yaml
403
+ - name: 'returnLocation : getTerminal(idPropertyName:"returnLocationId").name'
404
+ exportPath: "returnLocation.name"
405
+ ```
406
+
159
407
  ---
160
408
 
161
409
  ## text
@@ -169,6 +417,10 @@ Typography text display with template interpolation.
169
417
  | `type` | `h1-h6 \| p \| span \| block` | `span` | HTML element / MUI variant |
170
418
  | `color` | `string` | `text` | MUI color |
171
419
  | `options` | `object` | — | Additional MUI Typography props |
420
+ | `label` | `string \| localized \| template` | — | Optional label rendered with the text |
421
+ | `labelPosition` | `top \| left` | `top` | Label placement |
422
+ | `labelColor` | `string` | `text.secondary` | MUI color for label |
423
+ | `labelWidth` | `string \| number` | `auto` | Minimum label width when `labelPosition: left` |
172
424
  | `stopPropagation` | `boolean` | — | Stop click propagation |
173
425
 
174
426
  **Events:** `onClick`
@@ -184,6 +436,9 @@ Typography text display with template interpolation.
184
436
  - component: text
185
437
  name: statusLabel
186
438
  props:
439
+ label: { en-US: "Last updated" }
440
+ labelPosition: left
441
+ labelWidth: 8rem
187
442
  value: "{{ format lastModified LLL }}"
188
443
  type: span
189
444
  color: text.secondary
@@ -219,14 +474,33 @@ props:
219
474
 
220
475
  ## badge
221
476
 
222
- Colored chip/badge with dot indicator.
477
+ Compact theme-aware badge. Prefer semantic variants for new modules; the dot is opt-in.
478
+
479
+ ## avatar, infoLine, and progressBar
480
+
481
+ Use these template-aware display components for compact entity cards and planner headers.
482
+
483
+ ```yaml
484
+ - component: avatar
485
+ props: { name: '{{ row.record.name }}', colorSeed: '{{ row.record.id }}', size: 40 }
486
+ - component: infoLine
487
+ props: { icon: tabler-phone, value: '{{ row.record.phone }}', href: 'tel:{{ row.record.phone }}' }
488
+ - component: progressBar
489
+ props: { items: '{{ row.items }}', completedPath: status, completedValue: Completed }
490
+ ```
491
+
492
+ `avatar` derives initials from names/email and uses `src` as an optional image. `infoLine` renders nothing for an empty value and only links allowlisted URL schemes. `progressBar` accepts direct `value`/`max` or derives counts from `items`; choose `count`/`percent` and `linear`/`circular`/`segmented` display modes. On mobile, `activeColor` and `trackColor` customize segmented progress; `tooltip` is exposed to assistive technology rather than hover UI.
223
493
 
224
494
  **Props:**
225
495
  | Prop | Type | Description |
226
496
  |------|------|-------------|
227
- | `label` | `string` | Badge text (template-parsed) |
228
- | `colorKey` | `string` | Color lookup key (template-parsed; defaults to lowercased label) |
229
- | `options.colors` | `Record<string, {label, bgcolor, dot}>` | Color map (must include `default`) |
497
+ | `label` | `string` | Badge text (template-parsed with store, component variables, and form values) |
498
+ | `colorKey` | `string` | Color lookup key (template-parsed with store, component variables, and form values; defaults to lowercased label) |
499
+ | `color` / `variant` | `string` | Seed hex or semantic variant (`danger`, `warning`, `info`, `success`, `primary`, `neutral`) |
500
+ | `size` / `appearance` | `string` | `xs|sm|md`; `soft|outline|solid|ghost` |
501
+ | `uppercase`, `dot` | `boolean` | Both default to `false` |
502
+ | `icon`, `maxWidth` | `string`, `string \| number` | Optional icon and ellipsis width |
503
+ | `options.colors` | `Record<string, string \| object>` | Optional variants, hexes, token objects, or legacy triples |
230
504
  | `onClick` | `Action[]` | Actions to dispatch when the badge is clicked. Makes the badge interactive (pointer cursor). |
231
505
 
232
506
  ```yaml
@@ -361,7 +635,7 @@ props:
361
635
 
362
636
  ## diff
363
637
 
364
- Side-by-side diff viewer for comparing text.
638
+ Side-by-side diff viewer for comparing text. Long lines wrap within each pane, and gutters/markers keep fixed widths so the two columns stay balanced.
365
639
 
366
640
  **Props:**
367
641
  | Prop | Type | Default | Description |