@praxisui/table 10.0.0-rc.27 → 10.0.0-rc.29
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/ai/component-registry.json +2 -2
- package/fesm2022/praxisui-table-authoring.mjs +160 -6
- package/fesm2022/{praxisui-table-praxisui-table-CosVmN5P.mjs → praxisui-table-praxisui-table-By0aZFU7.mjs} +1913 -244
- package/fesm2022/{praxisui-table-table-agentic-authoring-turn-flow-CtHAHd7Y.mjs → praxisui-table-table-agentic-authoring-turn-flow-BbqceuRl.mjs} +1 -1
- package/fesm2022/{praxisui-table-table-ai.adapter-DYY3eUYu.mjs → praxisui-table-table-ai.adapter-DIf5nJOG.mjs} +1 -1
- package/fesm2022/praxisui-table.mjs +1 -1
- package/package.json +10 -10
- package/src/lib/praxis-table.json-api.md +2 -0
- package/types/praxisui-table.d.ts +100 -10
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "1.0.0",
|
|
3
|
-
"generatedAt": "2026-10-
|
|
3
|
+
"generatedAt": "2026-10-16T14:27:38.517Z",
|
|
4
4
|
"packageName": "@praxisui/table",
|
|
5
|
-
"packageVersion": "10.0.0-rc.
|
|
5
|
+
"packageVersion": "10.0.0-rc.29",
|
|
6
6
|
"sourceRegistry": "praxis-component-registry-ingestion",
|
|
7
7
|
"sourceRegistryVersion": "1.0.0",
|
|
8
8
|
"componentCount": 3,
|
|
@@ -389,8 +389,141 @@ function inspectInlineDetailSchema(schema, config) {
|
|
|
389
389
|
Object.values(node).forEach(visit);
|
|
390
390
|
};
|
|
391
391
|
visit(schema);
|
|
392
|
+
const offContract = hasOffContractRichChildren([schema]);
|
|
393
|
+
if (offContract.cardGrid)
|
|
394
|
+
issues.push('cardGridContent');
|
|
395
|
+
if (offContract.compose)
|
|
396
|
+
issues.push('composeContent');
|
|
392
397
|
return issues;
|
|
393
398
|
}
|
|
399
|
+
/** Rich node types accepted as `cardGrid` card content by the canonical `TableDetailCardGridCardNode` contract. */
|
|
400
|
+
const TABLE_DETAIL_CARD_GRID_PRESENTER_TYPES = new Set([
|
|
401
|
+
'text', 'icon', 'image', 'badge', 'avatar', 'metric', 'progress', 'progressBar',
|
|
402
|
+
'microVisualization', 'link', 'chip', 'button', 'rating',
|
|
403
|
+
]);
|
|
404
|
+
/** `RichComposeNode.items` accepts presenters only (no nested compose). */
|
|
405
|
+
function isTableDetailComposeItemNode(node) {
|
|
406
|
+
if (!node || typeof node !== 'object' || Array.isArray(node))
|
|
407
|
+
return false;
|
|
408
|
+
return TABLE_DETAIL_CARD_GRID_PRESENTER_TYPES.has(String(node['type'] || '').trim());
|
|
409
|
+
}
|
|
410
|
+
function isTableDetailCardGridContentNode(node) {
|
|
411
|
+
if (!node || typeof node !== 'object' || Array.isArray(node))
|
|
412
|
+
return false;
|
|
413
|
+
const type = String(node['type'] || '').trim();
|
|
414
|
+
return type === 'compose' || TABLE_DETAIL_CARD_GRID_PRESENTER_TYPES.has(type);
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Projects an authored node into canonical `cardGrid` card content (`RichPresenterNode | RichComposeNode`).
|
|
418
|
+
* Table-detail `value` fields become `metric` (labelled) or `text` presenters; structural blocks that
|
|
419
|
+
* cannot live inside a rich card (stack, tabs, card, timeline, chartRef, richContent) return `null`.
|
|
420
|
+
*/
|
|
421
|
+
function toTableDetailCardGridContentNode(node) {
|
|
422
|
+
if (isTableDetailCardGridContentNode(node))
|
|
423
|
+
return node;
|
|
424
|
+
const type = String(node?.['type'] || '').trim();
|
|
425
|
+
if (type === 'cardGrid') {
|
|
426
|
+
const first = Array.isArray(node['cards']) ? node['cards'][0]?.content?.[0] : undefined;
|
|
427
|
+
return first ? toTableDetailCardGridContentNode(structuredClone(first)) : null;
|
|
428
|
+
}
|
|
429
|
+
if (type !== 'value')
|
|
430
|
+
return null;
|
|
431
|
+
const field = String(node['field'] || node['valueField'] || '').trim();
|
|
432
|
+
const authoredExpr = typeof node['valueExpr'] === 'string' ? node['valueExpr'].trim().replace(/^=\s*/, '') : '';
|
|
433
|
+
const valueExpr = authoredExpr || (field ? `row.${field}` : '');
|
|
434
|
+
if (!valueExpr)
|
|
435
|
+
return null;
|
|
436
|
+
const label = typeof node['label'] === 'string' ? node['label'].trim() : '';
|
|
437
|
+
return {
|
|
438
|
+
...(node['id'] ? { id: node['id'] } : {}),
|
|
439
|
+
...(label ? { type: 'metric', label, valueExpr } : { type: 'text', textExpr: valueExpr }),
|
|
440
|
+
...(node['visibleWhen'] != null ? { visibleWhen: node['visibleWhen'] } : {}),
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
/** Projects an authored node into a canonical compose item (presenter); a compose result yields its first presenter. */
|
|
444
|
+
function toTableDetailComposeItemNode(node) {
|
|
445
|
+
const projected = toTableDetailCardGridContentNode(node);
|
|
446
|
+
if (!projected)
|
|
447
|
+
return null;
|
|
448
|
+
if (projected['type'] !== 'compose')
|
|
449
|
+
return projected;
|
|
450
|
+
const first = Array.isArray(projected['items'])
|
|
451
|
+
? projected['items'].find((item) => isTableDetailComposeItemNode(item))
|
|
452
|
+
: undefined;
|
|
453
|
+
return first ? structuredClone(first) : null;
|
|
454
|
+
}
|
|
455
|
+
/** True when a cardGrid card or a compose (outside richContent documents) holds off-contract children. */
|
|
456
|
+
function hasOffContractRichChildren(nodes) {
|
|
457
|
+
const result = { cardGrid: false, compose: false };
|
|
458
|
+
const visit = (value) => {
|
|
459
|
+
if (!Array.isArray(value))
|
|
460
|
+
return;
|
|
461
|
+
for (const node of value) {
|
|
462
|
+
if (!node || typeof node !== 'object' || Array.isArray(node))
|
|
463
|
+
continue;
|
|
464
|
+
const record = node;
|
|
465
|
+
if (record['type'] === 'richContent')
|
|
466
|
+
continue;
|
|
467
|
+
if (record['type'] === 'cardGrid' && Array.isArray(record['cards'])) {
|
|
468
|
+
for (const card of record['cards']) {
|
|
469
|
+
const content = card?.['content'];
|
|
470
|
+
if (Array.isArray(content) && content.some((item) => !isTableDetailCardGridContentNode(item))) {
|
|
471
|
+
result.cardGrid = true;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
if (record['type'] === 'compose' && Array.isArray(record['items'])
|
|
476
|
+
&& record['items'].some((item) => !isTableDetailComposeItemNode(item))) {
|
|
477
|
+
result.compose = true;
|
|
478
|
+
}
|
|
479
|
+
visit(record['items']);
|
|
480
|
+
visit(record['content']);
|
|
481
|
+
visit(record['cards']);
|
|
482
|
+
}
|
|
483
|
+
};
|
|
484
|
+
visit(nodes);
|
|
485
|
+
return result;
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Losslessly rewrites legacy table-detail `value` fields that sit inside cardGrid cards or compose items
|
|
489
|
+
* into canonical presenters. Structural blocks are left untouched (still reported) to avoid data loss.
|
|
490
|
+
* Returns the number of rewritten nodes.
|
|
491
|
+
*/
|
|
492
|
+
function normalizeTableDetailRichChildren(schema) {
|
|
493
|
+
let rewritten = 0;
|
|
494
|
+
const rewrite = (list, project, accepts) => {
|
|
495
|
+
if (!Array.isArray(list))
|
|
496
|
+
return;
|
|
497
|
+
list.forEach((item, index) => {
|
|
498
|
+
if (accepts(item) || item?.['type'] !== 'value')
|
|
499
|
+
return;
|
|
500
|
+
const projected = project(item);
|
|
501
|
+
if (projected) {
|
|
502
|
+
list[index] = projected;
|
|
503
|
+
rewritten += 1;
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
};
|
|
507
|
+
const visit = (value) => {
|
|
508
|
+
if (!Array.isArray(value))
|
|
509
|
+
return;
|
|
510
|
+
for (const node of value) {
|
|
511
|
+
if (!node || typeof node !== 'object' || Array.isArray(node) || node['type'] === 'richContent')
|
|
512
|
+
continue;
|
|
513
|
+
if (node['type'] === 'cardGrid' && Array.isArray(node['cards'])) {
|
|
514
|
+
for (const card of node['cards'])
|
|
515
|
+
rewrite(card?.['content'], toTableDetailCardGridContentNode, isTableDetailCardGridContentNode);
|
|
516
|
+
}
|
|
517
|
+
if (node['type'] === 'compose')
|
|
518
|
+
rewrite(node['items'], toTableDetailComposeItemNode, isTableDetailComposeItemNode);
|
|
519
|
+
visit(node['items']);
|
|
520
|
+
visit(node['content']);
|
|
521
|
+
visit(node['cards']);
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
visit([schema]);
|
|
525
|
+
return rewritten;
|
|
526
|
+
}
|
|
394
527
|
/** Edits the original authoring tree; keys exist only in the editor's WeakMap. */
|
|
395
528
|
class TableDetailTreeDraft {
|
|
396
529
|
keys = new WeakMap();
|
|
@@ -449,8 +582,11 @@ class TableDetailTreeDraft {
|
|
|
449
582
|
entry.siblings.splice(next, 0, entry.node);
|
|
450
583
|
}
|
|
451
584
|
add(node, nested = false) {
|
|
452
|
-
const
|
|
585
|
+
const selectedEntry = this.selected();
|
|
586
|
+
const selected = selectedEntry?.node;
|
|
453
587
|
const isCardLike = selected?.type === 'card' || (!selected?.type && Array.isArray(selected?.content));
|
|
588
|
+
// Cards stored in `cardGrid.cards` follow TableDetailCardGridCardNode: rich presenters/compose only.
|
|
589
|
+
const isCardGridCard = !!selectedEntry && isCardLike && this.entries().some((entry) => entry.node['type'] === 'cardGrid' && entry.node['cards'] === selectedEntry.siblings);
|
|
454
590
|
const childKey = selected?.type === 'cardGrid'
|
|
455
591
|
? 'cards'
|
|
456
592
|
: (isCardLike || selected?.type === 'tab')
|
|
@@ -466,23 +602,40 @@ class TableDetailTreeDraft {
|
|
|
466
602
|
node = structuredClone(node.cards[0]);
|
|
467
603
|
}
|
|
468
604
|
else if (node.type === 'card') {
|
|
605
|
+
const content = (Array.isArray(node.content) ? node.content : [])
|
|
606
|
+
.map((child) => toTableDetailCardGridContentNode(child))
|
|
607
|
+
.filter((child) => !!child);
|
|
469
608
|
node = {
|
|
470
609
|
...(node.id ? { id: node.id } : {}),
|
|
471
610
|
title: node.title ?? '',
|
|
472
611
|
...(node.subtitle !== undefined ? { subtitle: node.subtitle } : {}),
|
|
473
|
-
content:
|
|
474
|
-
? node.content
|
|
475
|
-
: [{ type: 'text', text: node.title || 'Detalhe' }],
|
|
612
|
+
content: content.length ? content : [{ type: 'text', text: node.title || 'Detalhe' }],
|
|
476
613
|
};
|
|
477
614
|
}
|
|
478
615
|
else if (!Array.isArray(node.content)) {
|
|
616
|
+
const content = toTableDetailCardGridContentNode(node);
|
|
617
|
+
if (!content)
|
|
618
|
+
return null;
|
|
479
619
|
node = {
|
|
480
620
|
title: node.title || node.label || '',
|
|
481
|
-
content: [
|
|
621
|
+
content: [content],
|
|
482
622
|
};
|
|
483
623
|
}
|
|
484
624
|
}
|
|
485
|
-
else if (nested &&
|
|
625
|
+
else if (nested && isCardGridCard) {
|
|
626
|
+
const content = toTableDetailCardGridContentNode(node);
|
|
627
|
+
if (!content)
|
|
628
|
+
return null;
|
|
629
|
+
node = content;
|
|
630
|
+
}
|
|
631
|
+
else if (nested && selected?.type === 'compose') {
|
|
632
|
+
// RichComposeNode.items accepts presenters only; the runtime drops anything else silently.
|
|
633
|
+
const item = toTableDetailComposeItemNode(node);
|
|
634
|
+
if (!item)
|
|
635
|
+
return null;
|
|
636
|
+
node = item;
|
|
637
|
+
}
|
|
638
|
+
else if (nested && isCardLike && node.type === 'cardGrid' && Array.isArray(node.cards)) {
|
|
486
639
|
const firstCardContent = node.cards[0]?.content;
|
|
487
640
|
if (Array.isArray(firstCardContent) && firstCardContent.length > 0) {
|
|
488
641
|
node = structuredClone(firstCardContent[0]);
|
|
@@ -492,6 +645,7 @@ class TableDetailTreeDraft {
|
|
|
492
645
|
parent[key] = [];
|
|
493
646
|
parent[key].push(node);
|
|
494
647
|
this.selectedKey = this.entries().find(entry => entry.node === node)?.key ?? null;
|
|
648
|
+
return node;
|
|
495
649
|
}
|
|
496
650
|
}
|
|
497
651
|
|