Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
71bcc8f
fix(form): export FieldErrorMessage from the package root
Sep 7, 2026
46def59
fix(color-wheel-flower): render standalone instead of crashing the page
Sep 7, 2026
e1b2edf
fix(icons): draw everything from one Iconify set
Sep 7, 2026
ec8375f
fix(pkg): give passwordRules a deep import path
Sep 8, 2026
f6382fb
test(qa): sweep components against the browser that ships
Sep 8, 2026
4496809
test(qa): refuse a driver too old to give the right answer
Sep 8, 2026
7b7084b
build: develop against the Solid the fleet actually runs
Sep 9, 2026
40acbe1
fix(button): stop rendering a neutral outline button invisible
Sep 9, 2026
a5965cb
fix(popover): give the dialog the name written on Popover.Dialog
Sep 9, 2026
e39bdcd
feat(icon): let a meaningful icon carry a name
Sep 9, 2026
0cfea24
feat(text): let a title be a heading
Sep 9, 2026
363ae3d
fix(card): stop putting a button inside a link
Sep 9, 2026
79c6054
fix(popover,drawer): let a trigger be the control it was given
Sep 9, 2026
689929f
test(dropdown): pin where an off-screen trigger puts its menu
Sep 9, 2026
a79d90c
fix(accordion,collapsible): take a closed panel out of the tab order
Sep 9, 2026
95a9cda
docs(toggles): say that a Switch, Radio or Checkbox has to be named
Sep 9, 2026
9cf4cfe
fix(live-chat): read a chat timestamp without Intl
Sep 9, 2026
3d5e905
fix(immersive-landing): stop a cookie category press closing the dialog
Sep 9, 2026
f9eed5b
fix(calendar): format dates from a table, not from Intl
Sep 9, 2026
06afaa3
fix(ui): preserve consumer layouts and validated form output
Sep 11, 2026
c5a9395
fix(calendar): update existing cells when selection changes
Sep 11, 2026
df0406b
docs: record verified recovery and coordinated release progress
Sep 11, 2026
bf685d8
docs(release): record final packed-candidate evidence
Sep 11, 2026
dcfe3e4
docs(release): record public-stack approval
Sep 11, 2026
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
79 changes: 23 additions & 56 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,52 +43,22 @@ jobs:
# the next corrective run rebuild the observability stack from zero.
cache-on-failure: true

# Track the current ps-qa release so UI coverage cannot silently remain
# on an obsolete harness — but build each tool against the dependency set
# it was published with.
# The host is the browser, and the browser is not a crate a site can
# install: `chuzz-headless` is built from source by the composite action
# below, which also installs the driver. That replaced `qa-inspect-host`,
# which was a second headless browser with the web platform in only the
# other one -- no `URLSearchParams`, no `matchMedia`, no storage, no
# observers -- so every gap closed for the browser had to be closed a
# second time there by hand, or the sweep measured a browser nobody
# ships.
#
# Resolving these fresh picks the newest `ps-blitz-*` that satisfies the
# requirements, and those crates are not compatible across minor versions:
# `qa-inspect-host` ended up compiled against `ps-blitz-script` 0.4.1
# while its `tauri-runtime-blitz` expected 0.3.x, so the same type
# existed twice and every call between them failed to typecheck. That
# broke this step, and because everything below depends on it, Lint, Type
# Check, Build and the whole test suite were skipped rather than failed —
# a green-looking pipeline that had verified nothing.
#
# `--locked` is gone, and it did cost currency: a lockfile is frozen at
# publication, so the host was pinned to whatever engine existed the day
# it was released. A renderer fix could then never reach this gate without
# a host release, and that is not hypothetical -- `ps-blitz` 0.4.3 fixes
# three defects in checkbox activation, and the host published before it
# kept installing 0.4.2, so `switch`, `checkbox` and `radio` went on
# failing here against an engine that had already been fixed.
#
# The mismatch `--locked` was added for is gone with it: it happened when
# `qa-inspect-host` wanted `ps-blitz` 0.4.x while its `tauri-runtime-blitz`
# wanted 0.3.x, so the same type existed twice. Both now require `^0.4`
# and resolve to one copy.
#
# One command per tool, deliberately. `cargo install a b --locked`
# resolves the two together and downgrades to satisfy both — it picks
# `qa-inspect-host` 0.1.4 instead of 0.1.8. Installed separately they
# each get their own resolution and stay current.
- name: Install native QA tools
env:
# cargo install otherwise builds in disposable temporary directories,
# which leaves rust-cache nothing useful to restore on the next run.
CARGO_TARGET_DIR: target/qa-tools
run: |
# Pinned to a floor, not left to "latest".
#
# The sweep needs `--headless` and a host that can replace a text
# field without a font catalogue. Installing whatever is newest meant
# a version without those failed as `unexpected argument`, which
# reads as a broken workflow rather than a tool that is too old --
# and a host that silently appended to a field would not have failed
# at all until a check disagreed about a value.
cargo install ps-qa --version "^0.6.2"
cargo install qa-inspect-host --version "^0.1.12"
# 0.1.12 is still on crates.io, so nothing broke when the crate was
# deleted from source; this is the last consumer to move off it.
- name: Headless browser host
id: qa
uses: pathscale/chuzz/.github/actions/headless-host@master
with:
token: ${{ secrets.SIBLING_REPOS_TOKEN }}

- name: Install Dependencies
run: bun install
Expand All @@ -110,23 +80,20 @@ jobs:
run: bun run build

# Native renderer outcomes replace jsdom interaction tests as the release
# gate. One headless host per component keeps the complete sweep below two
# minutes while preserving a clean document between components.
# gate. One headless host per component preserves a clean document.
- name: Rendered component outcomes
env:
# A shared runner takes longer than a local machine for outcomes that pass
# locally well inside the budget. This widens scheduling deadlines only; every
# declared rendered-state transition is still required.
QA_TIMEOUT_SCALE: 2
# This runner has no font catalogue, and it should not have one: a
# component library that needs a GUI stack installed to be tested is
# a component library nobody can test. With no fonts every glyph
# shapes to nothing, so anything sized by its text lays out flat and
# every paint assertion fails for a reason that says nothing about
# the component. The headless profile asks the same questions about
# layout instead; the full profile keeps the visual half and runs
# where there are fonts. See `PROFILES` in generate-checks.ts.
QA_PROFILE: headless
# The shared host action installs fonts without a desktop stack.
# Keep actual paint assertions in the release gate.
QA_PROFILE: full
# The harness looks for `chuzz-headless` on PATH; here it is the
# build the composite action above just made, so it is named
# outright.
QA_HOST: ${{ steps.qa.outputs.host }}
run: |
bun run qa:checks
bun run qa:entries
Expand Down
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ yarn add @pathscale/ui solid-layouts && yarn add -D rsbuild-plugin-solid-layouts

## Setup

`@pathscale/ui` 2.x is a compiled Layout bundle. Configure the application compiler before
`@pathscale/ui` 3.x is a compiled Layout bundle. Configure the application compiler before
Solid transforms JSX:

```ts
Expand Down Expand Up @@ -58,11 +58,22 @@ import "@pathscale/ui/index.css";

export const Example = () => (
<Flex direction="col" gap="sm">
<Button variant="primary" size="md">Primary</Button>
<Button variant="solid" flavor="primary" size="md">Primary</Button>
</Flex>
);
```

In the application's Tailwind v4 stylesheet, register the package as a source
(adjust the relative path from that stylesheet):

```css
@source "../node_modules/@pathscale/ui";
```

This includes the published `dist/responsive-classes.txt` scanner input. Grid and
Flex compose responsive classes at runtime, so scanning only the compiled JavaScript
misses utilities such as `md:grid-cols-3`.

## Theming

Two themes ship with the library: `light` (the default when no attribute is set) and `dark`.
Expand Down
26 changes: 25 additions & 1 deletion docs/api-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ invisible for a day behind a doc that looked correct the whole time.
When an API change is intentional, run `bun run check:api -- --write`, read the
diff, and commit it. The diff is the review.

186 components. An empty list means the component adds nothing beyond
187 components. An empty list means the component adds nothing beyond
HTML attributes and `UIBaseProps`; that is an assertion, not a gap.

---
Expand Down Expand Up @@ -226,6 +226,7 @@ _No props beyond HTML attributes and `UIBaseProps`._
### Calendar

```ts
dateNames?: DateNames
defaultValue?: Date
disabled?: boolean
isDateUnavailable?: (date: Date) => boolean
Expand Down Expand Up @@ -253,11 +254,14 @@ elevation?: CardElevation
flavor?: Flavor
footer?: JSX.Element
header?: JSX.Element
href?: string
isInteractive?: boolean
material?: Material
padding?: Space
radius?: Radius
rel?: string
state?: CardState
target?: JSX.AnchorHTMLAttributes<HTMLAnchorElement>["target"]
variant?: Variant
```

Expand Down Expand Up @@ -287,11 +291,14 @@ elevation?: CardElevation
flavor?: Flavor
footer?: JSX.Element
header?: JSX.Element
href?: string
isInteractive?: boolean
material?: Material
padding?: Space
radius?: Radius
rel?: string
state?: CardState
target?: JSX.AnchorHTMLAttributes<HTMLAnchorElement>["target"]
variant?: Variant
```

Expand Down Expand Up @@ -446,8 +453,12 @@ wheelClass?: string

```ts
class?: string
color?: ColorValue | string
defaultColor?: ColorValue | string
disabled?: boolean
id?: string
mode?: ColorWheelFlowerMode
onChange?: (color: ColorValue) => void
palette?: readonly string[]
```

Expand Down Expand Up @@ -645,6 +656,7 @@ _No props beyond HTML attributes and `UIBaseProps`._
### DatePicker

```ts
dateNames?: DateNames
defaultOpen?: boolean
defaultValue?: Date
disabled?: boolean
Expand All @@ -665,6 +677,7 @@ weekdayFormat?: CalendarWeekdayFormat
### DateRangePicker

```ts
dateNames?: DateNames
defaultOpen?: boolean
defaultValue?: DateRangeValue
disabled?: boolean
Expand Down Expand Up @@ -890,6 +903,7 @@ id?: string
### DrawerTrigger

```ts
as?: ValidComponent
children: JSX.Element
```

Expand All @@ -912,6 +926,12 @@ placement?: DropdownPlacement
children: JSX.Element
```

### FieldErrorMessage

```ts
message?: string
```

### FieldGroup

```ts
Expand All @@ -936,6 +956,7 @@ _No props beyond HTML attributes and `UIBaseProps`._

```ts
extensionUrl?: string
icon?: string | JSX.Element
onDismiss?: () => void
onInstall?: () => void
storageKey?: string
Expand Down Expand Up @@ -1051,6 +1072,7 @@ i18n: I18nStore
```ts
flavor?: Flavor
height?: number
label?: string
src?: string | JSX.Element
width?: number
```
Expand Down Expand Up @@ -1537,6 +1559,7 @@ variant?: RadioGroupVariant
### RangeCalendar

```ts
dateNames?: DateNames
defaultValue?: RangeCalendarValue
disabled?: boolean
isDateUnavailable?: (date: Date) => boolean
Expand Down Expand Up @@ -1729,6 +1752,7 @@ variant?: TabsVariant
### Text

```ts
as?: TextAs
children?: JSX.Element
family?: TextFamily
leading?: TextLeading
Expand Down
Loading
Loading