@builder.io/mitosis 0.4.2 → 0.4.4

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.
@@ -1,4 +1,28 @@
1
+ import { type MitosisComponent } from '../../types/mitosis-component';
1
2
  export declare const HELPER_FUNCTIONS: (isTs?: boolean) => {
2
3
  [key: string]: string;
3
4
  };
4
5
  export declare const getAppropriateTemplateFunctionKeys: (code: string) => string[];
6
+ /**
7
+ * Adds code to the `onUpdate` hook of a MitosisComponent.
8
+ *
9
+ * @param {MitosisComponent} root - The root MitosisComponent.
10
+ * @param {string} code - The code to be added to the `onUpdate` hook.
11
+ */
12
+ export declare const addCodeToOnUpdate: (root: MitosisComponent, code: string) => void;
13
+ /**
14
+ * Adds code to the `onInit` hook of a MitosisComponent.
15
+ *
16
+ * @param {MitosisComponent} root - The root MitosisComponent.
17
+ * @param {string} code - The code to be added to the `onInit` hook.
18
+ */
19
+ export declare const addCodeToOnInit: (root: MitosisComponent, code: string) => void;
20
+ /**
21
+ * Creates a reactive state in Angular.
22
+ * Initializes the state with `null` because we cannot access `state.` or `props.` properties before the component is initialized.
23
+ * Adds the code (init/re-init code) to the `onInit` and `onUpdate` hooks.
24
+ * @param root The root MitosisComponent.
25
+ * @param stateName The name of the reactive state.
26
+ * @param code The code to be added to the onInit and onUpdate hooks.
27
+ */
28
+ export declare const makeReactiveState: (root: MitosisComponent, stateName: string, code: string) => void;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getAppropriateTemplateFunctionKeys = exports.HELPER_FUNCTIONS = void 0;
3
+ exports.makeReactiveState = exports.addCodeToOnInit = exports.addCodeToOnUpdate = exports.getAppropriateTemplateFunctionKeys = exports.HELPER_FUNCTIONS = void 0;
4
4
  const HELPER_FUNCTIONS = (isTs) => ({
5
5
  useObjectWrapper: `useObjectWrapper(...args${isTs ? ': any[]' : ''}) {
6
6
  let obj = {}
@@ -18,7 +18,68 @@ const HELPER_FUNCTIONS = (isTs) => ({
18
18
  useJsonStringify: `useJsonStringify(...args${isTs ? ': any' : ''})${isTs ? ': string' : ''}) {
19
19
  return JSON.stringify(...args);
20
20
  }`,
21
+ setAttributes: `setAttributes(el${isTs ? ': HTMLElement' : ''}, value${isTs ? ': any' : ''}, changes${isTs ? '?: any' : ''}) {
22
+ if (!el) {
23
+ return;
24
+ }
25
+ const target = typeof changes === 'undefined' ? value : changes;
26
+ Object.keys(target).forEach((key) => {
27
+ if (key.startsWith('on')) {
28
+ if (this._listenerFns.has(key)) {
29
+ this._listenerFns.get(key)${isTs ? '!' : ''}();
30
+ }
31
+ this._listenerFns.set(key, this.renderer.listen(
32
+ el,
33
+ key.replace('on', '').toLowerCase(),
34
+ target[key]
35
+ ));
36
+ } else {
37
+ this.renderer.setAttribute(el, key.toLowerCase(), target[key] ?? '');
38
+ }
39
+ });
40
+ }`,
21
41
  });
22
42
  exports.HELPER_FUNCTIONS = HELPER_FUNCTIONS;
23
43
  const getAppropriateTemplateFunctionKeys = (code) => Object.keys((0, exports.HELPER_FUNCTIONS)()).filter((key) => code.includes(key));
24
44
  exports.getAppropriateTemplateFunctionKeys = getAppropriateTemplateFunctionKeys;
45
+ /**
46
+ * Adds code to the `onUpdate` hook of a MitosisComponent.
47
+ *
48
+ * @param {MitosisComponent} root - The root MitosisComponent.
49
+ * @param {string} code - The code to be added to the `onUpdate` hook.
50
+ */
51
+ const addCodeToOnUpdate = (root, code) => {
52
+ root.hooks.onUpdate = root.hooks.onUpdate || [];
53
+ root.hooks.onUpdate.push({
54
+ code,
55
+ });
56
+ };
57
+ exports.addCodeToOnUpdate = addCodeToOnUpdate;
58
+ /**
59
+ * Adds code to the `onInit` hook of a MitosisComponent.
60
+ *
61
+ * @param {MitosisComponent} root - The root MitosisComponent.
62
+ * @param {string} code - The code to be added to the `onInit` hook.
63
+ */
64
+ const addCodeToOnInit = (root, code) => {
65
+ var _a;
66
+ if (!((_a = root.hooks.onInit) === null || _a === void 0 ? void 0 : _a.code)) {
67
+ root.hooks.onInit = { code: '' };
68
+ }
69
+ root.hooks.onInit.code += `\n${code};`;
70
+ };
71
+ exports.addCodeToOnInit = addCodeToOnInit;
72
+ /**
73
+ * Creates a reactive state in Angular.
74
+ * Initializes the state with `null` because we cannot access `state.` or `props.` properties before the component is initialized.
75
+ * Adds the code (init/re-init code) to the `onInit` and `onUpdate` hooks.
76
+ * @param root The root MitosisComponent.
77
+ * @param stateName The name of the reactive state.
78
+ * @param code The code to be added to the onInit and onUpdate hooks.
79
+ */
80
+ const makeReactiveState = (root, stateName, code) => {
81
+ root.state[stateName] = { code: 'null', type: 'property' };
82
+ (0, exports.addCodeToOnInit)(root, code);
83
+ (0, exports.addCodeToOnUpdate)(root, code);
84
+ };
85
+ exports.makeReactiveState = makeReactiveState;
@@ -41,13 +41,16 @@ const on_mount_1 = require("../helpers/on-mount");
41
41
  const helpers_2 = require("./helpers");
42
42
  const types_1 = require("./types");
43
43
  const mappers = {
44
- Fragment: (root, json, options) => {
44
+ Fragment: (root, json, options, blockOptions) => {
45
45
  return `<ng-container>${json.children
46
- .map((item) => (0, exports.blockToAngular)({ root, json: item, options }))
46
+ .map((item) => (0, exports.blockToAngular)({ root, json: item, options, blockOptions }))
47
47
  .join('\n')}</ng-container>`;
48
48
  },
49
- Slot: (root, json, options) => {
50
- const renderChildren = () => { var _a; return (_a = json.children) === null || _a === void 0 ? void 0 : _a.map((item) => (0, exports.blockToAngular)({ root, json: item, options })).join('\n'); };
49
+ Slot: (root, json, options, blockOptions) => {
50
+ const renderChildren = () => {
51
+ var _a;
52
+ return (_a = json.children) === null || _a === void 0 ? void 0 : _a.map((item) => (0, exports.blockToAngular)({ root, json: item, options, blockOptions })).join('\n');
53
+ };
51
54
  return `<ng-content ${Object.entries({ ...json.bindings, ...json.properties })
52
55
  .map(([binding, value]) => {
53
56
  if (value && binding === 'name') {
@@ -158,10 +161,11 @@ const processEventBinding = (key, code, nodeName, customArg) => {
158
161
  };
159
162
  };
160
163
  const stringifyBinding = (node, options, blockOptions) => ([key, binding]) => {
161
- if (options.state === 'inline-with-wrappers' && (binding === null || binding === void 0 ? void 0 : binding.type) === 'spread') {
164
+ var _a;
165
+ if (key.startsWith('$') || key.startsWith('"') || key === 'key') {
162
166
  return;
163
167
  }
164
- if (key.startsWith('$') || key.startsWith('"') || key === 'key') {
168
+ if ((binding === null || binding === void 0 ? void 0 : binding.type) === 'spread') {
165
169
  return;
166
170
  }
167
171
  const keyToUse = BINDINGS_MAPPER[key] || key;
@@ -174,11 +178,11 @@ const stringifyBinding = (node, options, blockOptions) => ([key, binding]) => {
174
178
  else if (keyToUse === 'class') {
175
179
  return ` [class]="${code}" `;
176
180
  }
177
- else if (keyToUse === 'ref') {
181
+ else if (keyToUse === 'ref' || keyToUse === 'spreadRef') {
178
182
  return ` #${code} `;
179
183
  }
180
184
  else if ((html_tags_1.VALID_HTML_TAGS.includes(node.name.trim()) || keyToUse.includes('-')) &&
181
- !blockOptions.nativeAttributes.includes(keyToUse) &&
185
+ !((_a = blockOptions.nativeAttributes) === null || _a === void 0 ? void 0 : _a.includes(keyToUse)) &&
182
186
  !Object.values(BINDINGS_MAPPER).includes(keyToUse)) {
183
187
  // standard html elements need the attr to satisfy the compiler in many cases: eg: svg elements and [fill]
184
188
  return ` [attr.${keyToUse}]="${code}" `;
@@ -238,10 +242,10 @@ const handleNgOutletBindings = (node, options) => {
238
242
  const blockToAngular = ({ root, json, options = {}, blockOptions = {
239
243
  nativeAttributes: [],
240
244
  }, }) => {
241
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
245
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
242
246
  const childComponents = (blockOptions === null || blockOptions === void 0 ? void 0 : blockOptions.childComponents) || [];
243
247
  if (mappers[json.name]) {
244
- return mappers[json.name](root, json, options);
248
+ return mappers[json.name](root, json, options, blockOptions);
245
249
  }
246
250
  if ((0, is_children_1.default)({ node: json })) {
247
251
  return `<ng-content></ng-content>`;
@@ -314,18 +318,10 @@ const blockToAngular = ({ root, json, options = {}, blockOptions = {
314
318
  type: 'property',
315
319
  };
316
320
  if (!((_j = root.hooks.onInit) === null || _j === void 0 ? void 0 : _j.code.includes(inputsPropsStateName))) {
317
- if (!root.hooks.onInit) {
318
- root.hooks.onInit = { code: '' };
319
- }
320
- root.hooks.onInit.code += `\nthis.${inputsPropsStateName} = {${allProps}};\n`;
321
+ (0, helpers_2.addCodeToOnInit)(root, `this.${inputsPropsStateName} = {${allProps}};`);
321
322
  }
322
323
  if (!((_k = root.hooks.onUpdate) === null || _k === void 0 ? void 0 : _k.map((hook) => hook.code).join('').includes(inputsPropsStateName))) {
323
- if (!root.hooks.onUpdate) {
324
- root.hooks.onUpdate = [];
325
- }
326
- root.hooks.onUpdate.push({
327
- code: `this.${inputsPropsStateName} = {${allProps}}`,
328
- });
324
+ (0, helpers_2.addCodeToOnUpdate)(root, `this.${inputsPropsStateName} = {${allProps}};`);
329
325
  }
330
326
  allProps = `${inputsPropsStateName}`;
331
327
  }
@@ -344,12 +340,6 @@ const blockToAngular = ({ root, json, options = {}, blockOptions = {
344
340
  ? (0, lodash_1.kebabCase)(json.name)
345
341
  : json.name;
346
342
  str += `<${elSelector} `;
347
- // TODO: spread support for angular
348
- // if (json.bindings._spread) {
349
- // str += `v-bind="${stripStateAndPropsRefs(
350
- // json.bindings._spread as string,
351
- // )}"`;
352
- // }
353
343
  for (const key in json.properties) {
354
344
  if (key.startsWith('$')) {
355
345
  continue;
@@ -357,6 +347,61 @@ const blockToAngular = ({ root, json, options = {}, blockOptions = {
357
347
  const value = json.properties[key];
358
348
  str += ` ${key}="${value}" `;
359
349
  }
350
+ for (const key in json.bindings) {
351
+ if (((_l = json.bindings[key]) === null || _l === void 0 ? void 0 : _l.type) === 'spread' && html_tags_1.VALID_HTML_TAGS.includes(json.name.trim())) {
352
+ if (((_m = json.bindings[key]) === null || _m === void 0 ? void 0 : _m.code) === 'this') {
353
+ // if its an arbitrary { ...props } spread then we skip because Angular needs a named prop to be defined
354
+ continue;
355
+ }
356
+ let refName = '';
357
+ if ((_o = json.bindings['spreadRef']) === null || _o === void 0 ? void 0 : _o.code) {
358
+ refName = json.bindings['spreadRef'].code;
359
+ }
360
+ else {
361
+ const spreadRefIndex = root.meta._spreadRefIndex || 0;
362
+ refName = `elRef${spreadRefIndex}`;
363
+ root.meta._spreadRefIndex = spreadRefIndex + 1;
364
+ json.bindings['spreadRef'] = { code: refName, type: 'single' };
365
+ root.refs[refName] = { argument: '' };
366
+ }
367
+ json.bindings['spreadRef'] = { code: refName, type: 'single' };
368
+ root.refs[refName] = { argument: '' };
369
+ root.meta.onViewInit = (root.meta.onViewInit || { code: '' });
370
+ let spreadCode = '';
371
+ let changesCode = '';
372
+ if ((_p = json.bindings[key]) === null || _p === void 0 ? void 0 : _p.code.startsWith('{')) {
373
+ json.meta._spreadStateRef = json.meta._spreadStateRef || 0;
374
+ const name = `${refName}_state_${json.meta._spreadStateRef}`;
375
+ json.meta._spreadStateRef = json.meta._spreadStateRef + 1;
376
+ (0, helpers_2.makeReactiveState)(root, name, `this.${name} = ${(_q = json.bindings[key]) === null || _q === void 0 ? void 0 : _q.code};`);
377
+ spreadCode = `this.${name}`;
378
+ changesCode = `changes['${spreadCode.replace('this.', '')}']?.currentValue`;
379
+ }
380
+ else {
381
+ spreadCode = `${(_r = json.bindings[key]) === null || _r === void 0 ? void 0 : _r.code}`;
382
+ changesCode = `changes['${spreadCode.replace('this.', '')}']?.currentValue`;
383
+ }
384
+ if (!root.compileContext) {
385
+ root.compileContext = {
386
+ angular: {
387
+ hooks: {
388
+ ngAfterViewInit: {
389
+ code: '',
390
+ },
391
+ },
392
+ },
393
+ };
394
+ }
395
+ root.compileContext.angular.hooks.ngAfterViewInit.code += `\nthis.setAttributes(this.${refName}?.nativeElement, ${spreadCode});`;
396
+ (0, helpers_2.addCodeToOnUpdate)(root, `this.setAttributes(this.${refName}?.nativeElement, ${spreadCode}${changesCode ? `, ${changesCode}` : ''});`);
397
+ if (!root.state['setAttributes']) {
398
+ root.state['setAttributes'] = {
399
+ code: (0, helpers_2.HELPER_FUNCTIONS)(options === null || options === void 0 ? void 0 : options.typescript).setAttributes,
400
+ type: 'method',
401
+ };
402
+ }
403
+ }
404
+ }
360
405
  const stringifiedBindings = Object.entries(json.bindings)
361
406
  .map(stringifyBinding(json, options, blockOptions))
362
407
  .join('');
@@ -405,7 +450,7 @@ const isASimpleProperty = (code) => {
405
450
  };
406
451
  const generateNewBindingName = (index, name) => `node_${index}_${name.replaceAll('.', '_').replaceAll('-', '_')}`;
407
452
  const handleBindings = (json, item, index, forName, indexName) => {
408
- var _a, _b, _c, _d, _e, _f, _g, _h;
453
+ var _a, _b, _c, _d, _e, _f;
409
454
  for (const key in item.bindings) {
410
455
  if (key.startsWith('"') ||
411
456
  key.startsWith('$') ||
@@ -450,20 +495,13 @@ const handleBindings = (json, item, index, forName, indexName) => {
450
495
  else if ((_c = item.bindings[key]) === null || _c === void 0 ? void 0 : _c.code) {
451
496
  if (((_d = item.bindings[key]) === null || _d === void 0 ? void 0 : _d.type) !== 'spread' && !key.startsWith('on')) {
452
497
  json.state[newBindingName] = { code: 'null', type: 'property' };
453
- if (!((_e = json.hooks['onInit']) === null || _e === void 0 ? void 0 : _e.code)) {
454
- json.hooks['onInit'] = { code: '' };
455
- }
456
- json.hooks['onInit'].code += `\nstate.${newBindingName} = ${item.bindings[key].code};\n`;
457
- json.hooks['onUpdate'] = json.hooks['onUpdate'] || [];
458
- json.hooks['onUpdate'].push({
459
- code: `state.${newBindingName} = ${item.bindings[key].code}`,
460
- });
498
+ (0, helpers_2.makeReactiveState)(json, newBindingName, `this.${newBindingName} = ${item.bindings[key].code}`);
461
499
  item.bindings[key].code = `state.${newBindingName}`;
462
500
  }
463
501
  else if (key.startsWith('on')) {
464
502
  const { arguments: cusArgs = ['event'] } = item.bindings[key];
465
- if (((_f = item.bindings[key]) === null || _f === void 0 ? void 0 : _f.code.trim().startsWith('{')) &&
466
- ((_g = item.bindings[key]) === null || _g === void 0 ? void 0 : _g.code.trim().endsWith('}'))) {
503
+ if (((_e = item.bindings[key]) === null || _e === void 0 ? void 0 : _e.code.trim().startsWith('{')) &&
504
+ ((_f = item.bindings[key]) === null || _f === void 0 ? void 0 : _f.code.trim().endsWith('}'))) {
467
505
  json.state[newBindingName] = {
468
506
  code: `(${cusArgs.join(', ')}) => ${item.bindings[key].code}`,
469
507
  type: 'function',
@@ -472,15 +510,7 @@ const handleBindings = (json, item, index, forName, indexName) => {
472
510
  }
473
511
  }
474
512
  else {
475
- json.state[newBindingName] = { code: `null`, type: 'property' };
476
- if (!((_h = json.hooks['onInit']) === null || _h === void 0 ? void 0 : _h.code)) {
477
- json.hooks['onInit'] = { code: '' };
478
- }
479
- json.hooks['onInit'].code += `\nstate.${newBindingName} = {...(${item.bindings[key].code})};\n`;
480
- json.hooks['onUpdate'] = json.hooks['onUpdate'] || [];
481
- json.hooks['onUpdate'].push({
482
- code: `state.${newBindingName} = {...(${item.bindings[key].code})}`,
483
- });
513
+ (0, helpers_2.makeReactiveState)(json, newBindingName, `state.${newBindingName} = {...(${item.bindings[key].code})}`);
484
514
  item.bindings[newBindingName] = item.bindings[key];
485
515
  item.bindings[key].code = `state.${newBindingName}`;
486
516
  delete item.bindings[key];
@@ -558,7 +588,7 @@ const transformState = (json) => {
558
588
  });
559
589
  };
560
590
  const componentToAngular = (userOptions = {}) => ({ component: _component }) => {
561
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
591
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
562
592
  // Make a copy we can safely mutate, similar to babel's toolchain
563
593
  let json = (0, fast_clone_1.fastClone)(_component);
564
594
  const useMetadata = (_a = json.meta) === null || _a === void 0 ? void 0 : _a.useMetadata;
@@ -575,7 +605,7 @@ const componentToAngular = (userOptions = {}) => ({ component: _component }) =>
575
605
  });
576
606
  options.plugins = [
577
607
  ...(options.plugins || []),
578
- (0, process_code_1.CODE_PROCESSOR_PLUGIN)((codeType) => {
608
+ (0, process_code_1.CODE_PROCESSOR_PLUGIN)((codeType, _, node) => {
579
609
  switch (codeType) {
580
610
  case 'hooks':
581
611
  return (0, function_1.flow)(processAngularCode({
@@ -595,11 +625,17 @@ const componentToAngular = (userOptions = {}) => ({ component: _component }) =>
595
625
  });
596
626
  });
597
627
  case 'bindings':
598
- return (code) => {
628
+ return (code, key) => {
629
+ var _a;
630
+ // we create a separate state property for spread binding and use ref to attach the attributes
631
+ // so we need to use `this.` inside the class to access state and props
632
+ const isSpreadAttributeBinding = ((_a = node === null || node === void 0 ? void 0 : node.bindings[key]) === null || _a === void 0 ? void 0 : _a.type) === 'spread' &&
633
+ html_tags_1.VALID_HTML_TAGS.includes(node.name.trim());
599
634
  const newLocal = processAngularCode({
600
635
  contextVars: [],
601
636
  outputVars,
602
637
  domRefs: [], // the template doesn't need the this keyword.
638
+ replaceWith: isSpreadAttributeBinding ? 'this' : undefined,
603
639
  })(code);
604
640
  return newLocal.replace(/"/g, '&quot;');
605
641
  };
@@ -620,7 +656,7 @@ const componentToAngular = (userOptions = {}) => ({ component: _component }) =>
620
656
  json = (0, plugins_1.runPreJsonPlugins)({ json, plugins: options.plugins });
621
657
  }
622
658
  const [forwardProp, hasPropRef] = (0, get_props_ref_1.getPropsRef)(json, true);
623
- const childComponents = [];
659
+ const childComponents = [json.name]; // a component can be recursively used in itself
624
660
  const propsTypeRef = json.propsTypeRef !== 'any' ? json.propsTypeRef : undefined;
625
661
  json.imports.forEach(({ imports }) => {
626
662
  Object.keys(imports).forEach((key) => {
@@ -645,7 +681,6 @@ const componentToAngular = (userOptions = {}) => ({ component: _component }) =>
645
681
  }
646
682
  return `public ${variableName} : ${variableType}`;
647
683
  });
648
- const hasConstructor = Boolean(injectables.length);
649
684
  const props = (0, get_props_1.getProps)(json);
650
685
  // prevent jsx props from showing up as @Input
651
686
  if (hasPropRef) {
@@ -718,15 +753,18 @@ const componentToAngular = (userOptions = {}) => ({ component: _component }) =>
718
753
  stateVars,
719
754
  }),
720
755
  });
756
+ const refsForObjSpread = (0, get_refs_1.getRefs)(json, 'spreadRef');
721
757
  const hostDisplayCss = options.visuallyIgnoreHostElement ? ':host { display: contents; }' : '';
722
758
  const styles = css.length ? [hostDisplayCss, css].join('\n') : hostDisplayCss;
723
759
  // Preparing built in component metadata parameters
724
760
  const componentMetadata = {
725
- selector: `'${(0, lodash_1.kebabCase)(json.name || 'my-component')}, ${json.name}'`,
761
+ selector: ((_e = useMetadata === null || useMetadata === void 0 ? void 0 : useMetadata.angular) === null || _e === void 0 ? void 0 : _e.selector)
762
+ ? `'${(_f = useMetadata === null || useMetadata === void 0 ? void 0 : useMetadata.angular) === null || _f === void 0 ? void 0 : _f.selector}'`
763
+ : `'${(0, lodash_1.kebabCase)(json.name || 'my-component')}'`,
726
764
  template: `\`
727
- ${(0, indent_1.indent)(dynamicTemplate, 8).replace(/`/g, '\\`').replace(/\$\{/g, '\\${')}
728
- ${(0, indent_1.indent)(template, 8).replace(/`/g, '\\`').replace(/\$\{/g, '\\${')}
729
- \``,
765
+ ${(0, indent_1.indent)(dynamicTemplate, 8).replace(/`/g, '\\`').replace(/\$\{/g, '\\${')}
766
+ ${(0, indent_1.indent)(template, 8).replace(/`/g, '\\`').replace(/\$\{/g, '\\${')}
767
+ \``,
730
768
  ...(styles
731
769
  ? {
732
770
  styles: `[\`${(0, indent_1.indent)(styles, 8)}\`]`,
@@ -758,14 +796,18 @@ const componentToAngular = (userOptions = {}) => ({ component: _component }) =>
758
796
  .join(',');
759
797
  return `const defaultProps = {${defalutPropsString}};\n`;
760
798
  };
799
+ const hasConstructor = Boolean(injectables.length) || dynamicComponents.size || refsForObjSpread.size;
761
800
  const angularCoreImports = [
762
801
  ...(outputs.length ? ['Output', 'EventEmitter'] : []),
763
- ...(((_e = options === null || options === void 0 ? void 0 : options.experimental) === null || _e === void 0 ? void 0 : _e.inject) ? ['Inject', 'forwardRef'] : []),
802
+ ...(((_g = options === null || options === void 0 ? void 0 : options.experimental) === null || _g === void 0 ? void 0 : _g.inject) ? ['Inject', 'forwardRef'] : []),
764
803
  'Component',
765
- ...(domRefs.size || dynamicComponents.size ? ['ViewChild', 'ElementRef'] : []),
804
+ ...(domRefs.size || dynamicComponents.size || refsForObjSpread.size
805
+ ? ['ViewChild', 'ElementRef']
806
+ : []),
807
+ ...(refsForObjSpread.size ? ['Renderer2'] : []),
766
808
  ...(props.size ? ['Input'] : []),
767
809
  ...(dynamicComponents.size ? ['ViewContainerRef', 'TemplateRef'] : []),
768
- ...(((_f = json.hooks.onUpdate) === null || _f === void 0 ? void 0 : _f.length) && options.typescript ? ['SimpleChanges'] : []),
810
+ ...(((_h = json.hooks.onUpdate) === null || _h === void 0 ? void 0 : _h.length) && options.typescript ? ['SimpleChanges'] : []),
769
811
  ].join(', ');
770
812
  let str = (0, dedent_1.dedent) `
771
813
  import { ${angularCoreImports} } from '@angular/core';
@@ -809,6 +851,10 @@ const componentToAngular = (userOptions = {}) => ({ component: _component }) =>
809
851
  ${Array.from(domRefs)
810
852
  .map((refName) => `@ViewChild('${refName}') ${refName}${options.typescript ? '!: ElementRef' : ''}`)
811
853
  .join('\n')}
854
+
855
+ ${Array.from(refsForObjSpread)
856
+ .map((refName) => `@ViewChild('${refName}') ${refName}${options.typescript ? '!: ElementRef' : ''}`)
857
+ .join('\n')}
812
858
 
813
859
  ${Array.from(dynamicComponents)
814
860
  .map((component) => `@ViewChild('${component
@@ -819,6 +865,9 @@ const componentToAngular = (userOptions = {}) => ({ component: _component }) =>
819
865
  .join('\n')}
820
866
 
821
867
  ${dynamicComponents.size ? `myContent${options.typescript ? '?: any[][];' : ''}` : ''}
868
+ ${refsForObjSpread.size
869
+ ? `_listenerFns = new Map${options.typescript ? '<string, () => void>' : ''}()`
870
+ : ''}
822
871
 
823
872
  ${dataString}
824
873
 
@@ -840,19 +889,21 @@ const componentToAngular = (userOptions = {}) => ({ component: _component }) =>
840
889
  })
841
890
  .join('\n')}
842
891
 
843
- ${!hasConstructor && !dynamicComponents.size
892
+ ${!hasConstructor
844
893
  ? ''
845
894
  : `constructor(\n${injectables.join(',\n')}${dynamicComponents.size
846
895
  ? `\nprivate vcRef${options.typescript ? ': ViewContainerRef' : ''},\n`
896
+ : ''}${refsForObjSpread.size
897
+ ? `\nprivate renderer${options.typescript ? ': Renderer2' : ''},\n`
847
898
  : ''}) {}
848
899
  `}
849
- ${!json.hooks.onMount.length && !dynamicComponents.size && !((_g = json.hooks.onInit) === null || _g === void 0 ? void 0 : _g.code)
900
+ ${!json.hooks.onMount.length && !dynamicComponents.size && !((_j = json.hooks.onInit) === null || _j === void 0 ? void 0 : _j.code)
850
901
  ? ''
851
902
  : `ngOnInit() {
852
- ${!((_h = json.hooks) === null || _h === void 0 ? void 0 : _h.onInit)
903
+ ${!((_k = json.hooks) === null || _k === void 0 ? void 0 : _k.onInit)
853
904
  ? ''
854
905
  : `
855
- ${(_j = json.hooks.onInit) === null || _j === void 0 ? void 0 : _j.code}
906
+ ${(_l = json.hooks.onInit) === null || _l === void 0 ? void 0 : _l.code}
856
907
  `}
857
908
  ${json.hooks.onMount.length > 0
858
909
  ? `
@@ -872,11 +923,21 @@ const componentToAngular = (userOptions = {}) => ({ component: _component }) =>
872
923
  : ''}
873
924
  }`}
874
925
 
875
- ${!((_k = json.hooks.onUpdate) === null || _k === void 0 ? void 0 : _k.length)
926
+ ${
927
+ // hooks specific to Angular
928
+ ((_o = (_m = json.compileContext) === null || _m === void 0 ? void 0 : _m.angular) === null || _o === void 0 ? void 0 : _o.hooks)
929
+ ? Object.entries((_q = (_p = json.compileContext) === null || _p === void 0 ? void 0 : _p.angular) === null || _q === void 0 ? void 0 : _q.hooks).map(([key, value]) => {
930
+ return `${key}() {
931
+ ${value.code}
932
+ }`;
933
+ })
934
+ : ''}
935
+
936
+ ${!((_r = json.hooks.onUpdate) === null || _r === void 0 ? void 0 : _r.length)
876
937
  ? ''
877
938
  : `ngOnChanges(changes${options.typescript ? ': SimpleChanges' : ''}) {
878
939
  if (typeof window !== 'undefined') {
879
- ${(_l = json.hooks.onUpdate) === null || _l === void 0 ? void 0 : _l.reduce((code, hook) => {
940
+ ${(_s = json.hooks.onUpdate) === null || _s === void 0 ? void 0 : _s.reduce((code, hook) => {
880
941
  code += hook.code;
881
942
  return code + '\n';
882
943
  }, '')}
@@ -884,10 +945,13 @@ const componentToAngular = (userOptions = {}) => ({ component: _component }) =>
884
945
  }
885
946
  `}
886
947
 
887
- ${!json.hooks.onUnMount
948
+ ${!json.hooks.onUnMount && !refsForObjSpread.size
888
949
  ? ''
889
950
  : `ngOnDestroy() {
890
- ${json.hooks.onUnMount.code}
951
+ ${((_t = json.hooks.onUnMount) === null || _t === void 0 ? void 0 : _t.code) || ''}
952
+ ${refsForObjSpread.size
953
+ ? `for (const fn of this._listenerFns.values()) { fn(); }`
954
+ : ''}
891
955
  }`}
892
956
 
893
957
  }
@@ -12,5 +12,6 @@ export interface ToAngularOptions extends BaseTranspilerOptions {
12
12
  export declare const DEFAULT_ANGULAR_OPTIONS: ToAngularOptions;
13
13
  export interface AngularBlockOptions {
14
14
  childComponents?: string[];
15
- nativeAttributes: string[];
15
+ nativeAttributes?: string[];
16
+ selector?: string;
16
17
  }
@@ -33,7 +33,8 @@ const mapComponentName = (name) => {
33
33
  for (const prefix of builderBlockPrefixes) {
34
34
  if (name.startsWith(prefix)) {
35
35
  const suffix = name.replace(prefix, '');
36
- if ((0, is_upper_case_1.isUpperCase)(suffix[0])) {
36
+ const restOfName = suffix[0];
37
+ if (restOfName && (0, is_upper_case_1.isUpperCase)(restOfName)) {
37
38
  return `${prefix}:${name.replace(prefix, '')}`;
38
39
  }
39
40
  }
@@ -148,7 +149,7 @@ function tryFormat(code) {
148
149
  return str;
149
150
  }
150
151
  const blockToBuilder = (json, options = {}, _internalOptions = {}) => {
151
- var _a, _b, _c, _d, _e, _f;
152
+ var _a, _b, _c, _d, _e, _f, _g;
152
153
  const mapper = !_internalOptions.skipMapper && componentMappers[json.name];
153
154
  if (mapper) {
154
155
  return mapper(json, options);
@@ -167,7 +168,8 @@ const blockToBuilder = (json, options = {}, _internalOptions = {}) => {
167
168
  component: {
168
169
  name: 'Text',
169
170
  options: {
170
- text: json.properties._text,
171
+ // Mitosis uses {} for bindings, but Builder expects {{}} so we need to convert
172
+ text: (_c = json.properties._text) === null || _c === void 0 ? void 0 : _c.replace(/\{(.*?)\}/g, '{{$1}}'),
171
173
  },
172
174
  },
173
175
  }, options);
@@ -177,10 +179,10 @@ const blockToBuilder = (json, options = {}, _internalOptions = {}) => {
177
179
  const actions = {};
178
180
  for (const key in bindings) {
179
181
  const eventBindingKeyRegex = /^on([A-Z])/;
180
- const firstCharMatchForEventBindingKey = (_c = key.match(eventBindingKeyRegex)) === null || _c === void 0 ? void 0 : _c[1];
182
+ const firstCharMatchForEventBindingKey = (_d = key.match(eventBindingKeyRegex)) === null || _d === void 0 ? void 0 : _d[1];
181
183
  if (firstCharMatchForEventBindingKey) {
182
184
  actions[key.replace(eventBindingKeyRegex, firstCharMatchForEventBindingKey.toLowerCase())] =
183
- (0, remove_surrounding_block_1.removeSurroundingBlock)((_d = bindings[key]) === null || _d === void 0 ? void 0 : _d.code);
185
+ (0, remove_surrounding_block_1.removeSurroundingBlock)((_e = bindings[key]) === null || _e === void 0 ? void 0 : _e.code);
184
186
  delete bindings[key];
185
187
  }
186
188
  }
@@ -201,12 +203,12 @@ const blockToBuilder = (json, options = {}, _internalOptions = {}) => {
201
203
  }
202
204
  }
203
205
  }
204
- const hasCss = !!((_e = bindings.css) === null || _e === void 0 ? void 0 : _e.code);
206
+ const hasCss = !!((_f = bindings.css) === null || _f === void 0 ? void 0 : _f.code);
205
207
  let responsiveStyles = {
206
208
  large: {},
207
209
  };
208
210
  if (hasCss) {
209
- const cssRules = json5_1.default.parse((_f = bindings.css) === null || _f === void 0 ? void 0 : _f.code);
211
+ const cssRules = json5_1.default.parse((_g = bindings.css) === null || _g === void 0 ? void 0 : _g.code);
210
212
  const cssRuleKeys = Object.keys(cssRules);
211
213
  for (const ruleKey of cssRuleKeys) {
212
214
  const mediaQueryMatch = ruleKey.match(media_sizes_1.mediaQueryRegex);
@@ -284,6 +286,7 @@ const componentToBuilder = (options = {}) => ({ component }) => {
284
286
  ${(0, on_mount_1.stringifySingleScopeOnMount)(component)}
285
287
  })`}
286
288
  `),
289
+ cssCode: component === null || component === void 0 ? void 0 : component.style,
287
290
  blocks: component.children
288
291
  .filter(filter_empty_text_nodes_1.filterEmptyTextNodes)
289
292
  .map((child) => (0, exports.blockToBuilder)(child, options)),
@@ -171,6 +171,8 @@ const componentToMitosis = (toMitosisOptions = {}) => ({ component }) => {
171
171
 
172
172
  ${!((_a = json.hooks.onUnMount) === null || _a === void 0 ? void 0 : _a.code) ? '' : `onUnMount(() => { ${json.hooks.onUnMount.code} })`}
173
173
 
174
+ ${json.style ? `useStyle(\`${json.style}\`)` : ''}
175
+
174
176
  return (${addWrapper ? '<>' : ''}
175
177
  ${json.children.map((item) => (0, exports.blockToMitosis)(item, options, component)).join('\n')}
176
178
  ${addWrapper ? '</>' : ''})
@@ -1,2 +1,2 @@
1
1
  import { MitosisComponent } from '../types/mitosis-component';
2
- export declare const getRefs: (json: MitosisComponent) => Set<string>;
2
+ export declare const getRefs: (json: MitosisComponent, refKey?: string) => Set<string>;
@@ -6,13 +6,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.getRefs = void 0;
7
7
  const legacy_1 = __importDefault(require("neotraverse/legacy"));
8
8
  const is_mitosis_node_1 = require("./is-mitosis-node");
9
- const getRefs = (json) => {
9
+ const getRefs = (json, refKey = 'ref') => {
10
10
  const refs = new Set();
11
11
  (0, legacy_1.default)(json).forEach(function (item) {
12
- var _a;
13
12
  if ((0, is_mitosis_node_1.isMitosisNode)(item)) {
14
- if (typeof ((_a = item.bindings.ref) === null || _a === void 0 ? void 0 : _a.code) === 'string') {
15
- refs.add(item.bindings.ref.code);
13
+ const binding = item.bindings[refKey];
14
+ if (binding && typeof binding.code === 'string') {
15
+ refs.add(binding.code);
16
16
  }
17
17
  }
18
18
  });
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isUpperCase = void 0;
4
- const isUpperCase = (str) => str.toUpperCase() === str;
4
+ const isUpperCase = (str) => typeof str === 'string' && str.toUpperCase() === str;
5
5
  exports.isUpperCase = isUpperCase;
@@ -393,10 +393,11 @@ const componentMappers = {
393
393
  });
394
394
  }
395
395
  const text = block.component.options.text;
396
+ // Builder uses {{}} for bindings, but Mitosis expects {} so we need to convert
396
397
  const innerProperties = innerBindings._text
397
398
  ? {}
398
399
  : {
399
- [options.preserveTextBlocks ? 'innerHTML' : '_text']: text,
400
+ [options.preserveTextBlocks ? 'innerHTML' : '_text']: text.replace(/\{\{(.*?)\}\}/g, '{$1}'),
400
401
  };
401
402
  if (options.preserveTextBlocks) {
402
403
  return (0, create_mitosis_node_1.createMitosisNode)({
@@ -867,7 +868,7 @@ exports.createBuilderElement = createBuilderElement;
867
868
  const isBuilderElement = (el) => (el === null || el === void 0 ? void 0 : el['@type']) === '@builder.io/sdk:Element';
868
869
  exports.isBuilderElement = isBuilderElement;
869
870
  const builderContentPartToMitosisComponent = (builderContent, options = {}) => {
870
- var _a, _b, _c, _d, _e, _f, _g, _h;
871
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
871
872
  builderContent = (0, fast_clone_1.fastClone)(builderContent);
872
873
  (0, legacy_1.default)(builderContent).forEach(function (elem) {
873
874
  var _a, _b;
@@ -910,9 +911,11 @@ const builderContentPartToMitosisComponent = (builderContent, options = {}) => {
910
911
  useMetadata: {
911
912
  httpRequests: (_d = builderContent.data) === null || _d === void 0 ? void 0 : _d.httpRequests,
912
913
  },
914
+ // cmp.meta.cssCode exists for backwards compatibility, prefer cmp.style
913
915
  ...(((_e = builderContent.data) === null || _e === void 0 ? void 0 : _e.cssCode) && { cssCode: builderContent.data.cssCode }),
914
916
  },
915
- inputs: (_g = (_f = builderContent.data) === null || _f === void 0 ? void 0 : _f.inputs) === null || _g === void 0 ? void 0 : _g.map((input) => ({
917
+ ...(((_f = builderContent.data) === null || _f === void 0 ? void 0 : _f.cssCode) && { style: (_g = builderContent.data) === null || _g === void 0 ? void 0 : _g.cssCode }),
918
+ inputs: (_j = (_h = builderContent.data) === null || _h === void 0 ? void 0 : _h.inputs) === null || _j === void 0 ? void 0 : _j.map((input) => ({
916
919
  name: input.name,
917
920
  defaultValue: input.defaultValue,
918
921
  })),
@@ -926,7 +929,7 @@ const builderContentPartToMitosisComponent = (builderContent, options = {}) => {
926
929
  : []),
927
930
  ],
928
931
  },
929
- children: (((_h = builderContent.data) === null || _h === void 0 ? void 0 : _h.blocks) || [])
932
+ children: (((_k = builderContent.data) === null || _k === void 0 ? void 0 : _k.blocks) || [])
930
933
  .filter((item) => {
931
934
  var _a, _b;
932
935
  if ((_b = (_a = item.properties) === null || _a === void 0 ? void 0 : _a.src) === null || _b === void 0 ? void 0 : _b.includes('/api/v1/pixel')) {
@@ -10,7 +10,8 @@ export type ComponentMetadata = {
10
10
  httpRequests?: Record<string, string>;
11
11
  options?: TargetOptions;
12
12
  angular?: {
13
- nativeAttributes: string[];
13
+ nativeAttributes?: string[];
14
+ selector?: string;
14
15
  };
15
16
  qwik?: {
16
17
  component?: {
@@ -136,4 +136,16 @@ export type MitosisComponent = {
136
136
  propsTypeRef?: string;
137
137
  defaultProps?: MitosisState;
138
138
  style?: string;
139
+ /**
140
+ * Used to store context of a component for a specific framework
141
+ * that we need access only during compilation (for internal use only) and gets removed after compilation.
142
+ */
143
+ compileContext?: {
144
+ [K in Target]?: {
145
+ state?: MitosisState;
146
+ hooks?: {
147
+ [hookName: string]: BaseHook;
148
+ };
149
+ };
150
+ };
139
151
  };
package/package.json CHANGED
@@ -22,7 +22,7 @@
22
22
  "name": "Builder.io",
23
23
  "url": "https://www.builder.io"
24
24
  },
25
- "version": "0.4.2",
25
+ "version": "0.4.4",
26
26
  "homepage": "https://github.com/BuilderIO/mitosis",
27
27
  "main": "./dist/src/index.js",
28
28
  "exports": {