@treeui/mcp 0.2.0 → 0.4.0
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/{chunk-HN245XRN.js → chunk-K6NB25EB.js} +1159 -51
- package/dist/cli.cjs +1159 -51
- package/dist/cli.js +1 -1
- package/dist/index.cjs +1159 -51
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// src/generated/treeui.catalog.json
|
|
2
2
|
var treeui_catalog_default = {
|
|
3
|
-
generatedAt: "2026-
|
|
3
|
+
generatedAt: "2026-07-18T01:52:38.578Z",
|
|
4
4
|
packageName: "@treeui/vue",
|
|
5
|
-
packageVersion: "0.
|
|
5
|
+
packageVersion: "0.14.0",
|
|
6
6
|
decisionGuides: [
|
|
7
7
|
{
|
|
8
8
|
id: "single-choice",
|
|
@@ -200,6 +200,50 @@ var treeui_catalog_default = {
|
|
|
200
200
|
notes: []
|
|
201
201
|
}
|
|
202
202
|
]
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
id: "data-viz-choice",
|
|
206
|
+
question: "Visualize numeric data",
|
|
207
|
+
options: [
|
|
208
|
+
{
|
|
209
|
+
use: "TStat",
|
|
210
|
+
when: [
|
|
211
|
+
"The story is a single headline number, optionally with a trend and delta.",
|
|
212
|
+
"It is not a plot \u2014 prefer the number over a chart when one value says it."
|
|
213
|
+
],
|
|
214
|
+
notes: []
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
use: "TSparkline",
|
|
218
|
+
when: [
|
|
219
|
+
"You want an inline micro-trend next to a value, in a table cell, or in text.",
|
|
220
|
+
"No axes, legend, or tooltip are needed."
|
|
221
|
+
],
|
|
222
|
+
notes: []
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
use: "TChart",
|
|
226
|
+
when: [
|
|
227
|
+
"You need line, area, or bar plots with axes, gridlines, legend, and hover tooltip.",
|
|
228
|
+
"There are one or more series over shared categories."
|
|
229
|
+
],
|
|
230
|
+
notes: []
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
use: "TDonutChart",
|
|
234
|
+
when: [
|
|
235
|
+
"The data is a part-of-whole breakdown (donut or pie)."
|
|
236
|
+
],
|
|
237
|
+
notes: []
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
use: "TProgress",
|
|
241
|
+
when: [
|
|
242
|
+
"You are showing completion toward a single target, not a distribution or trend."
|
|
243
|
+
],
|
|
244
|
+
notes: []
|
|
245
|
+
}
|
|
246
|
+
]
|
|
203
247
|
}
|
|
204
248
|
],
|
|
205
249
|
recipes: [
|
|
@@ -249,11 +293,28 @@ var treeui_catalog_default = {
|
|
|
249
293
|
"Set end `min` from the selected start time when appropriate."
|
|
250
294
|
]
|
|
251
295
|
},
|
|
296
|
+
{
|
|
297
|
+
id: "app-shell",
|
|
298
|
+
name: "Full-viewport application shell",
|
|
299
|
+
useWhen: [
|
|
300
|
+
"The app needs a header plus side navigation that fills the whole screen and adapts to mobile.",
|
|
301
|
+
"The layout must use the full page width on large monitors, not a centered column."
|
|
302
|
+
],
|
|
303
|
+
compose: [
|
|
304
|
+
"TAppShell",
|
|
305
|
+
"TNavMenu"
|
|
306
|
+
],
|
|
307
|
+
notes: [
|
|
308
|
+
"`TAppShell` orchestrates the header, sidebar, and fluid content in one component; put a `TNavMenu` in its `sidebar` slot and it inherits collapsed state automatically.",
|
|
309
|
+
"Leave `mobile` unset to auto-switch at `breakpoint` (default 768px), or bind it to force mobile; the sidebar becomes an off-canvas drawer with a header menu button.",
|
|
310
|
+
"Mount it at the app root. Wrap only inner regions in `TContainer` if a specific area needs a constrained reading width."
|
|
311
|
+
]
|
|
312
|
+
},
|
|
252
313
|
{
|
|
253
314
|
id: "sidebar-shell",
|
|
254
315
|
name: "Sidebar application shell",
|
|
255
316
|
useWhen: [
|
|
256
|
-
"The screen needs persistent section navigation."
|
|
317
|
+
"The screen needs persistent section navigation and you are composing the shell by hand."
|
|
257
318
|
],
|
|
258
319
|
compose: [
|
|
259
320
|
"TSidebar",
|
|
@@ -262,7 +323,8 @@ var treeui_catalog_default = {
|
|
|
262
323
|
"TContainer"
|
|
263
324
|
],
|
|
264
325
|
notes: [
|
|
265
|
-
"Let `TNavMenu` inherit collapsed state from `TSidebar` when possible."
|
|
326
|
+
"Let `TNavMenu` inherit collapsed state from `TSidebar` when possible.",
|
|
327
|
+
"Prefer `TAppShell` (recipe `app-shell`) when you also need full-viewport sizing and a responsive mobile drawer."
|
|
266
328
|
]
|
|
267
329
|
},
|
|
268
330
|
{
|
|
@@ -360,15 +422,38 @@ var treeui_catalog_default = {
|
|
|
360
422
|
id: "chart-surface",
|
|
361
423
|
name: "Chart surface",
|
|
362
424
|
useWhen: [
|
|
363
|
-
"A screen needs data visualization
|
|
425
|
+
"A screen needs data visualization inside a framed, titled surface."
|
|
364
426
|
],
|
|
365
427
|
compose: [
|
|
366
428
|
"TCard",
|
|
367
429
|
"TStack",
|
|
368
|
-
"
|
|
430
|
+
"TChart",
|
|
431
|
+
"TSelect"
|
|
369
432
|
],
|
|
370
433
|
notes: [
|
|
371
|
-
"
|
|
434
|
+
"Prefer the native TChart / TDonutChart / TSparkline \u2014 no external charting library is required.",
|
|
435
|
+
"Use TreeUI for the surrounding surface, headings, badges, range filters, and empty/loading states.",
|
|
436
|
+
"TChart has its own loading and empty slots; you can still wrap it in TCard for the frame.",
|
|
437
|
+
"Only reach for an external chart engine for chart types TreeUI does not cover yet (e.g. scatter, heatmap)."
|
|
438
|
+
]
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
id: "metric-dashboard",
|
|
442
|
+
name: "Metric dashboard",
|
|
443
|
+
useWhen: [
|
|
444
|
+
"A dashboard shows KPIs alongside trends and breakdowns."
|
|
445
|
+
],
|
|
446
|
+
compose: [
|
|
447
|
+
"TStat",
|
|
448
|
+
"TSparkline",
|
|
449
|
+
"TChart",
|
|
450
|
+
"TDonutChart",
|
|
451
|
+
"TGrid"
|
|
452
|
+
],
|
|
453
|
+
notes: [
|
|
454
|
+
"Lead with TStat tiles; embed a TSparkline in a stat's meta slot for the inline trend.",
|
|
455
|
+
"Use one TChart for the main time series and a TDonutChart for a part-of-whole split.",
|
|
456
|
+
"Keep series colors stable across the dashboard \u2014 rely on the --tree-color-chart-* order, do not remap by rank."
|
|
372
457
|
]
|
|
373
458
|
},
|
|
374
459
|
{
|
|
@@ -518,17 +603,27 @@ var treeui_catalog_default = {
|
|
|
518
603
|
"Use `accept`, `multiple`, and size limits in the app layer to constrain uploads."
|
|
519
604
|
]
|
|
520
605
|
},
|
|
606
|
+
TAppShell: {
|
|
607
|
+
required: [],
|
|
608
|
+
notes: [
|
|
609
|
+
"Mount at the app root; it fills the viewport (100dvh, full width) and scrolls its content region independently.",
|
|
610
|
+
"Put navigation in the `sidebar` slot (e.g. `TNavMenu`) \u2014 it inherits collapsed state from the shell provider like `TSidebar`.",
|
|
611
|
+
"Leave `mobile` unset to auto-switch to an off-canvas drawer at `breakpoint`, or bind `mobile` to control it explicitly.",
|
|
612
|
+
"Use `v-model:collapsed` for the desktop rail and `v-model:sidebarOpen` for the mobile drawer when the app persists layout state."
|
|
613
|
+
]
|
|
614
|
+
},
|
|
521
615
|
TSidebar: {
|
|
522
616
|
required: [],
|
|
523
617
|
notes: [
|
|
524
618
|
"Pair with `TNavMenu` for app-section navigation.",
|
|
525
|
-
"Use controlled `collapsed` state when the app shell persists layout preferences."
|
|
619
|
+
"Use controlled `collapsed` state when the app shell persists layout preferences.",
|
|
620
|
+
"Prefer `TAppShell` when you also want full-viewport sizing, a top header, and a responsive mobile drawer."
|
|
526
621
|
]
|
|
527
622
|
},
|
|
528
623
|
TNavMenu: {
|
|
529
624
|
required: [],
|
|
530
625
|
notes: [
|
|
531
|
-
"When nested inside `TSidebar`, `collapsed` can be inherited from the sidebar provider."
|
|
626
|
+
"When nested inside `TSidebar` or `TAppShell`, `collapsed` can be inherited from the sidebar provider."
|
|
532
627
|
]
|
|
533
628
|
},
|
|
534
629
|
TTreeView: {
|
|
@@ -562,6 +657,32 @@ var treeui_catalog_default = {
|
|
|
562
657
|
"Use `href` for native links.",
|
|
563
658
|
"Use `to` when the app has vue-router and breadcrumb items should render RouterLink."
|
|
564
659
|
]
|
|
660
|
+
},
|
|
661
|
+
TChart: {
|
|
662
|
+
required: [],
|
|
663
|
+
notes: [
|
|
664
|
+
"Pass `series` as `{ name, data, color? }[]` and `labels` as a parallel `string[]` (one label per data index).",
|
|
665
|
+
"Set `type` to `line`, `area`, or `bar`; use `stacked` only with `bar`.",
|
|
666
|
+
"Series colors come from `--tree-color-chart-1..8` in order; pass `color` per series to override \u2014 do not remap colors when the series set changes.",
|
|
667
|
+
"Pass `valueFormat: (n) => string` to format axis and tooltip values (currency, compact, etc.).",
|
|
668
|
+
"No charting library or provider is required \u2014 the SVG and geometry are built in."
|
|
669
|
+
]
|
|
670
|
+
},
|
|
671
|
+
TSparkline: {
|
|
672
|
+
required: [],
|
|
673
|
+
notes: [
|
|
674
|
+
"Pass `data` as `number[]`; there are no axes, legend, or tooltip by design.",
|
|
675
|
+
"Size it with `width`/`height`; use it inside `TStat`, table cells, or text.",
|
|
676
|
+
"Always keep a visible number nearby \u2014 a sparkline supplements a value, it does not replace it."
|
|
677
|
+
]
|
|
678
|
+
},
|
|
679
|
+
TDonutChart: {
|
|
680
|
+
required: [],
|
|
681
|
+
notes: [
|
|
682
|
+
"Pass `segments` as `{ label, value, color? }[]`; non-positive values are dropped.",
|
|
683
|
+
"Set `thickness: 0` for a full pie; keep the default for a donut with a center readout.",
|
|
684
|
+
"Use the `center` slot (donut only) for a custom center; otherwise it shows the total or the hovered slice."
|
|
685
|
+
]
|
|
565
686
|
}
|
|
566
687
|
},
|
|
567
688
|
appPatterns: {
|
|
@@ -575,6 +696,9 @@ var treeui_catalog_default = {
|
|
|
575
696
|
commonCompositions: [
|
|
576
697
|
"TFormField + input-like control",
|
|
577
698
|
"TGrid + TStat",
|
|
699
|
+
"TStat + TSparkline",
|
|
700
|
+
"TCard + TChart",
|
|
701
|
+
"TAppShell + TNavMenu",
|
|
578
702
|
"TSidebar + TNavMenu",
|
|
579
703
|
"TTable + TPagination",
|
|
580
704
|
"TPricing + TPricingCard"
|
|
@@ -735,6 +859,211 @@ var treeui_catalog_default = {
|
|
|
735
859
|
},
|
|
736
860
|
recipes: []
|
|
737
861
|
},
|
|
862
|
+
{
|
|
863
|
+
name: "TAppShell",
|
|
864
|
+
aliases: [],
|
|
865
|
+
package: "@treeui/vue",
|
|
866
|
+
kind: "layout",
|
|
867
|
+
category: "Layout",
|
|
868
|
+
status: "available",
|
|
869
|
+
purpose: "Full-viewport application shell with a top header, a persistent side navigation, and a fluid content area that collapses the sidebar into an off-canvas drawer on small screens.",
|
|
870
|
+
sourceFile: "packages/vue/src/components/TAppShell.vue",
|
|
871
|
+
storyFile: "apps/docs/src/stories/AppShell.stories.ts",
|
|
872
|
+
storyTitle: "Components/Layout/AppShell",
|
|
873
|
+
manifestFile: "docs/ai/COMPONENTS/app-shell.yaml",
|
|
874
|
+
props: [
|
|
875
|
+
{
|
|
876
|
+
name: "as",
|
|
877
|
+
type: "string",
|
|
878
|
+
default: "div"
|
|
879
|
+
},
|
|
880
|
+
{
|
|
881
|
+
name: "side",
|
|
882
|
+
type: "TSidebarSide",
|
|
883
|
+
default: "left",
|
|
884
|
+
values: [
|
|
885
|
+
"left",
|
|
886
|
+
"right"
|
|
887
|
+
]
|
|
888
|
+
},
|
|
889
|
+
{
|
|
890
|
+
name: "sidebarWidth",
|
|
891
|
+
type: "string",
|
|
892
|
+
default: "17.5rem"
|
|
893
|
+
},
|
|
894
|
+
{
|
|
895
|
+
name: "collapsedWidth",
|
|
896
|
+
type: "string",
|
|
897
|
+
default: "4.75rem"
|
|
898
|
+
},
|
|
899
|
+
{
|
|
900
|
+
name: "collapsible",
|
|
901
|
+
type: "boolean",
|
|
902
|
+
default: "false"
|
|
903
|
+
},
|
|
904
|
+
{
|
|
905
|
+
name: "collapsed",
|
|
906
|
+
type: "boolean",
|
|
907
|
+
default: "undefined"
|
|
908
|
+
},
|
|
909
|
+
{
|
|
910
|
+
name: "defaultCollapsed",
|
|
911
|
+
type: "boolean",
|
|
912
|
+
default: "false"
|
|
913
|
+
},
|
|
914
|
+
{
|
|
915
|
+
name: "mobile",
|
|
916
|
+
type: "boolean",
|
|
917
|
+
default: "undefined"
|
|
918
|
+
},
|
|
919
|
+
{
|
|
920
|
+
name: "breakpoint",
|
|
921
|
+
type: "string",
|
|
922
|
+
default: "768px"
|
|
923
|
+
},
|
|
924
|
+
{
|
|
925
|
+
name: "sidebarOpen",
|
|
926
|
+
type: "boolean",
|
|
927
|
+
default: "undefined"
|
|
928
|
+
},
|
|
929
|
+
{
|
|
930
|
+
name: "defaultSidebarOpen",
|
|
931
|
+
type: "boolean",
|
|
932
|
+
default: "false"
|
|
933
|
+
},
|
|
934
|
+
{
|
|
935
|
+
name: "closeOnEscape",
|
|
936
|
+
type: "boolean",
|
|
937
|
+
default: "true"
|
|
938
|
+
},
|
|
939
|
+
{
|
|
940
|
+
name: "closeOnOverlay",
|
|
941
|
+
type: "boolean",
|
|
942
|
+
default: "true"
|
|
943
|
+
},
|
|
944
|
+
{
|
|
945
|
+
name: "showMenuButton",
|
|
946
|
+
type: "boolean",
|
|
947
|
+
default: "true"
|
|
948
|
+
},
|
|
949
|
+
{
|
|
950
|
+
name: "menuLabel",
|
|
951
|
+
type: "string",
|
|
952
|
+
default: "Open menu"
|
|
953
|
+
},
|
|
954
|
+
{
|
|
955
|
+
name: "closeLabel",
|
|
956
|
+
type: "string",
|
|
957
|
+
default: "Close menu"
|
|
958
|
+
},
|
|
959
|
+
{
|
|
960
|
+
name: "sidebarLabel",
|
|
961
|
+
type: "string",
|
|
962
|
+
default: "Sidebar"
|
|
963
|
+
}
|
|
964
|
+
],
|
|
965
|
+
events: [
|
|
966
|
+
{
|
|
967
|
+
name: "update:collapsed"
|
|
968
|
+
},
|
|
969
|
+
{
|
|
970
|
+
name: "collapse-change"
|
|
971
|
+
},
|
|
972
|
+
{
|
|
973
|
+
name: "update:sidebarOpen"
|
|
974
|
+
},
|
|
975
|
+
{
|
|
976
|
+
name: "sidebar-open-change"
|
|
977
|
+
}
|
|
978
|
+
],
|
|
979
|
+
slots: [
|
|
980
|
+
{
|
|
981
|
+
name: "header"
|
|
982
|
+
},
|
|
983
|
+
{
|
|
984
|
+
name: "sidebar"
|
|
985
|
+
},
|
|
986
|
+
{
|
|
987
|
+
name: "default"
|
|
988
|
+
},
|
|
989
|
+
{
|
|
990
|
+
name: "menu-icon"
|
|
991
|
+
}
|
|
992
|
+
],
|
|
993
|
+
a11y: [
|
|
994
|
+
"role: dialog",
|
|
995
|
+
"aria_modal: true",
|
|
996
|
+
"focus_trap: true",
|
|
997
|
+
"restores_focus_on_close: true",
|
|
998
|
+
"escape_closes_when_enabled: true",
|
|
999
|
+
"menu_button_aria_expanded: true",
|
|
1000
|
+
"menu_button_aria_controls_drawer: true",
|
|
1001
|
+
"sidebar_labelled_by_sidebar_label: true"
|
|
1002
|
+
],
|
|
1003
|
+
behavior: [
|
|
1004
|
+
"fills_viewport_full_width_and_height: true",
|
|
1005
|
+
"header_spans_full_width_above_sidebar_and_content: true",
|
|
1006
|
+
"content_area_scrolls_independently: true",
|
|
1007
|
+
"auto_switches_to_mobile_at_breakpoint_when_mobile_undefined: true",
|
|
1008
|
+
"mobile_prop_forces_mobile_mode: true",
|
|
1009
|
+
"mobile_sidebar_becomes_off_canvas_drawer: true",
|
|
1010
|
+
"auto_menu_button_in_header_on_mobile: true",
|
|
1011
|
+
"controlled_and_uncontrolled_collapsed_state: true",
|
|
1012
|
+
"controlled_and_uncontrolled_sidebar_open_state: true",
|
|
1013
|
+
"provides_collapsed_state_to_descendants: true",
|
|
1014
|
+
"drawer_reports_collapsed_false_to_descendants_and_slots: true",
|
|
1015
|
+
"left_and_right_variants: true",
|
|
1016
|
+
"locks_body_scroll_while_drawer_open: true",
|
|
1017
|
+
"overlay_click_closes_when_enabled: true",
|
|
1018
|
+
"exposes_slot_props_with_mobile_collapsed_and_toggles: true"
|
|
1019
|
+
],
|
|
1020
|
+
selection: {
|
|
1021
|
+
keywords: [
|
|
1022
|
+
"app shell",
|
|
1023
|
+
"layout",
|
|
1024
|
+
"dashboard",
|
|
1025
|
+
"admin",
|
|
1026
|
+
"header sidebar",
|
|
1027
|
+
"full screen",
|
|
1028
|
+
"responsive shell",
|
|
1029
|
+
"off-canvas"
|
|
1030
|
+
],
|
|
1031
|
+
useWhen: [
|
|
1032
|
+
"You need a full-viewport application layout with a header, a side navigation, and a fluid content area.",
|
|
1033
|
+
"The layout should use the entire page width (not a centered max-width) and switch the sidebar to an off-canvas drawer on small screens."
|
|
1034
|
+
],
|
|
1035
|
+
avoidWhen: [
|
|
1036
|
+
"You only need one region (just a top bar, or just a side rail) \u2014 compose TNavbar or TSidebar directly.",
|
|
1037
|
+
"The page content should be centered with a readable max width \u2014 use TContainer inside the shell content instead."
|
|
1038
|
+
],
|
|
1039
|
+
alternatives: [
|
|
1040
|
+
{
|
|
1041
|
+
component: "TSidebar",
|
|
1042
|
+
when: "You want a standalone collapsible side rail without the header/content orchestration or responsive drawer."
|
|
1043
|
+
},
|
|
1044
|
+
{
|
|
1045
|
+
component: "TNavbar",
|
|
1046
|
+
when: "You only need the top application bar."
|
|
1047
|
+
},
|
|
1048
|
+
{
|
|
1049
|
+
component: "TDrawer",
|
|
1050
|
+
when: "You need a general temporary overlay panel rather than the shell's responsive navigation."
|
|
1051
|
+
}
|
|
1052
|
+
]
|
|
1053
|
+
},
|
|
1054
|
+
setup: {
|
|
1055
|
+
required: [],
|
|
1056
|
+
notes: [
|
|
1057
|
+
"Mount at the app root; it fills the viewport (100dvh, full width) and scrolls its content region independently.",
|
|
1058
|
+
"Put navigation in the `sidebar` slot (e.g. `TNavMenu`) \u2014 it inherits collapsed state from the shell provider like `TSidebar`.",
|
|
1059
|
+
"Leave `mobile` unset to auto-switch to an off-canvas drawer at `breakpoint`, or bind `mobile` to control it explicitly.",
|
|
1060
|
+
"Use `v-model:collapsed` for the desktop rail and `v-model:sidebarOpen` for the mobile drawer when the app persists layout state."
|
|
1061
|
+
]
|
|
1062
|
+
},
|
|
1063
|
+
recipes: [
|
|
1064
|
+
"app-shell"
|
|
1065
|
+
]
|
|
1066
|
+
},
|
|
738
1067
|
{
|
|
739
1068
|
name: "TAvatar",
|
|
740
1069
|
aliases: [],
|
|
@@ -958,15 +1287,17 @@ var treeui_catalog_default = {
|
|
|
958
1287
|
},
|
|
959
1288
|
{
|
|
960
1289
|
name: "variant",
|
|
961
|
-
type: "TVariant",
|
|
1290
|
+
type: "TVariant | brand",
|
|
962
1291
|
default: "solid",
|
|
963
1292
|
values: [
|
|
964
1293
|
"solid",
|
|
965
1294
|
"outline",
|
|
966
1295
|
"ghost",
|
|
967
1296
|
"soft",
|
|
968
|
-
"danger"
|
|
969
|
-
|
|
1297
|
+
"danger",
|
|
1298
|
+
"brand"
|
|
1299
|
+
],
|
|
1300
|
+
note: "`brand` is a button-only, high-emphasis gradient variant driven by the `--tree-gradient-brand` token. Use it for the single primary CTA of a screen."
|
|
970
1301
|
},
|
|
971
1302
|
{
|
|
972
1303
|
name: "size",
|
|
@@ -1096,7 +1427,8 @@ var treeui_catalog_default = {
|
|
|
1096
1427
|
],
|
|
1097
1428
|
a11y: [],
|
|
1098
1429
|
behavior: [
|
|
1099
|
-
"body_wrapper_class:
|
|
1430
|
+
"body_wrapper_class: t-card__body",
|
|
1431
|
+
"solid_variant_rescopes_color_tokens_for_nested_content: true"
|
|
1100
1432
|
],
|
|
1101
1433
|
selection: {
|
|
1102
1434
|
keywords: [
|
|
@@ -1131,6 +1463,202 @@ var treeui_catalog_default = {
|
|
|
1131
1463
|
"chart-surface"
|
|
1132
1464
|
]
|
|
1133
1465
|
},
|
|
1466
|
+
{
|
|
1467
|
+
name: "TChart",
|
|
1468
|
+
aliases: [],
|
|
1469
|
+
package: "@treeui/vue",
|
|
1470
|
+
kind: "data-display",
|
|
1471
|
+
category: "Data Display",
|
|
1472
|
+
status: "available",
|
|
1473
|
+
purpose: "Lightweight cartesian chart (line, area, bar) for multi-series data, with axes, gridlines, hover tooltip, legend, and an accessible data table. No external charting dependency.",
|
|
1474
|
+
sourceFile: "packages/vue/src/components/TChart.vue",
|
|
1475
|
+
storyFile: "apps/docs/src/stories/Chart.stories.ts",
|
|
1476
|
+
storyTitle: "Components/Data Display/Chart",
|
|
1477
|
+
manifestFile: "docs/ai/COMPONENTS/chart.yaml",
|
|
1478
|
+
props: [
|
|
1479
|
+
{
|
|
1480
|
+
name: "type",
|
|
1481
|
+
type: "TChartType",
|
|
1482
|
+
default: "line",
|
|
1483
|
+
values: [
|
|
1484
|
+
"line",
|
|
1485
|
+
"area",
|
|
1486
|
+
"bar"
|
|
1487
|
+
]
|
|
1488
|
+
},
|
|
1489
|
+
{
|
|
1490
|
+
name: "series",
|
|
1491
|
+
type: "TChartSeries[]",
|
|
1492
|
+
default: "[]",
|
|
1493
|
+
note: "Each item is { name: string; data: number[]; color?: string }."
|
|
1494
|
+
},
|
|
1495
|
+
{
|
|
1496
|
+
name: "labels",
|
|
1497
|
+
type: "string[]",
|
|
1498
|
+
default: "[]",
|
|
1499
|
+
note: "X-axis categories, aligned index-for-index to each series' data."
|
|
1500
|
+
},
|
|
1501
|
+
{
|
|
1502
|
+
name: "height",
|
|
1503
|
+
type: "number",
|
|
1504
|
+
default: "260",
|
|
1505
|
+
note: "Width is fluid (measured via ResizeObserver)."
|
|
1506
|
+
},
|
|
1507
|
+
{
|
|
1508
|
+
name: "smooth",
|
|
1509
|
+
type: "boolean",
|
|
1510
|
+
default: "false",
|
|
1511
|
+
note: "Curved line/area."
|
|
1512
|
+
},
|
|
1513
|
+
{
|
|
1514
|
+
name: "stacked",
|
|
1515
|
+
type: "boolean",
|
|
1516
|
+
default: "false",
|
|
1517
|
+
note: "Stacks bar series; ignored for line/area. Negative values are clamped to 0 in stacked mode (grouped mode renders them)."
|
|
1518
|
+
},
|
|
1519
|
+
{
|
|
1520
|
+
name: "showGrid",
|
|
1521
|
+
type: "boolean",
|
|
1522
|
+
default: "true"
|
|
1523
|
+
},
|
|
1524
|
+
{
|
|
1525
|
+
name: "showLegend",
|
|
1526
|
+
type: "boolean",
|
|
1527
|
+
default: "auto (true when more than one series)"
|
|
1528
|
+
},
|
|
1529
|
+
{
|
|
1530
|
+
name: "showXAxis",
|
|
1531
|
+
type: "boolean",
|
|
1532
|
+
default: "true"
|
|
1533
|
+
},
|
|
1534
|
+
{
|
|
1535
|
+
name: "showYAxis",
|
|
1536
|
+
type: "boolean",
|
|
1537
|
+
default: "true"
|
|
1538
|
+
},
|
|
1539
|
+
{
|
|
1540
|
+
name: "showTooltip",
|
|
1541
|
+
type: "boolean",
|
|
1542
|
+
default: "true"
|
|
1543
|
+
},
|
|
1544
|
+
{
|
|
1545
|
+
name: "showPoints",
|
|
1546
|
+
type: "boolean",
|
|
1547
|
+
default: "false",
|
|
1548
|
+
note: "Always draw markers on line/area points."
|
|
1549
|
+
},
|
|
1550
|
+
{
|
|
1551
|
+
name: "yTicks",
|
|
1552
|
+
type: "number",
|
|
1553
|
+
default: "5"
|
|
1554
|
+
},
|
|
1555
|
+
{
|
|
1556
|
+
name: "valueFormat",
|
|
1557
|
+
type: "(value: number) => string",
|
|
1558
|
+
default: "locale integers for |value| >= 1000"
|
|
1559
|
+
},
|
|
1560
|
+
{
|
|
1561
|
+
name: "minY",
|
|
1562
|
+
type: "number",
|
|
1563
|
+
default: "auto"
|
|
1564
|
+
},
|
|
1565
|
+
{
|
|
1566
|
+
name: "maxY",
|
|
1567
|
+
type: "number",
|
|
1568
|
+
default: "auto"
|
|
1569
|
+
},
|
|
1570
|
+
{
|
|
1571
|
+
name: "animated",
|
|
1572
|
+
type: "boolean",
|
|
1573
|
+
default: "true",
|
|
1574
|
+
note: "Draw-in animation; disabled under prefers-reduced-motion."
|
|
1575
|
+
},
|
|
1576
|
+
{
|
|
1577
|
+
name: "loading",
|
|
1578
|
+
type: "boolean",
|
|
1579
|
+
default: "false"
|
|
1580
|
+
},
|
|
1581
|
+
{
|
|
1582
|
+
name: "ariaLabel",
|
|
1583
|
+
type: "string",
|
|
1584
|
+
default: "auto-generated summary"
|
|
1585
|
+
}
|
|
1586
|
+
],
|
|
1587
|
+
events: [
|
|
1588
|
+
{
|
|
1589
|
+
name: "point-click",
|
|
1590
|
+
payload: "{ index: number; label: string; values: { name: string; value: number; color: string }[] }"
|
|
1591
|
+
}
|
|
1592
|
+
],
|
|
1593
|
+
slots: [
|
|
1594
|
+
{
|
|
1595
|
+
name: "legend"
|
|
1596
|
+
},
|
|
1597
|
+
{
|
|
1598
|
+
name: "tooltip"
|
|
1599
|
+
},
|
|
1600
|
+
{
|
|
1601
|
+
name: "empty"
|
|
1602
|
+
}
|
|
1603
|
+
],
|
|
1604
|
+
a11y: [
|
|
1605
|
+
"SVG is aria-hidden; a visually-hidden <table> mirrors the series data for assistive tech.",
|
|
1606
|
+
"Legend defaults on for multiple series so identity is not color-only.",
|
|
1607
|
+
"Provide a meaningful ariaLabel describing what the chart shows."
|
|
1608
|
+
],
|
|
1609
|
+
behavior: [
|
|
1610
|
+
"colors_auto_assign_from_chart_palette: --tree-color-chart-1..8, cycling; per-series color overrides",
|
|
1611
|
+
"bar_zero_baseline: true",
|
|
1612
|
+
"line_domain_uses_nice_ticks: true",
|
|
1613
|
+
"hover_shows_crosshair_and_tooltip: true"
|
|
1614
|
+
],
|
|
1615
|
+
selection: {
|
|
1616
|
+
keywords: [
|
|
1617
|
+
"chart",
|
|
1618
|
+
"graph",
|
|
1619
|
+
"line chart",
|
|
1620
|
+
"area chart",
|
|
1621
|
+
"bar chart",
|
|
1622
|
+
"plot",
|
|
1623
|
+
"dashboard",
|
|
1624
|
+
"time series",
|
|
1625
|
+
"analytics"
|
|
1626
|
+
],
|
|
1627
|
+
useWhen: [
|
|
1628
|
+
"You need a line, area, or bar chart with axes, gridlines, legend, and a hover tooltip.",
|
|
1629
|
+
"One or more series share a set of category labels."
|
|
1630
|
+
],
|
|
1631
|
+
avoidWhen: [
|
|
1632
|
+
"A single value tells the story \u2014 use TStat.",
|
|
1633
|
+
"You only need an inline trend with no axes \u2014 use TSparkline.",
|
|
1634
|
+
"The data is a part-of-whole breakdown \u2014 use TDonutChart."
|
|
1635
|
+
],
|
|
1636
|
+
alternatives: [
|
|
1637
|
+
{
|
|
1638
|
+
component: "TSparkline",
|
|
1639
|
+
when: "The trend should be inline and axis-less."
|
|
1640
|
+
},
|
|
1641
|
+
{
|
|
1642
|
+
component: "TDonutChart",
|
|
1643
|
+
when: "The data is proportional (parts of a whole)."
|
|
1644
|
+
}
|
|
1645
|
+
]
|
|
1646
|
+
},
|
|
1647
|
+
setup: {
|
|
1648
|
+
required: [],
|
|
1649
|
+
notes: [
|
|
1650
|
+
"Pass `series` as `{ name, data, color? }[]` and `labels` as a parallel `string[]` (one label per data index).",
|
|
1651
|
+
"Set `type` to `line`, `area`, or `bar`; use `stacked` only with `bar`.",
|
|
1652
|
+
"Series colors come from `--tree-color-chart-1..8` in order; pass `color` per series to override \u2014 do not remap colors when the series set changes.",
|
|
1653
|
+
"Pass `valueFormat: (n) => string` to format axis and tooltip values (currency, compact, etc.).",
|
|
1654
|
+
"No charting library or provider is required \u2014 the SVG and geometry are built in."
|
|
1655
|
+
]
|
|
1656
|
+
},
|
|
1657
|
+
recipes: [
|
|
1658
|
+
"chart-surface",
|
|
1659
|
+
"metric-dashboard"
|
|
1660
|
+
]
|
|
1661
|
+
},
|
|
1134
1662
|
{
|
|
1135
1663
|
name: "TCheckbox",
|
|
1136
1664
|
aliases: [],
|
|
@@ -1614,9 +2142,14 @@ var treeui_catalog_default = {
|
|
|
1614
2142
|
"The page shell should stay full-width while content stays readable."
|
|
1615
2143
|
],
|
|
1616
2144
|
avoidWhen: [
|
|
1617
|
-
"You need internal spacing between children."
|
|
2145
|
+
"You need internal spacing between children.",
|
|
2146
|
+
"You are laying out a whole screen \u2014 reach for TPage, which adds page padding and vertical rhythm."
|
|
1618
2147
|
],
|
|
1619
2148
|
alternatives: [
|
|
2149
|
+
{
|
|
2150
|
+
component: "TPage",
|
|
2151
|
+
when: "You want a full page region with block padding and vertical spacing between sections, not just a width constraint."
|
|
2152
|
+
},
|
|
1620
2153
|
{
|
|
1621
2154
|
component: "TStack",
|
|
1622
2155
|
when: "The main need is vertical or horizontal spacing."
|
|
@@ -2102,6 +2635,142 @@ var treeui_catalog_default = {
|
|
|
2102
2635
|
},
|
|
2103
2636
|
recipes: []
|
|
2104
2637
|
},
|
|
2638
|
+
{
|
|
2639
|
+
name: "TDonutChart",
|
|
2640
|
+
aliases: [],
|
|
2641
|
+
package: "@treeui/vue",
|
|
2642
|
+
kind: "data-display",
|
|
2643
|
+
category: "Data Display",
|
|
2644
|
+
status: "available",
|
|
2645
|
+
purpose: "Part-of-whole chart rendered as a donut (default) or full pie, with a legend, percentages, an interactive center readout, and an accessible label.",
|
|
2646
|
+
sourceFile: "packages/vue/src/components/TDonutChart.vue",
|
|
2647
|
+
storyFile: "apps/docs/src/stories/DonutChart.stories.ts",
|
|
2648
|
+
storyTitle: "Components/Data Display/Donut Chart",
|
|
2649
|
+
manifestFile: "docs/ai/COMPONENTS/donut-chart.yaml",
|
|
2650
|
+
props: [
|
|
2651
|
+
{
|
|
2652
|
+
name: "segments",
|
|
2653
|
+
type: "TDonutSegment[]",
|
|
2654
|
+
default: "[]",
|
|
2655
|
+
note: "Each item is { label: string; value: number; color?: string }. Non-positive values are omitted."
|
|
2656
|
+
},
|
|
2657
|
+
{
|
|
2658
|
+
name: "size",
|
|
2659
|
+
type: "number",
|
|
2660
|
+
default: "200",
|
|
2661
|
+
note: "Square canvas in px."
|
|
2662
|
+
},
|
|
2663
|
+
{
|
|
2664
|
+
name: "thickness",
|
|
2665
|
+
type: "number",
|
|
2666
|
+
default: "26",
|
|
2667
|
+
note: "Ring thickness; 0 renders a full pie."
|
|
2668
|
+
},
|
|
2669
|
+
{
|
|
2670
|
+
name: "gap",
|
|
2671
|
+
type: "number",
|
|
2672
|
+
default: "2",
|
|
2673
|
+
note: "Gap between slices, in degrees."
|
|
2674
|
+
},
|
|
2675
|
+
{
|
|
2676
|
+
name: "rounded",
|
|
2677
|
+
type: "boolean",
|
|
2678
|
+
default: "false",
|
|
2679
|
+
note: "Round the ends of donut segments (widens the gap to make room). Best with a thinner ring."
|
|
2680
|
+
},
|
|
2681
|
+
{
|
|
2682
|
+
name: "showLegend",
|
|
2683
|
+
type: "boolean",
|
|
2684
|
+
default: "true"
|
|
2685
|
+
},
|
|
2686
|
+
{
|
|
2687
|
+
name: "showPercent",
|
|
2688
|
+
type: "boolean",
|
|
2689
|
+
default: "true"
|
|
2690
|
+
},
|
|
2691
|
+
{
|
|
2692
|
+
name: "centerLabel",
|
|
2693
|
+
type: "string",
|
|
2694
|
+
default: "Total",
|
|
2695
|
+
note: "Donut only; ignored for pie."
|
|
2696
|
+
},
|
|
2697
|
+
{
|
|
2698
|
+
name: "centerValue",
|
|
2699
|
+
type: "string | number",
|
|
2700
|
+
default: "auto (sum of values)"
|
|
2701
|
+
},
|
|
2702
|
+
{
|
|
2703
|
+
name: "valueFormat",
|
|
2704
|
+
type: "(value: number) => string",
|
|
2705
|
+
default: "locale integers for |value| >= 1000"
|
|
2706
|
+
},
|
|
2707
|
+
{
|
|
2708
|
+
name: "loading",
|
|
2709
|
+
type: "boolean",
|
|
2710
|
+
default: "false"
|
|
2711
|
+
},
|
|
2712
|
+
{
|
|
2713
|
+
name: "ariaLabel",
|
|
2714
|
+
type: "string",
|
|
2715
|
+
default: "auto-generated summary"
|
|
2716
|
+
}
|
|
2717
|
+
],
|
|
2718
|
+
events: [],
|
|
2719
|
+
slots: [
|
|
2720
|
+
{
|
|
2721
|
+
name: "center"
|
|
2722
|
+
},
|
|
2723
|
+
{
|
|
2724
|
+
name: "empty"
|
|
2725
|
+
}
|
|
2726
|
+
],
|
|
2727
|
+
a11y: [
|
|
2728
|
+
"Renders role=img with an aria-label summarizing the chart.",
|
|
2729
|
+
"Legend + percentages give a non-visual reading of each slice."
|
|
2730
|
+
],
|
|
2731
|
+
behavior: [
|
|
2732
|
+
"colors_auto_assign_from_chart_palette: --tree-color-chart-1..8, cycling; per-segment color overrides",
|
|
2733
|
+
"hovering_a_slice_dims_the_rest_and_updates_center: true",
|
|
2734
|
+
"center_shows_total_or_the_hovered_segment: true"
|
|
2735
|
+
],
|
|
2736
|
+
selection: {
|
|
2737
|
+
keywords: [
|
|
2738
|
+
"donut",
|
|
2739
|
+
"doughnut",
|
|
2740
|
+
"pie",
|
|
2741
|
+
"proportion",
|
|
2742
|
+
"share",
|
|
2743
|
+
"breakdown",
|
|
2744
|
+
"part of whole",
|
|
2745
|
+
"percentage"
|
|
2746
|
+
],
|
|
2747
|
+
useWhen: [
|
|
2748
|
+
"You are showing how a total splits into a handful of categories.",
|
|
2749
|
+
"A donut center readout (total or hovered slice) is useful."
|
|
2750
|
+
],
|
|
2751
|
+
avoidWhen: [
|
|
2752
|
+
"There are many categories or precise comparison matters \u2014 use TChart bars.",
|
|
2753
|
+
"The data is a trend over time \u2014 use TChart or TSparkline."
|
|
2754
|
+
],
|
|
2755
|
+
alternatives: [
|
|
2756
|
+
{
|
|
2757
|
+
component: "TChart",
|
|
2758
|
+
when: "Precise magnitude comparison across categories is needed (bars)."
|
|
2759
|
+
}
|
|
2760
|
+
]
|
|
2761
|
+
},
|
|
2762
|
+
setup: {
|
|
2763
|
+
required: [],
|
|
2764
|
+
notes: [
|
|
2765
|
+
"Pass `segments` as `{ label, value, color? }[]`; non-positive values are dropped.",
|
|
2766
|
+
"Set `thickness: 0` for a full pie; keep the default for a donut with a center readout.",
|
|
2767
|
+
"Use the `center` slot (donut only) for a custom center; otherwise it shows the total or the hovered slice."
|
|
2768
|
+
]
|
|
2769
|
+
},
|
|
2770
|
+
recipes: [
|
|
2771
|
+
"metric-dashboard"
|
|
2772
|
+
]
|
|
2773
|
+
},
|
|
2105
2774
|
{
|
|
2106
2775
|
name: "TDrawer",
|
|
2107
2776
|
aliases: [],
|
|
@@ -2303,6 +2972,16 @@ var treeui_catalog_default = {
|
|
|
2303
2972
|
name: "label",
|
|
2304
2973
|
type: "string",
|
|
2305
2974
|
default: ""
|
|
2975
|
+
},
|
|
2976
|
+
{
|
|
2977
|
+
name: "align",
|
|
2978
|
+
type: "TDropdownAlign",
|
|
2979
|
+
default: "start",
|
|
2980
|
+
values: [
|
|
2981
|
+
"start",
|
|
2982
|
+
"end"
|
|
2983
|
+
],
|
|
2984
|
+
note: "Horizontal alignment of the menu relative to the trigger. Use `end` when the trigger sits near the right edge of a clipping container (e.g. a table actions column)."
|
|
2306
2985
|
}
|
|
2307
2986
|
],
|
|
2308
2987
|
events: [
|
|
@@ -2338,7 +3017,8 @@ var treeui_catalog_default = {
|
|
|
2338
3017
|
behavior: [
|
|
2339
3018
|
"outside_click_closes_menu: true",
|
|
2340
3019
|
"focus_restores_on_close: true",
|
|
2341
|
-
"chevron_rotates_when_open: true"
|
|
3020
|
+
"chevron_rotates_when_open: true",
|
|
3021
|
+
"menu_grows_to_fit_items_without_wrapping: true"
|
|
2342
3022
|
],
|
|
2343
3023
|
selection: {
|
|
2344
3024
|
keywords: [
|
|
@@ -2468,7 +3148,7 @@ var treeui_catalog_default = {
|
|
|
2468
3148
|
kind: "form",
|
|
2469
3149
|
category: "Form",
|
|
2470
3150
|
status: "available",
|
|
2471
|
-
purpose: "Composable dropzone and file picker with browse, drag-and-drop, and Ctrl+V paste support.",
|
|
3151
|
+
purpose: "Composable dropzone and file picker with browse, drag-and-drop, and Ctrl+V paste support, plus per-file upload state: progress, remaining time, thumbnails, and independent per-file retry/resume.",
|
|
2472
3152
|
sourceFile: "packages/vue/src/components/TFileUpload.vue",
|
|
2473
3153
|
storyFile: "apps/docs/src/stories/FileUpload.stories.ts",
|
|
2474
3154
|
storyTitle: "Components/Form/FileUpload",
|
|
@@ -2492,12 +3172,14 @@ var treeui_catalog_default = {
|
|
|
2492
3172
|
{
|
|
2493
3173
|
name: "disabled",
|
|
2494
3174
|
type: "boolean",
|
|
2495
|
-
default: "false"
|
|
3175
|
+
default: "false",
|
|
3176
|
+
description: "The ONLY prop that gates interaction. Disables the dropzone, the native input, Clear all, and every per-row Remove/Retry."
|
|
2496
3177
|
},
|
|
2497
3178
|
{
|
|
2498
3179
|
name: "loading",
|
|
2499
3180
|
type: "boolean",
|
|
2500
|
-
default: "false"
|
|
3181
|
+
default: "false",
|
|
3182
|
+
description: "Presentational only. Applies `is-loading`, `aria-busy` on the dropzone, and the corner spinner. It gates NO interaction \u2014 see behavior.loading_is_presentational."
|
|
2501
3183
|
},
|
|
2502
3184
|
{
|
|
2503
3185
|
name: "invalid",
|
|
@@ -2530,72 +3212,170 @@ var treeui_catalog_default = {
|
|
|
2530
3212
|
default: "Drop files here"
|
|
2531
3213
|
},
|
|
2532
3214
|
{
|
|
2533
|
-
name: "description",
|
|
3215
|
+
name: "description",
|
|
3216
|
+
type: "string",
|
|
3217
|
+
default: "Click to browse, drag and drop, or paste with Ctrl+V."
|
|
3218
|
+
},
|
|
3219
|
+
{
|
|
3220
|
+
name: "buttonLabel",
|
|
3221
|
+
type: "string",
|
|
3222
|
+
default: "Browse files"
|
|
3223
|
+
},
|
|
3224
|
+
{
|
|
3225
|
+
name: "filesLabel",
|
|
3226
|
+
type: "string",
|
|
3227
|
+
default: "Selected files"
|
|
3228
|
+
},
|
|
3229
|
+
{
|
|
3230
|
+
name: "paste",
|
|
3231
|
+
type: "boolean",
|
|
3232
|
+
default: "true"
|
|
3233
|
+
},
|
|
3234
|
+
{
|
|
3235
|
+
name: "drop",
|
|
3236
|
+
type: "boolean",
|
|
3237
|
+
default: "true"
|
|
3238
|
+
},
|
|
3239
|
+
{
|
|
3240
|
+
name: "showFileList",
|
|
3241
|
+
type: "boolean",
|
|
3242
|
+
default: "true"
|
|
3243
|
+
},
|
|
3244
|
+
{
|
|
3245
|
+
name: "uploadState",
|
|
3246
|
+
type: "TFileUploadStateSource",
|
|
3247
|
+
default: "none",
|
|
3248
|
+
description: "Per-file transport state, keyed by File OBJECT IDENTITY. Accepts a ReadonlyMap<File, TFileUploadState> or a (file, index) => TFileUploadState | undefined resolver. Omit it and the component renders exactly as before: no bars, no status lines, no retry."
|
|
3249
|
+
},
|
|
3250
|
+
{
|
|
3251
|
+
name: "dragLabel",
|
|
3252
|
+
type: "string",
|
|
3253
|
+
default: "Release to upload",
|
|
3254
|
+
description: "Replaces `label` in the dropzone while an acceptable drag is over it. Set it to the same value as `label` to opt out of the text swap."
|
|
3255
|
+
},
|
|
3256
|
+
{
|
|
3257
|
+
name: "dragRejectLabel",
|
|
2534
3258
|
type: "string",
|
|
2535
|
-
default: "
|
|
3259
|
+
default: "This file type is not accepted",
|
|
3260
|
+
description: "Replaces `label` while a drag that cannot work is over the dropzone. Only reachable when drag-reject detection is possible \u2014 see behavior.drag_reject_detection_is_mime_only."
|
|
2536
3261
|
},
|
|
2537
3262
|
{
|
|
2538
|
-
name: "
|
|
2539
|
-
type: "
|
|
2540
|
-
default: "
|
|
3263
|
+
name: "thumbnails",
|
|
3264
|
+
type: "boolean",
|
|
3265
|
+
default: "true",
|
|
3266
|
+
description: "Mint object-URL previews and decode dimensions for image/* files. Set false when you always supply `state.thumbnailUrl` yourself."
|
|
2541
3267
|
},
|
|
2542
3268
|
{
|
|
2543
|
-
name: "
|
|
3269
|
+
name: "maxThumbnailSize",
|
|
3270
|
+
type: "number | null",
|
|
3271
|
+
default: "10 * 1024 * 1024",
|
|
3272
|
+
description: "Skip auto-thumbnailing above this byte size. null removes the cap."
|
|
3273
|
+
},
|
|
3274
|
+
{
|
|
3275
|
+
name: "retryLabel",
|
|
2544
3276
|
type: "string",
|
|
2545
|
-
default: "
|
|
3277
|
+
default: "Retry"
|
|
2546
3278
|
},
|
|
2547
3279
|
{
|
|
2548
|
-
name: "
|
|
2549
|
-
type: "
|
|
2550
|
-
default: "
|
|
3280
|
+
name: "resumeLabel",
|
|
3281
|
+
type: "(percent: number) => string",
|
|
3282
|
+
default: "(percent) => `Resume from ${percent}%`",
|
|
3283
|
+
description: "Receives Math.round(state.progress). Used only when state.resumable === true AND state.progress is a number."
|
|
2551
3284
|
},
|
|
2552
3285
|
{
|
|
2553
|
-
name: "
|
|
2554
|
-
type: "
|
|
2555
|
-
default: "
|
|
3286
|
+
name: "remainingTimeFormat",
|
|
3287
|
+
type: "(remainingMs: number) => string",
|
|
3288
|
+
default: "5s/60s/60min thresholds \u2014 see behavior.remaining_time_strings",
|
|
3289
|
+
description: "Formats state.remainingMs. Ignored for a row that supplies state.remainingLabel."
|
|
2556
3290
|
},
|
|
2557
3291
|
{
|
|
2558
|
-
name: "
|
|
2559
|
-
type: "
|
|
2560
|
-
default: "
|
|
3292
|
+
name: "statusLabels",
|
|
3293
|
+
type: "Partial<Record<TFileUploadStatus, string>>",
|
|
3294
|
+
default: "{}",
|
|
3295
|
+
description: "MERGED over the defaults { pending: Waiting, uploading: Uploading, paused: Paused, error: Upload failed, success: Uploaded } \u2014 pass only the keys you override."
|
|
2561
3296
|
}
|
|
2562
3297
|
],
|
|
2563
3298
|
events: [
|
|
2564
3299
|
{
|
|
2565
|
-
name: "update:modelValue"
|
|
3300
|
+
name: "update:modelValue",
|
|
3301
|
+
description: "Emitted with the next file list when files are added, removed, or cleared.",
|
|
3302
|
+
payload: "File[]"
|
|
3303
|
+
},
|
|
3304
|
+
{
|
|
3305
|
+
name: "files-accepted",
|
|
3306
|
+
description: "Emitted with only the newly accepted files, after accept/maxFiles/maxFileSize validation.",
|
|
3307
|
+
payload: "File[]"
|
|
2566
3308
|
},
|
|
2567
3309
|
{
|
|
2568
|
-
name: "files-
|
|
3310
|
+
name: "files-rejected",
|
|
3311
|
+
description: "Pre-acceptance validation failures. Unrelated to transport errors, which you report through `uploadState`.",
|
|
3312
|
+
payload: "TFileUploadRejection[]"
|
|
2569
3313
|
},
|
|
2570
3314
|
{
|
|
2571
|
-
name: "
|
|
3315
|
+
name: "retry",
|
|
3316
|
+
description: "Emitted when a row's retry affordance is activated. Pure intent \u2014 the component performs no upload. Use `payload.mode` ('resume' | 'restart'); it reports the affordance the component ACTUALLY DREW, so never re-derive it from your own state.",
|
|
3317
|
+
payload: "TFileUploadRetryPayload"
|
|
3318
|
+
},
|
|
3319
|
+
{
|
|
3320
|
+
name: "cancel",
|
|
3321
|
+
description: "Emitted ONLY for rows whose status is 'uploading' or 'paused', immediately BEFORE the `update:modelValue` that drops them \u2014 so the file is still in the list when your handler runs and you can abort the request. `reason` is 'remove' for one row or 'clear' (one event per in-flight file) for Clear all.",
|
|
3322
|
+
payload: "TFileUploadCancelPayload"
|
|
2572
3323
|
}
|
|
2573
3324
|
],
|
|
2574
3325
|
slots: [
|
|
2575
3326
|
{
|
|
2576
|
-
name: "icon"
|
|
3327
|
+
name: "icon",
|
|
3328
|
+
description: "Replaces the dropzone icon."
|
|
2577
3329
|
},
|
|
2578
3330
|
{
|
|
2579
|
-
name: "default"
|
|
3331
|
+
name: "default",
|
|
3332
|
+
description: "Replaces the dropzone body. Receives `{ files, isDragActive, isDragReject, openFileDialog, clearFiles }`."
|
|
2580
3333
|
},
|
|
2581
3334
|
{
|
|
2582
|
-
name: "file"
|
|
3335
|
+
name: "file",
|
|
3336
|
+
description: "Full row override. Receives all of TFileUploadFileSlotProps, including every derived label, so a custom row re-derives nothing."
|
|
2583
3337
|
},
|
|
2584
3338
|
{
|
|
2585
|
-
name: "
|
|
3339
|
+
name: "file-status",
|
|
3340
|
+
description: "Replaces ONLY the progress bar + status line + error block inside the default row. Receives TFileUploadFileSlotProps. Name, meta, thumbnail, Retry, and Remove keep rendering. Ignored when the `file` slot is provided."
|
|
3341
|
+
},
|
|
3342
|
+
{
|
|
3343
|
+
name: "actions",
|
|
3344
|
+
description: "Footer actions. Receives `{ files, openFileDialog, clearFiles }` \u2014 no upload state."
|
|
2586
3345
|
}
|
|
2587
3346
|
],
|
|
2588
3347
|
a11y: [
|
|
2589
3348
|
"dropzone_role: button",
|
|
2590
3349
|
"keyboard_activation: Enter_and_Space_open_the_file_picker",
|
|
2591
3350
|
"supports_paste_when_component_is_focused: true",
|
|
2592
|
-
"file_feedback_announced_via_live_region: true"
|
|
3351
|
+
"file_feedback_announced_via_live_region: true",
|
|
3352
|
+
"aria_busy_on_dropzone_tracks_loading_prop: true",
|
|
3353
|
+
"aria_busy_on_row_tracks_that_rows_uploading_status: true",
|
|
3354
|
+
"per_row_progressbar_is_labelled_with_status_and_filename: e.g. 'Uploading hero.png' \u2014 every row's bar has a distinct accessible name.",
|
|
3355
|
+
"terminal_transitions_announced_with_filenames: One polite root live region (`role=log`) announces only success/error, e.g. 'alpha.txt uploaded.' / 'alpha.txt failed. Connection lost.'",
|
|
3356
|
+
"repeated_identical_messages_are_still_announced: The log appends each message as a new node rather than overwriting one string, so a retry that fails with the byte-identical error still mutates the region and is announced. It is not aria-atomic: only the appended message is read, and the trimmed history (5 most recent) is not.",
|
|
3357
|
+
"percentages_are_never_announced: Percent and ETA live in non-live text; the value reaches assistive tech through the progressbar's aria-valuenow.",
|
|
3358
|
+
"retry_button_is_described_by_its_row_error: Announces 'Resume from 90%, Connection lost at 90%'.",
|
|
3359
|
+
"focus_is_rescued_when_retry_unmounts: Flipping error -> uploading removes the focused Retry; focus moves to that row's Remove (or the dropzone), and only when it was genuinely lost.",
|
|
3360
|
+
"remove_and_retry_meet_the_44px_target: true"
|
|
2593
3361
|
],
|
|
2594
3362
|
behavior: [
|
|
2595
3363
|
"accepts_files_from_input_drop_and_paste: true",
|
|
2596
3364
|
"multiple_false_replaces_existing_selection: true",
|
|
2597
3365
|
"accept_maxFiles_and_maxFileSize_apply_to_all_entry_points: true",
|
|
2598
|
-
"selected_files_can_be_removed_or_cleared: true"
|
|
3366
|
+
"selected_files_can_be_removed_or_cleared: true",
|
|
3367
|
+
"upload_state_is_keyed_by_file_identity: Both source shapes key on the File object, never on index or name. Key your own store with the File objects you receive from `files-accepted`.",
|
|
3368
|
+
"a_lookup_miss_renders_nothing: An unknown File yields `undefined` and the row falls back to name + meta only \u2014 no bar, no status, no retry. This fail-blank is deliberate: it is the back-compat path and it fails loudly instead of showing another file's percentage.",
|
|
3369
|
+
"loading_is_presentational: BREAKING since 0.14.0 \u2014 `loading` no longer disables anything. It was freezing the dropzone, Clear all, and every Remove, which blocked removing file 1 while file 4 uploaded. Use `:disabled` to reproduce the old behavior; prefer `uploadState` and freeze nothing.",
|
|
3370
|
+
"each_file_has_an_independent_track: One row's error, progress, or retry never gates another's. Remove stays enabled for in-flight rows and emits `cancel` so you can abort.",
|
|
3371
|
+
"errors_are_per_row: Transport errors go in `state.error` and render under their own row. They never enter the dropzone feedback list, which Remove and Clear all wipe.",
|
|
3372
|
+
"drag_feedback_has_three_signals: Border, glow, and a text swap to `dragLabel` \u2014 all three fire together, including when files are already listed.",
|
|
3373
|
+
"drag_reject_detection_is_mime_only: `is-drag-reject` + `dragRejectLabel` require every `accept` token to be a MIME token; with any `.ext` token the dropzone stays neutral, because a drag exposes only `.type`. A mixed drag (one good file, one bad) is NOT rejected, and the drop is never blocked \u2014 rejected files always get the normal `files-rejected` explanation.",
|
|
3374
|
+
"progress_bar_visibility: Shown on uploading/paused/error, and on success only with numeric progress. 'uploading' without progress is indeterminate; paused/error without progress is a determinate 0 \u2014 an errored bar must never animate.",
|
|
3375
|
+
"the_bar_is_never_reset_on_error: It holds `state.progress` in the error tone. That retained 90% is what makes the resume promise legible.",
|
|
3376
|
+
"remaining_time_strings: < 5000ms -> 'Less than 5s left'; < 60s -> 'About 12s left'; < 60min -> 'About 2 min left'; else 'About 2h left'. Negative, NaN, and Infinity render nothing.",
|
|
3377
|
+
"status_line_composition: Joins the present parts with ' \xB7 ': 'Uploading \xB7 62% \xB7 About 12s left' while uploading, 'Upload failed \xB7 2.1 MB of 2.4 MB uploaded' on a resumable error.",
|
|
3378
|
+
"thumbnails_are_client_only: Object URLs are minted after mount and revoked on removal and unmount. SSR and the hydrating render both show the extension chip, so there is no mismatch."
|
|
2599
3379
|
],
|
|
2600
3380
|
selection: {
|
|
2601
3381
|
keywords: [],
|
|
@@ -2838,7 +3618,8 @@ var treeui_catalog_default = {
|
|
|
2838
3618
|
},
|
|
2839
3619
|
recipes: [
|
|
2840
3620
|
"date-range-form",
|
|
2841
|
-
"stat-grid"
|
|
3621
|
+
"stat-grid",
|
|
3622
|
+
"metric-dashboard"
|
|
2842
3623
|
]
|
|
2843
3624
|
},
|
|
2844
3625
|
{
|
|
@@ -3649,7 +4430,7 @@ var treeui_catalog_default = {
|
|
|
3649
4430
|
name: "items",
|
|
3650
4431
|
type: "TNavMenuItem[]",
|
|
3651
4432
|
default: "[]",
|
|
3652
|
-
note: "Array of `{ label, value, shortLabel?, description?, icon?, to?, badge?, disabled? }`."
|
|
4433
|
+
note: "Array of `{ label, value, shortLabel?, description?, icon?, to?, badge?, disabled?, exact? }`."
|
|
3653
4434
|
},
|
|
3654
4435
|
{
|
|
3655
4436
|
name: "size",
|
|
@@ -3670,6 +4451,12 @@ var treeui_catalog_default = {
|
|
|
3670
4451
|
name: "disabled",
|
|
3671
4452
|
type: "boolean",
|
|
3672
4453
|
default: "false"
|
|
4454
|
+
},
|
|
4455
|
+
{
|
|
4456
|
+
name: "exact",
|
|
4457
|
+
type: "boolean",
|
|
4458
|
+
default: "true",
|
|
4459
|
+
note: "Default active-match strategy for router-link items. `true` keeps only the exactly-active route highlighted (prevents prefix matches from lighting up several items at once). Override per item via `TNavMenuItem.exact`."
|
|
3673
4460
|
}
|
|
3674
4461
|
],
|
|
3675
4462
|
events: [
|
|
@@ -3728,10 +4515,11 @@ var treeui_catalog_default = {
|
|
|
3728
4515
|
setup: {
|
|
3729
4516
|
required: [],
|
|
3730
4517
|
notes: [
|
|
3731
|
-
"When nested inside `TSidebar`, `collapsed` can be inherited from the sidebar provider."
|
|
4518
|
+
"When nested inside `TSidebar` or `TAppShell`, `collapsed` can be inherited from the sidebar provider."
|
|
3732
4519
|
]
|
|
3733
4520
|
},
|
|
3734
4521
|
recipes: [
|
|
4522
|
+
"app-shell",
|
|
3735
4523
|
"sidebar-shell"
|
|
3736
4524
|
]
|
|
3737
4525
|
},
|
|
@@ -3842,6 +4630,193 @@ var treeui_catalog_default = {
|
|
|
3842
4630
|
},
|
|
3843
4631
|
recipes: []
|
|
3844
4632
|
},
|
|
4633
|
+
{
|
|
4634
|
+
name: "TPage",
|
|
4635
|
+
aliases: [],
|
|
4636
|
+
package: "@treeui/vue",
|
|
4637
|
+
kind: "layout",
|
|
4638
|
+
category: "Layout",
|
|
4639
|
+
status: "available",
|
|
4640
|
+
purpose: "Semantic page region under the app shell: block padding, a centered max-width content column, and standardized vertical rhythm between sections.",
|
|
4641
|
+
sourceFile: "packages/vue/src/components/TPage.vue",
|
|
4642
|
+
storyFile: "apps/docs/src/stories/Page.stories.ts",
|
|
4643
|
+
storyTitle: "Components/Layout/Page",
|
|
4644
|
+
manifestFile: "docs/ai/COMPONENTS/page.yaml",
|
|
4645
|
+
props: [
|
|
4646
|
+
{
|
|
4647
|
+
name: "as",
|
|
4648
|
+
type: "string",
|
|
4649
|
+
default: "div"
|
|
4650
|
+
},
|
|
4651
|
+
{
|
|
4652
|
+
name: "width",
|
|
4653
|
+
type: "TContainerSize",
|
|
4654
|
+
default: "lg",
|
|
4655
|
+
values: [
|
|
4656
|
+
"sm",
|
|
4657
|
+
"md",
|
|
4658
|
+
"lg",
|
|
4659
|
+
"xl",
|
|
4660
|
+
"full"
|
|
4661
|
+
],
|
|
4662
|
+
note: "Max-width of the centered content column. Mirrors TContainer sizes."
|
|
4663
|
+
},
|
|
4664
|
+
{
|
|
4665
|
+
name: "padded",
|
|
4666
|
+
type: "boolean",
|
|
4667
|
+
default: "true",
|
|
4668
|
+
note: "Adds vertical (block) padding on the region and horizontal padding on the inner column."
|
|
4669
|
+
},
|
|
4670
|
+
{
|
|
4671
|
+
name: "gap",
|
|
4672
|
+
type: "TPageGap",
|
|
4673
|
+
default: "lg",
|
|
4674
|
+
values: [
|
|
4675
|
+
"sm",
|
|
4676
|
+
"md",
|
|
4677
|
+
"lg"
|
|
4678
|
+
],
|
|
4679
|
+
note: "Vertical spacing between direct children (e.g. a TPageHeader and content sections)."
|
|
4680
|
+
}
|
|
4681
|
+
],
|
|
4682
|
+
events: [],
|
|
4683
|
+
slots: [
|
|
4684
|
+
{
|
|
4685
|
+
name: "default"
|
|
4686
|
+
}
|
|
4687
|
+
],
|
|
4688
|
+
a11y: [
|
|
4689
|
+
"Structural wrapper only; landmark semantics come from `as` and the surrounding app shell (avoid nesting a second `main`)."
|
|
4690
|
+
],
|
|
4691
|
+
behavior: [
|
|
4692
|
+
"centers_content_column_by_width: true",
|
|
4693
|
+
"applies_block_padding_when_padded: true",
|
|
4694
|
+
"spaces_children_vertically_by_gap: true"
|
|
4695
|
+
],
|
|
4696
|
+
selection: {
|
|
4697
|
+
keywords: [
|
|
4698
|
+
"page",
|
|
4699
|
+
"page shell",
|
|
4700
|
+
"content column",
|
|
4701
|
+
"screen layout"
|
|
4702
|
+
],
|
|
4703
|
+
useWhen: [
|
|
4704
|
+
"You want a standard screen region under the app shell with consistent max width, page padding, and vertical rhythm between sections."
|
|
4705
|
+
],
|
|
4706
|
+
avoidWhen: [
|
|
4707
|
+
"You only need a bare width constraint with no page padding or child spacing."
|
|
4708
|
+
],
|
|
4709
|
+
alternatives: [
|
|
4710
|
+
{
|
|
4711
|
+
component: "TContainer",
|
|
4712
|
+
when: "You just need a centered max-width wrapper without page-level block padding or child spacing."
|
|
4713
|
+
},
|
|
4714
|
+
{
|
|
4715
|
+
component: "TStack",
|
|
4716
|
+
when: "You only need to space a group of children, not lay out a whole page."
|
|
4717
|
+
}
|
|
4718
|
+
]
|
|
4719
|
+
},
|
|
4720
|
+
setup: {
|
|
4721
|
+
required: [],
|
|
4722
|
+
notes: []
|
|
4723
|
+
},
|
|
4724
|
+
recipes: []
|
|
4725
|
+
},
|
|
4726
|
+
{
|
|
4727
|
+
name: "TPageHeader",
|
|
4728
|
+
aliases: [],
|
|
4729
|
+
package: "@treeui/vue",
|
|
4730
|
+
kind: "layout",
|
|
4731
|
+
category: "Layout",
|
|
4732
|
+
status: "available",
|
|
4733
|
+
purpose: "Canonical page title block: heading, optional subtitle, and a right-aligned actions area, so title hierarchy and alignment stay consistent across screens.",
|
|
4734
|
+
sourceFile: "packages/vue/src/components/TPageHeader.vue",
|
|
4735
|
+
storyFile: "apps/docs/src/stories/PageHeader.stories.ts",
|
|
4736
|
+
storyTitle: "Components/Layout/PageHeader",
|
|
4737
|
+
manifestFile: "docs/ai/COMPONENTS/page-header.yaml",
|
|
4738
|
+
props: [
|
|
4739
|
+
{
|
|
4740
|
+
name: "title",
|
|
4741
|
+
type: "string",
|
|
4742
|
+
default: "",
|
|
4743
|
+
note: "Rendered inside the heading element. Overridden by the `title` slot."
|
|
4744
|
+
},
|
|
4745
|
+
{
|
|
4746
|
+
name: "subtitle",
|
|
4747
|
+
type: "string",
|
|
4748
|
+
default: ""
|
|
4749
|
+
},
|
|
4750
|
+
{
|
|
4751
|
+
name: "level",
|
|
4752
|
+
type: "1 | 2 | 3 | 4 | 5 | 6",
|
|
4753
|
+
default: "1",
|
|
4754
|
+
note: "Heading level for the title element. Default `1` treats it as the page title; lower it when the page already has an h1."
|
|
4755
|
+
},
|
|
4756
|
+
{
|
|
4757
|
+
name: "as",
|
|
4758
|
+
type: "string",
|
|
4759
|
+
default: "header"
|
|
4760
|
+
}
|
|
4761
|
+
],
|
|
4762
|
+
events: [],
|
|
4763
|
+
slots: [
|
|
4764
|
+
{
|
|
4765
|
+
name: "breadcrumb"
|
|
4766
|
+
},
|
|
4767
|
+
{
|
|
4768
|
+
name: "title"
|
|
4769
|
+
},
|
|
4770
|
+
{
|
|
4771
|
+
name: "subtitle"
|
|
4772
|
+
},
|
|
4773
|
+
{
|
|
4774
|
+
name: "actions"
|
|
4775
|
+
},
|
|
4776
|
+
{
|
|
4777
|
+
name: "default"
|
|
4778
|
+
}
|
|
4779
|
+
],
|
|
4780
|
+
a11y: [
|
|
4781
|
+
"Title renders as a real heading element (`h1`\u2013`h6`) chosen by `level`; keep one h1 per page.",
|
|
4782
|
+
"Actions area holds standard focusable controls (e.g. TButton) \u2014 no custom roles added."
|
|
4783
|
+
],
|
|
4784
|
+
behavior: [
|
|
4785
|
+
"title_and_subtitle_optional: true",
|
|
4786
|
+
"heading_level_controlled_by_level: true",
|
|
4787
|
+
"actions_area_right_aligned_and_wraps: true",
|
|
4788
|
+
"default_slot_renders_below_heading: true"
|
|
4789
|
+
],
|
|
4790
|
+
selection: {
|
|
4791
|
+
keywords: [
|
|
4792
|
+
"page header",
|
|
4793
|
+
"title bar",
|
|
4794
|
+
"page title",
|
|
4795
|
+
"heading and actions"
|
|
4796
|
+
],
|
|
4797
|
+
useWhen: [
|
|
4798
|
+
"A screen needs a title (and optional subtitle) with a right-aligned actions area in a consistent hierarchy."
|
|
4799
|
+
],
|
|
4800
|
+
avoidWhen: [
|
|
4801
|
+
"You need cross-page hierarchy or navigation trails rather than a single page title."
|
|
4802
|
+
],
|
|
4803
|
+
alternatives: [
|
|
4804
|
+
{
|
|
4805
|
+
component: "TBreadcrumb",
|
|
4806
|
+
when: "You are showing where the page sits in a hierarchy, not its title."
|
|
4807
|
+
},
|
|
4808
|
+
{
|
|
4809
|
+
component: "TNavbar",
|
|
4810
|
+
when: "You need a top application bar, not a per-page title block."
|
|
4811
|
+
}
|
|
4812
|
+
]
|
|
4813
|
+
},
|
|
4814
|
+
setup: {
|
|
4815
|
+
required: [],
|
|
4816
|
+
notes: []
|
|
4817
|
+
},
|
|
4818
|
+
recipes: []
|
|
4819
|
+
},
|
|
3845
4820
|
{
|
|
3846
4821
|
name: "TPagination",
|
|
3847
4822
|
aliases: [],
|
|
@@ -4558,7 +5533,8 @@ var treeui_catalog_default = {
|
|
|
4558
5533
|
"check_icon_on_selected_option: true",
|
|
4559
5534
|
"outside_click_closes_dropdown: true",
|
|
4560
5535
|
"focus_restores_on_close: true",
|
|
4561
|
-
"numeric_values_supported_without_string_coercion: true"
|
|
5536
|
+
"numeric_values_supported_without_string_coercion: true",
|
|
5537
|
+
"listbox_flips_above_trigger_when_space_below_is_insufficient: true"
|
|
4562
5538
|
],
|
|
4563
5539
|
selection: {
|
|
4564
5540
|
keywords: [
|
|
@@ -4591,7 +5567,9 @@ var treeui_catalog_default = {
|
|
|
4591
5567
|
"Use `placeholder` when no selection has been made."
|
|
4592
5568
|
]
|
|
4593
5569
|
},
|
|
4594
|
-
recipes: [
|
|
5570
|
+
recipes: [
|
|
5571
|
+
"chart-surface"
|
|
5572
|
+
]
|
|
4595
5573
|
},
|
|
4596
5574
|
{
|
|
4597
5575
|
name: "TSelectableList",
|
|
@@ -4813,7 +5791,8 @@ var treeui_catalog_default = {
|
|
|
4813
5791
|
"controlled_and_uncontrolled_collapsed_state: true",
|
|
4814
5792
|
"provides_collapsed_state_to_descendants: true",
|
|
4815
5793
|
"left_and_right_variants: true",
|
|
4816
|
-
"exposes_slot_props_with_collapsed_state: true"
|
|
5794
|
+
"exposes_slot_props_with_collapsed_state: true",
|
|
5795
|
+
"collapsed_state_centers_header_and_footer_content: true"
|
|
4817
5796
|
],
|
|
4818
5797
|
selection: {
|
|
4819
5798
|
keywords: [
|
|
@@ -4838,7 +5817,8 @@ var treeui_catalog_default = {
|
|
|
4838
5817
|
required: [],
|
|
4839
5818
|
notes: [
|
|
4840
5819
|
"Pair with `TNavMenu` for app-section navigation.",
|
|
4841
|
-
"Use controlled `collapsed` state when the app shell persists layout preferences."
|
|
5820
|
+
"Use controlled `collapsed` state when the app shell persists layout preferences.",
|
|
5821
|
+
"Prefer `TAppShell` when you also want full-viewport sizing, a top header, and a responsive mobile drawer."
|
|
4842
5822
|
]
|
|
4843
5823
|
},
|
|
4844
5824
|
recipes: [
|
|
@@ -4908,6 +5888,129 @@ var treeui_catalog_default = {
|
|
|
4908
5888
|
},
|
|
4909
5889
|
recipes: []
|
|
4910
5890
|
},
|
|
5891
|
+
{
|
|
5892
|
+
name: "TSparkline",
|
|
5893
|
+
aliases: [],
|
|
5894
|
+
package: "@treeui/vue",
|
|
5895
|
+
kind: "data-display",
|
|
5896
|
+
category: "Data Display",
|
|
5897
|
+
status: "available",
|
|
5898
|
+
purpose: "Tiny, axis-less inline trend chart (line, area, or bar) sized for stat tiles, table cells, and running text.",
|
|
5899
|
+
sourceFile: "packages/vue/src/components/TSparkline.vue",
|
|
5900
|
+
storyFile: "apps/docs/src/stories/Sparkline.stories.ts",
|
|
5901
|
+
storyTitle: "Components/Data Display/Sparkline",
|
|
5902
|
+
manifestFile: "docs/ai/COMPONENTS/sparkline.yaml",
|
|
5903
|
+
props: [
|
|
5904
|
+
{
|
|
5905
|
+
name: "data",
|
|
5906
|
+
type: "number[]",
|
|
5907
|
+
default: "[]"
|
|
5908
|
+
},
|
|
5909
|
+
{
|
|
5910
|
+
name: "type",
|
|
5911
|
+
type: "line | area | bar",
|
|
5912
|
+
default: "line"
|
|
5913
|
+
},
|
|
5914
|
+
{
|
|
5915
|
+
name: "color",
|
|
5916
|
+
type: "string",
|
|
5917
|
+
default: "var(--tree-color-chart-1)",
|
|
5918
|
+
note: "Any CSS color."
|
|
5919
|
+
},
|
|
5920
|
+
{
|
|
5921
|
+
name: "width",
|
|
5922
|
+
type: "number",
|
|
5923
|
+
default: "120"
|
|
5924
|
+
},
|
|
5925
|
+
{
|
|
5926
|
+
name: "height",
|
|
5927
|
+
type: "number",
|
|
5928
|
+
default: "32"
|
|
5929
|
+
},
|
|
5930
|
+
{
|
|
5931
|
+
name: "smooth",
|
|
5932
|
+
type: "boolean",
|
|
5933
|
+
default: "false",
|
|
5934
|
+
note: "Curved line/area."
|
|
5935
|
+
},
|
|
5936
|
+
{
|
|
5937
|
+
name: "strokeWidth",
|
|
5938
|
+
type: "number",
|
|
5939
|
+
default: "2",
|
|
5940
|
+
note: "Line/area only."
|
|
5941
|
+
},
|
|
5942
|
+
{
|
|
5943
|
+
name: "min",
|
|
5944
|
+
type: "number",
|
|
5945
|
+
default: "data min"
|
|
5946
|
+
},
|
|
5947
|
+
{
|
|
5948
|
+
name: "max",
|
|
5949
|
+
type: "number",
|
|
5950
|
+
default: "data max"
|
|
5951
|
+
},
|
|
5952
|
+
{
|
|
5953
|
+
name: "showLastPoint",
|
|
5954
|
+
type: "boolean",
|
|
5955
|
+
default: "false",
|
|
5956
|
+
note: "Marker on the final point (line/area)."
|
|
5957
|
+
},
|
|
5958
|
+
{
|
|
5959
|
+
name: "ariaLabel",
|
|
5960
|
+
type: "string",
|
|
5961
|
+
default: "Trend sparkline"
|
|
5962
|
+
}
|
|
5963
|
+
],
|
|
5964
|
+
events: [],
|
|
5965
|
+
slots: [],
|
|
5966
|
+
a11y: [
|
|
5967
|
+
"Renders role=img with an aria-label; pass a specific one for meaningful trends.",
|
|
5968
|
+
"Pair with a visible number \u2014 a sparkline supplements a value, it does not replace it."
|
|
5969
|
+
],
|
|
5970
|
+
behavior: [
|
|
5971
|
+
"no_axes_or_legend: true",
|
|
5972
|
+
"flat_series_renders_centered: true",
|
|
5973
|
+
"scales_to_intrinsic_width_and_height: true"
|
|
5974
|
+
],
|
|
5975
|
+
selection: {
|
|
5976
|
+
keywords: [
|
|
5977
|
+
"sparkline",
|
|
5978
|
+
"mini chart",
|
|
5979
|
+
"inline chart",
|
|
5980
|
+
"micro trend",
|
|
5981
|
+
"trend line",
|
|
5982
|
+
"table chart"
|
|
5983
|
+
],
|
|
5984
|
+
useWhen: [
|
|
5985
|
+
"You want a compact trend beside a value, in a table cell, or inline in text.",
|
|
5986
|
+
"No axes, legend, or tooltip are required."
|
|
5987
|
+
],
|
|
5988
|
+
avoidWhen: [
|
|
5989
|
+
"You need axes, multiple labeled series, or a tooltip \u2014 use TChart."
|
|
5990
|
+
],
|
|
5991
|
+
alternatives: [
|
|
5992
|
+
{
|
|
5993
|
+
component: "TChart",
|
|
5994
|
+
when: "The chart needs axes, a legend, or a tooltip."
|
|
5995
|
+
},
|
|
5996
|
+
{
|
|
5997
|
+
component: "TStat",
|
|
5998
|
+
when: "A single value with a trend badge is enough."
|
|
5999
|
+
}
|
|
6000
|
+
]
|
|
6001
|
+
},
|
|
6002
|
+
setup: {
|
|
6003
|
+
required: [],
|
|
6004
|
+
notes: [
|
|
6005
|
+
"Pass `data` as `number[]`; there are no axes, legend, or tooltip by design.",
|
|
6006
|
+
"Size it with `width`/`height`; use it inside `TStat`, table cells, or text.",
|
|
6007
|
+
"Always keep a visible number nearby \u2014 a sparkline supplements a value, it does not replace it."
|
|
6008
|
+
]
|
|
6009
|
+
},
|
|
6010
|
+
recipes: [
|
|
6011
|
+
"metric-dashboard"
|
|
6012
|
+
]
|
|
6013
|
+
},
|
|
4911
6014
|
{
|
|
4912
6015
|
name: "TSpinner",
|
|
4913
6016
|
aliases: [],
|
|
@@ -5161,6 +6264,10 @@ var treeui_catalog_default = {
|
|
|
5161
6264
|
{
|
|
5162
6265
|
component: "TCard",
|
|
5163
6266
|
when: "The content is not a metric."
|
|
6267
|
+
},
|
|
6268
|
+
{
|
|
6269
|
+
component: "TSparkline",
|
|
6270
|
+
when: "You want to show the metric's trend as an inline mini-chart."
|
|
5164
6271
|
}
|
|
5165
6272
|
]
|
|
5166
6273
|
},
|
|
@@ -5169,7 +6276,8 @@ var treeui_catalog_default = {
|
|
|
5169
6276
|
notes: []
|
|
5170
6277
|
},
|
|
5171
6278
|
recipes: [
|
|
5172
|
-
"stat-grid"
|
|
6279
|
+
"stat-grid",
|
|
6280
|
+
"metric-dashboard"
|
|
5173
6281
|
]
|
|
5174
6282
|
},
|
|
5175
6283
|
{
|