@lowdefy/blocks-diff 0.0.0-experimental-20260420110710

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.
@@ -0,0 +1,314 @@
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 React from 'react';
16
+ import { Collapse, Descriptions, Space, Tag, Typography } from 'antd';
17
+ import { type } from '@lowdefy/helpers';
18
+ import ChangeTypeTag from '../ChangeTypeTag.js';
19
+ import ValueCell from '../ValueCell.js';
20
+ import { breadcrumbLabel, humaniseSegment, isIndex, pathLabel, singularise } from '../pathUtils.js';
21
+ import { CHANGE_TYPES, GROUP_ROOT } from '../constants.js';
22
+ const { Text } = Typography;
23
+ function resolveGroupLabel(group, labels) {
24
+ if (!group.label) return '';
25
+ return pathLabel([
26
+ group.key
27
+ ], labels) || humaniseSegment(group.key);
28
+ }
29
+ function SummaryChips({ summary }) {
30
+ const chips = [];
31
+ if (summary.added > 0) {
32
+ chips.push(/*#__PURE__*/ React.createElement(Tag, {
33
+ key: "added",
34
+ color: "success",
35
+ style: {
36
+ marginInlineEnd: 0
37
+ }
38
+ }, `+${summary.added}`));
39
+ }
40
+ if (summary.removed > 0) {
41
+ chips.push(/*#__PURE__*/ React.createElement(Tag, {
42
+ key: "removed",
43
+ color: "error",
44
+ style: {
45
+ marginInlineEnd: 0
46
+ }
47
+ }, `−${summary.removed}`));
48
+ }
49
+ if (summary.changed > 0) {
50
+ chips.push(/*#__PURE__*/ React.createElement(Tag, {
51
+ key: "changed",
52
+ color: "warning",
53
+ style: {
54
+ marginInlineEnd: 0
55
+ }
56
+ }, `~${summary.changed}`));
57
+ }
58
+ if (summary.unchanged > 0) {
59
+ chips.push(/*#__PURE__*/ React.createElement(Tag, {
60
+ key: "unchanged",
61
+ style: {
62
+ marginInlineEnd: 0
63
+ }
64
+ }, `·${summary.unchanged}`));
65
+ }
66
+ if (chips.length === 0) return null;
67
+ return /*#__PURE__*/ React.createElement(Space, {
68
+ size: 4,
69
+ wrap: true
70
+ }, chips);
71
+ }
72
+ function ArraySummary({ summary }) {
73
+ const parts = [];
74
+ if (summary.added > 0) parts.push(`+${summary.added} added`);
75
+ if (summary.removed > 0) parts.push(`−${summary.removed} removed`);
76
+ if (summary.changed > 0) parts.push(`~${summary.changed} changed`);
77
+ if (parts.length === 0) return null;
78
+ return /*#__PURE__*/ React.createElement(Text, {
79
+ type: "secondary",
80
+ style: {
81
+ fontSize: '0.85em',
82
+ paddingInlineStart: 4
83
+ }
84
+ }, parts.join(' · '));
85
+ }
86
+ function partitionGroup(changes) {
87
+ const byItem = new Map();
88
+ const direct = [];
89
+ changes.forEach((change)=>{
90
+ if (change.path.length >= 2 && isIndex(change.path[1])) {
91
+ const key = String(change.path[1]);
92
+ if (!byItem.has(key)) byItem.set(key, []);
93
+ byItem.get(key).push(change);
94
+ return;
95
+ }
96
+ direct.push(change);
97
+ });
98
+ return {
99
+ byItem,
100
+ direct
101
+ };
102
+ }
103
+ function summariseSubset(changes) {
104
+ const summary = {
105
+ added: 0,
106
+ removed: 0,
107
+ changed: 0,
108
+ unchanged: 0,
109
+ hasArrayIndices: false
110
+ };
111
+ changes.forEach((change)=>{
112
+ if (change.type === CHANGE_TYPES.CREATE) summary.added += 1;
113
+ else if (change.type === CHANGE_TYPES.REMOVE) summary.removed += 1;
114
+ else if (change.type === CHANGE_TYPES.CHANGE) summary.changed += 1;
115
+ else if (change.type === CHANGE_TYPES.UNCHANGED) summary.unchanged += 1;
116
+ if (change.path.length > 1 && isIndex(change.path[1])) {
117
+ summary.hasArrayIndices = true;
118
+ }
119
+ });
120
+ return summary;
121
+ }
122
+ function buildDescriptionItems(changes, { classNames, changeTypeLabels, collapseNested, labels, inItemBlock = false }) {
123
+ return changes.map((change, index)=>{
124
+ let rowLabel;
125
+ if (inItemBlock && change.depth >= 4) {
126
+ rowLabel = breadcrumbLabel(change.path.slice(2), labels);
127
+ } else if (!inItemBlock && change.depth >= 3) {
128
+ rowLabel = change.breadcrumb;
129
+ } else {
130
+ rowLabel = change.label || change.displayPath;
131
+ }
132
+ return {
133
+ key: change.pathStr || `row-${index}`,
134
+ label: /*#__PURE__*/ React.createElement(Space, {
135
+ size: 8,
136
+ align: "center",
137
+ wrap: true
138
+ }, /*#__PURE__*/ React.createElement("span", {
139
+ className: classNames?.row
140
+ }, rowLabel), /*#__PURE__*/ React.createElement(ChangeTypeTag, {
141
+ type: change.type,
142
+ labels: changeTypeLabels,
143
+ className: classNames?.tag
144
+ })),
145
+ children: /*#__PURE__*/ React.createElement(ValueCell, {
146
+ change: change,
147
+ collapseNested: collapseNested
148
+ })
149
+ };
150
+ });
151
+ }
152
+ function resolveItemLabelBase(group, labels) {
153
+ if (type.isObject(labels) && type.isString(labels[group.key]) && labels[group.key].length > 0) {
154
+ return singularise(labels[group.key]);
155
+ }
156
+ return singularise(humaniseSegment(String(group.key)));
157
+ }
158
+ function ItemBlock({ itemKey, itemChanges, itemLabelBase, classNames, changeTypeLabels, collapseNested, labels }) {
159
+ const subSummary = summariseSubset(itemChanges);
160
+ const itemLabel = `${itemLabelBase} ${Number(itemKey) + 1}`;
161
+ const items = buildDescriptionItems(itemChanges, {
162
+ classNames,
163
+ changeTypeLabels,
164
+ collapseNested,
165
+ labels,
166
+ inItemBlock: true
167
+ });
168
+ return /*#__PURE__*/ React.createElement("div", {
169
+ style: {
170
+ paddingInlineStart: 12
171
+ }
172
+ }, /*#__PURE__*/ React.createElement(Space, {
173
+ size: 8,
174
+ align: "center",
175
+ style: {
176
+ marginBottom: 8
177
+ }
178
+ }, /*#__PURE__*/ React.createElement(Text, {
179
+ strong: true
180
+ }, itemLabel), /*#__PURE__*/ React.createElement(SummaryChips, {
181
+ summary: subSummary
182
+ })), /*#__PURE__*/ React.createElement(Descriptions, {
183
+ size: "small",
184
+ column: 1,
185
+ colon: false,
186
+ bordered: true,
187
+ items: items,
188
+ className: classNames?.group
189
+ }));
190
+ }
191
+ function GroupBody({ group, classNames, changeTypeLabels, collapseNested, labels }) {
192
+ const { byItem, direct } = partitionGroup(group.changes);
193
+ if (byItem.size === 0) {
194
+ const items = buildDescriptionItems(group.changes, {
195
+ classNames,
196
+ changeTypeLabels,
197
+ collapseNested,
198
+ labels
199
+ });
200
+ return /*#__PURE__*/ React.createElement(Space, {
201
+ direction: "vertical",
202
+ size: 8,
203
+ style: {
204
+ display: 'flex',
205
+ width: '100%'
206
+ }
207
+ }, group.summary.hasArrayIndices && /*#__PURE__*/ React.createElement(ArraySummary, {
208
+ summary: group.summary
209
+ }), /*#__PURE__*/ React.createElement(Descriptions, {
210
+ size: "small",
211
+ column: 1,
212
+ colon: false,
213
+ bordered: true,
214
+ items: items,
215
+ className: classNames?.group
216
+ }));
217
+ }
218
+ const sortedItems = Array.from(byItem.entries()).sort(([a], [b])=>Number(a) - Number(b));
219
+ const itemLabelBase = resolveItemLabelBase(group, labels);
220
+ const directItems = direct.length > 0 ? buildDescriptionItems(direct, {
221
+ classNames,
222
+ changeTypeLabels,
223
+ collapseNested,
224
+ labels
225
+ }) : null;
226
+ return /*#__PURE__*/ React.createElement(Space, {
227
+ direction: "vertical",
228
+ size: 8,
229
+ style: {
230
+ display: 'flex',
231
+ width: '100%'
232
+ }
233
+ }, directItems && /*#__PURE__*/ React.createElement(Descriptions, {
234
+ size: "small",
235
+ column: 1,
236
+ colon: false,
237
+ bordered: true,
238
+ items: directItems,
239
+ className: classNames?.group
240
+ }), sortedItems.map(([itemKey, itemChanges])=>/*#__PURE__*/ React.createElement(ItemBlock, {
241
+ key: itemKey,
242
+ itemKey: itemKey,
243
+ itemChanges: itemChanges,
244
+ itemLabelBase: itemLabelBase,
245
+ classNames: classNames,
246
+ changeTypeLabels: changeTypeLabels,
247
+ collapseNested: collapseNested,
248
+ labels: labels
249
+ })));
250
+ }
251
+ function ListRenderer({ model, classNames = {}, styles = {}, collapseNested = true, changeTypeLabels, labels }) {
252
+ const meaningful = model.groups.filter((group)=>group.changes.length > 0);
253
+ if (meaningful.length === 0) return null;
254
+ const rootGroup = meaningful.find((group)=>group.key === GROUP_ROOT);
255
+ const namedGroups = meaningful.filter((group)=>group.key !== GROUP_ROOT);
256
+ return /*#__PURE__*/ React.createElement(Space, {
257
+ direction: "vertical",
258
+ size: "middle",
259
+ style: {
260
+ display: 'flex',
261
+ width: '100%'
262
+ }
263
+ }, rootGroup && /*#__PURE__*/ React.createElement(GroupBody, {
264
+ group: rootGroup,
265
+ classNames: classNames,
266
+ changeTypeLabels: changeTypeLabels,
267
+ collapseNested: collapseNested,
268
+ labels: labels
269
+ }), namedGroups.length === 1 && /*#__PURE__*/ React.createElement("div", {
270
+ className: classNames?.group,
271
+ style: styles?.group
272
+ }, /*#__PURE__*/ React.createElement(Space, {
273
+ size: 8,
274
+ align: "center",
275
+ style: {
276
+ marginBottom: 8
277
+ }
278
+ }, /*#__PURE__*/ React.createElement(Text, {
279
+ strong: true
280
+ }, resolveGroupLabel(namedGroups[0], labels)), /*#__PURE__*/ React.createElement(SummaryChips, {
281
+ summary: namedGroups[0].summary
282
+ })), /*#__PURE__*/ React.createElement(GroupBody, {
283
+ group: namedGroups[0],
284
+ classNames: classNames,
285
+ changeTypeLabels: changeTypeLabels,
286
+ collapseNested: collapseNested,
287
+ labels: labels
288
+ })), namedGroups.length > 1 && /*#__PURE__*/ React.createElement(Collapse, {
289
+ size: "small",
290
+ defaultActiveKey: namedGroups.filter((group)=>group.summary.added + group.summary.removed + group.summary.changed > 0).map((group)=>group.key),
291
+ items: namedGroups.map((group)=>({
292
+ key: group.key,
293
+ label: /*#__PURE__*/ React.createElement(Space, {
294
+ size: 8,
295
+ align: "center",
296
+ wrap: true
297
+ }, /*#__PURE__*/ React.createElement(Text, {
298
+ strong: true
299
+ }, resolveGroupLabel(group, labels)), /*#__PURE__*/ React.createElement(SummaryChips, {
300
+ summary: group.summary
301
+ })),
302
+ children: /*#__PURE__*/ React.createElement(GroupBody, {
303
+ group: group,
304
+ classNames: classNames,
305
+ changeTypeLabels: changeTypeLabels,
306
+ collapseNested: collapseNested,
307
+ labels: labels
308
+ })
309
+ })),
310
+ className: classNames?.group,
311
+ style: styles?.group
312
+ }));
313
+ }
314
+ export default ListRenderer;
@@ -0,0 +1,193 @@
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 React from 'react';
16
+ import { Col, Descriptions, Row, Space, Typography } from 'antd';
17
+ import { type } from '@lowdefy/helpers';
18
+ import ValueCell from '../ValueCell.js';
19
+ import formatValue from '../formatValue.js';
20
+ import { CHANGE_TYPES } from '../constants.js';
21
+ import { humaniseSegment, isIndex, singularise } from '../pathUtils.js';
22
+ const { Text } = Typography;
23
+ const CHANGE_STRIP_STYLE = {
24
+ background: 'var(--ant-color-warning-bg, rgba(250,173,20,0.1))',
25
+ padding: '1px 6px',
26
+ borderRadius: 'var(--ant-border-radius-sm, 4px)'
27
+ };
28
+ function partitionGroup(changes) {
29
+ const byItem = new Map();
30
+ const direct = [];
31
+ changes.forEach((change)=>{
32
+ if (change.path.length >= 2 && isIndex(change.path[1])) {
33
+ const key = String(change.path[1]);
34
+ if (!byItem.has(key)) byItem.set(key, []);
35
+ byItem.get(key).push(change);
36
+ return;
37
+ }
38
+ direct.push(change);
39
+ });
40
+ return {
41
+ byItem,
42
+ direct
43
+ };
44
+ }
45
+ function resolveItemLabelBase(group, labels) {
46
+ if (type.isObject(labels) && type.isString(labels[group.key]) && labels[group.key].length > 0) {
47
+ return singularise(labels[group.key]);
48
+ }
49
+ return singularise(humaniseSegment(String(group.key)));
50
+ }
51
+ function renderLeftCell(change, collapseNested) {
52
+ if (change.type === CHANGE_TYPES.CHANGE) {
53
+ return /*#__PURE__*/ React.createElement("span", {
54
+ style: CHANGE_STRIP_STYLE
55
+ }, formatValue(change.oldValue, change.formatter));
56
+ }
57
+ if (change.type === CHANGE_TYPES.CREATE) {
58
+ return /*#__PURE__*/ React.createElement(Text, {
59
+ type: "secondary"
60
+ }, "—");
61
+ }
62
+ if (change.type === CHANGE_TYPES.REMOVE) {
63
+ return /*#__PURE__*/ React.createElement(ValueCell, {
64
+ change: change,
65
+ collapseNested: collapseNested
66
+ });
67
+ }
68
+ return /*#__PURE__*/ React.createElement(Text, {
69
+ type: "secondary"
70
+ }, formatValue(change.oldValue, change.formatter));
71
+ }
72
+ function renderRightCell(change, collapseNested) {
73
+ if (change.type === CHANGE_TYPES.CHANGE) {
74
+ return /*#__PURE__*/ React.createElement("span", {
75
+ style: CHANGE_STRIP_STYLE
76
+ }, formatValue(change.newValue, change.formatter));
77
+ }
78
+ if (change.type === CHANGE_TYPES.CREATE) {
79
+ return /*#__PURE__*/ React.createElement(ValueCell, {
80
+ change: change,
81
+ collapseNested: collapseNested
82
+ });
83
+ }
84
+ if (change.type === CHANGE_TYPES.REMOVE) {
85
+ return /*#__PURE__*/ React.createElement(Text, {
86
+ type: "secondary"
87
+ }, "—");
88
+ }
89
+ return /*#__PURE__*/ React.createElement(Text, {
90
+ type: "secondary"
91
+ }, formatValue(change.newValue, change.formatter));
92
+ }
93
+ function buildSide(changes, side, collapseNested) {
94
+ return changes.map((change, index)=>({
95
+ key: `${side}-${change.pathStr || index}`,
96
+ label: change.breadcrumb,
97
+ children: side === 'left' ? renderLeftCell(change, collapseNested) : renderRightCell(change, collapseNested)
98
+ }));
99
+ }
100
+ function PairedDescriptions({ changes, classNames, collapseNested }) {
101
+ const leftItems = buildSide(changes, 'left', collapseNested);
102
+ const rightItems = buildSide(changes, 'right', collapseNested);
103
+ return /*#__PURE__*/ React.createElement(Row, {
104
+ gutter: [
105
+ 16,
106
+ 16
107
+ ]
108
+ }, /*#__PURE__*/ React.createElement(Col, {
109
+ xs: 24,
110
+ md: 12
111
+ }, /*#__PURE__*/ React.createElement(Descriptions, {
112
+ size: "small",
113
+ column: 1,
114
+ colon: false,
115
+ bordered: true,
116
+ items: leftItems,
117
+ className: classNames?.group
118
+ })), /*#__PURE__*/ React.createElement(Col, {
119
+ xs: 24,
120
+ md: 12
121
+ }, /*#__PURE__*/ React.createElement(Descriptions, {
122
+ size: "small",
123
+ column: 1,
124
+ colon: false,
125
+ bordered: true,
126
+ items: rightItems,
127
+ className: classNames?.group
128
+ })));
129
+ }
130
+ function GroupView({ group, labels, classNames, collapseNested }) {
131
+ const { byItem, direct } = partitionGroup(group.changes);
132
+ if (byItem.size === 0) {
133
+ return /*#__PURE__*/ React.createElement(PairedDescriptions, {
134
+ changes: group.changes,
135
+ classNames: classNames,
136
+ collapseNested: collapseNested
137
+ });
138
+ }
139
+ const itemLabelBase = resolveItemLabelBase(group, labels);
140
+ const sortedItems = Array.from(byItem.entries()).sort(([a], [b])=>Number(a) - Number(b));
141
+ return /*#__PURE__*/ React.createElement(Space, {
142
+ direction: "vertical",
143
+ size: 12,
144
+ style: {
145
+ display: 'flex',
146
+ width: '100%'
147
+ }
148
+ }, direct.length > 0 && /*#__PURE__*/ React.createElement(PairedDescriptions, {
149
+ changes: direct,
150
+ classNames: classNames,
151
+ collapseNested: collapseNested
152
+ }), sortedItems.map(([itemKey, itemChanges])=>{
153
+ const itemLabel = `${itemLabelBase} ${Number(itemKey) + 1}`;
154
+ return /*#__PURE__*/ React.createElement("div", {
155
+ key: itemKey,
156
+ style: {
157
+ paddingInlineStart: 12
158
+ }
159
+ }, /*#__PURE__*/ React.createElement(Space, {
160
+ size: 8,
161
+ align: "center",
162
+ style: {
163
+ marginBottom: 8
164
+ }
165
+ }, /*#__PURE__*/ React.createElement(Text, {
166
+ strong: true
167
+ }, itemLabel)), /*#__PURE__*/ React.createElement(PairedDescriptions, {
168
+ changes: itemChanges,
169
+ classNames: classNames,
170
+ collapseNested: collapseNested
171
+ }));
172
+ }));
173
+ }
174
+ function SideBySideRenderer({ model, labels, classNames = {}, styles = {}, collapseNested = true }) {
175
+ const meaningful = model.groups.filter((group)=>group.changes.length > 0);
176
+ if (meaningful.length === 0) return null;
177
+ return /*#__PURE__*/ React.createElement(Space, {
178
+ direction: "vertical",
179
+ size: "middle",
180
+ style: {
181
+ display: 'flex',
182
+ width: '100%',
183
+ ...styles?.group
184
+ }
185
+ }, meaningful.map((group)=>/*#__PURE__*/ React.createElement(GroupView, {
186
+ key: group.key,
187
+ group: group,
188
+ labels: labels,
189
+ classNames: classNames,
190
+ collapseNested: collapseNested
191
+ })));
192
+ }
193
+ export default SideBySideRenderer;
@@ -0,0 +1,57 @@
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 React from 'react';
16
+ import { Space, Timeline, Typography } from 'antd';
17
+ import { EditOutlined, MinusCircleOutlined, PauseCircleOutlined, PlusCircleOutlined } from '@ant-design/icons';
18
+ import ValueCell from '../ValueCell.js';
19
+ import { CHANGE_TYPES } from '../constants.js';
20
+ const { Text } = Typography;
21
+ const COLOR_MAP = {
22
+ [CHANGE_TYPES.CREATE]: 'green',
23
+ [CHANGE_TYPES.REMOVE]: 'red',
24
+ [CHANGE_TYPES.CHANGE]: 'blue',
25
+ [CHANGE_TYPES.UNCHANGED]: 'gray'
26
+ };
27
+ const ICON_MAP = {
28
+ [CHANGE_TYPES.CREATE]: /*#__PURE__*/ React.createElement(PlusCircleOutlined, null),
29
+ [CHANGE_TYPES.REMOVE]: /*#__PURE__*/ React.createElement(MinusCircleOutlined, null),
30
+ [CHANGE_TYPES.CHANGE]: /*#__PURE__*/ React.createElement(EditOutlined, null),
31
+ [CHANGE_TYPES.UNCHANGED]: /*#__PURE__*/ React.createElement(PauseCircleOutlined, null)
32
+ };
33
+ function TimelineRenderer({ model, collapseNested = true, showUnchanged = false, classNames = {}, styles = {} }) {
34
+ const flattened = model.groups.flatMap((group)=>group.changes);
35
+ const filtered = flattened.filter((change)=>showUnchanged === true || change.type !== CHANGE_TYPES.UNCHANGED);
36
+ if (filtered.length === 0) return null;
37
+ const items = filtered.map((change, index)=>({
38
+ key: change.pathStr || `change-${index}`,
39
+ color: COLOR_MAP[change.type],
40
+ dot: ICON_MAP[change.type],
41
+ children: /*#__PURE__*/ React.createElement(Space, {
42
+ direction: "vertical",
43
+ size: 2
44
+ }, /*#__PURE__*/ React.createElement(Text, {
45
+ strong: true
46
+ }, change.breadcrumb), /*#__PURE__*/ React.createElement(ValueCell, {
47
+ change: change,
48
+ collapseNested: collapseNested
49
+ }))
50
+ }));
51
+ return /*#__PURE__*/ React.createElement(Timeline, {
52
+ items: items,
53
+ className: classNames?.group,
54
+ style: styles?.group
55
+ });
56
+ }
57
+ export default TimelineRenderer;
@@ -0,0 +1,74 @@
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 YAML from 'yaml';
16
+ import { type } from '@lowdefy/helpers';
17
+ import { matchesPath } from './pathUtils.js';
18
+ function joinPath(basePath, segment) {
19
+ return basePath.length === 0 ? String(segment) : `${basePath}.${segment}`;
20
+ }
21
+ export function filter(value, { hide, show } = {}, basePath = '') {
22
+ const hasHide = type.isArray(hide) && hide.length > 0;
23
+ const hasShow = type.isArray(show) && show.length > 0;
24
+ if (!hasHide && !hasShow) return value;
25
+ if (type.isArray(value)) {
26
+ const result = [];
27
+ value.forEach((item, index)=>{
28
+ const childPath = joinPath(basePath, index);
29
+ if (type.isArray(item) || type.isObject(item)) {
30
+ result.push(filter(item, {
31
+ hide,
32
+ show
33
+ }, childPath));
34
+ return;
35
+ }
36
+ if (hasHide && matchesPath(childPath, hide)) return;
37
+ if (hasShow && !matchesPath(childPath, show)) return;
38
+ result.push(item);
39
+ });
40
+ return result;
41
+ }
42
+ if (type.isObject(value)) {
43
+ const result = {};
44
+ Object.keys(value).forEach((key)=>{
45
+ const childValue = value[key];
46
+ const childPath = joinPath(basePath, key);
47
+ if (type.isArray(childValue) || type.isObject(childValue)) {
48
+ result[key] = filter(childValue, {
49
+ hide,
50
+ show
51
+ }, childPath);
52
+ return;
53
+ }
54
+ if (hasHide && matchesPath(childPath, hide)) return;
55
+ if (hasShow && !matchesPath(childPath, show)) return;
56
+ result[key] = childValue;
57
+ });
58
+ return result;
59
+ }
60
+ return value;
61
+ }
62
+ function serializeYaml(obj, { hide, show } = {}) {
63
+ if (type.isNone(obj)) return '';
64
+ if (!type.isArray(obj) && !type.isObject(obj)) return '';
65
+ const filtered = filter(obj, {
66
+ hide,
67
+ show
68
+ });
69
+ return YAML.stringify(filtered, {
70
+ sortMapEntries: true,
71
+ lineWidth: 0
72
+ });
73
+ }
74
+ export default serializeYaml;
@@ -0,0 +1,40 @@
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 React from 'react';
16
+ import { ConfigProvider } from 'antd';
17
+ import { type } from '@lowdefy/helpers';
18
+ function withTheme(antdComponentName, BlockComponent) {
19
+ const Wrapped = (props)=>{
20
+ const { theme, ...restProperties } = props.properties;
21
+ // Only intercept object themes (design tokens for ConfigProvider).
22
+ // String themes (e.g. Menu's 'dark'/'light') pass through to the component.
23
+ if (!type.isObject(theme)) {
24
+ return /*#__PURE__*/ React.createElement(BlockComponent, props);
25
+ }
26
+ return /*#__PURE__*/ React.createElement(ConfigProvider, {
27
+ theme: {
28
+ components: {
29
+ [antdComponentName]: theme
30
+ }
31
+ }
32
+ }, /*#__PURE__*/ React.createElement(BlockComponent, {
33
+ ...props,
34
+ properties: restProperties
35
+ }));
36
+ };
37
+ Wrapped.displayName = BlockComponent.displayName || BlockComponent.name;
38
+ return Wrapped;
39
+ }
40
+ export default withTheme;
package/dist/types.js ADDED
@@ -0,0 +1,17 @@
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 { extractBlockTypes } from '@lowdefy/block-utils';
16
+ import * as metas from './metas.js';
17
+ export default extractBlockTypes(metas);