Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
"loose": true,
"modules": false
}
]
]
],
"@babel/preset-react"
],
"plugins": ["inline-react-svg"]
}
7 changes: 6 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"node": true,
"es2021": true
},
"extends": ["eslint:recommended"],
"extends": ["eslint:recommended", "plugin:react/recommended"],
"overrides": [
{
"files": ["*.mjs"],
Expand Down Expand Up @@ -56,5 +56,10 @@
}
],
"simple-import-sort/exports": "error"
},
"settings": {
"react": {
"version": "detect"
}
}
}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@ npm-debug.log
*.iml

# Build files
storybook-static/
/exampleFunction.mjs
/exampleStyles.css
/ExampleComponent.mjs
6 changes: 5 additions & 1 deletion .jest-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,9 @@
"moduleFileExtensions": ["js", "json", "mjs"],
"modulePaths": ["<rootDir>/node_modules", "<rootDir>/src"],
"setupFilesAfterEnv": ["<rootDir>/test/setup.mjs"],
"testMatch": ["**/*.test.mjs"]
"testEnvironment": "jsdom",
"testMatch": ["**/*.test.mjs"],
"transform": {
"^.+\\.m?js$": "babel-jest"
}
}
15 changes: 15 additions & 0 deletions .postcssrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use strict';

const autoprefixer = require('autoprefixer');
const cssnano = require('cssnano');

module.exports = {
plugins: [
autoprefixer({
cascade: false,
}),
cssnano({
preset: 'default',
}),
],
};
18 changes: 18 additions & 0 deletions .storybook/main.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export default {
addons: ['@storybook/addon-docs', 'storybook-dark-mode'],
framework: {
name: '@storybook/react-webpack5',
options: {},
},
stories: ['../!(node_modules)/**/*.stories.mdx'],
webpackFinal: async (config) => {
config.module.rules.map((rule) => {
if (!rule.type || rule.type !== 'asset/source') {
// ? Ensure any loaders are not run on any 'raw' file imports
rule.resourceQuery = { not: [/raw/] };
}
return rule;
});
return config;
},
};
5 changes: 5 additions & 0 deletions .storybook/manager.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { addons } from '@storybook/addons';

addons.setConfig({
showPanel: false,
});
8 changes: 8 additions & 0 deletions .storybook/preview.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const parameters = {
docs: {
source: {
state: 'open',
},
},
viewMode: 'docs',
};
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# template-esm
# template-esm-react

Quickly setup ESM repositories with preconfigured functionality.
Quickly setup ESM React repositories with preconfigured functionality.

## Installation

