Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/tame-hounds-yell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@baloise/ds-react': minor
'@baloise/ds-core': patch
---

**react**: add `@baloise/ds-react`, generated React component wrappers for the design system, plus a `useDesignSystem()` bootstrapping helper
**core**: wire up the Stencil React output target (`@stencil/react-output-target`) to generate `@baloise/ds-react`'s bindings on build
2 changes: 1 addition & 1 deletion .github/workflows/actions/archive-download/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ runs:
using: 'composite'
steps:
- name: Download Archive
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8
with:
name: ${{ inputs.name }}
path: ${{ inputs.path }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/actions/archive-upload/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ runs:
run: zip -q -r ${{ inputs.output }} ${{ inputs.paths }}
shell: bash
- name: Upload Archive
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: ${{ inputs.name }}
path: ${{ inputs.output }}
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/actions/setup-environment/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,14 @@ runs:
git log -1 --oneline

- name: Setup pnpm
uses: pnpm/action-setup@v4
uses: pnpm/action-setup@v6

- name: Setup Node.js environment
uses: actions/setup-node@v6
with:
node-version: 24
cache: 'pnpm'
registry-url: 'https://registry.npmjs.org'
always-auth: true

## setup-node writes the registry config to a runner-temp .npmrc (not the
## repo checkout or $HOME) and resolves the auth token from NODE_AUTH_TOKEN
Expand Down
50 changes: 50 additions & 0 deletions .github/workflows/continuous.yml
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,53 @@ jobs:
name: playwright-report-shard-${{ matrix.shardIndex }}
path: packages/core/playwright-report
retention-days: 7

react:
name: 🧪 React
runs-on: ubuntu-24.04
timeout-minutes: 30
needs: [assembleInformation]
env:
HUSKY: 0
CI: 1
strategy:
fail-fast: false
matrix:
apps: [v19]
steps:
- name: Check out code
uses: actions/checkout@v7
with:
ref: ${{ needs.assembleInformation.outputs.branch }}
fetch-depth: 2

- uses: ./.github/workflows/actions/setup-environment
with:
branch: ${{ needs.assembleInformation.outputs.branch }}
action: ${{ needs.assembleInformation.outputs.action }}

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Scaffold and link the ${{ matrix.apps }} smoke-test app
run: bash test/react/build.sh ${{ matrix.apps }}

- name: Install Playwright browsers
working-directory: test/react/${{ matrix.apps }}
run: pnpm exec playwright install --with-deps chromium

- name: Build app
working-directory: test/react/${{ matrix.apps }}
run: pnpm run build

- name: Run Playwright tests
working-directory: test/react/${{ matrix.apps }}
run: pnpm exec playwright test

- name: Upload Playwright HTML report
if: always()
uses: actions/upload-artifact@v7
with:
name: react-playwright-report-${{ matrix.apps }}
path: test/react/${{ matrix.apps }}/playwright-report
retention-days: 7
1 change: 1 addition & 0 deletions CONTEXT-MAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ This file maps the multi-context layout of this monorepo. Each context has its o
| **CSS & Styles** | `packages/css/CONTEXT.md` | Global CSS, utility classes, responsive design, theming, CSS variable conventions |
| **Assets** | `packages/assets/CONTEXT.md` | Fonts, icons, images, asset management, brand guidelines |
| **Playwright** | `packages/playwright/CONTEXT.md` | E2E testing library, page objects, accessibility testing, visual regression |
| **React Bindings** | `packages/react/CONTEXT.md` | Generated React component wrappers, `useDesignSystem()` bootstrapping |
| **Documentation** | `docs/CONTEXT.md` | Storybook setup, documentation patterns, MDX authoring, component showcase |
| **Internal Libraries** | `libs/CONTEXT.md` | ESLint plugin, output targets (Angular), shared utilities, code generation |

Expand Down
51 changes: 51 additions & 0 deletions docs/adr/0003-ds-react-no-custom-output-target.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# 3. `ds-react` uses the off-the-shelf Stencil React output target directly, no custom `libs/output-target-react`

Date: 2026-07-21

## Status

Accepted

## Context

`libs/output-target-angular` exists as a custom package because Angular
bindings need non-trivial extra logic: `ValueAccessorConfig`s that wire
form components (`ds-select`, `ds-checkbox`, `ds-date`, …) into Angular's
`ControlValueAccessor`/reactive-forms machinery, which the stock
`@angular/*` output-targets ecosystem doesn't provide out of the box.
That custom layer is why `libs/output-target-angular` is its own package
with its own generator code (`generate-angular-component.ts`,
`generate-value-accessors.ts`, etc.).

React has no equivalent problem. `@stencil/react-output-target` already
generates typed function-component wrappers with JSX props/events for
every Stencil component, and the previous Baloise design system (see
`packages/core/config/stencil.bindings.react.ts` on the old
`design-system` `main` branch) only ever called `reactOutputTarget(...)`
directly from a thin config file — it never needed a custom wrapper
package for React, unlike Angular.

## Decision

`ds-react` bindings are generated by calling `reactOutputTarget()` from
`@stencil/react-output-target` directly inside a new
`packages/core/config/stencil.bindings.react.ts`, registered in
`stencil.config.ts`'s `outputTargets`. No `libs/output-target-react`
package is created. No `excludeComponents` are configured — every
`ds-*` component gets a React wrapper, and no React-specific
value-accessor-style exclusions are needed, because React consumers
handle controlled/uncontrolled state themselves via the generated
props/events, not via a forms integration layer.

## Consequences

- Less code to own and test than Angular's binding layer — the generated
wrappers are a direct pass-through of Stencil's component metadata.
- If a genuine React-specific customization need shows up later (e.g. a
custom prop-forwarding rule, a Next.js-specific wrapper), it will need
its own design — this ADR does not rule that out, it just says today's
scope doesn't require it.
- Keeps `libs/output-target-angular` as the only precedent for "custom
output-target logic," which should make it obvious to a future reader
that React was a deliberate case of "the stock tool was enough," not an
oversight.
50 changes: 50 additions & 0 deletions docs/adr/0004-react-smoke-test-app-outside-workspace.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# 4. React framework smoke-test app lives outside the pnpm workspace, linked via `pnpm link`

Date: 2026-07-21

## Status

Accepted

## Context

The design system is a pnpm workspace managed by Turborepo. If the React
smoke-test app (`test/react/v19`, generated by `test/react/build.sh`) were
added as a workspace member, `@baloise/ds-react` and `@baloise/ds-core`
would resolve to each other purely through pnpm's workspace protocol —
symlinks into the monorepo's own `node_modules`, bypassing npm package
resolution entirely.

The old Baloise design system's equivalent app (`test/react/v19` on the
`main` branch of the previous repo) deliberately lived outside its Nx
workspace and linked to the built packages via `npm link`, simulating what
an external consumer actually experiences: installing `@baloise/ds-react`
from the registry and resolving it through its `package.json`
`exports`/`main`/`peerDependencies`. That's the whole point of the smoke
test — catching packaging problems (wrong `exports` map, a dependency
that should have been a `peerDependency`, a file missing from `files:`)
that workspace-protocol resolution can silently paper over.

