@thisismanta/react-playbook
Version:
**Playbook** is a UI library made for listing React components.
370 lines (369 loc) • 17.3 kB
JavaScript
;
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) && ', ')))));
}