@lowdefy/blocks-antd 5.2.0 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/dist/blocks/AutoComplete/AutoComplete.js +1 -0
  2. package/dist/blocks/AutoComplete/meta.js +2 -1
  3. package/dist/blocks/ButtonSelector/ButtonSelector.js +74 -27
  4. package/dist/blocks/ButtonSelector/meta.js +18 -4
  5. package/dist/blocks/Carousel/meta.js +16 -0
  6. package/dist/blocks/CheckboxSelector/CheckboxSelector.js +46 -14
  7. package/dist/blocks/CheckboxSelector/meta.js +7 -1
  8. package/dist/blocks/CheckboxSwitch/CheckboxSwitch.js +1 -0
  9. package/dist/blocks/CheckboxSwitch/meta.js +4 -1
  10. package/dist/blocks/ColorSelector/ColorSelector.js +1 -0
  11. package/dist/blocks/ColorSelector/meta.js +2 -1
  12. package/dist/blocks/ConfigProvider/ConfigProvider.js +1 -0
  13. package/dist/blocks/ConfigProvider/meta.js +7 -0
  14. package/dist/blocks/ConfirmModal/ConfirmModal.js +2 -2
  15. package/dist/blocks/ConfirmModal/meta.js +2 -4
  16. package/dist/blocks/DateRangeSelector/DateRangeSelector.js +4 -9
  17. package/dist/blocks/DateRangeSelector/meta.js +4 -8
  18. package/dist/blocks/DateSelector/DateSelector.js +4 -3
  19. package/dist/blocks/DateSelector/meta.js +4 -5
  20. package/dist/blocks/DateTimeSelector/DateTimeSelector.js +4 -3
  21. package/dist/blocks/DateTimeSelector/meta.js +4 -5
  22. package/dist/blocks/DropdownMenu/meta.js +46 -6
  23. package/dist/blocks/Label/Label.js +30 -5
  24. package/dist/blocks/Label/meta.js +8 -2
  25. package/dist/blocks/ListSelector/ListSelector.js +384 -0
  26. package/dist/blocks/ListSelector/e2e.js +40 -0
  27. package/dist/blocks/ListSelector/meta.js +215 -0
  28. package/dist/blocks/Menu/Menu.js +26 -80
  29. package/dist/blocks/Menu/meta.js +160 -64
  30. package/dist/blocks/MobileMenu/meta.js +50 -50
  31. package/dist/blocks/Modal/Modal.js +2 -2
  32. package/dist/blocks/Modal/meta.js +2 -4
  33. package/dist/blocks/MonthSelector/MonthSelector.js +4 -3
  34. package/dist/blocks/MonthSelector/meta.js +4 -5
  35. package/dist/blocks/MultipleSelector/MultipleSelector.js +41 -9
  36. package/dist/blocks/MultipleSelector/meta.js +24 -5
  37. package/dist/blocks/NumberInput/NumberInput.js +3 -1
  38. package/dist/blocks/NumberInput/meta.js +3 -3
  39. package/dist/blocks/PageHeaderMenu/PageHeaderMenu.js +12 -3
  40. package/dist/blocks/PageHeaderMenu/meta.js +8 -1
  41. package/dist/blocks/PageSidebarLayout/PageSidebarLayout.js +2 -1
  42. package/dist/blocks/PageSidebarLayout/meta.js +8 -1
  43. package/dist/blocks/PageSiderMenu/PageSiderMenu.js +2 -1
  44. package/dist/blocks/PageSiderMenu/meta.js +8 -1
  45. package/dist/blocks/PasswordInput/PasswordInput.js +1 -0
  46. package/dist/blocks/PasswordInput/meta.js +2 -1
  47. package/dist/blocks/PhoneNumberInput/PhoneNumberInput.js +1 -0
  48. package/dist/blocks/PhoneNumberInput/meta.js +2 -1
  49. package/dist/blocks/RadioSelector/RadioSelector.js +44 -14
  50. package/dist/blocks/RadioSelector/meta.js +7 -1
  51. package/dist/blocks/RatingSlider/meta.js +2 -1
  52. package/dist/blocks/SegmentedSelector/SegmentedSelector.js +10 -4
  53. package/dist/blocks/SegmentedSelector/meta.js +7 -4
  54. package/dist/blocks/Selector/Selector.js +55 -9
  55. package/dist/blocks/Selector/meta.js +24 -5
  56. package/dist/blocks/Slider/Slider.js +1 -0
  57. package/dist/blocks/Slider/meta.js +2 -1
  58. package/dist/blocks/Switch/Switch.js +1 -0
  59. package/dist/blocks/Switch/meta.js +2 -1
  60. package/dist/blocks/Tabs/Tabs.js +30 -43
  61. package/dist/blocks/Tabs/meta.js +8 -10
  62. package/dist/blocks/TextArea/TextArea.js +1 -0
  63. package/dist/blocks/TextArea/meta.js +2 -1
  64. package/dist/blocks/TextInput/TextInput.js +1 -0
  65. package/dist/blocks/TextInput/meta.js +2 -1
  66. package/dist/blocks/TreeInput/TreeInput.js +91 -0
  67. package/dist/blocks/TreeInput/e2e.js +33 -0
  68. package/dist/blocks/TreeInput/meta.js +68 -0
  69. package/dist/blocks/TreeMultipleSelector/TreeMultipleSelector.js +161 -0
  70. package/dist/blocks/TreeMultipleSelector/e2e.js +46 -0
  71. package/dist/blocks/TreeMultipleSelector/meta.js +128 -0
  72. package/dist/blocks/TreeSelector/TreeSelector.js +127 -88
  73. package/dist/blocks/TreeSelector/e2e.js +20 -9
  74. package/dist/blocks/TreeSelector/meta.js +70 -254
  75. package/dist/blocks/WeekSelector/WeekSelector.js +2 -1
  76. package/dist/blocks/WeekSelector/meta.js +3 -3
  77. package/dist/blocks/buildMenuItems.js +89 -26
  78. package/dist/blocks/headerActions.js +87 -3
  79. package/dist/blocks/normalizeItemClassAndStyle.js +77 -0
  80. package/dist/blocks.js +3 -0
  81. package/dist/e2e.js +3 -0
  82. package/dist/getContrastTextColor.js +45 -0
  83. package/dist/getOptionColorStyle.js +36 -0
  84. package/dist/getSelectedIndex.js +42 -0
  85. package/dist/getSelectorOptions.js +67 -0
  86. package/dist/getTreeData.js +94 -0
  87. package/dist/metas.js +3 -0
  88. package/dist/schemas/dataOptions.js +36 -0
  89. package/dist/schemas/index.js +1 -0
  90. package/dist/schemas/label.js +3 -1
  91. package/dist/schemas/labelTooltip.js +44 -0
  92. package/dist/schemas/options.js +7 -3
  93. package/dist/schemas/treeSelectTheme.js +125 -0
  94. package/dist/serializeSelectorValue.js +38 -0
  95. package/dist/useSelectorOptions.js +38 -0
  96. package/dist/useSetData.js +27 -0
  97. package/package.json +9 -7
