@stencil/vue-output-target
Advanced tools
Comparing version 0.4.3 to 0.5.0-0
import { ComponentCompilerMeta } from '@stencil/core/internal'; | ||
import { ComponentModelConfig } from './types'; | ||
export declare const createComponentDefinition: (importTypes: string, componentModelConfig: ComponentModelConfig[] | undefined) => (cmpMeta: Pick<ComponentCompilerMeta, 'properties' | 'tagName' | 'methods' | 'events'>) => string; | ||
export declare const createComponentDefinition: (importTypes: string, componentModelConfig: ComponentModelConfig[] | undefined, includeCustomElement?: boolean) => (cmpMeta: Pick<ComponentCompilerMeta, 'properties' | 'tagName' | 'methods' | 'events'>) => string; |
import { dashToPascalCase } from './utils'; | ||
export const createComponentDefinition = (importTypes, componentModelConfig) => (cmpMeta) => { | ||
export const createComponentDefinition = (importTypes, componentModelConfig, includeCustomElement = false) => (cmpMeta) => { | ||
const tagNameAsPascal = dashToPascalCase(cmpMeta.tagName); | ||
const importAs = (includeCustomElement) ? tagNameAsPascal + 'Cmp' : 'undefined'; | ||
let props = []; | ||
@@ -15,3 +16,4 @@ if (Array.isArray(cmpMeta.properties) && cmpMeta.properties.length > 0) { | ||
let templateString = ` | ||
export const ${tagNameAsPascal} = /*@__PURE__*/ defineContainer<${importTypes}.${tagNameAsPascal}>('${cmpMeta.tagName}'`; | ||
export const ${tagNameAsPascal} = /*@__PURE__*/ defineContainer<${importTypes}.${tagNameAsPascal}>('${cmpMeta.tagName}', ${importAs}`; | ||
const findModel = componentModelConfig && componentModelConfig.find(config => config.elements.includes(cmpMeta.tagName)); | ||
if (props.length > 0) { | ||
@@ -21,13 +23,29 @@ templateString += `, [ | ||
]`; | ||
/** | ||
* If there are no props, | ||
* but but v-model is stil used, | ||
* make sure we pass in an empty array | ||
* otherwise all of the defineContainer properties | ||
* will be off by one space. | ||
* Note: If you are using v-model then | ||
* the props array should never be empty | ||
* as there must be a prop for v-model to update, | ||
* but this check is there so builds do not crash. | ||
*/ | ||
} | ||
let options = {}; | ||
const findModel = componentModelConfig && componentModelConfig.find(config => config.elements.includes(cmpMeta.tagName)); | ||
else if (findModel) { | ||
templateString += `, []`; | ||
} | ||
if (findModel) { | ||
options.modelProp = findModel.targetAttr; | ||
options.modelUpdateEvent = findModel.event; | ||
options.externalModelUpdateEvent = findModel.externalEvent; | ||
} | ||
if (Object.keys(options).length > 0) { | ||
const targetProp = findModel.targetAttr; | ||
/** | ||
* If developer is trying to bind v-model support to a component's | ||
* prop, but that prop was not defined, warn them of this otherwise | ||
* v-model will not work as expected. | ||
*/ | ||
if (!props.includes(`'${targetProp}'`)) { | ||
console.warn(`Your '${cmpMeta.tagName}' component is configured to have v-model support bound to '${targetProp}', but '${targetProp}' is not defined as a property on the component. v-model integration may not work as expected.`); | ||
} | ||
templateString += `,\n`; | ||
templateString += JSON.stringify(options, null, 2); | ||
templateString += `'${targetProp}', '${findModel.event}', '${findModel.externalEvent}'`; | ||
} | ||
@@ -34,0 +52,0 @@ templateString += `);\n`; |
@@ -90,4 +90,5 @@ 'use strict'; | ||
const createComponentDefinition = (importTypes, componentModelConfig) => (cmpMeta) => { | ||
const createComponentDefinition = (importTypes, componentModelConfig, includeCustomElement = false) => (cmpMeta) => { | ||
const tagNameAsPascal = dashToPascalCase(cmpMeta.tagName); | ||
const importAs = (includeCustomElement) ? tagNameAsPascal + 'Cmp' : 'undefined'; | ||
let props = []; | ||
@@ -104,3 +105,4 @@ if (Array.isArray(cmpMeta.properties) && cmpMeta.properties.length > 0) { | ||
let templateString = ` | ||
export const ${tagNameAsPascal} = /*@__PURE__*/ defineContainer<${importTypes}.${tagNameAsPascal}>('${cmpMeta.tagName}'`; | ||
export const ${tagNameAsPascal} = /*@__PURE__*/ defineContainer<${importTypes}.${tagNameAsPascal}>('${cmpMeta.tagName}', ${importAs}`; | ||
const findModel = componentModelConfig && componentModelConfig.find(config => config.elements.includes(cmpMeta.tagName)); | ||
if (props.length > 0) { | ||
@@ -110,13 +112,29 @@ templateString += `, [ | ||
]`; | ||
/** | ||
* If there are no props, | ||
* but but v-model is stil used, | ||
* make sure we pass in an empty array | ||
* otherwise all of the defineContainer properties | ||
* will be off by one space. | ||
* Note: If you are using v-model then | ||
* the props array should never be empty | ||
* as there must be a prop for v-model to update, | ||
* but this check is there so builds do not crash. | ||
*/ | ||
} | ||
let options = {}; | ||
const findModel = componentModelConfig && componentModelConfig.find(config => config.elements.includes(cmpMeta.tagName)); | ||
else if (findModel) { | ||
templateString += `, []`; | ||
} | ||
if (findModel) { | ||
options.modelProp = findModel.targetAttr; | ||
options.modelUpdateEvent = findModel.event; | ||
options.externalModelUpdateEvent = findModel.externalEvent; | ||
} | ||
if (Object.keys(options).length > 0) { | ||
const targetProp = findModel.targetAttr; | ||
/** | ||
* If developer is trying to bind v-model support to a component's | ||
* prop, but that prop was not defined, warn them of this otherwise | ||
* v-model will not work as expected. | ||
*/ | ||
if (!props.includes(`'${targetProp}'`)) { | ||
console.warn(`Your '${cmpMeta.tagName}' component is configured to have v-model support bound to '${targetProp}', but '${targetProp}' is not defined as a property on the component. v-model integration may not work as expected.`); | ||
} | ||
templateString += `,\n`; | ||
templateString += JSON.stringify(options, null, 2); | ||
templateString += `'${targetProp}', '${findModel.event}', '${findModel.externalEvent}'`; | ||
} | ||
@@ -147,8 +165,21 @@ templateString += `);\n`; | ||
import { defineContainer } from './vue-component-lib/utils';\n`; | ||
const typeImports = !outputTarget.componentCorePackage | ||
? `import type { ${IMPORT_TYPES} } from '${normalizePath(componentsTypeFile)}';\n` | ||
: `import type { ${IMPORT_TYPES} } from '${normalizePath(outputTarget.componentCorePackage)}';\n`; | ||
const generateTypeImports = () => { | ||
if (outputTarget.componentCorePackage !== undefined) { | ||
const dirPath = outputTarget.includeImportCustomElements ? `/${outputTarget.customElementsDir || 'components'}` : ''; | ||
return `import type { ${IMPORT_TYPES} } from '${normalizePath(outputTarget.componentCorePackage)}${dirPath}';\n`; | ||
} | ||
return `import type { ${IMPORT_TYPES} } from '${normalizePath(componentsTypeFile)}';\n`; | ||
}; | ||
const typeImports = generateTypeImports(); | ||
let sourceImports = ''; | ||
let registerCustomElements = ''; | ||
if (outputTarget.includePolyfills && outputTarget.includeDefineCustomElements) { | ||
if (outputTarget.includeImportCustomElements && outputTarget.componentCorePackage !== undefined) { | ||
const cmpImports = components.map(component => { | ||
const pascalImport = dashToPascalCase(component.tagName); | ||
return `import { ${pascalImport} as ${pascalImport}Cmp } from '${normalizePath(outputTarget.componentCorePackage)}/${outputTarget.customElementsDir || | ||
'components'}/${component.tagName}.js';`; | ||
}); | ||
sourceImports = cmpImports.join('\n'); | ||
} | ||
else if (outputTarget.includePolyfills && outputTarget.includeDefineCustomElements) { | ||
sourceImports = `import { ${APPLY_POLYFILLS}, ${REGISTER_CUSTOM_ELEMENTS} } from '${pathToCorePackageLoader}';\n`; | ||
@@ -167,3 +198,3 @@ registerCustomElements = `${APPLY_POLYFILLS}().then(() => ${REGISTER_CUSTOM_ELEMENTS}());`; | ||
components | ||
.map(createComponentDefinition(IMPORT_TYPES, outputTarget.componentModels)) | ||
.map(createComponentDefinition(IMPORT_TYPES, outputTarget.componentModels, outputTarget.includeImportCustomElements)) | ||
.join('\n'), | ||
@@ -228,2 +259,8 @@ ]; | ||
} | ||
if (outputTarget.includeDefineCustomElements && outputTarget.includeImportCustomElements) { | ||
throw new Error('includeDefineCustomElements cannot be used at the same time as includeImportCustomElements since includeDefineCustomElements is used for lazy loading components. Set `includeDefineCustomElements: false` in your Vue output target config to resolve this.'); | ||
} | ||
if (outputTarget.includeImportCustomElements && outputTarget.includePolyfills) { | ||
throw new Error('includePolyfills cannot be used at the same time as includeImportCustomElements. Set `includePolyfills: false` in your Vue output target config to resolve this.'); | ||
} | ||
if (outputTarget.directivesProxyFile && !path__default['default'].isAbsolute(outputTarget.directivesProxyFile)) { | ||
@@ -230,0 +267,0 @@ results.proxiesFile = normalizePath(path__default['default'].join(config.rootDir, outputTarget.proxiesFile)); |
@@ -81,4 +81,5 @@ import path from 'path'; | ||
const createComponentDefinition = (importTypes, componentModelConfig) => (cmpMeta) => { | ||
const createComponentDefinition = (importTypes, componentModelConfig, includeCustomElement = false) => (cmpMeta) => { | ||
const tagNameAsPascal = dashToPascalCase(cmpMeta.tagName); | ||
const importAs = (includeCustomElement) ? tagNameAsPascal + 'Cmp' : 'undefined'; | ||
let props = []; | ||
@@ -95,3 +96,4 @@ if (Array.isArray(cmpMeta.properties) && cmpMeta.properties.length > 0) { | ||
let templateString = ` | ||
export const ${tagNameAsPascal} = /*@__PURE__*/ defineContainer<${importTypes}.${tagNameAsPascal}>('${cmpMeta.tagName}'`; | ||
export const ${tagNameAsPascal} = /*@__PURE__*/ defineContainer<${importTypes}.${tagNameAsPascal}>('${cmpMeta.tagName}', ${importAs}`; | ||
const findModel = componentModelConfig && componentModelConfig.find(config => config.elements.includes(cmpMeta.tagName)); | ||
if (props.length > 0) { | ||
@@ -101,13 +103,29 @@ templateString += `, [ | ||
]`; | ||
/** | ||
* If there are no props, | ||
* but but v-model is stil used, | ||
* make sure we pass in an empty array | ||
* otherwise all of the defineContainer properties | ||
* will be off by one space. | ||
* Note: If you are using v-model then | ||
* the props array should never be empty | ||
* as there must be a prop for v-model to update, | ||
* but this check is there so builds do not crash. | ||
*/ | ||
} | ||
let options = {}; | ||
const findModel = componentModelConfig && componentModelConfig.find(config => config.elements.includes(cmpMeta.tagName)); | ||
else if (findModel) { | ||
templateString += `, []`; | ||
} | ||
if (findModel) { | ||
options.modelProp = findModel.targetAttr; | ||
options.modelUpdateEvent = findModel.event; | ||
options.externalModelUpdateEvent = findModel.externalEvent; | ||
} | ||
if (Object.keys(options).length > 0) { | ||
const targetProp = findModel.targetAttr; | ||
/** | ||
* If developer is trying to bind v-model support to a component's | ||
* prop, but that prop was not defined, warn them of this otherwise | ||
* v-model will not work as expected. | ||
*/ | ||
if (!props.includes(`'${targetProp}'`)) { | ||
console.warn(`Your '${cmpMeta.tagName}' component is configured to have v-model support bound to '${targetProp}', but '${targetProp}' is not defined as a property on the component. v-model integration may not work as expected.`); | ||
} | ||
templateString += `,\n`; | ||
templateString += JSON.stringify(options, null, 2); | ||
templateString += `'${targetProp}', '${findModel.event}', '${findModel.externalEvent}'`; | ||
} | ||
@@ -138,8 +156,21 @@ templateString += `);\n`; | ||
import { defineContainer } from './vue-component-lib/utils';\n`; | ||
const typeImports = !outputTarget.componentCorePackage | ||
? `import type { ${IMPORT_TYPES} } from '${normalizePath(componentsTypeFile)}';\n` | ||
: `import type { ${IMPORT_TYPES} } from '${normalizePath(outputTarget.componentCorePackage)}';\n`; | ||
const generateTypeImports = () => { | ||
if (outputTarget.componentCorePackage !== undefined) { | ||
const dirPath = outputTarget.includeImportCustomElements ? `/${outputTarget.customElementsDir || 'components'}` : ''; | ||
return `import type { ${IMPORT_TYPES} } from '${normalizePath(outputTarget.componentCorePackage)}${dirPath}';\n`; | ||
} | ||
return `import type { ${IMPORT_TYPES} } from '${normalizePath(componentsTypeFile)}';\n`; | ||
}; | ||
const typeImports = generateTypeImports(); | ||
let sourceImports = ''; | ||
let registerCustomElements = ''; | ||
if (outputTarget.includePolyfills && outputTarget.includeDefineCustomElements) { | ||
if (outputTarget.includeImportCustomElements && outputTarget.componentCorePackage !== undefined) { | ||
const cmpImports = components.map(component => { | ||
const pascalImport = dashToPascalCase(component.tagName); | ||
return `import { ${pascalImport} as ${pascalImport}Cmp } from '${normalizePath(outputTarget.componentCorePackage)}/${outputTarget.customElementsDir || | ||
'components'}/${component.tagName}.js';`; | ||
}); | ||
sourceImports = cmpImports.join('\n'); | ||
} | ||
else if (outputTarget.includePolyfills && outputTarget.includeDefineCustomElements) { | ||
sourceImports = `import { ${APPLY_POLYFILLS}, ${REGISTER_CUSTOM_ELEMENTS} } from '${pathToCorePackageLoader}';\n`; | ||
@@ -158,3 +189,3 @@ registerCustomElements = `${APPLY_POLYFILLS}().then(() => ${REGISTER_CUSTOM_ELEMENTS}());`; | ||
components | ||
.map(createComponentDefinition(IMPORT_TYPES, outputTarget.componentModels)) | ||
.map(createComponentDefinition(IMPORT_TYPES, outputTarget.componentModels, outputTarget.includeImportCustomElements)) | ||
.join('\n'), | ||
@@ -219,2 +250,8 @@ ]; | ||
} | ||
if (outputTarget.includeDefineCustomElements && outputTarget.includeImportCustomElements) { | ||
throw new Error('includeDefineCustomElements cannot be used at the same time as includeImportCustomElements since includeDefineCustomElements is used for lazy loading components. Set `includeDefineCustomElements: false` in your Vue output target config to resolve this.'); | ||
} | ||
if (outputTarget.includeImportCustomElements && outputTarget.includePolyfills) { | ||
throw new Error('includePolyfills cannot be used at the same time as includeImportCustomElements. Set `includePolyfills: false` in your Vue output target config to resolve this.'); | ||
} | ||
if (outputTarget.directivesProxyFile && !path.isAbsolute(outputTarget.directivesProxyFile)) { | ||
@@ -221,0 +258,0 @@ results.proxiesFile = normalizePath(path.join(config.rootDir, outputTarget.proxiesFile)); |
import path from 'path'; | ||
import { createComponentDefinition } from './generate-vue-component'; | ||
import { normalizePath, readPackageJson, relativeImport, sortBy } from './utils'; | ||
import { normalizePath, readPackageJson, relativeImport, sortBy, dashToPascalCase } from './utils'; | ||
export async function vueProxyOutput(config, compilerCtx, outputTarget, components) { | ||
@@ -24,8 +24,21 @@ const filteredComponents = getFilteredComponents(outputTarget.excludeComponents, components); | ||
import { defineContainer } from './vue-component-lib/utils';\n`; | ||
const typeImports = !outputTarget.componentCorePackage | ||
? `import type { ${IMPORT_TYPES} } from '${normalizePath(componentsTypeFile)}';\n` | ||
: `import type { ${IMPORT_TYPES} } from '${normalizePath(outputTarget.componentCorePackage)}';\n`; | ||
const generateTypeImports = () => { | ||
if (outputTarget.componentCorePackage !== undefined) { | ||
const dirPath = outputTarget.includeImportCustomElements ? `/${outputTarget.customElementsDir || 'components'}` : ''; | ||
return `import type { ${IMPORT_TYPES} } from '${normalizePath(outputTarget.componentCorePackage)}${dirPath}';\n`; | ||
} | ||
return `import type { ${IMPORT_TYPES} } from '${normalizePath(componentsTypeFile)}';\n`; | ||
}; | ||
const typeImports = generateTypeImports(); | ||
let sourceImports = ''; | ||
let registerCustomElements = ''; | ||
if (outputTarget.includePolyfills && outputTarget.includeDefineCustomElements) { | ||
if (outputTarget.includeImportCustomElements && outputTarget.componentCorePackage !== undefined) { | ||
const cmpImports = components.map(component => { | ||
const pascalImport = dashToPascalCase(component.tagName); | ||
return `import { ${pascalImport} as ${pascalImport}Cmp } from '${normalizePath(outputTarget.componentCorePackage)}/${outputTarget.customElementsDir || | ||
'components'}/${component.tagName}.js';`; | ||
}); | ||
sourceImports = cmpImports.join('\n'); | ||
} | ||
else if (outputTarget.includePolyfills && outputTarget.includeDefineCustomElements) { | ||
sourceImports = `import { ${APPLY_POLYFILLS}, ${REGISTER_CUSTOM_ELEMENTS} } from '${pathToCorePackageLoader}';\n`; | ||
@@ -44,3 +57,3 @@ registerCustomElements = `${APPLY_POLYFILLS}().then(() => ${REGISTER_CUSTOM_ELEMENTS}());`; | ||
components | ||
.map(createComponentDefinition(IMPORT_TYPES, outputTarget.componentModels)) | ||
.map(createComponentDefinition(IMPORT_TYPES, outputTarget.componentModels, outputTarget.includeImportCustomElements)) | ||
.join('\n'), | ||
@@ -47,0 +60,0 @@ ]; |
@@ -25,2 +25,8 @@ import { normalizePath } from './utils'; | ||
} | ||
if (outputTarget.includeDefineCustomElements && outputTarget.includeImportCustomElements) { | ||
throw new Error('includeDefineCustomElements cannot be used at the same time as includeImportCustomElements since includeDefineCustomElements is used for lazy loading components. Set `includeDefineCustomElements: false` in your Vue output target config to resolve this.'); | ||
} | ||
if (outputTarget.includeImportCustomElements && outputTarget.includePolyfills) { | ||
throw new Error('includePolyfills cannot be used at the same time as includeImportCustomElements. Set `includePolyfills: false` in your Vue output target config to resolve this.'); | ||
} | ||
if (outputTarget.directivesProxyFile && !path.isAbsolute(outputTarget.directivesProxyFile)) { | ||
@@ -27,0 +33,0 @@ results.proxiesFile = normalizePath(path.join(config.rootDir, outputTarget.proxiesFile)); |
@@ -9,8 +9,5 @@ export interface OutputTargetVue { | ||
includeDefineCustomElements?: boolean; | ||
includeImportCustomElements?: boolean; | ||
customElementsDir?: string; | ||
} | ||
export interface ComponentOptions { | ||
modelProp?: string; | ||
modelUpdateEvent?: string | string[]; | ||
externalModelUpdateEvent?: string; | ||
} | ||
export interface ComponentModelConfig { | ||
@@ -17,0 +14,0 @@ elements: string | string[]; |
{ | ||
"name": "@stencil/vue-output-target", | ||
"version": "0.4.3", | ||
"version": "0.5.0-0", | ||
"description": "Vue output target for @stencil/core components.", | ||
@@ -35,3 +35,3 @@ "main": "dist/index.cjs.js", | ||
"peerDependencies": { | ||
"@stencil/core": ">=1.8.0" | ||
"@stencil/core": ">=1.8.0 || ^2.0.0" | ||
}, | ||
@@ -38,0 +38,0 @@ "jest": { |
@@ -17,8 +17,2 @@ import { VNode, defineComponent, getCurrentInstance, h, inject, ref, Ref } from 'vue'; | ||
interface ComponentOptions { | ||
modelProp?: string; | ||
modelUpdateEvent?: string | string[]; | ||
externalModelUpdateEvent?: string; | ||
} | ||
const getComponentClasses = (classes: unknown) => { | ||
@@ -40,10 +34,32 @@ return (classes as string)?.split(' ') || []; | ||
* in each component's TSX file. | ||
* @prop componentOptions - An object that defines additional | ||
* options for the component such as router or v-model | ||
* integrations. | ||
* @prop customElement - An option custom element instance to pass | ||
* to customElements.define. Only set if `includeImportCustomElements: true` in your config. | ||
* @prop modelProp - The prop that v-model binds to (i.e. value) | ||
* @prop modelUpdateEvent - The event that is fired from your Web Component when the value changes (i.e. ionChange) | ||
* @prop externalModelUpdateEvent - The external event to fire from your Vue component when modelUpdateEvent fires. This is used for ensuring that v-model references have been | ||
* correctly updated when a user's event callback fires. | ||
*/ | ||
export const defineContainer = <Props>(name: string, componentProps: string[] = [], componentOptions: ComponentOptions = {}) => { | ||
const { modelProp, modelUpdateEvent, externalModelUpdateEvent } = componentOptions; | ||
export const defineContainer = <Props>( | ||
name: string, | ||
customElement: any, | ||
componentProps: string[] = [], | ||
modelProp?: string, | ||
modelUpdateEvent?: string, | ||
externalModelUpdateEvent?: string | ||
) => { | ||
/** | ||
* If importing custom elements, register it | ||
* with the custom elements registry only if | ||
* it has not already been registered. | ||
*/ | ||
if ( | ||
customElement !== undefined && | ||
typeof customElements !== 'undefined' && | ||
!customElements.get(name) | ||
) { | ||
customElements.define(name, customElement); | ||
} | ||
/** | ||
* Create a Vue component wrapper around a Web Component. | ||
@@ -50,0 +66,0 @@ * Note: The `props` here are not all properties on a component. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
47393
968