Comparing version 4.0.0 to 4.1.0
@@ -7,2 +7,20 @@ import React from 'react'; | ||
/** | ||
* Size of the gap between an element's columns. | ||
* | ||
* @default 0 | ||
*/ | ||
readonly columnGap?: number; | ||
/** | ||
* Size of the gap between element's rows. | ||
* | ||
* @default 0 | ||
*/ | ||
readonly rowGap?: number; | ||
/** | ||
* Size of the gap between an element's columns and rows. Shorthand for `columnGap` and `rowGap`. | ||
* | ||
* @default 0 | ||
*/ | ||
readonly gap?: number; | ||
/** | ||
* Margin on all sides. Equivalent to setting `marginTop`, `marginBottom`, `marginLeft` and `marginRight`. | ||
@@ -43,2 +61,20 @@ * | ||
readonly paddingY?: number; | ||
/** | ||
* Behavior for an element's overflow in both directions. | ||
* | ||
* @default 'visible' | ||
*/ | ||
readonly overflow?: 'visible' | 'hidden'; | ||
/** | ||
* Behavior for an element's overflow in horizontal direction. | ||
* | ||
* @default 'visible' | ||
*/ | ||
readonly overflowX?: 'visible' | 'hidden'; | ||
/** | ||
* Behavior for an element's overflow in vertical direction. | ||
* | ||
* @default 'visible' | ||
*/ | ||
readonly overflowY?: 'visible' | 'hidden'; | ||
}; | ||
@@ -50,2 +86,20 @@ /** | ||
/** | ||
* Size of the gap between an element's columns. | ||
* | ||
* @default 0 | ||
*/ | ||
readonly columnGap?: number | undefined; | ||
/** | ||
* Size of the gap between element's rows. | ||
* | ||
* @default 0 | ||
*/ | ||
readonly rowGap?: number | undefined; | ||
/** | ||
* Size of the gap between an element's columns and rows. Shorthand for `columnGap` and `rowGap`. | ||
* | ||
* @default 0 | ||
*/ | ||
readonly gap?: number | undefined; | ||
/** | ||
* Margin on all sides. Equivalent to setting `marginTop`, `marginBottom`, `marginLeft` and `marginRight`. | ||
@@ -86,2 +140,20 @@ * | ||
readonly paddingY?: number | undefined; | ||
/** | ||
* Behavior for an element's overflow in both directions. | ||
* | ||
* @default 'visible' | ||
*/ | ||
readonly overflow?: "visible" | "hidden" | undefined; | ||
/** | ||
* Behavior for an element's overflow in horizontal direction. | ||
* | ||
* @default 'visible' | ||
*/ | ||
readonly overflowX?: "visible" | "hidden" | undefined; | ||
/** | ||
* Behavior for an element's overflow in vertical direction. | ||
* | ||
* @default 'visible' | ||
*/ | ||
readonly overflowY?: "visible" | "hidden" | undefined; | ||
} & { | ||
@@ -88,0 +160,0 @@ children?: React.ReactNode; |
@@ -9,2 +9,4 @@ /* eslint-disable @typescript-eslint/prefer-nullish-coalescing */ | ||
...style, | ||
columnGap: style.columnGap || style.gap || 0, | ||
rowGap: style.rowGap || style.gap || 0, | ||
marginLeft: style.marginLeft || style.marginX || style.margin || 0, | ||
@@ -17,3 +19,5 @@ marginRight: style.marginRight || style.marginX || style.margin || 0, | ||
paddingTop: style.paddingTop || style.paddingY || style.padding || 0, | ||
paddingBottom: style.paddingBottom || style.paddingY || style.padding || 0 | ||
paddingBottom: style.paddingBottom || style.paddingY || style.padding || 0, | ||
overflowX: style.overflowX || style.overflow || 'visible', | ||
overflowY: style.overflowY || style.overflow || 'visible' | ||
}; | ||
@@ -24,2 +28,3 @@ return (React.createElement("ink-box", { ref: ref, style: transformedStyle }, children)); | ||
Box.defaultProps = { | ||
flexWrap: 'nowrap', | ||
flexDirection: 'row', | ||
@@ -26,0 +31,0 @@ flexGrow: 0, |
@@ -1,3 +0,2 @@ | ||
/// <reference types="yoga-layout" /> | ||
import Yoga from 'yoga-layout-prebuilt'; | ||
import { type Node as YogaNode } from 'yoga-wasm-web/auto'; | ||
import { type Styles } from './styles.js'; | ||
@@ -7,3 +6,3 @@ import { type OutputTransformer } from './render-node-to-output.js'; | ||
parentNode: DOMElement | undefined; | ||
yogaNode?: Yoga.YogaNode; | ||
yogaNode?: YogaNode; | ||
internal_static?: boolean; | ||
@@ -22,2 +21,3 @@ style: Styles; | ||
staticNode?: DOMElement; | ||
onComputeLayout?: () => void; | ||
onRender?: () => void; | ||
@@ -24,0 +24,0 @@ onImmediateRender?: () => void; |
@@ -1,2 +0,3 @@ | ||
import Yoga from 'yoga-layout-prebuilt'; | ||
// eslint-disable-next-line n/file-extension-in-import | ||
import Yoga from 'yoga-wasm-web/auto'; | ||
import measureText from './measure-text.js'; | ||
@@ -3,0 +4,0 @@ import applyStyles from './styles.js'; |
@@ -1,3 +0,3 @@ | ||
import Yoga from 'yoga-layout-prebuilt'; | ||
declare const getMaxWidth: (yogaNode: Yoga.YogaNode) => number; | ||
import { type Node as YogaNode } from 'yoga-wasm-web/auto'; | ||
declare const getMaxWidth: (yogaNode: YogaNode) => number; | ||
export default getMaxWidth; |
@@ -1,2 +0,3 @@ | ||
import Yoga from 'yoga-layout-prebuilt'; | ||
// eslint-disable-next-line n/file-extension-in-import | ||
import Yoga from 'yoga-wasm-web/auto'; | ||
const getMaxWidth = (yogaNode) => { | ||
@@ -3,0 +4,0 @@ return (yogaNode.getComputedWidth() - |
@@ -25,5 +25,7 @@ /// <reference types="node" resolution-mode="require"/> | ||
constructor(options: Options); | ||
resized: () => void; | ||
resolveExitPromise: () => void; | ||
rejectExitPromise: (reason?: Error) => void; | ||
unsubscribeExit: () => void; | ||
calculateLayout: () => void; | ||
onRender: () => void; | ||
@@ -30,0 +32,0 @@ render(node: ReactNode): void; |
import process from 'node:process'; | ||
import React from 'react'; | ||
import { throttle } from 'lodash-es'; | ||
import throttle from 'lodash/throttle.js'; | ||
import ansiEscapes from 'ansi-escapes'; | ||
@@ -9,2 +9,4 @@ import originalIsCi from 'is-ci'; | ||
import patchConsole from 'patch-console'; | ||
// eslint-disable-next-line n/file-extension-in-import | ||
import Yoga from 'yoga-wasm-web/auto'; | ||
import reconciler from './reconciler.js'; | ||
@@ -89,2 +91,11 @@ import render from './renderer.js'; | ||
}); | ||
Object.defineProperty(this, "resized", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: () => { | ||
this.calculateLayout(); | ||
this.onRender(); | ||
} | ||
}); | ||
Object.defineProperty(this, "resolveExitPromise", { | ||
@@ -108,2 +119,14 @@ enumerable: true, | ||
}); | ||
Object.defineProperty(this, "calculateLayout", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: () => { | ||
// The 'columns' property can be undefined or 0 when not using a TTY. | ||
// In that case we fall back to 80. | ||
const terminalWidth = this.options.stdout.columns || 80; | ||
this.rootNode.yogaNode.setWidth(terminalWidth); | ||
this.rootNode.yogaNode.calculateLayout(undefined, undefined, Yoga.DIRECTION_LTR); | ||
} | ||
}); | ||
Object.defineProperty(this, "onRender", { | ||
@@ -117,6 +140,3 @@ enumerable: true, | ||
} | ||
const { output, outputHeight, staticOutput } = render(this.rootNode, | ||
// The 'columns' property can be undefined or 0 when not using a TTY. | ||
// In that case we fall back to 80. | ||
this.options.stdout.columns || 80); | ||
const { output, outputHeight, staticOutput } = render(this.rootNode); | ||
// If <Static> output isn't empty, it means new children have been added to it | ||
@@ -161,2 +181,3 @@ const hasStaticOutput = staticOutput && staticOutput !== '\n'; | ||
this.rootNode = dom.createNode('ink-root'); | ||
this.rootNode.onComputeLayout = this.calculateLayout; | ||
this.rootNode.onRender = options.debug | ||
@@ -202,5 +223,5 @@ ? this.onRender | ||
if (!isCi) { | ||
options.stdout.on('resize', this.onRender); | ||
options.stdout.on('resize', this.resized); | ||
this.unsubscribeResize = () => { | ||
options.stdout.off('resize', this.onRender); | ||
options.stdout.off('resize', this.resized); | ||
}; | ||
@@ -251,2 +272,3 @@ } | ||
} | ||
this.calculateLayout(); | ||
this.onRender(); | ||
@@ -253,0 +275,0 @@ this.unsubscribeExit(); |
@@ -14,6 +14,12 @@ import { type OutputTransformer } from './render-node-to-output.js'; | ||
}; | ||
type Clip = { | ||
x1: number | undefined; | ||
x2: number | undefined; | ||
y1: number | undefined; | ||
y2: number | undefined; | ||
}; | ||
export default class Output { | ||
width: number; | ||
height: number; | ||
private readonly writes; | ||
private readonly operations; | ||
constructor(options: Options); | ||
@@ -23,2 +29,4 @@ write(x: number, y: number, text: string, options: { | ||
}): void; | ||
clip(clip: Clip): void; | ||
unclip(): void; | ||
get(): { | ||
@@ -25,0 +33,0 @@ output: string; |
import sliceAnsi from 'slice-ansi'; | ||
import stringWidth from 'string-width'; | ||
import widestLine from 'widest-line'; | ||
export default class Output { | ||
@@ -17,4 +18,3 @@ constructor(options) { | ||
}); | ||
// Initialize output array with a specific set of rows, so that margin/padding at the bottom is preserved | ||
Object.defineProperty(this, "writes", { | ||
Object.defineProperty(this, "operations", { | ||
enumerable: true, | ||
@@ -34,5 +34,23 @@ configurable: true, | ||
} | ||
this.writes.push({ x, y, text, transformers }); | ||
this.operations.push({ | ||
type: 'write', | ||
x, | ||
y, | ||
text, | ||
transformers | ||
}); | ||
} | ||
clip(clip) { | ||
this.operations.push({ | ||
type: 'clip', | ||
clip | ||
}); | ||
} | ||
unclip() { | ||
this.operations.push({ | ||
type: 'unclip' | ||
}); | ||
} | ||
get() { | ||
// Initialize output array with a specific set of rows, so that margin/padding at the bottom is preserved | ||
const output = []; | ||
@@ -42,21 +60,70 @@ for (let y = 0; y < this.height; y++) { | ||
} | ||
for (const write of this.writes) { | ||
const { x, y, text, transformers } = write; | ||
const lines = text.split('\n'); | ||
let offsetY = 0; | ||
for (let line of lines) { | ||
const currentLine = output[y + offsetY]; | ||
// Line can be missing if `text` is taller than height of pre-initialized `this.output` | ||
if (!currentLine) { | ||
continue; | ||
const clips = []; | ||
for (const operation of this.operations) { | ||
if (operation.type === 'clip') { | ||
clips.push(operation.clip); | ||
} | ||
if (operation.type === 'unclip') { | ||
clips.pop(); | ||
} | ||
if (operation.type === 'write') { | ||
const { text, transformers } = operation; | ||
let { x, y } = operation; | ||
let lines = text.split('\n'); | ||
const clip = clips[clips.length - 1]; | ||
if (clip) { | ||
const clipHorizontally = typeof clip?.x1 === 'number' && typeof clip?.x2 === 'number'; | ||
const clipVertically = typeof clip?.y1 === 'number' && typeof clip?.y2 === 'number'; | ||
// If text is positioned outside of clipping area altogether, | ||
// skip to the next operation to avoid unnecessary calculations | ||
if (clipHorizontally) { | ||
const width = widestLine(text); | ||
if (x + width < clip.x1 || x > clip.x2) { | ||
continue; | ||
} | ||
} | ||
if (clipVertically) { | ||
const height = lines.length; | ||
if (y + height < clip.y1 || y > clip.y2) { | ||
continue; | ||
} | ||
} | ||
if (clipHorizontally) { | ||
lines = lines.map(line => { | ||
const from = x < clip.x1 ? clip.x1 - x : 0; | ||
const width = stringWidth(line); | ||
const to = x + width > clip.x2 ? clip.x2 - x : width; | ||
return sliceAnsi(line, from, to); | ||
}); | ||
if (x < clip.x1) { | ||
x = clip.x1; | ||
} | ||
} | ||
if (clipVertically) { | ||
const from = y < clip.y1 ? clip.y1 - y : 0; | ||
const height = lines.length; | ||
const to = y + height > clip.y2 ? clip.y2 - y : height; | ||
lines = lines.slice(from, to); | ||
if (y < clip.y1) { | ||
y = clip.y1; | ||
} | ||
} | ||
} | ||
const width = stringWidth(line); | ||
for (const transformer of transformers) { | ||
line = transformer(line); | ||
let offsetY = 0; | ||
for (let line of lines) { | ||
const currentLine = output[y + offsetY]; | ||
// Line can be missing if `text` is taller than height of pre-initialized `this.output` | ||
if (!currentLine) { | ||
continue; | ||
} | ||
const width = stringWidth(line); | ||
for (const transformer of transformers) { | ||
line = transformer(line); | ||
} | ||
output[y + offsetY] = | ||
sliceAnsi(currentLine, 0, x) + | ||
line + | ||
sliceAnsi(currentLine, x + width); | ||
offsetY++; | ||
} | ||
output[y + offsetY] = | ||
sliceAnsi(currentLine, 0, x) + | ||
line + | ||
sliceAnsi(currentLine, x + width); | ||
offsetY++; | ||
} | ||
@@ -63,0 +130,0 @@ } |
import process from 'node:process'; | ||
import createReconciler from 'react-reconciler'; | ||
import { DefaultEventPriority } from 'react-reconciler/constants.js'; | ||
import Yoga from 'yoga-layout-prebuilt'; | ||
// eslint-disable-next-line n/file-extension-in-import | ||
import Yoga from 'yoga-wasm-web/auto'; | ||
import { createTextNode, appendChildNode, insertBeforeNode, removeChildNode, setStyle, setTextNodeValue, createNode, setAttribute } from './dom.js'; | ||
@@ -40,2 +41,5 @@ // We need to conditionally perform devtools connection to avoid | ||
resetAfterCommit(rootNode) { | ||
if (typeof rootNode.onComputeLayout === 'function') { | ||
rootNode.onComputeLayout(); | ||
} | ||
// Since renders are throttled at the instance level and <Static> component children | ||
@@ -161,2 +165,3 @@ // are rendered only once and then get deleted, we need an escape hatch to | ||
// Always include `borderColor` and `borderStyle` to ensure border is rendered, | ||
// and `overflowX` and `overflowY` to ensure content is clipped, | ||
// otherwise resulting `updatePayload` may not contain them | ||
@@ -174,2 +179,4 @@ // if they weren't changed during this update | ||
newStyle.borderColor; | ||
updatePayload['style'].overflowX = newStyle.overflowX; | ||
updatePayload['style'].overflowY = newStyle.overflowY; | ||
} | ||
@@ -176,0 +183,0 @@ if (newStyle[styleKey] !== oldStyle[styleKey]) { |
@@ -1,4 +0,5 @@ | ||
import Yoga from 'yoga-layout-prebuilt'; | ||
import widestLine from 'widest-line'; | ||
import indentString from 'indent-string'; | ||
// eslint-disable-next-line n/file-extension-in-import | ||
import Yoga from 'yoga-wasm-web/auto'; | ||
import wrapText from './wrap-text.js'; | ||
@@ -57,4 +58,27 @@ import getMaxWidth from './get-max-width.js'; | ||
} | ||
let clipped = false; | ||
if (node.nodeName === 'ink-box') { | ||
renderBorder(x, y, node, output); | ||
const clipHorizontally = node.style.overflowX === 'hidden'; | ||
const clipVertically = node.style.overflowY === 'hidden'; | ||
if (clipHorizontally || clipVertically) { | ||
const x1 = clipHorizontally | ||
? x + yogaNode.getComputedBorder(Yoga.EDGE_LEFT) | ||
: undefined; | ||
const x2 = clipHorizontally | ||
? x + | ||
yogaNode.getComputedWidth() - | ||
yogaNode.getComputedBorder(Yoga.EDGE_RIGHT) | ||
: undefined; | ||
const y1 = clipVertically | ||
? y + yogaNode.getComputedBorder(Yoga.EDGE_TOP) | ||
: undefined; | ||
const y2 = clipVertically | ||
? y + | ||
yogaNode.getComputedHeight() - | ||
yogaNode.getComputedBorder(Yoga.EDGE_BOTTOM) | ||
: undefined; | ||
output.clip({ x1, x2, y1, y2 }); | ||
clipped = true; | ||
} | ||
} | ||
@@ -70,2 +94,5 @@ if (node.nodeName === 'ink-root' || node.nodeName === 'ink-box') { | ||
} | ||
if (clipped) { | ||
output.unclip(); | ||
} | ||
} | ||
@@ -72,0 +99,0 @@ } |
@@ -7,3 +7,3 @@ import { type DOMElement } from './dom.js'; | ||
}; | ||
declare const renderer: (node: DOMElement, terminalWidth: number) => Result; | ||
declare const renderer: (node: DOMElement) => Result; | ||
export default renderer; |
@@ -1,8 +0,5 @@ | ||
import Yoga from 'yoga-layout-prebuilt'; | ||
import renderNodeToOutput from './render-node-to-output.js'; | ||
import Output from './output.js'; | ||
const renderer = (node, terminalWidth) => { | ||
node.yogaNode.setWidth(terminalWidth); | ||
const renderer = (node) => { | ||
if (node.yogaNode) { | ||
node.yogaNode.calculateLayout(undefined, undefined, Yoga.DIRECTION_LTR); | ||
const output = new Output({ | ||
@@ -9,0 +6,0 @@ width: node.yogaNode.getComputedWidth(), |
@@ -1,5 +0,5 @@ | ||
import { type YogaNode } from 'yoga-layout-prebuilt'; | ||
import { type Boxes } from 'cli-boxes'; | ||
import { type LiteralUnion } from 'type-fest'; | ||
import { type ForegroundColorName } from 'chalk'; | ||
import { type Node as YogaNode } from 'yoga-wasm-web/auto'; | ||
export type Styles = { | ||
@@ -9,2 +9,10 @@ readonly textWrap?: 'wrap' | 'end' | 'middle' | 'truncate-end' | 'truncate' | 'truncate-middle' | 'truncate-start'; | ||
/** | ||
* Gap between element's columns. | ||
*/ | ||
readonly columnGap?: number; | ||
/** | ||
* Gap between element's rows. | ||
*/ | ||
readonly rowGap?: number; | ||
/** | ||
* Top margin. | ||
@@ -62,2 +70,7 @@ */ | ||
/** | ||
* It defines whether the flex items are forced in a single line or can be flowed into multiple lines. If set to multiple lines, it also defines the cross-axis which determines the direction new lines are stacked in. | ||
* See [flex-wrap](https://css-tricks.com/almanac/properties/f/flex-wrap/). | ||
*/ | ||
readonly flexWrap?: 'nowrap' | 'wrap' | 'wrap-reverse'; | ||
/** | ||
* The align-items property defines the default behavior for how items are laid out along the cross axis (perpendicular to the main axis). | ||
@@ -109,4 +122,12 @@ * See [align-items](https://css-tricks.com/almanac/properties/a/align-items/). | ||
readonly borderColor?: LiteralUnion<ForegroundColorName, string>; | ||
/** | ||
* Behavior for an element's overflow in horizontal direction. | ||
*/ | ||
readonly overflowX?: 'visible' | 'hidden'; | ||
/** | ||
* Behavior for an element's overflow in vertical direction. | ||
*/ | ||
readonly overflowY?: 'visible' | 'hidden'; | ||
}; | ||
declare const styles: (node: YogaNode, style?: Styles) => void; | ||
export default styles; |
@@ -1,3 +0,3 @@ | ||
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */ | ||
import Yoga from 'yoga-layout-prebuilt'; | ||
// eslint-disable-next-line n/file-extension-in-import | ||
import Yoga from 'yoga-wasm-web/auto'; | ||
const applyPositionStyles = (node, style) => { | ||
@@ -45,2 +45,13 @@ if ('position' in style) { | ||
} | ||
if ('flexWrap' in style) { | ||
if (style.flexWrap === 'nowrap') { | ||
node.setFlexWrap(Yoga.WRAP_NO_WRAP); | ||
} | ||
if (style.flexWrap === 'wrap') { | ||
node.setFlexWrap(Yoga.WRAP_WRAP); | ||
} | ||
if (style.flexWrap === 'wrap-reverse') { | ||
node.setFlexWrap(Yoga.WRAP_WRAP_REVERSE); | ||
} | ||
} | ||
if ('flexDirection' in style) { | ||
@@ -172,2 +183,10 @@ if (style.flexDirection === 'row') { | ||
}; | ||
const applyGapStyles = (node, style) => { | ||
if ('columnGap' in style) { | ||
node.setGap(Yoga.GUTTER_COLUMN, style.columnGap ?? 0); | ||
} | ||
if ('rowGap' in style) { | ||
node.setGap(Yoga.GUTTER_ROW, style.rowGap ?? 0); | ||
} | ||
}; | ||
const styles = (node, style = {}) => { | ||
@@ -181,4 +200,5 @@ applyPositionStyles(node, style); | ||
applyBorderStyles(node, style); | ||
applyGapStyles(node, style); | ||
}; | ||
export default styles; | ||
//# sourceMappingURL=styles.js.map |
{ | ||
"name": "ink", | ||
"version": "4.0.0", | ||
"version": "4.1.0", | ||
"description": "React for CLI", | ||
@@ -54,3 +54,3 @@ "license": "MIT", | ||
"is-ci": "^3.0.1", | ||
"lodash-es": "^4.17.21", | ||
"lodash": "^4.17.21", | ||
"patch-console": "^2.0.0", | ||
@@ -60,3 +60,3 @@ "react-reconciler": "^0.29.0", | ||
"signal-exit": "^3.0.7", | ||
"slice-ansi": "^5.0.0", | ||
"slice-ansi": "^6.0.0", | ||
"stack-utils": "^2.0.6", | ||
@@ -68,3 +68,3 @@ "string-width": "^5.1.2", | ||
"ws": "^8.12.0", | ||
"yoga-layout-prebuilt": "^1.9.6" | ||
"yoga-wasm-web": "~0.3.3" | ||
}, | ||
@@ -76,3 +76,3 @@ "devDependencies": { | ||
"@types/is-ci": "^2.0.0", | ||
"@types/lodash-es": "^4.17.6", | ||
"@types/lodash": "^4.14.191", | ||
"@types/ms": "^0.7.31", | ||
@@ -79,0 +79,0 @@ "@types/node": "*", |
123
readme.md
@@ -130,2 +130,3 @@ [![](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://github.com/vshymanskyy/StandWithUkraine/blob/main/docs/README.md) | ||
- [Shopify CLI](https://github.com/Shopify/cli) - Build apps, themes, and storefronts for Shopify. | ||
- [ToDesktop CLI](https://www.todesktop.com/electron) - An all-in-one platform for building Electron apps. | ||
@@ -584,2 +585,54 @@ ## Contents | ||
#### Gap | ||
#### gap | ||
Type: `number`\ | ||
Default: `0` | ||
Size of the gap between an element's columns and rows. Shorthand for `columnGap` and `rowGap`. | ||
```jsx | ||
<Box gap={1} width={3} flexWrap="wrap"> | ||
<Text>A</Text> | ||
<Text>B</Text> | ||
<Text>C</Text> | ||
</Box> | ||
// A B | ||
// | ||
// C | ||
``` | ||
#### columnGap | ||
Type: `number`\ | ||
Default: `0` | ||
Size of the gap between an element's columns. | ||
```jsx | ||
<Box gap={1}> | ||
<Text>A</Text> | ||
<Text>B</Text> | ||
</Box> | ||
// A B | ||
``` | ||
#### rowGap | ||
Type: `number`\ | ||
Default: `0` | ||
Size of the gap between element's rows. | ||
```jsx | ||
<Box flexDirection="column" gap={1}> | ||
<Text>A</Text> | ||
<Text>B</Text> | ||
</Box> | ||
// A | ||
// | ||
// B | ||
``` | ||
#### Flex | ||
@@ -686,2 +739,28 @@ | ||
##### flexWrap | ||
Type: `string`\ | ||
Allowed values: `nowrap` `wrap` `wrap-reverse` | ||
See [flex-wrap](https://css-tricks.com/almanac/properties/f/flex-wrap/). | ||
```jsx | ||
<Box width={2} flexWrap="wrap"> | ||
<Text>A</Text> | ||
<Text>BC</Text> | ||
</Box> | ||
// A | ||
// B C | ||
``` | ||
```jsx | ||
<Box flexDirection="column" height={2} flexWrap="wrap"> | ||
<Text>A</Text> | ||
<Text>B</Text> | ||
<Text>C</Text> | ||
</Box> | ||
// A C | ||
// B | ||
``` | ||
##### alignItems | ||
@@ -827,2 +906,26 @@ | ||
##### overflowX | ||
Type: `string`\ | ||
Allowed values: `visible` `hidden`\ | ||
Default: `visible` | ||
Behavior for an element's overflow in horizontal direction. | ||
##### overflowY | ||
Type: `string`\ | ||
Allowed values: `visible` `hidden`\ | ||
Default: `visible` | ||
Behavior for an element's overflow in vertical direction. | ||
##### overflow | ||
Type: `string`\ | ||
Allowed values: `visible` `hidden`\ | ||
Default: `visible` | ||
Shortcut for setting `overflowX` and `overflowY` at the same time. | ||
#### Borders | ||
@@ -1840,13 +1943,13 @@ | ||
- [Jest](examples/jest/jest.js) - Implementation of basic Jest UI [(live demo)](https://ink-jest-demo.vadimdemedes.repl.run/). | ||
- [Counter](examples/counter/counter.js) - Simple counter that increments every 100ms [(live demo)](https://ink-counter-demo.vadimdemedes.repl.run/). | ||
- [Jest](examples/jest/jest.tsx) - Implementation of basic Jest UI [(live demo)](https://ink-jest-demo.vadimdemedes.repl.run/). | ||
- [Counter](examples/counter/counter.tsx) - Simple counter that increments every 100ms [(live demo)](https://ink-counter-demo.vadimdemedes.repl.run/). | ||
- [Form with validation](https://github.com/final-form/rff-cli-example) - Manage form state using [Final Form](https://github.com/final-form/final-form#-final-form). | ||
- [Borders](examples/borders/borders.js) - Add borders to `<Box>` component. | ||
- [Suspense](examples/suspense/suspense.js) - Use React Suspense. | ||
- [Table](examples/table/table.js) - Render a table with multiple columns and rows. | ||
- [Focus management](examples/use-focus/use-focus.js) - Use `useFocus` hook to manage focus between components. | ||
- [User input](examples/use-input/use-input.js) - Listen to user input. | ||
- [Write to stdout](examples/use-stdout/use-stdout.js) - Write to stdout bypassing main Ink output. | ||
- [Write to stderr](examples/use-stderr/use-stderr.js) - Write to stderr bypassing main Ink output. | ||
- [Static](examples/static/static.js) - Use `<Static>` to render permanent output. | ||
- [Borders](examples/borders/borders.tsx) - Add borders to `<Box>` component. | ||
- [Suspense](examples/suspense/suspense.tsx) - Use React Suspense. | ||
- [Table](examples/table/table.tsx) - Render a table with multiple columns and rows. | ||
- [Focus management](examples/use-focus/use-focus.tsx) - Use `useFocus` hook to manage focus between components. | ||
- [User input](examples/use-input/use-input.tsx) - Listen to user input. | ||
- [Write to stdout](examples/use-stdout/use-stdout.tsx) - Write to stdout bypassing main Ink output. | ||
- [Write to stderr](examples/use-stderr/use-stderr.tsx) - Write to stderr bypassing main Ink output. | ||
- [Static](examples/static/static.tsx) - Use `<Static>` to render permanent output. | ||
- [Child process](examples/subprocess-output) - Render output from a child process. | ||
@@ -1853,0 +1956,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
242531
3322
1956
+ Addedlodash@^4.17.21
+ Addedyoga-wasm-web@~0.3.3
+ Addedlodash@4.17.21(transitive)
+ Addedslice-ansi@6.0.0(transitive)
+ Addedyoga-wasm-web@0.3.3(transitive)
- Removedlodash-es@^4.17.21
- Removedyoga-layout-prebuilt@^1.9.6
- Removed@types/yoga-layout@1.9.2(transitive)
- Removedlodash-es@4.17.21(transitive)
- Removedyoga-layout-prebuilt@1.10.0(transitive)
Updatedslice-ansi@^6.0.0