@wix/himalaya-cli 0.1616.0 → 0.1618.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.
Files changed (73) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/builder.d.ts +15 -0
  2. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/schema.d.ts +28 -0
  3. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/screens/src/index.d.ts +2 -0
  4. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/screens/src/one-app-section.d.ts +39 -0
  5. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/screens/src/one-app-visibility.d.ts +22 -0
  6. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/core.mjs +1 -0
  7. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/screens.mjs +151 -24
  8. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/sdui.mjs +8 -0
  9. package/dist/cli.mjs +1042 -389
  10. package/dist/preview-assets.generated.bin +0 -0
  11. package/guides/component-reference.json +10 -1
  12. package/guides/component-reference.md +25 -2
  13. package/guides/designing-himi-screens.md +3 -1
  14. package/guides/hhp.md +3 -1
  15. package/guides/himi-json-output.md +11 -1
  16. package/guides/index.json +1 -1
  17. package/guides/one-app-section-mappings.md +32 -0
  18. package/guides/one-app-to-himi-app.md +133 -9
  19. package/guides/tier-5-add-a-screen.md +1 -1
  20. package/package.json +2 -2
  21. package/templates/beauty-salon/dev/index.ts +37 -18
  22. package/templates/beauty-salon/tier5-src/_shared/sign-in-sheet.ts +18 -0
  23. package/templates/beauty-salon/tier5-src/himi-booking-service/index.ts +8 -3
  24. package/templates/beauty-salon/tier5-src/himi-branded-lite-agenda/index.ts +7 -2
  25. package/templates/beauty-salon/tier5-src/himi-branded-lite-place-summary/index.ts +7 -2
  26. package/templates/beauty-salon/tier5-src/himi-store-account/index.ts +8 -2
  27. package/templates/branded-lite/dev/index.ts +95 -47
  28. package/templates/branded-lite/tier5-src/_shared/sign-in-sheet.ts +18 -0
  29. package/templates/branded-lite/tier5-src/himi-booking-service/index.ts +8 -3
  30. package/templates/branded-lite/tier5-src/himi-branded-lite-agenda/index.ts +7 -2
  31. package/templates/branded-lite/tier5-src/himi-branded-lite-place-summary/index.ts +7 -2
  32. package/templates/branded-lite/tier5-src/himi-branded-lite-program/index.ts +7 -2
  33. package/templates/branded-lite/tier5-src/himi-store-account/index.ts +8 -2
  34. package/templates/community-club/dev/index.ts +27 -13
  35. package/templates/community-club/tier5-src/_shared/sign-in-sheet.ts +18 -0
  36. package/templates/community-club/tier5-src/himi-store-account/index.ts +8 -2
  37. package/templates/events-meetups/dev/index.ts +25 -12
  38. package/templates/events-meetups/tier5-src/_shared/sign-in-sheet.ts +18 -0
  39. package/templates/events-meetups/tier5-src/himi-store-account/index.ts +8 -2
  40. package/templates/gym-fitness/dev/index.ts +41 -20
  41. package/templates/gym-fitness/tier5-src/_shared/sign-in-sheet.ts +18 -0
  42. package/templates/gym-fitness/tier5-src/himi-booking-service/index.ts +8 -3
  43. package/templates/gym-fitness/tier5-src/himi-branded-lite-agenda/index.ts +7 -2
  44. package/templates/gym-fitness/tier5-src/himi-branded-lite-place-summary/index.ts +7 -2
  45. package/templates/gym-fitness/tier5-src/himi-store-account/index.ts +8 -2
  46. package/templates/nonprofit-cause/dev/index.ts +31 -15
  47. package/templates/nonprofit-cause/tier5-src/_shared/sign-in-sheet.ts +18 -0
  48. package/templates/nonprofit-cause/tier5-src/himi-branded-lite-place-summary/index.ts +7 -2
  49. package/templates/nonprofit-cause/tier5-src/himi-store-account/index.ts +8 -2
  50. package/templates/podcast-creator/dev/index.ts +29 -14
  51. package/templates/podcast-creator/tier5-src/_shared/sign-in-sheet.ts +18 -0
  52. package/templates/podcast-creator/tier5-src/himi-branded-lite-place-summary/index.ts +7 -2
  53. package/templates/podcast-creator/tier5-src/himi-store-account/index.ts +8 -2
  54. package/templates/portfolio-creative/dev/index.ts +31 -15
  55. package/templates/portfolio-creative/tier5-src/_shared/sign-in-sheet.ts +18 -0
  56. package/templates/portfolio-creative/tier5-src/himi-store-account/index.ts +8 -2
  57. package/templates/restaurant/dev/index.ts +27 -13
  58. package/templates/restaurant/tier5-src/_shared/sign-in-sheet.ts +18 -0
  59. package/templates/restaurant/tier5-src/himi-store-account/index.ts +8 -2
  60. package/templates/retail-store/dev/index.ts +25 -12
  61. package/templates/retail-store/tier5-src/_shared/sign-in-sheet.ts +18 -0
  62. package/templates/retail-store/tier5-src/himi-store-account/index.ts +8 -2
  63. package/templates/salon-spa/tier5-src/_shared/sign-in-sheet.ts +18 -0
  64. package/templates/salon-spa/tier5-src/himi-booking-service/index.ts +8 -3
  65. package/templates/salon-spa/tier5-src/himi-branded-lite-agenda/index.ts +7 -2
  66. package/templates/salon-spa/tier5-src/himi-store-account/index.ts +8 -2
  67. package/templates/yoga-studio/dev/index.ts +37 -18
  68. package/templates/yoga-studio/tier5-src/_shared/sign-in-sheet.ts +18 -0
  69. package/templates/yoga-studio/tier5-src/himi-booking-service/index.ts +8 -3
  70. package/templates/yoga-studio/tier5-src/himi-branded-lite-agenda/index.ts +7 -2
  71. package/templates/yoga-studio/tier5-src/himi-branded-lite-place-summary/index.ts +7 -2
  72. package/templates/yoga-studio/tier5-src/himi-branded-lite-program/index.ts +7 -2
  73. package/templates/yoga-studio/tier5-src/himi-store-account/index.ts +8 -2
Binary file
@@ -2,7 +2,7 @@
2
2
  "_comment": "GENERATED by core/web-embed/authoring/gen-reference.mjs from core/ts/src/schema.ts — do not hand-edit. The schema is the source of truth; regenerate on schema changes.",
