diff --git a/.gitignore b/.gitignore index 75786b8dd..b37bb3942 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,6 @@ node_modules/ stamp-yarn stats.json /_site/* + +*storybook.log +*storybook-static/ diff --git a/.storybook/main.js b/.storybook/main.js new file mode 100644 index 000000000..55f7daed0 --- /dev/null +++ b/.storybook/main.js @@ -0,0 +1,13 @@ +module.exports = { + stories: ["../src/stories/**/*.stories.js", "../src/stories/**/*.docs.mdx"], + addons: [ + "@storybook/addon-links", + "@storybook/addon-essentials", + "@storybook/addon-interactions", + "@storybook/addon-docs", + ], + framework: { + name: "@storybook/html-webpack5", + options: {}, + }, +}; diff --git a/.storybook/preview.js b/.storybook/preview.js new file mode 100644 index 000000000..80dad9ac4 --- /dev/null +++ b/.storybook/preview.js @@ -0,0 +1,25 @@ +import "bootstrap"; +import "bootstrap/dist/css/bootstrap.min.css"; +import { fn } from "@storybook/test"; + +const preview = { + parameters: { + actions: { + handles: { + onClick: fn(), + onSubmit: fn(), + onChange: fn(), + }, + }, + controls: { + expanded: true, + matchers: { + color: /(background|color)$/i, + date: /Date$/i, + }, + }, + layout: "centered", + }, +}; + +export default preview; diff --git a/Makefile b/Makefile index b76244942..948bb753a 100644 --- a/Makefile +++ b/Makefile @@ -46,3 +46,11 @@ bundle-pre: -$(YARN) unlink @patternslib/pat-code-editor -$(YARN) unlink @patternslib/patternslib $(YARN) install --force + +.PHONY: storybook +storybook: install ## Run Storybook in dev mode + $(YARN) run storybook + +.PHONY: build-storybook +build-storybook: install ## Build Storybook as static files + $(YARN) build-storybook diff --git a/package.json b/package.json index 5be98ebc1..2abd0639b 100644 --- a/package.json +++ b/package.json @@ -49,13 +49,25 @@ "@11ty/eleventy": "^2.0.1", "@11ty/eleventy-navigation": "^0.3.5", "@11ty/eleventy-plugin-syntaxhighlight": "^4.2.0", + "@chromatic-com/storybook": "^3.2.4", "@patternslib/dev": "^3.7.2", + "@storybook/addon-docs": "^8.5.3", + "@storybook/addon-essentials": "^8.5.3", + "@storybook/addon-interactions": "^8.5.3", + "@storybook/addon-links": "^8.5.3", + "@storybook/blocks": "^8.5.3", + "@storybook/core": "^8.5.3", + "@storybook/html": "^8.5.3", + "@storybook/html-webpack5": "^8.5.3", + "@storybook/manager-api": "^8.5.3", + "@storybook/test": "^8.5.3", "@testing-library/jest-dom": "^6.6.3", "@types/sinon": "^10.0.20", "css.escape": "^1.5.1", "npm-run-all2": "^7.0.2", "rimraf": "^4.1.3", "sinon": "^15.2.0", + "storybook": "^8.5.3", "svelte": "^4.2.19", "svelte-jester": "^3.0.0", "svelte-loader": "^3.2.3", @@ -104,7 +116,9 @@ "start": "npm run clean && npm-run-all --parallel start:*", "test": "jest", "testwatch": "jest --watch", - "i18n": "node src/i18n.js" + "i18n": "node src/i18n.js", + "storybook": "storybook dev -p 6006", + "build-storybook": "storybook build" }, "files": [ "/dist", diff --git a/src/stories/toggle.docs.mdx b/src/stories/toggle.docs.mdx new file mode 100644 index 000000000..32784db8f --- /dev/null +++ b/src/stories/toggle.docs.mdx @@ -0,0 +1,126 @@ +import { Meta, Story } from "@storybook/addon-docs"; +import { + ToggleItself, + ToggleTarget, + ToggleTargetScope, + ToggleTargetManyScope, +} from "./toggle.stories.js"; + + + +# Toggle Pattern + +A pattern to toggle classes on HTML elements. + +# Migration note (Plone 6) + +This mockup pattern will probably replaced by patternslib/toggle. Some features are +already broken like "Toggle an element by hover event". +We decided to not migrate all examples and no tests. + +# Configuration + +```md +| **Option** | **Type** | **Default** | **Description** | +| ------------- | -------- | ----------- | -------------------------------------------------------- | +| `target` | `string` | `null` | Selector of the target elements to toggle (`undefined`). | +| `targetScope` | `null` | `global` | Selector of a target scope element in ancestors. | +| `attribute` | `string` | `null` | Element attribute which will be toggled (`class`). | +| `event` | `string` | `null` | Event that will trigger toggling (`click`). | +``` + +# Examples + +## Toggle itself + +
+ + +```html + +``` + +## Toggle all targets (global scope) + +
+ + +```html +
+
+ Hello World +
+``` + +## Toggle specific target inside a target scope + +
+ + +```html +
+
+
+ Hello World +
+
+
+ Hello World +
+
+``` + +## Toggle more than one target inside a specific target scope + +
+ + +```html +
+
+
+ Hello World + Hello again +
+
+
+ Hello World +
+
+``` diff --git a/src/stories/toggle.stories.js b/src/stories/toggle.stories.js new file mode 100644 index 000000000..61dbf2d52 --- /dev/null +++ b/src/stories/toggle.stories.js @@ -0,0 +1,144 @@ +import $ from "jquery"; +import registry from "@patternslib/patternslib/src/core/registry"; +import Toggle from "../../src/pat/toggle/toggle.js"; + +export default { + title: "Patterns/Toggle", + argTypes: { + value: { + control: "text", + table: { + disable: true, + }, + }, + target: { + control: "text", + table: { + disable: true, + }, + }, + scope: { + control: "text", + table: { + disable: true, + }, + }, + }, +}; + +const RenderHTML = (args, getStoryHtml) => { + const wrapper = document.createElement("div"); + wrapper.innerHTML = getStoryHtml(args); + + // Ensure PatternsLib initializes after render + setTimeout(() => { + registry.scan(wrapper); + }, 300); + + return wrapper; +}; + +// Toggle itself +const getToggleItself = ({ value }) => ` + +`; + +export const ToggleItself = { + render: (args) => RenderHTML(args, getToggleItself), + args: { + value: "btn-lg", + }, +}; + +// Toggle many target elements +const getToggleTarget = ({ value, target }) => ` + + Hello World +`; + +export const ToggleTarget = { + render: (args) => RenderHTML(args, getToggleTarget), + args: { + target: ".targetElement", + value: "bg-success", + }, +}; + +// Toggle target elements with scope +const getToggleTargetScope = ({ value, target, scope }) => ` +
+
+
+ Hello World +
+
+
+ Hello World +
+
+`; + +export const ToggleTargetScope = { + render: (args) => RenderHTML(args, getToggleTargetScope), + args: { + value: "bg-success", + target: ".targetElement", + scope: ".myScope", + }, +}; + +// Toggle more than one target inside a specific target scope +const getToggleManyTargetScope = ({ value, target, scope }) => ` +
+
+
+ Hello World + Hello again +
+
+
+ Hello World +
+
+`; + +export const ToggleTargetManyScope = { + render: (args) => RenderHTML(args, getToggleManyTargetScope), + args: { + value: "bg-success", + target: ".targetElement", + scope: ".myScope", + }, +};