Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@stencil/vue-output-target

Package Overview
Dependencies
Maintainers
2
Versions
159
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@stencil/vue-output-target - npm Package Compare versions

Comparing version 0.5.1-6 to 0.5.1-dev.11685564559.1b0b6e89

15

dist/generate-vue-component.js
import { dashToPascalCase } from './utils';
export const createComponentDefinition = (importTypes, componentModelConfig, includeCustomElement = false) => (cmpMeta) => {
const tagNameAsPascal = dashToPascalCase(cmpMeta.tagName);
const importAs = (includeCustomElement) ? tagNameAsPascal + 'Cmp' : 'undefined';
const importAs = includeCustomElement ? 'define' + tagNameAsPascal : 'undefined';
let props = [];

@@ -10,10 +10,9 @@ if (Array.isArray(cmpMeta.properties) && cmpMeta.properties.length > 0) {

if (Array.isArray(cmpMeta.events) && cmpMeta.events.length > 0) {
props = [
...props,
...cmpMeta.events.map((event) => `'${event.name}'`)
];
props = [...props, ...cmpMeta.events.map((event) => `'${event.name}'`)];
}
const componentType = `${importTypes}.${tagNameAsPascal}`;
const findModel = componentModelConfig && componentModelConfig.find((config) => config.elements.includes(cmpMeta.tagName));
const modelType = findModel !== undefined ? `, ${componentType}["${findModel.targetAttr}"]` : '';
let templateString = `
export const ${tagNameAsPascal} = /*@__PURE__*/ defineContainer<${importTypes}.${tagNameAsPascal}>('${cmpMeta.tagName}', ${importAs}`;
const findModel = componentModelConfig && componentModelConfig.find(config => config.elements.includes(cmpMeta.tagName));
export const ${tagNameAsPascal} = /*@__PURE__*/ defineContainer<${componentType}${modelType}>('${cmpMeta.tagName}', ${importAs}`;
if (props.length > 0) {

@@ -25,3 +24,3 @@ templateString += `, [

* If there are no props,
* but but v-model is stil used,
* but v-model is still used,
* make sure we pass in an empty array

@@ -28,0 +27,0 @@ * otherwise all of the defineContainer properties

@@ -92,3 +92,3 @@ 'use strict';

const tagNameAsPascal = dashToPascalCase(cmpMeta.tagName);
const importAs = (includeCustomElement) ? tagNameAsPascal + 'Cmp' : 'undefined';
const importAs = includeCustomElement ? 'define' + tagNameAsPascal : 'undefined';
let props = [];

@@ -99,10 +99,9 @@ if (Array.isArray(cmpMeta.properties) && cmpMeta.properties.length > 0) {

if (Array.isArray(cmpMeta.events) && cmpMeta.events.length > 0) {
props = [
...props,
...cmpMeta.events.map((event) => `'${event.name}'`)
];
props = [...props, ...cmpMeta.events.map((event) => `'${event.name}'`)];
}
const componentType = `${importTypes}.${tagNameAsPascal}`;
const findModel = componentModelConfig && componentModelConfig.find((config) => config.elements.includes(cmpMeta.tagName));
const modelType = findModel !== undefined ? `, ${componentType}["${findModel.targetAttr}"]` : '';
let templateString = `
export const ${tagNameAsPascal} = /*@__PURE__*/ defineContainer<${importTypes}.${tagNameAsPascal}>('${cmpMeta.tagName}', ${importAs}`;
const findModel = componentModelConfig && componentModelConfig.find(config => config.elements.includes(cmpMeta.tagName));
export const ${tagNameAsPascal} = /*@__PURE__*/ defineContainer<${componentType}${modelType}>('${cmpMeta.tagName}', ${importAs}`;
if (props.length > 0) {

@@ -114,3 +113,3 @@ templateString += `, [

* If there are no props,
* but but v-model is stil used,
* but v-model is still used,
* make sure we pass in an empty array

@@ -170,3 +169,5 @@ * otherwise all of the defineContainer properties

if (outputTarget.componentCorePackage !== undefined) {
const dirPath = outputTarget.includeImportCustomElements ? `/${outputTarget.customElementsDir || 'components'}` : '';
const dirPath = outputTarget.includeImportCustomElements
? `/${outputTarget.customElementsDir || 'components'}`
: '';
return `import type { ${IMPORT_TYPES} } from '${normalizePath(outputTarget.componentCorePackage)}${dirPath}';\n`;

@@ -180,6 +181,5 @@ }

if (outputTarget.includeImportCustomElements && outputTarget.componentCorePackage !== undefined) {
const cmpImports = components.map(component => {
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';`;
return `import { defineCustomElement as define${pascalImport} } from '${normalizePath(outputTarget.componentCorePackage)}/${outputTarget.customElementsDir || 'components'}/${component.tagName}.js';`;
});

@@ -229,5 +229,3 @@ sourceImports = cmpImports.join('\n');

: null;
const distRelEsmLoaderPath = config.rootDir && distAbsEsmLoaderPath
? path__default['default'].relative(config.rootDir, distAbsEsmLoaderPath)
: null;
const distRelEsmLoaderPath = config.rootDir && distAbsEsmLoaderPath ? path__default['default'].relative(config.rootDir, distAbsEsmLoaderPath) : null;
const loaderDir = outputTarget.loaderDir || distRelEsmLoaderPath || DEFAULT_LOADER_DIR;

@@ -234,0 +232,0 @@ return normalizePath(path__default['default'].join(basePkg, loaderDir));

@@ -83,3 +83,3 @@ import path from 'path';

const tagNameAsPascal = dashToPascalCase(cmpMeta.tagName);
const importAs = (includeCustomElement) ? tagNameAsPascal + 'Cmp' : 'undefined';
const importAs = includeCustomElement ? 'define' + tagNameAsPascal : 'undefined';
let props = [];

@@ -90,10 +90,9 @@ if (Array.isArray(cmpMeta.properties) && cmpMeta.properties.length > 0) {

if (Array.isArray(cmpMeta.events) && cmpMeta.events.length > 0) {
props = [
...props,
...cmpMeta.events.map((event) => `'${event.name}'`)
];
props = [...props, ...cmpMeta.events.map((event) => `'${event.name}'`)];
}
const componentType = `${importTypes}.${tagNameAsPascal}`;
const findModel = componentModelConfig && componentModelConfig.find((config) => config.elements.includes(cmpMeta.tagName));
const modelType = findModel !== undefined ? `, ${componentType}["${findModel.targetAttr}"]` : '';
let templateString = `
export const ${tagNameAsPascal} = /*@__PURE__*/ defineContainer<${importTypes}.${tagNameAsPascal}>('${cmpMeta.tagName}', ${importAs}`;
const findModel = componentModelConfig && componentModelConfig.find(config => config.elements.includes(cmpMeta.tagName));
export const ${tagNameAsPascal} = /*@__PURE__*/ defineContainer<${componentType}${modelType}>('${cmpMeta.tagName}', ${importAs}`;
if (props.length > 0) {

@@ -105,3 +104,3 @@ templateString += `, [

* If there are no props,
* but but v-model is stil used,
* but v-model is still used,
* make sure we pass in an empty array

@@ -161,3 +160,5 @@ * otherwise all of the defineContainer properties

if (outputTarget.componentCorePackage !== undefined) {
const dirPath = outputTarget.includeImportCustomElements ? `/${outputTarget.customElementsDir || 'components'}` : '';
const dirPath = outputTarget.includeImportCustomElements
? `/${outputTarget.customElementsDir || 'components'}`
: '';
return `import type { ${IMPORT_TYPES} } from '${normalizePath(outputTarget.componentCorePackage)}${dirPath}';\n`;

@@ -171,6 +172,5 @@ }

if (outputTarget.includeImportCustomElements && outputTarget.componentCorePackage !== undefined) {
const cmpImports = components.map(component => {
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';`;
return `import { defineCustomElement as define${pascalImport} } from '${normalizePath(outputTarget.componentCorePackage)}/${outputTarget.customElementsDir || 'components'}/${component.tagName}.js';`;
});

@@ -220,5 +220,3 @@ sourceImports = cmpImports.join('\n');

: null;
const distRelEsmLoaderPath = config.rootDir && distAbsEsmLoaderPath
? path.relative(config.rootDir, distAbsEsmLoaderPath)
: null;
const distRelEsmLoaderPath = config.rootDir && distAbsEsmLoaderPath ? path.relative(config.rootDir, distAbsEsmLoaderPath) : null;
const loaderDir = outputTarget.loaderDir || distRelEsmLoaderPath || DEFAULT_LOADER_DIR;

@@ -225,0 +223,0 @@ return normalizePath(path.join(basePkg, loaderDir));

@@ -26,3 +26,5 @@ import path from 'path';

if (outputTarget.componentCorePackage !== undefined) {
const dirPath = outputTarget.includeImportCustomElements ? `/${outputTarget.customElementsDir || 'components'}` : '';
const dirPath = outputTarget.includeImportCustomElements
? `/${outputTarget.customElementsDir || 'components'}`
: '';
return `import type { ${IMPORT_TYPES} } from '${normalizePath(outputTarget.componentCorePackage)}${dirPath}';\n`;

@@ -36,6 +38,5 @@ }

if (outputTarget.includeImportCustomElements && outputTarget.componentCorePackage !== undefined) {
const cmpImports = components.map(component => {
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';`;
return `import { defineCustomElement as define${pascalImport} } from '${normalizePath(outputTarget.componentCorePackage)}/${outputTarget.customElementsDir || 'components'}/${component.tagName}.js';`;
});

@@ -85,5 +86,3 @@ sourceImports = cmpImports.join('\n');

: null;
const distRelEsmLoaderPath = config.rootDir && distAbsEsmLoaderPath
? path.relative(config.rootDir, distAbsEsmLoaderPath)
: null;
const distRelEsmLoaderPath = config.rootDir && distAbsEsmLoaderPath ? path.relative(config.rootDir, distAbsEsmLoaderPath) : null;
const loaderDir = outputTarget.loaderDir || distRelEsmLoaderPath || DEFAULT_LOADER_DIR;

@@ -90,0 +89,0 @@ return normalizePath(path.join(basePkg, loaderDir));

import type { PackageJSON } from './types';
export declare const toLowerCase: (str: string) => string;
export declare const dashToPascalCase: (str: string) => string;
export declare function flatOne<T>(array: T[][]): T[];
export declare function sortBy<T>(array: T[], prop: (item: T) => string): T[];

@@ -6,0 +5,0 @@ export declare function normalizePath(str: string): string;

@@ -10,11 +10,2 @@ import path from 'path';

.join('');
export function flatOne(array) {
if (array.flat) {
return array.flat(1);
}
return array.reduce((result, item) => {
result.push(...item);
return result;
}, []);
}
export function sortBy(array, prop) {

@@ -21,0 +12,0 @@ return array.slice().sort((a, b) => {

{
"name": "@stencil/vue-output-target",
"version": "0.5.1-6",
"version": "0.5.1-dev.11685564559.1b0b6e89",
"description": "Vue output target for @stencil/core components.",

@@ -16,2 +16,3 @@ "main": "dist/index.cjs.js",

"scripts": {
"prepublishOnly": "npm run build",
"prebuild": "rimraf ./dist",

@@ -22,2 +23,5 @@ "build": "tsc && npm run rollup",

"version": "npm run build",
"prettier": "npm run prettier.base -- --write",
"prettier.base": "prettier \"./({vue-component-lib,src,test,__tests__}/**/*.{ts,tsx,js,jsx})|*.{ts,tsx,js,jsx}\"",
"prettier.dry-run": "npm run prettier.base -- --list-different",
"release": "np",

@@ -37,3 +41,3 @@ "test": "jest"

"peerDependencies": {
"@stencil/core": ">=1.8.0 || ^2.0.0"
"@stencil/core": "^2.9.0 || ^3.0.0"
},

@@ -54,3 +58,6 @@ "jest": {

},
"gitHead": "a3588e905186a0e86e7f88418fd5b2f9531b55e0"
"gitHead": "b0b6e898b94958cabecfa212c9a58c9e9ac4411e",
"volta": {
"extends": "../../package.json"
}
}
# @stencil/vue-output-target
This is an output plugin for stencil.
Stencil can generate Vue component wrappers for your web components. This allows your Stencil components to be used within a Vue application.
For a detailed guide on how to add the vue output target to a project, visit: https://stenciljs.com/docs/vue.
## Installation
```bash
npm install @stencil/vue-output-target
```
### Usage
In your `stencil.config.ts` add the following configuration to the `outputTargets` section:
```ts
import { Config } from '@stencil/core';
import { vueOutputTarget } from '@stencil/vue-output-target';
export const config: Config = {
namespace: 'demo',
outputTargets: [
vueOutputTarget({
componentCorePackage: 'component-library',
proxiesFile: '../component-library-vue/src/components.ts',
}),
{
type: 'dist',
esmLoaderPath: '../loader',
},
],
};
```
## Config Options
| Property | Description |
| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `componentCorePackage` | The NPM package name of your Stencil component library. This package is used as a dependency for your Vue wrappers. |
| `proxiesFile` | The output file of all the component wrappers generated by the output target. This file path should point to a location within your Vue library/project. |
| `excludeComponents` | An array of tag names to exclude from generating component wrappers for. This is helpful when have a custom framework implementation of a specific component or need to extend the base component wrapper behavior. |
| `componentModels` | This is an array of `ComponentModelConfig` objects for components that should be integrated with `v-model`. |
| `loaderDir` | This is the path to where the `defineCustomElements` function exists in your built project. If `loaderDir` is not provided, the `/dist/loader` directory will be used. |
| `includePolyfills` | If `true`, polyfills will automatically be imported and the `applyPolyfills` function will be called in your proxies file. This can only be used when lazy loading Web Components and will not work when `includeImportCustomElements` is `true`. |
| `includeDefineCustomElements` | If `true`, all Web Components will automatically be registered with the Custom Elements Registry. This can only be used when lazy loading Web Components and will not work when `includeImportCustomElements` is `true`. |
| `includeImportCustomElements` | If `true`, the output target will import the custom element instance and register it with the Custom Elements Registry when the component is imported inside of a user's app. This can only be used with the [Custom Elements Bundle](https://stenciljs.com/docs/custom-elements) and will not work with lazy loaded components. |
| `customElementsDir` | This is the directory where the custom elements are imported from when using the [Custom Elements Bundle](https://stenciljs.com/docs/custom-elements). Defaults to the `components` directory. Only applies when `includeImportCustomElements` is `true`. |
## Interfaces
### ComponentModelConfig
The interface used for `componentModels`.
```typescript
export interface ComponentModelConfig {
/**
* An array of element names that
* should have v-model integration.
*/
elements: string | string[];
/**
* The event emitted from the Web Component
* that should trigger a `v-model` update.
*/
event: string;
/**
* The Web Component property that the value
* of the `v-model` reference is based off.
*/
targetAttr: string;
/**
* (optional) The event to emit from the Vue component
* wrapper. When listening directly to the `event` emitted
* from the Web Component, the `v-model` reference has not
* yet had a chance to update. By setting `externalEvent`,
* your Web Component can emit `event`, the Vue output target
* can update the `v-model` reference, and then emit `externalEvent`,
* notifying the end user that `v-model` has changed. Defaults to `event`.
*/
externalEvent?: string;
}
```
Example usage within `stencil.config.ts`:
```typescript
vueOutputTarget({
...,
componentModels: [
{
elements: ['my-input', 'my-textarea'],
event: 'v-on-change',
externalEvent: 'on-change',
targetAttr: 'value'
}
]
})
```

@@ -0,5 +1,7 @@

// @ts-nocheck
// It's easier and safer for Volar to disable typechecking and let the return type inference do its job.
import { VNode, defineComponent, getCurrentInstance, h, inject, ref, Ref } from 'vue';
export interface InputProps extends Object {
modelValue: string | boolean;
export interface InputProps<T> {
modelValue?: T;
}

@@ -12,3 +14,3 @@

const ROUTER_PROP_PREFIX = 'router';
const ARIA_PROP_PREFIX = 'aria';
/**

@@ -34,24 +36,29 @@ * Starting in Vue 3.1.0, all properties are

const getElementClasses = (ref: Ref<HTMLElement | undefined>, componentClasses: Set<string>, defaultClasses: string[] = []) => {
return [ ...Array.from(ref.value?.classList || []), ...defaultClasses ]
.filter((c: string, i, self) => !componentClasses.has(c) && self.indexOf(c) === i);
const getElementClasses = (
ref: Ref<HTMLElement | undefined>,
componentClasses: Set<string>,
defaultClasses: string[] = []
) => {
return [...Array.from(ref.value?.classList || []), ...defaultClasses].filter(
(c: string, i, self) => !componentClasses.has(c) && self.indexOf(c) === i
);
};
/**
* Create a callback to define a Vue component wrapper around a Web Component.
*
* @prop name - The component tag name (i.e. `ion-button`)
* @prop componentProps - An array of properties on the
* component. These usually match up with the @Prop definitions
* in each component's TSX file.
* @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>(
* Create a callback to define a Vue component wrapper around a Web Component.
*
* @prop name - The component tag name (i.e. `ion-button`)
* @prop componentProps - An array of properties on the
* component. These usually match up with the @Prop definitions
* in each component's TSX file.
* @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, VModelType = string | number | boolean>(
name: string,
customElement: any,
defineCustomElement: any,
componentProps: string[] = [],

@@ -63,16 +70,12 @@ modelProp?: string,

/**
* Create a Vue component wrapper around a Web Component.
* Note: The `props` here are not all properties on a component.
* They refer to whatever properties are set on an instance of a component.
*/
* Create a Vue component wrapper around a Web Component.
* Note: The `props` here are not all properties on a component.
* They refer to whatever properties are set on an instance of a component.
*/
if (
customElement !== undefined &&
typeof customElements !== 'undefined' &&
!customElements.get(name)
) {
customElements.define(name, customElement);
if (defineCustomElement !== undefined) {
defineCustomElement();
}
const Container = defineComponent<Props & InputProps>((props: any, { attrs, slots, emit }) => {
const Container = defineComponent<Props & InputProps<VModelType>>((props, { attrs, slots, emit }) => {
let modelPropValue = props[modelProp];

@@ -86,3 +89,3 @@ const containerRef = ref<HTMLElement>();

eventsNames.forEach((eventName: string) => {
vnode.el.addEventListener(eventName.toLowerCase(), (e: Event) => {
vnode.el!.addEventListener(eventName.toLowerCase(), (e: Event) => {
modelPropValue = (e?.target as any)[modelProp];

@@ -127,3 +130,3 @@ emit(UPDATE_VALUE_EVENT, modelPropValue);

}
}
};

@@ -133,3 +136,3 @@ return () => {

getComponentClasses(attrs.class).forEach(value => {
getComponentClasses(attrs.class).forEach((value) => {
classes.add(value);

@@ -146,3 +149,3 @@ });

}
}
};

@@ -153,3 +156,3 @@ let propsToAdd: any = {

onClick: handleClick,
onVnodeBeforeMount: (modelUpdateEvent) ? onVnodeBeforeMount : undefined
onVnodeBeforeMount: modelUpdateEvent ? onVnodeBeforeMount : undefined,
};

@@ -165,3 +168,3 @@

const value = props[key];
if (props.hasOwnProperty(key) && value !== EMPTY_PROP) {
if ((props.hasOwnProperty(key) && value !== EMPTY_PROP) || key.startsWith(ARIA_PROP_PREFIX)) {
propsToAdd[key] = value;

@@ -181,9 +184,9 @@ }

...propsToAdd,
[modelProp]: props[MODEL_VALUE]
}
[modelProp]: props[MODEL_VALUE],
};
} else if (modelPropValue !== EMPTY_PROP) {
propsToAdd = {
...propsToAdd,
[modelProp]: modelPropValue
}
[modelProp]: modelPropValue,
};
}

@@ -193,18 +196,20 @@ }

return h(name, propsToAdd, slots.default && slots.default());
}
};
});
Container.displayName = name;
if (typeof Container !== 'function') {
Container.name = name;
Container.props = {
[ROUTER_LINK_VALUE]: DEFAULT_EMPTY_PROP
};
Container.props = {
[ROUTER_LINK_VALUE]: DEFAULT_EMPTY_PROP,
};
componentProps.forEach(componentProp => {
Container.props[componentProp] = DEFAULT_EMPTY_PROP;
});
componentProps.forEach((componentProp) => {
Container.props[componentProp] = DEFAULT_EMPTY_PROP;
});
if (modelProp) {
Container.props[MODEL_VALUE] = DEFAULT_EMPTY_PROP;
Container.emits = [UPDATE_VALUE_EVENT, externalModelUpdateEvent];
if (modelProp) {
Container.props[MODEL_VALUE] = DEFAULT_EMPTY_PROP;
Container.emits = [UPDATE_VALUE_EVENT, externalModelUpdateEvent];
}
}

@@ -211,0 +216,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc