Skip to content

AB#131731 chat-components: layout variant mechanism (webchat + c26)#242

Closed
apdemin wants to merge 22 commits intomainfrom
feature/131731-layout-variant-mechanism
Closed

AB#131731 chat-components: layout variant mechanism (webchat + c26)#242
apdemin wants to merge 22 commits intomainfrom
feature/131731-layout-variant-mechanism

Conversation

@apdemin
Copy link
Copy Markdown
Contributor

@apdemin apdemin commented Apr 20, 2026

Summary

  • Introduces <Message layout="webchat" | "c26"> prop (default "webchat" — backward compatible).
  • Extracts current <Message> body to WebchatLayout; adds new C26Layout with optional label + avatar injection slots.
  • Adds c26 token layer in theme.css via :is([data-layout="c26"]) scope. New c26-only internal tokens: --cc-avatar-size, --cc-label-color, --cc-label-icon-size, --cc-font-family.
  • Discriminated-union MessageProps with never sentinels rejects c26-only props (label, avatar) on webchat callers at compile time.
  • Zero changes required for existing webchat consumers — default prop keeps current DOM and token behavior identical.

Scope

Mechanism only. Detailed c26 styling and Figma-derived token values land in a follow-up PR. Fallbacks marked /* PLACEHOLDER */ in theme.css.

Spec: alu-resources/design-artifacts/specs/2026-04-20-chat-components-layout-variant-spec.md
Plan: alu-resources/design-artifacts/plans/2026-04-20-chat-components-layout-variant-plan.md

Commits

  • d4487d6 test: webchat layout regression baseline (6 tests)
  • f45b3f7 refactor: extract WebchatLayout from Message (mechanical)
  • b9d2d94 feat: layout prop + discriminated union types (+ 3 runtime + 4 compile-time TS contract tests)
  • de95389 feat: c26 token layer in theme.css via :is([data-layout="c26"]) (+ 6 tests)
  • b63cb60 feat: C26Layout with label and avatar slots (+ 8 structural tests)
  • dda62fb test: fullscreen escape + gallery/quick-replies parity (+ 5 tests)

Test plan

  • npm run test — 149/149 pass (18 files)
  • npm run build — dist builds clean; dist/index.d.ts exports MessageLayout, C26Label
  • npm run lint — clean
  • npx tsc --noEmit — clean
  • Manual: wire <Message layout="c26"> into an IP MFE scenario (follow-up PR)
  • Manual: install locally into the webchat consumer — verify no visible regression (reviewer task)

Out of scope (follow-up)

  • Detailed c26 token values (radius, padding, spacing, typography) from Figma — next PR replaces PLACEHOLDER defaults
  • Consumer integration in cognigy/microfrontends/interaction-panel — separate PR
  • Font bundle optimization (Figtree side-effect import retained)
  • Fullscreen branch MessageProvider wrap — latent bug documented; current test injects context-free plugin as workaround
  • Pre-existing --cc-text-dark/--cc-text-light bare-ident fallback bug in :root

🤖 Generated with Claude Code

apdemin and others added 6 commits April 20, 2026 16:08
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…n types

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…slots

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…erer parity tests

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@graymalkin77
Copy link
Copy Markdown

graymalkin77 commented Apr 20, 2026

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues
Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

apdemin and others added 3 commits April 20, 2026 19:49
Extracted BaseLayoutProps, MatchedPlugins, and MessageFocusTarget to
src/layouts/shared/. Unified focus-target id prefix so the existing
moveFocusToMessageFocusTarget util works under c26. Moved layouts up to
src/layouts/. Replaced :global(.user) with [data-source="user"]. Dropped
narration comments and redundant narrowing ternaries.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ayouts barrel

Plugin CSS (ChatBubble.module.css, File.module.css) targets
`article:global(.bot|.user|.agent)` for bubble backgrounds and user-side
file alignment. Simplification pass dropped the bare source class on
C26Layout's article, regressing those styles under layout="c26". Restore
it. Also route Message.tsx through the src/layouts barrel and expose
BaseLayoutProps from it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… asymmetric corners, token-via-UCL fallback)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@kwinto
Copy link
Copy Markdown
Contributor

kwinto commented Apr 21, 2026

Major testing surface: rendering on this branch does not introduce any dom tree change when compared against latest library release.

Should be an automated scenario rendering both and doing strict comparison.

Criterion yet to define, indentation change is OK.

apdemin and others added 5 commits April 22, 2026 11:06
…on token parameterization

Pre-landing of structural wiring for c26 visual theme pass:
- Rename C26Layout.content → .bubble with role-aware fills
- Parameterize ActionButton/ActionButtons with --cc-button-* and --cc-buttons-* tokens
- Add action-button token defaults in theme.css c26 block

Token values for the glass variant + shadow + role-differentiated max-width
land in follow-up commits per
design-artifacts/plans/2026-04-22-chat-components-c26-visual-theme-plan.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- User bubble fallback: neutral-50 → primary-25 (faint lavender so
  both bubbles share the purple family on white MFE)
