UNPKG

@hypothesis/frontend-shared

Version:

Shared components, styles and utilities for Hypothesis projects

406 lines (384 loc) 11.2 kB
var _jsxFileName = "/home/runner/work/frontend-shared/frontend-shared/src/pattern-library/components/Library.js"; import classnames from 'classnames'; import { toChildArray } from 'preact'; import { useState } from 'preact/hooks'; import { Frame } from '../../components/containers'; import { jsxToHTML } from '../util/jsx-to-string'; /** * @typedef LibraryBaseProps * @prop {import("preact").ComponentChildren} [intro] - Optional * introductory content * @prop {import("preact").ComponentChildren} [children] * @prop {string} [title] * */ /** * Components for rendering patterns, examples and demos in the pattern-library * page. A pattern-library Page contains Patterns, which in turn contain * Examples. An Example _may_ contain one or more Demos. Child content (markup) * may also be rendered in these components, as desired. * * Example of structure: * * <Library.Page intro={<p>Some introductory content</p>} title="Elephants"> * <p>Any content you want on the page.</p> * More content: it can be any valid `ComponentChildren` * * <Library.Pattern title="Elephant"> * <p>The `Elephant` component is used to render information about elephant * personalities.</p> * <Library.Example title="Colored elephants"> * <p>You can change the color of your elephant.</p> * <Library.Demo withSource> * <Elephant color="pink" /> * </Library.Demo> * </Library.Example> * // More Examples if desired * </Library.Pattern> * * // more Patterns if desired... * </Library.Page> */ /** * Render a pattern-library page. * * @param {LibraryBaseProps} props */ import { jsxDEV as _jsxDEV } from "preact/jsx-dev-runtime"; import { Fragment as _Fragment } from "preact/jsx-dev-runtime"; function Page({ children, intro, title }) { return _jsxDEV("section", { className: "max-w-6xl pb-16 space-y-8 text-slate-7", children: [_jsxDEV(PageTitle, { title: title }, void 0, false, { fileName: _jsxFileName, lineNumber: 54, columnNumber: 7 }, this), intro && _jsxDEV(PageIntro, { children: intro }, void 0, false, { fileName: _jsxFileName, lineNumber: 55, columnNumber: 17 }, this), _jsxDEV("div", { className: "px-4 space-y-16 styled-text", children: children }, void 0, false, { fileName: _jsxFileName, lineNumber: 56, columnNumber: 7 }, this)] }, void 0, true, { fileName: _jsxFileName, lineNumber: 53, columnNumber: 5 }, this); } /** * Sticky pattern-library page header */ function PageTitle({ title }) { return _jsxDEV("div", { className: "sticky top-0 z-4 h-16 flex items-center bg-slate-0 border-b", children: _jsxDEV("h1", { className: "px-4 text-4xl font-light", children: title }, void 0, false, { fileName: _jsxFileName, lineNumber: 67, columnNumber: 7 }, this) }, void 0, false, { fileName: _jsxFileName, lineNumber: 66, columnNumber: 5 }, this); } /** * Page introductory text */ function PageIntro({ children }) { return _jsxDEV("div", { className: "styled-text px-4 text-xl font-light space-y-4 leading-relaxed", children: children }, void 0, false, { fileName: _jsxFileName, lineNumber: 77, columnNumber: 5 }, this); } /** * Render info about a single pattern (or component) on a pattern-library page. * * @param {LibraryBaseProps} props */ function Pattern({ children, title }) { return _jsxDEV("section", { className: "space-y-8", children: [_jsxDEV("h2", { className: "text-2xl text-slate-7", children: title }, void 0, false, { fileName: _jsxFileName, lineNumber: 91, columnNumber: 7 }, this), _jsxDEV("div", { className: "space-y-8 px-4", children: children }, void 0, false, { fileName: _jsxFileName, lineNumber: 92, columnNumber: 7 }, this)] }, void 0, true, { fileName: _jsxFileName, lineNumber: 90, columnNumber: 5 }, this); } /** * @typedef LibraryExampleProps * @prop {import("preact").ComponentChildren} [children] * @prop {string} [title] * @prop {'split'|'wide'} [variant='split'] - Layout variant. Applies * appropriate className. * - Split (default) lays out in a row. Non-demo example content is rendered * left, with demos right. Demos in this variant stack vertically. * - Wide lays out in a full-width column. Non-example is rendered first, * then a row to contain demos. Demos in this variant render next to each * other in a single row. */ /** * Render example content and optional Demo(s) for a pattern. * * @param {LibraryExampleProps} props */ function Example({ children, title, variant = 'split' }) { const kids = toChildArray(children); // Extract Demo components out of any children const demos = kids.filter(kid => typeof kid === 'object' && (kid === null || kid === void 0 ? void 0 : kid.type) === Demo); // And everything else that is not a demo... const notDemos = kids.filter(kid => !demos.includes(kid)); return _jsxDEV("div", { className: "space-y-6", children: [title && _jsxDEV("h3", { className: "text-xl text-slate-9 font-light", children: title }, void 0, false, { fileName: _jsxFileName, lineNumber: 127, columnNumber: 17 }, this), _jsxDEV("div", { className: "space-y-6 px-4", children: notDemos }, void 0, false, { fileName: _jsxFileName, lineNumber: 129, columnNumber: 7 }, this), _jsxDEV("div", { className: classnames({ 'space-y-16 px-4': variant === 'split', 'flex flex-row gap-16 flex-wrap': variant === 'wide' }), children: demos }, void 0, false, { fileName: _jsxFileName, lineNumber: 130, columnNumber: 7 }, this)] }, void 0, true, { fileName: _jsxFileName, lineNumber: 126, columnNumber: 5 }, this); } /** * @typedef DemoButtonProps * @prop {import("preact").ComponentChildren} [children] * @prop {() => void} [onClick] * @prop {boolean} pressed */ /** * * @param {DemoButtonProps} props */ function DemoButton({ children, onClick, pressed }) { return _jsxDEV("button", { className: classnames('flex items-center gap-x-1.5 rounded-sm shadow py-1 px-2', 'text-sm text-color-text-light hover:bg-grey-0 hover:text-grey-7 hover:shadow-md', { 'bg-grey-2': pressed }), onClick: onClick, "aria-pressed": pressed, children: children }, void 0, false, { fileName: _jsxFileName, lineNumber: 155, columnNumber: 5 }, this); } /** * @typedef DemoProps * @prop {import("preact").ComponentChildren} [children] * @prop {string} [classes] - Extra CSS classes for the demo content's immediate * parent container * @prop {boolean} [withSource=false] - Should the demo also render the source? * When true, a "Source" tab will be rendered, which will display the JSX * source of the Demo's children * @prop {object} [style] - Inline styles to apply to the demo container * @prop {string} [title] */ /** * Render a "Demo", with optional source. This will render the children as * provided in a tabbed container. If `withSource` is `true`, the JSX source * of the children will be provided in a separate "Source" tab from the * rendered Demo content. * * @param {DemoProps} props */ function Demo({ children, classes, withSource = false, style = {}, title }) { const [visibleTab, setVisibleTab] = useState('demo'); const source = toChildArray(children).map((child, idx) => { return _jsxDEV("li", { children: _jsxDEV("code", { children: _jsxDEV("pre", { className: "font-pre whitespace-pre-wrap break-words text-sm", dangerouslySetInnerHTML: { __html: jsxToHTML(child) } }, void 0, false, { fileName: _jsxFileName, lineNumber: 197, columnNumber: 11 }, this) }, void 0, false, { fileName: _jsxFileName, lineNumber: 196, columnNumber: 9 }, this) }, idx, false, { fileName: _jsxFileName, lineNumber: 195, columnNumber: 7 }, this); }); return _jsxDEV("div", { className: "space-y-2 p-4", children: [_jsxDEV("div", { className: "flex items-center", children: [_jsxDEV("div", { className: "py-2 grow", children: _jsxDEV("h4", { className: "text-lg italic text-slate-7 font-light", children: title }, void 0, false, { fileName: _jsxFileName, lineNumber: 209, columnNumber: 11 }, this) }, void 0, false, { fileName: _jsxFileName, lineNumber: 208, columnNumber: 9 }, this), _jsxDEV("div", { className: "flex flex-row items-center justify-end gap-x-4", children: withSource && _jsxDEV(_Fragment, { children: [_jsxDEV(DemoButton, { onClick: () => setVisibleTab('demo'), pressed: visibleTab === 'demo', children: "Demo" }, void 0, false, { fileName: _jsxFileName, lineNumber: 214, columnNumber: 15 }, this), _jsxDEV(DemoButton, { onClick: () => setVisibleTab('source'), pressed: visibleTab === 'source', children: "Source" }, void 0, false, { fileName: _jsxFileName, lineNumber: 220, columnNumber: 15 }, this)] }, void 0, true) }, void 0, false, { fileName: _jsxFileName, lineNumber: 211, columnNumber: 9 }, this)] }, void 0, true, { fileName: _jsxFileName, lineNumber: 207, columnNumber: 7 }, this), _jsxDEV("div", { className: "bg-slate-0 p-2 rounded-md unstyled-text", children: [visibleTab === 'demo' && _jsxDEV("div", { className: "w-full bg-white p-8 rounded-md", style: style, children: _jsxDEV("div", { className: classnames('h-full flex flex-row items-center justify-center gap-2', classes), children: children }, void 0, false, { fileName: _jsxFileName, lineNumber: 233, columnNumber: 13 }, this) }, void 0, false, { fileName: _jsxFileName, lineNumber: 232, columnNumber: 11 }, this), visibleTab === 'source' && _jsxDEV(Frame, { classes: "w-full rounded-md bg-slate-7 text-color-text-inverted p-4", children: _jsxDEV("ul", { children: source }, void 0, false, { fileName: _jsxFileName, lineNumber: 245, columnNumber: 13 }, this) }, void 0, false, { fileName: _jsxFileName, lineNumber: 244, columnNumber: 11 }, this)] }, void 0, true, { fileName: _jsxFileName, lineNumber: 230, columnNumber: 7 }, this)] }, void 0, true, { fileName: _jsxFileName, lineNumber: 206, columnNumber: 5 }, this); } export default { Page, Pattern, Example, Demo }; //# sourceMappingURL=Library.js.map