@lowdefy/blocks-antd 5.5.1 → 5.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,7 +13,7 @@
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  */ import React from 'react';
16
- import { Checkbox, ConfigProvider, Space } from 'antd';
16
+ import { Checkbox, Col, ConfigProvider, Row, Space, theme } from 'antd';
17
17
  import { type } from '@lowdefy/helpers';
18
18
  import { renderHtml, withBlockDefaults } from '@lowdefy/block-utils';
19
19
  import Label from '../Label/Label.js';
@@ -21,6 +21,7 @@ import getSelectedIndex from '../../getSelectedIndex.js';
21
21
  import useSelectorOptions from '../../useSelectorOptions.js';
22
22
  import withTheme from '../withTheme.js';
23
23
  const CheckboxSelector = ({ blockId, classNames = {}, components, events, loading, properties, required, styles = {}, validation, value, methods })=>{
24
+ const { token } = theme.useToken();
24
25
  const uniqueValueOptions = useSelectorOptions({
25
26
  properties,
26
27
  methods
@@ -29,33 +30,17 @@ const CheckboxSelector = ({ blockId, classNames = {}, components, events, loadin
29
30
  properties,
30
31
  multiple: true
31
32
  }));
32
- const checkboxGroup = /*#__PURE__*/ React.createElement(Checkbox.Group, {
33
- id: `${blockId}_input`,
34
- className: classNames.element,
35
- disabled: properties.disabled || loading,
36
- style: styles.element,
37
- onChange: (newVal)=>{
38
- const val = [];
39
- newVal.forEach((nv)=>{
40
- val.push(type.isPrimitive(uniqueValueOptions[nv]) ? uniqueValueOptions[nv] : uniqueValueOptions[nv].value);
41
- });
42
- methods.setValue(val);
43
- methods.triggerEvent({
44
- name: 'onChange',
45
- event: {
46
- value: val
47
- }
48
- });
49
- },
50
- value: getSelectedIndex(value, uniqueValueOptions, {
51
- properties,
52
- multiple: true
53
- })
54
- }, /*#__PURE__*/ React.createElement(Space, {
55
- direction: properties.direction,
56
- wrap: type.isNone(properties.wrap) ? true : properties.wrap,
57
- align: type.isNone(properties.align) ? 'start' : properties.align
58
- }, uniqueValueOptions.map((opt, i)=>{
33
+ const grid = !type.isNone(properties.columns);
34
+ // Col takes spans, not counts, so a breakpoint map of counts converts per key.
35
+ const colProps = type.isObject(properties.columns) ? Object.fromEntries(Object.entries(properties.columns).map(([breakpoint, columns])=>[
36
+ breakpoint,
37
+ {
38
+ span: 24 / columns
39
+ }
40
+ ])) : {
41
+ span: 24 / properties.columns
42
+ };
43
+ const renderOption = (opt, i)=>{
59
44
  if (type.isPrimitive(opt)) {
60
45
  return /*#__PURE__*/ React.createElement(Checkbox, {
61
46
  id: `${blockId}_${i}`,
@@ -95,7 +80,47 @@ const CheckboxSelector = ({ blockId, classNames = {}, components, events, loadin
95
80
  }
96
81
  }
97
82
  }, checkbox);
98
- })));
83
+ };
84
+ const checkboxGroup = /*#__PURE__*/ React.createElement(Checkbox.Group, {
85
+ id: `${blockId}_input`,
86
+ className: classNames.element,
87
+ disabled: properties.disabled || loading,
88
+ // Checkbox.Group is inline-flex and shrink-wraps, so the Row inside it can
89
+ // only fill a group that has been given a width.
90
+ style: grid ? {
91
+ width: '100%',
92
+ ...styles.element
93
+ } : styles.element,
94
+ onChange: (newVal)=>{
95
+ const val = [];
96
+ newVal.forEach((nv)=>{
97
+ val.push(type.isPrimitive(uniqueValueOptions[nv]) ? uniqueValueOptions[nv] : uniqueValueOptions[nv].value);
98
+ });
99
+ methods.setValue(val);
100
+ methods.triggerEvent({
101
+ name: 'onChange',
102
+ event: {
103
+ value: val
104
+ }
105
+ });
106
+ },
107
+ value: getSelectedIndex(value, uniqueValueOptions, {
108
+ properties,
109
+ multiple: true
110
+ })
111
+ }, grid ? /*#__PURE__*/ React.createElement(Row, {
112
+ gutter: type.isNone(properties.gutter) ? [
113
+ token.paddingXS,
114
+ 0
115
+ ] : properties.gutter
116
+ }, uniqueValueOptions.map((opt, i)=>/*#__PURE__*/ React.createElement(Col, {
117
+ key: i,
118
+ ...colProps
119
+ }, renderOption(opt, i)))) : /*#__PURE__*/ React.createElement(Space, {
120
+ direction: properties.direction,
121
+ wrap: type.isNone(properties.wrap) ? true : properties.wrap,
122
+ align: type.isNone(properties.align) ? 'start' : properties.align
123
+ }, uniqueValueOptions.map(renderOption)));
99
124
  return /*#__PURE__*/ React.createElement(Label, {
100
125
  blockId: blockId,
101
126
  methods: methods,
@@ -51,7 +51,7 @@ export default {
51
51
  'baseline'
52
52
  ],
53
53
  default: 'start',
54
- description: 'Align options.'
54
+ description: "Align options. Ignored when 'columns' is set."
55
55
  },
56
56
  color: {
57
57
  type: 'string',
@@ -60,6 +60,16 @@ export default {
60
60
  displayType: 'color'
61
61
  }
62
62
  },
63
+ columns: {
64
+ type: [
65
+ 'integer',
66
+ 'object'
67
+ ],
68
+ description: 'Number of columns to lay the options out in, or a responsive breakpoint object. Use a count that divides 24 evenly.',
69
+ docs: {
70
+ displayType: 'yaml'
71
+ }
72
+ },
63
73
  disabled,
64
74
  direction: {
65
75
  type: 'string',
@@ -68,12 +78,22 @@ export default {
68
78
  'vertical'
69
79
  ],
70
80
  default: 'horizontal',
71
- description: 'List options horizontally or vertical.'
81
+ description: "List options horizontally or vertical. Ignored when 'columns' is set."
82
+ },
83
+ gutter: {
84
+ type: [
85
+ 'number',
86
+ 'array'
87
+ ],
88
+ description: "Gap between options in the grid. Number or [horizontal, vertical] array. Applies when 'columns' is set.",
89
+ docs: {
90
+ displayType: 'yaml'
91
+ }
72
92
  },
73
93
  wrap: {
74
94
  type: 'boolean',
75
95
  default: true,
76
- description: "Specifies wrapping of options. Applies when 'direction' is 'horizontal'."
96
+ description: "Specifies wrapping of options. Applies when 'direction' is 'horizontal'. Ignored when 'columns' is set."
77
97
  },
78
98
  options,
79
99
  data,
@@ -142,7 +162,7 @@ export default {
142
162
  marginXS: {
143
163
  type: 'number',
144
164
  default: 8,
145
- description: 'Horizontal gap between checkboxes in a group.'
165
+ description: "Column gap on the checkbox group element. Does not space the options apart; set 'gutter' for a grid."
146
166
  },
147
167
  paddingXS: {
148
168
  type: 'number',
@@ -28,7 +28,7 @@ const validationKeyMap = {
28
28
  };
29
29
  let iconMap;
30
30
  const Label = ({ blockId, classNames: blockClassNames = {}, components: { Icon }, content, methods, properties, required, styles = {}, validation })=>{
31
- const { extraClassName, extraStyle, feedbackClassName, feedbackStyle, iconClassName, label, labelClassName, labelCol, labelColClassName, labelColStyle, labelStyle, rowClassName, rowStyle, showExtra, showFeedback, wrapperCol } = labelLogic({
31
+ const { extraClassName, extraStyle, feedbackClassName, feedbackStyle, iconClassName, label, labelClassName, labelCol, labelColClassName, labelColStyle, labelStyle, rowClassName, rowStyle, showExtra, showFeedback, showFeedbackIcon, wrapperCol } = labelLogic({
32
32
  blockId,
33
33
  blockClassNames,
34
34
  content,
@@ -53,8 +53,8 @@ const Label = ({ blockId, classNames: blockClassNames = {}, components: { Icon }
53
53
  })
54
54
  };
55
55
  }
56
- const IconNode = validation.status && iconMap[validation.status];
57
- const icon = validation.status && IconNode ? /*#__PURE__*/ React.createElement("span", {
56
+ const IconNode = showFeedbackIcon && iconMap[validation.status];
57
+ const icon = IconNode ? /*#__PURE__*/ React.createElement("span", {
58
58
  className: iconClassName
59
59
  }, /*#__PURE__*/ React.createElement(IconNode, null)) : null;
60
60
  // tooltip is either a string (the tooltip text) or an object that also
@@ -78,8 +78,10 @@ const labelLogic = ({ blockId, blockClassNames = {}, content, properties = {}, r
78
78
  'ant-form-item-feedback-icon-validating': validation.status === 'validating',
79
79
  'ldf-feedback-icon': true
80
80
  });
81
+ const hasFeedback = properties.hasFeedback !== false;
81
82
  const showExtra = !!properties.extra && (!validation.status || validation.status === 'success');
82
- const showFeedback = validation.status === 'warning' || validation.status === 'error';
83
+ const showFeedback = hasFeedback && (validation.status === 'warning' || validation.status === 'error');
84
+ const showFeedbackIcon = hasFeedback && !type.isNone(validation.status);
83
85
  return {
84
86
  extraClassName,
85
87
  extraStyle,
@@ -96,6 +98,7 @@ const labelLogic = ({ blockId, blockClassNames = {}, content, properties = {}, r
96
98
  rowStyle,
97
99
  showExtra,
98
100
  showFeedback,
101
+ showFeedbackIcon,
99
102
  wrapperCol
100
103
  };
101
104
  };
@@ -13,7 +13,7 @@
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  */ import React from 'react';
16
- import { ConfigProvider, Radio, Space } from 'antd';
16
+ import { Col, ConfigProvider, Radio, Row, Space, theme } from 'antd';
17
17
  import { renderHtml, withBlockDefaults } from '@lowdefy/block-utils';
18
18
  import { type } from '@lowdefy/helpers';
19
19
  import Label from '../Label/Label.js';
@@ -22,6 +22,7 @@ import useSelectorOptions from '../../useSelectorOptions.js';
22
22
  import withTheme from '../withTheme.js';
23
23
  const RadioGroup = Radio.Group;
24
24
  const RadioSelector = ({ blockId, classNames = {}, components, events, loading, properties, required, styles = {}, validation, value, methods })=>{
25
+ const { token } = theme.useToken();
25
26
  const uniqueValueOptions = useSelectorOptions({
26
27
  properties,
27
28
  methods
@@ -29,29 +30,17 @@ const RadioSelector = ({ blockId, classNames = {}, components, events, loading,
29
30
  const selectedIndex = getSelectedIndex(value, uniqueValueOptions, {
30
31
  properties
31
32
  });
32
- const radioGroup = /*#__PURE__*/ React.createElement(RadioGroup, {
33
- id: `${blockId}_input`,
34
- className: classNames.element,
35
- disabled: properties.disabled || loading,
36
- style: styles.element,
37
- onChange: (event)=>{
38
- const val = type.isPrimitive(uniqueValueOptions[event.target.value]) ? uniqueValueOptions[event.target.value] : uniqueValueOptions[event.target.value].value;
39
- methods.setValue(val);
40
- methods.triggerEvent({
41
- name: 'onChange',
42
- event: {
43
- value: val
44
- }
45
- });
46
- },
47
- value: `${getSelectedIndex(value, uniqueValueOptions, {
48
- properties
49
- })}`
50
- }, /*#__PURE__*/ React.createElement(Space, {
51
- direction: properties.direction,
52
- wrap: type.isNone(properties.wrap) ? true : properties.wrap,
53
- align: type.isNone(properties.align) ? 'start' : properties.align
54
- }, uniqueValueOptions.map((opt, i)=>{
33
+ const grid = !type.isNone(properties.columns);
34
+ // Col takes spans, not counts, so a breakpoint map of counts converts per key.
35
+ const colProps = type.isObject(properties.columns) ? Object.fromEntries(Object.entries(properties.columns).map(([breakpoint, columns])=>[
36
+ breakpoint,
37
+ {
38
+ span: 24 / columns
39
+ }
40
+ ])) : {
41
+ span: 24 / properties.columns
42
+ };
43
+ const renderOption = (opt, i)=>{
55
44
  if (type.isPrimitive(opt)) {
56
45
  return /*#__PURE__*/ React.createElement(Radio, {
57
46
  id: `${blockId}_${opt}`,
@@ -91,7 +80,43 @@ const RadioSelector = ({ blockId, classNames = {}, components, events, loading,
91
80
  }
92
81
  }
93
82
  }, radio);
94
- })));
83
+ };
84
+ const radioGroup = /*#__PURE__*/ React.createElement(RadioGroup, {
85
+ id: `${blockId}_input`,
86
+ className: classNames.element,
87
+ disabled: properties.disabled || loading,
88
+ // Radio.Group is inline-block and shrink-wraps, so the Row inside it can
89
+ // only fill a group that has been given a width.
90
+ style: grid ? {
91
+ width: '100%',
92
+ ...styles.element
93
+ } : styles.element,
94
+ onChange: (event)=>{
95
+ const val = type.isPrimitive(uniqueValueOptions[event.target.value]) ? uniqueValueOptions[event.target.value] : uniqueValueOptions[event.target.value].value;
96
+ methods.setValue(val);
97
+ methods.triggerEvent({
98
+ name: 'onChange',
99
+ event: {
100
+ value: val
101
+ }
102
+ });
103
+ },
104
+ value: `${getSelectedIndex(value, uniqueValueOptions, {
105
+ properties
106
+ })}`
107
+ }, grid ? /*#__PURE__*/ React.createElement(Row, {
108
+ gutter: type.isNone(properties.gutter) ? [
109
+ token.paddingXS,
110
+ 0
111
+ ] : properties.gutter
112
+ }, uniqueValueOptions.map((opt, i)=>/*#__PURE__*/ React.createElement(Col, {
113
+ key: i,
114
+ ...colProps
115
+ }, renderOption(opt, i)))) : /*#__PURE__*/ React.createElement(Space, {
116
+ direction: properties.direction,
117
+ wrap: type.isNone(properties.wrap) ? true : properties.wrap,
118
+ align: type.isNone(properties.align) ? 'start' : properties.align
119
+ }, uniqueValueOptions.map(renderOption)));
95
120
  return /*#__PURE__*/ React.createElement(Label, {
96
121
  blockId: blockId,
97
122
  methods: methods,
@@ -51,7 +51,7 @@ export default {
51
51
  'baseline'
52
52
  ],
53
53
  default: 'start',
54
- description: 'Align options.'
54
+ description: "Align options. Ignored when 'columns' is set."
55
55
  },
56
56
  color: {
57
57
  type: 'string',
@@ -60,6 +60,16 @@ export default {
60
60
  displayType: 'color'
61
61
  }
62
62
  },
63
+ columns: {
64
+ type: [
65
+ 'integer',
66
+ 'object'
67
+ ],
68
+ description: 'Number of columns to lay the options out in, or a responsive breakpoint object. Use a count that divides 24 evenly.',
69
+ docs: {
70
+ displayType: 'yaml'
71
+ }
72
+ },
63
73
  disabled,
64
74
  direction: {
65
75
  type: 'string',
@@ -68,12 +78,22 @@ export default {
68
78
  'vertical'
69
79
  ],
70
80
  default: 'horizontal',
71
- description: 'List options horizontally or vertical.'
81
+ description: "List options horizontally or vertical. Ignored when 'columns' is set."
82
+ },
83
+ gutter: {
84
+ type: [
85
+ 'number',
86
+ 'array'
87
+ ],
88
+ description: "Gap between options in the grid. Number or [horizontal, vertical] array. Applies when 'columns' is set.",
89
+ docs: {
90
+ displayType: 'yaml'
91
+ }
72
92
  },
73
93
  wrap: {
74
94
  type: 'boolean',
75
95
  default: true,
76
- description: "Specifies wrapping of options. Applies when 'direction' is 'horizontal'."
96
+ description: "Specifies wrapping of options. Applies when 'direction' is 'horizontal'. Ignored when 'columns' is set."
77
97
  },
78
98
  label,
79
99
  options,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lowdefy/blocks-antd",
3
- "version": "5.5.1",
3
+ "version": "5.6.0",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Lowdefy Ant Design Blocks",
6
6
  "homepage": "https://lowdefy.com",
@@ -45,9 +45,9 @@
45
45
  ],
46
46
  "dependencies": {
47
47
  "@ant-design/icons": "6.1.0",
48
- "@lowdefy/block-utils": "5.5.1",
49
- "@lowdefy/helpers": "5.5.1",
50
- "@lowdefy/nunjucks": "5.5.1",
48
+ "@lowdefy/block-utils": "5.6.0",
49
+ "@lowdefy/helpers": "5.6.0",
50
+ "@lowdefy/nunjucks": "5.6.0",
51
51
  "@rc-component/motion": "1.3.1",
52
52
  "classnames": "2.3.2",
53
53
  "dayjs": "1.11.19",
@@ -60,9 +60,9 @@
60
60
  "react-dom": ">=18"
61
61
  },
62
62
  "devDependencies": {
63
- "@lowdefy/block-dev-e2e": "5.5.1",
64
- "@lowdefy/e2e-utils": "5.5.1",
65
- "@lowdefy/node-utils": "5.5.1",
63
+ "@lowdefy/block-dev-e2e": "5.6.0",
64
+ "@lowdefy/e2e-utils": "5.6.0",
65
+ "@lowdefy/node-utils": "5.6.0",
66
66
  "@playwright/test": "1.50.1",
67
67
  "@swc/cli": "0.8.0",
68
68
  "@swc/core": "1.15.18",