3
3
  "schemaSource": "core/ts/src/schema.ts",
4
4
  "bindingGrammar": "$service:<service>.<path> (worker state) · $item.<field> (list row) · $flag:<key> (feature flag) · $env:<key> (client environment — #1056). Bindings resolve in the text/value props marked 'binding-aware' below — INCLUDING Modifiers token refs — but only `background` and `border.color`, which are the two whose token a binding actually fills: a worker can drive per-item theming (e.g. a game board's per-square color), not just text. `shadow` is NOT binding-aware on any renderer, and a gradient is driven by its own `backgroundGradientPath` prop resolving to a gradient token NAME, not by a binding inside a token ref — so `shadow: { token: \"$item.x\" }` and `backgroundGradient: { token: \"$item.x\" }` keep the sentinel and silently lose the per-item styling. Colour slots split by LEVEL, not by component: inside modifiers a colour is a TokenRef OBJECT ({ token: \"…\" }), inside props it is a bare TokenName STRING — there is no modifiers.color or modifiers.tint (see the 'Token slots' section in component-reference.md). A few input props render the LITERAL and are NOT binding-aware — notably SearchField.placeholder and Chip.label; SearchField.value is live and binding-aware like other content props. Bindings also CANNOT target strict-enum fields (style, size, alignment, severity, presentation, contentMode, …) — those fail at render, not validation. $env: is client-resolved (no worker) and valid in modifiers.hiddenPath and FragmentSlot.casePath ONLY — keys reduceMotion/colorScheme/sizeClass/isRTL/keyboardVisible, e.g. hiddenPath:\"$env:reduceMotion\" or hiddenPath:\"$env:colorScheme==light\", casePath:\"$env:colorScheme\"; unknown key fails open (shown / defaultCase).",
5
- "componentCount": 88,
5
+ "componentCount": 89,
6
6
  "notImplementedComponents": [
7
7
  "Text",
8
8
  "Icon",
@@ -97,6 +97,15 @@
97
97
  ],
98
98
  "propsSource": "export interface ErrorStateProps {\n /** Default `\"server\"`. An unknown value is treated as `\"server\"`. */\n variant?: \"server\" | \"offline\" | \"permission\" | \"signIn\";\n /** `$service:` binding that selects the variant at runtime; wins over `variant`. */\n variantPath?: string;\n title?: string;\n body?: string;\n /** The CTA's action. Absent → no button. */\n cta?: Action;\n ctaLabel?: string;\n /** `\"screen\"` (default, ~96px from the top) or `\"section\"` (~24px). */\n placement?: \"screen\" | \"section\";\n}"
99
99
  },
