Skip to content

ROU-12955: merge dev into new theme branch - #1206

Merged
BenOsodrac merged 34 commits into
ROU-12714from
ROU-12955
Aug 12, 2026
Merged

ROU-12955: merge dev into new theme branch#1206
BenOsodrac merged 34 commits into
ROU-12714from
ROU-12955

Conversation

@BenOsodrac

@BenOsodrac BenOsodrac commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Brings ROU-12714 up to date with dev (28 commits, 3d9c417e6..d52518b15), plus the follow-up work the merge surfaced. Conflict policy: this branch is the source of truth for UI/SCSS styling; dev wins on TS behaviour, tooling, and build system. 13 conflicts resolved.

Taken from dev as-is

  • Toolchain: TypeScript 5.9.3 with the new tsc-based TsTranspile (drops gulp-typescript), typescript-eslint 8.64, typedoc 0.28, Volta pin (node 24.13.1), version 2.30.0
  • Carousel (ROU-12937): Splide.ts refactor — bare <img> slides are no longer div-wrapped (fixes removeChild NotFoundError on data refresh) + splide 4.1.4
  • Menu open-state contract: .is--open on .app-menu-content (kept our --size-side-menu naming/tokens). Verified rule-by-rule against dev's compiled CSS
  • Virtual Select 1.4.0: vendor baseline refresh, library-validation-message suppression, reduced-motion rules — relocated into 04-patterns/.../dropdown/provider/
  • New Wizard/WizardItem TS pattern (ROU-125682), APIs and build specs

Dev fixes ported into our token system

Dropped deliberately (Phase 15 policy)

PatternsDeprecated spec, 10-deprecated wizard styles, O11 SCSS entry.

Fixes surfaced by the merge

Storybook

  • Wizard story rebuilt against the new pattern APIs (Wizard/Vertical/Interactive variants), left ui-pending for UI sign-off; verified headless (pattern classes + a11y roles applied)
  • deprecated/ baseline CSS refreshed from dev @ d52518b15 (provenance in its README)

Compiled-artifact audit (dev vs this branch)

JS differs by only ~102 lines (~5KB/platform), all deliberate branch work: the LegacyTokenMap runtime shim, GlobalEnum var renames (--footer-height--size-footer, --header-size-content--size-header-content), a few behaviour tweaks, and prettier-only noise.

Verified

npm i + npm run build (exit 0, both platforms, lint clean) and build-storybook (105 entries) on the merged tree; Chromatic on this PR published 102 stories with UI tests green.

Reviewer pointers

  • Manual check worth doing: menu open/close on phone/tablet/RTL (two structural rewrites merged)
  • Wizard visuals are intentionally pending UI review (new pattern + restyle)
  • "OutsystemsUI - PR pipeline" shows as skipped — its ADO branch filters don't include ROU-12714; expected for all PRs into this branch

JoaoFerreira-FrontEnd and others added 30 commits May 20, 2026 17:50
* - update app-menu class selector;

* - fix desktop layout app-menu-content;
* ROU-12834: Fix dropdown arrow placement

* ROU-12834: Move dropdown arrow class to form file
Co-authored-by: Gonçalo M. <goncalo.martins@outsystems.com>
* Update Virtual Select to v1.3.0

* Set new showSecureTextWarning default
* ROU-12855: Update node version

* update actions/checkout

* update azure/cli action

* update Azure DevOps Login hash
* - update eslint;

* update to stable TS
Co-authored-by: Gonçalo M. <goncalo.martins@outsystems.com>
update labels action version;
clean validate-pr-title action dependency;
…#1157)

