UNPKG

@discoveryjs/discovery

Version:

Frontend framework for rapid data (JSON) analysis, shareable serverless reports and dashboards

170 lines (129 loc) 7.71 kB
export default ` ## Working with text views Text views in Discovery.js adhere to the same underlying principles as standard web-based views but are simplified due to the constraints of textual representation (e.g., lack of interactivity and styling). Text views are managed through the \`Model#textView\` interface, enabling text rendering for any model type (\`Model\`, \`ViewModel\`, \`ScriptModel\`, etc.): \`\`\`js model.textView.define('text-view-name', render); // ... const renderTree = model.textView.render(null, 'text-view-name:...', data, context); const { text } = model.textView.serialize(renderTree); console.log(text); \`\`\` Each text view supports a limited set of properties compared to regular views, but these retain the same semantics: - \`view\` (required) — Specifies the view type. - \`when\` — Controls whether the view should be rendered. Evaluated before \`data\` transformation. - \`context\` — Transforms the input context for the view and its nested views. - \`data\` — Transforms the input data for the view and its nested views. - \`whenData\` — Controls rendering based on the computed \`data\`. Evaluated after \`context\` and \`data\` are set. ## Layout model The text renderer builds a render tree composed of **box nodes** and **text nodes**. - **Text nodes**: Represent direct text strings. Their values can include newline characters. - **Box nodes**: Define the layout of their content and can optionally render a "border" around it. The content is generated by rendering child nodes, which can be a mix of box and text nodes. Box nodes support several display types: - \`inline\` — Inserts its content lines as-is. - \`inline-block\` — Ensures that whitespace is added before and after its content to prevent merging with adjacent boxes. If the content spans multiple lines, subsequent lines align with the first line. - \`line\` — Places the box's content on a new line within its parent box. - \`block\` — Similar to \`line\`, but also adds an extra empty line before and after the content when needed. \`\`\`render:text [ 'text:"…text…"', 'inline:"<inline\\\\nwith multi-line\\\\ntext...>"', 'text:"…text…"', 'inline-block:"<inline-block\\\\nwith multi-line\\\\ntext...>"', 'text:"…text…"', 'line:"<line\\\\nwith multi-line\\\\ntext...>"', 'text:"…text…"', 'block:"<block\\\\nwith multi-line\\\\ntext...>"', 'text:"…text…"' ] \`\`\` ## Box border A box border is an optional decorative frame that can be drawn around a box node’s content. Although termed a "border", its appearance is highly customizable and might not resemble a traditional border. A border can consist of up to four sides – top, right, bottom, and left – and by default, boxes have no border. There are slight differences in how vertical (left and right) and horizontal (top and bottom) borders are defined, though the corresponding pairs behave similarly. ### Vertical sides (left and right) Left and right borders specify the characters to be prepended or appended to each line of the box’s content, effectively drawing vertical lines along the sides. The value for these borders can be defined in several ways: - **Falsy value:** A falsy value (e.g., \`null\`, empty string) means no border is drawn. - **String:** A static string that is added to the beginning (for \`left\`) or end (for \`right\`) of each line. For the \`right\` border, lines are padded with spaces to ensure consistent line lengths. - **Function:** A function with the signature \`(index, total) => string | undefined\` for fine-tuned control. This allows different characters for the first, middle, and last lines. For example: \`\`\`js const leftBorder = (index, total) => total === 1 ? '[' : index === 0 ? '⎡' : index + 1 === total ? '⎣' : '⎢'; \`\`\` If the function returns strings of varying lengths, they are padded with spaces (from the start for \`left\` and from the end for \`right\`) to equalize their lengths. - **Array of strings:** An array of 1 to 4 strings representing \`start\`, \`middle\`, \`end\`, and \`single\` cases, respectively. For example: \`\`\`js const leftBorder = ['⎡', '⎢', '⎣', '[']; \`\`\` This form is equivalent to a function that selects the appropriate border based on the line index and total number of lines: \`\`\`ts function borderLR(start: string, mid = start, end = mid, single = start) { return (idx: number, total: number) => total === 1 ? single : idx === 0 ? start : idx + 1 === total ? end : mid; } \`\`\` ### Horizontal Sides (top and bottom) Top and bottom borders define the first and last lines of the box after the left and right borders have been applied. Their value can be set in one of the following ways: - **Falsy value:** No border is drawn if the value is falsy. - **String:** A static string that is repeated to achieve the required total length (\`midLen + leftLen + rightLen\`). - **Function:** A function with the signature \`(midLen, leftLen, rightLen) => string | undefined\` that returns a string. If the returned string is non-empty, it is truncated to match the total length. For example: \`\`\`js const topBorder = (midLength, leftLen, rightLen) => \`\${<}\${''.padEnd(midLength + leftLen + rightLen, '-')}\${>}\`; \`\`\` - **Array of strings:** An array of 1 to 3 strings representing \`start\`, \`middle\`, and \`end\` segments. This is equivalent to a function that constructs the border by concatenating the start, a repeated middle, and the end string. For example: \`\`\`js const topBorder = ['<', '-', '>']; \`\`\` This form is equivalent to a call the function: \`\`\`ts function borderTB(start: string, mid = start, end = mid) { return (m: number, l: number, r: number) => \`\${start}\${''.padStart(m + l + r - start.length - end.length, mid)}\${end}\`; } \`\`\` ### Using borders in views Most view definitions include a preset border that cannot be modified. However, any content can be wrapped in a basic box view (\`inline\`, \`inline-block\`, \`line\`, or \`block\`) to add a border. For example, a full border definition using array notation for sides: \`\`\`render:text { view: 'inline-list', data: [1, 2, 3, 4, 5], item: { view: 'inline-block', data: '$seq:=>?[...$ - 1 | $seq(), "line " + $]:[];$seq().join("\\\\n")', border: { top: ['←', '-', '→'], left: ['↑ ', '|', '↓', '[ '], right: [' ↑', '|', '↓', ' ]'], bottom: ['←', '-', '→'] } } } \`\`\` Borders can also be specified in a compact array notation following the TRBL (top, right, bottom, left) order, similar to CSS: \`\`\`render:text { view: 'block', border: ['T', 'R', 'B', 'L'], content: 'text:" \\\\n "' } \`\`\` If the bottom border element is undefined, it inherits the top border value (if defined). Similarly, if the left border is undefined while the right border is specified, the left border adopts the right border value. This mechanism allows you to define vertical and horizontal borders with just two elements. \`\`\`render:text { view: 'block', border: ['-', '|'], content: 'text:" \\\\n "' } \`\`\` The following example demonstrates the difference between \`undefined\` and a falsy value (such as \`null\`): \`\`\`render:text { view: 'block', border: [['+', '-', '+'], '|', undefined, null], content: 'text:" \\\\n "' } \`\`\` Each element in the concise notation accepts any value applicable for a side in object notation, i.e. a string, a function or array of strings. `;