@arronqzy/react-view 1.0.26 → 1.0.28
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arronqzy/react-view",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.28",
|
|
4
4
|
"files": [
|
|
5
5
|
"src",
|
|
6
6
|
"dist",
|
|
@@ -31,13 +31,13 @@
|
|
|
31
31
|
"@codemirror/theme-one-dark": "^6.1.2",
|
|
32
32
|
"@codemirror/view": "^6.36.2",
|
|
33
33
|
"@arronqzy/ui": "1.0.9",
|
|
34
|
-
"@arronqzy/blueprint-dsl": "1.0.14",
|
|
35
34
|
"@arronqzy/react-blueprint": "1.0.16",
|
|
35
|
+
"@arronqzy/blueprint-dsl": "1.0.14",
|
|
36
36
|
"@arronqzy/i18n": "0.1.11",
|
|
37
37
|
"@arronqzy/rx-store": "1.0.8",
|
|
38
38
|
"@arronqzy/view-scene3d": "0.1.5",
|
|
39
|
-
"@arronqzy/
|
|
40
|
-
"@arronqzy/
|
|
39
|
+
"@arronqzy/webllm-assistant": "0.1.16",
|
|
40
|
+
"@arronqzy/view-table": "0.1.8"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/react": "^19.0.1",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"eslint": "^8.57.0",
|
|
47
47
|
"typescript": "^5.5.4",
|
|
48
48
|
"@arronqzy/eslint-config": "0.0.0",
|
|
49
|
-
"@arronqzy/
|
|
50
|
-
"@arronqzy/
|
|
49
|
+
"@arronqzy/tailwind": "1.0.2",
|
|
50
|
+
"@arronqzy/typescript-config": "1.0.0"
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
53
|
"lint": "eslint \"src/**/*.{ts,tsx}\"",
|
|
@@ -213,30 +213,30 @@ export function PanelConfigSidebar({
|
|
|
213
213
|
if (!hit) return null;
|
|
214
214
|
matchCountRef.current += 1;
|
|
215
215
|
return (
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
</div>
|
|
216
|
+
<Collapsible
|
|
217
|
+
open={hasSearch ? true : isSectionExpanded(key, defaultOpen)}
|
|
218
|
+
onOpenChange={(open) => setSectionExpanded(key, open)}
|
|
219
|
+
className="rounded-xl border border-border/70 bg-card/95 shadow-sm"
|
|
220
|
+
data-config-section={key}
|
|
221
|
+
>
|
|
222
|
+
<div className="flex items-center gap-1.5 px-3 py-2">
|
|
223
|
+
<CollapsibleTrigger asChild>
|
|
224
|
+
<button
|
|
225
|
+
type="button"
|
|
226
|
+
className="flex h-6 w-6 items-center justify-center rounded-md text-xs hover:bg-accent"
|
|
227
|
+
>
|
|
228
|
+
{isSectionExpanded(key, defaultOpen) ? "▾" : "▸"}
|
|
229
|
+
</button>
|
|
230
|
+
</CollapsibleTrigger>
|
|
231
|
+
<div className="flex min-w-0 flex-1 items-center gap-1">
|
|
232
|
+
<div className="text-[11px] font-semibold tracking-wide text-muted-foreground">{title}</div>
|
|
233
|
+
{hint ? <ConfigHintIcon label={title}>{hint}</ConfigHintIcon> : null}
|
|
235
234
|
</div>
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
</
|
|
235
|
+
</div>
|
|
236
|
+
<CollapsibleContent className="space-y-3 border-t border-border/60 bg-muted/[0.1] px-3 pb-3 pt-2.5">
|
|
237
|
+
{children}
|
|
238
|
+
</CollapsibleContent>
|
|
239
|
+
</Collapsible>
|
|
240
240
|
);
|
|
241
241
|
};
|
|
242
242
|
|
|
@@ -360,51 +360,51 @@ export function PanelConfigSidebar({
|
|
|
360
360
|
warnings={scopeWarnings}
|
|
361
361
|
scrollContainerRef={sidebarScrollRef}
|
|
362
362
|
>
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
363
|
+
<aside
|
|
364
|
+
ref={sidebarScrollRef}
|
|
365
|
+
className={`scope-config-sidebar h-full overflow-auto border-l border-border bg-muted/[0.14] px-3 py-3 text-foreground [&_.config-field--highlight]:rounded-md [&_.config-field--highlight]:ring-2 [&_.config-field--highlight]:ring-sky-400/80 [&_.scope-field--highlight]:rounded-md [&_.scope-field--highlight]:ring-2 [&_.scope-field--highlight]:ring-amber-400/80 [&_button[role=checkbox]]:border-2 [&_button[role=checkbox]]:border-foreground/80 [&_button[role=checkbox]]:bg-background [&_button[role=checkbox]]:ring-1 [&_button[role=checkbox]]:ring-foreground/40 [&_button[role=checkbox][data-state=checked]]:border-primary [&_button[role=checkbox][data-state=checked]]:ring-primary/40 ${themedScrollbarClass}`}
|
|
366
|
+
>
|
|
367
|
+
<div className="sticky top-0 z-20 mb-3 rounded-lg border border-border/70 bg-card/95 px-2.5 py-2 shadow-sm backdrop-blur supports-[backdrop-filter]:bg-card/80">
|
|
368
|
+
<div className="flex items-center justify-between gap-2">
|
|
369
|
+
<div className="text-xs font-semibold tracking-wide">{t("panel.config.panelTitle")}</div>
|
|
370
|
+
</div>
|
|
371
371
|
{showScopePanel ? <ViewElementScopePanel scope={viewElementScope} /> : null}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
</div>
|
|
389
|
-
{!isSearchCollapsed ? (
|
|
390
|
-
<div className="mt-2">
|
|
391
|
-
<Input
|
|
392
|
-
value={configSearch}
|
|
393
|
-
onChange={(e) => setConfigSearch(e.target.value)}
|
|
394
|
-
placeholder={t("panel.config.searchPlaceholder")}
|
|
395
|
-
className="h-7"
|
|
396
|
-
data-scope-autocomplete="off"
|
|
397
|
-
/>
|
|
398
|
-
{hasSearch ? (
|
|
399
|
-
<div className="mt-1 text-[11px] text-muted-foreground">
|
|
400
|
-
{t("panel.config.searching", { query: configSearch })}
|
|
401
|
-
</div>
|
|
402
|
-
) : null}
|
|
403
|
-
</div>
|
|
404
|
-
) : null}
|
|
372
|
+
<ScopeTemplateWarningsPanel />
|
|
373
|
+
<div
|
|
374
|
+
className={
|
|
375
|
+
showScopePanel || scopeWarnings.length > 0
|
|
376
|
+
? "mt-2 border-t border-border/50 pt-2"
|
|
377
|
+
: "mt-0"
|
|
378
|
+
}
|
|
379
|
+
>
|
|
380
|
+
<div className="flex items-center justify-end gap-2">
|
|
381
|
+
<button
|
|
382
|
+
type="button"
|
|
383
|
+
className="rounded border border-border px-1.5 py-0.5 text-[11px] text-muted-foreground hover:bg-accent"
|
|
384
|
+
onClick={() => setIsSearchCollapsed((prev) => !prev)}
|
|
385
|
+
>
|
|
386
|
+
{isSearchCollapsed ? t("panel.config.expandSearch") : t("panel.config.collapseSearch")}
|
|
387
|
+
</button>
|
|
405
388
|
</div>
|
|
389
|
+
{!isSearchCollapsed ? (
|
|
390
|
+
<div className="mt-2">
|
|
391
|
+
<Input
|
|
392
|
+
value={configSearch}
|
|
393
|
+
onChange={(e) => setConfigSearch(e.target.value)}
|
|
394
|
+
placeholder={t("panel.config.searchPlaceholder")}
|
|
395
|
+
className="h-7"
|
|
396
|
+
data-scope-autocomplete="off"
|
|
397
|
+
/>
|
|
398
|
+
{hasSearch ? (
|
|
399
|
+
<div className="mt-1 text-[11px] text-muted-foreground">
|
|
400
|
+
{t("panel.config.searching", { query: configSearch })}
|
|
401
|
+
</div>
|
|
402
|
+
) : null}
|
|
403
|
+
</div>
|
|
404
|
+
) : null}
|
|
406
405
|
</div>
|
|
407
|
-
|
|
406
|
+
</div>
|
|
407
|
+
{isMultiSelectMode ? (
|
|
408
408
|
<PanelConfigMultiSelect
|
|
409
409
|
elements={effectiveSelectedElements}
|
|
410
410
|
helpers={helpers}
|
|
@@ -414,34 +414,34 @@ export function PanelConfigSidebar({
|
|
|
414
414
|
onExcludeSelectedNode={onExcludeSelectedNode}
|
|
415
415
|
onAdjustNodeZOrder={onAdjustNodeZOrder}
|
|
416
416
|
/>
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
417
|
+
) : null}
|
|
418
|
+
{!isMultiSelectMode && !selectedElement ? (
|
|
419
|
+
<Empty className="py-7">
|
|
420
|
+
<EmptyIcon>
|
|
421
|
+
<svg
|
|
422
|
+
viewBox="0 0 24 24"
|
|
423
|
+
className="h-4 w-4"
|
|
424
|
+
fill="none"
|
|
425
|
+
stroke="currentColor"
|
|
426
|
+
strokeWidth="1.8"
|
|
427
|
+
aria-hidden="true"
|
|
428
|
+
>
|
|
429
|
+
<rect x="4" y="4" width="16" height="16" rx="2.5" />
|
|
430
|
+
<path d="M8 9h8M8 12h8M8 15h5" />
|
|
431
|
+
</svg>
|
|
432
|
+
</EmptyIcon>
|
|
433
|
+
<EmptyTitle>{t("panel.config.emptyNoNodeTitle")}</EmptyTitle>
|
|
434
|
+
<EmptyDescription>{t("panel.config.emptyNoNodeDesc")}</EmptyDescription>
|
|
435
|
+
</Empty>
|
|
436
|
+
) : !isMultiSelectMode && selectedElement ? (
|
|
437
|
+
<div className="space-y-3">
|
|
438
|
+
{!isNodeEditable ? (
|
|
439
|
+
<div className="rounded border border-amber-500/40 bg-amber-500/10 px-2 py-1.5 text-[11px] text-amber-700 dark:text-amber-300">
|
|
440
|
+
{readonlyReason}
|
|
441
|
+
</div>
|
|
442
|
+
) : null}
|
|
443
|
+
<fieldset disabled={!isNodeEditable} className={!isNodeEditable ? "opacity-60" : ""}>
|
|
444
|
+
<div className="space-y-3.5 text-xs">
|
|
445
445
|
<PanelConfigNodeInfo
|
|
446
446
|
element={selectedElement}
|
|
447
447
|
helpers={helpers}
|
|
@@ -449,26 +449,26 @@ export function PanelConfigSidebar({
|
|
|
449
449
|
nodeZOrderLabel={nodeZOrderLabel}
|
|
450
450
|
onAdjustNodeZOrder={onAdjustNodeZOrder}
|
|
451
451
|
/>
|
|
452
|
-
</div>
|
|
453
|
-
</fieldset>
|
|
454
|
-
<div className="rounded-lg border border-border/60 bg-card/80 px-2.5 py-2 text-xs">
|
|
455
|
-
<label className="flex items-center gap-2">
|
|
456
|
-
<Checkbox
|
|
457
|
-
checked={selectedElement.locked === true}
|
|
458
|
-
disabled={!canToggleNodeLock}
|
|
459
|
-
className="h-4 w-4 border-2 border-foreground/80 bg-background ring-1 ring-foreground/40 data-[state=checked]:border-primary data-[state=checked]:ring-primary/40"
|
|
460
|
-
onCheckedChange={(checked) =>
|
|
461
|
-
updateElement(selectedElement.id, {
|
|
462
|
-
locked: checked === true,
|
|
463
|
-
})
|
|
464
|
-
}
|
|
465
|
-
/>
|
|
466
|
-
<span>{t("panel.config.lockNode")}</span>
|
|
467
|
-
</label>
|
|
468
452
|
</div>
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
453
|
+
</fieldset>
|
|
454
|
+
<div className="rounded-lg border border-border/60 bg-card/80 px-2.5 py-2 text-xs">
|
|
455
|
+
<label className="flex items-center gap-2">
|
|
456
|
+
<Checkbox
|
|
457
|
+
checked={selectedElement.locked === true}
|
|
458
|
+
disabled={!canToggleNodeLock}
|
|
459
|
+
className="h-4 w-4 border-2 border-foreground/80 bg-background ring-1 ring-foreground/40 data-[state=checked]:border-primary data-[state=checked]:ring-primary/40"
|
|
460
|
+
onCheckedChange={(checked) =>
|
|
461
|
+
updateElement(selectedElement.id, {
|
|
462
|
+
locked: checked === true,
|
|
463
|
+
})
|
|
464
|
+
}
|
|
465
|
+
/>
|
|
466
|
+
<span>{t("panel.config.lockNode")}</span>
|
|
467
|
+
</label>
|
|
468
|
+
</div>
|
|
469
|
+
<fieldset disabled={!isNodeEditable} className={!isNodeEditable ? "opacity-60" : ""}>
|
|
470
|
+
<div className="space-y-3.5 text-xs">
|
|
471
|
+
{isChartElement ? (
|
|
472
472
|
<PanelConfigChartSection
|
|
473
473
|
element={selectedElement}
|
|
474
474
|
helpers={helpers}
|
|
@@ -476,23 +476,23 @@ export function PanelConfigSidebar({
|
|
|
476
476
|
/>
|
|
477
477
|
) : materialType === "table" ? (
|
|
478
478
|
helpers.renderSection(
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
479
|
+
"tableConfig",
|
|
480
|
+
t("panel.config.sectionTable"),
|
|
481
|
+
<PanelConfigTableSection
|
|
482
|
+
element={selectedElement}
|
|
483
|
+
disabled={!isNodeEditable}
|
|
484
|
+
updateElement={updateElement}
|
|
485
|
+
blueprintNodeOptions={blueprintNodeOptions}
|
|
486
|
+
/>,
|
|
487
|
+
true,
|
|
488
|
+
[
|
|
489
|
+
t("panel.material.table"),
|
|
490
|
+
"table",
|
|
491
|
+
t("panel.config.tableSource"),
|
|
492
|
+
t("panel.config.tableColumns"),
|
|
493
|
+
t("panel.config.tableRowsText"),
|
|
494
|
+
]
|
|
495
|
+
)
|
|
496
496
|
) : materialType === "text" ? (
|
|
497
497
|
<PanelConfigTextSection
|
|
498
498
|
element={selectedElement}
|
|
@@ -511,7 +511,7 @@ export function PanelConfigSidebar({
|
|
|
511
511
|
helpers={helpers}
|
|
512
512
|
updateElement={updateElement}
|
|
513
513
|
/>
|
|
514
|
-
|
|
514
|
+
) : null}
|
|
515
515
|
<PanelConfigGridChildSpan
|
|
516
516
|
element={selectedElement}
|
|
517
517
|
helpers={helpers}
|
|
@@ -525,22 +525,22 @@ export function PanelConfigSidebar({
|
|
|
525
525
|
/>
|
|
526
526
|
) : materialType === "scene3d" ? (
|
|
527
527
|
helpers.renderSection(
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
528
|
+
"scene3dConfig",
|
|
529
|
+
t("panel.config.sectionScene3d"),
|
|
530
|
+
<PanelConfigScene3dSection
|
|
531
|
+
element={selectedElement}
|
|
532
|
+
updateElement={updateElement}
|
|
533
|
+
/>,
|
|
534
|
+
true,
|
|
535
|
+
[
|
|
536
|
+
t("panel.material.scene3d"),
|
|
537
|
+
"3d",
|
|
538
|
+
"glb",
|
|
539
|
+
t("panel.config.scene3dUploadModels"),
|
|
540
|
+
t("panel.config.groupScene3dCamera"),
|
|
541
|
+
t("panel.config.groupScene3dModelAnim"),
|
|
542
|
+
]
|
|
543
|
+
)
|
|
544
544
|
) : materialType === "grid" ? (
|
|
545
545
|
<PanelConfigGridSection
|
|
546
546
|
element={selectedElement}
|
|
@@ -564,10 +564,10 @@ export function PanelConfigSidebar({
|
|
|
564
564
|
setReferenceCopyMode={setReferenceCopyMode}
|
|
565
565
|
/>
|
|
566
566
|
) : materialType === "image" ? null : (
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
567
|
+
<div className="text-xs leading-6 text-muted-foreground">
|
|
568
|
+
{t("panel.config.notChartType")}
|
|
569
|
+
</div>
|
|
570
|
+
)}
|
|
571
571
|
<PanelConfigStyleSections
|
|
572
572
|
element={selectedElement}
|
|
573
573
|
helpers={helpers}
|
|
@@ -578,11 +578,11 @@ export function PanelConfigSidebar({
|
|
|
578
578
|
matchCountRef={matchCountRef}
|
|
579
579
|
label={t("panel.config.noMatch")}
|
|
580
580
|
/>
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
581
|
+
</div>
|
|
582
|
+
</fieldset>
|
|
583
|
+
</div>
|
|
584
|
+
) : null}
|
|
585
|
+
</aside>
|
|
586
586
|
</ScopeConfigProvider>
|
|
587
587
|
);
|
|
588
588
|
}
|
|
@@ -2,6 +2,7 @@ import type { EChartsOption } from "echarts";
|
|
|
2
2
|
import type { PanelChartConfig, PanelElement } from "../types";
|
|
3
3
|
|
|
4
4
|
const DEFAULT_CHART_VALUES = [12, 18, 9, 24];
|
|
5
|
+
const DEFAULT_CHART_LABELS = ["A", "B", "C", "D"];
|
|
5
6
|
|
|
6
7
|
export function getChartValuesDisplayText(chart?: PanelChartConfig): string {
|
|
7
8
|
if (chart?.valuesText !== undefined) return chart.valuesText;
|
|
@@ -13,10 +14,26 @@ export function getChartLabelsDisplayText(chart?: PanelChartConfig): string {
|
|
|
13
14
|
return (chart?.labels ?? []).join(",");
|
|
14
15
|
}
|
|
15
16
|
|
|
17
|
+
export function parseChartLabelsFromText(
|
|
18
|
+
text: string | undefined,
|
|
19
|
+
fallback: string[] = DEFAULT_CHART_LABELS
|
|
20
|
+
): string[] {
|
|
21
|
+
if (text === undefined) return fallback;
|
|
22
|
+
const trimmed = text.trim();
|
|
23
|
+
if (!trimmed) return fallback;
|
|
24
|
+
const parts = trimmed.split(",").map((s) => s.trim()).filter(Boolean);
|
|
25
|
+
if (!parts.length) return fallback;
|
|
26
|
+
return parts;
|
|
27
|
+
}
|
|
28
|
+
|
|
16
29
|
export function resolveChartLabels(element: PanelElement): string[] {
|
|
17
30
|
const chart = element.chart;
|
|
31
|
+
if (chart?.labelsText !== undefined) {
|
|
32
|
+
const parsed = parseChartLabelsFromText(chart.labelsText, []);
|
|
33
|
+
return parsed.length ? parsed : DEFAULT_CHART_LABELS;
|
|
34
|
+
}
|
|
18
35
|
if (chart?.labels?.length) return chart.labels;
|
|
19
|
-
return
|
|
36
|
+
return DEFAULT_CHART_LABELS;
|
|
20
37
|
}
|
|
21
38
|
|
|
22
39
|
export function parseChartValuesFromText(
|