source dump of claude code
at main 308 lines 7.4 kB view raw
1import Yoga, { 2 Align, 3 Direction, 4 Display, 5 Edge, 6 FlexDirection, 7 Gutter, 8 Justify, 9 MeasureMode, 10 Overflow, 11 PositionType, 12 Wrap, 13 type Node as YogaNode, 14} from 'src/native-ts/yoga-layout/index.js' 15import { 16 type LayoutAlign, 17 LayoutDisplay, 18 type LayoutEdge, 19 type LayoutFlexDirection, 20 type LayoutGutter, 21 type LayoutJustify, 22 type LayoutMeasureFunc, 23 LayoutMeasureMode, 24 type LayoutNode, 25 type LayoutOverflow, 26 type LayoutPositionType, 27 type LayoutWrap, 28} from './node.js' 29 30// -- 31// Edge/Gutter mapping 32 33const EDGE_MAP: Record<LayoutEdge, Edge> = { 34 all: Edge.All, 35 horizontal: Edge.Horizontal, 36 vertical: Edge.Vertical, 37 left: Edge.Left, 38 right: Edge.Right, 39 top: Edge.Top, 40 bottom: Edge.Bottom, 41 start: Edge.Start, 42 end: Edge.End, 43} 44 45const GUTTER_MAP: Record<LayoutGutter, Gutter> = { 46 all: Gutter.All, 47 column: Gutter.Column, 48 row: Gutter.Row, 49} 50 51// -- 52// Yoga adapter 53 54export class YogaLayoutNode implements LayoutNode { 55 readonly yoga: YogaNode 56 57 constructor(yoga: YogaNode) { 58 this.yoga = yoga 59 } 60 61 // Tree 62 63 insertChild(child: LayoutNode, index: number): void { 64 this.yoga.insertChild((child as YogaLayoutNode).yoga, index) 65 } 66 67 removeChild(child: LayoutNode): void { 68 this.yoga.removeChild((child as YogaLayoutNode).yoga) 69 } 70 71 getChildCount(): number { 72 return this.yoga.getChildCount() 73 } 74 75 getParent(): LayoutNode | null { 76 const p = this.yoga.getParent() 77 return p ? new YogaLayoutNode(p) : null 78 } 79 80 // Layout 81 82 calculateLayout(width?: number, _height?: number): void { 83 this.yoga.calculateLayout(width, undefined, Direction.LTR) 84 } 85 86 setMeasureFunc(fn: LayoutMeasureFunc): void { 87 this.yoga.setMeasureFunc((w, wMode) => { 88 const mode = 89 wMode === MeasureMode.Exactly 90 ? LayoutMeasureMode.Exactly 91 : wMode === MeasureMode.AtMost 92 ? LayoutMeasureMode.AtMost 93 : LayoutMeasureMode.Undefined 94 return fn(w, mode) 95 }) 96 } 97 98 unsetMeasureFunc(): void { 99 this.yoga.unsetMeasureFunc() 100 } 101 102 markDirty(): void { 103 this.yoga.markDirty() 104 } 105 106 // Computed layout 107 108 getComputedLeft(): number { 109 return this.yoga.getComputedLeft() 110 } 111 112 getComputedTop(): number { 113 return this.yoga.getComputedTop() 114 } 115 116 getComputedWidth(): number { 117 return this.yoga.getComputedWidth() 118 } 119 120 getComputedHeight(): number { 121 return this.yoga.getComputedHeight() 122 } 123 124 getComputedBorder(edge: LayoutEdge): number { 125 return this.yoga.getComputedBorder(EDGE_MAP[edge]!) 126 } 127 128 getComputedPadding(edge: LayoutEdge): number { 129 return this.yoga.getComputedPadding(EDGE_MAP[edge]!) 130 } 131 132 // Style setters 133 134 setWidth(value: number): void { 135 this.yoga.setWidth(value) 136 } 137 setWidthPercent(value: number): void { 138 this.yoga.setWidthPercent(value) 139 } 140 setWidthAuto(): void { 141 this.yoga.setWidthAuto() 142 } 143 setHeight(value: number): void { 144 this.yoga.setHeight(value) 145 } 146 setHeightPercent(value: number): void { 147 this.yoga.setHeightPercent(value) 148 } 149 setHeightAuto(): void { 150 this.yoga.setHeightAuto() 151 } 152 setMinWidth(value: number): void { 153 this.yoga.setMinWidth(value) 154 } 155 setMinWidthPercent(value: number): void { 156 this.yoga.setMinWidthPercent(value) 157 } 158 setMinHeight(value: number): void { 159 this.yoga.setMinHeight(value) 160 } 161 setMinHeightPercent(value: number): void { 162 this.yoga.setMinHeightPercent(value) 163 } 164 setMaxWidth(value: number): void { 165 this.yoga.setMaxWidth(value) 166 } 167 setMaxWidthPercent(value: number): void { 168 this.yoga.setMaxWidthPercent(value) 169 } 170 setMaxHeight(value: number): void { 171 this.yoga.setMaxHeight(value) 172 } 173 setMaxHeightPercent(value: number): void { 174 this.yoga.setMaxHeightPercent(value) 175 } 176 177 setFlexDirection(dir: LayoutFlexDirection): void { 178 const map: Record<LayoutFlexDirection, FlexDirection> = { 179 row: FlexDirection.Row, 180 'row-reverse': FlexDirection.RowReverse, 181 column: FlexDirection.Column, 182 'column-reverse': FlexDirection.ColumnReverse, 183 } 184 this.yoga.setFlexDirection(map[dir]!) 185 } 186 187 setFlexGrow(value: number): void { 188 this.yoga.setFlexGrow(value) 189 } 190 setFlexShrink(value: number): void { 191 this.yoga.setFlexShrink(value) 192 } 193 setFlexBasis(value: number): void { 194 this.yoga.setFlexBasis(value) 195 } 196 setFlexBasisPercent(value: number): void { 197 this.yoga.setFlexBasisPercent(value) 198 } 199 200 setFlexWrap(wrap: LayoutWrap): void { 201 const map: Record<LayoutWrap, Wrap> = { 202 nowrap: Wrap.NoWrap, 203 wrap: Wrap.Wrap, 204 'wrap-reverse': Wrap.WrapReverse, 205 } 206 this.yoga.setFlexWrap(map[wrap]!) 207 } 208 209 setAlignItems(align: LayoutAlign): void { 210 const map: Record<LayoutAlign, Align> = { 211 auto: Align.Auto, 212 stretch: Align.Stretch, 213 'flex-start': Align.FlexStart, 214 center: Align.Center, 215 'flex-end': Align.FlexEnd, 216 } 217 this.yoga.setAlignItems(map[align]!) 218 } 219 220 setAlignSelf(align: LayoutAlign): void { 221 const map: Record<LayoutAlign, Align> = { 222 auto: Align.Auto, 223 stretch: Align.Stretch, 224 'flex-start': Align.FlexStart, 225 center: Align.Center, 226 'flex-end': Align.FlexEnd, 227 } 228 this.yoga.setAlignSelf(map[align]!) 229 } 230 231 setJustifyContent(justify: LayoutJustify): void { 232 const map: Record<LayoutJustify, Justify> = { 233 'flex-start': Justify.FlexStart, 234 center: Justify.Center, 235 'flex-end': Justify.FlexEnd, 236 'space-between': Justify.SpaceBetween, 237 'space-around': Justify.SpaceAround, 238 'space-evenly': Justify.SpaceEvenly, 239 } 240 this.yoga.setJustifyContent(map[justify]!) 241 } 242 243 setDisplay(display: LayoutDisplay): void { 244 this.yoga.setDisplay(display === 'flex' ? Display.Flex : Display.None) 245 } 246 247 getDisplay(): LayoutDisplay { 248 return this.yoga.getDisplay() === Display.None 249 ? LayoutDisplay.None 250 : LayoutDisplay.Flex 251 } 252 253 setPositionType(type: LayoutPositionType): void { 254 this.yoga.setPositionType( 255 type === 'absolute' ? PositionType.Absolute : PositionType.Relative, 256 ) 257 } 258 259 setPosition(edge: LayoutEdge, value: number): void { 260 this.yoga.setPosition(EDGE_MAP[edge]!, value) 261 } 262 263 setPositionPercent(edge: LayoutEdge, value: number): void { 264 this.yoga.setPositionPercent(EDGE_MAP[edge]!, value) 265 } 266 267 setOverflow(overflow: LayoutOverflow): void { 268 const map: Record<LayoutOverflow, Overflow> = { 269 visible: Overflow.Visible, 270 hidden: Overflow.Hidden, 271 scroll: Overflow.Scroll, 272 } 273 this.yoga.setOverflow(map[overflow]!) 274 } 275 276 setMargin(edge: LayoutEdge, value: number): void { 277 this.yoga.setMargin(EDGE_MAP[edge]!, value) 278 } 279 setPadding(edge: LayoutEdge, value: number): void { 280 this.yoga.setPadding(EDGE_MAP[edge]!, value) 281 } 282 setBorder(edge: LayoutEdge, value: number): void { 283 this.yoga.setBorder(EDGE_MAP[edge]!, value) 284 } 285 setGap(gutter: LayoutGutter, value: number): void { 286 this.yoga.setGap(GUTTER_MAP[gutter]!, value) 287 } 288 289 // Lifecycle 290 291 free(): void { 292 this.yoga.free() 293 } 294 freeRecursive(): void { 295 this.yoga.freeRecursive() 296 } 297} 298 299// -- 300// Instance management 301// 302// The TS yoga-layout port is synchronous — no WASM loading, no linear memory 303// growth, so no preload/swap/reset machinery is needed. The Yoga instance is 304// just a plain JS object available at import time. 305 306export function createYogaLayoutNode(): LayoutNode { 307 return new YogaLayoutNode(Yoga.Node.create()) 308}