@wix/himalaya-cli 0.1525.0 → 0.1527.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/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/builder.d.ts +14 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/state/src/connectivity.d.ts +5 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/state/src/index.d.ts +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/schema.d.ts +22 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/worker-subtree-safe-types.generated.d.ts +4 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/core.mjs +7 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/sdui.mjs +13 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/state.mjs +14 -0
- package/dist/cli.mjs +157 -40
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/designing-himi-screens.md +43 -18
- package/guides/himi-test.md +3 -3
- package/guides/recipe-dynamic-list.md +7 -7
- package/guides/recipe-four-state.md +47 -41
- package/guides/recipe-search.md +1 -1
- package/package.json +2 -2
- package/templates/beauty-salon/dev/index.ts +1943 -646
- package/templates/beauty-salon/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/beauty-salon/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/beauty-salon/tier5-src/himi-booking-bookings/index.ts +1 -0
- package/templates/beauty-salon/tier5-src/himi-booking-time/index.ts +803 -284
- package/templates/beauty-salon/tier5-src/himi-branded-lite-address/index.ts +3 -1
- package/templates/beauty-salon/tier5-src/himi-branded-lite-addresses/index.ts +3 -1
- package/templates/beauty-salon/tier5-src/himi-branded-lite-agenda/index.ts +9 -1
- package/templates/beauty-salon/tier5-src/himi-branded-lite-cart/index.ts +3 -0
- package/templates/beauty-salon/tier5-src/himi-branded-lite-order/index.ts +3 -1
- package/templates/beauty-salon/tier5-src/himi-branded-lite-place-summary/index.ts +12 -1
- package/templates/beauty-salon/tier5-src/himi-branded-lite-plans/index.ts +13 -1
- package/templates/beauty-salon/tier5-src/himi-branded-lite-wallet/index.ts +3 -1
- package/templates/beauty-salon/tier5-src/himi-store-account/index.ts +69 -10
- package/templates/beauty-salon/tier5-src/himi-store-product/index.ts +10 -4
- package/templates/beauty-salon-owner/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/beauty-salon-owner/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/branded-lite/dev/index.ts +2404 -1020
- package/templates/branded-lite/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/branded-lite/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/branded-lite/tier5-src/business-chat/index.ts +4 -0
- package/templates/branded-lite/tier5-src/himi-booking-bookings/index.ts +1 -0
- package/templates/branded-lite/tier5-src/himi-booking-time/index.ts +803 -284
- package/templates/branded-lite/tier5-src/himi-branded-lite-address/index.ts +3 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-addresses/index.ts +3 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-agenda/index.ts +9 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-cart/index.ts +3 -0
- package/templates/branded-lite/tier5-src/himi-branded-lite-feed/index.ts +3 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-group/index.ts +3 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-notifications/index.ts +6 -4
- package/templates/branded-lite/tier5-src/himi-branded-lite-notifsettings/index.ts +6 -4
- package/templates/branded-lite/tier5-src/himi-branded-lite-order/index.ts +3 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-place-summary/index.ts +12 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-plans/index.ts +13 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-program/index.ts +3 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-reservations/index.ts +6 -4
- package/templates/branded-lite/tier5-src/himi-branded-lite-reserve/index.ts +3 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-wallet/index.ts +3 -1
- package/templates/branded-lite/tier5-src/himi-events-detail/index.ts +8 -1
- package/templates/branded-lite/tier5-src/himi-events-rsvp/index.ts +7 -4
- package/templates/branded-lite/tier5-src/himi-store-account/index.ts +69 -10
- package/templates/branded-lite/tier5-src/himi-store-product/index.ts +10 -4
- package/templates/community-club/dev/index.ts +40 -21
- package/templates/community-club/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/community-club/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/community-club/tier5-src/himi-branded-lite-feed/index.ts +3 -1
- package/templates/community-club/tier5-src/himi-branded-lite-group/index.ts +3 -1
- package/templates/community-club/tier5-src/himi-events-detail/index.ts +8 -1
- package/templates/community-club/tier5-src/himi-events-rsvp/index.ts +7 -4
- package/templates/community-club/tier5-src/himi-store-account/index.ts +69 -10
- package/templates/community-club-owner/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/community-club-owner/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/events-meetups/dev/index.ts +36 -19
- package/templates/events-meetups/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/events-meetups/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/events-meetups/tier5-src/himi-branded-lite-feed/index.ts +3 -1
- package/templates/events-meetups/tier5-src/himi-branded-lite-group/index.ts +3 -1
- package/templates/events-meetups/tier5-src/himi-events-detail/index.ts +8 -1
- package/templates/events-meetups/tier5-src/himi-events-rsvp/index.ts +7 -4
- package/templates/events-meetups/tier5-src/himi-store-account/index.ts +69 -10
- package/templates/events-meetups-owner/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/events-meetups-owner/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/gym-fitness/dev/index.ts +1944 -645
- package/templates/gym-fitness/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/gym-fitness/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/gym-fitness/tier5-src/himi-booking-bookings/index.ts +1 -0
- package/templates/gym-fitness/tier5-src/himi-booking-time/index.ts +803 -284
- package/templates/gym-fitness/tier5-src/himi-branded-lite-address/index.ts +3 -1
- package/templates/gym-fitness/tier5-src/himi-branded-lite-addresses/index.ts +3 -1
- package/templates/gym-fitness/tier5-src/himi-branded-lite-agenda/index.ts +9 -1
- package/templates/gym-fitness/tier5-src/himi-branded-lite-cart/index.ts +3 -0
- package/templates/gym-fitness/tier5-src/himi-branded-lite-order/index.ts +3 -1
- package/templates/gym-fitness/tier5-src/himi-branded-lite-place-summary/index.ts +12 -1
- package/templates/gym-fitness/tier5-src/himi-branded-lite-plans/index.ts +13 -1
- package/templates/gym-fitness/tier5-src/himi-branded-lite-wallet/index.ts +3 -1
- package/templates/gym-fitness/tier5-src/himi-events-detail/index.ts +8 -1
- package/templates/gym-fitness/tier5-src/himi-events-rsvp/index.ts +7 -4
- package/templates/gym-fitness/tier5-src/himi-store-account/index.ts +69 -10
- package/templates/gym-fitness/tier5-src/himi-store-product/index.ts +10 -4
- package/templates/gym-fitness-owner/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/gym-fitness-owner/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/nonprofit-cause/dev/index.ts +47 -29
- package/templates/nonprofit-cause/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/nonprofit-cause/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-feed/index.ts +3 -1
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-group/index.ts +3 -1
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-place-summary/index.ts +12 -1
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-plans/index.ts +13 -1
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-wallet/index.ts +3 -1
- package/templates/nonprofit-cause/tier5-src/himi-events-detail/index.ts +8 -1
- package/templates/nonprofit-cause/tier5-src/himi-events-rsvp/index.ts +7 -4
- package/templates/nonprofit-cause/tier5-src/himi-store-account/index.ts +69 -10
- package/templates/nonprofit-cause-owner/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/nonprofit-cause-owner/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/owner-lite/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/owner-lite/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/podcast-creator/dev/index.ts +47 -29
- package/templates/podcast-creator/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/podcast-creator/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/podcast-creator/tier5-src/himi-branded-lite-feed/index.ts +3 -1
- package/templates/podcast-creator/tier5-src/himi-branded-lite-place-summary/index.ts +12 -1
- package/templates/podcast-creator/tier5-src/himi-branded-lite-plans/index.ts +13 -1
- package/templates/podcast-creator/tier5-src/himi-branded-lite-wallet/index.ts +3 -1
- package/templates/podcast-creator/tier5-src/himi-events-detail/index.ts +8 -1
- package/templates/podcast-creator/tier5-src/himi-events-rsvp/index.ts +7 -4
- package/templates/podcast-creator/tier5-src/himi-store-account/index.ts +69 -10
- package/templates/podcast-creator-owner/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/podcast-creator-owner/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/portfolio-creative/dev/index.ts +52 -27
- package/templates/portfolio-creative/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/portfolio-creative/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-address/index.ts +3 -1
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-addresses/index.ts +3 -1
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-cart/index.ts +3 -0
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-order/index.ts +3 -1
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-wallet/index.ts +3 -1
- package/templates/portfolio-creative/tier5-src/himi-events-detail/index.ts +8 -1
- package/templates/portfolio-creative/tier5-src/himi-events-rsvp/index.ts +7 -4
- package/templates/portfolio-creative/tier5-src/himi-store-account/index.ts +69 -10
- package/templates/portfolio-creative/tier5-src/himi-store-product/index.ts +10 -4
- package/templates/portfolio-creative-owner/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/portfolio-creative-owner/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/restaurant/dev/index.ts +48 -25
- package/templates/restaurant/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/restaurant/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/restaurant/tier5-src/himi-branded-lite-address/index.ts +3 -1
- package/templates/restaurant/tier5-src/himi-branded-lite-addresses/index.ts +3 -1
- package/templates/restaurant/tier5-src/himi-branded-lite-reserve/index.ts +3 -1
- package/templates/restaurant/tier5-src/himi-branded-lite-wallet/index.ts +3 -1
- package/templates/restaurant/tier5-src/himi-events-detail/index.ts +8 -1
- package/templates/restaurant/tier5-src/himi-events-rsvp/index.ts +7 -4
- package/templates/restaurant/tier5-src/himi-store-account/index.ts +69 -10
- package/templates/restaurant-owner/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/restaurant-owner/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/retail-store/dev/index.ts +44 -23
- package/templates/retail-store/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/retail-store/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/retail-store/tier5-src/himi-branded-lite-address/index.ts +3 -1
- package/templates/retail-store/tier5-src/himi-branded-lite-addresses/index.ts +3 -1
- package/templates/retail-store/tier5-src/himi-branded-lite-cart/index.ts +3 -0
- package/templates/retail-store/tier5-src/himi-branded-lite-order/index.ts +3 -1
- package/templates/retail-store/tier5-src/himi-branded-lite-wallet/index.ts +3 -1
- package/templates/retail-store/tier5-src/himi-store-account/index.ts +69 -10
- package/templates/retail-store/tier5-src/himi-store-product/index.ts +10 -4
- package/templates/retail-store-owner/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/retail-store-owner/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/yoga-studio/dev/index.ts +2102 -811
- package/templates/yoga-studio/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/yoga-studio/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/yoga-studio/tier5-src/himi-booking-bookings/index.ts +1 -0
- package/templates/yoga-studio/tier5-src/himi-booking-time/index.ts +803 -284
- package/templates/yoga-studio/tier5-src/himi-branded-lite-agenda/index.ts +9 -1
- package/templates/yoga-studio/tier5-src/himi-branded-lite-place-summary/index.ts +12 -1
- package/templates/yoga-studio/tier5-src/himi-branded-lite-plans/index.ts +13 -1
- package/templates/yoga-studio/tier5-src/himi-branded-lite-program/index.ts +3 -1
- package/templates/yoga-studio/tier5-src/himi-branded-lite-wallet/index.ts +3 -1
- package/templates/yoga-studio/tier5-src/himi-events-detail/index.ts +8 -1
- package/templates/yoga-studio/tier5-src/himi-events-rsvp/index.ts +7 -4
- package/templates/yoga-studio/tier5-src/himi-store-account/index.ts +69 -10
- package/templates/yoga-studio-owner/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/yoga-studio-owner/tier5-src/_shared/online-actions.ts +76 -0
|
Binary file
|
|
@@ -257,7 +257,7 @@ scroll. *Reach for `SegmentedControl` for 2–4 in-content modes; `Tabs`/tab-bar
|
|
|
257
257
|
> in the *outer* column, between the pager and the bottom CTA). Its built-in indicator is faint; pair an
|
|
258
258
|
> explicit `PageControl` if the dots need to read.
|
|
259
259
|
|
|
260
|
-
**Feedback & overlays** — `Banner` for a persistent inline message (with a retry action when a refresh fails over content you kept; a screen with nothing to show uses an
|
|
260
|
+
**Feedback & overlays** — `Banner` for a persistent inline message (with a retry action when a refresh fails over content you kept; a screen with nothing to show uses an `ErrorState`, see §5);
|
|
261
261
|
`Snackbar` for a transient confirmation; `AlertDialog` for a blocking decision; `BottomSheet` for
|
|
262
262
|
contextual actions/detail; `Tooltip`/`Popover` for a small anchored hint. *Reach for `Snackbar`, not
|
|
263
263
|
`AlertDialog`, to confirm a completed action — don't block on success.* The `Snackbar` COMPONENT draws
|
|
@@ -345,7 +345,7 @@ to drive them:
|
|
|
345
345
|
|---|---|---|
|
|
346
346
|
| **Loading** | `Skeleton` (shape of the eventual content) or `StatefulSection` / `ActivityIndicator` | Required on every screen that loads data asynchronously, and re-checked on every redesign. Prefer a content-shaped `Skeleton` over a bare spinner — it previews the layout. The descriptor renders against the state-skeleton, then repaints as worker state lands. See [Loading states](#loading-states-part-of-the-design) below. |
|
|
347
347
|
| **Empty** | `EmptyState` (`title`, optional `icon` / `subtitle`) **plus a directive action** (`action` + `actionLabel`) | An empty screen is an invitation to act, not a dead end. Give it the next step, for example `"actionLabel": "Add your first item"`. Use `EmptyState` for **every** empty state, so all empty states in the app have the same layout and style. See [Empty states](#empty-states-one-component-one-layout) below. |
|
|
348
|
-
| **Error** | Classified first. Nothing on screen: an `
|
|
348
|
+
| **Error** | Classified first. Nothing on screen: an `ErrorState` per class (user-facing `title` + `body`, a `cta` only for a real recovery). Rows on screen: keep them, add a `Banner` with retry. Field and action errors stay local. | Say what happened in the user's words and offer recovery only when there is one; never a blank screen or a raw error string. See [Error states](#error-states-classify-then-present) below. |
|
|
349
349
|
| **Loaded** | the real content | The one everyone remembers to build. |
|
|
350
350
|
|
|
351
351
|
Bind visibility to worker state with `hidden_path` (`$service:…`/`$item.` data-bound collapse in
|
|
@@ -433,13 +433,14 @@ its own recovery.
|
|
|
433
433
|
| **Field validation** | A value the user typed is not valid. | Beside the field, in its own error slot (see **Inputs & forms** in §3). | "Enter a valid email." | The user corrects the field. No retry. |
|
|
434
434
|
| **Action failure** | A write or a command failed (save, delete, book). | Near the action or the affected content — a line by the button, or a `danger` snackbar (`ui.snackbar({ message, tone: "danger" })`). | "Couldn't save your changes. Try again." | Keep what the user entered; the action itself is the retry. |
|
|
435
435
|
|
|
436
|
-
- **A screen- or section-level error is an `
|
|
437
|
-
`
|
|
438
|
-
recovery — retry, reload, the app's auth flow, or
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
436
|
+
- **A screen- or section-level error is an `ErrorState`.** Set its `variant`, and `title` and
|
|
437
|
+
`body` when the default copy does not fit. Add a `cta` (with `ctaLabel` when the default label
|
|
438
|
+
does not fit) only when the user has a useful recovery — retry, reload, the app's auth flow, or
|
|
439
|
+
the site's join flow when available. Every error then has the same layout and style. Do not
|
|
440
|
+
build one by hand from `Icon`, `Text` and `Button` nodes.
|
|
441
|
+
- **One node per class.** iOS and Android do not resolve a `$service:` binding in `ErrorState`
|
|
442
|
+
`title` or `body`, so the worker cannot swap the text. Give each class the screen can hit its
|
|
443
|
+
own `ErrorState` with literal copy or `$t:` keys, and gate each one with `hiddenPath` bound to a
|
|
443
444
|
worker flag. The worker classifies the failure once and sets the flags — see
|
|
444
445
|
`himi docs recipe-four-state` for the whole pattern.
|
|
445
446
|
- **User-facing language, never the raw error.** Say what happened and what the user can do. Never
|
|
@@ -461,17 +462,41 @@ its own recovery.
|
|
|
461
462
|
|
|
462
463
|
```jsonc
|
|
463
464
|
{ "id": "orders.error.offline",
|
|
464
|
-
"body": { "package": "himalaya", "type": "
|
|
465
|
-
"props": { "
|
|
466
|
-
"
|
|
467
|
-
"action": { "actionId": "tier5.orders.retry" },
|
|
468
|
-
"actionLabel": "Try again" } },
|
|
465
|
+
"body": { "package": "himalaya", "type": "ErrorState",
|
|
466
|
+
"props": { "variant": "offline",
|
|
467
|
+
"cta": { "actionId": "tier5.orders.retry" } } },
|
|
469
468
|
"modifiers": { "hiddenPath": "$service:orders.hideOfflineError" } }
|
|
470
469
|
```
|
|
471
470
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
471
|
+
**`ErrorState` draws the same layout on iOS, Android, macOS, web and React Native:** a centred
|
|
472
|
+
glyph, title, body and one primary button, with no icon tile and no card.
|
|
473
|
+
|
|
474
|
+
| `variant` | Glyph | Title | Body | Button |
|
|
475
|
+
|---|---|---|---|---|
|
|
476
|
+
| `server` (default) | error | Unable to load this content | There was a technical issue on our end. Please wait and try again later. | Try again |
|
|
477
|
+
| `offline` | wifi | Reconnect to the Internet | Connect to the internet, then try again. | Try again |
|
|
478
|
+
| `permission` | error | You need permission to view this screen | none | Contact customer care |
|
|
479
|
+
| `signIn` | person | Sign in to view this content | none | Sign in |
|
|
480
|
+
|
|
481
|
+
- `title`, `body` and `ctaLabel` replace the copy of the variant, for example
|
|
482
|
+
`"title": "Unable to load orders"`. Site membership has no variant: use `permission` with your
|
|
483
|
+
own `title` and `body`. Write the copy as literal text or `$t:` keys: iOS and Android show a
|
|
484
|
+
`$service:` binding there as raw text, so `himi validate` refuses it.
|
|
485
|
+
- `variantPath` is a `$service:` binding that selects the variant and wins over `variant`. An
|
|
486
|
+
unknown value (`membership`, `""`) keeps `variant`. It switches only the default copy and glyph:
|
|
487
|
+
`cta`, `title`, `body` and `ctaLabel` apply to every variant. So one node bound to the worker's
|
|
488
|
+
`errorKind` covers the kinds that share a button — offline and server, both **Try again** — and
|
|
489
|
+
sign-in (its own action) and permission (no button) each keep a node of their own.
|
|
490
|
+
- The button draws only when you set `cta`. Leave it out for a permission error.
|
|
491
|
+
- `placement` is `screen` (default, about 96px from the top) or `section` (about 24px).
|
|
492
|
+
|
|
493
|
+
```jsonc
|
|
494
|
+
{ "id": "orders.error",
|
|
495
|
+
"body": { "package": "himalaya", "type": "ErrorState",
|
|
496
|
+
"props": { "variantPath": "$service:orders.errorKind",
|
|
497
|
+
"cta": { "actionId": "tier5.orders.retry" } } },
|
|
498
|
+
"modifiers": { "hiddenPath": "$service:orders.hideRetryableError" } } // offline or server
|
|
499
|
+
```
|
|
475
500
|
|
|
476
501
|
**Loading & empty states are first-class — use the `Skeleton` and `EmptyState` component types.**
|
|
477
502
|
|
|
@@ -546,7 +571,7 @@ Run this punch list on the screen (it's also a good reviewer checklist):
|
|
|
546
571
|
|
|
547
572
|
- [ ] **One** primary action, on the one `accentPrimary` surface?
|
|
548
573
|
- [ ] All four states designed — loading / empty / error / loaded (empty has a directive action; error has a recovery action when one exists)?
|
|
549
|
-
- [ ] Errors classified (offline / server / sign-in / site membership / permission), each an
|
|
574
|
+
- [ ] Errors classified (offline / server / sign-in / site membership / permission), each an `ErrorState` with user-facing copy — no raw error text? Empty results shown as empty, not as an error? A failed refresh keeps the content?
|
|
550
575
|
- [ ] Loading state matches the loaded layout (a content-shaped `Skeleton` where the layout is known)? For a redesign, was the existing loading state reviewed against the new layout? A static screen has none?
|
|
551
576
|
- [ ] Every value a token — zero literal hex / off-scale spacing / invented type sizes?
|
|
552
577
|
- [ ] Is every user-facing string routed through a copy key with a sensible fallback (`copyOf(key, fallback)` backed by your own `COPY` map; worker strings via `onAppear` params) — none baked directly into the descriptor?
|
package/guides/himi-test.md
CHANGED
|
@@ -320,7 +320,7 @@ pretty report:
|
|
|
320
320
|
"writes": [
|
|
321
321
|
{ "screen": "himi_blog_post", "action": "tier5.himiBlogPost.like", "via": "wix", "method": "POST", "path": "/blog/v3/posts/post-0001/like" },
|
|
322
322
|
{ "screen": "himi_time", "action": "tier5.himiBookingTime.register", "via": "native", "capability": "himi.wix.registerDirect", "kind": "member-signup", "what": "creates a site member" },
|
|
323
|
-
{ "screen": "himi_time", "action": "tier5.himiBookingTime.
|
|
323
|
+
{ "screen": "himi_time", "action": "tier5.himiBookingTime.pickSlot", "via": "wix", "method": "POST", "path": "/ecom/v1/checkouts" }
|
|
324
324
|
],
|
|
325
325
|
"unreachedWrites": [
|
|
326
326
|
{ "screen": "himi_time", "action": "unreached", "via": "native", "capability": "capability.wix_cashier.proceedToPayment", "kind": "payment" }
|
|
@@ -354,12 +354,12 @@ Put the owner-approved data-access matrix in `SPEC.md` (or `MOBILE-UX.md`) as a
|
|
|
354
354
|
| Screen | Role | Reads | Wix writes | Prohibited |
|
|
355
355
|
| --- | --- | --- | --- | --- |
|
|
356
356
|
| himi_blog_post | visitor | posts, comments | none | like, comment |
|
|
357
|
-
| himi_time | visitor | services, slots | `
|
|
357
|
+
| himi_time | visitor | services, slots | `pickSlot`, `POST /bookings/v2/bookings` | signup, payment |
|
|
358
358
|
| * | visitor | published content | none | |
|
|
359
359
|
```
|
|
360
360
|
|
|
361
361
|
A `Wix writes` cell is `none` (or empty, `-`, `read-only`), or a comma list naming each approved
|
|
362
|
-
write by its **action** (`
|
|
362
|
+
write by its **action** (`pickSlot` or `tier5.himiBookingTime.pickSlot`), its **endpoint**
|
|
363
363
|
(`POST /bookings/v2/bookings` — exact, with `*` for one path segment such as an id:
|
|
364
364
|
`POST /blog/v3/posts/*/like`), its **capability** (`registerDirect`) or its
|
|
365
365
|
**kind** (`payment`, `signup`). Prose such as "create a booking" approves nothing: it cannot say
|
|
@@ -157,8 +157,9 @@ A list loads data, so it ships all four states — the full idiom is
|
|
|
157
157
|
It shows only while the first load runs with nothing on screen; a pull-to-refresh
|
|
158
158
|
keeps the rows and uses the list's own spinner.
|
|
159
159
|
- **Empty** — an `EmptyState` with a directive action, gated by `notEmpty`.
|
|
160
|
-
- **Error, nothing on screen** — one `
|
|
161
|
-
return (offline, server, sign-in, site membership, permission)
|
|
160
|
+
- **Error, nothing on screen** — one `ErrorState` per class `classifyError` can
|
|
161
|
+
return (offline, server, sign-in, site membership, permission): no icon tile or custom icon
|
|
162
|
+
(the `variant` picks the glyph), user-facing copy.
|
|
162
163
|
Offline and server get **Try again** → `tier5.products.retry`; sign-in gets
|
|
163
164
|
**Sign in**; membership opens the site's join flow when available; permission gets no action. A list with no sign-in flow maps
|
|
164
165
|
`"signIn"` to `"permission"` — a visitor still gets a 401 or 403 (Bookings
|
|
@@ -178,10 +179,9 @@ A list loads data, so it ships all four states — the full idiom is
|
|
|
178
179
|
"props": { "height": 72, "cornerRadius": 12, "count": 6 } },
|
|
179
180
|
"modifiers": { "hiddenPath": "$service:products.hideLoading" } },
|
|
180
181
|
{ "id": "error.server",
|
|
181
|
-
"body": { "package": "himalaya", "type": "
|
|
182
|
-
"props": { "title": "Unable to load products",
|
|
183
|
-
"
|
|
184
|
-
"action": { "actionId": "tier5.products.retry" }, "actionLabel": "Try again" } },
|
|
182
|
+
"body": { "package": "himalaya", "type": "ErrorState",
|
|
183
|
+
"props": { "variant": "server", "title": "Unable to load products",
|
|
184
|
+
"cta": { "actionId": "tier5.products.retry" } } },
|
|
185
185
|
"modifiers": { "hiddenPath": "$service:products.hideServerError" } }
|
|
186
186
|
```
|
|
187
187
|
|
|
@@ -234,7 +234,7 @@ word:
|
|
|
234
234
|
- **Except when page 2 loses access.** A `signIn`, `membership` or `permission` failure on
|
|
235
235
|
`loadMore` is not retryable and the rows already shown are no longer the
|
|
236
236
|
user's to see: clear them and go to the same sign-in, membership or
|
|
237
|
-
permission `
|
|
237
|
+
permission `ErrorState` a refresh uses — membership with its join action (`load()` in `himi docs recipe-four-state`). Keep
|
|
238
238
|
page 1 and offer the cursor retry only for `offline` and `server`.
|
|
239
239
|
- APIs that don't page (or v1 fallbacks without cursors) simply never set
|
|
240
240
|
`nextCursor` — the gesture props are safe to leave in place.
|
|
@@ -13,7 +13,7 @@ Every data-backed screen has four states, and Himi's idiom renders all of them
|
|
|
13
13
|
from **one flat layout** — no conditional trees, no separate loading screen. Each
|
|
14
14
|
state is its own node, gated with the `hiddenPath` modifier bound to a worker
|
|
15
15
|
boolean, and the worker derives every flag from one `status` field. The empty state
|
|
16
|
-
and each error class
|
|
16
|
+
is an `EmptyState` node and each error class an `ErrorState` node, gated the same way.
|
|
17
17
|
|
|
18
18
|
This is the corpus norm: of the in-repo worker bundles, ~3 in 4 model loading,
|
|
19
19
|
more than half model error, and the reference apps (`apps/himi-owner-lite`,
|
|
@@ -32,7 +32,7 @@ interface State {
|
|
|
32
32
|
// hiddenPath hides a node when its flag is TRUE — name flags in the hide direction.
|
|
33
33
|
hideLoading: boolean; // the skeleton: shown only while loading with nothing on screen
|
|
34
34
|
notEmpty: boolean; // the EmptyState: shown only when ready with zero rows
|
|
35
|
-
hideOfflineError: boolean; // one
|
|
35
|
+
hideOfflineError: boolean; // one ErrorState per error class …
|
|
36
36
|
hideServerError: boolean;
|
|
37
37
|
hideSignInError: boolean;
|
|
38
38
|
hideMembershipError: boolean;
|
|
@@ -141,40 +141,40 @@ only when the screen shows the user something different for it.
|
|
|
141
141
|
"actionLabel": "Add your first product" } },
|
|
142
142
|
"modifiers": { "hiddenPath": "$service:products.notEmpty" } },
|
|
143
143
|
|
|
144
|
-
// Errors: an
|
|
145
|
-
//
|
|
144
|
+
// Errors: an ErrorState per class, with user-facing copy and a `cta` only when the
|
|
145
|
+
// user can recover. `variant` picks the glyph; the authored copy wins over its default.
|
|
146
146
|
{ "id": "error.offline",
|
|
147
|
-
"body": { "package": "himalaya", "type": "
|
|
148
|
-
"props": { "title": "Reconnect to the internet",
|
|
149
|
-
"
|
|
150
|
-
"
|
|
151
|
-
"
|
|
147
|
+
"body": { "package": "himalaya", "type": "ErrorState",
|
|
148
|
+
"props": { "variant": "offline", "title": "Reconnect to the internet",
|
|
149
|
+
"body": "Connect to the internet, then try again.",
|
|
150
|
+
"cta": { "actionId": "tier5.products.retry" },
|
|
151
|
+
"ctaLabel": "Try again" } },
|
|
152
152
|
"modifiers": { "hiddenPath": "$service:products.hideOfflineError" } },
|
|
153
153
|
{ "id": "error.server",
|
|
154
|
-
"body": { "package": "himalaya", "type": "
|
|
155
|
-
"props": { "title": "Unable to load products",
|
|
156
|
-
"
|
|
157
|
-
"
|
|
158
|
-
"
|
|
154
|
+
"body": { "package": "himalaya", "type": "ErrorState",
|
|
155
|
+
"props": { "variant": "server", "title": "Unable to load products",
|
|
156
|
+
"body": "There was a technical issue on our end. Please wait and try again later.",
|
|
157
|
+
"cta": { "actionId": "tier5.products.retry" },
|
|
158
|
+
"ctaLabel": "Try again" } },
|
|
159
159
|
"modifiers": { "hiddenPath": "$service:products.hideServerError" } },
|
|
160
160
|
{ "id": "error.signIn",
|
|
161
|
-
"body": { "package": "himalaya", "type": "
|
|
162
|
-
"props": { "title": "Sign in to view products",
|
|
163
|
-
"
|
|
164
|
-
"
|
|
165
|
-
"
|
|
161
|
+
"body": { "package": "himalaya", "type": "ErrorState",
|
|
162
|
+
"props": { "variant": "signIn", "title": "Sign in to view products",
|
|
163
|
+
"body": "Your session has ended.",
|
|
164
|
+
"cta": { "actionId": "tier5.products.openSignIn" },
|
|
165
|
+
"ctaLabel": "Sign in" } },
|
|
166
166
|
"modifiers": { "hiddenPath": "$service:products.hideSignInError" } },
|
|
167
167
|
{ "id": "error.membership",
|
|
168
|
-
"body": { "package": "himalaya", "type": "
|
|
169
|
-
"props": { "title": "Join this site to view products",
|
|
170
|
-
"
|
|
171
|
-
"
|
|
172
|
-
"
|
|
168
|
+
"body": { "package": "himalaya", "type": "ErrorState",
|
|
169
|
+
"props": { "variant": "permission", "title": "Join this site to view products",
|
|
170
|
+
"body": "Use this site's join flow, or ask the owner for access.",
|
|
171
|
+
"cta": { "actionId": "tier5.products.openJoin" },
|
|
172
|
+
"ctaLabel": "Join this site" } },
|
|
173
173
|
"modifiers": { "hiddenPath": "$service:products.hideMembershipError" } },
|
|
174
174
|
{ "id": "error.permission", // no action: retrying gives the same answer
|
|
175
|
-
"body": { "package": "himalaya", "type": "
|
|
176
|
-
"props": { "title": "You need permission to view this screen",
|
|
177
|
-
"
|
|
175
|
+
"body": { "package": "himalaya", "type": "ErrorState",
|
|
176
|
+
"props": { "variant": "permission", "title": "You need permission to view this screen",
|
|
177
|
+
"body": "Ask the owner of this business for access." } },
|
|
178
178
|
"modifiers": { "hiddenPath": "$service:products.hidePermissionError" } },
|
|
179
179
|
|
|
180
180
|
// A refresh that failed over rows we kept: say so above the rows, keep the rows.
|
|
@@ -193,13 +193,13 @@ only when the screen shows the user something different for it.
|
|
|
193
193
|
- Ready state is simply the data itself (the list rows, the detail fields) — it
|
|
194
194
|
needs no dedicated marker.
|
|
195
195
|
- **Sign in uses a real auth flow.** A renderer cannot dispatch `himi.wix.*`, so
|
|
196
|
-
the sign-in `
|
|
196
|
+
the sign-in `ErrorState` calls an app action that opens its configured auth gate
|
|
197
197
|
or sign-in screen, then reloads after authentication. Do not dispatch
|
|
198
198
|
`himi.wix.signInDirect` from this button: it requires the email and password
|
|
199
199
|
collected by a credential form (`himi docs wix-login-integration`).
|
|
200
200
|
- **Membership is not sign-in.** `NotSiteMember` (Android: `not a member of
|
|
201
201
|
site`) means the account must join this site. Route it to the membership state;
|
|
202
|
-
wire its
|
|
202
|
+
wire its `cta` to the app's join/registration UI, or omit the `cta` when no
|
|
203
203
|
such flow exists. A `403 WDE0027` is NOT membership: Wix Data returns it to a
|
|
204
204
|
signed-in member without access too, so it stays a permission error.
|
|
205
205
|
- **A 403 is a permission error** — the user lacks access and signing in again
|
|
@@ -211,29 +211,35 @@ only when the screen shows the user something different for it.
|
|
|
211
211
|
layout — the same rows at about the same size. `StatefulSection` or
|
|
212
212
|
`ActivityIndicator` are fine where they fit better. A plain `"Loading…"` `Text`
|
|
213
213
|
bound to a worker string (`collapseWhenEmpty: true`) is the minimum, not the goal.
|
|
214
|
-
- **Use `EmptyState` for every empty state and every screen-level
|
|
215
|
-
draws one standard layout on every platform with the app's tokens.
|
|
216
|
-
|
|
217
|
-
default label
|
|
218
|
-
`
|
|
219
|
-
- Write the
|
|
220
|
-
|
|
221
|
-
why each error class is its own node instead of one
|
|
214
|
+
- **Use `EmptyState` for every empty state and `ErrorState` for every screen-level
|
|
215
|
+
error.** Each draws one standard layout on every platform with the app's tokens.
|
|
216
|
+
An `EmptyState` needs `title`, and `actionLabel` whenever it has an `action` (there
|
|
217
|
+
is no default label; `himi validate` reports a missing one). An `ErrorState` needs
|
|
218
|
+
nothing: its `variant` supplies default copy and a button label.
|
|
219
|
+
- Write the copy as literal text or `$t:` keys. Today, iOS and Android do not
|
|
220
|
+
resolve a `$service:` binding in those props (`himi validate` refuses one in
|
|
221
|
+
`ErrorState` copy) — which is why each error class is its own node instead of one
|
|
222
|
+
node with bound text.
|
|
222
223
|
- **A node for every class `classifyError` can return** — otherwise that failure
|
|
223
224
|
paints a blank screen. A screen with no sign-in flow still gets a 401 when a
|
|
224
225
|
session ends; map `"signIn"` to `"permission"` in its classifier rather than drop
|
|
225
226
|
the node.
|
|
226
|
-
- **
|
|
227
|
-
|
|
227
|
+
- **Fewer nodes with `variantPath`.** `variantPath: "$service:products.errorKind"`
|
|
228
|
+
switches only the default copy and glyph; `cta`, `title`, `body` and `ctaLabel`
|
|
229
|
+
apply to every variant. So `offline` and `server` can share ONE node with the retry
|
|
230
|
+
`cta` and no authored copy — gate it on one flag `shape()` sets for either
|
|
231
|
+
(`hideRetryableError: !(blank && (errorKind === "offline" || errorKind === "server"))`),
|
|
232
|
+
since `hiddenPath` takes a single boolean — while `signIn`, `permission` and
|
|
233
|
+
`membership` keep their own. See `himi docs designing-himi-screens` → Error states.
|
|
228
234
|
|
|
229
235
|
## 3. Which state when
|
|
230
236
|
|
|
231
237
|
| State | Set where | User affordance |
|
|
232
238
|
|---|---|---|
|
|
233
239
|
| loading | initial state (`status: "loading"`) | content-shaped skeleton; NO retry |
|
|
234
|
-
| error, nothing on screen | `catch` in the first load | the class's `
|
|
240
|
+
| error, nothing on screen | `catch` in the first load | the class's `ErrorState`: user-facing copy + a recovery `cta` where one exists |
|
|
235
241
|
| error, rows on screen | `catch` in a refresh (offline or server) | rows stay; a `Banner` with **Try again** above them |
|
|
236
|
-
| sign-in, membership or permission | `catch` in any load | rows go; the class's `
|
|
242
|
+
| sign-in, membership or permission | `catch` in any load | rows go; the class's `ErrorState` (auth flow, join flow, or no `cta`) |
|
|
237
243
|
| empty | derived: ready + 0 rows | say what *would* fill it, and how |
|
|
238
244
|
| ready | successful fetch | the content |
|
|
239
245
|
|
package/guides/recipe-search.md
CHANGED
|
@@ -66,7 +66,7 @@ not say why there are no rows.
|
|
|
66
66
|
| Results | Matching rows, result count, and the available sort/filter controls. |
|
|
67
67
|
| No matches | An `EmptyState` explaining that the current query or filters found nothing; offer a way to adjust them, and Clear only where the field is controlled (the native slot) — the inline `SearchField` is uncontrolled, so Clear there empties the query but not the field. |
|
|
68
68
|
| Empty catalog | Explain that the catalog itself has no items yet, independent of the query; provide a useful browse/back action. |
|
|
69
|
-
| Error | Classified as in `himi docs recipe-four-state`: an
|
|
69
|
+
| Error | Classified as in `himi docs recipe-four-state`: an `ErrorState` per class with user-facing copy, a Try again `cta` only for offline and server, the app's auth flow for sign-in, the site's join flow for `NotSiteMember`, and no `cta` for permission. Retain the query and controls, and keep it distinct from no matches. |
|
|
70
70
|
|
|
71
71
|
### Native slot and old-client fallback
|
|
72
72
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1527.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": [
|
|
@@ -71,5 +71,5 @@
|
|
|
71
71
|
"artifactId": "himalaya-cli"
|
|
72
72
|
}
|
|
73
73
|
},
|
|
74
|
-
"falconPackageHash": "
|
|
74
|
+
"falconPackageHash": "7d4595824e3745b02e52e9cc9c3d3b444992162a8b5792733b07a811"
|
|
75
75
|
}
|