From 711ec3000e4d6d8a64306cfc6df47cf80d018c83 Mon Sep 17 00:00:00 2001 From: Gian Bata Date: Thu, 9 Jul 2026 05:29:48 -0700 Subject: [PATCH 1/7] Add shared-ui React components as EDS blocks (native authoring POC) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reuse HAL @hal-sbn-root/shared-ui inside Edge Delivery Services via a React-in-a-block island, authorable in DA.live. - blocks/_react/: esbuild-bundled island runtime, registry, generic table->props parser, block glue - blocks/{button,headline,savings-badge,fare-card,choose-your-fare}/: 5 shared-ui components wired as EDS blocks - component-definition.json / component-filters.json: DA.live picker entries - build/esbuild.mjs + build:blocks script: bundles the island (EDS is no-build) - POC-GUIDE.md: code-level map of the POC Scoped to the native track; the headless app (frontend/) is excluded. package.json documents deps; lockfile/.npmrc omitted (shared-ui installs from HAL Artifactory over VPN — the committed island bundle runs without install). --- POC-GUIDE.md | 142 +++++++++++++++++++ blocks/_react/block.js | 20 +++ blocks/_react/gallery.html | 104 ++++++++++++++ blocks/_react/parse.js | 38 +++++ blocks/_react/react-runtime.css | 1 + blocks/_react/react-runtime.js | 103 ++++++++++++++ blocks/_react/registry.jsx | 17 +++ blocks/_react/runtime.jsx | 33 +++++ blocks/button/button.js | 5 + blocks/choose-your-fare/choose-your-fare.css | 5 + blocks/choose-your-fare/choose-your-fare.js | 5 + blocks/choose-your-fare/harness.html | 50 +++++++ blocks/fare-card/fare-card.js | 5 + blocks/headline/headline.js | 5 + blocks/savings-badge/savings-badge.js | 5 + build/esbuild.mjs | 33 +++++ component-definition.json | 70 +++++++++ component-filters.json | 7 +- package.json | 14 +- 19 files changed, 660 insertions(+), 2 deletions(-) create mode 100644 POC-GUIDE.md create mode 100644 blocks/_react/block.js create mode 100644 blocks/_react/gallery.html create mode 100644 blocks/_react/parse.js create mode 100644 blocks/_react/react-runtime.css create mode 100644 blocks/_react/react-runtime.js create mode 100644 blocks/_react/registry.jsx create mode 100644 blocks/_react/runtime.jsx create mode 100644 blocks/button/button.js create mode 100644 blocks/choose-your-fare/choose-your-fare.css create mode 100644 blocks/choose-your-fare/choose-your-fare.js create mode 100644 blocks/choose-your-fare/harness.html create mode 100644 blocks/fare-card/fare-card.js create mode 100644 blocks/headline/headline.js create mode 100644 blocks/savings-badge/savings-badge.js create mode 100644 build/esbuild.mjs diff --git a/POC-GUIDE.md b/POC-GUIDE.md new file mode 100644 index 0000000..44c5d1e --- /dev/null +++ b/POC-GUIDE.md @@ -0,0 +1,142 @@ +# HAL × Adobe EDS / DA.live — Authoring POC Guide + +**Start here.** This repo (`hal`, from `AdobeDevXSC/hal`) hosts a two-track proof-of-concept +answering one question: **can we reuse HAL's `@hal-sbn-root/shared-ui` design system with +Adobe Edge Delivery Services (EDS), authored in DA.live (Document Authoring)?** + +Two tracks, one design system: + +| Track | Who renders the page | Lives in | Status | +|-------|----------------------|----------|--------| +| **A — Headless** | our Next.js app | `frontend/` | ✅ end-to-end, live | +| **B — Native (EDS-rendered)** | Adobe's edge | `blocks/`, `build/`, `component-*.json` | ✅ system built; drag-drop = last mile | + +Two docs, two purposes: +- **`frontend/public/aem-eds-pipeline.html`** — the *visual* explainer (concepts, diagrams, + the naming taxonomy, headless-vs-native comparison). Open it in a browser. +- **This file** — the *code-level* map: which file does what, and where the interesting bits are. + +--- + +## Track A — Headless (`frontend/`) + +Our Next.js 16 + React 19 app fetches DA.live content and renders shared-ui. Flow: + +``` +DA.live sheet (authored) ──Publish──> JSON at *.aem.live/.json + │ + ▼ browser +ChooseYourFareView.tsx ──useQuery──> daLiveClient.ts ──fetch──> /api/dalive + │ │ + │ ★ THE API CALL HAPPENS HERE: src/app/api/dalive/route.ts + │ (server fetches DA server-to-server → dodges CORS) + ▼ +mapDaLiveToChooseYourFare.ts (flat key/value sheet → typed component props) + ▼ + wrapped in providers (src/app/providers.tsx) +``` + +**Key files** (all already commented inline): +- **`src/app/api/dalive/route.ts` — ★ where the API call happens.** Server-side proxy. DA's + published JSON sends no CORS header, so the browser can't fetch it cross-origin — this route + fetches it server-to-server. Preview vs live host chosen by `?preview`. +- `src/lib/daLiveClient.ts` — browser-side client that calls the proxy + flattens the sheet envelope. +- `src/app/[lang]/[region]/choose-your-fare/mapDaLiveToChooseYourFare.ts` — maps the flat + `card1.*` / `card2.*` key/value sheet into typed `ChooseYourFare` props. +- `src/app/[lang]/[region]/choose-your-fare/ChooseYourFareView.tsx` — client component: + `useQuery` → map → render (with a `MOCK` fallback until the sheet is authored). +- `src/app/providers.tsx` + `layout.tsx` — Redux + QueryClient + Router + ThemeProvider + design + tokens. shared-ui isn't SSR-safe → client-only render behind a `mounted` gate. + +Run it: `cd frontend && npm run dev` → open `/en/us/choose-your-fare`. + +--- + +## Track B — Native / EDS-rendered (`blocks/`, `build/`, `component-*.json`) + +Adobe's edge renders the page; our shared-ui components run as **React islands** inside vanilla +EDS blocks. EDS is *no-build*, so we pre-bundle the React runtime with esbuild and commit the output. + +### ★ How the React → block mapping works + +When EDS renders a page, for each block named `` it auto-imports `blocks//.js` +and calls its default export with the block's DOM element (EDS's `decorate()` contract): + +``` +Authored block table (rows of: key | value) + │ + ▼ EDS auto-loads blocks//.js (e.g. blocks/button/button.js) +renderBlock(block, 'Button') ← blocks/_react/block.js (orchestrator) + │ + ├─ parseBlock(block) ← blocks/_react/parse.js ★ the table → props mapping + │ reads the 2-col rows into a props object; supports dotted + [index] paths + booleans: + │ children -> "Book now" + │ fareCards[0].title -> array of objects + │ card1.isBestValue -> boolean + │ + ├─ ensureIslandCss() injects react-runtime.css once + │ + ▼ dynamic import of the esbuild bundle (react-runtime.js) +mountComponent(el, 'Button', props) ← blocks/_react/runtime.jsx (the island) + │ registry['Button'] → the shared-ui Button ← blocks/_react/registry.jsx + ▼ +createRoot(el).render(