Add vue 3 package (#293)

* init vue next package

* Refactor naming

* adjust readme

* add typescript support

* Fix es module build

* Bump alpha version

* Fix size property not working

* Fix issue with default attributes in this PR

* small fixes

* Update README.md

* Fix peer dep

* Add return

* update release workflow

Co-authored-by: AdamSGit <adamelio@protonmail.com>
This commit is contained in:
Eric Fennis
2021-05-20 21:24:54 +02:00
committed by GitHub
parent 15ac2cf282
commit 81b85839eb
22 changed files with 5291 additions and 8 deletions
+4 -2
View File
@@ -11,8 +11,10 @@ const srcDirectory = path.join(__dirname, '../dist');
// Declare type definitions
const typeDefinitions = `\
/// <reference types="react" />
import { SVGAttributes } from 'react'
/// <reference types="vue" />
import { SVGAttributes } from 'vue'
declare module 'lucide-vue-next'
// Create interface extending SVGAttributes
export interface LucideProps extends Partial<React.SVGProps<SVGSVGElement>> {
+9
View File
@@ -0,0 +1,9 @@
stats
node_modules
tests
scripts
build
src
babel.config.js
jest.config.js
rollup.config.js
+15
View File
@@ -0,0 +1,15 @@
ISC License
Copyright (c) 2020, Lucide Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+107
View File
@@ -0,0 +1,107 @@
# Lucide Vue Next
Implementation of the lucide icon library for Vue 3 applications.
> What is lucide? Read it [here](https://github.com/lucide-icons/lucide#what-is-lucide).
> :warning: This version of lucide is for Vue 3, For Vue 2 got to [lucide-vue-next](https://github.com/lucide-icons/lucide/tree/master/packages/lucide-vue#lucide-vue)
## Installation
```sh
yarn add lucide-vue-next
# or
npm install lucide-vue-next
```
## How to use
It's build with ESmodules so it's completely threeshakable.
Each icon can be imported as a vue component.
### Example
You can pass additional props to adjust the icon.
``` vue
<template>
<Camera
color="red"
:size="32"
/>
</template>
<script>
// Returns Vue component
import { Camera } from 'lucide-vue-next';
export default {
name: "My Component",
components: { Camera }
}
</script>
```
### Props
| name | type | default
| ------------ | -------- | --------
| `size` | *Number* | 24
| `color` | *String* | currentColor
| `strokeWidth`| *Number* | 2
| `defaultClass`| *String* | lucide-icon
### Custom props
You can also pass custom props that will be added in the svg as attributes.
``` vue
<template>
<Camera fill="red" />
</template>
```
### One generic icon component
It is possible to create one generic icon component to load icons.
> :warning: Example below importing all EsModules, caution using this example, not recommended when you using bundlers, your application build size will grow strongly.
#### Icon Component Example
``` vue
<template>
<component :is="icon" />
</template>
<script>
import * as icons from "lucide-vue-next";
export default {
props: {
name: {
type: String,
required: true,
},
},
computed: {
icon() {
return icons[this.name];
},
},
};
</script>
```
##### Then you can use it like this
``` vue
<template>
<div id="app">
<Icon name="Airplay" />
</div>
</template>
```
+14
View File
@@ -0,0 +1,14 @@
const mainConfig = require('../../babel.config');
module.exports = {
presets: [
[
'@babel/env',
{
loose: true,
modules: false,
},
],
],
env: mainConfig.env,
};
+14
View File
@@ -0,0 +1,14 @@
module.exports = {
verbose: true,
roots: ['<rootDir>/src/', '<rootDir>/tests/'],
moduleFileExtensions: ['js'],
transform: {
'^.+\\.js$': 'babel-jest',
'^.+\\.vue$': 'vue-jest',
},
transformIgnorePatterns: [`/node_modules`],
snapshotSerializers: ['jest-serializer-vue'],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
};
+41
View File
@@ -0,0 +1,41 @@
{
"name": "lucide-vue-next",
"version": "0.15.17-beta.0",
"author": "Eric Fennis",
"description": "Lucide Vue 3 Package",
"license": "ISC",
"homepage": "https://lucide.dev",
"bugs": "https://github.com/lucide-icons/lucide/issues",
"repository": {
"type": "git",
"url": "https://github.com/lucide-icons/lucide.git",
"directory": "packages/lucide-vue-next"
},
"amdName": "lucide-vue-next",
"source": "build/lucide-vue-next.js",
"main": "dist/cjs/lucide-vue-next.js",
"main:umd": "dist/umd/lucide-vue-next.js",
"module": "dist/esm/lucide-vue-next.js",
"unpkg": "dist/umd/lucide-vue-next.min.js",
"typings": "dist/lucide-vue-next.d.ts",
"scripts": {
"build": "yarn clean && yarn build:icons && yarn build:es && yarn build:types && yarn build:bundles",
"clean": "rm -rf dist && rm -rf ./src/icons/*.js",
"build:icons": "yarn --cwd ../../ build:icons --output=../packages/lucide-vue-next/src --templateSrc=../packages/lucide-vue-next/scripts/exportTemplate",
"build:es": "babel src -d dist/esm",
"build:types": "yarn --cwd ../../ babel-node packages/lucide-vue-next/scripts/buildTypes.js",
"build:bundles": "yarn --cwd ../../ rollup -c packages/lucide-vue-next/rollup.config.js",
"test": "jest",
"test:watch": "jest --watchAll"
},
"devDependencies": {
"@vue/compiler-sfc": "^3.0.0",
"@vue/test-utils": "^2.0.0-rc.6",
"jest-serializer-vue": "^2.0.2",
"vue-jest": "^5.0.0-alpha.7",
"vue": "3.0.6"
},
"peerDependencies": {
"vue": "^3.0.0"
}
}
+47
View File
@@ -0,0 +1,47 @@
import plugins from '../../rollup.plugins';
import pkg from './package.json';
const packageName = 'LucideVueNext';
const outputFileName = 'lucide-vue-next';
const rootDir = 'packages/lucide-vue-next'; // It runs from the root
const outputDir = `${rootDir}/dist`;
const inputs = [`${rootDir}/src/lucide-vue-next.js`];
const bundles = [
{
format: 'umd',
inputs,
outputDir,
minify: true,
},
{
format: 'umd',
inputs,
outputDir,
},
{
format: 'cjs',
inputs,
outputDir,
},
];
const configs = bundles
.map(({ inputs, outputDir, format, minify }) =>
inputs.map(input => ({
input,
plugins: plugins(pkg, minify),
external: ['vue'],
output: {
name: packageName,
file: `${outputDir}/${format}/${outputFileName}${minify ? '.min' : ''}.js`,
format,
sourcemap: true,
globals: {
vue: 'vue',
},
},
})),
)
.flat();
export default configs;
@@ -0,0 +1,37 @@
import path from 'path';
import { readSvgDirectory, resetFile, appendFile, toPascalCase } from '../../../scripts/helpers';
import defaultAttributes from '../src/defaultAttributes';
const TARGET_DIR = path.join(__dirname, '../dist');
const ICONS_DIR = path.resolve(__dirname, '../../../icons');
const TYPES_FILE_NAME = 'lucide-vue-next.d.ts';
// Generates header of d.ts file include some types and functions
const typeDefinitions = `\
import { Component } from 'vue';
declare module 'lucide-vue-next'
// Create interface extending SVGAttributes
export interface SVGProps extends Partial<SVGElement> ${JSON.stringify(defaultAttributes, null, 2)}
// Generated icons
`;
resetFile(TYPES_FILE_NAME, TARGET_DIR);
appendFile(typeDefinitions, TYPES_FILE_NAME, TARGET_DIR);
const svgFiles = readSvgDirectory(ICONS_DIR);
svgFiles.forEach(svgFile => {
const nameSvg = path.basename(svgFile, '.svg');
const componentName = toPascalCase(nameSvg);
appendFile(
`export declare const ${componentName}: (props: SVGProps) => Component;\n`,
TYPES_FILE_NAME,
TARGET_DIR,
);
});
console.log(`Generated ${TYPES_FILE_NAME} file with`, svgFiles.length, 'icons');
@@ -0,0 +1,7 @@
export default ({ componentName, children }) => `
import createVueComponent from '../createVueComponent';
const ${componentName} = createVueComponent('${componentName}Icon', ${JSON.stringify(children)});
export default ${componentName};
`;
@@ -0,0 +1,19 @@
import { h } from 'vue';
import defaultAttributes from './defaultAttributes';
const createVueComponent = (iconName, iconNode) => (props, context) =>
h(
'svg',
{
...defaultAttributes,
...{
width: props.size || defaultAttributes.width,
height: props.size || defaultAttributes.height,
},
...context.attrs,
...props,
},
iconNode.map(child => h(...child)),
);
export default createVueComponent;
@@ -0,0 +1,11 @@
export default {
xmlns: 'http://www.w3.org/2000/svg',
width: 24,
height: 24,
viewBox: '0 0 24 24',
fill: 'none',
stroke: 'currentColor',
'stroke-width': 2,
'stroke-linecap': 'round',
'stroke-linejoin': 'round',
};
@@ -0,0 +1 @@
Folder for generated icons
@@ -0,0 +1 @@
export * from './icons';
@@ -0,0 +1,577 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Using lucide icon components should add a class to the element 1`] = `
VueWrapper {
"__app": Object {
"_component": Object {
"__emits": Object {},
"__props": Array [
Object {},
Array [],
],
"name": "VTU_ROOT",
"render": [Function],
},
"_container": <div
data-v-app=""
>
<svg
class="lucide-icon my-icon"
fill="none"
height="24"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="12"
cy="12"
r="10"
/>
<path
d="M8 14s1.5 2 4 2 4-2 4-2"
/>
<line
x1="9"
x2="9.01"
y1="9"
y2="9"
/>
<line
x1="15"
x2="15.01"
y1="9"
y2="9"
/>
</svg>
</div>,
"_context": Object {
"app": [Circular],
"components": Object {
"transition": Object {
"name": "transition",
"props": undefined,
"render": [Function],
},
"transition-group": Object {
"name": "transition-group",
"props": undefined,
"render": [Function],
},
},
"config": Object {
"errorHandler": undefined,
"globalProperties": Object {},
"isCustomElement": [Function],
"isNativeTag": [Function],
"optionMergeStrategies": Object {},
"performance": false,
"warnHandler": undefined,
},
"directives": Object {},
"mixins": Array [
Object {
"__emits": null,
"__props": Array [],
"beforeCreate": [Function],
},
],
"provides": Object {},
"reload": [Function],
},
"_props": null,
"_uid": 2,
"component": [Function],
"config": Object {
"errorHandler": undefined,
"globalProperties": Object {},
"isCustomElement": [Function],
"isNativeTag": [Function],
"optionMergeStrategies": Object {},
"performance": false,
"warnHandler": undefined,
},
"directive": [Function],
"mixin": [Function],
"mount": [Function],
"provide": [Function],
"unmount": [Function],
"use": [Function],
"version": "3.0.6",
},
"__setProps": [Function],
"componentVM": Object {
"hasOwnProperty": [Function],
},
"rootVM": Object {},
"wrapperElement": <svg
class="lucide-icon my-icon"
fill="none"
height="24"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="12"
cy="12"
r="10"
/>
<path
d="M8 14s1.5 2 4 2 4-2 4-2"
/>
<line
x1="9"
x2="9.01"
y1="9"
y2="9"
/>
<line
x1="15"
x2="15.01"
y1="9"
y2="9"
/>
</svg>,
}
`;
exports[`Using lucide icon components should add a style attribute to the element 1`] = `
VueWrapper {
"__app": Object {
"_component": Object {
"__emits": Object {},
"__props": Array [
Object {},
Array [],
],
"name": "VTU_ROOT",
"render": [Function],
},
"_container": <div
data-v-app=""
>
<svg
fill="none"
height="24"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
style="position: absolute;"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="12"
cy="12"
r="10"
/>
<path
d="M8 14s1.5 2 4 2 4-2 4-2"
/>
<line
x1="9"
x2="9.01"
y1="9"
y2="9"
/>
<line
x1="15"
x2="15.01"
y1="9"
y2="9"
/>
</svg>
</div>,
"_context": Object {
"app": [Circular],
"components": Object {
"transition": Object {
"name": "transition",
"props": undefined,
"render": [Function],
},
"transition-group": Object {
"name": "transition-group",
"props": undefined,
"render": [Function],
},
},
"config": Object {
"errorHandler": undefined,
"globalProperties": Object {},
"isCustomElement": [Function],
"isNativeTag": [Function],
"optionMergeStrategies": Object {},
"performance": false,
"warnHandler": undefined,
},
"directives": Object {},
"mixins": Array [
Object {
"__emits": null,
"__props": Array [],
"beforeCreate": [Function],
},
],
"provides": Object {},
"reload": [Function],
},
"_props": null,
"_uid": 3,
"component": [Function],
"config": Object {
"errorHandler": undefined,
"globalProperties": Object {},
"isCustomElement": [Function],
"isNativeTag": [Function],
"optionMergeStrategies": Object {},
"performance": false,
"warnHandler": undefined,
},
"directive": [Function],
"mixin": [Function],
"mount": [Function],
"provide": [Function],
"unmount": [Function],
"use": [Function],
"version": "3.0.6",
},
"__setProps": [Function],
"componentVM": Object {
"hasOwnProperty": [Function],
},
"rootVM": Object {},
"wrapperElement": <svg
fill="none"
height="24"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
style="position: absolute;"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="12"
cy="12"
r="10"
/>
<path
d="M8 14s1.5 2 4 2 4-2 4-2"
/>
<line
x1="9"
x2="9.01"
y1="9"
y2="9"
/>
<line
x1="15"
x2="15.01"
y1="9"
y2="9"
/>
</svg>,
}
`;
exports[`Using lucide icon components should adjust the size, stroke color and stroke width 1`] = `
VueWrapper {
"__app": Object {
"_component": Object {
"__emits": Object {},
"__props": Array [
Object {},
Array [],
],
"name": "VTU_ROOT",
"render": [Function],
},
"_container": <div
data-v-app=""
>
<svg
fill="none"
height="48"
size="48"
stroke="red"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
strokeWidth="4"
viewBox="0 0 24 24"
width="48"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="12"
cy="12"
r="10"
/>
<path
d="M8 14s1.5 2 4 2 4-2 4-2"
/>
<line
x1="9"
x2="9.01"
y1="9"
y2="9"
/>
<line
x1="15"
x2="15.01"
y1="9"
y2="9"
/>
</svg>
</div>,
"_context": Object {
"app": [Circular],
"components": Object {
"transition": Object {
"name": "transition",
"props": undefined,
"render": [Function],
},
"transition-group": Object {
"name": "transition-group",
"props": undefined,
"render": [Function],
},
},
"config": Object {
"errorHandler": undefined,
"globalProperties": Object {},
"isCustomElement": [Function],
"isNativeTag": [Function],
"optionMergeStrategies": Object {},
"performance": false,
"warnHandler": undefined,
},
"directives": Object {},
"mixins": Array [
Object {
"__emits": null,
"__props": Array [],
"beforeCreate": [Function],
},
],
"provides": Object {},
"reload": [Function],
},
"_props": null,
"_uid": 1,
"component": [Function],
"config": Object {
"errorHandler": undefined,
"globalProperties": Object {},
"isCustomElement": [Function],
"isNativeTag": [Function],
"optionMergeStrategies": Object {},
"performance": false,
"warnHandler": undefined,
},
"directive": [Function],
"mixin": [Function],
"mount": [Function],
"provide": [Function],
"unmount": [Function],
"use": [Function],
"version": "3.0.6",
},
"__setProps": [Function],
"componentVM": Object {
"hasOwnProperty": [Function],
},
"rootVM": Object {},
"wrapperElement": <svg
fill="none"
height="48"
size="48"
stroke="red"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
strokeWidth="4"
viewBox="0 0 24 24"
width="48"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="12"
cy="12"
r="10"
/>
<path
d="M8 14s1.5 2 4 2 4-2 4-2"
/>
<line
x1="9"
x2="9.01"
y1="9"
y2="9"
/>
<line
x1="15"
x2="15.01"
y1="9"
y2="9"
/>
</svg>,
}
`;
exports[`Using lucide icon components should render an component 1`] = `
VueWrapper {
"__app": Object {
"_component": Object {
"__emits": Object {},
"__props": Array [
Object {},
Array [],
],
"name": "VTU_ROOT",
"render": [Function],
},
"_container": <div
data-v-app=""
>
<svg
fill="none"
height="24"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="12"
cy="12"
r="10"
/>
<path
d="M8 14s1.5 2 4 2 4-2 4-2"
/>
<line
x1="9"
x2="9.01"
y1="9"
y2="9"
/>
<line
x1="15"
x2="15.01"
y1="9"
y2="9"
/>
</svg>
</div>,
"_context": Object {
"app": [Circular],
"components": Object {
"transition": Object {
"name": "transition",
"props": undefined,
"render": [Function],
},
"transition-group": Object {
"name": "transition-group",
"props": undefined,
"render": [Function],
},
},
"config": Object {
"errorHandler": undefined,
"globalProperties": Object {},
"isCustomElement": [Function],
"isNativeTag": [Function],
"optionMergeStrategies": Object {},
"performance": false,
"warnHandler": undefined,
},
"directives": Object {},
"mixins": Array [
Object {
"__emits": null,
"__props": Array [],
"beforeCreate": [Function],
},
],
"provides": Object {},
"reload": [Function],
},
"_props": null,
"_uid": 0,
"component": [Function],
"config": Object {
"errorHandler": undefined,
"globalProperties": Object {},
"isCustomElement": [Function],
"isNativeTag": [Function],
"optionMergeStrategies": Object {},
"performance": false,
"warnHandler": undefined,
},
"directive": [Function],
"mixin": [Function],
"mount": [Function],
"provide": [Function],
"unmount": [Function],
"use": [Function],
"version": "3.0.6",
},
"__setProps": [Function],
"componentVM": Object {
"hasOwnProperty": [Function],
},
"rootVM": Object {},
"wrapperElement": <svg
fill="none"
height="24"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="12"
cy="12"
r="10"
/>
<path
d="M8 14s1.5 2 4 2 4-2 4-2"
/>
<line
x1="9"
x2="9.01"
y1="9"
y2="9"
/>
<line
x1="15"
x2="15.01"
y1="9"
y2="9"
/>
</svg>,
}
`;
@@ -0,0 +1,44 @@
import { mount } from '@vue/test-utils'
import { Smile } from '../src/icons'
describe('Using lucide icon components', () => {
it('should render an component', () => {
const wrapper = mount(Smile)
expect(wrapper).toMatchSnapshot();
});
it('should adjust the size, stroke color and stroke width', () => {
const wrapper = mount(Smile, {
propsData: {
size: 48,
stroke: 'red',
strokeWidth: 4
}
})
expect(wrapper).toMatchSnapshot();
});
it('should add a class to the element', () => {
const wrapper = mount(Smile, {
attrs: {
class: "lucide-icon my-icon"
}
})
expect(wrapper).toMatchSnapshot();
expect(String(wrapper.classes())).toBe(String(['lucide-icon', 'my-icon']))
});
it('should add a style attribute to the element', () => {
const wrapper = mount(Smile, {
attrs: {
style: 'position: absolute',
}
})
expect(wrapper).toMatchSnapshot();
expect(wrapper.attributes('style')).toContain('position: absolute')
});
});
File diff suppressed because it is too large Load Diff
+2
View File
@@ -4,6 +4,8 @@ Implementation of the lucide icon library for Vue applications.
> What is lucide? Read it [here](https://github.com/lucide-icons/lucide#what-is-lucide).
> :warning: This version of lucide is for Vue 2, For Vue 3 got to [lucide-vue-next](https://github.com/lucide-icons/lucide/tree/master/packages/lucide-vue-next#lucide-vue-next)
## Installation
```sh
+1 -1
View File
@@ -24,7 +24,7 @@
"build": "yarn clean && yarn build:icons && yarn build:es && yarn build:bundles",
"clean": "rm -rf dist && rm -rf stats && rm -rf ./src/icons/*.js",
"build:icons": "yarn --cwd ../../ build:icons --output=../packages/lucide-vue/src --templateSrc=../packages/lucide-vue/scripts/exportTemplate",
"build:es": "yarn --cwd ../../ babel packages/lucide-vue/src -d packages/lucide-vue/dist/esm",
"build:es": "babel src -d dist/esm",
"build:bundles": "yarn --cwd ../../ rollup -c packages/lucide-vue/rollup.config.js",
"test": "jest",
"test:watch": "jest --watchAll"