UNPKG

@furystack/shades-common-components

Version:

Common UI components for FuryStack Shades

1,013 lines (647 loc) β€’ 70.9 kB
# 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 `![pasted image](data:...)` 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`. #