## Decision

`test/react/` stays outside the pnpm workspace (not listed in the root
`pnpm-workspace.yaml`). `test/react/build.sh` builds `@baloise/ds-core`
and `@baloise/ds-react` from their `dist/` output and links them into the
generated app via `pnpm link`, mirroring the old repo's `npm link`
approach. The generated app has its own `package.json`,
`node_modules`, and lockfile, entirely separate from the monorepo's.

## Consequences

- The smoke test actually exercises the published package shape, not just
the source tree — a real regression class (broken `exports`, missing
build output, wrong peer dependency) is caught here that a workspace
member app would miss.
- Slightly more setup than a workspace-member app would need: `build.sh`
has to build and link explicitly rather than relying on pnpm's automatic
workspace symlinking, and CI has to run that script rather than just
`pnpm install`.
- This app is intentionally _not_ wired through `turbo run` as a workspace
task — it's invoked directly (`bash test/react/build.sh v19`, then
`pnpm --dir test/react/v19 ...`), both from CI and from the root
`react:app` convenience script.
66 changes: 66 additions & 0 deletions docs/adr/0005-duplicate-pnpm-overrides.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# 5. Duplicate pnpm `overrides` in both `pnpm-workspace.yaml` and `package.json`

Date: 2026-07-21

## Status

Accepted

## Context

pnpm dependency overrides (used here to force patched versions of
transitive devDependencies like `brace-expansion` and `js-yaml` that carry
high-severity advisories) moved from `package.json`'s `pnpm.overrides`
field to `pnpm-workspace.yaml`'s `overrides` field in pnpm 11. Running
`pnpm install` locally (pnpm 11.12.0) now prints:

```
[WARN] The "pnpm" field in package.json is no longer read by pnpm. The
following keys were ignored: "pnpm.overrides".
```

...and only applies the `pnpm-workspace.yaml` copy. This makes the
`package.json` copy look like dead config that should be deleted.

It isn't. Removing it broke the Vercel build: `pnpm install
--frozen-lockfile` (configured in `vercel.json`) failed there once
`package.json`'s `pnpm.overrides` no longer matched what the lockfile
expected, even though `pnpm-workspace.yaml`'s `overrides` were untouched
and the exact same `pnpm@11.12.0` is pinned via `packageManager` and
resolved through corepack (`ENABLE_EXPERIMENTAL_COREPACK=1`). In practice,
Vercel's install path is sensitive to the `package.json` copy in a way
local pnpm is not.

## Decision

Keep both override blocks — `overrides` in `pnpm-workspace.yaml` and
`pnpm.overrides` in `package.json` — and require them to stay identical.

Enforcement:

- `scripts/check-overrides.mjs` parses both files and fails if the
override sets don't match exactly (ignoring an informational
`_comment` key in `package.json`'s block, see below).
- The root `lint` script (`package.json`) runs this check after `turbo
run lint`, so it runs in CI alongside normal linting and fails the
build on drift.
- Each file carries a short comment pointing at the other and at this
ADR. `package.json` is strict JSON and can't hold a `//` comment, so
the pointer lives as a `_comment` string _sibling_ of `overrides`
inside the `pnpm` object — not a key inside the `overrides` map
itself, where pnpm would try to parse it as a `package@range` rule
and fail on `"Kept in sync..."` not being a valid version.

When adding, changing, or removing an override: update both files in the
same commit. The check script will catch it if you forget.

## Consequences

- Two files to touch for one logical change; mildly annoying but cheap
compared to a broken Vercel deploy.
- The `_comment` key is invisible to pnpm's override resolution (it's
outside the `overrides` map) but is technically dead data from pnpm's
point of view — it exists purely for the next human reading the file.
- If a future pnpm/Vercel upgrade makes `pnpm-workspace.yaml` the single
source of truth everywhere, this ADR and the duplication it describes
should be revisited and likely deleted.
Loading
Loading