@treeui/mcp 0.5.0 → 0.7.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-2Y7LP7ZZ.js} +2128 -377
- package/dist/cli.cjs +2128 -377
- package/dist/cli.js +1 -1
- package/dist/index.cjs +2145 -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/index.cjs
CHANGED
|
@@ -50,9 +50,9 @@ module.exports = __toCommonJS(index_exports);
|
|
|
50
50
|
|
|
51
51
|
// src/generated/treeui.catalog.json
|
|
52
52
|
var treeui_catalog_default = {
|
|
53
|
-
generatedAt: "2026-07-
|
|
53
|
+
generatedAt: "2026-07-21T20:31:07.075Z",
|
|
54
54
|
packageName: "@treeui/vue",
|
|
55
|
-
packageVersion: "0.
|
|
55
|
+
packageVersion: "0.19.1",
|
|
56
56
|
decisionGuides: [
|
|
57
57
|
{
|
|
58
58
|
id: "single-choice",
|
|
@@ -103,6 +103,14 @@ var treeui_catalog_default = {
|
|
|
103
103
|
"The options are hierarchical."
|
|
104
104
|
],
|
|
105
105
|
notes: []
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
use: "TLanguageSelect",
|
|
109
|
+
when: [
|
|
110
|
+
"The value is the application language or locale.",
|
|
111
|
+
"Each language should show a country flag beside its name."
|
|
112
|
+
],
|
|
113
|
+
notes: []
|
|
106
114
|
}
|
|
107
115
|
]
|
|
108
116
|
},
|
|
@@ -415,6 +423,52 @@ var treeui_catalog_default = {
|
|
|
415
423
|
"Prefer `TAppShell` (recipe `app-shell`) when you also need full-viewport sizing and a responsive mobile drawer."
|
|
416
424
|
]
|
|
417
425
|
},
|
|
426
|
+
{
|
|
427
|
+
id: "brand-lockup",
|
|
428
|
+
name: "Product brand lockup in a shell header",
|
|
429
|
+
useWhen: [
|
|
430
|
+
"A shell header needs a logo plus a product name (and optional subtitle) that stays aligned as the sidebar collapses."
|
|
431
|
+
],
|
|
432
|
+
compose: [
|
|
433
|
+
"TAppShell",
|
|
434
|
+
"TAvatar",
|
|
435
|
+
"TText",
|
|
436
|
+
"TStack"
|
|
437
|
+
],
|
|
438
|
+
notes: [
|
|
439
|
+
"Put the lockup in the `header-start` slot, not `header`. Filling `header-start` switches the header to the shell's own grid, so the mark tracks `--tree-app-shell-sidebar-width` and animates with the collapse \u2014 no local column math.",
|
|
440
|
+
'The slot is scoped: use its `collapsed` binding to drop the wordmark and keep only the mark (`v-if="!collapsed"`), rather than hiding text with CSS.',
|
|
441
|
+
'Logo is `TAvatar` (`size`, `alt`, `initials` fallback) or a plain `<img>` sized with `--tree-size-icon-*`; name and subtitle are `TText` (`weight`, `tone="muted"`, `truncate`) \u2014 never raw `<strong>`/`<span>` with a local class.',
|
|
442
|
+
"TreeUI ships no `TBrand` component on purpose: the logo asset, the product name, and what survives collapse are product identity, which must stay in the consumer. See DECISIONS.md \u2192 Portability Boundary.",
|
|
443
|
+
"Company and service logos (AWS, LocalStack, social networks) are brand assets and are not TreeUI icons \u2014 source them from the app's brand policy, not the icon registry."
|
|
444
|
+
]
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
id: "nav-menu-icons",
|
|
448
|
+
name: "Icons on navigation items",
|
|
449
|
+
useWhen: [
|
|
450
|
+
"Navigation items each carry an icon.",
|
|
451
|
+
"The navigation collapses to an icon-only rail, so the icon is the only thing left identifying a section.",
|
|
452
|
+
"Some of the icons the app needs are not TreeUI built-ins."
|
|
453
|
+
],
|
|
454
|
+
compose: [
|
|
455
|
+
"TNavMenu",
|
|
456
|
+
"TIcon",
|
|
457
|
+
"registerTreeIcons",
|
|
458
|
+
"resetTreeIcons"
|
|
459
|
+
],
|
|
460
|
+
notes: [
|
|
461
|
+
"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.",
|
|
462
|
+
"`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.",
|
|
463
|
+
"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.",
|
|
464
|
+
"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.",
|
|
465
|
+
"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.",
|
|
466
|
+
"Keep the icon vocabulary consistent: built-ins use TreeUI's descriptive kebab-case names, so register custom ones with the same convention.",
|
|
467
|
+
"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.",
|
|
468
|
+
"Set `to` for the route target on each item \u2014 `TNavMenuItem` has no `href` and no `id`; identity is `value`.",
|
|
469
|
+
"This recipe covers the icons only; the surrounding layout is its own recipe (`app-shell` or `sidebar-shell`)."
|
|
470
|
+
]
|
|
471
|
+
},
|
|
418
472
|
{
|
|
419
473
|
id: "stat-grid",
|
|
420
474
|
name: "Dashboard metric grid",
|
|
@@ -588,6 +642,150 @@ var treeui_catalog_default = {
|
|
|
588
642
|
notes: [
|
|
589
643
|
'Use `selectionMode="multiple"` when permissions or tag assignment spans nested nodes.'
|
|
590
644
|
]
|
|
645
|
+
},
|
|
646
|
+
{
|
|
647
|
+
id: "language-switcher",
|
|
648
|
+
name: "Application language switcher",
|
|
649
|
+
useWhen: [
|
|
650
|
+
"The app lets the user pick a language or locale, with an optional flag per option."
|
|
651
|
+
],
|
|
652
|
+
compose: [
|
|
653
|
+
"TFormField",
|
|
654
|
+
"TLanguageSelect"
|
|
655
|
+
],
|
|
656
|
+
notes: [
|
|
657
|
+
"The app owns the language list: TreeUI ships no locale dataset, so pass `options` with your own `label`, `value`, and optional `code` and `description`.",
|
|
658
|
+
"`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).",
|
|
659
|
+
"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.",
|
|
660
|
+
"Set `flagBaseUrl` once, at the switcher, when flag assets are self-hosted; it is forwarded to every nested `TFlag`.",
|
|
661
|
+
"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."
|
|
662
|
+
]
|
|
663
|
+
}
|
|
664
|
+
],
|
|
665
|
+
practices: [
|
|
666
|
+
{
|
|
667
|
+
id: "interaction-feedback",
|
|
668
|
+
title: "Visual interaction feedback",
|
|
669
|
+
summary: "Every interaction answers back. Hover, focus, active, loading, and disabled are designed states \u2014 never afterthoughts left to the consumer.",
|
|
670
|
+
rules: [
|
|
671
|
+
"Interactive surfaces ship hover, active, and focus-visible treatments out of the box.",
|
|
672
|
+
"Loading states announce themselves (aria-busy plus a labelled, localizable spinner), replace the resting glyph instead of stacking beside it, and block duplicate activation.",
|
|
673
|
+
"Disabled and loading elements never emit activation events.",
|
|
674
|
+
"Focus indicators stay visible in both light and dark themes."
|
|
675
|
+
],
|
|
676
|
+
components: [
|
|
677
|
+
"TButton",
|
|
678
|
+
"TLink",
|
|
679
|
+
"TInput",
|
|
680
|
+
"TSelect",
|
|
681
|
+
"TCheckbox",
|
|
682
|
+
"TSwitch",
|
|
683
|
+
"TTabs",
|
|
684
|
+
"TPagination",
|
|
685
|
+
"TDropdown",
|
|
686
|
+
"TSelectableList"
|
|
687
|
+
]
|
|
688
|
+
},
|
|
689
|
+
{
|
|
690
|
+
id: "accessible-by-default",
|
|
691
|
+
title: "Accessible by default",
|
|
692
|
+
summary: "Native semantics first, ARIA where the pattern requires it, full keyboard support, and focus management the consumer never has to write.",
|
|
693
|
+
rules: [
|
|
694
|
+
'Native elements before roles; role="dialog", aria-modal, aria-labelledby only where semantics require them, and no composite-widget role (grid, tree) is claimed without its full keyboard model.',
|
|
695
|
+
"Tab/Shift+Tab order, Escape to close, Enter/Space to activate, arrow keys where the pattern expects them.",
|
|
696
|
+
"Overlays trap focus while open and restore it on close.",
|
|
697
|
+
"Clickable targets stay at or above 44\xD744px."
|
|
698
|
+
],
|
|
699
|
+
components: [
|
|
700
|
+
"TModal",
|
|
701
|
+
"TDrawer",
|
|
702
|
+
"TConfirmDialog",
|
|
703
|
+
"TDropdown",
|
|
704
|
+
"TTooltip",
|
|
705
|
+
"TAccordion",
|
|
706
|
+
"TFormField",
|
|
707
|
+
"TTreeView",
|
|
708
|
+
"TToastProvider",
|
|
709
|
+
"TButton"
|
|
710
|
+
]
|
|
711
|
+
},
|
|
712
|
+
{
|
|
713
|
+
id: "predictable-api",
|
|
714
|
+
title: "One predictable API",
|
|
715
|
+
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.",
|
|
716
|
+
rules: [
|
|
717
|
+
"Sizes are sm | md | lg across the library.",
|
|
718
|
+
"Action variants come from one scale: solid, outline, ghost, soft, danger.",
|
|
719
|
+
"Form controls speak modelValue + update:modelValue (v-model).",
|
|
720
|
+
"Overlays speak open/defaultOpen + update:open/open-change."
|
|
721
|
+
],
|
|
722
|
+
components: [
|
|
723
|
+
"TButton",
|
|
724
|
+
"TInput",
|
|
725
|
+
"TSelect",
|
|
726
|
+
"TBadge",
|
|
727
|
+
"TTag",
|
|
728
|
+
"TCard",
|
|
729
|
+
"TModal"
|
|
730
|
+
]
|
|
731
|
+
},
|
|
732
|
+
{
|
|
733
|
+
id: "state-clarity",
|
|
734
|
+
title: "Empty, loading, and error are designed states",
|
|
735
|
+
summary: "Screens communicate status honestly: skeletons while loading, purposeful empty states, and status surfaces on one semantic tone scale.",
|
|
736
|
+
rules: [
|
|
737
|
+
"Default, hover, active, focus, disabled, loading, and error/empty states are designed and documented \u2014 not just the happy path.",
|
|
738
|
+
"Status tones map to semantic tokens (success, warning, error, info) and pass both themes.",
|
|
739
|
+
"Async feedback is immediate: skeleton or spinner first, toast or alert on completion."
|
|
740
|
+
],
|
|
741
|
+
components: [
|
|
742
|
+
"TSkeleton",
|
|
743
|
+
"TSpinner",
|
|
744
|
+
"TProgress",
|
|
745
|
+
"TEmptyState",
|
|
746
|
+
"TAlert",
|
|
747
|
+
"TToastProvider",
|
|
748
|
+
"TBadge",
|
|
749
|
+
"TTable"
|
|
750
|
+
]
|
|
751
|
+
},
|
|
752
|
+
{
|
|
753
|
+
id: "content-alignment",
|
|
754
|
+
title: "Alignment without custom CSS",
|
|
755
|
+
summary: "Layout primitives absorb spacing, alignment, and rhythm so product code never hand-rolls the same flexbox again.",
|
|
756
|
+
rules: [
|
|
757
|
+
"Spacing comes from the --tree-space-* scale, applied by layout components.",
|
|
758
|
+
"Compose TPage, TStack, TGrid, and TSplit before writing a custom layout div.",
|
|
759
|
+
"Forms align through TFormField + TStack + TGrid \u2014 labels, hints, and errors line up by contract.",
|
|
760
|
+
"Reading widths and page gutters come from TContainer/TPage, not local max-widths."
|
|
761
|
+
],
|
|
762
|
+
components: [
|
|
763
|
+
"TStack",
|
|
764
|
+
"TGrid",
|
|
765
|
+
"TSplit",
|
|
766
|
+
"TContainer",
|
|
767
|
+
"TSpacer",
|
|
768
|
+
"TPage",
|
|
769
|
+
"TPageHeader",
|
|
770
|
+
"TFormField"
|
|
771
|
+
]
|
|
772
|
+
},
|
|
773
|
+
{
|
|
774
|
+
id: "token-driven",
|
|
775
|
+
title: "Token-driven clarity",
|
|
776
|
+
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.",
|
|
777
|
+
rules: [
|
|
778
|
+
"Zero hardcoded colors, spacing, or typography in component code.",
|
|
779
|
+
"Light and dark are first-class themes; every state passes both.",
|
|
780
|
+
"Themes switch by attribute (data-tree-theme) with no component changes."
|
|
781
|
+
],
|
|
782
|
+
components: [
|
|
783
|
+
"TCard",
|
|
784
|
+
"TNavbar",
|
|
785
|
+
"TBadge",
|
|
786
|
+
"TTag",
|
|
787
|
+
"TChart"
|
|
788
|
+
]
|
|
591
789
|
}
|
|
592
790
|
],
|
|
593
791
|
setup: {
|
|
@@ -662,6 +860,43 @@ var treeui_catalog_default = {
|
|
|
662
860
|
"Use `maxVisibleTags` to control trigger density in compact layouts."
|
|
663
861
|
]
|
|
664
862
|
},
|
|
863
|
+
TFlag: {
|
|
864
|
+
required: [
|
|
865
|
+
"Pass `code` as an ISO 3166-1 alpha-2 country code. Matching is case-insensitive \u2014 the value is trimmed and lowercased internally.",
|
|
866
|
+
"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."
|
|
867
|
+
],
|
|
868
|
+
notes: [
|
|
869
|
+
"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`.",
|
|
870
|
+
"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.",
|
|
871
|
+
"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.",
|
|
872
|
+
"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.",
|
|
873
|
+
"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.",
|
|
874
|
+
"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.",
|
|
875
|
+
"`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.",
|
|
876
|
+
"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`.",
|
|
877
|
+
"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."
|
|
878
|
+
]
|
|
879
|
+
},
|
|
880
|
+
TLanguageSelect: {
|
|
881
|
+
required: [
|
|
882
|
+
"Pass `options` as `{ label, value, code?, description?, disabled? }[]`. TreeUI ships no language, locale, or country dataset \u2014 the app owns its language list.",
|
|
883
|
+
"Apply locale side effects (i18n locale, `lang` attribute, persistence) in the app layer; the component only reports the selected `value`.",
|
|
884
|
+
"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."
|
|
885
|
+
],
|
|
886
|
+
notes: [
|
|
887
|
+
"`variant` is `field` (default) or `switcher`, typed as `TLanguageSelectVariant` and exported from `@treeui/vue`.",
|
|
888
|
+
'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.',
|
|
889
|
+
'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.',
|
|
890
|
+
"A switcher sizes to its content, so `width` does not apply, and its listbox aligns to the trigger's right edge.",
|
|
891
|
+
"`iconOnly` is switcher-only and drops the visible language name, leaving the translate icon and the current flag.",
|
|
892
|
+
"`value` is an opaque application key, typically a BCP-47 tag such as `pt-BR`. TreeUI never parses or validates it.",
|
|
893
|
+
"`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.",
|
|
894
|
+
"Use `description` for a secondary line such as the endonym.",
|
|
895
|
+
"Set `flagBaseUrl` once on the select rather than per option; it is forwarded to every nested `TFlag`.",
|
|
896
|
+
"Bind `modelValue` to a `string`, and use `v-model:open` when the app controls open state.",
|
|
897
|
+
"The CDN and Content-Security-Policy requirements under `TFlag` apply whenever any option carries a `code`."
|
|
898
|
+
]
|
|
899
|
+
},
|
|
665
900
|
TToggleGroup: {
|
|
666
901
|
required: [],
|
|
667
902
|
notes: [
|
|
@@ -711,7 +946,20 @@ var treeui_catalog_default = {
|
|
|
711
946
|
TNavMenu: {
|
|
712
947
|
required: [],
|
|
713
948
|
notes: [
|
|
714
|
-
"When nested inside `TSidebar` or `TAppShell`, `collapsed` can be inherited from the sidebar provider."
|
|
949
|
+
"When nested inside `TSidebar` or `TAppShell`, `collapsed` can be inherited from the sidebar provider.",
|
|
950
|
+
"Pass `items` as `{ label, value, icon?, to?, badge?, description?, shortLabel?, disabled?, exact? }[]`.",
|
|
951
|
+
"`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.",
|
|
952
|
+
"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.",
|
|
953
|
+
"Register any icon the app needs beyond the built-ins first \u2014 see `icons` above."
|
|
954
|
+
]
|
|
955
|
+
},
|
|
956
|
+
TIcon: {
|
|
957
|
+
required: [
|
|
958
|
+
"Use a registered name: one of the built-ins, or one the app added with `registerTreeIcons`. See `icons` above."
|
|
959
|
+
],
|
|
960
|
+
notes: [
|
|
961
|
+
'`size` is a pixel count, not `sm | md | lg`. Passing `size="md"` renders an unsized svg.',
|
|
962
|
+
"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."
|
|
715
963
|
]
|
|
716
964
|
},
|
|
717
965
|
TTreeView: {
|
|
@@ -783,6 +1031,7 @@ var treeui_catalog_default = {
|
|
|
783
1031
|
],
|
|
784
1032
|
commonCompositions: [
|
|
785
1033
|
"TFormField + input-like control",
|
|
1034
|
+
"TFormField + TLanguageSelect",
|
|
786
1035
|
"TGrid + TStat",
|
|
787
1036
|
"TStat + TSparkline",
|
|
788
1037
|
"TCard + TChart",
|
|
@@ -806,15 +1055,83 @@ var treeui_catalog_default = {
|
|
|
806
1055
|
storyFile: "apps/docs/src/stories/Accordion.stories.ts",
|
|
807
1056
|
storyTitle: "Components/Data Display/Accordion",
|
|
808
1057
|
manifestFile: "docs/ai/COMPONENTS/accordion.yaml",
|
|
809
|
-
props: [
|
|
810
|
-
|
|
811
|
-
|
|
1058
|
+
props: [
|
|
1059
|
+
{
|
|
1060
|
+
name: "type",
|
|
1061
|
+
type: "'single' | 'multiple'",
|
|
1062
|
+
default: "'single'",
|
|
1063
|
+
values: [
|
|
1064
|
+
"single",
|
|
1065
|
+
"multiple"
|
|
1066
|
+
],
|
|
1067
|
+
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"
|
|
1068
|
+
},
|
|
1069
|
+
{
|
|
1070
|
+
name: "modelValue",
|
|
1071
|
+
type: "string | string[] | undefined",
|
|
1072
|
+
default: "undefined",
|
|
1073
|
+
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'
|
|
1074
|
+
},
|
|
1075
|
+
{
|
|
1076
|
+
name: "defaultValue",
|
|
1077
|
+
type: "string | string[] | undefined",
|
|
1078
|
+
default: "undefined",
|
|
1079
|
+
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"
|
|
1080
|
+
},
|
|
1081
|
+
{
|
|
1082
|
+
name: "disabled",
|
|
1083
|
+
type: "boolean",
|
|
1084
|
+
default: "false",
|
|
1085
|
+
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"
|
|
1086
|
+
},
|
|
1087
|
+
{
|
|
1088
|
+
name: "collapsible",
|
|
1089
|
+
type: "boolean",
|
|
1090
|
+
default: "false",
|
|
1091
|
+
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'
|
|
1092
|
+
}
|
|
1093
|
+
],
|
|
1094
|
+
events: [
|
|
1095
|
+
{
|
|
1096
|
+
name: "update:modelValue",
|
|
1097
|
+
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',
|
|
1098
|
+
payload: "string | string[] | undefined"
|
|
1099
|
+
}
|
|
1100
|
+
],
|
|
1101
|
+
slots: [
|
|
1102
|
+
{
|
|
1103
|
+
name: "default",
|
|
1104
|
+
description: "Accepts TAccordionItem children."
|
|
1105
|
+
}
|
|
1106
|
+
],
|
|
812
1107
|
a11y: [
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
1108
|
+
"container_is_a_plain_div_with_no_aria_role: true",
|
|
1109
|
+
"trigger_is_a_heading_wrapped_native_button: h3 > button",
|
|
1110
|
+
"aria_expanded_on_trigger_reflects_open_state: true",
|
|
1111
|
+
"aria_controls_on_trigger_references_panel_id: true",
|
|
1112
|
+
"panel_uses_role_region: true",
|
|
1113
|
+
"aria_labelledby_on_panel_references_trigger_id: true",
|
|
1114
|
+
"disabled_items_use_the_native_disabled_attribute: true",
|
|
1115
|
+
"chevron_icon_is_aria_hidden: true",
|
|
1116
|
+
"trigger_hit_area_is_at_least_44px: via the .t-accordion__trigger::after overlay",
|
|
1117
|
+
"enter_space_toggle_the_focused_item: native button activation",
|
|
1118
|
+
"arrow_down_focuses_next_enabled_trigger_wrapping_to_first: true",
|
|
1119
|
+
"arrow_up_focuses_previous_enabled_trigger_wrapping_to_last: true",
|
|
1120
|
+
"home_focuses_first_enabled_trigger: true",
|
|
1121
|
+
"end_focuses_last_enabled_trigger: true"
|
|
1122
|
+
],
|
|
1123
|
+
behavior: [
|
|
1124
|
+
"controlled_only_while_model_value_is_not_undefined: true",
|
|
1125
|
+
"default_value_seeds_uncontrolled_state_once: true",
|
|
1126
|
+
"single_mode_opening_an_item_closes_the_previous_one: true",
|
|
1127
|
+
"single_mode_collapsing_requires_collapsible: true",
|
|
1128
|
+
"multiple_mode_ignores_collapsible: true",
|
|
1129
|
+
"container_and_item_disabled_are_combined_with_or: true",
|
|
1130
|
+
"arrow_navigation_skips_disabled_triggers: true",
|
|
1131
|
+
"arrow_navigation_wraps_around: true",
|
|
1132
|
+
"trigger_order_follows_item_mount_order: true",
|
|
1133
|
+
"only_open_panels_are_rendered: true"
|
|
816
1134
|
],
|
|
817
|
-
behavior: [],
|
|
818
1135
|
selection: {
|
|
819
1136
|
keywords: [
|
|
820
1137
|
"accordion",
|
|
@@ -845,7 +1162,10 @@ var treeui_catalog_default = {
|
|
|
845
1162
|
required: [],
|
|
846
1163
|
notes: []
|
|
847
1164
|
},
|
|
848
|
-
recipes: []
|
|
1165
|
+
recipes: [],
|
|
1166
|
+
practices: [
|
|
1167
|
+
"accessible-by-default"
|
|
1168
|
+
]
|
|
849
1169
|
},
|
|
850
1170
|
{
|
|
851
1171
|
name: "TAlert",
|
|
@@ -862,14 +1182,15 @@ var treeui_catalog_default = {
|
|
|
862
1182
|
props: [
|
|
863
1183
|
{
|
|
864
1184
|
name: "variant",
|
|
865
|
-
type: "
|
|
1185
|
+
type: "TAlertVariant",
|
|
866
1186
|
default: "info",
|
|
867
1187
|
values: [
|
|
868
1188
|
"info",
|
|
869
1189
|
"success",
|
|
870
1190
|
"warning",
|
|
871
1191
|
"danger"
|
|
872
|
-
]
|
|
1192
|
+
],
|
|
1193
|
+
description: "Semantic tone. Sets the --tree-alert-* custom properties that colour the surface, border, icon, and dismiss button."
|
|
873
1194
|
},
|
|
874
1195
|
{
|
|
875
1196
|
name: "size",
|
|
@@ -879,42 +1200,55 @@ var treeui_catalog_default = {
|
|
|
879
1200
|
"sm",
|
|
880
1201
|
"md",
|
|
881
1202
|
"lg"
|
|
882
|
-
]
|
|
1203
|
+
],
|
|
1204
|
+
description: "Adjusts padding and font size only. md is the baseline defined on .t-alert itself."
|
|
883
1205
|
},
|
|
884
1206
|
{
|
|
885
1207
|
name: "dismissible",
|
|
886
1208
|
type: "boolean",
|
|
887
|
-
default: "false"
|
|
1209
|
+
default: "false",
|
|
1210
|
+
description: "Renders the trailing dismiss button. The button is the only thing gated by this prop; the alert never hides itself."
|
|
888
1211
|
}
|
|
889
1212
|
],
|
|
890
1213
|
events: [
|
|
891
1214
|
{
|
|
892
1215
|
name: "dismiss",
|
|
893
|
-
description: "Emitted when the dismiss button is clicked.",
|
|
1216
|
+
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",
|
|
894
1217
|
payload: "none"
|
|
895
1218
|
}
|
|
896
1219
|
],
|
|
897
1220
|
slots: [
|
|
898
1221
|
{
|
|
899
1222
|
name: "default",
|
|
900
|
-
description: "Alert message content."
|
|
1223
|
+
description: "Alert message content, rendered inside .t-alert__content."
|
|
901
1224
|
},
|
|
902
1225
|
{
|
|
903
1226
|
name: "icon",
|
|
904
|
-
description:
|
|
1227
|
+
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'
|
|
905
1228
|
},
|
|
906
1229
|
{
|
|
907
1230
|
name: "dismiss-icon",
|
|
908
|
-
description:
|
|
1231
|
+
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'
|
|
909
1232
|
}
|
|
910
1233
|
],
|
|
911
1234
|
a11y: [
|
|
912
1235
|
"role: alert",
|
|
1236
|
+
"role_is_on_root_element: true",
|
|
913
1237
|
"icon_slot_marked_aria_hidden: true",
|
|
1238
|
+
"default_dismiss_icon_marked_aria_hidden: true",
|
|
914
1239
|
"dismiss_button_aria_label: Dismiss",
|
|
915
|
-
"
|
|
1240
|
+
"dismiss_button_label_is_hardcoded: true",
|
|
1241
|
+
"dismiss_button_hit_area: 44x44 via a .t-alert__dismiss::after pseudo-element; the visible button is 1.5rem.",
|
|
1242
|
+
"keyboard: Tab to dismiss button, Enter/Space to activate",
|
|
1243
|
+
'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.'
|
|
1244
|
+
],
|
|
1245
|
+
behavior: [
|
|
1246
|
+
"self_removes_on_dismiss: false",
|
|
1247
|
+
"icon_wrapper_rendered_only_when_icon_slot_provided: true",
|
|
1248
|
+
"dismiss_button_rendered_only_when_dismissible: true",
|
|
1249
|
+
"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.",
|
|
1250
|
+
'variant_sets_local_custom_properties: ["--tree-alert-bg","--tree-alert-border","--tree-alert-text","--tree-alert-accent"]'
|
|
916
1251
|
],
|
|
917
|
-
behavior: [],
|
|
918
1252
|
selection: {
|
|
919
1253
|
keywords: [
|
|
920
1254
|
"alert",
|
|
@@ -945,7 +1279,10 @@ var treeui_catalog_default = {
|
|
|
945
1279
|
required: [],
|
|
946
1280
|
notes: []
|
|
947
1281
|
},
|
|
948
|
-
recipes: []
|
|
1282
|
+
recipes: [],
|
|
1283
|
+
practices: [
|
|
1284
|
+
"state-clarity"
|
|
1285
|
+
]
|
|
949
1286
|
},
|
|
950
1287
|
{
|
|
951
1288
|
name: "TAppShell",
|
|
@@ -963,7 +1300,8 @@ var treeui_catalog_default = {
|
|
|
963
1300
|
{
|
|
964
1301
|
name: "as",
|
|
965
1302
|
type: "string",
|
|
966
|
-
default: "div"
|
|
1303
|
+
default: "div",
|
|
1304
|
+
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."
|
|
967
1305
|
},
|
|
968
1306
|
{
|
|
969
1307
|
name: "side",
|
|
@@ -977,164 +1315,254 @@ var treeui_catalog_default = {
|
|
|
977
1315
|
{
|
|
978
1316
|
name: "sidebarWidth",
|
|
979
1317
|
type: "string",
|
|
980
|
-
default: "17.5rem"
|
|
1318
|
+
default: "17.5rem",
|
|
1319
|
+
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)`."
|
|
981
1320
|
},
|
|
982
1321
|
{
|
|
983
1322
|
name: "collapsedWidth",
|
|
984
1323
|
type: "string",
|
|
985
|
-
default: "4.75rem"
|
|
1324
|
+
default: "4.75rem",
|
|
1325
|
+
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)."
|
|
986
1326
|
},
|
|
987
1327
|
{
|
|
988
1328
|
name: "collapsible",
|
|
989
1329
|
type: "boolean",
|
|
990
|
-
default: "false"
|
|
1330
|
+
default: "false",
|
|
1331
|
+
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."
|
|
991
1332
|
},
|
|
992
1333
|
{
|
|
993
1334
|
name: "collapsed",
|
|
994
1335
|
type: "boolean",
|
|
995
|
-
default: "undefined"
|
|
1336
|
+
default: "undefined",
|
|
1337
|
+
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."
|
|
996
1338
|
},
|
|
997
1339
|
{
|
|
998
1340
|
name: "defaultCollapsed",
|
|
999
1341
|
type: "boolean",
|
|
1000
|
-
default: "false"
|
|
1342
|
+
default: "false",
|
|
1343
|
+
note: "Initial value for uncontrolled use. Read once during setup; later changes to the prop are ignored."
|
|
1001
1344
|
},
|
|
1002
1345
|
{
|
|
1003
1346
|
name: "mobile",
|
|
1004
1347
|
type: "boolean",
|
|
1005
|
-
default: "undefined"
|
|
1348
|
+
default: "undefined",
|
|
1349
|
+
note: "Forces mobile mode when explicitly true or false. Leave undefined to auto-detect from `breakpoint`."
|
|
1006
1350
|
},
|
|
1007
1351
|
{
|
|
1008
1352
|
name: "breakpoint",
|
|
1009
1353
|
type: "string",
|
|
1010
|
-
default: "768px"
|
|
1354
|
+
default: "768px",
|
|
1355
|
+
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."
|
|
1011
1356
|
},
|
|
1012
1357
|
{
|
|
1013
1358
|
name: "sidebarOpen",
|
|
1014
1359
|
type: "boolean",
|
|
1015
|
-
default: "undefined"
|
|
1360
|
+
default: "undefined",
|
|
1361
|
+
note: "Controlled off-canvas drawer state (v-model:sidebarOpen). Mobile-only \u2014 the flag is tracked in desktop mode but nothing renders from it."
|
|
1016
1362
|
},
|
|
1017
1363
|
{
|
|
1018
1364
|
name: "defaultSidebarOpen",
|
|
1019
1365
|
type: "boolean",
|
|
1020
|
-
default: "false"
|
|
1366
|
+
default: "false",
|
|
1367
|
+
note: "Initial value for uncontrolled use. Read once during setup."
|
|
1368
|
+
},
|
|
1369
|
+
{
|
|
1370
|
+
name: "immersive",
|
|
1371
|
+
type: "boolean",
|
|
1372
|
+
default: "undefined",
|
|
1373
|
+
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."
|
|
1374
|
+
},
|
|
1375
|
+
{
|
|
1376
|
+
name: "defaultImmersive",
|
|
1377
|
+
type: "boolean",
|
|
1378
|
+
default: "false",
|
|
1379
|
+
note: "Initial value for uncontrolled use. Read once during setup."
|
|
1021
1380
|
},
|
|
1022
1381
|
{
|
|
1023
1382
|
name: "closeOnEscape",
|
|
1024
1383
|
type: "boolean",
|
|
1025
|
-
default: "true"
|
|
1384
|
+
default: "true",
|
|
1385
|
+
note: "Drawer only. Escape is handled on the drawer surface, so it fires only while focus is inside the drawer."
|
|
1026
1386
|
},
|
|
1027
1387
|
{
|
|
1028
1388
|
name: "closeOnOverlay",
|
|
1029
1389
|
type: "boolean",
|
|
1030
|
-
default: "true"
|
|
1390
|
+
default: "true",
|
|
1391
|
+
note: "Drawer only. Set false to keep the drawer open on backdrop clicks."
|
|
1031
1392
|
},
|
|
1032
1393
|
{
|
|
1033
1394
|
name: "showMenuButton",
|
|
1034
1395
|
type: "boolean",
|
|
1035
|
-
default: "true"
|
|
1396
|
+
default: "true",
|
|
1397
|
+
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."
|
|
1036
1398
|
},
|
|
1037
1399
|
{
|
|
1038
1400
|
name: "showCollapseButton",
|
|
1039
1401
|
type: "boolean",
|
|
1040
1402
|
default: "true",
|
|
1041
|
-
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."
|
|
1403
|
+
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."
|
|
1042
1404
|
},
|
|
1043
1405
|
{
|
|
1044
1406
|
name: "collapseLabel",
|
|
1045
1407
|
type: "string",
|
|
1046
|
-
default: "Collapse sidebar"
|
|
1408
|
+
default: "Collapse sidebar",
|
|
1409
|
+
note: "aria-label of the collapse toggle while the rail is expanded."
|
|
1047
1410
|
},
|
|
1048
1411
|
{
|
|
1049
1412
|
name: "expandLabel",
|
|
1050
1413
|
type: "string",
|
|
1051
|
-
default: "Expand sidebar"
|
|
1414
|
+
default: "Expand sidebar",
|
|
1415
|
+
note: "aria-label of the collapse toggle while the rail is collapsed."
|
|
1052
1416
|
},
|
|
1053
1417
|
{
|
|
1054
1418
|
name: "menuLabel",
|
|
1055
1419
|
type: "string",
|
|
1056
|
-
default: "Open menu"
|
|
1420
|
+
default: "Open menu",
|
|
1421
|
+
note: "aria-label of the built-in hamburger. Static \u2014 it does not swap to a close label while the drawer is open."
|
|
1057
1422
|
},
|
|
1058
1423
|
{
|
|
1059
1424
|
name: "closeLabel",
|
|
1060
1425
|
type: "string",
|
|
1061
|
-
default: "Close menu"
|
|
1426
|
+
default: "Close menu",
|
|
1427
|
+
note: "aria-label of the drawer's close button."
|
|
1062
1428
|
},
|
|
1063
1429
|
{
|
|
1064
1430
|
name: "sidebarLabel",
|
|
1065
1431
|
type: "string",
|
|
1066
|
-
default: "Sidebar"
|
|
1432
|
+
default: "Sidebar",
|
|
1433
|
+
note: "aria-label applied to both the desktop <aside> and the drawer <aside>."
|
|
1067
1434
|
}
|
|
1068
1435
|
],
|
|
1069
1436
|
events: [
|
|
1070
1437
|
{
|
|
1071
|
-
name: "update:collapsed"
|
|
1438
|
+
name: "update:collapsed",
|
|
1439
|
+
description: "Desktop rail collapsed state changed. Enables v-model:collapsed.",
|
|
1440
|
+
payload: "[value: boolean]"
|
|
1072
1441
|
},
|
|
1073
1442
|
{
|
|
1074
|
-
name: "collapse-change"
|
|
1443
|
+
name: "collapse-change",
|
|
1444
|
+
description: "Same change as update:collapsed, for non-v-model usage. Both always fire together.",
|
|
1445
|
+
payload: "[value: boolean]"
|
|
1446
|
+
},
|
|
1447
|
+
{
|
|
1448
|
+
name: "update:sidebarOpen",
|
|
1449
|
+
description: "Off-canvas drawer open state changed. Enables v-model:sidebarOpen.",
|
|
1450
|
+
payload: "[value: boolean]"
|
|
1075
1451
|
},
|
|
1076
1452
|
{
|
|
1077
|
-
name: "
|
|
1453
|
+
name: "sidebar-open-change",
|
|
1454
|
+
description: "Same change as update:sidebarOpen, for non-v-model usage. Both always fire together.",
|
|
1455
|
+
payload: "[value: boolean]"
|
|
1456
|
+
},
|
|
1457
|
+
{
|
|
1458
|
+
name: "update:immersive",
|
|
1459
|
+
description: "Immersive state changed. Enables v-model:immersive.",
|
|
1460
|
+
payload: "[value: boolean]"
|
|
1078
1461
|
},
|
|
1079
1462
|
{
|
|
1080
|
-
name: "
|
|
1463
|
+
name: "immersive-change",
|
|
1464
|
+
description: "Same change as update:immersive, for non-v-model usage. Both always fire together.",
|
|
1465
|
+
payload: "[value: boolean]"
|
|
1081
1466
|
}
|
|
1082
1467
|
],
|
|
1083
1468
|
slots: [
|
|
1084
1469
|
{
|
|
1085
|
-
name: "header"
|
|
1470
|
+
name: "header",
|
|
1471
|
+
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",
|
|
1472
|
+
note: "AppShellSlotProps \u2014 { mobile, collapsed, sidebarOpen, immersive, toggleSidebar, closeSidebar, toggleCollapsed, toggleImmersive }"
|
|
1086
1473
|
},
|
|
1087
1474
|
{
|
|
1088
|
-
name: "header-start"
|
|
1475
|
+
name: "header-start",
|
|
1476
|
+
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",
|
|
1477
|
+
note: "AppShellSlotProps"
|
|
1089
1478
|
},
|
|
1090
1479
|
{
|
|
1091
|
-
name: "sidebar-header"
|
|
1480
|
+
name: "sidebar-header",
|
|
1481
|
+
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",
|
|
1482
|
+
note: "AppShellSlotProps"
|
|
1092
1483
|
},
|
|
1093
1484
|
{
|
|
1094
|
-
name: "sidebar"
|
|
1485
|
+
name: "sidebar",
|
|
1486
|
+
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",
|
|
1487
|
+
note: "AppShellSlotProps"
|
|
1095
1488
|
},
|
|
1096
1489
|
{
|
|
1097
|
-
name: "sidebar-footer"
|
|
1490
|
+
name: "sidebar-footer",
|
|
1491
|
+
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",
|
|
1492
|
+
note: "AppShellSlotProps"
|
|
1098
1493
|
},
|
|
1099
1494
|
{
|
|
1100
|
-
name: "default"
|
|
1495
|
+
name: "default",
|
|
1496
|
+
description: "Main content area. Scrolls independently of the header and sidebar.",
|
|
1497
|
+
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."
|
|
1101
1498
|
},
|
|
1102
1499
|
{
|
|
1103
|
-
name: "menu-icon"
|
|
1500
|
+
name: "menu-icon",
|
|
1501
|
+
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",
|
|
1502
|
+
note: "{ sidebarOpen: boolean }"
|
|
1104
1503
|
},
|
|
1105
1504
|
{
|
|
1106
|
-
name: "collapse-icon"
|
|
1505
|
+
name: "collapse-icon",
|
|
1506
|
+
description: "Replaces the default glyph inside the built-in collapse toggle. Renders inside the button, so it must be presentational only.\n",
|
|
1507
|
+
note: "{ collapsed: boolean }"
|
|
1107
1508
|
}
|
|
1108
1509
|
],
|
|
1109
1510
|
a11y: [
|
|
1110
|
-
"
|
|
1511
|
+
"semantic_regions: <header>, <aside> and <main>; the shell root itself is a plain div and is not a landmark",
|
|
1512
|
+
"role: dialog \u2014 on the mobile drawer only",
|
|
1111
1513
|
"aria_modal: true",
|
|
1112
|
-
"focus_trap:
|
|
1113
|
-
"restores_focus_on_close:
|
|
1514
|
+
"focus_trap: Tab and Shift+Tab cycle inside the drawer; with no focusable descendant, focus is pinned to the drawer itself",
|
|
1515
|
+
"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",
|
|
1114
1516
|
"escape_closes_when_enabled: true",
|
|
1115
1517
|
"menu_button_aria_expanded: true",
|
|
1116
|
-
"menu_button_aria_controls_drawer:
|
|
1117
|
-
"
|
|
1518
|
+
"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",
|
|
1519
|
+
"collapse_button_aria_expanded: reflects the expanded rail, i.e. !collapsed",
|
|
1520
|
+
"collapse_button_aria_controls_sidebar: true",
|
|
1521
|
+
"collapse_button_label_swaps_by_state: collapseLabel while expanded, expandLabel while collapsed",
|
|
1522
|
+
"drawer_close_button_labelled_by_close_label: true",
|
|
1523
|
+
"sidebar_labelled_by_sidebar_label: true",
|
|
1524
|
+
"drawer_focusable_via_tabindex_minus_one: true",
|
|
1525
|
+
"backdrop_is_aria_hidden: true",
|
|
1526
|
+
"built_in_icons_are_aria_hidden: true",
|
|
1527
|
+
"menu_and_drawer_close_buttons_are_44px: true"
|
|
1118
1528
|
],
|
|
1119
1529
|
behavior: [
|
|
1120
1530
|
"fills_viewport_full_width_and_height: true",
|
|
1531
|
+
"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",
|
|
1121
1532
|
"header_spans_full_width_above_sidebar_and_content: true",
|
|
1122
1533
|
"content_area_scrolls_independently: true",
|
|
1123
1534
|
"auto_switches_to_mobile_at_breakpoint_when_mobile_undefined: true",
|
|
1124
1535
|
"mobile_prop_forces_mobile_mode: true",
|
|
1125
1536
|
"mobile_sidebar_becomes_off_canvas_drawer: true",
|
|
1537
|
+
"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",
|
|
1538
|
+
"drawer_is_rendered_only_while_mobile_and_open: true",
|
|
1126
1539
|
"auto_menu_button_in_header_on_mobile: true",
|
|
1127
1540
|
"controlled_and_uncontrolled_collapsed_state: true",
|
|
1128
1541
|
"controlled_and_uncontrolled_sidebar_open_state: true",
|
|
1542
|
+
"controlled_and_uncontrolled_immersive_state: true",
|
|
1543
|
+
"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",
|
|
1544
|
+
"immersive_suppresses_the_mobile_drawer: while immersive the overlay is not rendered, since the trigger that opens it lives in the hidden header",
|
|
1545
|
+
"controlled_mode_does_not_self_update: when collapsed, sidebarOpen or immersive is bound, the component only emits \u2014 the parent must apply the value",
|
|
1546
|
+
"no_emit_when_the_value_is_unchanged: true",
|
|
1547
|
+
"toggle_collapsed_is_a_noop_when_collapsible_is_false: true",
|
|
1548
|
+
"collapse_toggle_requires_desktop_and_collapsible_and_show_collapse_button: true",
|
|
1129
1549
|
"provides_collapsed_state_to_descendants: true",
|
|
1130
1550
|
"drawer_reports_collapsed_false_to_descendants_and_slots: true",
|
|
1131
1551
|
"left_and_right_variants: true",
|
|
1132
1552
|
"locks_body_scroll_while_drawer_open: true",
|
|
1553
|
+
"releases_the_scroll_lock_when_leaving_mobile_while_open: true",
|
|
1554
|
+
"rearms_the_overlay_when_reentering_mobile_while_open: true",
|
|
1133
1555
|
"overlay_click_closes_when_enabled: true",
|
|
1134
1556
|
"exposes_slot_props_with_mobile_collapsed_and_toggles: true",
|
|
1135
1557
|
"sidebar_footer_pinned_to_bottom: true",
|
|
1136
1558
|
"sidebar_header_and_footer_inset_to_align_with_nav_icons: true",
|
|
1137
|
-
"header_mirrors_shell_columns_when_header_start_is_used: true"
|
|
1559
|
+
"header_mirrors_shell_columns_when_header_start_is_used: true",
|
|
1560
|
+
"header_start_falls_back_to_a_single_flex_row_on_mobile: true",
|
|
1561
|
+
"animates_the_rail_width_via_grid_template_columns: true",
|
|
1562
|
+
"main_panel_has_a_rounded_inner_corner_on_the_sidebar_side_on_desktop: true",
|
|
1563
|
+
"drawer_width_is_capped_at_min_of_100_percent_and_sidebar_width: true",
|
|
1564
|
+
'root_data_attribute: data-mobile="true" | "false" on the shell root',
|
|
1565
|
+
"respects_prefers_reduced_motion: true"
|
|
1138
1566
|
],
|
|
1139
1567
|
selection: {
|
|
1140
1568
|
keywords: [
|
|
@@ -1180,15 +1608,17 @@ var treeui_catalog_default = {
|
|
|
1180
1608
|
]
|
|
1181
1609
|
},
|
|
1182
1610
|
recipes: [
|
|
1183
|
-
"app-shell"
|
|
1184
|
-
|
|
1611
|
+
"app-shell",
|
|
1612
|
+
"brand-lockup"
|
|
1613
|
+
],
|
|
1614
|
+
practices: []
|
|
1185
1615
|
},
|
|
1186
1616
|
{
|
|
1187
1617
|
name: "TAvatar",
|
|
1188
1618
|
aliases: [],
|
|
1189
1619
|
package: "@treeui/vue",
|
|
1190
1620
|
category: "Data Display",
|
|
1191
|
-
description: "User image
|
|
1621
|
+
description: "User avatar that renders an image when `src` is set, otherwise initials derived from `alt`, plus an optional status indicator dot.",
|
|
1192
1622
|
sourceFile: "packages/vue/src/components/TAvatar.vue",
|
|
1193
1623
|
storyFile: "apps/docs/src/stories/Avatar.stories.ts",
|
|
1194
1624
|
storyTitle: "Components/Data Display/Avatar",
|
|
@@ -1198,19 +1628,19 @@ var treeui_catalog_default = {
|
|
|
1198
1628
|
name: "src",
|
|
1199
1629
|
type: "string",
|
|
1200
1630
|
required: false,
|
|
1201
|
-
description: "URL of the avatar image."
|
|
1631
|
+
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"
|
|
1202
1632
|
},
|
|
1203
1633
|
{
|
|
1204
1634
|
name: "alt",
|
|
1205
1635
|
type: "string",
|
|
1206
1636
|
default: '""',
|
|
1207
|
-
description: "Accessible label for the avatar
|
|
1637
|
+
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"
|
|
1208
1638
|
},
|
|
1209
1639
|
{
|
|
1210
1640
|
name: "initials",
|
|
1211
1641
|
type: "string",
|
|
1212
1642
|
required: false,
|
|
1213
|
-
description:
|
|
1643
|
+
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'
|
|
1214
1644
|
},
|
|
1215
1645
|
{
|
|
1216
1646
|
name: "size",
|
|
@@ -1220,7 +1650,8 @@ var treeui_catalog_default = {
|
|
|
1220
1650
|
"sm",
|
|
1221
1651
|
"md",
|
|
1222
1652
|
"lg"
|
|
1223
|
-
]
|
|
1653
|
+
],
|
|
1654
|
+
description: "Fixed square dimensions \u2014 sm 2rem, md 2.5rem, lg 3.5rem \u2014 with matching font size for initials."
|
|
1224
1655
|
},
|
|
1225
1656
|
{
|
|
1226
1657
|
name: "status",
|
|
@@ -1232,20 +1663,23 @@ var treeui_catalog_default = {
|
|
|
1232
1663
|
"busy",
|
|
1233
1664
|
"away"
|
|
1234
1665
|
],
|
|
1235
|
-
description: "Shows a colored status dot on the avatar
|
|
1666
|
+
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"
|
|
1236
1667
|
}
|
|
1237
1668
|
],
|
|
1238
1669
|
events: [],
|
|
1239
1670
|
slots: [
|
|
1240
1671
|
{
|
|
1241
1672
|
name: "default",
|
|
1242
|
-
description:
|
|
1673
|
+
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'
|
|
1243
1674
|
}
|
|
1244
1675
|
],
|
|
1245
1676
|
a11y: [
|
|
1246
|
-
"role: img",
|
|
1247
|
-
|
|
1248
|
-
|
|
1677
|
+
"role: img (always set on the root span, including when only initials render)",
|
|
1678
|
+
'aria-label: Set from `alt`. Omitted entirely when `alt` is empty (the default), which leaves the `role="img"` element without an accessible name.',
|
|
1679
|
+
'initials: Marked `aria-hidden="true"` \u2014 the name comes from `alt`, not the visible text.',
|
|
1680
|
+
"image: Receives the `alt` prop as its native `alt` attribute.",
|
|
1681
|
+
"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.",
|
|
1682
|
+
'slot_content: Not announced \u2014 the `role="img"` root makes descendant content presentational.'
|
|
1249
1683
|
],
|
|
1250
1684
|
behavior: [],
|
|
1251
1685
|
selection: {
|
|
@@ -1258,7 +1692,10 @@ var treeui_catalog_default = {
|
|
|
1258
1692
|
required: [],
|
|
1259
1693
|
notes: []
|
|
1260
1694
|
},
|
|
1261
|
-
recipes: [
|
|
1695
|
+
recipes: [
|
|
1696
|
+
"brand-lockup"
|
|
1697
|
+
],
|
|
1698
|
+
practices: []
|
|
1262
1699
|
},
|
|
1263
1700
|
{
|
|
1264
1701
|
name: "TBadge",
|
|
@@ -1283,7 +1720,8 @@ var treeui_catalog_default = {
|
|
|
1283
1720
|
"ghost",
|
|
1284
1721
|
"soft",
|
|
1285
1722
|
"danger"
|
|
1286
|
-
]
|
|
1723
|
+
],
|
|
1724
|
+
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."
|
|
1287
1725
|
},
|
|
1288
1726
|
{
|
|
1289
1727
|
name: "tone",
|
|
@@ -1296,7 +1734,7 @@ var treeui_catalog_default = {
|
|
|
1296
1734
|
"danger",
|
|
1297
1735
|
"info"
|
|
1298
1736
|
],
|
|
1299
|
-
description: "
|
|
1737
|
+
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."
|
|
1300
1738
|
},
|
|
1301
1739
|
{
|
|
1302
1740
|
name: "size",
|
|
@@ -1306,7 +1744,8 @@ var treeui_catalog_default = {
|
|
|
1306
1744
|
"sm",
|
|
1307
1745
|
"md",
|
|
1308
1746
|
"lg"
|
|
1309
|
-
]
|
|
1747
|
+
],
|
|
1748
|
+
description: "Changes min-height and font-size only; inline padding is constant across sizes."
|
|
1310
1749
|
}
|
|
1311
1750
|
],
|
|
1312
1751
|
events: [],
|
|
@@ -1319,10 +1758,19 @@ var treeui_catalog_default = {
|
|
|
1319
1758
|
}
|
|
1320
1759
|
],
|
|
1321
1760
|
a11y: [
|
|
1761
|
+
"semantic_element: span",
|
|
1322
1762
|
"interactive_by_default: false",
|
|
1323
|
-
"icon_slot_marked_aria_hidden: true"
|
|
1763
|
+
"icon_slot_marked_aria_hidden: true",
|
|
1764
|
+
"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."
|
|
1765
|
+
],
|
|
1766
|
+
behavior: [
|
|
1767
|
+
"always_applies_one_modifier_per_prop: true",
|
|
1768
|
+
"tone_remaps_variant_color_variables: true",
|
|
1769
|
+
"tone_overrides_variant_danger_palette: true",
|
|
1770
|
+
"tone_neutral_has_no_stylesheet_rule: true",
|
|
1771
|
+
"icon_wrapper_rendered_only_when_slot_filled: true",
|
|
1772
|
+
"icon_renders_before_default_slot: true"
|
|
1324
1773
|
],
|
|
1325
|
-
behavior: [],
|
|
1326
1774
|
selection: {
|
|
1327
1775
|
keywords: [],
|
|
1328
1776
|
useWhen: [],
|
|
@@ -1335,6 +1783,11 @@ var treeui_catalog_default = {
|
|
|
1335
1783
|
},
|
|
1336
1784
|
recipes: [
|
|
1337
1785
|
"pricing-section"
|
|
1786
|
+
],
|
|
1787
|
+
practices: [
|
|
1788
|
+
"predictable-api",
|
|
1789
|
+
"state-clarity",
|
|
1790
|
+
"token-driven"
|
|
1338
1791
|
]
|
|
1339
1792
|
},
|
|
1340
1793
|
{
|
|
@@ -1354,23 +1807,32 @@ var treeui_catalog_default = {
|
|
|
1354
1807
|
name: "separator",
|
|
1355
1808
|
type: "string",
|
|
1356
1809
|
default: "/",
|
|
1357
|
-
description: "Character or string
|
|
1810
|
+
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."
|
|
1358
1811
|
}
|
|
1359
1812
|
],
|
|
1360
1813
|
events: [],
|
|
1361
1814
|
slots: [
|
|
1362
1815
|
{
|
|
1363
|
-
name: "default"
|
|
1816
|
+
name: "default",
|
|
1817
|
+
description: "Breadcrumb trail content, rendered inside the <ol class='t-breadcrumb__list'>. Expects TBreadcrumbItem children so each entry becomes an <li>. No scoped props."
|
|
1364
1818
|
}
|
|
1365
1819
|
],
|
|
1366
1820
|
a11y: [
|
|
1367
1821
|
"element: nav",
|
|
1368
1822
|
"aria_label: Breadcrumb",
|
|
1823
|
+
"aria_label_hardcoded_but_overridable_via_fallthrough_attrs: true",
|
|
1369
1824
|
"current_page_aria_current: page",
|
|
1370
1825
|
"uses_ol_for_ordered_list: true",
|
|
1371
1826
|
"interactive_by_default: false"
|
|
1372
1827
|
],
|
|
1373
|
-
behavior: [
|
|
1828
|
+
behavior: [
|
|
1829
|
+
"link_target_precedence: to + resolvable RouterLink, then href, then string to",
|
|
1830
|
+
"string_to_without_router_renders_native_anchor: true",
|
|
1831
|
+
"object_to_without_router_renders_current_span: true",
|
|
1832
|
+
"current_state_is_not_positional: true",
|
|
1833
|
+
"separator_rendered_by_css_pseudo_element: true",
|
|
1834
|
+
"separator_ignores_pointer_events: true"
|
|
1835
|
+
],
|
|
1374
1836
|
selection: {
|
|
1375
1837
|
keywords: [],
|
|
1376
1838
|
useWhen: [],
|
|
@@ -1384,7 +1846,8 @@ var treeui_catalog_default = {
|
|
|
1384
1846
|
"Use `to` when the app has vue-router and breadcrumb items should render RouterLink."
|
|
1385
1847
|
]
|
|
1386
1848
|
},
|
|
1387
|
-
recipes: []
|
|
1849
|
+
recipes: [],
|
|
1850
|
+
practices: []
|
|
1388
1851
|
},
|
|
1389
1852
|
{
|
|
1390
1853
|
name: "TButton",
|
|
@@ -1402,7 +1865,8 @@ var treeui_catalog_default = {
|
|
|
1402
1865
|
{
|
|
1403
1866
|
name: "as",
|
|
1404
1867
|
type: "string",
|
|
1405
|
-
default: "button"
|
|
1868
|
+
default: "button",
|
|
1869
|
+
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."
|
|
1406
1870
|
},
|
|
1407
1871
|
{
|
|
1408
1872
|
name: "variant",
|
|
@@ -1426,23 +1890,50 @@ var treeui_catalog_default = {
|
|
|
1426
1890
|
"sm",
|
|
1427
1891
|
"md",
|
|
1428
1892
|
"lg"
|
|
1429
|
-
]
|
|
1893
|
+
],
|
|
1894
|
+
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."
|
|
1430
1895
|
},
|
|
1431
1896
|
{
|
|
1432
1897
|
name: "disabled",
|
|
1433
1898
|
type: "boolean",
|
|
1434
|
-
default: "false"
|
|
1899
|
+
default: "false",
|
|
1900
|
+
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.'
|
|
1435
1901
|
},
|
|
1436
1902
|
{
|
|
1437
1903
|
name: "loading",
|
|
1438
1904
|
type: "boolean",
|
|
1439
1905
|
default: "false",
|
|
1440
|
-
note: "loading implies disabled behavior"
|
|
1906
|
+
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`."
|
|
1907
|
+
},
|
|
1908
|
+
{
|
|
1909
|
+
name: "loadingLabel",
|
|
1910
|
+
type: "string",
|
|
1911
|
+
default: "Loading",
|
|
1912
|
+
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)."
|
|
1913
|
+
},
|
|
1914
|
+
{
|
|
1915
|
+
name: "hideIconWhileLoading",
|
|
1916
|
+
type: "boolean",
|
|
1917
|
+
default: "true",
|
|
1918
|
+
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."
|
|
1919
|
+
},
|
|
1920
|
+
{
|
|
1921
|
+
name: "iconOnly",
|
|
1922
|
+
type: "boolean",
|
|
1923
|
+
default: "false",
|
|
1924
|
+
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."
|
|
1925
|
+
},
|
|
1926
|
+
{
|
|
1927
|
+
name: "label",
|
|
1928
|
+
type: "string",
|
|
1929
|
+
default: "undefined",
|
|
1930
|
+
note: "Accessible name, rendered as `aria-label`. Required whenever `iconOnly` is set; ignored for ordinary buttons that already have visible text."
|
|
1441
1931
|
},
|
|
1442
1932
|
{
|
|
1443
1933
|
name: "type",
|
|
1444
1934
|
type: "button | submit | reset",
|
|
1445
|
-
default: "button"
|
|
1935
|
+
default: "button",
|
|
1936
|
+
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.'
|
|
1446
1937
|
},
|
|
1447
1938
|
{
|
|
1448
1939
|
name: "block",
|
|
@@ -1454,12 +1945,14 @@ var treeui_catalog_default = {
|
|
|
1454
1945
|
name: "align",
|
|
1455
1946
|
type: "start | center | end",
|
|
1456
1947
|
default: "center",
|
|
1457
|
-
note: "Content alignment; only meaningful together with `block`. Use `start` for left-aligned icon+label menu rows."
|
|
1948
|
+
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."
|
|
1458
1949
|
}
|
|
1459
1950
|
],
|
|
1460
1951
|
events: [
|
|
1461
1952
|
{
|
|
1462
|
-
name: "click"
|
|
1953
|
+
name: "click",
|
|
1954
|
+
description: "Emitted on activation. Suppressed while disabled or loading: the internal handler calls preventDefault() and stopPropagation() and returns without emitting.",
|
|
1955
|
+
payload: "[event: MouseEvent]"
|
|
1463
1956
|
}
|
|
1464
1957
|
],
|
|
1465
1958
|
slots: [
|
|
@@ -1472,13 +1965,22 @@ var treeui_catalog_default = {
|
|
|
1472
1965
|
],
|
|
1473
1966
|
a11y: [
|
|
1474
1967
|
"native_button_by_default: true",
|
|
1968
|
+
"native_disabled_attr_only_when_button: true",
|
|
1475
1969
|
"aria_busy_when_loading: true",
|
|
1476
1970
|
"aria_disabled_for_non_button: true",
|
|
1477
|
-
"tabindex_minus_one_when_non_button_disabled: true"
|
|
1971
|
+
"tabindex_minus_one_when_non_button_disabled: true",
|
|
1972
|
+
"icon_slot_marked_aria_hidden: true",
|
|
1973
|
+
"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.",
|
|
1974
|
+
"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.",
|
|
1975
|
+
"touch_targets: 44\xD744px minimum via the .t-button::after overlay",
|
|
1976
|
+
"focus_visible: box-shadow focus ring on the root element"
|
|
1478
1977
|
],
|
|
1479
1978
|
behavior: [
|
|
1480
1979
|
"blocks_click_when_disabled_or_loading: true",
|
|
1481
|
-
"renders_spinner_when_loading: true"
|
|
1980
|
+
"renders_spinner_when_loading: true",
|
|
1981
|
+
"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.",
|
|
1982
|
+
"icon_slot_wrapper_rendered_only_when_filled: true",
|
|
1983
|
+
"default_slot_wrapped_in_label_element_unless_icon_only: true"
|
|
1482
1984
|
],
|
|
1483
1985
|
selection: {
|
|
1484
1986
|
keywords: [],
|
|
@@ -1493,6 +1995,11 @@ var treeui_catalog_default = {
|
|
|
1493
1995
|
recipes: [
|
|
1494
1996
|
"confirm-destructive-action",
|
|
1495
1997
|
"pricing-section"
|
|
1998
|
+
],
|
|
1999
|
+
practices: [
|
|
2000
|
+
"interaction-feedback",
|
|
2001
|
+
"accessible-by-default",
|
|
2002
|
+
"predictable-api"
|
|
1496
2003
|
]
|
|
1497
2004
|
},
|
|
1498
2005
|
{
|
|
@@ -1502,7 +2009,7 @@ var treeui_catalog_default = {
|
|
|
1502
2009
|
kind: "layout",
|
|
1503
2010
|
category: "Data Display",
|
|
1504
2011
|
status: "available",
|
|
1505
|
-
purpose: "Surface container with optional header and footer slots.",
|
|
2012
|
+
purpose: "Surface container with optional header, actions, and footer slots.",
|
|
1506
2013
|
sourceFile: "packages/vue/src/components/TCard.vue",
|
|
1507
2014
|
storyFile: "apps/docs/src/stories/Card.stories.ts",
|
|
1508
2015
|
storyTitle: "Components/Data Display/Card",
|
|
@@ -1511,7 +2018,8 @@ var treeui_catalog_default = {
|
|
|
1511
2018
|
{
|
|
1512
2019
|
name: "as",
|
|
1513
2020
|
type: "string",
|
|
1514
|
-
default: "section"
|
|
2021
|
+
default: "section",
|
|
2022
|
+
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'
|
|
1515
2023
|
},
|
|
1516
2024
|
{
|
|
1517
2025
|
name: "variant",
|
|
@@ -1527,37 +2035,44 @@ var treeui_catalog_default = {
|
|
|
1527
2035
|
name: "size",
|
|
1528
2036
|
type: "TSize",
|
|
1529
2037
|
default: "md",
|
|
1530
|
-
|
|
1531
|
-
"sm",
|
|
1532
|
-
"md",
|
|
1533
|
-
"lg"
|
|
1534
|
-
]
|
|
2038
|
+
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"
|
|
1535
2039
|
},
|
|
1536
2040
|
{
|
|
1537
2041
|
name: "title",
|
|
1538
2042
|
type: "string",
|
|
1539
2043
|
default: "undefined",
|
|
1540
|
-
description: "Optional card heading
|
|
2044
|
+
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"
|
|
1541
2045
|
}
|
|
1542
2046
|
],
|
|
1543
2047
|
events: [],
|
|
1544
2048
|
slots: [
|
|
1545
2049
|
{
|
|
1546
|
-
name: "header"
|
|
2050
|
+
name: "header",
|
|
2051
|
+
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"
|
|
1547
2052
|
},
|
|
1548
2053
|
{
|
|
1549
|
-
name: "actions"
|
|
2054
|
+
name: "actions",
|
|
2055
|
+
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"
|
|
1550
2056
|
},
|
|
1551
2057
|
{
|
|
1552
|
-
name: "default"
|
|
2058
|
+
name: "default",
|
|
2059
|
+
description: "Card body. Always rendered, wrapped in `div.t-card__body`. Receives no slot props.\n"
|
|
1553
2060
|
},
|
|
1554
2061
|
{
|
|
1555
|
-
name: "footer"
|
|
2062
|
+
name: "footer",
|
|
2063
|
+
description: "Renders `footer.t-card__footer` only when the slot is supplied; there is no `footer` prop fallback. Receives no slot props.\n"
|
|
1556
2064
|
}
|
|
1557
2065
|
],
|
|
1558
|
-
a11y: [
|
|
2066
|
+
a11y: [
|
|
2067
|
+
"root_role: None applied by the component \u2014 semantics come entirely from `as` (default `section`).",
|
|
2068
|
+
"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.",
|
|
2069
|
+
"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."
|
|
2070
|
+
],
|
|
1559
2071
|
behavior: [
|
|
1560
2072
|
"body_wrapper_class: t-card__body",
|
|
2073
|
+
"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.",
|
|
2074
|
+
"footer_render_condition: The `footer.t-card__footer` element renders only when the `footer` slot is supplied.",
|
|
2075
|
+
"slot_props: None. No slot on this component is scoped; all four are plain content slots.",
|
|
1561
2076
|
'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."}',
|
|
1562
2077
|
"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."
|
|
1563
2078
|
],
|
|
@@ -1592,6 +2107,10 @@ var treeui_catalog_default = {
|
|
|
1592
2107
|
},
|
|
1593
2108
|
recipes: [
|
|
1594
2109
|
"chart-surface"
|
|
2110
|
+
],
|
|
2111
|
+
practices: [
|
|
2112
|
+
"predictable-api",
|
|
2113
|
+
"token-driven"
|
|
1595
2114
|
]
|
|
1596
2115
|
},
|
|
1597
2116
|
{
|
|
@@ -1621,13 +2140,13 @@ var treeui_catalog_default = {
|
|
|
1621
2140
|
name: "series",
|
|
1622
2141
|
type: "TChartSeries[]",
|
|
1623
2142
|
default: "[]",
|
|
1624
|
-
note: "Each item is { name: string; data: number[]; color?: string }."
|
|
2143
|
+
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."
|
|
1625
2144
|
},
|
|
1626
2145
|
{
|
|
1627
2146
|
name: "labels",
|
|
1628
2147
|
type: "string[]",
|
|
1629
2148
|
default: "[]",
|
|
1630
|
-
note: "X-axis categories, aligned index-for-index to each series' data."
|
|
2149
|
+
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."
|
|
1631
2150
|
},
|
|
1632
2151
|
{
|
|
1633
2152
|
name: "height",
|
|
@@ -1639,80 +2158,91 @@ var treeui_catalog_default = {
|
|
|
1639
2158
|
name: "smooth",
|
|
1640
2159
|
type: "boolean",
|
|
1641
2160
|
default: "false",
|
|
1642
|
-
note: "Curved line/area."
|
|
2161
|
+
note: "Curved line/area; ignored for bar."
|
|
1643
2162
|
},
|
|
1644
2163
|
{
|
|
1645
2164
|
name: "stacked",
|
|
1646
2165
|
type: "boolean",
|
|
1647
2166
|
default: "false",
|
|
1648
|
-
note: "Stacks bar series; ignored for line/area. Negative values are clamped to 0 in stacked mode (grouped mode renders them)."
|
|
2167
|
+
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."
|
|
1649
2168
|
},
|
|
1650
2169
|
{
|
|
1651
2170
|
name: "showGrid",
|
|
1652
2171
|
type: "boolean",
|
|
1653
|
-
default: "true"
|
|
2172
|
+
default: "true",
|
|
2173
|
+
note: "Horizontal gridlines at the y ticks. Independent of showYAxis, which controls the tick text."
|
|
1654
2174
|
},
|
|
1655
2175
|
{
|
|
1656
2176
|
name: "showLegend",
|
|
1657
|
-
type: "boolean",
|
|
1658
|
-
default: "auto (true when more than one series)"
|
|
2177
|
+
type: "boolean | undefined",
|
|
2178
|
+
default: "auto (true when more than one series)",
|
|
2179
|
+
note: "The legend is suppressed whenever there is no data, even when set to true."
|
|
1659
2180
|
},
|
|
1660
2181
|
{
|
|
1661
2182
|
name: "showXAxis",
|
|
1662
2183
|
type: "boolean",
|
|
1663
|
-
default: "true"
|
|
2184
|
+
default: "true",
|
|
2185
|
+
note: "When false the category labels are skipped and the bottom margin collapses from 28px to 10px."
|
|
1664
2186
|
},
|
|
1665
2187
|
{
|
|
1666
2188
|
name: "showYAxis",
|
|
1667
2189
|
type: "boolean",
|
|
1668
|
-
default: "true"
|
|
2190
|
+
default: "true",
|
|
2191
|
+
note: "When false the tick text is skipped and the left margin collapses from 44px to 10px. Gridlines are unaffected."
|
|
1669
2192
|
},
|
|
1670
2193
|
{
|
|
1671
2194
|
name: "showTooltip",
|
|
1672
2195
|
type: "boolean",
|
|
1673
|
-
default: "true"
|
|
2196
|
+
default: "true",
|
|
2197
|
+
note: "Gates hover tracking as a whole: the crosshair, the tooltip panel, and the point-click event all stop when false."
|
|
1674
2198
|
},
|
|
1675
2199
|
{
|
|
1676
2200
|
name: "showPoints",
|
|
1677
2201
|
type: "boolean",
|
|
1678
2202
|
default: "false",
|
|
1679
|
-
note: "Always draw markers on line/area points."
|
|
2203
|
+
note: "Always draw markers on line/area points; ignored for bar."
|
|
1680
2204
|
},
|
|
1681
2205
|
{
|
|
1682
2206
|
name: "yTicks",
|
|
1683
2207
|
type: "number",
|
|
1684
|
-
default: "5"
|
|
2208
|
+
default: "5",
|
|
2209
|
+
note: "Target tick count handed to niceScale \u2014 the rendered count may differ once the bounds are rounded."
|
|
1685
2210
|
},
|
|
1686
2211
|
{
|
|
1687
2212
|
name: "valueFormat",
|
|
1688
2213
|
type: "(value: number) => string",
|
|
1689
|
-
default: "locale integers for |value| >= 1000"
|
|
2214
|
+
default: "locale integers for |value| >= 1000",
|
|
2215
|
+
note: "Applies to y-axis ticks, tooltip values, and the a11y table cells."
|
|
1690
2216
|
},
|
|
1691
2217
|
{
|
|
1692
2218
|
name: "minY",
|
|
1693
2219
|
type: "number",
|
|
1694
|
-
default: "auto"
|
|
2220
|
+
default: "auto (min(0, data min) for bar/area, data min for line)",
|
|
2221
|
+
note: "A hint, not a hard bound: niceScale rounds the low end down, so the rendered domain can start below it."
|
|
1695
2222
|
},
|
|
1696
2223
|
{
|
|
1697
2224
|
name: "maxY",
|
|
1698
2225
|
type: "number",
|
|
1699
|
-
default: "auto"
|
|
2226
|
+
default: "auto",
|
|
2227
|
+
note: "A hint, not a hard bound: niceScale rounds the high end up, so the rendered domain can extend above it."
|
|
1700
2228
|
},
|
|
1701
2229
|
{
|
|
1702
2230
|
name: "animated",
|
|
1703
2231
|
type: "boolean",
|
|
1704
2232
|
default: "true",
|
|
1705
|
-
note: "Draw-in animation; disabled under prefers-reduced-motion."
|
|
2233
|
+
note: "Draw-in animation via the is-animated root class; disabled under prefers-reduced-motion."
|
|
1706
2234
|
},
|
|
1707
2235
|
{
|
|
1708
2236
|
name: "loading",
|
|
1709
2237
|
type: "boolean",
|
|
1710
|
-
default: "false"
|
|
2238
|
+
default: "false",
|
|
2239
|
+
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."
|
|
1711
2240
|
},
|
|
1712
2241
|
{
|
|
1713
2242
|
name: "ariaLabel",
|
|
1714
2243
|
type: "string",
|
|
1715
|
-
default: "auto-generated summary"
|
|
2244
|
+
default: "auto-generated summary ('<type> chart with <n> series')",
|
|
2245
|
+
note: "Rendered as the <caption> of the visually-hidden data table \u2014 it is not applied as an aria-label attribute on the root."
|
|
1716
2246
|
}
|
|
1717
2247
|
],
|
|
1718
2248
|
events: [
|
|
@@ -1734,14 +2264,19 @@ var treeui_catalog_default = {
|
|
|
1734
2264
|
],
|
|
1735
2265
|
a11y: [
|
|
1736
2266
|
"SVG is aria-hidden; a visually-hidden <table> mirrors the series data for assistive tech.",
|
|
2267
|
+
"The table's <caption> carries ariaLabel (or the auto-generated summary); the root div itself has no role or accessible name.",
|
|
1737
2268
|
"Legend defaults on for multiple series so identity is not color-only.",
|
|
1738
|
-
"Provide a meaningful ariaLabel describing what the chart shows."
|
|
2269
|
+
"Provide a meaningful ariaLabel describing what the chart shows.",
|
|
2270
|
+
"point-click has no keyboard equivalent \u2014 do not make it the only way to reach a behavior."
|
|
1739
2271
|
],
|
|
1740
2272
|
behavior: [
|
|
1741
|
-
"colors_auto_assign_from_chart_palette: --tree-color-chart-1..8, cycling; per-series color overrides",
|
|
1742
|
-
"
|
|
1743
|
-
"
|
|
1744
|
-
"hover_shows_crosshair_and_tooltip: true"
|
|
2273
|
+
"colors_auto_assign_from_chart_palette: --tree-color-chart-1..8, cycling by series index; per-series color overrides",
|
|
2274
|
+
"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.",
|
|
2275
|
+
"y_domain_uses_nice_ticks: every type runs through niceScale, which rounds the min down and the max up to round numbers",
|
|
2276
|
+
"hover_shows_crosshair_and_tooltip: only while showTooltip is true",
|
|
2277
|
+
"width_measured_with_resize_observer: falls back to 640px until the canvas is mounted and measured",
|
|
2278
|
+
"x_labels_decimate_when_crowded: keeps every max(2, floor(innerWidth / 52))-th label and hides the rest; the last category is always kept",
|
|
2279
|
+
"empty_state_when_no_series_has_data: true"
|
|
1745
2280
|
],
|
|
1746
2281
|
selection: {
|
|
1747
2282
|
keywords: [
|
|
@@ -1788,6 +2323,9 @@ var treeui_catalog_default = {
|
|
|
1788
2323
|
recipes: [
|
|
1789
2324
|
"chart-surface",
|
|
1790
2325
|
"metric-dashboard"
|
|
2326
|
+
],
|
|
2327
|
+
practices: [
|
|
2328
|
+
"token-driven"
|
|
1791
2329
|
]
|
|
1792
2330
|
},
|
|
1793
2331
|
{
|
|
@@ -1806,7 +2344,8 @@ var treeui_catalog_default = {
|
|
|
1806
2344
|
{
|
|
1807
2345
|
name: "modelValue",
|
|
1808
2346
|
type: "boolean",
|
|
1809
|
-
default: "false"
|
|
2347
|
+
default: "false",
|
|
2348
|
+
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"
|
|
1810
2349
|
},
|
|
1811
2350
|
{
|
|
1812
2351
|
name: "size",
|
|
@@ -1816,44 +2355,60 @@ var treeui_catalog_default = {
|
|
|
1816
2355
|
"sm",
|
|
1817
2356
|
"md",
|
|
1818
2357
|
"lg"
|
|
1819
|
-
]
|
|
2358
|
+
],
|
|
2359
|
+
description: "Control and label scale. Always rendered as a t-checkbox--<size> modifier."
|
|
1820
2360
|
},
|
|
1821
2361
|
{
|
|
1822
2362
|
name: "disabled",
|
|
1823
2363
|
type: "boolean",
|
|
1824
|
-
default: "false"
|
|
2364
|
+
default: "false",
|
|
2365
|
+
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"
|
|
1825
2366
|
},
|
|
1826
2367
|
{
|
|
1827
2368
|
name: "indeterminate",
|
|
1828
2369
|
type: "boolean",
|
|
1829
|
-
default: "false"
|
|
2370
|
+
default: "false",
|
|
2371
|
+
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.
|
|
2372
|
+
`
|
|
1830
2373
|
},
|
|
1831
2374
|
{
|
|
1832
2375
|
name: "invalid",
|
|
1833
2376
|
type: "boolean",
|
|
1834
|
-
default: "false"
|
|
2377
|
+
default: "false",
|
|
2378
|
+
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'
|
|
1835
2379
|
}
|
|
1836
2380
|
],
|
|
1837
2381
|
events: [
|
|
1838
2382
|
{
|
|
1839
|
-
name: "update:modelValue"
|
|
2383
|
+
name: "update:modelValue",
|
|
2384
|
+
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",
|
|
2385
|
+
payload: "[value: boolean]"
|
|
1840
2386
|
}
|
|
1841
2387
|
],
|
|
1842
2388
|
slots: [
|
|
1843
2389
|
{
|
|
1844
|
-
name: "default"
|
|
2390
|
+
name: "default",
|
|
2391
|
+
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'
|
|
1845
2392
|
}
|
|
1846
2393
|
],
|
|
1847
2394
|
a11y: [
|
|
1848
2395
|
"role: native_checkbox",
|
|
2396
|
+
"accessible_name: From the default slot; absent when the slot is omitted \u2014 supply aria-label or aria-labelledby",
|
|
2397
|
+
"aria_checked_explicitly_bound: 'mixed' when indeterminate, otherwise the modelValue boolean",
|
|
1849
2398
|
"aria_checked_mixed_when_indeterminate: true",
|
|
1850
2399
|
"aria_invalid_when_invalid: true",
|
|
2400
|
+
"native_indeterminate_property_synced: true",
|
|
2401
|
+
"disabled_uses_native_attribute: true",
|
|
1851
2402
|
"focus_visible_on_control: true",
|
|
2403
|
+
"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",
|
|
1852
2404
|
"clickable_target_44x44: true"
|
|
1853
2405
|
],
|
|
1854
2406
|
behavior: [
|
|
1855
2407
|
"update_payload_type: boolean",
|
|
2408
|
+
"controlled_only: No internal state; the checkbox does not change appearance until the parent updates modelValue",
|
|
2409
|
+
"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",
|
|
1856
2410
|
"indeterminate_clears_on_user_toggle: false",
|
|
2411
|
+
"indeterminate_is_parent_owned: The component never clears indeterminate \u2014 set it to false yourself when handling update:modelValue",
|
|
1857
2412
|
"label_click_toggles_checkbox: true"
|
|
1858
2413
|
],
|
|
1859
2414
|
selection: {
|
|
@@ -1886,7 +2441,10 @@ var treeui_catalog_default = {
|
|
|
1886
2441
|
required: [],
|
|
1887
2442
|
notes: []
|
|
1888
2443
|
},
|
|
1889
|
-
recipes: []
|
|
2444
|
+
recipes: [],
|
|
2445
|
+
practices: [
|
|
2446
|
+
"interaction-feedback"
|
|
2447
|
+
]
|
|
1890
2448
|
},
|
|
1891
2449
|
{
|
|
1892
2450
|
name: "TColorSwatch",
|
|
@@ -1905,19 +2463,19 @@ var treeui_catalog_default = {
|
|
|
1905
2463
|
name: "modelValue",
|
|
1906
2464
|
type: "string",
|
|
1907
2465
|
default: "undefined",
|
|
1908
|
-
note: "Selected colour as a hex string.
|
|
2466
|
+
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."
|
|
1909
2467
|
},
|
|
1910
2468
|
{
|
|
1911
2469
|
name: "options",
|
|
1912
2470
|
type: "TColorSwatchOption[]",
|
|
1913
2471
|
default: "[]",
|
|
1914
|
-
note: "Preset swatches, each `{ label, value }`. `label`
|
|
2472
|
+
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)."
|
|
1915
2473
|
},
|
|
1916
2474
|
{
|
|
1917
2475
|
name: "allowCustom",
|
|
1918
2476
|
type: "boolean",
|
|
1919
2477
|
default: "false",
|
|
1920
|
-
note: 'Appends a native `<input type="color">` for values outside the
|
|
2478
|
+
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.'
|
|
1921
2479
|
},
|
|
1922
2480
|
{
|
|
1923
2481
|
name: "size",
|
|
@@ -1927,23 +2485,26 @@ var treeui_catalog_default = {
|
|
|
1927
2485
|
"sm",
|
|
1928
2486
|
"md",
|
|
1929
2487
|
"lg"
|
|
1930
|
-
]
|
|
2488
|
+
],
|
|
2489
|
+
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."
|
|
1931
2490
|
},
|
|
1932
2491
|
{
|
|
1933
2492
|
name: "label",
|
|
1934
2493
|
type: "string",
|
|
1935
2494
|
default: "Color",
|
|
1936
|
-
note: 'Accessible label for the swatch group (`role="group"`).'
|
|
2495
|
+
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.'
|
|
1937
2496
|
},
|
|
1938
2497
|
{
|
|
1939
2498
|
name: "customLabel",
|
|
1940
2499
|
type: "string",
|
|
1941
|
-
default: "Custom color"
|
|
2500
|
+
default: "Custom color",
|
|
2501
|
+
note: "Accessible label (`aria-label`) for the native colour input, and its only accessible name. Applies only when `allowCustom` is set."
|
|
1942
2502
|
},
|
|
1943
2503
|
{
|
|
1944
2504
|
name: "disabled",
|
|
1945
2505
|
type: "boolean",
|
|
1946
|
-
default: "false"
|
|
2506
|
+
default: "false",
|
|
2507
|
+
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."
|
|
1947
2508
|
}
|
|
1948
2509
|
],
|
|
1949
2510
|
events: [
|
|
@@ -1953,14 +2514,21 @@ var treeui_catalog_default = {
|
|
|
1953
2514
|
],
|
|
1954
2515
|
slots: [],
|
|
1955
2516
|
a11y: [
|
|
1956
|
-
'Wrapper is `role="group"` labelled by `label`.',
|
|
1957
|
-
|
|
1958
|
-
"Selection is conveyed by an outline (not colour alone), since the swatch's own colour is the content."
|
|
2517
|
+
'Wrapper is `role="group"` labelled by `label` via `aria-label`.',
|
|
2518
|
+
'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.',
|
|
2519
|
+
"Selection is conveyed by an outline (not colour alone), since the swatch's own colour is the content.",
|
|
2520
|
+
'The custom input is a native `<input type="color">` named only by `customLabel`.',
|
|
2521
|
+
"No roving focus and no arrow-key navigation \u2014 every swatch and the custom input is its own Tab stop."
|
|
1959
2522
|
],
|
|
1960
2523
|
behavior: [
|
|
2524
|
+
"update_payload_type: string",
|
|
1961
2525
|
"emits_on_preset_click: true",
|
|
1962
2526
|
"emits_on_custom_input: true",
|
|
1963
|
-
"blocks_interaction_when_disabled: true"
|
|
2527
|
+
"blocks_interaction_when_disabled: true",
|
|
2528
|
+
"selection_match_is_case_insensitive: true",
|
|
2529
|
+
"custom_input_rendered_only_when_allow_custom: true",
|
|
2530
|
+
"custom_input_emits_on_input_not_change: true",
|
|
2531
|
+
"fully_controlled_no_internal_selection_state: true"
|
|
1964
2532
|
],
|
|
1965
2533
|
selection: {
|
|
1966
2534
|
keywords: [],
|
|
@@ -1972,7 +2540,8 @@ var treeui_catalog_default = {
|
|
|
1972
2540
|
required: [],
|
|
1973
2541
|
notes: []
|
|
1974
2542
|
},
|
|
1975
|
-
recipes: []
|
|
2543
|
+
recipes: [],
|
|
2544
|
+
practices: []
|
|
1976
2545
|
},
|
|
1977
2546
|
{
|
|
1978
2547
|
name: "TCombobox",
|
|
@@ -1990,7 +2559,8 @@ var treeui_catalog_default = {
|
|
|
1990
2559
|
{
|
|
1991
2560
|
name: "modelValue",
|
|
1992
2561
|
type: "string",
|
|
1993
|
-
default: ""
|
|
2562
|
+
default: "",
|
|
2563
|
+
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."
|
|
1994
2564
|
},
|
|
1995
2565
|
{
|
|
1996
2566
|
name: "options",
|
|
@@ -2001,12 +2571,14 @@ var treeui_catalog_default = {
|
|
|
2001
2571
|
{
|
|
2002
2572
|
name: "open",
|
|
2003
2573
|
type: "boolean",
|
|
2004
|
-
default: "undefined"
|
|
2574
|
+
default: "undefined",
|
|
2575
|
+
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."
|
|
2005
2576
|
},
|
|
2006
2577
|
{
|
|
2007
2578
|
name: "defaultOpen",
|
|
2008
2579
|
type: "boolean",
|
|
2009
|
-
default: "false"
|
|
2580
|
+
default: "false",
|
|
2581
|
+
note: "Uncontrolled initial open state, read once on mount. Later changes to it are ignored."
|
|
2010
2582
|
},
|
|
2011
2583
|
{
|
|
2012
2584
|
name: "size",
|
|
@@ -2016,17 +2588,20 @@ var treeui_catalog_default = {
|
|
|
2016
2588
|
"sm",
|
|
2017
2589
|
"md",
|
|
2018
2590
|
"lg"
|
|
2019
|
-
]
|
|
2591
|
+
],
|
|
2592
|
+
note: "Sizes the control only. `md` has no CSS rule of its own \u2014 it is the base `.t-combobox__control` styling."
|
|
2020
2593
|
},
|
|
2021
2594
|
{
|
|
2022
2595
|
name: "disabled",
|
|
2023
2596
|
type: "boolean",
|
|
2024
|
-
default: "false"
|
|
2597
|
+
default: "false",
|
|
2598
|
+
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.'
|
|
2025
2599
|
},
|
|
2026
2600
|
{
|
|
2027
2601
|
name: "loading",
|
|
2028
2602
|
type: "boolean",
|
|
2029
|
-
default: "false"
|
|
2603
|
+
default: "false",
|
|
2604
|
+
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.'
|
|
2030
2605
|
},
|
|
2031
2606
|
{
|
|
2032
2607
|
name: "invalid",
|
|
@@ -2041,56 +2616,102 @@ var treeui_catalog_default = {
|
|
|
2041
2616
|
{
|
|
2042
2617
|
name: "emptyText",
|
|
2043
2618
|
type: "string",
|
|
2044
|
-
default: "No results found."
|
|
2619
|
+
default: "No results found.",
|
|
2620
|
+
note: "Fallback content of the `empty` slot \u2014 supplying that slot shadows this prop entirely."
|
|
2045
2621
|
}
|
|
2046
2622
|
],
|
|
2047
2623
|
events: [
|
|
2048
2624
|
{
|
|
2049
|
-
name: "update:modelValue"
|
|
2625
|
+
name: "update:modelValue",
|
|
2626
|
+
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).',
|
|
2627
|
+
payload: '["string"]'
|
|
2050
2628
|
},
|
|
2051
2629
|
{
|
|
2052
|
-
name: "update:open"
|
|
2630
|
+
name: "update:open",
|
|
2631
|
+
description: "Emitted whenever the open state changes. Deduped \u2014 no emit when the next value equals the current one.",
|
|
2632
|
+
payload: '["boolean"]'
|
|
2053
2633
|
},
|
|
2054
2634
|
{
|
|
2055
|
-
name: "open-change"
|
|
2635
|
+
name: "open-change",
|
|
2636
|
+
description: "Emitted immediately after `update:open`, with the same payload. Alias for consumers that do not use v-model:open.",
|
|
2637
|
+
payload: '["boolean"]'
|
|
2056
2638
|
},
|
|
2057
2639
|
{
|
|
2058
|
-
name: "input-change"
|
|
2640
|
+
name: "input-change",
|
|
2641
|
+
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`.",
|
|
2642
|
+
payload: '["string"]'
|
|
2059
2643
|
}
|
|
2060
2644
|
],
|
|
2061
2645
|
slots: [
|
|
2062
2646
|
{
|
|
2063
|
-
name: "prefix"
|
|
2647
|
+
name: "prefix",
|
|
2648
|
+
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.'
|
|
2064
2649
|
},
|
|
2065
2650
|
{
|
|
2066
|
-
name: "option"
|
|
2651
|
+
name: "option",
|
|
2652
|
+
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'
|
|
2067
2653
|
},
|
|
2068
2654
|
{
|
|
2069
|
-
name: "empty"
|
|
2655
|
+
name: "empty",
|
|
2656
|
+
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.'
|
|
2070
2657
|
}
|
|
2071
2658
|
],
|
|
2072
2659
|
a11y: [
|
|
2073
2660
|
"role: combobox",
|
|
2661
|
+
"combobox_element: input",
|
|
2662
|
+
"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.",
|
|
2074
2663
|
"trigger_aria_haspopup: listbox",
|
|
2075
2664
|
"trigger_aria_expanded: true",
|
|
2665
|
+
"trigger_aria_controls_when_open: true",
|
|
2076
2666
|
"aria_autocomplete: list",
|
|
2077
2667
|
"aria_activedescendant_on_active_option: true",
|
|
2668
|
+
"aria_activedescendant_cleared_while_closed: true",
|
|
2078
2669
|
"aria_invalid_when_invalid: true",
|
|
2079
2670
|
"aria_busy_when_loading: true",
|
|
2671
|
+
"listbox_role: listbox",
|
|
2672
|
+
"option_role: option",
|
|
2673
|
+
"listbox_mirrors_aria_label_and_aria_labelledby: true",
|
|
2080
2674
|
"aria_selected_on_options: true",
|
|
2081
2675
|
"aria_disabled_on_disabled_options: true",
|
|
2676
|
+
"focus_stays_on_the_input_options_are_never_focused: true",
|
|
2082
2677
|
"keyboard_arrow_navigation: true",
|
|
2678
|
+
"arrow_navigation_does_not_wrap_at_the_ends: true",
|
|
2679
|
+
"arrow_navigation_skips_disabled_options: true",
|
|
2083
2680
|
"escape_closes_and_restores_previous_selection: true",
|
|
2681
|
+
"escape_is_ignored_while_closed: true",
|
|
2084
2682
|
"enter_selects_active_option: true",
|
|
2683
|
+
"tab_closes_and_restores_previous_selection: true",
|
|
2085
2684
|
"home_end_navigation: true"
|
|
2086
2685
|
],
|
|
2087
2686
|
behavior: [
|
|
2088
2687
|
"update_payload_type: string",
|
|
2688
|
+
"input_text_is_internal_state_not_model_value: true",
|
|
2089
2689
|
"local_filtering_by_label_description_and_keywords: true",
|
|
2690
|
+
"filtering_is_case_insensitive_substring_on_a_trimmed_query: true",
|
|
2691
|
+
"empty_query_shows_all_options: true",
|
|
2692
|
+
"input_change_emits_the_raw_query_for_async_filtering: true",
|
|
2693
|
+
"async_results_are_fed_back_through_the_options_prop: true",
|
|
2090
2694
|
"loading_does_not_disable_by_itself: true",
|
|
2695
|
+
"spinner_replaces_the_chevron_when_loading: true",
|
|
2696
|
+
"chevron_rotates_when_open: true",
|
|
2697
|
+
"check_icon_on_selected_option: true",
|
|
2698
|
+
"focus_opens_the_listbox: true",
|
|
2699
|
+
"click_on_input_opens_the_listbox: true",
|
|
2700
|
+
"typing_opens_the_listbox: true",
|
|
2701
|
+
"arrow_down_opens_the_listbox_with_the_first_enabled_option_active: true",
|
|
2702
|
+
"arrow_up_opens_the_listbox_with_the_last_enabled_option_active: true",
|
|
2703
|
+
"active_option_defaults_to_the_current_selection_when_it_is_in_the_filtered_list: true",
|
|
2704
|
+
"disabled_options_cannot_be_activated_selected_or_hovered: true",
|
|
2705
|
+
"selecting_an_option_sets_the_input_text_to_its_label_and_closes_without_restoring: true",
|
|
2091
2706
|
"outside_click_closes_dropdown: true",
|
|
2707
|
+
"outside_click_is_detected_on_pointerdown_on_document: true",
|
|
2092
2708
|
"query_clears_selection_when_closed_empty: true",
|
|
2093
|
-
"selected_value_restores_when_search_is_abandoned: true"
|
|
2709
|
+
"selected_value_restores_when_search_is_abandoned: true",
|
|
2710
|
+
"external_model_value_and_options_changes_resync_the_input_text_only_while_closed: true",
|
|
2711
|
+
"active_option_is_revalidated_when_the_filtered_list_changes: true",
|
|
2712
|
+
"open_state_emits_are_deduped: true",
|
|
2713
|
+
"listbox_is_not_rendered_while_disabled: true",
|
|
2714
|
+
"listbox_renders_in_flow_with_no_portal_and_no_flip_positioning: true"
|
|
2094
2715
|
],
|
|
2095
2716
|
selection: {
|
|
2096
2717
|
keywords: [
|
|
@@ -2123,7 +2744,8 @@ var treeui_catalog_default = {
|
|
|
2123
2744
|
"Pass `options` as labeled items and keep labels human-readable because search matches visible fields."
|
|
2124
2745
|
]
|
|
2125
2746
|
},
|
|
2126
|
-
recipes: []
|
|
2747
|
+
recipes: [],
|
|
2748
|
+
practices: []
|
|
2127
2749
|
},
|
|
2128
2750
|
{
|
|
2129
2751
|
name: "TConfirmDialog",
|
|
@@ -2146,12 +2768,14 @@ var treeui_catalog_default = {
|
|
|
2146
2768
|
{
|
|
2147
2769
|
name: "defaultOpen",
|
|
2148
2770
|
type: "boolean",
|
|
2149
|
-
default: "false"
|
|
2771
|
+
default: "false",
|
|
2772
|
+
note: "Uncontrolled initial state. Read once on setup \u2014 later changes are ignored. Only meaningful when `open` is left undefined."
|
|
2150
2773
|
},
|
|
2151
2774
|
{
|
|
2152
2775
|
name: "disabled",
|
|
2153
2776
|
type: "boolean",
|
|
2154
|
-
default: "false"
|
|
2777
|
+
default: "false",
|
|
2778
|
+
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."
|
|
2155
2779
|
},
|
|
2156
2780
|
{
|
|
2157
2781
|
name: "size",
|
|
@@ -2161,47 +2785,63 @@ var treeui_catalog_default = {
|
|
|
2161
2785
|
"sm",
|
|
2162
2786
|
"md",
|
|
2163
2787
|
"lg"
|
|
2164
|
-
]
|
|
2788
|
+
],
|
|
2789
|
+
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`)."
|
|
2165
2790
|
},
|
|
2166
2791
|
{
|
|
2167
2792
|
name: "title",
|
|
2168
2793
|
type: "string",
|
|
2169
|
-
default: ""
|
|
2794
|
+
default: "",
|
|
2795
|
+
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."
|
|
2170
2796
|
},
|
|
2171
2797
|
{
|
|
2172
2798
|
name: "description",
|
|
2173
2799
|
type: "string",
|
|
2174
|
-
default: ""
|
|
2800
|
+
default: "",
|
|
2801
|
+
note: "Rendered by TModal as `t-modal__description` and referenced by `aria-describedby`. The default slot body is NOT part of the accessible description."
|
|
2175
2802
|
},
|
|
2176
2803
|
{
|
|
2177
2804
|
name: "confirmLabel",
|
|
2178
2805
|
type: "string",
|
|
2179
|
-
default: "Confirm"
|
|
2806
|
+
default: "Confirm",
|
|
2807
|
+
note: "Ignored when the `actions` slot is supplied."
|
|
2180
2808
|
},
|
|
2181
2809
|
{
|
|
2182
2810
|
name: "cancelLabel",
|
|
2183
2811
|
type: "string",
|
|
2184
|
-
default: "Cancel"
|
|
2812
|
+
default: "Cancel",
|
|
2813
|
+
note: "Ignored when the `actions` slot is supplied."
|
|
2185
2814
|
},
|
|
2186
2815
|
{
|
|
2187
2816
|
name: "confirmVariant",
|
|
2188
2817
|
type: "TVariant",
|
|
2189
|
-
default: "danger"
|
|
2818
|
+
default: "danger",
|
|
2819
|
+
values: [
|
|
2820
|
+
"solid",
|
|
2821
|
+
"outline",
|
|
2822
|
+
"ghost",
|
|
2823
|
+
"soft",
|
|
2824
|
+
"danger"
|
|
2825
|
+
],
|
|
2826
|
+
note: "Ignored when the `actions` slot is supplied."
|
|
2190
2827
|
},
|
|
2191
2828
|
{
|
|
2192
2829
|
name: "confirmDisabled",
|
|
2193
2830
|
type: "boolean",
|
|
2194
|
-
default: "false"
|
|
2831
|
+
default: "false",
|
|
2832
|
+
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."
|
|
2195
2833
|
},
|
|
2196
2834
|
{
|
|
2197
2835
|
name: "cancelDisabled",
|
|
2198
2836
|
type: "boolean",
|
|
2199
|
-
default: "false"
|
|
2837
|
+
default: "false",
|
|
2838
|
+
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."
|
|
2200
2839
|
},
|
|
2201
2840
|
{
|
|
2202
2841
|
name: "loading",
|
|
2203
2842
|
type: "boolean",
|
|
2204
|
-
default: "false"
|
|
2843
|
+
default: "false",
|
|
2844
|
+
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."
|
|
2205
2845
|
},
|
|
2206
2846
|
{
|
|
2207
2847
|
name: "closeOnEscape",
|
|
@@ -2211,27 +2851,32 @@ var treeui_catalog_default = {
|
|
|
2211
2851
|
{
|
|
2212
2852
|
name: "closeOnOverlay",
|
|
2213
2853
|
type: "boolean",
|
|
2214
|
-
default: "false"
|
|
2854
|
+
default: "false",
|
|
2855
|
+
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."
|
|
2215
2856
|
},
|
|
2216
2857
|
{
|
|
2217
2858
|
name: "showCloseButton",
|
|
2218
2859
|
type: "boolean",
|
|
2219
|
-
default: "false"
|
|
2860
|
+
default: "false",
|
|
2861
|
+
note: "Deliberately opt-in \u2014 TModal defaults this to true. Enabling it adds a header close button that dismisses without emitting `cancel`."
|
|
2220
2862
|
},
|
|
2221
2863
|
{
|
|
2222
2864
|
name: "closeLabel",
|
|
2223
2865
|
type: "string",
|
|
2224
|
-
default: "Close dialog"
|
|
2866
|
+
default: "Close dialog",
|
|
2867
|
+
note: "Accessible name of the header close button. Only rendered when `showCloseButton` is true."
|
|
2225
2868
|
},
|
|
2226
2869
|
{
|
|
2227
2870
|
name: "closeOnConfirm",
|
|
2228
2871
|
type: "boolean",
|
|
2229
|
-
default: "true"
|
|
2872
|
+
default: "true",
|
|
2873
|
+
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`."
|
|
2230
2874
|
},
|
|
2231
2875
|
{
|
|
2232
2876
|
name: "closeOnCancel",
|
|
2233
2877
|
type: "boolean",
|
|
2234
|
-
default: "true"
|
|
2878
|
+
default: "true",
|
|
2879
|
+
note: "Set false to keep the dialog open after `cancel` \u2014 the caller then owns closing via `open`."
|
|
2235
2880
|
}
|
|
2236
2881
|
],
|
|
2237
2882
|
events: [
|
|
@@ -2250,16 +2895,20 @@ var treeui_catalog_default = {
|
|
|
2250
2895
|
],
|
|
2251
2896
|
slots: [
|
|
2252
2897
|
{
|
|
2253
|
-
name: "trigger"
|
|
2898
|
+
name: "trigger",
|
|
2899
|
+
description: "Element that opens the dialog on click. Omit for imperative use."
|
|
2254
2900
|
},
|
|
2255
2901
|
{
|
|
2256
|
-
name: "icon"
|
|
2902
|
+
name: "icon",
|
|
2903
|
+
description: "Decorative leading icon. Presence switches the block to the two-column icon layout."
|
|
2257
2904
|
},
|
|
2258
2905
|
{
|
|
2259
|
-
name: "default"
|
|
2906
|
+
name: "default",
|
|
2907
|
+
description: "Extra body content rendered under the description."
|
|
2260
2908
|
},
|
|
2261
2909
|
{
|
|
2262
|
-
name: "actions"
|
|
2910
|
+
name: "actions",
|
|
2911
|
+
description: "Replaces the whole footer. Scope gives you confirm(), cancel(), and loading."
|
|
2263
2912
|
}
|
|
2264
2913
|
],
|
|
2265
2914
|
a11y: [
|
|
@@ -2267,15 +2916,26 @@ var treeui_catalog_default = {
|
|
|
2267
2916
|
"aria_modal: true",
|
|
2268
2917
|
"focus_trap: inherited_from_modal",
|
|
2269
2918
|
"restores_focus_on_close: inherited_from_modal",
|
|
2919
|
+
"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.",
|
|
2920
|
+
"accessible_name_source: `title` prop, via aria-labelledby; absent when `title` is empty",
|
|
2921
|
+
"accessible_description_source: `description` prop, via aria-describedby; the default slot body is not included",
|
|
2922
|
+
"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.",
|
|
2270
2923
|
"icon_slot_marked_aria_hidden: true"
|
|
2271
2924
|
],
|
|
2272
2925
|
behavior: [
|
|
2273
2926
|
"built_on_modal_contract: true",
|
|
2274
2927
|
"default_confirm_button_variant: danger",
|
|
2928
|
+
"default_cancel_button_variant: ghost",
|
|
2275
2929
|
"overlay_click_disabled_by_default: true",
|
|
2276
2930
|
"close_button_hidden_by_default: true",
|
|
2277
2931
|
"loading_state_applies_to_confirm_button: true",
|
|
2278
|
-
"
|
|
2932
|
+
"confirm_suppressed_when: confirmDisabled || loading \u2014 the handler returns before emitting, so neither `confirm` nor the close runs",
|
|
2933
|
+
"cancel_suppressed_when: cancelDisabled \u2014 the handler returns before emitting, so neither `cancel` nor the close runs",
|
|
2934
|
+
"closes_after_confirm_when: closeOnConfirm",
|
|
2935
|
+
"closes_after_cancel_when: closeOnCancel",
|
|
2936
|
+
"guards_and_auto_close_apply_to_actions_slot: true",
|
|
2937
|
+
"close_button_and_escape_do_not_emit_cancel: true",
|
|
2938
|
+
"inherits_teleport_scroll_lock_and_focus_trap_from_modal: true"
|
|
2279
2939
|
],
|
|
2280
2940
|
selection: {
|
|
2281
2941
|
keywords: [],
|
|
@@ -2289,6 +2949,9 @@ var treeui_catalog_default = {
|
|
|
2289
2949
|
},
|
|
2290
2950
|
recipes: [
|
|
2291
2951
|
"confirm-destructive-action"
|
|
2952
|
+
],
|
|
2953
|
+
practices: [
|
|
2954
|
+
"accessible-by-default"
|
|
2292
2955
|
]
|
|
2293
2956
|
},
|
|
2294
2957
|
{
|
|
@@ -2341,7 +3004,9 @@ var treeui_catalog_default = {
|
|
|
2341
3004
|
}
|
|
2342
3005
|
],
|
|
2343
3006
|
a11y: [
|
|
2344
|
-
"Acts as a structural wrapper only; semantics come from the `as` prop and child content."
|
|
3007
|
+
"Acts as a structural wrapper only; semantics come from the `as` prop and child content.",
|
|
3008
|
+
'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',
|
|
3009
|
+
"`aria-*` and `role` attributes fall through to the root element (see `forwards_attrs_to`)."
|
|
2345
3010
|
],
|
|
2346
3011
|
behavior: [
|
|
2347
3012
|
"semantic_element_controlled_by_as: true",
|
|
@@ -2385,6 +3050,9 @@ var treeui_catalog_default = {
|
|
|
2385
3050
|
},
|
|
2386
3051
|
recipes: [
|
|
2387
3052
|
"sidebar-shell"
|
|
3053
|
+
],
|
|
3054
|
+
practices: [
|
|
3055
|
+
"content-alignment"
|
|
2388
3056
|
]
|
|
2389
3057
|
},
|
|
2390
3058
|
{
|
|
@@ -2393,6 +3061,8 @@ var treeui_catalog_default = {
|
|
|
2393
3061
|
package: "@treeui/vue",
|
|
2394
3062
|
category: "Overlay",
|
|
2395
3063
|
status: "stable",
|
|
3064
|
+
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",
|
|
3065
|
+
sourceFile: "packages/vue/src/components/TContextMenu.vue",
|
|
2396
3066
|
storyFile: "apps/docs/src/stories/ContextMenu.stories.ts",
|
|
2397
3067
|
storyTitle: "Components/Overlay/ContextMenu",
|
|
2398
3068
|
manifestFile: "docs/ai/COMPONENTS/context-menu.yaml",
|
|
@@ -2401,73 +3071,84 @@ var treeui_catalog_default = {
|
|
|
2401
3071
|
name: "items",
|
|
2402
3072
|
type: "TContextMenuItem[]",
|
|
2403
3073
|
default: "[]",
|
|
2404
|
-
description:
|
|
3074
|
+
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'
|
|
2405
3075
|
},
|
|
2406
3076
|
{
|
|
2407
3077
|
name: "open",
|
|
2408
3078
|
type: "boolean | undefined",
|
|
2409
3079
|
default: "undefined",
|
|
2410
|
-
description: "Controlled open state (v-model:open)."
|
|
3080
|
+
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"
|
|
2411
3081
|
},
|
|
2412
3082
|
{
|
|
2413
3083
|
name: "defaultOpen",
|
|
2414
3084
|
type: "boolean",
|
|
2415
3085
|
default: "false",
|
|
2416
|
-
description: "Uncontrolled initial open state."
|
|
3086
|
+
description: "Uncontrolled initial open state. Read once during setup \u2014 later changes to this prop have no effect.\n"
|
|
2417
3087
|
},
|
|
2418
3088
|
{
|
|
2419
3089
|
name: "disabled",
|
|
2420
3090
|
type: "boolean",
|
|
2421
3091
|
default: "false",
|
|
2422
|
-
description: "Prevents the context menu from opening."
|
|
3092
|
+
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"
|
|
2423
3093
|
},
|
|
2424
3094
|
{
|
|
2425
3095
|
name: "size",
|
|
2426
3096
|
type: "TSize",
|
|
2427
3097
|
default: "md",
|
|
2428
|
-
|
|
3098
|
+
values: [
|
|
3099
|
+
"sm",
|
|
3100
|
+
"md",
|
|
3101
|
+
"lg"
|
|
3102
|
+
],
|
|
3103
|
+
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"
|
|
2429
3104
|
}
|
|
2430
3105
|
],
|
|
2431
3106
|
events: [
|
|
2432
3107
|
{
|
|
2433
3108
|
name: "select",
|
|
2434
|
-
description: "Emitted when
|
|
3109
|
+
description: "Emitted with `item.value` when an enabled item is activated by click or Enter/Space. Disabled items emit nothing.\n",
|
|
2435
3110
|
payload: "[value: string]"
|
|
2436
3111
|
},
|
|
2437
3112
|
{
|
|
2438
3113
|
name: "update:open",
|
|
2439
|
-
description: "Emitted when open state changes (v-model support).",
|
|
3114
|
+
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",
|
|
2440
3115
|
payload: "[value: boolean]"
|
|
2441
3116
|
},
|
|
2442
3117
|
{
|
|
2443
3118
|
name: "open-change",
|
|
2444
|
-
description: "Emitted when open state changes.",
|
|
3119
|
+
description: "Emitted when open state changes. Always fires together with `update:open`, including in controlled mode.\n",
|
|
2445
3120
|
payload: "[value: boolean]"
|
|
2446
3121
|
}
|
|
2447
3122
|
],
|
|
2448
3123
|
slots: [
|
|
2449
3124
|
{
|
|
2450
3125
|
name: "default",
|
|
2451
|
-
description: "Content that acts as the right-click trigger area."
|
|
3126
|
+
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"
|
|
2452
3127
|
},
|
|
2453
3128
|
{
|
|
2454
3129
|
name: "item",
|
|
2455
|
-
description:
|
|
3130
|
+
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'
|
|
2456
3131
|
}
|
|
2457
3132
|
],
|
|
2458
3133
|
a11y: [
|
|
2459
|
-
"role: menu (on the floating list)",
|
|
3134
|
+
"role: menu (on the teleported floating list)",
|
|
2460
3135
|
"items_role: menuitem",
|
|
2461
|
-
'keyboard: ["Right-click / contextmenu event opens menu at cursor","ArrowDown / ArrowUp
|
|
2462
|
-
'aria: ["aria-disabled on disabled items","aria-label on menu element"]',
|
|
2463
|
-
'focus: ["First enabled item receives focus on open","Focus restored to trigger area on close"]'
|
|
3136
|
+
'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"]',
|
|
3137
|
+
'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"]',
|
|
3138
|
+
'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"]'
|
|
2464
3139
|
],
|
|
2465
3140
|
behavior: [
|
|
2466
|
-
"Opens at cursor position on right-click (contextmenu event).",
|
|
2467
|
-
"Uses Teleport to body to escape stacking contexts.",
|
|
2468
|
-
"
|
|
2469
|
-
"
|
|
2470
|
-
"
|
|
3141
|
+
"Opens at cursor position on right-click (contextmenu event), using event.clientX / clientY.",
|
|
3142
|
+
"Uses Teleport to body to escape stacking contexts; the menu is not a DOM descendant of the trigger.",
|
|
3143
|
+
"Uses position fixed at the raw cursor coordinates, stacked at var(--tree-z-dropdown).",
|
|
3144
|
+
"No collision detection or viewport clamping \u2014 a menu opened near the right or bottom edge overflows.",
|
|
3145
|
+
"Closes on pointerdown outside the menu (including on the trigger itself), Escape, or item selection.",
|
|
3146
|
+
"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.",
|
|
3147
|
+
"A document-level contextmenu listener covers keyboard-invoked menus (Shift+F10 / Menu key) raised outside the trigger.",
|
|
3148
|
+
"Prevents native browser context menu on trigger area, but only while not disabled.",
|
|
3149
|
+
'Exposes data-state="open" | "closed" on the root element for external styling.',
|
|
3150
|
+
"Document pointerdown / contextmenu listeners are attached only while open, and removed on close and before unmount.",
|
|
3151
|
+
"Menu enter / leave uses the shared t-fade transition (opacity plus scale 0.95)."
|
|
2471
3152
|
],
|
|
2472
3153
|
selection: {
|
|
2473
3154
|
keywords: [
|
|
@@ -2492,7 +3173,8 @@ var treeui_catalog_default = {
|
|
|
2492
3173
|
required: [],
|
|
2493
3174
|
notes: []
|
|
2494
3175
|
},
|
|
2495
|
-
recipes: []
|
|
3176
|
+
recipes: [],
|
|
3177
|
+
practices: []
|
|
2496
3178
|
},
|
|
2497
3179
|
{
|
|
2498
3180
|
name: "TDatePicker",
|
|
@@ -2510,17 +3192,20 @@ var treeui_catalog_default = {
|
|
|
2510
3192
|
{
|
|
2511
3193
|
name: "modelValue",
|
|
2512
3194
|
type: "string",
|
|
2513
|
-
default: ""
|
|
3195
|
+
default: "",
|
|
3196
|
+
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."
|
|
2514
3197
|
},
|
|
2515
3198
|
{
|
|
2516
3199
|
name: "open",
|
|
2517
3200
|
type: "boolean",
|
|
2518
|
-
default: "
|
|
3201
|
+
default: "undefined",
|
|
3202
|
+
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."
|
|
2519
3203
|
},
|
|
2520
3204
|
{
|
|
2521
3205
|
name: "defaultOpen",
|
|
2522
3206
|
type: "boolean",
|
|
2523
|
-
default: "false"
|
|
3207
|
+
default: "false",
|
|
3208
|
+
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."
|
|
2524
3209
|
},
|
|
2525
3210
|
{
|
|
2526
3211
|
name: "size",
|
|
@@ -2530,41 +3215,48 @@ var treeui_catalog_default = {
|
|
|
2530
3215
|
"sm",
|
|
2531
3216
|
"md",
|
|
2532
3217
|
"lg"
|
|
2533
|
-
]
|
|
3218
|
+
],
|
|
3219
|
+
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."
|
|
2534
3220
|
},
|
|
2535
3221
|
{
|
|
2536
3222
|
name: "disabled",
|
|
2537
3223
|
type: "boolean",
|
|
2538
|
-
default: "false"
|
|
3224
|
+
default: "false",
|
|
3225
|
+
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.'
|
|
2539
3226
|
},
|
|
2540
3227
|
{
|
|
2541
3228
|
name: "invalid",
|
|
2542
3229
|
type: "boolean",
|
|
2543
|
-
default: "false"
|
|
3230
|
+
default: "false",
|
|
3231
|
+
note: 'Adds `is-invalid` to the root and `aria-invalid="true"` to the trigger. Purely presentational \u2014 it does not block opening or selection.'
|
|
2544
3232
|
},
|
|
2545
3233
|
{
|
|
2546
3234
|
name: "placeholder",
|
|
2547
3235
|
type: "string",
|
|
2548
|
-
default: "Select date"
|
|
3236
|
+
default: "Select date",
|
|
3237
|
+
note: "Rendered inside `.t-date-picker__value` with a `data-placeholder` attribute whenever `modelValue` does not parse."
|
|
2549
3238
|
},
|
|
2550
3239
|
{
|
|
2551
3240
|
name: "locale",
|
|
2552
3241
|
type: "string",
|
|
2553
|
-
default: "en-US"
|
|
3242
|
+
default: "en-US",
|
|
3243
|
+
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."
|
|
2554
3244
|
},
|
|
2555
3245
|
{
|
|
2556
3246
|
name: "min",
|
|
2557
3247
|
type: "string",
|
|
2558
|
-
default: ""
|
|
3248
|
+
default: "",
|
|
3249
|
+
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."
|
|
2559
3250
|
},
|
|
2560
3251
|
{
|
|
2561
3252
|
name: "max",
|
|
2562
3253
|
type: "string",
|
|
2563
|
-
default: ""
|
|
3254
|
+
default: "",
|
|
3255
|
+
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."
|
|
2564
3256
|
},
|
|
2565
3257
|
{
|
|
2566
3258
|
name: "weekStartsOn",
|
|
2567
|
-
type: "
|
|
3259
|
+
type: "0 | 1 | 2 | 3 | 4 | 5 | 6",
|
|
2568
3260
|
default: "0",
|
|
2569
3261
|
values: [
|
|
2570
3262
|
"0",
|
|
@@ -2574,46 +3266,90 @@ var treeui_catalog_default = {
|
|
|
2574
3266
|
"4",
|
|
2575
3267
|
"5",
|
|
2576
3268
|
"6"
|
|
2577
|
-
]
|
|
3269
|
+
],
|
|
3270
|
+
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)."
|
|
2578
3271
|
},
|
|
2579
3272
|
{
|
|
2580
3273
|
name: "id",
|
|
2581
3274
|
type: "string",
|
|
2582
|
-
default: "auto"
|
|
3275
|
+
default: "auto",
|
|
3276
|
+
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."
|
|
2583
3277
|
}
|
|
2584
3278
|
],
|
|
2585
3279
|
events: [
|
|
2586
3280
|
{
|
|
2587
|
-
name: "update:modelValue"
|
|
3281
|
+
name: "update:modelValue",
|
|
3282
|
+
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.',
|
|
3283
|
+
payload: '["string"]'
|
|
2588
3284
|
},
|
|
2589
3285
|
{
|
|
2590
|
-
name: "update:open"
|
|
3286
|
+
name: "update:open",
|
|
3287
|
+
description: "Emitted whenever the open state changes. Deduped \u2014 no emit when the next value equals the current one.",
|
|
3288
|
+
payload: '["boolean"]'
|
|
2591
3289
|
},
|
|
2592
3290
|
{
|
|
2593
|
-
name: "open-change"
|
|
3291
|
+
name: "open-change",
|
|
3292
|
+
description: "Emitted immediately after `update:open`, with the same payload. Alias for consumers that do not use v-model:open.",
|
|
3293
|
+
payload: '["boolean"]'
|
|
2594
3294
|
},
|
|
2595
3295
|
{
|
|
2596
|
-
name: "select"
|
|
3296
|
+
name: "select",
|
|
3297
|
+
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`.",
|
|
3298
|
+
payload: '["string"]'
|
|
2597
3299
|
}
|
|
2598
3300
|
],
|
|
2599
3301
|
slots: [
|
|
2600
3302
|
{
|
|
2601
|
-
name: "prefix"
|
|
3303
|
+
name: "prefix",
|
|
3304
|
+
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.'
|
|
2602
3305
|
},
|
|
2603
3306
|
{
|
|
2604
|
-
name: "suffix"
|
|
3307
|
+
name: "suffix",
|
|
3308
|
+
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.'
|
|
2605
3309
|
}
|
|
2606
3310
|
],
|
|
2607
3311
|
a11y: [
|
|
3312
|
+
"role: dialog",
|
|
3313
|
+
"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>.",
|
|
2608
3314
|
"trigger_has_popup_dialog: true",
|
|
3315
|
+
"trigger_aria_expanded: true",
|
|
3316
|
+
"trigger_aria_controls_when_open: true",
|
|
3317
|
+
"aria_invalid_when_invalid: true",
|
|
2609
3318
|
"calendar_uses_grid_roles: true",
|
|
3319
|
+
"calendar_aria_modal: false",
|
|
3320
|
+
"calendar_labelled_by_month_caption: true",
|
|
3321
|
+
"weekday_header_is_aria_hidden: true",
|
|
3322
|
+
"aria_selected_rendered_on_every_gridcell: true",
|
|
3323
|
+
"aria_current_date_on_today: true",
|
|
3324
|
+
"day_aria_label_is_the_raw_iso_key: true",
|
|
3325
|
+
"nav_buttons_labelled_previous_month_and_next_month: true",
|
|
3326
|
+
"roving_tabindex_one_focusable_day: true",
|
|
2610
3327
|
"escape_closes: true",
|
|
2611
|
-
"returns_focus_to_trigger_after_selection: true"
|
|
3328
|
+
"returns_focus_to_trigger_after_selection: true",
|
|
3329
|
+
"returns_focus_to_trigger_on_escape_from_a_day: true",
|
|
3330
|
+
"focus_is_not_trapped_and_tab_leaves_the_open_calendar: true"
|
|
2612
3331
|
],
|
|
2613
3332
|
behavior: [
|
|
3333
|
+
"value_format: YYYY-MM-DD",
|
|
3334
|
+
"controlled_and_uncontrolled_open: true",
|
|
3335
|
+
"open_state_emits_are_deduped: true",
|
|
2614
3336
|
"selection_closes_popover: true",
|
|
2615
3337
|
"hidden_input_created_when_name_attr_present: true",
|
|
2616
|
-
"
|
|
3338
|
+
"hidden_input_submits_the_raw_unparsed_model_value: true",
|
|
3339
|
+
"out_of_range_dates_disabled: true",
|
|
3340
|
+
"min_and_max_also_disable_the_month_nav_buttons: true",
|
|
3341
|
+
"popover_is_not_rendered_while_disabled: true",
|
|
3342
|
+
"outside_click_closes_calendar: true",
|
|
3343
|
+
"outside_click_is_detected_on_pointerdown_on_document: true",
|
|
3344
|
+
"outside_click_and_trigger_toggle_close_without_restoring_focus: true",
|
|
3345
|
+
"grid_is_always_six_weeks_forty_two_days: true",
|
|
3346
|
+
"leading_and_trailing_days_render_muted_and_stay_selectable: true",
|
|
3347
|
+
"opening_syncs_the_view_to_the_selected_date_else_the_last_focused_date_else_today: true",
|
|
3348
|
+
"external_model_value_changes_move_the_view_and_the_focused_day: true",
|
|
3349
|
+
"clearing_the_model_value_resets_the_view_to_today_only_while_closed: true",
|
|
3350
|
+
"month_nav_moves_the_focused_day_to_the_first_of_the_new_month_and_focuses_it: true",
|
|
3351
|
+
"today_is_computed_once_at_setup_not_re_evaluated_across_midnight: true",
|
|
3352
|
+
"popover_renders_in_flow_with_no_portal_and_no_flip_positioning: true"
|
|
2617
3353
|
],
|
|
2618
3354
|
selection: {
|
|
2619
3355
|
keywords: [
|
|
@@ -2641,13 +3377,14 @@ var treeui_catalog_default = {
|
|
|
2641
3377
|
"Use `min` and `max` with the same format."
|
|
2642
3378
|
]
|
|
2643
3379
|
},
|
|
2644
|
-
recipes: []
|
|
3380
|
+
recipes: [],
|
|
3381
|
+
practices: []
|
|
2645
3382
|
},
|
|
2646
3383
|
{
|
|
2647
3384
|
name: "TDateTimePicker",
|
|
2648
3385
|
aliases: [],
|
|
2649
3386
|
package: "@treeui/vue",
|
|
2650
|
-
kind: "
|
|
3387
|
+
kind: "form_overlay",
|
|
2651
3388
|
category: "Data Entry",
|
|
2652
3389
|
status: "available",
|
|
2653
3390
|
purpose: "Date and time picker with a calendar grid, time selection, and overlay trigger.",
|
|
@@ -2660,7 +3397,7 @@ var treeui_catalog_default = {
|
|
|
2660
3397
|
name: "modelValue",
|
|
2661
3398
|
type: "string",
|
|
2662
3399
|
default: "",
|
|
2663
|
-
note: "
|
|
3400
|
+
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."
|
|
2664
3401
|
},
|
|
2665
3402
|
{
|
|
2666
3403
|
name: "open",
|
|
@@ -2680,17 +3417,20 @@ var treeui_catalog_default = {
|
|
|
2680
3417
|
"sm",
|
|
2681
3418
|
"md",
|
|
2682
3419
|
"lg"
|
|
2683
|
-
]
|
|
3420
|
+
],
|
|
3421
|
+
note: "Renders as `t-date-picker--<size>` on the root \u2014 there is no `t-date-time-picker--<size>` modifier."
|
|
2684
3422
|
},
|
|
2685
3423
|
{
|
|
2686
3424
|
name: "disabled",
|
|
2687
3425
|
type: "boolean",
|
|
2688
|
-
default: "false"
|
|
3426
|
+
default: "false",
|
|
3427
|
+
note: "Blocks opening via click/keyboard and suppresses the overlay entirely, even when `open` is true."
|
|
2689
3428
|
},
|
|
2690
3429
|
{
|
|
2691
3430
|
name: "loading",
|
|
2692
3431
|
type: "boolean",
|
|
2693
|
-
default: "false"
|
|
3432
|
+
default: "false",
|
|
3433
|
+
note: "Only swaps the default suffix icon for a TSpinner; the trigger stays enabled and interactive."
|
|
2694
3434
|
},
|
|
2695
3435
|
{
|
|
2696
3436
|
name: "invalid",
|
|
@@ -2705,33 +3445,38 @@ var treeui_catalog_default = {
|
|
|
2705
3445
|
{
|
|
2706
3446
|
name: "locale",
|
|
2707
3447
|
type: "string",
|
|
2708
|
-
default: "en-US"
|
|
3448
|
+
default: "en-US",
|
|
3449
|
+
note: "Feeds all four Intl.DateTimeFormat calls: trigger text, draft preview, month caption, weekday labels."
|
|
2709
3450
|
},
|
|
2710
3451
|
{
|
|
2711
3452
|
name: "min",
|
|
2712
3453
|
type: "string",
|
|
2713
|
-
default: ""
|
|
3454
|
+
default: "",
|
|
3455
|
+
note: "`YYYY-MM-DD` (resolved to 00:00 of that day) or `YYYY-MM-DDTHH:mm`."
|
|
2714
3456
|
},
|
|
2715
3457
|
{
|
|
2716
3458
|
name: "max",
|
|
2717
3459
|
type: "string",
|
|
2718
|
-
default: ""
|
|
3460
|
+
default: "",
|
|
3461
|
+
note: "`YYYY-MM-DD` (resolved to 23:59:59.999 of that day) or `YYYY-MM-DDTHH:mm`."
|
|
2719
3462
|
},
|
|
2720
3463
|
{
|
|
2721
3464
|
name: "weekStartsOn",
|
|
2722
3465
|
type: "0 | 1 | 2 | 3 | 4 | 5 | 6",
|
|
2723
|
-
default: "0"
|
|
3466
|
+
default: "0",
|
|
3467
|
+
note: "0 = Sunday. Reorders the weekday header labels, the grid start date, and Home/End day navigation."
|
|
2724
3468
|
},
|
|
2725
3469
|
{
|
|
2726
3470
|
name: "id",
|
|
2727
3471
|
type: "string",
|
|
2728
|
-
default: "auto"
|
|
3472
|
+
default: "auto",
|
|
3473
|
+
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."
|
|
2729
3474
|
},
|
|
2730
3475
|
{
|
|
2731
3476
|
name: "step",
|
|
2732
3477
|
type: "number",
|
|
2733
3478
|
default: "60",
|
|
2734
|
-
note: "Seconds between
|
|
3479
|
+
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."
|
|
2735
3480
|
}
|
|
2736
3481
|
],
|
|
2737
3482
|
events: [
|
|
@@ -2751,12 +3496,28 @@ var treeui_catalog_default = {
|
|
|
2751
3496
|
name: "select"
|
|
2752
3497
|
}
|
|
2753
3498
|
],
|
|
2754
|
-
slots: [
|
|
3499
|
+
slots: [
|
|
3500
|
+
{
|
|
3501
|
+
name: "prefix"
|
|
3502
|
+
},
|
|
3503
|
+
{
|
|
3504
|
+
name: "suffix"
|
|
3505
|
+
}
|
|
3506
|
+
],
|
|
2755
3507
|
a11y: [
|
|
2756
3508
|
"role: dialog",
|
|
3509
|
+
"aria_modal: false \u2014 the overlay is non-modal and does not trap focus",
|
|
2757
3510
|
"trigger_aria_haspopup: dialog",
|
|
2758
3511
|
"trigger_aria_expanded: true",
|
|
2759
|
-
"
|
|
3512
|
+
"trigger_aria_controls_when_open: true",
|
|
3513
|
+
"overlay_labelled_by_month_caption: true",
|
|
3514
|
+
"calendar_uses_grid_roles: true",
|
|
3515
|
+
"day_buttons_use_roving_tabindex: true",
|
|
3516
|
+
"day_buttons_aria_pressed_when_selected: true",
|
|
3517
|
+
"gridcell_aria_selected: true",
|
|
3518
|
+
"weekday_row_aria_hidden: true",
|
|
3519
|
+
"time_selects_have_aria_labels: true",
|
|
3520
|
+
"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.",
|
|
2760
3521
|
"keyboard_calendar_navigation: true",
|
|
2761
3522
|
"escape_closes_overlay: true",
|
|
2762
3523
|
"aria_invalid_when_invalid: true",
|
|
@@ -2766,7 +3527,21 @@ var treeui_catalog_default = {
|
|
|
2766
3527
|
"controlled_and_uncontrolled_open: true",
|
|
2767
3528
|
"value_format: YYYY-MM-DDTHH:mm",
|
|
2768
3529
|
"min_and_max_limit_available_values: true",
|
|
2769
|
-
"time_options_generated_from_step: true"
|
|
3530
|
+
"time_options_generated_from_step: true",
|
|
3531
|
+
"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.",
|
|
3532
|
+
"apply_emit_order: update:modelValue, then change, then select \u2014 all carrying the same `YYYY-MM-DDTHH:mm` string.",
|
|
3533
|
+
"clear_emits_empty_string: Clear emits update:modelValue, change, and select with `''`, then closes.",
|
|
3534
|
+
"default_draft_when_value_is_empty: Now, rounded UP to the next `step` boundary (minimum 60s) with seconds zeroed, then clamped into min/max.",
|
|
3535
|
+
"draft_resyncs_from_model_value_only_while_closed: true",
|
|
3536
|
+
"draft_is_clamped_into_min_max_on_open_and_on_day_select: true",
|
|
3537
|
+
"minute_options_always_include_the_current_draft_minute: true",
|
|
3538
|
+
"hour_option_disabled_when_no_minute_in_that_hour_is_available: true",
|
|
3539
|
+
"month_nav_buttons_disabled_at_min_max_month: true",
|
|
3540
|
+
"out_of_range_days_disabled: true",
|
|
3541
|
+
"outside_pointerdown_closes: true",
|
|
3542
|
+
"overlay_is_not_rendered_while_disabled: true",
|
|
3543
|
+
"hidden_input_created_when_name_attr_present: true",
|
|
3544
|
+
"open_state_emits_are_deduped: true"
|
|
2770
3545
|
],
|
|
2771
3546
|
selection: {
|
|
2772
3547
|
keywords: [
|
|
@@ -2799,14 +3574,15 @@ var treeui_catalog_default = {
|
|
|
2799
3574
|
},
|
|
2800
3575
|
recipes: [
|
|
2801
3576
|
"date-range-form"
|
|
2802
|
-
]
|
|
3577
|
+
],
|
|
3578
|
+
practices: []
|
|
2803
3579
|
},
|
|
2804
3580
|
{
|
|
2805
3581
|
name: "TDivider",
|
|
2806
3582
|
aliases: [],
|
|
2807
3583
|
package: "@treeui/vue",
|
|
2808
3584
|
category: "Layout",
|
|
2809
|
-
description:
|
|
3585
|
+
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',
|
|
2810
3586
|
sourceFile: "packages/vue/src/components/TDivider.vue",
|
|
2811
3587
|
storyFile: "apps/docs/src/stories/Divider.stories.ts",
|
|
2812
3588
|
storyTitle: "Components/Layout/Divider",
|
|
@@ -2814,34 +3590,41 @@ var treeui_catalog_default = {
|
|
|
2814
3590
|
props: [
|
|
2815
3591
|
{
|
|
2816
3592
|
name: "orientation",
|
|
2817
|
-
type: "
|
|
3593
|
+
type: '"horizontal" | "vertical"',
|
|
2818
3594
|
default: "horizontal",
|
|
2819
3595
|
values: [
|
|
2820
3596
|
"horizontal",
|
|
2821
3597
|
"vertical"
|
|
2822
|
-
]
|
|
3598
|
+
],
|
|
3599
|
+
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"
|
|
2823
3600
|
},
|
|
2824
3601
|
{
|
|
2825
3602
|
name: "decorative",
|
|
2826
3603
|
type: "boolean",
|
|
2827
3604
|
default: "true",
|
|
2828
|
-
description:
|
|
3605
|
+
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'
|
|
2829
3606
|
},
|
|
2830
3607
|
{
|
|
2831
3608
|
name: "label",
|
|
2832
3609
|
type: "string",
|
|
2833
3610
|
required: false,
|
|
2834
|
-
description:
|
|
3611
|
+
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'
|
|
2835
3612
|
}
|
|
2836
3613
|
],
|
|
2837
3614
|
events: [],
|
|
2838
3615
|
slots: [],
|
|
2839
3616
|
a11y: [
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
"aria-label: Set from `label` prop when non-decorative."
|
|
3617
|
+
'role: "none" when decorative (the default), "separator" when `decorative` is false.',
|
|
3618
|
+
'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.',
|
|
3619
|
+
"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).",
|
|
3620
|
+
'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.'
|
|
3621
|
+
],
|
|
3622
|
+
behavior: [
|
|
3623
|
+
"Renders a native <hr> element as its single root node.",
|
|
3624
|
+
"Extra attrs and class/style fall through to that <hr> (attribute inheritance is not disabled).",
|
|
3625
|
+
"Applies exactly two classes; no state, size, or variant modifiers exist.",
|
|
3626
|
+
"A vertical divider needs a flex or grid parent to have any height."
|
|
2843
3627
|
],
|
|
2844
|
-
behavior: [],
|
|
2845
3628
|
selection: {
|
|
2846
3629
|
keywords: [],
|
|
2847
3630
|
useWhen: [],
|
|
@@ -2852,7 +3635,8 @@ var treeui_catalog_default = {
|
|
|
2852
3635
|
required: [],
|
|
2853
3636
|
notes: []
|
|
2854
3637
|
},
|
|
2855
|
-
recipes: []
|
|
3638
|
+
recipes: [],
|
|
3639
|
+
practices: []
|
|
2856
3640
|
},
|
|
2857
3641
|
{
|
|
2858
3642
|
name: "TDonutChart",
|
|
@@ -2871,67 +3655,73 @@ var treeui_catalog_default = {
|
|
|
2871
3655
|
name: "segments",
|
|
2872
3656
|
type: "TDonutSegment[]",
|
|
2873
3657
|
default: "[]",
|
|
2874
|
-
note: "Each item is { label: string; value: number; color?: string }.
|
|
3658
|
+
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."
|
|
2875
3659
|
},
|
|
2876
3660
|
{
|
|
2877
3661
|
name: "size",
|
|
2878
3662
|
type: "number",
|
|
2879
3663
|
default: "200",
|
|
2880
|
-
note: "Square canvas in px."
|
|
3664
|
+
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."
|
|
2881
3665
|
},
|
|
2882
3666
|
{
|
|
2883
3667
|
name: "thickness",
|
|
2884
3668
|
type: "number",
|
|
2885
3669
|
default: "26",
|
|
2886
|
-
note: "Ring thickness
|
|
3670
|
+
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."
|
|
2887
3671
|
},
|
|
2888
3672
|
{
|
|
2889
3673
|
name: "gap",
|
|
2890
3674
|
type: "number",
|
|
2891
3675
|
default: "2",
|
|
2892
|
-
note: "Gap between slices, in degrees."
|
|
3676
|
+
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."
|
|
2893
3677
|
},
|
|
2894
3678
|
{
|
|
2895
3679
|
name: "rounded",
|
|
2896
3680
|
type: "boolean",
|
|
2897
3681
|
default: "false",
|
|
2898
|
-
note: "Round the ends of donut segments (widens the gap to make room). Best with a thinner ring."
|
|
3682
|
+
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."
|
|
2899
3683
|
},
|
|
2900
3684
|
{
|
|
2901
3685
|
name: "showLegend",
|
|
2902
3686
|
type: "boolean",
|
|
2903
|
-
default: "true"
|
|
3687
|
+
default: "true",
|
|
3688
|
+
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."
|
|
2904
3689
|
},
|
|
2905
3690
|
{
|
|
2906
3691
|
name: "showPercent",
|
|
2907
3692
|
type: "boolean",
|
|
2908
|
-
default: "true"
|
|
3693
|
+
default: "true",
|
|
3694
|
+
note: "Legend only. Percentages are rounded to whole numbers, so they may not sum to exactly 100%."
|
|
2909
3695
|
},
|
|
2910
3696
|
{
|
|
2911
3697
|
name: "centerLabel",
|
|
2912
3698
|
type: "string",
|
|
2913
|
-
default: "
|
|
2914
|
-
note: "Donut only;
|
|
3699
|
+
default: "undefined",
|
|
3700
|
+
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."
|
|
2915
3701
|
},
|
|
2916
3702
|
{
|
|
2917
3703
|
name: "centerValue",
|
|
2918
3704
|
type: "string | number",
|
|
2919
|
-
default: "
|
|
3705
|
+
default: "undefined",
|
|
3706
|
+
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."
|
|
2920
3707
|
},
|
|
2921
3708
|
{
|
|
2922
3709
|
name: "valueFormat",
|
|
2923
3710
|
type: "(value: number) => string",
|
|
2924
|
-
default: "locale integers for |value| >= 1000"
|
|
3711
|
+
default: "locale integers for |value| >= 1000",
|
|
3712
|
+
note: "Applies to the legend values and to the center value. Not applied to percentages, nor to an explicitly supplied centerValue."
|
|
2925
3713
|
},
|
|
2926
3714
|
{
|
|
2927
3715
|
name: "loading",
|
|
2928
3716
|
type: "boolean",
|
|
2929
|
-
default: "false"
|
|
3717
|
+
default: "false",
|
|
3718
|
+
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."
|
|
2930
3719
|
},
|
|
2931
3720
|
{
|
|
2932
3721
|
name: "ariaLabel",
|
|
2933
3722
|
type: "string",
|
|
2934
|
-
default: "auto-generated summary"
|
|
3723
|
+
default: "auto-generated summary ('Donut chart with <n> segments' / 'Pie chart with <n> segments')",
|
|
3724
|
+
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.'
|
|
2935
3725
|
}
|
|
2936
3726
|
],
|
|
2937
3727
|
events: [],
|
|
@@ -2944,13 +3734,20 @@ var treeui_catalog_default = {
|
|
|
2944
3734
|
}
|
|
2945
3735
|
],
|
|
2946
3736
|
a11y: [
|
|
2947
|
-
"
|
|
2948
|
-
"Legend + percentages give a non-visual reading of each slice."
|
|
3737
|
+
"The inner <svg> carries role=img plus the ariaLabel (or the auto-generated summary); the root div has no role or accessible name.",
|
|
3738
|
+
"Legend + percentages give a non-visual reading of each slice.",
|
|
3739
|
+
"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.",
|
|
3740
|
+
"Legend swatches are aria-hidden, so color is never the only carrier of identity.",
|
|
3741
|
+
"Provide a meaningful ariaLabel describing what the chart shows."
|
|
2949
3742
|
],
|
|
2950
3743
|
behavior: [
|
|
2951
|
-
"colors_auto_assign_from_chart_palette: --tree-color-chart-1..8, cycling; per-segment color overrides",
|
|
2952
|
-
"hovering_a_slice_dims_the_rest_and_updates_center:
|
|
2953
|
-
"
|
|
3744
|
+
"colors_auto_assign_from_chart_palette: --tree-color-chart-1..8, cycling by visible-segment index; per-segment color overrides",
|
|
3745
|
+
"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",
|
|
3746
|
+
"hovering_a_legend_row_drives_the_same_highlight: legend items carry the same pointerenter/pointerleave handlers as the segments",
|
|
3747
|
+
"center_readout_precedence: hovered segment > centerValue > formatted total; the label half is hovered segment label > centerLabel > 'Total'",
|
|
3748
|
+
"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",
|
|
3749
|
+
"empty_state_when_no_visible_segment_has_value: total <= 0 renders the empty slot instead of the svg; loading wins over it",
|
|
3750
|
+
"segments_fade_in_staggered: 70ms animation delay per segment index; removed under prefers-reduced-motion"
|
|
2954
3751
|
],
|
|
2955
3752
|
selection: {
|
|
2956
3753
|
keywords: [
|
|
@@ -2988,7 +3785,8 @@ var treeui_catalog_default = {
|
|
|
2988
3785
|
},
|
|
2989
3786
|
recipes: [
|
|
2990
3787
|
"metric-dashboard"
|
|
2991
|
-
]
|
|
3788
|
+
],
|
|
3789
|
+
practices: []
|
|
2992
3790
|
},
|
|
2993
3791
|
{
|
|
2994
3792
|
name: "TDrawer",
|
|
@@ -3006,17 +3804,20 @@ var treeui_catalog_default = {
|
|
|
3006
3804
|
{
|
|
3007
3805
|
name: "open",
|
|
3008
3806
|
type: "boolean",
|
|
3009
|
-
default: "controlled_optional"
|
|
3807
|
+
default: "controlled_optional",
|
|
3808
|
+
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."
|
|
3010
3809
|
},
|
|
3011
3810
|
{
|
|
3012
3811
|
name: "defaultOpen",
|
|
3013
3812
|
type: "boolean",
|
|
3014
|
-
default: "false"
|
|
3813
|
+
default: "false",
|
|
3814
|
+
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."
|
|
3015
3815
|
},
|
|
3016
3816
|
{
|
|
3017
3817
|
name: "disabled",
|
|
3018
3818
|
type: "boolean",
|
|
3019
|
-
default: "false"
|
|
3819
|
+
default: "false",
|
|
3820
|
+
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."
|
|
3020
3821
|
},
|
|
3021
3822
|
{
|
|
3022
3823
|
name: "size",
|
|
@@ -3026,7 +3827,8 @@ var treeui_catalog_default = {
|
|
|
3026
3827
|
"sm",
|
|
3027
3828
|
"md",
|
|
3028
3829
|
"lg"
|
|
3029
|
-
]
|
|
3830
|
+
],
|
|
3831
|
+
note: "Applied as `t-drawer__surface--<size>`. Sizes the cross axis of the panel: width for `side: left | right`, height for `side: top | bottom`."
|
|
3030
3832
|
},
|
|
3031
3833
|
{
|
|
3032
3834
|
name: "side",
|
|
@@ -3037,42 +3839,50 @@ var treeui_catalog_default = {
|
|
|
3037
3839
|
"right",
|
|
3038
3840
|
"bottom",
|
|
3039
3841
|
"left"
|
|
3040
|
-
]
|
|
3842
|
+
],
|
|
3843
|
+
note: "Applied as `t-drawer__surface--<side>`. Also selects the slide-in translate direction and which corners are rounded."
|
|
3041
3844
|
},
|
|
3042
3845
|
{
|
|
3043
3846
|
name: "title",
|
|
3044
3847
|
type: "string",
|
|
3045
|
-
default: ""
|
|
3848
|
+
default: "",
|
|
3849
|
+
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."
|
|
3046
3850
|
},
|
|
3047
3851
|
{
|
|
3048
3852
|
name: "description",
|
|
3049
3853
|
type: "string",
|
|
3050
|
-
default: ""
|
|
3854
|
+
default: "",
|
|
3855
|
+
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."
|
|
3051
3856
|
},
|
|
3052
3857
|
{
|
|
3053
3858
|
name: "closeOnEscape",
|
|
3054
3859
|
type: "boolean",
|
|
3055
|
-
default: "true"
|
|
3860
|
+
default: "true",
|
|
3861
|
+
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."
|
|
3056
3862
|
},
|
|
3057
3863
|
{
|
|
3058
3864
|
name: "closeOnOverlay",
|
|
3059
3865
|
type: "boolean",
|
|
3060
|
-
default: "true"
|
|
3866
|
+
default: "true",
|
|
3867
|
+
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."
|
|
3061
3868
|
},
|
|
3062
3869
|
{
|
|
3063
3870
|
name: "showCloseButton",
|
|
3064
3871
|
type: "boolean",
|
|
3065
|
-
default: "true"
|
|
3872
|
+
default: "true",
|
|
3873
|
+
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."
|
|
3066
3874
|
},
|
|
3067
3875
|
{
|
|
3068
3876
|
name: "closeLabel",
|
|
3069
3877
|
type: "string",
|
|
3070
|
-
default: "Close drawer"
|
|
3878
|
+
default: "Close drawer",
|
|
3879
|
+
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."
|
|
3071
3880
|
},
|
|
3072
3881
|
{
|
|
3073
3882
|
name: "id",
|
|
3074
3883
|
type: "string",
|
|
3075
|
-
default: "auto"
|
|
3884
|
+
default: "auto",
|
|
3885
|
+
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."
|
|
3076
3886
|
}
|
|
3077
3887
|
],
|
|
3078
3888
|
events: [
|
|
@@ -3085,34 +3895,53 @@ var treeui_catalog_default = {
|
|
|
3085
3895
|
],
|
|
3086
3896
|
slots: [
|
|
3087
3897
|
{
|
|
3088
|
-
name: "trigger"
|
|
3898
|
+
name: "trigger",
|
|
3899
|
+
description: "Element that opens the drawer on click. Omit for controlled or imperative use."
|
|
3089
3900
|
},
|
|
3090
3901
|
{
|
|
3091
|
-
name: "header"
|
|
3902
|
+
name: "header",
|
|
3903
|
+
description: "Replaces the default title heading in the topbar."
|
|
3092
3904
|
},
|
|
3093
3905
|
{
|
|
3094
|
-
name: "default"
|
|
3906
|
+
name: "default",
|
|
3907
|
+
description: "Drawer body content."
|
|
3095
3908
|
},
|
|
3096
3909
|
{
|
|
3097
|
-
name: "content"
|
|
3910
|
+
name: "content",
|
|
3911
|
+
description: "Drawer body content; takes precedence over the default slot."
|
|
3098
3912
|
},
|
|
3099
3913
|
{
|
|
3100
|
-
name: "footer"
|
|
3914
|
+
name: "footer",
|
|
3915
|
+
description: "Action row pinned under the body."
|
|
3101
3916
|
}
|
|
3102
3917
|
],
|
|
3103
3918
|
a11y: [
|
|
3104
3919
|
"role: dialog",
|
|
3105
3920
|
"aria_modal: true",
|
|
3106
3921
|
"focus_trap: true",
|
|
3107
|
-
|
|
3108
|
-
"escape_closes_when_enabled: true"
|
|
3922
|
+
'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"}',
|
|
3923
|
+
"escape_closes_when_enabled: true",
|
|
3924
|
+
"escape_scope: The keydown listener lives on the surface, so Escape only closes while focus is inside the drawer.",
|
|
3925
|
+
"accessible_name_source: the `t-drawer__header` div, via aria-labelledby; unset when `title` is empty and no `header` slot is supplied",
|
|
3926
|
+
"accessible_description_source: the `description` prop, via aria-describedby; the body slots are not included",
|
|
3927
|
+
'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.',
|
|
3928
|
+
"backdrop_marked_aria_hidden: true",
|
|
3929
|
+
"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."
|
|
3109
3930
|
],
|
|
3110
3931
|
behavior: [
|
|
3111
3932
|
"uses_teleport_to_body: true",
|
|
3112
3933
|
"locks_body_scroll_while_open: true",
|
|
3113
3934
|
"overlay_click_closes_when_enabled: true",
|
|
3114
3935
|
"close_button_optional: true",
|
|
3115
|
-
"slides_in_from_side: true"
|
|
3936
|
+
"slides_in_from_side: true",
|
|
3937
|
+
"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.",
|
|
3938
|
+
"topbar_rendered_when: title is non-empty OR the `header` slot is supplied OR showCloseButton is true",
|
|
3939
|
+
"body_slot_precedence: content > default",
|
|
3940
|
+
"footer_rendered_when: the `footer` slot is supplied",
|
|
3941
|
+
'data_state_attribute: `data-state="open" | "closed"` on both the `t-drawer` root and the `t-drawer__portal`',
|
|
3942
|
+
"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.",
|
|
3943
|
+
'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"}',
|
|
3944
|
+
'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"}'
|
|
3116
3945
|
],
|
|
3117
3946
|
selection: {
|
|
3118
3947
|
keywords: [
|
|
@@ -3141,7 +3970,10 @@ var treeui_catalog_default = {
|
|
|
3141
3970
|
required: [],
|
|
3142
3971
|
notes: []
|
|
3143
3972
|
},
|
|
3144
|
-
recipes: []
|
|
3973
|
+
recipes: [],
|
|
3974
|
+
practices: [
|
|
3975
|
+
"accessible-by-default"
|
|
3976
|
+
]
|
|
3145
3977
|
},
|
|
3146
3978
|
{
|
|
3147
3979
|
name: "TDropdown",
|
|
@@ -3160,22 +3992,25 @@ var treeui_catalog_default = {
|
|
|
3160
3992
|
name: "items",
|
|
3161
3993
|
type: "TDropdownItem[]",
|
|
3162
3994
|
default: "[]",
|
|
3163
|
-
note:
|
|
3995
|
+
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.'
|
|
3164
3996
|
},
|
|
3165
3997
|
{
|
|
3166
3998
|
name: "open",
|
|
3167
3999
|
type: "boolean",
|
|
3168
|
-
default: "undefined"
|
|
4000
|
+
default: "undefined",
|
|
4001
|
+
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."
|
|
3169
4002
|
},
|
|
3170
4003
|
{
|
|
3171
4004
|
name: "defaultOpen",
|
|
3172
4005
|
type: "boolean",
|
|
3173
|
-
default: "false"
|
|
4006
|
+
default: "false",
|
|
4007
|
+
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."
|
|
3174
4008
|
},
|
|
3175
4009
|
{
|
|
3176
4010
|
name: "disabled",
|
|
3177
4011
|
type: "boolean",
|
|
3178
|
-
default: "false"
|
|
4012
|
+
default: "false",
|
|
4013
|
+
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.'
|
|
3179
4014
|
},
|
|
3180
4015
|
{
|
|
3181
4016
|
name: "size",
|
|
@@ -3185,12 +4020,14 @@ var treeui_catalog_default = {
|
|
|
3185
4020
|
"sm",
|
|
3186
4021
|
"md",
|
|
3187
4022
|
"lg"
|
|
3188
|
-
]
|
|
4023
|
+
],
|
|
4024
|
+
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."
|
|
3189
4025
|
},
|
|
3190
4026
|
{
|
|
3191
4027
|
name: "label",
|
|
3192
4028
|
type: "string",
|
|
3193
|
-
default: ""
|
|
4029
|
+
default: "",
|
|
4030
|
+
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.'
|
|
3194
4031
|
},
|
|
3195
4032
|
{
|
|
3196
4033
|
name: "align",
|
|
@@ -3200,18 +4037,30 @@ var treeui_catalog_default = {
|
|
|
3200
4037
|
"start",
|
|
3201
4038
|
"end"
|
|
3202
4039
|
],
|
|
3203
|
-
note: "Horizontal alignment of the menu relative to the trigger
|
|
4040
|
+
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`."
|
|
4041
|
+
},
|
|
4042
|
+
{
|
|
4043
|
+
name: "id",
|
|
4044
|
+
type: "string",
|
|
4045
|
+
default: "undefined",
|
|
4046
|
+
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."
|
|
3204
4047
|
}
|
|
3205
4048
|
],
|
|
3206
4049
|
events: [
|
|
3207
4050
|
{
|
|
3208
|
-
name: "select"
|
|
4051
|
+
name: "select",
|
|
4052
|
+
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.",
|
|
4053
|
+
payload: '[{"value":"string"}]'
|
|
3209
4054
|
},
|
|
3210
4055
|
{
|
|
3211
|
-
name: "update:open"
|
|
4056
|
+
name: "update:open",
|
|
4057
|
+
description: "Emitted whenever the open state changes. Deduped \u2014 no emit when the next value equals the current one.",
|
|
4058
|
+
payload: '["boolean"]'
|
|
3212
4059
|
},
|
|
3213
4060
|
{
|
|
3214
|
-
name: "open-change"
|
|
4061
|
+
name: "open-change",
|
|
4062
|
+
description: "Emitted immediately after `update:open`, with the same payload. Alias for consumers that do not use v-model:open.",
|
|
4063
|
+
payload: '["boolean"]'
|
|
3215
4064
|
}
|
|
3216
4065
|
],
|
|
3217
4066
|
slots: [
|
|
@@ -3224,23 +4073,39 @@ var treeui_catalog_default = {
|
|
|
3224
4073
|
],
|
|
3225
4074
|
a11y: [
|
|
3226
4075
|
"role: menu",
|
|
4076
|
+
"menu_accessible_name_comes_from_the_label_prop: true",
|
|
3227
4077
|
"trigger_aria_haspopup: menu",
|
|
3228
4078
|
"trigger_aria_expanded: true",
|
|
3229
4079
|
"trigger_aria_controls: menu id, while open",
|
|
4080
|
+
"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.",
|
|
4081
|
+
"item_role: menuitem",
|
|
3230
4082
|
"aria_disabled_on_disabled_items: true",
|
|
4083
|
+
"disabled_items_get_tabindex_minus_1_but_stay_programmatically_focusable: true",
|
|
3231
4084
|
"focus_visible_on_trigger: true",
|
|
4085
|
+
"items_receive_real_dom_focus_no_aria_activedescendant: true",
|
|
3232
4086
|
"keyboard_arrow_navigation: true",
|
|
4087
|
+
"arrow_navigation_skips_disabled_items: true",
|
|
4088
|
+
"arrow_navigation_does_not_wrap_at_the_ends: true",
|
|
4089
|
+
"arrow_down_or_arrow_up_on_the_trigger_both_open_at_the_first_enabled_item: true",
|
|
3233
4090
|
"escape_closes_menu: true",
|
|
3234
4091
|
"enter_space_selects_item: true",
|
|
3235
|
-
"home_end_navigation: true"
|
|
4092
|
+
"home_end_navigation: true",
|
|
4093
|
+
"no_typeahead: true",
|
|
4094
|
+
"tab_does_not_close_the_menu: true"
|
|
3236
4095
|
],
|
|
3237
4096
|
behavior: [
|
|
3238
|
-
|
|
4097
|
+
'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"}',
|
|
3239
4098
|
"outside_click_restores_focus: false",
|
|
3240
4099
|
"chevron_rotates_when_open: true",
|
|
3241
4100
|
"menu_grows_to_fit_items_without_wrapping: true",
|
|
3242
|
-
"
|
|
3243
|
-
|
|
4101
|
+
"menu_scrolls_vertically_past_15rem: true",
|
|
4102
|
+
"menu_renders_in_flow_with_no_portal_and_no_flip_positioning: true",
|
|
4103
|
+
"menu_is_not_rendered_while_disabled: true",
|
|
4104
|
+
"open_state_emits_are_deduped: true",
|
|
4105
|
+
"controlled_open_requires_writing_the_value_back: true",
|
|
4106
|
+
'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"}',
|
|
4107
|
+
'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"}',
|
|
4108
|
+
'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}'
|
|
3244
4109
|
],
|
|
3245
4110
|
selection: {
|
|
3246
4111
|
keywords: [
|
|
@@ -3269,7 +4134,11 @@ var treeui_catalog_default = {
|
|
|
3269
4134
|
required: [],
|
|
3270
4135
|
notes: []
|
|
3271
4136
|
},
|
|
3272
|
-
recipes: []
|
|
4137
|
+
recipes: [],
|
|
4138
|
+
practices: [
|
|
4139
|
+
"interaction-feedback",
|
|
4140
|
+
"accessible-by-default"
|
|
4141
|
+
]
|
|
3273
4142
|
},
|
|
3274
4143
|
{
|
|
3275
4144
|
name: "TEmptyState",
|
|
@@ -3361,7 +4230,10 @@ var treeui_catalog_default = {
|
|
|
3361
4230
|
required: [],
|
|
3362
4231
|
notes: []
|
|
3363
4232
|
},
|
|
3364
|
-
recipes: []
|
|
4233
|
+
recipes: [],
|
|
4234
|
+
practices: [
|
|
4235
|
+
"state-clarity"
|
|
4236
|
+
]
|
|
3365
4237
|
},
|
|
3366
4238
|
{
|
|
3367
4239
|
name: "TFileUpload",
|
|
@@ -3395,7 +4267,7 @@ var treeui_catalog_default = {
|
|
|
3395
4267
|
name: "disabled",
|
|
3396
4268
|
type: "boolean",
|
|
3397
4269
|
default: "false",
|
|
3398
|
-
description: "The ONLY prop that gates interaction. Disables the dropzone, the native input, Clear all, and every per-row Remove/Retry."
|
|
4270
|
+
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."
|
|
3399
4271
|
},
|
|
3400
4272
|
{
|
|
3401
4273
|
name: "loading",
|
|
@@ -3420,13 +4292,15 @@ var treeui_catalog_default = {
|
|
|
3420
4292
|
},
|
|
3421
4293
|
{
|
|
3422
4294
|
name: "maxFiles",
|
|
3423
|
-
type: "number",
|
|
3424
|
-
default: "
|
|
4295
|
+
type: "number | null",
|
|
4296
|
+
default: "null",
|
|
4297
|
+
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."
|
|
3425
4298
|
},
|
|
3426
4299
|
{
|
|
3427
4300
|
name: "maxFileSize",
|
|
3428
|
-
type: "number",
|
|
3429
|
-
default: "
|
|
4301
|
+
type: "number | null",
|
|
4302
|
+
default: "null",
|
|
4303
|
+
description: "Per-file byte cap. Enforced only when it is a number greater than 0 \u2014 both `null` and `0` disable the check."
|
|
3430
4304
|
},
|
|
3431
4305
|
{
|
|
3432
4306
|
name: "label",
|
|
@@ -3606,13 +4480,138 @@ var treeui_catalog_default = {
|
|
|
3606
4480
|
alternatives: []
|
|
3607
4481
|
},
|
|
3608
4482
|
setup: {
|
|
3609
|
-
required: [],
|
|
4483
|
+
required: [],
|
|
4484
|
+
notes: [
|
|
4485
|
+
"Bind `modelValue` to `File[]`.",
|
|
4486
|
+
"Use `accept`, `multiple`, and size limits in the app layer to constrain uploads."
|
|
4487
|
+
]
|
|
4488
|
+
},
|
|
4489
|
+
recipes: [],
|
|
4490
|
+
practices: []
|
|
4491
|
+
},
|
|
4492
|
+
{
|
|
4493
|
+
name: "TFlag",
|
|
4494
|
+
aliases: [],
|
|
4495
|
+
package: "@treeui/vue",
|
|
4496
|
+
kind: "display",
|
|
4497
|
+
category: "Data Display",
|
|
4498
|
+
status: "available",
|
|
4499
|
+
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.",
|
|
4500
|
+
sourceFile: "packages/vue/src/components/TFlag.vue",
|
|
4501
|
+
storyFile: "apps/docs/src/stories/Flag.stories.ts",
|
|
4502
|
+
storyTitle: "Components/Data Display/Flag",
|
|
4503
|
+
manifestFile: "docs/ai/COMPONENTS/flag.yaml",
|
|
4504
|
+
props: [
|
|
4505
|
+
{
|
|
4506
|
+
name: "code",
|
|
4507
|
+
type: "string",
|
|
4508
|
+
required: true,
|
|
4509
|
+
description: "ISO 3166-1 alpha-2 country code. Case-insensitive \u2014 trimmed and lowercased before the URL is built."
|
|
4510
|
+
},
|
|
4511
|
+
{
|
|
4512
|
+
name: "baseUrl",
|
|
4513
|
+
type: "string",
|
|
4514
|
+
default: "https://flagcdn.com",
|
|
4515
|
+
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."
|
|
4516
|
+
},
|
|
4517
|
+
{
|
|
4518
|
+
name: "size",
|
|
4519
|
+
type: "TSize",
|
|
4520
|
+
default: "md",
|
|
4521
|
+
values: [
|
|
4522
|
+
"sm",
|
|
4523
|
+
"md",
|
|
4524
|
+
"lg"
|
|
4525
|
+
],
|
|
4526
|
+
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`."
|
|
4527
|
+
},
|
|
4528
|
+
{
|
|
4529
|
+
name: "label",
|
|
4530
|
+
type: "string",
|
|
4531
|
+
default: "undefined",
|
|
4532
|
+
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.'
|
|
4533
|
+
},
|
|
4534
|
+
{
|
|
4535
|
+
name: "fallbackText",
|
|
4536
|
+
type: "string",
|
|
4537
|
+
default: "undefined",
|
|
4538
|
+
description: 'Text shown when the image cannot load. Defaults to the normalized `code` uppercased, so a padded `" br "` falls back to `BR`.'
|
|
4539
|
+
}
|
|
4540
|
+
],
|
|
4541
|
+
events: [],
|
|
4542
|
+
slots: [],
|
|
4543
|
+
a11y: [
|
|
4544
|
+
"decorative_by_default: true",
|
|
4545
|
+
"becomes_image_when_labeled: true",
|
|
4546
|
+
'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.',
|
|
4547
|
+
'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.',
|
|
4548
|
+
'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.',
|
|
4549
|
+
"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."
|
|
4550
|
+
],
|
|
4551
|
+
behavior: [
|
|
4552
|
+
"falls_back_to_text_when_image_fails: true",
|
|
4553
|
+
"failed_state_resets_when_resolved_src_changes: true",
|
|
4554
|
+
"code_is_trimmed_and_lowercased: true",
|
|
4555
|
+
"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.",
|
|
4556
|
+
"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.",
|
|
4557
|
+
"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.",
|
|
4558
|
+
"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.",
|
|
4559
|
+
"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.",
|
|
4560
|
+
"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.",
|
|
4561
|
+
"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).",
|
|
4562
|
+
"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`.",
|
|
4563
|
+
"no_country_or_locale_dataset_is_shipped: TreeUI never maps a language or locale to a country code \u2014 the application owns that decision."
|
|
4564
|
+
],
|
|
4565
|
+
selection: {
|
|
4566
|
+
keywords: [
|
|
4567
|
+
"flag",
|
|
4568
|
+
"country flag",
|
|
4569
|
+
"country",
|
|
4570
|
+
"nationality",
|
|
4571
|
+
"region",
|
|
4572
|
+
"iso 3166",
|
|
4573
|
+
"alpha-2"
|
|
4574
|
+
],
|
|
4575
|
+
useWhen: [
|
|
4576
|
+
"You need a country flag rendered from an ISO 3166-1 alpha-2 code.",
|
|
4577
|
+
"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.",
|
|
4578
|
+
"You want a text fallback when the flag asset cannot load."
|
|
4579
|
+
],
|
|
4580
|
+
avoidWhen: [
|
|
4581
|
+
"The flag would be the only carrier of meaning \u2014 always pair it with adjacent text such as the language or country name.",
|
|
4582
|
+
"You need an interface glyph rather than a country flag.",
|
|
4583
|
+
"You are treating the flag as a language identity \u2014 a flag names a country, not a language."
|
|
4584
|
+
],
|
|
4585
|
+
alternatives: [
|
|
4586
|
+
{
|
|
4587
|
+
component: "TIcon",
|
|
4588
|
+
when: "The graphic is a registered TreeUI icon, not a country flag."
|
|
4589
|
+
},
|
|
4590
|
+
{
|
|
4591
|
+
component: "TLanguageSelect",
|
|
4592
|
+
when: "The flag belongs to a language or locale picker rather than standing alone."
|
|
4593
|
+
}
|
|
4594
|
+
]
|
|
4595
|
+
},
|
|
4596
|
+
setup: {
|
|
4597
|
+
required: [
|
|
4598
|
+
"Pass `code` as an ISO 3166-1 alpha-2 country code. Matching is case-insensitive \u2014 the value is trimmed and lowercased internally.",
|
|
4599
|
+
"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."
|
|
4600
|
+
],
|
|
3610
4601
|
notes: [
|
|
3611
|
-
"
|
|
3612
|
-
"
|
|
4602
|
+
"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`.",
|
|
4603
|
+
"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.",
|
|
4604
|
+
"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.",
|
|
4605
|
+
"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.",
|
|
4606
|
+
"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.",
|
|
4607
|
+
"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.",
|
|
4608
|
+
"`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.",
|
|
4609
|
+
"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`.",
|
|
4610
|
+
"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."
|
|
3613
4611
|
]
|
|
3614
4612
|
},
|
|
3615
|
-
recipes: []
|
|
4613
|
+
recipes: [],
|
|
4614
|
+
practices: []
|
|
3616
4615
|
},
|
|
3617
4616
|
{
|
|
3618
4617
|
name: "TFormField",
|
|
@@ -3741,7 +4740,12 @@ var treeui_catalog_default = {
|
|
|
3741
4740
|
"date-range-form",
|
|
3742
4741
|
"color-field",
|
|
3743
4742
|
"tag-input",
|
|
3744
|
-
"hierarchy-picker"
|
|
4743
|
+
"hierarchy-picker",
|
|
4744
|
+
"language-switcher"
|
|
4745
|
+
],
|
|
4746
|
+
practices: [
|
|
4747
|
+
"accessible-by-default",
|
|
4748
|
+
"content-alignment"
|
|
3745
4749
|
]
|
|
3746
4750
|
},
|
|
3747
4751
|
{
|
|
@@ -3843,6 +4847,9 @@ var treeui_catalog_default = {
|
|
|
3843
4847
|
"date-range-form",
|
|
3844
4848
|
"stat-grid",
|
|
3845
4849
|
"metric-dashboard"
|
|
4850
|
+
],
|
|
4851
|
+
practices: [
|
|
4852
|
+
"content-alignment"
|
|
3846
4853
|
]
|
|
3847
4854
|
},
|
|
3848
4855
|
{
|
|
@@ -3863,24 +4870,380 @@ var treeui_catalog_default = {
|
|
|
3863
4870
|
type: "TIconName",
|
|
3864
4871
|
required: true,
|
|
3865
4872
|
values: [
|
|
4873
|
+
"account",
|
|
4874
|
+
"activity",
|
|
4875
|
+
"ai-studio",
|
|
3866
4876
|
"alert-circle",
|
|
4877
|
+
"align-left",
|
|
4878
|
+
"app-window",
|
|
4879
|
+
"apps-grid",
|
|
4880
|
+
"archive",
|
|
4881
|
+
"archive-restore",
|
|
4882
|
+
"arrow-down",
|
|
4883
|
+
"arrow-left",
|
|
4884
|
+
"arrow-left-right",
|
|
4885
|
+
"arrow-right",
|
|
4886
|
+
"arrow-up",
|
|
4887
|
+
"arrow-up-right",
|
|
4888
|
+
"assistant",
|
|
4889
|
+
"automation-key",
|
|
4890
|
+
"automations",
|
|
4891
|
+
"badge",
|
|
4892
|
+
"badge-check",
|
|
4893
|
+
"badge-star",
|
|
4894
|
+
"ban",
|
|
4895
|
+
"bell",
|
|
4896
|
+
"book-open",
|
|
4897
|
+
"bookmark",
|
|
4898
|
+
"bot",
|
|
4899
|
+
"bot-badge",
|
|
4900
|
+
"bot-users",
|
|
4901
|
+
"boxes",
|
|
4902
|
+
"boxes-model",
|
|
4903
|
+
"braces",
|
|
4904
|
+
"brackets",
|
|
4905
|
+
"brain",
|
|
4906
|
+
"brain-circuit",
|
|
4907
|
+
"brain-lock",
|
|
4908
|
+
"browser",
|
|
4909
|
+
"brush",
|
|
4910
|
+
"brush-stroke",
|
|
4911
|
+
"bug",
|
|
4912
|
+
"building-2",
|
|
4913
|
+
"calculator",
|
|
3867
4914
|
"calendar",
|
|
4915
|
+
"calendar-clock",
|
|
4916
|
+
"calendar-day",
|
|
4917
|
+
"calendar-days",
|
|
4918
|
+
"calendar-dot",
|
|
4919
|
+
"calendar-plus",
|
|
4920
|
+
"calendar-range",
|
|
4921
|
+
"calendar-x",
|
|
4922
|
+
"carousel",
|
|
4923
|
+
"catalog",
|
|
4924
|
+
"chart-column",
|
|
4925
|
+
"chart-line",
|
|
4926
|
+
"chart-pie",
|
|
4927
|
+
"chat",
|
|
3868
4928
|
"check",
|
|
3869
|
-
"
|
|
4929
|
+
"check-circle",
|
|
4930
|
+
"check-square",
|
|
3870
4931
|
"chevron-down",
|
|
4932
|
+
"chevron-left",
|
|
3871
4933
|
"chevron-right",
|
|
4934
|
+
"chevron-up",
|
|
4935
|
+
"chevron-updown",
|
|
4936
|
+
"chevrons-up-down",
|
|
4937
|
+
"circle-alert",
|
|
4938
|
+
"circle-check",
|
|
4939
|
+
"circle-dot",
|
|
4940
|
+
"circle-help",
|
|
4941
|
+
"circle-x",
|
|
4942
|
+
"clipboard-list",
|
|
4943
|
+
"clock",
|
|
4944
|
+
"clock-alert",
|
|
4945
|
+
"clock-sparkles",
|
|
4946
|
+
"clock-x",
|
|
4947
|
+
"close",
|
|
4948
|
+
"cloud",
|
|
4949
|
+
"cloud-off",
|
|
4950
|
+
"code",
|
|
4951
|
+
"code-2",
|
|
4952
|
+
"code-api",
|
|
4953
|
+
"coins",
|
|
4954
|
+
"comment",
|
|
4955
|
+
"companion",
|
|
4956
|
+
"compass",
|
|
4957
|
+
"connections",
|
|
4958
|
+
"contentpilot",
|
|
4959
|
+
"copy",
|
|
4960
|
+
"cpu",
|
|
4961
|
+
"cpu-chip",
|
|
4962
|
+
"credit-card",
|
|
4963
|
+
"crosshair",
|
|
4964
|
+
"crown",
|
|
4965
|
+
"cube",
|
|
4966
|
+
"database",
|
|
4967
|
+
"developer-settings",
|
|
4968
|
+
"device-link",
|
|
4969
|
+
"dollar-circle",
|
|
4970
|
+
"dollar-limit",
|
|
4971
|
+
"download",
|
|
4972
|
+
"download-video",
|
|
4973
|
+
"draw",
|
|
4974
|
+
"droplet",
|
|
4975
|
+
"ellipsis",
|
|
4976
|
+
"ellipsis-vertical",
|
|
4977
|
+
"embed-code",
|
|
4978
|
+
"eraser",
|
|
4979
|
+
"extension",
|
|
4980
|
+
"external-link",
|
|
4981
|
+
"eye",
|
|
4982
|
+
"eye-off",
|
|
4983
|
+
"file",
|
|
4984
|
+
"file-archive",
|
|
4985
|
+
"file-audio",
|
|
4986
|
+
"file-code",
|
|
4987
|
+
"file-edit",
|
|
4988
|
+
"file-image",
|
|
4989
|
+
"file-pdf",
|
|
4990
|
+
"file-plus",
|
|
4991
|
+
"file-scan",
|
|
4992
|
+
"file-text",
|
|
4993
|
+
"file-video",
|
|
4994
|
+
"file-warning",
|
|
4995
|
+
"files",
|
|
4996
|
+
"film",
|
|
4997
|
+
"filter",
|
|
4998
|
+
"filter-capabilities",
|
|
4999
|
+
"fingerprint",
|
|
5000
|
+
"flag",
|
|
5001
|
+
"flask-play",
|
|
5002
|
+
"folder",
|
|
5003
|
+
"folder-input",
|
|
5004
|
+
"folder-kanban",
|
|
5005
|
+
"folder-open",
|
|
5006
|
+
"folder-plus",
|
|
5007
|
+
"folder-shared",
|
|
5008
|
+
"folder-tree",
|
|
5009
|
+
"folder-x",
|
|
5010
|
+
"folders",
|
|
5011
|
+
"gauge",
|
|
5012
|
+
"gauge-high",
|
|
5013
|
+
"gauge-low",
|
|
5014
|
+
"gauge-medium",
|
|
5015
|
+
"gavel",
|
|
5016
|
+
"git-branch",
|
|
5017
|
+
"git-fork",
|
|
5018
|
+
"globe",
|
|
5019
|
+
"globe-check",
|
|
5020
|
+
"grid",
|
|
5021
|
+
"grip-vertical",
|
|
5022
|
+
"hand-check",
|
|
5023
|
+
"hard-drive",
|
|
5024
|
+
"hard-drive-alert",
|
|
5025
|
+
"hard-drive-off",
|
|
5026
|
+
"hash",
|
|
5027
|
+
"heart",
|
|
5028
|
+
"heart-chart-up",
|
|
5029
|
+
"heart-pulse",
|
|
5030
|
+
"help",
|
|
5031
|
+
"hierarchy",
|
|
5032
|
+
"history",
|
|
5033
|
+
"home",
|
|
5034
|
+
"hourglass",
|
|
5035
|
+
"house",
|
|
5036
|
+
"human-lock",
|
|
5037
|
+
"id-badge",
|
|
5038
|
+
"image",
|
|
5039
|
+
"image-minus",
|
|
5040
|
+
"image-plus",
|
|
5041
|
+
"image-up",
|
|
5042
|
+
"inbox",
|
|
5043
|
+
"inbox-empty",
|
|
3872
5044
|
"info",
|
|
5045
|
+
"install",
|
|
5046
|
+
"journal",
|
|
5047
|
+
"key",
|
|
5048
|
+
"key-off",
|
|
5049
|
+
"key-round",
|
|
5050
|
+
"languages",
|
|
5051
|
+
"laptop",
|
|
5052
|
+
"laptop-bridge",
|
|
5053
|
+
"layers",
|
|
5054
|
+
"layout-dashboard",
|
|
5055
|
+
"layout-grid",
|
|
5056
|
+
"layout-kanban",
|
|
5057
|
+
"leaf",
|
|
5058
|
+
"library-books",
|
|
5059
|
+
"life-buoy",
|
|
5060
|
+
"lightbulb",
|
|
5061
|
+
"lightbulb-sparkles",
|
|
5062
|
+
"line-width",
|
|
5063
|
+
"link",
|
|
5064
|
+
"link-2",
|
|
5065
|
+
"link-off",
|
|
5066
|
+
"list",
|
|
5067
|
+
"list-checks",
|
|
5068
|
+
"list-ordered",
|
|
5069
|
+
"list-rule",
|
|
5070
|
+
"list-todo",
|
|
5071
|
+
"llm",
|
|
3873
5072
|
"loader-circle",
|
|
5073
|
+
"lock",
|
|
5074
|
+
"lock-keyhole",
|
|
5075
|
+
"log-in",
|
|
5076
|
+
"log-out",
|
|
5077
|
+
"log-out-all",
|
|
5078
|
+
"magic-wand",
|
|
5079
|
+
"mail",
|
|
5080
|
+
"mail-check",
|
|
5081
|
+
"mail-open",
|
|
5082
|
+
"mail-plus",
|
|
5083
|
+
"mail-warning",
|
|
5084
|
+
"mails",
|
|
5085
|
+
"market",
|
|
5086
|
+
"maximize-2",
|
|
5087
|
+
"megaphone",
|
|
5088
|
+
"memory-stick",
|
|
5089
|
+
"menu",
|
|
5090
|
+
"message-circle",
|
|
5091
|
+
"message-square",
|
|
5092
|
+
"message-square-plus",
|
|
5093
|
+
"messages-square",
|
|
5094
|
+
"mic",
|
|
5095
|
+
"microphone",
|
|
5096
|
+
"minimize-2",
|
|
5097
|
+
"minus",
|
|
5098
|
+
"minus-square",
|
|
5099
|
+
"monitor-home",
|
|
5100
|
+
"monitor-smartphone",
|
|
5101
|
+
"moon",
|
|
5102
|
+
"more-horizontal",
|
|
5103
|
+
"mouse-pointer-2",
|
|
5104
|
+
"move-horizontal",
|
|
5105
|
+
"network",
|
|
5106
|
+
"network-nodes",
|
|
5107
|
+
"newsletter",
|
|
5108
|
+
"newspaper",
|
|
5109
|
+
"octagon-x",
|
|
5110
|
+
"package",
|
|
5111
|
+
"package-download",
|
|
5112
|
+
"page-snapshot",
|
|
5113
|
+
"palette",
|
|
5114
|
+
"panel-left",
|
|
5115
|
+
"panel-right",
|
|
5116
|
+
"panels-top-left",
|
|
5117
|
+
"paper-plane",
|
|
5118
|
+
"paperclip",
|
|
5119
|
+
"pause",
|
|
5120
|
+
"pause-circle",
|
|
5121
|
+
"pencil",
|
|
5122
|
+
"persona",
|
|
5123
|
+
"piggy-bank",
|
|
5124
|
+
"pipette",
|
|
5125
|
+
"play",
|
|
5126
|
+
"play-circle",
|
|
5127
|
+
"plug",
|
|
5128
|
+
"plug-cloud",
|
|
5129
|
+
"plug-off",
|
|
5130
|
+
"plug-plus",
|
|
5131
|
+
"plugin",
|
|
5132
|
+
"plus",
|
|
5133
|
+
"price-tag",
|
|
5134
|
+
"publish",
|
|
5135
|
+
"quote",
|
|
5136
|
+
"radio",
|
|
5137
|
+
"radio-tower",
|
|
5138
|
+
"receipt",
|
|
5139
|
+
"refresh",
|
|
5140
|
+
"refresh-cw",
|
|
5141
|
+
"refresh-cw-off",
|
|
5142
|
+
"repeat",
|
|
5143
|
+
"repeat-2",
|
|
5144
|
+
"repeat-fallback",
|
|
5145
|
+
"repeat-interval",
|
|
5146
|
+
"responses-list",
|
|
5147
|
+
"rocket",
|
|
5148
|
+
"rotate-ccw",
|
|
5149
|
+
"rotate-cw",
|
|
5150
|
+
"route",
|
|
5151
|
+
"rss",
|
|
5152
|
+
"save",
|
|
5153
|
+
"scale",
|
|
5154
|
+
"scan",
|
|
3874
5155
|
"search",
|
|
3875
|
-
"x"
|
|
5156
|
+
"search-x",
|
|
5157
|
+
"send",
|
|
5158
|
+
"send-check",
|
|
5159
|
+
"send-request",
|
|
5160
|
+
"server",
|
|
5161
|
+
"server-api",
|
|
5162
|
+
"server-environment",
|
|
5163
|
+
"settings",
|
|
5164
|
+
"settings-2",
|
|
5165
|
+
"share",
|
|
5166
|
+
"share-nodes",
|
|
5167
|
+
"shield",
|
|
5168
|
+
"shield-check",
|
|
5169
|
+
"shield-lock",
|
|
5170
|
+
"shield-question",
|
|
5171
|
+
"shield-x",
|
|
5172
|
+
"shopping-basket",
|
|
5173
|
+
"shopping-cart",
|
|
5174
|
+
"shuffle",
|
|
5175
|
+
"signal",
|
|
5176
|
+
"signal-high",
|
|
5177
|
+
"signal-low",
|
|
5178
|
+
"signal-medium",
|
|
5179
|
+
"signal-off",
|
|
5180
|
+
"siren",
|
|
5181
|
+
"sliders-horizontal",
|
|
5182
|
+
"smartphone",
|
|
5183
|
+
"sparkles",
|
|
5184
|
+
"square",
|
|
5185
|
+
"square-check",
|
|
5186
|
+
"square-plus",
|
|
5187
|
+
"square-terminal",
|
|
5188
|
+
"star",
|
|
5189
|
+
"sticker",
|
|
5190
|
+
"storage",
|
|
5191
|
+
"store",
|
|
5192
|
+
"story",
|
|
5193
|
+
"sun",
|
|
5194
|
+
"support",
|
|
5195
|
+
"target",
|
|
5196
|
+
"target-choice",
|
|
5197
|
+
"tasks",
|
|
5198
|
+
"terminal",
|
|
5199
|
+
"ticket",
|
|
5200
|
+
"ticket-plus",
|
|
5201
|
+
"tickets",
|
|
5202
|
+
"timeline",
|
|
5203
|
+
"timer",
|
|
5204
|
+
"toggle-left",
|
|
5205
|
+
"toggle-right",
|
|
5206
|
+
"token-input",
|
|
5207
|
+
"token-output",
|
|
5208
|
+
"trail",
|
|
5209
|
+
"trash-2",
|
|
5210
|
+
"trend-up",
|
|
5211
|
+
"triangle-alert",
|
|
5212
|
+
"type",
|
|
5213
|
+
"unlink",
|
|
5214
|
+
"unplug",
|
|
5215
|
+
"upload",
|
|
5216
|
+
"upload-cloud",
|
|
5217
|
+
"user",
|
|
5218
|
+
"user-check",
|
|
5219
|
+
"user-cog",
|
|
5220
|
+
"user-minus",
|
|
5221
|
+
"user-plus",
|
|
5222
|
+
"user-round",
|
|
5223
|
+
"user-x",
|
|
5224
|
+
"users",
|
|
5225
|
+
"users-round",
|
|
5226
|
+
"vault",
|
|
5227
|
+
"volume-2",
|
|
5228
|
+
"wallet",
|
|
5229
|
+
"wand-sparkles",
|
|
5230
|
+
"warehouse",
|
|
5231
|
+
"workflow",
|
|
5232
|
+
"workspace",
|
|
5233
|
+
"wrench",
|
|
5234
|
+
"wrench-zap",
|
|
5235
|
+
"x",
|
|
5236
|
+
"zap"
|
|
3876
5237
|
],
|
|
3877
|
-
description: "Icon identifier from the @treeui/icons registry."
|
|
5238
|
+
description: "Icon identifier from the @treeui/icons registry. Widens as `TIconRegistry` is augmented, so registered app icons are valid values too.",
|
|
5239
|
+
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."
|
|
3878
5240
|
},
|
|
3879
5241
|
{
|
|
3880
5242
|
name: "size",
|
|
3881
5243
|
type: "number | string",
|
|
3882
5244
|
default: "20",
|
|
3883
|
-
description: "Pixel size for both width and height of the rendered svg."
|
|
5245
|
+
description: "Pixel size for both width and height of the rendered svg.",
|
|
5246
|
+
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'
|
|
3884
5247
|
},
|
|
3885
5248
|
{
|
|
3886
5249
|
name: "strokeWidth",
|
|
@@ -3907,33 +5270,60 @@ var treeui_catalog_default = {
|
|
|
3907
5270
|
"becomes_image_when_labeled: true",
|
|
3908
5271
|
"rule: Provide `label` only when the icon conveys meaning that is not already in adjacent text."
|
|
3909
5272
|
],
|
|
3910
|
-
behavior: [
|
|
5273
|
+
behavior: [
|
|
5274
|
+
"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.",
|
|
5275
|
+
'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).',
|
|
5276
|
+
"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.",
|
|
5277
|
+
"resolved_per_render: TIcon resolves its name in a computed, not once at setup, so an icon registered after the component mounted still appears.",
|
|
5278
|
+
"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.",
|
|
5279
|
+
"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."
|
|
5280
|
+
],
|
|
3911
5281
|
selection: {
|
|
3912
5282
|
keywords: [
|
|
3913
5283
|
"icon",
|
|
3914
5284
|
"svg",
|
|
3915
5285
|
"glyph",
|
|
3916
|
-
"pictogram"
|
|
5286
|
+
"pictogram",
|
|
5287
|
+
"register",
|
|
5288
|
+
"register icon",
|
|
5289
|
+
"custom icon",
|
|
5290
|
+
"icon registry",
|
|
5291
|
+
"registerTreeIcons",
|
|
5292
|
+
"createTreeIcon"
|
|
3917
5293
|
],
|
|
3918
5294
|
useWhen: [
|
|
3919
|
-
"You need to render
|
|
3920
|
-
|
|
5295
|
+
"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.",
|
|
5296
|
+
'The icon is one of the built-ins: `<TIcon name="cpu" />`. `listTreeIcons()` returns every registered name at runtime.',
|
|
5297
|
+
"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."
|
|
3921
5298
|
],
|
|
3922
5299
|
avoidWhen: [
|
|
3923
|
-
"The
|
|
5300
|
+
"The graphic is a country flag \u2014 a flag names a country, not an interface concept.",
|
|
5301
|
+
"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."
|
|
3924
5302
|
],
|
|
3925
5303
|
alternatives: [
|
|
3926
5304
|
{
|
|
3927
|
-
component: "
|
|
3928
|
-
when: "You
|
|
5305
|
+
component: "a component passed straight to `TNavMenuItem.icon`, or rendered into an `#icon` slot",
|
|
5306
|
+
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."
|
|
5307
|
+
},
|
|
5308
|
+
{
|
|
5309
|
+
component: "TFlag",
|
|
5310
|
+
when: "The graphic is a country flag rendered from an ISO 3166-1 alpha-2 code."
|
|
3929
5311
|
}
|
|
3930
5312
|
]
|
|
3931
5313
|
},
|
|
3932
5314
|
setup: {
|
|
3933
|
-
required: [
|
|
3934
|
-
|
|
5315
|
+
required: [
|
|
5316
|
+
"Use a registered name: one of the built-ins, or one the app added with `registerTreeIcons`. See `icons` above."
|
|
5317
|
+
],
|
|
5318
|
+
notes: [
|
|
5319
|
+
'`size` is a pixel count, not `sm | md | lg`. Passing `size="md"` renders an unsized svg.',
|
|
5320
|
+
"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."
|
|
5321
|
+
]
|
|
3935
5322
|
},
|
|
3936
|
-
recipes: [
|
|
5323
|
+
recipes: [
|
|
5324
|
+
"nav-menu-icons"
|
|
5325
|
+
],
|
|
5326
|
+
practices: []
|
|
3937
5327
|
},
|
|
3938
5328
|
{
|
|
3939
5329
|
name: "TInput",
|
|
@@ -4059,6 +5449,10 @@ var treeui_catalog_default = {
|
|
|
4059
5449
|
recipes: [
|
|
4060
5450
|
"form-field-input",
|
|
4061
5451
|
"tag-input"
|
|
5452
|
+
],
|
|
5453
|
+
practices: [
|
|
5454
|
+
"interaction-feedback",
|
|
5455
|
+
"predictable-api"
|
|
4062
5456
|
]
|
|
4063
5457
|
},
|
|
4064
5458
|
{
|
|
@@ -4096,7 +5490,245 @@ var treeui_catalog_default = {
|
|
|
4096
5490
|
required: [],
|
|
4097
5491
|
notes: []
|
|
4098
5492
|
},
|
|
4099
|
-
recipes: []
|
|
5493
|
+
recipes: [],
|
|
5494
|
+
practices: []
|
|
5495
|
+
},
|
|
5496
|
+
{
|
|
5497
|
+
name: "TLanguageSelect",
|
|
5498
|
+
aliases: [],
|
|
5499
|
+
package: "@treeui/vue",
|
|
5500
|
+
kind: "form_overlay",
|
|
5501
|
+
category: "Data Entry",
|
|
5502
|
+
status: "available",
|
|
5503
|
+
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.",
|
|
5504
|
+
sourceFile: "packages/vue/src/components/TLanguageSelect.vue",
|
|
5505
|
+
storyFile: "apps/docs/src/stories/LanguageSelect.stories.ts",
|
|
5506
|
+
storyTitle: "Components/Data Entry/LanguageSelect",
|
|
5507
|
+
manifestFile: "docs/ai/COMPONENTS/language-select.yaml",
|
|
5508
|
+
props: [
|
|
5509
|
+
{
|
|
5510
|
+
name: "modelValue",
|
|
5511
|
+
type: "string",
|
|
5512
|
+
default: ""
|
|
5513
|
+
},
|
|
5514
|
+
{
|
|
5515
|
+
name: "options",
|
|
5516
|
+
type: "TLanguageOption[]",
|
|
5517
|
+
default: "[]",
|
|
5518
|
+
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."
|
|
5519
|
+
},
|
|
5520
|
+
{
|
|
5521
|
+
name: "open",
|
|
5522
|
+
type: "boolean",
|
|
5523
|
+
default: "undefined"
|
|
5524
|
+
},
|
|
5525
|
+
{
|
|
5526
|
+
name: "defaultOpen",
|
|
5527
|
+
type: "boolean",
|
|
5528
|
+
default: "false"
|
|
5529
|
+
},
|
|
5530
|
+
{
|
|
5531
|
+
name: "size",
|
|
5532
|
+
type: "TSize",
|
|
5533
|
+
default: "md",
|
|
5534
|
+
values: [
|
|
5535
|
+
"sm",
|
|
5536
|
+
"md",
|
|
5537
|
+
"lg"
|
|
5538
|
+
]
|
|
5539
|
+
},
|
|
5540
|
+
{
|
|
5541
|
+
name: "variant",
|
|
5542
|
+
type: "TLanguageSelectVariant",
|
|
5543
|
+
default: "field",
|
|
5544
|
+
values: [
|
|
5545
|
+
"field",
|
|
5546
|
+
"switcher"
|
|
5547
|
+
],
|
|
5548
|
+
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."
|
|
5549
|
+
},
|
|
5550
|
+
{
|
|
5551
|
+
name: "iconOnly",
|
|
5552
|
+
type: "boolean",
|
|
5553
|
+
default: "false",
|
|
5554
|
+
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`."
|
|
5555
|
+
},
|
|
5556
|
+
{
|
|
5557
|
+
name: "width",
|
|
5558
|
+
type: "TFieldWidth",
|
|
5559
|
+
default: "full",
|
|
5560
|
+
values: [
|
|
5561
|
+
"xs",
|
|
5562
|
+
"sm",
|
|
5563
|
+
"md",
|
|
5564
|
+
"lg",
|
|
5565
|
+
"xl",
|
|
5566
|
+
"full"
|
|
5567
|
+
],
|
|
5568
|
+
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."
|
|
5569
|
+
},
|
|
5570
|
+
{
|
|
5571
|
+
name: "disabled",
|
|
5572
|
+
type: "boolean",
|
|
5573
|
+
default: "false"
|
|
5574
|
+
},
|
|
5575
|
+
{
|
|
5576
|
+
name: "loading",
|
|
5577
|
+
type: "boolean",
|
|
5578
|
+
default: "false"
|
|
5579
|
+
},
|
|
5580
|
+
{
|
|
5581
|
+
name: "invalid",
|
|
5582
|
+
type: "boolean",
|
|
5583
|
+
default: "false"
|
|
5584
|
+
},
|
|
5585
|
+
{
|
|
5586
|
+
name: "placeholder",
|
|
5587
|
+
type: "string",
|
|
5588
|
+
default: ""
|
|
5589
|
+
},
|
|
5590
|
+
{
|
|
5591
|
+
name: "flagBaseUrl",
|
|
5592
|
+
type: "string",
|
|
5593
|
+
default: "undefined",
|
|
5594
|
+
note: "Forwarded to every nested TFlag. When omitted, TFlag's own default origin applies. Set once here to self-host flag assets."
|
|
5595
|
+
},
|
|
5596
|
+
{
|
|
5597
|
+
name: "emptyText",
|
|
5598
|
+
type: "string",
|
|
5599
|
+
default: "No languages available."
|
|
5600
|
+
}
|
|
5601
|
+
],
|
|
5602
|
+
events: [
|
|
5603
|
+
{
|
|
5604
|
+
name: "update:modelValue"
|
|
5605
|
+
},
|
|
5606
|
+
{
|
|
5607
|
+
name: "update:open"
|
|
5608
|
+
},
|
|
5609
|
+
{
|
|
5610
|
+
name: "open-change"
|
|
5611
|
+
}
|
|
5612
|
+
],
|
|
5613
|
+
slots: [
|
|
5614
|
+
{
|
|
5615
|
+
name: "prefix",
|
|
5616
|
+
description: "Leading content inside the trigger, before everything else \u2014 the selected flag and label in `field`, the translate icon in `switcher`."
|
|
5617
|
+
},
|
|
5618
|
+
{
|
|
5619
|
+
name: "option",
|
|
5620
|
+
description: `Replaces the default option body (flag, label, description). Renders INSIDE the row's <li role="option">, so it must contain only presentational content.
|
|
5621
|
+
`
|
|
5622
|
+
},
|
|
5623
|
+
{
|
|
5624
|
+
name: "empty",
|
|
5625
|
+
description: "Replaces `emptyText` when `options` is empty."
|
|
5626
|
+
}
|
|
5627
|
+
],
|
|
5628
|
+
a11y: [
|
|
5629
|
+
"role: listbox",
|
|
5630
|
+
"trigger_aria_haspopup: listbox",
|
|
5631
|
+
"trigger_aria_expanded: true",
|
|
5632
|
+
"trigger_aria_controls_when_open: true",
|
|
5633
|
+
"aria_invalid_when_invalid: true",
|
|
5634
|
+
"aria_busy_when_loading: true",
|
|
5635
|
+
"aria_selected_on_options: true",
|
|
5636
|
+
"aria_disabled_on_disabled_options: true",
|
|
5637
|
+
"focus_visible_on_trigger: true",
|
|
5638
|
+
"keyboard_arrow_navigation: true",
|
|
5639
|
+
"escape_closes_dropdown: true",
|
|
5640
|
+
"enter_space_selects_option: true",
|
|
5641
|
+
"home_end_navigation: true",
|
|
5642
|
+
"home_end_target_first_last_enabled_option: true",
|
|
5643
|
+
"focus_restores_to_trigger_on_close: true",
|
|
5644
|
+
"icon_only_removes_the_visible_language_name: true",
|
|
5645
|
+
"icon_only_requires_a_consumer_supplied_aria_label_on_the_trigger: true",
|
|
5646
|
+
"translate_icon_and_flags_are_decorative_not_the_accessible_name: true"
|
|
5647
|
+
],
|
|
5648
|
+
behavior: [
|
|
5649
|
+
"update_payload_type: string",
|
|
5650
|
+
"loading_does_not_disable_by_itself: true",
|
|
5651
|
+
"placeholder_shown_as_muted_text: true",
|
|
5652
|
+
"chevron_rotates_when_open: true",
|
|
5653
|
+
"check_icon_on_selected_option: true",
|
|
5654
|
+
"outside_click_closes_dropdown: true",
|
|
5655
|
+
"listbox_flips_above_trigger_when_space_below_is_insufficient: true",
|
|
5656
|
+
"options_without_a_code_render_without_a_flag: true",
|
|
5657
|
+
"empty_options_render_the_empty_slot_or_empty_text: true",
|
|
5658
|
+
"field_variant_leads_the_trigger_with_the_selected_flag: true",
|
|
5659
|
+
"field_variant_trigger_fills_its_container: true",
|
|
5660
|
+
"switcher_variant_leads_the_trigger_with_a_translate_icon: true",
|
|
5661
|
+
"switcher_variant_trails_the_current_flag_before_the_chevron: true",
|
|
5662
|
+
"switcher_variant_trigger_sizes_to_its_content: true",
|
|
5663
|
+
"switcher_variant_ignores_the_width_prop: true",
|
|
5664
|
+
"switcher_listbox_aligns_to_the_trigger_right_edge: true",
|
|
5665
|
+
"switcher_listbox_may_be_wider_than_the_trigger: true",
|
|
5666
|
+
"icon_only_applies_to_the_switcher_variant_only: true",
|
|
5667
|
+
"root_classes: t-language-select--field | t-language-select--switcher, plus t-language-select--icon-only"
|
|
5668
|
+
],
|
|
5669
|
+
selection: {
|
|
5670
|
+
keywords: [
|
|
5671
|
+
"language select",
|
|
5672
|
+
"language picker",
|
|
5673
|
+
"locale",
|
|
5674
|
+
"locale picker",
|
|
5675
|
+
"i18n",
|
|
5676
|
+
"internationalization",
|
|
5677
|
+
"translation",
|
|
5678
|
+
"country flag"
|
|
5679
|
+
],
|
|
5680
|
+
useWhen: [
|
|
5681
|
+
"The user is picking the interface language or locale.",
|
|
5682
|
+
'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.',
|
|
5683
|
+
'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`.',
|
|
5684
|
+
"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.",
|
|
5685
|
+
"Each language should render with its country flag, and optionally an endonym as a second line.",
|
|
5686
|
+
"The app owns the language list and applies the locale side effects itself."
|
|
5687
|
+
],
|
|
5688
|
+
avoidWhen: [
|
|
5689
|
+
"The values are not languages or locales.",
|
|
5690
|
+
"The language list is long enough that the user must type to narrow it down.",
|
|
5691
|
+
"You expect TreeUI to supply the locale dataset \u2014 it ships none, so pass your own `options`."
|
|
5692
|
+
],
|
|
5693
|
+
alternatives: [
|
|
5694
|
+
{
|
|
5695
|
+
component: "TSelect",
|
|
5696
|
+
when: "The values are ordinary application data rather than languages or locales."
|
|
5697
|
+
},
|
|
5698
|
+
{
|
|
5699
|
+
component: "TCombobox",
|
|
5700
|
+
when: "The language list is long enough that typing to narrow it down is required."
|
|
5701
|
+
},
|
|
5702
|
+
{
|
|
5703
|
+
component: "TFlag",
|
|
5704
|
+
when: "You only need to render one country flag, without a picker around it."
|
|
5705
|
+
}
|
|
5706
|
+
]
|
|
5707
|
+
},
|
|
5708
|
+
setup: {
|
|
5709
|
+
required: [
|
|
5710
|
+
"Pass `options` as `{ label, value, code?, description?, disabled? }[]`. TreeUI ships no language, locale, or country dataset \u2014 the app owns its language list.",
|
|
5711
|
+
"Apply locale side effects (i18n locale, `lang` attribute, persistence) in the app layer; the component only reports the selected `value`.",
|
|
5712
|
+
"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."
|
|
5713
|
+
],
|
|
5714
|
+
notes: [
|
|
5715
|
+
"`variant` is `field` (default) or `switcher`, typed as `TLanguageSelectVariant` and exported from `@treeui/vue`.",
|
|
5716
|
+
'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.',
|
|
5717
|
+
'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.',
|
|
5718
|
+
"A switcher sizes to its content, so `width` does not apply, and its listbox aligns to the trigger's right edge.",
|
|
5719
|
+
"`iconOnly` is switcher-only and drops the visible language name, leaving the translate icon and the current flag.",
|
|
5720
|
+
"`value` is an opaque application key, typically a BCP-47 tag such as `pt-BR`. TreeUI never parses or validates it.",
|
|
5721
|
+
"`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.",
|
|
5722
|
+
"Use `description` for a secondary line such as the endonym.",
|
|
5723
|
+
"Set `flagBaseUrl` once on the select rather than per option; it is forwarded to every nested `TFlag`.",
|
|
5724
|
+
"Bind `modelValue` to a `string`, and use `v-model:open` when the app controls open state.",
|
|
5725
|
+
"The CDN and Content-Security-Policy requirements under `TFlag` apply whenever any option carries a `code`."
|
|
5726
|
+
]
|
|
5727
|
+
},
|
|
5728
|
+
recipes: [
|
|
5729
|
+
"language-switcher"
|
|
5730
|
+
],
|
|
5731
|
+
practices: []
|
|
4100
5732
|
},
|
|
4101
5733
|
{
|
|
4102
5734
|
name: "TLink",
|
|
@@ -4197,7 +5829,10 @@ var treeui_catalog_default = {
|
|
|
4197
5829
|
required: [],
|
|
4198
5830
|
notes: []
|
|
4199
5831
|
},
|
|
4200
|
-
recipes: []
|
|
5832
|
+
recipes: [],
|
|
5833
|
+
practices: [
|
|
5834
|
+
"interaction-feedback"
|
|
5835
|
+
]
|
|
4201
5836
|
},
|
|
4202
5837
|
{
|
|
4203
5838
|
name: "TMarkdownEditor",
|
|
@@ -4306,7 +5941,8 @@ var treeui_catalog_default = {
|
|
|
4306
5941
|
required: [],
|
|
4307
5942
|
notes: []
|
|
4308
5943
|
},
|
|
4309
|
-
recipes: []
|
|
5944
|
+
recipes: [],
|
|
5945
|
+
practices: []
|
|
4310
5946
|
},
|
|
4311
5947
|
{
|
|
4312
5948
|
name: "TModal",
|
|
@@ -4454,7 +6090,11 @@ var treeui_catalog_default = {
|
|
|
4454
6090
|
"Use `v-model:open` for the idiomatic Vue controlled pattern."
|
|
4455
6091
|
]
|
|
4456
6092
|
},
|
|
4457
|
-
recipes: []
|
|
6093
|
+
recipes: [],
|
|
6094
|
+
practices: [
|
|
6095
|
+
"accessible-by-default",
|
|
6096
|
+
"predictable-api"
|
|
6097
|
+
]
|
|
4458
6098
|
},
|
|
4459
6099
|
{
|
|
4460
6100
|
name: "TMultiSelect",
|
|
@@ -4613,7 +6253,8 @@ var treeui_catalog_default = {
|
|
|
4613
6253
|
},
|
|
4614
6254
|
recipes: [
|
|
4615
6255
|
"searchable-multi-choice"
|
|
4616
|
-
]
|
|
6256
|
+
],
|
|
6257
|
+
practices: []
|
|
4617
6258
|
},
|
|
4618
6259
|
{
|
|
4619
6260
|
name: "TNavbar",
|
|
@@ -4711,6 +6352,9 @@ var treeui_catalog_default = {
|
|
|
4711
6352
|
},
|
|
4712
6353
|
recipes: [
|
|
4713
6354
|
"sidebar-shell"
|
|
6355
|
+
],
|
|
6356
|
+
practices: [
|
|
6357
|
+
"token-driven"
|
|
4714
6358
|
]
|
|
4715
6359
|
},
|
|
4716
6360
|
{
|
|
@@ -4803,10 +6447,13 @@ var treeui_catalog_default = {
|
|
|
4803
6447
|
keywords: [
|
|
4804
6448
|
"nav menu",
|
|
4805
6449
|
"sidebar nav",
|
|
4806
|
-
"section nav"
|
|
6450
|
+
"section nav",
|
|
6451
|
+
"nav icons",
|
|
6452
|
+
"sidebar rail"
|
|
4807
6453
|
],
|
|
4808
6454
|
useWhen: [
|
|
4809
|
-
"You need app-section navigation inside a shell or sidebar."
|
|
6455
|
+
"You need app-section navigation inside a shell or sidebar.",
|
|
6456
|
+
"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."
|
|
4810
6457
|
],
|
|
4811
6458
|
avoidWhen: [
|
|
4812
6459
|
"You need tabs for small panel switching."
|
|
@@ -4825,13 +6472,19 @@ var treeui_catalog_default = {
|
|
|
4825
6472
|
setup: {
|
|
4826
6473
|
required: [],
|
|
4827
6474
|
notes: [
|
|
4828
|
-
"When nested inside `TSidebar` or `TAppShell`, `collapsed` can be inherited from the sidebar provider."
|
|
6475
|
+
"When nested inside `TSidebar` or `TAppShell`, `collapsed` can be inherited from the sidebar provider.",
|
|
6476
|
+
"Pass `items` as `{ label, value, icon?, to?, badge?, description?, shortLabel?, disabled?, exact? }[]`.",
|
|
6477
|
+
"`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.",
|
|
6478
|
+
"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.",
|
|
6479
|
+
"Register any icon the app needs beyond the built-ins first \u2014 see `icons` above."
|
|
4829
6480
|
]
|
|
4830
6481
|
},
|
|
4831
6482
|
recipes: [
|
|
4832
6483
|
"app-shell",
|
|
4833
|
-
"sidebar-shell"
|
|
4834
|
-
|
|
6484
|
+
"sidebar-shell",
|
|
6485
|
+
"nav-menu-icons"
|
|
6486
|
+
],
|
|
6487
|
+
practices: []
|
|
4835
6488
|
},
|
|
4836
6489
|
{
|
|
4837
6490
|
name: "TNumberInput",
|
|
@@ -4938,7 +6591,8 @@ var treeui_catalog_default = {
|
|
|
4938
6591
|
required: [],
|
|
4939
6592
|
notes: []
|
|
4940
6593
|
},
|
|
4941
|
-
recipes: []
|
|
6594
|
+
recipes: [],
|
|
6595
|
+
practices: []
|
|
4942
6596
|
},
|
|
4943
6597
|
{
|
|
4944
6598
|
name: "TPage",
|
|
@@ -5031,7 +6685,10 @@ var treeui_catalog_default = {
|
|
|
5031
6685
|
required: [],
|
|
5032
6686
|
notes: []
|
|
5033
6687
|
},
|
|
5034
|
-
recipes: []
|
|
6688
|
+
recipes: [],
|
|
6689
|
+
practices: [
|
|
6690
|
+
"content-alignment"
|
|
6691
|
+
]
|
|
5035
6692
|
},
|
|
5036
6693
|
{
|
|
5037
6694
|
name: "TPageHeader",
|
|
@@ -5125,7 +6782,10 @@ var treeui_catalog_default = {
|
|
|
5125
6782
|
required: [],
|
|
5126
6783
|
notes: []
|
|
5127
6784
|
},
|
|
5128
|
-
recipes: []
|
|
6785
|
+
recipes: [],
|
|
6786
|
+
practices: [
|
|
6787
|
+
"content-alignment"
|
|
6788
|
+
]
|
|
5129
6789
|
},
|
|
5130
6790
|
{
|
|
5131
6791
|
name: "TPagination",
|
|
@@ -5238,6 +6898,9 @@ var treeui_catalog_default = {
|
|
|
5238
6898
|
},
|
|
5239
6899
|
recipes: [
|
|
5240
6900
|
"data-listing"
|
|
6901
|
+
],
|
|
6902
|
+
practices: [
|
|
6903
|
+
"interaction-feedback"
|
|
5241
6904
|
]
|
|
5242
6905
|
},
|
|
5243
6906
|
{
|
|
@@ -5297,7 +6960,7 @@ var treeui_catalog_default = {
|
|
|
5297
6960
|
slots: [
|
|
5298
6961
|
{
|
|
5299
6962
|
name: "trigger",
|
|
5300
|
-
description: "Custom trigger element. Receives current open state
|
|
6963
|
+
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"
|
|
5301
6964
|
},
|
|
5302
6965
|
{
|
|
5303
6966
|
name: "default",
|
|
@@ -5306,9 +6969,9 @@ var treeui_catalog_default = {
|
|
|
5306
6969
|
],
|
|
5307
6970
|
a11y: [
|
|
5308
6971
|
"role: dialog",
|
|
5309
|
-
'attrs: ["aria-haspopup=\\"dialog\\" on trigger","aria-expanded on trigger","aria-controls linking trigger to content","tabindex=\\"-1\\" on content for focus management"]',
|
|
6972
|
+
'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"]',
|
|
5310
6973
|
'keyboard: ["Click or Enter/Space on trigger toggles popover","Escape closes popover and restores focus to trigger","Tab navigates within popover content"]',
|
|
5311
|
-
'focus: ["On open, focuses first focusable element inside content (or content itself)","On Escape close, restores focus to trigger"]',
|
|
6974
|
+
'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"]',
|
|
5312
6975
|
'dismiss: ["Outside click closes popover","Escape key closes popover"]'
|
|
5313
6976
|
],
|
|
5314
6977
|
behavior: [],
|
|
@@ -5341,7 +7004,8 @@ var treeui_catalog_default = {
|
|
|
5341
7004
|
},
|
|
5342
7005
|
recipes: [
|
|
5343
7006
|
"anchored-help"
|
|
5344
|
-
]
|
|
7007
|
+
],
|
|
7008
|
+
practices: []
|
|
5345
7009
|
},
|
|
5346
7010
|
{
|
|
5347
7011
|
name: "TPricing",
|
|
@@ -5405,7 +7069,8 @@ var treeui_catalog_default = {
|
|
|
5405
7069
|
},
|
|
5406
7070
|
recipes: [
|
|
5407
7071
|
"pricing-section"
|
|
5408
|
-
]
|
|
7072
|
+
],
|
|
7073
|
+
practices: []
|
|
5409
7074
|
},
|
|
5410
7075
|
{
|
|
5411
7076
|
name: "TPricingCard",
|
|
@@ -5534,7 +7199,8 @@ var treeui_catalog_default = {
|
|
|
5534
7199
|
},
|
|
5535
7200
|
recipes: [
|
|
5536
7201
|
"pricing-section"
|
|
5537
|
-
]
|
|
7202
|
+
],
|
|
7203
|
+
practices: []
|
|
5538
7204
|
},
|
|
5539
7205
|
{
|
|
5540
7206
|
name: "TProgress",
|
|
@@ -5596,7 +7262,10 @@ var treeui_catalog_default = {
|
|
|
5596
7262
|
required: [],
|
|
5597
7263
|
notes: []
|
|
5598
7264
|
},
|
|
5599
|
-
recipes: []
|
|
7265
|
+
recipes: [],
|
|
7266
|
+
practices: [
|
|
7267
|
+
"state-clarity"
|
|
7268
|
+
]
|
|
5600
7269
|
},
|
|
5601
7270
|
{
|
|
5602
7271
|
name: "TRadio",
|
|
@@ -5664,7 +7333,8 @@ var treeui_catalog_default = {
|
|
|
5664
7333
|
required: [],
|
|
5665
7334
|
notes: []
|
|
5666
7335
|
},
|
|
5667
|
-
recipes: []
|
|
7336
|
+
recipes: [],
|
|
7337
|
+
practices: []
|
|
5668
7338
|
},
|
|
5669
7339
|
{
|
|
5670
7340
|
name: "TRadioGroup",
|
|
@@ -5739,7 +7409,8 @@ var treeui_catalog_default = {
|
|
|
5739
7409
|
required: [],
|
|
5740
7410
|
notes: []
|
|
5741
7411
|
},
|
|
5742
|
-
recipes: []
|
|
7412
|
+
recipes: [],
|
|
7413
|
+
practices: []
|
|
5743
7414
|
},
|
|
5744
7415
|
{
|
|
5745
7416
|
name: "TSelect",
|
|
@@ -5894,6 +7565,10 @@ var treeui_catalog_default = {
|
|
|
5894
7565
|
},
|
|
5895
7566
|
recipes: [
|
|
5896
7567
|
"chart-surface"
|
|
7568
|
+
],
|
|
7569
|
+
practices: [
|
|
7570
|
+
"interaction-feedback",
|
|
7571
|
+
"predictable-api"
|
|
5897
7572
|
]
|
|
5898
7573
|
},
|
|
5899
7574
|
{
|
|
@@ -6004,7 +7679,10 @@ var treeui_catalog_default = {
|
|
|
6004
7679
|
required: [],
|
|
6005
7680
|
notes: []
|
|
6006
7681
|
},
|
|
6007
|
-
recipes: []
|
|
7682
|
+
recipes: [],
|
|
7683
|
+
practices: [
|
|
7684
|
+
"interaction-feedback"
|
|
7685
|
+
]
|
|
6008
7686
|
},
|
|
6009
7687
|
{
|
|
6010
7688
|
name: "TSidebar",
|
|
@@ -6152,7 +7830,8 @@ var treeui_catalog_default = {
|
|
|
6152
7830
|
},
|
|
6153
7831
|
recipes: [
|
|
6154
7832
|
"sidebar-shell"
|
|
6155
|
-
]
|
|
7833
|
+
],
|
|
7834
|
+
practices: []
|
|
6156
7835
|
},
|
|
6157
7836
|
{
|
|
6158
7837
|
name: "TSkeleton",
|
|
@@ -6215,7 +7894,10 @@ var treeui_catalog_default = {
|
|
|
6215
7894
|
required: [],
|
|
6216
7895
|
notes: []
|
|
6217
7896
|
},
|
|
6218
|
-
recipes: []
|
|
7897
|
+
recipes: [],
|
|
7898
|
+
practices: [
|
|
7899
|
+
"state-clarity"
|
|
7900
|
+
]
|
|
6219
7901
|
},
|
|
6220
7902
|
{
|
|
6221
7903
|
name: "TSpacer",
|
|
@@ -6255,7 +7937,10 @@ var treeui_catalog_default = {
|
|
|
6255
7937
|
required: [],
|
|
6256
7938
|
notes: []
|
|
6257
7939
|
},
|
|
6258
|
-
recipes: []
|
|
7940
|
+
recipes: [],
|
|
7941
|
+
practices: [
|
|
7942
|
+
"content-alignment"
|
|
7943
|
+
]
|
|
6259
7944
|
},
|
|
6260
7945
|
{
|
|
6261
7946
|
name: "TSparkline",
|
|
@@ -6378,7 +8063,8 @@ var treeui_catalog_default = {
|
|
|
6378
8063
|
},
|
|
6379
8064
|
recipes: [
|
|
6380
8065
|
"metric-dashboard"
|
|
6381
|
-
]
|
|
8066
|
+
],
|
|
8067
|
+
practices: []
|
|
6382
8068
|
},
|
|
6383
8069
|
{
|
|
6384
8070
|
name: "TSpinner",
|
|
@@ -6427,7 +8113,10 @@ var treeui_catalog_default = {
|
|
|
6427
8113
|
required: [],
|
|
6428
8114
|
notes: []
|
|
6429
8115
|
},
|
|
6430
|
-
recipes: []
|
|
8116
|
+
recipes: [],
|
|
8117
|
+
practices: [
|
|
8118
|
+
"state-clarity"
|
|
8119
|
+
]
|
|
6431
8120
|
},
|
|
6432
8121
|
{
|
|
6433
8122
|
name: "TSplit",
|
|
@@ -6503,7 +8192,10 @@ var treeui_catalog_default = {
|
|
|
6503
8192
|
required: [],
|
|
6504
8193
|
notes: []
|
|
6505
8194
|
},
|
|
6506
|
-
recipes: []
|
|
8195
|
+
recipes: [],
|
|
8196
|
+
practices: [
|
|
8197
|
+
"content-alignment"
|
|
8198
|
+
]
|
|
6507
8199
|
},
|
|
6508
8200
|
{
|
|
6509
8201
|
name: "TStack",
|
|
@@ -6604,9 +8296,13 @@ var treeui_catalog_default = {
|
|
|
6604
8296
|
notes: []
|
|
6605
8297
|
},
|
|
6606
8298
|
recipes: [
|
|
8299
|
+
"brand-lockup",
|
|
6607
8300
|
"tag-input",
|
|
6608
8301
|
"data-listing",
|
|
6609
8302
|
"chart-surface"
|
|
8303
|
+
],
|
|
8304
|
+
practices: [
|
|
8305
|
+
"content-alignment"
|
|
6610
8306
|
]
|
|
6611
8307
|
},
|
|
6612
8308
|
{
|
|
@@ -6681,7 +8377,8 @@ var treeui_catalog_default = {
|
|
|
6681
8377
|
required: [],
|
|
6682
8378
|
notes: []
|
|
6683
8379
|
},
|
|
6684
|
-
recipes: []
|
|
8380
|
+
recipes: [],
|
|
8381
|
+
practices: []
|
|
6685
8382
|
},
|
|
6686
8383
|
{
|
|
6687
8384
|
name: "TStat",
|
|
@@ -6803,7 +8500,8 @@ var treeui_catalog_default = {
|
|
|
6803
8500
|
recipes: [
|
|
6804
8501
|
"stat-grid",
|
|
6805
8502
|
"metric-dashboard"
|
|
6806
|
-
]
|
|
8503
|
+
],
|
|
8504
|
+
practices: []
|
|
6807
8505
|
},
|
|
6808
8506
|
{
|
|
6809
8507
|
name: "TSteps",
|
|
@@ -6907,7 +8605,8 @@ var treeui_catalog_default = {
|
|
|
6907
8605
|
"Pass explicit `status` per item only when the app should override the computed complete/current/upcoming logic."
|
|
6908
8606
|
]
|
|
6909
8607
|
},
|
|
6910
|
-
recipes: []
|
|
8608
|
+
recipes: [],
|
|
8609
|
+
practices: []
|
|
6911
8610
|
},
|
|
6912
8611
|
{
|
|
6913
8612
|
name: "TSwitch",
|
|
@@ -6996,7 +8695,10 @@ var treeui_catalog_default = {
|
|
|
6996
8695
|
required: [],
|
|
6997
8696
|
notes: []
|
|
6998
8697
|
},
|
|
6999
|
-
recipes: []
|
|
8698
|
+
recipes: [],
|
|
8699
|
+
practices: [
|
|
8700
|
+
"interaction-feedback"
|
|
8701
|
+
]
|
|
7000
8702
|
},
|
|
7001
8703
|
{
|
|
7002
8704
|
name: "TTable",
|
|
@@ -7036,6 +8738,13 @@ var treeui_catalog_default = {
|
|
|
7036
8738
|
type: "TTableSortState",
|
|
7037
8739
|
required: false,
|
|
7038
8740
|
description: "Controlled sort state. When provided, overrides internal sort tracking."
|
|
8741
|
+
},
|
|
8742
|
+
{
|
|
8743
|
+
name: "caption",
|
|
8744
|
+
type: "string",
|
|
8745
|
+
required: false,
|
|
8746
|
+
description: "Visible `<caption>` naming the table.",
|
|
8747
|
+
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."
|
|
7039
8748
|
}
|
|
7040
8749
|
],
|
|
7041
8750
|
events: [
|
|
@@ -7060,7 +8769,9 @@ var treeui_catalog_default = {
|
|
|
7060
8769
|
}
|
|
7061
8770
|
],
|
|
7062
8771
|
a11y: [
|
|
7063
|
-
"role:
|
|
8772
|
+
"role: table (native). No explicit role is emitted.",
|
|
8773
|
+
'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.',
|
|
8774
|
+
"accessible_name: Use `caption` for a visible name or `aria-label` / `aria-labelledby` for an invisible one. Both land on the `<table>`.",
|
|
7064
8775
|
"aria-sort: Set on sortable column headers (ascending, descending, none).",
|
|
7065
8776
|
"keyboard: Sortable headers are focusable and activated with Enter or Space.",
|
|
7066
8777
|
"scope: col on all th elements."
|
|
@@ -7097,6 +8808,9 @@ var treeui_catalog_default = {
|
|
|
7097
8808
|
},
|
|
7098
8809
|
recipes: [
|
|
7099
8810
|
"data-listing"
|
|
8811
|
+
],
|
|
8812
|
+
practices: [
|
|
8813
|
+
"state-clarity"
|
|
7100
8814
|
]
|
|
7101
8815
|
},
|
|
7102
8816
|
{
|
|
@@ -7203,6 +8917,9 @@ var treeui_catalog_default = {
|
|
|
7203
8917
|
},
|
|
7204
8918
|
recipes: [
|
|
7205
8919
|
"router-backed-tabs"
|
|
8920
|
+
],
|
|
8921
|
+
practices: [
|
|
8922
|
+
"interaction-feedback"
|
|
7206
8923
|
]
|
|
7207
8924
|
},
|
|
7208
8925
|
{
|
|
@@ -7283,6 +9000,10 @@ var treeui_catalog_default = {
|
|
|
7283
9000
|
},
|
|
7284
9001
|
recipes: [
|
|
7285
9002
|
"tag-input"
|
|
9003
|
+
],
|
|
9004
|
+
practices: [
|
|
9005
|
+
"predictable-api",
|
|
9006
|
+
"token-driven"
|
|
7286
9007
|
]
|
|
7287
9008
|
},
|
|
7288
9009
|
{
|
|
@@ -7347,6 +9068,12 @@ var treeui_catalog_default = {
|
|
|
7347
9068
|
type: "boolean",
|
|
7348
9069
|
default: "false",
|
|
7349
9070
|
note: "Clip to a single line with an ellipsis."
|
|
9071
|
+
},
|
|
9072
|
+
{
|
|
9073
|
+
name: "preserveWhitespace",
|
|
9074
|
+
type: "boolean",
|
|
9075
|
+
default: "false",
|
|
9076
|
+
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."
|
|
7350
9077
|
}
|
|
7351
9078
|
],
|
|
7352
9079
|
events: [],
|
|
@@ -7360,7 +9087,8 @@ var treeui_catalog_default = {
|
|
|
7360
9087
|
],
|
|
7361
9088
|
behavior: [
|
|
7362
9089
|
"semantic_element_controlled_by_as: true",
|
|
7363
|
-
"token_driven_size_tone_weight: true"
|
|
9090
|
+
"token_driven_size_tone_weight: true",
|
|
9091
|
+
"truncate_takes_precedence_over_preserve_whitespace: true"
|
|
7364
9092
|
],
|
|
7365
9093
|
selection: {
|
|
7366
9094
|
keywords: [],
|
|
@@ -7372,7 +9100,10 @@ var treeui_catalog_default = {
|
|
|
7372
9100
|
required: [],
|
|
7373
9101
|
notes: []
|
|
7374
9102
|
},
|
|
7375
|
-
recipes: [
|
|
9103
|
+
recipes: [
|
|
9104
|
+
"brand-lockup"
|
|
9105
|
+
],
|
|
9106
|
+
practices: []
|
|
7376
9107
|
},
|
|
7377
9108
|
{
|
|
7378
9109
|
name: "TTextarea",
|
|
@@ -7489,7 +9220,8 @@ var treeui_catalog_default = {
|
|
|
7489
9220
|
required: [],
|
|
7490
9221
|
notes: []
|
|
7491
9222
|
},
|
|
7492
|
-
recipes: []
|
|
9223
|
+
recipes: [],
|
|
9224
|
+
practices: []
|
|
7493
9225
|
},
|
|
7494
9226
|
{
|
|
7495
9227
|
name: "TTimeline",
|
|
@@ -7549,7 +9281,8 @@ var treeui_catalog_default = {
|
|
|
7549
9281
|
required: [],
|
|
7550
9282
|
notes: []
|
|
7551
9283
|
},
|
|
7552
|
-
recipes: []
|
|
9284
|
+
recipes: [],
|
|
9285
|
+
practices: []
|
|
7553
9286
|
},
|
|
7554
9287
|
{
|
|
7555
9288
|
name: "TToast",
|
|
@@ -7612,7 +9345,8 @@ var treeui_catalog_default = {
|
|
|
7612
9345
|
},
|
|
7613
9346
|
recipes: [
|
|
7614
9347
|
"confirm-destructive-action"
|
|
7615
|
-
]
|
|
9348
|
+
],
|
|
9349
|
+
practices: []
|
|
7616
9350
|
},
|
|
7617
9351
|
{
|
|
7618
9352
|
name: "TToggleGroup",
|
|
@@ -7729,7 +9463,8 @@ var treeui_catalog_default = {
|
|
|
7729
9463
|
'Use `selectionMode="multiple"` for small visible multi-choice sets.'
|
|
7730
9464
|
]
|
|
7731
9465
|
},
|
|
7732
|
-
recipes: []
|
|
9466
|
+
recipes: [],
|
|
9467
|
+
practices: []
|
|
7733
9468
|
},
|
|
7734
9469
|
{
|
|
7735
9470
|
name: "TTooltip",
|
|
@@ -7841,6 +9576,9 @@ var treeui_catalog_default = {
|
|
|
7841
9576
|
},
|
|
7842
9577
|
recipes: [
|
|
7843
9578
|
"anchored-help"
|
|
9579
|
+
],
|
|
9580
|
+
practices: [
|
|
9581
|
+
"accessible-by-default"
|
|
7844
9582
|
]
|
|
7845
9583
|
},
|
|
7846
9584
|
{
|
|
@@ -7853,7 +9591,7 @@ var treeui_catalog_default = {
|
|
|
7853
9591
|
purpose: "Hierarchical tree view with expansion, keyboard navigation, and single or multiple selection.",
|
|
7854
9592
|
sourceFile: "packages/vue/src/components/TTreeView.vue",
|
|
7855
9593
|
storyFile: "apps/docs/src/stories/TreeView.stories.ts",
|
|
7856
|
-
storyTitle: "Components/Navigation & Disclosure/
|
|
9594
|
+
storyTitle: "Components/Navigation & Disclosure/TreeView",
|
|
7857
9595
|
manifestFile: "docs/ai/COMPONENTS/tree-view.yaml",
|
|
7858
9596
|
props: [
|
|
7859
9597
|
{
|
|
@@ -7963,6 +9701,9 @@ var treeui_catalog_default = {
|
|
|
7963
9701
|
},
|
|
7964
9702
|
recipes: [
|
|
7965
9703
|
"hierarchy-picker"
|
|
9704
|
+
],
|
|
9705
|
+
practices: [
|
|
9706
|
+
"accessible-by-default"
|
|
7966
9707
|
]
|
|
7967
9708
|
}
|
|
7968
9709
|
],
|
|
@@ -9119,7 +10860,8 @@ var formatComponentSummary = (component) => {
|
|
|
9119
10860
|
"Setup",
|
|
9120
10861
|
[...component.setup.required, ...component.setup.notes]
|
|
9121
10862
|
),
|
|
9122
|
-
component.recipes.length > 0 ? `Recipes: ${component.recipes.join(", ")}` : void 0
|
|
10863
|
+
component.recipes.length > 0 ? `Recipes: ${component.recipes.join(", ")}` : void 0,
|
|
10864
|
+
component.practices.length > 0 ? `Practices: ${component.practices.join(", ")}` : void 0
|
|
9123
10865
|
].filter(Boolean);
|
|
9124
10866
|
return lines.join("\n");
|
|
9125
10867
|
};
|
|
@@ -9660,6 +11402,21 @@ var normalizeRecipes = (value) => {
|
|
|
9660
11402
|
};
|
|
9661
11403
|
});
|
|
9662
11404
|
};
|
|
11405
|
+
var normalizePractices = (value) => {
|
|
11406
|
+
if (!Array.isArray(value)) {
|
|
11407
|
+
return [];
|
|
11408
|
+
}
|
|
11409
|
+
return value.map((practice) => {
|
|
11410
|
+
const record = practice;
|
|
11411
|
+
return {
|
|
11412
|
+
id: String(record.id),
|
|
11413
|
+
title: String(record.title),
|
|
11414
|
+
summary: stringifyValue(record.summary) ?? "",
|
|
11415
|
+
rules: normalizeStringList(record.rules),
|
|
11416
|
+
components: normalizeStringList(record.components)
|
|
11417
|
+
};
|
|
11418
|
+
});
|
|
11419
|
+
};
|
|
9663
11420
|
var loadYamlDocuments = (filePath) => (0, import_yaml.parseAllDocuments)(readText(filePath)).map((document) => document.toJSON()).filter((document) => Boolean(document));
|
|
9664
11421
|
var buildStoryIndex = (repoRoot) => {
|
|
9665
11422
|
const storiesDir = import_node_path.default.join(repoRoot, "apps/docs/src/stories");
|
|
@@ -9698,10 +11455,12 @@ var buildCatalogFromRepo = (repoRoot) => {
|
|
|
9698
11455
|
const setupDoc = loadYamlDocuments(import_node_path.default.join(docsDir, "SETUP.yaml"))[0] ?? {};
|
|
9699
11456
|
const recipesDoc = loadYamlDocuments(import_node_path.default.join(docsDir, "RECIPES.yaml"))[0] ?? {};
|
|
9700
11457
|
const contractsDoc = loadYamlDocuments(import_node_path.default.join(docsDir, "CONTRACTS.yaml"))[0] ?? {};
|
|
11458
|
+
const practicesDoc = JSON.parse(readText(import_node_path.default.join(docsDir, "practices.json")));
|
|
9701
11459
|
const componentProfiles = selectionDoc.component_profiles ?? {};
|
|
9702
11460
|
const componentSetup = setupDoc.component_setup ?? {};
|
|
9703
11461
|
const aliasMap = contractsDoc.compatibility_aliases ?? {};
|
|
9704
11462
|
const recipes = normalizeRecipes(recipesDoc.recipes);
|
|
11463
|
+
const practices = normalizePractices(practicesDoc.practices);
|
|
9705
11464
|
const components = import_node_fs.default.readdirSync(componentsDir).filter((fileName) => fileName.endsWith(".yaml")).flatMap((fileName) => {
|
|
9706
11465
|
const filePath = import_node_path.default.join(componentsDir, fileName);
|
|
9707
11466
|
return loadYamlDocuments(filePath).flatMap((document) => {
|
|
@@ -9720,6 +11479,7 @@ var buildCatalogFromRepo = (repoRoot) => {
|
|
|
9720
11479
|
)
|
|
9721
11480
|
);
|
|
9722
11481
|
const componentRecipes = recipes.filter((recipe) => recipe.compose.includes(name)).map((recipe) => recipe.id);
|
|
11482
|
+
const componentPractices = practices.filter((practice) => practice.components.includes(name)).map((practice) => practice.id);
|
|
9723
11483
|
const entry = {
|
|
9724
11484
|
name,
|
|
9725
11485
|
legacyAlias: aliasMap[name] ?? aliases.find((alias) => alias.startsWith("Tree")),
|
|
@@ -9741,7 +11501,8 @@ var buildCatalogFromRepo = (repoRoot) => {
|
|
|
9741
11501
|
behavior: normalizeStringList(document.behavior),
|
|
9742
11502
|
selection,
|
|
9743
11503
|
setup: setup2,
|
|
9744
|
-
recipes: componentRecipes
|
|
11504
|
+
recipes: componentRecipes,
|
|
11505
|
+
practices: componentPractices
|
|
9745
11506
|
};
|
|
9746
11507
|
return [entry];
|
|
9747
11508
|
});
|
|
@@ -9784,6 +11545,7 @@ var buildCatalogFromRepo = (repoRoot) => {
|
|
|
9784
11545
|
packageVersion: vuePackage.version,
|
|
9785
11546
|
decisionGuides: normalizeDecisionGuides(selectionDoc.decision_guides),
|
|
9786
11547
|
recipes,
|
|
11548
|
+
practices,
|
|
9787
11549
|
setup,
|
|
9788
11550
|
components,
|
|
9789
11551
|
tokens: buildTokenEntries()
|
|
@@ -9819,6 +11581,12 @@ var resourceList = [
|
|
|
9819
11581
|
description: "Reusable multi-component composition recipes.",
|
|
9820
11582
|
mimeType: "application/json"
|
|
9821
11583
|
},
|
|
11584
|
+
{
|
|
11585
|
+
uri: "treeui://practices",
|
|
11586
|
+
name: "TreeUI practices",
|
|
11587
|
+
description: "Named UX practices and the components that follow them.",
|
|
11588
|
+
mimeType: "application/json"
|
|
11589
|
+
},
|
|
9822
11590
|
{
|
|
9823
11591
|
uri: "treeui://tokens",
|
|
9824
11592
|
name: "TreeUI design tokens",
|
|
@@ -9852,6 +11620,9 @@ var readResourcePayload = (uri) => {
|
|
|
9852
11620
|
if (uri === "treeui://recipes") {
|
|
9853
11621
|
return catalog.recipes;
|
|
9854
11622
|
}
|
|
11623
|
+
if (uri === "treeui://practices") {
|
|
11624
|
+
return catalog.practices;
|
|
11625
|
+
}
|
|
9855
11626
|
if (uri === "treeui://tokens") {
|
|
9856
11627
|
return catalog.tokens;
|
|
9857
11628
|
}
|