@lowdefy/layout 4.7.3 → 5.1.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/Area.js CHANGED
@@ -13,29 +13,45 @@
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 { Row } from 'antd';
17
- import { blockDefaultProps } from '@lowdefy/block-utils';
18
- import gutterSetup from './gutterSetup.js';
16
+ import { withBlockDefaults } from '@lowdefy/block-utils';
19
17
  import layoutParamsToArea from './layoutParamsToArea.js';
20
- const Area = ({ area = {}, areaKey, areaStyle, children, id, layout, makeCssClass })=>{
18
+ import deriveAreaStyle from './deriveAreaStyle.js';
19
+ const ALIGN_MAP = {
20
+ top: 'flex-start',
21
+ middle: 'center',
22
+ bottom: 'flex-end',
23
+ stretch: 'stretch'
24
+ };
25
+ const JUSTIFY_MAP = {
26
+ start: 'flex-start',
27
+ center: 'center',
28
+ end: 'flex-end',
29
+ 'space-between': 'space-between',
30
+ 'space-around': 'space-around',
31
+ 'space-evenly': 'space-evenly'
32
+ };
33
+ const Area = ({ area = {}, areaKey, children, id, layout, className, style })=>{
21
34
  const derivedArea = layoutParamsToArea({
22
35
  area,
23
36
  areaKey,
24
37
  layout
25
38
  });
26
- return /*#__PURE__*/ React.createElement(Row, {
39
+ const gapStyle = deriveAreaStyle(derivedArea);
40
+ return /*#__PURE__*/ React.createElement("div", {
27
41
  id: id,
28
- align: derivedArea.align,
29
- className: makeCssClass(areaStyle),
30
- gutter: gutterSetup(derivedArea.gutter),
31
- justify: derivedArea.justify,
42
+ className: [
43
+ 'lf-row',
44
+ className
45
+ ].filter(Boolean).join(' '),
32
46
  style: {
33
- // antd keeps bottom margin which can cause overflow issues.
47
+ ...gapStyle,
48
+ alignItems: ALIGN_MAP[derivedArea.align],
49
+ justifyContent: JUSTIFY_MAP[derivedArea.justify],
34
50
  flexDirection: derivedArea.direction,
35
- flexWrap: derivedArea.wrap,
36
- overflow: derivedArea.overflow
51
+ flexWrap: derivedArea.wrap ?? 'wrap',
52
+ overflow: derivedArea.overflow,
53
+ ...style
37
54
  }
38
55
  }, children);
39
56
  };
40
- Area.defaultProps = blockDefaultProps;
41
- export default Area;
57
+ export default withBlockDefaults(Area);
@@ -13,36 +13,33 @@
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 { Col } from 'antd';
16
+ import { withBlockDefaults } from '@lowdefy/block-utils';
17
17
  import deriveLayout from './deriveLayout.js';
18
- import { blockDefaultProps } from '@lowdefy/block-utils';
19
- const alignSelf = (align)=>{
20
- if (align === 'bottom') {
21
- return 'flex-end';
22
- }
23
- if (align === 'top') {
24
- return 'flex-start';
25
- }
26
- if (align === 'middle') {
27
- return 'center';
28
- }
29
- return align;
18
+ const ALIGN_SELF_MAP = {
19
+ top: 'flex-start',
20
+ middle: 'center',
21
+ bottom: 'flex-end'
30
22
  };
31
- const BlockLayout = ({ id, blockStyle, children, layout = {}, makeCssClass })=>{
23
+ const BlockLayout = ({ id, children, layout = {}, className, style })=>{
32
24
  if (layout.disabled) {
33
25
  return /*#__PURE__*/ React.createElement("div", {
34
26
  id: id,
35
- className: makeCssClass(blockStyle)
27
+ className: className,
28
+ style: style
36
29
  }, children);
37
30
  }
38
- return /*#__PURE__*/ React.createElement(Col, {
39
- ...deriveLayout(layout),
40
- style: {
41
- alignSelf: alignSelf(layout.align)
42
- },
31
+ const derived = deriveLayout(layout);
32
+ return /*#__PURE__*/ React.createElement("div", {
43
33
  id: id,
44
- className: makeCssClass(blockStyle)
34
+ className: [
35
+ derived.className,
36
+ className
37
+ ].filter(Boolean).join(' '),
38
+ style: {
39
+ ...derived.style,
40
+ alignSelf: ALIGN_SELF_MAP[layout.selfAlign] ?? layout.selfAlign,
41
+ ...style
42
+ }
45
43
  }, children);
46
44
  };
47
- BlockLayout.defaultProps = blockDefaultProps;
48
- export default BlockLayout;
45
+ export default withBlockDefaults(BlockLayout);
@@ -0,0 +1,61 @@
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
+ */ import { type } from '@lowdefy/helpers';
16
+ const BREAKPOINT_SUFFIXES = [
17
+ 'sm',
18
+ 'md',
19
+ 'lg',
20
+ 'xl',
21
+ '2xl'
22
+ ];
23
+ function setGapAxis(style, axis, value) {
24
+ if (type.isNumber(value)) {
25
+ style[`--lf-gap-${axis}`] = `${Math.round(value)}px`;
26
+ return;
27
+ }
28
+ if (type.isObject(value)) {
29
+ if (value.xs != null) {
30
+ style[`--lf-gap-${axis}`] = `${Math.round(value.xs)}px`;
31
+ }
32
+ for (const bp of BREAKPOINT_SUFFIXES){
33
+ if (value[bp] != null) {
34
+ style[`--lf-gap-${axis}-${bp}`] = `${Math.round(value[bp])}px`;
35
+ }
36
+ }
37
+ }
38
+ }
39
+ function deriveAreaStyle(area) {
40
+ const { gap } = area;
41
+ if (type.isNone(gap)) return {};
42
+ const style = {};
43
+ if (type.isNumber(gap)) {
44
+ const px = `${Math.round(gap)}px`;
45
+ style['--lf-gap-x'] = px;
46
+ style['--lf-gap-y'] = px;
47
+ return style;
48
+ }
49
+ if (type.isArray(gap)) {
50
+ setGapAxis(style, 'x', gap[0]);
51
+ setGapAxis(style, 'y', gap[1]);
52
+ return style;
53
+ }
54
+ if (type.isObject(gap)) {
55
+ setGapAxis(style, 'x', gap);
56
+ setGapAxis(style, 'y', gap);
57
+ return style;
58
+ }
59
+ return style;
60
+ }
61
+ export default deriveAreaStyle;
@@ -61,32 +61,29 @@ const deriveFlex = ({ flex, grow, shrink, size })=>{
61
61
  }
62
62
  return `${sanitizeGrow(grow)} ${sanitizeShrink(shrink)} ${sanitizeSize(size)}`;
63
63
  };
64
- const diffOffsetAndSpan = (obj)=>{
65
- if (obj.offset && !obj.span) {
66
- obj.span = 24 - obj.offset;
67
- return obj;
64
+ const resolveSpan = (span, offset)=>{
65
+ if (type.isNone(span)) {
66
+ return offset ? 24 - offset : 24;
68
67
  }
69
- if (!obj.span) {
70
- obj.span = 24;
68
+ return span;
69
+ };
70
+ const applyBreakpoint = (cssVars, classes, bp, obj)=>{
71
+ const suffix = bp ? `-${bp}` : '';
72
+ const span = resolveSpan(obj.span, obj.offset);
73
+ cssVars[`--lf-display${suffix}`] = span === 0 ? 'none' : 'block';
74
+ cssVars[`--lf-span${suffix}`] = span;
75
+ if (!type.isNone(obj.offset)) cssVars[`--lf-offset${suffix}`] = obj.offset;
76
+ if (!type.isNone(obj.order)) cssVars[`--lf-order${suffix}`] = obj.order;
77
+ if (!type.isNone(obj.push)) {
78
+ cssVars[`--lf-push${suffix}`] = obj.push;
79
+ if (!classes.includes('lf-col-push')) classes.push('lf-col-push');
80
+ }
81
+ if (!type.isNone(obj.pull)) {
82
+ cssVars[`--lf-pull${suffix}`] = obj.pull;
83
+ if (!classes.includes('lf-col-pull')) classes.push('lf-col-pull');
71
84
  }
72
- return obj;
73
85
  };
74
- const deriveLayout = ({ flex, offset, order, pull, push, span, grow, shrink, size, xs, sm, md, lg, xl, xxl })=>{
75
- let colProps = {
76
- xs: {
77
- span: 24
78
- },
79
- sm: {
80
- span: 24
81
- },
82
- md: diffOffsetAndSpan({
83
- offset,
84
- order,
85
- pull,
86
- push,
87
- span
88
- })
89
- };
86
+ const deriveLayout = ({ flex, offset, order, pull, push, span, grow, shrink, size, xs, sm, md, lg, xl, '2xl': bp2xl })=>{
90
87
  const flexValue = deriveFlex({
91
88
  flex,
92
89
  grow,
@@ -94,42 +91,78 @@ const deriveLayout = ({ flex, offset, order, pull, push, span, grow, shrink, siz
94
91
  size
95
92
  });
96
93
  if (flexValue) {
97
- colProps = {
98
- flex: flexValue,
99
- order
94
+ return {
95
+ className: '',
96
+ style: {
97
+ flex: flexValue,
98
+ order
99
+ }
100
100
  };
101
101
  }
102
+ const classes = [
103
+ 'lf-col'
104
+ ];
105
+ const cssVars = {};
106
+ // Base (xs): always full width
107
+ cssVars['--lf-span'] = 24;
108
+ // md: uses top-level span/offset/order/push/pull
109
+ // Always emit --lf-span-md to break the CSS var() fallback chain
110
+ const mdSpan = resolveSpan(span, offset);
111
+ cssVars['--lf-span-md'] = mdSpan;
112
+ if (mdSpan === 0) cssVars['--lf-display-md'] = 'none';
113
+ if (!type.isNone(offset)) cssVars['--lf-offset-md'] = offset;
114
+ if (!type.isNone(order)) cssVars['--lf-order-md'] = order;
115
+ if (!type.isNone(push)) {
116
+ cssVars['--lf-push-md'] = push;
117
+ classes.push('lf-col-push');
118
+ }
119
+ if (!type.isNone(pull)) {
120
+ cssVars['--lf-pull-md'] = pull;
121
+ classes.push('lf-col-pull');
122
+ }
123
+ // sm: cascades down to xs (base vars) AND sets -sm vars
102
124
  if (type.isObject(sm)) {
103
- colProps.sm = {
104
- ...colProps.sm,
105
- ...diffOffsetAndSpan(sm)
106
- };
107
- colProps.xs = {
108
- ...colProps.xs,
109
- ...diffOffsetAndSpan(sm)
125
+ const smObj = {
126
+ ...sm
110
127
  };
111
- }
128
+ const smSpan = resolveSpan(smObj.span, smObj.offset);
129
+ cssVars['--lf-span'] = smSpan;
130
+ cssVars['--lf-display'] = smSpan === 0 ? 'none' : 'block';
131
+ if (!type.isNone(smObj.offset)) cssVars['--lf-offset'] = smObj.offset;
132
+ if (!type.isNone(smObj.order)) cssVars['--lf-order'] = smObj.order;
133
+ if (!type.isNone(smObj.push)) {
134
+ cssVars['--lf-push'] = smObj.push;
135
+ if (!classes.includes('lf-col-push')) classes.push('lf-col-push');
136
+ }
137
+ if (!type.isNone(smObj.pull)) {
138
+ cssVars['--lf-pull'] = smObj.pull;
139
+ if (!classes.includes('lf-col-pull')) classes.push('lf-col-pull');
140
+ }
141
+ applyBreakpoint(cssVars, classes, 'sm', smObj);
142
+ }
143
+ // xs: applied AFTER sm, overrides the sm→xs cascade
112
144
  if (type.isObject(xs)) {
113
- colProps.xs = {
114
- ...colProps.xs,
115
- ...diffOffsetAndSpan(xs)
116
- };
145
+ applyBreakpoint(cssVars, classes, null, {
146
+ ...xs
147
+ });
117
148
  }
149
+ // md override: spread-merge with baseline
118
150
  if (type.isObject(md)) {
119
- colProps.md = {
120
- ...colProps.md,
121
- ...diffOffsetAndSpan(md)
122
- };
123
- }
124
- if (type.isObject(lg)) {
125
- colProps.lg = diffOffsetAndSpan(lg);
126
- }
127
- if (type.isObject(xl)) {
128
- colProps.xl = diffOffsetAndSpan(xl);
129
- }
130
- if (type.isObject(xxl)) {
131
- colProps.xxl = diffOffsetAndSpan(xxl);
132
- }
133
- return colProps;
151
+ applyBreakpoint(cssVars, classes, 'md', {
152
+ offset,
153
+ order,
154
+ push,
155
+ pull,
156
+ ...md
157
+ });
158
+ }
159
+ // lg, xl, 2xl: direct assignment — no baseline merge
160
+ if (type.isObject(lg)) applyBreakpoint(cssVars, classes, 'lg', lg);
161
+ if (type.isObject(xl)) applyBreakpoint(cssVars, classes, 'xl', xl);
162
+ if (type.isObject(bp2xl)) applyBreakpoint(cssVars, classes, '2xl', bp2xl);
163
+ return {
164
+ className: classes.join(' '),
165
+ style: cssVars
166
+ };
134
167
  };
135
168
  export default deriveLayout;
package/dist/grid.css ADDED
@@ -0,0 +1,334 @@
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
+ */
16
+
17
+ @layer components {
18
+ /* =====================================================
19
+ Row (Area)
20
+
21
+ --_gap is the resolved horizontal gap at the current
22
+ breakpoint. It's used for column-gap on the row AND
23
+ inherited by child .lf-col elements for the flex-basis
24
+ gap adjustment formula.
25
+ ===================================================== */
26
+ .lf-row {
27
+ --_gap: var(--lf-gap-x, 0px);
28
+ display: flex;
29
+ /* flex-wrap is set via inline style (derivedArea.wrap ?? 'wrap') */
30
+ column-gap: var(--_gap);
31
+ row-gap: var(--lf-gap-y, 0px);
32
+ }
33
+
34
+ @media (min-width: 640px) {
35
+ .lf-row {
36
+ --_gap: var(--lf-gap-x-sm, var(--lf-gap-x, 0px));
37
+ column-gap: var(--_gap);
38
+ row-gap: var(--lf-gap-y-sm, var(--lf-gap-y, 0px));
39
+ }
40
+ }
41
+ @media (min-width: 768px) {
42
+ .lf-row {
43
+ --_gap: var(--lf-gap-x-md, var(--lf-gap-x-sm, var(--lf-gap-x, 0px)));
44
+ column-gap: var(--_gap);
45
+ row-gap: var(--lf-gap-y-md, var(--lf-gap-y-sm, var(--lf-gap-y, 0px)));
46
+ }
47
+ }
48
+ @media (min-width: 1024px) {
49
+ .lf-row {
50
+ --_gap: var(--lf-gap-x-lg, var(--lf-gap-x-md, var(--lf-gap-x-sm, var(--lf-gap-x, 0px))));
51
+ column-gap: var(--_gap);
52
+ row-gap: var(--lf-gap-y-lg, var(--lf-gap-y-md, var(--lf-gap-y-sm, var(--lf-gap-y, 0px))));
53
+ }
54
+ }
55
+ @media (min-width: 1280px) {
56
+ .lf-row {
57
+ --_gap: var(
58
+ --lf-gap-x-xl,
59
+ var(--lf-gap-x-lg, var(--lf-gap-x-md, var(--lf-gap-x-sm, var(--lf-gap-x, 0px))))
60
+ );
61
+ column-gap: var(--_gap);
62
+ row-gap: var(
63
+ --lf-gap-y-xl,
64
+ var(--lf-gap-y-lg, var(--lf-gap-y-md, var(--lf-gap-y-sm, var(--lf-gap-y, 0px))))
65
+ );
66
+ }
67
+ }
68
+ @media (min-width: 1536px) {
69
+ .lf-row {
70
+ --_gap: var(
71
+ --lf-gap-x-2xl,
72
+ var(
73
+ --lf-gap-x-xl,
74
+ var(--lf-gap-x-lg, var(--lf-gap-x-md, var(--lf-gap-x-sm, var(--lf-gap-x, 0px))))
75
+ )
76
+ );
77
+ column-gap: var(--_gap);
78
+ row-gap: var(
79
+ --lf-gap-y-2xl,
80
+ var(
81
+ --lf-gap-y-xl,
82
+ var(--lf-gap-y-lg, var(--lf-gap-y-md, var(--lf-gap-y-sm, var(--lf-gap-y, 0px))))
83
+ )
84
+ );
85
+ }
86
+ }
87
+
88
+ /* =====================================================
89
+ Col (BlockLayout)
90
+
91
+ The flex-basis formula accounts for CSS gap to ensure
92
+ columns + gaps sum to exactly the container width:
93
+
94
+ flex-basis = span/24 * (100% + gap) - gap
95
+
96
+ Proof: for N columns summing to 24 spans with (N-1) gaps:
97
+ sum(span_i/24 * (W + G) - G) + (N-1)*G
98
+ = (W + G) * sum(span_i)/24 - N*G + (N-1)*G
99
+ = (W + G) * 1 - G = W ✓
100
+
101
+ The --_gap variable is inherited from the parent .lf-row.
102
+ When gap is 0, the formula simplifies to span/24 * 100%.
103
+ ===================================================== */
104
+ .lf-col {
105
+ display: var(--lf-display, block);
106
+ min-height: 1px;
107
+ flex: 0 0 calc(var(--lf-span, 24) / 24 * (100% + var(--_gap, 0px)) - var(--_gap, 0px));
108
+ max-width: calc(var(--lf-span, 24) / 24 * (100% + var(--_gap, 0px)) - var(--_gap, 0px));
109
+ margin-inline-start: calc(var(--lf-offset, 0) / 24 * (100% + var(--_gap, 0px)));
110
+ order: var(--lf-order, 0);
111
+ }
112
+
113
+ /* Push/pull: only apply positioning when class is present */
114
+ .lf-col-push {
115
+ position: relative;
116
+ inset-inline-start: calc(var(--lf-push, 0) / 24 * (100% + var(--_gap, 0px)));
117
+ }
118
+ .lf-col-pull {
119
+ position: relative;
120
+ inset-inline-end: calc(var(--lf-pull, 0) / 24 * (100% + var(--_gap, 0px)));
121
+ }
122
+
123
+ /* --- sm (≥640px) --- */
124
+ @media (min-width: 640px) {
125
+ .lf-col {
126
+ display: var(--lf-display-sm, var(--lf-display, block));
127
+ flex: 0 0
128
+ calc(
129
+ var(--lf-span-sm, var(--lf-span, 24)) / 24 * (100% + var(--_gap, 0px)) - var(--_gap, 0px)
130
+ );
131
+ max-width: calc(
132
+ var(--lf-span-sm, var(--lf-span, 24)) / 24 * (100% + var(--_gap, 0px)) - var(--_gap, 0px)
133
+ );
134
+ margin-inline-start: calc(
135
+ var(--lf-offset-sm, var(--lf-offset, 0)) / 24 * (100% + var(--_gap, 0px))
136
+ );
137
+ order: var(--lf-order-sm, var(--lf-order, 0));
138
+ }
139
+ .lf-col-push {
140
+ inset-inline-start: calc(
141
+ var(--lf-push-sm, var(--lf-push, 0)) / 24 * (100% + var(--_gap, 0px))
142
+ );
143
+ }
144
+ .lf-col-pull {
145
+ inset-inline-end: calc(var(--lf-pull-sm, var(--lf-pull, 0)) / 24 * (100% + var(--_gap, 0px)));
146
+ }
147
+ }
148
+
149
+ /* --- md (≥768px) --- */
150
+ @media (min-width: 768px) {
151
+ .lf-col {
152
+ display: var(--lf-display-md, var(--lf-display-sm, var(--lf-display, block)));
153
+ flex: 0 0
154
+ calc(
155
+ var(--lf-span-md, var(--lf-span-sm, var(--lf-span, 24))) / 24 * (100% + var(--_gap, 0px)) -
156
+ var(--_gap, 0px)
157
+ );
158
+ max-width: calc(
159
+ var(--lf-span-md, var(--lf-span-sm, var(--lf-span, 24))) / 24 * (100% + var(--_gap, 0px)) -
160
+ var(--_gap, 0px)
161
+ );
162
+ margin-inline-start: calc(
163
+ var(--lf-offset-md, var(--lf-offset-sm, var(--lf-offset, 0))) / 24 *
164
+ (100% + var(--_gap, 0px))
165
+ );
166
+ order: var(--lf-order-md, var(--lf-order-sm, var(--lf-order, 0)));
167
+ }
168
+ .lf-col-push {
169
+ inset-inline-start: calc(
170
+ var(--lf-push-md, var(--lf-push-sm, var(--lf-push, 0))) / 24 * (100% + var(--_gap, 0px))
171
+ );
172
+ }
173
+ .lf-col-pull {
174
+ inset-inline-end: calc(
175
+ var(--lf-pull-md, var(--lf-pull-sm, var(--lf-pull, 0))) / 24 * (100% + var(--_gap, 0px))
176
+ );
177
+ }
178
+ }
179
+
180
+ /* --- lg (≥1024px) --- */
181
+ @media (min-width: 1024px) {
182
+ .lf-col {
183
+ display: var(
184
+ --lf-display-lg,
185
+ var(--lf-display-md, var(--lf-display-sm, var(--lf-display, block)))
186
+ );
187
+ flex: 0 0
188
+ calc(
189
+ var(--lf-span-lg, var(--lf-span-md, var(--lf-span-sm, var(--lf-span, 24)))) / 24 *
190
+ (100% + var(--_gap, 0px)) - var(--_gap, 0px)
191
+ );
192
+ max-width: calc(
193
+ var(--lf-span-lg, var(--lf-span-md, var(--lf-span-sm, var(--lf-span, 24)))) / 24 *
194
+ (100% + var(--_gap, 0px)) - var(--_gap, 0px)
195
+ );
196
+ margin-inline-start: calc(
197
+ var(--lf-offset-lg, var(--lf-offset-md, var(--lf-offset-sm, var(--lf-offset, 0)))) / 24 *
198
+ (100% + var(--_gap, 0px))
199
+ );
200
+ order: var(--lf-order-lg, var(--lf-order-md, var(--lf-order-sm, var(--lf-order, 0))));
201
+ }
202
+ .lf-col-push {
203
+ inset-inline-start: calc(
204
+ var(--lf-push-lg, var(--lf-push-md, var(--lf-push-sm, var(--lf-push, 0)))) / 24 *
205
+ (100% + var(--_gap, 0px))
206
+ );
207
+ }
208
+ .lf-col-pull {
209
+ inset-inline-end: calc(
210
+ var(--lf-pull-lg, var(--lf-pull-md, var(--lf-pull-sm, var(--lf-pull, 0)))) / 24 *
211
+ (100% + var(--_gap, 0px))
212
+ );
213
+ }
214
+ }
215
+
216
+ /* --- xl (≥1280px) --- */
217
+ @media (min-width: 1280px) {
218
+ .lf-col {
219
+ display: var(
220
+ --lf-display-xl,
221
+ var(--lf-display-lg, var(--lf-display-md, var(--lf-display-sm, var(--lf-display, block))))
222
+ );
223
+ flex: 0 0
224
+ calc(
225
+ var(
226
+ --lf-span-xl,
227
+ var(--lf-span-lg, var(--lf-span-md, var(--lf-span-sm, var(--lf-span, 24))))
228
+ ) / 24 * (100% + var(--_gap, 0px)) - var(--_gap, 0px)
229
+ );
230
+ max-width: calc(
231
+ var(
232
+ --lf-span-xl,
233
+ var(--lf-span-lg, var(--lf-span-md, var(--lf-span-sm, var(--lf-span, 24))))
234
+ ) / 24 * (100% + var(--_gap, 0px)) - var(--_gap, 0px)
235
+ );
236
+ margin-inline-start: calc(
237
+ var(
238
+ --lf-offset-xl,
239
+ var(--lf-offset-lg, var(--lf-offset-md, var(--lf-offset-sm, var(--lf-offset, 0))))
240
+ ) / 24 * (100% + var(--_gap, 0px))
241
+ );
242
+ order: var(
243
+ --lf-order-xl,
244
+ var(--lf-order-lg, var(--lf-order-md, var(--lf-order-sm, var(--lf-order, 0))))
245
+ );
246
+ }
247
+ .lf-col-push {
248
+ inset-inline-start: calc(
249
+ var(
250
+ --lf-push-xl,
251
+ var(--lf-push-lg, var(--lf-push-md, var(--lf-push-sm, var(--lf-push, 0))))
252
+ ) / 24 * (100% + var(--_gap, 0px))
253
+ );
254
+ }
255
+ .lf-col-pull {
256
+ inset-inline-end: calc(
257
+ var(
258
+ --lf-pull-xl,
259
+ var(--lf-pull-lg, var(--lf-pull-md, var(--lf-pull-sm, var(--lf-pull, 0))))
260
+ ) / 24 * (100% + var(--_gap, 0px))
261
+ );
262
+ }
263
+ }
264
+
265
+ /* --- 2xl (≥1536px) --- */
266
+ @media (min-width: 1536px) {
267
+ .lf-col {
268
+ display: var(
269
+ --lf-display-2xl,
270
+ var(
271
+ --lf-display-xl,
272
+ var(--lf-display-lg, var(--lf-display-md, var(--lf-display-sm, var(--lf-display, block))))
273
+ )
274
+ );
275
+ flex: 0 0
276
+ calc(
277
+ var(
278
+ --lf-span-2xl,
279
+ var(
280
+ --lf-span-xl,
281
+ var(--lf-span-lg, var(--lf-span-md, var(--lf-span-sm, var(--lf-span, 24))))
282
+ )
283
+ ) / 24 * (100% + var(--_gap, 0px)) - var(--_gap, 0px)
284
+ );
285
+ max-width: calc(
286
+ var(
287
+ --lf-span-2xl,
288
+ var(
289
+ --lf-span-xl,
290
+ var(--lf-span-lg, var(--lf-span-md, var(--lf-span-sm, var(--lf-span, 24))))
291
+ )
292
+ ) / 24 * (100% + var(--_gap, 0px)) - var(--_gap, 0px)
293
+ );
294
+ margin-inline-start: calc(
295
+ var(
296
+ --lf-offset-2xl,
297
+ var(
298
+ --lf-offset-xl,
299
+ var(--lf-offset-lg, var(--lf-offset-md, var(--lf-offset-sm, var(--lf-offset, 0))))
300
+ )
301
+ ) / 24 * (100% + var(--_gap, 0px))
302
+ );
303
+ order: var(
304
+ --lf-order-2xl,
305
+ var(
306
+ --lf-order-xl,
307
+ var(--lf-order-lg, var(--lf-order-md, var(--lf-order-sm, var(--lf-order, 0))))
308
+ )
309
+ );
310
+ }
311
+ .lf-col-push {
312
+ inset-inline-start: calc(
313
+ var(
314
+ --lf-push-2xl,
315
+ var(
316
+ --lf-push-xl,
317
+ var(--lf-push-lg, var(--lf-push-md, var(--lf-push-sm, var(--lf-push, 0))))
318
+ )
319
+ ) / 24 * (100% + var(--_gap, 0px))
320
+ );
321
+ }
322
+ .lf-col-pull {
323
+ inset-inline-end: calc(
324
+ var(
325
+ --lf-pull-2xl,
326
+ var(
327
+ --lf-pull-xl,
328
+ var(--lf-pull-lg, var(--lf-pull-md, var(--lf-pull-sm, var(--lf-pull, 0))))
329
+ )
330
+ ) / 24 * (100% + var(--_gap, 0px))
331
+ );
332
+ }
333
+ }
334
+ }
@@ -13,16 +13,41 @@
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  */ import { type } from '@lowdefy/helpers';
16
- const layoutParamsToArea = ({ areaKey, area = {}, layout = {} })=>{
16
+ function resolveDeprecated(layout, newName, ...oldNames) {
17
+ if (!type.isNone(layout[newName])) {
18
+ return layout[newName];
19
+ }
20
+ for (const oldName of oldNames){
21
+ if (!type.isNone(layout[oldName])) {
22
+ console.warn(`[Lowdefy] layout.${oldName} is deprecated. Use layout.${newName} instead.`);
23
+ return layout[oldName];
24
+ }
25
+ }
26
+ return undefined;
27
+ }
28
+ function resolveLayoutAlign(layout) {
29
+ if (!type.isNone(layout.align) && type.isNone(layout.selfAlign)) {
30
+ console.warn('[Lowdefy] layout.align for self-alignment is deprecated. Use layout.selfAlign instead.');
31
+ return undefined;
32
+ }
33
+ return layout.align;
34
+ }
35
+ function layoutParamsToArea({ areaKey, area = {}, layout = {} }) {
36
+ // Normalize area.gutter → area.gap (deprecated)
37
+ if (!type.isNone(area.gutter) && type.isNone(area.gap)) {
38
+ console.warn('[Lowdefy] slots.content.gutter is deprecated. Use gap instead.');
39
+ area.gap = area.gutter;
40
+ }
17
41
  if (areaKey !== 'content') {
18
42
  return area;
19
43
  }
20
- area.align = type.isNone(area.align) ? layout.contentAlign : area.align;
21
- area.direction = type.isNone(area.direction) ? layout.contentDirection : area.direction;
22
- area.gutter = type.isNone(area.gutter) ? layout.contentGutter : area.gutter;
23
- area.justify = type.isNone(area.justify) ? layout.contentJustify : area.justify;
24
- area.overflow = type.isNone(area.overflow) ? layout.contentOverflow : area.overflow;
25
- area.wrap = type.isNone(area.wrap) ? layout.contentWrap : area.wrap;
44
+ const layoutAlign = resolveLayoutAlign(layout);
45
+ if (type.isNone(area.gap)) area.gap = resolveDeprecated(layout, 'gap', 'contentGutter', 'contentGap');
46
+ if (type.isNone(area.align)) area.align = layoutAlign;
47
+ if (type.isNone(area.justify)) area.justify = resolveDeprecated(layout, 'justify', 'contentJustify');
48
+ if (type.isNone(area.direction)) area.direction = resolveDeprecated(layout, 'direction', 'contentDirection');
49
+ if (type.isNone(area.wrap)) area.wrap = resolveDeprecated(layout, 'wrap', 'contentWrap');
50
+ if (type.isNone(area.overflow)) area.overflow = resolveDeprecated(layout, 'overflow', 'contentOverflow');
26
51
  return area;
27
- };
52
+ }
28
53
  export default layoutParamsToArea;
@@ -0,0 +1,53 @@
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
+ */ import { type } from '@lowdefy/helpers';
16
+ function resolveDeprecated(layout, newName, ...oldNames) {
17
+ if (!type.isNone(layout[newName])) {
18
+ return layout[newName];
19
+ }
20
+ for (const oldName of oldNames){
21
+ if (!type.isNone(layout[oldName])) {
22
+ console.warn(`[Lowdefy] layout.${oldName} is deprecated. Use layout.${newName} instead.`);
23
+ return layout[oldName];
24
+ }
25
+ }
26
+ return undefined;
27
+ }
28
+ function resolveLayoutAlign(layout) {
29
+ if (!type.isNone(layout.align) && type.isNone(layout.selfAlign)) {
30
+ console.warn('[Lowdefy] layout.align for self-alignment is deprecated. Use layout.selfAlign instead.');
31
+ return undefined;
32
+ }
33
+ return layout.align;
34
+ }
35
+ function layoutParamsToSlot({ slotKey, slot = {}, layout = {} }) {
36
+ // Normalize slot.gutter → slot.gap (deprecated)
37
+ if (!type.isNone(slot.gutter) && type.isNone(slot.gap)) {
38
+ console.warn('[Lowdefy] slots.content.gutter is deprecated. Use gap instead.');
39
+ slot.gap = slot.gutter;
40
+ }
41
+ if (slotKey !== 'content') {
42
+ return slot;
43
+ }
44
+ const layoutAlign = resolveLayoutAlign(layout);
45
+ if (type.isNone(slot.gap)) slot.gap = resolveDeprecated(layout, 'gap', 'contentGutter', 'contentGap');
46
+ if (type.isNone(slot.align)) slot.align = layoutAlign;
47
+ if (type.isNone(slot.justify)) slot.justify = resolveDeprecated(layout, 'justify', 'contentJustify');
48
+ if (type.isNone(slot.direction)) slot.direction = resolveDeprecated(layout, 'direction', 'contentDirection');
49
+ if (type.isNone(slot.wrap)) slot.wrap = resolveDeprecated(layout, 'wrap', 'contentWrap');
50
+ if (type.isNone(slot.overflow)) slot.overflow = resolveDeprecated(layout, 'overflow', 'contentOverflow');
51
+ return slot;
52
+ }
53
+ export default layoutParamsToSlot;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lowdefy/layout",
3
- "version": "4.7.3",
3
+ "version": "5.1.0",
4
4
  "license": "Apache-2.0",
5
5
  "description": "",
6
6
  "homepage": "https://lowdefy.com",
@@ -34,20 +34,18 @@
34
34
  "dist/*"
35
35
  ],
36
36
  "dependencies": {
37
- "@lowdefy/block-utils": "4.7.3",
38
- "@lowdefy/helpers": "4.7.3",
39
- "antd": "4.24.14",
37
+ "@lowdefy/block-utils": "5.1.0",
38
+ "@lowdefy/helpers": "5.1.0",
40
39
  "react": "18.2.0",
41
40
  "react-dom": "18.2.0"
42
41
  },
43
42
  "devDependencies": {
44
- "@emotion/jest": "11.10.5",
45
43
  "@jest/globals": "28.1.3",
46
- "@lowdefy/block-dev": "4.7.3",
47
- "@lowdefy/jest-yaml-transform": "4.7.3",
48
- "@swc/cli": "0.1.63",
49
- "@swc/core": "1.3.99",
50
- "@swc/jest": "0.2.29",
44
+ "@lowdefy/block-dev": "5.1.0",
45
+ "@lowdefy/jest-yaml-transform": "5.1.0",
46
+ "@swc/cli": "0.8.0",
47
+ "@swc/core": "1.15.18",
48
+ "@swc/jest": "0.2.39",
51
49
  "@testing-library/dom": "8.19.1",
52
50
  "@testing-library/react": "13.4.0",
53
51
  "@testing-library/user-event": "14.4.3",
@@ -60,7 +58,7 @@
60
58
  "access": "public"
61
59
  },
62
60
  "scripts": {
63
- "build": "swc src --out-dir dist --config-file ../../.swcrc --delete-dir-on-start && pnpm copyfiles",
61
+ "build": "swc src --out-dir dist --config-file ../../.swcrc --cli-config-file ../../.swc-cli.json && pnpm copyfiles",
64
62
  "clean": "rm -rf dist",
65
63
  "copyfiles": "copyfiles -u 1 \"./src/**/*\" dist -e \"./src/**/*.js\" -e \"./src/**/*.yaml\" -e \"./src/**/*.snap\"",
66
64
  "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
@@ -1,25 +0,0 @@
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
- */ import { type } from '@lowdefy/helpers';
16
- const gutterSetup = (gutter)=>{
17
- if (type.isInt(gutter) || type.isObject(gutter)) {
18
- return [
19
- gutter,
20
- gutter
21
- ];
22
- }
23
- return gutter;
24
- };
25
- export default gutterSetup;
package/dist/style.less DELETED
@@ -1,17 +0,0 @@
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
- */
16
-
17
- @import 'antd/lib/grid/style/index.less';