@@ -0,0 +1,215 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ export default {
16
+ category: 'input',
17
+ icons: [],
18
+ valueType: 'any',
19
+ cssKeys: {
20
+ element: 'The list container.',
21
+ card: 'Each Card element.',
22
+ body: 'Each Card body.',
23
+ selected: 'The selected card.',
24
+ search: 'The search bar wrapper above the list.',
25
+ noResults: 'The "no results" placeholder shown when the search filter matches zero items.',
26
+ noData: 'The "no data" placeholder shown when the data array is empty.'
27
+ },
28
+ events: {
29
+ onChange: {
30
+ description: 'Triggered when the selection changes (only fires when `selectable` is true).',
31
+ event: {
32
+ value: 'The newly selected value — the `valueKey` field when set, otherwise the whole data item; null when the selection is cleared.',
33
+ index: 'Zero-based index of the clicked card.',
34
+ item: 'The data item bound to the clicked card.'
35
+ }
36
+ },
37
+ onClick: {
38
+ description: 'Triggered when a card is clicked.',
39
+ event: {
40
+ index: 'Zero-based index of the clicked card.',
41
+ item: 'The data item bound to the clicked card.'
42
+ }
43
+ },
44
+ onSearch: {
45
+ description: 'Triggered when the debounced search query changes (only fires when the `search` property is set).',
46
+ event: {
47
+ value: 'The current debounced search query string.',
48
+ resultCount: 'Number of items currently visible. Equals data.length when the query is empty or below `minLength`.'
49
+ }
50
+ }
51
+ },
52
+ properties: {
53
+ type: 'object',
54
+ additionalProperties: false,
55
+ properties: {
56
+ data: {
57
+ type: 'array',
58
+ default: [],
59
+ description: 'Array of items. Each item is rendered as one card by passing it to the html Nunjucks template as `item`.'
60
+ },
61
+ html: {
62
+ type: 'string',
63
+ description: 'Nunjucks template used to render the body of each card. The context exposes `item` (the current data row) and `index` (the zero-based row index).'
64
+ },
65
+ selectable: {
66
+ type: 'boolean',
67
+ default: true,
68
+ description: 'Enable selecting a card. When true, clicking a card sets the block value to that data item and highlights it. When false, the block is a read-only card list that stores no value.'
69
+ },
70
+ allowDeselect: {
71
+ type: 'boolean',
72
+ default: true,
73
+ description: 'Allow clicking the selected card again to clear the selection (sets the value to null). Ignored when `selectable` is false.'
74
+ },
75
+ valueKey: {
76
+ type: 'string',
77
+ description: 'Field of each data item stored as the block value when a card is selected (e.g. "id"). Omit to store the whole item. Lets the selection be driven with SetState using a simple key. Supports dotted paths.'
78
+ },
79
+ primaryKey: {
80
+ type: 'string',
81
+ description: 'Field used to match the current value (e.g. set with SetState) back to a card for highlighting. Defaults to `valueKey`. Set this when the stored value is the whole item but a single field (e.g. "id") uniquely identifies it. Supports dotted paths.'
82
+ },
83
+ bordered: {
84
+ type: 'boolean',
85
+ default: true,
86
+ description: 'Toggles the border around each card.'
87
+ },
88
+ hoverable: {
89
+ type: 'boolean',
90
+ default: false,
91
+ description: 'Lift each card up when hovered.'
92
+ },
93
+ size: {
94
+ type: 'string',
95
+ enum: [
96
+ 'default',
97
+ 'small'
98
+ ],
99
+ default: 'default',
100
+ description: 'Card size.'
101
+ },
102
+ gap: {
103
+ type: 'number',
104
+ default: 8,
105
+ description: 'Pixel gap between cards.'
106
+ },
107
+ height: {
108
+ type: [
109
+ 'number',
110
+ 'string'
111
+ ],
112
+ description: 'Optional pixel height (number) or CSS height string of the scroll container. When omitted, the list scrolls with the page.'
113
+ },
114
+ overscan: {
115
+ type: 'number',
116
+ default: 400,
117
+ description: 'Pixels of off-screen rows to render above and below the viewport. Increase for smoother fast-scroll, decrease to reduce DOM cost.'
118
+ },
119
+ noData: {
120
+ type: 'string',
121
+ description: 'Text shown in place of the list when the `data` array is empty. Defaults to the `blocks.listSelector.noData` message ("No data").'
122
+ },
123
+ search: {
124
+ type: 'object',
125
+ additionalProperties: false,
126
+ description: 'Optional client-side search bar above the list. When this property is set, a debounced search input filters rows by text. Omit to hide the bar.',
127
+ properties: {
128
+ placeholder: {
129
+ type: 'string',
130
+ default: 'Search…',
131
+ description: 'Placeholder text in the input.'
132
+ },
133
+ fields: {
134
+ type: 'array',
135
+ items: {
136
+ type: 'string'
137
+ },
138
+ description: 'Dotted field paths to match against (e.g. "user.name"). When omitted, every field path is searched (whole-item stringify).'
139
+ },
140
+ caseSensitive: {
141
+ type: 'boolean',
142
+ default: false,
143
+ description: 'Match case exactly.'
144
+ },
145
+ debounce: {
146
+ type: 'number',
147
+ default: 150,
148
+ description: 'Milliseconds to wait after the last keystroke before filtering.'
149
+ },
150
+ sticky: {
151
+ type: 'boolean',
152
+ default: true,
153
+ description: 'Stick the search bar to the top while scrolling.'
154
+ },
155
+ allowClear: {
156
+ type: 'boolean',
157
+ default: true,
158
+ description: 'Show a clear (×) icon in the input.'
159
+ },
160
+ minLength: {
161
+ type: 'number',
162
+ default: 0,
163
+ description: 'Skip filtering until the query is at least this many characters.'
164
+ },
165
+ noResultsText: {
166
+ type: 'string',
167
+ default: 'No results',
168
+ description: 'Text shown when the filter matches zero items.'
169
+ }
170
+ }
171
+ },
172
+ theme: {
173
+ type: 'object',
174
+ description: 'Antd design token overrides for the cards. See <a href="https://ant.design/components/overview#design-token">antd design tokens</a>.',
175
+ docs: {
176
+ displayType: 'yaml',
177
+ link: 'https://ant.design/components/card#design-token'
178
+ },
179
+ properties: {
180
+ bodyPadding: {
181
+ type: 'number',
182
+ default: 24,
183
+ description: 'Padding of each card body.'
184
+ },
185
+ bodyPaddingSM: {
186
+ type: 'number',
187
+ default: 12,
188
+ description: 'Padding of each card body for small cards.'
189
+ },
190
+ borderRadiusLG: {
191
+ type: 'number',
192
+ default: 8,
193
+ description: 'Border radius of each card.'
194
+ },
195
+ colorBorderSecondary: {
196
+ type: 'string',
197
+ description: 'Border color of each card.'
198
+ },
199
+ colorBgContainer: {
200
+ type: 'string',
201
+ description: 'Background color of each card body.'
202
+ },
203
+ colorText: {
204
+ type: 'string',
205
+ description: 'Text color inside each card.'
206
+ },
207
+ boxShadowTertiary: {
208
+ type: 'string',
209
+ description: 'Shadow applied to each card on hover when hoverable is true.'
210
+ }
211
+ }
212
+ }
213
+ }
214
+ }
215
+ };
@@ -19,13 +19,13 @@ const SiderContext = Layout._InternalSiderContext;
19
19
  import { withBlockDefaults } from '@lowdefy/block-utils';