- Avatar: 36px → 40px (matches UCL size-10)
- Add --cc-bubble-max-width-bot/-user (role-differentiated:
  min(80%,480px) / min(70%,320px)) and --cc-bubble-box-shadow
  (UCL shadow-sm)
- Replace action-button tokens with glass variant (translucent white
  18%, white text, faint border, blur 4px) + new --cc-button-border /
  -hover-border / -backdrop-filter tokens
- Temporary --cc-bubble-max-width alias to bot cap; removed in Task 2
  when C26Layout.module.css:115 is rewritten

Extends test/theme-c26.spec.ts with 6 new assertions (uses existing
c26Block var from beforeAll). 155/155 tests pass.

Spec: alu-resources/design-artifacts/specs/2026-04-22-chat-components-c26-visual-theme-spec.md
Plan: alu-resources/design-artifacts/plans/2026-04-22-chat-components-c26-visual-theme-plan.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… c26 bubbles

C26Layout.module.css (outer c26 .bubble, visible surface):
- Add box-shadow: var(--cc-bubble-box-shadow)
- Replace base .bubble max-width with role-scoped rules:
  - .article:not([data-source=user]) .bubble → bot cap
  - .article[data-source=user] .bubble → user cap

theme.css:
- Drop the temporary --cc-bubble-max-width alias added in Task 1
- Add c26-scoped .chat-bubble role-diff max-width rules alongside the
  asymmetric-corner rules (inner ChatBubble rendered by Text plugin
  would otherwise fall back to 295px default inside c26)

Tests:
- Flip theme-c26 alias assertion back to not.toMatch
- Add C26Layout.spec.tsx CSS-file regex assertions for box-shadow +
  role-scoped max-width (tightened with [^}]*? to not cross block
  boundaries)
- Add theme-c26 assertions for the scoped .chat-bubble max-width rules

Known follow-up: C26Layout's outer .bubble nests plugin-internal
.chat-bubble. Both currently carry bg/border/padding/max-width, which
double up visually. Dedup in a later phase; both caps kept in sync
via the role-scoped rules above.

159/159 tests pass.

Spec: alu-resources/design-artifacts/specs/2026-04-22-chat-components-c26-visual-theme-spec.md
Plan: alu-resources/design-artifacts/plans/2026-04-22-chat-components-c26-visual-theme-plan.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Flip .avatar align-items: flex-start → flex-end and align-self:
start → end so the avatar sits at the bubble's bottom edge. The
asymmetric bubble corner (bottom-left straight for bot/agent,
bottom-right straight for user) now visually points at the avatar.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…n-backdrop-filter in ActionButton

Add token reads for the glass-variant properties Task 1 defined:
- border: var(--cc-button-border, none) on base rule
- backdrop-filter: var(--cc-button-backdrop-filter, none) on base
- border: var(--cc-button-hover-border, var(--cc-button-border, none))
  on hover/focus (chains through so webchat stays borderless)

Webchat :root does not set these tokens; all three reads resolve to
`none`, keeping webchat buttons byte-identical. In c26 scope the tokens
light up (1px solid rgba(255,255,255,0.25) border, blur(4px) filter).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread scripts/install-dom-compat-baseline.mjs Fixed
Comment thread scripts/install-dom-compat-baseline.mjs Fixed
Comment thread scripts/install-dom-compat-baseline.mjs Fixed
Comment thread scripts/install-dom-compat-baseline.mjs Fixed
Comment thread scripts/install-dom-compat-baseline.mjs Fixed
Comment thread scripts/install-dom-compat-baseline.mjs Fixed
Comment thread scripts/install-dom-compat-baseline.mjs Fixed
Comment thread scripts/install-dom-compat-baseline.mjs Fixed
…t release

Renders every supported <Message> variant (core layouts + all demo-page
tabs) against the branch's built dist/ and the latest published
@cognigy/chat-components, and asserts the normalized DOM matches. Guards
against silent regressions in the default webchat layout consumers
depend on.

Runs as its own GitHub Action ("DOM Compatibility") so a break shows as
a distinct PR check. The baseline is resolved at CI time via `npm view`
so we never drift against a stale pin. Excluded from the default `npm
test` because it requires a dist/ build and the dynamically-installed
alias.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@kwinto kwinto force-pushed the feature/131731-layout-variant-mechanism branch from db91b9d to b901373 Compare April 22, 2026 11:22
apdemin and others added 7 commits April 22, 2026 13:26
…y button polish

Nested-bubble dedup:
- Neutralize plugin-internal .chat-bubble in c26 scope (bg transparent,
  border/padding/max-width/radius/shadow zeroed). Outer C26Layout .bubble
  owns chrome.
- Move asymmetric-corner tail (bot: bottom-left, user: bottom-right) from
  .chat-bubble to outer .bubble via role-scoped selectors.
- Bump override specificity to (0,3,0) via [data-layout="c26"][data-source]
  to beat article:global(.bot) .bubble (0,2,1) from ChatBubble.module.css.

Quick-reply button polish:
- Parameterize TextWithButtons.module.css .buttons (it had its own
  hardcoded align-items/margin-top/max-width that overrode
  ActionButtons.module.css tokens; now reads --cc-buttons-*).
