UNPKG

@thisismanta/react-playbook

Version:

**Playbook** is a UI library made for listing React components.

370 lines (369 loc) 17.3 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = Catalog; exports.getTagName = getTagName; const react_1 = __importStar(require("react")); const lodash_1 = require("lodash"); const classnames_1 = __importDefault(require("classnames")); const ErrorBoundary_1 = __importDefault(require("./ErrorBoundary")); require("./Catalog.css"); function Catalog(props) { const elements = react_1.default.Children.toArray(props.children).map((element, index) => react_1.default.isValidElement(element) && (react_1.default.createElement(ErrorBoundary_1.default, { key: index }, react_1.default.createElement(Entry, { element: element, style: props.style })))); return react_1.default.createElement(react_1.default.Fragment, null, elements); } const BlinkTrackerContext = react_1.default.createContext(new Map()); function Entry(props) { const [overridingProps, setOverridingProps] = (0, react_1.useState)({}); const [blinkTracker, setBlinkTracker] = (0, react_1.useState)(new Map()); const blinkTrackerRef = (0, react_1.useRef)(new Map()); const blinkCallbacks = (0, react_1.useMemo)(() => { return Object.fromEntries((0, lodash_1.compact)(Object.entries(props.element.props).map(([name, originalCallback]) => { if (typeof originalCallback !== 'function') { return null; } const wrapperCallback = (...args) => { if (blinkTrackerRef.current.has(originalCallback)) { window.clearTimeout(blinkTrackerRef.current.get(originalCallback)); } const timerID = window.setTimeout(() => { setBlinkTracker(current => { const copy = new Map(current); copy.delete(wrapperCallback); return copy; }); }, 1500); setBlinkTracker(current => { const copy = new Map(current); copy.set(wrapperCallback, timerID); return copy; }); blinkTrackerRef.current.set(originalCallback, timerID); return originalCallback(...args); }; wrapperCallback.toString = () => originalCallback.toString(); return [name, wrapperCallback]; }))); }, [props.element]); const element = (0, react_1.useMemo)(() => react_1.default.cloneElement(props.element, { ...overridingProps, ...blinkCallbacks }), [props.element, overridingProps, blinkCallbacks]); return (react_1.default.createElement("section", { className: 'playbook__catalog' }, /^\.\$/.test(props.element.key || '') && (react_1.default.createElement("header", { className: 'playbook__catalog__caption' }, react_1.default.createElement("svg", { className: 'playbook__catalog__caption__icon', xmlns: "http://www.w3.org/2000/svg", height: "24", viewBox: "0 -960 960 960", width: "24" }, react_1.default.createElement("path", { d: "M685-128v-418H329l146 146-74 74-273-273 273-273 74 74-146 146h462v524H685Z" })), props.element.key?.match(/^\.\$(.+)/)?.[1])), react_1.default.createElement("div", { className: 'playbook__catalog__columns' }, react_1.default.createElement("div", { className: 'playbook__catalog__property' }, react_1.default.createElement(BlinkTrackerContext.Provider, { value: blinkTracker }, react_1.default.createElement(ElementIntrospection, { setOverridingProps: setOverridingProps }, element))), react_1.default.createElement("div", { className: 'playbook__catalog__content' }, react_1.default.createElement("div", { style: props.style }, element))))); } Catalog.Grid = function CatalogGrid(props) { return (react_1.default.createElement("div", { className: 'playbook__catalog__grid' }, react_1.default.createElement(Catalog, { style: props.style }, props.children))); }; function ElementIntrospection(props) { const setOverridingProps = props.setOverridingProps; if (!props.children || props.children === true) { return null; } if (typeof props.children === 'string' || typeof props.children === 'number') { if (setOverridingProps) { return (react_1.default.createElement("span", { className: 'playbook__catalog__property__interactive', contentEditable: true, suppressContentEditableWarning: true, onBlur: (e) => { setOverridingProps(otherProps => ({ ...otherProps, children: e.target.innerText })); } }, String(props.children))); } return String(props.children); } if (Array.isArray(props.children)) { return props.children.map((node, index) => (react_1.default.createElement(ElementIntrospection, { key: index }, node))); } if (react_1.default.isValidElement(props.children)) { const tagName = react_1.default.createElement("span", { className: 'playbook__catalog__property__tag' }, getTagName(props.children)); const { children, ...attributes } = props.children.props; const attributeElements = Object.entries(attributes).map(([name, value]) => { const openingQuote = typeof value === 'string' ? '"' : '{'; const closingQuote = typeof value === 'string' ? '"' : '}'; const setOverridingValue = setOverridingProps ? (nextValue) => { setOverridingProps((otherProps) => ({ ...otherProps, [name]: nextValue })); } : undefined; return (react_1.default.createElement("div", { key: name, className: 'playbook__catalog__property__indent' }, name, "=", openingQuote, react_1.default.createElement(ValueIntrospection, { setOverridingValue: setOverridingValue }, value), closingQuote)); }); if (children) { return (react_1.default.createElement("div", null, '<', tagName, attributeElements.length === 0 ? '' : ' ', attributeElements, '>', react_1.default.createElement("div", { className: 'playbook__catalog__property__indent' }, react_1.default.createElement(ElementIntrospection, { setOverridingProps: setOverridingProps }, children)), '</', tagName, '>')); } else { return react_1.default.createElement("div", null, '<', tagName, ' ', attributeElements, '/>'); } } return null; } function ValueIntrospection(props) { const setOverridingValue = props.setOverridingValue; const blinkCallbacks = (0, react_1.useContext)(BlinkTrackerContext); if (react_1.default.isValidElement(props.children)) { return (react_1.default.createElement("div", { className: 'playbook__catalog__property__indent' }, react_1.default.createElement(ElementIntrospection, null, props.children))); } if (typeof props.children === 'boolean') { const text = String(props.children); if (setOverridingValue) { return (react_1.default.createElement("span", { className: 'playbook__catalog__property__interactive', onClick: () => { setOverridingValue(!props.children); } }, text)); } return text; } if (typeof props.children === 'string' || typeof props.children === 'number') { const text = String(props.children); if (setOverridingValue) { return (react_1.default.createElement("span", { className: 'playbook__catalog__property__interactive', contentEditable: true, suppressContentEditableWarning: true, onBlur: (e) => { if (typeof props.children === 'number') { const nextValue = Number(e.target.innerText); if (isNaN(nextValue)) { setOverridingValue(e.target.innerText); } else { setOverridingValue(nextValue); } } else { setOverridingValue(e.target.innerText); } } }, text)); } return text; } if (props.children instanceof Date) { if (setOverridingValue) { return (react_1.default.createElement("span", null, "new Date(\"", react_1.default.createElement("span", { className: 'playbook__catalog__property__interactive', contentEditable: true, suppressContentEditableWarning: true, onBlur: (e) => { setOverridingValue(new Date(e.target.innerText)); } }, props.children.toJSON()), "\")")); } return getContentText(props.children); } if (typeof props.children === 'function') { return (react_1.default.createElement("span", { className: (0, classnames_1.default)('playbook__catalog__property__function', blinkCallbacks.has(props.children) && '--blink'), title: getContentText(props.children) }, "function")); } if (Array.isArray(props.children)) { const list = []; let lastRank = 0; let textLong = 0; for (; lastRank < props.children.length; lastRank++) { const text = getContentText(props.children[lastRank]); if (textLong + text.length > 240) { break; } list.push(react_1.default.createElement(ValueIntrospection, { key: lastRank }, props.children[lastRank])); textLong += text.length; } if (list.length < props.children.length) { const hint = []; for (; lastRank < props.children.length; lastRank++) { const text = getContentText(props.children[lastRank]); hint.push(text); } list.push(react_1.default.createElement("span", { key: lastRank, title: hint.join(',\n') }, "...")); } if (textLong > 80) { return react_1.default.createElement("span", null, "[", wrapLine(list), "]"); } else { return react_1.default.createElement("span", null, "[", wrapItem(list), "]"); } } if ((0, lodash_1.isPlainObject)(props.children)) { const list = []; let lastRank = 0; let textLong = 0; const pairs = Object.entries(props.children); for (; lastRank < pairs.length; lastRank++) { const [key, value] = pairs[lastRank]; const text = key + ': ' + getContentText(value); if (textLong + text.length > 240) { break; } list.push(react_1.default.createElement("span", { key: key }, key, ": ", react_1.default.createElement(ValueIntrospection, null, value))); textLong += text.length; } if (list.length < Object.keys(props.children).length) { const hint = []; for (; lastRank < pairs.length; lastRank++) { const [k, v] = pairs[lastRank]; hint.push(k + ': ' + getContentText(v)); } list.push(react_1.default.createElement("span", { key: lastRank, title: hint.join('\n') }, "...")); } if (textLong > 80) { return react_1.default.createElement("span", null, '{', wrapLine(list), '}'); } else { return react_1.default.createElement("span", null, '{ ', wrapItem(list), ' }'); } } return getContentText(props.children); } function getTagName(element) { if (element.type === react_1.default.Fragment) { return 'Fragment'; } if (typeof element.type === 'string') { return element.type; } const displayName = (0, lodash_1.get)(element.type, 'displayName'); if (displayName) { return displayName; } const functionName = (0, lodash_1.get)(element.type, 'name'); if (functionName === '__vite_ssr_export_default__') { return 'Component'; } else if (functionName) { return functionName; } const className = (0, lodash_1.get)(element.type, 'constructor.name'); if (className && className !== 'Function') { return className; } return 'Component'; } function getContentText(value) { if (react_1.default.isValidElement(value)) { const { children, ...attributes } = value.props; const attributeText = Object.entries(attributes) .map(([name, value]) => { const openingQuote = typeof value === 'string' ? '' : '{'; const closingQuote = typeof value === 'string' ? '' : '}'; return `${name}=${openingQuote}${getContentText(value)}${closingQuote}`; }).map(line => ' ' + line.split(/\r?\n/).map(line => ' ' + line).join('\n') + '\n').join(''); return '<' + getTagName(value) + (attributeText ? '\n' + attributeText : '') + ((0, lodash_1.isNil)(children) ? '/' : ('>' + getContentText(children) + '<' + getTagName(value))) + '>'; } if (typeof value === 'function') { const lines = String(value).split(/\r?\n/); const indent = new RegExp('^' + ((0, lodash_1.minBy)((0, lodash_1.compact)(lines.map(line => (0, lodash_1.get)(line.replace(/\t/g, ' ').match(/^\s+/), 0))), match => match.length) || '')); return lines.map(line => line.replace(indent, '')).join('\n'); } if (Array.isArray(value)) { const items = value.map(getContentText); const length = (0, lodash_1.sumBy)(items, item => item.length); if (length > 80) { return '[\n' + items.map(item => ' ' + item.split(/\r?\n/).map(line => ' ' + line).join('\n') + ',').join('\n') + '\n]'; } else { return '[' + items.join(', ') + ']'; } } if ((0, lodash_1.isPlainObject)(value)) { const items = Object.entries(value).map(([key, value]) => { return key + ': ' + getContentText(value); }); const length = (0, lodash_1.sumBy)(items, item => item.length); if (length > 80) { return '{\n' + items.map(item => ' ' + item.split(/\r?\n/).map(line => ' ' + line).join('\n') + ',').join('\n') + '\n}'; } else { return '{ ' + items.join(', ') + ' }'; } } if (value instanceof Date) { return `new Date("${value.toJSON()}")`; } if (value === undefined) { return 'undefined'; } return JSON.stringify(value, null, ''); } function wrapLine(values) { return (react_1.default.createElement("div", { className: 'playbook__catalog__property__indent' }, values.map((value, index) => (react_1.default.createElement(react_1.default.Fragment, { key: index }, value, ",", (index < values.length - 1) && react_1.default.createElement("br", null)))))); } function wrapItem(values) { return (react_1.default.createElement(react_1.default.Fragment, null, values.map((value, index) => (react_1.default.createElement(react_1.default.Fragment, { key: index }, value, (index < values.length - 1) && ', '))))); }