kopia lustrzana https://github.com/shoelace-style/shoelace
use plop for npm run create
rodzic
94fe4f1f46
commit
19dba93cca
|
@ -1,3 +1,4 @@
|
||||||
|
*.hbs
|
||||||
*.md
|
*.md
|
||||||
.cache
|
.cache
|
||||||
.github
|
.github
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
- [Tag](/components/tag)
|
- [Tag](/components/tag)
|
||||||
- [Textarea](/components/textarea)
|
- [Textarea](/components/textarea)
|
||||||
- [Tooltip](/components/tooltip)
|
- [Tooltip](/components/tooltip)
|
||||||
|
<!--plop:component-->
|
||||||
|
|
||||||
- Utilities
|
- Utilities
|
||||||
- [Animation](/components/animation)
|
- [Animation](/components/animation)
|
||||||
|
|
Plik diff jest za duży
Load Diff
|
@ -33,7 +33,7 @@
|
||||||
"build": "node scripts/build.js",
|
"build": "node scripts/build.js",
|
||||||
"prepublishOnly": "npm run build && npm run test",
|
"prepublishOnly": "npm run build && npm run test",
|
||||||
"prettier": "prettier --write --loglevel warn .",
|
"prettier": "prettier --write --loglevel warn .",
|
||||||
"create": "node scripts/create-component.js",
|
"create": "plop --plopfile scripts/plop/plopfile.cjs",
|
||||||
"test": "web-test-runner \"src/**/*.test.ts\" --node-resolve --puppeteer",
|
"test": "web-test-runner \"src/**/*.test.ts\" --node-resolve --puppeteer",
|
||||||
"test:watch": "web-test-runner \"src/**/*.test.ts\" --node-resolve --puppeteer --watch"
|
"test:watch": "web-test-runner \"src/**/*.test.ts\" --node-resolve --puppeteer --watch"
|
||||||
},
|
},
|
||||||
|
@ -66,6 +66,7 @@
|
||||||
"front-matter": "^4.0.2",
|
"front-matter": "^4.0.2",
|
||||||
"get-port": "^5.1.1",
|
"get-port": "^5.1.1",
|
||||||
"husky": "^4.3.8",
|
"husky": "^4.3.8",
|
||||||
|
"plop": "^2.7.4",
|
||||||
"prettier": "^2.2.1",
|
"prettier": "^2.2.1",
|
||||||
"recursive-copy": "^2.0.11",
|
"recursive-copy": "^2.0.11",
|
||||||
"sass": "^1.32.7",
|
"sass": "^1.32.7",
|
||||||
|
|
|
@ -1,153 +0,0 @@
|
||||||
import chalk from 'chalk';
|
|
||||||
import fs from 'fs';
|
|
||||||
import mkdirp from 'mkdirp';
|
|
||||||
import path from 'path';
|
|
||||||
import process from 'process';
|
|
||||||
|
|
||||||
const args = process.argv.slice(2);
|
|
||||||
const tagName = (args[0] + '').toLowerCase().trim();
|
|
||||||
const tagNameWithoutPrefix = tagName.replace(/^sl-/, '');
|
|
||||||
const className = tagName.replace(/(^\w|-\w)/g, string => string.replace(/-/, '').toUpperCase());
|
|
||||||
const readableName = tagNameWithoutPrefix
|
|
||||||
.replace(/-/g, ' ')
|
|
||||||
.replace(/\w\S*/g, string => string.charAt(0).toUpperCase() + string.substr(1).toLowerCase());
|
|
||||||
|
|
||||||
const packageData = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
|
|
||||||
const minorVersion = packageData.version.split('.').slice(0, 2).join('.');
|
|
||||||
|
|
||||||
// Check for tag name
|
|
||||||
if (!tagName) {
|
|
||||||
console.error('Please provide a tag name for the new component.\n');
|
|
||||||
process.exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify tag name prefix
|
|
||||||
if (!/^sl-/.test(tagName)) {
|
|
||||||
console.error('Tag names must start with the sl- prefix.\n');
|
|
||||||
process.exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate a source file
|
|
||||||
const componentFile = `src/components/${tagNameWithoutPrefix}/${tagNameWithoutPrefix}.ts`;
|
|
||||||
if (fs.existsSync(componentFile)) {
|
|
||||||
console.error(`There is already a component using the <${tagName}> tag!\n`);
|
|
||||||
process.exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
const componentSource = `
|
|
||||||
import { LitElement, html, unsafeCSS } from 'lit';
|
|
||||||
import { customElement } from 'lit/decorators.js';
|
|
||||||
import styles from 'sass:./${tagNameWithoutPrefix}.scss';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @since ${minorVersion}
|
|
||||||
* @status experimental
|
|
||||||
*
|
|
||||||
* @dependency sl-tag-here
|
|
||||||
* @dependency sl-tag-here
|
|
||||||
*
|
|
||||||
* @slot - The default slot.
|
|
||||||
* @slot example - A named slot called example.
|
|
||||||
*
|
|
||||||
* @part base - The component's base wrapper.
|
|
||||||
*
|
|
||||||
* @customProperty example - An example custom property
|
|
||||||
*
|
|
||||||
* @animation example.show - An example animation.
|
|
||||||
* @animation example.hide - An example animation.
|
|
||||||
*/
|
|
||||||
@customElement('${tagName}')
|
|
||||||
export default class ${className} extends LitElement {
|
|
||||||
static styles = unsafeCSS(styles);
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return html\`
|
|
||||||
<div part="base">
|
|
||||||
<slot></slot>
|
|
||||||
</div>
|
|
||||||
\`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
'${tagName}': ${className};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`.trimLeft();
|
|
||||||
|
|
||||||
// Generate a stylesheet
|
|
||||||
const stylesFile = `src/components/${tagNameWithoutPrefix}/${tagNameWithoutPrefix}.scss`;
|
|
||||||
const stylesSource = `
|
|
||||||
@use '../../styles/component';
|
|
||||||
|
|
||||||
:host {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
`.trimLeft();
|
|
||||||
|
|
||||||
// Generate a docs page
|
|
||||||
const docsFile = `docs/components/${tagNameWithoutPrefix}.md`;
|
|
||||||
const docsSource = `
|
|
||||||
# ${readableName}
|
|
||||||
|
|
||||||
[component-header:${tagName}]
|
|
||||||
|
|
||||||
Brief description of the component here, followed by an example.
|
|
||||||
|
|
||||||
\`\`\`html preview
|
|
||||||
<${tagName}>
|
|
||||||
Hello, world!
|
|
||||||
</${tagName}>
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
### Variation
|
|
||||||
|
|
||||||
A description of the variation, followed by an example.
|
|
||||||
|
|
||||||
\`\`\`html preview
|
|
||||||
<${tagName}>
|
|
||||||
Here is a variation
|
|
||||||
</${tagName}>
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
[component-metadata:${tagName}]
|
|
||||||
`.trimLeft();
|
|
||||||
|
|
||||||
// Create the files
|
|
||||||
mkdirp.sync(path.dirname(componentFile));
|
|
||||||
mkdirp.sync(path.dirname(stylesFile));
|
|
||||||
mkdirp.sync(path.dirname(docsFile));
|
|
||||||
|
|
||||||
fs.writeFileSync(componentFile, componentSource, 'utf8');
|
|
||||||
fs.writeFileSync(stylesFile, stylesSource, 'utf8');
|
|
||||||
fs.writeFileSync(docsFile, docsSource, 'utf8');
|
|
||||||
|
|
||||||
// Add it to shoelace.ts
|
|
||||||
const allExports = fs.readFileSync('src/shoelace.ts', 'utf8');
|
|
||||||
fs.writeFileSync(
|
|
||||||
'src/shoelace.ts',
|
|
||||||
`${allExports.trimRight()}\nexport { default as ${className} } from './components/${tagNameWithoutPrefix}/${tagNameWithoutPrefix}';\n`,
|
|
||||||
'utf8'
|
|
||||||
);
|
|
||||||
|
|
||||||
// Add it to _sidebar.md
|
|
||||||
const sidebar = fs.readFileSync('docs/_sidebar.md', 'utf8');
|
|
||||||
fs.writeFileSync(
|
|
||||||
'docs/_sidebar.md',
|
|
||||||
sidebar.replace('- Components', `- Components\n - [${readableName}](/components/${tagNameWithoutPrefix}.md)`),
|
|
||||||
'utf8'
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log(chalk.green(`The <${tagName}> component has been created:`));
|
|
||||||
console.log(`
|
|
||||||
- created ${componentFile}
|
|
||||||
- created ${stylesFile}
|
|
||||||
- created ${docsFile}
|
|
||||||
- updated src/shoelace.ts
|
|
||||||
- updated docs/_sidebar.md
|
|
||||||
|
|
||||||
Use ${chalk.cyan('npm start')} to launch the dev server.
|
|
||||||
`);
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
module.exports = function (plop) {
|
||||||
|
plop.setHelper('tagWithoutPrefix', tag => tag.replace(/^sl-/, ''));
|
||||||
|
|
||||||
|
plop.setHelper('tagToTitle', tag => {
|
||||||
|
const withoutPrefix = plop.getHelper('tagWithoutPrefix');
|
||||||
|
const titleCase = plop.getHelper('titleCase');
|
||||||
|
return titleCase(withoutPrefix(tag));
|
||||||
|
});
|
||||||
|
|
||||||
|
plop.setGenerator('component', {
|
||||||
|
description: 'Generate a new component',
|
||||||
|
prompts: [
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
name: 'tag',
|
||||||
|
message: 'Tag name? (e.g. sl-button)',
|
||||||
|
validate: value => {
|
||||||
|
// Start with sl- and include only a-z + dashes
|
||||||
|
if (!/^sl-[a-z-+]+/.test(value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No double dashes or ending dash
|
||||||
|
if (value.includes('--') || value.endsWith('-')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'add',
|
||||||
|
path: '../../src/components/{{ tagWithoutPrefix tag }}/{{ tagWithoutPrefix tag }}.ts',
|
||||||
|
templateFile: 'templates/component/component.hbs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'add',
|
||||||
|
path: '../../src/components/{{ tagWithoutPrefix tag }}/{{ tagWithoutPrefix tag }}.scss',
|
||||||
|
templateFile: 'templates/component/styles.hbs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'add',
|
||||||
|
path: '../../src/components/{{ tagWithoutPrefix tag }}/{{ tagWithoutPrefix tag }}.test.ts',
|
||||||
|
templateFile: 'templates/component/tests.hbs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'add',
|
||||||
|
path: '../../docs/components/{{ tagWithoutPrefix tag }}.md',
|
||||||
|
templateFile: 'templates/component/docs.hbs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'modify',
|
||||||
|
path: '../../docs/_sidebar.md',
|
||||||
|
pattern: /<!--plop:component-->/,
|
||||||
|
template: `- [{{ tagToTitle tag }}](/components/{{ tagWithoutPrefix tag }})\n <!--plop:component-->`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'modify',
|
||||||
|
path: '../../src/shoelace.ts',
|
||||||
|
pattern: /\/\* plop:component \*\//,
|
||||||
|
template: `export { default as {{ properCase tag }} } from './components/{{ tagWithoutPrefix tag }}/{{ tagWithoutPrefix tag }}';\n/* plop:component */`
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { LitElement, html, unsafeCSS } from 'lit';
|
||||||
|
import { customElement, property } from 'lit/decorators.js';
|
||||||
|
import { event, EventEmitter } from '../../internal/decorators';
|
||||||
|
import styles from 'sass:./{{ tagWithoutPrefix tag }}.scss';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 2.0
|
||||||
|
* @status experimental
|
||||||
|
*
|
||||||
|
* @dependency sl-example
|
||||||
|
*
|
||||||
|
* @slot - The default slot.
|
||||||
|
* @slot example - An example slot.
|
||||||
|
*
|
||||||
|
* @part base - The component's base wrapper.
|
||||||
|
*/
|
||||||
|
@customElement('{{ tag }}')
|
||||||
|
export default class {{ properCase tag }} extends LitElement {
|
||||||
|
static styles = unsafeCSS(styles);
|
||||||
|
|
||||||
|
/** An example property. */
|
||||||
|
@property() prop = 'example';
|
||||||
|
|
||||||
|
/** An example event. */
|
||||||
|
@event('sl-event') slEvent: EventEmitter<void>;
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html` <slot></slot> `;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'{{ tag }}': {{ properCase tag }};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
# {{ tagToTitle tag }}
|
||||||
|
|
||||||
|
[component-header:{{ tag }}]
|
||||||
|
|
||||||
|
A description of the component goes here.
|
||||||
|
|
||||||
|
```html preview
|
||||||
|
<{{ tag }}></{{ tag }}>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### First Example
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
### Second Example
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
[component-metadata:{{ tag }}]
|
|
@ -0,0 +1 @@
|
||||||
|
@use '../../styles/component';
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { expect, fixture, html, waitUntil } from '@open-wc/testing';
|
||||||
|
// import sinon from 'sinon';
|
||||||
|
|
||||||
|
import '../../../dist/shoelace.js';
|
||||||
|
import type {{ properCase tag }} from './{{ tagWithoutPrefix tag }}';
|
||||||
|
|
||||||
|
describe('<{{ tag }}>', () => {
|
||||||
|
it('should render a component', async () => {
|
||||||
|
const el = await fixture(html` <{{ tag }}></{{ tag }}> `);
|
||||||
|
|
||||||
|
expect(el).to.exist;
|
||||||
|
});
|
||||||
|
});
|
|
@ -45,6 +45,7 @@ export { default as SlTabPanel } from './components/tab-panel/tab-panel';
|
||||||
export { default as SlTag } from './components/tag/tag';
|
export { default as SlTag } from './components/tag/tag';
|
||||||
export { default as SlTextarea } from './components/textarea/textarea';
|
export { default as SlTextarea } from './components/textarea/textarea';
|
||||||
export { default as SlTooltip } from './components/tooltip/tooltip';
|
export { default as SlTooltip } from './components/tooltip/tooltip';
|
||||||
|
/* plop:component */
|
||||||
|
|
||||||
// Utilities
|
// Utilities
|
||||||
export * from './utilities/animation';
|
export * from './utilities/animation';
|
||||||
|
|
Ładowanie…
Reference in New Issue