@apteva/apteva-kit 0.1.69 → 0.1.70
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/dist/index.d.mts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +241 -68
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +322 -149
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -23,6 +23,8 @@ interface Widget {
|
|
|
23
23
|
actions?: Action[];
|
|
24
24
|
/** Additional data not displayed but captured via onWidgetRender */
|
|
25
25
|
meta?: Record<string, any>;
|
|
26
|
+
/** Whether the widget is still receiving streaming data */
|
|
27
|
+
isStreaming?: boolean;
|
|
26
28
|
}
|
|
27
29
|
interface CardWidget extends Widget {
|
|
28
30
|
type: 'card';
|
|
@@ -392,7 +394,9 @@ interface CardProps {
|
|
|
392
394
|
declare function Card({ widget, onAction }: CardProps): react_jsx_runtime.JSX.Element;
|
|
393
395
|
|
|
394
396
|
interface ListProps {
|
|
395
|
-
widget: ListWidget
|
|
397
|
+
widget: ListWidget & {
|
|
398
|
+
isStreaming?: boolean;
|
|
399
|
+
};
|
|
396
400
|
onAction?: (action: ActionEvent) => void;
|
|
397
401
|
}
|
|
398
402
|
declare function List({ widget, onAction }: ListProps): react_jsx_runtime.JSX.Element;
|
package/dist/index.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ interface Widget {
|
|
|
23
23
|
actions?: Action[];
|
|
24
24
|
/** Additional data not displayed but captured via onWidgetRender */
|
|
25
25
|
meta?: Record<string, any>;
|
|
26
|
+
/** Whether the widget is still receiving streaming data */
|
|
27
|
+
isStreaming?: boolean;
|
|
26
28
|
}
|
|
27
29
|
interface CardWidget extends Widget {
|
|
28
30
|
type: 'card';
|
|
@@ -392,7 +394,9 @@ interface CardProps {
|
|
|
392
394
|
declare function Card({ widget, onAction }: CardProps): react_jsx_runtime.JSX.Element;
|
|
393
395
|
|
|
394
396
|
interface ListProps {
|
|
395
|
-
widget: ListWidget
|
|
397
|
+
widget: ListWidget & {
|
|
398
|
+
isStreaming?: boolean;
|
|
399
|
+
};
|
|
396
400
|
onAction?: (action: ActionEvent) => void;
|
|
397
401
|
}
|
|
398
402
|
declare function List({ widget, onAction }: ListProps): react_jsx_runtime.JSX.Element;
|
package/dist/index.js
CHANGED
|
@@ -502,6 +502,71 @@ function validateFile(file) {
|
|
|
502
502
|
}
|
|
503
503
|
|
|
504
504
|
// src/utils/widget-parser.ts
|
|
505
|
+
var STREAMABLE_WIDGET_TYPES = ["list", "table"];
|
|
506
|
+
function parsePartialItemsArray(partialJson) {
|
|
507
|
+
const items = [];
|
|
508
|
+
let isStreaming = false;
|
|
509
|
+
const itemsMatch = partialJson.match(/"items"\s*:\s*\[/);
|
|
510
|
+
if (!itemsMatch) {
|
|
511
|
+
return { items, isStreaming: false };
|
|
512
|
+
}
|
|
513
|
+
const arrayStart = partialJson.indexOf("[", itemsMatch.index);
|
|
514
|
+
if (arrayStart === -1) {
|
|
515
|
+
return { items, isStreaming: true };
|
|
516
|
+
}
|
|
517
|
+
let depth = 0;
|
|
518
|
+
let inString = false;
|
|
519
|
+
let escapeNext = false;
|
|
520
|
+
let objectStart = -1;
|
|
521
|
+
for (let i = arrayStart + 1; i < partialJson.length; i++) {
|
|
522
|
+
const char = partialJson[i];
|
|
523
|
+
if (escapeNext) {
|
|
524
|
+
escapeNext = false;
|
|
525
|
+
continue;
|
|
526
|
+
}
|
|
527
|
+
if (char === "\\" && inString) {
|
|
528
|
+
escapeNext = true;
|
|
529
|
+
continue;
|
|
530
|
+
}
|
|
531
|
+
if (char === '"') {
|
|
532
|
+
inString = !inString;
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
535
|
+
if (inString) continue;
|
|
536
|
+
if (char === "{") {
|
|
537
|
+
if (depth === 0) {
|
|
538
|
+
objectStart = i;
|
|
539
|
+
}
|
|
540
|
+
depth++;
|
|
541
|
+
} else if (char === "}") {
|
|
542
|
+
depth--;
|
|
543
|
+
if (depth === 0 && objectStart !== -1) {
|
|
544
|
+
const objectJson = partialJson.slice(objectStart, i + 1);
|
|
545
|
+
try {
|
|
546
|
+
const item = JSON.parse(objectJson);
|
|
547
|
+
if (!item.id) {
|
|
548
|
+
item.id = `item-${items.length}-${simpleHash(objectJson)}`;
|
|
549
|
+
}
|
|
550
|
+
items.push(item);
|
|
551
|
+
} catch (e) {
|
|
552
|
+
}
|
|
553
|
+
objectStart = -1;
|
|
554
|
+
}
|
|
555
|
+
} else if (char === "]" && depth === 0) {
|
|
556
|
+
isStreaming = false;
|
|
557
|
+
break;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
if (depth > 0 || objectStart !== -1) {
|
|
561
|
+
isStreaming = true;
|
|
562
|
+
}
|
|
563
|
+
const afterItems = partialJson.slice(arrayStart);
|
|
564
|
+
const closingBracket = findMatchingBracket(afterItems, 0);
|
|
565
|
+
if (closingBracket === -1) {
|
|
566
|
+
isStreaming = true;
|
|
567
|
+
}
|
|
568
|
+
return { items, isStreaming };
|
|
569
|
+
}
|
|
505
570
|
function simpleHash(str) {
|
|
506
571
|
let hash = 0;
|
|
507
572
|
for (let i = 0; i < str.length; i++) {
|
|
@@ -563,9 +628,38 @@ function parseWidgetsFromText(text) {
|
|
|
563
628
|
const fullBracketStart = lastWidgetStart + bracketOpenIndex;
|
|
564
629
|
const bracketEnd = findMatchingBracket(text, fullBracketStart);
|
|
565
630
|
if (bracketEnd === -1) {
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
631
|
+
if (STREAMABLE_WIDGET_TYPES.includes(widgetType)) {
|
|
632
|
+
const partialContent = text.slice(fullBracketStart + 1);
|
|
633
|
+
const { items, isStreaming } = parsePartialItemsArray(partialContent);
|
|
634
|
+
if (items.length > 0) {
|
|
635
|
+
processText = text.slice(0, lastWidgetStart);
|
|
636
|
+
const widgetId = `widget-${widgetType}-streaming-${simpleHash(partialContent)}`;
|
|
637
|
+
const textBefore = processText.replace(/[\s:;\-–—\.]+$/g, "").trim();
|
|
638
|
+
if (textBefore) {
|
|
639
|
+
segments.push({ type: "text", content: textBefore });
|
|
640
|
+
}
|
|
641
|
+
segments.push({
|
|
642
|
+
type: "widget",
|
|
643
|
+
widget: {
|
|
644
|
+
type: widgetType,
|
|
645
|
+
id: widgetId,
|
|
646
|
+
props: widgetType === "table" ? { rows: items, columns: [] } : { items },
|
|
647
|
+
isStreaming: true
|
|
648
|
+
}
|
|
649
|
+
});
|
|
650
|
+
hasWidgets = true;
|
|
651
|
+
hasPendingWidget = false;
|
|
652
|
+
processText = "";
|
|
653
|
+
} else {
|
|
654
|
+
processText = text.slice(0, lastWidgetStart);
|
|
655
|
+
pendingWidgetType = widgetType;
|
|
656
|
+
hasPendingWidget = true;
|
|
657
|
+
}
|
|
658
|
+
} else {
|
|
659
|
+
processText = text.slice(0, lastWidgetStart);
|
|
660
|
+
pendingWidgetType = widgetType;
|
|
661
|
+
hasPendingWidget = true;
|
|
662
|
+
}
|
|
569
663
|
}
|
|
570
664
|
}
|
|
571
665
|
}
|
|
@@ -729,38 +823,73 @@ function Card({ widget, onAction }) {
|
|
|
729
823
|
|
|
730
824
|
// src/components/Widgets/widget-library/List.tsx
|
|
731
825
|
|
|
826
|
+
|
|
732
827
|
function List({ widget, onAction }) {
|
|
733
828
|
const { items } = widget.props;
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
829
|
+
const isStreaming = _nullishCoalesce(widget.isStreaming, () => ( false));
|
|
830
|
+
const seenItemsRef = _react.useRef.call(void 0, /* @__PURE__ */ new Set());
|
|
831
|
+
const [newItemIds, setNewItemIds] = _react.useState.call(void 0, /* @__PURE__ */ new Set());
|
|
832
|
+
_react.useEffect.call(void 0, () => {
|
|
833
|
+
const currentIds = new Set(items.map((item) => item.id));
|
|
834
|
+
const newIds = /* @__PURE__ */ new Set();
|
|
835
|
+
items.forEach((item) => {
|
|
836
|
+
if (!seenItemsRef.current.has(item.id)) {
|
|
837
|
+
newIds.add(item.id);
|
|
838
|
+
}
|
|
839
|
+
});
|
|
840
|
+
items.forEach((item) => seenItemsRef.current.add(item.id));
|
|
841
|
+
if (newIds.size > 0) {
|
|
842
|
+
setNewItemIds(newIds);
|
|
843
|
+
const timer = setTimeout(() => {
|
|
844
|
+
setNewItemIds(/* @__PURE__ */ new Set());
|
|
845
|
+
}, 500);
|
|
846
|
+
return () => clearTimeout(timer);
|
|
847
|
+
}
|
|
848
|
+
}, [items]);
|
|
849
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "border border-neutral-200 dark:border-neutral-700 rounded-xl bg-white dark:bg-neutral-900 overflow-hidden", children: [
|
|
850
|
+
items.map((item, index) => {
|
|
851
|
+
const isNew = newItemIds.has(item.id);
|
|
852
|
+
const isLast = index === items.length - 1;
|
|
853
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
854
|
+
"div",
|
|
855
|
+
{
|
|
856
|
+
className: `apteva-list-item flex items-center p-4 transition-colors ${!isLast || isStreaming ? "border-b border-neutral-200 dark:border-neutral-700" : ""} ${!item.backgroundColor ? "hover:bg-neutral-50 dark:hover:bg-neutral-800" : ""} ${isNew ? "apteva-list-item-new" : ""}`,
|
|
857
|
+
style: item.backgroundColor ? { backgroundColor: item.backgroundColor } : void 0,
|
|
858
|
+
children: [
|
|
859
|
+
item.image && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { src: item.image, alt: item.title, className: "w-16 h-16 rounded object-cover" }),
|
|
860
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: `flex-1 ${item.image ? "ml-4" : ""}`, children: [
|
|
861
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h4", { className: "font-semibold !text-neutral-900 dark:!text-white", children: item.title }),
|
|
862
|
+
item.subtitle && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "!text-sm !text-neutral-600 dark:!text-neutral-400", children: item.subtitle }),
|
|
863
|
+
item.description && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "!text-xs !text-neutral-500 dark:!text-neutral-500 mt-1", children: item.description })
|
|
864
|
+
] }),
|
|
865
|
+
widget.actions && widget.actions.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex gap-2", children: widget.actions.map((action, idx) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
866
|
+
"button",
|
|
867
|
+
{
|
|
868
|
+
onClick: () => _optionalChain([onAction, 'optionalCall', _3 => _3({
|
|
869
|
+
type: action.type,
|
|
870
|
+
payload: item.metadata || item,
|
|
871
|
+
widgetId: widget.id,
|
|
872
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
873
|
+
})]),
|
|
874
|
+
className: "px-3 py-1.5 !text-sm rounded-lg font-medium transition-colors bg-blue-500 !text-white hover:bg-blue-600",
|
|
875
|
+
children: action.label
|
|
876
|
+
},
|
|
877
|
+
idx
|
|
878
|
+
)) })
|
|
879
|
+
]
|
|
880
|
+
},
|
|
881
|
+
item.id
|
|
882
|
+
);
|
|
883
|
+
}),
|
|
884
|
+
isStreaming && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "apteva-list-streaming flex items-center gap-3 p-4 text-neutral-500 dark:text-neutral-400", children: [
|
|
885
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "apteva-streaming-dots flex gap-1", children: [
|
|
886
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "w-2 h-2 bg-current rounded-full animate-pulse", style: { animationDelay: "0ms" } }),
|
|
887
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "w-2 h-2 bg-current rounded-full animate-pulse", style: { animationDelay: "150ms" } }),
|
|
888
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "w-2 h-2 bg-current rounded-full animate-pulse", style: { animationDelay: "300ms" } })
|
|
889
|
+
] }),
|
|
890
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-sm", children: "Loading more..." })
|
|
891
|
+
] })
|
|
892
|
+
] });
|
|
764
893
|
}
|
|
765
894
|
|
|
766
895
|
// src/components/Widgets/widget-library/Button.tsx
|
|
@@ -840,8 +969,32 @@ function ButtonGroup({ widget, onAction }) {
|
|
|
840
969
|
|
|
841
970
|
// src/components/Widgets/widget-library/Table.tsx
|
|
842
971
|
|
|
972
|
+
|
|
843
973
|
function Table({ widget, onAction }) {
|
|
844
974
|
const { columns, rows, caption, compact = false, striped = false } = widget.props;
|
|
975
|
+
const isStreaming = _nullishCoalesce(widget.isStreaming, () => ( false));
|
|
976
|
+
const seenRowsRef = _react.useRef.call(void 0, /* @__PURE__ */ new Set());
|
|
977
|
+
const [newRowIds, setNewRowIds] = _react.useState.call(void 0, /* @__PURE__ */ new Set());
|
|
978
|
+
_react.useEffect.call(void 0, () => {
|
|
979
|
+
const newIds = /* @__PURE__ */ new Set();
|
|
980
|
+
rows.forEach((row, index) => {
|
|
981
|
+
const rowId = row.id || `row-${index}`;
|
|
982
|
+
if (!seenRowsRef.current.has(rowId)) {
|
|
983
|
+
newIds.add(rowId);
|
|
984
|
+
}
|
|
985
|
+
});
|
|
986
|
+
rows.forEach((row, index) => {
|
|
987
|
+
const rowId = row.id || `row-${index}`;
|
|
988
|
+
seenRowsRef.current.add(rowId);
|
|
989
|
+
});
|
|
990
|
+
if (newIds.size > 0) {
|
|
991
|
+
setNewRowIds(newIds);
|
|
992
|
+
const timer = setTimeout(() => {
|
|
993
|
+
setNewRowIds(/* @__PURE__ */ new Set());
|
|
994
|
+
}, 500);
|
|
995
|
+
return () => clearTimeout(timer);
|
|
996
|
+
}
|
|
997
|
+
}, [rows]);
|
|
845
998
|
const getAlignment = (align) => {
|
|
846
999
|
switch (align) {
|
|
847
1000
|
case "center":
|
|
@@ -868,47 +1021,67 @@ function Table({ widget, onAction }) {
|
|
|
868
1021
|
column.key
|
|
869
1022
|
)) }) }),
|
|
870
1023
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tbody", { children: [
|
|
871
|
-
rows.map((row, rowIndex) =>
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
{
|
|
893
|
-
className: cn(
|
|
894
|
-
"text-neutral-700 dark:text-neutral-300",
|
|
895
|
-
compact ? "px-3 py-2 text-xs" : "px-4 py-3 text-sm",
|
|
896
|
-
getAlignment(column.align)
|
|
897
|
-
),
|
|
898
|
-
children: _nullishCoalesce(row[column.key], () => ( "\u2014"))
|
|
1024
|
+
rows.map((row, rowIndex) => {
|
|
1025
|
+
const rowId = row.id || `row-${rowIndex}`;
|
|
1026
|
+
const isNew = newRowIds.has(rowId);
|
|
1027
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1028
|
+
"tr",
|
|
1029
|
+
{
|
|
1030
|
+
className: cn(
|
|
1031
|
+
"apteva-table-row border-b border-neutral-200 dark:border-neutral-700 last:border-b-0",
|
|
1032
|
+
"transition-colors hover:bg-neutral-50 dark:hover:bg-neutral-800",
|
|
1033
|
+
striped && rowIndex % 2 === 1 && "bg-neutral-50/50 dark:bg-neutral-800/50",
|
|
1034
|
+
isNew && "apteva-table-row-new"
|
|
1035
|
+
),
|
|
1036
|
+
onClick: () => {
|
|
1037
|
+
if (widget.actions && widget.actions.length > 0) {
|
|
1038
|
+
_optionalChain([onAction, 'optionalCall', _15 => _15({
|
|
1039
|
+
type: widget.actions[0].type,
|
|
1040
|
+
payload: row,
|
|
1041
|
+
widgetId: widget.id,
|
|
1042
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
1043
|
+
})]);
|
|
1044
|
+
}
|
|
899
1045
|
},
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
1046
|
+
style: { cursor: _optionalChain([widget, 'access', _16 => _16.actions, 'optionalAccess', _17 => _17.length]) ? "pointer" : "default" },
|
|
1047
|
+
children: columns.map((column) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1048
|
+
"td",
|
|
1049
|
+
{
|
|
1050
|
+
className: cn(
|
|
1051
|
+
"text-neutral-700 dark:text-neutral-300",
|
|
1052
|
+
compact ? "px-3 py-2 text-xs" : "px-4 py-3 text-sm",
|
|
1053
|
+
getAlignment(column.align)
|
|
1054
|
+
),
|
|
1055
|
+
children: _nullishCoalesce(row[column.key], () => ( "\u2014"))
|
|
1056
|
+
},
|
|
1057
|
+
column.key
|
|
1058
|
+
))
|
|
1059
|
+
},
|
|
1060
|
+
rowId
|
|
1061
|
+
);
|
|
1062
|
+
}),
|
|
1063
|
+
rows.length === 0 && !isStreaming && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "tr", { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
906
1064
|
"td",
|
|
907
1065
|
{
|
|
908
|
-
colSpan: columns.length,
|
|
1066
|
+
colSpan: columns.length || 1,
|
|
909
1067
|
className: "px-4 py-8 text-center text-sm text-neutral-500 dark:text-neutral-400",
|
|
910
1068
|
children: "No data available"
|
|
911
1069
|
}
|
|
1070
|
+
) }),
|
|
1071
|
+
isStreaming && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "tr", { className: "apteva-table-streaming", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1072
|
+
"td",
|
|
1073
|
+
{
|
|
1074
|
+
colSpan: columns.length || 1,
|
|
1075
|
+
className: "px-4 py-3 text-center",
|
|
1076
|
+
children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center justify-center gap-3 text-neutral-500 dark:text-neutral-400", children: [
|
|
1077
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex gap-1", children: [
|
|
1078
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "w-2 h-2 bg-current rounded-full animate-pulse", style: { animationDelay: "0ms" } }),
|
|
1079
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "w-2 h-2 bg-current rounded-full animate-pulse", style: { animationDelay: "150ms" } }),
|
|
1080
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "w-2 h-2 bg-current rounded-full animate-pulse", style: { animationDelay: "300ms" } })
|
|
1081
|
+
] }),
|
|
1082
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-sm", children: "Loading more..." })
|
|
1083
|
+
] })
|
|
1084
|
+
}
|
|
912
1085
|
) })
|
|
913
1086
|
] })
|
|
914
1087
|
] }) }) });
|