- Split ul.buttons margin-block into margin-block-start (token) +
  margin-block-end (0) so the c26 margin-top token is not zeroed by
  the higher-specificity ul.buttons rule.
- Parameterize ul.buttons li with --cc-button-flex + --cc-button-min-width
  so flex:1 1 0 + min-width:0 propagates through the LI wrapper, yielding
  equal-width buttons.
- Add --cc-button-width (100%) so buttons fill their LI.
- Consolidate button flex shorthand into a single --cc-button-flex token.
- Add --cc-buttons-align-items (stretch in c26).
- Tune token defaults for c26: button min-height 1.75rem (Tailwind h-7
  28px — UCL spacing scale jumps 24→32, no native 28), min-width 0,
  buttons-gap 0.375rem (6px), buttons-margin-top --space-2 (8px, matches
  bubble bottom padding so text→buttons == buttons→bubble-bottom).

Tests: +3 new CSS-file-regex assertions. 161/161 pass. Build clean.

Webchat untouched — all new tokens fall back to existing hardcoded values
at :root.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ibility workflow

- eslint.config.js: add a `**/*.mjs` block declaring `globals.node`.
  Flat config ignores legacy `/* eslint-env node */` directives, so
  without this `console`/`process` in our install script tripped
  `no-undef` under CodeQL's ESLint pass (local `npm run lint` only
  scans .ts/.tsx so it missed this).
- scripts/install-dom-compat-baseline.mjs: drop the stale
  `/* eslint-env node */` comment that no longer does anything.
- .github/workflows/dom-compat.yml: drop the single-value matrix.
  With a matrix GitHub appends "(22.x)" to the PR-check title,
  which reads as if "22.x" were the release being compared against.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ble shrink-to-fit

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`npx prettier --check .` on CI flagged three whitespace issues in
test/layouts/dom-compat.spec.tsx (arrow-body / call-args that fit on a
single line). Ran `prettier --write` on the file to fix. No semantic
changes; 29/29 dom-compat tests still pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…tiles + nav + bullets + no-image)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…Cognigy/chat-components into feature/131731-layout-variant-mechanism
…ate :is() + :has() predicates + fix dead declarations)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@apdemin
Copy link
Copy Markdown
Contributor Author

apdemin commented Apr 23, 2026

Abandoning layout variant approach. Starting fresh — c26 will be theme-only.

@apdemin apdemin closed this Apr 23, 2026
kwinto added a commit that referenced this pull request Apr 28, 2026
…ssage types

Pulls in every demo tab the spec previously skipped behind the
"requires widgetSettings.config injection" excuse and renames the
fixture helper to drop the layout-PR vestige.

Coverage growth: 28 → 40 cases (12 new). Each new case was verified
end-to-end by reintroducing the perturbation experiment from commit
0f2fed4 (sentinel attribute on `<article>`) — all 40/40 cases now fail
under that perturbation, confirming none of the additions is a vacuous
empty-vs-empty pass.

New cases (each cited from test/demo.tsx):
- Adaptive Cards [1] and [2] (was just [0]).
- Default Preview x2 — exercises the `enableDefaultPreview` branch.
  Both fixtures encode "RENDER OK" in `_defaultPreview` and "RENDER
  WRONG" in `_webchat`, so a regression that flipped channel selection
  fails the comparison.
- xApp Buttons x2 — quick-reply pill (`_default._quickReplies` +
  `_webchat.quick_replies` with `content_type: "openXApp"`) and template
  button (`attachment.template_type: "button"` with `type: "openXApp"`).
- HTML Sanitization x3 — default tags, `customAllowedHtmlTags: ["p",
  "strong"]`, and `disableHtmlContentSanitization: true`. Default-config
  case is already covered by `bot text message`.
- Markdown text + borderless text — exercises the `renderMarkdown` and
  `disableBotOutputBorder` branches inside Text.tsx.
- Collated bot follow-up with `prevMessage` — header-suppression path
  through the matcher's collation rules.

Mechanical changes:
- `Case` type gains optional `prevMessage`; `assertSameDom` forwards it
  to both renders symmetrically.
- Per-tab widget configs (`defaultPreviewConfig`,
  `customAllowedTagsConfig`, `sanitizationDisabledConfig`,
  `renderMarkdownConfig`, `disableBorderConfig`) extracted as named
  constants rather than inlined per case.
- Spec docstring updated to drop the now-obsolete skip list — only
  "UI Components" (not Message-rendered) and "Streaming messages"
  (animationState changes DOM over time) remain genuinely out of reach.

File rename: `test/fixtures/layout-messages.ts` →
`test/fixtures/messages.ts`. The "layout-" prefix was a vestige of the
closed PR #242 layout-variant work and read oddly here. New fixtures
live alongside the existing source-variant + plugin-payload exports in
the renamed file.

Verification: tsc --noEmit clean, lint clean, `npm run test` 121/121,
`npm run test:dom-compat` 40/40, perturbation experiment 40/40 fail.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants