@treeui/mcp 0.5.0 → 0.6.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-TRJAXZUC.js → chunk-ITEC3SEF.js} +2097 -377
- package/dist/cli.cjs +2097 -377
- package/dist/cli.js +1 -1
- package/dist/index.cjs +2114 -374
- package/dist/index.d.cts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +22 -2
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -34,9 +34,9 @@ var import_server = require("@modelcontextprotocol/sdk/server/index.js");
|
|
|
34
34
|
|
|
35
35
|
// src/generated/treeui.catalog.json
|
|
36
36
|
var treeui_catalog_default = {
|
|
37
|
-
generatedAt: "2026-07-
|
|
37
|
+
generatedAt: "2026-07-21T19:17:20.408Z",
|
|
38
38
|
packageName: "@treeui/vue",
|
|
39
|
-
packageVersion: "0.
|
|
39
|
+
packageVersion: "0.19.0",
|
|
40
40
|
decisionGuides: [
|
|
41
41
|
{
|
|
42
42
|
id: "single-choice",
|
|
@@ -87,6 +87,14 @@ var treeui_catalog_default = {
|
|
|
87
87
|
"The options are hierarchical."
|
|
88
88
|
],
|
|
89
89
|
notes: []
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
use: "TLanguageSelect",
|
|
93
|
+
when: [
|
|
94
|
+
"The value is the application language or locale.",
|
|
95
|
+
"Each language should show a country flag beside its name."
|
|
96
|
+
],
|
|
97
|
+
notes: []
|
|
90
98
|
}
|
|
91
99
|
]
|
|
92
100
|
},
|
|
@@ -399,6 +407,32 @@ var treeui_catalog_default = {
|
|
|
399
407
|
"Prefer `TAppShell` (recipe `app-shell`) when you also need full-viewport sizing and a responsive mobile drawer."
|
|
400
408
|
]
|
|
401
409
|
},
|
|
410
|
+
{
|
|
411
|
+
id: "nav-menu-icons",
|
|
412
|
+
name: "Icons on navigation items",
|
|
413
|
+
useWhen: [
|
|
414
|
+
"Navigation items each carry an icon.",
|
|
415
|
+
"The navigation collapses to an icon-only rail, so the icon is the only thing left identifying a section.",
|
|
416
|
+
"Some of the icons the app needs are not TreeUI built-ins."
|
|
417
|
+
],
|
|
418
|
+
compose: [
|
|
419
|
+
"TNavMenu",
|
|
420
|
+
"TIcon",
|
|
421
|
+
"registerTreeIcons",
|
|
422
|
+
"resetTreeIcons"
|
|
423
|
+
],
|
|
424
|
+
notes: [
|
|
425
|
+
"Set `icon` on the item, as a registered NAME: `{ label: 'Dashboard', value: 'dashboard', icon: 'layout-dashboard' }`. Do not import an icon component per item, and do not put a `TIcon` in the `#item` slot just to get an icon \u2014 the item renders it for you.",
|
|
426
|
+
"`TNavMenuItem.icon` is `TIconInput`, so a component is accepted too. Prefer the name: `items` normally lives in a `ref`, a `computed`, or a route config, and a string is never made reactive \u2014 a component object there needs `markRaw` or Vue warns.",
|
|
427
|
+
"An item with no icon (or an unregistered name) falls back to a letter marker, and a `console.warn` lists the valid names \u2014 once per name, in production builds too. Give every item an icon before shipping a collapsible rail, or the collapsed state is a column of letters.",
|
|
428
|
+
"Icons the app needs but TreeUI does not ship are REGISTERED, not worked around: one `registerTreeIcons` call in `main.ts` and they are usable by name everywhere. Never hand-roll an `<svg>` \u2014 without the `absoluteStrokeWidth` correction its stroke scales with the icon (1.67px at size 20, 4px at 48), so it looks bolder than its neighbours at every size above 24.",
|
|
429
|
+
"Check the name is not already taken before registering it \u2014 `hasTreeIcon(name)` answers that. Registering one of the 364 built-in names replaces that built-in everywhere, silently, which is a supported swap but never what you want when the goal was adding an icon.",
|
|
430
|
+
"Keep the icon vocabulary consistent: built-ins use TreeUI's descriptive kebab-case names, so register custom ones with the same convention.",
|
|
431
|
+
"Icon registration is process-wide state. In component tests that register icons, call `resetTreeIcons()` in an `afterEach` so one case's icons do not leak into the next.",
|
|
432
|
+
"Set `to` for the route target on each item \u2014 `TNavMenuItem` has no `href` and no `id`; identity is `value`.",
|
|
433
|
+
"This recipe covers the icons only; the surrounding layout is its own recipe (`app-shell` or `sidebar-shell`)."
|
|
434
|
+
]
|
|
435
|
+
},
|
|
402
436
|
{
|
|
403
437
|
id: "stat-grid",
|
|
404
438
|
name: "Dashboard metric grid",
|
|
@@ -572,6 +606,148 @@ var treeui_catalog_default = {
|
|
|
572
606
|
notes: [
|
|
573
607
|
'Use `selectionMode="multiple"` when permissions or tag assignment spans nested nodes.'
|
|
574
608
|
]
|
|
609
|
+
},
|
|
610
|
+
{
|
|
611
|
+
id: "language-switcher",
|
|
612
|
+
name: "Application language switcher",
|
|
613
|
+
useWhen: [
|
|
614
|
+
"The app lets the user pick a language or locale, with an optional flag per option."
|
|
615
|
+
],
|
|
616
|
+
compose: [
|
|
617
|
+
"TFormField",
|
|
618
|
+
"TLanguageSelect"
|
|
619
|
+
],
|
|
620
|
+
notes: [
|
|
621
|
+
"The app owns the language list: TreeUI ships no locale dataset, so pass `options` with your own `label`, `value`, and optional `code` and `description`.",
|
|
622
|
+
"`TLanguageSelect` only emits the chosen `value` through `update:modelValue`; the app performs every locale side effect (i18n locale, persistence, `document.documentElement.lang`, route or API updates).",
|
|
623
|
+
"Set `code` only where a flag is meaningful \u2014 a language is not a country \u2014 and omit it to render that option without a flag.",
|
|
624
|
+
"Set `flagBaseUrl` once, at the switcher, when flag assets are self-hosted; it is forwarded to every nested `TFlag`.",
|
|
625
|
+
"Wrap with `TFormField` when the switcher sits in a form and needs a label, hint, or error text; drop the wrapper for a bare toolbar or header control."
|
|
626
|
+
]
|
|
627
|
+
}
|
|
628
|
+
],
|
|
629
|
+
practices: [
|
|
630
|
+
{
|
|
631
|
+
id: "interaction-feedback",
|
|
632
|
+
title: "Visual interaction feedback",
|
|
633
|
+
summary: "Every interaction answers back. Hover, focus, active, loading, and disabled are designed states \u2014 never afterthoughts left to the consumer.",
|
|
634
|
+
rules: [
|
|
635
|
+
"Interactive surfaces ship hover, active, and focus-visible treatments out of the box.",
|
|
636
|
+
"Loading states announce themselves (aria-busy, spinner) and block duplicate activation.",
|
|
637
|
+
"Disabled and loading elements never emit activation events.",
|
|
638
|
+
"Focus indicators stay visible in both light and dark themes."
|
|
639
|
+
],
|
|
640
|
+
components: [
|
|
641
|
+
"TButton",
|
|
642
|
+
"TLink",
|
|
643
|
+
"TInput",
|
|
644
|
+
"TSelect",
|
|
645
|
+
"TCheckbox",
|
|
646
|
+
"TSwitch",
|
|
647
|
+
"TTabs",
|
|
648
|
+
"TPagination",
|
|
649
|
+
"TDropdown",
|
|
650
|
+
"TSelectableList"
|
|
651
|
+
]
|
|
652
|
+
},
|
|
653
|
+
{
|
|
654
|
+
id: "accessible-by-default",
|
|
655
|
+
title: "Accessible by default",
|
|
656
|
+
summary: "Native semantics first, ARIA where the pattern requires it, full keyboard support, and focus management the consumer never has to write.",
|
|
657
|
+
rules: [
|
|
658
|
+
'Native elements before roles; role="dialog", aria-modal, aria-labelledby only where semantics require them.',
|
|
659
|
+
"Tab/Shift+Tab order, Escape to close, Enter/Space to activate, arrow keys where the pattern expects them.",
|
|
660
|
+
"Overlays trap focus while open and restore it on close.",
|
|
661
|
+
"Clickable targets stay at or above 44\xD744px."
|
|
662
|
+
],
|
|
663
|
+
components: [
|
|
664
|
+
"TModal",
|
|
665
|
+
"TDrawer",
|
|
666
|
+
"TConfirmDialog",
|
|
667
|
+
"TDropdown",
|
|
668
|
+
"TTooltip",
|
|
669
|
+
"TAccordion",
|
|
670
|
+
"TFormField",
|
|
671
|
+
"TTreeView",
|
|
672
|
+
"TToastProvider"
|
|
673
|
+
]
|
|
674
|
+
},
|
|
675
|
+
{
|
|
676
|
+
id: "predictable-api",
|
|
677
|
+
title: "One predictable API",
|
|
678
|
+
summary: "The same contracts everywhere: one size scale, one action-variant scale, v-model for form controls, open/close for overlays. Learn one component and you know them all.",
|
|
679
|
+
rules: [
|
|
680
|
+
"Sizes are sm | md | lg across the library.",
|
|
681
|
+
"Action variants come from one scale: solid, outline, ghost, soft, danger.",
|
|
682
|
+
"Form controls speak modelValue + update:modelValue (v-model).",
|
|
683
|
+
"Overlays speak open/defaultOpen + update:open/open-change."
|
|
684
|
+
],
|
|
685
|
+
components: [
|
|
686
|
+
"TButton",
|
|
687
|
+
"TInput",
|
|
688
|
+
"TSelect",
|
|
689
|
+
"TBadge",
|
|
690
|
+
"TTag",
|
|
691
|
+
"TCard",
|
|
692
|
+
"TModal"
|
|
693
|
+
]
|
|
694
|
+
},
|
|
695
|
+
{
|
|
696
|
+
id: "state-clarity",
|
|
697
|
+
title: "Empty, loading, and error are designed states",
|
|
698
|
+
summary: "Screens communicate status honestly: skeletons while loading, purposeful empty states, and status surfaces on one semantic tone scale.",
|
|
699
|
+
rules: [
|
|
700
|
+
"Default, hover, active, focus, disabled, loading, and error/empty states are designed and documented \u2014 not just the happy path.",
|
|
701
|
+
"Status tones map to semantic tokens (success, warning, error, info) and pass both themes.",
|
|
702
|
+
"Async feedback is immediate: skeleton or spinner first, toast or alert on completion."
|
|
703
|
+
],
|
|
704
|
+
components: [
|
|
705
|
+
"TSkeleton",
|
|
706
|
+
"TSpinner",
|
|
707
|
+
"TProgress",
|
|
708
|
+
"TEmptyState",
|
|
709
|
+
"TAlert",
|
|
710
|
+
"TToastProvider",
|
|
711
|
+
"TBadge"
|
|
712
|
+
]
|
|
713
|
+
},
|
|
714
|
+
{
|
|
715
|
+
id: "content-alignment",
|
|
716
|
+
title: "Alignment without custom CSS",
|
|
717
|
+
summary: "Layout primitives absorb spacing, alignment, and rhythm so product code never hand-rolls the same flexbox again.",
|
|
718
|
+
rules: [
|
|
719
|
+
"Spacing comes from the --tree-space-* scale, applied by layout components.",
|
|
720
|
+
"Compose TPage, TStack, TGrid, and TSplit before writing a custom layout div.",
|
|
721
|
+
"Forms align through TFormField + TStack + TGrid \u2014 labels, hints, and errors line up by contract.",
|
|
722
|
+
"Reading widths and page gutters come from TContainer/TPage, not local max-widths."
|
|
723
|
+
],
|
|
724
|
+
components: [
|
|
725
|
+
"TStack",
|
|
726
|
+
"TGrid",
|
|
727
|
+
"TSplit",
|
|
728
|
+
"TContainer",
|
|
729
|
+
"TSpacer",
|
|
730
|
+
"TPage",
|
|
731
|
+
"TPageHeader",
|
|
732
|
+
"TFormField"
|
|
733
|
+
]
|
|
734
|
+
},
|
|
735
|
+
{
|
|
736
|
+
id: "token-driven",
|
|
737
|
+
title: "Token-driven clarity",
|
|
738
|
+
summary: "No raw hex, px, or font values anywhere. Every visual decision references a --tree-* token, so light/dark and brand theming stay coherent by construction.",
|
|
739
|
+
rules: [
|
|
740
|
+
"Zero hardcoded colors, spacing, or typography in component code.",
|
|
741
|
+
"Light and dark are first-class themes; every state passes both.",
|
|
742
|
+
"Themes switch by attribute (data-tree-theme) with no component changes."
|
|
743
|
+
],
|
|
744
|
+
components: [
|
|
745
|
+
"TCard",
|
|
746
|
+
"TNavbar",
|
|
747
|
+
"TBadge",
|
|
748
|
+
"TTag",
|
|
749
|
+
"TChart"
|
|
750
|
+
]
|
|
575
751
|
}
|
|
576
752
|
],
|
|
577
753
|
setup: {
|
|
@@ -646,6 +822,43 @@ var treeui_catalog_default = {
|
|
|
646
822
|
"Use `maxVisibleTags` to control trigger density in compact layouts."
|
|
647
823
|
]
|
|
648
824
|
},
|
|
825
|
+
TFlag: {
|
|
826
|
+
required: [
|
|
827
|
+
"Pass `code` as an ISO 3166-1 alpha-2 country code. Matching is case-insensitive \u2014 the value is trimmed and lowercased internally.",
|
|
828
|
+
"Allow `https://flagcdn.com` in the app `Content-Security-Policy` `img-src` directive, or point `baseUrl` at a self-hosted mirror \u2014 flag images are fetched from a third-party CDN at runtime."
|
|
829
|
+
],
|
|
830
|
+
notes: [
|
|
831
|
+
"A mirror must serve `{baseUrl}/{segment}/{code}.png` for both steps of every size: 1x `h20` (sm), `h20` (md), `h24` (lg); 2x `h40` (sm), `h40` (md), `h60` (lg). The 2x asset is emitted through `srcset`.",
|
|
832
|
+
"Those fixed-height segments are part of the contract, and they are the CDN's flat artwork \u2014 a mirror must serve flat flags, not the waving ones.",
|
|
833
|
+
"Do not substitute the CDN's ratio-normalised width-by-height endpoints. They equalise aspect ratio only by switching to the waving artwork, which reads as decoration next to flat UI icons.",
|
|
834
|
+
"The fixed-height assets keep each flag's true proportions \u2014 Nepal is a pennant, Switzerland is square, Qatar is elongated. A shared height, not a shared ratio, is what aligns a column of flags.",
|
|
835
|
+
"CSS puts the image in a fixed 3:2 box (3:2 being the most common national flag ratio) with `object-fit: contain`, so outliers centre inside the box instead of being cropped or distorted.",
|
|
836
|
+
"Each retina segment is at least twice its box height \u2014 boxes are `--tree-size-icon-sm/md/lg` = 16px/20px/24px \u2014 so 2x screens never upscale.",
|
|
837
|
+
"`baseUrl` may be written with or without a trailing slash; trailing slashes are stripped before the path is built. An unknown `size` falls back to the `md` assets.",
|
|
838
|
+
"When the image cannot load \u2014 offline, blocked by CSP, unknown code \u2014 the component renders the uppercased `code` as text. Override that text with `fallbackText`.",
|
|
839
|
+
"The flag is `aria-hidden` by default. Pass `label` only when the flag carries meaning on its own; beside a visible country or language name it should stay decorative."
|
|
840
|
+
]
|
|
841
|
+
},
|
|
842
|
+
TLanguageSelect: {
|
|
843
|
+
required: [
|
|
844
|
+
"Pass `options` as `{ label, value, code?, description?, disabled? }[]`. TreeUI ships no language, locale, or country dataset \u2014 the app owns its language list.",
|
|
845
|
+
"Apply locale side effects (i18n locale, `lang` attribute, persistence) in the app layer; the component only reports the selected `value`.",
|
|
846
|
+
"Pass an `aria-label` whenever `iconOnly` is set \u2014 the visible language name is gone, so it is the control's only accessible name. It also labels the listbox."
|
|
847
|
+
],
|
|
848
|
+
notes: [
|
|
849
|
+
"`variant` is `field` (default) or `switcher`, typed as `TLanguageSelectVariant` and exported from `@treeui/vue`.",
|
|
850
|
+
'Use `variant="field"` inside a form, next to other inputs, or wrapped in `TFormField`: the flag leads the trigger, the trigger fills its container, and `width` applies. A visible field label already says what the control changes.',
|
|
851
|
+
'Use `variant="switcher"` for a page-level control in a navbar or app bar, where nothing nearby labels it. A translate icon (`TIcon name="languages"`) leads and the current flag trails before the chevron, so the control reads as "page language, now set to this" without an external label.',
|
|
852
|
+
"A switcher sizes to its content, so `width` does not apply, and its listbox aligns to the trigger's right edge.",
|
|
853
|
+
"`iconOnly` is switcher-only and drops the visible language name, leaving the translate icon and the current flag.",
|
|
854
|
+
"`value` is an opaque application key, typically a BCP-47 tag such as `pt-BR`. TreeUI never parses or validates it.",
|
|
855
|
+
"`code` is the ISO 3166-1 alpha-2 code used for the option flag. Omit it to render the option without a flag \u2014 a language is not a country, so many entries have no honest flag.",
|
|
856
|
+
"Use `description` for a secondary line such as the endonym.",
|
|
857
|
+
"Set `flagBaseUrl` once on the select rather than per option; it is forwarded to every nested `TFlag`.",
|
|
858
|
+
"Bind `modelValue` to a `string`, and use `v-model:open` when the app controls open state.",
|
|
859
|
+
"The CDN and Content-Security-Policy requirements under `TFlag` apply whenever any option carries a `code`."
|
|
860
|
+
]
|
|
861
|
+
},
|
|
649
862
|
TToggleGroup: {
|
|
650
863
|
required: [],
|
|
651
864
|
notes: [
|
|
@@ -695,7 +908,20 @@ var treeui_catalog_default = {
|
|
|
695
908
|
TNavMenu: {
|
|
696
909
|
required: [],
|
|
697
910
|
notes: [
|
|
698
|
-
"When nested inside `TSidebar` or `TAppShell`, `collapsed` can be inherited from the sidebar provider."
|
|
911
|
+
"When nested inside `TSidebar` or `TAppShell`, `collapsed` can be inherited from the sidebar provider.",
|
|
912
|
+
"Pass `items` as `{ label, value, icon?, to?, badge?, description?, shortLabel?, disabled?, exact? }[]`.",
|
|
913
|
+
"`icon` is `TIconInput` \u2014 a registered icon name (`icon: 'layout-dashboard'`) or a component. Use the name: it needs no import, and no `markRaw` when the item list is reactive.",
|
|
914
|
+
"An item with no icon, or with a name that is not registered, shows a letter marker instead. That marker is also all a collapsed rail can show, so give every item an icon when the sidebar collapses.",
|
|
915
|
+
"Register any icon the app needs beyond the built-ins first \u2014 see `icons` above."
|
|
916
|
+
]
|
|
917
|
+
},
|
|
918
|
+
TIcon: {
|
|
919
|
+
required: [
|
|
920
|
+
"Use a registered name: one of the built-ins, or one the app added with `registerTreeIcons`. See `icons` above."
|
|
921
|
+
],
|
|
922
|
+
notes: [
|
|
923
|
+
'`size` is a pixel count, not `sm | md | lg`. Passing `size="md"` renders an unsized svg.',
|
|
924
|
+
"The icon is `aria-hidden` by default. Pass `label` only when the icon carries meaning on its own; beside visible text it should stay decorative."
|
|
699
925
|
]
|
|
700
926
|
},
|
|
701
927
|
TTreeView: {
|
|
@@ -767,6 +993,7 @@ var treeui_catalog_default = {
|
|
|
767
993
|
],
|
|
768
994
|
commonCompositions: [
|
|
769
995
|
"TFormField + input-like control",
|
|
996
|
+
"TFormField + TLanguageSelect",
|
|
770
997
|
"TGrid + TStat",
|
|
771
998
|
"TStat + TSparkline",
|
|
772
999
|
"TCard + TChart",
|
|
@@ -790,15 +1017,83 @@ var treeui_catalog_default = {
|
|
|
790
1017
|
storyFile: "apps/docs/src/stories/Accordion.stories.ts",
|
|
791
1018
|
storyTitle: "Components/Data Display/Accordion",
|
|
792
1019
|
manifestFile: "docs/ai/COMPONENTS/accordion.yaml",
|
|
793
|
-
props: [
|
|
794
|
-
|
|
795
|
-
|
|
1020
|
+
props: [
|
|
1021
|
+
{
|
|
1022
|
+
name: "type",
|
|
1023
|
+
type: "'single' | 'multiple'",
|
|
1024
|
+
default: "'single'",
|
|
1025
|
+
values: [
|
|
1026
|
+
"single",
|
|
1027
|
+
"multiple"
|
|
1028
|
+
],
|
|
1029
|
+
description: "single \u2013 at most one item open at a time (opening one closes the rest). multiple \u2013 any number of items may be open simultaneously.\n"
|
|
1030
|
+
},
|
|
1031
|
+
{
|
|
1032
|
+
name: "modelValue",
|
|
1033
|
+
type: "string | string[] | undefined",
|
|
1034
|
+
default: "undefined",
|
|
1035
|
+
description: 'Controlled open state. For type="single" pass a string (the item value). For type="multiple" pass an array of strings. The accordion treats itself as controlled only while modelValue !== undefined; passing undefined leaves it uncontrolled and it falls back to its internal state.\n'
|
|
1036
|
+
},
|
|
1037
|
+
{
|
|
1038
|
+
name: "defaultValue",
|
|
1039
|
+
type: "string | string[] | undefined",
|
|
1040
|
+
default: "undefined",
|
|
1041
|
+
description: "Initial open state for uncontrolled usage. Read once when the accordion is created \u2014 changing it after mount has no effect. Ignored while modelValue is set. Do not combine it with modelValue: see notes.\n"
|
|
1042
|
+
},
|
|
1043
|
+
{
|
|
1044
|
+
name: "disabled",
|
|
1045
|
+
type: "boolean",
|
|
1046
|
+
default: "false",
|
|
1047
|
+
description: "Disables all items. OR-ed with each item's own disabled prop, so an item is disabled when either is true. Provided to items as a computed ref, so flipping it after mount updates every item.\n"
|
|
1048
|
+
},
|
|
1049
|
+
{
|
|
1050
|
+
name: "collapsible",
|
|
1051
|
+
type: "boolean",
|
|
1052
|
+
default: "false",
|
|
1053
|
+
description: 'Only applies when type="single". When true, the open item can be collapsed by clicking its trigger again, which emits undefined. When false, clicking the already-open trigger is a no-op and emits nothing. In type="multiple" any item can always be collapsed and this prop is ignored.\n'
|
|
1054
|
+
}
|
|
1055
|
+
],
|
|
1056
|
+
events: [
|
|
1057
|
+
{
|
|
1058
|
+
name: "update:modelValue",
|
|
1059
|
+
description: 'Emitted when the open state changes (v-model support). type="single" emits the open item value as a string, or undefined when it is collapsed. type="multiple" always emits a string[] of the open values.\n',
|
|
1060
|
+
payload: "string | string[] | undefined"
|
|
1061
|
+
}
|
|
1062
|
+
],
|
|
1063
|
+
slots: [
|
|
1064
|
+
{
|
|
1065
|
+
name: "default",
|
|
1066
|
+
description: "Accepts TAccordionItem children."
|
|
1067
|
+
}
|
|
1068
|
+
],
|
|
796
1069
|
a11y: [
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
1070
|
+
"container_is_a_plain_div_with_no_aria_role: true",
|
|
1071
|
+
"trigger_is_a_heading_wrapped_native_button: h3 > button",
|
|
1072
|
+
"aria_expanded_on_trigger_reflects_open_state: true",
|
|
1073
|
+
"aria_controls_on_trigger_references_panel_id: true",
|
|
1074
|
+
"panel_uses_role_region: true",
|
|
1075
|
+
"aria_labelledby_on_panel_references_trigger_id: true",
|
|
1076
|
+
"disabled_items_use_the_native_disabled_attribute: true",
|
|
1077
|
+
"chevron_icon_is_aria_hidden: true",
|
|
1078
|
+
"trigger_hit_area_is_at_least_44px: via the .t-accordion__trigger::after overlay",
|
|
1079
|
+
"enter_space_toggle_the_focused_item: native button activation",
|
|
1080
|
+
"arrow_down_focuses_next_enabled_trigger_wrapping_to_first: true",
|
|
1081
|
+
"arrow_up_focuses_previous_enabled_trigger_wrapping_to_last: true",
|
|
1082
|
+
"home_focuses_first_enabled_trigger: true",
|
|
1083
|
+
"end_focuses_last_enabled_trigger: true"
|
|
1084
|
+
],
|
|
1085
|
+
behavior: [
|
|
1086
|
+
"controlled_only_while_model_value_is_not_undefined: true",
|
|
1087
|
+
"default_value_seeds_uncontrolled_state_once: true",
|
|
1088
|
+
"single_mode_opening_an_item_closes_the_previous_one: true",
|
|
1089
|
+
"single_mode_collapsing_requires_collapsible: true",
|
|
1090
|
+
"multiple_mode_ignores_collapsible: true",
|
|
1091
|
+
"container_and_item_disabled_are_combined_with_or: true",
|
|
1092
|
+
"arrow_navigation_skips_disabled_triggers: true",
|
|
1093
|
+
"arrow_navigation_wraps_around: true",
|
|
1094
|
+
"trigger_order_follows_item_mount_order: true",
|
|
1095
|
+
"only_open_panels_are_rendered: true"
|
|
800
1096
|
],
|
|
801
|
-
behavior: [],
|
|
802
1097
|
selection: {
|
|
803
1098
|
keywords: [
|
|
804
1099
|
"accordion",
|
|
@@ -829,7 +1124,10 @@ var treeui_catalog_default = {
|
|
|
829
1124
|
required: [],
|
|
830
1125
|
notes: []
|
|
831
1126
|
},
|
|
832
|
-
recipes: []
|
|
1127
|
+
recipes: [],
|
|
1128
|
+
practices: [
|
|
1129
|
+
"accessible-by-default"
|
|
1130
|
+
]
|
|
833
1131
|
},
|
|
834
1132
|
{
|
|
835
1133
|
name: "TAlert",
|
|
@@ -846,14 +1144,15 @@ var treeui_catalog_default = {
|
|
|
846
1144
|
props: [
|
|
847
1145
|
{
|
|
848
1146
|
name: "variant",
|
|
849
|
-
type: "
|
|
1147
|
+
type: "TAlertVariant",
|
|
850
1148
|
default: "info",
|
|
851
1149
|
values: [
|
|
852
1150
|
"info",
|
|
853
1151
|
"success",
|
|
854
1152
|
"warning",
|
|
855
1153
|
"danger"
|
|
856
|
-
]
|
|
1154
|
+
],
|
|
1155
|
+
description: "Semantic tone. Sets the --tree-alert-* custom properties that colour the surface, border, icon, and dismiss button."
|
|
857
1156
|
},
|
|
858
1157
|
{
|
|
859
1158
|
name: "size",
|
|
@@ -863,42 +1162,55 @@ var treeui_catalog_default = {
|
|
|
863
1162
|
"sm",
|
|
864
1163
|
"md",
|
|
865
1164
|
"lg"
|
|
866
|
-
]
|
|
1165
|
+
],
|
|
1166
|
+
description: "Adjusts padding and font size only. md is the baseline defined on .t-alert itself."
|
|
867
1167
|
},
|
|
868
1168
|
{
|
|
869
1169
|
name: "dismissible",
|
|
870
1170
|
type: "boolean",
|
|
871
|
-
default: "false"
|
|
1171
|
+
default: "false",
|
|
1172
|
+
description: "Renders the trailing dismiss button. The button is the only thing gated by this prop; the alert never hides itself."
|
|
872
1173
|
}
|
|
873
1174
|
],
|
|
874
1175
|
events: [
|
|
875
1176
|
{
|
|
876
1177
|
name: "dismiss",
|
|
877
|
-
description: "Emitted when the dismiss button is clicked.",
|
|
1178
|
+
description: "Emitted when the dismiss button is clicked. TAlert is stateless \u2014 it does not hide, unmount, or animate itself out. The consumer owns removal (v-if, a list splice, or a store flag); without a handler the button is inert.\n",
|
|
878
1179
|
payload: "none"
|
|
879
1180
|
}
|
|
880
1181
|
],
|
|
881
1182
|
slots: [
|
|
882
1183
|
{
|
|
883
1184
|
name: "default",
|
|
884
|
-
description: "Alert message content."
|
|
1185
|
+
description: "Alert message content, rendered inside .t-alert__content."
|
|
885
1186
|
},
|
|
886
1187
|
{
|
|
887
1188
|
name: "icon",
|
|
888
|
-
description:
|
|
1189
|
+
description: 'Optional leading icon. The .t-alert__icon wrapper span is rendered only when the slot is provided (v-if="$slots.icon") and is marked aria-hidden, so the icon is decorative \u2014 never put meaning there that is not also in the message text. The wrapper inherits the variant colour via --tree-alert-accent.\n'
|
|
889
1190
|
},
|
|
890
1191
|
{
|
|
891
1192
|
name: "dismiss-icon",
|
|
892
|
-
description:
|
|
1193
|
+
description: 'Replaces the default 16x16 \xD7 SVG inside the dismiss button. Rendered only when dismissible is true, since the slot lives inside the button. Has a working default, so it is optional. The button keeps its aria-label="Dismiss" regardless of content.\n'
|
|
893
1194
|
}
|
|
894
1195
|
],
|
|
895
1196
|
a11y: [
|
|
896
1197
|
"role: alert",
|
|
1198
|
+
"role_is_on_root_element: true",
|
|
897
1199
|
"icon_slot_marked_aria_hidden: true",
|
|
1200
|
+
"default_dismiss_icon_marked_aria_hidden: true",
|
|
898
1201
|
"dismiss_button_aria_label: Dismiss",
|
|
899
|
-
"
|
|
1202
|
+
"dismiss_button_label_is_hardcoded: true",
|
|
1203
|
+
"dismiss_button_hit_area: 44x44 via a .t-alert__dismiss::after pseudo-element; the visible button is 1.5rem.",
|
|
1204
|
+
"keyboard: Tab to dismiss button, Enter/Space to activate",
|
|
1205
|
+
'live_region_caveat: role="alert" is an assertive live region. An alert that is already in the DOM on first paint is generally not announced \u2014 mount it dynamically (v-if / list insert) when you need the message read out.'
|
|
1206
|
+
],
|
|
1207
|
+
behavior: [
|
|
1208
|
+
"self_removes_on_dismiss: false",
|
|
1209
|
+
"icon_wrapper_rendered_only_when_icon_slot_provided: true",
|
|
1210
|
+
"dismiss_button_rendered_only_when_dismissible: true",
|
|
1211
|
+
"size_md_emits_class_without_css_rule: t-alert--md is always emitted but carries no CSS rule of its own; .t-alert is the md baseline and only --sm and --lg override padding and font size.",
|
|
1212
|
+
'variant_sets_local_custom_properties: ["--tree-alert-bg","--tree-alert-border","--tree-alert-text","--tree-alert-accent"]'
|
|
900
1213
|
],
|
|
901
|
-
behavior: [],
|
|
902
1214
|
selection: {
|
|
903
1215
|
keywords: [
|
|
904
1216
|
"alert",
|
|
@@ -929,7 +1241,10 @@ var treeui_catalog_default = {
|
|
|
929
1241
|
required: [],
|
|
930
1242
|
notes: []
|
|
931
1243
|
},
|
|
932
|
-
recipes: []
|
|
1244
|
+
recipes: [],
|
|
1245
|
+
practices: [
|
|
1246
|
+
"state-clarity"
|
|
1247
|
+
]
|
|
933
1248
|
},
|
|
934
1249
|
{
|
|
935
1250
|
name: "TAppShell",
|
|
@@ -947,7 +1262,8 @@ var treeui_catalog_default = {
|
|
|
947
1262
|
{
|
|
948
1263
|
name: "as",
|
|
949
1264
|
type: "string",
|
|
950
|
-
default: "div"
|
|
1265
|
+
default: "div",
|
|
1266
|
+
note: "Tag or component rendered as the shell root. The root is a plain `div` by default and is therefore not a landmark \u2014 the header/sidebar/main regions carry the semantics."
|
|
951
1267
|
},
|
|
952
1268
|
{
|
|
953
1269
|
name: "side",
|
|
@@ -961,164 +1277,254 @@ var treeui_catalog_default = {
|
|
|
961
1277
|
{
|
|
962
1278
|
name: "sidebarWidth",
|
|
963
1279
|
type: "string",
|
|
964
|
-
default: "17.5rem"
|
|
1280
|
+
default: "17.5rem",
|
|
1281
|
+
note: "Any CSS length. Sets `--tree-app-shell-sidebar-width` on the root, which drives the desktop rail track and also caps the mobile drawer at `min(100%, sidebarWidth)`."
|
|
965
1282
|
},
|
|
966
1283
|
{
|
|
967
1284
|
name: "collapsedWidth",
|
|
968
1285
|
type: "string",
|
|
969
|
-
default: "4.75rem"
|
|
1286
|
+
default: "4.75rem",
|
|
1287
|
+
note: "Any CSS length. Sets `--tree-app-shell-collapsed-width` on the root, but it only takes effect while the root carries `is-collapsed` (desktop + `collapsible` + collapsed)."
|
|
970
1288
|
},
|
|
971
1289
|
{
|
|
972
1290
|
name: "collapsible",
|
|
973
1291
|
type: "boolean",
|
|
974
|
-
default: "false"
|
|
1292
|
+
default: "false",
|
|
1293
|
+
note: "Master gate for the desktop rail. While false the root never gets `is-collapsed`, the built-in collapse toggle is not rendered, and `toggleCollapsed` is a no-op."
|
|
975
1294
|
},
|
|
976
1295
|
{
|
|
977
1296
|
name: "collapsed",
|
|
978
1297
|
type: "boolean",
|
|
979
|
-
default: "undefined"
|
|
1298
|
+
default: "undefined",
|
|
1299
|
+
note: "Controlled desktop rail state (v-model:collapsed). Leave undefined for uncontrolled. When set, the component only emits \u2014 the parent must apply the new value."
|
|
980
1300
|
},
|
|
981
1301
|
{
|
|
982
1302
|
name: "defaultCollapsed",
|
|
983
1303
|
type: "boolean",
|
|
984
|
-
default: "false"
|
|
1304
|
+
default: "false",
|
|
1305
|
+
note: "Initial value for uncontrolled use. Read once during setup; later changes to the prop are ignored."
|
|
985
1306
|
},
|
|
986
1307
|
{
|
|
987
1308
|
name: "mobile",
|
|
988
1309
|
type: "boolean",
|
|
989
|
-
default: "undefined"
|
|
1310
|
+
default: "undefined",
|
|
1311
|
+
note: "Forces mobile mode when explicitly true or false. Leave undefined to auto-detect from `breakpoint`."
|
|
990
1312
|
},
|
|
991
1313
|
{
|
|
992
1314
|
name: "breakpoint",
|
|
993
1315
|
type: "string",
|
|
994
|
-
default: "768px"
|
|
1316
|
+
default: "768px",
|
|
1317
|
+
note: "Any CSS length. Evaluated as `(max-width: <breakpoint>)` via matchMedia, and only consulted while `mobile` is undefined. Changing it tears down and rebuilds the media query listener."
|
|
995
1318
|
},
|
|
996
1319
|
{
|
|
997
1320
|
name: "sidebarOpen",
|
|
998
1321
|
type: "boolean",
|
|
999
|
-
default: "undefined"
|
|
1322
|
+
default: "undefined",
|
|
1323
|
+
note: "Controlled off-canvas drawer state (v-model:sidebarOpen). Mobile-only \u2014 the flag is tracked in desktop mode but nothing renders from it."
|
|
1000
1324
|
},
|
|
1001
1325
|
{
|
|
1002
1326
|
name: "defaultSidebarOpen",
|
|
1003
1327
|
type: "boolean",
|
|
1004
|
-
default: "false"
|
|
1328
|
+
default: "false",
|
|
1329
|
+
note: "Initial value for uncontrolled use. Read once during setup."
|
|
1330
|
+
},
|
|
1331
|
+
{
|
|
1332
|
+
name: "immersive",
|
|
1333
|
+
type: "boolean",
|
|
1334
|
+
default: "undefined",
|
|
1335
|
+
note: "Controlled immersive state (v-model:immersive). Hides the header and sidebar so the content fills the viewport. The chrome is hidden with CSS rather than unmounted, so toggling never remounts the default slot. While immersive, the mobile drawer is not rendered."
|
|
1336
|
+
},
|
|
1337
|
+
{
|
|
1338
|
+
name: "defaultImmersive",
|
|
1339
|
+
type: "boolean",
|
|
1340
|
+
default: "false",
|
|
1341
|
+
note: "Initial value for uncontrolled use. Read once during setup."
|
|
1005
1342
|
},
|
|
1006
1343
|
{
|
|
1007
1344
|
name: "closeOnEscape",
|
|
1008
1345
|
type: "boolean",
|
|
1009
|
-
default: "true"
|
|
1346
|
+
default: "true",
|
|
1347
|
+
note: "Drawer only. Escape is handled on the drawer surface, so it fires only while focus is inside the drawer."
|
|
1010
1348
|
},
|
|
1011
1349
|
{
|
|
1012
1350
|
name: "closeOnOverlay",
|
|
1013
1351
|
type: "boolean",
|
|
1014
|
-
default: "true"
|
|
1352
|
+
default: "true",
|
|
1353
|
+
note: "Drawer only. Set false to keep the drawer open on backdrop clicks."
|
|
1015
1354
|
},
|
|
1016
1355
|
{
|
|
1017
1356
|
name: "showMenuButton",
|
|
1018
1357
|
type: "boolean",
|
|
1019
|
-
default: "true"
|
|
1358
|
+
default: "true",
|
|
1359
|
+
note: "Renders the built-in hamburger in the header. Mobile only. Set false to supply your own trigger and call the `toggleSidebar` slot prop from the `header` or `header-start` slot."
|
|
1020
1360
|
},
|
|
1021
1361
|
{
|
|
1022
1362
|
name: "showCollapseButton",
|
|
1023
1363
|
type: "boolean",
|
|
1024
1364
|
default: "true",
|
|
1025
|
-
note: "Renders the built-in collapse toggle in the sidebar footer. Desktop only, and only when `collapsible` is set \u2014 no need to wire your own."
|
|
1365
|
+
note: "Renders the built-in collapse toggle in the sidebar footer. Desktop only, and only when `collapsible` is set \u2014 no need to wire your own. Never rendered in the mobile drawer."
|
|
1026
1366
|
},
|
|
1027
1367
|
{
|
|
1028
1368
|
name: "collapseLabel",
|
|
1029
1369
|
type: "string",
|
|
1030
|
-
default: "Collapse sidebar"
|
|
1370
|
+
default: "Collapse sidebar",
|
|
1371
|
+
note: "aria-label of the collapse toggle while the rail is expanded."
|
|
1031
1372
|
},
|
|
1032
1373
|
{
|
|
1033
1374
|
name: "expandLabel",
|
|
1034
1375
|
type: "string",
|
|
1035
|
-
default: "Expand sidebar"
|
|
1376
|
+
default: "Expand sidebar",
|
|
1377
|
+
note: "aria-label of the collapse toggle while the rail is collapsed."
|
|
1036
1378
|
},
|
|
1037
1379
|
{
|
|
1038
1380
|
name: "menuLabel",
|
|
1039
1381
|
type: "string",
|
|
1040
|
-
default: "Open menu"
|
|
1382
|
+
default: "Open menu",
|
|
1383
|
+
note: "aria-label of the built-in hamburger. Static \u2014 it does not swap to a close label while the drawer is open."
|
|
1041
1384
|
},
|
|
1042
1385
|
{
|
|
1043
1386
|
name: "closeLabel",
|
|
1044
1387
|
type: "string",
|
|
1045
|
-
default: "Close menu"
|
|
1388
|
+
default: "Close menu",
|
|
1389
|
+
note: "aria-label of the drawer's close button."
|
|
1046
1390
|
},
|
|
1047
1391
|
{
|
|
1048
1392
|
name: "sidebarLabel",
|
|
1049
1393
|
type: "string",
|
|
1050
|
-
default: "Sidebar"
|
|
1394
|
+
default: "Sidebar",
|
|
1395
|
+
note: "aria-label applied to both the desktop <aside> and the drawer <aside>."
|
|
1051
1396
|
}
|
|
1052
1397
|
],
|
|
1053
1398
|
events: [
|
|
1054
1399
|
{
|
|
1055
|
-
name: "update:collapsed"
|
|
1400
|
+
name: "update:collapsed",
|
|
1401
|
+
description: "Desktop rail collapsed state changed. Enables v-model:collapsed.",
|
|
1402
|
+
payload: "[value: boolean]"
|
|
1056
1403
|
},
|
|
1057
1404
|
{
|
|
1058
|
-
name: "collapse-change"
|
|
1405
|
+
name: "collapse-change",
|
|
1406
|
+
description: "Same change as update:collapsed, for non-v-model usage. Both always fire together.",
|
|
1407
|
+
payload: "[value: boolean]"
|
|
1408
|
+
},
|
|
1409
|
+
{
|
|
1410
|
+
name: "update:sidebarOpen",
|
|
1411
|
+
description: "Off-canvas drawer open state changed. Enables v-model:sidebarOpen.",
|
|
1412
|
+
payload: "[value: boolean]"
|
|
1059
1413
|
},
|
|
1060
1414
|
{
|
|
1061
|
-
name: "
|
|
1415
|
+
name: "sidebar-open-change",
|
|
1416
|
+
description: "Same change as update:sidebarOpen, for non-v-model usage. Both always fire together.",
|
|
1417
|
+
payload: "[value: boolean]"
|
|
1418
|
+
},
|
|
1419
|
+
{
|
|
1420
|
+
name: "update:immersive",
|
|
1421
|
+
description: "Immersive state changed. Enables v-model:immersive.",
|
|
1422
|
+
payload: "[value: boolean]"
|
|
1062
1423
|
},
|
|
1063
1424
|
{
|
|
1064
|
-
name: "
|
|
1425
|
+
name: "immersive-change",
|
|
1426
|
+
description: "Same change as update:immersive, for non-v-model usage. Both always fire together.",
|
|
1427
|
+
payload: "[value: boolean]"
|
|
1065
1428
|
}
|
|
1066
1429
|
],
|
|
1067
1430
|
slots: [
|
|
1068
1431
|
{
|
|
1069
|
-
name: "header"
|
|
1432
|
+
name: "header",
|
|
1433
|
+
description: "Main header region. Spans the full header width by default; once `header-start` is filled it is constrained to the content column so it lines up with the panel underneath. On mobile the header falls back to a single flex row either way.\n",
|
|
1434
|
+
note: "AppShellSlotProps \u2014 { mobile, collapsed, sidebarOpen, immersive, toggleSidebar, closeSidebar, toggleCollapsed, toggleImmersive }"
|
|
1070
1435
|
},
|
|
1071
1436
|
{
|
|
1072
|
-
name: "header-start"
|
|
1437
|
+
name: "header-start",
|
|
1438
|
+
description: "Header region sitting over the sidebar rail (typically the brand mark). Filling it adds `has-start` to the header, which switches the header to the shell's own two-column grid and tracks the rail width as it collapses.\n",
|
|
1439
|
+
note: "AppShellSlotProps"
|
|
1073
1440
|
},
|
|
1074
1441
|
{
|
|
1075
|
-
name: "sidebar-header"
|
|
1442
|
+
name: "sidebar-header",
|
|
1443
|
+
description: "Pinned above the sidebar body, inset to line up with nav item icons. Rendered in both the desktop aside and the mobile drawer.\n",
|
|
1444
|
+
note: "AppShellSlotProps"
|
|
1076
1445
|
},
|
|
1077
1446
|
{
|
|
1078
|
-
name: "sidebar"
|
|
1447
|
+
name: "sidebar",
|
|
1448
|
+
description: "Sidebar body \u2014 the natural home for a TNavMenu, which picks up the collapsed state through provide/inject. Rendered in both the desktop aside and the mobile drawer, and takes the vertical slack so the footer pins to the bottom.\n",
|
|
1449
|
+
note: "AppShellSlotProps"
|
|
1079
1450
|
},
|
|
1080
1451
|
{
|
|
1081
|
-
name: "sidebar-footer"
|
|
1452
|
+
name: "sidebar-footer",
|
|
1453
|
+
description: "Pinned to the bottom of the sidebar, inset to line up with nav item icons. In the desktop aside it shares one container with the built-in collapse toggle, which is rendered after the slot content; in the mobile drawer the container holds the slot content alone.\n",
|
|
1454
|
+
note: "AppShellSlotProps"
|
|
1082
1455
|
},
|
|
1083
1456
|
{
|
|
1084
|
-
name: "default"
|
|
1457
|
+
name: "default",
|
|
1458
|
+
description: "Main content area. Scrolls independently of the header and sidebar.",
|
|
1459
|
+
note: "{ mobile: boolean, collapsed: boolean, immersive: boolean, toggleImmersive: () => void } \u2014 a subset of AppShellSlotProps. toggleImmersive is included because immersive hides the chrome, so the content is the only place an exit control can live."
|
|
1085
1460
|
},
|
|
1086
1461
|
{
|
|
1087
|
-
name: "menu-icon"
|
|
1462
|
+
name: "menu-icon",
|
|
1463
|
+
description: "Replaces the default hamburger glyph inside the built-in menu button. Use `sidebarOpen` to swap the icon while the drawer is open. Renders inside the button, so it must be presentational only.\n",
|
|
1464
|
+
note: "{ sidebarOpen: boolean }"
|
|
1088
1465
|
},
|
|
1089
1466
|
{
|
|
1090
|
-
name: "collapse-icon"
|
|
1467
|
+
name: "collapse-icon",
|
|
1468
|
+
description: "Replaces the default glyph inside the built-in collapse toggle. Renders inside the button, so it must be presentational only.\n",
|
|
1469
|
+
note: "{ collapsed: boolean }"
|
|
1091
1470
|
}
|
|
1092
1471
|
],
|
|
1093
1472
|
a11y: [
|
|
1094
|
-
"
|
|
1473
|
+
"semantic_regions: <header>, <aside> and <main>; the shell root itself is a plain div and is not a landmark",
|
|
1474
|
+
"role: dialog \u2014 on the mobile drawer only",
|
|
1095
1475
|
"aria_modal: true",
|
|
1096
|
-
"focus_trap:
|
|
1097
|
-
"restores_focus_on_close:
|
|
1476
|
+
"focus_trap: Tab and Shift+Tab cycle inside the drawer; with no focusable descendant, focus is pinned to the drawer itself",
|
|
1477
|
+
"restores_focus_on_close: only when the drawer was opened through the built-in menu button or the toggleSidebar slot prop \u2014 those capture document.activeElement first",
|
|
1098
1478
|
"escape_closes_when_enabled: true",
|
|
1099
1479
|
"menu_button_aria_expanded: true",
|
|
1100
|
-
"menu_button_aria_controls_drawer:
|
|
1101
|
-
"
|
|
1480
|
+
"menu_button_aria_controls_drawer: aria-controls always points at the sidebar id, and on mobile that element exists only while the drawer is open",
|
|
1481
|
+
"collapse_button_aria_expanded: reflects the expanded rail, i.e. !collapsed",
|
|
1482
|
+
"collapse_button_aria_controls_sidebar: true",
|
|
1483
|
+
"collapse_button_label_swaps_by_state: collapseLabel while expanded, expandLabel while collapsed",
|
|
1484
|
+
"drawer_close_button_labelled_by_close_label: true",
|
|
1485
|
+
"sidebar_labelled_by_sidebar_label: true",
|
|
1486
|
+
"drawer_focusable_via_tabindex_minus_one: true",
|
|
1487
|
+
"backdrop_is_aria_hidden: true",
|
|
1488
|
+
"built_in_icons_are_aria_hidden: true",
|
|
1489
|
+
"menu_and_drawer_close_buttons_are_44px: true"
|
|
1102
1490
|
],
|
|
1103
1491
|
behavior: [
|
|
1104
1492
|
"fills_viewport_full_width_and_height: true",
|
|
1493
|
+
"resets_body_margin_while_a_shell_is_mounted: body:has(.t-app-shell) { margin: 0 } \u2014 a deliberate global rule, scoped so it only applies to pages that mount a shell",
|
|
1105
1494
|
"header_spans_full_width_above_sidebar_and_content: true",
|
|
1106
1495
|
"content_area_scrolls_independently: true",
|
|
1107
1496
|
"auto_switches_to_mobile_at_breakpoint_when_mobile_undefined: true",
|
|
1108
1497
|
"mobile_prop_forces_mobile_mode: true",
|
|
1109
1498
|
"mobile_sidebar_becomes_off_canvas_drawer: true",
|
|
1499
|
+
"desktop_sidebar_is_removed_from_the_dom_on_mobile: crossing the breakpoint unmounts and remounts the sidebar slot, so component state inside it is not preserved",
|
|
1500
|
+
"drawer_is_rendered_only_while_mobile_and_open: true",
|
|
1110
1501
|
"auto_menu_button_in_header_on_mobile: true",
|
|
1111
1502
|
"controlled_and_uncontrolled_collapsed_state: true",
|
|
1112
1503
|
"controlled_and_uncontrolled_sidebar_open_state: true",
|
|
1504
|
+
"controlled_and_uncontrolled_immersive_state: true",
|
|
1505
|
+
"immersive_hides_chrome_without_remounting_content: the header and sidebar are hidden with CSS and the grid collapses to a single `main` area, so the default slot keeps its component state across the toggle \u2014 unlike the mobile breakpoint, which does remount the sidebar slot",
|
|
1506
|
+
"immersive_suppresses_the_mobile_drawer: while immersive the overlay is not rendered, since the trigger that opens it lives in the hidden header",
|
|
1507
|
+
"controlled_mode_does_not_self_update: when collapsed, sidebarOpen or immersive is bound, the component only emits \u2014 the parent must apply the value",
|
|
1508
|
+
"no_emit_when_the_value_is_unchanged: true",
|
|
1509
|
+
"toggle_collapsed_is_a_noop_when_collapsible_is_false: true",
|
|
1510
|
+
"collapse_toggle_requires_desktop_and_collapsible_and_show_collapse_button: true",
|
|
1113
1511
|
"provides_collapsed_state_to_descendants: true",
|
|
1114
1512
|
"drawer_reports_collapsed_false_to_descendants_and_slots: true",
|
|
1115
1513
|
"left_and_right_variants: true",
|
|
1116
1514
|
"locks_body_scroll_while_drawer_open: true",
|
|
1515
|
+
"releases_the_scroll_lock_when_leaving_mobile_while_open: true",
|
|
1516
|
+
"rearms_the_overlay_when_reentering_mobile_while_open: true",
|
|
1117
1517
|
"overlay_click_closes_when_enabled: true",
|
|
1118
1518
|
"exposes_slot_props_with_mobile_collapsed_and_toggles: true",
|
|
1119
1519
|
"sidebar_footer_pinned_to_bottom: true",
|
|
1120
1520
|
"sidebar_header_and_footer_inset_to_align_with_nav_icons: true",
|
|
1121
|
-
"header_mirrors_shell_columns_when_header_start_is_used: true"
|
|
1521
|
+
"header_mirrors_shell_columns_when_header_start_is_used: true",
|
|
1522
|
+
"header_start_falls_back_to_a_single_flex_row_on_mobile: true",
|
|
1523
|
+
"animates_the_rail_width_via_grid_template_columns: true",
|
|
1524
|
+
"main_panel_has_a_rounded_inner_corner_on_the_sidebar_side_on_desktop: true",
|
|
1525
|
+
"drawer_width_is_capped_at_min_of_100_percent_and_sidebar_width: true",
|
|
1526
|
+
'root_data_attribute: data-mobile="true" | "false" on the shell root',
|
|
1527
|
+
"respects_prefers_reduced_motion: true"
|
|
1122
1528
|
],
|
|
1123
1529
|
selection: {
|
|
1124
1530
|
keywords: [
|
|
@@ -1165,14 +1571,15 @@ var treeui_catalog_default = {
|
|
|
1165
1571
|
},
|
|
1166
1572
|
recipes: [
|
|
1167
1573
|
"app-shell"
|
|
1168
|
-
]
|
|
1574
|
+
],
|
|
1575
|
+
practices: []
|
|
1169
1576
|
},
|
|
1170
1577
|
{
|
|
1171
1578
|
name: "TAvatar",
|
|
1172
1579
|
aliases: [],
|
|
1173
1580
|
package: "@treeui/vue",
|
|
1174
1581
|
category: "Data Display",
|
|
1175
|
-
description: "User image
|
|
1582
|
+
description: "User avatar that renders an image when `src` is set, otherwise initials derived from `alt`, plus an optional status indicator dot.",
|
|
1176
1583
|
sourceFile: "packages/vue/src/components/TAvatar.vue",
|
|
1177
1584
|
storyFile: "apps/docs/src/stories/Avatar.stories.ts",
|
|
1178
1585
|
storyTitle: "Components/Data Display/Avatar",
|
|
@@ -1182,19 +1589,19 @@ var treeui_catalog_default = {
|
|
|
1182
1589
|
name: "src",
|
|
1183
1590
|
type: "string",
|
|
1184
1591
|
required: false,
|
|
1185
|
-
description: "URL of the avatar image."
|
|
1592
|
+
description: "URL of the avatar image. When set, the `<img>` branch renders and the initials span is NOT in the DOM at all (`v-else`). If the image fails to load, the `<img>` is hidden via inline `display: none` \u2014 the component does NOT fall back to initials, leaving an empty circle. Pass no `src` if you want initials.\n"
|
|
1186
1593
|
},
|
|
1187
1594
|
{
|
|
1188
1595
|
name: "alt",
|
|
1189
1596
|
type: "string",
|
|
1190
1597
|
default: '""',
|
|
1191
|
-
description: "Accessible label for the avatar
|
|
1598
|
+
description: "Accessible label for the avatar and the `alt` attribute of the `<img>`. Also the source for derived initials when `initials` is not set. Defaults to an empty string, in which case no `aria-label` is rendered at all (`alt || undefined`) and derived initials are empty \u2014 always pass a meaningful `alt`.\n"
|
|
1192
1599
|
},
|
|
1193
1600
|
{
|
|
1194
1601
|
name: "initials",
|
|
1195
1602
|
type: "string",
|
|
1196
1603
|
required: false,
|
|
1197
|
-
description:
|
|
1604
|
+
description: 'Explicit initials, rendered only when `src` is unset. Takes precedence over initials derived from `alt`. When omitted, initials are derived from `alt` by splitting on spaces, taking the first character of the first two words, and uppercasing (e.g. "Jane Doe" -> "JD").\n'
|
|
1198
1605
|
},
|
|
1199
1606
|
{
|
|
1200
1607
|
name: "size",
|
|
@@ -1204,7 +1611,8 @@ var treeui_catalog_default = {
|
|
|
1204
1611
|
"sm",
|
|
1205
1612
|
"md",
|
|
1206
1613
|
"lg"
|
|
1207
|
-
]
|
|
1614
|
+
],
|
|
1615
|
+
description: "Fixed square dimensions \u2014 sm 2rem, md 2.5rem, lg 3.5rem \u2014 with matching font size for initials."
|
|
1208
1616
|
},
|
|
1209
1617
|
{
|
|
1210
1618
|
name: "status",
|
|
@@ -1216,20 +1624,23 @@ var treeui_catalog_default = {
|
|
|
1216
1624
|
"busy",
|
|
1217
1625
|
"away"
|
|
1218
1626
|
],
|
|
1219
|
-
description: "Shows a colored status dot on the avatar
|
|
1627
|
+
description: "Shows a colored status dot pinned to the bottom-right of the avatar bounding box. Renders alongside either branch (image or initials). The dot sits on the corner outside the circular mask, so `.t-avatar` deliberately has no `overflow: hidden`.\n"
|
|
1220
1628
|
}
|
|
1221
1629
|
],
|
|
1222
1630
|
events: [],
|
|
1223
1631
|
slots: [
|
|
1224
1632
|
{
|
|
1225
1633
|
name: "default",
|
|
1226
|
-
description:
|
|
1634
|
+
description: 'Optional overlay content, rendered inside the `.t-avatar` span after the image/initials and before the status dot. The parent is `position: relative`, so children can be absolutely positioned. Note the wrapper carries `role="img"`, which makes its subtree presentational to assistive technology \u2014 slot content is visual only and will not be announced.\n'
|
|
1227
1635
|
}
|
|
1228
1636
|
],
|
|
1229
1637
|
a11y: [
|
|
1230
|
-
"role: img",
|
|
1231
|
-
|
|
1232
|
-
|
|
1638
|
+
"role: img (always set on the root span, including when only initials render)",
|
|
1639
|
+
'aria-label: Set from `alt`. Omitted entirely when `alt` is empty (the default), which leaves the `role="img"` element without an accessible name.',
|
|
1640
|
+
'initials: Marked `aria-hidden="true"` \u2014 the name comes from `alt`, not the visible text.',
|
|
1641
|
+
"image: Receives the `alt` prop as its native `alt` attribute.",
|
|
1642
|
+
"status_dot: Carries `aria-label` with the status value, but the element is a bare `<span>` with no role, so the label is not exposed to assistive technology. Convey status in text if it matters.",
|
|
1643
|
+
'slot_content: Not announced \u2014 the `role="img"` root makes descendant content presentational.'
|
|
1233
1644
|
],
|
|
1234
1645
|
behavior: [],
|
|
1235
1646
|
selection: {
|
|
@@ -1242,7 +1653,8 @@ var treeui_catalog_default = {
|
|
|
1242
1653
|
required: [],
|
|
1243
1654
|
notes: []
|
|
1244
1655
|
},
|
|
1245
|
-
recipes: []
|
|
1656
|
+
recipes: [],
|
|
1657
|
+
practices: []
|
|
1246
1658
|
},
|
|
1247
1659
|
{
|
|
1248
1660
|
name: "TBadge",
|
|
@@ -1267,7 +1679,8 @@ var treeui_catalog_default = {
|
|
|
1267
1679
|
"ghost",
|
|
1268
1680
|
"soft",
|
|
1269
1681
|
"danger"
|
|
1270
|
-
]
|
|
1682
|
+
],
|
|
1683
|
+
description: "Surface treatment. Selects which --tree-badge-<variant>-* colour variables the badge consumes; danger is a surface style, not a semantic guarantee \u2014 its red palette is replaced when tone is success, warning, or info."
|
|
1271
1684
|
},
|
|
1272
1685
|
{
|
|
1273
1686
|
name: "tone",
|
|
@@ -1280,7 +1693,7 @@ var treeui_catalog_default = {
|
|
|
1280
1693
|
"danger",
|
|
1281
1694
|
"info"
|
|
1282
1695
|
],
|
|
1283
|
-
description: "
|
|
1696
|
+
description: "Semantic palette. Re-maps the --tree-badge-* colour variables that the chosen variant consumes, so it recolours the badge without changing its surface treatment. neutral keeps the brand palette."
|
|
1284
1697
|
},
|
|
1285
1698
|
{
|
|
1286
1699
|
name: "size",
|
|
@@ -1290,7 +1703,8 @@ var treeui_catalog_default = {
|
|
|
1290
1703
|
"sm",
|
|
1291
1704
|
"md",
|
|
1292
1705
|
"lg"
|
|
1293
|
-
]
|
|
1706
|
+
],
|
|
1707
|
+
description: "Changes min-height and font-size only; inline padding is constant across sizes."
|
|
1294
1708
|
}
|
|
1295
1709
|
],
|
|
1296
1710
|
events: [],
|
|
@@ -1303,10 +1717,19 @@ var treeui_catalog_default = {
|
|
|
1303
1717
|
}
|
|
1304
1718
|
],
|
|
1305
1719
|
a11y: [
|
|
1720
|
+
"semantic_element: span",
|
|
1306
1721
|
"interactive_by_default: false",
|
|
1307
|
-
"icon_slot_marked_aria_hidden: true"
|
|
1722
|
+
"icon_slot_marked_aria_hidden: true",
|
|
1723
|
+
"tone_conveys_meaning_by_color_only: No role or aria state is set, so put the status word in the badge text rather than relying on tone alone."
|
|
1724
|
+
],
|
|
1725
|
+
behavior: [
|
|
1726
|
+
"always_applies_one_modifier_per_prop: true",
|
|
1727
|
+
"tone_remaps_variant_color_variables: true",
|
|
1728
|
+
"tone_overrides_variant_danger_palette: true",
|
|
1729
|
+
"tone_neutral_has_no_stylesheet_rule: true",
|
|
1730
|
+
"icon_wrapper_rendered_only_when_slot_filled: true",
|
|
1731
|
+
"icon_renders_before_default_slot: true"
|
|
1308
1732
|
],
|
|
1309
|
-
behavior: [],
|
|
1310
1733
|
selection: {
|
|
1311
1734
|
keywords: [],
|
|
1312
1735
|
useWhen: [],
|
|
@@ -1319,6 +1742,11 @@ var treeui_catalog_default = {
|
|
|
1319
1742
|
},
|
|
1320
1743
|
recipes: [
|
|
1321
1744
|
"pricing-section"
|
|
1745
|
+
],
|
|
1746
|
+
practices: [
|
|
1747
|
+
"predictable-api",
|
|
1748
|
+
"state-clarity",
|
|
1749
|
+
"token-driven"
|
|
1322
1750
|
]
|
|
1323
1751
|
},
|
|
1324
1752
|
{
|
|
@@ -1338,23 +1766,32 @@ var treeui_catalog_default = {
|
|
|
1338
1766
|
name: "separator",
|
|
1339
1767
|
type: "string",
|
|
1340
1768
|
default: "/",
|
|
1341
|
-
description: "Character or string
|
|
1769
|
+
description: "Character or string shown between items. Applied as the inline CSS custom property --tree-breadcrumb-separator on the <ol>, wrapped in single quotes, and drawn by the .t-breadcrumb__item:not(:last-child)::after pseudo-element \u2014 it never enters the DOM as text. A value containing a single quote or a backslash produces an invalid CSS value and the separator stops rendering."
|
|
1342
1770
|
}
|
|
1343
1771
|
],
|
|
1344
1772
|
events: [],
|
|
1345
1773
|
slots: [
|
|
1346
1774
|
{
|
|
1347
|
-
name: "default"
|
|
1775
|
+
name: "default",
|
|
1776
|
+
description: "Breadcrumb trail content, rendered inside the <ol class='t-breadcrumb__list'>. Expects TBreadcrumbItem children so each entry becomes an <li>. No scoped props."
|
|
1348
1777
|
}
|
|
1349
1778
|
],
|
|
1350
1779
|
a11y: [
|
|
1351
1780
|
"element: nav",
|
|
1352
1781
|
"aria_label: Breadcrumb",
|
|
1782
|
+
"aria_label_hardcoded_but_overridable_via_fallthrough_attrs: true",
|
|
1353
1783
|
"current_page_aria_current: page",
|
|
1354
1784
|
"uses_ol_for_ordered_list: true",
|
|
1355
1785
|
"interactive_by_default: false"
|
|
1356
1786
|
],
|
|
1357
|
-
behavior: [
|
|
1787
|
+
behavior: [
|
|
1788
|
+
"link_target_precedence: to + resolvable RouterLink, then href, then string to",
|
|
1789
|
+
"string_to_without_router_renders_native_anchor: true",
|
|
1790
|
+
"object_to_without_router_renders_current_span: true",
|
|
1791
|
+
"current_state_is_not_positional: true",
|
|
1792
|
+
"separator_rendered_by_css_pseudo_element: true",
|
|
1793
|
+
"separator_ignores_pointer_events: true"
|
|
1794
|
+
],
|
|
1358
1795
|
selection: {
|
|
1359
1796
|
keywords: [],
|
|
1360
1797
|
useWhen: [],
|
|
@@ -1368,7 +1805,8 @@ var treeui_catalog_default = {
|
|
|
1368
1805
|
"Use `to` when the app has vue-router and breadcrumb items should render RouterLink."
|
|
1369
1806
|
]
|
|
1370
1807
|
},
|
|
1371
|
-
recipes: []
|
|
1808
|
+
recipes: [],
|
|
1809
|
+
practices: []
|
|
1372
1810
|
},
|
|
1373
1811
|
{
|
|
1374
1812
|
name: "TButton",
|
|
@@ -1386,7 +1824,8 @@ var treeui_catalog_default = {
|
|
|
1386
1824
|
{
|
|
1387
1825
|
name: "as",
|
|
1388
1826
|
type: "string",
|
|
1389
|
-
default: "button"
|
|
1827
|
+
default: "button",
|
|
1828
|
+
note: "Root tag rendered through `<component :is>`. Any value other than `button` switches the component onto the non-native accessibility path (see `a11y`) and stops the `type` attribute from being rendered."
|
|
1390
1829
|
},
|
|
1391
1830
|
{
|
|
1392
1831
|
name: "variant",
|
|
@@ -1410,23 +1849,50 @@ var treeui_catalog_default = {
|
|
|
1410
1849
|
"sm",
|
|
1411
1850
|
"md",
|
|
1412
1851
|
"lg"
|
|
1413
|
-
]
|
|
1852
|
+
],
|
|
1853
|
+
note: "`t-button--md` is emitted but carries no CSS rule of its own \u2014 md is the base sizing, and only sm/lg override height, padding, and font size."
|
|
1414
1854
|
},
|
|
1415
1855
|
{
|
|
1416
1856
|
name: "disabled",
|
|
1417
1857
|
type: "boolean",
|
|
1418
|
-
default: "false"
|
|
1858
|
+
default: "false",
|
|
1859
|
+
note: 'Applied as the native `disabled` attribute only when `as` is `button`; for any other tag the component falls back to `aria-disabled="true"` plus `tabindex="-1"`. Clicks are blocked in both cases.'
|
|
1419
1860
|
},
|
|
1420
1861
|
{
|
|
1421
1862
|
name: "loading",
|
|
1422
1863
|
type: "boolean",
|
|
1423
1864
|
default: "false",
|
|
1424
|
-
note: "loading implies disabled behavior"
|
|
1865
|
+
note: "loading implies disabled behavior \u2014 the effective disabled state is `disabled || loading`, so `loading` on its own disables the button and applies `is-disabled`."
|
|
1866
|
+
},
|
|
1867
|
+
{
|
|
1868
|
+
name: "loadingLabel",
|
|
1869
|
+
type: "string",
|
|
1870
|
+
default: "Loading",
|
|
1871
|
+
note: "Accessible announcement while loading, forwarded to the nested TSpinner's `label`. The default is English because TreeUI ships no i18n layer \u2014 pass the active locale's string to localize it (see DECISIONS.md \u2192 Locale Data)."
|
|
1872
|
+
},
|
|
1873
|
+
{
|
|
1874
|
+
name: "hideIconWhileLoading",
|
|
1875
|
+
type: "boolean",
|
|
1876
|
+
default: "true",
|
|
1877
|
+
note: "While loading, the `icon` slot is not rendered so the spinner replaces the icon instead of rendering beside it. Set to `false` to restore the pre-0.19 behavior of showing both."
|
|
1878
|
+
},
|
|
1879
|
+
{
|
|
1880
|
+
name: "iconOnly",
|
|
1881
|
+
type: "boolean",
|
|
1882
|
+
default: "false",
|
|
1883
|
+
note: "Square, icon-only button \u2014 collapses the inline padding to a 1:1 control matching the size token and suppresses the `t-button__label` wrapper. Requires an accessible name via `label` (or `aria-label`), since the icon slot is aria-hidden."
|
|
1884
|
+
},
|
|
1885
|
+
{
|
|
1886
|
+
name: "label",
|
|
1887
|
+
type: "string",
|
|
1888
|
+
default: "undefined",
|
|
1889
|
+
note: "Accessible name, rendered as `aria-label`. Required whenever `iconOnly` is set; ignored for ordinary buttons that already have visible text."
|
|
1425
1890
|
},
|
|
1426
1891
|
{
|
|
1427
1892
|
name: "type",
|
|
1428
1893
|
type: "button | submit | reset",
|
|
1429
|
-
default: "button"
|
|
1894
|
+
default: "button",
|
|
1895
|
+
note: 'Only forwarded when `as` is `button`; for any other tag no `type` attribute is rendered. Set `type="submit"` for the submit control of an enclosing form.'
|
|
1430
1896
|
},
|
|
1431
1897
|
{
|
|
1432
1898
|
name: "block",
|
|
@@ -1438,12 +1904,14 @@ var treeui_catalog_default = {
|
|
|
1438
1904
|
name: "align",
|
|
1439
1905
|
type: "start | center | end",
|
|
1440
1906
|
default: "center",
|
|
1441
|
-
note: "Content alignment; only meaningful together with `block`. Use `start` for left-aligned icon+label menu rows."
|
|
1907
|
+
note: "Content alignment; only meaningful once the button is wider than its content, which in practice means together with `block`, since the base rule is `min-width: max-content`. Use `start` for left-aligned icon+label menu rows. The default `center` emits no modifier class \u2014 it is the base rule."
|
|
1442
1908
|
}
|
|
1443
1909
|
],
|
|
1444
1910
|
events: [
|
|
1445
1911
|
{
|
|
1446
|
-
name: "click"
|
|
1912
|
+
name: "click",
|
|
1913
|
+
description: "Emitted on activation. Suppressed while disabled or loading: the internal handler calls preventDefault() and stopPropagation() and returns without emitting.",
|
|
1914
|
+
payload: "[event: MouseEvent]"
|
|
1447
1915
|
}
|
|
1448
1916
|
],
|
|
1449
1917
|
slots: [
|
|
@@ -1456,13 +1924,22 @@ var treeui_catalog_default = {
|
|
|
1456
1924
|
],
|
|
1457
1925
|
a11y: [
|
|
1458
1926
|
"native_button_by_default: true",
|
|
1927
|
+
"native_disabled_attr_only_when_button: true",
|
|
1459
1928
|
"aria_busy_when_loading: true",
|
|
1460
1929
|
"aria_disabled_for_non_button: true",
|
|
1461
|
-
"tabindex_minus_one_when_non_button_disabled: true"
|
|
1930
|
+
"tabindex_minus_one_when_non_button_disabled: true",
|
|
1931
|
+
"icon_slot_marked_aria_hidden: true",
|
|
1932
|
+
"loading_spinner_is_announced: The nested TSpinner carries role=\"status\" and a visually hidden label, so the button's accessible name gains that text while loading. The text comes from `loadingLabel`, so it follows the app's locale.",
|
|
1933
|
+
"icon_only_requires_an_accessible_name: With `iconOnly` there is no visible text and the icon slot is aria-hidden, so the name must come from `label` or `aria-label`. This is a documented requirement, not a runtime assertion \u2014 the package ships ESM+CJS with no dev-only build define, so there is no dev-stripped warning.",
|
|
1934
|
+
"touch_targets: 44\xD744px minimum via the .t-button::after overlay",
|
|
1935
|
+
"focus_visible: box-shadow focus ring on the root element"
|
|
1462
1936
|
],
|
|
1463
1937
|
behavior: [
|
|
1464
1938
|
"blocks_click_when_disabled_or_loading: true",
|
|
1465
|
-
"renders_spinner_when_loading: true"
|
|
1939
|
+
"renders_spinner_when_loading: true",
|
|
1940
|
+
"spinner_replaces_the_icon_slot_while_loading: The spinner takes the icon's leading position, so by default the icon slot is withheld while loading and the order is spinner, label. Set `hideIconWhileLoading: false` for the older spinner, icon, label order.",
|
|
1941
|
+
"icon_slot_wrapper_rendered_only_when_filled: true",
|
|
1942
|
+
"default_slot_wrapped_in_label_element_unless_icon_only: true"
|
|
1466
1943
|
],
|
|
1467
1944
|
selection: {
|
|
1468
1945
|
keywords: [],
|
|
@@ -1477,6 +1954,10 @@ var treeui_catalog_default = {
|
|
|
1477
1954
|
recipes: [
|
|
1478
1955
|
"confirm-destructive-action",
|
|
1479
1956
|
"pricing-section"
|
|
1957
|
+
],
|
|
1958
|
+
practices: [
|
|
1959
|
+
"interaction-feedback",
|
|
1960
|
+
"predictable-api"
|
|
1480
1961
|
]
|
|
1481
1962
|
},
|
|
1482
1963
|
{
|
|
@@ -1486,7 +1967,7 @@ var treeui_catalog_default = {
|
|
|
1486
1967
|
kind: "layout",
|
|
1487
1968
|
category: "Data Display",
|
|
1488
1969
|
status: "available",
|
|
1489
|
-
purpose: "Surface container with optional header and footer slots.",
|
|
1970
|
+
purpose: "Surface container with optional header, actions, and footer slots.",
|
|
1490
1971
|
sourceFile: "packages/vue/src/components/TCard.vue",
|
|
1491
1972
|
storyFile: "apps/docs/src/stories/Card.stories.ts",
|
|
1492
1973
|
storyTitle: "Components/Data Display/Card",
|
|
@@ -1495,7 +1976,8 @@ var treeui_catalog_default = {
|
|
|
1495
1976
|
{
|
|
1496
1977
|
name: "as",
|
|
1497
1978
|
type: "string",
|
|
1498
|
-
default: "section"
|
|
1979
|
+
default: "section",
|
|
1980
|
+
description: 'Tag or component used for the polymorphic root, rendered through `<component :is="as">`. Change it to `article`, `aside`, `li`, or `div` when the default `section` element is wrong for the surrounding document structure. It only swaps the element \u2014 classes, slots, and layout are unchanged.\n'
|
|
1499
1981
|
},
|
|
1500
1982
|
{
|
|
1501
1983
|
name: "variant",
|
|
@@ -1511,37 +1993,44 @@ var treeui_catalog_default = {
|
|
|
1511
1993
|
name: "size",
|
|
1512
1994
|
type: "TSize",
|
|
1513
1995
|
default: "md",
|
|
1514
|
-
|
|
1515
|
-
"sm",
|
|
1516
|
-
"md",
|
|
1517
|
-
"lg"
|
|
1518
|
-
]
|
|
1996
|
+
description: "Padding scale only \u2014 it does not change typography, border, or radius. `sm` uses --tree-space-3, `md` --tree-space-4, `lg` --tree-space-5.\n"
|
|
1519
1997
|
},
|
|
1520
1998
|
{
|
|
1521
1999
|
name: "title",
|
|
1522
2000
|
type: "string",
|
|
1523
2001
|
default: "undefined",
|
|
1524
|
-
description: "Optional card heading
|
|
2002
|
+
description: "Optional card heading. Rendered as the fallback content of the `header` slot inside a `span.t-card__title`, so supplying `#header` replaces it entirely. Setting it also forces the header element to render. Because it is declared as a prop it is consumed by the component and never reaches the root element as the native HTML `title` tooltip attribute.\n"
|
|
1525
2003
|
}
|
|
1526
2004
|
],
|
|
1527
2005
|
events: [],
|
|
1528
2006
|
slots: [
|
|
1529
2007
|
{
|
|
1530
|
-
name: "header"
|
|
2008
|
+
name: "header",
|
|
2009
|
+
description: "Replaces the `title` fallback inside `header.t-card__header`. When this slot is supplied the `title` prop renders nothing. Receives no slot props.\n"
|
|
1531
2010
|
},
|
|
1532
2011
|
{
|
|
1533
|
-
name: "actions"
|
|
2012
|
+
name: "actions",
|
|
2013
|
+
description: "Trailing controls wrapped in `span.t-card__actions`, rendered as a sibling after the header content inside the same `header.t-card__header`. Supplying it is enough to render the header on its own, with no `title` and no `header` slot. Receives no slot props.\n"
|
|
1534
2014
|
},
|
|
1535
2015
|
{
|
|
1536
|
-
name: "default"
|
|
2016
|
+
name: "default",
|
|
2017
|
+
description: "Card body. Always rendered, wrapped in `div.t-card__body`. Receives no slot props.\n"
|
|
1537
2018
|
},
|
|
1538
2019
|
{
|
|
1539
|
-
name: "footer"
|
|
2020
|
+
name: "footer",
|
|
2021
|
+
description: "Renders `footer.t-card__footer` only when the slot is supplied; there is no `footer` prop fallback. Receives no slot props.\n"
|
|
1540
2022
|
}
|
|
1541
2023
|
],
|
|
1542
|
-
a11y: [
|
|
2024
|
+
a11y: [
|
|
2025
|
+
"root_role: None applied by the component \u2014 semantics come entirely from `as` (default `section`).",
|
|
2026
|
+
"title_is_not_a_heading: `title` renders a `span.t-card__title`, styled at heading size and weight but carrying no heading semantics, so it does not enter the document outline. When the card must be reachable by heading navigation, put a real `<h2>`/`<h3>` in the `header` slot instead of using the prop.",
|
|
2027
|
+
"unnamed_section_root: The default `section` root has no accessible name, so assistive tech exposes it as generic rather than as a region. The component sets no `inheritAttrs: false` and has a single root, so `aria-label` / `aria-labelledby` passed by the consumer fall through to that root when a named region is wanted."
|
|
2028
|
+
],
|
|
1543
2029
|
behavior: [
|
|
1544
2030
|
"body_wrapper_class: t-card__body",
|
|
2031
|
+
"header_render_condition: The `header.t-card__header` element renders when ANY of the `header` slot, a truthy `title` prop, or the `actions` slot is present. All three branches are independent \u2014 actions alone still produces a header.",
|
|
2032
|
+
"footer_render_condition: The `footer.t-card__footer` element renders only when the `footer` slot is supplied.",
|
|
2033
|
+
"slot_props: None. No slot on this component is scoped; all four are plain content slots.",
|
|
1545
2034
|
'variant_effects: {"outline":"Base surface with a default border. The styling baseline \u2014 the `t-card--outline` class is emitted but carries no CSS rule of its own.","soft":"Subtle tinted surface (bg-subtle), same border and shadow as outline.","inset":"Same tinted surface as soft, but with no shadow, so it reads as recessed inside another surface."}',
|
|
1546
2035
|
"note: No card variant inverts its surface, so nested content inherits the normal color tokens. For a high-emphasis card, use a brand-colored border rather than an inverted background."
|
|
1547
2036
|
],
|
|
@@ -1576,6 +2065,10 @@ var treeui_catalog_default = {
|
|
|
1576
2065
|
},
|
|
1577
2066
|
recipes: [
|
|
1578
2067
|
"chart-surface"
|
|
2068
|
+
],
|
|
2069
|
+
practices: [
|
|
2070
|
+
"predictable-api",
|
|
2071
|
+
"token-driven"
|
|
1579
2072
|
]
|
|
1580
2073
|
},
|
|
1581
2074
|
{
|
|
@@ -1605,13 +2098,13 @@ var treeui_catalog_default = {
|
|
|
1605
2098
|
name: "series",
|
|
1606
2099
|
type: "TChartSeries[]",
|
|
1607
2100
|
default: "[]",
|
|
1608
|
-
note: "Each item is { name: string; data: number[]; color?: string }."
|
|
2101
|
+
note: "Each item is { name: string; data: number[]; color?: string }. Series with an empty data array are dropped before rendering \u2014 they never reach the plot, legend, tooltip, or a11y table."
|
|
1609
2102
|
},
|
|
1610
2103
|
{
|
|
1611
2104
|
name: "labels",
|
|
1612
2105
|
type: "string[]",
|
|
1613
2106
|
default: "[]",
|
|
1614
|
-
note: "X-axis categories, aligned index-for-index to each series' data."
|
|
2107
|
+
note: "X-axis categories, aligned index-for-index to each series' data. Labels past the longest series are ignored; a missing label falls back to '#<n>' in the tooltip and to an empty header cell in the a11y table."
|
|
1615
2108
|
},
|
|
1616
2109
|
{
|
|
1617
2110
|
name: "height",
|
|
@@ -1623,80 +2116,91 @@ var treeui_catalog_default = {
|
|
|
1623
2116
|
name: "smooth",
|
|
1624
2117
|
type: "boolean",
|
|
1625
2118
|
default: "false",
|
|
1626
|
-
note: "Curved line/area."
|
|
2119
|
+
note: "Curved line/area; ignored for bar."
|
|
1627
2120
|
},
|
|
1628
2121
|
{
|
|
1629
2122
|
name: "stacked",
|
|
1630
2123
|
type: "boolean",
|
|
1631
2124
|
default: "false",
|
|
1632
|
-
note: "Stacks bar series; ignored for line/area. Negative values are clamped to 0 in stacked mode (grouped mode renders them)."
|
|
2125
|
+
note: "Stacks bar series; ignored for line/area. Negative values are clamped to 0 in stacked mode (grouped mode renders them below the baseline). The tooltip always reports the raw per-series values, not the cumulative stack."
|
|
1633
2126
|
},
|
|
1634
2127
|
{
|
|
1635
2128
|
name: "showGrid",
|
|
1636
2129
|
type: "boolean",
|
|
1637
|
-
default: "true"
|
|
2130
|
+
default: "true",
|
|
2131
|
+
note: "Horizontal gridlines at the y ticks. Independent of showYAxis, which controls the tick text."
|
|
1638
2132
|
},
|
|
1639
2133
|
{
|
|
1640
2134
|
name: "showLegend",
|
|
1641
|
-
type: "boolean",
|
|
1642
|
-
default: "auto (true when more than one series)"
|
|
2135
|
+
type: "boolean | undefined",
|
|
2136
|
+
default: "auto (true when more than one series)",
|
|
2137
|
+
note: "The legend is suppressed whenever there is no data, even when set to true."
|
|
1643
2138
|
},
|
|
1644
2139
|
{
|
|
1645
2140
|
name: "showXAxis",
|
|
1646
2141
|
type: "boolean",
|
|
1647
|
-
default: "true"
|
|
2142
|
+
default: "true",
|
|
2143
|
+
note: "When false the category labels are skipped and the bottom margin collapses from 28px to 10px."
|
|
1648
2144
|
},
|
|
1649
2145
|
{
|
|
1650
2146
|
name: "showYAxis",
|
|
1651
2147
|
type: "boolean",
|
|
1652
|
-
default: "true"
|
|
2148
|
+
default: "true",
|
|
2149
|
+
note: "When false the tick text is skipped and the left margin collapses from 44px to 10px. Gridlines are unaffected."
|
|
1653
2150
|
},
|
|
1654
2151
|
{
|
|
1655
2152
|
name: "showTooltip",
|
|
1656
2153
|
type: "boolean",
|
|
1657
|
-
default: "true"
|
|
2154
|
+
default: "true",
|
|
2155
|
+
note: "Gates hover tracking as a whole: the crosshair, the tooltip panel, and the point-click event all stop when false."
|
|
1658
2156
|
},
|
|
1659
2157
|
{
|
|
1660
2158
|
name: "showPoints",
|
|
1661
2159
|
type: "boolean",
|
|
1662
2160
|
default: "false",
|
|
1663
|
-
note: "Always draw markers on line/area points."
|
|
2161
|
+
note: "Always draw markers on line/area points; ignored for bar."
|
|
1664
2162
|
},
|
|
1665
2163
|
{
|
|
1666
2164
|
name: "yTicks",
|
|
1667
2165
|
type: "number",
|
|
1668
|
-
default: "5"
|
|
2166
|
+
default: "5",
|
|
2167
|
+
note: "Target tick count handed to niceScale \u2014 the rendered count may differ once the bounds are rounded."
|
|
1669
2168
|
},
|
|
1670
2169
|
{
|
|
1671
2170
|
name: "valueFormat",
|
|
1672
2171
|
type: "(value: number) => string",
|
|
1673
|
-
default: "locale integers for |value| >= 1000"
|
|
2172
|
+
default: "locale integers for |value| >= 1000",
|
|
2173
|
+
note: "Applies to y-axis ticks, tooltip values, and the a11y table cells."
|
|
1674
2174
|
},
|
|
1675
2175
|
{
|
|
1676
2176
|
name: "minY",
|
|
1677
2177
|
type: "number",
|
|
1678
|
-
default: "auto"
|
|
2178
|
+
default: "auto (min(0, data min) for bar/area, data min for line)",
|
|
2179
|
+
note: "A hint, not a hard bound: niceScale rounds the low end down, so the rendered domain can start below it."
|
|
1679
2180
|
},
|
|
1680
2181
|
{
|
|
1681
2182
|
name: "maxY",
|
|
1682
2183
|
type: "number",
|
|
1683
|
-
default: "auto"
|
|
2184
|
+
default: "auto",
|
|
2185
|
+
note: "A hint, not a hard bound: niceScale rounds the high end up, so the rendered domain can extend above it."
|
|
1684
2186
|
},
|
|
1685
2187
|
{
|
|
1686
2188
|
name: "animated",
|
|
1687
2189
|
type: "boolean",
|
|
1688
2190
|
default: "true",
|
|
1689
|
-
note: "Draw-in animation; disabled under prefers-reduced-motion."
|
|
2191
|
+
note: "Draw-in animation via the is-animated root class; disabled under prefers-reduced-motion."
|
|
1690
2192
|
},
|
|
1691
2193
|
{
|
|
1692
2194
|
name: "loading",
|
|
1693
2195
|
type: "boolean",
|
|
1694
|
-
default: "false"
|
|
2196
|
+
default: "false",
|
|
2197
|
+
note: "Replaces the plot with five pulsing skeleton bars and adds the is-loading root class. Takes precedence over the empty state; the legend still renders when data is present."
|
|
1695
2198
|
},
|
|
1696
2199
|
{
|
|
1697
2200
|
name: "ariaLabel",
|
|
1698
2201
|
type: "string",
|
|
1699
|
-
default: "auto-generated summary"
|
|
2202
|
+
default: "auto-generated summary ('<type> chart with <n> series')",
|
|
2203
|
+
note: "Rendered as the <caption> of the visually-hidden data table \u2014 it is not applied as an aria-label attribute on the root."
|
|
1700
2204
|
}
|
|
1701
2205
|
],
|
|
1702
2206
|
events: [
|
|
@@ -1718,14 +2222,19 @@ var treeui_catalog_default = {
|
|
|
1718
2222
|
],
|
|
1719
2223
|
a11y: [
|
|
1720
2224
|
"SVG is aria-hidden; a visually-hidden <table> mirrors the series data for assistive tech.",
|
|
2225
|
+
"The table's <caption> carries ariaLabel (or the auto-generated summary); the root div itself has no role or accessible name.",
|
|
1721
2226
|
"Legend defaults on for multiple series so identity is not color-only.",
|
|
1722
|
-
"Provide a meaningful ariaLabel describing what the chart shows."
|
|
2227
|
+
"Provide a meaningful ariaLabel describing what the chart shows.",
|
|
2228
|
+
"point-click has no keyboard equivalent \u2014 do not make it the only way to reach a behavior."
|
|
1723
2229
|
],
|
|
1724
2230
|
behavior: [
|
|
1725
|
-
"colors_auto_assign_from_chart_palette: --tree-color-chart-1..8, cycling; per-series color overrides",
|
|
1726
|
-
"
|
|
1727
|
-
"
|
|
1728
|
-
"hover_shows_crosshair_and_tooltip: true"
|
|
2231
|
+
"colors_auto_assign_from_chart_palette: --tree-color-chart-1..8, cycling by series index; per-series color overrides",
|
|
2232
|
+
"zero_baseline_for_bar_and_area: the y domain is extended to include 0 for bar and area; line uses the data extent. minY overrides it.",
|
|
2233
|
+
"y_domain_uses_nice_ticks: every type runs through niceScale, which rounds the min down and the max up to round numbers",
|
|
2234
|
+
"hover_shows_crosshair_and_tooltip: only while showTooltip is true",
|
|
2235
|
+
"width_measured_with_resize_observer: falls back to 640px until the canvas is mounted and measured",
|
|
2236
|
+
"x_labels_decimate_when_crowded: keeps every max(2, floor(innerWidth / 52))-th label and hides the rest; the last category is always kept",
|
|
2237
|
+
"empty_state_when_no_series_has_data: true"
|
|
1729
2238
|
],
|
|
1730
2239
|
selection: {
|
|
1731
2240
|
keywords: [
|
|
@@ -1772,6 +2281,9 @@ var treeui_catalog_default = {
|
|
|
1772
2281
|
recipes: [
|
|
1773
2282
|
"chart-surface",
|
|
1774
2283
|
"metric-dashboard"
|
|
2284
|
+
],
|
|
2285
|
+
practices: [
|
|
2286
|
+
"token-driven"
|
|
1775
2287
|
]
|
|
1776
2288
|
},
|
|
1777
2289
|
{
|
|
@@ -1790,7 +2302,8 @@ var treeui_catalog_default = {
|
|
|
1790
2302
|
{
|
|
1791
2303
|
name: "modelValue",
|
|
1792
2304
|
type: "boolean",
|
|
1793
|
-
default: "false"
|
|
2305
|
+
default: "false",
|
|
2306
|
+
description: "Checked state. Fully controlled \u2014 the component holds no internal state and never mutates this prop; it emits update:modelValue and the parent must write the value back.\n"
|
|
1794
2307
|
},
|
|
1795
2308
|
{
|
|
1796
2309
|
name: "size",
|
|
@@ -1800,44 +2313,60 @@ var treeui_catalog_default = {
|
|
|
1800
2313
|
"sm",
|
|
1801
2314
|
"md",
|
|
1802
2315
|
"lg"
|
|
1803
|
-
]
|
|
2316
|
+
],
|
|
2317
|
+
description: "Control and label scale. Always rendered as a t-checkbox--<size> modifier."
|
|
1804
2318
|
},
|
|
1805
2319
|
{
|
|
1806
2320
|
name: "disabled",
|
|
1807
2321
|
type: "boolean",
|
|
1808
|
-
default: "false"
|
|
2322
|
+
default: "false",
|
|
2323
|
+
description: "Sets the native disabled attribute on the input and adds is-disabled to the root. No aria-disabled is emitted \u2014 the native attribute carries the state.\n"
|
|
1809
2324
|
},
|
|
1810
2325
|
{
|
|
1811
2326
|
name: "indeterminate",
|
|
1812
2327
|
type: "boolean",
|
|
1813
|
-
default: "false"
|
|
2328
|
+
default: "false",
|
|
2329
|
+
description: `Mixed state. Renders the dash icon and sets aria-checked="mixed", taking precedence over modelValue for both. Synced to the input's native indeterminate DOM property.
|
|
2330
|
+
`
|
|
1814
2331
|
},
|
|
1815
2332
|
{
|
|
1816
2333
|
name: "invalid",
|
|
1817
2334
|
type: "boolean",
|
|
1818
|
-
default: "false"
|
|
2335
|
+
default: "false",
|
|
2336
|
+
description: 'Adds is-invalid to the root and aria-invalid="true" to the input. When false the aria-invalid attribute is omitted entirely, not set to "false".\n'
|
|
1819
2337
|
}
|
|
1820
2338
|
],
|
|
1821
2339
|
events: [
|
|
1822
2340
|
{
|
|
1823
|
-
name: "update:modelValue"
|
|
2341
|
+
name: "update:modelValue",
|
|
2342
|
+
description: "Emitted on the native input's change event. The payload is always the negation of the current modelValue prop, not the DOM checked state. Enables v-model binding.\n",
|
|
2343
|
+
payload: "[value: boolean]"
|
|
1824
2344
|
}
|
|
1825
2345
|
],
|
|
1826
2346
|
slots: [
|
|
1827
2347
|
{
|
|
1828
|
-
name: "default"
|
|
2348
|
+
name: "default",
|
|
2349
|
+
description: 'Label content, wrapped in <span class="t-checkbox__label">. Rendered only when the slot is supplied (v-if="$slots.default"). The root element is a <label> that wraps the input, so slot text labels the control implicitly \u2014 no for/id pairing is needed.\n'
|
|
1829
2350
|
}
|
|
1830
2351
|
],
|
|
1831
2352
|
a11y: [
|
|
1832
2353
|
"role: native_checkbox",
|
|
2354
|
+
"accessible_name: From the default slot; absent when the slot is omitted \u2014 supply aria-label or aria-labelledby",
|
|
2355
|
+
"aria_checked_explicitly_bound: 'mixed' when indeterminate, otherwise the modelValue boolean",
|
|
1833
2356
|
"aria_checked_mixed_when_indeterminate: true",
|
|
1834
2357
|
"aria_invalid_when_invalid: true",
|
|
2358
|
+
"native_indeterminate_property_synced: true",
|
|
2359
|
+
"disabled_uses_native_attribute: true",
|
|
1835
2360
|
"focus_visible_on_control: true",
|
|
2361
|
+
"input_is_visually_hidden_but_focusable: clip-rect hidden input keeps native semantics and tab order; the focus ring is drawn on t-checkbox__control",
|
|
1836
2362
|
"clickable_target_44x44: true"
|
|
1837
2363
|
],
|
|
1838
2364
|
behavior: [
|
|
1839
2365
|
"update_payload_type: boolean",
|
|
2366
|
+
"controlled_only: No internal state; the checkbox does not change appearance until the parent updates modelValue",
|
|
2367
|
+
"indeterminate_precedence: indeterminate wins over modelValue for the rendered icon and for aria-checked; is-checked and is-indeterminate can both be present at once",
|
|
1840
2368
|
"indeterminate_clears_on_user_toggle: false",
|
|
2369
|
+
"indeterminate_is_parent_owned: The component never clears indeterminate \u2014 set it to false yourself when handling update:modelValue",
|
|
1841
2370
|
"label_click_toggles_checkbox: true"
|
|
1842
2371
|
],
|
|
1843
2372
|
selection: {
|
|
@@ -1870,7 +2399,10 @@ var treeui_catalog_default = {
|
|
|
1870
2399
|
required: [],
|
|
1871
2400
|
notes: []
|
|
1872
2401
|
},
|
|
1873
|
-
recipes: []
|
|
2402
|
+
recipes: [],
|
|
2403
|
+
practices: [
|
|
2404
|
+
"interaction-feedback"
|
|
2405
|
+
]
|
|
1874
2406
|
},
|
|
1875
2407
|
{
|
|
1876
2408
|
name: "TColorSwatch",
|
|
@@ -1889,19 +2421,19 @@ var treeui_catalog_default = {
|
|
|
1889
2421
|
name: "modelValue",
|
|
1890
2422
|
type: "string",
|
|
1891
2423
|
default: "undefined",
|
|
1892
|
-
note: "Selected colour as a hex string.
|
|
2424
|
+
note: "Selected colour as a hex string. Matched against `options[].value` by case-insensitive exact string comparison, so `#0969DA` matches `#0969da` but `#fff` never matches `#ffffff`. A value matching no preset leaves every swatch unselected and is still written to the custom input."
|
|
1893
2425
|
},
|
|
1894
2426
|
{
|
|
1895
2427
|
name: "options",
|
|
1896
2428
|
type: "TColorSwatchOption[]",
|
|
1897
2429
|
default: "[]",
|
|
1898
|
-
note: "Preset swatches, each `{ label, value }`. `label`
|
|
2430
|
+
note: "Preset swatches, each `{ label, value }`. `value` is applied raw as the button `background`, so any CSS colour renders, but keep it `#rrggbb` so matching and the custom input agree. `label` is the button's only accessible name \u2014 the button renders no text content. An empty array renders an empty group (only the custom input, when enabled)."
|
|
1899
2431
|
},
|
|
1900
2432
|
{
|
|
1901
2433
|
name: "allowCustom",
|
|
1902
2434
|
type: "boolean",
|
|
1903
2435
|
default: "false",
|
|
1904
|
-
note: 'Appends a native `<input type="color">` for values outside the
|
|
2436
|
+
note: 'Appends a native `<input type="color">` after the presets for values outside them. When false the input is not rendered at all and `customLabel` has no effect.'
|
|
1905
2437
|
},
|
|
1906
2438
|
{
|
|
1907
2439
|
name: "size",
|
|
@@ -1911,23 +2443,26 @@ var treeui_catalog_default = {
|
|
|
1911
2443
|
"sm",
|
|
1912
2444
|
"md",
|
|
1913
2445
|
"lg"
|
|
1914
|
-
]
|
|
2446
|
+
],
|
|
2447
|
+
note: "Drives `--tree-color-swatch-size` (sm 1.5rem, md 1.75rem, lg 2rem). Swatches are square; the custom input is one `--tree-space-2` wider."
|
|
1915
2448
|
},
|
|
1916
2449
|
{
|
|
1917
2450
|
name: "label",
|
|
1918
2451
|
type: "string",
|
|
1919
2452
|
default: "Color",
|
|
1920
|
-
note: 'Accessible label for the swatch group (`role="group"`).'
|
|
2453
|
+
note: 'Accessible label for the swatch group (`role="group"`). Rendered as `aria-label` on the root, so an `aria-label` passed by the consumer falls through to the same element and overrides it.'
|
|
1921
2454
|
},
|
|
1922
2455
|
{
|
|
1923
2456
|
name: "customLabel",
|
|
1924
2457
|
type: "string",
|
|
1925
|
-
default: "Custom color"
|
|
2458
|
+
default: "Custom color",
|
|
2459
|
+
note: "Accessible label (`aria-label`) for the native colour input, and its only accessible name. Applies only when `allowCustom` is set."
|
|
1926
2460
|
},
|
|
1927
2461
|
{
|
|
1928
2462
|
name: "disabled",
|
|
1929
2463
|
type: "boolean",
|
|
1930
|
-
default: "false"
|
|
2464
|
+
default: "false",
|
|
2465
|
+
note: "Sets the native `disabled` attribute on every preset button and on the custom input, so the group stops emitting and drops out of the Tab order. Not reflected on the wrapper, and there is no `is-disabled` class."
|
|
1931
2466
|
}
|
|
1932
2467
|
],
|
|
1933
2468
|
events: [
|
|
@@ -1937,14 +2472,21 @@ var treeui_catalog_default = {
|
|
|
1937
2472
|
],
|
|
1938
2473
|
slots: [],
|
|
1939
2474
|
a11y: [
|
|
1940
|
-
'Wrapper is `role="group"` labelled by `label`.',
|
|
1941
|
-
|
|
1942
|
-
"Selection is conveyed by an outline (not colour alone), since the swatch's own colour is the content."
|
|
2475
|
+
'Wrapper is `role="group"` labelled by `label` via `aria-label`.',
|
|
2476
|
+
'Each swatch is a native `<button type="button">` with `aria-pressed` reflecting selection and `aria-label` from the option label; it has no text content, so an option without a `label` is unnamed.',
|
|
2477
|
+
"Selection is conveyed by an outline (not colour alone), since the swatch's own colour is the content.",
|
|
2478
|
+
'The custom input is a native `<input type="color">` named only by `customLabel`.',
|
|
2479
|
+
"No roving focus and no arrow-key navigation \u2014 every swatch and the custom input is its own Tab stop."
|
|
1943
2480
|
],
|
|
1944
2481
|
behavior: [
|
|
2482
|
+
"update_payload_type: string",
|
|
1945
2483
|
"emits_on_preset_click: true",
|
|
1946
2484
|
"emits_on_custom_input: true",
|
|
1947
|
-
"blocks_interaction_when_disabled: true"
|
|
2485
|
+
"blocks_interaction_when_disabled: true",
|
|
2486
|
+
"selection_match_is_case_insensitive: true",
|
|
2487
|
+
"custom_input_rendered_only_when_allow_custom: true",
|
|
2488
|
+
"custom_input_emits_on_input_not_change: true",
|
|
2489
|
+
"fully_controlled_no_internal_selection_state: true"
|
|
1948
2490
|
],
|
|
1949
2491
|
selection: {
|
|
1950
2492
|
keywords: [],
|
|
@@ -1956,7 +2498,8 @@ var treeui_catalog_default = {
|
|
|
1956
2498
|
required: [],
|
|
1957
2499
|
notes: []
|
|
1958
2500
|
},
|
|
1959
|
-
recipes: []
|
|
2501
|
+
recipes: [],
|
|
2502
|
+
practices: []
|
|
1960
2503
|
},
|
|
1961
2504
|
{
|
|
1962
2505
|
name: "TCombobox",
|
|
@@ -1974,7 +2517,8 @@ var treeui_catalog_default = {
|
|
|
1974
2517
|
{
|
|
1975
2518
|
name: "modelValue",
|
|
1976
2519
|
type: "string",
|
|
1977
|
-
default: ""
|
|
2520
|
+
default: "",
|
|
2521
|
+
note: "The SELECTED option value, never the text in the input. The input renders an internal `query` string that is re-synced from the selected option's label whenever the listbox is closed. A `modelValue` with no matching entry in `options` resolves to an empty label."
|
|
1978
2522
|
},
|
|
1979
2523
|
{
|
|
1980
2524
|
name: "options",
|
|
@@ -1985,12 +2529,14 @@ var treeui_catalog_default = {
|
|
|
1985
2529
|
{
|
|
1986
2530
|
name: "open",
|
|
1987
2531
|
type: "boolean",
|
|
1988
|
-
default: "undefined"
|
|
2532
|
+
default: "undefined",
|
|
2533
|
+
note: "Controlled open state. Once a boolean is passed the component stops tracking open state internally \u2014 it only emits update:open / open-change and the consumer MUST write the value back, or the listbox never opens."
|
|
1989
2534
|
},
|
|
1990
2535
|
{
|
|
1991
2536
|
name: "defaultOpen",
|
|
1992
2537
|
type: "boolean",
|
|
1993
|
-
default: "false"
|
|
2538
|
+
default: "false",
|
|
2539
|
+
note: "Uncontrolled initial open state, read once on mount. Later changes to it are ignored."
|
|
1994
2540
|
},
|
|
1995
2541
|
{
|
|
1996
2542
|
name: "size",
|
|
@@ -2000,17 +2546,20 @@ var treeui_catalog_default = {
|
|
|
2000
2546
|
"sm",
|
|
2001
2547
|
"md",
|
|
2002
2548
|
"lg"
|
|
2003
|
-
]
|
|
2549
|
+
],
|
|
2550
|
+
note: "Sizes the control only. `md` has no CSS rule of its own \u2014 it is the base `.t-combobox__control` styling."
|
|
2004
2551
|
},
|
|
2005
2552
|
{
|
|
2006
2553
|
name: "disabled",
|
|
2007
2554
|
type: "boolean",
|
|
2008
|
-
default: "false"
|
|
2555
|
+
default: "false",
|
|
2556
|
+
note: 'Sets the native `disabled` attribute on the input, adds `is-disabled` to the root, and suppresses the listbox entirely (`v-if="isOpen && !disabled"`) \u2014 even while `open` is true. Also short-circuits opening, typing side effects, and keydown handling.'
|
|
2009
2557
|
},
|
|
2010
2558
|
{
|
|
2011
2559
|
name: "loading",
|
|
2012
2560
|
type: "boolean",
|
|
2013
|
-
default: "false"
|
|
2561
|
+
default: "false",
|
|
2562
|
+
note: 'Presentational only. Replaces the chevron indicator with `<TSpinner size="sm" label="Loading" />` and sets aria-busy; it never blocks typing, opening, filtering, or selection.'
|
|
2014
2563
|
},
|
|
2015
2564
|
{
|
|
2016
2565
|
name: "invalid",
|
|
@@ -2025,56 +2574,102 @@ var treeui_catalog_default = {
|
|
|
2025
2574
|
{
|
|
2026
2575
|
name: "emptyText",
|
|
2027
2576
|
type: "string",
|
|
2028
|
-
default: "No results found."
|
|
2577
|
+
default: "No results found.",
|
|
2578
|
+
note: "Fallback content of the `empty` slot \u2014 supplying that slot shadows this prop entirely."
|
|
2029
2579
|
}
|
|
2030
2580
|
],
|
|
2031
2581
|
events: [
|
|
2032
2582
|
{
|
|
2033
|
-
name: "update:modelValue"
|
|
2583
|
+
name: "update:modelValue",
|
|
2584
|
+
description: 'Emitted with the chosen option\'s `value` when an option is selected, and with `""` when the listbox closes while the input text is blank and a value was set (the clear-by-erasing path).',
|
|
2585
|
+
payload: '["string"]'
|
|
2034
2586
|
},
|
|
2035
2587
|
{
|
|
2036
|
-
name: "update:open"
|
|
2588
|
+
name: "update:open",
|
|
2589
|
+
description: "Emitted whenever the open state changes. Deduped \u2014 no emit when the next value equals the current one.",
|
|
2590
|
+
payload: '["boolean"]'
|
|
2037
2591
|
},
|
|
2038
2592
|
{
|
|
2039
|
-
name: "open-change"
|
|
2593
|
+
name: "open-change",
|
|
2594
|
+
description: "Emitted immediately after `update:open`, with the same payload. Alias for consumers that do not use v-model:open.",
|
|
2595
|
+
payload: '["boolean"]'
|
|
2040
2596
|
},
|
|
2041
2597
|
{
|
|
2042
|
-
name: "input-change"
|
|
2598
|
+
name: "input-change",
|
|
2599
|
+
description: "Emitted on every keystroke with the raw, untrimmed input text \u2014 the same string the `empty` slot receives as `query`. This is the only hook for server-side / async filtering; it does not replace or disable the built-in local filtering, so an async consumer must feed results back through `options`.",
|
|
2600
|
+
payload: '["string"]'
|
|
2043
2601
|
}
|
|
2044
2602
|
],
|
|
2045
2603
|
slots: [
|
|
2046
2604
|
{
|
|
2047
|
-
name: "prefix"
|
|
2605
|
+
name: "prefix",
|
|
2606
|
+
description: 'Leading content inside `.t-combobox__control`, before the input. Rendered only when the slot is supplied, wrapped in `<span class="t-combobox__slot t-combobox__slot--prefix">`. No scoped props.'
|
|
2048
2607
|
},
|
|
2049
2608
|
{
|
|
2050
|
-
name: "option"
|
|
2609
|
+
name: "option",
|
|
2610
|
+
description: 'Replaces the default option body (label, description, and the selected check icon). Renders INSIDE the row\'s `<li role="option">`, which owns the click and mouseenter handlers, so it must contain only presentational content. `selected` is `option.value === modelValue`; `active` is the keyboard-highlighted row, which is NOT DOM focus \u2014 focus stays on the input at all times.\n'
|
|
2051
2611
|
},
|
|
2052
2612
|
{
|
|
2053
|
-
name: "empty"
|
|
2613
|
+
name: "empty",
|
|
2614
|
+
description: 'Replaces `emptyText` inside `<li class="t-combobox__empty">` when the filter matches no option. `query` is the current raw input text, untrimmed and uncased. Passing both this slot and `emptyText` renders only the slot.'
|
|
2054
2615
|
}
|
|
2055
2616
|
],
|
|
2056
2617
|
a11y: [
|
|
2057
2618
|
"role: combobox",
|
|
2619
|
+
"combobox_element: input",
|
|
2620
|
+
"accessible_name: None is generated \u2014 there is no label element and no default slot. Pass aria-label or aria-labelledby (which also names the listbox), or pass `id` and wrap in TFormField with a matching `html-for`; TFormField does not link the label on its own.",
|
|
2058
2621
|
"trigger_aria_haspopup: listbox",
|
|
2059
2622
|
"trigger_aria_expanded: true",
|
|
2623
|
+
"trigger_aria_controls_when_open: true",
|
|
2060
2624
|
"aria_autocomplete: list",
|
|
2061
2625
|
"aria_activedescendant_on_active_option: true",
|
|
2626
|
+
"aria_activedescendant_cleared_while_closed: true",
|
|
2062
2627
|
"aria_invalid_when_invalid: true",
|
|
2063
2628
|
"aria_busy_when_loading: true",
|
|
2629
|
+
"listbox_role: listbox",
|
|
2630
|
+
"option_role: option",
|
|
2631
|
+
"listbox_mirrors_aria_label_and_aria_labelledby: true",
|
|
2064
2632
|
"aria_selected_on_options: true",
|
|
2065
2633
|
"aria_disabled_on_disabled_options: true",
|
|
2634
|
+
"focus_stays_on_the_input_options_are_never_focused: true",
|
|
2066
2635
|
"keyboard_arrow_navigation: true",
|
|
2636
|
+
"arrow_navigation_does_not_wrap_at_the_ends: true",
|
|
2637
|
+
"arrow_navigation_skips_disabled_options: true",
|
|
2067
2638
|
"escape_closes_and_restores_previous_selection: true",
|
|
2639
|
+
"escape_is_ignored_while_closed: true",
|
|
2068
2640
|
"enter_selects_active_option: true",
|
|
2641
|
+
"tab_closes_and_restores_previous_selection: true",
|
|
2069
2642
|
"home_end_navigation: true"
|
|
2070
2643
|
],
|
|
2071
2644
|
behavior: [
|
|
2072
2645
|
"update_payload_type: string",
|
|
2646
|
+
"input_text_is_internal_state_not_model_value: true",
|
|
2073
2647
|
"local_filtering_by_label_description_and_keywords: true",
|
|
2648
|
+
"filtering_is_case_insensitive_substring_on_a_trimmed_query: true",
|
|
2649
|
+
"empty_query_shows_all_options: true",
|
|
2650
|
+
"input_change_emits_the_raw_query_for_async_filtering: true",
|
|
2651
|
+
"async_results_are_fed_back_through_the_options_prop: true",
|
|
2074
2652
|
"loading_does_not_disable_by_itself: true",
|
|
2653
|
+
"spinner_replaces_the_chevron_when_loading: true",
|
|
2654
|
+
"chevron_rotates_when_open: true",
|
|
2655
|
+
"check_icon_on_selected_option: true",
|
|
2656
|
+
"focus_opens_the_listbox: true",
|
|
2657
|
+
"click_on_input_opens_the_listbox: true",
|
|
2658
|
+
"typing_opens_the_listbox: true",
|
|
2659
|
+
"arrow_down_opens_the_listbox_with_the_first_enabled_option_active: true",
|
|
2660
|
+
"arrow_up_opens_the_listbox_with_the_last_enabled_option_active: true",
|
|
2661
|
+
"active_option_defaults_to_the_current_selection_when_it_is_in_the_filtered_list: true",
|
|
2662
|
+
"disabled_options_cannot_be_activated_selected_or_hovered: true",
|
|
2663
|
+
"selecting_an_option_sets_the_input_text_to_its_label_and_closes_without_restoring: true",
|
|
2075
2664
|
"outside_click_closes_dropdown: true",
|
|
2665
|
+
"outside_click_is_detected_on_pointerdown_on_document: true",
|
|
2076
2666
|
"query_clears_selection_when_closed_empty: true",
|
|
2077
|
-
"selected_value_restores_when_search_is_abandoned: true"
|
|
2667
|
+
"selected_value_restores_when_search_is_abandoned: true",
|
|
2668
|
+
"external_model_value_and_options_changes_resync_the_input_text_only_while_closed: true",
|
|
2669
|
+
"active_option_is_revalidated_when_the_filtered_list_changes: true",
|
|
2670
|
+
"open_state_emits_are_deduped: true",
|
|
2671
|
+
"listbox_is_not_rendered_while_disabled: true",
|
|
2672
|
+
"listbox_renders_in_flow_with_no_portal_and_no_flip_positioning: true"
|
|
2078
2673
|
],
|
|
2079
2674
|
selection: {
|
|
2080
2675
|
keywords: [
|
|
@@ -2107,7 +2702,8 @@ var treeui_catalog_default = {
|
|
|
2107
2702
|
"Pass `options` as labeled items and keep labels human-readable because search matches visible fields."
|
|
2108
2703
|
]
|
|
2109
2704
|
},
|
|
2110
|
-
recipes: []
|
|
2705
|
+
recipes: [],
|
|
2706
|
+
practices: []
|
|
2111
2707
|
},
|
|
2112
2708
|
{
|
|
2113
2709
|
name: "TConfirmDialog",
|
|
@@ -2130,12 +2726,14 @@ var treeui_catalog_default = {
|
|
|
2130
2726
|
{
|
|
2131
2727
|
name: "defaultOpen",
|
|
2132
2728
|
type: "boolean",
|
|
2133
|
-
default: "false"
|
|
2729
|
+
default: "false",
|
|
2730
|
+
note: "Uncontrolled initial state. Read once on setup \u2014 later changes are ignored. Only meaningful when `open` is left undefined."
|
|
2134
2731
|
},
|
|
2135
2732
|
{
|
|
2136
2733
|
name: "disabled",
|
|
2137
2734
|
type: "boolean",
|
|
2138
|
-
default: "false"
|
|
2735
|
+
default: "false",
|
|
2736
|
+
note: "Only blocks opening from the `trigger` slot (the trigger wrapper gets `aria-disabled` and its click is swallowed). It does NOT block a programmatic open through `open`/`defaultOpen`, and it does not disable the confirm/cancel buttons \u2014 use `confirmDisabled`/`cancelDisabled` for those."
|
|
2139
2737
|
},
|
|
2140
2738
|
{
|
|
2141
2739
|
name: "size",
|
|
@@ -2145,47 +2743,63 @@ var treeui_catalog_default = {
|
|
|
2145
2743
|
"sm",
|
|
2146
2744
|
"md",
|
|
2147
2745
|
"lg"
|
|
2148
|
-
]
|
|
2746
|
+
],
|
|
2747
|
+
note: "Forwarded to TModal and applied as `t-modal__surface--<size>` \u2014 it sizes the dialog surface, not the confirm-dialog block, and it does not size the default footer buttons (those are always TButton `md`)."
|
|
2149
2748
|
},
|
|
2150
2749
|
{
|
|
2151
2750
|
name: "title",
|
|
2152
2751
|
type: "string",
|
|
2153
|
-
default: ""
|
|
2752
|
+
default: "",
|
|
2753
|
+
note: "Rendered by TModal as `t-modal__title` and referenced by `aria-labelledby`. TConfirmDialog does not expose TModal's `header` slot, so an empty title leaves the dialog without an accessible name."
|
|
2154
2754
|
},
|
|
2155
2755
|
{
|
|
2156
2756
|
name: "description",
|
|
2157
2757
|
type: "string",
|
|
2158
|
-
default: ""
|
|
2758
|
+
default: "",
|
|
2759
|
+
note: "Rendered by TModal as `t-modal__description` and referenced by `aria-describedby`. The default slot body is NOT part of the accessible description."
|
|
2159
2760
|
},
|
|
2160
2761
|
{
|
|
2161
2762
|
name: "confirmLabel",
|
|
2162
2763
|
type: "string",
|
|
2163
|
-
default: "Confirm"
|
|
2764
|
+
default: "Confirm",
|
|
2765
|
+
note: "Ignored when the `actions` slot is supplied."
|
|
2164
2766
|
},
|
|
2165
2767
|
{
|
|
2166
2768
|
name: "cancelLabel",
|
|
2167
2769
|
type: "string",
|
|
2168
|
-
default: "Cancel"
|
|
2770
|
+
default: "Cancel",
|
|
2771
|
+
note: "Ignored when the `actions` slot is supplied."
|
|
2169
2772
|
},
|
|
2170
2773
|
{
|
|
2171
2774
|
name: "confirmVariant",
|
|
2172
2775
|
type: "TVariant",
|
|
2173
|
-
default: "danger"
|
|
2776
|
+
default: "danger",
|
|
2777
|
+
values: [
|
|
2778
|
+
"solid",
|
|
2779
|
+
"outline",
|
|
2780
|
+
"ghost",
|
|
2781
|
+
"soft",
|
|
2782
|
+
"danger"
|
|
2783
|
+
],
|
|
2784
|
+
note: "Ignored when the `actions` slot is supplied."
|
|
2174
2785
|
},
|
|
2175
2786
|
{
|
|
2176
2787
|
name: "confirmDisabled",
|
|
2177
2788
|
type: "boolean",
|
|
2178
|
-
default: "false"
|
|
2789
|
+
default: "false",
|
|
2790
|
+
note: "Disables the default confirm button AND short-circuits the confirm handler \u2014 no `confirm` emit and no close, including when the handler is invoked from the `actions` slot scope."
|
|
2179
2791
|
},
|
|
2180
2792
|
{
|
|
2181
2793
|
name: "cancelDisabled",
|
|
2182
2794
|
type: "boolean",
|
|
2183
|
-
default: "false"
|
|
2795
|
+
default: "false",
|
|
2796
|
+
note: "Disables the default cancel button AND short-circuits the cancel handler \u2014 no `cancel` emit and no close, including when the handler is invoked from the `actions` slot scope."
|
|
2184
2797
|
},
|
|
2185
2798
|
{
|
|
2186
2799
|
name: "loading",
|
|
2187
2800
|
type: "boolean",
|
|
2188
|
-
default: "false"
|
|
2801
|
+
default: "false",
|
|
2802
|
+
note: "Puts the default confirm button into its spinner state (TButton adds `is-loading`, `aria-busy`, and the native `disabled` attribute) and short-circuits the confirm handler exactly like `confirmDisabled`. It does not affect the cancel button. Also passed to the `actions` slot scope so a custom footer can mirror the state."
|
|
2189
2803
|
},
|
|
2190
2804
|
{
|
|
2191
2805
|
name: "closeOnEscape",
|
|
@@ -2195,27 +2809,32 @@ var treeui_catalog_default = {
|
|
|
2195
2809
|
{
|
|
2196
2810
|
name: "closeOnOverlay",
|
|
2197
2811
|
type: "boolean",
|
|
2198
|
-
default: "false"
|
|
2812
|
+
default: "false",
|
|
2813
|
+
note: "Deliberately opt-in \u2014 TModal defaults this to true, TConfirmDialog flips it to false so a confirmation is not dismissed by a stray backdrop click."
|
|
2199
2814
|
},
|
|
2200
2815
|
{
|
|
2201
2816
|
name: "showCloseButton",
|
|
2202
2817
|
type: "boolean",
|
|
2203
|
-
default: "false"
|
|
2818
|
+
default: "false",
|
|
2819
|
+
note: "Deliberately opt-in \u2014 TModal defaults this to true. Enabling it adds a header close button that dismisses without emitting `cancel`."
|
|
2204
2820
|
},
|
|
2205
2821
|
{
|
|
2206
2822
|
name: "closeLabel",
|
|
2207
2823
|
type: "string",
|
|
2208
|
-
default: "Close dialog"
|
|
2824
|
+
default: "Close dialog",
|
|
2825
|
+
note: "Accessible name of the header close button. Only rendered when `showCloseButton` is true."
|
|
2209
2826
|
},
|
|
2210
2827
|
{
|
|
2211
2828
|
name: "closeOnConfirm",
|
|
2212
2829
|
type: "boolean",
|
|
2213
|
-
default: "true"
|
|
2830
|
+
default: "true",
|
|
2831
|
+
note: "Set false for async confirmation: `confirm` fires but the dialog stays open, so the caller can hold it open with `loading` while the request resolves and then close it via `open`."
|
|
2214
2832
|
},
|
|
2215
2833
|
{
|
|
2216
2834
|
name: "closeOnCancel",
|
|
2217
2835
|
type: "boolean",
|
|
2218
|
-
default: "true"
|
|
2836
|
+
default: "true",
|
|
2837
|
+
note: "Set false to keep the dialog open after `cancel` \u2014 the caller then owns closing via `open`."
|
|
2219
2838
|
}
|
|
2220
2839
|
],
|
|
2221
2840
|
events: [
|
|
@@ -2234,16 +2853,20 @@ var treeui_catalog_default = {
|
|
|
2234
2853
|
],
|
|
2235
2854
|
slots: [
|
|
2236
2855
|
{
|
|
2237
|
-
name: "trigger"
|
|
2856
|
+
name: "trigger",
|
|
2857
|
+
description: "Element that opens the dialog on click. Omit for imperative use."
|
|
2238
2858
|
},
|
|
2239
2859
|
{
|
|
2240
|
-
name: "icon"
|
|
2860
|
+
name: "icon",
|
|
2861
|
+
description: "Decorative leading icon. Presence switches the block to the two-column icon layout."
|
|
2241
2862
|
},
|
|
2242
2863
|
{
|
|
2243
|
-
name: "default"
|
|
2864
|
+
name: "default",
|
|
2865
|
+
description: "Extra body content rendered under the description."
|
|
2244
2866
|
},
|
|
2245
2867
|
{
|
|
2246
|
-
name: "actions"
|
|
2868
|
+
name: "actions",
|
|
2869
|
+
description: "Replaces the whole footer. Scope gives you confirm(), cancel(), and loading."
|
|
2247
2870
|
}
|
|
2248
2871
|
],
|
|
2249
2872
|
a11y: [
|
|
@@ -2251,15 +2874,26 @@ var treeui_catalog_default = {
|
|
|
2251
2874
|
"aria_modal: true",
|
|
2252
2875
|
"focus_trap: inherited_from_modal",
|
|
2253
2876
|
"restores_focus_on_close: inherited_from_modal",
|
|
2877
|
+
"restore_focus_caveat: TModal only records the previously focused element when the dialog is opened by clicking its `trigger` slot. A dialog opened programmatically \u2014 by setting `open` from a row action, a menu item, or `defaultOpen` \u2014 has nothing recorded, so focus is not restored on close. Move focus back yourself in that case.",
|
|
2878
|
+
"accessible_name_source: `title` prop, via aria-labelledby; absent when `title` is empty",
|
|
2879
|
+
"accessible_description_source: `description` prop, via aria-describedby; the default slot body is not included",
|
|
2880
|
+
"initial_focus: First focusable element inside the dialog surface. With the default footer and `showCloseButton: false` that is the cancel button, which is the safe landing spot for a destructive confirmation. Enabling `showCloseButton` moves initial focus to the header close button instead. A `loading` or `confirmDisabled` confirm button carries the native `disabled` attribute and is skipped.",
|
|
2254
2881
|
"icon_slot_marked_aria_hidden: true"
|
|
2255
2882
|
],
|
|
2256
2883
|
behavior: [
|
|
2257
2884
|
"built_on_modal_contract: true",
|
|
2258
2885
|
"default_confirm_button_variant: danger",
|
|
2886
|
+
"default_cancel_button_variant: ghost",
|
|
2259
2887
|
"overlay_click_disabled_by_default: true",
|
|
2260
2888
|
"close_button_hidden_by_default: true",
|
|
2261
2889
|
"loading_state_applies_to_confirm_button: true",
|
|
2262
|
-
"
|
|
2890
|
+
"confirm_suppressed_when: confirmDisabled || loading \u2014 the handler returns before emitting, so neither `confirm` nor the close runs",
|
|
2891
|
+
"cancel_suppressed_when: cancelDisabled \u2014 the handler returns before emitting, so neither `cancel` nor the close runs",
|
|
2892
|
+
"closes_after_confirm_when: closeOnConfirm",
|
|
2893
|
+
"closes_after_cancel_when: closeOnCancel",
|
|
2894
|
+
"guards_and_auto_close_apply_to_actions_slot: true",
|
|
2895
|
+
"close_button_and_escape_do_not_emit_cancel: true",
|
|
2896
|
+
"inherits_teleport_scroll_lock_and_focus_trap_from_modal: true"
|
|
2263
2897
|
],
|
|
2264
2898
|
selection: {
|
|
2265
2899
|
keywords: [],
|
|
@@ -2273,6 +2907,9 @@ var treeui_catalog_default = {
|
|
|
2273
2907
|
},
|
|
2274
2908
|
recipes: [
|
|
2275
2909
|
"confirm-destructive-action"
|
|
2910
|
+
],
|
|
2911
|
+
practices: [
|
|
2912
|
+
"accessible-by-default"
|
|
2276
2913
|
]
|
|
2277
2914
|
},
|
|
2278
2915
|
{
|
|
@@ -2325,7 +2962,9 @@ var treeui_catalog_default = {
|
|
|
2325
2962
|
}
|
|
2326
2963
|
],
|
|
2327
2964
|
a11y: [
|
|
2328
|
-
"Acts as a structural wrapper only; semantics come from the `as` prop and child content."
|
|
2965
|
+
"Acts as a structural wrapper only; semantics come from the `as` prop and child content.",
|
|
2966
|
+
'Renders a non-semantic `div` by default. Pass `as` to make it a landmark (e.g. `as="main"`, `as="section"`, `as="header"`) \u2014 avoid nesting a second `main` inside an app shell or a TPage that already provides one.\n',
|
|
2967
|
+
"`aria-*` and `role` attributes fall through to the root element (see `forwards_attrs_to`)."
|
|
2329
2968
|
],
|
|
2330
2969
|
behavior: [
|
|
2331
2970
|
"semantic_element_controlled_by_as: true",
|
|
@@ -2369,6 +3008,9 @@ var treeui_catalog_default = {
|
|
|
2369
3008
|
},
|
|
2370
3009
|
recipes: [
|
|
2371
3010
|
"sidebar-shell"
|
|
3011
|
+
],
|
|
3012
|
+
practices: [
|
|
3013
|
+
"content-alignment"
|
|
2372
3014
|
]
|
|
2373
3015
|
},
|
|
2374
3016
|
{
|
|
@@ -2377,6 +3019,8 @@ var treeui_catalog_default = {
|
|
|
2377
3019
|
package: "@treeui/vue",
|
|
2378
3020
|
category: "Overlay",
|
|
2379
3021
|
status: "stable",
|
|
3022
|
+
description: "Right-click (contextmenu) menu teleported to body and positioned at the cursor. The component renders no chrome of its own \u2014 the root wrapper is `display: contents` and only wraps the slotted trigger area.\n",
|
|
3023
|
+
sourceFile: "packages/vue/src/components/TContextMenu.vue",
|
|
2380
3024
|
storyFile: "apps/docs/src/stories/ContextMenu.stories.ts",
|
|
2381
3025
|
storyTitle: "Components/Overlay/ContextMenu",
|
|
2382
3026
|
manifestFile: "docs/ai/COMPONENTS/context-menu.yaml",
|
|
@@ -2385,73 +3029,84 @@ var treeui_catalog_default = {
|
|
|
2385
3029
|
name: "items",
|
|
2386
3030
|
type: "TContextMenuItem[]",
|
|
2387
3031
|
default: "[]",
|
|
2388
|
-
description:
|
|
3032
|
+
description: 'Menu items to render, one `role="menuitem"` <li> each. An empty array is allowed and still opens an empty `role="menu"` list with nothing focused.\n'
|
|
2389
3033
|
},
|
|
2390
3034
|
{
|
|
2391
3035
|
name: "open",
|
|
2392
3036
|
type: "boolean | undefined",
|
|
2393
3037
|
default: "undefined",
|
|
2394
|
-
description: "Controlled open state (v-model:open)."
|
|
3038
|
+
description: "Controlled open state (v-model:open). When defined it wins over the internal state and `defaultOpen` is ignored; the component still emits and expects the parent to write the new value back. `disabled` overrides this \u2014 a disabled component renders no menu even while `open` is true.\n"
|
|
2395
3039
|
},
|
|
2396
3040
|
{
|
|
2397
3041
|
name: "defaultOpen",
|
|
2398
3042
|
type: "boolean",
|
|
2399
3043
|
default: "false",
|
|
2400
|
-
description: "Uncontrolled initial open state."
|
|
3044
|
+
description: "Uncontrolled initial open state. Read once during setup \u2014 later changes to this prop have no effect.\n"
|
|
2401
3045
|
},
|
|
2402
3046
|
{
|
|
2403
3047
|
name: "disabled",
|
|
2404
3048
|
type: "boolean",
|
|
2405
3049
|
default: "false",
|
|
2406
|
-
description: "Prevents the context menu from opening."
|
|
3050
|
+
description: "Prevents the context menu from opening, and hides it if it is already open. While disabled the component does not call preventDefault on `contextmenu`, so the native browser menu appears instead.\n"
|
|
2407
3051
|
},
|
|
2408
3052
|
{
|
|
2409
3053
|
name: "size",
|
|
2410
3054
|
type: "TSize",
|
|
2411
3055
|
default: "md",
|
|
2412
|
-
|
|
3056
|
+
values: [
|
|
3057
|
+
"sm",
|
|
3058
|
+
"md",
|
|
3059
|
+
"lg"
|
|
3060
|
+
],
|
|
3061
|
+
description: "Item sizing variant. The modifier class is applied to both the root and the teleported menu, but only the copy on the menu is effective (the root is teleport-detached from the menu subtree).\n"
|
|
2413
3062
|
}
|
|
2414
3063
|
],
|
|
2415
3064
|
events: [
|
|
2416
3065
|
{
|
|
2417
3066
|
name: "select",
|
|
2418
|
-
description: "Emitted when
|
|
3067
|
+
description: "Emitted with `item.value` when an enabled item is activated by click or Enter/Space. Disabled items emit nothing.\n",
|
|
2419
3068
|
payload: "[value: string]"
|
|
2420
3069
|
},
|
|
2421
3070
|
{
|
|
2422
3071
|
name: "update:open",
|
|
2423
|
-
description: "Emitted when open state changes (v-model support).",
|
|
3072
|
+
description: "Emitted when open state changes (v-model support). Only fires on an actual transition \u2014 setting the same value again is a no-op.\n",
|
|
2424
3073
|
payload: "[value: boolean]"
|
|
2425
3074
|
},
|
|
2426
3075
|
{
|
|
2427
3076
|
name: "open-change",
|
|
2428
|
-
description: "Emitted when open state changes.",
|
|
3077
|
+
description: "Emitted when open state changes. Always fires together with `update:open`, including in controlled mode.\n",
|
|
2429
3078
|
payload: "[value: boolean]"
|
|
2430
3079
|
}
|
|
2431
3080
|
],
|
|
2432
3081
|
slots: [
|
|
2433
3082
|
{
|
|
2434
3083
|
name: "default",
|
|
2435
|
-
description: "Content that acts as the right-click trigger area."
|
|
3084
|
+
description: "Content that acts as the right-click trigger area. It is rendered inside the root <div>, which is `display: contents` and therefore contributes no box of its own \u2014 the slotted content keeps its own layout, and the `contextmenu` handler still fires through event bubbling.\n"
|
|
2436
3085
|
},
|
|
2437
3086
|
{
|
|
2438
3087
|
name: "item",
|
|
2439
|
-
description:
|
|
3088
|
+
description: 'Custom rendering for each menu item; scoped props `{ item, index }`, falls back to `{{ item.label }}`. Rendered inside the `role="menuitem"` <li>, which already owns click, keydown, tabindex and aria-disabled \u2014 keep the content presentational, nested interactive controls are not reachable inside a menuitem.\n'
|
|
2440
3089
|
}
|
|
2441
3090
|
],
|
|
2442
3091
|
a11y: [
|
|
2443
|
-
"role: menu (on the floating list)",
|
|
3092
|
+
"role: menu (on the teleported floating list)",
|
|
2444
3093
|
"items_role: menuitem",
|
|
2445
|
-
'keyboard: ["Right-click / contextmenu event opens menu at cursor","ArrowDown / ArrowUp
|
|
2446
|
-
'aria: ["aria-disabled on disabled items","aria-label on menu element"]',
|
|
2447
|
-
'focus: ["First enabled item receives focus on open","Focus restored to trigger area on close"]'
|
|
3094
|
+
'keyboard: ["Right-click / contextmenu event opens menu at cursor","ArrowDown / ArrowUp move focus to the next / previous enabled item (clamped, no wrap)","Home / End jumps to first / last enabled item","Enter / Space selects focused item","Escape closes menu and restores focus","All key handling lives on the items \u2014 keys are only handled while an item has focus"]',
|
|
3095
|
+
'aria: ["aria-disabled on disabled items (omitted, not false, when enabled)","aria-label=\\"Context menu\\" on the menu element \u2014 hardcoded, not configurable or localizable","Menu id is generated with createId(\'t-context-menu\'); there is no `id` prop","tabindex 0 on enabled items, -1 on disabled items \u2014 no roving tabindex, every enabled item is tab-reachable"]',
|
|
3096
|
+
'focus: ["First enabled item receives focus on open","When every item is disabled, focus still goes to the first item; with an empty `items` array nothing is focused","Focus restored to trigger area on close from Escape or item selection","An outside click closes without restoring focus, leaving it where the pointer put it"]'
|
|
2448
3097
|
],
|
|
2449
3098
|
behavior: [
|
|
2450
|
-
"Opens at cursor position on right-click (contextmenu event).",
|
|
2451
|
-
"Uses Teleport to body to escape stacking contexts.",
|
|
2452
|
-
"
|
|
2453
|
-
"
|
|
2454
|
-
"
|
|
3099
|
+
"Opens at cursor position on right-click (contextmenu event), using event.clientX / clientY.",
|
|
3100
|
+
"Uses Teleport to body to escape stacking contexts; the menu is not a DOM descendant of the trigger.",
|
|
3101
|
+
"Uses position fixed at the raw cursor coordinates, stacked at var(--tree-z-dropdown).",
|
|
3102
|
+
"No collision detection or viewport clamping \u2014 a menu opened near the right or bottom edge overflows.",
|
|
3103
|
+
"Closes on pointerdown outside the menu (including on the trigger itself), Escape, or item selection.",
|
|
3104
|
+
"Right-clicking again inside the trigger area repositions the menu \u2014 the outside pointerdown closes it and the following contextmenu reopens it at the new coordinates.",
|
|
3105
|
+
"A document-level contextmenu listener covers keyboard-invoked menus (Shift+F10 / Menu key) raised outside the trigger.",
|
|
3106
|
+
"Prevents native browser context menu on trigger area, but only while not disabled.",
|
|
3107
|
+
'Exposes data-state="open" | "closed" on the root element for external styling.',
|
|
3108
|
+
"Document pointerdown / contextmenu listeners are attached only while open, and removed on close and before unmount.",
|
|
3109
|
+
"Menu enter / leave uses the shared t-fade transition (opacity plus scale 0.95)."
|
|
2455
3110
|
],
|
|
2456
3111
|
selection: {
|
|
2457
3112
|
keywords: [
|
|
@@ -2476,7 +3131,8 @@ var treeui_catalog_default = {
|
|
|
2476
3131
|
required: [],
|
|
2477
3132
|
notes: []
|
|
2478
3133
|
},
|
|
2479
|
-
recipes: []
|
|
3134
|
+
recipes: [],
|
|
3135
|
+
practices: []
|
|
2480
3136
|
},
|
|
2481
3137
|
{
|
|
2482
3138
|
name: "TDatePicker",
|
|
@@ -2494,17 +3150,20 @@ var treeui_catalog_default = {
|
|
|
2494
3150
|
{
|
|
2495
3151
|
name: "modelValue",
|
|
2496
3152
|
type: "string",
|
|
2497
|
-
default: ""
|
|
3153
|
+
default: "",
|
|
3154
|
+
note: "Parsed with `parseDateValue`, which accepts ONLY a strict `YYYY-MM-DD` string that resolves to a real calendar date. Anything else (empty, `2026-13-01`, an ISO datetime, a Date object stringified) resolves to null and the trigger falls back to `placeholder`. The hidden input, when present, still submits the raw prop verbatim \u2014 an unparseable value renders as the placeholder but is submitted as-is."
|
|
2498
3155
|
},
|
|
2499
3156
|
{
|
|
2500
3157
|
name: "open",
|
|
2501
3158
|
type: "boolean",
|
|
2502
|
-
default: "
|
|
3159
|
+
default: "undefined",
|
|
3160
|
+
note: "Controlled open state. Once a boolean is passed the component stops tracking open state internally \u2014 it only emits update:open / open-change and the consumer MUST write the value back, or the calendar never opens."
|
|
2503
3161
|
},
|
|
2504
3162
|
{
|
|
2505
3163
|
name: "defaultOpen",
|
|
2506
3164
|
type: "boolean",
|
|
2507
|
-
default: "false"
|
|
3165
|
+
default: "false",
|
|
3166
|
+
note: "Uncontrolled initial open state, read once on mount. Later changes to it are ignored. Opening this way skips `openCalendar`, so no day button receives DOM focus until the user tabs or arrows into the grid."
|
|
2508
3167
|
},
|
|
2509
3168
|
{
|
|
2510
3169
|
name: "size",
|
|
@@ -2514,41 +3173,48 @@ var treeui_catalog_default = {
|
|
|
2514
3173
|
"sm",
|
|
2515
3174
|
"md",
|
|
2516
3175
|
"lg"
|
|
2517
|
-
]
|
|
3176
|
+
],
|
|
3177
|
+
note: "Sizes the trigger only, never the popover. `md` has no CSS rule of its own \u2014 it is the base `.t-date-picker__trigger` styling \u2014 but the `t-date-picker--md` class is still rendered."
|
|
2518
3178
|
},
|
|
2519
3179
|
{
|
|
2520
3180
|
name: "disabled",
|
|
2521
3181
|
type: "boolean",
|
|
2522
|
-
default: "false"
|
|
3182
|
+
default: "false",
|
|
3183
|
+
note: 'Sets the native `disabled` attribute on the trigger, adds `is-disabled` to the root, short-circuits `openCalendar` and trigger keydown, makes `isDateDisabled` return true for every date, and suppresses the popover entirely (`v-if="isOpen && !disabled"`) even while `open` is true.'
|
|
2523
3184
|
},
|
|
2524
3185
|
{
|
|
2525
3186
|
name: "invalid",
|
|
2526
3187
|
type: "boolean",
|
|
2527
|
-
default: "false"
|
|
3188
|
+
default: "false",
|
|
3189
|
+
note: 'Adds `is-invalid` to the root and `aria-invalid="true"` to the trigger. Purely presentational \u2014 it does not block opening or selection.'
|
|
2528
3190
|
},
|
|
2529
3191
|
{
|
|
2530
3192
|
name: "placeholder",
|
|
2531
3193
|
type: "string",
|
|
2532
|
-
default: "Select date"
|
|
3194
|
+
default: "Select date",
|
|
3195
|
+
note: "Rendered inside `.t-date-picker__value` with a `data-placeholder` attribute whenever `modelValue` does not parse."
|
|
2533
3196
|
},
|
|
2534
3197
|
{
|
|
2535
3198
|
name: "locale",
|
|
2536
3199
|
type: "string",
|
|
2537
|
-
default: "en-US"
|
|
3200
|
+
default: "en-US",
|
|
3201
|
+
note: "BCP-47 tag passed to three separate `Intl.DateTimeFormat` calls: the trigger text (day numeric / month long / year numeric), the popover month caption (month long / year numeric), and the weekday header (weekday short). It does NOT localize the per-day `aria-label`, which is always the raw `YYYY-MM-DD` key."
|
|
2538
3202
|
},
|
|
2539
3203
|
{
|
|
2540
3204
|
name: "min",
|
|
2541
3205
|
type: "string",
|
|
2542
|
-
default: ""
|
|
3206
|
+
default: "",
|
|
3207
|
+
note: "Inclusive lower bound. Days before it get the native `disabled` attribute and cannot be selected or arrowed onto; the Previous-month nav button is disabled once the view reaches the min month. A value that fails `parseDateValue` is ignored, i.e. treated as no bound."
|
|
2543
3208
|
},
|
|
2544
3209
|
{
|
|
2545
3210
|
name: "max",
|
|
2546
3211
|
type: "string",
|
|
2547
|
-
default: ""
|
|
3212
|
+
default: "",
|
|
3213
|
+
note: "Inclusive upper bound, mirroring `min`: out-of-range days are disabled and the Next-month nav button is disabled once the view reaches the max month."
|
|
2548
3214
|
},
|
|
2549
3215
|
{
|
|
2550
3216
|
name: "weekStartsOn",
|
|
2551
|
-
type: "
|
|
3217
|
+
type: "0 | 1 | 2 | 3 | 4 | 5 | 6",
|
|
2552
3218
|
default: "0",
|
|
2553
3219
|
values: [
|
|
2554
3220
|
"0",
|
|
@@ -2558,46 +3224,90 @@ var treeui_catalog_default = {
|
|
|
2558
3224
|
"4",
|
|
2559
3225
|
"5",
|
|
2560
3226
|
"6"
|
|
2561
|
-
]
|
|
3227
|
+
],
|
|
3228
|
+
note: "0 = Sunday. Drives the weekday header order, the leading offset of the day grid, and the Home/End keys (which jump to the first/last day of the week as defined by this prop)."
|
|
2562
3229
|
},
|
|
2563
3230
|
{
|
|
2564
3231
|
name: "id",
|
|
2565
3232
|
type: "string",
|
|
2566
|
-
default: "auto"
|
|
3233
|
+
default: "auto",
|
|
3234
|
+
note: "Names the CALENDAR POPOVER, not the trigger. It becomes the popover's `id` (referenced by the trigger's `aria-controls` while open) and seeds the month caption id as `${id}-caption`. Read once at setup \u2014 later changes are ignored. Because `id` is a declared prop it never falls through to the trigger button, so the trigger has no id and a `<label for>` / `TFormField html-for` cannot target it; name the control with `aria-label` instead."
|
|
2567
3235
|
}
|
|
2568
3236
|
],
|
|
2569
3237
|
events: [
|
|
2570
3238
|
{
|
|
2571
|
-
name: "update:modelValue"
|
|
3239
|
+
name: "update:modelValue",
|
|
3240
|
+
description: 'Emitted with the chosen day as `YYYY-MM-DD` from `selectDate` only \u2014 a click or Enter/Space on an enabled day button. Nothing else in the component emits it; there is no clear affordance, so the value never becomes `""` on its own.',
|
|
3241
|
+
payload: '["string"]'
|
|
2572
3242
|
},
|
|
2573
3243
|
{
|
|
2574
|
-
name: "update:open"
|
|
3244
|
+
name: "update:open",
|
|
3245
|
+
description: "Emitted whenever the open state changes. Deduped \u2014 no emit when the next value equals the current one.",
|
|
3246
|
+
payload: '["boolean"]'
|
|
2575
3247
|
},
|
|
2576
3248
|
{
|
|
2577
|
-
name: "open-change"
|
|
3249
|
+
name: "open-change",
|
|
3250
|
+
description: "Emitted immediately after `update:open`, with the same payload. Alias for consumers that do not use v-model:open.",
|
|
3251
|
+
payload: '["boolean"]'
|
|
2578
3252
|
},
|
|
2579
3253
|
{
|
|
2580
|
-
name: "select"
|
|
3254
|
+
name: "select",
|
|
3255
|
+
description: "Emitted from `selectDate` immediately after `update:modelValue`, with the same `YYYY-MM-DD` payload. It is the user-intent signal: it fires only on an actual day activation and never when `modelValue` changes from outside, which is what distinguishes it from `update:modelValue`.",
|
|
3256
|
+
payload: '["string"]'
|
|
2581
3257
|
}
|
|
2582
3258
|
],
|
|
2583
3259
|
slots: [
|
|
2584
3260
|
{
|
|
2585
|
-
name: "prefix"
|
|
3261
|
+
name: "prefix",
|
|
3262
|
+
description: 'Leading content inside the trigger button, before the value text. Rendered only when the slot is supplied, wrapped in `<span class="t-date-picker__slot t-date-picker__slot--prefix">`. No scoped props. Content is inside a `<button>`, so it must be presentational only.'
|
|
2586
3263
|
},
|
|
2587
3264
|
{
|
|
2588
|
-
name: "suffix"
|
|
3265
|
+
name: "suffix",
|
|
3266
|
+
description: 'Trailing content inside the trigger button, in `<span class="t-date-picker__slot t-date-picker__slot--suffix">`. Unlike `prefix` the wrapper is always rendered; supplying the slot replaces the default calendar icon. No scoped props, and the same presentational-only restriction applies.'
|
|
2589
3267
|
}
|
|
2590
3268
|
],
|
|
2591
3269
|
a11y: [
|
|
3270
|
+
"role: dialog",
|
|
3271
|
+
"accessible_name: None is generated for the trigger beyond its own text content, which is the formatted date or the placeholder \u2014 that changes as the user picks, so it is not a stable label. Pass `aria-label` (see example). The `id` prop cannot be used to link an external <label>.",
|
|
2592
3272
|
"trigger_has_popup_dialog: true",
|
|
3273
|
+
"trigger_aria_expanded: true",
|
|
3274
|
+
"trigger_aria_controls_when_open: true",
|
|
3275
|
+
"aria_invalid_when_invalid: true",
|
|
2593
3276
|
"calendar_uses_grid_roles: true",
|
|
3277
|
+
"calendar_aria_modal: false",
|
|
3278
|
+
"calendar_labelled_by_month_caption: true",
|
|
3279
|
+
"weekday_header_is_aria_hidden: true",
|
|
3280
|
+
"aria_selected_rendered_on_every_gridcell: true",
|
|
3281
|
+
"aria_current_date_on_today: true",
|
|
3282
|
+
"day_aria_label_is_the_raw_iso_key: true",
|
|
3283
|
+
"nav_buttons_labelled_previous_month_and_next_month: true",
|
|
3284
|
+
"roving_tabindex_one_focusable_day: true",
|
|
2594
3285
|
"escape_closes: true",
|
|
2595
|
-
"returns_focus_to_trigger_after_selection: true"
|
|
3286
|
+
"returns_focus_to_trigger_after_selection: true",
|
|
3287
|
+
"returns_focus_to_trigger_on_escape_from_a_day: true",
|
|
3288
|
+
"focus_is_not_trapped_and_tab_leaves_the_open_calendar: true"
|
|
2596
3289
|
],
|
|
2597
3290
|
behavior: [
|
|
3291
|
+
"value_format: YYYY-MM-DD",
|
|
3292
|
+
"controlled_and_uncontrolled_open: true",
|
|
3293
|
+
"open_state_emits_are_deduped: true",
|
|
2598
3294
|
"selection_closes_popover: true",
|
|
2599
3295
|
"hidden_input_created_when_name_attr_present: true",
|
|
2600
|
-
"
|
|
3296
|
+
"hidden_input_submits_the_raw_unparsed_model_value: true",
|
|
3297
|
+
"out_of_range_dates_disabled: true",
|
|
3298
|
+
"min_and_max_also_disable_the_month_nav_buttons: true",
|
|
3299
|
+
"popover_is_not_rendered_while_disabled: true",
|
|
3300
|
+
"outside_click_closes_calendar: true",
|
|
3301
|
+
"outside_click_is_detected_on_pointerdown_on_document: true",
|
|
3302
|
+
"outside_click_and_trigger_toggle_close_without_restoring_focus: true",
|
|
3303
|
+
"grid_is_always_six_weeks_forty_two_days: true",
|
|
3304
|
+
"leading_and_trailing_days_render_muted_and_stay_selectable: true",
|
|
3305
|
+
"opening_syncs_the_view_to_the_selected_date_else_the_last_focused_date_else_today: true",
|
|
3306
|
+
"external_model_value_changes_move_the_view_and_the_focused_day: true",
|
|
3307
|
+
"clearing_the_model_value_resets_the_view_to_today_only_while_closed: true",
|
|
3308
|
+
"month_nav_moves_the_focused_day_to_the_first_of_the_new_month_and_focuses_it: true",
|
|
3309
|
+
"today_is_computed_once_at_setup_not_re_evaluated_across_midnight: true",
|
|
3310
|
+
"popover_renders_in_flow_with_no_portal_and_no_flip_positioning: true"
|
|
2601
3311
|
],
|
|
2602
3312
|
selection: {
|
|
2603
3313
|
keywords: [
|
|
@@ -2625,13 +3335,14 @@ var treeui_catalog_default = {
|
|
|
2625
3335
|
"Use `min` and `max` with the same format."
|
|
2626
3336
|
]
|
|
2627
3337
|
},
|
|
2628
|
-
recipes: []
|
|
3338
|
+
recipes: [],
|
|
3339
|
+
practices: []
|
|
2629
3340
|
},
|
|
2630
3341
|
{
|
|
2631
3342
|
name: "TDateTimePicker",
|
|
2632
3343
|
aliases: [],
|
|
2633
3344
|
package: "@treeui/vue",
|
|
2634
|
-
kind: "
|
|
3345
|
+
kind: "form_overlay",
|
|
2635
3346
|
category: "Data Entry",
|
|
2636
3347
|
status: "available",
|
|
2637
3348
|
purpose: "Date and time picker with a calendar grid, time selection, and overlay trigger.",
|
|
@@ -2644,7 +3355,7 @@ var treeui_catalog_default = {
|
|
|
2644
3355
|
name: "modelValue",
|
|
2645
3356
|
type: "string",
|
|
2646
3357
|
default: "",
|
|
2647
|
-
note: "
|
|
3358
|
+
note: "Always emitted as `YYYY-MM-DDTHH:mm`. On input it also parses `YYYY-MM-DD` (midnight) and `YYYY-MM-DDTHH:mm:ss`; anything else parses to null and renders the placeholder."
|
|
2648
3359
|
},
|
|
2649
3360
|
{
|
|
2650
3361
|
name: "open",
|
|
@@ -2664,17 +3375,20 @@ var treeui_catalog_default = {
|
|
|
2664
3375
|
"sm",
|
|
2665
3376
|
"md",
|
|
2666
3377
|
"lg"
|
|
2667
|
-
]
|
|
3378
|
+
],
|
|
3379
|
+
note: "Renders as `t-date-picker--<size>` on the root \u2014 there is no `t-date-time-picker--<size>` modifier."
|
|
2668
3380
|
},
|
|
2669
3381
|
{
|
|
2670
3382
|
name: "disabled",
|
|
2671
3383
|
type: "boolean",
|
|
2672
|
-
default: "false"
|
|
3384
|
+
default: "false",
|
|
3385
|
+
note: "Blocks opening via click/keyboard and suppresses the overlay entirely, even when `open` is true."
|
|
2673
3386
|
},
|
|
2674
3387
|
{
|
|
2675
3388
|
name: "loading",
|
|
2676
3389
|
type: "boolean",
|
|
2677
|
-
default: "false"
|
|
3390
|
+
default: "false",
|
|
3391
|
+
note: "Only swaps the default suffix icon for a TSpinner; the trigger stays enabled and interactive."
|
|
2678
3392
|
},
|
|
2679
3393
|
{
|
|
2680
3394
|
name: "invalid",
|
|
@@ -2689,33 +3403,38 @@ var treeui_catalog_default = {
|
|
|
2689
3403
|
{
|
|
2690
3404
|
name: "locale",
|
|
2691
3405
|
type: "string",
|
|
2692
|
-
default: "en-US"
|
|
3406
|
+
default: "en-US",
|
|
3407
|
+
note: "Feeds all four Intl.DateTimeFormat calls: trigger text, draft preview, month caption, weekday labels."
|
|
2693
3408
|
},
|
|
2694
3409
|
{
|
|
2695
3410
|
name: "min",
|
|
2696
3411
|
type: "string",
|
|
2697
|
-
default: ""
|
|
3412
|
+
default: "",
|
|
3413
|
+
note: "`YYYY-MM-DD` (resolved to 00:00 of that day) or `YYYY-MM-DDTHH:mm`."
|
|
2698
3414
|
},
|
|
2699
3415
|
{
|
|
2700
3416
|
name: "max",
|
|
2701
3417
|
type: "string",
|
|
2702
|
-
default: ""
|
|
3418
|
+
default: "",
|
|
3419
|
+
note: "`YYYY-MM-DD` (resolved to 23:59:59.999 of that day) or `YYYY-MM-DDTHH:mm`."
|
|
2703
3420
|
},
|
|
2704
3421
|
{
|
|
2705
3422
|
name: "weekStartsOn",
|
|
2706
3423
|
type: "0 | 1 | 2 | 3 | 4 | 5 | 6",
|
|
2707
|
-
default: "0"
|
|
3424
|
+
default: "0",
|
|
3425
|
+
note: "0 = Sunday. Reorders the weekday header labels, the grid start date, and Home/End day navigation."
|
|
2708
3426
|
},
|
|
2709
3427
|
{
|
|
2710
3428
|
name: "id",
|
|
2711
3429
|
type: "string",
|
|
2712
|
-
default: "auto"
|
|
3430
|
+
default: "auto",
|
|
3431
|
+
note: "Id of the overlay dialog only \u2014 not of the root or the trigger. Read once at setup, so later changes are ignored. The trigger points at it with aria-controls while open."
|
|
2713
3432
|
},
|
|
2714
3433
|
{
|
|
2715
3434
|
name: "step",
|
|
2716
3435
|
type: "number",
|
|
2717
3436
|
default: "60",
|
|
2718
|
-
note: "Seconds between
|
|
3437
|
+
note: "Seconds between minute options. Must be a positive multiple of 60 below 3600; any other value falls back to 1-minute options. Hours are always 0-23 regardless of step."
|
|
2719
3438
|
}
|
|
2720
3439
|
],
|
|
2721
3440
|
events: [
|
|
@@ -2735,12 +3454,28 @@ var treeui_catalog_default = {
|
|
|
2735
3454
|
name: "select"
|
|
2736
3455
|
}
|
|
2737
3456
|
],
|
|
2738
|
-
slots: [
|
|
3457
|
+
slots: [
|
|
3458
|
+
{
|
|
3459
|
+
name: "prefix"
|
|
3460
|
+
},
|
|
3461
|
+
{
|
|
3462
|
+
name: "suffix"
|
|
3463
|
+
}
|
|
3464
|
+
],
|
|
2739
3465
|
a11y: [
|
|
2740
3466
|
"role: dialog",
|
|
3467
|
+
"aria_modal: false \u2014 the overlay is non-modal and does not trap focus",
|
|
2741
3468
|
"trigger_aria_haspopup: dialog",
|
|
2742
3469
|
"trigger_aria_expanded: true",
|
|
2743
|
-
"
|
|
3470
|
+
"trigger_aria_controls_when_open: true",
|
|
3471
|
+
"overlay_labelled_by_month_caption: true",
|
|
3472
|
+
"calendar_uses_grid_roles: true",
|
|
3473
|
+
"day_buttons_use_roving_tabindex: true",
|
|
3474
|
+
"day_buttons_aria_pressed_when_selected: true",
|
|
3475
|
+
"gridcell_aria_selected: true",
|
|
3476
|
+
"weekday_row_aria_hidden: true",
|
|
3477
|
+
"time_selects_have_aria_labels: true",
|
|
3478
|
+
"focus_restores_on_close: Only when closing via Apply, Clear, or Escape from a day button. Closing by clicking the trigger, Escape on the trigger, or an outside pointerdown leaves focus where it is.",
|
|
2744
3479
|
"keyboard_calendar_navigation: true",
|
|
2745
3480
|
"escape_closes_overlay: true",
|
|
2746
3481
|
"aria_invalid_when_invalid: true",
|
|
@@ -2750,7 +3485,21 @@ var treeui_catalog_default = {
|
|
|
2750
3485
|
"controlled_and_uncontrolled_open: true",
|
|
2751
3486
|
"value_format: YYYY-MM-DDTHH:mm",
|
|
2752
3487
|
"min_and_max_limit_available_values: true",
|
|
2753
|
-
"time_options_generated_from_step: true"
|
|
3488
|
+
"time_options_generated_from_step: true",
|
|
3489
|
+
"draft_then_commit: Choosing a day and changing the Hour/Minute selects mutate an internal draft only. Nothing is emitted and the overlay does NOT close until Apply \u2014 unlike TDatePicker, where selecting a day commits and closes.",
|
|
3490
|
+
"apply_emit_order: update:modelValue, then change, then select \u2014 all carrying the same `YYYY-MM-DDTHH:mm` string.",
|
|
3491
|
+
"clear_emits_empty_string: Clear emits update:modelValue, change, and select with `''`, then closes.",
|
|
3492
|
+
"default_draft_when_value_is_empty: Now, rounded UP to the next `step` boundary (minimum 60s) with seconds zeroed, then clamped into min/max.",
|
|
3493
|
+
"draft_resyncs_from_model_value_only_while_closed: true",
|
|
3494
|
+
"draft_is_clamped_into_min_max_on_open_and_on_day_select: true",
|
|
3495
|
+
"minute_options_always_include_the_current_draft_minute: true",
|
|
3496
|
+
"hour_option_disabled_when_no_minute_in_that_hour_is_available: true",
|
|
3497
|
+
"month_nav_buttons_disabled_at_min_max_month: true",
|
|
3498
|
+
"out_of_range_days_disabled: true",
|
|
3499
|
+
"outside_pointerdown_closes: true",
|
|
3500
|
+
"overlay_is_not_rendered_while_disabled: true",
|
|
3501
|
+
"hidden_input_created_when_name_attr_present: true",
|
|
3502
|
+
"open_state_emits_are_deduped: true"
|
|
2754
3503
|
],
|
|
2755
3504
|
selection: {
|
|
2756
3505
|
keywords: [
|
|
@@ -2783,14 +3532,15 @@ var treeui_catalog_default = {
|
|
|
2783
3532
|
},
|
|
2784
3533
|
recipes: [
|
|
2785
3534
|
"date-range-form"
|
|
2786
|
-
]
|
|
3535
|
+
],
|
|
3536
|
+
practices: []
|
|
2787
3537
|
},
|
|
2788
3538
|
{
|
|
2789
3539
|
name: "TDivider",
|
|
2790
3540
|
aliases: [],
|
|
2791
3541
|
package: "@treeui/vue",
|
|
2792
3542
|
category: "Layout",
|
|
2793
|
-
description:
|
|
3543
|
+
description: 'Horizontal or vertical visual separator. Renders a single native <hr> and nothing else \u2014 there is no default slot, so the "text in the middle of a rule" pattern (an "OR" divider) is NOT supported; compose that yourself from a flex row plus TText. The `label` prop is an accessible name only, never visible text. There are no size, variant, tone, or spacing props.\n',
|
|
2794
3544
|
sourceFile: "packages/vue/src/components/TDivider.vue",
|
|
2795
3545
|
storyFile: "apps/docs/src/stories/Divider.stories.ts",
|
|
2796
3546
|
storyTitle: "Components/Layout/Divider",
|
|
@@ -2798,34 +3548,41 @@ var treeui_catalog_default = {
|
|
|
2798
3548
|
props: [
|
|
2799
3549
|
{
|
|
2800
3550
|
name: "orientation",
|
|
2801
|
-
type: "
|
|
3551
|
+
type: '"horizontal" | "vertical"',
|
|
2802
3552
|
default: "horizontal",
|
|
2803
3553
|
values: [
|
|
2804
3554
|
"horizontal",
|
|
2805
3555
|
"vertical"
|
|
2806
|
-
]
|
|
3556
|
+
],
|
|
3557
|
+
description: "Selects the `t-divider--{orientation}` modifier \u2014 the only class the component varies. `horizontal` spans the full inline width (width 100%, height 0) with `margin-block` spacing. `vertical` is a zero-width rule (width 0, height auto) that takes its height from `align-self: stretch`, so it is only visible inside a flex or grid row \u2014 in a plain block container it collapses to zero height and renders nothing.\n"
|
|
2807
3558
|
},
|
|
2808
3559
|
{
|
|
2809
3560
|
name: "decorative",
|
|
2810
3561
|
type: "boolean",
|
|
2811
3562
|
default: "true",
|
|
2812
|
-
description:
|
|
3563
|
+
description: 'When true (the default) renders `role="none"` and no ARIA attributes at all \u2014 purely visual, removed from the accessibility tree, and the `label` prop is dropped. When false renders `role="separator"` plus `aria-orientation`, and `aria-label` when `label` is set.\n'
|
|
2813
3564
|
},
|
|
2814
3565
|
{
|
|
2815
3566
|
name: "label",
|
|
2816
3567
|
type: "string",
|
|
2817
3568
|
required: false,
|
|
2818
|
-
description:
|
|
3569
|
+
description: 'Accessible name, applied as `aria-label` ONLY when `decorative` is false. Because `decorative` defaults to true, `<TDivider label="Section" />` on its own renders no label at all \u2014 pass `:decorative="false"` as well. Never rendered as visible text.\n'
|
|
2819
3570
|
}
|
|
2820
3571
|
],
|
|
2821
3572
|
events: [],
|
|
2822
3573
|
slots: [],
|
|
2823
3574
|
a11y: [
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
"aria-label: Set from `label` prop when non-decorative."
|
|
3575
|
+
'role: "none" when decorative (the default), "separator" when `decorative` is false.',
|
|
3576
|
+
'aria-orientation: Set to the `orientation` value only when `decorative` is false; omitted otherwise. Note that "horizontal" is already the implicit default for `role="separator"`, so it is redundant there but harmless.',
|
|
3577
|
+
"aria-label: Set from the `label` prop only when `decorative` is false. Omitted when `label` is unset, so a non-decorative divider without a label is an unnamed separator (valid \u2014 separators need no name).",
|
|
3578
|
+
'notes: The decorative default is the right one for most dividers: a purely visual rule should not be announced. Use `:decorative="false"` only when the rule genuinely separates two sections that assistive technology should perceive as distinct, and pair it with `label` when the sections need naming.'
|
|
3579
|
+
],
|
|
3580
|
+
behavior: [
|
|
3581
|
+
"Renders a native <hr> element as its single root node.",
|
|
3582
|
+
"Extra attrs and class/style fall through to that <hr> (attribute inheritance is not disabled).",
|
|
3583
|
+
"Applies exactly two classes; no state, size, or variant modifiers exist.",
|
|
3584
|
+
"A vertical divider needs a flex or grid parent to have any height."
|
|
2827
3585
|
],
|
|
2828
|
-
behavior: [],
|
|
2829
3586
|
selection: {
|
|
2830
3587
|
keywords: [],
|
|
2831
3588
|
useWhen: [],
|
|
@@ -2836,7 +3593,8 @@ var treeui_catalog_default = {
|
|
|
2836
3593
|
required: [],
|
|
2837
3594
|
notes: []
|
|
2838
3595
|
},
|
|
2839
|
-
recipes: []
|
|
3596
|
+
recipes: [],
|
|
3597
|
+
practices: []
|
|
2840
3598
|
},
|
|
2841
3599
|
{
|
|
2842
3600
|
name: "TDonutChart",
|
|
@@ -2855,67 +3613,73 @@ var treeui_catalog_default = {
|
|
|
2855
3613
|
name: "segments",
|
|
2856
3614
|
type: "TDonutSegment[]",
|
|
2857
3615
|
default: "[]",
|
|
2858
|
-
note: "Each item is { label: string; value: number; color?: string }.
|
|
3616
|
+
note: "Each item is { label: string; value: number; color?: string }. Values <= 0 are filtered out before anything renders \u2014 they reach neither the chart, the legend, nor the segment count in the auto aria-label. Because the palette cycles by *visible* index, dropping a non-positive item shifts the colors of every segment after it."
|
|
2859
3617
|
},
|
|
2860
3618
|
{
|
|
2861
3619
|
name: "size",
|
|
2862
3620
|
type: "number",
|
|
2863
3621
|
default: "200",
|
|
2864
|
-
note: "Square canvas in px."
|
|
3622
|
+
note: "Square canvas in px; applied to both the svg and the figure box. Donut geometry insets the ring by thickness/2 + 3px so the hover growth cannot clip; pie geometry uses a radius of size/2 - 2."
|
|
2865
3623
|
},
|
|
2866
3624
|
{
|
|
2867
3625
|
name: "thickness",
|
|
2868
3626
|
type: "number",
|
|
2869
3627
|
default: "26",
|
|
2870
|
-
note: "Ring thickness
|
|
3628
|
+
note: "Ring thickness in px. `0` switches the whole render mode: segments become filled wedges to the center (a pie) and the center block is not rendered at all. Hovering a donut segment temporarily draws it at thickness + 4."
|
|
2871
3629
|
},
|
|
2872
3630
|
{
|
|
2873
3631
|
name: "gap",
|
|
2874
3632
|
type: "number",
|
|
2875
3633
|
default: "2",
|
|
2876
|
-
note: "Gap between slices, in degrees."
|
|
3634
|
+
note: "Gap between slices, in degrees. In donut mode it is converted to arc length on the mid-radius circle and then floored \u2014 the effective gap is at least 2px, or at least thickness + 2px when rounded \u2014 so small values (including 0) still leave a visible seam. Forced to 0 whenever exactly one segment is visible."
|
|
2877
3635
|
},
|
|
2878
3636
|
{
|
|
2879
3637
|
name: "rounded",
|
|
2880
3638
|
type: "boolean",
|
|
2881
3639
|
default: "false",
|
|
2882
|
-
note: "Round the ends of donut segments (widens the gap to make room). Best with a thinner ring."
|
|
3640
|
+
note: "Round the ends of donut segments (widens the gap to make room). Best with a thinner ring. Donut only \u2014 stroke-linecap is not applied to pie wedges, so it is ignored when thickness is 0."
|
|
2883
3641
|
},
|
|
2884
3642
|
{
|
|
2885
3643
|
name: "showLegend",
|
|
2886
3644
|
type: "boolean",
|
|
2887
|
-
default: "true"
|
|
3645
|
+
default: "true",
|
|
3646
|
+
note: "The legend only renders when there is data \u2014 it is suppressed in the empty state even when true, but it is NOT suppressed while loading, so real values sit next to the skeleton. The has-legend root class tracks the prop alone, not whether the legend actually rendered."
|
|
2888
3647
|
},
|
|
2889
3648
|
{
|
|
2890
3649
|
name: "showPercent",
|
|
2891
3650
|
type: "boolean",
|
|
2892
|
-
default: "true"
|
|
3651
|
+
default: "true",
|
|
3652
|
+
note: "Legend only. Percentages are rounded to whole numbers, so they may not sum to exactly 100%."
|
|
2893
3653
|
},
|
|
2894
3654
|
{
|
|
2895
3655
|
name: "centerLabel",
|
|
2896
3656
|
type: "string",
|
|
2897
|
-
default: "
|
|
2898
|
-
note: "Donut only;
|
|
3657
|
+
default: "undefined",
|
|
3658
|
+
note: "Static label under the center value. Falls back to the literal string 'Total' when unset, and is replaced by the hovered segment's label while a segment is hovered. Donut only; the center block is not rendered for a pie."
|
|
2899
3659
|
},
|
|
2900
3660
|
{
|
|
2901
3661
|
name: "centerValue",
|
|
2902
3662
|
type: "string | number",
|
|
2903
|
-
default: "
|
|
3663
|
+
default: "undefined",
|
|
3664
|
+
note: "Overrides the auto total in the center readout; falls back to the formatted sum of the visible values. Interpolated as-is (no valueFormat). Lower precedence than hover: hovering a segment replaces it with that segment's formatted value. Donut only."
|
|
2904
3665
|
},
|
|
2905
3666
|
{
|
|
2906
3667
|
name: "valueFormat",
|
|
2907
3668
|
type: "(value: number) => string",
|
|
2908
|
-
default: "locale integers for |value| >= 1000"
|
|
3669
|
+
default: "locale integers for |value| >= 1000",
|
|
3670
|
+
note: "Applies to the legend values and to the center value. Not applied to percentages, nor to an explicitly supplied centerValue."
|
|
2909
3671
|
},
|
|
2910
3672
|
{
|
|
2911
3673
|
name: "loading",
|
|
2912
3674
|
type: "boolean",
|
|
2913
|
-
default: "false"
|
|
3675
|
+
default: "false",
|
|
3676
|
+
note: "Replaces the figure with a pulsing skeleton disc and adds the is-loading root class. Takes precedence over the empty state; the legend still renders when data is present."
|
|
2914
3677
|
},
|
|
2915
3678
|
{
|
|
2916
3679
|
name: "ariaLabel",
|
|
2917
3680
|
type: "string",
|
|
2918
|
-
default: "auto-generated summary"
|
|
3681
|
+
default: "auto-generated summary ('Donut chart with <n> segments' / 'Pie chart with <n> segments')",
|
|
3682
|
+
note: 'Applied to the inner <svg role="img">, which only exists in the data state \u2014 neither the loading nor the empty state carries it.'
|
|
2919
3683
|
}
|
|
2920
3684
|
],
|
|
2921
3685
|
events: [],
|
|
@@ -2928,13 +3692,20 @@ var treeui_catalog_default = {
|
|
|
2928
3692
|
}
|
|
2929
3693
|
],
|
|
2930
3694
|
a11y: [
|
|
2931
|
-
"
|
|
2932
|
-
"Legend + percentages give a non-visual reading of each slice."
|
|
3695
|
+
"The inner <svg> carries role=img plus the ariaLabel (or the auto-generated summary); the root div has no role or accessible name.",
|
|
3696
|
+
"Legend + percentages give a non-visual reading of each slice.",
|
|
3697
|
+
"The hover readout is pointer-only \u2014 segments are not focusable and there is no keyboard equivalent, so never make it the only way to reach a value. The legend already carries the same numbers.",
|
|
3698
|
+
"Legend swatches are aria-hidden, so color is never the only carrier of identity.",
|
|
3699
|
+
"Provide a meaningful ariaLabel describing what the chart shows."
|
|
2933
3700
|
],
|
|
2934
3701
|
behavior: [
|
|
2935
|
-
"colors_auto_assign_from_chart_palette: --tree-color-chart-1..8, cycling; per-segment color overrides",
|
|
2936
|
-
"hovering_a_slice_dims_the_rest_and_updates_center:
|
|
2937
|
-
"
|
|
3702
|
+
"colors_auto_assign_from_chart_palette: --tree-color-chart-1..8, cycling by visible-segment index; per-segment color overrides",
|
|
3703
|
+
"hovering_a_slice_dims_the_rest_and_updates_center: the other segments get is-dimmed, the hovered donut segment grows to thickness + 4, and its legend row gets is-active",
|
|
3704
|
+
"hovering_a_legend_row_drives_the_same_highlight: legend items carry the same pointerenter/pointerleave handlers as the segments",
|
|
3705
|
+
"center_readout_precedence: hovered segment > centerValue > formatted total; the label half is hovered segment label > centerLabel > 'Total'",
|
|
3706
|
+
"single_segment_drops_the_gap: with exactly one visible segment the gap is forced to 0 in both donut and pie mode, so the ring/disc closes",
|
|
3707
|
+
"empty_state_when_no_visible_segment_has_value: total <= 0 renders the empty slot instead of the svg; loading wins over it",
|
|
3708
|
+
"segments_fade_in_staggered: 70ms animation delay per segment index; removed under prefers-reduced-motion"
|
|
2938
3709
|
],
|
|
2939
3710
|
selection: {
|
|
2940
3711
|
keywords: [
|
|
@@ -2972,7 +3743,8 @@ var treeui_catalog_default = {
|
|
|
2972
3743
|
},
|
|
2973
3744
|
recipes: [
|
|
2974
3745
|
"metric-dashboard"
|
|
2975
|
-
]
|
|
3746
|
+
],
|
|
3747
|
+
practices: []
|
|
2976
3748
|
},
|
|
2977
3749
|
{
|
|
2978
3750
|
name: "TDrawer",
|
|
@@ -2990,17 +3762,20 @@ var treeui_catalog_default = {
|
|
|
2990
3762
|
{
|
|
2991
3763
|
name: "open",
|
|
2992
3764
|
type: "boolean",
|
|
2993
|
-
default: "controlled_optional"
|
|
3765
|
+
default: "controlled_optional",
|
|
3766
|
+
note: "Runtime default is `undefined`. While it holds anything other than `undefined` the drawer is fully controlled \u2014 the internal state is ignored and the panel only moves when the parent updates this prop."
|
|
2994
3767
|
},
|
|
2995
3768
|
{
|
|
2996
3769
|
name: "defaultOpen",
|
|
2997
3770
|
type: "boolean",
|
|
2998
|
-
default: "false"
|
|
3771
|
+
default: "false",
|
|
3772
|
+
note: "Uncontrolled initial state. Read once on setup \u2014 later changes are ignored. Only meaningful while `open` is undefined. Opening this way skips the on-open side effects; see behavior.initial_open_skips_open_side_effects."
|
|
2999
3773
|
},
|
|
3000
3774
|
{
|
|
3001
3775
|
name: "disabled",
|
|
3002
3776
|
type: "boolean",
|
|
3003
|
-
default: "false"
|
|
3777
|
+
default: "false",
|
|
3778
|
+
note: "Only blocks opening from the `trigger` slot \u2014 the trigger wrapper gets `aria-disabled` and its click is swallowed (preventDefault + stopPropagation). It does NOT block a programmatic open through `open`/`defaultOpen`, and it disables nothing inside the drawer."
|
|
3004
3779
|
},
|
|
3005
3780
|
{
|
|
3006
3781
|
name: "size",
|
|
@@ -3010,7 +3785,8 @@ var treeui_catalog_default = {
|
|
|
3010
3785
|
"sm",
|
|
3011
3786
|
"md",
|
|
3012
3787
|
"lg"
|
|
3013
|
-
]
|
|
3788
|
+
],
|
|
3789
|
+
note: "Applied as `t-drawer__surface--<size>`. Sizes the cross axis of the panel: width for `side: left | right`, height for `side: top | bottom`."
|
|
3014
3790
|
},
|
|
3015
3791
|
{
|
|
3016
3792
|
name: "side",
|
|
@@ -3021,42 +3797,50 @@ var treeui_catalog_default = {
|
|
|
3021
3797
|
"right",
|
|
3022
3798
|
"bottom",
|
|
3023
3799
|
"left"
|
|
3024
|
-
]
|
|
3800
|
+
],
|
|
3801
|
+
note: "Applied as `t-drawer__surface--<side>`. Also selects the slide-in translate direction and which corners are rounded."
|
|
3025
3802
|
},
|
|
3026
3803
|
{
|
|
3027
3804
|
name: "title",
|
|
3028
3805
|
type: "string",
|
|
3029
|
-
default: ""
|
|
3806
|
+
default: "",
|
|
3807
|
+
note: "Rendered as `t-drawer__title` inside the fallback content of the `header` slot. An empty title with no `header` slot removes the header block entirely and leaves `aria-labelledby` unset \u2014 the dialog then has no accessible name."
|
|
3030
3808
|
},
|
|
3031
3809
|
{
|
|
3032
3810
|
name: "description",
|
|
3033
3811
|
type: "string",
|
|
3034
|
-
default: ""
|
|
3812
|
+
default: "",
|
|
3813
|
+
note: "Rendered as `t-drawer__description` between the topbar and the body, and referenced by `aria-describedby`. Only rendered when non-empty. The `content`/`default` body is NOT part of the accessible description."
|
|
3035
3814
|
},
|
|
3036
3815
|
{
|
|
3037
3816
|
name: "closeOnEscape",
|
|
3038
3817
|
type: "boolean",
|
|
3039
|
-
default: "true"
|
|
3818
|
+
default: "true",
|
|
3819
|
+
note: "Escape is handled on the surface's own keydown, so it only fires while focus is inside the drawer. When enabled the handler also calls preventDefault."
|
|
3040
3820
|
},
|
|
3041
3821
|
{
|
|
3042
3822
|
name: "closeOnOverlay",
|
|
3043
3823
|
type: "boolean",
|
|
3044
|
-
default: "true"
|
|
3824
|
+
default: "true",
|
|
3825
|
+
note: "Applies to clicks on `t-drawer__backdrop` only. The backdrop is a sibling of the surface, not an ancestor, so clicks inside the panel never reach it regardless of this prop."
|
|
3045
3826
|
},
|
|
3046
3827
|
{
|
|
3047
3828
|
name: "showCloseButton",
|
|
3048
3829
|
type: "boolean",
|
|
3049
|
-
default: "true"
|
|
3830
|
+
default: "true",
|
|
3831
|
+
note: "The topbar renders when `title` or the `header` slot is present OR this is true. Setting it false with no title and no `header` slot collapses the topbar entirely."
|
|
3050
3832
|
},
|
|
3051
3833
|
{
|
|
3052
3834
|
name: "closeLabel",
|
|
3053
3835
|
type: "string",
|
|
3054
|
-
default: "Close drawer"
|
|
3836
|
+
default: "Close drawer",
|
|
3837
|
+
note: "Accessible name (aria-label) of the header close button, which is icon-only and has no text. Only rendered when `showCloseButton` is true. The component's only localisation hook."
|
|
3055
3838
|
},
|
|
3056
3839
|
{
|
|
3057
3840
|
name: "id",
|
|
3058
3841
|
type: "string",
|
|
3059
|
-
default: "auto"
|
|
3842
|
+
default: "auto",
|
|
3843
|
+
note: "Id of the dialog surface; seeds `<id>-title` and `<id>-description`. Read once on setup (not reactive). Auto-generated via `createId('t-drawer')` when omitted."
|
|
3060
3844
|
}
|
|
3061
3845
|
],
|
|
3062
3846
|
events: [
|
|
@@ -3069,34 +3853,53 @@ var treeui_catalog_default = {
|
|
|
3069
3853
|
],
|
|
3070
3854
|
slots: [
|
|
3071
3855
|
{
|
|
3072
|
-
name: "trigger"
|
|
3856
|
+
name: "trigger",
|
|
3857
|
+
description: "Element that opens the drawer on click. Omit for controlled or imperative use."
|
|
3073
3858
|
},
|
|
3074
3859
|
{
|
|
3075
|
-
name: "header"
|
|
3860
|
+
name: "header",
|
|
3861
|
+
description: "Replaces the default title heading in the topbar."
|
|
3076
3862
|
},
|
|
3077
3863
|
{
|
|
3078
|
-
name: "default"
|
|
3864
|
+
name: "default",
|
|
3865
|
+
description: "Drawer body content."
|
|
3079
3866
|
},
|
|
3080
3867
|
{
|
|
3081
|
-
name: "content"
|
|
3868
|
+
name: "content",
|
|
3869
|
+
description: "Drawer body content; takes precedence over the default slot."
|
|
3082
3870
|
},
|
|
3083
3871
|
{
|
|
3084
|
-
name: "footer"
|
|
3872
|
+
name: "footer",
|
|
3873
|
+
description: "Action row pinned under the body."
|
|
3085
3874
|
}
|
|
3086
3875
|
],
|
|
3087
3876
|
a11y: [
|
|
3088
3877
|
"role: dialog",
|
|
3089
3878
|
"aria_modal: true",
|
|
3090
3879
|
"focus_trap: true",
|
|
3091
|
-
|
|
3092
|
-
"escape_closes_when_enabled: true"
|
|
3880
|
+
'restores_focus_on_close: {"value":"partial","detail":"The previously focused element is recorded only in the trigger-click path. A drawer opened programmatically \u2014 by setting `open` from elsewhere, or by `defaultOpen` \u2014 records nothing, so focus is not restored on close. Move focus back yourself in that case.\\n"}',
|
|
3881
|
+
"escape_closes_when_enabled: true",
|
|
3882
|
+
"escape_scope: The keydown listener lives on the surface, so Escape only closes while focus is inside the drawer.",
|
|
3883
|
+
"accessible_name_source: the `t-drawer__header` div, via aria-labelledby; unset when `title` is empty and no `header` slot is supplied",
|
|
3884
|
+
"accessible_description_source: the `description` prop, via aria-describedby; the body slots are not included",
|
|
3885
|
+
'initial_focus: First focusable element inside the surface, else the surface itself (`tabindex=\\"-1\\"`, with a visible `:focus-visible` ring). Applied on the closed \u2192 open transition only.',
|
|
3886
|
+
"backdrop_marked_aria_hidden: true",
|
|
3887
|
+
"trigger_state_not_announced: The trigger wrapper gets no aria-haspopup, aria-expanded, or aria-controls, and no scoped props are exposed to build them. A trigger that needs to announce the drawer must wire those attributes from consumer state."
|
|
3093
3888
|
],
|
|
3094
3889
|
behavior: [
|
|
3095
3890
|
"uses_teleport_to_body: true",
|
|
3096
3891
|
"locks_body_scroll_while_open: true",
|
|
3097
3892
|
"overlay_click_closes_when_enabled: true",
|
|
3098
3893
|
"close_button_optional: true",
|
|
3099
|
-
"slides_in_from_side: true"
|
|
3894
|
+
"slides_in_from_side: true",
|
|
3895
|
+
"root_uses_display_contents_without_trigger: `t-drawer` is `display: inline-flex`, but a root with no `t-drawer__trigger` child switches to `display: contents` so the empty wrapper does not generate a line box and add stray height to the page.",
|
|
3896
|
+
"topbar_rendered_when: title is non-empty OR the `header` slot is supplied OR showCloseButton is true",
|
|
3897
|
+
"body_slot_precedence: content > default",
|
|
3898
|
+
"footer_rendered_when: the `footer` slot is supplied",
|
|
3899
|
+
'data_state_attribute: `data-state="open" | "closed"` on both the `t-drawer` root and the `t-drawer__portal`',
|
|
3900
|
+
"focus_trap_detail: Tab and Shift+Tab cycle within the surface. With no focusable descendants, Tab is swallowed and focus is pushed back to the surface itself.",
|
|
3901
|
+
'initial_open_skips_open_side_effects: {"value":true,"detail":"The on-open work \u2014 body scroll lock and initial focus \u2014 runs from a watcher on the open state that is not immediate, so a drawer that starts open via `defaultOpen: true` (or an `open` prop already true on first render) never locks scroll and never moves focus into the surface. Focus trap and Escape therefore stay dormant until the user tabs in. Start closed and open on the next tick if you need the full behavior.\\n"}',
|
|
3902
|
+
'body_scroll_lock_scope: {"value":"per_component_instance","detail":"The overlay counter and the saved `overflow` value are per instance, not shared across overlays. Two overlays open at once each restore what they individually saw, so closing the first-opened one while a second is still open unlocks page scroll early.\\n"}'
|
|
3100
3903
|
],
|
|
3101
3904
|
selection: {
|
|
3102
3905
|
keywords: [
|
|
@@ -3125,7 +3928,10 @@ var treeui_catalog_default = {
|
|
|
3125
3928
|
required: [],
|
|
3126
3929
|
notes: []
|
|
3127
3930
|
},
|
|
3128
|
-
recipes: []
|
|
3931
|
+
recipes: [],
|
|
3932
|
+
practices: [
|
|
3933
|
+
"accessible-by-default"
|
|
3934
|
+
]
|
|
3129
3935
|
},
|
|
3130
3936
|
{
|
|
3131
3937
|
name: "TDropdown",
|
|
@@ -3144,22 +3950,25 @@ var treeui_catalog_default = {
|
|
|
3144
3950
|
name: "items",
|
|
3145
3951
|
type: "TDropdownItem[]",
|
|
3146
3952
|
default: "[]",
|
|
3147
|
-
note:
|
|
3953
|
+
note: 'Array of { label: string; value: string; disabled?: boolean }. Each entry renders one `<li role="menuitem">`, keyed by `value` \u2014 values must be unique, because the internal element map that drives focus is also keyed by `value` and duplicates collide. With the default `[]` the component still renders an empty `<ul role="menu">` and focus stays on the trigger; there is no empty-state affordance (no `emptyText`, no `empty` slot), so guard on `items.length` yourself.'
|
|
3148
3954
|
},
|
|
3149
3955
|
{
|
|
3150
3956
|
name: "open",
|
|
3151
3957
|
type: "boolean",
|
|
3152
|
-
default: "undefined"
|
|
3958
|
+
default: "undefined",
|
|
3959
|
+
note: "Controlled open state. Once a boolean is passed the component stops tracking open state internally \u2014 it only emits update:open / open-change and the consumer MUST write the value back, or the menu never opens. Flipping it externally does not run the open routine: no item is focused and the outside-click listener is only attached from the transition, so an initially-`true` value opens the menu with focus untouched."
|
|
3153
3960
|
},
|
|
3154
3961
|
{
|
|
3155
3962
|
name: "defaultOpen",
|
|
3156
3963
|
type: "boolean",
|
|
3157
|
-
default: "false"
|
|
3964
|
+
default: "false",
|
|
3965
|
+
note: "Uncontrolled initial open state, read once on mount. Later changes to it are ignored. It renders the menu already open but does NOT focus the first item (focusedIndex stays -1, so no `is-focused` row) and does NOT arm the outside-click listener until the open state changes at least once \u2014 see behavior.outside_click_closes_menu."
|
|
3158
3966
|
},
|
|
3159
3967
|
{
|
|
3160
3968
|
name: "disabled",
|
|
3161
3969
|
type: "boolean",
|
|
3162
|
-
default: "false"
|
|
3970
|
+
default: "false",
|
|
3971
|
+
note: 'Sets the native `disabled` attribute on the built-in trigger button, adds `is-disabled` to the root, and suppresses the menu entirely (`v-if="isOpen && !disabled"`) \u2014 even while `open` is true. Also short-circuits openMenu, toggleMenu and the trigger keydown handler. It is bound only to the default button, so a custom `trigger` slot must render its own disabled state.'
|
|
3163
3972
|
},
|
|
3164
3973
|
{
|
|
3165
3974
|
name: "size",
|
|
@@ -3169,12 +3978,14 @@ var treeui_catalog_default = {
|
|
|
3169
3978
|
"sm",
|
|
3170
3979
|
"md",
|
|
3171
3980
|
"lg"
|
|
3172
|
-
]
|
|
3981
|
+
],
|
|
3982
|
+
note: "Sizes the trigger and the menu rows. `t-dropdown--md` is emitted but has no CSS rule of its own \u2014 it is the base `.t-dropdown__trigger` / `.t-dropdown__item` styling."
|
|
3173
3983
|
},
|
|
3174
3984
|
{
|
|
3175
3985
|
name: "label",
|
|
3176
3986
|
type: "string",
|
|
3177
|
-
default: ""
|
|
3987
|
+
default: "",
|
|
3988
|
+
note: 'Text of the built-in trigger button AND the menu\'s accessible name (`:aria-label="label || undefined"` on the `<ul role="menu">`). A custom `trigger` slot does not render `label`, but it still names the menu \u2014 keep passing it, or the menu has no accessible name at all.'
|
|
3178
3989
|
},
|
|
3179
3990
|
{
|
|
3180
3991
|
name: "align",
|
|
@@ -3184,18 +3995,30 @@ var treeui_catalog_default = {
|
|
|
3184
3995
|
"start",
|
|
3185
3996
|
"end"
|
|
3186
3997
|
],
|
|
3187
|
-
note: "Horizontal alignment of the menu relative to the trigger
|
|
3998
|
+
note: "Horizontal alignment of the menu relative to the trigger \u2014 `start` pins `left: 0`, `end` pins `right: 0`. Use `end` when the trigger sits near the right edge of a clipping container (e.g. a table actions column). There is no collision detection: the menu is a plain absolutely-positioned child of the root, so it never flips and is clipped by any ancestor with `overflow: hidden`."
|
|
3999
|
+
},
|
|
4000
|
+
{
|
|
4001
|
+
name: "id",
|
|
4002
|
+
type: "string",
|
|
4003
|
+
default: "undefined",
|
|
4004
|
+
note: "Custom id for the menu element. Auto-generated when omitted; also exposed to the `trigger` slot as `menuId` so a custom trigger can wire aria-controls. Resolved once during setup \u2014 it is NOT reactive, so changing `id` after mount has no effect."
|
|
3188
4005
|
}
|
|
3189
4006
|
],
|
|
3190
4007
|
events: [
|
|
3191
4008
|
{
|
|
3192
|
-
name: "select"
|
|
4009
|
+
name: "select",
|
|
4010
|
+
description: "Emitted with the chosen item's `value`. Disabled items never emit. Fires before the menu closes; the close that follows restores focus to the trigger.",
|
|
4011
|
+
payload: '[{"value":"string"}]'
|
|
3193
4012
|
},
|
|
3194
4013
|
{
|
|
3195
|
-
name: "update:open"
|
|
4014
|
+
name: "update:open",
|
|
4015
|
+
description: "Emitted whenever the open state changes. Deduped \u2014 no emit when the next value equals the current one.",
|
|
4016
|
+
payload: '["boolean"]'
|
|
3196
4017
|
},
|
|
3197
4018
|
{
|
|
3198
|
-
name: "open-change"
|
|
4019
|
+
name: "open-change",
|
|
4020
|
+
description: "Emitted immediately after `update:open`, with the same payload. Alias for consumers that do not use v-model:open.",
|
|
4021
|
+
payload: '["boolean"]'
|
|
3199
4022
|
}
|
|
3200
4023
|
],
|
|
3201
4024
|
slots: [
|
|
@@ -3208,23 +4031,39 @@ var treeui_catalog_default = {
|
|
|
3208
4031
|
],
|
|
3209
4032
|
a11y: [
|
|
3210
4033
|
"role: menu",
|
|
4034
|
+
"menu_accessible_name_comes_from_the_label_prop: true",
|
|
3211
4035
|
"trigger_aria_haspopup: menu",
|
|
3212
4036
|
"trigger_aria_expanded: true",
|
|
3213
4037
|
"trigger_aria_controls: menu id, while open",
|
|
4038
|
+
"custom_trigger_caveat: The three trigger_aria_* guarantees above describe the BUILT-IN trigger button only. A custom `trigger` slot replaces that button, so the consumer must bind them from the `isOpen` and `menuId` scoped props \u2014 see slots.trigger.",
|
|
4039
|
+
"item_role: menuitem",
|
|
3214
4040
|
"aria_disabled_on_disabled_items: true",
|
|
4041
|
+
"disabled_items_get_tabindex_minus_1_but_stay_programmatically_focusable: true",
|
|
3215
4042
|
"focus_visible_on_trigger: true",
|
|
4043
|
+
"items_receive_real_dom_focus_no_aria_activedescendant: true",
|
|
3216
4044
|
"keyboard_arrow_navigation: true",
|
|
4045
|
+
"arrow_navigation_skips_disabled_items: true",
|
|
4046
|
+
"arrow_navigation_does_not_wrap_at_the_ends: true",
|
|
4047
|
+
"arrow_down_or_arrow_up_on_the_trigger_both_open_at_the_first_enabled_item: true",
|
|
3217
4048
|
"escape_closes_menu: true",
|
|
3218
4049
|
"enter_space_selects_item: true",
|
|
3219
|
-
"home_end_navigation: true"
|
|
4050
|
+
"home_end_navigation: true",
|
|
4051
|
+
"no_typeahead: true",
|
|
4052
|
+
"tab_does_not_close_the_menu: true"
|
|
3220
4053
|
],
|
|
3221
4054
|
behavior: [
|
|
3222
|
-
|
|
4055
|
+
'outside_click_closes_menu: {"value":true,"detail":"Detected on a document `pointerdown` listener that is attached by a watcher on the open state. The watcher is not immediate, so a menu that is already open on mount \u2014 via `defaultOpen` or an initially-`true` `open` \u2014 has no listener until the open state changes at least once, and outside clicks do not close it.\\n"}',
|
|
3223
4056
|
"outside_click_restores_focus: false",
|
|
3224
4057
|
"chevron_rotates_when_open: true",
|
|
3225
4058
|
"menu_grows_to_fit_items_without_wrapping: true",
|
|
3226
|
-
"
|
|
3227
|
-
|
|
4059
|
+
"menu_scrolls_vertically_past_15rem: true",
|
|
4060
|
+
"menu_renders_in_flow_with_no_portal_and_no_flip_positioning: true",
|
|
4061
|
+
"menu_is_not_rendered_while_disabled: true",
|
|
4062
|
+
"open_state_emits_are_deduped: true",
|
|
4063
|
+
"controlled_open_requires_writing_the_value_back: true",
|
|
4064
|
+
'opening_focuses_first_enabled_item: {"value":true,"detail":"Applies to the open routine only \u2014 a click or Enter/Space/ArrowDown/ArrowUp on the trigger. `defaultOpen` and an externally driven `open` skip it, leaving focusedIndex at -1 with no row focused and no `is-focused` class. With an empty `items` array focus stays on the trigger; when every item is disabled, focus lands on the first (disabled) item.\\n"}',
|
|
4065
|
+
'keyboard_activation_on_the_trigger_never_closes_the_menu: {"value":true,"detail":"Clicking the trigger toggles, but Enter/Space/Arrow keys always call the open routine, so pressing them while the menu is open re-focuses the first enabled item instead of closing. Escape is the keyboard close.\\n"}',
|
|
4066
|
+
'focus_restores_on_close: {"value":true,"detail":"Focus returns to the trigger when the menu closes from inside it \u2014 selecting an item or pressing Escape on an item. Closing from the trigger itself (clicking it again, or Escape while the trigger holds focus) does not run the restore, because focus is already there. It deliberately does NOT move focus on an outside click, where the pointer has already placed focus elsewhere.\\n","applies_to_custom_trigger":true}'
|
|
3228
4067
|
],
|
|
3229
4068
|
selection: {
|
|
3230
4069
|
keywords: [
|
|
@@ -3253,7 +4092,11 @@ var treeui_catalog_default = {
|
|
|
3253
4092
|
required: [],
|
|
3254
4093
|
notes: []
|
|
3255
4094
|
},
|
|
3256
|
-
recipes: []
|
|
4095
|
+
recipes: [],
|
|
4096
|
+
practices: [
|
|
4097
|
+
"interaction-feedback",
|
|
4098
|
+
"accessible-by-default"
|
|
4099
|
+
]
|
|
3257
4100
|
},
|
|
3258
4101
|
{
|
|
3259
4102
|
name: "TEmptyState",
|
|
@@ -3345,7 +4188,10 @@ var treeui_catalog_default = {
|
|
|
3345
4188
|
required: [],
|
|
3346
4189
|
notes: []
|
|
3347
4190
|
},
|
|
3348
|
-
recipes: []
|
|
4191
|
+
recipes: [],
|
|
4192
|
+
practices: [
|
|
4193
|
+
"state-clarity"
|
|
4194
|
+
]
|
|
3349
4195
|
},
|
|
3350
4196
|
{
|
|
3351
4197
|
name: "TFileUpload",
|
|
@@ -3379,7 +4225,7 @@ var treeui_catalog_default = {
|
|
|
3379
4225
|
name: "disabled",
|
|
3380
4226
|
type: "boolean",
|
|
3381
4227
|
default: "false",
|
|
3382
|
-
description: "The ONLY prop that gates interaction. Disables the dropzone, the native input, Clear all, and every per-row Remove/Retry."
|
|
4228
|
+
description: "The ONLY prop that gates interaction. Disables the dropzone, the native input, Clear all, and every per-row Remove/Retry, and makes the paste and drop handlers early-return."
|
|
3383
4229
|
},
|
|
3384
4230
|
{
|
|
3385
4231
|
name: "loading",
|
|
@@ -3404,13 +4250,15 @@ var treeui_catalog_default = {
|
|
|
3404
4250
|
},
|
|
3405
4251
|
{
|
|
3406
4252
|
name: "maxFiles",
|
|
3407
|
-
type: "number",
|
|
3408
|
-
default: "
|
|
4253
|
+
type: "number | null",
|
|
4254
|
+
default: "null",
|
|
4255
|
+
description: "Cap on the TOTAL list size, not on one batch \u2014 remaining slots are counted against the files already selected. `multiple: false` overrides it with a hard cap of 1. Values below 0 are clamped to 0, which rejects everything."
|
|
3409
4256
|
},
|
|
3410
4257
|
{
|
|
3411
4258
|
name: "maxFileSize",
|
|
3412
|
-
type: "number",
|
|
3413
|
-
default: "
|
|
4259
|
+
type: "number | null",
|
|
4260
|
+
default: "null",
|
|
4261
|
+
description: "Per-file byte cap. Enforced only when it is a number greater than 0 \u2014 both `null` and `0` disable the check."
|
|
3414
4262
|
},
|
|
3415
4263
|
{
|
|
3416
4264
|
name: "label",
|
|
@@ -3584,19 +4432,144 @@ var treeui_catalog_default = {
|
|
|
3584
4432
|
"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."
|
|
3585
4433
|
],
|
|
3586
4434
|
selection: {
|
|
3587
|
-
keywords: [],
|
|
3588
|
-
useWhen: [],
|
|
3589
|
-
avoidWhen: [],
|
|
3590
|
-
alternatives: []
|
|
4435
|
+
keywords: [],
|
|
4436
|
+
useWhen: [],
|
|
4437
|
+
avoidWhen: [],
|
|
4438
|
+
alternatives: []
|
|
4439
|
+
},
|
|
4440
|
+
setup: {
|
|
4441
|
+
required: [],
|
|
4442
|
+
notes: [
|
|
4443
|
+
"Bind `modelValue` to `File[]`.",
|
|
4444
|
+
"Use `accept`, `multiple`, and size limits in the app layer to constrain uploads."
|
|
4445
|
+
]
|
|
4446
|
+
},
|
|
4447
|
+
recipes: [],
|
|
4448
|
+
practices: []
|
|
4449
|
+
},
|
|
4450
|
+
{
|
|
4451
|
+
name: "TFlag",
|
|
4452
|
+
aliases: [],
|
|
4453
|
+
package: "@treeui/vue",
|
|
4454
|
+
kind: "display",
|
|
4455
|
+
category: "Data Display",
|
|
4456
|
+
status: "available",
|
|
4457
|
+
purpose: "Render a flat country flag image from a CDN at a fixed height, centred in a 3:2 box, with a text fallback when the request fails.",
|
|
4458
|
+
sourceFile: "packages/vue/src/components/TFlag.vue",
|
|
4459
|
+
storyFile: "apps/docs/src/stories/Flag.stories.ts",
|
|
4460
|
+
storyTitle: "Components/Data Display/Flag",
|
|
4461
|
+
manifestFile: "docs/ai/COMPONENTS/flag.yaml",
|
|
4462
|
+
props: [
|
|
4463
|
+
{
|
|
4464
|
+
name: "code",
|
|
4465
|
+
type: "string",
|
|
4466
|
+
required: true,
|
|
4467
|
+
description: "ISO 3166-1 alpha-2 country code. Case-insensitive \u2014 trimmed and lowercased before the URL is built."
|
|
4468
|
+
},
|
|
4469
|
+
{
|
|
4470
|
+
name: "baseUrl",
|
|
4471
|
+
type: "string",
|
|
4472
|
+
default: "https://flagcdn.com",
|
|
4473
|
+
description: "Origin serving the flag assets. The component appends a fixed path built from the CDN's fixed-height segments, so a self-hosted mirror must reproduce it exactly: 1x is `${baseUrl}/h20/{code}.png` (sm), `${baseUrl}/h20/{code}.png` (md), `${baseUrl}/h24/{code}.png` (lg); the matching 2x asset is emitted via srcset as `${baseUrl}/h40/{code}.png` (sm), `${baseUrl}/h40/{code}.png` (md), `${baseUrl}/h60/{code}.png` (lg). A trailing slash is stripped, so `https://cdn.example.com/flags/` and `https://cdn.example.com/flags` behave identically."
|
|
4474
|
+
},
|
|
4475
|
+
{
|
|
4476
|
+
name: "size",
|
|
4477
|
+
type: "TSize",
|
|
4478
|
+
default: "md",
|
|
4479
|
+
values: [
|
|
4480
|
+
"sm",
|
|
4481
|
+
"md",
|
|
4482
|
+
"lg"
|
|
4483
|
+
],
|
|
4484
|
+
description: "Box height, taken from `--tree-size-icon-sm/md/lg` (16px / 20px / 24px); the box width is 3:2 of that height. Also selects which CDN asset pair is requested \u2014 see `baseUrl`."
|
|
4485
|
+
},
|
|
4486
|
+
{
|
|
4487
|
+
name: "label",
|
|
4488
|
+
type: "string",
|
|
4489
|
+
default: "undefined",
|
|
4490
|
+
description: 'Accessible label. When set, the flag becomes role="img" with aria-label; otherwise it is aria-hidden. An empty string counts as unset \u2014 the flag stays decorative.'
|
|
4491
|
+
},
|
|
4492
|
+
{
|
|
4493
|
+
name: "fallbackText",
|
|
4494
|
+
type: "string",
|
|
4495
|
+
default: "undefined",
|
|
4496
|
+
description: 'Text shown when the image cannot load. Defaults to the normalized `code` uppercased, so a padded `" br "` falls back to `BR`.'
|
|
4497
|
+
}
|
|
4498
|
+
],
|
|
4499
|
+
events: [],
|
|
4500
|
+
slots: [],
|
|
4501
|
+
a11y: [
|
|
4502
|
+
"decorative_by_default: true",
|
|
4503
|
+
"becomes_image_when_labeled: true",
|
|
4504
|
+
'image_alt_is_always_empty: The `<img>` always carries `alt=""`, so the accessible name comes only from `label` on the root span \u2014 never from the image itself.',
|
|
4505
|
+
'fallback_text_is_hidden_when_decorative: The fallback text renders inside the root span, so without `label` it inherits `aria-hidden="true"` and is not announced. It is a visual affordance, not an accessible name.',
|
|
4506
|
+
'consumer_aria_label_does_not_replace_label: Fallthrough attributes land on the same root span, so a consumer-supplied `aria-label` overrides the one built from `label` \u2014 but it does not set `role="img"` or clear `aria-hidden="true"`, leaving the flag hidden and the label unannounced. Use the `label` prop instead.',
|
|
4507
|
+
"rule: Provide `label` only when the flag carries meaning that is not already in adjacent text \u2014 inside a language option the label is redundant."
|
|
4508
|
+
],
|
|
4509
|
+
behavior: [
|
|
4510
|
+
"falls_back_to_text_when_image_fails: true",
|
|
4511
|
+
"failed_state_resets_when_resolved_src_changes: true",
|
|
4512
|
+
"code_is_trimmed_and_lowercased: true",
|
|
4513
|
+
"fixed_height_endpoints_serve_flat_artwork_at_true_proportions: The CDN's ratio-normalised (width-by-height) endpoints do force every flag into one box, but only by serving the WAVING artwork, which reads as decoration next to flat UI icons. The fixed-height endpoints used here (h20, h24, h40, h60) serve the flat artwork at each flag's true proportions instead: Nepal stays a pennant, Switzerland stays square, Qatar stays elongated.",
|
|
4514
|
+
"shared_height_not_shared_ratio_is_what_aligns_a_column: Within a size step every flag is requested at the same asset height, so a stacked list lines up even though the widths differ. CSS then places each flag in a fixed 3:2 box (3:2 being the most common national flag ratio) with `object-fit: contain`, so the majority fill the box and the outliers centre inside it rather than being cropped or distorted.",
|
|
4515
|
+
"retina_asset_is_at_least_twice_the_box_height: Box heights come from `--tree-size-icon-sm/md/lg` (16px / 20px / 24px) and the srcset asset is h40 (sm, md) or h60 (lg), so a 2x screen never upscales.",
|
|
4516
|
+
"size_outside_the_union_falls_back_to_md: A JS consumer can pass a size outside `TSize`; the asset lookup falls back to the md pair rather than throwing on an undefined entry.",
|
|
4517
|
+
"base_url_trailing_slash_is_normalised: Trailing slashes are stripped from `baseUrl` before the path is appended, so a self-hosted mirror cannot silently produce a double-slashed URL.",
|
|
4518
|
+
"sm_and_md_share_one_asset_pair: sm and md both request h20 (h40 at 2x); only lg differs (h24, h60 at 2x). Four distinct segments exist in total, not one pair per size step, so a mirror needs four directories per flag.",
|
|
4519
|
+
"path_template_is_public_contract: Changing `baseUrl` is a config change, not a breaking one, as long as the mirror serves the same fixed-height segments (h20, h24, h40, h60).",
|
|
4520
|
+
"image_element_is_removed_not_hidden_on_failure: The `<img>` is behind `v-if`, so a failed load takes it out of the DOM and swaps in the fallback span \u2014 it is not left in place with `display: none`.",
|
|
4521
|
+
"no_country_or_locale_dataset_is_shipped: TreeUI never maps a language or locale to a country code \u2014 the application owns that decision."
|
|
4522
|
+
],
|
|
4523
|
+
selection: {
|
|
4524
|
+
keywords: [
|
|
4525
|
+
"flag",
|
|
4526
|
+
"country flag",
|
|
4527
|
+
"country",
|
|
4528
|
+
"nationality",
|
|
4529
|
+
"region",
|
|
4530
|
+
"iso 3166",
|
|
4531
|
+
"alpha-2"
|
|
4532
|
+
],
|
|
4533
|
+
useWhen: [
|
|
4534
|
+
"You need a country flag rendered from an ISO 3166-1 alpha-2 code.",
|
|
4535
|
+
"Flags stacked in a list must share one height so rows stay aligned \u2014 the flat assets keep each flag's true proportions and centre inside a fixed 3:2 box.",
|
|
4536
|
+
"You want a text fallback when the flag asset cannot load."
|
|
4537
|
+
],
|
|
4538
|
+
avoidWhen: [
|
|
4539
|
+
"The flag would be the only carrier of meaning \u2014 always pair it with adjacent text such as the language or country name.",
|
|
4540
|
+
"You need an interface glyph rather than a country flag.",
|
|
4541
|
+
"You are treating the flag as a language identity \u2014 a flag names a country, not a language."
|
|
4542
|
+
],
|
|
4543
|
+
alternatives: [
|
|
4544
|
+
{
|
|
4545
|
+
component: "TIcon",
|
|
4546
|
+
when: "The graphic is a registered TreeUI icon, not a country flag."
|
|
4547
|
+
},
|
|
4548
|
+
{
|
|
4549
|
+
component: "TLanguageSelect",
|
|
4550
|
+
when: "The flag belongs to a language or locale picker rather than standing alone."
|
|
4551
|
+
}
|
|
4552
|
+
]
|
|
3591
4553
|
},
|
|
3592
4554
|
setup: {
|
|
3593
|
-
required: [
|
|
4555
|
+
required: [
|
|
4556
|
+
"Pass `code` as an ISO 3166-1 alpha-2 country code. Matching is case-insensitive \u2014 the value is trimmed and lowercased internally.",
|
|
4557
|
+
"Allow `https://flagcdn.com` in the app `Content-Security-Policy` `img-src` directive, or point `baseUrl` at a self-hosted mirror \u2014 flag images are fetched from a third-party CDN at runtime."
|
|
4558
|
+
],
|
|
3594
4559
|
notes: [
|
|
3595
|
-
"
|
|
3596
|
-
"
|
|
4560
|
+
"A mirror must serve `{baseUrl}/{segment}/{code}.png` for both steps of every size: 1x `h20` (sm), `h20` (md), `h24` (lg); 2x `h40` (sm), `h40` (md), `h60` (lg). The 2x asset is emitted through `srcset`.",
|
|
4561
|
+
"Those fixed-height segments are part of the contract, and they are the CDN's flat artwork \u2014 a mirror must serve flat flags, not the waving ones.",
|
|
4562
|
+
"Do not substitute the CDN's ratio-normalised width-by-height endpoints. They equalise aspect ratio only by switching to the waving artwork, which reads as decoration next to flat UI icons.",
|
|
4563
|
+
"The fixed-height assets keep each flag's true proportions \u2014 Nepal is a pennant, Switzerland is square, Qatar is elongated. A shared height, not a shared ratio, is what aligns a column of flags.",
|
|
4564
|
+
"CSS puts the image in a fixed 3:2 box (3:2 being the most common national flag ratio) with `object-fit: contain`, so outliers centre inside the box instead of being cropped or distorted.",
|
|
4565
|
+
"Each retina segment is at least twice its box height \u2014 boxes are `--tree-size-icon-sm/md/lg` = 16px/20px/24px \u2014 so 2x screens never upscale.",
|
|
4566
|
+
"`baseUrl` may be written with or without a trailing slash; trailing slashes are stripped before the path is built. An unknown `size` falls back to the `md` assets.",
|
|
4567
|
+
"When the image cannot load \u2014 offline, blocked by CSP, unknown code \u2014 the component renders the uppercased `code` as text. Override that text with `fallbackText`.",
|
|
4568
|
+
"The flag is `aria-hidden` by default. Pass `label` only when the flag carries meaning on its own; beside a visible country or language name it should stay decorative."
|
|
3597
4569
|
]
|
|
3598
4570
|
},
|
|
3599
|
-
recipes: []
|
|
4571
|
+
recipes: [],
|
|
4572
|
+
practices: []
|
|
3600
4573
|
},
|
|
3601
4574
|
{
|
|
3602
4575
|
name: "TFormField",
|
|
@@ -3725,7 +4698,12 @@ var treeui_catalog_default = {
|
|
|
3725
4698
|
"date-range-form",
|
|
3726
4699
|
"color-field",
|
|
3727
4700
|
"tag-input",
|
|
3728
|
-
"hierarchy-picker"
|
|
4701
|
+
"hierarchy-picker",
|
|
4702
|
+
"language-switcher"
|
|
4703
|
+
],
|
|
4704
|
+
practices: [
|
|
4705
|
+
"accessible-by-default",
|
|
4706
|
+
"content-alignment"
|
|
3729
4707
|
]
|
|
3730
4708
|
},
|
|
3731
4709
|
{
|
|
@@ -3827,6 +4805,9 @@ var treeui_catalog_default = {
|
|
|
3827
4805
|
"date-range-form",
|
|
3828
4806
|
"stat-grid",
|
|
3829
4807
|
"metric-dashboard"
|
|
4808
|
+
],
|
|
4809
|
+
practices: [
|
|
4810
|
+
"content-alignment"
|
|
3830
4811
|
]
|
|
3831
4812
|
},
|
|
3832
4813
|
{
|
|
@@ -3847,24 +4828,380 @@ var treeui_catalog_default = {
|
|
|
3847
4828
|
type: "TIconName",
|
|
3848
4829
|
required: true,
|
|
3849
4830
|
values: [
|
|
4831
|
+
"account",
|
|
4832
|
+
"activity",
|
|
4833
|
+
"ai-studio",
|
|
3850
4834
|
"alert-circle",
|
|
4835
|
+
"align-left",
|
|
4836
|
+
"app-window",
|
|
4837
|
+
"apps-grid",
|
|
4838
|
+
"archive",
|
|
4839
|
+
"archive-restore",
|
|
4840
|
+
"arrow-down",
|
|
4841
|
+
"arrow-left",
|
|
4842
|
+
"arrow-left-right",
|
|
4843
|
+
"arrow-right",
|
|
4844
|
+
"arrow-up",
|
|
4845
|
+
"arrow-up-right",
|
|
4846
|
+
"assistant",
|
|
4847
|
+
"automation-key",
|
|
4848
|
+
"automations",
|
|
4849
|
+
"badge",
|
|
4850
|
+
"badge-check",
|
|
4851
|
+
"badge-star",
|
|
4852
|
+
"ban",
|
|
4853
|
+
"bell",
|
|
4854
|
+
"book-open",
|
|
4855
|
+
"bookmark",
|
|
4856
|
+
"bot",
|
|
4857
|
+
"bot-badge",
|
|
4858
|
+
"bot-users",
|
|
4859
|
+
"boxes",
|
|
4860
|
+
"boxes-model",
|
|
4861
|
+
"braces",
|
|
4862
|
+
"brackets",
|
|
4863
|
+
"brain",
|
|
4864
|
+
"brain-circuit",
|
|
4865
|
+
"brain-lock",
|
|
4866
|
+
"browser",
|
|
4867
|
+
"brush",
|
|
4868
|
+
"brush-stroke",
|
|
4869
|
+
"bug",
|
|
4870
|
+
"building-2",
|
|
4871
|
+
"calculator",
|
|
3851
4872
|
"calendar",
|
|
4873
|
+
"calendar-clock",
|
|
4874
|
+
"calendar-day",
|
|
4875
|
+
"calendar-days",
|
|
4876
|
+
"calendar-dot",
|
|
4877
|
+
"calendar-plus",
|
|
4878
|
+
"calendar-range",
|
|
4879
|
+
"calendar-x",
|
|
4880
|
+
"carousel",
|
|
4881
|
+
"catalog",
|
|
4882
|
+
"chart-column",
|
|
4883
|
+
"chart-line",
|
|
4884
|
+
"chart-pie",
|
|
4885
|
+
"chat",
|
|
3852
4886
|
"check",
|
|
3853
|
-
"
|
|
4887
|
+
"check-circle",
|
|
4888
|
+
"check-square",
|
|
3854
4889
|
"chevron-down",
|
|
4890
|
+
"chevron-left",
|
|
3855
4891
|
"chevron-right",
|
|
4892
|
+
"chevron-up",
|
|
4893
|
+
"chevron-updown",
|
|
4894
|
+
"chevrons-up-down",
|
|
4895
|
+
"circle-alert",
|
|
4896
|
+
"circle-check",
|
|
4897
|
+
"circle-dot",
|
|
4898
|
+
"circle-help",
|
|
4899
|
+
"circle-x",
|
|
4900
|
+
"clipboard-list",
|
|
4901
|
+
"clock",
|
|
4902
|
+
"clock-alert",
|
|
4903
|
+
"clock-sparkles",
|
|
4904
|
+
"clock-x",
|
|
4905
|
+
"close",
|
|
4906
|
+
"cloud",
|
|
4907
|
+
"cloud-off",
|
|
4908
|
+
"code",
|
|
4909
|
+
"code-2",
|
|
4910
|
+
"code-api",
|
|
4911
|
+
"coins",
|
|
4912
|
+
"comment",
|
|
4913
|
+
"companion",
|
|
4914
|
+
"compass",
|
|
4915
|
+
"connections",
|
|
4916
|
+
"contentpilot",
|
|
4917
|
+
"copy",
|
|
4918
|
+
"cpu",
|
|
4919
|
+
"cpu-chip",
|
|
4920
|
+
"credit-card",
|
|
4921
|
+
"crosshair",
|
|
4922
|
+
"crown",
|
|
4923
|
+
"cube",
|
|
4924
|
+
"database",
|
|
4925
|
+
"developer-settings",
|
|
4926
|
+
"device-link",
|
|
4927
|
+
"dollar-circle",
|
|
4928
|
+
"dollar-limit",
|
|
4929
|
+
"download",
|
|
4930
|
+
"download-video",
|
|
4931
|
+
"draw",
|
|
4932
|
+
"droplet",
|
|
4933
|
+
"ellipsis",
|
|
4934
|
+
"ellipsis-vertical",
|
|
4935
|
+
"embed-code",
|
|
4936
|
+
"eraser",
|
|
4937
|
+
"extension",
|
|
4938
|
+
"external-link",
|
|
4939
|
+
"eye",
|
|
4940
|
+
"eye-off",
|
|
4941
|
+
"file",
|
|
4942
|
+
"file-archive",
|
|
4943
|
+
"file-audio",
|
|
4944
|
+
"file-code",
|
|
4945
|
+
"file-edit",
|
|
4946
|
+
"file-image",
|
|
4947
|
+
"file-pdf",
|
|
4948
|
+
"file-plus",
|
|
4949
|
+
"file-scan",
|
|
4950
|
+
"file-text",
|
|
4951
|
+
"file-video",
|
|
4952
|
+
"file-warning",
|
|
4953
|
+
"files",
|
|
4954
|
+
"film",
|
|
4955
|
+
"filter",
|
|
4956
|
+
"filter-capabilities",
|
|
4957
|
+
"fingerprint",
|
|
4958
|
+
"flag",
|
|
4959
|
+
"flask-play",
|
|
4960
|
+
"folder",
|
|
4961
|
+
"folder-input",
|
|
4962
|
+
"folder-kanban",
|
|
4963
|
+
"folder-open",
|
|
4964
|
+
"folder-plus",
|
|
4965
|
+
"folder-shared",
|
|
4966
|
+
"folder-tree",
|
|
4967
|
+
"folder-x",
|
|
4968
|
+
"folders",
|
|
4969
|
+
"gauge",
|
|
4970
|
+
"gauge-high",
|
|
4971
|
+
"gauge-low",
|
|
4972
|
+
"gauge-medium",
|
|
4973
|
+
"gavel",
|
|
4974
|
+
"git-branch",
|
|
4975
|
+
"git-fork",
|
|
4976
|
+
"globe",
|
|
4977
|
+
"globe-check",
|
|
4978
|
+
"grid",
|
|
4979
|
+
"grip-vertical",
|
|
4980
|
+
"hand-check",
|
|
4981
|
+
"hard-drive",
|
|
4982
|
+
"hard-drive-alert",
|
|
4983
|
+
"hard-drive-off",
|
|
4984
|
+
"hash",
|
|
4985
|
+
"heart",
|
|
4986
|
+
"heart-chart-up",
|
|
4987
|
+
"heart-pulse",
|
|
4988
|
+
"help",
|
|
4989
|
+
"hierarchy",
|
|
4990
|
+
"history",
|
|
4991
|
+
"home",
|
|
4992
|
+
"hourglass",
|
|
4993
|
+
"house",
|
|
4994
|
+
"human-lock",
|
|
4995
|
+
"id-badge",
|
|
4996
|
+
"image",
|
|
4997
|
+
"image-minus",
|
|
4998
|
+
"image-plus",
|
|
4999
|
+
"image-up",
|
|
5000
|
+
"inbox",
|
|
5001
|
+
"inbox-empty",
|
|
3856
5002
|
"info",
|
|
5003
|
+
"install",
|
|
5004
|
+
"journal",
|
|
5005
|
+
"key",
|
|
5006
|
+
"key-off",
|
|
5007
|
+
"key-round",
|
|
5008
|
+
"languages",
|
|
5009
|
+
"laptop",
|
|
5010
|
+
"laptop-bridge",
|
|
5011
|
+
"layers",
|
|
5012
|
+
"layout-dashboard",
|
|
5013
|
+
"layout-grid",
|
|
5014
|
+
"layout-kanban",
|
|
5015
|
+
"leaf",
|
|
5016
|
+
"library-books",
|
|
5017
|
+
"life-buoy",
|
|
5018
|
+
"lightbulb",
|
|
5019
|
+
"lightbulb-sparkles",
|
|
5020
|
+
"line-width",
|
|
5021
|
+
"link",
|
|
5022
|
+
"link-2",
|
|
5023
|
+
"link-off",
|
|
5024
|
+
"list",
|
|
5025
|
+
"list-checks",
|
|
5026
|
+
"list-ordered",
|
|
5027
|
+
"list-rule",
|
|
5028
|
+
"list-todo",
|
|
5029
|
+
"llm",
|
|
3857
5030
|
"loader-circle",
|
|
5031
|
+
"lock",
|
|
5032
|
+
"lock-keyhole",
|
|
5033
|
+
"log-in",
|
|
5034
|
+
"log-out",
|
|
5035
|
+
"log-out-all",
|
|
5036
|
+
"magic-wand",
|
|
5037
|
+
"mail",
|
|
5038
|
+
"mail-check",
|
|
5039
|
+
"mail-open",
|
|
5040
|
+
"mail-plus",
|
|
5041
|
+
"mail-warning",
|
|
5042
|
+
"mails",
|
|
5043
|
+
"market",
|
|
5044
|
+
"maximize-2",
|
|
5045
|
+
"megaphone",
|
|
5046
|
+
"memory-stick",
|
|
5047
|
+
"menu",
|
|
5048
|
+
"message-circle",
|
|
5049
|
+
"message-square",
|
|
5050
|
+
"message-square-plus",
|
|
5051
|
+
"messages-square",
|
|
5052
|
+
"mic",
|
|
5053
|
+
"microphone",
|
|
5054
|
+
"minimize-2",
|
|
5055
|
+
"minus",
|
|
5056
|
+
"minus-square",
|
|
5057
|
+
"monitor-home",
|
|
5058
|
+
"monitor-smartphone",
|
|
5059
|
+
"moon",
|
|
5060
|
+
"more-horizontal",
|
|
5061
|
+
"mouse-pointer-2",
|
|
5062
|
+
"move-horizontal",
|
|
5063
|
+
"network",
|
|
5064
|
+
"network-nodes",
|
|
5065
|
+
"newsletter",
|
|
5066
|
+
"newspaper",
|
|
5067
|
+
"octagon-x",
|
|
5068
|
+
"package",
|
|
5069
|
+
"package-download",
|
|
5070
|
+
"page-snapshot",
|
|
5071
|
+
"palette",
|
|
5072
|
+
"panel-left",
|
|
5073
|
+
"panel-right",
|
|
5074
|
+
"panels-top-left",
|
|
5075
|
+
"paper-plane",
|
|
5076
|
+
"paperclip",
|
|
5077
|
+
"pause",
|
|
5078
|
+
"pause-circle",
|
|
5079
|
+
"pencil",
|
|
5080
|
+
"persona",
|
|
5081
|
+
"piggy-bank",
|
|
5082
|
+
"pipette",
|
|
5083
|
+
"play",
|
|
5084
|
+
"play-circle",
|
|
5085
|
+
"plug",
|
|
5086
|
+
"plug-cloud",
|
|
5087
|
+
"plug-off",
|
|
5088
|
+
"plug-plus",
|
|
5089
|
+
"plugin",
|
|
5090
|
+
"plus",
|
|
5091
|
+
"price-tag",
|
|
5092
|
+
"publish",
|
|
5093
|
+
"quote",
|
|
5094
|
+
"radio",
|
|
5095
|
+
"radio-tower",
|
|
5096
|
+
"receipt",
|
|
5097
|
+
"refresh",
|
|
5098
|
+
"refresh-cw",
|
|
5099
|
+
"refresh-cw-off",
|
|
5100
|
+
"repeat",
|
|
5101
|
+
"repeat-2",
|
|
5102
|
+
"repeat-fallback",
|
|
5103
|
+
"repeat-interval",
|
|
5104
|
+
"responses-list",
|
|
5105
|
+
"rocket",
|
|
5106
|
+
"rotate-ccw",
|
|
5107
|
+
"rotate-cw",
|
|
5108
|
+
"route",
|
|
5109
|
+
"rss",
|
|
5110
|
+
"save",
|
|
5111
|
+
"scale",
|
|
5112
|
+
"scan",
|
|
3858
5113
|
"search",
|
|
3859
|
-
"x"
|
|
5114
|
+
"search-x",
|
|
5115
|
+
"send",
|
|
5116
|
+
"send-check",
|
|
5117
|
+
"send-request",
|
|
5118
|
+
"server",
|
|
5119
|
+
"server-api",
|
|
5120
|
+
"server-environment",
|
|
5121
|
+
"settings",
|
|
5122
|
+
"settings-2",
|
|
5123
|
+
"share",
|
|
5124
|
+
"share-nodes",
|
|
5125
|
+
"shield",
|
|
5126
|
+
"shield-check",
|
|
5127
|
+
"shield-lock",
|
|
5128
|
+
"shield-question",
|
|
5129
|
+
"shield-x",
|
|
5130
|
+
"shopping-basket",
|
|
5131
|
+
"shopping-cart",
|
|
5132
|
+
"shuffle",
|
|
5133
|
+
"signal",
|
|
5134
|
+
"signal-high",
|
|
5135
|
+
"signal-low",
|
|
5136
|
+
"signal-medium",
|
|
5137
|
+
"signal-off",
|
|
5138
|
+
"siren",
|
|
5139
|
+
"sliders-horizontal",
|
|
5140
|
+
"smartphone",
|
|
5141
|
+
"sparkles",
|
|
5142
|
+
"square",
|
|
5143
|
+
"square-check",
|
|
5144
|
+
"square-plus",
|
|
5145
|
+
"square-terminal",
|
|
5146
|
+
"star",
|
|
5147
|
+
"sticker",
|
|
5148
|
+
"storage",
|
|
5149
|
+
"store",
|
|
5150
|
+
"story",
|
|
5151
|
+
"sun",
|
|
5152
|
+
"support",
|
|
5153
|
+
"target",
|
|
5154
|
+
"target-choice",
|
|
5155
|
+
"tasks",
|
|
5156
|
+
"terminal",
|
|
5157
|
+
"ticket",
|
|
5158
|
+
"ticket-plus",
|
|
5159
|
+
"tickets",
|
|
5160
|
+
"timeline",
|
|
5161
|
+
"timer",
|
|
5162
|
+
"toggle-left",
|
|
5163
|
+
"toggle-right",
|
|
5164
|
+
"token-input",
|
|
5165
|
+
"token-output",
|
|
5166
|
+
"trail",
|
|
5167
|
+
"trash-2",
|
|
5168
|
+
"trend-up",
|
|
5169
|
+
"triangle-alert",
|
|
5170
|
+
"type",
|
|
5171
|
+
"unlink",
|
|
5172
|
+
"unplug",
|
|
5173
|
+
"upload",
|
|
5174
|
+
"upload-cloud",
|
|
5175
|
+
"user",
|
|
5176
|
+
"user-check",
|
|
5177
|
+
"user-cog",
|
|
5178
|
+
"user-minus",
|
|
5179
|
+
"user-plus",
|
|
5180
|
+
"user-round",
|
|
5181
|
+
"user-x",
|
|
5182
|
+
"users",
|
|
5183
|
+
"users-round",
|
|
5184
|
+
"vault",
|
|
5185
|
+
"volume-2",
|
|
5186
|
+
"wallet",
|
|
5187
|
+
"wand-sparkles",
|
|
5188
|
+
"warehouse",
|
|
5189
|
+
"workflow",
|
|
5190
|
+
"workspace",
|
|
5191
|
+
"wrench",
|
|
5192
|
+
"wrench-zap",
|
|
5193
|
+
"x",
|
|
5194
|
+
"zap"
|
|
3860
5195
|
],
|
|
3861
|
-
description: "Icon identifier from the @treeui/icons registry."
|
|
5196
|
+
description: "Icon identifier from the @treeui/icons registry. Widens as `TIconRegistry` is augmented, so registered app icons are valid values too.",
|
|
5197
|
+
note: "Names use TreeUI's descriptive kebab-case vocabulary. The catalog covers common application needs; anything missing is one `registerTreeIcons` call away, and `listTreeIcons()` returns the live list at runtime."
|
|
3862
5198
|
},
|
|
3863
5199
|
{
|
|
3864
5200
|
name: "size",
|
|
3865
5201
|
type: "number | string",
|
|
3866
5202
|
default: "20",
|
|
3867
|
-
description: "Pixel size for both width and height of the rendered svg."
|
|
5203
|
+
description: "Pixel size for both width and height of the rendered svg.",
|
|
5204
|
+
note: 'This is a PIXEL COUNT, not the sm | md | lg token scale used by nearly every\nother TreeUI component. `<TIcon size="md" />` does not fail loudly: it writes\nwidth="md" / height="md" onto the svg, which the browser discards, so the\nicon becomes unsized and stretches to fill its container. Pass a number\n(20, 32) or a numeric string ("20"). To size an icon from tokens, leave `size`\nalone and set width/height in CSS from the icon scale \u2014 --tree-size-icon-sm |\n-md | -lg | -xl | -2xl (1rem / 1.25rem / 1.5rem / 2rem / 3rem) \u2014 which is what\nTLanguageSelect\'s switcher variant does.\n'
|
|
3868
5205
|
},
|
|
3869
5206
|
{
|
|
3870
5207
|
name: "strokeWidth",
|
|
@@ -3891,33 +5228,60 @@ var treeui_catalog_default = {
|
|
|
3891
5228
|
"becomes_image_when_labeled: true",
|
|
3892
5229
|
"rule: Provide `label` only when the icon conveys meaning that is not already in adjacent text."
|
|
3893
5230
|
],
|
|
3894
|
-
behavior: [
|
|
5231
|
+
behavior: [
|
|
5232
|
+
"unknown_name_renders_nothing: An unregistered name makes `resolveTreeIcon` return `undefined`, and `TIcon`'s `v-if` then renders no element at all \u2014 no empty box, no placeholder, no error. A `console.warn` names the missing icon, suggests the `registerTreeIcons` call, and lists every valid name. It warns once per NAME (not per message \u2014 the message embeds the valid-name list, which changes on every registration), so a miss inside a render loop cannot flood the console. The warning is NOT gated on `process.env.NODE_ENV`: it fires in production builds too, deliberately, because a missing icon is a misconfiguration worth hearing about once and `process` is undefined in most browser bundles. Components with a marker fallback (TNavMenu) show that instead \u2014 see nav-menu.yaml.",
|
|
5233
|
+
'absolute_stroke_width_math: Icons draw on `viewBox="0 0 24 24"` with the svg sized to `size`, so painted pixels = (stroke-width attribute) * size / 24. With `absoluteStrokeWidth` (the default) the attribute is set to `(strokeWidth * 24) / size`, which cancels the scale: at the default `strokeWidth: 2` the attribute is 2.4 at size 20, 1.5 at 32, and 1.0 at 48 \u2014 a constant 2px painted at every size. That is the entire point of the correction: a 48px icon sits beside a 20px one at the same optical weight. A `size` of 0 or a non-numeric value keeps the nominal stroke rather than producing NaN/Infinity. Setting `absoluteStrokeWidth: false` pins the attribute at `strokeWidth`, which is the hand-rolled behaviour: the painted stroke then scales WITH the icon (1.67px at 20, 2.67px at 32, 4px at 48 \u2014 double the library weight).',
|
|
5234
|
+
"icons_are_built_lazily_and_cached: Geometry lives in a data registry; a component is created on first lookup and reused after that, so an unused icon stays as DATA instead of becoming a `defineComponent`. Note what this does not claim: the geometry for all 364 built-ins is retained by any import of the package (the registry copies `builtinTreeIconNodes` into a `Map` at module scope, so a live reference exists and nothing tree-shakes it away \u2014 `sideEffects: false` does not change that). The saving is component construction, not bundle bytes.",
|
|
5235
|
+
"resolved_per_render: TIcon resolves its name in a computed, not once at setup, so an icon registered after the component mounted still appears.",
|
|
5236
|
+
"migration_aliases: Twelve compatibility names resolve to the same geometry as their canonical names: grid \u2192 layout-grid, share \u2192 share-nodes, chevron-updown \u2192 chevrons-up-down, refresh \u2192 refresh-cw, comment/chat \u2192 message-circle, check-square \u2192 square-check, help \u2192 circle-help, automations \u2192 zap, connections \u2192 external-link, persona \u2192 user-round, and close \u2192 x.",
|
|
5237
|
+
"company_logos_are_app_owned: Company logos are not built-ins. When an application needs one, it imports the official SVG as its own component and passes or registers that component under an application-owned name."
|
|
5238
|
+
],
|
|
3895
5239
|
selection: {
|
|
3896
5240
|
keywords: [
|
|
3897
5241
|
"icon",
|
|
3898
5242
|
"svg",
|
|
3899
5243
|
"glyph",
|
|
3900
|
-
"pictogram"
|
|
5244
|
+
"pictogram",
|
|
5245
|
+
"register",
|
|
5246
|
+
"register icon",
|
|
5247
|
+
"custom icon",
|
|
5248
|
+
"icon registry",
|
|
5249
|
+
"registerTreeIcons",
|
|
5250
|
+
"createTreeIcon"
|
|
3901
5251
|
],
|
|
3902
5252
|
useWhen: [
|
|
3903
|
-
"You need to render
|
|
3904
|
-
|
|
5253
|
+
"You need to render an interface icon. `TIcon` is the way to render one \u2014 it resolves the name through the registry and applies the shared size, stroke, and a11y defaults.",
|
|
5254
|
+
'The icon is one of the built-ins: `<TIcon name="cpu" />`. `listTreeIcons()` returns every registered name at runtime.',
|
|
5255
|
+
"The icon is your own: register it once with `registerTreeIcons`, then use it by name exactly like a built-in. A missing icon is registered, not worked around."
|
|
3905
5256
|
],
|
|
3906
5257
|
avoidWhen: [
|
|
3907
|
-
"The
|
|
5258
|
+
"The graphic is a country flag \u2014 a flag names a country, not an interface concept.",
|
|
5259
|
+
"A slot already renders the icon for you (`#icon` on TAlert, TBadge, TButton, TConfirmDialog, TEmptyState, TFileUpload, TStat, TTag) \u2014 put the `TIcon` inside that slot rather than beside it. None of those components has an `icon` PROP; the slot is the whole interface."
|
|
3908
5260
|
],
|
|
3909
5261
|
alternatives: [
|
|
3910
5262
|
{
|
|
3911
|
-
component: "
|
|
3912
|
-
when: "You
|
|
5263
|
+
component: "a component passed straight to `TNavMenuItem.icon`, or rendered into an `#icon` slot",
|
|
5264
|
+
when: "You want the escape hatch with no registry entry \u2014 a one-off icon, an imported SVG component, or the result of `createTreeIcon(...)`. `TNavMenuItem.icon` is `TIconInput` and takes the component directly; everywhere else, render it inside the component's `#icon` slot. `TIcon` itself will not take a component \u2014 its `name` is `TIconName`. Prefer registering when the icon is used in more than one place."
|
|
5265
|
+
},
|
|
5266
|
+
{
|
|
5267
|
+
component: "TFlag",
|
|
5268
|
+
when: "The graphic is a country flag rendered from an ISO 3166-1 alpha-2 code."
|
|
3913
5269
|
}
|
|
3914
5270
|
]
|
|
3915
5271
|
},
|
|
3916
5272
|
setup: {
|
|
3917
|
-
required: [
|
|
3918
|
-
|
|
5273
|
+
required: [
|
|
5274
|
+
"Use a registered name: one of the built-ins, or one the app added with `registerTreeIcons`. See `icons` above."
|
|
5275
|
+
],
|
|
5276
|
+
notes: [
|
|
5277
|
+
'`size` is a pixel count, not `sm | md | lg`. Passing `size="md"` renders an unsized svg.',
|
|
5278
|
+
"The icon is `aria-hidden` by default. Pass `label` only when the icon carries meaning on its own; beside visible text it should stay decorative."
|
|
5279
|
+
]
|
|
3919
5280
|
},
|
|
3920
|
-
recipes: [
|
|
5281
|
+
recipes: [
|
|
5282
|
+
"nav-menu-icons"
|
|
5283
|
+
],
|
|
5284
|
+
practices: []
|
|
3921
5285
|
},
|
|
3922
5286
|
{
|
|
3923
5287
|
name: "TInput",
|
|
@@ -4043,6 +5407,10 @@ var treeui_catalog_default = {
|
|
|
4043
5407
|
recipes: [
|
|
4044
5408
|
"form-field-input",
|
|
4045
5409
|
"tag-input"
|
|
5410
|
+
],
|
|
5411
|
+
practices: [
|
|
5412
|
+
"interaction-feedback",
|
|
5413
|
+
"predictable-api"
|
|
4046
5414
|
]
|
|
4047
5415
|
},
|
|
4048
5416
|
{
|
|
@@ -4080,7 +5448,245 @@ var treeui_catalog_default = {
|
|
|
4080
5448
|
required: [],
|
|
4081
5449
|
notes: []
|
|
4082
5450
|
},
|
|
4083
|
-
recipes: []
|
|
5451
|
+
recipes: [],
|
|
5452
|
+
practices: []
|
|
5453
|
+
},
|
|
5454
|
+
{
|
|
5455
|
+
name: "TLanguageSelect",
|
|
5456
|
+
aliases: [],
|
|
5457
|
+
package: "@treeui/vue",
|
|
5458
|
+
kind: "form_overlay",
|
|
5459
|
+
category: "Data Entry",
|
|
5460
|
+
status: "available",
|
|
5461
|
+
purpose: "Language/locale picker with a listbox, a flag per option, and the shared overlay contract; controlled and uncontrolled via v-model and open/defaultOpen.",
|
|
5462
|
+
sourceFile: "packages/vue/src/components/TLanguageSelect.vue",
|
|
5463
|
+
storyFile: "apps/docs/src/stories/LanguageSelect.stories.ts",
|
|
5464
|
+
storyTitle: "Components/Data Entry/LanguageSelect",
|
|
5465
|
+
manifestFile: "docs/ai/COMPONENTS/language-select.yaml",
|
|
5466
|
+
props: [
|
|
5467
|
+
{
|
|
5468
|
+
name: "modelValue",
|
|
5469
|
+
type: "string",
|
|
5470
|
+
default: ""
|
|
5471
|
+
},
|
|
5472
|
+
{
|
|
5473
|
+
name: "options",
|
|
5474
|
+
type: "TLanguageOption[]",
|
|
5475
|
+
default: "[]",
|
|
5476
|
+
note: "Array of { label: string; value: string; code?: string; description?: string; disabled?: boolean }. `value` is an opaque application key (typically a BCP-47 tag) \u2014 never parsed or validated. `code` is an ISO 3166-1 alpha-2 country code for the flag; omit it to render the option without one. `description` is a secondary line, e.g. the endonym."
|
|
5477
|
+
},
|
|
5478
|
+
{
|
|
5479
|
+
name: "open",
|
|
5480
|
+
type: "boolean",
|
|
5481
|
+
default: "undefined"
|
|
5482
|
+
},
|
|
5483
|
+
{
|
|
5484
|
+
name: "defaultOpen",
|
|
5485
|
+
type: "boolean",
|
|
5486
|
+
default: "false"
|
|
5487
|
+
},
|
|
5488
|
+
{
|
|
5489
|
+
name: "size",
|
|
5490
|
+
type: "TSize",
|
|
5491
|
+
default: "md",
|
|
5492
|
+
values: [
|
|
5493
|
+
"sm",
|
|
5494
|
+
"md",
|
|
5495
|
+
"lg"
|
|
5496
|
+
]
|
|
5497
|
+
},
|
|
5498
|
+
{
|
|
5499
|
+
name: "variant",
|
|
5500
|
+
type: "TLanguageSelectVariant",
|
|
5501
|
+
default: "field",
|
|
5502
|
+
values: [
|
|
5503
|
+
"field",
|
|
5504
|
+
"switcher"
|
|
5505
|
+
],
|
|
5506
|
+
note: "`field` is a form control, sized and laid out like any other input. `switcher` is a page-level control for a navbar/appbar where nothing nearby labels it: it leads with a translate icon, trails the current flag, and sizes to its content."
|
|
5507
|
+
},
|
|
5508
|
+
{
|
|
5509
|
+
name: "iconOnly",
|
|
5510
|
+
type: "boolean",
|
|
5511
|
+
default: "false",
|
|
5512
|
+
note: "`switcher` only \u2014 ignored by `field`. Drops the visible language name, leaving the translate icon, the current flag, and the chevron. The trigger then has no text, so the consumer MUST pass an `aria-label`."
|
|
5513
|
+
},
|
|
5514
|
+
{
|
|
5515
|
+
name: "width",
|
|
5516
|
+
type: "TFieldWidth",
|
|
5517
|
+
default: "full",
|
|
5518
|
+
values: [
|
|
5519
|
+
"xs",
|
|
5520
|
+
"sm",
|
|
5521
|
+
"md",
|
|
5522
|
+
"lg",
|
|
5523
|
+
"xl",
|
|
5524
|
+
"full"
|
|
5525
|
+
],
|
|
5526
|
+
note: "Inline-size cap (max-inline-size). Fluid by default; use instead of an inline width style. Applies to `variant: field` only \u2014 a `switcher` sizes to its content and ignores it."
|
|
5527
|
+
},
|
|
5528
|
+
{
|
|
5529
|
+
name: "disabled",
|
|
5530
|
+
type: "boolean",
|
|
5531
|
+
default: "false"
|
|
5532
|
+
},
|
|
5533
|
+
{
|
|
5534
|
+
name: "loading",
|
|
5535
|
+
type: "boolean",
|
|
5536
|
+
default: "false"
|
|
5537
|
+
},
|
|
5538
|
+
{
|
|
5539
|
+
name: "invalid",
|
|
5540
|
+
type: "boolean",
|
|
5541
|
+
default: "false"
|
|
5542
|
+
},
|
|
5543
|
+
{
|
|
5544
|
+
name: "placeholder",
|
|
5545
|
+
type: "string",
|
|
5546
|
+
default: ""
|
|
5547
|
+
},
|
|
5548
|
+
{
|
|
5549
|
+
name: "flagBaseUrl",
|
|
5550
|
+
type: "string",
|
|
5551
|
+
default: "undefined",
|
|
5552
|
+
note: "Forwarded to every nested TFlag. When omitted, TFlag's own default origin applies. Set once here to self-host flag assets."
|
|
5553
|
+
},
|
|
5554
|
+
{
|
|
5555
|
+
name: "emptyText",
|
|
5556
|
+
type: "string",
|
|
5557
|
+
default: "No languages available."
|
|
5558
|
+
}
|
|
5559
|
+
],
|
|
5560
|
+
events: [
|
|
5561
|
+
{
|
|
5562
|
+
name: "update:modelValue"
|
|
5563
|
+
},
|
|
5564
|
+
{
|
|
5565
|
+
name: "update:open"
|
|
5566
|
+
},
|
|
5567
|
+
{
|
|
5568
|
+
name: "open-change"
|
|
5569
|
+
}
|
|
5570
|
+
],
|
|
5571
|
+
slots: [
|
|
5572
|
+
{
|
|
5573
|
+
name: "prefix",
|
|
5574
|
+
description: "Leading content inside the trigger, before everything else \u2014 the selected flag and label in `field`, the translate icon in `switcher`."
|
|
5575
|
+
},
|
|
5576
|
+
{
|
|
5577
|
+
name: "option",
|
|
5578
|
+
description: `Replaces the default option body (flag, label, description). Renders INSIDE the row's <li role="option">, so it must contain only presentational content.
|
|
5579
|
+
`
|
|
5580
|
+
},
|
|
5581
|
+
{
|
|
5582
|
+
name: "empty",
|
|
5583
|
+
description: "Replaces `emptyText` when `options` is empty."
|
|
5584
|
+
}
|
|
5585
|
+
],
|
|
5586
|
+
a11y: [
|
|
5587
|
+
"role: listbox",
|
|
5588
|
+
"trigger_aria_haspopup: listbox",
|
|
5589
|
+
"trigger_aria_expanded: true",
|
|
5590
|
+
"trigger_aria_controls_when_open: true",
|
|
5591
|
+
"aria_invalid_when_invalid: true",
|
|
5592
|
+
"aria_busy_when_loading: true",
|
|
5593
|
+
"aria_selected_on_options: true",
|
|
5594
|
+
"aria_disabled_on_disabled_options: true",
|
|
5595
|
+
"focus_visible_on_trigger: true",
|
|
5596
|
+
"keyboard_arrow_navigation: true",
|
|
5597
|
+
"escape_closes_dropdown: true",
|
|
5598
|
+
"enter_space_selects_option: true",
|
|
5599
|
+
"home_end_navigation: true",
|
|
5600
|
+
"home_end_target_first_last_enabled_option: true",
|
|
5601
|
+
"focus_restores_to_trigger_on_close: true",
|
|
5602
|
+
"icon_only_removes_the_visible_language_name: true",
|
|
5603
|
+
"icon_only_requires_a_consumer_supplied_aria_label_on_the_trigger: true",
|
|
5604
|
+
"translate_icon_and_flags_are_decorative_not_the_accessible_name: true"
|
|
5605
|
+
],
|
|
5606
|
+
behavior: [
|
|
5607
|
+
"update_payload_type: string",
|
|
5608
|
+
"loading_does_not_disable_by_itself: true",
|
|
5609
|
+
"placeholder_shown_as_muted_text: true",
|
|
5610
|
+
"chevron_rotates_when_open: true",
|
|
5611
|
+
"check_icon_on_selected_option: true",
|
|
5612
|
+
"outside_click_closes_dropdown: true",
|
|
5613
|
+
"listbox_flips_above_trigger_when_space_below_is_insufficient: true",
|
|
5614
|
+
"options_without_a_code_render_without_a_flag: true",
|
|
5615
|
+
"empty_options_render_the_empty_slot_or_empty_text: true",
|
|
5616
|
+
"field_variant_leads_the_trigger_with_the_selected_flag: true",
|
|
5617
|
+
"field_variant_trigger_fills_its_container: true",
|
|
5618
|
+
"switcher_variant_leads_the_trigger_with_a_translate_icon: true",
|
|
5619
|
+
"switcher_variant_trails_the_current_flag_before_the_chevron: true",
|
|
5620
|
+
"switcher_variant_trigger_sizes_to_its_content: true",
|
|
5621
|
+
"switcher_variant_ignores_the_width_prop: true",
|
|
5622
|
+
"switcher_listbox_aligns_to_the_trigger_right_edge: true",
|
|
5623
|
+
"switcher_listbox_may_be_wider_than_the_trigger: true",
|
|
5624
|
+
"icon_only_applies_to_the_switcher_variant_only: true",
|
|
5625
|
+
"root_classes: t-language-select--field | t-language-select--switcher, plus t-language-select--icon-only"
|
|
5626
|
+
],
|
|
5627
|
+
selection: {
|
|
5628
|
+
keywords: [
|
|
5629
|
+
"language select",
|
|
5630
|
+
"language picker",
|
|
5631
|
+
"locale",
|
|
5632
|
+
"locale picker",
|
|
5633
|
+
"i18n",
|
|
5634
|
+
"internationalization",
|
|
5635
|
+
"translation",
|
|
5636
|
+
"country flag"
|
|
5637
|
+
],
|
|
5638
|
+
useWhen: [
|
|
5639
|
+
"The user is picking the interface language or locale.",
|
|
5640
|
+
'The control is a labelled form field for the language value \u2014 `variant="field"` (the default), where the flag leads the trigger and `width` applies.',
|
|
5641
|
+
'The control is a page-level language switcher in a navbar or app bar, where nothing nearby says what it changes \u2014 `variant="switcher"` leads with a translate icon and trails the current flag, sizes to its content, and ignores `width`.',
|
|
5642
|
+
"A navbar switcher should shrink to icon and flag only \u2014 `iconOnly` drops the language name, so pass an `aria-label` to name the control.",
|
|
5643
|
+
"Each language should render with its country flag, and optionally an endonym as a second line.",
|
|
5644
|
+
"The app owns the language list and applies the locale side effects itself."
|
|
5645
|
+
],
|
|
5646
|
+
avoidWhen: [
|
|
5647
|
+
"The values are not languages or locales.",
|
|
5648
|
+
"The language list is long enough that the user must type to narrow it down.",
|
|
5649
|
+
"You expect TreeUI to supply the locale dataset \u2014 it ships none, so pass your own `options`."
|
|
5650
|
+
],
|
|
5651
|
+
alternatives: [
|
|
5652
|
+
{
|
|
5653
|
+
component: "TSelect",
|
|
5654
|
+
when: "The values are ordinary application data rather than languages or locales."
|
|
5655
|
+
},
|
|
5656
|
+
{
|
|
5657
|
+
component: "TCombobox",
|
|
5658
|
+
when: "The language list is long enough that typing to narrow it down is required."
|
|
5659
|
+
},
|
|
5660
|
+
{
|
|
5661
|
+
component: "TFlag",
|
|
5662
|
+
when: "You only need to render one country flag, without a picker around it."
|
|
5663
|
+
}
|
|
5664
|
+
]
|
|
5665
|
+
},
|
|
5666
|
+
setup: {
|
|
5667
|
+
required: [
|
|
5668
|
+
"Pass `options` as `{ label, value, code?, description?, disabled? }[]`. TreeUI ships no language, locale, or country dataset \u2014 the app owns its language list.",
|
|
5669
|
+
"Apply locale side effects (i18n locale, `lang` attribute, persistence) in the app layer; the component only reports the selected `value`.",
|
|
5670
|
+
"Pass an `aria-label` whenever `iconOnly` is set \u2014 the visible language name is gone, so it is the control's only accessible name. It also labels the listbox."
|
|
5671
|
+
],
|
|
5672
|
+
notes: [
|
|
5673
|
+
"`variant` is `field` (default) or `switcher`, typed as `TLanguageSelectVariant` and exported from `@treeui/vue`.",
|
|
5674
|
+
'Use `variant="field"` inside a form, next to other inputs, or wrapped in `TFormField`: the flag leads the trigger, the trigger fills its container, and `width` applies. A visible field label already says what the control changes.',
|
|
5675
|
+
'Use `variant="switcher"` for a page-level control in a navbar or app bar, where nothing nearby labels it. A translate icon (`TIcon name="languages"`) leads and the current flag trails before the chevron, so the control reads as "page language, now set to this" without an external label.',
|
|
5676
|
+
"A switcher sizes to its content, so `width` does not apply, and its listbox aligns to the trigger's right edge.",
|
|
5677
|
+
"`iconOnly` is switcher-only and drops the visible language name, leaving the translate icon and the current flag.",
|
|
5678
|
+
"`value` is an opaque application key, typically a BCP-47 tag such as `pt-BR`. TreeUI never parses or validates it.",
|
|
5679
|
+
"`code` is the ISO 3166-1 alpha-2 code used for the option flag. Omit it to render the option without a flag \u2014 a language is not a country, so many entries have no honest flag.",
|
|
5680
|
+
"Use `description` for a secondary line such as the endonym.",
|
|
5681
|
+
"Set `flagBaseUrl` once on the select rather than per option; it is forwarded to every nested `TFlag`.",
|
|
5682
|
+
"Bind `modelValue` to a `string`, and use `v-model:open` when the app controls open state.",
|
|
5683
|
+
"The CDN and Content-Security-Policy requirements under `TFlag` apply whenever any option carries a `code`."
|
|
5684
|
+
]
|
|
5685
|
+
},
|
|
5686
|
+
recipes: [
|
|
5687
|
+
"language-switcher"
|
|
5688
|
+
],
|
|
5689
|
+
practices: []
|
|
4084
5690
|
},
|
|
4085
5691
|
{
|
|
4086
5692
|
name: "TLink",
|
|
@@ -4181,7 +5787,10 @@ var treeui_catalog_default = {
|
|
|
4181
5787
|
required: [],
|
|
4182
5788
|
notes: []
|
|
4183
5789
|
},
|
|
4184
|
-
recipes: []
|
|
5790
|
+
recipes: [],
|
|
5791
|
+
practices: [
|
|
5792
|
+
"interaction-feedback"
|
|
5793
|
+
]
|
|
4185
5794
|
},
|
|
4186
5795
|
{
|
|
4187
5796
|
name: "TMarkdownEditor",
|
|
@@ -4290,7 +5899,8 @@ var treeui_catalog_default = {
|
|
|
4290
5899
|
required: [],
|
|
4291
5900
|
notes: []
|
|
4292
5901
|
},
|
|
4293
|
-
recipes: []
|
|
5902
|
+
recipes: [],
|
|
5903
|
+
practices: []
|
|
4294
5904
|
},
|
|
4295
5905
|
{
|
|
4296
5906
|
name: "TModal",
|
|
@@ -4438,7 +6048,11 @@ var treeui_catalog_default = {
|
|
|
4438
6048
|
"Use `v-model:open` for the idiomatic Vue controlled pattern."
|
|
4439
6049
|
]
|
|
4440
6050
|
},
|
|
4441
|
-
recipes: []
|
|
6051
|
+
recipes: [],
|
|
6052
|
+
practices: [
|
|
6053
|
+
"accessible-by-default",
|
|
6054
|
+
"predictable-api"
|
|
6055
|
+
]
|
|
4442
6056
|
},
|
|
4443
6057
|
{
|
|
4444
6058
|
name: "TMultiSelect",
|
|
@@ -4597,7 +6211,8 @@ var treeui_catalog_default = {
|
|
|
4597
6211
|
},
|
|
4598
6212
|
recipes: [
|
|
4599
6213
|
"searchable-multi-choice"
|
|
4600
|
-
]
|
|
6214
|
+
],
|
|
6215
|
+
practices: []
|
|
4601
6216
|
},
|
|
4602
6217
|
{
|
|
4603
6218
|
name: "TNavbar",
|
|
@@ -4695,6 +6310,9 @@ var treeui_catalog_default = {
|
|
|
4695
6310
|
},
|
|
4696
6311
|
recipes: [
|
|
4697
6312
|
"sidebar-shell"
|
|
6313
|
+
],
|
|
6314
|
+
practices: [
|
|
6315
|
+
"token-driven"
|
|
4698
6316
|
]
|
|
4699
6317
|
},
|
|
4700
6318
|
{
|
|
@@ -4787,10 +6405,13 @@ var treeui_catalog_default = {
|
|
|
4787
6405
|
keywords: [
|
|
4788
6406
|
"nav menu",
|
|
4789
6407
|
"sidebar nav",
|
|
4790
|
-
"section nav"
|
|
6408
|
+
"section nav",
|
|
6409
|
+
"nav icons",
|
|
6410
|
+
"sidebar rail"
|
|
4791
6411
|
],
|
|
4792
6412
|
useWhen: [
|
|
4793
|
-
"You need app-section navigation inside a shell or sidebar."
|
|
6413
|
+
"You need app-section navigation inside a shell or sidebar.",
|
|
6414
|
+
"Each section should carry an icon \u2014 set `icon` on the item to a registered name (`icon: 'layout-dashboard'`). Items with no icon fall back to a letter marker, which is also what a collapsed rail shows."
|
|
4794
6415
|
],
|
|
4795
6416
|
avoidWhen: [
|
|
4796
6417
|
"You need tabs for small panel switching."
|
|
@@ -4809,13 +6430,19 @@ var treeui_catalog_default = {
|
|
|
4809
6430
|
setup: {
|
|
4810
6431
|
required: [],
|
|
4811
6432
|
notes: [
|
|
4812
|
-
"When nested inside `TSidebar` or `TAppShell`, `collapsed` can be inherited from the sidebar provider."
|
|
6433
|
+
"When nested inside `TSidebar` or `TAppShell`, `collapsed` can be inherited from the sidebar provider.",
|
|
6434
|
+
"Pass `items` as `{ label, value, icon?, to?, badge?, description?, shortLabel?, disabled?, exact? }[]`.",
|
|
6435
|
+
"`icon` is `TIconInput` \u2014 a registered icon name (`icon: 'layout-dashboard'`) or a component. Use the name: it needs no import, and no `markRaw` when the item list is reactive.",
|
|
6436
|
+
"An item with no icon, or with a name that is not registered, shows a letter marker instead. That marker is also all a collapsed rail can show, so give every item an icon when the sidebar collapses.",
|
|
6437
|
+
"Register any icon the app needs beyond the built-ins first \u2014 see `icons` above."
|
|
4813
6438
|
]
|
|
4814
6439
|
},
|
|
4815
6440
|
recipes: [
|
|
4816
6441
|
"app-shell",
|
|
4817
|
-
"sidebar-shell"
|
|
4818
|
-
|
|
6442
|
+
"sidebar-shell",
|
|
6443
|
+
"nav-menu-icons"
|
|
6444
|
+
],
|
|
6445
|
+
practices: []
|
|
4819
6446
|
},
|
|
4820
6447
|
{
|
|
4821
6448
|
name: "TNumberInput",
|
|
@@ -4922,7 +6549,8 @@ var treeui_catalog_default = {
|
|
|
4922
6549
|
required: [],
|
|
4923
6550
|
notes: []
|
|
4924
6551
|
},
|
|
4925
|
-
recipes: []
|
|
6552
|
+
recipes: [],
|
|
6553
|
+
practices: []
|
|
4926
6554
|
},
|
|
4927
6555
|
{
|
|
4928
6556
|
name: "TPage",
|
|
@@ -5015,7 +6643,10 @@ var treeui_catalog_default = {
|
|
|
5015
6643
|
required: [],
|
|
5016
6644
|
notes: []
|
|
5017
6645
|
},
|
|
5018
|
-
recipes: []
|
|
6646
|
+
recipes: [],
|
|
6647
|
+
practices: [
|
|
6648
|
+
"content-alignment"
|
|
6649
|
+
]
|
|
5019
6650
|
},
|
|
5020
6651
|
{
|
|
5021
6652
|
name: "TPageHeader",
|
|
@@ -5109,7 +6740,10 @@ var treeui_catalog_default = {
|
|
|
5109
6740
|
required: [],
|
|
5110
6741
|
notes: []
|
|
5111
6742
|
},
|
|
5112
|
-
recipes: []
|
|
6743
|
+
recipes: [],
|
|
6744
|
+
practices: [
|
|
6745
|
+
"content-alignment"
|
|
6746
|
+
]
|
|
5113
6747
|
},
|
|
5114
6748
|
{
|
|
5115
6749
|
name: "TPagination",
|
|
@@ -5222,6 +6856,9 @@ var treeui_catalog_default = {
|
|
|
5222
6856
|
},
|
|
5223
6857
|
recipes: [
|
|
5224
6858
|
"data-listing"
|
|
6859
|
+
],
|
|
6860
|
+
practices: [
|
|
6861
|
+
"interaction-feedback"
|
|
5225
6862
|
]
|
|
5226
6863
|
},
|
|
5227
6864
|
{
|
|
@@ -5281,7 +6918,7 @@ var treeui_catalog_default = {
|
|
|
5281
6918
|
slots: [
|
|
5282
6919
|
{
|
|
5283
6920
|
name: "trigger",
|
|
5284
|
-
description: "Custom trigger element. Receives current open state
|
|
6921
|
+
description: "Custom trigger element. Receives the current open state and the id of the content panel, so aria-expanded and aria-controls can be wired by hand.\n"
|
|
5285
6922
|
},
|
|
5286
6923
|
{
|
|
5287
6924
|
name: "default",
|
|
@@ -5290,9 +6927,9 @@ var treeui_catalog_default = {
|
|
|
5290
6927
|
],
|
|
5291
6928
|
a11y: [
|
|
5292
6929
|
"role: dialog",
|
|
5293
|
-
'attrs: ["aria-haspopup=\\"dialog\\" on trigger","aria-expanded on trigger","aria-controls linking trigger to content","tabindex=\\"-1\\" on content for focus management"]',
|
|
6930
|
+
'attrs: ["aria-haspopup=\\"dialog\\" on the built-in trigger (custom triggers must supply it)","aria-expanded on the built-in trigger (custom triggers bind it from `isOpen`)","aria-controls linking trigger to content (custom triggers bind it from `contentId`)","tabindex=\\"-1\\" on content for focus management"]',
|
|
5294
6931
|
'keyboard: ["Click or Enter/Space on trigger toggles popover","Escape closes popover and restores focus to trigger","Tab navigates within popover content"]',
|
|
5295
|
-
'focus: ["On open, focuses first focusable element inside content (or content itself)","On Escape close, restores focus to trigger"]',
|
|
6932
|
+
'focus: ["On open, focuses first focusable element inside content (or content itself)","On Escape close, restores focus to trigger","Focus restore works with a custom trigger too: the ref lives on the `t-popover__anchor` wrapper, not on the built-in button, and focus returns to the first focusable element inside it.\\n"]',
|
|
5296
6933
|
'dismiss: ["Outside click closes popover","Escape key closes popover"]'
|
|
5297
6934
|
],
|
|
5298
6935
|
behavior: [],
|
|
@@ -5325,7 +6962,8 @@ var treeui_catalog_default = {
|
|
|
5325
6962
|
},
|
|
5326
6963
|
recipes: [
|
|
5327
6964
|
"anchored-help"
|
|
5328
|
-
]
|
|
6965
|
+
],
|
|
6966
|
+
practices: []
|
|
5329
6967
|
},
|
|
5330
6968
|
{
|
|
5331
6969
|
name: "TPricing",
|
|
@@ -5389,7 +7027,8 @@ var treeui_catalog_default = {
|
|
|
5389
7027
|
},
|
|
5390
7028
|
recipes: [
|
|
5391
7029
|
"pricing-section"
|
|
5392
|
-
]
|
|
7030
|
+
],
|
|
7031
|
+
practices: []
|
|
5393
7032
|
},
|
|
5394
7033
|
{
|
|
5395
7034
|
name: "TPricingCard",
|
|
@@ -5518,7 +7157,8 @@ var treeui_catalog_default = {
|
|
|
5518
7157
|
},
|
|
5519
7158
|
recipes: [
|
|
5520
7159
|
"pricing-section"
|
|
5521
|
-
]
|
|
7160
|
+
],
|
|
7161
|
+
practices: []
|
|
5522
7162
|
},
|
|
5523
7163
|
{
|
|
5524
7164
|
name: "TProgress",
|
|
@@ -5580,7 +7220,10 @@ var treeui_catalog_default = {
|
|
|
5580
7220
|
required: [],
|
|
5581
7221
|
notes: []
|
|
5582
7222
|
},
|
|
5583
|
-
recipes: []
|
|
7223
|
+
recipes: [],
|
|
7224
|
+
practices: [
|
|
7225
|
+
"state-clarity"
|
|
7226
|
+
]
|
|
5584
7227
|
},
|
|
5585
7228
|
{
|
|
5586
7229
|
name: "TRadio",
|
|
@@ -5648,7 +7291,8 @@ var treeui_catalog_default = {
|
|
|
5648
7291
|
required: [],
|
|
5649
7292
|
notes: []
|
|
5650
7293
|
},
|
|
5651
|
-
recipes: []
|
|
7294
|
+
recipes: [],
|
|
7295
|
+
practices: []
|
|
5652
7296
|
},
|
|
5653
7297
|
{
|
|
5654
7298
|
name: "TRadioGroup",
|
|
@@ -5723,7 +7367,8 @@ var treeui_catalog_default = {
|
|
|
5723
7367
|
required: [],
|
|
5724
7368
|
notes: []
|
|
5725
7369
|
},
|
|
5726
|
-
recipes: []
|
|
7370
|
+
recipes: [],
|
|
7371
|
+
practices: []
|
|
5727
7372
|
},
|
|
5728
7373
|
{
|
|
5729
7374
|
name: "TSelect",
|
|
@@ -5878,6 +7523,10 @@ var treeui_catalog_default = {
|
|
|
5878
7523
|
},
|
|
5879
7524
|
recipes: [
|
|
5880
7525
|
"chart-surface"
|
|
7526
|
+
],
|
|
7527
|
+
practices: [
|
|
7528
|
+
"interaction-feedback",
|
|
7529
|
+
"predictable-api"
|
|
5881
7530
|
]
|
|
5882
7531
|
},
|
|
5883
7532
|
{
|
|
@@ -5988,7 +7637,10 @@ var treeui_catalog_default = {
|
|
|
5988
7637
|
required: [],
|
|
5989
7638
|
notes: []
|
|
5990
7639
|
},
|
|
5991
|
-
recipes: []
|
|
7640
|
+
recipes: [],
|
|
7641
|
+
practices: [
|
|
7642
|
+
"interaction-feedback"
|
|
7643
|
+
]
|
|
5992
7644
|
},
|
|
5993
7645
|
{
|
|
5994
7646
|
name: "TSidebar",
|
|
@@ -6136,7 +7788,8 @@ var treeui_catalog_default = {
|
|
|
6136
7788
|
},
|
|
6137
7789
|
recipes: [
|
|
6138
7790
|
"sidebar-shell"
|
|
6139
|
-
]
|
|
7791
|
+
],
|
|
7792
|
+
practices: []
|
|
6140
7793
|
},
|
|
6141
7794
|
{
|
|
6142
7795
|
name: "TSkeleton",
|
|
@@ -6199,7 +7852,10 @@ var treeui_catalog_default = {
|
|
|
6199
7852
|
required: [],
|
|
6200
7853
|
notes: []
|
|
6201
7854
|
},
|
|
6202
|
-
recipes: []
|
|
7855
|
+
recipes: [],
|
|
7856
|
+
practices: [
|
|
7857
|
+
"state-clarity"
|
|
7858
|
+
]
|
|
6203
7859
|
},
|
|
6204
7860
|
{
|
|
6205
7861
|
name: "TSpacer",
|
|
@@ -6239,7 +7895,10 @@ var treeui_catalog_default = {
|
|
|
6239
7895
|
required: [],
|
|
6240
7896
|
notes: []
|
|
6241
7897
|
},
|
|
6242
|
-
recipes: []
|
|
7898
|
+
recipes: [],
|
|
7899
|
+
practices: [
|
|
7900
|
+
"content-alignment"
|
|
7901
|
+
]
|
|
6243
7902
|
},
|
|
6244
7903
|
{
|
|
6245
7904
|
name: "TSparkline",
|
|
@@ -6362,7 +8021,8 @@ var treeui_catalog_default = {
|
|
|
6362
8021
|
},
|
|
6363
8022
|
recipes: [
|
|
6364
8023
|
"metric-dashboard"
|
|
6365
|
-
]
|
|
8024
|
+
],
|
|
8025
|
+
practices: []
|
|
6366
8026
|
},
|
|
6367
8027
|
{
|
|
6368
8028
|
name: "TSpinner",
|
|
@@ -6411,7 +8071,10 @@ var treeui_catalog_default = {
|
|
|
6411
8071
|
required: [],
|
|
6412
8072
|
notes: []
|
|
6413
8073
|
},
|
|
6414
|
-
recipes: []
|
|
8074
|
+
recipes: [],
|
|
8075
|
+
practices: [
|
|
8076
|
+
"state-clarity"
|
|
8077
|
+
]
|
|
6415
8078
|
},
|
|
6416
8079
|
{
|
|
6417
8080
|
name: "TSplit",
|
|
@@ -6487,7 +8150,10 @@ var treeui_catalog_default = {
|
|
|
6487
8150
|
required: [],
|
|
6488
8151
|
notes: []
|
|
6489
8152
|
},
|
|
6490
|
-
recipes: []
|
|
8153
|
+
recipes: [],
|
|
8154
|
+
practices: [
|
|
8155
|
+
"content-alignment"
|
|
8156
|
+
]
|
|
6491
8157
|
},
|
|
6492
8158
|
{
|
|
6493
8159
|
name: "TStack",
|
|
@@ -6591,6 +8257,9 @@ var treeui_catalog_default = {
|
|
|
6591
8257
|
"tag-input",
|
|
6592
8258
|
"data-listing",
|
|
6593
8259
|
"chart-surface"
|
|
8260
|
+
],
|
|
8261
|
+
practices: [
|
|
8262
|
+
"content-alignment"
|
|
6594
8263
|
]
|
|
6595
8264
|
},
|
|
6596
8265
|
{
|
|
@@ -6665,7 +8334,8 @@ var treeui_catalog_default = {
|
|
|
6665
8334
|
required: [],
|
|
6666
8335
|
notes: []
|
|
6667
8336
|
},
|
|
6668
|
-
recipes: []
|
|
8337
|
+
recipes: [],
|
|
8338
|
+
practices: []
|
|
6669
8339
|
},
|
|
6670
8340
|
{
|
|
6671
8341
|
name: "TStat",
|
|
@@ -6787,7 +8457,8 @@ var treeui_catalog_default = {
|
|
|
6787
8457
|
recipes: [
|
|
6788
8458
|
"stat-grid",
|
|
6789
8459
|
"metric-dashboard"
|
|
6790
|
-
]
|
|
8460
|
+
],
|
|
8461
|
+
practices: []
|
|
6791
8462
|
},
|
|
6792
8463
|
{
|
|
6793
8464
|
name: "TSteps",
|
|
@@ -6891,7 +8562,8 @@ var treeui_catalog_default = {
|
|
|
6891
8562
|
"Pass explicit `status` per item only when the app should override the computed complete/current/upcoming logic."
|
|
6892
8563
|
]
|
|
6893
8564
|
},
|
|
6894
|
-
recipes: []
|
|
8565
|
+
recipes: [],
|
|
8566
|
+
practices: []
|
|
6895
8567
|
},
|
|
6896
8568
|
{
|
|
6897
8569
|
name: "TSwitch",
|
|
@@ -6980,7 +8652,10 @@ var treeui_catalog_default = {
|
|
|
6980
8652
|
required: [],
|
|
6981
8653
|
notes: []
|
|
6982
8654
|
},
|
|
6983
|
-
recipes: []
|
|
8655
|
+
recipes: [],
|
|
8656
|
+
practices: [
|
|
8657
|
+
"interaction-feedback"
|
|
8658
|
+
]
|
|
6984
8659
|
},
|
|
6985
8660
|
{
|
|
6986
8661
|
name: "TTable",
|
|
@@ -7020,6 +8695,13 @@ var treeui_catalog_default = {
|
|
|
7020
8695
|
type: "TTableSortState",
|
|
7021
8696
|
required: false,
|
|
7022
8697
|
description: "Controlled sort state. When provided, overrides internal sort tracking."
|
|
8698
|
+
},
|
|
8699
|
+
{
|
|
8700
|
+
name: "caption",
|
|
8701
|
+
type: "string",
|
|
8702
|
+
required: false,
|
|
8703
|
+
description: "Visible `<caption>` naming the table.",
|
|
8704
|
+
note: "For a name without visible text, pass `aria-label` / `aria-labelledby` instead \u2014 attribute inheritance is disabled and every non-class/style attr is forwarded to the `<table>`, so the name lands on the named element rather than the scroll wrapper."
|
|
7023
8705
|
}
|
|
7024
8706
|
],
|
|
7025
8707
|
events: [
|
|
@@ -7044,7 +8726,9 @@ var treeui_catalog_default = {
|
|
|
7044
8726
|
}
|
|
7045
8727
|
],
|
|
7046
8728
|
a11y: [
|
|
7047
|
-
"role:
|
|
8729
|
+
"role: table (native). No explicit role is emitted.",
|
|
8730
|
+
'why_not_grid: TTable previously set role="grid" without implementing the composite-widget keyboard model \u2014 no roving tabindex, no gridcell/row roles, no 2D arrow-key navigation. Screen readers switched to application/focus mode and offered cell navigation that did not exist. The role was removed so the component is honestly a reading table. An opt-in interactive grid mode is deliberately NOT offered until the keyboard model ships.',
|
|
8731
|
+
"accessible_name: Use `caption` for a visible name or `aria-label` / `aria-labelledby` for an invisible one. Both land on the `<table>`.",
|
|
7048
8732
|
"aria-sort: Set on sortable column headers (ascending, descending, none).",
|
|
7049
8733
|
"keyboard: Sortable headers are focusable and activated with Enter or Space.",
|
|
7050
8734
|
"scope: col on all th elements."
|
|
@@ -7081,7 +8765,8 @@ var treeui_catalog_default = {
|
|
|
7081
8765
|
},
|
|
7082
8766
|
recipes: [
|
|
7083
8767
|
"data-listing"
|
|
7084
|
-
]
|
|
8768
|
+
],
|
|
8769
|
+
practices: []
|
|
7085
8770
|
},
|
|
7086
8771
|
{
|
|
7087
8772
|
name: "TTabs",
|
|
@@ -7187,6 +8872,9 @@ var treeui_catalog_default = {
|
|
|
7187
8872
|
},
|
|
7188
8873
|
recipes: [
|
|
7189
8874
|
"router-backed-tabs"
|
|
8875
|
+
],
|
|
8876
|
+
practices: [
|
|
8877
|
+
"interaction-feedback"
|
|
7190
8878
|
]
|
|
7191
8879
|
},
|
|
7192
8880
|
{
|
|
@@ -7267,6 +8955,10 @@ var treeui_catalog_default = {
|
|
|
7267
8955
|
},
|
|
7268
8956
|
recipes: [
|
|
7269
8957
|
"tag-input"
|
|
8958
|
+
],
|
|
8959
|
+
practices: [
|
|
8960
|
+
"predictable-api",
|
|
8961
|
+
"token-driven"
|
|
7270
8962
|
]
|
|
7271
8963
|
},
|
|
7272
8964
|
{
|
|
@@ -7331,6 +9023,12 @@ var treeui_catalog_default = {
|
|
|
7331
9023
|
type: "boolean",
|
|
7332
9024
|
default: "false",
|
|
7333
9025
|
note: "Clip to a single line with an ellipsis."
|
|
9026
|
+
},
|
|
9027
|
+
{
|
|
9028
|
+
name: "preserveWhitespace",
|
|
9029
|
+
type: "boolean",
|
|
9030
|
+
default: "false",
|
|
9031
|
+
note: "Render authored line breaks and blank lines as written (`white-space: pre-wrap`) while still wrapping long lines. Use for plain-text output such as AI responses, so consumers never need a local `white-space: pre-wrap` class. Mutually exclusive with `truncate`, which needs `nowrap`; when both are set `truncate` wins and no `is-pre-wrap` class is emitted."
|
|
7334
9032
|
}
|
|
7335
9033
|
],
|
|
7336
9034
|
events: [],
|
|
@@ -7344,7 +9042,8 @@ var treeui_catalog_default = {
|
|
|
7344
9042
|
],
|
|
7345
9043
|
behavior: [
|
|
7346
9044
|
"semantic_element_controlled_by_as: true",
|
|
7347
|
-
"token_driven_size_tone_weight: true"
|
|
9045
|
+
"token_driven_size_tone_weight: true",
|
|
9046
|
+
"truncate_takes_precedence_over_preserve_whitespace: true"
|
|
7348
9047
|
],
|
|
7349
9048
|
selection: {
|
|
7350
9049
|
keywords: [],
|
|
@@ -7356,7 +9055,8 @@ var treeui_catalog_default = {
|
|
|
7356
9055
|
required: [],
|
|
7357
9056
|
notes: []
|
|
7358
9057
|
},
|
|
7359
|
-
recipes: []
|
|
9058
|
+
recipes: [],
|
|
9059
|
+
practices: []
|
|
7360
9060
|
},
|
|
7361
9061
|
{
|
|
7362
9062
|
name: "TTextarea",
|
|
@@ -7473,7 +9173,8 @@ var treeui_catalog_default = {
|
|
|
7473
9173
|
required: [],
|
|
7474
9174
|
notes: []
|
|
7475
9175
|
},
|
|
7476
|
-
recipes: []
|
|
9176
|
+
recipes: [],
|
|
9177
|
+
practices: []
|
|
7477
9178
|
},
|
|
7478
9179
|
{
|
|
7479
9180
|
name: "TTimeline",
|
|
@@ -7533,7 +9234,8 @@ var treeui_catalog_default = {
|
|
|
7533
9234
|
required: [],
|
|
7534
9235
|
notes: []
|
|
7535
9236
|
},
|
|
7536
|
-
recipes: []
|
|
9237
|
+
recipes: [],
|
|
9238
|
+
practices: []
|
|
7537
9239
|
},
|
|
7538
9240
|
{
|
|
7539
9241
|
name: "TToast",
|
|
@@ -7596,7 +9298,8 @@ var treeui_catalog_default = {
|
|
|
7596
9298
|
},
|
|
7597
9299
|
recipes: [
|
|
7598
9300
|
"confirm-destructive-action"
|
|
7599
|
-
]
|
|
9301
|
+
],
|
|
9302
|
+
practices: []
|
|
7600
9303
|
},
|
|
7601
9304
|
{
|
|
7602
9305
|
name: "TToggleGroup",
|
|
@@ -7713,7 +9416,8 @@ var treeui_catalog_default = {
|
|
|
7713
9416
|
'Use `selectionMode="multiple"` for small visible multi-choice sets.'
|
|
7714
9417
|
]
|
|
7715
9418
|
},
|
|
7716
|
-
recipes: []
|
|
9419
|
+
recipes: [],
|
|
9420
|
+
practices: []
|
|
7717
9421
|
},
|
|
7718
9422
|
{
|
|
7719
9423
|
name: "TTooltip",
|
|
@@ -7825,6 +9529,9 @@ var treeui_catalog_default = {
|
|
|
7825
9529
|
},
|
|
7826
9530
|
recipes: [
|
|
7827
9531
|
"anchored-help"
|
|
9532
|
+
],
|
|
9533
|
+
practices: [
|
|
9534
|
+
"accessible-by-default"
|
|
7828
9535
|
]
|
|
7829
9536
|
},
|
|
7830
9537
|
{
|
|
@@ -7837,7 +9544,7 @@ var treeui_catalog_default = {
|
|
|
7837
9544
|
purpose: "Hierarchical tree view with expansion, keyboard navigation, and single or multiple selection.",
|
|
7838
9545
|
sourceFile: "packages/vue/src/components/TTreeView.vue",
|
|
7839
9546
|
storyFile: "apps/docs/src/stories/TreeView.stories.ts",
|
|
7840
|
-
storyTitle: "Components/Navigation & Disclosure/
|
|
9547
|
+
storyTitle: "Components/Navigation & Disclosure/TreeView",
|
|
7841
9548
|
manifestFile: "docs/ai/COMPONENTS/tree-view.yaml",
|
|
7842
9549
|
props: [
|
|
7843
9550
|
{
|
|
@@ -7947,6 +9654,9 @@ var treeui_catalog_default = {
|
|
|
7947
9654
|
},
|
|
7948
9655
|
recipes: [
|
|
7949
9656
|
"hierarchy-picker"
|
|
9657
|
+
],
|
|
9658
|
+
practices: [
|
|
9659
|
+
"accessible-by-default"
|
|
7950
9660
|
]
|
|
7951
9661
|
}
|
|
7952
9662
|
],
|
|
@@ -9103,7 +10813,8 @@ var formatComponentSummary = (component) => {
|
|
|
9103
10813
|
"Setup",
|
|
9104
10814
|
[...component.setup.required, ...component.setup.notes]
|
|
9105
10815
|
),
|
|
9106
|
-
component.recipes.length > 0 ? `Recipes: ${component.recipes.join(", ")}` : void 0
|
|
10816
|
+
component.recipes.length > 0 ? `Recipes: ${component.recipes.join(", ")}` : void 0,
|
|
10817
|
+
component.practices.length > 0 ? `Practices: ${component.practices.join(", ")}` : void 0
|
|
9107
10818
|
].filter(Boolean);
|
|
9108
10819
|
return lines.join("\n");
|
|
9109
10820
|
};
|
|
@@ -9171,6 +10882,12 @@ var resourceList = [
|
|
|
9171
10882
|
description: "Reusable multi-component composition recipes.",
|
|
9172
10883
|
mimeType: "application/json"
|
|
9173
10884
|
},
|
|
10885
|
+
{
|
|
10886
|
+
uri: "treeui://practices",
|
|
10887
|
+
name: "TreeUI practices",
|
|
10888
|
+
description: "Named UX practices and the components that follow them.",
|
|
10889
|
+
mimeType: "application/json"
|
|
10890
|
+
},
|
|
9174
10891
|
{
|
|
9175
10892
|
uri: "treeui://tokens",
|
|
9176
10893
|
name: "TreeUI design tokens",
|
|
@@ -9204,6 +10921,9 @@ var readResourcePayload = (uri) => {
|
|
|
9204
10921
|
if (uri === "treeui://recipes") {
|
|
9205
10922
|
return catalog.recipes;
|
|
9206
10923
|
}
|
|
10924
|
+
if (uri === "treeui://practices") {
|
|
10925
|
+
return catalog.practices;
|
|
10926
|
+
}
|
|
9207
10927
|
if (uri === "treeui://tokens") {
|
|
9208
10928
|
return catalog.tokens;
|
|
9209
10929
|
}
|