20
20
  import withTheme from '../withTheme.js';
21
21
  import useItemShortcuts from '../useItemShortcuts.js';
22
+ import { buildMenuItems } from '../buildMenuItems.js';
22
23
  const getDefaultMenu = (menus, menuId = 'default', links)=>{
23
24
  if (type.isArray(links)) return links;
24
25
  if (!type.isArray(menus)) return [];
25
26
  const menu = menus.find((item)=>item.menuId === menuId) ?? menus[0] ?? {};
26
27
  return menu.links ?? [];
27
28
  };
28
- const getTitle = ({ id, properties, pageId, url })=>properties?.title ?? pageId ?? url ?? id;
29
29
  function collectLinkShortcuts(links) {
30
30
  const result = [];
31
31
  (links ?? []).forEach((link)=>{
@@ -43,83 +43,16 @@ function collectLinkShortcuts(links) {
43
43
  });
44
44
  return result;
45
45
  }
46
- function buildMenuItems({ links, events, components: { Icon, Link, ShortcutBadge }, classNames, styles, isTopLevel = true }) {
47
- return (links ?? []).map((link, i)=>{
48
- if (link.type === 'MenuDivider') {
49
- return {
50
- type: 'divider',
51
- key: link.id ?? i,
52
- dashed: link.properties?.dashed,
53
- style: link.style
54
- };
55
- }
56
- if (link.type === 'MenuGroup') {
57
- const groupItem = {
58
- key: link.pageId ?? link.id,
59
- label: /*#__PURE__*/ React.createElement(Link, {
60
- id: link.pageId ?? link.id ?? i,
61
- style: link.style,
62
- ...link
63
- }, getTitle(link)),
64
- children: buildMenuItems({
65
- links: link.links,
66
- events,
67
- components: {
68
- Icon,
69
- Link,
70
- ShortcutBadge
71
- },
72
- classNames,
73
- styles,
74
- isTopLevel: false
75
- })
76
- };
77
- if (isTopLevel) {
78
- // Top-level MenuGroup → collapsible submenu (with icon)
79
- groupItem.icon = link.properties?.icon ? /*#__PURE__*/ React.createElement(Icon, {
80
- blockId: `${link.id}_icon`,
81
- classNames: {
82
- element: classNames.icon
83
- },
84
- events: events,
85
- properties: link.properties.icon,
86
- styles: {
87
- element: styles.icon
88
- }
89
- }) : undefined;
90
- } else {
91
- // Nested MenuGroup → non-collapsible group header
92
- groupItem.type = 'group';
93
- }
94
- return groupItem;
95
- }
96
- // MenuLink (default)
97
- return {
98
- key: link.pageId ?? link.id,
99
- danger: link.properties?.danger,
100
- className: classNames.item,
101
- icon: link.properties?.icon ? /*#__PURE__*/ React.createElement(Icon, {
102
- blockId: `${link.id}_icon`,
103
- classNames: {
104
- element: classNames.icon
105
- },
106
- events: events,
107
- properties: link.properties.icon,
108
- styles: {
109
- element: styles.icon
110
- }
111
- }) : undefined,
112
- label: /*#__PURE__*/ React.createElement(Link, {
113
- id: link.pageId ?? link.id ?? i,
114
- style: link.style,
115
- url: link.url ?? link.properties?.url,
116
- newTab: link.newTab ?? link.properties?.newTab,
117
- ...link
118
- }, getTitle(link), /*#__PURE__*/ React.createElement(ShortcutBadge, {
119
- shortcut: link.properties?.shortcut
120
- }))
121
- };
122
- });
46
+ function makeWrapGroupLabel(Link) {
47
+ return function wrapGroupLabel({ link, labelText, classNames: labelClass, styles: labelStyle }) {
48
+ const { class: _omitClass, style: _omitStyle, ...linkRest } = link;
49
+ return /*#__PURE__*/ React.createElement(Link, {
50
+ ...linkRest,
51
+ id: link.pageId ?? link.id,
52
+ className: labelClass || undefined,
53
+ style: labelStyle
54
+ }, labelText);
55
+ };
123
56
  }
124
57
  function MenuComp({ blockId, classNames = {}, components: { Icon, Link, ShortcutBadge }, events, menus, methods, pageId, properties, rename, styles = {} }) {
125
58
  const horizontalStyles = {
@@ -136,6 +69,16 @@ function MenuComp({ blockId, classNames = {}, components: { Icon, Link, Shortcut
136
69
  const theme = properties.theme;
137
70
  const { siderCollapsed } = useContext(SiderContext) ?? {};
138
71
  const isCollapsed = properties.collapsed === true || siderCollapsed === true;
72
+ // Back-compat: the prior cssKey for the menu item icon was `icon`; the shared helper
73
+ // standardises on `itemIcon`. Map either through so existing YAML keeps working.
74
+ const itemsClassNames = {
75
+ ...classNames,
76
+ itemIcon: classNames.itemIcon ?? classNames.icon
77
+ };
78
+ const itemsStyles = {
79
+ ...styles,
80
+ itemIcon: styles.itemIcon ?? styles.icon
81
+ };
139
82
  const items = buildMenuItems({
140
83
  links: menu,
141
84
  events,
@@ -144,8 +87,11 @@ function MenuComp({ blockId, classNames = {}, components: { Icon, Link, Shortcut
144
87
  Link,
145
88
  ShortcutBadge
146
89
  },
147
- classNames,
148
- styles
90
+ classNames: itemsClassNames,
91
+ styles: itemsStyles,
92
+ wrapGroupLabel: makeWrapGroupLabel(Link),
93
+ nestedGroupAsGroup: true,
94
+ getKey: (link)=>link.pageId ?? link.id
149
95
  });
150
96
  const shortcutItems = collectLinkShortcuts(menu);
151
97
  const onShortcutMatch = useCallback((key)=>{
@@ -19,8 +19,9 @@
19
19
  cssKeys: {
20
20
  element: 'The Menu element.',
21
21
  expandIcon: 'The expand icon in the Menu.',
22
- icon: 'The icon in the Menu.',
23
- item: 'The Menu item.'
22
+ icon: 'Deprecated alias for `itemIcon`.',
23
+ itemIcon: 'The icon shown in each menu item.',
24
+ item: 'The Menu item wrapper (li).'
24
25
  },
25
26
  events: {
26
27
  onSelect: {
@@ -375,12 +376,24 @@
375
376
  description: 'Page to link to.'
376
377
  },
377
378
  style: {
378
- type: 'object',
379
- description: 'Css style to applied to link.',
379
+ type: [
380
+ 'object',
381
+ 'string',
382
+ 'array'
383
+ ],
384
+ description: 'CSS styles for the menu item. Use a flat object for the item wrapper, or use dot-prefixed slot keys (`.element`, `.icon`, `.label`) to target specific parts.',
380
385
  docs: {
381
386
  displayType: 'yaml'
382
387
  }
383
388
  },
389
+ class: {
390
+ type: [
391
+ 'string',
392
+ 'array',
393
+ 'object'
394
+ ],
395
+ description: 'CSS classes for the menu item (including Tailwind utilities). Flat string/array applies to the item wrapper. Use an object with dot-prefixed slot keys (`.element`, `.icon`, `.label`, `.popup` — popup only on MenuGroup) to target specific parts.'
396
+ },
384
397
  properties: {
385
398
  type: 'object',
386
399
  description: 'properties from menu item.',
@@ -402,16 +415,29 @@
402
415
  danger: {
403
416
  type: 'boolean',
404
417
  default: false,
405
- description: 'Apply danger style to menu item.'
418
+ description: 'Apply danger style (MenuLink only). Switches the item onto the `dangerItem*` token set — theme via `properties.theme.dangerItemColor` etc.'
419
+ },
420
+ disabled: {
421
+ type: 'boolean',
422
+ default: false,
423
+ description: 'Disable the menu item (blocks clicks and applies a greyed style).'
424
+ },
425
+ tooltip: {
426
+ type: 'string',
427
+ description: 'Tooltip text shown on hover when the menu is collapsed. Maps to antd item `title`.'
428
+ },
429
+ extra: {
430
+ type: 'string',
431
+ description: 'Free-form right-aligned label on a MenuLink (e.g. a status hint like "beta" or "soon"). For real keyboard shortcuts use `shortcut` instead — it renders a kbd badge AND wires the key handler. When both are set, `shortcut` sits to the far right of `extra`.'
406
432
  },
407
433
  dashed: {
408
434
  type: 'boolean',
409
435
  default: false,
410
- description: 'Whether the divider line is dashed.'
436
+ description: 'Whether the divider line is dashed (MenuDivider only).'
411
437
  },
412
438
  shortcut: {
413
439
  type: 'string',
414
- description: 'Keyboard shortcut to select this menu item. Renders a shortcut badge next to the label. Use "mod" for Cmd/Ctrl.'
440
+ description: 'Keyboard shortcut for this menu item. Renders a kbd badge floated to the far right of the item AND wires the key handler (fires onSelect when pressed). Use "mod" for Cmd/Ctrl.'
415
441
  }
416
442
  }
417
443
  },
@@ -439,12 +465,24 @@
439
465
  description: 'Menu item type.'
440
466
  },
441
467
  style: {
442
- type: 'object',
443
- description: 'Css style to applied to sub-link.',
468
+ type: [
469
+ 'object',
470
+ 'string',
471
+ 'array'
472
+ ],
473
+ description: 'CSS styles for the menu item. Use a flat object for the item wrapper, or dot-prefixed slot keys (`.element`, `.icon`, `.label`).',
444
474
  docs: {
445
475
  displayType: 'yaml'
446
476
  }
447
477
  },
478
+ class: {
479
+ type: [
480
+ 'string',
481
+ 'array',
482
+ 'object'
483
+ ],
484
+ description: 'CSS classes for the menu item. Flat applies to the item wrapper; use dot-prefixed slot keys to target parts.'
485
+ },
448
486
  pageId: {
449
487
  type: 'string',
450
488
  description: 'Page to link to.'
@@ -457,10 +495,33 @@
457
495
  type: 'string',
458
496
  description: 'Menu item title.'
459
497
  },
498
+ icon: {
499
+ type: [
500
+ 'string',
501
+ 'object'
502
+ ],
503
+ description: 'Icon name or Icon block properties.',
504
+ docs: {
505
+ displayType: 'icon'
506
+ }
507
+ },
460
508
  danger: {
461
509
  type: 'boolean',
462
510
  default: false,
463
- description: 'Apply danger style to menu item.'
511
+ description: 'Apply danger style (MenuLink only).'
512
+ },
513
+ disabled: {
514
+ type: 'boolean',
515
+ default: false,
516
+ description: 'Disable the menu item.'
517
+ },
518
+ tooltip: {
519
+ type: 'string',
520
+ description: 'Tooltip text shown when the menu is collapsed.'
521
+ },
522
+ extra: {
523
+ type: 'string',
524
+ description: 'Free-form right-aligned label on a MenuLink. For real keybindings use `shortcut`; when both are set, `shortcut` sits to the right of `extra`.'
464
525
  },
465
526
  dashed: {
466
527
  type: 'boolean',
@@ -469,64 +530,99 @@
469
530
  },
470
531
  shortcut: {
471
532
  type: 'string',
472
- description: 'Keyboard shortcut to select this menu item. Renders a shortcut badge next to the label. Use "mod" for Cmd/Ctrl.'
533
+ description: 'Keyboard shortcut for this menu item. Renders a kbd badge floated to the far right of the item AND wires the key handler (fires onSelect when pressed). Use "mod" for Cmd/Ctrl.'
473
534
  }
474
- },
475
- links: {
476
- type: 'array',
477
- items: {
478
- type: 'object',
479
- required: [
480
- 'id',
481
- 'type'
482
- ],
535
+ }
536
+ },
537
+ links: {
538
+ type: 'array',
539
+ items: {
540
+ type: 'object',
541
+ required: [
542
+ 'id',
543
+ 'type'
544
+ ],
545
+ properties: {
546
+ id: {
547
+ type: 'string',
548
+ description: 'Menu item id.'
549
+ },
550
+ type: {
551
+ type: 'string',
552
+ enum: [
553
+ 'MenuDivider',
554
+ 'MenuLink'
555
+ ],
556
+ default: 'MenuLink',
557
+ description: 'Menu item type.'
558
+ },
559
+ style: {
560
+ type: [
561
+ 'object',
562
+ 'string',
563
+ 'array'
564
+ ],
565
+ description: 'CSS styles for the menu item. Use a flat object or dot-prefixed slot keys.',
566
+ docs: {
567
+ displayType: 'yaml'
568
+ }
569
+ },
570
+ class: {
571
+ type: [
572
+ 'string',
573
+ 'array',
574
+ 'object'
575
+ ],
576
+ description: 'CSS classes for the menu item.'
577
+ },
578
+ pageId: {
579
+ type: 'string',
580
+ description: 'Page to link to.'
581
+ },
483
582
  properties: {
484
- id: {
485
- type: 'string',
486
- description: 'Menu item id.'
487
- },
488
- type: {
489
- type: 'string',
490
- enum: [
491
- 'MenuDivider',
492
- 'MenuLink'
493
- ],
494
- default: 'MenuLink',
495
- description: 'Menu item type.'
496
- },
497
- style: {
498
- type: 'object',
499
- description: 'Css style to applied to sub-link.',
500
- docs: {
501
- displayType: 'yaml'
502
- }
503
- },
504
- pageId: {
505
- type: 'string',
506
- description: 'Page to link to.'
507
- },
583
+ type: 'object',
584
+ description: 'properties from menu item.',
508
585
  properties: {
509
- type: 'object',
510
- description: 'properties from menu item.',
511
- properties: {
512
- title: {
513
- type: 'string',
514
- description: 'Menu item title.'
515
- },
516
- danger: {
517
- type: 'boolean',
518
- default: false,
519
- description: 'Apply danger style to menu item.'
520
- },
521
- dashed: {
522
- type: 'boolean',
523
- default: false,
524
- description: 'Whether the divider line is dashed.'
525
- },
526
- shortcut: {
527
- type: 'string',
528
- description: 'Keyboard shortcut to select this menu item. Renders a shortcut badge next to the label. Use "mod" for Cmd/Ctrl.'
586
+ title: {
587
+ type: 'string',
588
+ description: 'Menu item title.'
589
+ },
590
+ icon: {
591
+ type: [
592
+ 'string',
593
+ 'object'
594
+ ],
595
+ description: 'Icon name or Icon block properties.',
596
+ docs: {
597
+ displayType: 'icon'
529
598
  }
599
+ },
600
+ danger: {
601
+ type: 'boolean',
602
+ default: false,
603
+ description: 'Apply danger style (MenuLink only).'
604
+ },
605
+ disabled: {
606
+ type: 'boolean',
607
+ default: false,
608
+ description: 'Disable the menu item.'
609
+ },
610
+ tooltip: {
611
+ type: 'string',
612
+ description: 'Tooltip text shown when the menu is collapsed.'
613
+ },
614
+ extra: {
615
+ type: 'string',
616
+ description: 'Free-form right-aligned label on a MenuLink. For real keybindings use `shortcut`.'
617
+ },
618
+ dashed: {
619
+ type: 'boolean',
620
+ default: false,
621
+ description: 'Whether the divider line is dashed.'
622
+ },
623
+ shortcut: {
624
+ type: 'string',
625
+ description: 'Keyboard shortcut. Renders a kbd badge floated to the far right and wires the key handler. Use "mod" for Cmd/Ctrl.'
530
626
  }
531
627
  }
532
628
  }