gesso-core 0.2.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +121 -0
- package/dist/{CanvasSurface-5dU-U3qQ.js → CanvasSurface-BR7hECHm.js} +1075 -72
- package/dist/CanvasSurface-BR7hECHm.js.map +1 -0
- package/dist/{index-DAdauEn9.d.ts → index-BzXn0Bci.d.ts} +854 -12
- package/dist/index.d.ts +2 -2
- package/dist/index.js +756 -577
- package/dist/index.js.map +1 -1
- package/dist/testing.d.ts +10 -1
- package/dist/testing.js +24 -1
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
- package/dist/CanvasSurface-5dU-U3qQ.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as prepareInputSurface, $i as
|
|
1
|
+
import { $ as prepareInputSurface, $a as UiBinding, $i as defaultTextStyle, $n as EditableTextModel, $r as minmax, $t as DEFAULT_FONT_WEIGHT, A as accumulatedOffsetTo, Aa as UiVisualState, Ai as themeExtension, An as setLinkHover, Ar as validateStates, At as proportionalFontMetrics, B as parseFlexDirection, Ba as UiInputEvent, Bi as spacingEqual, Bn as nextCaretToggle, Br as transformsEqual, Bt as layoutTextLines, C as describeLength, Ca as UiNode, Ci as lightTheme, Cn as isNodeTabStop, Cr as UI_ROLES, Ct as selectionRectsIn, D as formatNumber, Da as resetOverrideWarnings, Di as defineThemeExtension, Dn as linkHoverOf, Dr as normalizeStates, Dt as spannedRunsFor, E as formatExplanation, Ea as overrideSources, Ei as withDensity, En as hasTextLinks, Er as isUiSemanticState, Et as ParagraphTextMeasurer, F as constraintsEqual, Fa as MOUSE_POINTER, Fi as raiseContrast, Fn as editorFor, Fr as pathValuesEqual, Ft as applyCanvasTextStyle, G as MainAxisAlignment, Ga as UiSelectionChangeEvent, Gi as boxShadowArraysEqual, Gn as caretRectFor, Gr as radialGradient, Gt as textRunBackgrounds, H as sizeGridTracks, Ha as UiPasteEvent, Hi as defaultShadows, Hn as resolveColorValue, Hr as gradientPaint, Ht as runFontString, I as tightenConstraints, Ia as UiBeforeInputEvent, Ii as relativeLuminance, In as editorOf, Ir as UiTransforms, It as buildFontString, J as parseMainAxisAlignment, Ja as UiWheelEvent, Ji as isShapeName, Jn as lineLimit, Jr as fr, Jt as clearFontStacks, K as parseAlignContent, Ka as UiTextChangeEvent, Ki as boxShadowsEqual, Kn as lineIndexAtY, Kr as validateGradient, Kt as textRunDecorations, L as MAX_MEASURES_PER_CHILD, La as UiEventType, Li as densityFactors, Ln as isEditableNode, Lr as parseTransform, Lt as createCanvasTextStyle, M as LayoutRecord, Ma as hasVisualState, Mi as withThemeExtension, Mn as CARET_WIDTH, Mr as validateSubgrid, Mt as detectEditingPlatform, N as Constraints, Na as visualState, Ni as contrastRatio, Nn as EDITOR_PROP, Nr as inputsEqual, Nt as isPrintable, O as labelNode, Oa as writeDeclaredProperty, Oi as hasThemeExtension, On as linkOf, Or as statesEqual, Ot as ELLIPSIS, P as clampSize, Pa as visualStatesEqual, Pi as highContrastColors, Pn as caretVisibleAt, Pr as paintValuesEqual, Pt as EditableLayout, Q as pointerDeviceOf, Qa as DirtyFlags, Qi as typographyEqual, Qn as selectionRects, Qr as isPercentLength, Qt as DEFAULT_FONT_SIZE, R as isLayoutProtocol, Ra as UiFocusEvent, Ri as defaultSpacing, Rn as isMultiline, Rr as transform, Rt as drawText, S as SCROLLBAR_LINGER_MS, Sa as UiEnvironment, Si as darkTheme, Sn as isNodeSelectable, Sr as UiProperties, St as paragraphGeometryFrom, T as formatConstraints, Ta as clearOverrideProperty, Ti as withContrast, Tn as clearLinkHover, Tr as isUiRole, Tt as CharacterCountTextMeasurer, U as AlignContent, Ua as UiPinchEvent, Ui as shadowsEqual, Un as isVideoSurface, Ur as gradientsEqual, Ut as spanOf, V as placeGridItems, Va as UiKeyboardEvent, Vi as spacingSteps, Vn as syncEditorValue, Vr as MAX_GRADIENT_STOPS, Vt as runCanvasStyleInto, W as CrossAxisAlignment, Wa as UiPointerEvent, Wi as boxShadow, Wn as videoFrameSize, Wr as linearGradient, Wt as textMeasureRequest, X as UiPlatformAdapter, Xa as wheelDeltaYOf, Xi as defaultTypography, Xn as offsetAtX, Xr as isFrLength, Xt as registerFontStack, Y as CanvasPlatformSurface, Ya as noKeyModifiers, Yi as shapesEqual, Yn as offsetAtPoint, Yr as isAutoLength, Yt as fontStackFor, Z as capturePointer, Za as UiNodeType, Zi as isTypographyRole, Zn as offsetForVerticalMove, Zr as isMinMaxTrack, Zt as DEFAULT_FONT_FAMILY, _ as LABEL_PADDING_X, _a as parseColor, _i as observeViewportInsets, _n as selectionRangeOf, _r as inheritedPropertyFlags, _t as scrollbarZoneAt, a as PaintPictureCache, aa as textContentOf, ai as borderRadiusCorners, an as normalizeTextAlign, ar as previousGraphemeStart, at as UiWheelController, b as LayoutEngine, ba as createEnvironmentKey, bi as containerBands, bn as isNodeHitTestable, br as propertyIsInherited, bt as offsetAtPointIn, c as EMPTY_RECORDING, ca as colorsEqualPalette, ci as borderRadiusValuesEqual, cn as DEFAULT_LINE_HEIGHT_FACTOR, cr as resolveBoolean, ct as UiPointerController, d as tracePathData, da as UiBasicColors, di as defineProperty, dn as matchRangesOf, dr as resolvePropertyByName, dt as SCROLLBAR_HOVER_ZONE, ea as editableSpansOf, ei as percent, en as DEFAULT_TEXT_COLOR, er as graphemeBoundaries, et as touchActionFor, f as ScaledImageCache, fa as colorToHex, fi as propertyValuesEqual, fn as setMatchRanges, fr as resolveString, ft as SCROLLBAR_INSET, g as paintsAfterChildren, ga as normalizeColor, gi as noInsets, gn as selectableTextOf, gr as getPropertyNames, gt as scrollbarThumbs, h as hasDecorationPhase, ha as colorsEqual, hi as insetsEqual, hn as selectableTextNodes, hr as findPropertyDefinition, ht as scrollbarThumb, i as traceRoundedRect, ia as spannedTextOf, ii as borderRadius, in as isPaintVisible, ir as nextWordEnd, it as UiPinchRecognizer, j as contentOffset, ja as defaultVisualState, ji as themeExtensionsEqual, jn as CARET_BLINK_MS, jr as UI_SUBGRID_AXES, jt as commandForKey, k as withOverrideSource, ka as writeOverrideProperty, ki as noThemeExtensions, kn as linkRunAtPointIn, kr as validateRole, kt as layoutParagraph, l as PaintRecorder, la as darkColors, li as normalizeBorderRadius, ln as TEXT_MATCHES_PROP, lr as resolveNumber, lt as UiFocusManager, m as decorationRect, ma as colorValuesEqual, mi as UiInsetRegistry, mn as clearSelectionRange, mr as closestPropertyName, mt as SCROLLBAR_THICKNESS, n as createCanvasSurface, na as resolvedSpansOf, ni as resolveLength, nn as computeObjectFitRect, nr as lineStartAt, nt as UiTouchScroller, o as paintPictures, oa as textSpansEqual, oi as borderRadiusEqual, on as normalizeVerticalAlign, or as previousWordStart, ot as isScrollContainer, p as decorationColor, pa as colorToRgba, pi as UiEnvironmentKeys, pn as TEXT_SELECTION_PROP, pr as UiGraph, pt as SCROLLBAR_MIN_THUMB, q as parseCrossAxisAlignment, qa as UiWheelDeltaMode, qi as defaultShapes, qn as lineIndexForOffset, qr as auto, qt as bumpFontStack, r as Canvas2DRenderer, ra as spanAtOffset, ri as UiBorderRadiuses, rn as createPaintState, rr as nextGraphemeEnd, rt as UiGestureRecognizer, s as PaintTarget, sa as textStylesEqual, si as borderRadiusIsZero, sn as resolvePaintState, sr as wordRangeAt, st as UiKeyboardController, t as CanvasSurface, ta as flattenTextSpans, ti as repeat, tn as colorToCss, tr as lineEndAt, tt as UiEditingController, u as replayPaint, ua as lightColors, ui as uniformBorderRadius, un as clearMatchRanges, ur as resolveProperty, ut as UiHitTester, v as drawOverlayShapes, va as rgb8, vi as UiContainerSizeSource, vn as setSelectionRange, vr as inheritedPropertyNames, vt as UiInputDispatcher, w as describeOverrides, wa as DirtyNodeSet, wi as themesEqual, wn as resolveCursor, wr as UI_SEMANTIC_STATES, wt as wordRangeIn, x as SCROLLBAR_FADE_MS, xa as findEnvironmentKey, xi as unknownContainerSize, xn as isNodeInert, xr as propertyValuesEqualByName, xt as paragraphGeometry, y as labelOrigin, ya as rgba, yi as bandOf, yn as isNodeFocusable, yr as propertyEffects, yt as hasDrawnText, z as FlexDirection, za as UiGestureEvent, zi as scaleSpacing, zn as isReadOnly, zr as transformIsIdentity, zt as fillTextRects } from "./CanvasSurface-BR7hECHm.js";
|
|
2
2
|
import { BehaviorSubject, EMPTY, Subject, combineLatest, distinctUntilChanged, isObservable as isObservable$1, map, of } from "rxjs";
|
|
3
3
|
//#region src/animation/UiEasing.ts
|
|
4
4
|
/** Progress equals time. What a spinner and a sweep want. */
|
|
@@ -1425,10 +1425,13 @@ const EVENT_PROPS = {
|
|
|
1425
1425
|
onKeyDown: "keydown",
|
|
1426
1426
|
onKeyUp: "keyup",
|
|
1427
1427
|
onFocus: "focus",
|
|
1428
|
+
onPaste: "paste",
|
|
1428
1429
|
onBlur: "blur",
|
|
1429
1430
|
onBeforeInput: "beforeinput",
|
|
1430
1431
|
onInput: "input",
|
|
1432
|
+
onSelectionChange: "selectionchange",
|
|
1431
1433
|
onClick: "click",
|
|
1434
|
+
onDoubleClick: "doubleclick",
|
|
1432
1435
|
onLongPress: "longpress",
|
|
1433
1436
|
onDragStart: "dragstart",
|
|
1434
1437
|
onDragMove: "dragmove",
|
|
@@ -2883,7 +2886,7 @@ var UiVirtualWindow = class {
|
|
|
2883
2886
|
const total = this.totalExtent();
|
|
2884
2887
|
const header = viewport.lead ?? 0;
|
|
2885
2888
|
this.checkViewport(viewport.extent, total + header);
|
|
2886
|
-
const scrolled = clamp$
|
|
2889
|
+
const scrolled = clamp$2(viewport.scroll + scrollAdjust, 0, Math.max(0, total + header - viewport.extent));
|
|
2887
2890
|
const scroll = Math.max(0, scrolled - header);
|
|
2888
2891
|
let first = 0;
|
|
2889
2892
|
let last = -1;
|
|
@@ -3054,7 +3057,7 @@ function markRow(row, props, subject) {
|
|
|
3054
3057
|
}
|
|
3055
3058
|
};
|
|
3056
3059
|
}
|
|
3057
|
-
function clamp$
|
|
3060
|
+
function clamp$2(value, min, max) {
|
|
3058
3061
|
return Math.min(Math.max(value, min), max);
|
|
3059
3062
|
}
|
|
3060
3063
|
function assertCount(count) {
|
|
@@ -3074,10 +3077,10 @@ function assertCount(count) {
|
|
|
3074
3077
|
const lazySource = defineModifier({
|
|
3075
3078
|
name: "lazySource",
|
|
3076
3079
|
attach(host, args) {
|
|
3077
|
-
follow$
|
|
3080
|
+
follow$2(host, args.count, (value) => args.window.setCount(value));
|
|
3078
3081
|
if (args.revision !== void 0) {
|
|
3079
3082
|
let first = true;
|
|
3080
|
-
follow$
|
|
3083
|
+
follow$2(host, args.revision, () => {
|
|
3081
3084
|
if (first) {
|
|
3082
3085
|
first = false;
|
|
3083
3086
|
return;
|
|
@@ -3087,7 +3090,7 @@ const lazySource = defineModifier({
|
|
|
3087
3090
|
}
|
|
3088
3091
|
}
|
|
3089
3092
|
});
|
|
3090
|
-
function follow$
|
|
3093
|
+
function follow$2(host, source, apply) {
|
|
3091
3094
|
if (!isObservable$1(source)) {
|
|
3092
3095
|
apply(source);
|
|
3093
3096
|
return;
|
|
@@ -3287,120 +3290,609 @@ function Responsive(props, build) {
|
|
|
3287
3290
|
}, [children]);
|
|
3288
3291
|
}
|
|
3289
3292
|
//#endregion
|
|
3290
|
-
//#region src/
|
|
3291
|
-
/**
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
}
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
*
|
|
3303
|
-
*
|
|
3304
|
-
*
|
|
3305
|
-
*
|
|
3306
|
-
*
|
|
3307
|
-
*
|
|
3308
|
-
*
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3293
|
+
//#region src/composition/UiVirtualSheet.ts
|
|
3294
|
+
/** The sheet sits on its scroll container under this property. */
|
|
3295
|
+
const VIRTUAL_SHEET_PROP = "virtualSheet";
|
|
3296
|
+
const EMPTY_RANGE = {
|
|
3297
|
+
firstRow: 0,
|
|
3298
|
+
lastRow: -1,
|
|
3299
|
+
firstColumn: 0,
|
|
3300
|
+
lastColumn: -1
|
|
3301
|
+
};
|
|
3302
|
+
var UiVirtualSheet = class {
|
|
3303
|
+
children$ = new BehaviorSubject([]);
|
|
3304
|
+
/**
|
|
3305
|
+
* The range now mounted, for whoever has to fetch the values in it.
|
|
3306
|
+
*
|
|
3307
|
+
* This is the whole reason the window is reachable from outside: the
|
|
3308
|
+
* render thread does not hold the cells, so the range it settles on
|
|
3309
|
+
* each frame is what it asks the application thread for. Emits only
|
|
3310
|
+
* when the range changes, so binding a command to it does not send
|
|
3311
|
+
* one per frame.
|
|
3312
|
+
*/
|
|
3313
|
+
range$ = new BehaviorSubject(EMPTY_RANGE);
|
|
3314
|
+
rowCount;
|
|
3315
|
+
columnCount;
|
|
3316
|
+
rowOverscan;
|
|
3317
|
+
columnOverscan;
|
|
3318
|
+
rowHeight;
|
|
3319
|
+
gutterWidth;
|
|
3320
|
+
headerHeight;
|
|
3321
|
+
frozenRows;
|
|
3322
|
+
frozenColumns;
|
|
3323
|
+
renderRow;
|
|
3324
|
+
renderHeader;
|
|
3325
|
+
extendRange;
|
|
3326
|
+
/** One width per column, or undefined when every column is the same. */
|
|
3327
|
+
widths;
|
|
3328
|
+
/** `offsets[c]` is where column `c` starts, measured past the gutter. */
|
|
3329
|
+
offsets = [];
|
|
3330
|
+
uniformWidth = 0;
|
|
3331
|
+
/**
|
|
3332
|
+
* The rows that are not `rowHeight` tall, in row order.
|
|
3333
|
+
*
|
|
3334
|
+
* Three parallel arrays rather than a map of objects: this is
|
|
3335
|
+
* searched on every hit test and on every frame that scrolls, and
|
|
3336
|
+
* the arrays are read in step.
|
|
3337
|
+
*/
|
|
3338
|
+
exceptionRows = [];
|
|
3339
|
+
exceptionHeights = [];
|
|
3340
|
+
/** `exceptionStarts[i]` is where `exceptionRows[i]` starts, past the header. */
|
|
3341
|
+
exceptionStarts = [];
|
|
3342
|
+
range = EMPTY_RANGE;
|
|
3343
|
+
viewport;
|
|
3344
|
+
/** Rows built for the current column range, so a vertical scroll rebuilds one row. */
|
|
3345
|
+
mountedRows = /* @__PURE__ */ new Map();
|
|
3346
|
+
/** The frozen rows, kept separately because they never leave. */
|
|
3347
|
+
frozenMounted = /* @__PURE__ */ new Map();
|
|
3348
|
+
mountedHeader;
|
|
3349
|
+
constructor(options, renderRow, renderHeader) {
|
|
3350
|
+
this.rowCount = typeof options.rowCount === "number" ? options.rowCount : 0;
|
|
3351
|
+
this.columnCount = typeof options.columnCount === "number" ? options.columnCount : 0;
|
|
3352
|
+
this.rowHeight = positive("rowHeight", options.rowHeight);
|
|
3353
|
+
this.adoptHeights(options.rowHeights);
|
|
3354
|
+
this.gutterWidth = Math.max(0, options.gutterWidth ?? 0);
|
|
3355
|
+
this.headerHeight = Math.max(0, options.headerHeight ?? 0);
|
|
3356
|
+
this.frozenRows = Math.max(0, Math.floor(options.frozenRows ?? 0));
|
|
3357
|
+
this.frozenColumns = Math.max(0, Math.floor(options.frozenColumns ?? 0));
|
|
3358
|
+
this.rowOverscan = typeof options.rowOverscan === "number" ? options.rowOverscan : 3;
|
|
3359
|
+
this.columnOverscan = typeof options.columnOverscan === "number" ? options.columnOverscan : 2;
|
|
3360
|
+
this.renderRow = renderRow;
|
|
3361
|
+
this.renderHeader = renderHeader;
|
|
3362
|
+
this.extendRange = options.extendRange;
|
|
3363
|
+
this.adoptWidths(options.columnWidth);
|
|
3364
|
+
this.viewport = {
|
|
3365
|
+
scrollX: 0,
|
|
3366
|
+
scrollY: 0,
|
|
3367
|
+
width: options.initialViewport?.width ?? 800,
|
|
3368
|
+
height: options.initialViewport?.height ?? 600
|
|
3369
|
+
};
|
|
3370
|
+
this.recompute();
|
|
3371
|
+
}
|
|
3372
|
+
/**
|
|
3373
|
+
* New column widths, as a drag on a header edge produces.
|
|
3374
|
+
*
|
|
3375
|
+
* The prefix sum is rebuilt whole. It is one pass over the columns
|
|
3376
|
+
* and it happens once per frame of a drag at most, against a
|
|
3377
|
+
* per-column offset that would otherwise have to be corrected
|
|
3378
|
+
* everywhere downstream of the column that moved.
|
|
3379
|
+
*/
|
|
3380
|
+
setColumnWidths(widths) {
|
|
3381
|
+
this.adoptWidths(widths);
|
|
3382
|
+
this.invalidate();
|
|
3383
|
+
}
|
|
3384
|
+
adoptWidths(widths) {
|
|
3385
|
+
if (typeof widths === "number") {
|
|
3386
|
+
this.uniformWidth = positive("columnWidth", widths);
|
|
3387
|
+
this.widths = void 0;
|
|
3388
|
+
this.offsets = [];
|
|
3389
|
+
return;
|
|
3335
3390
|
}
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3391
|
+
const owned = widths.slice();
|
|
3392
|
+
for (const width of owned) if (!(width >= 0)) throw new Error(`LazySheet column widths must not be negative, got ${String(width)}.`);
|
|
3393
|
+
this.widths = owned;
|
|
3394
|
+
this.offsets = Array.from({ length: owned.length + 1 });
|
|
3395
|
+
let running = 0;
|
|
3396
|
+
for (let column = 0; column < owned.length; column++) {
|
|
3397
|
+
this.offsets[column] = running;
|
|
3398
|
+
running += owned[column];
|
|
3399
|
+
}
|
|
3400
|
+
this.offsets[owned.length] = running;
|
|
3401
|
+
}
|
|
3402
|
+
/**
|
|
3403
|
+
* New row heights, as hiding a row or autofitting one produces.
|
|
3404
|
+
*
|
|
3405
|
+
* The exceptions are rebuilt whole, which is one pass over *them*
|
|
3406
|
+
* and not over the rows — the whole reason they are sparse. A
|
|
3407
|
+
* height of zero is a hidden row and is allowed; a negative one is
|
|
3408
|
+
* not.
|
|
3409
|
+
*/
|
|
3410
|
+
setRowHeights(heights) {
|
|
3411
|
+
this.adoptHeights(heights);
|
|
3412
|
+
this.invalidate();
|
|
3413
|
+
}
|
|
3414
|
+
/** The height every row has unless it is an exception. */
|
|
3415
|
+
setRowHeight(height) {
|
|
3416
|
+
const next = positive("rowHeight", height);
|
|
3417
|
+
if (next === this.rowHeight) return;
|
|
3418
|
+
this.rowHeight = next;
|
|
3419
|
+
this.rebuildExceptionStarts();
|
|
3420
|
+
this.invalidate();
|
|
3421
|
+
}
|
|
3422
|
+
adoptHeights(heights) {
|
|
3423
|
+
this.exceptionRows = [];
|
|
3424
|
+
this.exceptionHeights = [];
|
|
3425
|
+
if (heights !== void 0) {
|
|
3426
|
+
const rows = [...heights.keys()].sort((a, b) => a - b);
|
|
3427
|
+
for (const row of rows) {
|
|
3428
|
+
const height = heights.get(row) ?? 0;
|
|
3429
|
+
if (!(height >= 0)) throw new Error(`LazySheet row heights must not be negative, got ${String(height)}.`);
|
|
3430
|
+
if (height !== this.rowHeight) {
|
|
3431
|
+
this.exceptionRows.push(row);
|
|
3432
|
+
this.exceptionHeights.push(height);
|
|
3433
|
+
}
|
|
3434
|
+
}
|
|
3435
|
+
}
|
|
3436
|
+
this.rebuildExceptionStarts();
|
|
3437
|
+
}
|
|
3438
|
+
/**
|
|
3439
|
+
* Where each exception begins, and what they cost in total.
|
|
3440
|
+
*
|
|
3441
|
+
* `start` is the row's own offset past the header, so the inverse —
|
|
3442
|
+
* `rowAt` — can binary search it directly rather than reconstructing
|
|
3443
|
+
* it per probe.
|
|
3444
|
+
*/
|
|
3445
|
+
rebuildExceptionStarts() {
|
|
3446
|
+
this.exceptionStarts = Array.from({ length: this.exceptionRows.length });
|
|
3447
|
+
let extra = 0;
|
|
3448
|
+
for (let index = 0; index < this.exceptionRows.length; index++) {
|
|
3449
|
+
this.exceptionStarts[index] = this.exceptionRows[index] * this.rowHeight + extra;
|
|
3450
|
+
extra += this.exceptionHeights[index] - this.rowHeight;
|
|
3451
|
+
}
|
|
3452
|
+
}
|
|
3453
|
+
/** The index of the last exception starting at or before an offset, or -1. */
|
|
3454
|
+
exceptionAt(offset) {
|
|
3455
|
+
let low = 0;
|
|
3456
|
+
let high = this.exceptionStarts.length - 1;
|
|
3457
|
+
let found = -1;
|
|
3458
|
+
while (low <= high) {
|
|
3459
|
+
const mid = low + high >> 1;
|
|
3460
|
+
if (this.exceptionStarts[mid] <= offset) {
|
|
3461
|
+
found = mid;
|
|
3462
|
+
low = mid + 1;
|
|
3463
|
+
} else high = mid - 1;
|
|
3464
|
+
}
|
|
3465
|
+
return found;
|
|
3466
|
+
}
|
|
3467
|
+
/** How many exceptions come before a row, as an index into them. */
|
|
3468
|
+
exceptionsBefore(row) {
|
|
3469
|
+
let low = 0;
|
|
3470
|
+
let high = this.exceptionRows.length;
|
|
3471
|
+
while (low < high) {
|
|
3472
|
+
const mid = low + high >> 1;
|
|
3473
|
+
if (this.exceptionRows[mid] < row) low = mid + 1;
|
|
3474
|
+
else high = mid;
|
|
3351
3475
|
}
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3476
|
+
return low;
|
|
3477
|
+
}
|
|
3478
|
+
/** The height of one row. Zero when it is hidden. */
|
|
3479
|
+
rowHeightOf(row) {
|
|
3480
|
+
if (this.exceptionRows.length === 0) return this.rowHeight;
|
|
3481
|
+
const index = this.exceptionsBefore(row);
|
|
3482
|
+
return this.exceptionRows[index] === row ? this.exceptionHeights[index] : this.rowHeight;
|
|
3483
|
+
}
|
|
3484
|
+
/** Where a row starts, measured past the header. */
|
|
3485
|
+
rowOffsetOf(row) {
|
|
3486
|
+
const clamped = clamp$1(row, 0, this.rowCount);
|
|
3487
|
+
return clamped * this.rowHeight + this.extraWithin(clamped);
|
|
3488
|
+
}
|
|
3489
|
+
/** Total height of the rows, not counting the header. */
|
|
3490
|
+
get rowsHeight() {
|
|
3491
|
+
return this.rowCount * this.rowHeight + this.extraWithin(this.rowCount);
|
|
3492
|
+
}
|
|
3493
|
+
/**
|
|
3494
|
+
* What the exceptions before `row` add to or take off the offset.
|
|
3495
|
+
*
|
|
3496
|
+
* Read off the last exception before it rather than summed: the
|
|
3497
|
+
* start of an exception already carries everything before it, so
|
|
3498
|
+
* its end minus where it *would* have ended is the running total.
|
|
3499
|
+
*/
|
|
3500
|
+
extraWithin(row) {
|
|
3501
|
+
const before = this.exceptionsBefore(row);
|
|
3502
|
+
if (before === 0) return 0;
|
|
3503
|
+
const index = before - 1;
|
|
3504
|
+
return this.exceptionStarts[index] + this.exceptionHeights[index] - (this.exceptionRows[index] + 1) * this.rowHeight;
|
|
3505
|
+
}
|
|
3506
|
+
/** The width of one column. */
|
|
3507
|
+
widthOf(column) {
|
|
3508
|
+
if (this.widths === void 0) return this.uniformWidth;
|
|
3509
|
+
return this.widths[column] ?? 0;
|
|
3510
|
+
}
|
|
3511
|
+
/** Where a column starts, measured past the gutter. */
|
|
3512
|
+
offsetOf(column) {
|
|
3513
|
+
if (this.widths === void 0) return column * this.uniformWidth;
|
|
3514
|
+
const clamped = clamp$1(column, 0, this.offsets.length - 1);
|
|
3515
|
+
return this.offsets[clamped] ?? 0;
|
|
3516
|
+
}
|
|
3517
|
+
/** Total width of the columns, not counting the gutter. */
|
|
3518
|
+
get columnsWidth() {
|
|
3519
|
+
return this.widths === void 0 ? this.columnCount * this.uniformWidth : this.offsets[this.widths.length] ?? 0;
|
|
3520
|
+
}
|
|
3521
|
+
get contentWidth() {
|
|
3522
|
+
return this.gutterWidth + this.columnsWidth;
|
|
3523
|
+
}
|
|
3524
|
+
/** Where the scrolled columns begin, past the gutter and the frozen ones. */
|
|
3525
|
+
get frozenWidth() {
|
|
3526
|
+
return this.offsetOf(this.frozenColumns);
|
|
3527
|
+
}
|
|
3528
|
+
get contentHeight() {
|
|
3529
|
+
return this.headerHeight + this.rowsHeight;
|
|
3530
|
+
}
|
|
3531
|
+
/**
|
|
3532
|
+
* The cell under a point in the scroll container's own coordinates.
|
|
3533
|
+
*
|
|
3534
|
+
* The window already knows where everything is and how far it is
|
|
3535
|
+
* scrolled, which is the whole of this: a drag towards a cell — a
|
|
3536
|
+
* fill handle, a selection being stretched — is usually heading for
|
|
3537
|
+
* one that has not been mounted, so there is no node to hit-test and
|
|
3538
|
+
* arithmetic is the only answer available.
|
|
3539
|
+
*/
|
|
3540
|
+
cellAt(x, y) {
|
|
3541
|
+
return {
|
|
3542
|
+
row: this.rowAt(this.viewport.scrollY + y),
|
|
3543
|
+
column: this.columnAt(this.viewport.scrollX + x)
|
|
3357
3544
|
};
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3545
|
+
}
|
|
3546
|
+
/**
|
|
3547
|
+
* The row at a content offset, clamped to the sheet.
|
|
3548
|
+
*
|
|
3549
|
+
* A division when every row is the default height — the common case
|
|
3550
|
+
* by a very long way — and otherwise a binary search over the
|
|
3551
|
+
* exceptions followed by a division inside the uniform run that
|
|
3552
|
+
* follows the one it lands in.
|
|
3553
|
+
*
|
|
3554
|
+
* A hidden row occupies no offset at all, so the offset where it
|
|
3555
|
+
* *would* be belongs to the row after it. That falls out of the
|
|
3556
|
+
* arithmetic rather than being special-cased: a zero-height
|
|
3557
|
+
* exception starts and ends at the same place, so the point is
|
|
3558
|
+
* never inside it.
|
|
3559
|
+
*/
|
|
3560
|
+
rowAt(offset) {
|
|
3561
|
+
const last = Math.max(0, this.rowCount - 1);
|
|
3562
|
+
const past = offset - this.headerHeight;
|
|
3563
|
+
if (this.exceptionRows.length === 0) return clamp$1(Math.floor(past / this.rowHeight), 0, last);
|
|
3564
|
+
if (past <= 0) return 0;
|
|
3565
|
+
const index = this.exceptionAt(past);
|
|
3566
|
+
if (index === -1) return clamp$1(Math.floor(past / this.rowHeight), 0, last);
|
|
3567
|
+
const start = this.exceptionStarts[index];
|
|
3568
|
+
const height = this.exceptionHeights[index];
|
|
3569
|
+
if (past < start + height) return clamp$1(this.exceptionRows[index], 0, last);
|
|
3570
|
+
return clamp$1(this.exceptionRows[index] + 1 + Math.floor((past - start - height) / this.rowHeight), 0, last);
|
|
3571
|
+
}
|
|
3572
|
+
/**
|
|
3573
|
+
* The column at a content offset, clamped to the sheet.
|
|
3574
|
+
*
|
|
3575
|
+
* A binary search over the prefix sum when the columns differ, and
|
|
3576
|
+
* a division when they do not — the uniform case is the common one
|
|
3577
|
+
* and should not pay for the general one.
|
|
3578
|
+
*/
|
|
3579
|
+
columnAt(offset) {
|
|
3580
|
+
const last = Math.max(0, this.columnCount - 1);
|
|
3581
|
+
const past = offset - this.gutterWidth;
|
|
3582
|
+
if (this.widths === void 0) return clamp$1(Math.floor(past / this.uniformWidth), 0, last);
|
|
3583
|
+
if (past <= 0) return 0;
|
|
3584
|
+
if (past >= this.columnsWidth) return last;
|
|
3585
|
+
let low = 0;
|
|
3586
|
+
let high = last;
|
|
3587
|
+
while (low < high) {
|
|
3588
|
+
const mid = low + high + 1 >> 1;
|
|
3589
|
+
if (this.offsets[mid] <= past) low = mid;
|
|
3590
|
+
else high = mid - 1;
|
|
3591
|
+
}
|
|
3592
|
+
return low;
|
|
3593
|
+
}
|
|
3594
|
+
setRowCount(count) {
|
|
3595
|
+
if (count === this.rowCount) return;
|
|
3596
|
+
this.rowCount = Math.max(0, Math.floor(count));
|
|
3597
|
+
this.invalidate();
|
|
3598
|
+
}
|
|
3599
|
+
setColumnCount(count) {
|
|
3600
|
+
if (count === this.columnCount) return;
|
|
3601
|
+
this.columnCount = Math.max(0, Math.floor(count));
|
|
3602
|
+
this.invalidate();
|
|
3603
|
+
}
|
|
3604
|
+
/**
|
|
3605
|
+
* The bands, which the spike tunes from the screen.
|
|
3606
|
+
*
|
|
3607
|
+
* A band is the only defence against the round trip to the
|
|
3608
|
+
* application thread: rows inside it already hold their values when
|
|
3609
|
+
* the scroll reaches them. Widening it costs nodes on every frame
|
|
3610
|
+
* and cells on every publish, so what it should be is a measurement,
|
|
3611
|
+
* not a default — hence setters rather than a constant.
|
|
3612
|
+
*/
|
|
3613
|
+
setOverscan(rows, columns) {
|
|
3614
|
+
const nextRows = Math.max(0, Math.floor(rows));
|
|
3615
|
+
const nextColumns = Math.max(0, Math.floor(columns));
|
|
3616
|
+
if (nextRows === this.rowOverscan && nextColumns === this.columnOverscan) return;
|
|
3617
|
+
this.rowOverscan = nextRows;
|
|
3618
|
+
this.columnOverscan = nextColumns;
|
|
3619
|
+
this.invalidate();
|
|
3620
|
+
}
|
|
3621
|
+
/**
|
|
3622
|
+
* How many rows and columns stay put while the rest scrolls.
|
|
3623
|
+
*
|
|
3624
|
+
* Freezing changes which rows are in the scrolled window, so every
|
|
3625
|
+
* mounted row is rebuilt — a row that was scrolling is now frozen
|
|
3626
|
+
* or the other way about.
|
|
3627
|
+
*/
|
|
3628
|
+
setFrozen(rows, columns) {
|
|
3629
|
+
const nextRows = Math.max(0, Math.floor(rows));
|
|
3630
|
+
const nextColumns = Math.max(0, Math.floor(columns));
|
|
3631
|
+
if (nextRows === this.frozenRows && nextColumns === this.frozenColumns) return;
|
|
3632
|
+
this.frozenRows = nextRows;
|
|
3633
|
+
this.frozenColumns = nextColumns;
|
|
3634
|
+
this.invalidate();
|
|
3635
|
+
}
|
|
3636
|
+
/** Drops every mounted row and rebuilds against the last viewport. */
|
|
3637
|
+
invalidate() {
|
|
3638
|
+
this.mountedRows.clear();
|
|
3639
|
+
this.frozenMounted.clear();
|
|
3640
|
+
this.mountedHeader = void 0;
|
|
3641
|
+
this.range = EMPTY_RANGE;
|
|
3642
|
+
this.recompute();
|
|
3643
|
+
}
|
|
3644
|
+
/**
|
|
3645
|
+
* One step, run by the host each frame before layout.
|
|
3646
|
+
*
|
|
3647
|
+
* Nothing is measured and nothing is anchored: the offsets are exact,
|
|
3648
|
+
* so the rows a scroll reveals are placed correctly on the frame
|
|
3649
|
+
* that reveals them rather than corrected on the one after.
|
|
3650
|
+
*/
|
|
3651
|
+
update(viewport) {
|
|
3652
|
+
this.viewport = viewport;
|
|
3653
|
+
this.recompute();
|
|
3654
|
+
}
|
|
3655
|
+
recompute() {
|
|
3656
|
+
const next = this.windowFor(this.viewport);
|
|
3657
|
+
if (sameRange(next, this.range)) return;
|
|
3658
|
+
if (next.firstColumn !== this.range.firstColumn || next.lastColumn !== this.range.lastColumn) {
|
|
3659
|
+
this.mountedRows.clear();
|
|
3660
|
+
this.frozenMounted.clear();
|
|
3661
|
+
this.mountedHeader = void 0;
|
|
3662
|
+
}
|
|
3663
|
+
this.range = next;
|
|
3664
|
+
this.children$.next(this.buildChildren());
|
|
3665
|
+
this.range$.next(next);
|
|
3666
|
+
}
|
|
3667
|
+
/**
|
|
3668
|
+
* The window, in content coordinates.
|
|
3669
|
+
*
|
|
3670
|
+
* The header and the gutter are *content*: they occupy the first
|
|
3671
|
+
* `headerHeight` pixels and the first `gutterWidth`, and `rowAt` and
|
|
3672
|
+
* `columnAt` already subtract them. So the range comes out slightly
|
|
3673
|
+
* generous at the near edges — the rows a header is covering are
|
|
3674
|
+
* mounted, and the columns behind the gutter are too — which is
|
|
3675
|
+
* correct rather than wasteful, since a sticky strip is drawn over
|
|
3676
|
+
* cells that are really there.
|
|
3677
|
+
*/
|
|
3678
|
+
windowFor(viewport) {
|
|
3679
|
+
if (this.rowCount === 0 || this.columnCount === 0) return EMPTY_RANGE;
|
|
3680
|
+
const firstRow = Math.max(this.frozenRows, this.rowAt(viewport.scrollY) - this.rowOverscan);
|
|
3681
|
+
const lastRow = Math.min(this.rowCount - 1, this.rowAt(viewport.scrollY + Math.max(0, viewport.height)) + this.rowOverscan);
|
|
3682
|
+
const firstColumn = Math.max(this.frozenColumns, this.columnAt(viewport.scrollX) - this.columnOverscan);
|
|
3683
|
+
const lastColumn = Math.min(this.columnCount - 1, this.columnAt(viewport.scrollX + Math.max(0, viewport.width)) + this.columnOverscan);
|
|
3684
|
+
const range = {
|
|
3685
|
+
firstRow,
|
|
3686
|
+
lastRow,
|
|
3687
|
+
firstColumn,
|
|
3688
|
+
lastColumn
|
|
3363
3689
|
};
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
kind: "delete",
|
|
3372
|
-
unit: word ? "word" : "grapheme",
|
|
3373
|
-
direction: -1
|
|
3374
|
-
};
|
|
3375
|
-
case "Delete": return {
|
|
3376
|
-
kind: "delete",
|
|
3377
|
-
unit: word ? "word" : "grapheme",
|
|
3378
|
-
direction: 1
|
|
3690
|
+
if (this.extendRange === void 0) return range;
|
|
3691
|
+
const wanted = this.extendRange(range);
|
|
3692
|
+
return {
|
|
3693
|
+
firstRow: clamp$1(Math.min(wanted.firstRow, firstRow), this.frozenRows, firstRow),
|
|
3694
|
+
lastRow: clamp$1(Math.max(wanted.lastRow, lastRow), lastRow, this.rowCount - 1),
|
|
3695
|
+
firstColumn: clamp$1(Math.min(wanted.firstColumn, firstColumn), this.frozenColumns, firstColumn),
|
|
3696
|
+
lastColumn: clamp$1(Math.max(wanted.lastColumn, lastColumn), lastColumn, this.columnCount - 1)
|
|
3379
3697
|
};
|
|
3380
|
-
case "Enter": return primary ? null : { kind: "newline" };
|
|
3381
3698
|
}
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3699
|
+
buildChildren() {
|
|
3700
|
+
const { firstRow, lastRow, firstColumn, lastColumn } = this.range;
|
|
3701
|
+
if (lastRow < firstRow) return [];
|
|
3702
|
+
const width = this.contentWidth;
|
|
3703
|
+
const lead = this.offsetOf(firstColumn) - this.frozenWidth;
|
|
3704
|
+
const children = [];
|
|
3705
|
+
if (this.renderHeader !== void 0) {
|
|
3706
|
+
this.mountedHeader ??= this.wrapHeader(this.renderHeader(firstColumn, lastColumn), width, lead);
|
|
3707
|
+
children.push(this.mountedHeader);
|
|
3708
|
+
}
|
|
3709
|
+
for (let row = 0; row < this.frozenRows && row < this.rowCount; row++) {
|
|
3710
|
+
let built = this.frozenMounted.get(row);
|
|
3711
|
+
if (built === void 0) {
|
|
3712
|
+
built = this.wrap(row, width, lead);
|
|
3713
|
+
this.frozenMounted.set(row, built);
|
|
3714
|
+
}
|
|
3715
|
+
children.push(built);
|
|
3716
|
+
}
|
|
3717
|
+
children.push(spacer("sheet:top", this.rowOffsetOf(firstRow) - this.rowOffsetOf(this.frozenRows)));
|
|
3718
|
+
for (const row of this.mountedRows.keys()) if (row < firstRow || row > lastRow) this.mountedRows.delete(row);
|
|
3719
|
+
for (let row = firstRow; row <= lastRow; row++) {
|
|
3720
|
+
let built = this.mountedRows.get(row);
|
|
3721
|
+
if (built === void 0) {
|
|
3722
|
+
built = this.wrap(row, width, lead);
|
|
3723
|
+
this.mountedRows.set(row, built);
|
|
3724
|
+
}
|
|
3725
|
+
children.push(built);
|
|
3387
3726
|
}
|
|
3388
|
-
|
|
3727
|
+
children.push(spacer("sheet:bottom", this.rowsHeight - this.rowOffsetOf(lastRow + 1)));
|
|
3728
|
+
return children;
|
|
3389
3729
|
}
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3730
|
+
/**
|
|
3731
|
+
* The header, given the same geometry a row gets.
|
|
3732
|
+
*
|
|
3733
|
+
* Its own children are laid out exactly like a row's, so that a
|
|
3734
|
+
* column header lines up with the column under it without either
|
|
3735
|
+
* being told where the other is: the same leading spacer, the same
|
|
3736
|
+
* gutter-sized first cell, the same widths.
|
|
3737
|
+
*/
|
|
3738
|
+
wrapHeader(built, width, lead) {
|
|
3739
|
+
if (!isRowElement(built)) throw new Error("A sheet's header must be a Row element, laid out like the rows it labels.");
|
|
3740
|
+
return {
|
|
3741
|
+
...built,
|
|
3742
|
+
props: {
|
|
3743
|
+
...built.props,
|
|
3744
|
+
key: "sheet:header",
|
|
3745
|
+
width,
|
|
3746
|
+
height: this.headerHeight,
|
|
3747
|
+
flexShrink: 0
|
|
3748
|
+
},
|
|
3749
|
+
children: this.withLead(built.children, lead)
|
|
3750
|
+
};
|
|
3751
|
+
}
|
|
3752
|
+
/**
|
|
3753
|
+
* A row's children with the leading spacer in the right place.
|
|
3754
|
+
*
|
|
3755
|
+
* With a gutter, the renderer's first child *is* the gutter: it sits
|
|
3756
|
+
* at content x 0 and the columns begin past it, so the spacer for
|
|
3757
|
+
* the columns scrolled out of view goes after it. Without one the
|
|
3758
|
+
* spacer goes first. Either way the renderer is handed a range of
|
|
3759
|
+
* columns and never has to know where the window is.
|
|
3760
|
+
*/
|
|
3761
|
+
withLead(children, lead) {
|
|
3762
|
+
const pad = spacer("sheet:lead", void 0, lead);
|
|
3763
|
+
const stays = (this.gutterWidth > 0 ? 1 : 0) + this.frozenColumns;
|
|
3764
|
+
if (stays === 0) return [pad, ...children];
|
|
3765
|
+
return [
|
|
3766
|
+
...children.slice(0, stays),
|
|
3767
|
+
pad,
|
|
3768
|
+
...children.slice(stays)
|
|
3769
|
+
];
|
|
3770
|
+
}
|
|
3771
|
+
/**
|
|
3772
|
+
* The row the renderer returned, given its place in the sheet.
|
|
3773
|
+
*
|
|
3774
|
+
* The leading spacer is prepended here rather than asked of the
|
|
3775
|
+
* renderer, because it is windowing bookkeeping and not a cell: it is
|
|
3776
|
+
* what puts column `firstColumn` at its own offset without the row
|
|
3777
|
+
* holding the columns to its left.
|
|
3778
|
+
*/
|
|
3779
|
+
wrap(row, width, lead) {
|
|
3780
|
+
const built = this.renderRow(row, this.range.firstColumn, this.range.lastColumn);
|
|
3781
|
+
if (!isRowElement(built)) throw new Error(`A sheet row must be a Row element; row ${row} rendered something else. Its cells are laid out along one axis at widths the window already knows.`);
|
|
3782
|
+
return {
|
|
3783
|
+
...built,
|
|
3784
|
+
props: {
|
|
3785
|
+
...built.props,
|
|
3786
|
+
key: `sheet:row:${row}`,
|
|
3787
|
+
width,
|
|
3788
|
+
height: this.rowHeightOf(row),
|
|
3789
|
+
flexShrink: 0
|
|
3790
|
+
},
|
|
3791
|
+
children: this.withLead(built.children, lead)
|
|
3792
|
+
};
|
|
3793
|
+
}
|
|
3794
|
+
};
|
|
3795
|
+
function spacer(key, height, width) {
|
|
3796
|
+
return Box({
|
|
3797
|
+
key,
|
|
3798
|
+
height,
|
|
3799
|
+
width,
|
|
3800
|
+
flexShrink: 0
|
|
3801
|
+
});
|
|
3802
|
+
}
|
|
3803
|
+
function isRowElement(child) {
|
|
3804
|
+
return typeof child === "object" && child !== null && child.type === "row" && Array.isArray(child.children);
|
|
3805
|
+
}
|
|
3806
|
+
function sameRange(a, b) {
|
|
3807
|
+
return a.firstRow === b.firstRow && a.lastRow === b.lastRow && a.firstColumn === b.firstColumn && a.lastColumn === b.lastColumn;
|
|
3808
|
+
}
|
|
3809
|
+
function clamp$1(value, min, max) {
|
|
3810
|
+
return Math.min(Math.max(value, min), max);
|
|
3811
|
+
}
|
|
3812
|
+
function positive(name, value) {
|
|
3813
|
+
if (!(value > 0)) throw new Error(`LazySheet ${name} must be positive, got ${String(value)}.`);
|
|
3814
|
+
return value;
|
|
3395
3815
|
}
|
|
3396
|
-
/**
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3816
|
+
/**
|
|
3817
|
+
* Feeds a sheet the inputs that may change, with the node's lifetime.
|
|
3818
|
+
*
|
|
3819
|
+
* The same reasoning as `lazySource`: a modifier is released inside
|
|
3820
|
+
* `removeSubtree`, and it attaches after the element's props and
|
|
3821
|
+
* before its children, so a count that arrives with the tree is in the
|
|
3822
|
+
* window before the first children are read from it.
|
|
3823
|
+
*/
|
|
3824
|
+
const sheetSource = defineModifier({
|
|
3825
|
+
name: "sheetSource",
|
|
3826
|
+
attach(host, args) {
|
|
3827
|
+
follow$1(host, args.rowCount, (value) => args.sheet.setRowCount(value));
|
|
3828
|
+
follow$1(host, args.columnCount, (value) => args.sheet.setColumnCount(value));
|
|
3829
|
+
let rows;
|
|
3830
|
+
let columns;
|
|
3831
|
+
const apply = () => {
|
|
3832
|
+
if (rows !== void 0 || columns !== void 0) args.sheet.setOverscan(rows ?? 3, columns ?? 2);
|
|
3833
|
+
};
|
|
3834
|
+
if (args.rowOverscan !== void 0) follow$1(host, args.rowOverscan, (value) => {
|
|
3835
|
+
rows = value;
|
|
3836
|
+
apply();
|
|
3837
|
+
});
|
|
3838
|
+
if (args.columnOverscan !== void 0) follow$1(host, args.columnOverscan, (value) => {
|
|
3839
|
+
columns = value;
|
|
3840
|
+
apply();
|
|
3841
|
+
});
|
|
3402
3842
|
}
|
|
3403
|
-
|
|
3843
|
+
});
|
|
3844
|
+
function follow$1(host, source, apply) {
|
|
3845
|
+
if (!isObservable$1(source)) {
|
|
3846
|
+
apply(source);
|
|
3847
|
+
return;
|
|
3848
|
+
}
|
|
3849
|
+
host.own(source.subscribe((value) => {
|
|
3850
|
+
apply(value);
|
|
3851
|
+
host.requestFrame();
|
|
3852
|
+
}));
|
|
3853
|
+
}
|
|
3854
|
+
/**
|
|
3855
|
+
* A scrolling surface that mounts only the cells in view, on both axes.
|
|
3856
|
+
*
|
|
3857
|
+
* LazySheet({ rowCount: 10_000, columnCount: 100, rowHeight: 24, columnWidth: 96 },
|
|
3858
|
+
* (row, first, last) => Row({}, ...cells(row, first, last)))
|
|
3859
|
+
*
|
|
3860
|
+
* It is a ScrollView whose children are a spacer for the rows above
|
|
3861
|
+
* the window, the mounted rows, and a spacer for the rows below; each
|
|
3862
|
+
* row carries a spacer for the columns to its left and is as wide as
|
|
3863
|
+
* the whole sheet, so the container's content extent — and both
|
|
3864
|
+
* scrollbars — are the sheet's real size on the first frame rather
|
|
3865
|
+
* than an estimate that settles.
|
|
3866
|
+
*/
|
|
3867
|
+
function LazySheet(props, renderRow) {
|
|
3868
|
+
const { rowCount, columnCount, rowHeight, rowHeights, columnWidth, rowOverscan, columnOverscan, gutterWidth, headerHeight, frozenRows, frozenColumns, header, extendRange, modifiers, sheetRef, ...rest } = props;
|
|
3869
|
+
const sheet = new UiVirtualSheet({
|
|
3870
|
+
rowCount,
|
|
3871
|
+
columnCount,
|
|
3872
|
+
rowHeight,
|
|
3873
|
+
rowHeights,
|
|
3874
|
+
columnWidth,
|
|
3875
|
+
rowOverscan,
|
|
3876
|
+
columnOverscan,
|
|
3877
|
+
gutterWidth,
|
|
3878
|
+
headerHeight,
|
|
3879
|
+
frozenRows,
|
|
3880
|
+
frozenColumns,
|
|
3881
|
+
extendRange
|
|
3882
|
+
}, renderRow, header);
|
|
3883
|
+
sheetRef?.(sheet);
|
|
3884
|
+
return createElement("scroll-view", {
|
|
3885
|
+
...rest,
|
|
3886
|
+
modifiers: [...modifiers ?? [], sheetSource({
|
|
3887
|
+
sheet,
|
|
3888
|
+
rowCount,
|
|
3889
|
+
columnCount,
|
|
3890
|
+
rowOverscan,
|
|
3891
|
+
columnOverscan
|
|
3892
|
+
})],
|
|
3893
|
+
direction: "column",
|
|
3894
|
+
[VIRTUAL_SHEET_PROP]: sheet
|
|
3895
|
+
}, [sheet.children$]);
|
|
3404
3896
|
}
|
|
3405
3897
|
//#endregion
|
|
3406
3898
|
//#region src/environment/EnvironmentNotifier.ts
|
|
@@ -4263,7 +4755,13 @@ var UiDragSession = class {
|
|
|
4263
4755
|
return null;
|
|
4264
4756
|
case "drop":
|
|
4265
4757
|
if (this.current === null) this.begin(payload, message.x, message.y, null, true);
|
|
4266
|
-
else
|
|
4758
|
+
else {
|
|
4759
|
+
this.current = {
|
|
4760
|
+
...this.current,
|
|
4761
|
+
payload
|
|
4762
|
+
};
|
|
4763
|
+
this.move(message.x, message.y);
|
|
4764
|
+
}
|
|
4267
4765
|
return this.end();
|
|
4268
4766
|
}
|
|
4269
4767
|
}
|
|
@@ -4328,449 +4826,6 @@ function dragSessionFor(node) {
|
|
|
4328
4826
|
return session;
|
|
4329
4827
|
}
|
|
4330
4828
|
//#endregion
|
|
4331
|
-
//#region src/input/UiEditingController.ts
|
|
4332
|
-
/** How long two presses may be apart and still count as a double click. */
|
|
4333
|
-
const MULTI_CLICK_MS$1 = 500;
|
|
4334
|
-
const MULTI_CLICK_SLOP$1 = 4;
|
|
4335
|
-
/** Room kept around the caret when scrolling it into view. */
|
|
4336
|
-
const CARET_REVEAL_PADDING = 4;
|
|
4337
|
-
/**
|
|
4338
|
-
* Editing behaviour for EditableText nodes.
|
|
4339
|
-
*
|
|
4340
|
-
* The keyboard and pointer controllers call in here as their default
|
|
4341
|
-
* behaviour for an editable target — after the app's listeners have
|
|
4342
|
-
* run and only when none of them called preventDefault() — and the
|
|
4343
|
-
* host feeds it the shell's text input: `beforeinput` edits,
|
|
4344
|
-
* composition, paste. The model on the node is the single source of
|
|
4345
|
-
* truth; this class turns intents into model changes, marks the node
|
|
4346
|
-
* dirty so layout and paint follow, reports the change through an
|
|
4347
|
-
* `input` event, and keeps the caret in view.
|
|
4348
|
-
*
|
|
4349
|
-
* Text arrives one of two ways. A shell with an editing proxy sends
|
|
4350
|
-
* `beforeinput`, where the browser has already resolved the IME, dead
|
|
4351
|
-
* keys and the keyboard layout; then printable key presses are not
|
|
4352
|
-
* text and `textFromKeys` is off. Without a proxy — tests, a bare
|
|
4353
|
-
* runtime — printable keys become insertions.
|
|
4354
|
-
*/
|
|
4355
|
-
var UiEditingController = class {
|
|
4356
|
-
host;
|
|
4357
|
-
dispatcher;
|
|
4358
|
-
focus;
|
|
4359
|
-
/** Insert printable key presses as text; off when a shell delivers text through beforeinput. */
|
|
4360
|
-
textFromKeys = true;
|
|
4361
|
-
platform;
|
|
4362
|
-
paint = createPaintState();
|
|
4363
|
-
focusedEditable = null;
|
|
4364
|
-
visible = true;
|
|
4365
|
-
/** x the current run of vertical moves keeps returning to. */
|
|
4366
|
-
verticalGoalX = void 0;
|
|
4367
|
-
dragging = null;
|
|
4368
|
-
lastPress = null;
|
|
4369
|
-
compositionOpen = false;
|
|
4370
|
-
constructor(host, dispatcher, focus, options = {}) {
|
|
4371
|
-
this.host = host;
|
|
4372
|
-
this.dispatcher = dispatcher;
|
|
4373
|
-
this.focus = focus;
|
|
4374
|
-
this.platform = options.platform ?? detectEditingPlatform();
|
|
4375
|
-
this.focus.onFocusChange((node) => this.handleFocusChange(node));
|
|
4376
|
-
}
|
|
4377
|
-
/** The editable that holds focus, or null. */
|
|
4378
|
-
get focused() {
|
|
4379
|
-
return this.focusedEditable;
|
|
4380
|
-
}
|
|
4381
|
-
/** Whether the pointer controller should hand presses on the node to this controller. */
|
|
4382
|
-
isEditable(node) {
|
|
4383
|
-
return isEditableNode(node);
|
|
4384
|
-
}
|
|
4385
|
-
/**
|
|
4386
|
-
* Default keyboard behaviour for the focused editable. Returns true
|
|
4387
|
-
* when the key was an editing command, so the caller can mark the
|
|
4388
|
-
* event handled.
|
|
4389
|
-
*/
|
|
4390
|
-
handleKey(node, key, modifiers) {
|
|
4391
|
-
if (!isEditableNode(node)) return false;
|
|
4392
|
-
const command = commandForKey(key, modifiers, this.platform, this.textFromKeys);
|
|
4393
|
-
if (command === null) return false;
|
|
4394
|
-
return this.execute(node, command);
|
|
4395
|
-
}
|
|
4396
|
-
execute(node, command) {
|
|
4397
|
-
const model = editorFor(node);
|
|
4398
|
-
const readOnly = isReadOnly(node);
|
|
4399
|
-
switch (command.kind) {
|
|
4400
|
-
case "move":
|
|
4401
|
-
this.move(node, model, command.unit, command.direction, command.extend);
|
|
4402
|
-
return true;
|
|
4403
|
-
case "delete":
|
|
4404
|
-
if (readOnly) return true;
|
|
4405
|
-
return this.applyEdit(node, model, deleteInputType(command.unit, command.direction), null, () => {
|
|
4406
|
-
if (command.direction < 0) model.deleteBackward(command.unit);
|
|
4407
|
-
else model.deleteForward(command.unit);
|
|
4408
|
-
});
|
|
4409
|
-
case "newline":
|
|
4410
|
-
if (!isMultiline(node)) return false;
|
|
4411
|
-
if (readOnly) return true;
|
|
4412
|
-
return this.applyEdit(node, model, "insertLineBreak", "\n", () => model.insertText("\n"));
|
|
4413
|
-
case "insert":
|
|
4414
|
-
if (readOnly) return true;
|
|
4415
|
-
return this.applyEdit(node, model, "insertText", command.text, () => model.insertText(command.text));
|
|
4416
|
-
case "selectAll":
|
|
4417
|
-
model.selectAll();
|
|
4418
|
-
this.afterSelectionChange(node, model);
|
|
4419
|
-
return true;
|
|
4420
|
-
case "undo":
|
|
4421
|
-
if (readOnly) return true;
|
|
4422
|
-
this.history(node, model, "historyUndo", () => model.undo());
|
|
4423
|
-
return true;
|
|
4424
|
-
case "redo":
|
|
4425
|
-
if (readOnly) return true;
|
|
4426
|
-
this.history(node, model, "historyRedo", () => model.redo());
|
|
4427
|
-
return true;
|
|
4428
|
-
}
|
|
4429
|
-
}
|
|
4430
|
-
move(node, model, unit, direction, extend) {
|
|
4431
|
-
if (unit === "vertical") {
|
|
4432
|
-
const target = this.layoutOf(node).verticalMove(model.focus, direction, this.verticalGoalX);
|
|
4433
|
-
if (target === null) {
|
|
4434
|
-
model.moveTo(direction < 0 ? 0 : model.text.length, extend);
|
|
4435
|
-
this.verticalGoalX = void 0;
|
|
4436
|
-
} else {
|
|
4437
|
-
model.moveTo(target.offset, extend);
|
|
4438
|
-
this.verticalGoalX = target.x;
|
|
4439
|
-
}
|
|
4440
|
-
this.afterSelectionChange(node, model, true);
|
|
4441
|
-
return;
|
|
4442
|
-
}
|
|
4443
|
-
if (unit === "line") {
|
|
4444
|
-
const layout = this.layoutOf(node);
|
|
4445
|
-
const caret = layout.caretRect(model.focus);
|
|
4446
|
-
const line = layout.lines[caret.line];
|
|
4447
|
-
const hard = direction < 0 ? lineStartAt(model.text, model.focus) : lineEndAt(model.text, model.focus);
|
|
4448
|
-
const visual = direction < 0 ? line.start : line.end;
|
|
4449
|
-
model.moveTo(direction < 0 ? Math.max(hard, visual) : Math.min(hard, visual), extend);
|
|
4450
|
-
this.afterSelectionChange(node, model);
|
|
4451
|
-
return;
|
|
4452
|
-
}
|
|
4453
|
-
model.move(unit, direction, extend);
|
|
4454
|
-
this.afterSelectionChange(node, model);
|
|
4455
|
-
}
|
|
4456
|
-
/**
|
|
4457
|
-
* A `beforeinput` from the shell's editing proxy, in the DOM's
|
|
4458
|
-
* vocabulary. Returns true when it was applied to the focused
|
|
4459
|
-
* editable. Composition types are not handled here: the composition
|
|
4460
|
-
* methods carry them, and an engine that fires both must not insert
|
|
4461
|
-
* twice.
|
|
4462
|
-
*/
|
|
4463
|
-
beforeInput(inputType, data) {
|
|
4464
|
-
const node = this.focusedEditable;
|
|
4465
|
-
if (node === null) return false;
|
|
4466
|
-
const model = editorFor(node);
|
|
4467
|
-
const readOnly = isReadOnly(node);
|
|
4468
|
-
switch (inputType) {
|
|
4469
|
-
case "insertText":
|
|
4470
|
-
case "insertReplacementText":
|
|
4471
|
-
case "insertFromDrop":
|
|
4472
|
-
case "insertFromYank":
|
|
4473
|
-
if (data === null || data.length === 0) return false;
|
|
4474
|
-
return readOnly || this.insert(node, model, inputType, data);
|
|
4475
|
-
case "insertFromPaste": return readOnly || data !== null && this.insert(node, model, inputType, data);
|
|
4476
|
-
case "insertLineBreak":
|
|
4477
|
-
case "insertParagraph":
|
|
4478
|
-
if (!isMultiline(node)) return false;
|
|
4479
|
-
return readOnly || this.applyEdit(node, model, inputType, "\n", () => model.insertText("\n"));
|
|
4480
|
-
case "deleteContentBackward":
|
|
4481
|
-
case "deleteWordBackward":
|
|
4482
|
-
case "deleteSoftLineBackward":
|
|
4483
|
-
case "deleteHardLineBackward":
|
|
4484
|
-
case "deleteContentForward":
|
|
4485
|
-
case "deleteWordForward":
|
|
4486
|
-
case "deleteSoftLineForward":
|
|
4487
|
-
case "deleteHardLineForward":
|
|
4488
|
-
case "deleteContent":
|
|
4489
|
-
case "deleteByCut":
|
|
4490
|
-
case "deleteByDrag": {
|
|
4491
|
-
if (readOnly) return true;
|
|
4492
|
-
const unit = /Word/.test(inputType) ? "word" : /Line/.test(inputType) ? "line" : "grapheme";
|
|
4493
|
-
const forward = /Forward/.test(inputType);
|
|
4494
|
-
return this.applyEdit(node, model, inputType, null, () => {
|
|
4495
|
-
if (inputType === "deleteContent" || inputType === "deleteByCut" || inputType === "deleteByDrag") model.replaceRange(model.start, model.end, "");
|
|
4496
|
-
else if (forward) model.deleteForward(unit);
|
|
4497
|
-
else model.deleteBackward(unit);
|
|
4498
|
-
});
|
|
4499
|
-
}
|
|
4500
|
-
case "historyUndo": return readOnly || this.history(node, model, inputType, () => model.undo());
|
|
4501
|
-
case "historyRedo": return readOnly || this.history(node, model, inputType, () => model.redo());
|
|
4502
|
-
default: return false;
|
|
4503
|
-
}
|
|
4504
|
-
}
|
|
4505
|
-
/** Inserts text at the selection of the focused editable, as typing would. */
|
|
4506
|
-
insertText(text) {
|
|
4507
|
-
const node = this.focusedEditable;
|
|
4508
|
-
if (node === null || isReadOnly(node)) return false;
|
|
4509
|
-
return this.insert(node, editorFor(node), "insertText", text);
|
|
4510
|
-
}
|
|
4511
|
-
/**
|
|
4512
|
-
* Replaces the focused editable's whole text, as an assistive
|
|
4513
|
-
* technology's "set value" does.
|
|
4514
|
-
*
|
|
4515
|
-
* `insertReplacementText` is the DOM's own input type for this, so an
|
|
4516
|
-
* `onBeforeInput` that vets edits sees the same vocabulary it sees
|
|
4517
|
-
* for typing, and an app that rejects the edit rejects this one too.
|
|
4518
|
-
* Selecting everything first is what makes it one undo step and one
|
|
4519
|
-
* `onInput` rather than a delete and an insert.
|
|
4520
|
-
*/
|
|
4521
|
-
replaceText(text) {
|
|
4522
|
-
const node = this.focusedEditable;
|
|
4523
|
-
if (node === null || isReadOnly(node)) return false;
|
|
4524
|
-
const model = editorFor(node);
|
|
4525
|
-
model.selectAll();
|
|
4526
|
-
return this.insert(node, model, "insertReplacementText", text);
|
|
4527
|
-
}
|
|
4528
|
-
/** Pastes text: newlines are kept in a multiline field and become spaces in a single-line one. */
|
|
4529
|
-
paste(text) {
|
|
4530
|
-
const node = this.focusedEditable;
|
|
4531
|
-
if (node === null || isReadOnly(node)) return false;
|
|
4532
|
-
return this.insert(node, editorFor(node), "insertFromPaste", text);
|
|
4533
|
-
}
|
|
4534
|
-
insert(node, model, inputType, text) {
|
|
4535
|
-
const data = isMultiline(node) ? text : text.replace(/\r\n|\r|\n/g, " ");
|
|
4536
|
-
return this.applyEdit(node, model, inputType, data, () => model.insertText(data));
|
|
4537
|
-
}
|
|
4538
|
-
compositionStart() {
|
|
4539
|
-
const node = this.focusedEditable;
|
|
4540
|
-
if (node === null || isReadOnly(node)) return;
|
|
4541
|
-
const model = editorFor(node);
|
|
4542
|
-
model.beginComposition();
|
|
4543
|
-
this.compositionOpen = true;
|
|
4544
|
-
this.afterTextChange(node, model, false);
|
|
4545
|
-
}
|
|
4546
|
-
/** The composition text so far and the caret within it. */
|
|
4547
|
-
compositionUpdate(text, caret = text.length) {
|
|
4548
|
-
const node = this.focusedEditable;
|
|
4549
|
-
if (node === null || isReadOnly(node)) return;
|
|
4550
|
-
const model = editorFor(node);
|
|
4551
|
-
model.updateComposition(text, caret);
|
|
4552
|
-
this.compositionOpen = true;
|
|
4553
|
-
this.afterTextChange(node, model, false);
|
|
4554
|
-
}
|
|
4555
|
-
/** The IME committed `text` (possibly empty: the composition was cancelled). */
|
|
4556
|
-
compositionEnd(text) {
|
|
4557
|
-
const node = this.focusedEditable;
|
|
4558
|
-
this.compositionOpen = false;
|
|
4559
|
-
if (node === null || isReadOnly(node)) return;
|
|
4560
|
-
const model = editorFor(node);
|
|
4561
|
-
const data = isMultiline(node) ? text : text.replace(/\r\n|\r|\n/g, " ");
|
|
4562
|
-
const before = model.text;
|
|
4563
|
-
model.commitComposition(data);
|
|
4564
|
-
this.afterTextChange(node, model, before !== model.text);
|
|
4565
|
-
}
|
|
4566
|
-
/**
|
|
4567
|
-
* A press on an editable places the caret (Shift extends the
|
|
4568
|
-
* selection to it); a second press within the double-click window
|
|
4569
|
-
* selects the word, a third the line. Dragging afterwards extends the
|
|
4570
|
-
* selection from the anchor.
|
|
4571
|
-
*/
|
|
4572
|
-
pointerDown(node, x, y, modifiers) {
|
|
4573
|
-
if (!isEditableNode(node)) return;
|
|
4574
|
-
const model = editorFor(node);
|
|
4575
|
-
const layout = this.layoutOf(node);
|
|
4576
|
-
const local = this.host.toLocal(node, x, y);
|
|
4577
|
-
const offset = layout.offsetAt(local.x, local.y);
|
|
4578
|
-
const now = this.host.now();
|
|
4579
|
-
const last = this.lastPress;
|
|
4580
|
-
const count = !modifiers.shift && last !== null && last.node === node && now - last.at <= MULTI_CLICK_MS$1 && Math.abs(last.x - x) <= MULTI_CLICK_SLOP$1 && Math.abs(last.y - y) <= MULTI_CLICK_SLOP$1 ? last.count + 1 : 1;
|
|
4581
|
-
this.lastPress = {
|
|
4582
|
-
node,
|
|
4583
|
-
x,
|
|
4584
|
-
y,
|
|
4585
|
-
at: now,
|
|
4586
|
-
count
|
|
4587
|
-
};
|
|
4588
|
-
this.dragging = node;
|
|
4589
|
-
if (modifiers.shift) model.moveTo(offset, true);
|
|
4590
|
-
else if (count === 2) {
|
|
4591
|
-
const word = wordRangeAt(model.text, offset);
|
|
4592
|
-
model.select(word.start, word.end);
|
|
4593
|
-
} else if (count >= 3) model.select(lineStartAt(model.text, offset), lineEndAt(model.text, offset));
|
|
4594
|
-
else model.select(offset);
|
|
4595
|
-
model.breakUndoGroup();
|
|
4596
|
-
this.afterSelectionChange(node, model);
|
|
4597
|
-
}
|
|
4598
|
-
pointerMove(node, x, y) {
|
|
4599
|
-
if (this.dragging !== node) return;
|
|
4600
|
-
const model = editorFor(node);
|
|
4601
|
-
const layout = this.layoutOf(node);
|
|
4602
|
-
const local = this.host.toLocal(node, x, y);
|
|
4603
|
-
const offset = layout.offsetAt(local.x, local.y);
|
|
4604
|
-
if (offset !== model.focus) {
|
|
4605
|
-
model.moveTo(offset, true);
|
|
4606
|
-
this.afterSelectionChange(node, model);
|
|
4607
|
-
}
|
|
4608
|
-
}
|
|
4609
|
-
pointerUp() {
|
|
4610
|
-
this.dragging = null;
|
|
4611
|
-
}
|
|
4612
|
-
/** The focused editable's state for the shell to mirror, or null. */
|
|
4613
|
-
state() {
|
|
4614
|
-
const node = this.focusedEditable;
|
|
4615
|
-
if (node === null || this.host.recordFor(node) === void 0) return null;
|
|
4616
|
-
const model = editorFor(node);
|
|
4617
|
-
const caret = this.layoutOf(node).caretRect();
|
|
4618
|
-
const visible = this.host.visibleBox(node);
|
|
4619
|
-
return {
|
|
4620
|
-
text: model.text,
|
|
4621
|
-
selectionStart: model.start,
|
|
4622
|
-
selectionEnd: model.end,
|
|
4623
|
-
caret: {
|
|
4624
|
-
x: visible.x + caret.x,
|
|
4625
|
-
y: visible.y + caret.y,
|
|
4626
|
-
width: 1,
|
|
4627
|
-
height: caret.height
|
|
4628
|
-
},
|
|
4629
|
-
multiline: isMultiline(node),
|
|
4630
|
-
composing: model.composing
|
|
4631
|
-
};
|
|
4632
|
-
}
|
|
4633
|
-
/**
|
|
4634
|
-
* When the focused caret next toggles, or undefined when nothing
|
|
4635
|
-
* blinks: no focused editable, a composition in progress (the caret
|
|
4636
|
-
* holds), or a hidden page.
|
|
4637
|
-
*/
|
|
4638
|
-
nextCaretChange(now) {
|
|
4639
|
-
const node = this.focusedEditable;
|
|
4640
|
-
if (node === null || !this.visible) return;
|
|
4641
|
-
const model = editorFor(node);
|
|
4642
|
-
if (model.composing || !model.collapsed) return;
|
|
4643
|
-
return nextCaretToggle(model, now);
|
|
4644
|
-
}
|
|
4645
|
-
/**
|
|
4646
|
-
* The page was hidden or shown. A hidden page stops the blink so a
|
|
4647
|
-
* background tab schedules no frames; showing it restarts the caret.
|
|
4648
|
-
*/
|
|
4649
|
-
setVisible(visible) {
|
|
4650
|
-
if (this.visible === visible) return;
|
|
4651
|
-
this.visible = visible;
|
|
4652
|
-
const node = this.focusedEditable;
|
|
4653
|
-
if (node !== null) {
|
|
4654
|
-
editorFor(node).blinkOrigin = this.host.now();
|
|
4655
|
-
this.host.markDirty(node, 2);
|
|
4656
|
-
}
|
|
4657
|
-
}
|
|
4658
|
-
/** Whether the caret may be drawn at all (the page is visible). */
|
|
4659
|
-
get caretEnabled() {
|
|
4660
|
-
return this.visible;
|
|
4661
|
-
}
|
|
4662
|
-
handleFocusChange(node) {
|
|
4663
|
-
const previous = this.focusedEditable;
|
|
4664
|
-
const next = node !== null && isEditableNode(node) ? node : null;
|
|
4665
|
-
if (previous === next) return;
|
|
4666
|
-
if (previous !== null) {
|
|
4667
|
-
const model = editorFor(previous);
|
|
4668
|
-
if (model.composing) model.commitComposition(model.text.slice(model.composition.start, model.composition.end));
|
|
4669
|
-
model.focused = false;
|
|
4670
|
-
this.host.markDirty(previous, 2);
|
|
4671
|
-
}
|
|
4672
|
-
this.focusedEditable = next;
|
|
4673
|
-
this.compositionOpen = false;
|
|
4674
|
-
this.verticalGoalX = void 0;
|
|
4675
|
-
if (next !== null) {
|
|
4676
|
-
const model = editorFor(next);
|
|
4677
|
-
model.focused = true;
|
|
4678
|
-
model.blinkOrigin = this.host.now();
|
|
4679
|
-
this.host.markDirty(next, 2);
|
|
4680
|
-
}
|
|
4681
|
-
}
|
|
4682
|
-
/**
|
|
4683
|
-
* Runs an edit unless a `beforeinput` listener cancels it, then
|
|
4684
|
-
* reports it. Returns true when the input was consumed either way.
|
|
4685
|
-
*/
|
|
4686
|
-
applyEdit(node, model, inputType, data, run) {
|
|
4687
|
-
const before = new UiBeforeInputEvent(inputType, data);
|
|
4688
|
-
this.dispatcher.dispatch(before, node);
|
|
4689
|
-
if (before.defaultPrevented) return true;
|
|
4690
|
-
const text = model.text;
|
|
4691
|
-
run();
|
|
4692
|
-
this.afterTextChange(node, model, text !== model.text);
|
|
4693
|
-
return true;
|
|
4694
|
-
}
|
|
4695
|
-
history(node, model, inputType, run) {
|
|
4696
|
-
const before = new UiBeforeInputEvent(inputType, null);
|
|
4697
|
-
this.dispatcher.dispatch(before, node);
|
|
4698
|
-
if (before.defaultPrevented) return true;
|
|
4699
|
-
const text = model.text;
|
|
4700
|
-
run();
|
|
4701
|
-
this.afterTextChange(node, model, text !== model.text);
|
|
4702
|
-
return true;
|
|
4703
|
-
}
|
|
4704
|
-
afterTextChange(node, model, changed) {
|
|
4705
|
-
this.verticalGoalX = void 0;
|
|
4706
|
-
model.blinkOrigin = this.host.now();
|
|
4707
|
-
this.host.markDirty(node, changed || this.compositionOpen ? 5 : 2);
|
|
4708
|
-
if (changed) this.dispatcher.dispatch(new UiTextChangeEvent(model.text, model.start, model.end), node);
|
|
4709
|
-
this.revealCaret(node);
|
|
4710
|
-
}
|
|
4711
|
-
afterSelectionChange(node, model, keepGoal = false) {
|
|
4712
|
-
if (!keepGoal) this.verticalGoalX = void 0;
|
|
4713
|
-
model.blinkOrigin = this.host.now();
|
|
4714
|
-
this.host.markDirty(node, 2);
|
|
4715
|
-
this.revealCaret(node);
|
|
4716
|
-
}
|
|
4717
|
-
/**
|
|
4718
|
-
* Asks the host to scroll the caret into view, when the node has been
|
|
4719
|
-
* laid out: the field's own text first, then any scroll container
|
|
4720
|
-
* around it.
|
|
4721
|
-
*
|
|
4722
|
-
* `layoutOf` places the text where it is seen, so the caret comes
|
|
4723
|
-
* back with the field's own scroll already taken off; the reveal is
|
|
4724
|
-
* asked for in the node's unscrolled coordinates, which is where the
|
|
4725
|
-
* offset it wants is measured from.
|
|
4726
|
-
*/
|
|
4727
|
-
revealCaret(node) {
|
|
4728
|
-
const rec = this.host.recordFor(node);
|
|
4729
|
-
if (rec === void 0) return;
|
|
4730
|
-
const caret = this.layoutOf(node).caretRect();
|
|
4731
|
-
this.host.reveal(node, {
|
|
4732
|
-
x: caret.x + rec.scrollX - CARET_REVEAL_PADDING,
|
|
4733
|
-
y: caret.y + rec.scrollY - CARET_REVEAL_PADDING,
|
|
4734
|
-
width: 9,
|
|
4735
|
-
height: caret.height + 8
|
|
4736
|
-
});
|
|
4737
|
-
}
|
|
4738
|
-
/**
|
|
4739
|
-
* The node's text laid out in node-local coordinates: the content box
|
|
4740
|
-
* starts at the padding and is shifted by the field's own scroll, as
|
|
4741
|
-
* it is for the renderers in the parent's space. Points from the
|
|
4742
|
-
* pointer and the caret box the shell is given are both in that same
|
|
4743
|
-
* seen space, so neither has to know the offset. Before the first
|
|
4744
|
-
* layout the record is empty and the lines fall at the origin, which
|
|
4745
|
-
* is still a valid place for a caret.
|
|
4746
|
-
*/
|
|
4747
|
-
layoutOf(node) {
|
|
4748
|
-
const rec = this.host.recordFor(node);
|
|
4749
|
-
const state = resolvePaintState(node, this.paint);
|
|
4750
|
-
const box = rec === void 0 ? {
|
|
4751
|
-
x: 0,
|
|
4752
|
-
y: 0,
|
|
4753
|
-
width: 0,
|
|
4754
|
-
height: 0
|
|
4755
|
-
} : {
|
|
4756
|
-
x: rec.paddingLeft - rec.scrollX,
|
|
4757
|
-
y: rec.paddingTop - rec.scrollY,
|
|
4758
|
-
width: Math.max(0, rec.width - rec.paddingLeft - rec.paddingRight),
|
|
4759
|
-
height: Math.max(0, rec.height - rec.paddingTop - rec.paddingBottom)
|
|
4760
|
-
};
|
|
4761
|
-
return new EditableLayout(state.editor, box, state, this.host.measurer);
|
|
4762
|
-
}
|
|
4763
|
-
};
|
|
4764
|
-
function deleteInputType(unit, direction) {
|
|
4765
|
-
const side = direction < 0 ? "Backward" : "Forward";
|
|
4766
|
-
switch (unit) {
|
|
4767
|
-
case "word": return `deleteWord${side}`;
|
|
4768
|
-
case "line":
|
|
4769
|
-
case "document": return `deleteSoftLine${side}`;
|
|
4770
|
-
default: return `deleteContent${side}`;
|
|
4771
|
-
}
|
|
4772
|
-
}
|
|
4773
|
-
//#endregion
|
|
4774
4829
|
//#region src/layout/LayoutNotifier.ts
|
|
4775
4830
|
/**
|
|
4776
4831
|
* Tells listeners when a node's layout changed.
|
|
@@ -4976,6 +5031,110 @@ const DEFAULT_RING = kind$3(Object.freeze({}));
|
|
|
4976
5031
|
function focusRing(options) {
|
|
4977
5032
|
return options === void 0 ? DEFAULT_RING : kind$3(options);
|
|
4978
5033
|
}
|
|
5034
|
+
/**
|
|
5035
|
+
* A border per edge, as paint rather than as layout.
|
|
5036
|
+
*
|
|
5037
|
+
* `borderWidth` is one number and `borderColor` one colour, so a node
|
|
5038
|
+
* cannot have a heavy bottom edge and a hairline top. This is the gap
|
|
5039
|
+
* closed from the cheap side. A border in Gesso is paint-only —
|
|
5040
|
+
* `paintBorder` strokes inside the box and touches no layout — so four
|
|
5041
|
+
* edges are four filled rectangles in the node's own paint pass, with
|
|
5042
|
+
* nothing to lay out and nothing to hit test. A bordered cell costs
|
|
5043
|
+
* four draw instances and no extra nodes.
|
|
5044
|
+
*
|
|
5045
|
+
* Box({ modifiers: [borders({ bottom: 2, right: 1, color: 'border' })] })
|
|
5046
|
+
*
|
|
5047
|
+
* They lie *inside* the box, where `borderWidth` puts them, so a border
|
|
5048
|
+
* never changes where anything sits and never overlaps a neighbour.
|
|
5049
|
+
*
|
|
5050
|
+
* **Why this is a modifier and not four props, and why that is the
|
|
5051
|
+
* answer rather than a stopgap.** First-class `borderTopWidth` is a
|
|
5052
|
+
* much larger change, and the cost is not where it looks: the
|
|
5053
|
+
* property, the paint state and the Canvas2D stroke are easy, but the
|
|
5054
|
+
* WebGPU instance packs `radius, opacity, borderWidth` as one
|
|
5055
|
+
* `float32x3`, the fragment shader draws the border as an isotropic
|
|
5056
|
+
* SDF band, and one instance carries one colour — so four widths need
|
|
5057
|
+
* a wider vertex format, an anisotropic inner rect in the shader, and
|
|
5058
|
+
* up to four instances when the colours differ. This needs none of it,
|
|
5059
|
+
* because a decoration is already a rectangle with its own colour that
|
|
5060
|
+
* both backends draw.
|
|
5061
|
+
*
|
|
5062
|
+
* What the properties would buy over this, once written, is a rounded
|
|
5063
|
+
* per-edge border and one instance instead of four. The first is a
|
|
5064
|
+
* thing square-cornered borders are for — a grid, a table, a rule —
|
|
5065
|
+
* and the second is four draws on a node that already costs one. So
|
|
5066
|
+
* the properties are not planned. If something turns up that wants a
|
|
5067
|
+
* heavy bottom edge on a rounded card, that is the case to reopen it
|
|
5068
|
+
* with, and it will be a better case than "for completeness".
|
|
5069
|
+
*
|
|
5070
|
+
* What it does not do is round its corners. Four rectangles meeting at
|
|
5071
|
+
* a square corner is right for a grid, a table and a rule, which is
|
|
5072
|
+
* what per-edge borders are for; a rounded box wants the single
|
|
5073
|
+
* `borderWidth`, which the renderers draw as one band and get right.
|
|
5074
|
+
*/
|
|
5075
|
+
function borders(options) {
|
|
5076
|
+
return decorated(borderShapes(options));
|
|
5077
|
+
}
|
|
5078
|
+
/**
|
|
5079
|
+
* The rectangles `borders()` draws, without the modifier around them.
|
|
5080
|
+
*
|
|
5081
|
+
* For a surface that cannot afford a modifier per node and pushes its
|
|
5082
|
+
* decorations in instead. A spreadsheet is the case: ten thousand
|
|
5083
|
+
* mounted cells, each with its own border, fed from one writer into a
|
|
5084
|
+
* subject per cell — a modifier per cell would be ten thousand
|
|
5085
|
+
* attachments to do what ten thousand array writes already do. The
|
|
5086
|
+
* arithmetic is the same either way, and sharing it is the point:
|
|
5087
|
+
* an application that rolled its own would be the second place a
|
|
5088
|
+
* corner could be painted twice.
|
|
5089
|
+
*/
|
|
5090
|
+
function borderShapes(options) {
|
|
5091
|
+
const shared = options.color ?? "border";
|
|
5092
|
+
const edge = (side) => {
|
|
5093
|
+
if (side === void 0) return;
|
|
5094
|
+
const resolved = typeof side === "number" ? { width: side } : side;
|
|
5095
|
+
return resolved.width > 0 ? resolved : void 0;
|
|
5096
|
+
};
|
|
5097
|
+
const top = edge(options.top);
|
|
5098
|
+
const bottom = edge(options.bottom);
|
|
5099
|
+
const left = edge(options.left);
|
|
5100
|
+
const right = edge(options.right);
|
|
5101
|
+
const between = {
|
|
5102
|
+
y: top?.width ?? 0,
|
|
5103
|
+
bottom: bottom?.width ?? 0
|
|
5104
|
+
};
|
|
5105
|
+
const shapes = [];
|
|
5106
|
+
if (top !== void 0) shapes.push({
|
|
5107
|
+
kind: "fill",
|
|
5108
|
+
color: top.color ?? shared,
|
|
5109
|
+
y: 0,
|
|
5110
|
+
height: top.width,
|
|
5111
|
+
radius: 0
|
|
5112
|
+
});
|
|
5113
|
+
if (bottom !== void 0) shapes.push({
|
|
5114
|
+
kind: "fill",
|
|
5115
|
+
color: bottom.color ?? shared,
|
|
5116
|
+
bottom: 0,
|
|
5117
|
+
height: bottom.width,
|
|
5118
|
+
radius: 0
|
|
5119
|
+
});
|
|
5120
|
+
if (left !== void 0) shapes.push({
|
|
5121
|
+
kind: "fill",
|
|
5122
|
+
color: left.color ?? shared,
|
|
5123
|
+
x: 0,
|
|
5124
|
+
width: left.width,
|
|
5125
|
+
radius: 0,
|
|
5126
|
+
...between
|
|
5127
|
+
});
|
|
5128
|
+
if (right !== void 0) shapes.push({
|
|
5129
|
+
kind: "fill",
|
|
5130
|
+
color: right.color ?? shared,
|
|
5131
|
+
right: 0,
|
|
5132
|
+
width: right.width,
|
|
5133
|
+
radius: 0,
|
|
5134
|
+
...between
|
|
5135
|
+
});
|
|
5136
|
+
return shapes;
|
|
5137
|
+
}
|
|
4979
5138
|
//#endregion
|
|
4980
5139
|
//#region src/modifiers/focus.ts
|
|
4981
5140
|
/**
|
|
@@ -9660,12 +9819,16 @@ function buildRenderList(root, layout, measurer, logicalWidth, logicalHeight, dp
|
|
|
9660
9819
|
if (text.editor !== void 0) {
|
|
9661
9820
|
const model = text.editor;
|
|
9662
9821
|
const editable = new EditableLayout(model, contentBox, text, measurer);
|
|
9822
|
+
pushTextRects(textRunBackgrounds(editable.lines, text));
|
|
9663
9823
|
if (model.focused && !model.collapsed) {
|
|
9664
9824
|
const selection = parseColor$1(text.selectionColor);
|
|
9665
9825
|
if (selection !== void 0) for (const box of editable.selectionBoxes()) pushContentRect(box, selection);
|
|
9666
9826
|
}
|
|
9667
9827
|
if (editable.placeholderLines.length > 0) pushTextRun(editable.placeholderLines, colorToCss(text.placeholderColor));
|
|
9668
|
-
else
|
|
9828
|
+
else {
|
|
9829
|
+
pushTextRun(editable.lines, colorToCss(text.textColor));
|
|
9830
|
+
pushTextRects(textRunDecorations(editable.lines, text));
|
|
9831
|
+
}
|
|
9669
9832
|
if (model.composing) {
|
|
9670
9833
|
const underline = parseColor$1(text.textColor);
|
|
9671
9834
|
if (underline !== void 0) {
|
|
@@ -13380,6 +13543,7 @@ var UiScheduler = class {
|
|
|
13380
13543
|
dirty;
|
|
13381
13544
|
onFrame;
|
|
13382
13545
|
beforeCollect;
|
|
13546
|
+
onFrameError;
|
|
13383
13547
|
disposed = false;
|
|
13384
13548
|
active = true;
|
|
13385
13549
|
pending = false;
|
|
@@ -13398,6 +13562,9 @@ var UiScheduler = class {
|
|
|
13398
13562
|
this.dirty = options.dirty;
|
|
13399
13563
|
this.onFrame = options.onFrame;
|
|
13400
13564
|
this.beforeCollect = options.beforeCollect;
|
|
13565
|
+
this.onFrameError = options.onFrameError ?? ((error) => {
|
|
13566
|
+
console.error("A Gesso frame threw. The frame was abandoned and the clock kept running.", error);
|
|
13567
|
+
});
|
|
13401
13568
|
this.clock = options.clock((time) => {
|
|
13402
13569
|
this.handleFrame(time);
|
|
13403
13570
|
});
|
|
@@ -13505,30 +13672,42 @@ var UiScheduler = class {
|
|
|
13505
13672
|
this.collecting = true;
|
|
13506
13673
|
let frame;
|
|
13507
13674
|
let collected = 0;
|
|
13675
|
+
/**
|
|
13676
|
+
* Everything a frame does, inside one guard.
|
|
13677
|
+
*
|
|
13678
|
+
* The guard is the whole point: an exception used to unwind past
|
|
13679
|
+
* the re-arm at the bottom of this method, and since `pending` had
|
|
13680
|
+
* already been cleared at the top, nothing asked for another
|
|
13681
|
+
* frame. One throw stopped the application for good.
|
|
13682
|
+
*/
|
|
13508
13683
|
try {
|
|
13509
|
-
|
|
13684
|
+
try {
|
|
13685
|
+
this.beforeCollect?.(time);
|
|
13686
|
+
if (measuring) {
|
|
13687
|
+
collected = markNow();
|
|
13688
|
+
measureSpan("before collect", started, collected);
|
|
13689
|
+
}
|
|
13690
|
+
frame = this.collectFrame(time);
|
|
13691
|
+
} finally {
|
|
13692
|
+
this.collecting = false;
|
|
13693
|
+
}
|
|
13694
|
+
let processed = 0;
|
|
13510
13695
|
if (measuring) {
|
|
13511
|
-
|
|
13512
|
-
measureSpan("
|
|
13696
|
+
processed = markNow();
|
|
13697
|
+
measureSpan("collect", collected, processed);
|
|
13513
13698
|
}
|
|
13514
|
-
frame
|
|
13515
|
-
|
|
13516
|
-
|
|
13517
|
-
|
|
13518
|
-
|
|
13519
|
-
|
|
13520
|
-
|
|
13521
|
-
|
|
13522
|
-
|
|
13523
|
-
|
|
13524
|
-
|
|
13525
|
-
|
|
13526
|
-
const detail = {
|
|
13527
|
-
frame: frame.id,
|
|
13528
|
-
nodes: frame.size
|
|
13529
|
-
};
|
|
13530
|
-
measureSpan("process", processed, finished, detail);
|
|
13531
|
-
measureSpan("frame", started, finished, detail);
|
|
13699
|
+
if (frame.size > 0) this.onFrame(frame);
|
|
13700
|
+
if (measuring) {
|
|
13701
|
+
const finished = markNow();
|
|
13702
|
+
const detail = {
|
|
13703
|
+
frame: frame.id,
|
|
13704
|
+
nodes: frame.size
|
|
13705
|
+
};
|
|
13706
|
+
measureSpan("process", processed, finished, detail);
|
|
13707
|
+
measureSpan("frame", started, finished, detail);
|
|
13708
|
+
}
|
|
13709
|
+
} catch (error) {
|
|
13710
|
+
this.onFrameError(error, time);
|
|
13532
13711
|
}
|
|
13533
13712
|
if (!this.dirty.isEmpty()) this.notifyDirty();
|
|
13534
13713
|
}
|
|
@@ -14667,6 +14846,6 @@ function recordsEqual(a, b) {
|
|
|
14667
14846
|
return true;
|
|
14668
14847
|
}
|
|
14669
14848
|
//#endregion
|
|
14670
|
-
export { AlignContent, AnimationDriver, BUTTON_INTERACTION, Box, Button, CARET_BLINK_MS, CARET_WIDTH, CLIP_STRIDE_BYTES, CLIP_STRIDE_FLOATS, Canvas2DRenderer, CanvasPlatformSurface, CanvasSurface, CanvasTextMeasurer, CharacterCountTextMeasurer, Column, CommandKind, Constraints, CrossAxisAlignment, DEFAULT_BLOCK_SIZE, DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, DEFAULT_FONT_WEIGHT, DEFAULT_LINE_HEIGHT_FACTOR, DEFAULT_TEXT_COLOR, DefaultImageResolver, DefaultVideoResolver, DirtyFlags, DirtyNodeSet, EDITOR_PROP, ELLIPSIS, EMPTY_RECORDING, EXTERNAL_FILES, EditableLayout, EditableText, EditableTextModel, EnvironmentNotifier, FlexDirection, FocusNotifier, GLYPH_SUBPIXEL_PHASES, GlyphShaper, Grid, INSPECTOR_HEAT_MS, INSTANCE_STRIDE_BYTES, INSTANCE_STRIDE_FLOATS, IconRasterizer, LABEL_PADDING_X, LayoutEngine, LayoutInspector, LayoutNotifier, LayoutRecord, LazyColumn, LazyGrid, LazyRow, MARK_PREFIX, MAX_GRADIENT_STOPS, MAX_MEASURES_PER_CHILD, MOTION_CHANNELS, MOTION_REST, MOUSE_POINTER, MainAxisAlignment, Mp3Frames, NO_CLIP_INDEX, NodeTransitions, Paint, PaintPictureCache, PaintRecorder, PaintTarget, ParagraphTextMeasurer, PrimitiveKind, Responsive, Row, SCROLLBAR_FADE_MS, SCROLLBAR_HOVER_ZONE, SCROLLBAR_INSET, SCROLLBAR_LINGER_MS, SCROLLBAR_MIN_THUMB, SCROLLBAR_THICKNESS, ScrollView, Stack, TEXTURED_STRIDE_BYTES, TEXTURED_STRIDE_FLOATS, TEXT_MATCHES_PROP, TEXT_RUN_ID_SEPARATOR, TEXT_SELECTION_PROP, Text, UI_ROLES, UI_SEMANTIC_STATES, UI_SUBGRID_AXES, UiAnimation, UiAnimationFrameClock, UiBasicColors, UiBeforeInputEvent, UiBinding, UiBorderRadiuses, UiChildrenBinding, UiContainerSizeSource, UiDragSession, UiEditingController, UiEnvironment, UiEnvironmentKeys, UiEventBinding, UiEventType, UiFindController, UiFocusEvent, UiFocusManager, UiFrame, UiGestureEvent, UiGestureRecognizer, UiGraph, UiGraphBuilder, UiHitTester, UiHostFrameClock, UiInputDispatcher, UiInputEvent, UiInsetRegistry, UiKeyboardController, UiKeyboardEvent, UiManualFrameClock, UiModifierSet, UiNode, UiNodeType, UiPinchEvent, UiPinchRecognizer, UiPlatformAdapter, UiPointerController, UiPointerEvent, UiProperties, UiScheduler, UiSelectionController, UiSharedElements, UiShortcutRegistry, UiSpring, UiTextChangeEvent, UiTimerFrameClock, UiTouchScroller, UiTransforms, UiTween, UiUnknownModifierPropertyError, UiVirtualWindow, UiVisualState, UiWheelController, UiWheelDeltaMode, UiWheelEvent, VIRTUAL_INDEX_PROP, VIRTUAL_LEAD_PROP, VIRTUAL_WINDOW_PROP, WebGPUError, WebGPUGlyphAtlas, WebGPUGlyphPages, WebGPURenderer, WebGPUSurface, WebGPUTextureCache, accumulatedOffsetTo, animateLayout, applyCanvasTextStyle, assertModifierList, assertTransitionMap, auto, autoFocus, bandOf, borderRadius, borderRadiusCorners, borderRadiusEqual, borderRadiusIsZero, borderRadiusValuesEqual, boxShadow, boxShadowArraysEqual, boxShadowsEqual, breakpoint, bufferSource, buildFontString, buildRenderList, buildSemanticsSubtree, buildSemanticsTree, bumpFontStack, bundle, canDecodeVideo, capturePointer, caretRectFor, caretVisibleAt, clampSize, clearFontStacks, clearLinkHover, clearMatchRanges, clearOverrideProperty, clearSelectionRange, clickOutside, closestPropertyName, colorToCss, colorToHex, colorToRgba, colorValuesEqual, colorsEqual, colorsEqualPalette, commandForKey, computeObjectFitRect, constraintsEqual, containerBands, contentOffset, contextMenu, contrastRatio, createCanvasSurface, createCanvasTextStyle, createElement, createEnvironmentKey, createPaintState, createTextCache, createTween, createWebGPUSurface, cubicBezier, cueAt, darkColors, darkTheme, decorated, decorationColor, decorationRect, defaultMotion, defaultShadows, defaultShapes, defaultSpacing, defaultTextStyle, defaultTypography, defaultVisualState, defineModifier, defineProperty, defineThemeExtension, demuxMp4Audio, demuxMp4Video, densityFactors, describeLength, describeOverrides, detectEditingPlatform, diffSemantics, dragSessionFor, dragSource, draggable, drawOverlayShapes, drawText, dropTarget, easings, editorFor, editorOf, fade, fillTextRects, findEnvironmentKey, findMatchesIn, findPropertyDefinition, flattenTextSpans, focusRing, fontStackFor, formatConstraints, formatExplanation, formatShortcut, fr, getPropertyNames, glyphCount, gradientPaint, gradientsEqual, graphemeBoundaries, hasDecorationPhase, hasDrawnText, hasTextLinks, hasThemeExtension, hasVisualState, highContrastColors, hoverable, iconKey, iconSource, imageSource, inheritedPropertyFlags, inheritedPropertyNames, initializeWebGPU, inputsEqual, insetPadding, insetsEqual, interactive, interpolateColor, interpolateNumber, interpolateTransform, interpolatorFor, isAutoLength, isComponentLikeElement, isEditableNode, isFrLength, isLayoutProtocol, isMinMaxTrack, isMotionRest, isMultiline, isNodeFocusable, isNodeHitTestable, isNodeInert, isNodeSelectable, isObservable, isPaintVisible, isPercentLength, isPrintable, isReadOnly, isScrollContainer, isShapeName, isTypographyRole, isUiChild, isUiElement, isUiModifier, isUiRole, isUiSemanticState, isVideoSurface, isWebGPUAvailable, labelNode, labelOrigin, layoutParagraph, layoutTextLines, lazySource, lightColors, lightTheme, lineEndAt, lineIndexAtY, lineIndexForOffset, lineLimit, lineStartAt, linear, linearGradient, linkHoverOf, linkOf, linkRunAtPointIn, markInstant, markNow, matchRangesOf, measure, measureSpan, minmax, motion, nextCaretToggle, nextGraphemeEnd, nextWordEnd, noInsets, noKeyModifiers, noModifiers, noThemeExtensions, normalizeBorderRadius, normalizeColor, normalizeStates, normalizeTextAlign, normalizeTransition, normalizeVerticalAlign, observeViewportInsets, offsetAtPoint, offsetAtPointIn, offsetAtX, offsetForVerticalMove, overrideSources, paintPictures, paintValuesEqual, paintsAfterChildren, paragraphGeometry, paragraphGeometryFrom, parseAlignContent, parseColor, parseCrossAxisAlignment, parseFlexDirection, parseMainAxisAlignment, parseShortcut, parseTransform, parseWebVtt, pathValuesEqual, percent, performanceMarksEnabled, pinchable, placeGridItems, pointerDeviceOf, pop, prepareInputSurface, pressable, previousGraphemeStart, previousWordStart, propertyEffects, propertyIsInherited, propertyValuesEqual, propertyValuesEqualByName, proportionalFontMetrics, provideEnvironment, publishInset, radialGradient, raiseContrast, rangeSource, readMp3Header, recordsEqual, registerFontStack, relativeLuminance, reorderable, repeat, replayPaint, resetOverrideWarnings, resetTransitionWarnings, resolveBoolean, resolveCursor, resolveLength, resolveMotionState, resolveNumber, resolvePaintState, resolveProperty, resolvePropertyByName, resolveString, resolvedSpansOf, rgb8, rgba, rotateFrom, runCanvasStyleInto, runFontString, sameArgs, scaleFrom, scaleSpacing, scrollPosition, scrollbarThumb, scrollbarThumbs, scrollbarZoneAt, selectableTextNodes, selectableTextOf, selectionRangeOf, selectionRects, selectionRectsIn, semanticsInertAbove, setLinkHover, setMatchRanges, setPerformanceMarks, setSelectionRange, shadowsEqual, shapesEqual, sharedElement, shortcut, shortcuts, sizeContainer, sizeGridTracks, slideDown, slideFrom, slideUp, spacingEqual, spacingSteps, spanAtOffset, spannedRunsFor, spannedTextOf, splitMp3Frames, spring, statesEqual, steps, syncEditorValue, textContentOf, textRunBackgrounds, textRunDecorations, textRunOfRecordId, textRuns, textSpansEqual, textStylesEqual, themeExtension, themeExtensionsEqual, themeTokens, themesEqual, tightenConstraints, touchActionFor, tracePathData, traceRoundedRect, transform, transformIsIdentity, transformsEqual, tween, typographyEqual, uniformBorderRadius, unknownContainerSize, validateGradient, validateRole, validateStates, validateSubgrid, videoFrameSize, videoSource, visualState, visualStatesEqual, wheelDeltaYOf, withContrast, withDensity, withOverrideSource, withThemeExtension, wordRangeAt, wordRangeIn, writeDeclaredProperty, writeOverrideProperty };
|
|
14849
|
+
export { AlignContent, AnimationDriver, BUTTON_INTERACTION, Box, Button, CARET_BLINK_MS, CARET_WIDTH, CLIP_STRIDE_BYTES, CLIP_STRIDE_FLOATS, Canvas2DRenderer, CanvasPlatformSurface, CanvasSurface, CanvasTextMeasurer, CharacterCountTextMeasurer, Column, CommandKind, Constraints, CrossAxisAlignment, DEFAULT_BLOCK_SIZE, DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, DEFAULT_FONT_WEIGHT, DEFAULT_LINE_HEIGHT_FACTOR, DEFAULT_TEXT_COLOR, DefaultImageResolver, DefaultVideoResolver, DirtyFlags, DirtyNodeSet, EDITOR_PROP, ELLIPSIS, EMPTY_RECORDING, EXTERNAL_FILES, EditableLayout, EditableText, EditableTextModel, EnvironmentNotifier, FlexDirection, FocusNotifier, GLYPH_SUBPIXEL_PHASES, GlyphShaper, Grid, INSPECTOR_HEAT_MS, INSTANCE_STRIDE_BYTES, INSTANCE_STRIDE_FLOATS, IconRasterizer, LABEL_PADDING_X, LayoutEngine, LayoutInspector, LayoutNotifier, LayoutRecord, LazyColumn, LazyGrid, LazyRow, LazySheet, MARK_PREFIX, MAX_GRADIENT_STOPS, MAX_MEASURES_PER_CHILD, MOTION_CHANNELS, MOTION_REST, MOUSE_POINTER, MainAxisAlignment, Mp3Frames, NO_CLIP_INDEX, NodeTransitions, Paint, PaintPictureCache, PaintRecorder, PaintTarget, ParagraphTextMeasurer, PrimitiveKind, Responsive, Row, SCROLLBAR_FADE_MS, SCROLLBAR_HOVER_ZONE, SCROLLBAR_INSET, SCROLLBAR_LINGER_MS, SCROLLBAR_MIN_THUMB, SCROLLBAR_THICKNESS, ScrollView, Stack, TEXTURED_STRIDE_BYTES, TEXTURED_STRIDE_FLOATS, TEXT_MATCHES_PROP, TEXT_RUN_ID_SEPARATOR, TEXT_SELECTION_PROP, Text, UI_ROLES, UI_SEMANTIC_STATES, UI_SUBGRID_AXES, UiAnimation, UiAnimationFrameClock, UiBasicColors, UiBeforeInputEvent, UiBinding, UiBorderRadiuses, UiChildrenBinding, UiContainerSizeSource, UiDragSession, UiEditingController, UiEnvironment, UiEnvironmentKeys, UiEventBinding, UiEventType, UiFindController, UiFocusEvent, UiFocusManager, UiFrame, UiGestureEvent, UiGestureRecognizer, UiGraph, UiGraphBuilder, UiHitTester, UiHostFrameClock, UiInputDispatcher, UiInputEvent, UiInsetRegistry, UiKeyboardController, UiKeyboardEvent, UiManualFrameClock, UiModifierSet, UiNode, UiNodeType, UiPasteEvent, UiPinchEvent, UiPinchRecognizer, UiPlatformAdapter, UiPointerController, UiPointerEvent, UiProperties, UiScheduler, UiSelectionChangeEvent, UiSelectionController, UiSharedElements, UiShortcutRegistry, UiSpring, UiTextChangeEvent, UiTimerFrameClock, UiTouchScroller, UiTransforms, UiTween, UiUnknownModifierPropertyError, UiVirtualSheet, UiVirtualWindow, UiVisualState, UiWheelController, UiWheelDeltaMode, UiWheelEvent, VIRTUAL_INDEX_PROP, VIRTUAL_LEAD_PROP, VIRTUAL_SHEET_PROP, VIRTUAL_WINDOW_PROP, WebGPUError, WebGPUGlyphAtlas, WebGPUGlyphPages, WebGPURenderer, WebGPUSurface, WebGPUTextureCache, accumulatedOffsetTo, animateLayout, applyCanvasTextStyle, assertModifierList, assertTransitionMap, auto, autoFocus, bandOf, borderRadius, borderRadiusCorners, borderRadiusEqual, borderRadiusIsZero, borderRadiusValuesEqual, borderShapes, borders, boxShadow, boxShadowArraysEqual, boxShadowsEqual, breakpoint, bufferSource, buildFontString, buildRenderList, buildSemanticsSubtree, buildSemanticsTree, bumpFontStack, bundle, canDecodeVideo, capturePointer, caretRectFor, caretVisibleAt, clampSize, clearFontStacks, clearLinkHover, clearMatchRanges, clearOverrideProperty, clearSelectionRange, clickOutside, closestPropertyName, colorToCss, colorToHex, colorToRgba, colorValuesEqual, colorsEqual, colorsEqualPalette, commandForKey, computeObjectFitRect, constraintsEqual, containerBands, contentOffset, contextMenu, contrastRatio, createCanvasSurface, createCanvasTextStyle, createElement, createEnvironmentKey, createPaintState, createTextCache, createTween, createWebGPUSurface, cubicBezier, cueAt, darkColors, darkTheme, decorated, decorationColor, decorationRect, defaultMotion, defaultShadows, defaultShapes, defaultSpacing, defaultTextStyle, defaultTypography, defaultVisualState, defineModifier, defineProperty, defineThemeExtension, demuxMp4Audio, demuxMp4Video, densityFactors, describeLength, describeOverrides, detectEditingPlatform, diffSemantics, dragSessionFor, dragSource, draggable, drawOverlayShapes, drawText, dropTarget, easings, editableSpansOf, editorFor, editorOf, fade, fillTextRects, findEnvironmentKey, findMatchesIn, findPropertyDefinition, flattenTextSpans, focusRing, fontStackFor, formatConstraints, formatExplanation, formatShortcut, fr, getPropertyNames, glyphCount, gradientPaint, gradientsEqual, graphemeBoundaries, hasDecorationPhase, hasDrawnText, hasTextLinks, hasThemeExtension, hasVisualState, highContrastColors, hoverable, iconKey, iconSource, imageSource, inheritedPropertyFlags, inheritedPropertyNames, initializeWebGPU, inputsEqual, insetPadding, insetsEqual, interactive, interpolateColor, interpolateNumber, interpolateTransform, interpolatorFor, isAutoLength, isComponentLikeElement, isEditableNode, isFrLength, isLayoutProtocol, isMinMaxTrack, isMotionRest, isMultiline, isNodeFocusable, isNodeHitTestable, isNodeInert, isNodeSelectable, isNodeTabStop, isObservable, isPaintVisible, isPercentLength, isPrintable, isReadOnly, isScrollContainer, isShapeName, isTypographyRole, isUiChild, isUiElement, isUiModifier, isUiRole, isUiSemanticState, isVideoSurface, isWebGPUAvailable, labelNode, labelOrigin, layoutParagraph, layoutTextLines, lazySource, lightColors, lightTheme, lineEndAt, lineIndexAtY, lineIndexForOffset, lineLimit, lineStartAt, linear, linearGradient, linkHoverOf, linkOf, linkRunAtPointIn, markInstant, markNow, matchRangesOf, measure, measureSpan, minmax, motion, nextCaretToggle, nextGraphemeEnd, nextWordEnd, noInsets, noKeyModifiers, noModifiers, noThemeExtensions, normalizeBorderRadius, normalizeColor, normalizeStates, normalizeTextAlign, normalizeTransition, normalizeVerticalAlign, observeViewportInsets, offsetAtPoint, offsetAtPointIn, offsetAtX, offsetForVerticalMove, overrideSources, paintPictures, paintValuesEqual, paintsAfterChildren, paragraphGeometry, paragraphGeometryFrom, parseAlignContent, parseColor, parseCrossAxisAlignment, parseFlexDirection, parseMainAxisAlignment, parseShortcut, parseTransform, parseWebVtt, pathValuesEqual, percent, performanceMarksEnabled, pinchable, placeGridItems, pointerDeviceOf, pop, prepareInputSurface, pressable, previousGraphemeStart, previousWordStart, propertyEffects, propertyIsInherited, propertyValuesEqual, propertyValuesEqualByName, proportionalFontMetrics, provideEnvironment, publishInset, radialGradient, raiseContrast, rangeSource, readMp3Header, recordsEqual, registerFontStack, relativeLuminance, reorderable, repeat, replayPaint, resetOverrideWarnings, resetTransitionWarnings, resolveBoolean, resolveCursor, resolveLength, resolveMotionState, resolveNumber, resolvePaintState, resolveProperty, resolvePropertyByName, resolveString, resolvedSpansOf, rgb8, rgba, rotateFrom, runCanvasStyleInto, runFontString, sameArgs, scaleFrom, scaleSpacing, scrollPosition, scrollbarThumb, scrollbarThumbs, scrollbarZoneAt, selectableTextNodes, selectableTextOf, selectionRangeOf, selectionRects, selectionRectsIn, semanticsInertAbove, setLinkHover, setMatchRanges, setPerformanceMarks, setSelectionRange, shadowsEqual, shapesEqual, sharedElement, sheetSource, shortcut, shortcuts, sizeContainer, sizeGridTracks, slideDown, slideFrom, slideUp, spacingEqual, spacingSteps, spanAtOffset, spannedRunsFor, spannedTextOf, splitMp3Frames, spring, statesEqual, steps, syncEditorValue, textContentOf, textRunBackgrounds, textRunDecorations, textRunOfRecordId, textRuns, textSpansEqual, textStylesEqual, themeExtension, themeExtensionsEqual, themeTokens, themesEqual, tightenConstraints, touchActionFor, tracePathData, traceRoundedRect, transform, transformIsIdentity, transformsEqual, tween, typographyEqual, uniformBorderRadius, unknownContainerSize, validateGradient, validateRole, validateStates, validateSubgrid, videoFrameSize, videoSource, visualState, visualStatesEqual, wheelDeltaYOf, withContrast, withDensity, withOverrideSource, withThemeExtension, wordRangeAt, wordRangeIn, writeDeclaredProperty, writeOverrideProperty };
|
|
14671
14850
|
|
|
14672
14851
|
//# sourceMappingURL=index.js.map
|