@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
@@ -224,58 +224,58 @@
224
224
  default: false,
225
225
  description: 'Whether the divider line is dashed.'
226
226
  }
227
- },
228
- links: {
229
- type: 'array',
230
- items: {
231
- type: 'object',
232
- required: [
233
- 'id',
234
- 'type'
235
- ],
227
+ }
228
+ },
229
+ links: {
230
+ type: 'array',
231
+ items: {
232
+ type: 'object',
233
+ required: [
234
+ 'id',
235
+ 'type'
236
+ ],
237
+ properties: {
238
+ id: {
239
+ type: 'string',
240
+ description: 'Menu item id.'
241
+ },
242
+ type: {
243
+ type: 'string',
244
+ enum: [
245
+ 'MenuDivider',
246
+ 'MenuLink'
247
+ ],
248
+ default: 'MenuLink',
249
+ description: 'Menu item type.'
250
+ },
251
+ style: {
252
+ type: 'object',
253
+ description: 'Css style to applied to sub-link.',
254
+ docs: {
255
+ displayType: 'yaml'
256
+ }
257
+ },
258
+ pageId: {
259
+ type: 'string',
260
+ description: 'Page to link to.'
261
+ },
236
262
  properties: {
237
- id: {
238
- type: 'string',
239
- description: 'Menu item id.'
240
- },
241
- type: {
242
- type: 'string',
243
- enum: [
244
- 'MenuDivider',
245
- 'MenuLink'
246
- ],
247
- default: 'MenuLink',
248
- description: 'Menu item type.'
249
- },
250
- style: {
251
- type: 'object',
252
- description: 'Css style to applied to sub-link.',
253
- docs: {
254
- displayType: 'yaml'
255
- }
256
- },
257
- pageId: {
258
- type: 'string',
259
- description: 'Page to link to.'
260
- },
263
+ type: 'object',
264
+ description: 'properties from menu item.',
261
265
  properties: {
262
- type: 'object',
263
- description: 'properties from menu item.',
264
- properties: {
265
- title: {
266
- type: 'string',
267
- description: 'Menu item title.'
268
- },
269
- danger: {
270
- type: 'boolean',
271
- default: false,
272
- description: 'Apply danger style to menu item.'
273
- },
274
- dashed: {
275
- type: 'boolean',
276
- default: false,
277
- description: 'Whether the divider line is dashed.'
278
- }
266
+ title: {
267
+ type: 'string',
268
+ description: 'Menu item title.'
269
+ },
270
+ danger: {
271
+ type: 'boolean',
272
+ default: false,
273
+ description: 'Apply danger style to menu item.'
274
+ },
275
+ dashed: {
276
+ type: 'boolean',
277
+ default: false,
278
+ description: 'Whether the divider line is dashed.'
279
279
  }
280
280
  }
281
281
  }
@@ -59,14 +59,14 @@ const ModalBlock = ({ blockId, classNames = {}, content, events, methods, proper
59
59
  name: 'afterClose'
60
60
  }),
61
61
  cancelButtonProps: properties.cancelButtonProps,
62
- cancelText: properties.cancelText ?? 'Cancel',
62
+ cancelText: properties.cancelText,
63
63
  centered: !!properties.centered,
64
64
  closable: properties.closable !== undefined ? properties.closable : true,
65
65
  confirmLoading: get(events, 'onOk.loading'),
66
66
  mask: properties.mask !== undefined ? properties.mask : true,
67
67
  maskClosable: properties.maskClosable !== undefined ? properties.maskClosable : true,
68
68
  okButtonProps: properties.okButtonProps,
69
- okText: properties.okText ?? 'Ok',
69
+ okText: properties.okText,
70
70
  okType: properties.okButtonType ?? 'primary',
71
71
  title: renderHtml({
72
72
  html: properties.title,
@@ -70,8 +70,7 @@
70
70
  },
71
71
  okText: {
72
72
  type: 'string',
73
- default: 'Ok',
74
- description: 'Text of the Ok button.'
73
+ description: 'Text of the Ok button. When unset, antd uses the localized default from ConfigProvider locale.'
75
74
  },
76
75
  okButtonProps: {
77
76
  type: 'object',
@@ -82,8 +81,7 @@
82
81
  },
83
82
  cancelText: {
84
83
  type: 'string',
85
- default: 'Cancel',
86
- description: 'Text of the Cancel button.'
84
+ description: 'Text of the Cancel button. When unset, antd uses the localized default from ConfigProvider locale.'
87
85
  },
88
86
  cancelButtonProps: {
89
87
  type: 'object',
@@ -16,7 +16,7 @@
16
16
  import { DatePicker } from 'antd';
17
17
  import dayjs from 'dayjs';
18
18
  import utc from 'dayjs/plugin/utc.js';
19
- import { type } from '@lowdefy/helpers';
19
+ import { getLocaleDateFormat, type } from '@lowdefy/helpers';
20
20
  import { withBlockDefaults } from '@lowdefy/block-utils';
21
21
  import Label from '../Label/Label.js';
22
22
  import withTheme from '../withTheme.js';
@@ -26,6 +26,7 @@ const MonthSelector = ({ blockId, classNames = {}, components: { Icon }, events,
26
26
  const [elementId] = useState((0 | Math.random() * 9e2) + 1e2);
27
27
  return /*#__PURE__*/ React.createElement(Label, {
28
28
  blockId: blockId,
29
+ methods: methods,
29
30
  classNames: classNames,
30
31
  components: {
31
32
  Icon
@@ -59,9 +60,9 @@ const MonthSelector = ({ blockId, classNames = {}, components: { Icon }, events,
59
60
  },
60
61
  disabled: properties.disabled || loading,
61
62
  disabledDate: disabledDate(properties.disabledDates),
62
- format: properties.format ?? 'YYYY-MM',
63
+ format: properties.format ?? getLocaleDateFormat(methods.getLocale?.(), 'month') ?? 'YYYY-MM',
63
64
  getPopupContainer: ()=>document.getElementById(`${blockId}_${elementId}_popup`),
64
- placeholder: properties.placeholder ?? 'Select Month',
65
+ placeholder: properties.placeholder,
65
66
  size: properties.size,
66
67
  status: validation.status,
67
68
  value: type.isDate(value) ? dayjs.utc(value).startOf('month') : null,
@@ -38,7 +38,8 @@ export default {
38
38
  event: {
39
39
  value: 'The selected month value.'
40
40
  }
41
- }
41
+ },
42
+ onTooltipClick: 'Trigger actions when the tooltip icon is clicked.'
42
43
  },
43
44
  properties: {
44
45
  type: 'object',
@@ -68,12 +69,10 @@ export default {
68
69
  disabledDates,
69
70
  format: {
70
71
  type: 'string',
71
- default: 'YYYY-MM',
72
- description: 'Format in which to format the date value, eg. "MMMM YYYY" will format a date value of 1999-12-31 as "December 1999". The format has to conform to dayjs formats.'
72
+ description: 'Format in which to format the date value, eg. "MMMM YYYY" will format a date value of 1999-12-31 as "December 1999". The format has to conform to dayjs formats. Defaults to the active locale\'s month format, or "YYYY-MM" when no locale is configured.'
73
73
  },
74
74
  placeholder: {
75
- ...placeholder,
76
- default: 'Select Month'
75
+ ...placeholder
77
76
  },
78
77
  showToday: {
79
78
  type: 'boolean',
@@ -16,14 +16,25 @@
16
16
  import { renderHtml, withBlockDefaults } from '@lowdefy/block-utils';
17
17
  import { get, type } from '@lowdefy/helpers';
18
18
  import { Select } from 'antd';
19
- import getUniqueValues from '../../getUniqueValues.js';
20
- import getValueIndex from '../../getValueIndex.js';
19
+ import useSelectorOptions from '../../useSelectorOptions.js';
20
+ import getSelectedIndex from '../../getSelectedIndex.js';
21
+ import getContrastTextColor from '../../getContrastTextColor.js';
22
+ import getOptionColorStyle from '../../getOptionColorStyle.js';
21
23
  import Label from '../Label/Label.js';
22
24
  import withTheme from '../withTheme.js';
23
25
  import Tag from '../Tag/Tag.js';
24
26
  const Option = Select.Option;
25
- const tagRender = (props, option, methods, components)=>{
27
+ const tagRender = (props, option, methods, components, isOutline)=>{
26
28
  const { label, closable, onClose } = props;
29
+ // An explicit tag.color wins; otherwise the per-option color drives the pill.
30
+ const color = option?.tag?.color ?? option?.color;
31
+ const contrast = getContrastTextColor(color);
32
+ // Hex color → explicit solid/outlined pill (dark-mode safe), following the
33
+ // input variant. Preset name (or none) → antd's Tag color handling.
34
+ const colorStyle = contrast ? getOptionColorStyle({
35
+ color,
36
+ isOutline
37
+ }) : {};
27
38
  return /*#__PURE__*/ React.createElement(Tag, {
28
39
  components: components,
29
40
  methods: methods,
@@ -31,12 +42,14 @@ const tagRender = (props, option, methods, components)=>{
31
42
  styles: {
32
43
  element: {
33
44
  marginRight: 3,
45
+ ...colorStyle,
34
46
  ...option?.tag?.style ?? {}
35
47
  }
36
48
  },
37
49
  properties: {
38
50
  title: label ?? '',
39
51
  ...option?.tag ?? {},
52
+ color: contrast ? undefined : color,
40
53
  closable
41
54
  }
42
55
  });
@@ -44,9 +57,22 @@ const tagRender = (props, option, methods, components)=>{
44
57
  const MultipleSelector = ({ blockId, classNames = {}, components: { Icon, ShortcutBadge }, events, loading, methods, properties, required, styles = {}, validation, value })=>{
45
58
  const [fetchState, setFetch] = useState(false);
46
59
  const [elementId] = useState((0 | Math.random() * 9e2) + 1e2);
47
- const uniqueValueOptions = getUniqueValues(properties.options ?? []);
60
+ const uniqueValueOptions = useSelectorOptions({
61
+ properties,
62
+ methods
63
+ });
64
+ // Auto-enable custom tag rendering when any option carries a color/tag, so
65
+ // per-option pill colors work without requiring renderTags.
66
+ const hasTagStyling = uniqueValueOptions.some((opt)=>!type.isPrimitive(opt) && (opt.color || opt.tag));
67
+ // `outlined` → outlined colored tags; `solid` (or default) → filled colored tags.
68
+ const isOutline = properties.variant === 'outlined';
69
+ // `solid` is not a valid antd Select input variant — use outlined for the frame.
70
+ let antdVariant = properties.variant;
71
+ if (properties.variant === 'solid') antdVariant = 'outlined';
72
+ if (properties.bordered === false) antdVariant = 'borderless';
48
73
  return /*#__PURE__*/ React.createElement(Label, {
49
74
  blockId: blockId,
75
+ methods: methods,
50
76
  classNames: classNames,
51
77
  components: {
52
78
  Icon
@@ -71,7 +97,7 @@ const MultipleSelector = ({ blockId, classNames = {}, components: { Icon, Shortc
71
97
  allowClear: properties.allowClear !== false,
72
98
  autoClearSearchValue: properties.autoClearSearchValue,
73
99
  autoFocus: properties.autoFocus,
74
- variant: properties.bordered === false ? 'borderless' : properties.variant,
100
+ variant: antdVariant,
75
101
  className: classNames.element,
76
102
  classNames: {
77
103
  content: classNames.selector
@@ -86,10 +112,10 @@ const MultipleSelector = ({ blockId, classNames = {}, components: { Icon, Shortc
86
112
  disabled: properties.disabled || loading,
87
113
  getPopupContainer: ()=>document.getElementById(`${blockId}_${elementId}_popup`),
88
114
  mode: "multiple",
89
- tagRender: properties.renderTags && ((props)=>tagRender(props, uniqueValueOptions[props.value], methods, {
115
+ tagRender: (properties.renderTags || hasTagStyling) && ((props)=>tagRender(props, uniqueValueOptions[props.value], methods, {
90
116
  Icon,
91
117
  ShortcutBadge
92
- })),
118
+ }, isOutline)),
93
119
  maxTagCount: properties.maxTagCount,
94
120
  notFoundContent: fetchState ? properties.loadingPlaceholder || 'Loading' : properties.notFoundContent || 'Not found',
95
121
  placeholder: loading ? 'Loading...' : get(properties, 'placeholder', {
@@ -100,7 +126,10 @@ const MultipleSelector = ({ blockId, classNames = {}, components: { Icon, Shortc
100
126
  }),
101
127
  size: properties.size,
102
128
  status: validation.status,
103
- value: loading ? [] : getValueIndex(value, uniqueValueOptions, true),
129
+ value: loading ? [] : getSelectedIndex(value, uniqueValueOptions, {
130
+ properties,
131
+ multiple: true
132
+ }),
104
133
  suffixIcon: properties.suffixIcon && /*#__PURE__*/ React.createElement(Icon, {
105
134
  blockId: `${blockId}_suffixIcon`,
106
135
  classNames: {
@@ -184,7 +213,10 @@ const MultipleSelector = ({ blockId, classNames = {}, components: { Icon, Shortc
184
213
  })) : /*#__PURE__*/ React.createElement(Option, {
185
214
  style: {
186
215
  ...styles.options,
187
- ...opt.style
216
+ ...opt.style,
217
+ ...opt.color ? {
218
+ color: opt.color
219
+ } : {}
188
220
  },
189
221
  className: classNames.options,
190
222
  disabled: opt.disabled,
@@ -15,6 +15,7 @@
15
15
  */ import LabelMeta from '../Label/meta.js';
16
16
  import label from '../../schemas/label.js';
17
17
  import icon from '../../schemas/icon.js';
18
+ import { data, html, valueKey, primaryKey } from '../../schemas/dataOptions.js';
18
19
  import { disabled, autoFocus, variant, bordered, allowClear, sizeSmallDefaultLarge } from '../../schemas/inputProperties.js';
19
20
  export default {
20
21
  category: 'input',
@@ -46,7 +47,8 @@ export default {
46
47
  event: {
47
48
  value: 'The search input value.'
48
49
  }
49
- }
50
+ },
51
+ onTooltipClick: 'Trigger actions when the tooltip icon is clicked.'
50
52
  },
51
53
  properties: {
52
54
  type: 'object',
@@ -74,6 +76,10 @@ export default {
74
76
  },
75
77
  disabled,
76
78
  label,
79
+ data,
80
+ html,
81
+ valueKey,
82
+ primaryKey,
77
83
  options: {
78
84
  default: [],
79
85
  oneOf: [
@@ -103,9 +109,6 @@ export default {
103
109
  description: 'Options can either be an array of primitive values, on an array of label, value pairs.',
104
110
  items: {
105
111
  type: 'object',
106
- required: [
107
- 'value'
108
- ],
109
112
  properties: {
110
113
  label: {
111
114
  type: 'string',
@@ -150,6 +153,13 @@ export default {
150
153
  displayType: 'yaml'
151
154
  }
152
155
  },
156
+ color: {
157
+ type: 'string',
158
+ description: 'Color applied when this option is selected: drives the tag/pill color in the input and tints the option in the dropdown. An explicit `tag.color` takes precedence.',
159
+ docs: {
160
+ displayType: 'color'
161
+ }
162
+ },
153
163
  tag: {
154
164
  type: 'object',
155
165
  properties: {
@@ -220,7 +230,16 @@ export default {
220
230
  type: 'string',
221
231
  description: 'Multiple selector label title - supports html.'
222
232
  },
223
- variant,
233
+ variant: {
234
+ type: 'string',
235
+ enum: [
236
+ 'solid',
237
+ 'outlined',
238
+ 'filled',
239
+ 'borderless'
240
+ ],
241
+ description: 'Tag/input variant. `solid` renders filled colored tags; `outlined` renders outlined colored tags. `filled`/`borderless` are the antd input styles.'
242
+ },
224
243
  renderTags: {
225
244
  type: 'boolean',
226
245
  description: 'When true, the selected option labels are rendered as tags in the selector input. This field must be true to render option tag values.'
@@ -14,12 +14,14 @@
14
14
  limitations under the License.
15
15
  */ import React from 'react';
16
16
  import { InputNumber } from 'antd';
17
+ import { getLocaleDecimalSeparator } from '@lowdefy/helpers';
17
18
  import { withBlockDefaults } from '@lowdefy/block-utils';
18
19
  import Label from '../Label/Label.js';
19
20
  import withTheme from '../withTheme.js';
20
21
  const NumberInput = ({ blockId, classNames = {}, events, components, loading, methods, properties, required, styles = {}, validation, value })=>{
21
22
  return /*#__PURE__*/ React.createElement(Label, {
22
23
  blockId: blockId,
24
+ methods: methods,
23
25
  classNames: classNames,
24
26
  components: components,
25
27
  events: events,
@@ -43,7 +45,7 @@ const NumberInput = ({ blockId, classNames = {}, events, components, loading, me
43
45
  ...styles.element
44
46
  },
45
47
  controls: properties.controls,
46
- decimalSeparator: properties.decimalSeparator,
48
+ decimalSeparator: properties.decimalSeparator ?? getLocaleDecimalSeparator(methods.getLocale?.()) ?? '.',
47
49
  disabled: properties.disabled || loading,
48
50
  formatter: properties.formatter,
49
51
  keyboard: properties.keyboard,
@@ -36,7 +36,8 @@ export default {
36
36
  }
37
37
  },
38
38
  onFocus: 'Trigger action when number input gets focus.',
39
- onPressEnter: 'Trigger actions when input is focused and enter is pressed.'
39
+ onPressEnter: 'Trigger actions when input is focused and enter is pressed.',
40
+ onTooltipClick: 'Trigger actions when the tooltip icon is clicked.'
40
41
  },
41
42
  properties: {
42
43
  type: 'object',
@@ -87,8 +88,7 @@ export default {
87
88
  },
88
89
  decimalSeparator: {
89
90
  type: 'string',
90
- default: '.',
91
- description: 'Separator between number and decimal places.'
91
+ description: 'Separator between number and decimal places. Defaults to the active locale\'s decimal separator (e.g. "," for de-DE, "." for en-US), or "." when no locale is configured.'
92
92
  },
93
93
  precision: {
94
94
  type: 'integer',
@@ -22,10 +22,11 @@ import Header from '../Header/Header.js';
22
22
  import Layout from '../Layout/Layout.js';
23
23
  import Menu from '../Menu/Menu.js';
24
24
  import MobileMenu from '../MobileMenu/MobileMenu.js';
25
- import { getDarkMode, renderHeaderActions, registerDarkModeMethod } from '../headerActions.js';
25
+ import { getDarkMode, renderHeaderActions, registerDarkModeMethod, registerLocaleMethod } from '../headerActions.js';
26
26
  const PageHeaderMenu = ({ basePath, blockId, classNames = {}, components: { Icon, Link, ShortcutBadge }, content, events, menus, methods, pageId, properties, styles = {} })=>{
27
27
  useEffect(()=>{
28
28
  registerDarkModeMethod(methods);
29
+ registerLocaleMethod(methods);
29
30
  });
30
31
  return /*#__PURE__*/ React.createElement(Layout, {
31
32
  blockId: blockId,
@@ -59,7 +60,8 @@ const PageHeaderMenu = ({ basePath, blockId, classNames = {}, components: { Icon
59
60
  styles: {
60
61
  element: mergeObjects([
61
62
  {
62
- background: 'var(--ant-color-bg-container)'
63
+ background: 'var(--ant-color-bg-container)',
64
+ borderBottom: '1px solid var(--ant-color-border)'
63
65
  },
64
66
  styles.header
65
67
  ])
@@ -103,9 +105,16 @@ const PageHeaderMenu = ({ basePath, blockId, classNames = {}, components: { Icon
103
105
  properties.menuLg
104
106
  ]),
105
107
  styles: {
108
+ // Size the menu's line box to the header height minus its 1px bottom
109
+ // border, so the active item's underline lands exactly on that border
110
+ // (antd offsets horizontal items down by 1px expecting the menu's own
111
+ // border below them; reserving the border's 1px here makes the underline
112
+ // and the header divider coincide as a single line). borderBottom is left
113
+ // to the Header so the divider spans the full width, including the logo.
106
114
  element: mergeObjects([
107
115
  {
108
- borderBottom: 'none'
116
+ borderBottom: 'none',
117
+ lineHeight: 'calc(var(--ant-layout-header-height, 64px) - 1px)'
109
118
  },
110
119
  styles.menu
111
120
  ])
@@ -45,6 +45,8 @@ export default {
45
45
  profileAvatar: 'The profile avatar element.',
46
46
  profileMenu: 'The profile dropdown menu popup.',
47
47
  darkModeToggle: 'The PageHeaderMenu dark mode toggle button.',
48
+ localeSelector: 'The PageHeaderMenu locale selector trigger.',
49
+ localeSelectorMenu: 'The PageHeaderMenu locale selector dropdown popup.',
48
50
  mobileMenu: 'The PageHeaderMenu mobile menu.',
49
51
  menu: 'The PageHeaderMenu menu.',
50
52
  content: 'The PageHeaderMenu content.',
@@ -348,7 +350,7 @@ export default {
348
350
  },
349
351
  shortcut: {
350
352
  type: 'string',
351
- description: 'Keyboard shortcut. Renders a shortcut badge next to the label. Use "mod" for Cmd/Ctrl.'
353
+ description: 'Keyboard shortcut. Renders a kbd badge floated to the far right and wires the key handler. Use "mod" for Cmd/Ctrl.'
352
354
  }
353
355
  }
354
356
  },
@@ -408,6 +410,11 @@ export default {
408
410
  default: false,
409
411
  description: 'Show a dark mode toggle button in the header. Toggles the Ant Design dark theme for the entire page. Preference is persisted to localStorage.'
410
412
  },
413
+ localeSelector: {
414
+ type: 'boolean',
415
+ default: false,
416
+ description: 'Show a locale picker dropdown in the header. Lists locales declared in `config.i18n.locales` and dispatches `SetLocale` on selection. Renders nothing when `config.i18n` is not configured.'
417
+ },
411
418
  theme: {
412
419
  type: 'object',
413
420
  description: 'Antd design token overrides for this block. See <a href="https://ant.design/components/overview#design-token">antd design tokens</a>.',
@@ -25,7 +25,7 @@ import Layout from '../Layout/Layout.js';
25
25
  import Menu from '../Menu/Menu.js';
26
26
  import MobileMenu from '../MobileMenu/MobileMenu.js';
27
27
  import Sider from '../Sider/Sider.js';
28
- import { getDarkMode, renderHeaderActions, registerDarkModeMethod } from '../headerActions.js';
28
+ import { getDarkMode, renderHeaderActions, registerDarkModeMethod, registerLocaleMethod } from '../headerActions.js';
29
29
  function getInitialSiderState({ properties }) {
30
30
  const storageKey = `lf-${properties.siderStorageKey ?? 'sider'}-open`;
31
31
  try {
@@ -63,6 +63,7 @@ const PageSidebarLayout = ({ basePath, blockId, classNames = {}, components: { I
63
63
  }, []);
64
64
  useEffect(()=>{
65
65
  registerDarkModeMethod(methods);
66
+ registerLocaleMethod(methods);
66
67
  methods.registerMethod('toggleSiderOpen', ()=>{
67
68
  const next = !openSiderState;
68
69
  methods._toggleSiderOpen({
@@ -55,6 +55,8 @@ export default {
55
55
  profileAvatar: 'The profile avatar element.',
56
56
  profileMenu: 'The profile dropdown menu popup.',
57
57
  darkModeToggle: 'The dark mode toggle button.',
58
+ localeSelector: 'The locale selector trigger.',
59
+ localeSelectorMenu: 'The locale selector dropdown popup.',
58
60
  content: 'The PageSidebarLayout content.',
59
61
  breadcrumb: 'The PageSidebarLayout breadcrumb.',
60
62
  footer: 'The PageSidebarLayout footer.',
@@ -454,7 +456,7 @@ export default {
454
456
  },
455
457
  shortcut: {
456
458
  type: 'string',
457
- description: 'Keyboard shortcut. Renders a shortcut badge next to the label. Use "mod" for Cmd/Ctrl.'
459
+ description: 'Keyboard shortcut. Renders a kbd badge floated to the far right and wires the key handler. Use "mod" for Cmd/Ctrl.'
458
460
  }
459
461
  }
460
462
  },
@@ -514,6 +516,11 @@ export default {
514
516
  default: false,
515
517
  description: 'Show a dark mode toggle button in the sider and mobile header. Toggles the Ant Design dark theme for the entire page. Preference is persisted to localStorage.'
516
518
  },
519
+ localeSelector: {
520
+ type: 'boolean',
521
+ default: false,
522
+ description: 'Show a locale picker dropdown in the sider and mobile header. Lists locales declared in `config.i18n.locales` and dispatches `SetLocale` on selection. Renders nothing when `config.i18n` is not configured.'
523
+ },
517
524
  iconsColor: {
518
525
  type: 'string',
519
526
  description: 'Color for notification and dark mode toggle icons.',
@@ -25,7 +25,7 @@ import Layout from '../Layout/Layout.js';
25
25
  import Menu from '../Menu/Menu.js';
26
26
  import MobileMenu from '../MobileMenu/MobileMenu.js';
27
27
  import Sider from '../Sider/Sider.js';
28
- import { getDarkMode, renderHeaderActions, registerDarkModeMethod } from '../headerActions.js';
28
+ import { getDarkMode, renderHeaderActions, registerDarkModeMethod, registerLocaleMethod } from '../headerActions.js';
29
29
  function getInitialSiderState({ properties }) {
30
30
  const storageKey = `lf-${properties.siderStorageKey ?? 'sider'}-open`;
31
31
  try {
@@ -51,6 +51,7 @@ const PageSiderMenu = ({ basePath, blockId, classNames = {}, components: { Icon,
51
51
  }));
52
52
  useEffect(()=>{
53
53
  registerDarkModeMethod(methods);
54
+ registerLocaleMethod(methods);
54
55
  methods.registerMethod('toggleSiderOpen', ()=>{
55
56
  const next = !openSiderState;
56
57
  methods._setSiderOpen({
@@ -48,6 +48,8 @@ export default {
48
48
  profileAvatar: 'The profile avatar element.',
49
49
  profileMenu: 'The profile dropdown menu popup.',
50
50
  darkModeToggle: 'The PageSiderMenu dark mode toggle button.',
51
+ localeSelector: 'The PageSiderMenu locale selector trigger.',
52
+ localeSelectorMenu: 'The PageSiderMenu locale selector dropdown popup.',
51
53
  mobileMenu: 'The PageSiderMenu mobile menu.',
52
54
  layout: 'The PageSiderMenu inner layout.',
53
55
  sider: 'The PageSiderMenu sider.',
@@ -414,7 +416,7 @@ export default {
414
416
  },
415
417
  shortcut: {
416
418
  type: 'string',
417
- description: 'Keyboard shortcut. Renders a shortcut badge next to the label. Use "mod" for Cmd/Ctrl.'
419
+ description: 'Keyboard shortcut. Renders a kbd badge floated to the far right and wires the key handler. Use "mod" for Cmd/Ctrl.'
418
420
  }
419
421
  }
420
422
  },
@@ -474,6 +476,11 @@ export default {
474
476
  default: false,
475
477
  description: 'Show a dark mode toggle button in the header. Toggles the Ant Design dark theme for the entire page. Preference is persisted to localStorage.'
476
478
  },
479
+ localeSelector: {
480
+ type: 'boolean',
481
+ default: false,
482
+ description: 'Show a locale picker dropdown in the header. Lists locales declared in `config.i18n.locales` and dispatches `SetLocale` on selection. Renders nothing when `config.i18n` is not configured.'
483
+ },
477
484
  theme: {
478
485
  type: 'object',
479
486
  description: 'Antd design token overrides for this block. See <a href="https://ant.design/components/overview#design-token">antd design tokens</a>.',
@@ -21,6 +21,7 @@ import useRunAfterUpdate from '../../useRunAfterUpdate.js';
21
21
  const PasswordInput = ({ blockId, classNames = {}, components, events, loading, methods, properties, required, styles = {}, validation, value })=>{
22
22
  return /*#__PURE__*/ React.createElement(Label, {
23
23
  blockId: blockId,
24
+ methods: methods,
24
25
  classNames: classNames,
25
26
  components: components,
26
27
  events: events,
@@ -36,7 +36,8 @@ export default {
36
36
  }
37
37
  },
38
38
  onFocus: 'Trigger action when text input gets focus.',
39
- onPressEnter: 'Trigger action when enter is pressed while text input is focused.'
39
+ onPressEnter: 'Trigger action when enter is pressed while text input is focused.',
40
+ onTooltipClick: 'Trigger actions when the tooltip icon is clicked.'
40
41
  },
41
42
  properties: {
42
43
  type: 'object',
@@ -130,6 +130,7 @@ const PhoneNumberInput = ({ blockId, classNames = {}, components: { Icon, Link }
130
130
  }
131
131
  return /*#__PURE__*/ React.createElement(Label, {
132
132
  blockId: blockId,
133
+ methods: methods,
133
134
  classNames: classNames,
134
135
  components: {
135
136
  Icon,
@@ -43,7 +43,8 @@ export default {
43
43
  },
44
44
  onBlur: 'Trigger action event occurs when input loses focus.',
45
45
  onFocus: 'Trigger action when input gets focus.',
46
- onPressEnter: 'Trigger action when enter is pressed while text input is focused.'
46
+ onPressEnter: 'Trigger action when enter is pressed while text input is focused.',
47
+ onTooltipClick: 'Trigger actions when the tooltip icon is clicked.'
47
48
  },
48
49
  properties: {
49
50
  type: 'object',