@furystack/shades-common-components
Version:
Common UI components for FuryStack Shades
1,013 lines (647 loc) β’ 70.9 kB
Markdown
# Changelog
## [17.0.2] - 2026-06-05
### π· CI
- Raised the minimum supported Node.js to `>=24.0.0` (Node 24 LTS) in `engines`, dropping Node 22.
### β¬οΈ Dependencies
- Bumped dev `vitest` to `^4.1.8`. No source changes β dev-tooling bump only.
## [17.0.1] - 2026-05-21
### π Documentation
- Rewrote JSDoc on `CacheView` to follow the new value-test guidance: dropped restate-the-type narration, kept intent / trade-offs / constraints, and added a usage example for the recommended cache-rendering pattern.
### β¬οΈ Dependencies
- Bump dev `vitest` to `^4.1.5`.
- Bumped `@furystack/cache` to its new major version. No call sites in this package used the removed `obsoleteRange` / `removeRange` APIs, so no source changes were required. See the `@furystack/cache` changelog for the migration if you import the cache directly alongside this package.
- Bumped `vitest` to `^4.1.7`. No source changes β dev-tooling bump only.
### π§ Chores
- Bumped to keep the `@furystack/cache` dependency in sync after the `getKey` option was added to `Cache`. No code changes.
### π Bug fixes
- `Checkbox` change events now propagate to the parent `<Form>`, so `rawFormData` updates when the checkbox is toggled. Previously the inner input called `ev.stopPropagation()`, which swallowed the event before it reached the form.
- `Radio` and `Switch` no longer fire `props.onchange` twice per change. The inner input no longer carries a duplicate `onchange={props.onchange}` β Shade's `attachProps` already wires the handler on the host element, and the bubbled change event triggers it once.
- `Checkbox` and `Switch` now preserve the browser's native `"on"` default when the `value` prop is omitted, so form submissions emit `{ [name]: "on" }` instead of `{ [name]: "" }`.
## [17.0.0] - 2026-04-25
### π₯ Breaking Changes
Common services are declassed and moved behind DI tokens. See the [v7 migration guide](../../docs/migrations/v7-functional-di.md) for rationale, recipes, and pitfalls.
- `ThemeProviderService` and `NotyService` declassed to plain-object factories. The `EventHub` surface is preserved via composition (`Object.assign(hub, { ...methods })`). Resolve via `injector.get(ThemeProviderService)` / `injector.get(NotyService)`.
- `LayoutService` is now a throw-by-default scoped token plus a `createLayoutService(targetElement?)` factory. `<PageLayout>` creates `injector.createScope({ owner: 'page-layout' })`, instantiates the service, and `scope.bind(LayoutService, () => instance)`. Descendants (`<Drawer>`, `<DrawerToggleButton>`) resolve the scoped token as before.
- `FormService` declassed. Added `FormContextToken: Token<FormService | null, 'scoped'>` (default `null`) to replace `injector.cachedSingletons.has(FormService)` probes. `<Form>` binds the token on its own scope; inputs that opt into form integration read it via `injector.get(FormContextToken)` and branch on `null`.
- `SuggestManager` and `CommandPaletteManager` dropped `@Injectable` but remain plain classes β they are `new`'d inside `useDisposable` hooks, never resolved from the injector.
## [16.0.0] - 2026-04-22
### π₯ Breaking Changes
### Removed the legacy `Grid` component
The deprecated `Grid` component (and its `GridProps`, `HeaderCells`, `RowCells` helpers) has been removed. `DataGrid` is the supported replacement and has been the recommended API for some time.
**Impact:** Any module still importing `Grid` / `GridProps` / `HeaderCells` / `RowCells` from `@furystack/shades-common-components` will fail to resolve.
**Migration:** Switch to `DataGrid` + `CollectionService`. The showcase app's `DataGrid` page demonstrates the wiring with sorting, selection and pagination.
### Removed the legacy `Autocomplete` input
The deprecated `Autocomplete` input wrapper has been removed in favor of `Suggest`, which offers the same suggestion dropdown UX with both sync (`suggestions` prop) and async (`getEntries`/`getSuggestionEntry`) data sources and proper keyboard navigation.
**Impact:** Any module still importing `Autocomplete` from `@furystack/shades-common-components` will fail to resolve.
**Migration:** Replace `<Autocomplete suggestions={...} inputProps={...} />` with `<Suggest defaultPrefix={...} suggestions={...} onSelectSuggestion={...} />`. Labels and helper text previously configured through `inputProps` should be composed around the `Suggest` element using the existing `Input` / label components.
### Removed deprecated `onRowClick` / `onRowDoubleClick` options on `CollectionService`
The `CollectionServiceOptions.onRowClick` and `CollectionServiceOptions.onRowDoubleClick` constructor fields have been removed. These callbacks were replaced by the EventHub-based `subscribe('onRowClick', ...)` / `subscribe('onRowDoubleClick', ...)` (or `addListener`) API, which supports multiple subscribers and matches the rest of the observable primitives in the package.
**Impact:** `new CollectionService({ onRowClick, onRowDoubleClick })` no longer wires the callbacks; the options type no longer accepts them.
**Migration:** Subscribe after construction: `const service = new CollectionService(); service.addListener('onRowClick', handler);` (or `service.subscribe('onRowClick', handler)` for dispose-on-return semantics).
### `AppBarLink` now uses `path` instead of `href`
`AppBarLink` re-exports the `NestedRouteLinkProps` shape from `@furystack/shades`, which was renamed from `href` to `path` to align with the rest of the routing APIs.
**Before:**
```tsx
<AppBarLink href="/dashboard">Dashboard</AppBarLink>
<AppBarLink href="/users/:id" params={{ id: '1' }}>User</AppBarLink>
```
**After:**
```tsx
<AppBarLink path="/dashboard">Dashboard</AppBarLink>
<AppBarLink path="/users/:id" params={{ id: '1' }}>User</AppBarLink>
```
**Impact:** All call sites of `AppBarLink` and `createAppBarLink` must be updated. `props.href` reads inside downstream wrappers are no longer valid.
**Migration:** Rename every `<AppBarLink href="..." />` occurrence to `<AppBarLink path="..." />`, including `routingOptions`-augmented usages.
### β»οΈ Refactoring
- `Breadcrumb` now forwards the compiled path to the underlying `NestedRouteLink` as `path` rather than `href`.
- Type bounds on `createAppBarLink` / `createBreadcrumb` / `TypedBreadcrumbProps` were widened from `NestedRoute<unknown>` to `NestedRoute<any, any, any>` so routes declaring the new `query` / `hash` schemas satisfy them.
## [15.2.0] - 2026-04-17
### β¨ Features
### Automatic reference reconciliation in `CollectionService` via `idField`
`CollectionServiceOptions` now accepts an optional `idField` that identifies a stable identity key on entries. When provided, `CollectionService` subscribes to its own `data` observable and automatically reconciles `focusedEntry` and `selection` against the new entries array whenever `data` changes, swapping stale object references for their matching counterparts by id.
This keeps keyboard navigation (arrow keys, selection toggles, select-all) and the currently focused/selected rows working correctly when the backing data array is rebuilt with new object instances (e.g. after a refetch), instead of silently breaking because the held references no longer exist in the new array.
**Usage:**
```typescript
import { CollectionService } from '@furystack/shades-common-components'
interface User {
id: string
name: string
}
const service = new CollectionService<User>({ idField: 'id' })
service.data.setValue({ count: users.length, entries: users })
service.focusedEntry.setValue(users[1])
// Later, after a refetch that returns new object instances with the same ids:
service.data.setValue({ count: refetched.length, entries: refetched })
// focusedEntry and selection now point at the matching entries in `refetched`
// instead of the stale objects from the previous data set.
```
Entries whose id is no longer present in the new data are dropped from `selection`, and `focusedEntry` is cleared if its id disappeared. The feature is opt-in: if `idField` is not set, the previous behavior is preserved unchanged.
### π§ͺ Tests
- Added unit tests for `CollectionService` `idField` reconciliation, covering `focusedEntry` and `selection` updates on data changes, removal of stale entries, no-op behavior when `idField` is absent, reference-equality short-circuit, and end-to-end keyboard navigation after a data refresh.
### β¬οΈ Dependencies
- Raised `path-to-regexp` to ^8.4.2 and dev `typescript` to ^6.0.3 and `vitest` to ^4.1.4.
## [15.1.0] - 2026-03-30
### β¨ Features
### Unified `ComponentSize` type
Added a shared `ComponentSize` type (`'small' | 'medium' | 'large'`) exported from the package. All components that support sizing now reference this single type instead of individual inline union types, ensuring consistency across the component library.
### `size` prop on form controls
The following form controls now accept a `size` prop for density control:
- **Input** β adjusts label padding, input font size, and icon size
- **Select** β adjusts label padding, trigger font size, and dropdown item sizing
- **InputNumber** β adjusts label padding, input font size, and stepper button dimensions
- **TextArea** β adjusts label padding and content font size
- **Checkbox** β adjusts control box dimensions (`16px` / `20px` / `24px`) and label font size
- **Radio** β adjusts control circle dimensions and label font size
All default to `'medium'` with no visual changes for existing consumers.
### `large` size added to Chip, Switch, and SegmentedControl
These components previously only supported `'small' | 'medium'`. They now also accept `'large'` for better alignment with other components in dense or spacious layouts.
### `RouteBreadcrumb` component
Added a reusable `RouteBreadcrumb` component that automatically derives breadcrumb items from the current `RouteMatchService` match chain. It resolves route titles (including async resolvers) from `meta.title` and accumulates path segments to produce correct links.
```tsx
<RouteBreadcrumb homeItem={{ path: '/', label: <Icon icon={icons.home} size="small" /> }} separator=" βΊ " />
```
### Horizontal Timeline orientation
The `Timeline` component now accepts an `orientation` prop (`'vertical' | 'horizontal'`). Horizontal mode supports all existing `mode` values (`'left'`, `'right'`, `'alternate'`) as well as the `pending` indicator, rendering items in a row with a horizontal connector line.
### β οΈ Breaking Changes
### `Input` component: native `size` attribute replaced
The `Input` component's `size` prop is now typed as `ComponentSize` (`'small' | 'medium' | 'large'`) instead of the native HTML `<input size>` number attribute (which controlled visible character width). Consumers who relied on the native `size` attribute should use CSS `width` instead.
### π§ͺ Tests
- Added `size` prop tests (`small`, `medium`, `large`, unset) for Checkbox, Radio, Switch, Input, InputNumber, TextArea, and Select
- Added `large` size test for Chip and SegmentedControl
- Added tests for the new `RouteBreadcrumb` component covering route resolution, async titles, `skipRootPath`, `homeItem`, `separator`, and observable-driven updates
## [15.0.4] - 2026-03-27
### β¬οΈ Dependencies
- Updated `@furystack/shades` dependency
## [15.0.3] - 2026-03-27
### β¬οΈ Dependencies
- Updated `@furystack/cache` with cache timer fixes
- Updated `@furystack/shades` dependency
## [15.0.2] - 2026-03-25
### π¦ Build
- Removed deprecated `baseUrl` from tsconfig.json for TypeScript 6 compatibility
### β¬οΈ Dependencies
- Upgraded `typescript` from ^5.9.3 to ^6.0.2
- Upgraded `vitest` from ^4.1.0 to ^4.1.1
## [15.0.1] - 2026-03-19
### β¨ Features
- Added `navSection` prop to `Accordion`, `DataGrid`, `List`, and `Tree` for spatialβnavigation scoping.
- Added `trapFocus` and `navSection` props to `Modal` and `Dialog`, plus focusable behaviour for `Chip` and `Image` when interactive.
- Introduced `focusOutline` theme variable and `injectFocusVisibleStyles()` helper; added focus coordination to DataGrid/List/Tree and semantics improvements across components.
### β¬οΈ Dependencies
- Upgraded `vite` from ^7.3.1 to ^8.0.0 for improved build performance and new features
- Upgraded `vitest` from ^4.0.18 to ^4.1.0
- Upgraded `@vitest/coverage-istanbul` from ^4.0.18 to ^4.1.0
### π₯ Breaking Changes
- Removed arrowβkey and Tab handlers from `ListService`/`CollectionService`/`TreeService`; spatial navigation now handles boundaries.
- `AccordionItem` header changed to a native `<button disabled>`; custom CSS selectors must be updated.
- Themes must supply a `focusOutline` value; various behavioural changes to keyboard handling detailed in package changelog.
## [15.0.0] - 2026-03-10
### β¨ Features
- Added `navSection` prop to `Accordion`, `DataGrid`, `List`, and `Tree` β sets a `data-nav-section` attribute so `SpatialNavigationService` constrains arrow-key navigation within the component (auto-generated per instance when not provided)
- Added `trapFocus` and `navSection` props to `Modal` β when `trapFocus` is true, spatial navigation is locked within the modal's bounds until it closes
- Added `trapFocus` (defaults to `true`) and `navSection` props to `Dialog` β forwarded to the underlying `Modal` component
- Made `Chip` focusable when clickable (including delete button) for spatial/keyboard navigation
- Made `Image` focusable when `preview={true}` and activatable with Enter/Space for spatial/keyboard navigation
- Added `focusOutline` to the `ActionColors` theme type and `cssVariableTheme` β provides a dedicated CSS variable (`--shades-theme-action-focus-outline`) for keyboard/spatial focus indicators
- Added `injectFocusVisibleStyles()` helper that injects global `:focus-visible` / `:focus:not(:focus-visible)` styles using the theme's `focusOutline` variable
- Added `focusOutline` values to all built-in themes
- Added focus coordination to `DataGrid`, `List`, and `Tree` β `focusin`/`focusout` DOM events now sync `hasFocus` and `focusedEntry`/`focusedItem` state, replacing previous click-based focus management
- Added `data-nav-section="content"` to `PageLayout` main content area for spatial navigation scoping
- Added `:focus-visible` styles to `MarkdownDisplay` code blocks and links using the theme's `focusOutline` variable
- Made `MarkdownDisplay` code blocks focusable (`tabIndex={0}`) for keyboard navigation
### π₯ Breaking Changes
- Removed `ArrowUp`/`ArrowDown` handlers from `ListService` β arrow-key navigation is now fully delegated to `SpatialNavigationService`
- Changed `ArrowUp`/`ArrowDown` handlers in `CollectionService` β they no longer unconditionally `preventDefault()`, only intercepting when there is a valid adjacent entry to move to, allowing `SpatialNavigationService` to handle boundary navigation
- Removed `Tab` handler from `CollectionService` and `ListService` β focus management now uses native `focusin`/`focusout`
- `TreeService` `ArrowRight` on an expanded node no longer focuses the first child β delegated to spatial navigation
- `ActionColors` type now requires a `focusOutline` property β all custom themes must include this value
- `CommandPalette` and `Suggest` keyboard handling changed from `onkeyup` to `onkeydown` β arrow key navigation within the suggestion list now only activates when suggestions are open
- Scroll-to-focused-item behavior changed from `smooth` to `instant` in `List`, `DataGrid`, and `Tree` β keyboard navigation no longer animates scrolling
- `AccordionItem` header changed from `<div role="button" data-disabled>` to a native `<button disabled>` β consumers with CSS targeting `.accordion-header[data-disabled]` must update to `.accordion-header:disabled` or the host's `[data-disabled]`
**Custom themes** must add `focusOutline` to the `action` object:
hoverBackground: '...',
focusRing: '0 0 0 3px ...',
hoverBackground: '...',
focusRing: '0 0 0 3px ...',
focusOutline: '2px solid #3f51b5', // your theme's accent color
**ArrowUp/ArrowDown/Tab removal from CollectionService, ListService, and TreeService:**
**CommandPalette and Suggest `onkeyup` β `onkeydown`/`oninput`:**
### π Bug Fixes
- Added `outline: 'none'` to `AccordionItem`, `Checkbox`, `Radio`, `Slider`, and `Switch` `:focus-visible` styles to prevent double focus rings when using the global `focusOutline`
### π§ͺ Tests
- Added tests for `DataGrid` focus coordination and `navSection` attribute
- Added tests for `List` focus coordination behavior
- Added tests for `Modal` `trapFocus` and `navSection` behavior
- Updated `CollectionService`, `ListService`, and `TreeService` tests to verify arrow keys are no longer handled
### β¬οΈ Dependencies
- Updated `@furystack/core` dependency to the new major version
## [14.0.0] - 2026-03-07
### β¬οΈ Dependencies
- Updated internal FuryStack dependencies
- Updated `@furystack/shades` dependency
### π₯ Breaking Changes
### `shadowDomName` renamed to `customElementName`
All components now use `customElementName` instead of `shadowDomName`, following the upstream `@furystack/shades` rename.
### `CircularProgress` and `LinearProgress` `value` prop changed from `ObservableValue<number>` to `number`
The `value` prop on `CircularProgress` and `LinearProgress` no longer accepts an `ObservableValue<number>`. Pass a plain `number` instead and use `useObservable` at the call site to reactively update the value.
**Examples:**
```typescript
// β Before
<CircularProgress value={progressObservable} variant="determinate" />
// β
After
const [progress] = useObservable('progress', progressObservable)
<CircularProgress value={progress} variant="determinate" />
```
### `DataGrid`, `DataGridHeader`, `DataGridFooter`, and filter components: `findOptions` changed from `ObservableValue` to plain value with `onFindOptionsChange` callback
The `findOptions` prop on `DataGrid`, `DataGridHeader`, `DataGridFooter`, `OrderButton`, and all filter components (`StringFilter`, `NumberFilter`, `BooleanFilter`, `DateFilter`, `EnumFilter`) no longer accepts an `ObservableValue<FindOptions>`. Pass a plain `FindOptions` object along with a new `onFindOptionsChange` callback to handle state updates.
**Examples:**
```typescript
// β Before
const findOptions = new ObservableValue({ top: 10, skip: 0 })
<DataGrid findOptions={findOptions} ... />
// β
After
const [findOptions, setFindOptions] = useObservable('findOptions', findOptionsObservable)
<DataGrid
findOptions={findOptions}
onFindOptionsChange={setFindOptions}
...
/>
```
**Impact:** All consumers of `DataGrid` and its sub-components must be updated to provide `findOptions` as a plain object and supply the `onFindOptionsChange` callback.
### π Documentation
- Updated README examples to use `customElementName` and the new `onFindOptionsChange` pattern
### π§ͺ Tests
- Updated all component tests to use `customElementName` and the new prop signatures
## [13.5.0] - 2026-03-06
### β¨ Features
### Contained mode for `PageLayout`
Added a `contained` prop to `PageLayout` that uses `position: absolute` instead of `position: fixed`, allowing the layout to fill its nearest positioned ancestor rather than the viewport. This enables nesting multiple `PageLayout` instances on the same page (e.g. in a showcase grid or dashboard).
**Usage:**
```tsx
<div style={{ position: 'relative', height: '400px' }}>
<PageLayout contained appBar={{ variant: 'permanent', component: <MyAppBar /> }}>
<div>Scoped content</div>
</PageLayout>
</div>
```
### β»οΈ Refactoring
- Scoped `PageLayout` internal CSS selectors to direct children (`> * >`) to prevent styles from bleeding into nested `PageLayout` instances
- `PageContainer` now uses theme spacing tokens (`cssVariableTheme.spacing.md`) for default `padding` and `gap` instead of hardcoded pixel values
### π§ͺ Tests
- Added unit tests for `PageLayout` contained mode covering data attribute binding, absolute positioning, drawer toggle, and backdrop click behavior
## [13.4.1] - 2026-03-06
### π Bug Fixes
- Fixed duplicated content on re-render in `Alert` and `Result` components caused by reusing module-level JSX element constants across renders. Default icons are now created via factory functions (`getDefaultIcon()`) that return fresh elements per render call.
- Updated `Result` exports: renamed `resultDefaultIcons` to `resultGetDefaultIcon` (factory function) and added `resultDefaultIconDefs` (icon definition map)
### π§ͺ Tests
- Refactored `CacheView` tests to use `using()` / `usingAsync()` wrappers for `Cache` disposal, ensuring proper cleanup even if assertions fail
### π§ Chores
- Added `eslint-disable` comments for intentional `no-css-state-hooks` usage in `Input` (focused state) and `Select` (isFocused state) components where CSS state management via `useState` is the intended pattern
## [13.4.0] - 2026-03-05
### β¨ Features
- Added `viewTransition` prop to `Tabs` β animates tab panel switches via the View Transition API when the active tab changes
- Added `viewTransition` prop to `Wizard` β animates step transitions (next/prev) via the View Transition API
- Added `viewTransition` prop to `CacheView` β animates state category changes (loading β value, value β error, etc.) via the View Transition API
### π§ͺ Tests
- Added tests for `Tabs` verifying `startViewTransition` is called on tab switch when enabled and skipped when not set
- Added tests for `Wizard` verifying `startViewTransition` is called on next/prev navigation when enabled and skipped when not set
- Added tests for `CacheView` verifying `startViewTransition` is called on state category changes when enabled and skipped when not set
### β¬οΈ Dependencies
- Updated `@furystack/shades` peer dependency
## [13.3.1] - 2026-03-04
### β¬οΈ Dependencies
- Updated `@furystack/shades` dependency with nested router metadata support
### π§ͺ Tests
- Added regression test for the Drawer component verifying that ghost renders during disposal do not re-add cleared drawer state to `LayoutService`
## [13.3.0] - 2026-03-03
### ποΈ Deprecated
- `CollectionServiceOptions.onRowClick` β use `subscribe('onRowClick', ...)` on the `CollectionService` instance instead
- `CollectionServiceOptions.onRowDoubleClick` β use `subscribe('onRowDoubleClick', ...)` on the `CollectionService` instance instead
### β»οΈ Refactoring
- `CollectionService` now extends `EventHub` and routes row click/double-click through `onRowClick` and `onRowDoubleClick` events, enabling multiple subscribers
### π§ͺ Tests
- Added tests for `onRowClick` and `onRowDoubleClick` event emission
### β¬οΈ Dependencies
- Updated `@furystack/shades` with transitive dependency fixes
## [13.2.0] - 2026-02-28
### β¨ Features
- `useThemeCssVariables()` and `ThemeProviderService.setAssignedTheme()` now accept an optional `root` parameter to scope CSS variables to a specific element instead of `:root`
### π₯ Theme Type Changes
Several previously optional fields on the `Theme` type are now **required**. Any code that creates a `Theme` object and omits these fields will need to provide explicit values:
| Type | Field | Default value to use |
| ----------------- | --------------- | --------------------- |
| `Background` | `paperImage` | `'none'` |
| `Shape` | `borderWidth` | `'0px'` |
| `ThemeTypography` | `letterSpacing` | _(full scale object)_ |
| `ThemeTypography` | `textShadow` | `'none'` |
| `Theme` | `zIndex` | _(full object)_ |
| `Theme` | `effects` | _(full object)_ |
> **Note:** Most consumer code uses `DeepPartial<Theme>` (e.g. `setAssignedTheme()`) and is **not affected**.
> Only code that implements the full `Theme` interface directly needs to be updated.
### π Bug Fixes
- Fixed stale drawer state persisting in `LayoutService` after a `Drawer` component is unmounted, which could cause incorrect content margins when navigating between views
- Added `removeDrawer()` method to `LayoutService` to clean up drawer configuration and reset associated CSS variables
- Fixed `AppBar` `backdrop-filter` creating a CSS containing block that broke `position:fixed` descendants (e.g. `Dropdown` overlays); moved the effect to a `::before` pseudo-element
### β»οΈ Refactoring
- Simplified `CommandPaletteInput` by removing width animation; component is now always full-width with focus/clear on open/close
- Changed `Avatar` fallback icon to use percentage-based sizing with an inline SVG instead of the `Icon` component for better scaling at different sizes
### π§ͺ Tests
- Added tests for `removeDrawer()` covering left/right removal, isolation between drawers, no-op on missing drawer, and CSS variable reset
- Added test for `initDrawer()` overwriting an existing drawer configuration
- Added integration tests for `Drawer` component disposal cleanup
## [13.1.0] - 2026-02-28
### β¨ Features
### `contentProps` support for `CacheView`
`CacheView` now accepts a `contentProps` prop to forward additional type-safe props to the content component beyond `data`. The `CacheViewProps` type gained a third generic parameter `TContentProps` that constrains the content component's full props shape. When the content component requires extra props (excluding `data` and HTML element attributes), `contentProps` becomes required; otherwise it can be omitted.
**Usage:**
```tsx
const MyContent = Shade<{ data: CacheWithValue<User>; label: string }>({
shadowDomName: 'my-content',
render: ({ props }) => <div>{props.label}: {props.data.value.name}</div>,
})
<CacheView
cache={userCache}
args={[userId]}
content={MyContent}
contentProps={{ label: 'User' }}
/>
```
### π§ͺ Tests
- Added tests for `contentProps` forwarding to the content component
## [13.0.1] - 2026-02-26
### β¬οΈ Dependencies
- Updated internal `@furystack/*` dependencies
- Bumped due to updated workspace dependencies
## [13.0.0] - 2026-02-26
### π₯ Breaking Changes
### `getTextColor()` and `getRgbFromColorString()` removed from `ThemeProviderService`
The `getTextColor()` and `getRgbFromColorString()` instance methods have been removed from `ThemeProviderService`. They are now standalone functions exported from their own modules.
**Examples:**
```typescript
// β Before
import { ThemeProviderService } from '@furystack/shades-common-components'
const themeProvider = injector.getInstance(ThemeProviderService)
const textColor = themeProvider.getTextColor('#ff0000')
const rgb = themeProvider.getRgbFromColorString('#3f51b5')
// β
After
import { getTextColor, getRgbFromColorString } from '@furystack/shades-common-components'
const textColor = getTextColor('#ff0000')
const rgb = getRgbFromColorString('#3f51b5')
```
**Impact:** All callers that accessed these methods via a `ThemeProviderService` instance must switch to the standalone function imports.
### `RgbColor` class moved to its own module
The `RgbColor` class is no longer exported from `theme-provider-service.ts`. It is now in its own `rgb-color.ts` module, re-exported through the package barrel.
If you imported `RgbColor` from the package entry point, no change is needed. If you imported directly from `theme-provider-service.js`, update the import path:
```typescript
// β Before
import { RgbColor } from '@furystack/shades-common-components/services/theme-provider-service.js'
// β
After
import { RgbColor } from '@furystack/shades-common-components'
// or
import { RgbColor } from '@furystack/shades-common-components/services/rgb-color.js'
```
### β¨ Features
### Standalone Color Utilities
Extracted `getRgbFromColorString()` and `getTextColor()` as standalone pure functions, making them usable without a `ThemeProviderService` instance. The new `getRgbFromColorString()` also adds support for `rgb()` syntax and common CSS named colors (e.g. `red`, `dodgerblue`, `white`), in addition to the previously supported `#hex` and `rgba()` formats.
### 17 New Themes
Added a collection of pop-culture-inspired themes, each with its own color palette and visual style:
- `architectTheme` - Matrix-inspired with digital green on black, monospace typography, and a digital rain paper background
- `auditoreTheme` - Assassin's Creed-inspired with warm historical tones
- `blackMesaTheme` - Half-Life-inspired with HEV-suit Lambda orange on dark industrial backgrounds and hazard-stripe textures
- `chieftainTheme` - Warcraft 1 Orc-inspired with dark brown wood backgrounds and crimson accents
- `dragonbornTheme` - Skyrim-inspired with nordic fantasy colors
- `hawkinsTheme` - Stranger Things-inspired with warm dark backgrounds, CRT scanline pattern, Christmas-light red accents, and retro rounded typography
- `jediTheme` - Star Wars Jedi Order-inspired light theme with warm parchment backgrounds and lightsaber-blue accents
- `neonRunnerTheme` - Cyberpunk-inspired with neon accents on dark backgrounds
- `paladinTheme` - Warcraft 1 Human-inspired with cold stone backgrounds and gold accents
- `plumberTheme` - Mario-inspired with playful primary colors
- `replicantTheme` - Blade Runner-inspired with noir cyberpunk aesthetics
- `sandwormTheme` - Dune-inspired with desert earth tones
- `shadowBrokerTheme` - Mass Effect-inspired with sci-fi blue tones
- `sithTheme` - Star Wars Sith Order-inspired dark theme with near-black backgrounds, crimson accents, and bold angular typography
- `vaultDwellerTheme` - Fallout-inspired with retro-futuristic styling
- `wildHuntTheme` - Witcher 3-inspired with silver-steel accents and crimson highlights on dark stormy backgrounds
- `xenomorphTheme` - Alien franchise-inspired with cold metallic backgrounds, acid green accents, and condensed monospace typography
Each theme provides a full set of semantic palette colors (`primary`, `secondary`, `error`, `warning`, `success`, `info`) with `light`, `main`, `dark` variants and contrast colors.
### Theme Infrastructure Enhancements
- Added `paperImage` to `Background` type and CSS variable theme, allowing themes to define textured or patterned paper surfaces via `background-image`
- Added `borderWidth` to `Shape` type and CSS variable theme, enabling themes to control surface border thickness
### Semantic Typography
Refactored the `Typography` component to render semantic HTML elements (`h1`β`h6`, `p`, `span`) based on the `variant` prop instead of always rendering a generic `shade-typography` custom element. Ellipsis handling and copy functionality now apply directly to the host element, removing the need for an internal wrapper.
**Breaking:** The `<shade-typography>` custom element tag no longer exists. Typography now renders as native tags with an `is` attribute (e.g. `<p is="shade-typography-p">`). Update any CSS or JS selectors targeting `shade-typography` to use `[is^="shade-typography"]` instead.
### π Bug Fixes
- Fixed `Timeline` vertical alignment issues by replacing hardcoded pixel values with theme spacing tokens and adding consistent `lineHeight` to labels and content
- Fixed `Timeline` last-item detection to correctly exclude pending items when determining the final visible entry
- Fixed `Timeline` tail visibility on the last item by using `:last-of-type` CSS instead of a `data-last` attribute
### β»οΈ Refactoring
- Moved default theme files (`default-dark-palette.ts`, `default-dark-theme.ts`, `default-light-theme.ts`, `default-palette.ts`) from `services/` to a dedicated `themes/` directory
- Updated `Dialog`, `Result`, `PageHeader`, `Paper`, and `Card` components to use `Typography` instead of raw HTML heading/paragraph tags
- Updated `Paper` and `Card` components to support the new `paperImage` and `borderWidth` theme properties
- Added `fontFamily` from the theme to `Dialog`, `Paper`, `Card`, and `PageHeader` components for consistent font rendering across themes
### π§ͺ Tests
- Updated `Typography` tests to assert on semantic HTML tags (`p`, `h1`, `h6`, `span`) instead of inner wrapper elements
- Updated `PageHeader`, `Result`, `CacheView`, `AppBar`, and `NotyList` tests for compatibility with the new `Typography`-based rendering
- Added tests for the new `getRgbFromColorString()`, `getTextColor()`, and `RgbColor` standalone modules
### π Migration Guide
### Step 1: Replace `ThemeProviderService` color method calls
Search for usages of `getTextColor` and `getRgbFromColorString` on a `ThemeProviderService` instance:
```bash
grep -rn "getTextColor\|getRgbFromColorString" --include="*.ts" --include="*.tsx" src/
```
Replace instance method calls with standalone function imports:
```typescript
// β Before
const themeProvider = injector.getInstance(ThemeProviderService)
const color = themeProvider.getTextColor(bgColor)
const rgb = themeProvider.getRgbFromColorString(cssColor)
// β
After
import { getTextColor, getRgbFromColorString } from '@furystack/shades-common-components'
const color = getTextColor(bgColor)
const rgb = getRgbFromColorString(cssColor)
```
### Step 2: Update `RgbColor` imports (if using deep imports)
If you were importing `RgbColor` directly from the `theme-provider-service` module path, update to:
```typescript
import { RgbColor } from '@furystack/shades-common-components'
```
### Step 3: Update `Typography` selectors
If you have CSS or JS selectors targeting `shade-typography`, update them:
```css
/* β Before */
shade-typography { ... }
/* β
After */
[is^="shade-typography"] { ... }
```
### Step 4: Verify
```bash
yarn build
yarn test
```
## [12.7.0] - 2026-02-23
### β¨ Features
### MarkdownEditor Form Integration
`MarkdownEditor` now accepts form-related props forwarded from `MarkdownInputProps`, enabling direct use inside forms with validation and labeling support.
**New props:** `name`, `required`, `labelTitle`, `disabled`, `placeholder`, `rows`, `getValidationResult`, `getHelperText`
**Usage:**
```tsx
<MarkdownEditor
value={description}
onValueChange={setDescription}
labelTitle="Description"
name="description"
required
getValidationResult={({ value }) =>
value.length < 10 ? { isValid: false, message: 'Must be at least 10 characters' } : { isValid: true }
}
/>
```
The editor renders a label above the editing area, displays validation errors and helper text below it, and sets a `data-invalid` attribute on the host element when validation fails β allowing external styling of the invalid state.
### MarkdownInput `hideChrome` Prop
- Added `hideChrome` prop to `MarkdownInput` β when `true`, suppresses the label and helper text rendering while preserving form semantics (textarea `name`, `required`, etc.). This is used internally by `MarkdownEditor` to avoid duplicate chrome when it manages its own label and validation display.
## [12.6.0] - 2026-02-22
### ποΈ Deprecated
- `Grid` component is deprecated in favor of `DataGrid`. It will be removed in a future version.
- `Autocomplete` component is deprecated in favor of `Suggest` with the `suggestions` prop. It will be removed in a future version.
### β¨ Features
### Pagination support for `List` component
The `List` component now accepts an optional `pagination` prop to slice items into pages and render a `Pagination` control below the list.
**Usage:**
```typescript
<List
items={allItems}
listService={service}
renderItem={(item) => <span>{item.name}</span>}
pagination={{ itemsPerPage: 10, page: currentPage, onPageChange: setCurrentPage }}
/>
```
### Synchronous suggestions mode for `Suggest`
`Suggest` now supports a synchronous `suggestions` prop accepting a `string[]`, in addition to the existing async `getEntries` / `getSuggestionEntry` mode. The list is filtered client-side by the search term.
**Usage:**
```typescript
<Suggest
defaultPrefix="π"
suggestions={['Apple', 'Banana', 'Cherry']}
onSelectSuggestion={(entry) => console.log(entry)}
/>
```
### `Wizard` step indicator and progress bar
The `Wizard` component now supports a `stepLabels` prop to render a visual step indicator with numbered circles and labels, and a `showProgress` prop to display a progress bar that advances as the user navigates through steps.
### `MarkdownInput` form integration
`MarkdownInput` now supports `name`, `required`, `getValidationResult`, and `getHelperText` props, enabling validation and `FormService` integration. Invalid states are reflected via a `data-invalid` attribute with error styling.
### Customizable `DataGrid` pagination options
- Added a `paginationOptions` prop to `DataGrid` to customize the rows-per-page selector values. When only one option is provided, the selector is hidden.
- Made the `styles` prop optional on `DataGrid`
### β»οΈ Refactoring
- `DataGridFooter` now uses the `Pagination` component instead of a `<select>` element for page navigation
### π§ͺ Tests
- Added pagination tests for the `List` component (page slicing, `Pagination` rendering, `onPageChange` callback)
- Added form integration and validation tests for `MarkdownInput` (`name`, `required`, `getValidationResult`, `getHelperText`)
- Added synchronous suggestions mode tests for `Suggest`
- Added step indicator and progress bar tests for `Wizard`
- Added custom `paginationOptions` tests for `DataGridFooter`
## [12.5.0] - 2026-02-22
### β¨ Features
### Typed Column Filters for DataGrid
Added a new filter system for `DataGrid` with dedicated filter components for each data type, replacing the previous inline regex-only search form.
New `columnFilters` prop on `DataGrid` allows declarative filter configuration per column:
```typescript
<DataGrid
columns={['name', 'level', 'isActive', 'role', 'createdAt']}
columnFilters={{
name: { type: 'string' },
level: { type: 'number' },
isActive: { type: 'boolean' },
role: { type: 'enum', values: [{ label: 'Admin', value: 'admin' }, { label: 'User', value: 'user' }] },
createdAt: { type: 'date' },
}}
// ...other props
/>
```
**Available filter types:**
- `StringFilter` - supports contains, starts with, ends with, and exact match operators
- `NumberFilter` - supports `=`, `>`, `>=`, `<`, `<=` comparison operators
- `BooleanFilter` - toggle between true, false, or any using a `SegmentedControl`
- `EnumFilter` - multi-select checkboxes with include/exclude modes
- `DateFilter` - before, after, or between with datetime-local inputs
All filter components are exported from `@furystack/shades-common-components` via the `filters/` barrel.
- Added `FilterDropdown` component for positioning filter panels as dropdown overlays in the grid header
- `headerComponents` and `rowComponents` props on `DataGrid` are now optional
- `ToggleButton` now accepts `pressed` and `size` props for standalone use outside a `ToggleButtonGroup`
- `ToggleButtonGroup` now accepts a `size` prop that propagates to child buttons
### β»οΈ Refactoring
- Grid header height reduced from 48px to 36px with smaller font and tighter spacing for a more compact look
- Footer pager labels changed from "Goto page" / "Show X items per page" to "Page X of Y" / "Rows per page"
- `ToggleButton` no longer renders a box-shadow by default; the border is only applied when inside a `ToggleButtonGroup` (via `data-grouped` attribute)
### β οΈ Migration
- Column filter buttons are now **opt-in** via the `columnFilters` prop. Previously, every column showed a regex search button by default. To restore filtering, add a `columnFilters` config mapping for the columns you want to be filterable.
### π§ͺ Tests
- Added unit tests for `ToggleButton` standalone `pressed` and `size` props
- Added unit tests for `ToggleButtonGroup` `size` propagation to child buttons
- Updated `DataGridHeader` tests to cover filter button visibility, filter type routing for all five filter types, and dropdown opening
- Updated `DataGridFooter` tests to match new pager label text
## [12.4.0] - 2026-02-22
### β¨ Features
### Async form submission support
The `Form` component's `onSubmit` callback now accepts async functions (`() => void | Promise<void>`). New observables on `FormService`: `isSubmitting` tracks whether a submission is in progress, and `submitError` captures any error thrown during submission. When the `disableOnSubmit` prop is enabled, the form element becomes inert during submission, preventing duplicate submits.
**Usage:**
```typescript
<Form
validate={myValidator}
onSubmit={async (data) => {
await saveToServer(data)
}}
disableOnSubmit
>
{/* form fields */}
</Form>
```
### β»οΈ Refactoring
- Changed the `validate` prop type from `any` to `unknown` for stricter type safety
### π§ͺ Tests
- Added tests for async `onSubmit` behavior, `isSubmitting` state tracking, `disableOnSubmit` inert toggling, and error handling during async submission
## [12.3.0] - 2026-02-19
### β¨ Features
### Markdown Components
A new set of zero-dependency Markdown components for rendering and editing Markdown content.
**`parseMarkdown(source)`** β Converts a Markdown string into a typed AST. Supports headings, paragraphs, ordered/unordered lists, task-list checkboxes, fenced code blocks with language hints, blockquotes, horizontal rules, and inline formatting (bold, italic, inline code, links, images).
**`toggleCheckbox(source, lineIndex)`** β Toggles a checkbox at the given source line index in a raw Markdown string, returning the updated string.
**`MarkdownDisplay`** β Renders a Markdown string as styled HTML using FuryStack Shades components. When `readOnly` is set to `false`, task-list checkboxes become interactive and report changes via an `onChange` callback.
**`MarkdownInput`** β A textarea for editing raw Markdown. Supports pasting images from the clipboard, which are inlined as base64-encoded `` Markdown images (configurable size limit, defaults to 256 KB).
**`MarkdownEditor`** β A combined editor with an input pane and a live preview pane. Supports three layout modes: `side-by-side`, `tabs` (Edit / Preview), and `above-below`. Checkboxes toggled in the preview pane update the source text.
### π§ͺ Tests
- Added unit tests for `parseMarkdown` and `parseInline` covering headings, paragraphs, lists, checkboxes, code blocks, blockquotes, horizontal rules, and inline formatting
- Added unit tests for `toggleCheckbox` verifying checked/unchecked toggling and out-of-bounds handling
- Added unit tests for `MarkdownDisplay` rendering and interactive checkbox toggling
- Added unit tests for `MarkdownEditor` layout switching between side-by-side, tabs, and above-below modes
- Added unit tests for `MarkdownInput` text input and image paste behavior
## [12.2.0] - 2026-02-19
### β¬οΈ Dependencies
- Updated `@furystack/shades`
### β¨ Features
### Icon metadata for descriptions, categories, and search keywords
Extended the `IconDefinition` type with optional `name`, `description`, `keywords`, and `category` fields. All existing icons now include this metadata, enabling icon galleries to automatically group icons by category and support keyword-based search.
### 41 new icons
Added 41 new icon definitions covering areas such as communication (`envelope`, `messageCircle`), media (`music`, `film`, `image`, `images`), data visualization (`barChart`), development (`code`, `gamepad`, `puzzle`), and navigation (`arrowLeft`, `arrowRight`, `compass`). The icon set grew from 69 to 110 icons.
## [12.1.0] - 2026-02-11
### β¨ Features
### New `CacheView` component
Added a new `CacheView` component that renders the state of a cache entry. It subscribes to a `Cache` instance observable and handles all states automatically:
1. **Error first** β shows error UI with a retry button
2. **Value next** β renders the content component (triggers reload when obsolete)
3. **Loading last** β shows a custom loader or nothing by default
```tsx
import { CacheView } from '@furystack/shades-common-components'
<CacheView cache={userCache} args={[userId]} content={UserContent} />
// With custom loader and error UI
<CacheView
cache={userCache}
args={[userId]}
content={UserContent}
loader={<Skeleton />}
error={(err, retry) => (
<Alert severity="error">
<Button onclick={retry}>Retry</Button>
</Alert>
)}
/>
```
### π Bug Fixes
- Fixed `Skeleton` component background styles not rendering correctly when used inside Shadow DOM β moved gradient styles from host CSS to inline styles on the inner element
### π Documentation
- Added `CacheView` usage examples to the package README
### β¬οΈ Dependencies
- Added `@furystack/cache` (workspace:^) as a new dependency
## [12.0.1] - 2026-02-11
### π§ͺ Tests
- Wrapped all disposable resources in `using()` / `usingAsync()` across command palette, context menu, data grid, click-away service, list service, and tree service tests to ensure cleanup runs even when assertions fail
### β¬οΈ Dependencies
- Bump `vitest` from `^4.0.17` to `^4.0.18`
- Updated `@furystack/shades` dependency
- Removed `semaphore-async-await` dependency
- Updated `@furystack/shades` with fix for `useState` setter disposal error
## [12.0.0] - 2026-02-09
### π₯ Breaking Changes
### `Theme` interface extended with 6 new required properties
The `Theme` interface now requires the following additional properties: `action`, `shape`, `shadows`, `typography`, `transitions`, and `spacing`. Any custom theme objects must be updated to include these new token groups. See `defaultDarkTheme` and `defaultLightTheme` for reference implementations.
### Requires `@furystack/shades` v3
This package now depends on the new major version of `@furystack/shades` which removed the `constructed` callback. All components have been migrated to use `useDisposable()` inside `render` for one-time setup and cleanup.
### Migrated All Components from `element` to `useHostProps` and `useRef`
All components in this package have been updated to use the new declarative `useHostProps` and `useRef` APIs from `@furystack/shades`, replacing direct imperative DOM manipulation via the removed `element` parameter.
**Impact:** Components no longer accept or use the `element` render option. Any custom components that extended or wrapped these components and relied on `element` access patterns need to be updated.
**Migration:** The component API and behavior remain the same from a consumer perspective β this is a breaking change only due to the peer dependency bump on `@furystack/shades`.
- `AppBarLink` props changed from `RouteLinkProps` to `NestedRouteLinkProps` β `href` is now required and the rendered shadow DOM element changed from `route-link` to `nested-route-link`
### β¨ Features
### Component Pack 1 β 15 new UI components
Added a full set of general-purpose UI components, all themed via CSS variable tokens, with ARIA attributes, keyboard navigation, and `FormService` integration where applicable:
**Data Display:**
- `Accordion` / `AccordionItem` β Collapsible content sections with animated expand/collapse, keyboard support, and `outlined` / `elevation` variants
- `Badge` β Count or status-dot overlay with configurable `max`, palette colors, and show/hide animation
- `Chip` β Compact tag/label element with `filled` / `outlined` variants, optional delete button, and size options
- `Tooltip` β Contextual hover/focus popup with four placement options, configurable delay, and arrow indicator
**Feedback:**
- `Alert` β Severity-coded message banner (`error` / `warning` / `info` / `success`) with `filled`, `outlined`, and `standard` variants and an optional close button
- `CircularProgress` β SVG-based circular indicator with `determinate` and `indeterminate` variants, customisable size and thickness
- `LinearProgress` β Horizontal progress bar with `determinate` and `indeterminate` variants and size options
**Surfaces:**
- `Card` β Content surface with `CardHeader`, `CardContent`, `CardMedia`, and `CardActions` sub-components, elevation levels 0β3, and an outlined variant
- `Dialog` β Modal dialog with title, body, and action slots, backdrop overlay, show/hide animation, and a `ConfirmDialog` helper function
**Layout:**
- `Divider` β Visual separator with horizontal/vertical orientation, `full` / `inset` / `middle` variants, and optional inline text content
- `Pagination` β Page navigator with ellipsis, configurable sibling/boundary counts, prev/next buttons, and size/color variants
**Inputs:**
- `Checkbox` β Checkbox with label, indeterminate state, palette colors, and `FormService` integration
- `Radio` / `RadioGroup` β Radio buttons with a group container supporting controlled and uncontrolled modes, orientation options, and shared palette color
- `Select` β Custom dropdown with full keyboard navigation (Arrow, Enter, Escape, Home, End), validation and helper-text support, and `contained` / `outlined` variants
- `Switch` β Animated toggle switch with `small` / `medium` sizes and palette color support
### New design token groups on the `Theme` interface
Extended the theme system with six new token groups, enabling centralised control over interactive states, shape, elevation, typography, motion, and spacing:
- `action` β Interactive state colors (`hoverBackground`, `selectedBackground`, `activeBackground`, `focusRing`, `disabledOpacity`, `backdrop`, `subtleBorder`)
- `shape` β Border radius scale (`xs` through `full`) for consistent rounded corners
- `shadows` β Elevation presets (`none`, `sm`, `md`, `lg`, `xl`) for layered depth
- `typography` β Font family, size scale, weight scale, and line height scale
- `transitions` β Duration presets (`fast`, `normal`, `slow`) and easing functions (`default`, `easeOut`, `easeInOut`)
- `spacing` β Spacing scale (`xs` through `xl`) for consistent padding, margins, and gaps
All new tokens are available in `defaultDarkTheme`, `defaultLightTheme`, and `cssVariableTheme`.
### New exported types
All token group types are exported for type-safe custom themes: `ActionColors`, `BorderRadiusScale`, `Shape`, `Shadows`, `FontSizeScale`, `FontWeightScale`, `LineHeightScale`, `Typography`, `TransitionDurations`, `TransitionEasings`, `Transitions`, `Spacing`.
#