diff --git a/.changeset/7742-kanban-arm-batch70.md b/.changeset/7742-kanban-arm-batch70.md index d081080901..d33bfab4ff 100644 --- a/.changeset/7742-kanban-arm-batch70.md +++ b/.changeset/7742-kanban-arm-batch70.md @@ -25,13 +25,18 @@ failure objectui#7664's own first cut shipped at `onCardClick`. including tests: 0 hits / 0 files each, with `groupBy` (85 hits / 27 files), `cardTitle` (18/9) and `coverImageField` (17/3) firing as controls on the same instrument. An author who wrote `allowCollapse: true` validated green and got - a board that never collapsed off that key. Each capability exists on a - *different* channel, and the refusal message names it: a lane's own - `columns[].collapsed` for collapsing, a `templates` component prop for card - templates, a `useColumnWidths` hook option for widths. Wiring a board-level - switch to any of them would be new behaviour and is not ordered here. - `CardTemplate` and `ColumnWidthConfig` stay exported — the prop and the hook - still consume the types. + a board that never collapsed off that key. At this change, each capability + existed on a *different* channel, and the refusal message named it: a lane's + own `columns[].collapsed` for collapsing, a `templates` component prop for + card templates, a `useColumnWidths` hook option for widths. Wiring a + board-level switch to any of them would be new behaviour and is not ordered + here. `CardTemplate` and `ColumnWidthConfig` stay exported — at this change, + the prop and the hook consumed the types. + + ⚠️ **Dated note, 2026-09-25 — the `useColumnWidths` hook has since been + retired (objectui#8522), so the widths channel named above no longer exists + and `ColumnWidthConfig` has no `plugin-kanban` reader. `CardTemplate` is still + consumed, by the `CardTemplates` component's `templates` prop.** - **`titleField`** — ⚠️ **not** an inertness retirement, and reading it as one gets the mechanism backwards. `ObjectKanban` still reads the key and the read stays, because the **sibling `object-kanban` arm declares it and keeps it** diff --git a/.changeset/8522-retire-use-column-widths.md b/.changeset/8522-retire-use-column-widths.md new file mode 100644 index 0000000000..53b2d478b7 --- /dev/null +++ b/.changeset/8522-retire-use-column-widths.md @@ -0,0 +1,33 @@ +--- +'@object-ui/plugin-kanban': minor +--- + +**BREAKING (scored `minor` per this repo's version-alignment convention)** — +`useColumnWidths` is removed from `@object-ui/plugin-kanban`, together with its +`UseColumnWidthsOptions` and `UseColumnWidthsReturn` types (objectui#8522, +maintainer ruling: remove). + +The hook kept per-column widths in `localStorage`, and no kanban board read +them: a board sizes its lanes from its own width (`columnInlineStyle` in +`KanbanImpl`, derived on every render), and no kanban component accepts a +per-lane width. The published 17.6.0 entry exports the hook and both types, so +an import of it compiled and ran while changing nothing on screen. + +## Migration + +- `import { useColumnWidths } from '@object-ui/plugin-kanban'`, and the type + imports `UseColumnWidthsOptions` / `UseColumnWidthsReturn`, no longer resolve. + Delete the import and the call. Nothing replaces the hook, and removing the + call changes no rendered width, because no board ever consumed what it + returned. +- The `localStorage` key `objectui:kanban-column-widths` (and its per-board form, + that key followed by `:` and the `storageKey` you passed) is no longer written + or read by any package. Values already stored in a browser are inert; remove + them if you want the storage back. +- `ColumnWidthConfig` stays exported from `@object-ui/types` and from this + package. This change does not retire it. +- The objectui#7742 entry in this same release (batch #70, the `kanban` arm) + names a `useColumnWidths` hook option as the channel for column widths. That + channel is gone with this change, and no other channel replaces it. This + change adds a dated note to that entry saying so, leaving its declaration + untouched. diff --git a/packages/plugin-kanban/src/__tests__/kanban-plugin-dialect-authoritative-7664.test.ts b/packages/plugin-kanban/src/__tests__/kanban-plugin-dialect-authoritative-7664.test.ts index f8beee6578..7fed524010 100644 --- a/packages/plugin-kanban/src/__tests__/kanban-plugin-dialect-authoritative-7664.test.ts +++ b/packages/plugin-kanban/src/__tests__/kanban-plugin-dialect-authoritative-7664.test.ts @@ -72,8 +72,8 @@ type _RegistryIsReal = Assert, false>>; // `Equal` is invariant, so a re-declared twin that drifted by one member // turns this red. (`KanbanSchema` was the third member of this row until // objectui#8802 retired it with the bare `kanban` node key; the two that -// remain are consumed by `KanbanImpl`, `CardTemplates` and `useColumnWidths` -// and are NOT retired.) +// remain are consumed by `KanbanImpl` and `CardTemplates` and are NOT +// retired.) type _ColumnIsTheDeclaredOne = Assert>; type _CardIsTheDeclaredOne = Assert>; diff --git a/packages/plugin-kanban/src/__tests__/useColumnWidthsRetired-8522.test.ts b/packages/plugin-kanban/src/__tests__/useColumnWidthsRetired-8522.test.ts new file mode 100644 index 0000000000..0fc6ca489c --- /dev/null +++ b/packages/plugin-kanban/src/__tests__/useColumnWidthsRetired-8522.test.ts @@ -0,0 +1,55 @@ +/** + * ObjectUI + * Copyright (c) 2024-present ObjectStack Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * objectui#8522 — `useColumnWidths` is RETIRED from the package entry. + * + * The hook kept per-column widths in `localStorage` and no board read it: the + * rendered lane width comes from `KanbanImpl`'s `columnInlineStyle`, derived + * from the board's own width on every render. Ruled remove (a published + * capability with zero consumers retires immediately); the hook, its two option + * and return types, and its storage key went with it. ⛔ Resizable lanes are + * not rebuilt to keep it alive; if they are ever wanted, they come back as + * their own feature. + * + * What this pins is the entry's SHAPE, both halves: + * + * - runtime: the hook name is not an own key of the module namespace, with a + * sibling hook exported the same way and the board renderer as firing + * controls on the same probe; + * - compile time: the two type names do not resolve through the entry, with a + * sibling hook's return type resolving through the same type query as the + * control. Compiled by this package's `tsconfig.test.json` (chained off + * `type-check`); an export that comes back fails there with + * "Unused '@ts-expect-error' directive". + */ + +import { describe, expect, it } from 'vitest'; +import * as entry from '../index'; + +describe('@object-ui/plugin-kanban entry — useColumnWidths retired (objectui#8522)', () => { + it('no longer exports the hook, while live exports on the same probe still resolve', () => { + const keys = Object.keys(entry); + expect(keys).not.toContain('useColumnWidths'); + // Firing controls: a hook exported the same way, and the board renderer. + // Without them an empty or mis-resolved namespace would pass the line above. + expect(typeof (entry as Record).useCrossSwimlaneMove).toBe('function'); + expect(keys).toContain('ObjectKanbanRenderer'); + }); + + it('no longer exports the hook option and return types', () => { + // @ts-expect-error retired with the hook (objectui#8522). If the export + // comes back, tsc fails with "Unused '@ts-expect-error' directive". + type _OptionsRetired = import('../index').UseColumnWidthsOptions; + // @ts-expect-error retired with the hook (objectui#8522), as above. + type _ReturnRetired = import('../index').UseColumnWidthsReturn; + // Control: the same type query resolves a sibling hook's return type, so + // the two errors above are readings of the entry and not of a bad path. + type _SiblingResolves = import('../index').UseCrossSwimlaneMoveReturn; + }); +}); diff --git a/packages/plugin-kanban/src/index.tsx b/packages/plugin-kanban/src/index.tsx index a830d5731e..7e09f2d928 100644 --- a/packages/plugin-kanban/src/index.tsx +++ b/packages/plugin-kanban/src/index.tsx @@ -212,8 +212,6 @@ export { InlineQuickAdd } from './InlineQuickAdd'; export type { InlineQuickAddProps } from './InlineQuickAdd'; export { CardTemplates } from './CardTemplates'; export type { CardTemplatesProps } from './CardTemplates'; -export { useColumnWidths } from './useColumnWidths'; -export type { UseColumnWidthsOptions, UseColumnWidthsReturn } from './useColumnWidths'; export { useCrossSwimlaneMove } from './useCrossSwimlaneMove'; export type { Swimlane, CrossSwimlaneMoveEvent, UseCrossSwimlaneOptions, UseCrossSwimlaneMoveReturn } from './useCrossSwimlaneMove'; export { useQuickAddReorder } from './useQuickAddReorder'; diff --git a/packages/plugin-kanban/src/useColumnWidths.ts b/packages/plugin-kanban/src/useColumnWidths.ts deleted file mode 100644 index 6d1984987b..0000000000 --- a/packages/plugin-kanban/src/useColumnWidths.ts +++ /dev/null @@ -1,125 +0,0 @@ -/** - * ObjectUI - * Copyright (c) 2024-present ObjectStack Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import { useState, useCallback, useMemo } from "react" -import type { KanbanColumn, ColumnWidthConfig } from "./types" - -const STORAGE_KEY = "objectui:kanban-column-widths" - -export interface UseColumnWidthsOptions { - /** Columns on the board */ - columns: KanbanColumn[] - /** Default width in pixels applied to every column */ - defaultWidth?: number - /** Minimum allowed column width in pixels */ - minWidth?: number - /** Maximum allowed column width in pixels */ - maxWidth?: number - /** Optional persistence key suffix (to scope per-board) */ - storageKey?: string -} - -export interface UseColumnWidthsReturn { - /** Get the current width for a column (in px) */ - getColumnWidth: (columnId: string) => number - /** Set an override width for a column */ - setColumnWidth: (columnId: string, width: number) => void - /** Reset all overrides back to default widths */ - resetWidths: () => void - /** The full config (useful for serialization) */ - config: ColumnWidthConfig -} - -function loadPersistedWidths(key: string): Record { - try { - const raw = localStorage.getItem(key) - if (raw) { - const parsed = JSON.parse(raw) - if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) { - return parsed as Record - } - } - } catch { - /* ignore corrupt data */ - } - return {} -} - -function persistWidths(key: string, overrides: Record) { - try { - localStorage.setItem(key, JSON.stringify(overrides)) - } catch { - /* quota exceeded */ - } -} - -/** - * Hook for managing custom per-column widths with localStorage persistence. - * Supports per-column overrides clamped between minWidth and maxWidth. - */ -export function useColumnWidths({ - columns: _columns, - defaultWidth = 320, - minWidth = 200, - maxWidth = 600, - storageKey, -}: UseColumnWidthsOptions): UseColumnWidthsReturn { - const fullKey = storageKey ? `${STORAGE_KEY}:${storageKey}` : STORAGE_KEY - - const [overrides, setOverrides] = useState>(() => - loadPersistedWidths(fullKey), - ) - - const clamp = useCallback( - (value: number) => Math.max(minWidth, Math.min(maxWidth, value)), - [minWidth, maxWidth], - ) - - const getColumnWidth = useCallback( - (columnId: string): number => { - const override = overrides[columnId] - return override != null ? clamp(override) : defaultWidth - }, - [overrides, defaultWidth, clamp], - ) - - const setColumnWidth = useCallback( - (columnId: string, width: number) => { - const clamped = clamp(width) - setOverrides(prev => { - const next = { ...prev, [columnId]: clamped } - persistWidths(fullKey, next) - return next - }) - }, - [clamp, fullKey], - ) - - const resetWidths = useCallback(() => { - setOverrides({}) - try { - localStorage.removeItem(fullKey) - } catch { - /* ignore */ - } - }, [fullKey]) - - const config: ColumnWidthConfig = useMemo( - () => ({ - defaultWidth, - minWidth, - maxWidth, - overrides: { ...overrides }, - }), - [defaultWidth, minWidth, maxWidth, overrides], - ) - - return { getColumnWidth, setColumnWidth, resetWidths, config } -} - -export default useColumnWidths diff --git a/packages/types/src/complex.ts b/packages/types/src/complex.ts index 71e3e7924b..2e4964f0be 100644 --- a/packages/types/src/complex.ts +++ b/packages/types/src/complex.ts @@ -246,8 +246,10 @@ export interface KanbanColumn { * documents. * * {@link KanbanCard}, {@link KanbanColumn}, {@link CardTemplate} and - * {@link ColumnWidthConfig} are NOT retired — the renderer, the `CardTemplates` - * component and the `useColumnWidths` hook still consume them. + * {@link ColumnWidthConfig} are NOT retired — the renderer and the + * `CardTemplates` component still consume the first three. The one + * `plugin-kanban` reader of {@link ColumnWidthConfig} was removed by + * objectui#8522, whose ruling did not reach the type itself. * * Pinned in `./__tests__/bare-kanban-node-key-retired-8802.test.ts`. */ diff --git a/packages/types/src/objectql.ts b/packages/types/src/objectql.ts index 1db02f5e6d..c4c5a7498c 100644 --- a/packages/types/src/objectql.ts +++ b/packages/types/src/objectql.ts @@ -3727,7 +3727,7 @@ export interface ObjectKanbanSchema extends BaseSchema { * * `id` / `title` / `cards` / `limit` / `className` / `collapsed` are exactly * the lane members the two board implementations read, counted off - * `KanbanImpl`, `KanbanEnhanced`, `useColumnWidths`, `useCrossSwimlaneMove`, + * `KanbanImpl`, `KanbanEnhanced`, `useCrossSwimlaneMove`, * `useQuickAddReorder` and `bucketCardsIntoColumns`. Their VALUE types come * from those read sites too — see {@link id} for the one this card had to * correct.