@swiftbrowser/web 0.1.0 → 0.2.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/README.md +43 -6
- package/app/index.html +11 -0
- package/node/dist/node/apps.d.ts +16 -0
- package/node/dist/node/apps.d.ts.map +1 -1
- package/node/dist/node/apps.js +9 -0
- package/node/dist/node/apps.js.map +1 -1
- package/node/dist/node/config.d.ts +14 -1
- package/node/dist/node/config.d.ts.map +1 -1
- package/node/dist/node/config.js +20 -3
- package/node/dist/node/config.js.map +1 -1
- package/node/dist/node/examples.d.ts +2 -1
- package/node/dist/node/examples.d.ts.map +1 -1
- package/node/dist/node/examples.js +11 -2
- package/node/dist/node/examples.js.map +1 -1
- package/node/dist/plugins/app-manifests.d.ts +4 -1
- package/node/dist/plugins/app-manifests.d.ts.map +1 -1
- package/node/dist/plugins/app-manifests.js +3 -2
- package/node/dist/plugins/app-manifests.js.map +1 -1
- package/node/dist/plugins/asset-catalogs.d.ts +15 -3
- package/node/dist/plugins/asset-catalogs.d.ts.map +1 -1
- package/node/dist/plugins/asset-catalogs.js +111 -13
- package/node/dist/plugins/asset-catalogs.js.map +1 -1
- package/node/dist/plugins/included-sites.d.ts +26 -0
- package/node/dist/plugins/included-sites.d.ts.map +1 -0
- package/node/dist/plugins/included-sites.js +70 -0
- package/node/dist/plugins/included-sites.js.map +1 -0
- package/node/dist/plugins/pdfImages.d.ts +27 -0
- package/node/dist/plugins/pdfImages.d.ts.map +1 -0
- package/node/dist/plugins/pdfImages.js +145 -0
- package/node/dist/plugins/pdfImages.js.map +1 -0
- package/node/dist/plugins/swift-wasm.d.ts +19 -1
- package/node/dist/plugins/swift-wasm.d.ts.map +1 -1
- package/node/dist/plugins/swift-wasm.js +45 -7
- package/node/dist/plugins/swift-wasm.js.map +1 -1
- package/node/dist/plugins/symbolTemplates.d.ts +22 -0
- package/node/dist/plugins/symbolTemplates.d.ts.map +1 -0
- package/node/dist/plugins/symbolTemplates.js +83 -0
- package/node/dist/plugins/symbolTemplates.js.map +1 -0
- package/package.json +4 -2
- package/plugins/app-manifests.ts +3 -2
- package/plugins/asset-catalogs.ts +119 -14
- package/plugins/included-sites.ts +74 -0
- package/plugins/pdfImages.ts +163 -0
- package/plugins/swift-wasm.ts +52 -6
- package/plugins/symbolTemplates.ts +88 -0
- package/public/_headers +7 -0
- package/public/app/oauth-callback.html +62 -0
- package/src/animation.ts +235 -8
- package/src/appFiles.ts +201 -0
- package/src/base64.ts +43 -0
- package/src/bitmapPlan.ts +143 -0
- package/src/bitmapStore.ts +206 -0
- package/src/bitmapWorker.ts +41 -0
- package/src/bitmapWorkerProtocol.ts +15 -0
- package/src/bitmaps.ts +283 -0
- package/src/blockedHosts.ts +29 -0
- package/src/canvasDrawing.ts +361 -0
- package/src/chartDom.ts +2 -2
- package/src/chromeColor.ts +179 -0
- package/src/clipboard.ts +78 -0
- package/src/colorMultiply.ts +93 -0
- package/src/colorPicker.ts +44 -0
- package/src/corsProxy.ts +45 -0
- package/src/gaugeRing.ts +74 -0
- package/src/gif.ts +297 -0
- package/src/hostRequests.ts +426 -0
- package/src/imageOps.ts +592 -0
- package/src/interaction.ts +18 -1
- package/src/landing.ts +2 -2
- package/src/layout/chart.ts +9 -3
- package/src/layout/engine.ts +279 -25
- package/src/layout/index.ts +3 -1
- package/src/layout/text.ts +217 -1
- package/src/layout/types.ts +31 -0
- package/src/layout/typography.ts +24 -7
- package/src/layout/video.ts +24 -0
- package/src/layoutDom.ts +53 -3
- package/src/main.ts +124 -4
- package/src/media.ts +132 -0
- package/src/mock.ts +2 -1
- package/src/notifications.ts +109 -0
- package/src/pathShape.ts +156 -0
- package/src/protocol.ts +761 -12
- package/src/renderer.ts +584 -36
- package/src/richText.ts +65 -0
- package/src/scanner.ts +234 -0
- package/src/scrollTo.ts +123 -0
- package/src/styles.css +212 -7
- package/src/styles.ts +31 -0
- package/src/swiftData.ts +128 -0
- package/src/symbols.ts +564 -21
- package/src/translation.ts +126 -0
- package/src/video.ts +299 -0
- package/src/vite-env.d.ts +6 -0
- package/src/wasm.ts +227 -32
- package/src/webAuth.ts +267 -0
- package/src/webSocket.ts +148 -0
- package/src/zoneinfo.ts +269 -0
package/src/protocol.ts
CHANGED
|
@@ -26,7 +26,44 @@ export type SemanticColorName =
|
|
|
26
26
|
| 'accent'
|
|
27
27
|
| 'systemBackground'
|
|
28
28
|
| 'secondarySystemBackground'
|
|
29
|
-
|
|
29
|
+
/** UIKit's semantic colors, by their iOS names (`Color(uiColor:)`). */
|
|
30
|
+
| 'tertiarySystemBackground'
|
|
31
|
+
| 'systemGroupedBackground'
|
|
32
|
+
| 'secondarySystemGroupedBackground'
|
|
33
|
+
| 'tertiarySystemGroupedBackground'
|
|
34
|
+
| 'label'
|
|
35
|
+
| 'secondaryLabel'
|
|
36
|
+
| 'tertiaryLabel'
|
|
37
|
+
| 'quaternaryLabel'
|
|
38
|
+
| 'placeholderText'
|
|
39
|
+
| 'separator'
|
|
40
|
+
| 'opaqueSeparator'
|
|
41
|
+
| 'systemFill'
|
|
42
|
+
| 'secondarySystemFill'
|
|
43
|
+
| 'tertiarySystemFill'
|
|
44
|
+
| 'quaternarySystemFill'
|
|
45
|
+
| 'systemGray2'
|
|
46
|
+
| 'systemGray3'
|
|
47
|
+
| 'systemGray4'
|
|
48
|
+
| 'systemGray5'
|
|
49
|
+
| 'systemGray6'
|
|
50
|
+
/** The system palette (`Color.red`, `UIColor.systemRed`…): `--sb-color-<name>`. */
|
|
51
|
+
| 'red'
|
|
52
|
+
| 'orange'
|
|
53
|
+
| 'yellow'
|
|
54
|
+
| 'green'
|
|
55
|
+
| 'mint'
|
|
56
|
+
| 'teal'
|
|
57
|
+
| 'cyan'
|
|
58
|
+
| 'blue'
|
|
59
|
+
| 'indigo'
|
|
60
|
+
| 'purple'
|
|
61
|
+
| 'pink'
|
|
62
|
+
| 'brown'
|
|
63
|
+
| 'gray'
|
|
64
|
+
| 'clear'
|
|
65
|
+
/** `TintShapeStyle` (`.tint` as a style): the nearest `.tint(_:)`, else the accent color. */
|
|
66
|
+
| 'tint';
|
|
30
67
|
|
|
31
68
|
/**
|
|
32
69
|
* Semantic color the renderer resolves for the current color scheme. `a`
|
|
@@ -275,6 +312,11 @@ export interface Style {
|
|
|
275
312
|
background?: ShapeStyle;
|
|
276
313
|
frame?: Frame;
|
|
277
314
|
cornerRadius?: number;
|
|
315
|
+
/**
|
|
316
|
+
* `.background(_:)` in a container shape (`.containerShape`): the
|
|
317
|
+
* background's corner radius. Unlike `cornerRadius` it does not clip.
|
|
318
|
+
*/
|
|
319
|
+
backgroundCornerRadius?: number;
|
|
278
320
|
opacity?: number;
|
|
279
321
|
/** Dims the subtree (`opacity: 0.4`) and blocks input (`pointer-events: none`). */
|
|
280
322
|
disabled?: boolean;
|
|
@@ -293,6 +335,8 @@ export interface Style {
|
|
|
293
335
|
*/
|
|
294
336
|
animation?: Animation;
|
|
295
337
|
animationToken?: number;
|
|
338
|
+
/** This box is a `Label`'s icon: a list row tints it (its title keeps the row's color). */
|
|
339
|
+
labelIcon?: boolean;
|
|
296
340
|
/** How this subtree appears and disappears inside an animated commit. */
|
|
297
341
|
transition?: Transition;
|
|
298
342
|
// Phase 5
|
|
@@ -364,6 +408,34 @@ export type HStackAlignment = 'top' | 'center' | 'bottom';
|
|
|
364
408
|
|
|
365
409
|
export interface TextProps {
|
|
366
410
|
text: string;
|
|
411
|
+
/**
|
|
412
|
+
* Rich text (`Text + Text`, `Text(AttributedString)`, an interpolated
|
|
413
|
+
* image, a Text-only modifier such as `.italic()`): the text as runs, each
|
|
414
|
+
* styled on its own. `text` is then the plain content.
|
|
415
|
+
*/
|
|
416
|
+
runs?: TextRun[];
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* One run of a rich text: its `text`, or an inline `image` (an `image`
|
|
420
|
+
* element's props). Unset fields take the text's own style.
|
|
421
|
+
*/
|
|
422
|
+
export interface TextRun {
|
|
423
|
+
text?: string;
|
|
424
|
+
image?: ImageProps;
|
|
425
|
+
/** A Font JSON object applied over the text's font (as `styled` `font`). */
|
|
426
|
+
font?: Record<string, unknown>;
|
|
427
|
+
italic?: boolean;
|
|
428
|
+
/** A ShapeStyle JSON object (as `styled` `foreground`). */
|
|
429
|
+
foreground?: unknown;
|
|
430
|
+
/** A line through or under the run; `color` defaults to the run's own. */
|
|
431
|
+
strikethrough?: { color?: unknown };
|
|
432
|
+
underline?: { color?: unknown };
|
|
433
|
+
/** Extra space after each character, in points. */
|
|
434
|
+
kerning?: number;
|
|
435
|
+
/** Points to raise the run by (negative lowers it). */
|
|
436
|
+
baselineOffset?: number;
|
|
437
|
+
/** A tap on the run sends `link` with this URL. */
|
|
438
|
+
link?: string;
|
|
367
439
|
}
|
|
368
440
|
export interface VStackProps {
|
|
369
441
|
spacing: number | null;
|
|
@@ -399,6 +471,12 @@ export interface StyledProps {
|
|
|
399
471
|
/** Same alignment names as `Frame.alignment`; later children draw on top. */
|
|
400
472
|
export interface ZStackProps {
|
|
401
473
|
alignment: FrameAlignment;
|
|
474
|
+
/**
|
|
475
|
+
* Report the element's laid-out size with `geometry` events, as a
|
|
476
|
+
* `geometry` element does (an anchor preference's wrapper; see
|
|
477
|
+
* docs/ops-protocol.md, "Preferences").
|
|
478
|
+
*/
|
|
479
|
+
reportsSize?: boolean;
|
|
402
480
|
}
|
|
403
481
|
/** `systemName` is an SF Symbol name; the renderer picks the closest glyph. */
|
|
404
482
|
export interface SymbolImageProps {
|
|
@@ -415,7 +493,69 @@ export interface AssetImageProps {
|
|
|
415
493
|
name: string;
|
|
416
494
|
resizable: boolean;
|
|
417
495
|
}
|
|
418
|
-
|
|
496
|
+
/**
|
|
497
|
+
* Phase 13: a remote image (`AsyncImage`). The page loaded it already (an
|
|
498
|
+
* `image` request op) and told the app its pixel size; `width` / `height`
|
|
499
|
+
* are that size in points, the intrinsic size the layout engine uses unless
|
|
500
|
+
* `resizable`.
|
|
501
|
+
*/
|
|
502
|
+
export interface UrlImageProps {
|
|
503
|
+
url: string;
|
|
504
|
+
resizable: boolean;
|
|
505
|
+
width: number;
|
|
506
|
+
height: number;
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* A `UIImage` / `CGImage` bitmap (`Image(uiImage:)`): a recipe the page draws
|
|
510
|
+
* (src/bitmaps.ts). `width` / `height` are the image's size in points, the
|
|
511
|
+
* intrinsic size unless `resizable`. See docs/ops-protocol.md, "Bitmaps and
|
|
512
|
+
* Core Image".
|
|
513
|
+
*/
|
|
514
|
+
export interface BitmapImageProps {
|
|
515
|
+
bitmap: BitmapRecipe;
|
|
516
|
+
resizable: boolean;
|
|
517
|
+
width: number;
|
|
518
|
+
height: number;
|
|
519
|
+
/** `.interpolation(.none)`: scaled without smoothing. */
|
|
520
|
+
interpolation?: 'none';
|
|
521
|
+
}
|
|
522
|
+
export type ImageProps = SymbolImageProps | AssetImageProps | UrlImageProps | BitmapImageProps;
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* How to draw a bitmap: the `imagedata` source named by `source` (null: an
|
|
526
|
+
* empty image) with `steps` applied in order, in Core Image's coordinate
|
|
527
|
+
* space (units of source pixels, origin at the bottom left). The result is
|
|
528
|
+
* `width` × `height` pixels.
|
|
529
|
+
*/
|
|
530
|
+
export interface BitmapRecipe {
|
|
531
|
+
source: string | null;
|
|
532
|
+
/** A frame of an animated source (a GIF), composed as the frames before it leave the canvas; absent: the file as it is. */
|
|
533
|
+
frame?: number;
|
|
534
|
+
steps: BitmapStep[];
|
|
535
|
+
width: number;
|
|
536
|
+
height: number;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/** A point in Core Image's space. */
|
|
540
|
+
export type BitmapPoint = [number, number];
|
|
541
|
+
|
|
542
|
+
/** One step of a recipe; the formulas are in docs/ops-protocol.md. */
|
|
543
|
+
export type BitmapStep =
|
|
544
|
+
| { op: 'crop' | 'render'; x: number; y: number; width: number; height: number }
|
|
545
|
+
| { op: 'clamp' }
|
|
546
|
+
| { op: 'sepiaTone'; intensity: number }
|
|
547
|
+
| { op: 'edges'; intensity: number }
|
|
548
|
+
| { op: 'crystallize'; radius: number; center: BitmapPoint }
|
|
549
|
+
| { op: 'pixellate'; scale: number; center: BitmapPoint }
|
|
550
|
+
| { op: 'gaussianBlur'; radius: number }
|
|
551
|
+
| { op: 'unsharpMask'; radius: number; intensity: number }
|
|
552
|
+
| { op: 'vignette'; intensity: number; radius: number; center: BitmapPoint; size: number }
|
|
553
|
+
/** Core Graphics drawing an image in a rectangle: every point p goes to (p.x × sx + tx, p.y × sy + ty). */
|
|
554
|
+
| { op: 'place'; sx: number; sy: number; tx: number; ty: number }
|
|
555
|
+
/** A clip to a rounded rectangle (an ellipse when the radii are half its sides). */
|
|
556
|
+
| { op: 'roundedClip'; x: number; y: number; width: number; height: number; rx: number; ry: number }
|
|
557
|
+
/** `UIImage.withTintColor`: every pixel the color (straight RGBA, 0…1), at the pixel's alpha times the color's. */
|
|
558
|
+
| { op: 'tint'; r: number; g: number; b: number; a: number };
|
|
419
559
|
export type DividerProps = Record<string, never>;
|
|
420
560
|
export type ScrollAxes = 'vertical' | 'horizontal' | 'both';
|
|
421
561
|
export interface ScrollViewProps {
|
|
@@ -469,7 +609,9 @@ export interface ColorProps {
|
|
|
469
609
|
color: Color;
|
|
470
610
|
}
|
|
471
611
|
/** Phase 6 adds `containerRelative` (`ContainerRelativeShape`): a rounded rectangle with `cornerRadius`. */
|
|
472
|
-
export type ShapeKind = 'rectangle' | 'roundedRectangle' | 'circle' | 'capsule' | 'ellipse' | 'containerRelative'
|
|
612
|
+
export type ShapeKind = 'rectangle' | 'roundedRectangle' | 'circle' | 'capsule' | 'ellipse' | 'containerRelative'
|
|
613
|
+
/** A custom shape drawn from its path (`ShapeProps.path`). */
|
|
614
|
+
| 'path';
|
|
473
615
|
export interface Stroke {
|
|
474
616
|
/** Phase 6: any ShapeStyle; a gradient stroke falls back to its first stop. */
|
|
475
617
|
color: ShapeStyle;
|
|
@@ -480,6 +622,12 @@ export interface Stroke {
|
|
|
480
622
|
* `data-sb-stroke`.
|
|
481
623
|
*/
|
|
482
624
|
inset?: boolean;
|
|
625
|
+
/** A custom shape's `StrokeStyle` (a built-in shape's border has none of these). */
|
|
626
|
+
lineCap?: 'butt' | 'round' | 'square';
|
|
627
|
+
lineJoin?: 'miter' | 'round' | 'bevel';
|
|
628
|
+
miterLimit?: number;
|
|
629
|
+
dash?: number[];
|
|
630
|
+
dashPhase?: number;
|
|
483
631
|
}
|
|
484
632
|
/** `fill: null` means the current foreground color; fills its proposal. */
|
|
485
633
|
export interface ShapeProps {
|
|
@@ -488,9 +636,33 @@ export interface ShapeProps {
|
|
|
488
636
|
/** Phase 6: any ShapeStyle. */
|
|
489
637
|
fill: ShapeStyle | null;
|
|
490
638
|
stroke: Stroke | null;
|
|
639
|
+
/**
|
|
640
|
+
* `.trim(from:to:)`: the part of the outline between the fractions, drawn
|
|
641
|
+
* as a conic mask around the center from 3 o'clock, clockwise (exact for a
|
|
642
|
+
* circle). Absent when the shape is not trimmed.
|
|
643
|
+
*/
|
|
644
|
+
trim?: { from: number; to: number };
|
|
645
|
+
/**
|
|
646
|
+
* A custom shape (`shape: "path"`, src/pathShape.ts): SVG path data for a
|
|
647
|
+
* rectangle of `size` at the origin, the size the element reported
|
|
648
|
+
* (`reportsSize`). Empty until the first report.
|
|
649
|
+
*/
|
|
650
|
+
path?: string;
|
|
651
|
+
size?: { width: number; height: number };
|
|
652
|
+
/** `FillStyle(eoFill: true)`: overlapping parts of the path cancel out. */
|
|
653
|
+
fillRule?: 'evenodd';
|
|
654
|
+
/** The element reports its laid-out size (a custom shape draws its path for it). */
|
|
655
|
+
reportsSize?: boolean;
|
|
656
|
+
/**
|
|
657
|
+
* An animated change of the shape's `animatableData`: the path at each
|
|
658
|
+
* fraction of the change (`paths[index[i]]` at `progress[i]`), played in
|
|
659
|
+
* the commit's animation.
|
|
660
|
+
*/
|
|
661
|
+
frames?: { progress: number[]; index: number[]; paths: string[] };
|
|
491
662
|
}
|
|
492
663
|
/** Phase 8: `full` is `.fullScreenCover` (the card fills the screen). */
|
|
493
|
-
|
|
664
|
+
/** `height:<points>` / `fraction:<f>`: `.presentationDetents([.height(300)])`, `.fraction(0.4)`. */
|
|
665
|
+
export type Detent = 'medium' | 'large' | 'full' | `height:${number}` | `fraction:${number}`;
|
|
494
666
|
/**
|
|
495
667
|
* Always a root-level element (child of id 0) placed after the app's tree. A
|
|
496
668
|
* `tap` with the sheet's own id is a dismiss request.
|
|
@@ -510,6 +682,10 @@ export interface TabViewProps {
|
|
|
510
682
|
export interface TabProps {
|
|
511
683
|
title: string;
|
|
512
684
|
systemImage: string | null;
|
|
685
|
+
/** iOS 18 `Tab(…).badge(…)`: a red badge on the bar item (absent when none). */
|
|
686
|
+
badge?: string;
|
|
687
|
+
/** iOS 18 `Tab(role: .search)` (absent otherwise); Swift already put it last. */
|
|
688
|
+
role?: 'search';
|
|
513
689
|
}
|
|
514
690
|
export type PickerStyle = 'segmented' | 'menu' | 'inline';
|
|
515
691
|
/**
|
|
@@ -615,7 +791,7 @@ export type GaugeStyle =
|
|
|
615
791
|
/**
|
|
616
792
|
* `Gauge`: `value` is normalized to 0...1. Children in order: the label (when
|
|
617
793
|
* `hasLabel`) and the current value label (when `hasCurrentValueLabel`).
|
|
618
|
-
* Circular styles
|
|
794
|
+
* Circular styles draw a ring with one of the labels in the middle.
|
|
619
795
|
*/
|
|
620
796
|
export interface GaugeProps {
|
|
621
797
|
value: number;
|
|
@@ -641,7 +817,16 @@ export interface DecoratedProps {
|
|
|
641
817
|
* a popover built from the current items (`button`/`navlink` rows that send
|
|
642
818
|
* `tap`, `picker` sections that send `select`, `divider`, `section`, `text`).
|
|
643
819
|
*/
|
|
644
|
-
|
|
820
|
+
/**
|
|
821
|
+
* Lazy menus: `deferred: true` while the items are not built (only the label
|
|
822
|
+
* is a child). The page sends a `menu` event with `open: true` when the
|
|
823
|
+
* viewer opens it and shows the popover once the items arrive (`deferred:
|
|
824
|
+
* false`), and `open: false` when it closes. Absent when the app builds the
|
|
825
|
+
* items eagerly (headless runs, the mocks).
|
|
826
|
+
*/
|
|
827
|
+
export interface MenuProps {
|
|
828
|
+
deferred?: boolean;
|
|
829
|
+
}
|
|
645
830
|
export type ToolbarPlacement = 'trailing' | 'leading' | 'principal' | 'bottom';
|
|
646
831
|
/**
|
|
647
832
|
* `.toolbar { ToolbarItem(placement:) { ... } }`, an extra child of a
|
|
@@ -662,8 +847,13 @@ export interface SearchFieldProps {
|
|
|
662
847
|
/** Defaults to "Search". */
|
|
663
848
|
placeholder: string;
|
|
664
849
|
}
|
|
665
|
-
/**
|
|
666
|
-
|
|
850
|
+
/**
|
|
851
|
+
* `.onTapGesture`: one child, the child's size; a click anywhere on it sends
|
|
852
|
+
* `tap`. `location` (`onTapGesture { point in }`) adds the click's point.
|
|
853
|
+
*/
|
|
854
|
+
export interface TapGestureProps {
|
|
855
|
+
location?: boolean;
|
|
856
|
+
}
|
|
667
857
|
|
|
668
858
|
export interface ElementPropsByKind {
|
|
669
859
|
text: TextProps;
|
|
@@ -758,7 +948,238 @@ export interface DefaultsOp {
|
|
|
758
948
|
values: Record<string, unknown>;
|
|
759
949
|
}
|
|
760
950
|
|
|
761
|
-
|
|
951
|
+
/**
|
|
952
|
+
* Phase 13: something only the page can do for the app. The loader performs
|
|
953
|
+
* it (src/hostRequests.ts) and answers with a `ResponseEvent` of the same
|
|
954
|
+
* `id`; the renderer never sees it.
|
|
955
|
+
*/
|
|
956
|
+
export interface RequestOp {
|
|
957
|
+
op: 'request';
|
|
958
|
+
id: number;
|
|
959
|
+
kind: 'fetch' | 'image' | 'share' | 'pickFiles' | 'notification' | 'scanner' | 'websocket' | 'openURL' | 'webAuth' | 'media' | 'download' | 'clipboard' | 'translate' | 'pickColor';
|
|
960
|
+
params:
|
|
961
|
+
| FetchRequestParams
|
|
962
|
+
| ImageRequestParams
|
|
963
|
+
| ShareRequestParams
|
|
964
|
+
| PickFilesRequestParams
|
|
965
|
+
| NotificationRequestParams
|
|
966
|
+
| ScannerRequestParams
|
|
967
|
+
| WebSocketRequestParams
|
|
968
|
+
| OpenURLRequestParams
|
|
969
|
+
| WebAuthRequestParams
|
|
970
|
+
| MediaRequestParams
|
|
971
|
+
| DownloadRequestParams
|
|
972
|
+
| ClipboardRequestParams
|
|
973
|
+
| TranslateRequestParams
|
|
974
|
+
| PickColorRequestParams;
|
|
975
|
+
}
|
|
976
|
+
/**
|
|
977
|
+
* `translate` (Translation; src/translation.ts): `availability` of a pair
|
|
978
|
+
* (`source` null: detected from `text`), or `translate` the `texts` from
|
|
979
|
+
* `source` (null: detected) to `target`, BCP 47 tags. `allowDownload`: the
|
|
980
|
+
* session may download the pair's model.
|
|
981
|
+
*/
|
|
982
|
+
export interface TranslateRequestParams {
|
|
983
|
+
action: 'availability' | 'translate';
|
|
984
|
+
source?: string | null;
|
|
985
|
+
target: string;
|
|
986
|
+
text?: string;
|
|
987
|
+
texts?: string[];
|
|
988
|
+
allowDownload?: boolean;
|
|
989
|
+
}
|
|
990
|
+
/** `pickColor` (`ColorPicker`; src/colorPicker.ts): the chooser opens at `color` (`#rrggbb`). */
|
|
991
|
+
export interface PickColorRequestParams {
|
|
992
|
+
color?: string;
|
|
993
|
+
}
|
|
994
|
+
/**
|
|
995
|
+
* `URLSessionWebSocketTask`: one call on a socket (src/webSocket.ts). `open`
|
|
996
|
+
* takes `url` and `protocols`; the others the `socket` id `open` answered.
|
|
997
|
+
*/
|
|
998
|
+
/** `openURL` (`OpenURLAction`, a link in a `Text`, `UIApplication.open`): the page opens `url` in a new tab; the value is null. */
|
|
999
|
+
/**
|
|
1000
|
+
* `webAuth` (AuthenticationServices; docs/ops-protocol.md, "Signing in"):
|
|
1001
|
+
* `start` opens `url`, the provider's authorize page, in a popup window and
|
|
1002
|
+
* answers `{ url }`, the callback page URL the window ended at; `cancel` closes
|
|
1003
|
+
* the window, and the pending `start` fails with `cancelled: …`.
|
|
1004
|
+
* `callbackScheme` is the app's scheme the redirect stands for, `callbackPage`
|
|
1005
|
+
* the callback page the app put in its place; `ephemeral` is the app's wish
|
|
1006
|
+
* for a private session, which a popup cannot grant.
|
|
1007
|
+
*/
|
|
1008
|
+
export interface WebAuthRequestParams {
|
|
1009
|
+
action?: 'start' | 'cancel';
|
|
1010
|
+
url?: string;
|
|
1011
|
+
callbackScheme?: string;
|
|
1012
|
+
callbackPage?: string;
|
|
1013
|
+
ephemeral?: boolean;
|
|
1014
|
+
}
|
|
1015
|
+
export interface OpenURLRequestParams {
|
|
1016
|
+
url: string;
|
|
1017
|
+
}
|
|
1018
|
+
export interface WebSocketRequestParams {
|
|
1019
|
+
action: 'open' | 'send' | 'receive' | 'close';
|
|
1020
|
+
url?: string;
|
|
1021
|
+
protocols?: string[];
|
|
1022
|
+
socket?: number;
|
|
1023
|
+
/** `send`: a text message. */
|
|
1024
|
+
string?: string;
|
|
1025
|
+
/** `send`: a binary message, base64. */
|
|
1026
|
+
data?: string;
|
|
1027
|
+
/** `close`: the close code and reason. */
|
|
1028
|
+
code?: number;
|
|
1029
|
+
reason?: string;
|
|
1030
|
+
}
|
|
1031
|
+
/** `URLSession`: one HTTP request. `body` is base64; `timeout` in ms (0: none). */
|
|
1032
|
+
export interface FetchRequestParams {
|
|
1033
|
+
url: string;
|
|
1034
|
+
method: string;
|
|
1035
|
+
headers: Record<string, string>;
|
|
1036
|
+
body: string | null;
|
|
1037
|
+
timeout?: number;
|
|
1038
|
+
}
|
|
1039
|
+
/** `AsyncImage`: decode the image at `url` and report its pixel size. */
|
|
1040
|
+
export interface ImageRequestParams {
|
|
1041
|
+
url: string;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
/**
|
|
1045
|
+
* `ShareLink`: share through the Web Share API, or download where the browser
|
|
1046
|
+
* cannot. `images` are asset-catalog names, shared (or downloaded) as their
|
|
1047
|
+
* files. The response value is a `ShareResult`.
|
|
1048
|
+
*/
|
|
1049
|
+
export interface ShareRequestParams {
|
|
1050
|
+
title?: string;
|
|
1051
|
+
text?: string;
|
|
1052
|
+
url?: string;
|
|
1053
|
+
images?: string[];
|
|
1054
|
+
/** `Image(uiImage:)` items: recipes the page draws into PNG files. */
|
|
1055
|
+
bitmaps?: BitmapRecipe[];
|
|
1056
|
+
/** Files the app made: a `Transferable` item's exported bytes, a `UIImage`'s own file. */
|
|
1057
|
+
files?: SharedFile[];
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
/** A file the app hands to the page whole: its name, MIME type and bytes (base64). */
|
|
1061
|
+
export interface SharedFile {
|
|
1062
|
+
name: string;
|
|
1063
|
+
type: string;
|
|
1064
|
+
data: string;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
/**
|
|
1068
|
+
* Saving (Photos' change requests, `UIImageWriteToSavedPhotosAlbum`): the
|
|
1069
|
+
* page downloads each file, catalog image and bitmap (a PNG named after
|
|
1070
|
+
* `title`). The response value is a `ShareResult` (`downloaded`).
|
|
1071
|
+
*/
|
|
1072
|
+
export interface DownloadRequestParams {
|
|
1073
|
+
title?: string;
|
|
1074
|
+
files?: SharedFile[];
|
|
1075
|
+
images?: string[];
|
|
1076
|
+
bitmaps?: BitmapRecipe[];
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
/**
|
|
1080
|
+
* `UIPasteboard.general`: `write` copies `text`, or the first picture (a
|
|
1081
|
+
* file, catalog image or bitmap, as PNG) to the system clipboard and answers
|
|
1082
|
+
* `{}`; `readText` answers `{ text }`.
|
|
1083
|
+
*/
|
|
1084
|
+
export interface ClipboardRequestParams {
|
|
1085
|
+
action: 'write' | 'readText';
|
|
1086
|
+
text?: string;
|
|
1087
|
+
files?: SharedFile[];
|
|
1088
|
+
images?: string[];
|
|
1089
|
+
bitmaps?: BitmapRecipe[];
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
/**
|
|
1093
|
+
* `PhotosPicker`: let the viewer choose files with the browser's file
|
|
1094
|
+
* chooser. `accept` is the input's `accept` (`image/*,video/*`; empty: any
|
|
1095
|
+
* file). The response value is a `PickFilesResult`; a dismissed chooser
|
|
1096
|
+
* answers with no items.
|
|
1097
|
+
*/
|
|
1098
|
+
export interface PickFilesRequestParams {
|
|
1099
|
+
accept: string;
|
|
1100
|
+
multiple: boolean;
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
/**
|
|
1104
|
+
* UserNotifications (docs/ops-protocol.md, "Notifications"): `status` reads
|
|
1105
|
+
* `Notification.permission`, `request` asks for it, `show` presents a
|
|
1106
|
+
* notification that came due (`title` absent: the badge only), `close`
|
|
1107
|
+
* closes delivered ones by identifier, `badge` sets the app badge. The
|
|
1108
|
+
* response value is a `NotificationResult`.
|
|
1109
|
+
*/
|
|
1110
|
+
export interface NotificationRequestParams {
|
|
1111
|
+
action: 'status' | 'request' | 'show' | 'close' | 'badge';
|
|
1112
|
+
/** `show`: the request's identifier, the notification's `tag`. */
|
|
1113
|
+
id?: string;
|
|
1114
|
+
title?: string;
|
|
1115
|
+
subtitle?: string;
|
|
1116
|
+
body?: string;
|
|
1117
|
+
silent?: boolean;
|
|
1118
|
+
/** `show` and `badge`: the app badge (0 clears it). */
|
|
1119
|
+
badge?: number;
|
|
1120
|
+
/** `close`: the identifiers to close. */
|
|
1121
|
+
ids?: string[];
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
/**
|
|
1125
|
+
* AVFoundation's capture sessions (docs/ops-protocol.md, "Code scanning"):
|
|
1126
|
+
* `probe` asks whether the page can scan `formats` (`BarcodeDetector` names)
|
|
1127
|
+
* with a camera; `scan` opens the camera over the page until a code is found
|
|
1128
|
+
* or the viewer closes it, or, where the browser cannot read codes, asks the
|
|
1129
|
+
* viewer to type one. The response value is a `ScannerResult`.
|
|
1130
|
+
*/
|
|
1131
|
+
export interface ScannerRequestParams {
|
|
1132
|
+
action: 'probe' | 'scan';
|
|
1133
|
+
formats: string[];
|
|
1134
|
+
torch?: boolean;
|
|
1135
|
+
vibrate?: boolean;
|
|
1136
|
+
/** Which camera: the back one (`environment`, the default) or the front one (`user`). */
|
|
1137
|
+
facing?: 'environment' | 'user';
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
/**
|
|
1141
|
+
* Phase 18: one save of a SwiftData store (`ModelContext.save()`, or the main
|
|
1142
|
+
* context's autosave at the end of an event). The loader hands it to the page,
|
|
1143
|
+
* which writes it to the app's IndexedDB database (src/swiftData.ts) and
|
|
1144
|
+
* passes every store back at the next launch as `SB_SWIFTDATA`. `clear`
|
|
1145
|
+
* (`ModelContainer.deleteAllData()`) empties the store before `put`.
|
|
1146
|
+
*/
|
|
1147
|
+
export interface SwiftDataOp {
|
|
1148
|
+
op: 'swiftdata';
|
|
1149
|
+
store: string;
|
|
1150
|
+
put: SwiftDataRecord[];
|
|
1151
|
+
delete: number[];
|
|
1152
|
+
clear?: boolean;
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
/** A saved model: its key in the store, its entity (class) name and its properties' JSON. */
|
|
1156
|
+
export interface SwiftDataRecord {
|
|
1157
|
+
id: number;
|
|
1158
|
+
entity: string;
|
|
1159
|
+
values: Record<string, unknown>;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
/**
|
|
1163
|
+
* A bitmap's source, sent once (by content `key`) before the first element
|
|
1164
|
+
* that draws it: an encoded image file (`mime`, `data`) or a pixel buffer
|
|
1165
|
+
* (`format`, `pixels`: one gray or four RGBA bytes per pixel, rows from the
|
|
1166
|
+
* top). The bytes are base64 in printed ops; from a module with the
|
|
1167
|
+
* `sb_bytes_*` exports, src/wasm.ts reads them out of linear memory
|
|
1168
|
+
* (docs/ops-protocol.md, "Bytes"). `width` × `height` is its size in pixels, as
|
|
1169
|
+
* drawn (a JPEG's EXIF rotation applied). The renderer keeps it for the run.
|
|
1170
|
+
*/
|
|
1171
|
+
export interface ImageDataOp {
|
|
1172
|
+
op: 'imagedata';
|
|
1173
|
+
key: string;
|
|
1174
|
+
width: number;
|
|
1175
|
+
height: number;
|
|
1176
|
+
mime?: string;
|
|
1177
|
+
data?: string | Uint8Array;
|
|
1178
|
+
format?: 'gray' | 'rgba';
|
|
1179
|
+
pixels?: string | Uint8Array;
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
export type Op = CreateOp | UpdateOp | InsertOp | RemoveOp | CommitOp | DefaultsOp | RequestOp | SwiftDataOp | ImageDataOp;
|
|
762
1183
|
|
|
763
1184
|
// ---------------------------------------------------------------------------
|
|
764
1185
|
// Events (renderer → Swift)
|
|
@@ -806,6 +1227,15 @@ export function isDynamicTypeSize(value: unknown): value is DynamicTypeSize {
|
|
|
806
1227
|
export interface TapEvent {
|
|
807
1228
|
type: 'tap';
|
|
808
1229
|
id: ElementId;
|
|
1230
|
+
/** A `tapgesture` with `location`: the tap's point in the element's own coordinates. */
|
|
1231
|
+
x?: number;
|
|
1232
|
+
y?: number;
|
|
1233
|
+
}
|
|
1234
|
+
/** A link run (`TextRun.link`) of a `text` was tapped; `value` is its URL. */
|
|
1235
|
+
export interface LinkEvent {
|
|
1236
|
+
type: 'link';
|
|
1237
|
+
id: ElementId;
|
|
1238
|
+
value: string;
|
|
809
1239
|
}
|
|
810
1240
|
/** A `textfield` or `searchfield` received input. */
|
|
811
1241
|
export interface TextEvent {
|
|
@@ -875,13 +1305,32 @@ export type RendererEvent =
|
|
|
875
1305
|
| ToggleEvent
|
|
876
1306
|
| EnvironmentEvent
|
|
877
1307
|
| SelectEvent
|
|
1308
|
+
| LinkEvent
|
|
878
1309
|
| GeometryEvent
|
|
879
1310
|
| LayoutEvent
|
|
880
1311
|
| BatchEvent
|
|
881
1312
|
// Phase 8: gestures, rows, navigation (see the block at the end of this file)
|
|
882
1313
|
| InteractionEvent
|
|
883
1314
|
// Phase 8: alerts, controls (see the block at the end of this file)
|
|
884
|
-
| Phase8ControlEvent
|
|
1315
|
+
| Phase8ControlEvent
|
|
1316
|
+
// Phase 13: the answer to a `request` op
|
|
1317
|
+
| ResponseEvent
|
|
1318
|
+
// A `video` element's playback (src/video.ts)
|
|
1319
|
+
| VideoEvent
|
|
1320
|
+
| LazyEvent
|
|
1321
|
+
| MenuEvent;
|
|
1322
|
+
|
|
1323
|
+
/**
|
|
1324
|
+
* Phase 13: the page's answer to the `request` op with this `id`: `value`
|
|
1325
|
+
* (a `FetchResult` or `ImageResult` from src/hostRequests.ts) on success,
|
|
1326
|
+
* `error` (a short message the app maps to a `URLError`) on failure.
|
|
1327
|
+
*/
|
|
1328
|
+
export interface ResponseEvent {
|
|
1329
|
+
type: 'response';
|
|
1330
|
+
id: number;
|
|
1331
|
+
value?: unknown;
|
|
1332
|
+
error?: string;
|
|
1333
|
+
}
|
|
885
1334
|
|
|
886
1335
|
/**
|
|
887
1336
|
* Several events delivered in one `sb_event_json` call: Swift applies each
|
|
@@ -948,12 +1397,31 @@ export function isAssetImage(props: ImageProps): props is AssetImageProps {
|
|
|
948
1397
|
return typeof (props as AssetImageProps).name === 'string';
|
|
949
1398
|
}
|
|
950
1399
|
|
|
1400
|
+
/** True for the bitmap form of `image` props (`{ bitmap, resizable, width, height }`). */
|
|
1401
|
+
export function isBitmapImage(props: ImageProps): props is BitmapImageProps {
|
|
1402
|
+
const bitmap = (props as BitmapImageProps).bitmap;
|
|
1403
|
+
return typeof bitmap === 'object' && bitmap !== null;
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
/** True for the remote form of `image` props (`{ url, resizable, width, height }`, Phase 13). */
|
|
1407
|
+
export function isUrlImage(props: ImageProps): props is UrlImageProps {
|
|
1408
|
+
return typeof (props as UrlImageProps).url === 'string';
|
|
1409
|
+
}
|
|
1410
|
+
|
|
951
1411
|
/** Cheap structural check used when parsing an untrusted JSON buffer. */
|
|
952
1412
|
export function isOp(value: unknown): value is Op {
|
|
953
1413
|
if (typeof value !== 'object' || value === null) return false;
|
|
954
1414
|
const op = (value as { op?: unknown }).op;
|
|
955
1415
|
return (
|
|
956
|
-
op === 'create' ||
|
|
1416
|
+
op === 'create' ||
|
|
1417
|
+
op === 'update' ||
|
|
1418
|
+
op === 'insert' ||
|
|
1419
|
+
op === 'remove' ||
|
|
1420
|
+
op === 'commit' ||
|
|
1421
|
+
op === 'defaults' ||
|
|
1422
|
+
op === 'request' ||
|
|
1423
|
+
op === 'swiftdata' ||
|
|
1424
|
+
op === 'imagedata'
|
|
957
1425
|
);
|
|
958
1426
|
}
|
|
959
1427
|
|
|
@@ -1095,6 +1563,8 @@ export interface ChartAxisLabel {
|
|
|
1095
1563
|
/** Unit position along the axis (y: 0 is the top). */
|
|
1096
1564
|
at: number;
|
|
1097
1565
|
text: string;
|
|
1566
|
+
/** `leading`: an x label that starts at its tick (a date's) instead of centering on it. */
|
|
1567
|
+
anchor?: 'leading';
|
|
1098
1568
|
}
|
|
1099
1569
|
/** `null` for the whole axis means hidden. Positions are unit values along the axis. */
|
|
1100
1570
|
export interface ChartAxis {
|
|
@@ -1192,7 +1662,10 @@ export interface SwipeActionsProps {
|
|
|
1192
1662
|
}
|
|
1193
1663
|
|
|
1194
1664
|
/** `.contextMenu { }`: `[content, ...items]`; a long press or right click lists the items (as in a `menu`) in a popover. */
|
|
1195
|
-
|
|
1665
|
+
/** As `MenuProps`: `deferred` while the items (every child but the content) are not built. */
|
|
1666
|
+
export interface ContextMenuProps {
|
|
1667
|
+
deferred?: boolean;
|
|
1668
|
+
}
|
|
1196
1669
|
|
|
1197
1670
|
/**
|
|
1198
1671
|
* A `List` row that can be selected (`selectable`, `selected`) or deleted
|
|
@@ -1235,6 +1708,19 @@ export interface Style {
|
|
|
1235
1708
|
hitTesting?: boolean;
|
|
1236
1709
|
}
|
|
1237
1710
|
|
|
1711
|
+
export interface Style {
|
|
1712
|
+
/** `.blendMode`: the CSS `mix-blend-mode` the box is composited with. */
|
|
1713
|
+
blendMode?: string;
|
|
1714
|
+
/** `.zIndex(_:)`: the box's CSS `z-index` among its siblings. */
|
|
1715
|
+
zIndex?: number;
|
|
1716
|
+
/**
|
|
1717
|
+
* `.alignmentGuide(_:computeValue:)`: the box's guide `name` on `axis` is
|
|
1718
|
+
* `a + b·width + c·height` (`value: [a, b, c]`), which the containers that
|
|
1719
|
+
* align it by that guide use instead of the default (layout/engine.ts).
|
|
1720
|
+
*/
|
|
1721
|
+
alignmentGuide?: { axis: 'horizontal' | 'vertical'; name: string; value: [number, number, number] };
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1238
1724
|
export type DragPhase = 'began' | 'changed' | 'ended' | 'cancelled';
|
|
1239
1725
|
|
|
1240
1726
|
/**
|
|
@@ -1325,6 +1811,8 @@ export interface DatePickerProps {
|
|
|
1325
1811
|
/** A `<textarea>` filling the proposal; input sends `text` like a `textfield`. */
|
|
1326
1812
|
export interface TextEditorProps {
|
|
1327
1813
|
text: string;
|
|
1814
|
+
/** Bound focus (UIKit's `becomeFirstResponder`): the editor takes or gives up focus; `focus` events report changes. */
|
|
1815
|
+
focused?: boolean;
|
|
1328
1816
|
}
|
|
1329
1817
|
|
|
1330
1818
|
/** A `stepper` half was tapped: +1 or −1. */
|
|
@@ -1394,6 +1882,29 @@ export interface Style {
|
|
|
1394
1882
|
rotation3D?: Rotation3D;
|
|
1395
1883
|
/** `.blur(radius:)`: `filter: blur(<radius>px)`, combined with `shadow` in one `filter`. */
|
|
1396
1884
|
blur?: number;
|
|
1885
|
+
/** `.brightness(_:)`: SwiftUI's amount (-1…1), drawn as CSS `brightness(1 + amount)`. */
|
|
1886
|
+
brightness?: number;
|
|
1887
|
+
/** `.saturation(_:)`: CSS `saturate()`. */
|
|
1888
|
+
saturation?: number;
|
|
1889
|
+
/** `.contrast(_:)`: CSS `contrast()`. */
|
|
1890
|
+
contrast?: number;
|
|
1891
|
+
/** `.grayscale(_:)`: CSS `grayscale()` (0…1). */
|
|
1892
|
+
grayscale?: number;
|
|
1893
|
+
/** `.hueRotation(_:)`: degrees, CSS `hue-rotate()`. */
|
|
1894
|
+
hueRotation?: number;
|
|
1895
|
+
/** `.colorInvert()`: CSS `invert(1)`. */
|
|
1896
|
+
colorInvert?: boolean;
|
|
1897
|
+
/**
|
|
1898
|
+
* `.colorMultiply(_:)`: each component (and the alpha) multiplied by the
|
|
1899
|
+
* color's, drawn with an SVG `feColorMatrix` filter (colorMultiply.ts).
|
|
1900
|
+
*/
|
|
1901
|
+
colorMultiply?: Color;
|
|
1902
|
+
/** View `.underline(_:)`: underlines the texts below (false turns an ancestor's off). */
|
|
1903
|
+
underline?: boolean;
|
|
1904
|
+
/** View `.strikethrough(_:)`: strikes the texts below through (false turns it off). */
|
|
1905
|
+
strikethrough?: boolean;
|
|
1906
|
+
/** View `.italic(_:)`: slants the texts below (false turns it off). */
|
|
1907
|
+
italic?: boolean;
|
|
1397
1908
|
/**
|
|
1398
1909
|
* `.ignoresSafeArea(edges:)`: the engine extends the box to the screen
|
|
1399
1910
|
* edge on each listed side when the box touches that safe-area edge. The
|
|
@@ -1419,3 +1930,241 @@ export type ScenePhase = 'active' | 'inactive' | 'background';
|
|
|
1419
1930
|
export interface EnvironmentEvent {
|
|
1420
1931
|
scenePhase?: ScenePhase;
|
|
1421
1932
|
}
|
|
1933
|
+
|
|
1934
|
+
// ---------------------------------------------------------------------------
|
|
1935
|
+
// Multi-line text fields, view section headers, scrolling to a view
|
|
1936
|
+
// ---------------------------------------------------------------------------
|
|
1937
|
+
|
|
1938
|
+
export interface TextFieldProps {
|
|
1939
|
+
/**
|
|
1940
|
+
* `TextField(_:text:axis: .vertical)`: a `<textarea>` that grows with its
|
|
1941
|
+
* text between the enclosing `lineLimitMin` (1) and `lineLimit` (none)
|
|
1942
|
+
* lines and scrolls past that; Return breaks the line unless the field has
|
|
1943
|
+
* `submit` (then Shift-Return does). Absent for a one-line field.
|
|
1944
|
+
*/
|
|
1945
|
+
axis?: 'vertical';
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
export interface ListProps {
|
|
1949
|
+
/** `.scrollContentBackground(.hidden)`: the list draws no background of its own (rows keep theirs). */
|
|
1950
|
+
background?: 'hidden';
|
|
1951
|
+
/** `.scrollDismissesKeyboard(.immediately | .interactively)`: scrolling blurs the text input being edited inside. */
|
|
1952
|
+
dismissesKeyboard?: boolean;
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
export interface ScrollViewProps {
|
|
1956
|
+
/** As for `list`. */
|
|
1957
|
+
dismissesKeyboard?: boolean;
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1960
|
+
/**
|
|
1961
|
+
* A `Section`'s header or footer that is a view rather than a `Text`: the
|
|
1962
|
+
* first (`sectionheader`) or last (`sectionfooter`) child of the `section`,
|
|
1963
|
+
* holding the view. In a list it sits above / below the section's card in
|
|
1964
|
+
* the content width (footnote font, secondary color); elsewhere it stacks
|
|
1965
|
+
* with the rows.
|
|
1966
|
+
*/
|
|
1967
|
+
export type SectionSupplementProps = Record<string, never>;
|
|
1968
|
+
|
|
1969
|
+
export interface ElementPropsByKind {
|
|
1970
|
+
sectionheader: SectionSupplementProps;
|
|
1971
|
+
sectionfooter: SectionSupplementProps;
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1974
|
+
/** `ScrollViewProxy.scrollTo(_:anchor:)`: where the target should end up (null: as little scrolling as shows it). */
|
|
1975
|
+
export interface ScrollToCommand {
|
|
1976
|
+
anchor: UnitPoint | null;
|
|
1977
|
+
/** Increases with every request (across readers); the page carries out each serial once. */
|
|
1978
|
+
serial: number;
|
|
1979
|
+
}
|
|
1980
|
+
|
|
1981
|
+
export interface Style {
|
|
1982
|
+
/** `.id(_:)` inside a `ScrollViewReader`: this box is a scroll target. */
|
|
1983
|
+
scrollID?: boolean;
|
|
1984
|
+
/**
|
|
1985
|
+
* Set in the pass in which a `ScrollViewProxy` asks to scroll to this box
|
|
1986
|
+
* (and kept until the reader re-runs): after laying out a pass that brings
|
|
1987
|
+
* a serial above every one it handled, the page scrolls the scroll views
|
|
1988
|
+
* and lists around it (smoothly when the pass's commit is animated).
|
|
1989
|
+
*/
|
|
1990
|
+
scrollTo?: ScrollToCommand;
|
|
1991
|
+
/** The lower bound of a `.lineLimit(2...4)` range (absent for 1): a vertical text field's minimum lines. */
|
|
1992
|
+
lineLimitMin?: number;
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1995
|
+
// ---------------------------------------------------------------------------
|
|
1996
|
+
// Video and audio (docs/ops-protocol.md, "Video and audio")
|
|
1997
|
+
// ---------------------------------------------------------------------------
|
|
1998
|
+
|
|
1999
|
+
/**
|
|
2000
|
+
* A `video` element: an `AVPlayer` shown by a view (AVKit's `VideoPlayer`, an
|
|
2001
|
+
* `AVPlayerLayer`), as an HTML `<video>` (src/video.ts). No children.
|
|
2002
|
+
*/
|
|
2003
|
+
/**
|
|
2004
|
+
* Lazy rows: the rows of a `List` or lazy stack that are not built yet
|
|
2005
|
+
* (`remaining` of them, after the built ones). It takes no space; when it
|
|
2006
|
+
* comes within a screen of its scroll view's visible area the page sends a
|
|
2007
|
+
* `lazy` event, and Swift builds the next rows (a new spacer follows them).
|
|
2008
|
+
*/
|
|
2009
|
+
export interface LazySpacerProps {
|
|
2010
|
+
axis: 'vertical' | 'horizontal';
|
|
2011
|
+
remaining: number;
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
/** Lazy menus: the viewer opened (`open: true`) or closed a deferred `menu` / `contextmenu`. */
|
|
2015
|
+
export interface MenuEvent {
|
|
2016
|
+
type: 'menu';
|
|
2017
|
+
id: ElementId;
|
|
2018
|
+
open: boolean;
|
|
2019
|
+
}
|
|
2020
|
+
|
|
2021
|
+
/** A `lazyspacer` came near the visible area: build the next rows. */
|
|
2022
|
+
export interface LazyEvent {
|
|
2023
|
+
type: 'lazy';
|
|
2024
|
+
id: ElementId;
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
export interface VideoProps {
|
|
2028
|
+
/** The media URL (remote, data or blob); null while there is none. */
|
|
2029
|
+
url: string | null;
|
|
2030
|
+
/** Whether the player plays here (only the newest view of a player plays it). */
|
|
2031
|
+
playing: boolean;
|
|
2032
|
+
muted: boolean;
|
|
2033
|
+
/** 0…1. */
|
|
2034
|
+
volume: number;
|
|
2035
|
+
/** The playback rate (positive; the player's default rate while paused). */
|
|
2036
|
+
rate: number;
|
|
2037
|
+
/** An `AVPlayerLooper` loops the item. */
|
|
2038
|
+
loop: boolean;
|
|
2039
|
+
/** CSS `object-fit`: `contain`, `cover`, `fill`. */
|
|
2040
|
+
gravity: 'resizeAspect' | 'resizeAspectFill' | 'resize';
|
|
2041
|
+
/** The browser's native playback controls (`VideoPlayer`, `AVPlayerViewController`). */
|
|
2042
|
+
controls: boolean;
|
|
2043
|
+
/** Seconds; the page seeks once per serial (and reports `seeked` with it). */
|
|
2044
|
+
seek: { time: number; serial: number };
|
|
2045
|
+
/** Report the position this often (seconds) while playing, when shorter than `timeupdate`'s pace. */
|
|
2046
|
+
report?: number;
|
|
2047
|
+
/** The video's size in pixels, once known: the aspect ratio of an axis left open. */
|
|
2048
|
+
width?: number;
|
|
2049
|
+
height?: number;
|
|
2050
|
+
}
|
|
2051
|
+
|
|
2052
|
+
export interface ElementPropsByKind {
|
|
2053
|
+
video: VideoProps;
|
|
2054
|
+
lazyspacer: LazySpacerProps;
|
|
2055
|
+
}
|
|
2056
|
+
|
|
2057
|
+
/**
|
|
2058
|
+
* A gradient of a `Canvas` (`GraphicsContext.Shading`), in the drawing's own
|
|
2059
|
+
* coordinates (points, after the command's `transform`) rather than the
|
|
2060
|
+
* unit square of a view's box.
|
|
2061
|
+
*/
|
|
2062
|
+
export interface CanvasLinearGradientShading {
|
|
2063
|
+
canvasLinearGradient: { stops: GradientStop[]; start: { x: number; y: number }; end: { x: number; y: number } };
|
|
2064
|
+
}
|
|
2065
|
+
export interface CanvasRadialGradientShading {
|
|
2066
|
+
canvasRadialGradient: { stops: GradientStop[]; center: { x: number; y: number }; startRadius: number; endRadius: number };
|
|
2067
|
+
}
|
|
2068
|
+
export type CanvasShading = ShapeStyle | CanvasLinearGradientShading | CanvasRadialGradientShading;
|
|
2069
|
+
|
|
2070
|
+
/** A `GraphicsContext.Filter`: one key, its amount (degrees for `hueRotation`). */
|
|
2071
|
+
export type CanvasFilter =
|
|
2072
|
+
| { blur: number }
|
|
2073
|
+
| { shadow: { color: Color; radius: number; x: number; y: number } }
|
|
2074
|
+
| { grayscale: number }
|
|
2075
|
+
| { saturation: number }
|
|
2076
|
+
| { brightness: number }
|
|
2077
|
+
| { contrast: number }
|
|
2078
|
+
| { hueRotation: number }
|
|
2079
|
+
| { invert: number };
|
|
2080
|
+
|
|
2081
|
+
/** The context's state when a command was drawn. */
|
|
2082
|
+
export interface CanvasState {
|
|
2083
|
+
/** `[a, b, c, d, tx, ty]`, as `CGAffineTransform` (and SVG's `matrix()`); absent for the identity. */
|
|
2084
|
+
transform?: [number, number, number, number, number, number];
|
|
2085
|
+
opacity?: number;
|
|
2086
|
+
/** CSS `mix-blend-mode`. */
|
|
2087
|
+
blendMode?: string;
|
|
2088
|
+
/** SVG path data, in the canvas's coordinates; the command draws inside all of them. */
|
|
2089
|
+
clips?: string[];
|
|
2090
|
+
filters?: CanvasFilter[];
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2093
|
+
export type CanvasCommand = CanvasState &
|
|
2094
|
+
(
|
|
2095
|
+
| { op: 'fill'; path: string; shading: CanvasShading; evenOdd?: boolean }
|
|
2096
|
+
| {
|
|
2097
|
+
op: 'stroke';
|
|
2098
|
+
path: string;
|
|
2099
|
+
shading: CanvasShading;
|
|
2100
|
+
lineWidth: number;
|
|
2101
|
+
lineCap?: 'butt' | 'round' | 'square';
|
|
2102
|
+
lineJoin?: 'miter' | 'round' | 'bevel';
|
|
2103
|
+
miterLimit?: number;
|
|
2104
|
+
dash?: number[];
|
|
2105
|
+
dashPhase?: number;
|
|
2106
|
+
}
|
|
2107
|
+
| {
|
|
2108
|
+
op: 'image';
|
|
2109
|
+
image: ImageProps;
|
|
2110
|
+
/** The point `anchor` (a unit point of the image) is placed at. */
|
|
2111
|
+
x: number;
|
|
2112
|
+
y: number;
|
|
2113
|
+
anchor: UnitPoint;
|
|
2114
|
+
/** `draw(_:in:)`: the rectangle's size; otherwise the image's own size. */
|
|
2115
|
+
width?: number;
|
|
2116
|
+
height?: number;
|
|
2117
|
+
/** A resolved image's `shading`: a template image is painted with it. */
|
|
2118
|
+
shading?: CanvasShading;
|
|
2119
|
+
}
|
|
2120
|
+
| { op: 'text'; text: string; x: number; y: number; anchor: UnitPoint; shading: CanvasShading; font?: Font }
|
|
2121
|
+
);
|
|
2122
|
+
|
|
2123
|
+
/**
|
|
2124
|
+
* A `Canvas` at one size (src/canvasDrawing.ts): the commands its renderer
|
|
2125
|
+
* drew for `width` × `height`, the size the canvas reported. It fills its
|
|
2126
|
+
* proposal and clips the drawing to its box.
|
|
2127
|
+
*/
|
|
2128
|
+
export interface CanvasProps {
|
|
2129
|
+
width: number;
|
|
2130
|
+
height: number;
|
|
2131
|
+
commands: CanvasCommand[];
|
|
2132
|
+
}
|
|
2133
|
+
|
|
2134
|
+
export interface ElementPropsByKind {
|
|
2135
|
+
canvas: CanvasProps;
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2138
|
+
/**
|
|
2139
|
+
* What a `video` element reports: `ready` (metadata), `time`, `status`
|
|
2140
|
+
* (playing, waiting, paused), `seeked` (a `seek` serial done), `play` /
|
|
2141
|
+
* `pause` (the viewer used the controls; `reason: "blocked"` when the browser
|
|
2142
|
+
* refused to start), `volume`, `rate`, `ended`, `error` (a `MediaError` code).
|
|
2143
|
+
*/
|
|
2144
|
+
export interface VideoEvent {
|
|
2145
|
+
type: 'video';
|
|
2146
|
+
id: ElementId;
|
|
2147
|
+
event: 'ready' | 'time' | 'status' | 'seeked' | 'play' | 'pause' | 'volume' | 'rate' | 'ended' | 'error';
|
|
2148
|
+
url?: string;
|
|
2149
|
+
time?: number;
|
|
2150
|
+
duration?: number | null;
|
|
2151
|
+
width?: number;
|
|
2152
|
+
height?: number;
|
|
2153
|
+
status?: 'playing' | 'waiting' | 'paused';
|
|
2154
|
+
serial?: number;
|
|
2155
|
+
reason?: 'blocked';
|
|
2156
|
+
muted?: boolean;
|
|
2157
|
+
volume?: number;
|
|
2158
|
+
rate?: number;
|
|
2159
|
+
code?: number;
|
|
2160
|
+
message?: string;
|
|
2161
|
+
}
|
|
2162
|
+
|
|
2163
|
+
/** `media` requests (src/media.ts): AVFoundation's files and probes, QuickLook's previews. */
|
|
2164
|
+
export interface MediaRequestParams {
|
|
2165
|
+
action: 'file' | 'probe' | 'release' | 'open';
|
|
2166
|
+
url?: string;
|
|
2167
|
+
name?: string;
|
|
2168
|
+
type?: string;
|
|
2169
|
+
data?: string;
|
|
2170
|
+
}
|