@peektravel/app-utilities 0.7.3 → 0.7.4

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.
@@ -9,6 +9,36 @@
9
9
  * dependency-free.
10
10
  */
11
11
 
12
+ /* ---- unupgraded-element guard (FOUC) ------------------------------------- */
13
+ /*
14
+ * Hide each <ody-*> element until its definition upgrades it, so it never
15
+ * flashes as its raw text content (an un-upgraded `<ody-button>Save</ody-button>`
16
+ * would otherwise render the bare word "Save"). `visibility` (not `display`)
17
+ * preserves layout, so there is no reflow when the element upgrades; wrapping
18
+ * the tags in `:where` keeps specificity at zero so a consumer can override
19
+ * trivially. If the
20
+ * registration bundle never loads, elements stay hidden rather than showing raw
21
+ * text. This selector list is kept in sync with the component registry by the
22
+ * `defined-guard` drift test — add any new tag here when you register it.
23
+ */
24
+ :where(
25
+ ody-accordion, ody-alert, ody-app-page-container, ody-brand-icon, ody-breadcrumb,
26
+ ody-breadcrumb-item, ody-button, ody-card, ody-check-in-status, ody-checkbox,
27
+ ody-checkbox-group, ody-collapsible, ody-collapsible-collapsed, ody-collapsible-content,
28
+ ody-collapsible-section, ody-copy-button, ody-datepicker, ody-divider, ody-dropdown-multi,
29
+ ody-dropdown-single, ody-empty-state, ody-horizontal-divider, ody-icon, ody-inline-input,
30
+ ody-inline-list, ody-inline-list-item, ody-input, ody-list-item, ody-loading-bar,
31
+ ody-loading-spinner, ody-message, ody-modal, ody-money-input, ody-option, ody-page-container,
32
+ ody-panel, ody-percentage-input, ody-popover, ody-product-indicator, ody-radio-button-group,
33
+ ody-search-input, ody-section-column-item, ody-section-columns, ody-section-row-item,
34
+ ody-section-rows, ody-split-button, ody-stat, ody-stat-detail, ody-stat-summary,
35
+ ody-stat-summary-detail, ody-status-dot, ody-table, ody-table-header, ody-tabs, ody-tag,
36
+ ody-toast-host, ody-toggle-button, ody-tooltip, ody-two-column, ody-two-column-main,
37
+ ody-two-column-secondary, ody-two-column-secondary-header
38
+ ):not(:defined) {
39
+ visibility: hidden;
40
+ }
41
+
12
42
  /* ---- base ---------------------------------------------------------------- */
13
43
  ody-icon, ody-button, ody-tag, ody-alert, ody-card, ody-divider, ody-horizontal-divider,
14
44
  ody-status-dot, ody-message, ody-loading-spinner, ody-loading-bar {
package/docs/ui.md CHANGED
@@ -40,6 +40,33 @@ CSS can also be linked instead of imported:
40
40
  <link rel="stylesheet" href="…/@peektravel/app-utilities/ui/odyssey.css" />
41
41
  ```
42
42
 
43
+ Registration is **idempotent** — importing the module more than once (or from
44
+ more than one bundle) re-registers nothing and never throws, so lazy or
45
+ duplicated imports are safe.
46
+
47
+ If you register the bundle **lazily** (e.g. a dynamic `import()` to dodge SSR /
48
+ hydration mismatches), two things stop un-upgraded elements from flashing as
49
+ their raw text content (`<ody-button>Save</ody-button>` briefly showing the bare
50
+ word "Save"):
51
+
52
+ - `odyssey.css` ships a `:not(:defined) { visibility: hidden }` guard, so every
53
+ `<ody-*>` stays invisible — layout preserved, no reflow — until it upgrades.
54
+ Load the CSS **eagerly** so this applies before first paint. It has zero
55
+ specificity, so you can override it for a deliberate fallback.
56
+ - `whenOdysseyReady()` resolves once every imported element has upgraded, so you
57
+ can gate your first render on it:
58
+
59
+ ```ts
60
+ import { whenOdysseyReady } from '@peektravel/app-utilities/ui';
61
+ await whenOdysseyReady();
62
+ // …now render your <ody-*> tree
63
+ ```
64
+
65
+ A *failed* dynamic import rejects at the `import()` call site — handle load
66
+ failures there; `whenOdysseyReady()` reflects only the elements that did
67
+ register. `registeredTags()` returns the registered tag list if you need to
68
+ introspect it.
69
+
43
70
  Named exports for advanced use:
44
71
 
45
72
  ```ts
package/llms.txt CHANGED
@@ -250,6 +250,13 @@ effect; read-only state props (`isOpen`/`isVisible`) ignore the write (drive the
250
250
  via a `ref`'s imperative methods). No `only a getter` crash. TS still types them
251
251
  read-only — the setters are a runtime safety net.
252
252
 
253
+ Registration is idempotent (importing twice never throws). Lazy registration:
254
+ `odyssey.css` ships a `:not(:defined){visibility:hidden}` guard so un-upgraded
255
+ `<ody-*>` never flash as raw text (load the CSS eagerly), and `whenOdysseyReady()`
256
+ (`Promise<void>`) resolves once every imported element has upgraded — gate first
257
+ render on it. `registeredTags()` returns the registered tag list. A failed
258
+ dynamic import rejects at the `import()` call site.
259
+
253
260
  Tags by tier (see `docs/ui.md` for attributes/events/examples per component):
254
261
  - display: `ody-button`, `ody-tag`, `ody-alert`, `ody-card`, `ody-horizontal-divider`
255
262
  (1px rule with a default `margin-block: var(--gap16)`; `spacing="tight"|"none"`),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peektravel/app-utilities",
3
- "version": "0.7.3",
3
+ "version": "0.7.4",
4
4
  "description": "GraphQL JS mapping utilities extracted from the Peek Pro Autopilot connector.",
5
5
  "license": "MIT",
6
6
  "repository": {