├── .babelrc
├── .eslintrc.cjs
├── .github
└── workflows
│ ├── check-lint-package.yml
│ ├── chromatic.yml
│ └── interactions.yml
├── .gitignore
├── .husky
├── .gitignore
└── pre-commit
├── .storybook
├── Introduction.stories.mdx
├── assets
│ ├── code-brackets.svg
│ ├── colors.svg
│ ├── comments.svg
│ ├── direction.svg
│ ├── flow.svg
│ ├── plugin.svg
│ ├── repo.svg
│ └── stackalt.svg
├── main.js
├── package.json
├── preview-head.html
└── preview.js
├── .vscode
└── extensions.json
├── CODE-OF-CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── cypress.json
├── cypress
├── integration
│ └── First.spec.js
├── plugins
│ └── index.cjs
└── support
│ ├── commands.js
│ └── index.js
├── package.json
├── pnpm-lock.yaml
├── renovate.json
├── src
├── app.d.ts
├── app.html
├── lib
│ ├── first
│ │ ├── First.stories.svelte
│ │ └── First.svelte
│ └── index.js
└── routes
│ └── index.svelte
├── svelte.config.js
└── tsconfig.json
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [["@babel/preset-env", { "targets": { "node": "current" } }]]
3 | }
4 |
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | browser: true,
4 | 'cypress/globals': true,
5 | es2017: true,
6 | node: true,
7 | },
8 | extends: ['eslint:recommended', 'prettier'],
9 | ignorePatterns: ['*.cjs'],
10 | overrides: [
11 | {
12 | extends: ['plugin:@typescript-eslint/recommended'],
13 | files: ['*.svelte'],
14 | processor: 'svelte3/svelte3',
15 | },
16 | {
17 | extends: ['plugin:cypress/recommended'],
18 | files: ['./cypress/plugins/index.js', '*.spec.*'],
19 | },
20 | {
21 | extends: ['plugin:@typescript-eslint/recommended'],
22 | files: ['*.ts'],
23 | },
24 | ],
25 | parser: '@typescript-eslint/parser',
26 | parserOptions: {
27 | ecmaVersion: 2019,
28 | sourceType: 'module',
29 | },
30 | plugins: ['svelte3', '@typescript-eslint', 'cypress'],
31 | root: true,
32 | settings: {
33 | 'svelte3/typescript': () => require('typescript'),
34 | },
35 | };
36 |
--------------------------------------------------------------------------------
/.github/workflows/check-lint-package.yml:
--------------------------------------------------------------------------------
1 | name: Check, Lint & Package
2 |
3 | on:
4 | push:
5 | branches: [main]
6 | pull_request:
7 | branches: [main]
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 |
13 | strategy:
14 | matrix:
15 | node-version: ['lts/*']
16 |
17 | steps:
18 | - name: Checkout
19 | uses: actions/checkout@v3
20 |
21 | - name: Cache pnpm modules
22 | uses: actions/cache@v3
23 | with:
24 | path: ~/.pnpm-store
25 | key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
26 | restore-keys: |
27 | ${{ runner.os }}-
28 |
29 | - name: Install dependencies
30 | uses: pnpm/action-setup@v2.2.2
31 | with:
32 | version: ^6.0.0
33 | run_install: true
34 |
35 | - name: Use Node.js ${{ matrix.node-version }}
36 | uses: actions/setup-node@v3
37 | with:
38 | node-version: ${{ matrix.node-version }}
39 | - run: pnpm check
40 | - run: pnpm lint
41 | - run: pnpm package
42 |
--------------------------------------------------------------------------------
/.github/workflows/chromatic.yml:
--------------------------------------------------------------------------------
1 | name: Snapshot Tests
2 |
3 | on:
4 | push:
5 | branches: [main]
6 | pull_request:
7 | branches: [main]
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - name: Checkout
15 | uses: actions/checkout@v3
16 | with:
17 | fetch-depth: 0
18 |
19 | - name: Cache pnpm modules
20 | uses: actions/cache@v3
21 | with:
22 | path: ~/.pnpm-store
23 | key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
24 | restore-keys: |
25 | ${{ runner.os }}-
26 |
27 | - name: Install dependencies
28 | uses: pnpm/action-setup@v2.2.2
29 | with:
30 | version: ^6.0.0
31 | run_install: true
32 |
33 | - name: Publish to Chromatic
34 | uses: chromaui/action@v1
35 | with:
36 | projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
37 |
--------------------------------------------------------------------------------
/.github/workflows/interactions.yml:
--------------------------------------------------------------------------------
1 | name: Interaction Tests
2 |
3 | on:
4 | push:
5 | branches: [main]
6 | pull_request:
7 | branches: [main]
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 |
13 | strategy:
14 | matrix:
15 | node-version: ['lts/*']
16 |
17 | steps:
18 | - name: Checkout
19 | uses: actions/checkout@v3
20 |
21 | - name: Cache pnpm modules
22 | uses: actions/cache@v3
23 | with:
24 | path: ~/.pnpm-store
25 | key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
26 | restore-keys: |
27 | ${{ runner.os }}-
28 |
29 | - name: Install dependencies
30 | uses: pnpm/action-setup@v2.2.2
31 | with:
32 | version: ^6.0.0
33 | run_install: true
34 |
35 | - name: Use Node.js ${{ matrix.node-version }}
36 | uses: actions/setup-node@v3
37 | with:
38 | node-version: ${{ matrix.node-version }}
39 | - run: pnpm test
40 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.log
3 | /.svelte-kit
4 | /build
5 | /package
6 | cypress/screenshots
7 | cypress/videos
8 | node_modules
9 | storybook-static
--------------------------------------------------------------------------------
/.husky/.gitignore:
--------------------------------------------------------------------------------
1 | _
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | npx lint-staged
5 |
--------------------------------------------------------------------------------
/.storybook/Introduction.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta } from '@storybook/addon-docs';
2 | import Code from './assets/code-brackets.svg';
3 | import Colors from './assets/colors.svg';
4 | import Comments from './assets/comments.svg';
5 | import Direction from './assets/direction.svg';
6 | import Flow from './assets/flow.svg';
7 | import Plugin from './assets/plugin.svg';
8 | import Repo from './assets/repo.svg';
9 | import StackAlt from './assets/stackalt.svg';
10 |
11 |
12 |
13 |
116 |
117 | # Welcome to Storybook
118 |
119 | Storybook helps you build UI components in isolation from your app's business logic, data, and context.
120 | That makes it easy to develop hard-to-reach states. Save these UI states as **stories** to revisit during development, testing, or QA.
121 |
122 | Browse example stories now by navigating to them in the sidebar.
123 | View their code in the `src/stories` directory to learn how they work.
124 | We recommend building UIs with a [**component-driven**](https://componentdriven.org) process starting with atomic components and ending with pages.
125 |
126 |
Configure
127 |
128 |
174 |
175 | Learn
176 |
177 |
223 |
224 |
225 | TipEdit the Markdown in{' '}
226 | .storybook/Introduction.stories.mdx
227 |
228 |
--------------------------------------------------------------------------------
/.storybook/assets/code-brackets.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.storybook/assets/colors.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.storybook/assets/comments.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.storybook/assets/direction.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.storybook/assets/flow.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.storybook/assets/plugin.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.storybook/assets/repo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.storybook/assets/stackalt.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.storybook/main.js:
--------------------------------------------------------------------------------
1 | const preprocess = require('svelte-preprocess');
2 |
3 | module.exports = {
4 | stories: [
5 | './**/*.stories.mdx',
6 | '../src/**/*.stories.@(js|jsx|ts|tsx|svelte|mdx)',
7 | ],
8 | addons: [
9 | '@storybook/addon-links',
10 | '@storybook/addon-essentials',
11 | '@storybook/addon-svelte-csf',
12 | ],
13 | svelteOptions: {
14 | preprocess: preprocess(),
15 | },
16 | };
17 |
--------------------------------------------------------------------------------
/.storybook/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "commonjs"
3 | }
4 |
--------------------------------------------------------------------------------
/.storybook/preview-head.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
13 |
--------------------------------------------------------------------------------
/.storybook/preview.js:
--------------------------------------------------------------------------------
1 | export const parameters = {
2 | actions: { argTypesRegex: '^on[A-Z].*' },
3 | controls: {
4 | matchers: {
5 | color: /(background|color)$/i,
6 | date: /Date$/,
7 | },
8 | },
9 | };
10 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "svelte.svelte-vscode",
4 | "esbenp.prettier-vscode",
5 | "dbaeumer.vscode-eslint",
6 | "editorconfig.editorconfig",
7 | "knisterpeter.vscode-commitizen"
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/CODE-OF-CONDUCT.md:
--------------------------------------------------------------------------------
1 | Need help writing a `CODE-OF-CONDUCT`? Try [HERE](https://www.contributor-covenant.org/).
2 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Need help writing a `CONTRIBUTING` guideline? Try [HERE](https://gist.github.com/PurpleBooth/b24679402957c63ec426).
2 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Need help choosing an open-source license? Try [HERE](https://choosealicense.com/).
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Svelte 3 Component Template
2 |
3 | ## A highly-opinionated base for building shareable Svelte 3 components
4 |
5 | [](https://github.com/YogliB/svelte-component-template/actions?query=workflow%3A%22Node+CI%22)
6 | [](https://snyk.io/test/github/YogliB/svelte-component-template)
7 | [](https://renovatebot.com/)
8 | [](http://makeapullrequest.com)
9 |
10 | ## Table of Contents
11 |
12 | 1. [Features](#features)
13 | 1. [Getting started](#getting-started)
14 | 1. [Developing](#developing)
15 | 1. [Preprocessors](#preprocessors)
16 | 1. [Testing](#testing)
17 | 1. [Publishing to npm](#publishing-to-npm)
18 | 1. [Frequently Asked Questions](#frequently-asked-questions)
19 |
20 | ## Features
21 |
22 | - [Preprocessing](https://github.com/sveltejs/svelte-preprocess/blob/main/README.md)
23 | - [Formating](https://github.com/sveltejs/prettier-plugin-svelte)
24 | - [Linting](https://github.com/sveltejs/eslint-plugin-svelte3)
25 | - [Storybook](https://storybook.js.org/docs/svelte/get-started/introduction)
26 | - [Testing](https://storybook.js.org/docs/svelte/workflows/testing-with-storybook)
27 |
28 | ## Getting Started
29 |
30 | 1. Clone the template:
31 |
32 | Option #1: Clone it with Github's "Use this template" option:
33 |
34 | [](https://github.com/YogliB/svelte-component-template/generate)
35 |
36 | Option #2: Clone this repository with [degit](https://github.com/Rich-Harris/degit):
37 |
38 | ```bash
39 | npx degit YogliB/svelte-component-template `my-new-component`
40 | ```
41 |
42 | 2. Enter the folder:
43 |
44 | ```bash
45 | cd my-new-component
46 | ```
47 |
48 | 2. Initiate [Git](https://git-scm.com/):
49 |
50 | ```bash
51 | git init
52 | ```
53 |
54 | 3. Install dependencies:
55 |
56 | ```bash
57 | npm install
58 | ```
59 |
60 | 3. Configure `package.json`:
61 |
62 | ```bash
63 | npm init
64 | ```
65 |
66 | 4. Start coding:
67 |
68 | ```bash
69 | code .
70 | ```
71 |
72 | - Your component's source code lives in `src/lib/[MyComponent]/[MyComponent].svelte`.
73 |
74 | ## Developing
75 |
76 | 1. Start [SvelteKit](https://kit.svelte.dev/):
77 |
78 | ```bash
79 | npm run dev
80 | ```
81 |
82 | 2. Edit a component file in `src/lib`, save it and watch the magic happens.
83 |
84 | 3. Export your components in `src/lib/index.js`.
85 |
86 | 4. Import your components in `src/routes/index.svelte` from `$lib$, so you can preview and test it.
87 |
88 | 5. Navigate to [localhost:3000](http://localhost:3000) to see your components live.
89 |
90 | ## Preprocessors
91 |
92 | All preprocessing is handled with [svelte-preprocess](https://github.com/sveltejs/svelte-preprocess).
93 | Configure it in [`svelte.config.js`](https://kit.svelte.dev/docs#configuration).
94 |
95 | ## Testing
96 |
97 | ### Interaction testing
98 |
99 | This is a simple and intuitive method that can be done through Storybook, with the help of [Cypress](https://cypress.io).
100 | And example and pre-made test scripts can be found in this repository, and more info can be found in [Storybook's docs](https://storybook.js.org/docs/svelte/workflows/interaction-testing).
101 |
102 | ### Snapshot testing
103 |
104 | In this repo you'll find a [basic workflow](.github/chromatic.yml) that uses [Chromatic](https://www.chromatic.com/) for snapshot testing.
105 |
106 | ## Frequently Asked Questions
107 |
108 | ### What's the `index.js` file for?
109 |
110 | It's for Svelte to be able to import multiple components from a single source.
111 |
112 | For instance, it lets the user do:
113 |
114 | ```javascript
115 | import { MyComponent, MyOtherComponent } from 'my-component-library';
116 | ```
117 |
118 | Instead of:
119 |
120 | ```javascript
121 | import MyComponent from 'my-component-library/components/MyComponent.svelte';
122 | import MyOtherComponent from 'my-component-library/components/MyOtherComponent';
123 | ```
124 |
125 | ### How do I include 3'rd party css in my components?
126 |
127 | There are a few options to do this:
128 |
129 | 1. Don't include 3'rd party css and just tell your users to do that (Probably using PostCSS).
130 | 2. Include it via a cdn, like so:
131 |
132 | ```css
133 | @import url('https://unpkg.com/@scope/package/main.min.css');
134 | ```
135 |
136 | ## Publishing to [npm](https://www.npmjs.com)
137 |
138 | 1. Prepare the package for publishing:
139 |
140 | ```bash
141 | npm run package
142 | ```
143 |
144 | 2. Publish the package:
145 |
146 | ```bash
147 | cd package
148 | npm run publish
149 | ```
150 |
151 | - [Creating and publishing scoped public packages](https://docs.npmjs.com/creating-and-publishing-scoped-public-packages)
152 | - [Creating and publishing unscoped public packages](https://docs.npmjs.com/creating-and-publishing-unscoped-public-packages)
153 |
--------------------------------------------------------------------------------
/cypress.json:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/cypress/integration/First.spec.js:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | describe('First Component', () => {
5 | it('should respond to click on text by resetting', () => {
6 | cy.visit('http://localhost:6006/iframe.html?id=components-first--jane');
7 | cy.findByText('Hello Jane!').should('be.visible').dblclick();
8 | cy.findByText('Hello World!').should('be.visible');
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/cypress/plugins/index.cjs:
--------------------------------------------------------------------------------
1 | ///
2 | // ***********************************************************
3 | // This example plugins/index.js can be used to load plugins
4 | //
5 | // You can change the location of this file or turn off loading
6 | // the plugins file with the 'pluginsFile' configuration option.
7 | //
8 | // You can read more here:
9 | // https://on.cypress.io/plugins-guide
10 | // ***********************************************************
11 |
12 | // This function is called when a project is opened or re-opened (e.g. due to
13 | // the project's config changing)
14 |
15 | /**
16 | * @type {Cypress.PluginConfig}
17 | */
18 | // eslint-disable-next-line @typescript-eslint/no-unused-vars
19 | module.exports = (on, config) => {
20 | // `on` is used to hook into various events Cypress emits
21 | // `config` is the resolved Cypress config
22 | };
23 |
--------------------------------------------------------------------------------
/cypress/support/commands.js:
--------------------------------------------------------------------------------
1 | import '@testing-library/cypress/add-commands';
2 |
--------------------------------------------------------------------------------
/cypress/support/index.js:
--------------------------------------------------------------------------------
1 | import './commands';
2 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "author": {
3 | "email": "~TODO~",
4 | "name": "~TODO~",
5 | "url": "~TODO~"
6 | },
7 | "devDependencies": {
8 | "@babel/core": "7.18.9",
9 | "@babel/preset-env": "7.18.9",
10 | "@storybook/addon-actions": "6.5.9",
11 | "@storybook/addon-essentials": "6.5.9",
12 | "@storybook/addon-links": "6.5.9",
13 | "@storybook/addon-storyshots": "6.5.9",
14 | "@storybook/addon-svelte-csf": "2.0.6",
15 | "@storybook/svelte": "6.5.9",
16 | "@sveltejs/kit": "next",
17 | "@testing-library/cypress": "8.0.3",
18 | "@typescript-eslint/eslint-plugin": "5.31.0",
19 | "@typescript-eslint/parser": "5.31.0",
20 | "babel-loader": "8.2.5",
21 | "chromatic": "6.7.1",
22 | "cypress": "9.7.0",
23 | "eslint": "8.20.0",
24 | "eslint-config-prettier": "8.5.0",
25 | "eslint-plugin-cypress": "2.12.1",
26 | "eslint-plugin-svelte3": "4.0.0",
27 | "husky": "8.0.1",
28 | "lint-staged": "13.0.3",
29 | "prettier": "2.7.1",
30 | "prettier-plugin-svelte": "2.7.0",
31 | "start-server-and-test": "1.14.0",
32 | "svelte": "3.49.0",
33 | "svelte-check": "2.8.0",
34 | "svelte-loader": "3.1.3",
35 | "svelte-preprocess": "4.10.7",
36 | "svelte2tsx": "0.5.12",
37 | "tslib": "2.4.0",
38 | "typescript": "4.7.4"
39 | },
40 | "homepage": "~TODO~",
41 | "license": "~TODO~",
42 | "lint-staged": {
43 | "*.{js, ts, svelte}": [
44 | "eslint --fix"
45 | ],
46 | "*.{svelte, html, css, scss, stylus, js, ts, json, yml, yaml, md}": [
47 | "prettier --write --plugin-search-dir=."
48 | ]
49 | },
50 | "name": "~TODO~",
51 | "prettier": {
52 | "singleQuote": true,
53 | "tabWidth": 4,
54 | "useTabs": true
55 | },
56 | "repository": {
57 | "type": "git",
58 | "url": "~TODO~"
59 | },
60 | "scripts": {
61 | "build": "svelte-kit build",
62 | "build-storybook": "build-storybook",
63 | "check": "svelte-check --tsconfig ./tsconfig.json",
64 | "check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
65 | "chromatic": "chromatic --exit-zero-on-changes",
66 | "cy:open": "cypress open",
67 | "cy:run": "cypress run",
68 | "dev": "svelte-kit dev",
69 | "format": "prettier --ignore-path .gitignore --write --plugin-search-dir=. .",
70 | "lint": "eslint --ignore-path .gitignore .",
71 | "package": "svelte-kit package",
72 | "prepare": "svelte-kit sync",
73 | "preview": "svelte-kit preview",
74 | "storybook": "start-storybook -p 6006",
75 | "test": "start-server-and-test storybook http://localhost:6006 cy:run"
76 | },
77 | "type": "module",
78 | "version": "0.0.1"
79 | }
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["config:base"],
3 | "automerge": true
4 | }
5 |
--------------------------------------------------------------------------------
/src/app.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | // See https://kit.svelte.dev/docs/types#the-app-namespace
4 | // for information about these interfaces
5 | declare namespace App {
6 | // interface Locals {}
7 | // interface Platform {}
8 | // interface Session {}
9 | // interface Stuff {}
10 | }
11 |
--------------------------------------------------------------------------------
/src/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | %svelte.head%
7 |
8 |
9 | %svelte.body%
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/first/First.stories.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
15 |
16 |
17 |
18 |
19 |
20 |
27 |
28 |
35 |
36 |
43 |
--------------------------------------------------------------------------------
/src/lib/first/First.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 | Hello {name}!
12 |
13 |
22 |
--------------------------------------------------------------------------------
/src/lib/index.js:
--------------------------------------------------------------------------------
1 | import { default as First } from './first/First.svelte';
2 |
3 | export { First };
4 |
--------------------------------------------------------------------------------
/src/routes/index.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/svelte.config.js:
--------------------------------------------------------------------------------
1 | import preprocess from 'svelte-preprocess';
2 |
3 | /** @type {import('@sveltejs/kit').Config} */
4 | const config = {
5 | // Consult https://github.com/sveltejs/svelte-preprocess
6 | // for more information about preprocessors
7 | preprocess: preprocess(),
8 |
9 | kit: {
10 | package: {
11 | files(filepath) {
12 | return !filepath.endsWith('.stories.svelte');
13 | },
14 | },
15 | },
16 | };
17 |
18 | export default config;
19 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./.svelte-kit/tsconfig.json"
3 | }
--------------------------------------------------------------------------------