@builder.io/mitosis 0.12.1 → 0.13.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.
|
@@ -565,6 +565,59 @@ const blockToBuilder = (json, options = {}, _internalOptions = {}) => {
|
|
|
565
565
|
const element = mapper(json, options);
|
|
566
566
|
return processLocalizedValues(element, json);
|
|
567
567
|
}
|
|
568
|
+
const symbolBinding = json.bindings.symbol;
|
|
569
|
+
if (symbolBinding === null || symbolBinding === void 0 ? void 0 : symbolBinding.code) {
|
|
570
|
+
const isExplicitUserSymbol = json.type === 'user-symbol';
|
|
571
|
+
let hasValidSymbolMetadata = false;
|
|
572
|
+
if (!isExplicitUserSymbol) {
|
|
573
|
+
const parsed = (0, lodash_1.attempt)(() => json5_1.default.parse(symbolBinding.code));
|
|
574
|
+
hasValidSymbolMetadata =
|
|
575
|
+
!(parsed instanceof Error) &&
|
|
576
|
+
parsed &&
|
|
577
|
+
typeof parsed === 'object' &&
|
|
578
|
+
(parsed.entry || parsed.model === 'symbol');
|
|
579
|
+
}
|
|
580
|
+
if (isExplicitUserSymbol || hasValidSymbolMetadata) {
|
|
581
|
+
const symbolOptions = (0, lodash_1.attempt)(() => json5_1.default.parse(symbolBinding.code));
|
|
582
|
+
if (!(symbolOptions instanceof Error)) {
|
|
583
|
+
if (!symbolOptions.name) {
|
|
584
|
+
const displayName = json.name
|
|
585
|
+
.replace(/^Symbol/, '')
|
|
586
|
+
.replace(/([A-Z])/g, ' $1')
|
|
587
|
+
.trim();
|
|
588
|
+
if (displayName) {
|
|
589
|
+
symbolOptions.name = displayName;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
const inputData = {};
|
|
593
|
+
for (const key of Object.keys(json.bindings)) {
|
|
594
|
+
if (key !== 'symbol' && key !== 'css' && key !== 'style') {
|
|
595
|
+
const value = (0, lodash_1.attempt)(() => json5_1.default.parse(json.bindings[key].code));
|
|
596
|
+
if (!(value instanceof Error)) {
|
|
597
|
+
inputData[key] = value;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
for (const key of Object.keys(json.properties)) {
|
|
602
|
+
if (!key.startsWith('$') && !key.startsWith('_') && !key.startsWith('data-')) {
|
|
603
|
+
inputData[key] = json.properties[key];
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
if (Object.keys(inputData).length > 0) {
|
|
607
|
+
symbolOptions.data = { ...symbolOptions.data, ...inputData };
|
|
608
|
+
}
|
|
609
|
+
const element = el({
|
|
610
|
+
component: {
|
|
611
|
+
name: 'Symbol',
|
|
612
|
+
options: {
|
|
613
|
+
symbol: symbolOptions,
|
|
614
|
+
},
|
|
615
|
+
},
|
|
616
|
+
}, options);
|
|
617
|
+
return processLocalizedValues(element, json);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
568
621
|
if (json.properties._text || ((_a = json.bindings._text) === null || _a === void 0 ? void 0 : _a.code)) {
|
|
569
622
|
const element = el({
|
|
570
623
|
tagName: 'span',
|
|
@@ -233,6 +233,32 @@ const wrapBindingIfNeeded = (value, options) => {
|
|
|
233
233
|
}
|
|
234
234
|
return value;
|
|
235
235
|
};
|
|
236
|
+
/**
|
|
237
|
+
* Sanitizes a symbol name to be a valid JSX component name.
|
|
238
|
+
* - Converts to PascalCase
|
|
239
|
+
* - Removes invalid characters
|
|
240
|
+
* - Adds "Symbol" prefix to avoid collisions
|
|
241
|
+
* - Returns "Symbol" if no valid name can be generated
|
|
242
|
+
*/
|
|
243
|
+
const sanitizeSymbolName = (name) => {
|
|
244
|
+
if (!name || typeof name !== 'string') {
|
|
245
|
+
return 'Symbol';
|
|
246
|
+
}
|
|
247
|
+
// Remove special characters and split into words
|
|
248
|
+
const words = name
|
|
249
|
+
.replace(/[^a-zA-Z0-9\s]/g, ' ')
|
|
250
|
+
.split(/\s+/)
|
|
251
|
+
.filter(Boolean);
|
|
252
|
+
if (words.length === 0) {
|
|
253
|
+
return 'Symbol';
|
|
254
|
+
}
|
|
255
|
+
// Convert to PascalCase
|
|
256
|
+
const pascalCase = words
|
|
257
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
258
|
+
.join('');
|
|
259
|
+
// Add Symbol prefix to avoid collisions with other components
|
|
260
|
+
return `Symbol${pascalCase}`;
|
|
261
|
+
};
|
|
236
262
|
const getBlockActions = (block, options) => {
|
|
237
263
|
var _a;
|
|
238
264
|
const obj = {
|
|
@@ -308,16 +334,46 @@ const getBlockBindings = (block, options) => {
|
|
|
308
334
|
exports.symbolBlocksAsChildren = false;
|
|
309
335
|
const componentMappers = {
|
|
310
336
|
Symbol(block, options) {
|
|
311
|
-
var _a;
|
|
337
|
+
var _a, _b, _c, _d, _e;
|
|
312
338
|
let css = getCssFromBlock(block);
|
|
313
339
|
const styleString = (0, exports.getStyleStringFromBlock)(block, options);
|
|
314
340
|
const actionBindings = getActionBindingsFromBlock(block, options);
|
|
341
|
+
const symbolOptions = (_b = (_a = block.component) === null || _a === void 0 ? void 0 : _a.options) === null || _b === void 0 ? void 0 : _b.symbol;
|
|
342
|
+
const symbolName = ((_c = symbolOptions === null || symbolOptions === void 0 ? void 0 : symbolOptions.content) === null || _c === void 0 ? void 0 : _c.name) || (symbolOptions === null || symbolOptions === void 0 ? void 0 : symbolOptions.name);
|
|
343
|
+
const componentName = ((_d = block.component) === null || _d === void 0 ? void 0 : _d.name) !== 'Symbol'
|
|
344
|
+
? (_e = block.component) === null || _e === void 0 ? void 0 : _e.name // Use name already set by extractSymbols
|
|
345
|
+
: sanitizeSymbolName(symbolName);
|
|
346
|
+
// Extract inputs from symbol.data to make them visible as top-level JSX props
|
|
347
|
+
//
|
|
348
|
+
// In Builder.io, Symbol components can receive inputs through symbol.options.data,
|
|
349
|
+
// which contains key-value pairs for props passed to the symbol instance.
|
|
350
|
+
//
|
|
351
|
+
// We extract these from the nested data structure and create individual bindings
|
|
352
|
+
// for each input so they become first-class props in the generated code
|
|
353
|
+
// (e.g., <MySymbol title="Hello" count={5} />) instead of being buried in metadata
|
|
354
|
+
// (e.g., <MySymbol symbol={{ data: { title: "Hello", count: 5 } }} />).
|
|
355
|
+
//
|
|
356
|
+
// This transformation enables proper prop passing and makes the component usage
|
|
357
|
+
// more idiomatic in the target framework.
|
|
358
|
+
const symbolData = (symbolOptions === null || symbolOptions === void 0 ? void 0 : symbolOptions.data) || {};
|
|
359
|
+
const inputBindings = {};
|
|
360
|
+
const hasInputs = Object.keys(symbolData).length > 0;
|
|
361
|
+
// Only extract inputs if there are any to avoid data loss
|
|
362
|
+
if (hasInputs) {
|
|
363
|
+
// Create individual bindings for each input
|
|
364
|
+
for (const key in symbolData) {
|
|
365
|
+
inputBindings[key] = (0, bindings_1.createSingleBinding)({
|
|
366
|
+
code: json5_1.default.stringify(symbolData[key]),
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
// Keep symbol metadata - only omit data if we extracted inputs
|
|
371
|
+
const symbolMetadata = hasInputs ? (0, lodash_1.omit)(symbolOptions, 'data') : symbolOptions;
|
|
315
372
|
const bindings = {
|
|
316
373
|
symbol: (0, bindings_1.createSingleBinding)({
|
|
317
|
-
code: JSON.stringify(
|
|
318
|
-
...(_a = block.component) === null || _a === void 0 ? void 0 : _a.options.symbol,
|
|
319
|
-
}),
|
|
374
|
+
code: JSON.stringify(symbolMetadata),
|
|
320
375
|
}),
|
|
376
|
+
...inputBindings,
|
|
321
377
|
...actionBindings,
|
|
322
378
|
...(styleString && {
|
|
323
379
|
style: (0, bindings_1.createSingleBinding)({ code: styleString }),
|
|
@@ -327,7 +383,8 @@ const componentMappers = {
|
|
|
327
383
|
}),
|
|
328
384
|
};
|
|
329
385
|
return (0, create_mitosis_node_1.createMitosisNode)({
|
|
330
|
-
name:
|
|
386
|
+
name: componentName,
|
|
387
|
+
type: 'user-symbol',
|
|
331
388
|
bindings: bindings,
|
|
332
389
|
meta: (0, exports.getMetaFromBlock)(block, options),
|
|
333
390
|
});
|
|
@@ -484,7 +541,7 @@ const processBoundLogic = (code) => {
|
|
|
484
541
|
return code;
|
|
485
542
|
};
|
|
486
543
|
const builderElementToMitosisNode = (block, options, _internalOptions = {}) => {
|
|
487
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
|
|
544
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
|
|
488
545
|
const { includeSpecialBindings = true } = options;
|
|
489
546
|
const localizedValues = {};
|
|
490
547
|
if (((_a = block.component) === null || _a === void 0 ? void 0 : _a.name) === 'Core:Fragment') {
|
|
@@ -568,7 +625,14 @@ const builderElementToMitosisNode = (block, options, _internalOptions = {}) => {
|
|
|
568
625
|
});
|
|
569
626
|
}
|
|
570
627
|
}
|
|
571
|
-
const mapper = !_internalOptions.skipMapper &&
|
|
628
|
+
const mapper = !_internalOptions.skipMapper &&
|
|
629
|
+
block.component &&
|
|
630
|
+
(componentMappers[block.component.name] ||
|
|
631
|
+
// Handle symbols that were renamed by extractSymbols (e.g., "SymbolButtonComponent")
|
|
632
|
+
// Check for symbol options or exact 'Symbol' name instead of name pattern
|
|
633
|
+
(((_p = (_o = block.component) === null || _o === void 0 ? void 0 : _o.options) === null || _p === void 0 ? void 0 : _p.symbol) || ((_q = block.component) === null || _q === void 0 ? void 0 : _q.name) === 'Symbol'
|
|
634
|
+
? componentMappers['Symbol']
|
|
635
|
+
: undefined));
|
|
572
636
|
if (mapper) {
|
|
573
637
|
return mapper(block, options);
|
|
574
638
|
}
|
|
@@ -641,7 +705,7 @@ const builderElementToMitosisNode = (block, options, _internalOptions = {}) => {
|
|
|
641
705
|
properties.href = linkUrl;
|
|
642
706
|
}
|
|
643
707
|
}
|
|
644
|
-
if ((
|
|
708
|
+
if ((_r = block.component) === null || _r === void 0 ? void 0 : _r.options) {
|
|
645
709
|
for (const key in block.component.options) {
|
|
646
710
|
const value = block.component.options[key];
|
|
647
711
|
const valueIsArrayOfBuilderElements = Array.isArray(value) && value.every(exports.isBuilderElement);
|
|
@@ -677,7 +741,7 @@ const builderElementToMitosisNode = (block, options, _internalOptions = {}) => {
|
|
|
677
741
|
slots[key] = childrenElements;
|
|
678
742
|
}
|
|
679
743
|
else if (options.enableBlocksSlots &&
|
|
680
|
-
!componentMappers[(
|
|
744
|
+
!componentMappers[(_s = block.component) === null || _s === void 0 ? void 0 : _s.name] &&
|
|
681
745
|
(Array.isArray(value) || (typeof value === 'object' && value !== null))) {
|
|
682
746
|
/**
|
|
683
747
|
* Builder Elements that have their own mappers should not use blocksSlots
|
|
@@ -728,13 +792,13 @@ const builderElementToMitosisNode = (block, options, _internalOptions = {}) => {
|
|
|
728
792
|
if (block.groupLocked !== undefined) {
|
|
729
793
|
dataAttributes['data-builder-groupLocked'] = String(block.groupLocked);
|
|
730
794
|
}
|
|
731
|
-
if (((
|
|
732
|
-
/:/.test((
|
|
733
|
-
!generator_1.builderBlockPrefixes.includes((
|
|
734
|
-
dataAttributes['data-builder-originalName'] = (
|
|
795
|
+
if (((_t = block.component) === null || _t === void 0 ? void 0 : _t.name) &&
|
|
796
|
+
/:/.test((_u = block.component) === null || _u === void 0 ? void 0 : _u.name) &&
|
|
797
|
+
!generator_1.builderBlockPrefixes.includes((_v = block.component) === null || _v === void 0 ? void 0 : _v.name.split(':')[0])) {
|
|
798
|
+
dataAttributes['data-builder-originalName'] = (_w = block.component) === null || _w === void 0 ? void 0 : _w.name;
|
|
735
799
|
}
|
|
736
800
|
const node = (0, create_mitosis_node_1.createMitosisNode)({
|
|
737
|
-
name: ((
|
|
801
|
+
name: ((_y = (_x = block.component) === null || _x === void 0 ? void 0 : _x.name) === null || _y === void 0 ? void 0 : _y.replace(/[^a-z0-9]/gi, '')) ||
|
|
738
802
|
block.tagName ||
|
|
739
803
|
(block.linkUrl ? 'a' : 'div'),
|
|
740
804
|
properties: {
|
|
@@ -954,7 +1018,8 @@ function extractSymbols(json) {
|
|
|
954
1018
|
}
|
|
955
1019
|
continue;
|
|
956
1020
|
}
|
|
957
|
-
const
|
|
1021
|
+
const symbolName = elContent.name || (symbolValue === null || symbolValue === void 0 ? void 0 : symbolValue.name);
|
|
1022
|
+
const componentName = sanitizeSymbolName(symbolName);
|
|
958
1023
|
el.component.name = componentName;
|
|
959
1024
|
if ((_d = el.component) === null || _d === void 0 ? void 0 : _d.options.symbol.content) {
|
|
960
1025
|
delete el.component.options.symbol.content;
|
|
@@ -7,6 +7,7 @@ export declare function parseText(node: TemplateNode): {
|
|
|
7
7
|
'@type': "@builder.io/mitosis/node";
|
|
8
8
|
meta: import("../../../types/json").JSONObject;
|
|
9
9
|
scope: {};
|
|
10
|
+
type?: "user-symbol" | undefined;
|
|
10
11
|
bindings: {
|
|
11
12
|
[key: string]: import("../../..").Binding | undefined;
|
|
12
13
|
};
|
|
@@ -30,6 +31,7 @@ export declare function parseText(node: TemplateNode): {
|
|
|
30
31
|
indexName: string | undefined;
|
|
31
32
|
collectionName: string | undefined;
|
|
32
33
|
};
|
|
34
|
+
type?: "user-symbol" | undefined;
|
|
33
35
|
bindings: {
|
|
34
36
|
[key: string]: import("../../..").Binding | undefined;
|
|
35
37
|
};
|
|
@@ -49,6 +51,7 @@ export declare function parseText(node: TemplateNode): {
|
|
|
49
51
|
'@type': "@builder.io/mitosis/node";
|
|
50
52
|
meta: import("../../../types/json").JSONObject;
|
|
51
53
|
scope: {};
|
|
54
|
+
type?: "user-symbol" | undefined;
|
|
52
55
|
bindings: {
|
|
53
56
|
[key: string]: import("../../..").Binding | undefined;
|
|
54
57
|
};
|
|
@@ -38,6 +38,11 @@ export type BaseNode = {
|
|
|
38
38
|
meta: JSONObject;
|
|
39
39
|
name: string;
|
|
40
40
|
scope: {};
|
|
41
|
+
/**
|
|
42
|
+
* Optional type identifier for special node types (e.g., 'user-symbol' for Builder.io user symbols).
|
|
43
|
+
* Used to explicitly identify node types without relying on name patterns.
|
|
44
|
+
*/
|
|
45
|
+
type?: 'user-symbol';
|
|
41
46
|
/**
|
|
42
47
|
* Key-value store of string values for DOM attributes.
|
|
43
48
|
* ```js
|