Bumps the minor-and-patch group with 1 update in the / directory: [@splidejs/splide](https://github.com/Splidejs/splide).


Updates `@splidejs/splide` from 4.1.3 to 4.1.4
- [Release notes](https://github.com/Splidejs/splide/releases)
- [Commits](https://github.com/Splidejs/splide/commits)

---
updated-dependencies:
- dependency-name: "@splidejs/splide"
  dependency-version: 4.1.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Gonçalo M. <goncalo.martins@outsystems.com>
Bumps the minor-and-patch group with 2 updates: [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) and [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser).


Updates `@typescript-eslint/eslint-plugin` from 8.62.0 to 8.62.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.62.1/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.62.0 to 8.62.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.62.1/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.62.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.62.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* core(wizard, wizard-item) - adding new patterns

* core(lint) - run lintfix

* fix compilation errors due missing typification issue

* Update themes with these new patterns

* core(wizard): Add new wizard and deprecate the current one
Bumps the minor-and-patch group with 2 updates in the / directory: [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) and [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser).


Updates `@typescript-eslint/eslint-plugin` from 8.62.1 to 8.64.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.64.0/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.62.1 to 8.64.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.64.0/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.63.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.63.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
)

* ROU-12937: Fix Carousel removeChild NotFoundError on data refresh

Stop reparenting bare <img> carousel slides into a wrapper <div> in
_prepareCarouselItems(). The <img> is a platform-owned node; on ODC (React
runtime) moving it invalidates React's fiber parent record, so a
ParameterOnChange aggregate refresh crashes the reconcile with
'NotFoundError: Failed to execute removeChild on Node' (OS-CLRT-60500).
Regressed in v2.29.0 by c307023 (PR #1138).

Restore the pre-regression class-add loop (no node creation/movement) and
preserve PR #1138's a11y intent non-destructively: strip invalid ARIA roles
from <img> slides at the attribute level in _applyListRoles/_setListRoles
instead of moving them into a container.

* Update Carousel comment

* ROU-12937: Address a11y review feedback on Carousel list roles

- Skip list semantics when the carousel has bare <img> slides: images can't
  take role="listitem" without replacing their image semantics, and a
  role="list" without list items is invalid. Also drop a list role applied
  on a previous pass when content changes across platform refreshes.
- Correct misleading comments: role="presentation" is valid on an image but
  removes it from the accessibility tree; roles are stripped so images stay
  announced via alt text.
- Strip role="tabpanel" from slides that are native list elements (ul/ol/li)
  via tagName check instead of the descendant query — also fixes bare <li>
  slides that previously kept tabpanel.

* ROU-12937: Use OSFramework Dom helpers and A11Y role constants in Carousel

Address review feedback: replace raw DOM calls with the framework helpers for
consistency.
- _applyListRoles: Attribute.Get/Set/Remove with A11YAttributes.Role
  constants (AttrName/List/Listitem); detect native-list and image slides by
  reading direct children and checking tagName (kept direct-child-only so
  wrapped images still receive list roles).
- _prepareCarouselItems: Styles.ContainsClass / Styles.AddClass instead of
  classList.

* ROU-12937: Simplify list-role detection back to direct-child querySelector

Revert the Array.from(children).some() refactor: keep _hasImageSlides as a
concise direct-child querySelector (consistent with the adjacent
_hasNativeListChildren, which is now unchanged from 2.29.0) and restore the
querySelectorAll(':scope > *') loop. Keeps the Helper.Dom.Attribute/Styles +
Role-constant conversions from the review.

* Fix nit syntax detail

* Revert "Fix nit syntax detail"

This reverts commit 53b2daa.

* Fix nit details

* ROU-12937: Route Carousel list-role queries through Helper.Dom.TagSelector

Use Helper.Dom.TagSelector / TagSelectorAll (the framework querySelector
wrapper, used across the codebase with compound selectors) instead of raw
querySelector in _applyListRoles. The ':scope >' selectors keep the direct-child
semantics (a wrapped image must still receive list roles), so _applyListRoles is
now free of raw DOM queries.
* ROU-12910: Add Volta configuration and update README

* ROU-12910: Updated gulp version and removed gulp-typescript

* Updated gulpfile

* Accepted changes requested by sonar
* Adding ADR templates

* Add ADR-0001: Remove JS pixel viewport height

* Removing code that set the --viewport-height

* Add defaults for height if var not defined

* Setting html height to be device height

* Moved files to the correct folder

* Re-adjust the approach to viewport cover only
* ROU-12946: Update VirtualSelect provider to 1.4.0 (a11y, security, perf)

Re-vendors the library CSS and bumps the provider version for VirtualSelect
1.4.0, whose accessibility/security/performance release moves two elements out
of .vscomp-wrapper and adds three CSS rules.

_virtualselect_lib.scss - six substantive changes, verified by diffing the
released 1.3.0 stylesheet against the 1.4.0 build rather than by hand:

  - .vscomp-error-message and its ::before glyph (new: the validation message
    added for WCAG 3.3.1, with a non-colour cue)
  - .vscomp-wrapper.has-error ~ .vscomp-error-message (new, and a sibling
    selector because the message now renders outside the wrapper)
  - .vscomp-toggle-all-button gains min-height/min-width: 24px (WCAG 2.5.8)
  - the per-tag clear button goes 20px -> 24px, and the tag content width
    calc(100% - 20px) -> calc(100% - 24px) (same criterion)
  - a @media (prefers-reduced-motion: reduce) block zeroing transitions

The patched file was confirmed content-identical to the 1.4.0 build output
(whitespace- and quote-normalised), so nothing was missed. Patched in place
rather than regenerated to keep the diff reviewable.

_virtualselect.scss - suppress the library's validation message. OSUI owns
validation messaging: the platform calls validation(), which applies
.osui-dropdown--not-valid and appends its own .osui-dropdown-error-message
styled with OSUI tokens. Without this, a Dropdown that reached the library's
validation path would show two messages, one of them unthemed. Dormant today,
since getProviderConfig() passes neither `required` nor `minValues` - but the
extensibility configs merge arbitrary provider props straight through, so a
page can reach it. Specificity 0,4,0 beats the library's 0,3,0 without
!important.

Verified as needing NO change, rather than assumed:

  - Layout. The host .vscomp-ele is display: inline-block, not flex or grid, so
    the two new children stack in normal flow. The live region is
    position: absolute and clipped to 1px, and that visually-hidden rule was
    already vendored in 1.3.0. No rule anywhere in src/ uses a structural or
    positional selector (>, +, ~, :only-child, :first-child, :nth-*) on any
    vscomp class, so nothing depends on the wrapper's child count.
  - TypeScript. Nothing in src/ references combobox, aria-activedescendant,
    vscomp-search-input, vscomp-live-region or vscomp-error-message. The only
    aria-expanded writer is DropdownServerSide, a separate provider acting on
    its own element. setA11YProperties/setHtmlElements are MethodNotImplemented
    stubs, so all ARIA is delegated to the library.
  - Naming. OSUI's message class is osui-dropdown-error-message and its lookup
    is a querySelector for that class, so the library's vscomp-error-message
    cannot collide with it.
  - setGlobalDefaults/resetGlobalDefaults. Not called anywhere in OSUI.

ARCHITECTURE.md was stale at 1.1.0, two minors behind; corrected to 1.4.0
alongside the enum and README badge.

The package.json devDependency on virtual-select-plugin is deliberately left at
^1.1.0: it is unreferenced by gulp/ and tsconfig.json, and 1.4.0 is not
published to npm yet, so bumping it would break npm install. The library JS
ships as a module resource, not from this repo.

Not addressed here, needs a product decision: SanitizeDropdownValues is
initialised to false and forwarded as enableSecureText on every init, so the
explicit value defeats any page-level VirtualSelect.setGlobalDefaults. Option
description is the one field the wrapper does not sanitise itself and it
reaches a live HTML sink. Flipping the default also has a data-migration
consideration for values already persisted in escaped form.

* ROU-12946: Disable VirtualSelect internal validation

OSUI owns Dropdown validation: the platform calls validation(), which applies
.osui-dropdown--not-valid and appends its own .osui-dropdown-error-message.

VirtualSelect 1.4.0 added aria-invalid, an aria-describedby association and a
live-region announcement to its own validate(). Because OSUI hides the library's
message element, an app that reached validate() through the extensibility configs
(required / minValues) would get a combobox marked aria-invalid and described by a
display:none element - announced as invalid with no discoverable reason and no
visible message.

Setting disableValidation makes OSUI's ownership explicit and that state
unreachable. Apps that deliberately want the library's validation can still set
disableValidation: false, since the extensibility configs are merged last.

* ROU-12946: Honour prefers-reduced-motion on OSUI Dropdown transitions

VirtualSelect 1.4.0 zeroes its own transition durations under
prefers-reduced-motion, but only for the dropbox, the dropbox container/wrapper and
the toggle button. OSUI's override stylesheet declares four more transitions that the
library's media query does not reach - the toggle button arrow rotation, the checkbox
background and check fade, and the option hover fade - so the preference was only
partially honoured.

Zero those in OSUI's own stylesheet rather than editing the vendored library file,
which is kept as a verbatim copy of upstream.

* ROU-12946: Sanitize Dropdown option descriptions

getProviderConfig() sanitized each option label but left description untouched.
VirtualSelect renders description as HTML into the option row, and its own
secureText() is a no-op while SanitizeDropdownValues is False (the default), so an
app-supplied description containing markup was rendered as live HTML.

VirtualSelect 1.4.0 does not close this: its hardening covered attribute contexts
(data-value, aria-label), not this HTML sink.

Sanitize description alongside label, before _groupOptions() runs, so the copy placed
on customData stays consistent with what is rendered. Note this changes what
getSelectedValues() returns for descriptions containing < or >, matching the
treatment labels already receive.

* ROU-12946: Match upstream escaped form for error-message glyph

Upstream's 1.4.0 dist CSS ships content:"\26A0", not the literal character.
Restoring the escaped form keeps the vendored file byte-faithful to upstream
(only decimal-formatting differences remain), which is what allows mechanical
diffing against the upstream dist on future upgrades, and keeps the source
ASCII-only. Sass decodes the escape at compile time, so the built bundles are
unchanged.

* ROU-12946: Document VirtualSelect 1.4.0 upgrade and validation ownership decisions in ADR
Conflict policy: this branch is source of truth for UI/SCSS styling;
dev wins on TS behaviour, tooling and build system.

Taken from dev as-is:
- TypeScript 5.9.3 + tsc-based TsTranspile, typescript-eslint 8.64,
  typedoc 0.28, volta node 24.13.1, version 2.30.0
- Splide.ts ROU-12937 refactor (bare-img slides keep no role; no more
  div-wrapping — fixes removeChild NotFoundError on data refresh) + splide 4.1.4
- Menu open-state contract: .is--open on .app-menu-content (kept our
  --size-side-menu naming and tokens)
- Virtual Select 1.4.0: vendor baseline refresh + has-error suppression +
  reduced-motion rules, ported into 04-patterns/.../dropdown/provider/
- New Wizard/WizardItem TS pattern, APIs and specs

Kept ours / dev fixes ported into our token system:
- Icon libraries: dev search-icon fix (#1188/#1191) retokenized
  ($token-scale-400/1000, $token-icon-subtlest); submenu hide-arrow
  (ROU-12882) display:none default merged into our tokenized block
- Carousel: kept our restyled pagination; dev a11y-conditional WCAG dot
  sizing (#1147) retokenized ($token-scale-150/300)
- Dropdown serverside: dev 100vh viewport fallback + our --size-header
- Wizard SCSS: dev's new-pattern styles relocated to
  src/scss/04-patterns/02-content/wizard/ and translated (get-*() helpers
  and retired --space-*/--border-size-*/--font-size-* → tokens), keeping
  the --osui-wizard-* CSS API from our pre-merge wizard restyle
- Dropped per Phase 15: PatternsDeprecated spec, 10-deprecated wizard,
  O11 SCSS entry (deliberate deletions on this branch)

Verified: npm i + npm run build (both platforms, lint clean) and
build-storybook (104 stories) green on the merged tree.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ubmenu focus ring

- deprecated/: refresh baseline CSS from dev @ d52518b (v2.30.0) so the
  Storybook theme toggle compares against dev's actual current output;
  README now records provenance and the refresh procedure
- Wizard: graft the pre-merge Figma-aligned design onto the new TS pattern —
  40px icons driven by --osui-wizard-icon-size (connector geometry derives
  from the var instead of hardcoded 12/24px), active-state color-mix ring +
  medium label weight, focus-visible halo, 16px icon glyphs, empty-dot
  connector variant; RTL connector now uses the icon-size formula too
- Submenu: restore the .has-accessible-features :focus-within focus ring
  that the restyle had dropped (present on dev), tokenized

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
BenOsodrac and others added 4 commits August 11, 2026 15:56
The old story rendered the deleted CSS-only .wizard markup. Now drives the real
Wizard/WizardItem APIs (Create parent → items → Initialize parent → items) with
the [data-block*='WizardItem'] wrapper contract, plus Vertical and Interactive
variants. Left ui-pending for UI sign-off. Verified headless: pattern classes
(is-horizontal/is-vertical/is-interactive, item statuses) and a11y roles
(list/listitem + aria-current vs tablist/tab + aria-selected) all applied.

Introduction.mdx: Wizard moves from the CSS-only blocks list to the JS patterns
list.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
VS Code's bundled TypeScript 6.x rejects this repo's tsconfig (module=amd and
moduleResolution=node10 are deprecated-as-error there) and then falls back to
strict implicit-project defaults, surfacing phantom TS2564 errors on Config
classes that the real TS 5.9 build never reports. typescript.tsdk points the
language server at node_modules/typescript so editor and build agree.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Union-merged .gitignore (docs/ + .storybook/platform/). Everything else
auto-merged: optionalDependencies move, Storybook platform-CSS generator,
fork-safe Chromatic workflow, tsconfig types:[], tokens ^1.4.2 with the new
build:tokens flags.

Fixes surfaced by the combination:
- tsconfig: add explicit lib ES2019/DOM/DOM.Iterable — dev's VirtualSelect 1.4
  code uses Array.flat (ES2019), which previously only compiled because the
  auto-included @types/node dragged newer libs in via reference directives;
  #1203's types:[] removed that accident, so the lib must be declared honestly
- tsconfig: refresh the types:[] comment (the TS 4.9 rationale is historical —
  the merge moved the repo to TS 5.9)

Verified: npm i, npm run build (exit 0, both platforms), build-storybook
(105 stories) on the synced tree.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
prebuild/predev still called build.tokens without the --utilities false
--root false flags from #1204, so CI and dev builds kept generating
_root.scss/_utilities.scss that nothing imports (no ScssStructure spec, no
partial, not the generated entry file — partials consume only _variables.scss).
Both hooks now delegate to build:tokens, making it the single source of truth
for the flags; tokens:update already did.

Verified with a fresh-clone simulation: wiped src/scss/tokens/, full build
regenerates only _variables.scss and exits 0; the compiled bundle is unaffected
(it never included the generated :root token layer — the only --token-*
declarations in it are source-authored: _theme-dark.scss overrides and rating).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Aug 11, 2026

Copy link
Copy Markdown

Quality Gate Passed Quality Gate passed

Issues
0 New issues
0 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code

See analysis details on SonarQube Cloud

@github-actions

Copy link
Copy Markdown

🖼️ Storybook: Chromatic UI tests result: ✅ Passed

Metric Value
Visual changes 0
Errors 0
Storybook Preview
Chromatic Build View Results

@BenOsodrac
BenOsodrac marked this pull request as ready for review August 11, 2026 16:07
@BenOsodrac
BenOsodrac requested a review from a team as a code owner August 11, 2026 16:07

@joselrio joselrio left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@BenOsodrac
BenOsodrac merged commit da42c19 into ROU-12714 Aug 12, 2026
16 of 17 checks passed
@BenOsodrac
BenOsodrac deleted the ROU-12955 branch August 12, 2026 09:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants