@treeui/mcp 0.4.0 → 0.5.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/index.cjs CHANGED
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  buildCatalogFromRepo: () => buildCatalogFromRepo,
34
+ buildTokenEntries: () => buildTokenEntries,
34
35
  catalog: () => catalog,
35
36
  createTreeuiMcpServer: () => createTreeuiMcpServer,
36
37
  findComponent: () => findComponent,
@@ -38,18 +39,20 @@ __export(index_exports, {
38
39
  formatRecipeResults: () => formatRecipeResults,
39
40
  formatSearchResults: () => formatSearchResults,
40
41
  formatSetupGuide: () => formatSetupGuide,
42
+ formatTokenResults: () => formatTokenResults,
41
43
  getRepoRootFromPackageRoot: () => getRepoRootFromPackageRoot,
42
44
  recommendComponents: () => recommendComponents,
43
45
  searchComponents: () => searchComponents,
44
- searchRecipes: () => searchRecipes
46
+ searchRecipes: () => searchRecipes,
47
+ searchTokens: () => searchTokens
45
48
  });
46
49
  module.exports = __toCommonJS(index_exports);
47
50
 
48
51
  // src/generated/treeui.catalog.json
49
52
  var treeui_catalog_default = {
50
- generatedAt: "2026-07-18T01:52:38.578Z",
53
+ generatedAt: "2026-07-18T23:35:26.876Z",
51
54
  packageName: "@treeui/vue",
52
- packageVersion: "0.14.0",
55
+ packageVersion: "0.16.0",
53
56
  decisionGuides: [
54
57
  {
55
58
  id: "single-choice",
@@ -199,6 +202,44 @@ var treeui_catalog_default = {
199
202
  }
200
203
  ]
201
204
  },
205
+ {
206
+ id: "navigate-or-act",
207
+ question: "Navigate somewhere vs. perform an action",
208
+ options: [
209
+ {
210
+ use: "TLink",
211
+ when: [
212
+ "Activating it changes the URL \u2014 an external link, a route, or an in-page anchor.",
213
+ "It should be openable in a new tab, copyable, and crawlable."
214
+ ],
215
+ notes: []
216
+ },
217
+ {
218
+ use: "TButton",
219
+ when: [
220
+ "Activating it runs behavior on the current page \u2014 submit, open an overlay, delete, toggle.",
221
+ "It needs sizes, action variants, or a loading state."
222
+ ],
223
+ notes: [
224
+ 'Use `variant="ghost"` when an action needs to look understated like a link.'
225
+ ]
226
+ },
227
+ {
228
+ use: "TNavMenu",
229
+ when: [
230
+ "The links are app-section navigation inside a shell or sidebar."
231
+ ],
232
+ notes: []
233
+ },
234
+ {
235
+ use: "TBreadcrumb",
236
+ when: [
237
+ "The links express where the current page sits in a hierarchy."
238
+ ],
239
+ notes: []
240
+ }
241
+ ]
242
+ },
202
243
  {
203
244
  id: "feedback-choice",
204
245
  question: "Communicate status or feedback",
@@ -993,6 +1034,22 @@ var treeui_catalog_default = {
993
1034
  type: "boolean",
994
1035
  default: "true"
995
1036
  },
1037
+ {
1038
+ name: "showCollapseButton",
1039
+ type: "boolean",
1040
+ 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."
1042
+ },
1043
+ {
1044
+ name: "collapseLabel",
1045
+ type: "string",
1046
+ default: "Collapse sidebar"
1047
+ },
1048
+ {
1049
+ name: "expandLabel",
1050
+ type: "string",
1051
+ default: "Expand sidebar"
1052
+ },
996
1053
  {
997
1054
  name: "menuLabel",
998
1055
  type: "string",
@@ -1027,14 +1084,26 @@ var treeui_catalog_default = {
1027
1084
  {
1028
1085
  name: "header"
1029
1086
  },
1087
+ {
1088
+ name: "header-start"
1089
+ },
1090
+ {
1091
+ name: "sidebar-header"
1092
+ },
1030
1093
  {
1031
1094
  name: "sidebar"
1032
1095
  },
1096
+ {
1097
+ name: "sidebar-footer"
1098
+ },
1033
1099
  {
1034
1100
  name: "default"
1035
1101
  },
1036
1102
  {
1037
1103
  name: "menu-icon"
1104
+ },
1105
+ {
1106
+ name: "collapse-icon"
1038
1107
  }
1039
1108
  ],
1040
1109
  a11y: [
@@ -1062,7 +1131,10 @@ var treeui_catalog_default = {
1062
1131
  "left_and_right_variants: true",
1063
1132
  "locks_body_scroll_while_drawer_open: true",
1064
1133
  "overlay_click_closes_when_enabled: true",
1065
- "exposes_slot_props_with_mobile_collapsed_and_toggles: true"
1134
+ "exposes_slot_props_with_mobile_collapsed_and_toggles: true",
1135
+ "sidebar_footer_pinned_to_bottom: true",
1136
+ "sidebar_header_and_footer_inset_to_align_with_nav_icons: true",
1137
+ "header_mirrors_shell_columns_when_header_start_is_used: true"
1066
1138
  ],
1067
1139
  selection: {
1068
1140
  keywords: [
@@ -1371,6 +1443,18 @@ var treeui_catalog_default = {
1371
1443
  name: "type",
1372
1444
  type: "button | submit | reset",
1373
1445
  default: "button"
1446
+ },
1447
+ {
1448
+ name: "block",
1449
+ type: "boolean",
1450
+ default: "false",
1451
+ note: "Stretches the button to the full width of its container. Useful for menu rows and mobile CTAs."
1452
+ },
1453
+ {
1454
+ name: "align",
1455
+ type: "start | center | end",
1456
+ default: "center",
1457
+ note: "Content alignment; only meaningful together with `block`. Use `start` for left-aligned icon+label menu rows."
1374
1458
  }
1375
1459
  ],
1376
1460
  events: [
@@ -1436,7 +1520,6 @@ var treeui_catalog_default = {
1436
1520
  values: [
1437
1521
  "outline",
1438
1522
  "soft",
1439
- "solid",
1440
1523
  "inset"
1441
1524
  ]
1442
1525
  },
@@ -1475,7 +1558,8 @@ var treeui_catalog_default = {
1475
1558
  a11y: [],
1476
1559
  behavior: [
1477
1560
  "body_wrapper_class: t-card__body",
1478
- "solid_variant_rescopes_color_tokens_for_nested_content: true"
1561
+ '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
+ "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."
1479
1563
  ],
1480
1564
  selection: {
1481
1565
  keywords: [
@@ -1804,6 +1888,92 @@ var treeui_catalog_default = {
1804
1888
  },
1805
1889
  recipes: []
1806
1890
  },
1891
+ {
1892
+ name: "TColorSwatch",
1893
+ aliases: [],
1894
+ package: "@treeui/vue",
1895
+ kind: "form",
1896
+ category: "Data Entry",
1897
+ status: "available",
1898
+ purpose: "Pick a colour from a row of preset swatches, with an optional native colour input for an arbitrary value. Built for accent/brand pickers.",
1899
+ sourceFile: "packages/vue/src/components/TColorSwatch.vue",
1900
+ storyFile: "apps/docs/src/stories/ColorSwatch.stories.ts",
1901
+ storyTitle: "Components/Data Entry/ColorSwatch",
1902
+ manifestFile: "docs/ai/COMPONENTS/color-swatch.yaml",
1903
+ props: [
1904
+ {
1905
+ name: "modelValue",
1906
+ type: "string",
1907
+ default: "undefined",
1908
+ note: "Selected colour as a hex string. Matching is case-insensitive."
1909
+ },
1910
+ {
1911
+ name: "options",
1912
+ type: "TColorSwatchOption[]",
1913
+ default: "[]",
1914
+ note: "Preset swatches, each `{ label, value }`. `label` becomes the button's accessible name."
1915
+ },
1916
+ {
1917
+ name: "allowCustom",
1918
+ type: "boolean",
1919
+ default: "false",
1920
+ note: 'Appends a native `<input type="color">` for values outside the presets.'
1921
+ },
1922
+ {
1923
+ name: "size",
1924
+ type: "TSize",
1925
+ default: "md",
1926
+ values: [
1927
+ "sm",
1928
+ "md",
1929
+ "lg"
1930
+ ]
1931
+ },
1932
+ {
1933
+ name: "label",
1934
+ type: "string",
1935
+ default: "Color",
1936
+ note: 'Accessible label for the swatch group (`role="group"`).'
1937
+ },
1938
+ {
1939
+ name: "customLabel",
1940
+ type: "string",
1941
+ default: "Custom color"
1942
+ },
1943
+ {
1944
+ name: "disabled",
1945
+ type: "boolean",
1946
+ default: "false"
1947
+ }
1948
+ ],
1949
+ events: [
1950
+ {
1951
+ name: "update:modelValue"
1952
+ }
1953
+ ],
1954
+ slots: [],
1955
+ a11y: [
1956
+ 'Wrapper is `role="group"` labelled by `label`.',
1957
+ "Each swatch is a native button with `aria-pressed` reflecting selection and `aria-label` from the option label.",
1958
+ "Selection is conveyed by an outline (not colour alone), since the swatch's own colour is the content."
1959
+ ],
1960
+ behavior: [
1961
+ "emits_on_preset_click: true",
1962
+ "emits_on_custom_input: true",
1963
+ "blocks_interaction_when_disabled: true"
1964
+ ],
1965
+ selection: {
1966
+ keywords: [],
1967
+ useWhen: [],
1968
+ avoidWhen: [],
1969
+ alternatives: []
1970
+ },
1971
+ setup: {
1972
+ required: [],
1973
+ notes: []
1974
+ },
1975
+ recipes: []
1976
+ },
1807
1977
  {
1808
1978
  name: "TCombobox",
1809
1979
  aliases: [],
@@ -2154,12 +2324,14 @@ var treeui_catalog_default = {
2154
2324
  {
2155
2325
  name: "padded",
2156
2326
  type: "boolean",
2157
- default: "true"
2327
+ default: "true",
2328
+ note: "Adds `.is-padded`, i.e. an inline padding of `clamp(var(--tree-space-4), 3vw, var(--tree-space-6))`.\n"
2158
2329
  },
2159
2330
  {
2160
2331
  name: "centered",
2161
2332
  type: "boolean",
2162
- default: "true"
2333
+ default: "true",
2334
+ note: "Adds `.is-centered`, i.e. `margin-inline: auto`."
2163
2335
  }
2164
2336
  ],
2165
2337
  events: [],
@@ -3054,6 +3226,7 @@ var treeui_catalog_default = {
3054
3226
  "role: menu",
3055
3227
  "trigger_aria_haspopup: menu",
3056
3228
  "trigger_aria_expanded: true",
3229
+ "trigger_aria_controls: menu id, while open",
3057
3230
  "aria_disabled_on_disabled_items: true",
3058
3231
  "focus_visible_on_trigger: true",
3059
3232
  "keyboard_arrow_navigation: true",
@@ -3063,9 +3236,11 @@ var treeui_catalog_default = {
3063
3236
  ],
3064
3237
  behavior: [
3065
3238
  "outside_click_closes_menu: true",
3066
- "focus_restores_on_close: true",
3239
+ "outside_click_restores_focus: false",
3067
3240
  "chevron_rotates_when_open: true",
3068
- "menu_grows_to_fit_items_without_wrapping: true"
3241
+ "menu_grows_to_fit_items_without_wrapping: true",
3242
+ "opening_focuses_first_enabled_item: true",
3243
+ '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. It deliberately does NOT move focus on an outside click, where the pointer has already placed focus elsewhere.\\n","applies_to_custom_trigger":true}'
3069
3244
  ],
3070
3245
  selection: {
3071
3246
  keywords: [
@@ -3461,7 +3636,7 @@ var treeui_catalog_default = {
3461
3636
  name: "htmlFor",
3462
3637
  type: "string",
3463
3638
  required: false,
3464
- description: "The id of the associated form control, used on the <label> for attribute."
3639
+ description: "Rendered verbatim as the <label for> attribute. There is no id generation: when omitted, the label carries no `for` and is NOT associated with any control. The consumer must pass this AND set the same value as `id` on the child control.\n"
3465
3640
  },
3466
3641
  {
3467
3642
  name: "error",
@@ -3519,10 +3694,11 @@ var treeui_catalog_default = {
3519
3694
  }
3520
3695
  ],
3521
3696
  a11y: [
3522
- "Uses native <label> element with for attribute for input association.",
3697
+ "Renders a native <label> element, but ONLY when `label` or the `label` slot is provided.",
3523
3698
  "Error messages are wrapped in role='alert' for screen reader announcements.",
3524
3699
  "Required indicator (*) is aria-hidden to avoid redundant announcements; use aria-required on the input itself.",
3525
- "Error takes precedence over hint to avoid conflicting messages."
3700
+ "Error takes precedence over hint to avoid conflicting messages.",
3701
+ "Extra attrs land on the root <div> (inheritAttrs: false), not on the child control."
3526
3702
  ],
3527
3703
  behavior: [],
3528
3704
  selection: {
@@ -3787,6 +3963,20 @@ var treeui_catalog_default = {
3787
3963
  "lg"
3788
3964
  ]
3789
3965
  },
3966
+ {
3967
+ name: "width",
3968
+ type: "TFieldWidth",
3969
+ default: "full",
3970
+ values: [
3971
+ "xs",
3972
+ "sm",
3973
+ "md",
3974
+ "lg",
3975
+ "xl",
3976
+ "full"
3977
+ ],
3978
+ note: "Inline-size cap (max-inline-size). Fluid by default; use instead of an inline width style."
3979
+ },
3790
3980
  {
3791
3981
  name: "disabled",
3792
3982
  type: "boolean",
@@ -3871,6 +4061,43 @@ var treeui_catalog_default = {
3871
4061
  "tag-input"
3872
4062
  ]
3873
4063
  },
4064
+ {
4065
+ name: "TKbd",
4066
+ aliases: [],
4067
+ package: "@treeui/vue",
4068
+ kind: "primitive",
4069
+ category: "Data Display",
4070
+ status: "available",
4071
+ purpose: "Keyboard-key hint (e.g. \u2318K, Esc, Ctrl) rendered as a native <kbd> with the library's chip styling.",
4072
+ sourceFile: "packages/vue/src/components/TKbd.vue",
4073
+ storyFile: "apps/docs/src/stories/Kbd.stories.ts",
4074
+ storyTitle: "Components/Data Display/Kbd",
4075
+ manifestFile: "docs/ai/COMPONENTS/kbd.yaml",
4076
+ props: [],
4077
+ events: [],
4078
+ slots: [
4079
+ {
4080
+ name: "default"
4081
+ }
4082
+ ],
4083
+ a11y: [
4084
+ "Uses the native <kbd> element so assistive tech announces it as keyboard input."
4085
+ ],
4086
+ behavior: [
4087
+ "renders_native_kbd_element: true"
4088
+ ],
4089
+ selection: {
4090
+ keywords: [],
4091
+ useWhen: [],
4092
+ avoidWhen: [],
4093
+ alternatives: []
4094
+ },
4095
+ setup: {
4096
+ required: [],
4097
+ notes: []
4098
+ },
4099
+ recipes: []
4100
+ },
3874
4101
  {
3875
4102
  name: "TLink",
3876
4103
  aliases: [],
@@ -3932,10 +4159,39 @@ var treeui_catalog_default = {
3932
4159
  ],
3933
4160
  behavior: [],
3934
4161
  selection: {
3935
- keywords: [],
3936
- useWhen: [],
3937
- avoidWhen: [],
3938
- alternatives: []
4162
+ keywords: [
4163
+ "link",
4164
+ "anchor",
4165
+ "hyperlink",
4166
+ "navigation",
4167
+ "router link",
4168
+ "external link",
4169
+ "href",
4170
+ "to"
4171
+ ],
4172
+ useWhen: [
4173
+ "The action navigates somewhere \u2014 a URL, a route, or an anchor on the page.",
4174
+ "You want consistent link styling with `default`, `muted`, or `danger` emphasis.",
4175
+ "You want a component that renders RouterLink when vue-router is installed and a plain <a> when it is not, without branching in the template."
4176
+ ],
4177
+ avoidWhen: [
4178
+ "The control performs an action rather than navigating (submit, open a dialog, delete) \u2014 that is a button, even if it looks like a link.",
4179
+ "You need a full call-to-action surface with variants, sizes, and a loading state."
4180
+ ],
4181
+ alternatives: [
4182
+ {
4183
+ component: "TButton",
4184
+ when: 'The control performs an action. Use `variant="ghost"` for a low-emphasis, link-like button.'
4185
+ },
4186
+ {
4187
+ component: "TBreadcrumb",
4188
+ when: "The links form a hierarchy trail."
4189
+ },
4190
+ {
4191
+ component: "TNavMenu",
4192
+ when: "The links are app-section navigation in a shell or sidebar."
4193
+ }
4194
+ ]
3939
4195
  },
3940
4196
  setup: {
3941
4197
  required: [],
@@ -3949,7 +4205,8 @@ var treeui_catalog_default = {
3949
4205
  package: "@treeui/vue",
3950
4206
  category: "Form",
3951
4207
  status: "stable",
3952
- description: "A rich Markdown editor with live preview, toolbar formatting, keyboard shortcuts, and image paste/drop upload support.\n",
4208
+ description: "A Markdown editor with an always-visible side-by-side live preview, toolbar formatting, keyboard shortcuts, and image paste/drop upload support.\n",
4209
+ sourceFile: "packages/vue/src/components/TMarkdownEditor.vue",
3953
4210
  storyFile: "apps/docs/src/stories/MarkdownEditor.stories.ts",
3954
4211
  storyTitle: "Components/Form/MarkdownEditor",
3955
4212
  manifestFile: "docs/ai/COMPONENTS/markdown-editor.yaml",
@@ -3985,6 +4242,12 @@ var treeui_catalog_default = {
3985
4242
  type: "(file: File) => Promise<string>",
3986
4243
  default: "undefined",
3987
4244
  description: "Async function that receives a File and returns the uploaded image URL. When not provided, pasting an image inserts an empty markdown image tag.\n"
4245
+ },
4246
+ {
4247
+ name: "sanitize",
4248
+ type: "(html: string) => string",
4249
+ default: "undefined",
4250
+ description: "Optional extra sanitizer applied to the rendered preview HTML as the final step, after the built-in rendering. It is an ADDITIVE escape hatch, not a toggle: pass DOMPurify or a stricter policy of your own instead of forking the component.\n"
3988
4251
  }
3989
4252
  ],
3990
4253
  events: [
@@ -4011,12 +4274,12 @@ var treeui_catalog_default = {
4011
4274
  }
4012
4275
  ],
4013
4276
  a11y: [
4014
- 'Toolbar has role="toolbar" with aria-label.',
4015
- 'Tab buttons use role="tab" and aria-selected.',
4016
- 'Preview pane has aria-label="Markdown preview".',
4277
+ 'Toolbar has role="toolbar" with aria-label="Markdown formatting".',
4278
+ 'Toolbar groups are separated by elements with role="separator".',
4279
+ 'Preview pane carries aria-label="Markdown preview".',
4017
4280
  'Upload status bar uses role="status" and aria-live="polite".',
4018
4281
  "All toolbar buttons have title attributes describing the action.",
4019
- "Textarea has aria-label for screen readers."
4282
+ "Textarea has aria-label (mirrors the placeholder text)."
4020
4283
  ],
4021
4284
  behavior: [],
4022
4285
  selection: {
@@ -5092,7 +5355,7 @@ var treeui_catalog_default = {
5092
5355
  props: [
5093
5356
  {
5094
5357
  name: "plans",
5095
- type: "PricingPlan[]",
5358
+ type: "TPricingPlan[]",
5096
5359
  required: true,
5097
5360
  description: "Array of plan objects. Each plan supports the same props as PricingCard (title, description, price, currency, period, features, highlighted, badge, buttonText, disabled).\n"
5098
5361
  },
@@ -5113,14 +5376,14 @@ var treeui_catalog_default = {
5113
5376
  {
5114
5377
  name: "select",
5115
5378
  description: "Emitted when any plan's CTA is clicked. Provides the plan data and index.",
5116
- payload: "[plan: PricingPlan, index: number]"
5379
+ payload: "[plan: TPricingPlan, index: number]"
5117
5380
  }
5118
5381
  ],
5119
5382
  slots: [
5120
5383
  {
5121
5384
  name: "plan",
5122
5385
  description: "Custom rendering for each plan card.",
5123
- note: "{ plan: PricingPlan, index: number }"
5386
+ note: "{ plan: TPricingPlan, index: number }"
5124
5387
  }
5125
5388
  ],
5126
5389
  a11y: [
@@ -5279,7 +5542,7 @@ var treeui_catalog_default = {
5279
5542
  package: "@treeui/vue",
5280
5543
  category: "Feedback",
5281
5544
  status: "draft",
5282
- description: "Determinate and indeterminate progress indicator. Supports linear bar and circular ring variants.\n",
5545
+ description: "Determinate and indeterminate progress indicator. Renders a linear bar only \u2014 there is no circular, ring, or radial variant, and no `variant`/`shape`/`type` prop. Compose one yourself if you need it.\n",
5283
5546
  storyFile: "apps/docs/src/stories/Progress.stories.ts",
5284
5547
  storyTitle: "Components/Feedback/Progress",
5285
5548
  manifestFile: "docs/ai/COMPONENTS/progress.yaml",
@@ -5319,7 +5582,8 @@ var treeui_catalog_default = {
5319
5582
  "role: progressbar",
5320
5583
  'attributes: ["aria-valuenow (omitted when indeterminate)","aria-valuemin (always 0)","aria-valuemax (always 100)","aria-label"]',
5321
5584
  "keyboard:",
5322
- "notes: Indeterminate state omits aria-valuenow so assistive tech announces the bar as indeterminate."
5585
+ "notes: Indeterminate state omits aria-valuenow so assistive tech announces the bar as indeterminate.",
5586
+ "value_is_normalized: aria-valuenow is `value / max` expressed as a 0\u2013100 percentage, not the raw `value`. aria-valuemax stays 100 regardless of the `max` prop, so the two always agree. The `label` is also repeated in a visually hidden span."
5323
5587
  ],
5324
5588
  behavior: [],
5325
5589
  selection: {
@@ -5521,6 +5785,20 @@ var treeui_catalog_default = {
5521
5785
  "lg"
5522
5786
  ]
5523
5787
  },
5788
+ {
5789
+ name: "width",
5790
+ type: "TFieldWidth",
5791
+ default: "full",
5792
+ values: [
5793
+ "xs",
5794
+ "sm",
5795
+ "md",
5796
+ "lg",
5797
+ "xl",
5798
+ "full"
5799
+ ],
5800
+ note: "Inline-size cap (max-inline-size). Fluid by default; use instead of an inline width style."
5801
+ },
5524
5802
  {
5525
5803
  name: "disabled",
5526
5804
  type: "boolean",
@@ -5675,10 +5953,13 @@ var treeui_catalog_default = {
5675
5953
  ],
5676
5954
  slots: [
5677
5955
  {
5678
- name: "item"
5956
+ name: "item",
5957
+ description: `Replaces the default row body (indicator, label, description, meta). Renders INSIDE the row's <button role="option">.
5958
+ `
5679
5959
  },
5680
5960
  {
5681
- name: "empty"
5961
+ name: "empty",
5962
+ description: "Replaces `emptyText` when `items` is empty."
5682
5963
  }
5683
5964
  ],
5684
5965
  a11y: [
@@ -5691,7 +5972,8 @@ var treeui_catalog_default = {
5691
5972
  ],
5692
5973
  behavior: [
5693
5974
  "can_be_controlled_or_uncontrolled: true",
5694
- "supports_rich_row_rendering_via_slot: true",
5975
+ "supports_presentational_row_slot: true",
5976
+ "supports_interactive_content_in_rows: false",
5695
5977
  "empty_state_text_supported: true"
5696
5978
  ],
5697
5979
  selection: {
@@ -5935,6 +6217,46 @@ var treeui_catalog_default = {
5935
6217
  },
5936
6218
  recipes: []
5937
6219
  },
6220
+ {
6221
+ name: "TSpacer",
6222
+ aliases: [],
6223
+ package: "@treeui/vue",
6224
+ kind: "layout",
6225
+ category: "Layout",
6226
+ status: "available",
6227
+ purpose: "Flexible spacer that absorbs free space between siblings in a flex layout (e.g. TStack), replacing hand-written margin:auto / flex:1.",
6228
+ sourceFile: "packages/vue/src/components/TSpacer.vue",
6229
+ storyFile: "apps/docs/src/stories/Spacer.stories.ts",
6230
+ storyTitle: "Components/Layout/Spacer",
6231
+ manifestFile: "docs/ai/COMPONENTS/spacer.yaml",
6232
+ props: [
6233
+ {
6234
+ name: "as",
6235
+ type: "string",
6236
+ default: "div"
6237
+ }
6238
+ ],
6239
+ events: [],
6240
+ slots: [],
6241
+ a11y: [
6242
+ "Rendered with aria-hidden='true'; it is a layout-only element with no content."
6243
+ ],
6244
+ behavior: [
6245
+ "grows_to_fill_free_space: true",
6246
+ "pushes_siblings_apart_or_to_ends: true"
6247
+ ],
6248
+ selection: {
6249
+ keywords: [],
6250
+ useWhen: [],
6251
+ avoidWhen: [],
6252
+ alternatives: []
6253
+ },
6254
+ setup: {
6255
+ required: [],
6256
+ notes: []
6257
+ },
6258
+ recipes: []
6259
+ },
5938
6260
  {
5939
6261
  name: "TSparkline",
5940
6262
  aliases: [],
@@ -6108,49 +6430,125 @@ var treeui_catalog_default = {
6108
6430
  recipes: []
6109
6431
  },
6110
6432
  {
6111
- name: "TStack",
6433
+ name: "TSplit",
6112
6434
  aliases: [],
6113
6435
  package: "@treeui/vue",
6114
6436
  kind: "layout",
6115
6437
  category: "Layout",
6116
6438
  status: "available",
6117
- purpose: "One-dimensional spacing and alignment wrapper for vertical or horizontal compositions.",
6118
- sourceFile: "packages/vue/src/components/TStack.vue",
6119
- storyFile: "apps/docs/src/stories/Stack.stories.ts",
6120
- storyTitle: "Components/Layout/Stack",
6121
- manifestFile: "docs/ai/COMPONENTS/stack.yaml",
6439
+ purpose: "Responsive two-pane layout (a wider main pane + a narrower aside) that sits side by side and stacks to one column when narrow \u2014 no media query.",
6440
+ sourceFile: "packages/vue/src/components/TSplit.vue",
6441
+ storyFile: "apps/docs/src/stories/Split.stories.ts",
6442
+ storyTitle: "Components/Layout/Split",
6443
+ manifestFile: "docs/ai/COMPONENTS/split.yaml",
6122
6444
  props: [
6123
6445
  {
6124
6446
  name: "as",
6125
6447
  type: "string",
6126
6448
  default: "div"
6127
6449
  },
6128
- {
6129
- name: "direction",
6130
- type: "TStackDirection",
6131
- default: "vertical",
6132
- values: [
6133
- "vertical",
6134
- "horizontal"
6135
- ]
6136
- },
6137
6450
  {
6138
6451
  name: "gap",
6139
6452
  type: "string",
6140
- default: "var(--tree-space-4)"
6453
+ default: "var(--tree-space-5)"
6141
6454
  },
6142
6455
  {
6143
- name: "align",
6144
- type: "string",
6145
- default: "stretch"
6456
+ name: "ratio",
6457
+ type: "number",
6458
+ default: "2",
6459
+ note: "How many times faster the main pane grows than the aside pane."
6146
6460
  },
6147
6461
  {
6148
- name: "justify",
6462
+ name: "minWidth",
6149
6463
  type: "string",
6150
- default: "flex-start"
6464
+ default: "18rem",
6465
+ note: "Min width each pane keeps before the layout wraps to a single column (flex-wrap, no @media)."
6151
6466
  },
6152
6467
  {
6153
- name: "wrap",
6468
+ name: "side",
6469
+ type: "start | end",
6470
+ default: "end",
6471
+ note: "Which side the aside pane sits on when side by side."
6472
+ },
6473
+ {
6474
+ name: "align",
6475
+ type: "string",
6476
+ default: "start",
6477
+ note: "Cross-axis alignment (align-items)."
6478
+ }
6479
+ ],
6480
+ events: [],
6481
+ slots: [
6482
+ {
6483
+ name: "default"
6484
+ },
6485
+ {
6486
+ name: "aside"
6487
+ }
6488
+ ],
6489
+ a11y: [
6490
+ "Layout-only wrapper; semantics come from the slotted content."
6491
+ ],
6492
+ behavior: [
6493
+ "wraps_to_single_column_when_narrow: true",
6494
+ "media_query_free: true"
6495
+ ],
6496
+ selection: {
6497
+ keywords: [],
6498
+ useWhen: [],
6499
+ avoidWhen: [],
6500
+ alternatives: []
6501
+ },
6502
+ setup: {
6503
+ required: [],
6504
+ notes: []
6505
+ },
6506
+ recipes: []
6507
+ },
6508
+ {
6509
+ name: "TStack",
6510
+ aliases: [],
6511
+ package: "@treeui/vue",
6512
+ kind: "layout",
6513
+ category: "Layout",
6514
+ status: "available",
6515
+ purpose: "One-dimensional spacing and alignment wrapper for vertical or horizontal compositions.",
6516
+ sourceFile: "packages/vue/src/components/TStack.vue",
6517
+ storyFile: "apps/docs/src/stories/Stack.stories.ts",
6518
+ storyTitle: "Components/Layout/Stack",
6519
+ manifestFile: "docs/ai/COMPONENTS/stack.yaml",
6520
+ props: [
6521
+ {
6522
+ name: "as",
6523
+ type: "string",
6524
+ default: "div"
6525
+ },
6526
+ {
6527
+ name: "direction",
6528
+ type: "TStackDirection",
6529
+ default: "vertical",
6530
+ values: [
6531
+ "vertical",
6532
+ "horizontal"
6533
+ ]
6534
+ },
6535
+ {
6536
+ name: "gap",
6537
+ type: "string",
6538
+ default: "var(--tree-space-4)"
6539
+ },
6540
+ {
6541
+ name: "align",
6542
+ type: "string",
6543
+ default: "stretch"
6544
+ },
6545
+ {
6546
+ name: "justify",
6547
+ type: "string",
6548
+ default: "flex-start"
6549
+ },
6550
+ {
6551
+ name: "wrap",
6154
6552
  type: "boolean",
6155
6553
  default: "false"
6156
6554
  },
@@ -6158,6 +6556,12 @@ var treeui_catalog_default = {
6158
6556
  name: "reverse",
6159
6557
  type: "boolean",
6160
6558
  default: "false"
6559
+ },
6560
+ {
6561
+ name: "grow",
6562
+ type: "boolean",
6563
+ default: "false",
6564
+ note: "Expands the stack to fill available space along its parent's main axis (flex: 1 with min-size 0). Use it to make a sidebar column fill its container height."
6161
6565
  }
6162
6566
  ],
6163
6567
  events: [],
@@ -6205,6 +6609,80 @@ var treeui_catalog_default = {
6205
6609
  "chart-surface"
6206
6610
  ]
6207
6611
  },
6612
+ {
6613
+ name: "TStackItem",
6614
+ aliases: [],
6615
+ package: "@treeui/vue",
6616
+ kind: "layout",
6617
+ category: "Layout",
6618
+ status: "available",
6619
+ purpose: "Per-child flex control inside a TStack \u2014 grow, shrink, basis, min width and align-self \u2014 so one item can fill the row without hand-written CSS.",
6620
+ sourceFile: "packages/vue/src/components/TStackItem.vue",
6621
+ storyFile: "apps/docs/src/stories/StackItem.stories.ts",
6622
+ storyTitle: "Components/Layout/StackItem",
6623
+ manifestFile: "docs/ai/COMPONENTS/stack-item.yaml",
6624
+ props: [
6625
+ {
6626
+ name: "as",
6627
+ type: "string",
6628
+ default: "div"
6629
+ },
6630
+ {
6631
+ name: "grow",
6632
+ type: "boolean | number",
6633
+ default: "false",
6634
+ note: "true = flex-grow 1; a number sets the grow factor."
6635
+ },
6636
+ {
6637
+ name: "shrink",
6638
+ type: "boolean | number",
6639
+ default: "undefined",
6640
+ note: "false prevents shrinking; a number sets the shrink factor."
6641
+ },
6642
+ {
6643
+ name: "basis",
6644
+ type: "string",
6645
+ default: "undefined",
6646
+ note: "flex-basis (initial main-axis size)."
6647
+ },
6648
+ {
6649
+ name: "minWidth",
6650
+ type: "string",
6651
+ default: "undefined",
6652
+ note: "Minimum main-axis size before it wraps/shrinks."
6653
+ },
6654
+ {
6655
+ name: "align",
6656
+ type: "string",
6657
+ default: "undefined",
6658
+ note: "Per-item cross-axis alignment (align-self)."
6659
+ }
6660
+ ],
6661
+ events: [],
6662
+ slots: [
6663
+ {
6664
+ name: "default"
6665
+ }
6666
+ ],
6667
+ a11y: [
6668
+ "Layout-only wrapper; semantics come from the slotted content."
6669
+ ],
6670
+ behavior: [
6671
+ "controls_single_flex_child: true",
6672
+ "defaults_min_inline_size_zero: true"
6673
+ ],
6674
+ selection: {
6675
+ keywords: [],
6676
+ useWhen: [],
6677
+ avoidWhen: [],
6678
+ alternatives: []
6679
+ },
6680
+ setup: {
6681
+ required: [],
6682
+ notes: []
6683
+ },
6684
+ recipes: []
6685
+ },
6208
6686
  {
6209
6687
  name: "TStat",
6210
6688
  aliases: [],
@@ -6676,7 +7154,7 @@ var treeui_catalog_default = {
6676
7154
  ],
6677
7155
  slots: [
6678
7156
  {
6679
- name: "unnamed"
7157
+ name: "default"
6680
7158
  }
6681
7159
  ],
6682
7160
  a11y: [
@@ -6807,6 +7285,95 @@ var treeui_catalog_default = {
6807
7285
  "tag-input"
6808
7286
  ]
6809
7287
  },
7288
+ {
7289
+ name: "TText",
7290
+ aliases: [],
7291
+ package: "@treeui/vue",
7292
+ kind: "primitive",
7293
+ category: "Data Display",
7294
+ status: "available",
7295
+ purpose: "Typography primitive for body text, labels and headings \u2014 size, tone, weight and truncation from tokens, with no hand-written CSS.",
7296
+ sourceFile: "packages/vue/src/components/TText.vue",
7297
+ storyFile: "apps/docs/src/stories/Text.stories.ts",
7298
+ storyTitle: "Components/Data Display/Text",
7299
+ manifestFile: "docs/ai/COMPONENTS/text.yaml",
7300
+ props: [
7301
+ {
7302
+ name: "as",
7303
+ type: "string",
7304
+ default: "span",
7305
+ note: "Render element. Use `p`, `h1`\u2013`h6`, `label`, `small`, `strong`, \u2026 for correct semantics."
7306
+ },
7307
+ {
7308
+ name: "size",
7309
+ type: "TTextSize",
7310
+ default: "undefined",
7311
+ values: [
7312
+ "xs",
7313
+ "sm",
7314
+ "md",
7315
+ "lg",
7316
+ "xl",
7317
+ "2xl",
7318
+ "3xl"
7319
+ ],
7320
+ note: "Maps to --tree-font-size-*. Omitted = inherit."
7321
+ },
7322
+ {
7323
+ name: "tone",
7324
+ type: "TTextTone",
7325
+ default: "default",
7326
+ values: [
7327
+ "default",
7328
+ "muted",
7329
+ "inverse",
7330
+ "brand"
7331
+ ],
7332
+ note: "`default` inherits the current colour; others map to --tree-color-text-* / brand."
7333
+ },
7334
+ {
7335
+ name: "weight",
7336
+ type: "TTextWeight",
7337
+ default: "undefined",
7338
+ values: [
7339
+ "regular",
7340
+ "medium",
7341
+ "semibold",
7342
+ "bold"
7343
+ ]
7344
+ },
7345
+ {
7346
+ name: "truncate",
7347
+ type: "boolean",
7348
+ default: "false",
7349
+ note: "Clip to a single line with an ellipsis."
7350
+ }
7351
+ ],
7352
+ events: [],
7353
+ slots: [
7354
+ {
7355
+ name: "default"
7356
+ }
7357
+ ],
7358
+ a11y: [
7359
+ "Choose `as` to convey the correct semantics (e.g. headings via h1\u2013h6); TText adds only visual styling."
7360
+ ],
7361
+ behavior: [
7362
+ "semantic_element_controlled_by_as: true",
7363
+ "token_driven_size_tone_weight: true"
7364
+ ],
7365
+ selection: {
7366
+ keywords: [],
7367
+ useWhen: [],
7368
+ avoidWhen: [],
7369
+ alternatives: []
7370
+ },
7371
+ setup: {
7372
+ required: [],
7373
+ notes: []
7374
+ },
7375
+ recipes: []
7376
+ },
6810
7377
  {
6811
7378
  name: "TTextarea",
6812
7379
  aliases: [],
@@ -6835,6 +7402,20 @@ var treeui_catalog_default = {
6835
7402
  "lg"
6836
7403
  ]
6837
7404
  },
7405
+ {
7406
+ name: "width",
7407
+ type: "TFieldWidth",
7408
+ default: "full",
7409
+ values: [
7410
+ "xs",
7411
+ "sm",
7412
+ "md",
7413
+ "lg",
7414
+ "xl",
7415
+ "full"
7416
+ ],
7417
+ note: "Inline-size cap (max-inline-size). Fluid by default; use instead of an inline width style."
7418
+ },
6838
7419
  {
6839
7420
  name: "disabled",
6840
7421
  type: "boolean",
@@ -7384,54 +7965,895 @@ var treeui_catalog_default = {
7384
7965
  "hierarchy-picker"
7385
7966
  ]
7386
7967
  }
7387
- ]
7388
- };
7389
-
7390
- // src/catalog.ts
7391
- var catalog = treeui_catalog_default;
7392
- var normalizeText = (value) => value.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
7393
- var tokenize = (value) => normalizeText(value).split(/\s+/).filter(Boolean);
7394
- var stringifyFields = (values) => values.filter(Boolean).join(" ");
7395
- var recipeSearchText = (recipe) => normalizeText(
7396
- stringifyFields([
7397
- recipe.id,
7398
- recipe.name,
7399
- recipe.useWhen.join(" "),
7400
- recipe.compose.join(" "),
7401
- recipe.notes.join(" ")
7402
- ])
7403
- );
7404
- var scoreMatch = (query, haystack) => {
7405
- const normalizedQuery = normalizeText(query);
7406
- if (!normalizedQuery) {
7407
- return 0;
7408
- }
7409
- if (haystack === normalizedQuery) {
7410
- return 120;
7411
- }
7412
- let score = 0;
7413
- if (haystack.includes(normalizedQuery)) {
7414
- score += 40;
7415
- }
7416
- const tokens = tokenize(normalizedQuery);
7417
- for (const token of tokens) {
7418
- if (haystack.includes(token)) {
7419
- score += token.length > 3 ? 12 : 6;
7420
- }
7421
- }
7422
- return score;
7423
- };
7424
- var scoreComponent = (component, query) => {
7425
- const names = normalizeText(
7426
- stringifyFields([component.name, component.legacyAlias, ...component.aliases])
7427
- );
7428
- const keywords = normalizeText(component.selection.keywords.join(" "));
7429
- const useWhen = normalizeText(component.selection.useWhen.join(" "));
7430
- const avoidWhen = normalizeText(component.selection.avoidWhen.join(" "));
7431
- const purpose = normalizeText(
7432
- stringifyFields([component.description, component.purpose, component.kind, component.category])
7433
- );
7434
- const api = normalizeText(
7968
+ ],
7969
+ tokens: [
7970
+ {
7971
+ cssVar: "--tree-font-family-sans",
7972
+ path: "font.family.sans",
7973
+ value: "'Google Sans Flex', 'Segoe UI', sans-serif",
7974
+ category: "font",
7975
+ description: "Typography token: font family, size, weight, or line height."
7976
+ },
7977
+ {
7978
+ cssVar: "--tree-font-family-mono",
7979
+ path: "font.family.mono",
7980
+ value: "'Google Sans Code', 'SFMono-Regular', monospace",
7981
+ category: "font",
7982
+ description: "Typography token: font family, size, weight, or line height."
7983
+ },
7984
+ {
7985
+ cssVar: "--tree-font-size-xs",
7986
+ path: "font.size.xs",
7987
+ value: "0.6875rem",
7988
+ category: "font",
7989
+ description: "Typography token: font family, size, weight, or line height."
7990
+ },
7991
+ {
7992
+ cssVar: "--tree-font-size-sm",
7993
+ path: "font.size.sm",
7994
+ value: "0.8125rem",
7995
+ category: "font",
7996
+ description: "Typography token: font family, size, weight, or line height."
7997
+ },
7998
+ {
7999
+ cssVar: "--tree-font-size-md",
8000
+ path: "font.size.md",
8001
+ value: "0.9375rem",
8002
+ category: "font",
8003
+ description: "Typography token: font family, size, weight, or line height."
8004
+ },
8005
+ {
8006
+ cssVar: "--tree-font-size-base",
8007
+ path: "font.size.base",
8008
+ value: "0.9375rem",
8009
+ category: "font",
8010
+ description: "Typography token: font family, size, weight, or line height."
8011
+ },
8012
+ {
8013
+ cssVar: "--tree-font-size-lg",
8014
+ path: "font.size.lg",
8015
+ value: "1.125rem",
8016
+ category: "font",
8017
+ description: "Typography token: font family, size, weight, or line height."
8018
+ },
8019
+ {
8020
+ cssVar: "--tree-font-size-xl",
8021
+ path: "font.size.xl",
8022
+ value: "1.375rem",
8023
+ category: "font",
8024
+ description: "Typography token: font family, size, weight, or line height."
8025
+ },
8026
+ {
8027
+ cssVar: "--tree-font-size-2xl",
8028
+ path: "font.size.2xl",
8029
+ value: "1.375rem",
8030
+ category: "font",
8031
+ description: "Typography token: font family, size, weight, or line height."
8032
+ },
8033
+ {
8034
+ cssVar: "--tree-font-size-3xl",
8035
+ path: "font.size.3xl",
8036
+ value: "1.75rem",
8037
+ category: "font",
8038
+ description: "Typography token: font family, size, weight, or line height."
8039
+ },
8040
+ {
8041
+ cssVar: "--tree-font-size-4xl",
8042
+ path: "font.size.4xl",
8043
+ value: "2.25rem",
8044
+ category: "font",
8045
+ description: "Typography token: font family, size, weight, or line height."
8046
+ },
8047
+ {
8048
+ cssVar: "--tree-font-size-5xl",
8049
+ path: "font.size.5xl",
8050
+ value: "3rem",
8051
+ category: "font",
8052
+ description: "Typography token: font family, size, weight, or line height."
8053
+ },
8054
+ {
8055
+ cssVar: "--tree-font-weight-regular",
8056
+ path: "font.weight.regular",
8057
+ value: "400",
8058
+ category: "font",
8059
+ description: "Typography token: font family, size, weight, or line height."
8060
+ },
8061
+ {
8062
+ cssVar: "--tree-font-weight-medium",
8063
+ path: "font.weight.medium",
8064
+ value: "500",
8065
+ category: "font",
8066
+ description: "Typography token: font family, size, weight, or line height."
8067
+ },
8068
+ {
8069
+ cssVar: "--tree-font-weight-semibold",
8070
+ path: "font.weight.semibold",
8071
+ value: "600",
8072
+ category: "font",
8073
+ description: "Typography token: font family, size, weight, or line height."
8074
+ },
8075
+ {
8076
+ cssVar: "--tree-font-weight-bold",
8077
+ path: "font.weight.bold",
8078
+ value: "700",
8079
+ category: "font",
8080
+ description: "Typography token: font family, size, weight, or line height."
8081
+ },
8082
+ {
8083
+ cssVar: "--tree-font-weight-extrabold",
8084
+ path: "font.weight.extrabold",
8085
+ value: "800",
8086
+ category: "font",
8087
+ description: "Typography token: font family, size, weight, or line height."
8088
+ },
8089
+ {
8090
+ cssVar: "--tree-font-lineHeight-compact",
8091
+ path: "font.lineHeight.compact",
8092
+ value: "1.1",
8093
+ category: "font",
8094
+ description: "Typography token: font family, size, weight, or line height."
8095
+ },
8096
+ {
8097
+ cssVar: "--tree-font-lineHeight-ui",
8098
+ path: "font.lineHeight.ui",
8099
+ value: "1.15",
8100
+ category: "font",
8101
+ description: "Typography token: font family, size, weight, or line height."
8102
+ },
8103
+ {
8104
+ cssVar: "--tree-font-lineHeight-tight",
8105
+ path: "font.lineHeight.tight",
8106
+ value: "1.25",
8107
+ category: "font",
8108
+ description: "Typography token: font family, size, weight, or line height."
8109
+ },
8110
+ {
8111
+ cssVar: "--tree-font-lineHeight-heading",
8112
+ path: "font.lineHeight.heading",
8113
+ value: "1.3",
8114
+ category: "font",
8115
+ description: "Typography token: font family, size, weight, or line height."
8116
+ },
8117
+ {
8118
+ cssVar: "--tree-font-lineHeight-base",
8119
+ path: "font.lineHeight.base",
8120
+ value: "1.5",
8121
+ category: "font",
8122
+ description: "Typography token: font family, size, weight, or line height."
8123
+ },
8124
+ {
8125
+ cssVar: "--tree-font-lineHeight-body",
8126
+ path: "font.lineHeight.body",
8127
+ value: "1.6",
8128
+ category: "font",
8129
+ description: "Typography token: font family, size, weight, or line height."
8130
+ },
8131
+ {
8132
+ cssVar: "--tree-font-lineHeight-relaxed",
8133
+ path: "font.lineHeight.relaxed",
8134
+ value: "1.65",
8135
+ category: "font",
8136
+ description: "Typography token: font family, size, weight, or line height."
8137
+ },
8138
+ {
8139
+ cssVar: "--tree-space-0",
8140
+ path: "space.0",
8141
+ value: "0",
8142
+ category: "space",
8143
+ description: "Spacing scale step for padding, margin, and gap."
8144
+ },
8145
+ {
8146
+ cssVar: "--tree-space-1",
8147
+ path: "space.1",
8148
+ value: "0.25rem",
8149
+ category: "space",
8150
+ description: "Spacing scale step for padding, margin, and gap."
8151
+ },
8152
+ {
8153
+ cssVar: "--tree-space-2",
8154
+ path: "space.2",
8155
+ value: "0.5rem",
8156
+ category: "space",
8157
+ description: "Spacing scale step for padding, margin, and gap."
8158
+ },
8159
+ {
8160
+ cssVar: "--tree-space-3",
8161
+ path: "space.3",
8162
+ value: "0.75rem",
8163
+ category: "space",
8164
+ description: "Spacing scale step for padding, margin, and gap."
8165
+ },
8166
+ {
8167
+ cssVar: "--tree-space-4",
8168
+ path: "space.4",
8169
+ value: "1rem",
8170
+ category: "space",
8171
+ description: "Spacing scale step for padding, margin, and gap."
8172
+ },
8173
+ {
8174
+ cssVar: "--tree-space-5",
8175
+ path: "space.5",
8176
+ value: "1.25rem",
8177
+ category: "space",
8178
+ description: "Spacing scale step for padding, margin, and gap."
8179
+ },
8180
+ {
8181
+ cssVar: "--tree-space-6",
8182
+ path: "space.6",
8183
+ value: "1.5rem",
8184
+ category: "space",
8185
+ description: "Spacing scale step for padding, margin, and gap."
8186
+ },
8187
+ {
8188
+ cssVar: "--tree-space-8",
8189
+ path: "space.8",
8190
+ value: "2rem",
8191
+ category: "space",
8192
+ description: "Spacing scale step for padding, margin, and gap."
8193
+ },
8194
+ {
8195
+ cssVar: "--tree-space-12",
8196
+ path: "space.12",
8197
+ value: "3rem",
8198
+ category: "space",
8199
+ description: "Spacing scale step for padding, margin, and gap."
8200
+ },
8201
+ {
8202
+ cssVar: "--tree-space-16",
8203
+ path: "space.16",
8204
+ value: "4rem",
8205
+ category: "space",
8206
+ description: "Spacing scale step for padding, margin, and gap."
8207
+ },
8208
+ {
8209
+ cssVar: "--tree-radius-sm",
8210
+ path: "radius.sm",
8211
+ value: "0.375rem",
8212
+ category: "radius",
8213
+ description: "Corner radius scale step."
8214
+ },
8215
+ {
8216
+ cssVar: "--tree-radius-md",
8217
+ path: "radius.md",
8218
+ value: "0.625rem",
8219
+ category: "radius",
8220
+ description: "Corner radius scale step."
8221
+ },
8222
+ {
8223
+ cssVar: "--tree-radius-lg",
8224
+ path: "radius.lg",
8225
+ value: "0.875rem",
8226
+ category: "radius",
8227
+ description: "Corner radius scale step."
8228
+ },
8229
+ {
8230
+ cssVar: "--tree-radius-pill",
8231
+ path: "radius.pill",
8232
+ value: "999px",
8233
+ category: "radius",
8234
+ description: "Corner radius scale step."
8235
+ },
8236
+ {
8237
+ cssVar: "--tree-shadow-xs",
8238
+ path: "shadow.xs",
8239
+ value: "0 1px 2px rgba(15, 23, 42, 0.06)",
8240
+ category: "shadow",
8241
+ description: "Elevation shadow."
8242
+ },
8243
+ {
8244
+ cssVar: "--tree-shadow-sm",
8245
+ path: "shadow.sm",
8246
+ value: "0 6px 18px rgba(15, 23, 42, 0.08)",
8247
+ category: "shadow",
8248
+ description: "Elevation shadow."
8249
+ },
8250
+ {
8251
+ cssVar: "--tree-shadow-md",
8252
+ path: "shadow.md",
8253
+ value: "0 14px 34px rgba(15, 23, 42, 0.12)",
8254
+ category: "shadow",
8255
+ description: "Elevation shadow."
8256
+ },
8257
+ {
8258
+ cssVar: "--tree-gradient-brand",
8259
+ path: "gradient.brand",
8260
+ value: "linear-gradient(135deg, var(--tree-color-brand-primary), var(--tree-color-brand-hover))",
8261
+ category: "gradient",
8262
+ description: "Gradient composed from the themed brand variables."
8263
+ },
8264
+ {
8265
+ cssVar: "--tree-border-width-subtle",
8266
+ path: "border.width.subtle",
8267
+ value: "1px",
8268
+ category: "border",
8269
+ description: "Border width step."
8270
+ },
8271
+ {
8272
+ cssVar: "--tree-border-width-strong",
8273
+ path: "border.width.strong",
8274
+ value: "1.5px",
8275
+ category: "border",
8276
+ description: "Border width step."
8277
+ },
8278
+ {
8279
+ cssVar: "--tree-motion-duration-fast",
8280
+ path: "motion.duration.fast",
8281
+ value: "100ms",
8282
+ category: "motion",
8283
+ description: "Motion duration or easing curve."
8284
+ },
8285
+ {
8286
+ cssVar: "--tree-motion-duration-moderate",
8287
+ path: "motion.duration.moderate",
8288
+ value: "200ms",
8289
+ category: "motion",
8290
+ description: "Motion duration or easing curve."
8291
+ },
8292
+ {
8293
+ cssVar: "--tree-motion-duration-normal",
8294
+ path: "motion.duration.normal",
8295
+ value: "300ms",
8296
+ category: "motion",
8297
+ description: "Motion duration or easing curve."
8298
+ },
8299
+ {
8300
+ cssVar: "--tree-motion-duration-slow",
8301
+ path: "motion.duration.slow",
8302
+ value: "400ms",
8303
+ category: "motion",
8304
+ description: "Motion duration or easing curve."
8305
+ },
8306
+ {
8307
+ cssVar: "--tree-motion-duration-slower",
8308
+ path: "motion.duration.slower",
8309
+ value: "500ms",
8310
+ category: "motion",
8311
+ description: "Motion duration or easing curve."
8312
+ },
8313
+ {
8314
+ cssVar: "--tree-motion-easing-standard",
8315
+ path: "motion.easing.standard",
8316
+ value: "cubic-bezier(0.2, 0, 0, 1)",
8317
+ category: "motion",
8318
+ description: "Motion duration or easing curve."
8319
+ },
8320
+ {
8321
+ cssVar: "--tree-motion-easing-easeOut",
8322
+ path: "motion.easing.easeOut",
8323
+ value: "cubic-bezier(0, 0, 0.2, 1)",
8324
+ category: "motion",
8325
+ description: "Motion duration or easing curve."
8326
+ },
8327
+ {
8328
+ cssVar: "--tree-motion-easing-easeInOut",
8329
+ path: "motion.easing.easeInOut",
8330
+ value: "cubic-bezier(0.4, 0, 0.2, 1)",
8331
+ category: "motion",
8332
+ description: "Motion duration or easing curve."
8333
+ },
8334
+ {
8335
+ cssVar: "--tree-motion-easing-easeIn",
8336
+ path: "motion.easing.easeIn",
8337
+ value: "cubic-bezier(0.4, 0, 1, 1)",
8338
+ category: "motion",
8339
+ description: "Motion duration or easing curve."
8340
+ },
8341
+ {
8342
+ cssVar: "--tree-size-control-sm",
8343
+ path: "size.control.sm",
8344
+ value: "2rem",
8345
+ category: "size",
8346
+ description: "Control and icon sizing scale step."
8347
+ },
8348
+ {
8349
+ cssVar: "--tree-size-control-md",
8350
+ path: "size.control.md",
8351
+ value: "2.5rem",
8352
+ category: "size",
8353
+ description: "Control and icon sizing scale step."
8354
+ },
8355
+ {
8356
+ cssVar: "--tree-size-control-lg",
8357
+ path: "size.control.lg",
8358
+ value: "3rem",
8359
+ category: "size",
8360
+ description: "Control and icon sizing scale step."
8361
+ },
8362
+ {
8363
+ cssVar: "--tree-size-icon-sm",
8364
+ path: "size.icon.sm",
8365
+ value: "1rem",
8366
+ category: "size",
8367
+ description: "Control and icon sizing scale step."
8368
+ },
8369
+ {
8370
+ cssVar: "--tree-size-icon-md",
8371
+ path: "size.icon.md",
8372
+ value: "1.25rem",
8373
+ category: "size",
8374
+ description: "Control and icon sizing scale step."
8375
+ },
8376
+ {
8377
+ cssVar: "--tree-size-icon-lg",
8378
+ path: "size.icon.lg",
8379
+ value: "1.5rem",
8380
+ category: "size",
8381
+ description: "Control and icon sizing scale step."
8382
+ },
8383
+ {
8384
+ cssVar: "--tree-size-icon-xl",
8385
+ path: "size.icon.xl",
8386
+ value: "2rem",
8387
+ category: "size",
8388
+ description: "Control and icon sizing scale step."
8389
+ },
8390
+ {
8391
+ cssVar: "--tree-size-icon-2xl",
8392
+ path: "size.icon.2xl",
8393
+ value: "3rem",
8394
+ category: "size",
8395
+ description: "Control and icon sizing scale step."
8396
+ },
8397
+ {
8398
+ cssVar: "--tree-layout-grid-columns",
8399
+ path: "layout.grid.columns",
8400
+ value: "12",
8401
+ category: "layout",
8402
+ description: "Layout grid, gutter, or margin measurement."
8403
+ },
8404
+ {
8405
+ cssVar: "--tree-layout-grid-base",
8406
+ path: "layout.grid.base",
8407
+ value: "8px",
8408
+ category: "layout",
8409
+ description: "Layout grid, gutter, or margin measurement."
8410
+ },
8411
+ {
8412
+ cssVar: "--tree-layout-gutter-sm",
8413
+ path: "layout.gutter.sm",
8414
+ value: "1rem",
8415
+ category: "layout",
8416
+ description: "Layout grid, gutter, or margin measurement."
8417
+ },
8418
+ {
8419
+ cssVar: "--tree-layout-gutter-md",
8420
+ path: "layout.gutter.md",
8421
+ value: "1.5rem",
8422
+ category: "layout",
8423
+ description: "Layout grid, gutter, or margin measurement."
8424
+ },
8425
+ {
8426
+ cssVar: "--tree-layout-margin-sm",
8427
+ path: "layout.margin.sm",
8428
+ value: "1.5rem",
8429
+ category: "layout",
8430
+ description: "Layout grid, gutter, or margin measurement."
8431
+ },
8432
+ {
8433
+ cssVar: "--tree-layout-margin-md",
8434
+ path: "layout.margin.md",
8435
+ value: "2rem",
8436
+ category: "layout",
8437
+ description: "Layout grid, gutter, or margin measurement."
8438
+ },
8439
+ {
8440
+ cssVar: "--tree-layout-margin-lg",
8441
+ path: "layout.margin.lg",
8442
+ value: "3rem",
8443
+ category: "layout",
8444
+ description: "Layout grid, gutter, or margin measurement."
8445
+ },
8446
+ {
8447
+ cssVar: "--tree-z-base",
8448
+ path: "z.base",
8449
+ value: "1",
8450
+ category: "z",
8451
+ description: "Stacking layer (z-index)."
8452
+ },
8453
+ {
8454
+ cssVar: "--tree-z-dropdown",
8455
+ path: "z.dropdown",
8456
+ value: "1000",
8457
+ category: "z",
8458
+ description: "Stacking layer (z-index)."
8459
+ },
8460
+ {
8461
+ cssVar: "--tree-z-popover",
8462
+ path: "z.popover",
8463
+ value: "1050",
8464
+ category: "z",
8465
+ description: "Stacking layer (z-index)."
8466
+ },
8467
+ {
8468
+ cssVar: "--tree-z-sticky",
8469
+ path: "z.sticky",
8470
+ value: "1100",
8471
+ category: "z",
8472
+ description: "Stacking layer (z-index)."
8473
+ },
8474
+ {
8475
+ cssVar: "--tree-z-overlay",
8476
+ path: "z.overlay",
8477
+ value: "1200",
8478
+ category: "z",
8479
+ description: "Stacking layer (z-index)."
8480
+ },
8481
+ {
8482
+ cssVar: "--tree-z-modal",
8483
+ path: "z.modal",
8484
+ value: "1300",
8485
+ category: "z",
8486
+ description: "Stacking layer (z-index)."
8487
+ },
8488
+ {
8489
+ cssVar: "--tree-z-toast",
8490
+ path: "z.toast",
8491
+ value: "1400",
8492
+ category: "z",
8493
+ description: "Stacking layer (z-index)."
8494
+ },
8495
+ {
8496
+ cssVar: "--tree-breakpoint-sm",
8497
+ path: "breakpoint.sm",
8498
+ value: "640px",
8499
+ category: "breakpoint",
8500
+ description: "Responsive breakpoint width."
8501
+ },
8502
+ {
8503
+ cssVar: "--tree-breakpoint-md",
8504
+ path: "breakpoint.md",
8505
+ value: "768px",
8506
+ category: "breakpoint",
8507
+ description: "Responsive breakpoint width."
8508
+ },
8509
+ {
8510
+ cssVar: "--tree-breakpoint-lg",
8511
+ path: "breakpoint.lg",
8512
+ value: "1024px",
8513
+ category: "breakpoint",
8514
+ description: "Responsive breakpoint width."
8515
+ },
8516
+ {
8517
+ cssVar: "--tree-breakpoint-xl",
8518
+ path: "breakpoint.xl",
8519
+ value: "1280px",
8520
+ category: "breakpoint",
8521
+ description: "Responsive breakpoint width."
8522
+ },
8523
+ {
8524
+ cssVar: "--tree-color-bg-primary",
8525
+ path: "color.bg.primary",
8526
+ value: "#f6f8fa",
8527
+ category: "color",
8528
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8529
+ themeValues: {
8530
+ light: "#f6f8fa",
8531
+ dark: "#1c2128"
8532
+ }
8533
+ },
8534
+ {
8535
+ cssVar: "--tree-color-bg-surface",
8536
+ path: "color.bg.surface",
8537
+ value: "#ffffff",
8538
+ category: "color",
8539
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8540
+ themeValues: {
8541
+ light: "#ffffff",
8542
+ dark: "#22272e"
8543
+ }
8544
+ },
8545
+ {
8546
+ cssVar: "--tree-color-bg-subtle",
8547
+ path: "color.bg.subtle",
8548
+ value: "#eff2f5",
8549
+ category: "color",
8550
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8551
+ themeValues: {
8552
+ light: "#eff2f5",
8553
+ dark: "#2d333b"
8554
+ }
8555
+ },
8556
+ {
8557
+ cssVar: "--tree-color-border-default",
8558
+ path: "color.border.default",
8559
+ value: "#d0d7de",
8560
+ category: "color",
8561
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8562
+ themeValues: {
8563
+ light: "#d0d7de",
8564
+ dark: "#444c56"
8565
+ }
8566
+ },
8567
+ {
8568
+ cssVar: "--tree-color-border-strong",
8569
+ path: "color.border.strong",
8570
+ value: "#afb8c1",
8571
+ category: "color",
8572
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8573
+ themeValues: {
8574
+ light: "#afb8c1",
8575
+ dark: "#576270"
8576
+ }
8577
+ },
8578
+ {
8579
+ cssVar: "--tree-color-text-primary",
8580
+ path: "color.text.primary",
8581
+ value: "#1f2328",
8582
+ category: "color",
8583
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8584
+ themeValues: {
8585
+ light: "#1f2328",
8586
+ dark: "#adbac7"
8587
+ }
8588
+ },
8589
+ {
8590
+ cssVar: "--tree-color-text-muted",
8591
+ path: "color.text.muted",
8592
+ value: "#59636e",
8593
+ category: "color",
8594
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8595
+ themeValues: {
8596
+ light: "#59636e",
8597
+ dark: "#95a3b2"
8598
+ }
8599
+ },
8600
+ {
8601
+ cssVar: "--tree-color-text-inverse",
8602
+ path: "color.text.inverse",
8603
+ value: "#ffffff",
8604
+ category: "color",
8605
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8606
+ themeValues: {
8607
+ light: "#ffffff",
8608
+ dark: "#1c2128"
8609
+ }
8610
+ },
8611
+ {
8612
+ cssVar: "--tree-color-brand-primary",
8613
+ path: "color.brand.primary",
8614
+ value: "#0969da",
8615
+ category: "color",
8616
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8617
+ themeValues: {
8618
+ light: "#0969da",
8619
+ dark: "#539bf5"
8620
+ }
8621
+ },
8622
+ {
8623
+ cssVar: "--tree-color-brand-hover",
8624
+ path: "color.brand.hover",
8625
+ value: "#0550ae",
8626
+ category: "color",
8627
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8628
+ themeValues: {
8629
+ light: "#0550ae",
8630
+ dark: "#6cabf7"
8631
+ }
8632
+ },
8633
+ {
8634
+ cssVar: "--tree-color-brand-soft",
8635
+ path: "color.brand.soft",
8636
+ value: "#ddf4ff",
8637
+ category: "color",
8638
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8639
+ themeValues: {
8640
+ light: "#ddf4ff",
8641
+ dark: "#1a3453"
8642
+ }
8643
+ },
8644
+ {
8645
+ cssVar: "--tree-color-brand-contrast",
8646
+ path: "color.brand.contrast",
8647
+ value: "#ffffff",
8648
+ category: "color",
8649
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8650
+ themeValues: {
8651
+ light: "#ffffff",
8652
+ dark: "#0a1a2f"
8653
+ }
8654
+ },
8655
+ {
8656
+ cssVar: "--tree-color-status-success",
8657
+ path: "color.status.success",
8658
+ value: "#1a7f37",
8659
+ category: "color",
8660
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8661
+ themeValues: {
8662
+ light: "#1a7f37",
8663
+ dark: "#57ab5a"
8664
+ }
8665
+ },
8666
+ {
8667
+ cssVar: "--tree-color-status-warning",
8668
+ path: "color.status.warning",
8669
+ value: "#9a6700",
8670
+ category: "color",
8671
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8672
+ themeValues: {
8673
+ light: "#9a6700",
8674
+ dark: "#c69026"
8675
+ }
8676
+ },
8677
+ {
8678
+ cssVar: "--tree-color-status-error",
8679
+ path: "color.status.error",
8680
+ value: "#d1242f",
8681
+ category: "color",
8682
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8683
+ themeValues: {
8684
+ light: "#d1242f",
8685
+ dark: "#f47067"
8686
+ }
8687
+ },
8688
+ {
8689
+ cssVar: "--tree-color-status-info",
8690
+ path: "color.status.info",
8691
+ value: "#0969da",
8692
+ category: "color",
8693
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8694
+ themeValues: {
8695
+ light: "#0969da",
8696
+ dark: "#6cb6ff"
8697
+ }
8698
+ },
8699
+ {
8700
+ cssVar: "--tree-color-chart-1",
8701
+ path: "color.chart.1",
8702
+ value: "#2a78d6",
8703
+ category: "color",
8704
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8705
+ themeValues: {
8706
+ light: "#2a78d6",
8707
+ dark: "#3987e5"
8708
+ }
8709
+ },
8710
+ {
8711
+ cssVar: "--tree-color-chart-2",
8712
+ path: "color.chart.2",
8713
+ value: "#1baf7a",
8714
+ category: "color",
8715
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8716
+ themeValues: {
8717
+ light: "#1baf7a",
8718
+ dark: "#199e70"
8719
+ }
8720
+ },
8721
+ {
8722
+ cssVar: "--tree-color-chart-3",
8723
+ path: "color.chart.3",
8724
+ value: "#eda100",
8725
+ category: "color",
8726
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8727
+ themeValues: {
8728
+ light: "#eda100",
8729
+ dark: "#c98500"
8730
+ }
8731
+ },
8732
+ {
8733
+ cssVar: "--tree-color-chart-4",
8734
+ path: "color.chart.4",
8735
+ value: "#008300",
8736
+ category: "color",
8737
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8738
+ themeValues: {
8739
+ light: "#008300",
8740
+ dark: "#008300"
8741
+ }
8742
+ },
8743
+ {
8744
+ cssVar: "--tree-color-chart-5",
8745
+ path: "color.chart.5",
8746
+ value: "#4a3aa7",
8747
+ category: "color",
8748
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8749
+ themeValues: {
8750
+ light: "#4a3aa7",
8751
+ dark: "#9085e9"
8752
+ }
8753
+ },
8754
+ {
8755
+ cssVar: "--tree-color-chart-6",
8756
+ path: "color.chart.6",
8757
+ value: "#e34948",
8758
+ category: "color",
8759
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8760
+ themeValues: {
8761
+ light: "#e34948",
8762
+ dark: "#e66767"
8763
+ }
8764
+ },
8765
+ {
8766
+ cssVar: "--tree-color-chart-7",
8767
+ path: "color.chart.7",
8768
+ value: "#e87ba4",
8769
+ category: "color",
8770
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8771
+ themeValues: {
8772
+ light: "#e87ba4",
8773
+ dark: "#d55181"
8774
+ }
8775
+ },
8776
+ {
8777
+ cssVar: "--tree-color-chart-8",
8778
+ path: "color.chart.8",
8779
+ value: "#eb6834",
8780
+ category: "color",
8781
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8782
+ themeValues: {
8783
+ light: "#eb6834",
8784
+ dark: "#d95926"
8785
+ }
8786
+ },
8787
+ {
8788
+ cssVar: "--tree-color-overlay",
8789
+ path: "color.overlay",
8790
+ value: "rgba(31, 35, 40, 0.5)",
8791
+ category: "color",
8792
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8793
+ themeValues: {
8794
+ light: "rgba(31, 35, 40, 0.5)",
8795
+ dark: "rgba(13, 17, 23, 0.6)"
8796
+ }
8797
+ },
8798
+ {
8799
+ cssVar: "--tree-color-focus-ring",
8800
+ path: "color.focus-ring",
8801
+ value: "rgba(9, 105, 218, 0.32)",
8802
+ category: "color",
8803
+ description: "Themed semantic color, resolved per [data-tree-theme].",
8804
+ themeValues: {
8805
+ light: "rgba(9, 105, 218, 0.32)",
8806
+ dark: "rgba(83, 155, 245, 0.32)"
8807
+ }
8808
+ }
8809
+ ]
8810
+ };
8811
+
8812
+ // src/catalog.ts
8813
+ var catalog = treeui_catalog_default;
8814
+ var normalizeText = (value) => value.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
8815
+ var tokenize = (value) => normalizeText(value).split(/\s+/).filter(Boolean);
8816
+ var stringifyFields = (values) => values.filter(Boolean).join(" ");
8817
+ var recipeSearchText = (recipe) => normalizeText(
8818
+ stringifyFields([
8819
+ recipe.id,
8820
+ recipe.name,
8821
+ recipe.useWhen.join(" "),
8822
+ recipe.compose.join(" "),
8823
+ recipe.notes.join(" ")
8824
+ ])
8825
+ );
8826
+ var scoreMatch = (query, haystack) => {
8827
+ const normalizedQuery = normalizeText(query);
8828
+ if (!normalizedQuery) {
8829
+ return 0;
8830
+ }
8831
+ if (haystack === normalizedQuery) {
8832
+ return 120;
8833
+ }
8834
+ let score = 0;
8835
+ if (haystack.includes(normalizedQuery)) {
8836
+ score += 40;
8837
+ }
8838
+ const tokens = tokenize(normalizedQuery);
8839
+ for (const token of tokens) {
8840
+ if (haystack.includes(token)) {
8841
+ score += token.length > 3 ? 12 : 6;
8842
+ }
8843
+ }
8844
+ return score;
8845
+ };
8846
+ var scoreComponent = (component, query) => {
8847
+ const names = normalizeText(
8848
+ stringifyFields([component.name, component.legacyAlias, ...component.aliases])
8849
+ );
8850
+ const keywords = normalizeText(component.selection.keywords.join(" "));
8851
+ const useWhen = normalizeText(component.selection.useWhen.join(" "));
8852
+ const avoidWhen = normalizeText(component.selection.avoidWhen.join(" "));
8853
+ const purpose = normalizeText(
8854
+ stringifyFields([component.description, component.purpose, component.kind, component.category])
8855
+ );
8856
+ const api = normalizeText(
7435
8857
  stringifyFields([
7436
8858
  component.props.map((prop) => `${prop.name} ${prop.description ?? ""}`).join(" "),
7437
8859
  component.events.map((event) => event.name).join(" "),
@@ -7629,6 +9051,43 @@ var searchRecipes = (query, limit = 6) => catalog.recipes.map((recipe) => ({
7629
9051
  recipe,
7630
9052
  score: scoreMatch(query, recipeSearchText(recipe))
7631
9053
  })).filter((result) => result.score > 0).sort((left, right) => right.score - left.score || left.recipe.name.localeCompare(right.recipe.name)).slice(0, limit);
9054
+ var tokenValues = (token) => [
9055
+ token.value,
9056
+ ...Object.values(token.themeValues ?? {})
9057
+ ];
9058
+ var REM_ROOT_PX = 16;
9059
+ var lengthAliases = (query) => {
9060
+ const match = query.trim().match(/^(\d*\.?\d+)(rem|px)$/i);
9061
+ if (!match) {
9062
+ return [];
9063
+ }
9064
+ const amount = Number(match[1]);
9065
+ if (!Number.isFinite(amount)) {
9066
+ return [];
9067
+ }
9068
+ const unit = match[2].toLowerCase();
9069
+ const converted = unit === "rem" ? amount * REM_ROOT_PX : amount / REM_ROOT_PX;
9070
+ return [`${Number(converted.toFixed(4))}${unit === "rem" ? "px" : "rem"}`];
9071
+ };
9072
+ var scoreToken = (token, query) => {
9073
+ const identity = normalizeText(stringifyFields([token.cssVar, token.path]));
9074
+ const category = normalizeText(token.category);
9075
+ const values = normalizeText(stringifyFields(tokenValues(token)));
9076
+ const description = normalizeText(token.description ?? "");
9077
+ const valueScore = Math.max(
9078
+ ...[query, ...lengthAliases(query)].map((candidate) => scoreMatch(candidate, values))
9079
+ );
9080
+ let score = 0;
9081
+ score += scoreMatch(query, identity) * 3;
9082
+ score += scoreMatch(query, category) * 2;
9083
+ score += valueScore * 2;
9084
+ score += scoreMatch(query, description);
9085
+ return Math.max(score, 0);
9086
+ };
9087
+ var searchTokens = (query, limit = 12) => catalog.tokens.map((token) => ({
9088
+ token,
9089
+ score: scoreToken(token, query)
9090
+ })).filter((result) => result.score > 0).sort((left, right) => right.score - left.score || left.token.cssVar.localeCompare(right.token.cssVar)).slice(0, limit);
7632
9091
  var formatFieldList = (label, values) => values.length > 0 ? `${label}: ${values.join(", ")}` : void 0;
7633
9092
  var formatComponentSummary = (component) => {
7634
9093
  const lines = [
@@ -7673,6 +9132,12 @@ var formatRecipeResults = (results) => results.length > 0 ? results.map((result,
7673
9132
  const useWhen = result.recipe.useWhen[0];
7674
9133
  return `${index + 1}. ${result.recipe.name}: ${useWhen ?? "No recipe summary available."} Components: ${result.recipe.compose.join(", ")}.`;
7675
9134
  }).join("\n") : "No matching TreeUI recipes found.";
9135
+ var formatTokenResults = (results) => results.length > 0 ? results.map((result, index) => {
9136
+ const { token } = result;
9137
+ const themeValues = token.themeValues ? Object.entries(token.themeValues).map(([theme, value]) => `${theme} ${value}`).join(" | ") : void 0;
9138
+ const description = token.description ? ` ${token.description}` : "";
9139
+ return `${index + 1}. ${token.cssVar}: ${themeValues ?? token.value} (${token.category} | ${token.path}).${description}`;
9140
+ }).join("\n") : "No matching TreeUI design tokens found.";
7676
9141
  var formatSetupGuide = (componentName) => {
7677
9142
  if (!componentName) {
7678
9143
  return [
@@ -7700,6 +9165,291 @@ var formatSetupGuide = (componentName) => {
7700
9165
  var import_node_fs = __toESM(require("fs"), 1);
7701
9166
  var import_node_path = __toESM(require("path"), 1);
7702
9167
  var import_yaml = require("yaml");
9168
+
9169
+ // ../tokens/src/tokens.ts
9170
+ var treeTokens = {
9171
+ font: {
9172
+ family: {
9173
+ sans: "'Google Sans Flex', 'Segoe UI', sans-serif",
9174
+ mono: "'Google Sans Code', 'SFMono-Regular', monospace"
9175
+ },
9176
+ size: {
9177
+ xs: "0.6875rem",
9178
+ sm: "0.8125rem",
9179
+ md: "0.9375rem",
9180
+ base: "0.9375rem",
9181
+ lg: "1.125rem",
9182
+ xl: "1.375rem",
9183
+ "2xl": "1.375rem",
9184
+ "3xl": "1.75rem",
9185
+ "4xl": "2.25rem",
9186
+ "5xl": "3rem"
9187
+ },
9188
+ weight: {
9189
+ regular: "400",
9190
+ medium: "500",
9191
+ semibold: "600",
9192
+ bold: "700",
9193
+ extrabold: "800"
9194
+ },
9195
+ lineHeight: {
9196
+ compact: "1.1",
9197
+ ui: "1.15",
9198
+ tight: "1.25",
9199
+ heading: "1.3",
9200
+ base: "1.5",
9201
+ body: "1.6",
9202
+ relaxed: "1.65"
9203
+ }
9204
+ },
9205
+ space: {
9206
+ 0: "0",
9207
+ 1: "0.25rem",
9208
+ 2: "0.5rem",
9209
+ 3: "0.75rem",
9210
+ 4: "1rem",
9211
+ 5: "1.25rem",
9212
+ 6: "1.5rem",
9213
+ 8: "2rem",
9214
+ 12: "3rem",
9215
+ 16: "4rem"
9216
+ },
9217
+ radius: {
9218
+ sm: "0.375rem",
9219
+ md: "0.625rem",
9220
+ lg: "0.875rem",
9221
+ pill: "999px"
9222
+ },
9223
+ shadow: {
9224
+ xs: "0 1px 2px rgba(15, 23, 42, 0.06)",
9225
+ sm: "0 6px 18px rgba(15, 23, 42, 0.08)",
9226
+ md: "0 14px 34px rgba(15, 23, 42, 0.12)"
9227
+ },
9228
+ // Brand gradient for high-emphasis surfaces (e.g. the primary CTA).
9229
+ // References the theme brand vars so it follows light/dark automatically;
9230
+ // override `--tree-gradient-brand` to match a product's marketing gradient.
9231
+ gradient: {
9232
+ brand: "linear-gradient(135deg, var(--tree-color-brand-primary), var(--tree-color-brand-hover))"
9233
+ },
9234
+ border: {
9235
+ width: {
9236
+ subtle: "1px",
9237
+ strong: "1.5px"
9238
+ }
9239
+ },
9240
+ motion: {
9241
+ duration: {
9242
+ fast: "100ms",
9243
+ moderate: "200ms",
9244
+ normal: "300ms",
9245
+ slow: "400ms",
9246
+ slower: "500ms"
9247
+ },
9248
+ easing: {
9249
+ standard: "cubic-bezier(0.2, 0, 0, 1)",
9250
+ easeOut: "cubic-bezier(0, 0, 0.2, 1)",
9251
+ easeInOut: "cubic-bezier(0.4, 0, 0.2, 1)",
9252
+ easeIn: "cubic-bezier(0.4, 0, 1, 1)"
9253
+ }
9254
+ },
9255
+ size: {
9256
+ control: {
9257
+ sm: "2rem",
9258
+ md: "2.5rem",
9259
+ lg: "3rem"
9260
+ },
9261
+ icon: {
9262
+ sm: "1rem",
9263
+ md: "1.25rem",
9264
+ lg: "1.5rem",
9265
+ xl: "2rem",
9266
+ "2xl": "3rem"
9267
+ }
9268
+ },
9269
+ layout: {
9270
+ grid: {
9271
+ columns: "12",
9272
+ base: "8px"
9273
+ },
9274
+ gutter: {
9275
+ sm: "1rem",
9276
+ md: "1.5rem"
9277
+ },
9278
+ margin: {
9279
+ sm: "1.5rem",
9280
+ md: "2rem",
9281
+ lg: "3rem"
9282
+ }
9283
+ },
9284
+ z: {
9285
+ base: "1",
9286
+ dropdown: "1000",
9287
+ popover: "1050",
9288
+ sticky: "1100",
9289
+ overlay: "1200",
9290
+ modal: "1300",
9291
+ toast: "1400"
9292
+ },
9293
+ breakpoint: {
9294
+ sm: "640px",
9295
+ md: "768px",
9296
+ lg: "1024px",
9297
+ xl: "1280px"
9298
+ }
9299
+ };
9300
+ var treeThemes = {
9301
+ light: {
9302
+ color: {
9303
+ bg: {
9304
+ primary: "#f6f8fa",
9305
+ surface: "#ffffff",
9306
+ subtle: "#eff2f5"
9307
+ },
9308
+ border: {
9309
+ default: "#d0d7de",
9310
+ strong: "#afb8c1"
9311
+ },
9312
+ text: {
9313
+ primary: "#1f2328",
9314
+ muted: "#59636e",
9315
+ inverse: "#ffffff"
9316
+ },
9317
+ brand: {
9318
+ primary: "#0969da",
9319
+ hover: "#0550ae",
9320
+ soft: "#ddf4ff",
9321
+ contrast: "#ffffff"
9322
+ },
9323
+ status: {
9324
+ success: "#1a7f37",
9325
+ warning: "#9a6700",
9326
+ error: "#d1242f",
9327
+ info: "#0969da"
9328
+ },
9329
+ // Categorical data-viz palette. Fixed hue order (blue → orange), validated
9330
+ // for CVD separation and contrast against the light surface. Assign in order;
9331
+ // the components cycle after 8 as a fallback, but prefer folding a 9th+
9332
+ // category into "Other".
9333
+ chart: {
9334
+ 1: "#2a78d6",
9335
+ 2: "#1baf7a",
9336
+ 3: "#eda100",
9337
+ 4: "#008300",
9338
+ 5: "#4a3aa7",
9339
+ 6: "#e34948",
9340
+ 7: "#e87ba4",
9341
+ 8: "#eb6834"
9342
+ },
9343
+ overlay: "rgba(31, 35, 40, 0.5)",
9344
+ "focus-ring": "rgba(9, 105, 218, 0.32)"
9345
+ }
9346
+ },
9347
+ dark: {
9348
+ color: {
9349
+ bg: {
9350
+ primary: "#1c2128",
9351
+ surface: "#22272e",
9352
+ subtle: "#2d333b"
9353
+ },
9354
+ border: {
9355
+ default: "#444c56",
9356
+ strong: "#576270"
9357
+ },
9358
+ text: {
9359
+ primary: "#adbac7",
9360
+ muted: "#95a3b2",
9361
+ inverse: "#1c2128"
9362
+ },
9363
+ brand: {
9364
+ primary: "#539bf5",
9365
+ hover: "#6cabf7",
9366
+ soft: "#1a3453",
9367
+ contrast: "#0a1a2f"
9368
+ },
9369
+ status: {
9370
+ success: "#57ab5a",
9371
+ warning: "#c69026",
9372
+ error: "#f47067",
9373
+ info: "#6cb6ff"
9374
+ },
9375
+ // Same hue order stepped for the dark surface (not a separate palette) —
9376
+ // each step re-validated for the dark band and >= 3:1 on the dark surface.
9377
+ chart: {
9378
+ 1: "#3987e5",
9379
+ 2: "#199e70",
9380
+ 3: "#c98500",
9381
+ 4: "#008300",
9382
+ 5: "#9085e9",
9383
+ 6: "#e66767",
9384
+ 7: "#d55181",
9385
+ 8: "#d95926"
9386
+ },
9387
+ overlay: "rgba(13, 17, 23, 0.6)",
9388
+ "focus-ring": "rgba(83, 155, 245, 0.32)"
9389
+ }
9390
+ }
9391
+ };
9392
+
9393
+ // src/token-source.ts
9394
+ var toCssVariable = (path2) => `--tree-${path2.join("-")}`;
9395
+ var flattenTokens = (record, path2 = []) => Object.entries(record).flatMap(([key, value]) => {
9396
+ if (typeof value === "string" || typeof value === "number") {
9397
+ return [[[...path2, key], value]];
9398
+ }
9399
+ return flattenTokens(value, [...path2, key]);
9400
+ });
9401
+ var DEFAULT_THEME_NAME = "light";
9402
+ var categoryDescriptions = {
9403
+ font: "Typography token: font family, size, weight, or line height.",
9404
+ space: "Spacing scale step for padding, margin, and gap.",
9405
+ radius: "Corner radius scale step.",
9406
+ shadow: "Elevation shadow.",
9407
+ gradient: "Gradient composed from the themed brand variables.",
9408
+ border: "Border width step.",
9409
+ motion: "Motion duration or easing curve.",
9410
+ size: "Control and icon sizing scale step.",
9411
+ layout: "Layout grid, gutter, or margin measurement.",
9412
+ z: "Stacking layer (z-index).",
9413
+ breakpoint: "Responsive breakpoint width.",
9414
+ color: "Themed semantic color, resolved per [data-tree-theme]."
9415
+ };
9416
+ var describeToken = (category) => categoryDescriptions[category] ?? "TreeUI design token.";
9417
+ var buildTokenEntries = () => {
9418
+ const foundation = flattenTokens(treeTokens).map(
9419
+ ([path2, value]) => ({
9420
+ cssVar: toCssVariable(path2),
9421
+ path: path2.join("."),
9422
+ value: String(value),
9423
+ category: path2[0],
9424
+ description: describeToken(path2[0])
9425
+ })
9426
+ );
9427
+ const themed = /* @__PURE__ */ new Map();
9428
+ for (const [themeName, theme] of Object.entries(treeThemes)) {
9429
+ for (const [path2, value] of flattenTokens(theme)) {
9430
+ const cssVar = toCssVariable(path2);
9431
+ const existing = themed.get(cssVar);
9432
+ if (existing) {
9433
+ existing.themeValues = { ...existing.themeValues, [themeName]: String(value) };
9434
+ continue;
9435
+ }
9436
+ themed.set(cssVar, {
9437
+ cssVar,
9438
+ path: path2.join("."),
9439
+ value: String(value),
9440
+ category: path2[0],
9441
+ description: describeToken(path2[0]),
9442
+ themeValues: { [themeName]: String(value) }
9443
+ });
9444
+ }
9445
+ }
9446
+ for (const entry of themed.values()) {
9447
+ entry.value = entry.themeValues?.[DEFAULT_THEME_NAME] ?? entry.value;
9448
+ }
9449
+ return [...foundation, ...themed.values()];
9450
+ };
9451
+
9452
+ // src/catalog-source.ts
7703
9453
  var readText = (filePath) => import_node_fs.default.readFileSync(filePath, "utf8");
7704
9454
  var normalizeWhitespace = (value) => value.replace(/\s+/g, " ").trim();
7705
9455
  var stringifyValue = (value) => {
@@ -8035,7 +9785,8 @@ var buildCatalogFromRepo = (repoRoot) => {
8035
9785
  decisionGuides: normalizeDecisionGuides(selectionDoc.decision_guides),
8036
9786
  recipes,
8037
9787
  setup,
8038
- components
9788
+ components,
9789
+ tokens: buildTokenEntries()
8039
9790
  };
8040
9791
  };
8041
9792
  var getRepoRootFromPackageRoot = (packageRoot) => import_node_path.default.resolve(packageRoot, "../..");
@@ -8068,6 +9819,12 @@ var resourceList = [
8068
9819
  description: "Reusable multi-component composition recipes.",
8069
9820
  mimeType: "application/json"
8070
9821
  },
9822
+ {
9823
+ uri: "treeui://tokens",
9824
+ name: "TreeUI design tokens",
9825
+ description: "Flat list of --tree-* design tokens with per-theme values.",
9826
+ mimeType: "application/json"
9827
+ },
8071
9828
  ...catalog.components.map((component) => ({
8072
9829
  uri: `treeui://components/${component.name}`,
8073
9830
  name: component.name,
@@ -8095,6 +9852,9 @@ var readResourcePayload = (uri) => {
8095
9852
  if (uri === "treeui://recipes") {
8096
9853
  return catalog.recipes;
8097
9854
  }
9855
+ if (uri === "treeui://tokens") {
9856
+ return catalog.tokens;
9857
+ }
8098
9858
  const componentMatch = uri.match(/^treeui:\/\/components\/([^/]+)$/);
8099
9859
  if (componentMatch) {
8100
9860
  const component = findComponent(componentMatch[1]);
@@ -8196,6 +9956,21 @@ var createTreeuiMcpServer = () => {
8196
9956
  },
8197
9957
  required: ["query"]
8198
9958
  }
9959
+ },
9960
+ {
9961
+ name: "search_tokens",
9962
+ description: "Search TreeUI design tokens by CSS variable, category, path, or shipped value. Use this before hardcoding any color, spacing, radius, or breakpoint value.",
9963
+ inputSchema: {
9964
+ type: "object",
9965
+ properties: {
9966
+ query: {
9967
+ type: "string",
9968
+ description: "A CSS variable such as --tree-gradient-brand, a category or path such as space or color.status, or a literal value such as 64rem or #0969da."
9969
+ },
9970
+ limit: { type: "number", description: "Maximum number of tokens to return." }
9971
+ },
9972
+ required: ["query"]
9973
+ }
8199
9974
  }
8200
9975
  ]
8201
9976
  }));
@@ -8236,6 +10011,13 @@ var createTreeuiMcpServer = () => {
8236
10011
  }
8237
10012
  return asTextContent(formatRecipeResults(searchRecipes(query, readNumberArg(args, "limit", 6))));
8238
10013
  }
10014
+ if (name === "search_tokens") {
10015
+ const query = readStringArg(args, "query");
10016
+ if (!query) {
10017
+ return asErrorTextContent('The "query" argument is required.');
10018
+ }
10019
+ return asTextContent(formatTokenResults(searchTokens(query, readNumberArg(args, "limit", 12))));
10020
+ }
8239
10021
  return asErrorTextContent(`Unknown tool: ${name}`);
8240
10022
  });
8241
10023
  server.setRequestHandler(import_types.ListResourcesRequestSchema, async () => ({
@@ -8261,6 +10043,7 @@ var createTreeuiMcpServer = () => {
8261
10043
  // Annotate the CommonJS export names for ESM import in node:
8262
10044
  0 && (module.exports = {
8263
10045
  buildCatalogFromRepo,
10046
+ buildTokenEntries,
8264
10047
  catalog,
8265
10048
  createTreeuiMcpServer,
8266
10049
  findComponent,
@@ -8268,8 +10051,10 @@ var createTreeuiMcpServer = () => {
8268
10051
  formatRecipeResults,
8269
10052
  formatSearchResults,
8270
10053
  formatSetupGuide,
10054
+ formatTokenResults,
8271
10055
  getRepoRootFromPackageRoot,
8272
10056
  recommendComponents,
8273
10057
  searchComponents,
8274
- searchRecipes
10058
+ searchRecipes,
10059
+ searchTokens
8275
10060
  });