Expand All @@ -19,12 +19,21 @@ When adding source files, remember to add the build output file details to the `
`npm run prepare` runs all preparation clean & build scripts:

- `npm run prepare:clean` removes any files as specified in the `files` fields of [package.json](package.json)
- `npm run prepare:css` compiles SCSS files from `src` into CSS files in the root directory with [PostCSS](https://github.com/postcss/postcss) & [Sass](https://github.com/sass/sass)
- `npm run prepare:js` compiles JavaScript source files into the root directory files with [Babel](https://github.com/babel/babel)

_Note: the ["prepare" Life Cycle Script](https://docs.npmjs.com/cli/using-npm/scripts) runs automatically during `publish`, `pack` and on local `install`._

</details>

<details>
<summary>Storybook</summary>

- `npm run storybook` will run Storybook for local use
- `npm run storybook:build` will build Storybook to `./storybook-static` for deployment use

</details>

<details>
<summary>Testing</summary>

Expand Down
63 changes: 49 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
{
"name": "template-esm",
"version": "1.0.1",
"description": "Quickly setup ESM repositories with preconfigured functionality.",
"name": "template-esm-react",
"version": "0.0.0",
"description": "Quickly setup ESM React repositories with preconfigured functionality.",
"keywords": [
"react",
"babel",
"postcss",
"eslint",
"jest",
"scss",
"prettier",
"storybook",
"cleanup",
"esm",
"husky",
Expand All @@ -20,9 +24,9 @@
],
"license": "MIT",
"author": "Matthew Nuthall",
"repository": "github:idesigncode/template-esm",
"bugs": "https://github.com/idesigncode/template-esm/issues",
"homepage": "https://github.com/idesigncode/template-esm#readme",
"repository": "github:idesigncode/template-esm-react",
"bugs": "https://github.com/idesigncode/template-esm-react/issues",
"homepage": "https://github.com/idesigncode/template-esm-react#readme",
"engines": {
"node": ">= 18.0.0",
"npm": ">= 9.0.0"
Expand All @@ -34,34 +38,65 @@
"scripts": {
"eslint": "eslint . --ext .js,.cjs,.mjs --fix --ignore-path .gitignore",
"postprepare": "node .npm-postprepare.cjs",
"prepare": "npm run prepare:clean && npm run prepare:js && husky install",
"prepare": "npm run prepare:clean && npm run prepare:css && npm run prepare:js && husky install",
"prepare:clean": "node .npm-prepare-clean.cjs",
"prepare:css": "sass --no-source-map src:. && postcss *.css -d .",
"prepare:js": "babel src --out-dir . --ignore **/*.test.mjs,**/*.stories.mjs --keep-file-extension",
"prepublishOnly": "npm run test",
"prettier": "prettier --write . --ignore-path .gitignore",
"storybook": "npm run prepare:css && storybook dev --ci -p 6006",
"storybook:build": "npm run prepare:css && storybook build --quiet --docs",
"test": "npm run test:prettier && npm run test:eslint && npm run test:jest",
"test:eslint": "eslint . --ext .js,.cjs,.mjs --ignore-path .gitignore",
"test:jest": "NODE_OPTIONS=--experimental-vm-modules jest --config .jest-config.json",
"test:prettier": "prettier --check . --ignore-path .gitignore"
},
"files": [
"exampleFunction.mjs"
"ExampleComponent.mjs",
"exampleFunction.mjs",
"exampleStyles.css"
],
"exports": {
"./ExampleComponent.mjs": "./ExampleComponent.mjs",
"./exampleFunction.mjs": "./exampleFunction.mjs",
"./exampleStyles.css": "./exampleStyles.css",
"./package.json": "./package.json"
},
"dependencies": {
"prop-types": "^15.8.1",
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"devDependencies": {
"@babel/cli": "^7.21.0",
"@babel/core": "^7.21.3",
"@babel/preset-env": "^7.20.2",
"@babel/cli": "^7.21.5",
"@babel/core": "^7.21.8",
"@babel/preset-env": "^7.21.5",
"@babel/preset-react": "^7.18.6",
"@jest/globals": "^29.5.0",
"eslint": "^8.36.0",
"@storybook/addon-docs": "^7.0.8",
"@storybook/addons": "^7.0.8",
"@storybook/react": "^7.0.8",
"@storybook/react-webpack5": "^7.0.8",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.4.3",
"autoprefixer": "^10.4.14",
"babel-jest": "^29.5.0",
"babel-plugin-inline-react-svg": "^2.0.2",
"cssnano": "^6.0.1",
"eslint": "^8.39.0",
"eslint-plugin-jest": "^27.2.1",
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-simple-import-sort": "^10.0.0",
"husky": "^8.0.3",
"jest": "^29.5.0",
"lint-staged": "^13.2.0",
"prettier": "^2.8.7"
"jest-environment-jsdom": "^29.5.0",
"lint-staged": "^13.2.2",
"postcss": "^8.4.23",
"postcss-cli": "^10.1.0",
"prettier": "^2.8.8",
"sass": "^1.62.1",
"storybook": "^7.0.8",
"storybook-dark-mode": "^3.0.0"
}
}
17 changes: 17 additions & 0 deletions src/ExampleComponent.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* TODO - delete once src files setup
*/
import PropTypes from 'prop-types';
import React from 'react';

const ExampleComponent = ({ className, ...props }) => {
return (
<div {...props} className={className} data-testid="ExampleComponent" />
);
};

ExampleComponent.propTypes = {
className: PropTypes.string.isRequired,
};

export default ExampleComponent;
24 changes: 24 additions & 0 deletions src/ExampleComponent.stories.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[//]: # 'TODO - delete once src files setup'

import { Meta } from '@storybook/addon-docs';
import { Source } from '@storybook/addon-docs';
import ExampleComponent from './ExampleComponent.mjs';

<Meta title="ExampleComponent" />

# ExampleComponent

Description of the example component.

<ExampleComponent className="Example">
This is the contents of {'<ExampleComponent />'}
</ExampleComponent>

<Source
code={[
`<ExampleComponent className="Example">`,
` This is the contents of {'<ExampleComponent />'}`,
`</ExampleComponent>`,
].join('\n')}
dark
/>
57 changes: 57 additions & 0 deletions src/ExampleComponent.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* TODO - delete once src files setup
*/
/* eslint-disable react/prop-types */
import {
afterEach,
beforeEach,
describe,
expect,
jest,
test,
} from '@jest/globals';
import React from 'react';
import * as testUtils from '../test/test-utils.mjs';
import ExampleComponent from './ExampleComponent.mjs';

const { render, screen, user } = testUtils;

describe(`ExampleComponent`, () => {
describe(`renders correctly if required props given`, () => {
test(`is initially rendered`, async () => {
render(<ExampleComponent className="Test" />);

const div = screen.getByTestId('ExampleComponent');
expect(div).not.toBeNull();
expect(div.classList.contains('Test')).toBe(true);
});
});

describe(`logs console.errors if required props not given`, () => {
const { error } = console;
beforeEach(() => {
console.error = jest.fn();
});
afterEach(() => {
console.error = error;
});

test('`className`', async () => {
expect(console.error).not.toHaveBeenCalled();
render(<ExampleComponent />);
expect(console.error).toHaveBeenCalled();
});
});

describe(`[onClick] function fired`, () => {
test(`on user click event`, async () => {
const onClick = jest.fn();
expect(onClick).not.toHaveBeenCalled();

render(<ExampleComponent className="Test" onClick={onClick} />);

await user.click(screen.getByTestId('ExampleComponent'));
expect(onClick).toHaveBeenCalled();
});
});
});
17 changes: 17 additions & 0 deletions src/exampleFunction.stories.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import exampleFunction from './exampleFunction.mjs';
import { Meta } from '@storybook/addon-docs';
import { Source } from '@storybook/addon-docs';

<Meta title="exampleFunction" />

# exampleFunction

Description of the example function.

<p>{exampleFunction('This is the parameter given to exampleFunction')}</p>

<Source
code={`<p>{exampleFunction('This is the parameter given to exampleFunction')}</p>`}
dark
language="css"
/>
14 changes: 14 additions & 0 deletions src/exampleStyles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* TODO - delete once src files setup
*/
:root {
font-size: 10px;

&.dark {
color-scheme: dark;
}

&.light {
color-scheme: light;
}
}
9 changes: 9 additions & 0 deletions test/test-utils.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// ? Reference: https://testing-library.com/docs/react-testing-library/setup/

import userEvent from '@testing-library/user-event';
import '@testing-library/jest-dom/extend-expect.js';

export * from '@testing-library/react';

// ? Reference: https://github.com/testing-library/user-event/issues/833#issuecomment-1013632841
export const user = userEvent.setup({ delay: null });