@swiftbrowser/web 0.3.0 → 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/src/protocol.ts CHANGED
@@ -719,7 +719,15 @@ export interface PickerProps {
719
719
  * `GeometryReader`: fills its proposal and reports its size through a
720
720
  * `geometry` event whenever it changes. Exactly one child.
721
721
  */
722
- export type GeometryProps = Record<string, never>;
722
+ export interface GeometryProps {
723
+ /**
724
+ * Report the reader's frame on screen too (`x`, `y` and `safeArea` in its
725
+ * `geometry` events, kept current as its ancestors scroll), for
726
+ * `GeometryProxy.frame(in: .global)` and `safeAreaInsets`. Absent: the size
727
+ * only, as before.
728
+ */
729
+ reportsFrame?: boolean;
730
+ }
723
731
 
724
732
  // Phase 6 kinds (docs/phase6/layout-containers.md).
725
733
 
@@ -870,6 +878,19 @@ export interface TapGestureProps {
870
878
  location?: boolean;
871
879
  }
872
880
 
881
+ /**
882
+ * A box the page fills with its own DOM (src/hostContent.ts): `content` is
883
+ * the key the page registered its element under. `sizing: "fill"` takes the
884
+ * proposal, the content's own size on an unconstrained axis; `"content"`
885
+ * takes the content's size, its width capped by the proposal and its height
886
+ * measured at that width, like text. Only page-side producers (such as
887
+ * @swiftbrowser/react) emit it; the Swift core never does.
888
+ */
889
+ export interface HostProps {
890
+ content: string;
891
+ sizing: 'fill' | 'content';
892
+ }
893
+
873
894
  export interface ElementPropsByKind {
874
895
  text: TextProps;
875
896
  vstack: VStackProps;
@@ -905,6 +926,7 @@ export interface ElementPropsByKind {
905
926
  toolbar: ToolbarProps;
906
927
  searchfield: SearchFieldProps;
907
928
  tapgesture: TapGestureProps;
929
+ host: HostProps;
908
930
  }
909
931
 
910
932
  export type ElementKind = keyof ElementPropsByKind;
@@ -1289,6 +1311,11 @@ export interface GeometryEvent {
1289
1311
  id: ElementId;
1290
1312
  width: number;
1291
1313
  height: number;
1314
+ /** With `reportsFrame`: the box's origin in the root's coordinates, scrolling included (whole px). */
1315
+ x?: number;
1316
+ y?: number;
1317
+ /** With `reportsFrame`: how far the device's safe area reaches into the box on each edge. */
1318
+ safeArea?: { top: number; leading: number; bottom: number; trailing: number };
1292
1319
  }
1293
1320
 
1294
1321
  /** Host measurements of one subview of a `layout` element (points, 2 decimals; `"infinity"` for an unbounded axis). */
@@ -1333,7 +1360,8 @@ export type RendererEvent =
1333
1360
  // A `video` element's playback (src/video.ts)
1334
1361
  | VideoEvent
1335
1362
  | LazyEvent
1336
- | MenuEvent;
1363
+ | MenuEvent
1364
+ | HoverEvent;
1337
1365
 
1338
1366
  /**
1339
1367
  * Phase 13: the page's answer to the `request` op with this `id`: `value`
@@ -1451,7 +1479,10 @@ export function isOp(value: unknown): value is Op {
1451
1479
  // ---------------------------------------------------------------------------
1452
1480
 
1453
1481
  /** `NavigationSplitView` in the regular size class: children are `[sidebar, detail]`, each a `navstack`. */
1454
- export type NavSplitProps = Record<string, never>;
1482
+ export interface NavSplitProps {
1483
+ /** iPadOS: false hides the sidebar (`NavigationSplitViewVisibility.detailOnly`); absent or true shows it. */
1484
+ sidebarVisible?: boolean;
1485
+ }
1455
1486
 
1456
1487
  export type ViewThatFitsAxes = 'horizontal' | 'vertical' | 'both';
1457
1488
  /**
@@ -1466,6 +1497,17 @@ export interface ViewThatFitsProps {
1466
1497
  export interface ElementPropsByKind {
1467
1498
  navsplit: NavSplitProps;
1468
1499
  viewthatfits: ViewThatFitsProps;
1500
+ inspector: InspectorProps;
1501
+ inspectorpanel: Record<string, never>;
1502
+ }
1503
+
1504
+ /**
1505
+ * `.inspector(isPresented:)` in the regular size class: the children are the
1506
+ * content, then an `inspectorpanel` (the trailing column's content).
1507
+ */
1508
+ export interface InspectorProps {
1509
+ /** Whether the panel is shown; false slides it off the trailing edge. */
1510
+ presented: boolean;
1469
1511
  }
1470
1512
 
1471
1513
  export interface Style {
@@ -1688,14 +1730,40 @@ export interface ContextMenuProps {
1688
1730
  }
1689
1731
 
1690
1732
  /**
1691
- * A `List` row that can be selected (`selectable`, `selected`) or deleted
1692
- * (`deletable`, from `ForEach.onDelete`). A tap on a selectable row sends
1693
- * `tap` with the row id; swipe-to-delete or the edit-mode minus sends `delete`.
1733
+ * A `List` row that can be selected (`selectable`, `selected`), deleted
1734
+ * (`deletable`, from `ForEach.onDelete`) or moved (`movable`, from
1735
+ * `ForEach.onMove`; absent means false). A tap on a selectable row sends
1736
+ * `tap` with the row id; swipe-to-delete or the edit-mode minus sends
1737
+ * `delete`. A movable row shows a grip at its trailing edge while the list
1738
+ * is editing, and a long press lifts it otherwise; dragging it among its
1739
+ * neighbours and letting go sends `move` (src/dragDrop.ts).
1694
1740
  */
1695
1741
  export interface ListRowProps {
1696
1742
  selectable?: boolean;
1697
1743
  selected?: boolean;
1698
1744
  deletable?: boolean;
1745
+ movable?: boolean;
1746
+ }
1747
+
1748
+ /**
1749
+ * `.draggable` / `.onDrag`: exactly one child, the child's size. A long
1750
+ * press (touch) or a 10 px drag (mouse) lifts a copy of the content, which
1751
+ * follows the pointer; `dragstart` goes out as it lifts and `dragend` once
1752
+ * it is dropped or let go (src/dragDrop.ts).
1753
+ */
1754
+ export type DraggableProps = Record<string, never>;
1755
+
1756
+ /**
1757
+ * `.dropDestination` / `.onDrop`: exactly one child, the child's size. A
1758
+ * lifted `draggable` over it sends `drop` with the phase `entered` /
1759
+ * `exited`, and `performed` with the source when released over it. Text,
1760
+ * links and files dragged in from outside the page (the browser's own drag
1761
+ * and drop) are offered when their MIME type matches one of `accepts`
1762
+ * (`text/plain`, `image/*`, or a star over a star for anything); they
1763
+ * arrive as `items`.
1764
+ */
1765
+ export interface DropDestinationProps {
1766
+ accepts?: string[];
1699
1767
  }
1700
1768
 
1701
1769
  export interface ElementPropsByKind {
@@ -1703,12 +1771,14 @@ export interface ElementPropsByKind {
1703
1771
  swipeactions: SwipeActionsProps;
1704
1772
  contextmenu: ContextMenuProps;
1705
1773
  listrow: ListRowProps;
1774
+ draggable: DraggableProps;
1775
+ dropdestination: DropDestinationProps;
1706
1776
  }
1707
1777
 
1708
- export const INTERACTION_KINDS: readonly ElementKind[] = ['gesture', 'swipeactions', 'contextmenu', 'listrow'];
1778
+ export const INTERACTION_KINDS: readonly ElementKind[] = ['gesture', 'swipeactions', 'contextmenu', 'listrow', 'draggable', 'dropdestination'];
1709
1779
 
1710
1780
  export interface ListProps {
1711
- /** `EditButton` / `editMode`: every `listrow` gains a 44 pt leading control and its content shifts right 44. */
1781
+ /** `EditButton` / `editMode`: a selectable or deletable `listrow` gains a 44 pt leading control and its content shifts right 40; a movable one a trailing grip. */
1712
1782
  editing?: boolean;
1713
1783
  /** `.refreshable`: a pull past 60 pt at the top sends `refresh`. */
1714
1784
  refreshable?: boolean;
@@ -1772,9 +1842,52 @@ export interface RefreshEvent {
1772
1842
  type: 'refresh';
1773
1843
  id: ElementId;
1774
1844
  }
1845
+ /**
1846
+ * A movable `listrow` was dragged to a new place: `to` is the index among
1847
+ * its container's children (the `list`'s, or its `section`'s) before which
1848
+ * it goes, counted before it leaves (0 ... the child count), as
1849
+ * `move(fromOffsets:toOffset:)` takes its destination.
1850
+ */
1851
+ export interface MoveEvent {
1852
+ type: 'move';
1853
+ id: ElementId;
1854
+ to: number;
1855
+ }
1856
+ /** A `draggable` was lifted: its payload is made now and kept until `dragend`. */
1857
+ export interface DragStartEvent {
1858
+ type: 'dragstart';
1859
+ id: ElementId;
1860
+ }
1861
+ /** The lifted `draggable` was dropped or let go. */
1862
+ export interface DragEndEvent {
1863
+ type: 'dragend';
1864
+ id: ElementId;
1865
+ }
1866
+ /** One thing dragged in from outside the page: text (or a link, `text/uri-list`), or a file's bytes in base64. */
1867
+ export interface DropItem {
1868
+ type: string;
1869
+ text?: string;
1870
+ name?: string;
1871
+ data?: string;
1872
+ }
1873
+ /**
1874
+ * A drag over a `dropdestination`: it `entered`, `exited`, or `performed`
1875
+ * (was released over it). `source` is the lifted `draggable`'s id for a drag
1876
+ * that started in the app; `items` what came from outside the page. The
1877
+ * point is in the destination's own coordinates (0, 0 while entering and leaving).
1878
+ */
1879
+ export interface DropEvent {
1880
+ type: 'drop';
1881
+ id: ElementId;
1882
+ phase: 'entered' | 'exited' | 'performed';
1883
+ source?: ElementId;
1884
+ items?: DropItem[];
1885
+ x: number;
1886
+ y: number;
1887
+ }
1775
1888
 
1776
1889
  /** The Phase 8 events (merged into `RendererEvent` above). */
1777
- export type InteractionEvent = DragEvent | LongPressEvent | DeleteEvent | RefreshEvent;
1890
+ export type InteractionEvent = DragEvent | LongPressEvent | DeleteEvent | RefreshEvent | MoveEvent | DragStartEvent | DragEndEvent | DropEvent;
1778
1891
  // Phase 8: alerts, controls, effects
1779
1892
  // (docs/ops-protocol.md, "Phase 8: interaction"; gestures, swipe actions,
1780
1893
  // context menus, list rows and refresh live in their own block)
@@ -1970,11 +2083,24 @@ export interface ListProps {
1970
2083
  background?: 'hidden';
1971
2084
  /** `.scrollDismissesKeyboard(.immediately | .interactively)`: scrolling blurs the text input being edited inside. */
1972
2085
  dismissesKeyboard?: boolean;
2086
+ /**
2087
+ * `.scrollEdgeEffectStyle(_:for:)` / `.scrollEdgeEffectHidden(_:for:)`: the
2088
+ * scroll edge effect where the list runs under its screen's bar (`top`) or
2089
+ * a bar covering the bottom (`bottom`); an absent edge is automatic (soft).
2090
+ */
2091
+ edgeEffect?: EdgeEffectProps;
2092
+ }
2093
+
2094
+ export interface EdgeEffectProps {
2095
+ top?: 'hard' | 'soft' | 'hidden';
2096
+ bottom?: 'hard' | 'soft' | 'hidden';
1973
2097
  }
1974
2098
 
1975
2099
  export interface ScrollViewProps {
1976
2100
  /** As for `list`. */
1977
2101
  dismissesKeyboard?: boolean;
2102
+ /** As for `list`. */
2103
+ edgeEffect?: EdgeEffectProps;
1978
2104
  }
1979
2105
 
1980
2106
  /**
@@ -1992,6 +2118,59 @@ export interface ElementPropsByKind {
1992
2118
  }
1993
2119
 
1994
2120
  /** `ScrollViewProxy.scrollTo(_:anchor:)`: where the target should end up (null: as little scrolling as shows it). */
2121
+ /**
2122
+ * SF Symbols' effects (`.symbolEffect`), drawn with CSS on the styled box:
2123
+ * `bounce`, `pulse`, `variableColor` (as a pulse), `scale` (up while
2124
+ * active; `down` shrinks), `rotate`, `wiggle`, `breathe`, `appear` /
2125
+ * `disappear` (shown / hidden while active). Without `trigger` the effect
2126
+ * runs while the style carries it (`repeat` times, or forever); with one, it
2127
+ * plays once (`repeat` times) whenever `trigger` changes, like
2128
+ * `.symbolEffect(_:value:)`.
2129
+ */
2130
+ export interface SymbolEffectStyle {
2131
+ effect: 'bounce' | 'pulse' | 'variableColor' | 'scale' | 'rotate' | 'wiggle' | 'breathe' | 'appear' | 'disappear';
2132
+ direction?: 'up' | 'down';
2133
+ /** Seconds per run at speed 1 is the effect's own; `speed` divides it. */
2134
+ speed?: number;
2135
+ repeat?: number | 'forever';
2136
+ trigger?: number;
2137
+ }
2138
+
2139
+ export interface Style {
2140
+ /** The page sends `hover` events as a mouse enters and leaves the box (`.onHover`). */
2141
+ hover?: boolean;
2142
+ /** `.help(_:)`: a tooltip on the box. */
2143
+ help?: string;
2144
+ /** `.pointerStyle(_:)`: the CSS cursor over the box (`pointer`, `text`, `grab`…). */
2145
+ pointerStyle?: string;
2146
+ symbolEffect?: SymbolEffectStyle;
2147
+ /**
2148
+ * `.matchedGeometryEffect(id:in:)`: when an animated pass removes a box
2149
+ * with this id and inserts another with it, the inserted one starts from
2150
+ * the removed one's frame and the removed one's exit travels to the new
2151
+ * frame. The namespace is part of the id.
2152
+ */
2153
+ matchedGeometry?: string;
2154
+ /**
2155
+ * `.contentTransition(_:)`: how a text under the box changes in a pass that
2156
+ * animates. `numericText` rolls the old text out upward and the new one in
2157
+ * from below, or the other way when the new text reads as a smaller number
2158
+ * (`countsDown` fixes the direction); `opacity` and `interpolate` crossfade
2159
+ * them.
2160
+ */
2161
+ contentTransition?: { kind: 'numericText' | 'opacity' | 'interpolate'; countsDown?: boolean };
2162
+ }
2163
+
2164
+ /**
2165
+ * A mouse (or pen) entered (`value: true`) or left a box whose style has
2166
+ * `hover`. Touch never hovers.
2167
+ */
2168
+ export interface HoverEvent {
2169
+ type: 'hover';
2170
+ id: ElementId;
2171
+ value: boolean;
2172
+ }
2173
+
1995
2174
  export interface ScrollToCommand {
1996
2175
  anchor: UnitPoint | null;
1997
2176
  /** Increases with every request (across readers); the page carries out each serial once. */