100
+ {
101
+ "name": "QrCode",
102
+ "category": "Core",
103
+ "propsType": "QrCodeProps",
104
+ "bindings": [
105
+ "valuePath"
106
+ ],
107
+ "propsSource": "export interface QrCodeProps {\n /** Literal payload (UTF-8). One of `value` / `valuePath` is required. */\n value?: string;\n /** `$service:` / `$item.` binding for the payload; wins over `value` once it resolves to a\n * non-empty string (until then — no worker yet, an empty field — `value` draws). */\n valuePath?: string;\n /** Side length (pt/dp/px), quiet zone included. Default `160`. */\n size?: number;\n /** Default `\"M\"`. A literal over the level's capacity is a validator error. */\n errorCorrection?: \"L\" | \"M\" | \"Q\" | \"H\";\n /** Module colour token. Default `\"textPrimary\"`. */\n color?: string;\n /** Background colour token. Default `\"surfacePrimary\"`. */\n background?: string;\n /** Light margin, in modules. Default `4` (the spec minimum). */\n quietZone?: number;\n}"
108
+ },
100
109
  {
101
110
  "name": "Text",
102
111
  "category": "Core",
@@ -3,7 +3,7 @@
3
3
  > GENERATED from `core/ts/src/schema.ts` by `core/web-embed/authoring/gen-reference.mjs`.
4
4
  > The schema is the source of truth — regenerate on schema changes; do not hand-edit.
5
5
 
6
- **88 core component types.** Every component body is `{ "package": "himalaya", "type": "<Type>", "props": { … } }`.
6
+ **89 core component types.** Every component body is `{ "package": "himalaya", "type": "<Type>", "props": { … } }`.
7
7
  Binding grammar: `$service:<service>.<path>` (worker state) · `$item.<field>` (list row template) · `$flag:<key>` (feature flag) · `$env:<key>` (client environment — #1056).
8
8
  Bindings resolve in the text/value props marked **binding-aware** below — **including two `Modifiers` token refs**, `background` and `border.color`, which are the only two whose token a binding actually fills: a worker can drive per-item **theming** (e.g. a game board's per-square color, `background: { token: "$item.bg" }`), not just text content. `shadow` and `backgroundGradient` are `TokenRef`s but are **not** binding-aware on any renderer — `shadow: { token: "$item.x" }` keeps the sentinel as a literal token name and silently loses the per-item styling, and a gradient is driven by its own `backgroundGradientPath` prop resolving to a gradient token NAME, not by a binding inside a token ref.
9
9
  `$env:` is **client-resolved** (no worker) and valid in `modifiers.hiddenPath` and `FragmentSlot.casePath` **only** — keys `reduceMotion` / `colorScheme` / `sizeClass` / `isRTL` / `keyboardVisible` (an on-screen keyboard is up — `hiddenPath: "$env:keyboardVisible"` hides a header while typing), with an optional `==`/`!=` comparison (e.g. `hiddenPath: "$env:reduceMotion"`, `hiddenPath: "$env:colorScheme==light"`, `casePath: "$env:colorScheme"`). An unknown key fails open (shown / `defaultCase`).
@@ -38,6 +38,7 @@ See also **[Modifiers](#modifiers)** (the `modifiers` block) and **[Actions](#ac
38
38
  | `Spacer` | Core | — |
39
39
  | `EmptyState` | Core | — |
40
40
  | `ErrorState` | Core | `variantPath` |
41
+ | `QrCode` | Core | `valuePath` |
41
42
  | `Text` | Core | `text` |
42
43
  | `Image` | Core | `url`, `initials`, `contentDescription` |
43
44
  | `Icon` | Core | — |
@@ -120,7 +121,7 @@ See also **[Modifiers](#modifiers)** (the `modifiers` block) and **[Actions](#ac
120
121
 
121
122
  These props are accepted by the schema and pass validation, but the named platform's renderer never reads them — they silently do nothing (no warning, no log). Prefer a prop NOT listed here, or drive the behaviour from a worker.
122
123
 
123
- **Scope: 7 of 88 components, all of them android / web / ios-only** — every other component/platform pair reads every prop it decodes. The list splits in two, and the halves mean different things:
124
+ **Scope: 7 of 89 components, all of them android / web / ios-only** — every other component/platform pair reads every prop it decodes. The list splits in two, and the halves mean different things:
124
125
 
125
126
  - **`category` (2: `MediaPlayer`, `TimeGrid`)** — the prop changes the component's *kind*. These genuinely are **not implemented**: an overlay renders always-visible inline, so the component does not do the job its name implies. Check the row's note for a working alternative.
126
127
  - **`styling` (5: `Text`, `Icon`, `WebView`, `Video`, `PdfView`)** — the component itself **works**; only the listed prop is inert. Use the component; just do not depend on that one prop.
@@ -438,6 +439,28 @@ export interface ErrorStateProps {
438
439
  }
439
440
  ```
440
441
 
442
+ #### QrCode
443
+
444
+ ```ts
445
+ export interface QrCodeProps {
446
+ /** Literal payload (UTF-8). One of `value` / `valuePath` is required. */
447
+ value?: string;
448
+ /** `$service:` / `$item.` binding for the payload; wins over `value` once it resolves to a
449
+ * non-empty string (until then — no worker yet, an empty field — `value` draws). */
450
+ valuePath?: string;
451
+ /** Side length (pt/dp/px), quiet zone included. Default `160`. */
452
+ size?: number;
453
+ /** Default `"M"`. A literal over the level's capacity is a validator error. */
454
+ errorCorrection?: "L" | "M" | "Q" | "H";
455
+ /** Module colour token. Default `"textPrimary"`. */
456
+ color?: string;
457
+ /** Background colour token. Default `"surfacePrimary"`. */
458
+ background?: string;
459
+ /** Light margin, in modules. Default `4` (the spec minimum). */
460
+ quietZone?: number;
461
+ }
462
+ ```
463
+
441
464
  #### Text
442
465
 
443
466
  ```ts
@@ -317,7 +317,9 @@ dense row); `ProgressBar` for determinate progress, `ActivityIndicator` for inde
317
317
  a single dial metric. *Use a `Badge` for a count, a `Tag` for a category — they aren't interchangeable.*
318
318
 
319
319
  **Media** — `Image` (`fillWidth`, `height`, always `contentDescription`); `Video`/`Lottie`/`Rive` for
320
- motion media; `Map` for location; `Avatar` for a person; `WebView` only when native can't express it.
320
+ motion media; `Map` for location; `Avatar` for a person; `QrCode` to share a link, ticket or invite
321
+ as a code generated on the device (bind `valuePath`; keep the payload short, since a literal over the
322
+ level's capacity fails validation); `WebView` only when native can't express it.
321
323
  *Fill-width media gets a `cornerRadius` so it doesn't fight the card edges.*
322
324
  For audio apps, keep playback UI in SDUI and call `@himalaya/media-playback` from the Tier-5 worker:
323
325
  compose artwork with `Image`, transport controls with icon buttons, scrubbing with `Slider`, buffering
package/guides/hhp.md CHANGED
@@ -213,10 +213,12 @@ A screen may also carry `params` (the navigation input a device opens it with, u
213
213
  himi fidelity --content <dir> [--screen a,b] [--variant light,dark,rtl,tablet] [--ios <udid>] [--android <serial>] [--ios-tablet <udid>] [--android-tablet <serial>] [--app-id <id>] [--release <id>] [--serve <port>] [--no-native] [--json] [--post-pr <n>]
214
214
  ```
215
215
 
216
+ `rtl` runs only when config.ts `locale.default` or `locale.translations` names a right-to-left language the Player supports (today `he`), and `locale.pin` does not pin a left-to-right default. A language picked inside the app also outranks the device, and the command cannot read or reset it: on a device where the app's language was changed in the Player, reinstall the Player before an `rtl` run. The Player follows the app's locale, so an app that ships no such language stays left-to-right on a Hebrew device, and comparing it with a mirrored page would only report that. Otherwise every `rtl` row is reported `skipped` with the reason.
217
+
216
218
  For each screen and variant (`light`, `dark`, `rtl`, `tablet`), the command does four things:
217
219
 
218
220
  1. **Captures the mockup.** It draws the page in Chromium at the variant's width. Dark mode is drawn by emulating `prefers-color-scheme`. RTL is drawn by setting `dir=rtl` on the page.
219
- 2. **Captures the web render** from the app's recorded data, as `himi render` does by default. Native frames come from Himi Player on the devices you pass: `--ios <udid>` and `--android <serial>`, plus `--ios-tablet` and `--android-tablet` for the tablet variant. Only those devices are touched. For each variant the command sets dark or light appearance and, for `rtl`, the Hebrew language (iOS `AppleLanguages`, Android per-app locale, API 33+). It opens `himi://app/<app>/screen/<screen>` and captures once two frames match. Every setting it changed is restored afterwards, also on Ctrl-C. A variant with no device is reported `skipped`, never passed. Without `--release <id>` or `--serve <port>` the Player shows the app's **live** release, not your working copy. `--serve <port>` serves the working copy on `127.0.0.1:<port>` as `himi run` does, so native and web render the same release. The Player reads a local origin only from a Debug build that compiled it in (see [View your package on a device](himi-player-implementation.md#view-your-package-on-a-device)): build it with `HIMALAYA_API_BASE_URL_INFO=http://127.0.0.1:<port>` on iOS and `-PhimalayaDevServeBaseUrl=http://10.0.2.2:<port>` on Android. An iOS device whose Player reads another origin is skipped with the rebuild to run. Android's origin cannot be read back from the installed app, so check that build yourself. A screen that declares `params` is skipped natively for now, because the Player's deep link does not carry them yet. On a fresh iOS simulator, open one `himi://` link by hand first and accept iOS's "Open in Himi Player?" prompt: the command cannot answer it, and until it is accepted every iOS capture shows the prompt.
221
+ 2. **Captures the web render** from the app's recorded data, as `himi render` does by default. Native frames come from Himi Player on the devices you pass: `--ios <udid>` and `--android <serial>`, plus `--ios-tablet` and `--android-tablet` for the tablet variant. Only those devices are touched. For each variant the command sets dark or light appearance and, for `rtl`, the app's right-to-left language (iOS `AppleLanguages`, Android per-app locale, API 33+). It opens `himi://app/<app>/screen/<screen>` and captures once two frames match. Every setting it changed is restored afterwards, also on Ctrl-C. A variant with no device is reported `skipped`, never passed. Without `--release <id>` or `--serve <port>` the Player shows the app's **live** release, not your working copy. `--serve <port>` serves the working copy on `127.0.0.1:<port>` as `himi run` does, so native and web render the same release. The Player reads a local origin only from a Debug build that compiled it in (see [View your package on a device](himi-player-implementation.md#view-your-package-on-a-device)): build it with `HIMALAYA_API_BASE_URL_INFO=http://127.0.0.1:<port>` on iOS and `-PhimalayaDevServeBaseUrl=http://10.0.2.2:<port>` on Android. An iOS device whose Player reads another origin is skipped with the rebuild to run. Android's origin cannot be read back from the installed app, so check that build yourself. A screen that declares `params` is skipped natively for now, because the Player's deep link does not carry them yet. On a fresh iOS simulator, open one `himi://` link by hand first and accept iOS's "Open in Himi Player?" prompt: the command cannot answer it, and until it is accepted every iOS capture shows the prompt.
220
222
  3. **Scores mockup↔web** with ImageMagick SSIM, globally and per tile. The worst tile says where the screens differ most.
221
223
  4. **Asks a fresh model** two questions, using the repo's fidelity judge prompt. The model never ran in the session that wrote the app.
222
224
  - **Design:** does WEB look like the MOCKUP? This judges the port.
@@ -83,10 +83,20 @@ publication readiness or bound metadata not yet supplied to the final push.
83
83
  | --- | --- |
84
84
  | `invalid_usage` | Missing, repeated or unsupported checker arguments. |
85
85
  | `payment_review_unreadable` | The collected source evidence or site-bound payment review cannot be read or verified. |
86
- | `payment_decision_required` | Payment intent, readiness evidence or an explicit owner decision remains unresolved before scaffolding. Selecting connect-provider waits for setup and a new review. |
86
+ | `payment_decision_required` | Payment intent, site-bound evidence, target checkout compatibility or a required owner decision remains unresolved before scaffolding. Selecting connect-provider waits for setup and a new review. Unknown payment readiness alone does not refuse a reviewed, supported existing checkout. |
87
87
 
88
88
  The checker validates recorded evidence and decisions; it does not independently
89
89
  verify merchant readiness or create transactions. General publication remains unchanged.
90
+ Newly collected schema-2 payment reviews require checkout compatibility evidence
91
+ for every online-paid flow. Legacy schema-1 completed ready reviews remain accepted
92
+ without that field.
93
+
94
+ Successful checks include a `warnings` array. When an existing paid flow proceeds
95
+ with unverified payment readiness and supported target checkout, it contains
96
+ `{ code: "payment_readiness_unverified", flowId, message }` for that flow. This is
97
+ advisory: it does not mean payments are disconnected, does not require an owner
98
+ decision and does not certify a successful purchase. Other successful reviews
99
+ return an empty array.
90
100
 
91
101
  ## `himi one-app validate-identity` codes
92
102
 
package/guides/index.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "_comment": "AUTO-GENERATED by tools/authoring-kit/bundle.mjs — DO NOT EDIT. Regenerate with: npm run authoring:gen",
3
3
  "schemaStamp": {
4
- "componentCount": 88,
4
+ "componentCount": 89,
5
5
  "schemaSource": "core/ts/src/schema.ts"
6
6
  },
7
7
  "portalUrl": "https://apps.wix.com/_api/himi-serve/docs",
@@ -31,6 +31,38 @@ Source snapshots: Catalyst `617c06d43d2a5608b6876d724553269b1e5346f0`; Himalaya
31
31
 
32
32
  ## Mappings by server group
33
33
 
34
+ ### Member-only visibility during migration
35
+
36
+ The following eleven definitions omit `visitorModeEnabled`, whose source default
37
+ is false. Their authentication visibility is supported through
38
+ `oneAppSection`/`createOneAppSectionService`: hidden for visitors and unresolved
39
+ authentication, visible after confirmed sign-in subject to all other restrictions,
40
+ hidden again after sign-out. This visibility support does not change a row's data/UI
41
+ mapping classification or certify an unimplemented vertical.
42
+
43
+ | Section definition | Visibility migration rule |
44
+ | --- | --- |
45
+ | `food_section` | Signed-in-only; preserve instance settings, content and ordering. |
46
+ | `newBlog_submit_post_section` | Signed-in-only; preserve author permissions, settings and ordering. |
47
+ | `selections` | Signed-in-only; preserve instance settings, content and ordering. |
48
+ | `file_share_section` | Signed-in-only; preserve folder/file access, settings and View All action. |
49
+ | `events_guests_section` | Signed-in-only; preserve event scope, guest privacy and settings. |
50
+ | `events_discussion_section` | Signed-in-only; preserve event scope, discussion settings and actions. |
51
+ | `performance_tracker_section` | Signed-in-only; preserve member performance, settings and tracker CTA. |
52
+ | `achievements_participant_carousel_section` | Signed-in-only; preserve member participation/progress, settings, default limit 5 and participant-programs CTA. |
53
+ | `memberships_packages_section` | Signed-in-only; preserve member plan orders, balances/credits, settings and MyMemberships CTA. |
54
+ | `upcoming_bookings_section` | Signed-in-only; preserve upcoming-only selection, settings, limit and ActivityFeedCards CTA. |
55
+ | `loyalty_status_section` | Signed-in-only; preserve member points, tier/status and display settings. |
56
+
57
+ Use the collected definition when present, including an explicit visitor-enabled
58
+ override; otherwise the migration graph uses these pinned stable IDs. Preserve
59
+ general experiments, visitor experiments and other conditions, with unknown values
60
+ unresolved. Apply the same gate to layouts, detached layouts and Business Profile
61
+ placements of these eleven types, keeping duplicate instances separate. Other
62
+ section types retain their existing visibility/access behavior and receive no new
63
+ authentication gate, including when their definitions are absent. See the current migration guide's
64
+ [visibility recipe and deterministic test contract](https://apps.wix.com/_api/himi-serve/docs/one-app-to-himi-app.md#preserve-section-visibility-across-authentication).
65
+
34
66
  The **Himalaya implementation** cell is blank for every unassigned row. Notes on existing partial building blocks are not fallback selections.
35
67
 
36
68
  ### 1. mobile-app-widgets-section-definitions.json
@@ -164,6 +164,14 @@ The CLI's versioned native-widget inventory supplies these rows automatically.
164
164
  | `newBlog_postlist_vertical_section`, `newBlog_compact_post_list_vertical_section` | Row display options, unlimited paging or a limited count with See All Posts, and layout. Coverage derives these per placement from the authored settings: see "Generate blog post lists from their settings". |
165
165
  | `events_list_section` | Date badge, Share and the appropriate RSVP/ticket action. |
166
166
  | `platform_general_members_section`, `platform_general_members_section_bp` | Effective member strip and directory journey: totals/search, alphabetical sections, Follow, activity/privacy. Distinguish badge chips from actual viewed-member program progress. |
167
+ | `file_share_section` | Signed-in-only file/folder section. Preserve access rules, instance settings and View All (`media.openFileShareListScreen`); a media gallery is not File Share. |
168
+ | `events_guests_section` | Signed-in-only guests for the configured event, preserving the event selector, guest privacy and display settings; an avatar summary is not the full guest list. |
169
+ | `events_discussion_section` | Signed-in-only discussion for the configured event, preserving its selector, settings and actions; do not substitute a group feed or blog comments. |
170
+ | `performance_tracker_section` | Signed-in-only member performance tracker, settings and `wix.bookings.performanceTrackerCTA`; do not substitute a generic steps/session-goal widget. |
171
+ | `achievements_participant_carousel_section` | Signed-in-only participating-programs carousel with actual member progress, source selectors/settings, default limit 5 and `wix-one-app-achievements.ParticipantChallengesScreen` CTA; not the public Programs catalog. |
172
+ | `memberships_packages_section` | Signed-in-only memberships/packages, including member plan orders, package balances/session credits, authored settings and `memberships.screens.MyMemberships` CTA. |
173
+ | `upcoming_bookings_section` | Signed-in-only upcoming member bookings, preserving upcoming-only selection, source limit/settings and `wix.bookings.activities.ActivityFeedCards` CTA; do not include historical bookings. |
174
+ | `loyalty_status_section` | Signed-in-only member points, tier/status and authored display settings; the public rewards catalog does not implement member status. |
167
175
 
168
176
  This initial checklist comes from reported native source-device observations
169
177
  on 2026-11-02 across two migrations, not editor demo records.
@@ -177,6 +185,92 @@ no adaptation waiver, and this checklist must not force the disabled control on.
177
185
  Data/access-dependent controls need the relevant source state; never fabricate
178
186
  participants or derive program completion from a badge title.
179
187
 
188
+ ### Preserve section visibility across authentication
189
+
190
+ The eight member-only rows above are supported by the shared visibility recipe below;
191
+ their data/UI implementation still needs the per-section mapping and live verification.
192
+ The same visibility rule also applies to `food_section`,
193
+ `newBlog_submit_post_section` and `selections`; these three are intentionally not
194
+ added to the native-defaults table.
195
+
196
+ OneApp's section-definition contract defaults omitted `visitorModeEnabled` to
197
+ `false`. The eleven IDs above omit it in the pinned source definitions. The source
198
+ graph records `sectionVisibility[sectionId]` **only for these eleven definition IDs**, deterministically from collected
199
+ `definitions.sections[sectionDefinitionId]`, falling back to those pinned IDs
200
+ only when the definition is absent. A collected explicit `true` takes precedence.
201
+ For these eleven types, malformed definitions or flags/experiment lists remain unresolved; never
202
+ guess from a display name. The raw section instances, settings, permissions and
203
+ placement order remain intact, even when absent from the visitor-enriched view.
204
+
205
+ All other section types keep their existing visibility and access behavior. Do not
206
+ wrap them in this new authentication gate or infer member-only access from missing
207
+ definitions. An absent `sectionVisibility[sectionId]` means this recipe does not
208
+ apply; it does not mean hidden or unresolved. Preserve their existing permission,
209
+ experiment and other source restrictions separately.
210
+ The graph omits `sectionVisibility` entirely when no reviewed placements exist;
211
+ use `graph.sectionVisibility?.[sectionId]` when selecting the recipe.
212
+
213
+ For every placement **of these eleven types** in screen layouts, detached layouts and the Business Profile:
214
+
215
+ - Keep the section hidden while authentication is unresolved and while signed out.
216
+ Show it after successful sign-in in its original position, subject to its other
217
+ permission/OS/paid-plan and general experiment conditions. Hide it after sign-out.
218
+ Cancelled or failed sign-in does not reveal it; restored sessions reveal it only
219
+ after identity is established. Keep content/configuration, not the last member's
220
+ runtime data.
221
+ - Preserve `experiments` for every identity. For visitor-enabled definitions,
222
+ require all `visitorModeExperiments` for visitors; unknown values are unresolved,
223
+ never assumed true. General restrictions continue to apply after sign-in.
224
+ - Use `oneAppSection` and `createOneAppSectionService` from
225
+ `@wix/himalaya/screens` in the screen's worker. Assign a distinct stable service
226
+ and wrapper ID to every placement, including repeated types and profile copies.
227
+ Declare `wix_platform` and `app_info`, and set the screen bundle's
228
+ `minBinaryVersion: "1.9.0"` (`min_binary_version` on the wire), for identity reads and the host's reserved
229
+ `onIdentityChange` hook (iOS/macOS, Android and web). No rebuild or remigration
230
+ is needed on identity changes. Older hosts without this hook need a runtime
231
+ update; a one-time identity read alone is not parity. The helper also checks the
232
+ native binary version and hydration/persistence support (the web host uses
233
+ the advertised `identityChangeVersion` feature support, since its version is a
234
+ placeholder), resets legacy hydrated data
235
+ synchronously and stays hidden without reads on an incompatible runtime.
236
+ - Pass the graph's visibility rule to the service, current experiment values via
237
+ `experiments`, and the conjunction of the other rules via `otherAllowed`.
238
+ Pass `getIdentity: () => auth.getIdentity()` from the screen worker's
239
+ `@himalaya/wix-platform` import; the helper calls it only after runtime compatibility checks.
240
+ Call `load` when non-auth conditions change. Supply the member read through
241
+ `read`, bind its `data`/`loading`/`error` state in the authored content,
242
+ and compose it inside `oneAppSection(content, {id, service})`. Do not start an
243
+ eager member worker or read outside the gate. The helper's empty hidden
244
+ FragmentSlot case does not mount member controls/onAppear actions. It clears
245
+ runtime data on identity changes and drops late reads from the previous identity.
246
+
247
+ Coverage derives an `access-state` obligation only for placements with a visibility rule in that scoped map.
248
+ Do not mark it supported on a manual screenshot or AI evaluation alone: run
249
+ deterministic tests asserting migration output and observable rendered sections.
250
+ Parameterize all eleven IDs; assert unchanged content/settings/order and stable
251
+ repeat output; cover visitor → successful sign-in → sign-out, unresolved/restored
252
+ identity, cancelled/failed sign-in, duplicate instances, layouts plus Business
253
+ Profile, mixed public/private screens, omitted/false/true flags, experiments and
254
+ other restrictions. Assert zero hidden member reads and reject late results after
255
+ sign-out or account changes. Keep the test command/results and rendered evidence
256
+ with the exact release's coverage records.
257
+ Verify non-target section types, including those with absent definitions, receive
258
+ no new gate or authentication obligation and retain their content and placement.
259
+
260
+ For a signed-in-only placement, the passed `access-state` record must include
261
+ `sectionVisibility: {kind: "automated", command, hiddenMemberReads: 0, states,
262
+ testReport: {path, sha256}}`. The report path is relative to the content root and
263
+ its SHA-256 must match the actual test report. `states` must assert
264
+ `unresolved`, `visitor`, `signedOut`, `cancelled`, `failed` and
265
+ `otherRestricted` as `"hidden"`, and `signedIn`/`restored` as `"visible"`.
266
+ The check's existing requirement ID, target and release hash still apply.
267
+ Coverage verification rejects a generic/manual pass, missing assertions or changed
268
+ test reports. These records report tests actually run, never invented evidence.
269
+
270
+ Source evidence: [section definitions](https://github.com/wix-private/catalyst-server/tree/617c06d43d2a5608b6876d724553269b1e5346f0/one-app-sections/one-app-sections-definitions/src/main/resources/sections),
271
+ [visitor criteria](https://github.com/wix-private/mobile-apps-editor/blob/53cac5fabd41f761632d3574b6a74624c2816427/packages/mobile-apps-editor-middleware/src/domain/EnrichedStructure/DisplayCriteria.ts#L161)
272
+ and [layout/profile filtering](https://github.com/wix-private/mobile-apps-editor/blob/53cac5fabd41f761632d3574b6a74624c2816427/packages/mobile-apps-editor-middleware/src/domain/EnrichedStructure/EnrichedViewer.ts#L293).
273
+
180
274
  ### Generate blog post lists from their settings
181
275
 
182
276
  A migrated blog list is app-authored, not a template screen, so nothing makes it match the source
@@ -845,13 +939,39 @@ The readiness `metaSiteId` must match this migration's collected site. `state` i
845
939
  when it was checked. Use verified site-bound owner payment settings or a proven
846
940
  read-only contract when available. A denied or unavailable read remains
847
941
  `unverified`, with the actual access gap recorded. Never infer provider eligibility
848
- from the site's country. Ready evidence permits `decision: { action: "proceed" }`.
849
- For missing or unverified setup, tell the owner what is known and ask them to:
850
-
851
- - `connect-provider`: complete setup in their site dashboard, then recheck before
852
- generating that paid UI. Migration does not connect the provider itself.
942
+ from the site's country. The target must stay bound to the same site; preserve its
943
+ existing payment configuration instead of asking the owner to connect it again.
944
+
945
+ Review the source purchase action against the target's checkout path, including
946
+ the vertical, payment method and any native in-app purchase requirements. Record
947
+ `checkout: { state, evidence }`, where `state` is `supported`, `unsupported` or
948
+ `unverified` and `evidence` names the source flow and target implementation. Do not
949
+ mark an unsupported target ready just because the merchant has a provider.
950
+ Newly collected reviews use `schemaVersion: 2` and require `checkout` for every
951
+ online-paid flow, including those with verified merchant readiness. Legacy
952
+ schema-1 ready reviews without `checkout` remain accepted for compatibility.
953
+ Do not downgrade a newly collected review to bypass its checkout check.
954
+
955
+ If payment readiness is `ready`, use `decision: { action: "proceed" }` unless the
956
+ checkout review identifies a gap. If readiness is `unverified` and checkout is
957
+ `supported`, preserve the existing flow by default: omit `decision` or record
958
+ `{ action: "proceed" }`. No owner decision or pre-checkout warning is required
959
+ solely because the payment settings read is unavailable. Keep the uncertainty in
960
+ the review and migration report; the checker returns a per-flow
961
+ `payment_readiness_unverified` warning without refusing generation. Do not tell
962
+ the owner or customers that payments are disconnected based on an unavailable read.
963
+
964
+ For confirmed missing setup or a target checkout gap, explain the specific issue
965
+ and ask how to proceed. Investigate unverified target compatibility before asking
966
+ the owner to choose an adaptation. The available decisions are:
967
+
968
+ - `connect-provider`: for confirmed missing payment setup, complete setup in their
969
+ site dashboard, then recheck before generating that paid UI. Migration does not
970
+ connect the provider itself. Connecting a provider cannot resolve an unsupported
971
+ target checkout.
853
972
  - `retain`: keep the flow with a localized explanation **before checkout** that
854
- payments are unavailable or unverified, plus a real contact or back action.
973
+ describes the confirmed issue or unresolved compatibility, plus a real contact
974
+ or back action. Do not claim missing payment setup when its status is unknown.
855
975
  Record that copy in `decision.explanation` and the actual planned recovery in
856
976
  `decision.recovery`: `{ action: "back" }` or `{ action: "contact", target:
857
977
  "<real contact route>" }`. Implement the copy and action in the target; the
@@ -860,17 +980,21 @@ For missing or unverified setup, tell the owner what is known and ask them to:
860
980
  and the remaining free/offline content.
861
981
 
862
982
  Record their instruction in `decision.instruction`; cite an existing explicit
863
- instruction instead of asking again. Run `himi one-app validate-payments
983
+ instruction instead of asking again; an existing retain/hide/connect-provider
984
+ instruction still applies when the payment read is unavailable. Run `himi one-app validate-payments
864
985
  --evidence-dir .himi/one-app --json` before scaffolding. It reads this editable
865
986
  review and the hash-verified collected source, checks decisions and site binding,
866
987
  and creates nothing. A passing check validates the recorded plan, not the truth
867
988
  of merchant readiness. The review's original manifest hash describes the initial
868
989
  template; edit the review without rewriting collected evidence or manifest hashes.
869
990
  Keep the decision, resulting target controls and controlled runtime evidence in
870
- the reconstruction plan and migration report. For retained flows, handle the exact
991
+ the reconstruction plan and migration report. For all paid flows, handle the exact
871
992
  structured `SITE_NOT_ACCEPTING_PAYMENTS` failure with clear recovery; unrelated
872
993
  HTTP 428 failures must retain their own meaning. Test paid/free/offline and
873
- missing/ready/unverified cases without real transactions. General app validation
994
+ missing/ready/unverified cases and target checkout compatibility without real
995
+ transactions. If a purchase worked in the original app but fails after migration,
996
+ investigate the target checkout and site binding before attributing it to the
997
+ owner's payment setup. General app validation
874
998
  and publishing do not gain a new payment gate.
875
999
 
876
1000
  Write `SPEC.md` and `MOBILE-UX.md` in the workspace. Use the current
@@ -848,7 +848,7 @@ a tapped `himi.open` would — including the `args` arriving as `himalaya.input`
848
848
 
849
849
  | `_nav` | What the host does |
850
850
  |---|---|
851
- | `{ screenId, args?, presentation? }` | Opens the screen. `presentation` is `push` (the default), `replace`, `sheet` or `full_screen` — the same verbs a descriptor action uses. |
851
+ | `{ screenId, args?, presentation? }` | Opens the screen. `presentation` is `push` (the default), `replace`, `sheet` or `full_screen` — the same verbs a descriptor action uses. A `sheet` with `sheetStyle: "page"` in its args (or a descriptor action's params) is a modal page, such as a sign-in form: iOS shows its sheet, while Android, web and React Native, whose sheet is a bottom drawer, open it full screen with a Close button. |
852
852
  | `{ presentation: "back" }` or `{ presentation: "dismiss" }` | `back` pops the current screen; `dismiss` closes the open sheet or full-screen cover. No target. |
853
853
  | `{ tab: "<tabId>", reset?: true, screenId?, args? }` | Switches to that tab — a `tabBar` item, or a sidebar-rail item on a wide layout. With `reset: true` it then pops that tab to its root. With `screenId` it then pushes that screen, with `args`, onto **that** tab's stack. |
854
854
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/himalaya-cli",
3
- "version": "0.1616.0",
3
+ "version": "0.1618.0",
4
4
  "type": "module",
5
5
  "description": "himi — the Himalaya authoring CLI. Build a Tier-5 content package on your own machine, push it to the production serve as a draft, preview it on web + Himi Player, and read worker logs back — the remote dev loop. Wraps @himalaya/serve-cli for transport.",
6
6
  "keywords": [
@@ -72,5 +72,5 @@
72
72
  "artifactId": "himalaya-cli"
73
73
  }
74
74
  },
75
- "falconPackageHash": "2920a0f10129d7c77da46417f285a54ae1c40b05e0cb30b33fd6b0e8"
75
+ "falconPackageHash": "53661afff21585080db36c8653b597e5ec6bbe96697d7157bf90ee05"
76
76
  }
@@ -2841,7 +2841,8 @@ const SCREENS = runtimeSetting({
2841
2841
  "params": {
2842
2842
  "screenId": "himi_sign_in",
2843
2843
  "mode": "signin",
2844
- "modal": "1"
2844
+ "modal": "1",
2845
+ "sheetStyle": "page"
2845
2846
  },
2846
2847
  "presentation": "sheet"
2847
2848
  }
@@ -2862,7 +2863,8 @@ const SCREENS = runtimeSetting({
2862
2863
  "params": {
2863
2864
  "screenId": "himi_sign_in",
2864
2865
  "mode": "register",
2865
- "modal": "1"
2866
+ "modal": "1",
2867
+ "sheetStyle": "page"
2866
2868
  },
2867
2869
  "presentation": "sheet"
2868
2870
  }
@@ -4229,6 +4231,7 @@ const SCREENS = runtimeSetting({
4229
4231
  "restorePurchases": "1",
4230
4232
  "signInScreen": "himi_sign_in",
4231
4233
  "signInPresentation": "sheet",
4234
+ "signInSheetStyle": "page",
4232
4235
  "signInReturnTab": "profile",
4233
4236
  "pollIdentity": "1",
4234
4237
  "cartCount": "1",
@@ -4506,7 +4509,8 @@ const SCREENS = runtimeSetting({
4506
4509
  "screenId": "himi_sign_in",
4507
4510
  "mode": "signin",
4508
4511
  "returnScreenId": "himi_account_settings",
4509
- "modal": "1"
4512
+ "modal": "1",
4513
+ "sheetStyle": "page"
4510
4514
  },
4511
4515
  "presentation": "sheet"
4512
4516
  }
@@ -7526,7 +7530,8 @@ const SCREENS = runtimeSetting({
7526
7530
  "params": {
7527
7531
  "screenId": "himi_sign_in",
7528
7532
  "returnScreenId": "himi_notif_settings",
7529
- "modal": "1"
7533
+ "modal": "1",
7534
+ "sheetStyle": "page"
7530
7535
  },
7531
7536
  "presentation": "sheet"
7532
7537
  }
@@ -7921,7 +7926,8 @@ const SCREENS = runtimeSetting({
7921
7926
  "mode": "signin",
7922
7927
  "intent": "profile",
7923
7928
  "returnScreenId": "himi_view_profile",
7924
- "modal": "1"
7929
+ "modal": "1",
7930
+ "sheetStyle": "page"
7925
7931
  },
7926
7932
  "presentation": "sheet"
7927
7933
  }
@@ -17421,7 +17427,8 @@ const SCREENS = runtimeSetting({
17421
17427
  "mode": "signin",
17422
17428
  "intent": "orders",
17423
17429
  "returnScreenId": "himi_orders",
17424
- "modal": "1"
17430
+ "modal": "1",
17431
+ "sheetStyle": "page"
17425
17432
  },
17426
17433
  "presentation": "sheet"
17427
17434
  }
@@ -18158,7 +18165,8 @@ const SCREENS = runtimeSetting({
18158
18165
  "mode": "signin",
18159
18166
  "intent": "addresses",
18160
18167
  "returnScreenId": "himi_addresses",
18161
- "modal": "1"
18168
+ "modal": "1",
18169
+ "sheetStyle": "page"
18162
18170
  },
18163
18171
  "presentation": "sheet"
18164
18172
  }
@@ -19217,7 +19225,8 @@ const SCREENS = runtimeSetting({
19217
19225
  "mode": "signin",
19218
19226
  "intent": "addresses",
19219
19227
  "returnScreenId": "himi_address",
19220
- "modal": "1"
19228
+ "modal": "1",
19229
+ "sheetStyle": "page"
19221
19230
  },
19222
19231
  "presentation": "sheet"
19223
19232
  }
@@ -19890,7 +19899,8 @@ const SCREENS = runtimeSetting({
19890
19899
  "mode": "signin",
19891
19900
  "intent": "wallet",
19892
19901
  "returnScreenId": "himi_wallet",
19893
- "modal": "1"
19902
+ "modal": "1",
19903
+ "sheetStyle": "page"
19894
19904
  },
19895
19905
  "presentation": "sheet"
19896
19906
  }
@@ -20402,7 +20412,8 @@ const SCREENS = runtimeSetting({
20402
20412
  "actionId": "tier5.himiPlaceSummary.load",
20403
20413
  "params": {
20404
20414
  "verticals": "[\"store\",\"bookings\",\"plans\",\"blog\"]",
20405
- "signInPresentation": "sheet"
20415
+ "signInPresentation": "sheet",
20416
+ "signInSheetStyle": "page"
20406
20417
  }
20407
20418
  }
20408
20419
  }
@@ -23234,7 +23245,8 @@ const SCREENS = runtimeSetting({
23234
23245
  "screenId": "himi_sign_in",
23235
23246
  "mode": "signin",
23236
23247
  "returnScreenId": "himi_bookings",
23237
- "modal": "1"
23248
+ "modal": "1",
23249
+ "sheetStyle": "page"
23238
23250
  },
23239
23251
  "presentation": "sheet"
23240
23252
  },
@@ -26344,7 +26356,8 @@ const SCREENS = runtimeSetting({
26344
26356
  "actionId": "tier5.himiBrandedAgenda.load",
26345
26357
  "params": {
26346
26358
  "firstWeekday": "0",
26347
- "signInPresentation": "sheet"
26359
+ "signInPresentation": "sheet",
26360
+ "signInSheetStyle": "page"
26348
26361
  }
26349
26362
  }
26350
26363
  }
@@ -29487,7 +29500,8 @@ const SCREENS = runtimeSetting({
29487
29500
  "params": {
29488
29501
  "screenId": "himi_sign_in",
29489
29502
  "mode": "signin",
29490
- "modal": "1"
29503
+ "modal": "1",
29504
+ "sheetStyle": "page"
29491
29505
  },
29492
29506
  "presentation": "sheet"
29493
29507
  }
@@ -29875,7 +29889,8 @@ const SCREENS = runtimeSetting({
29875
29889
  "mode": "signin",
29876
29890
  "intent": "post",
29877
29891
  "returnScreenId": "himi_create_post",
29878
- "modal": "1"
29892
+ "modal": "1",
29893
+ "sheetStyle": "page"
29879
29894
  },
29880
29895
  "presentation": "sheet"
29881
29896
  }
@@ -34208,7 +34223,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
34208
34223
  "screenId": "himi_sign_in",
34209
34224
  "returnScreenId": "himi_order",
34210
34225
  "returnId": "$service:himiBrandedOrder.id",
34211
- "modal": "1"
34226
+ "modal": "1",
34227
+ "sheetStyle": "page"
34212
34228
  },
34213
34229
  "presentation": "sheet"
34214
34230
  }
@@ -38373,7 +38389,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
38373
38389
  "actionId": "tier5.himiBookingService.load",
38374
38390
  "params": {
38375
38391
  "signInScreenId": "himi_sign_in",
38376
- "signInPresentation": "sheet"
38392
+ "signInPresentation": "sheet",
38393
+ "signInSheetStyle": "page"
38377
38394
  }
38378
38395
  }
38379
38396
  }
@@ -41601,7 +41618,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
41601
41618
  "screenId": "himi_sign_in",
41602
41619
  "mode": "signin",
41603
41620
  "intent": "book",
41604
- "modal": "1"
41621
+ "modal": "1",
41622
+ "sheetStyle": "page"
41605
41623
  },
41606
41624
  "presentation": "sheet"
41607
41625
  }
@@ -41854,7 +41872,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
41854
41872
  "params": {
41855
41873
  "screenId": "himi_sign_in",
41856
41874
  "mode": "signin",
41857
- "modal": "1"
41875
+ "modal": "1",
41876
+ "sheetStyle": "page"
41858
41877
  },
41859
41878
  "presentation": "sheet"
41860
41879
  }
@@ -0,0 +1,18 @@
1
+ // A sign-in sheet can be a form page rather than a drawer. `sheetStyle: "page"` keeps the iOS sheet
2
+ // and opens a full-screen modal on Android and web, whose sheet is a bottom drawer. A host older
3
+ // than the param ignores it and draws its own sheet.
4
+ //
5
+ // Opt-in per app: the app passes `signInSheetStyle: "page"` beside `signInPresentation`. These
6
+ // workers are shared (Salon & Spa runs them too), and an app that opens its other sign-ins as a
7
+ // plain sheet must not get a page from some of them and a drawer from the rest.
8
+
9
+ /** The app's `signInSheetStyle` param, read beside `signInPresentation`: "page", else "". */
10
+ export function signInPageStyle(value: unknown): "page" | "" {
11
+ return value === "page" ? "page" : "";
12
+ }
13
+
14
+ /** The nav args a sign-in opened with `presentation` adds: `sheetStyle` on a sheet the app asked
15
+ * to open as a page, else none. */
16
+ export function signInSheetStyle(presentation: string | undefined, style: "page" | ""): { sheetStyle?: "page" } {
17
+ return presentation === "sheet" && style === "page" ? { sheetStyle: "page" } : {};
18
+ }