From c6e4e6dbb9f0257d760f0158a440b46e494af3df Mon Sep 17 00:00:00 2001 From: Axel Bocciarelli Date: Mon, 27 Apr 2026 16:17:55 +0200 Subject: [PATCH] Upgrade stories to CSF Next format --- apps/storybook/.storybook/main.ts | 17 ++- apps/storybook/.storybook/preview.ts | 11 +- apps/storybook/src/Annotation.stories.tsx | 42 +++---- .../src/AxialSelectToZoom.stories.tsx | 63 ++++------ .../src/AxialSelectionTool.stories.tsx | 43 ++----- apps/storybook/src/DataCurve.stories.tsx | 113 ++++++++++-------- .../src/DefaultInteractions.stories.tsx | 17 ++- .../storybook/src/DimensionMapper.stories.tsx | 59 ++++----- apps/storybook/src/ErrorBars.stories.tsx | 36 +++--- .../storybook/src/FloatingControl.stories.tsx | 13 +- apps/storybook/src/Glyphs.stories.tsx | 46 +++---- apps/storybook/src/Guides.stories.tsx | 25 ++-- apps/storybook/src/HeatmapMesh.stories.tsx | 45 +++---- .../lib/src/interactions/SelectionTool.tsx | 4 +- packages/lib/src/interactions/hooks.ts | 1 + packages/lib/src/vis/line/ErrorBars.tsx | 2 +- 16 files changed, 227 insertions(+), 310 deletions(-) diff --git a/apps/storybook/.storybook/main.ts b/apps/storybook/.storybook/main.ts index 497b6f1bf..6f02fef41 100644 --- a/apps/storybook/.storybook/main.ts +++ b/apps/storybook/.storybook/main.ts @@ -1,7 +1,7 @@ -import { type StorybookConfig } from '@storybook/react-vite'; +import { defineMain } from '@storybook/react-vite/node'; import remarkGfm from 'remark-gfm'; -const config: StorybookConfig = { +export default defineMain({ framework: '@storybook/react-vite', stories: ['../src/**/*.mdx', '../src/**/*.stories.tsx'], addons: [ @@ -14,7 +14,12 @@ const config: StorybookConfig = { }, '@storybook/addon-links', ], - core: { disableTelemetry: true }, -}; - -export default config; + core: { + // Use Vite config from `@h5web/lib` instead of Storybook's default to fix CSS modules + builder: { + name: '@storybook/builder-vite', + options: { viteConfigPath: '../../packages/lib/vite.config.js' }, + }, + disableTelemetry: true, + }, +}); diff --git a/apps/storybook/.storybook/preview.ts b/apps/storybook/.storybook/preview.ts index bc2700152..8c3eccefa 100644 --- a/apps/storybook/.storybook/preview.ts +++ b/apps/storybook/.storybook/preview.ts @@ -1,9 +1,12 @@ import '../src/styles.css'; -import { type Preview } from '@storybook/react-vite'; +import addonDocs from '@storybook/addon-docs'; +import addonLinks from '@storybook/addon-links'; +import { definePreview } from '@storybook/react-vite'; -const preview: Preview = { +export default definePreview({ tags: ['autodocs'], + addons: [addonDocs(), addonLinks()], parameters: { actions: { argTypesRegex: '^on[A-Z].*' }, options: { @@ -38,6 +41,4 @@ const preview: Preview = { }, }, }, -}; - -export default preview; +}); diff --git a/apps/storybook/src/Annotation.stories.tsx b/apps/storybook/src/Annotation.stories.tsx index f39d10cb1..6172f5500 100644 --- a/apps/storybook/src/Annotation.stories.tsx +++ b/apps/storybook/src/Annotation.stories.tsx @@ -6,13 +6,13 @@ import { VisCanvas, } from '@h5web/lib'; import { useRafState } from '@react-hookz/web'; -import { type Meta, type StoryObj } from '@storybook/react-vite'; import { type ReactNode } from 'react'; +import preview from '../.storybook/preview'; import FillHeight from './decorators/FillHeight'; import { formatCoord } from './utils'; -const meta = { +const meta = preview.meta({ title: 'Building Blocks/Annotation', component: Annotation, parameters: { @@ -31,17 +31,9 @@ const meta = { ), FillHeight, ], - args: { - overflowCanvas: false, - scaleOnZoom: false, - center: false, - }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); -export const Default = { +export const Default = meta.story({ render: (args) => { const { x, y, overflowCanvas, scaleOnZoom, center, style } = args; @@ -89,46 +81,42 @@ export const Default = { x: 10, y: 16, }, -} satisfies Story; +}); -export const OverflowCanvas = { - ...Default, +export const OverflowCanvas = Default.extend({ args: { x: 6, y: 16, overflowCanvas: true, }, -} satisfies Story; +}); -export const Centered = { - ...Default, +export const Centered = Default.extend({ args: { x: 5, y: 14, center: true, }, -} satisfies Story; +}); -export const ScaleOnZoom = { - ...Default, +export const ScaleOnZoom = Default.extend({ args: { x: 10, y: 16, scaleOnZoom: true, }, -} satisfies Story; +}); -export const ScaleOnZoomCentered = { - ...Default, +export const ScaleOnZoomCentered = Default.extend({ args: { x: 10, y: 16, scaleOnZoom: true, center: true, }, -} satisfies Story; +}); -export const FollowPointer = { +export const FollowPointer = meta.story({ render: (args) => ( {(x, y) => ( @@ -149,7 +137,7 @@ export const FollowPointer = { x: { control: false }, y: { control: false }, }, -} satisfies Story; +}); interface PointerTrackerProps { children: (x: number, y: number) => ReactNode; diff --git a/apps/storybook/src/AxialSelectToZoom.stories.tsx b/apps/storybook/src/AxialSelectToZoom.stories.tsx index 0798af09d..926f76314 100644 --- a/apps/storybook/src/AxialSelectToZoom.stories.tsx +++ b/apps/storybook/src/AxialSelectToZoom.stories.tsx @@ -12,39 +12,34 @@ import { VisCanvas, Zoom, } from '@h5web/lib'; -import { type Meta, type StoryObj } from '@storybook/react-vite'; import { range } from 'd3-array'; +import preview from '../.storybook/preview'; import FillHeight from './decorators/FillHeight'; const oneD = mockValues.oneD(); const typedTwoD = toTypedNdArray(mockValues.twoD(), Float32Array); -const meta = { +const meta = preview.meta({ title: 'Building Blocks/Interactions/AxialSelectToZoom', component: AxialSelectToZoom, decorators: [FillHeight], parameters: { layout: 'fullscreen' }, - args: { - axis: 'x', - modifierKey: [], - disabled: false, - }, argTypes: { - axis: { control: { type: 'inline-radio' } }, + axis: { + control: { type: 'inline-radio' }, + options: ['x', 'y'], + }, modifierKey: { control: { type: 'inline-check' }, options: ['Alt', 'Control', 'Shift'], }, }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); -const Default = { +export const XAxis = meta.story({ render: (args) => { - const { modifierKey } = args; + const { modifierKey = [] } = args; const domain = useDomain(oneD); assertDefined(domain); @@ -53,7 +48,7 @@ const Default = { abscissaConfig={{ visDomain: [0, oneD.size], showGrid: true }} ordinateConfig={{ visDomain: domain, showGrid: true }} > - + @@ -62,54 +57,45 @@ const Default = { ); }, -} satisfies Story; - -export const XAxis = { - ...Default, args: { axis: 'x', }, -} satisfies Story; +}); -export const YAxis = { - ...Default, +export const YAxis = XAxis.extend({ args: { axis: 'y', }, -} satisfies Story; +}); -export const ModifierKeyX = { - ...Default, +export const ModifierKeyX = XAxis.extend({ args: { axis: 'x', modifierKey: ['Alt'], }, -} satisfies Story; +}); -export const MultipleModifierKeysY = { - ...Default, +export const MultipleModifierKeysY = XAxis.extend({ args: { axis: 'y', modifierKey: ['Control', 'Shift'], }, -} satisfies Story; +}); -export const MinZoom = { - ...Default, +export const MinZoom = XAxis.extend({ args: { minZoom: 200, }, -} satisfies Story; +}); -export const Disabled = { - ...Default, +export const Disabled = XAxis.extend({ args: { axis: 'x', disabled: true, }, -} satisfies Story; +}); -export const DisabledInsideEqualAspectCanvas = { +export const DisabledInsideEqualAspectCanvas = meta.story({ render: (args) => { const [rows, cols] = typedTwoD.shape; const domain = useDomain(typedTwoD); @@ -135,8 +121,11 @@ export const DisabledInsideEqualAspectCanvas = { ); }, + args: { + axis: 'x', + }, argTypes: { modifierKey: { control: false }, disabled: { control: false }, }, -} satisfies Story; +}); diff --git a/apps/storybook/src/AxialSelectionTool.stories.tsx b/apps/storybook/src/AxialSelectionTool.stories.tsx index 765fb8ba8..5b4f39df1 100644 --- a/apps/storybook/src/AxialSelectionTool.stories.tsx +++ b/apps/storybook/src/AxialSelectionTool.stories.tsx @@ -10,22 +10,16 @@ import { Zoom, } from '@h5web/lib'; import { useThrottledState } from '@react-hookz/web'; -import { type Meta, type StoryObj } from '@storybook/react-vite'; +import preview from '../.storybook/preview'; import FillHeight from './decorators/FillHeight'; import { getTitleForSelection } from './utils'; -const meta = { +const meta = preview.meta({ title: 'Building Blocks/Interactions/AxialSelectionTool', component: AxialSelectionTool, decorators: [FillHeight], parameters: { layout: 'fullscreen' }, - args: { - axis: 'x', - disabled: false, - modifierKey: undefined, - children: undefined, - }, argTypes: { axis: { control: { type: 'inline-radio' }, @@ -36,12 +30,9 @@ const meta = { options: ['Alt', 'Control', 'Shift', undefined], }, }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -const Default = { +export const XAxis = meta.story({ render: (args) => { const { modifierKey } = args; @@ -77,39 +68,31 @@ const Default = { ); }, -} satisfies Story; - -export const XAxis = { - ...Default, args: { axis: 'x', }, -} satisfies Story; +}); -export const YAxis = { - ...Default, +export const YAxis = XAxis.extend({ args: { axis: 'y', }, -} satisfies Story; +}); -export const Disabled = { - ...Default, +export const Disabled = XAxis.extend({ args: { disabled: true, }, -} satisfies Story; +}); -export const WithModifierKey = { - ...Default, +export const WithModifierKey = XAxis.extend({ args: { modifierKey: 'Control', }, -} satisfies Story; +}); -export const WithValidation = { - ...Default, +export const WithValidation = XAxis.extend({ args: { validate: ({ html }) => Box.fromPoints(...html).hasMinSize(200), }, -} satisfies Story; +}); diff --git a/apps/storybook/src/DataCurve.stories.tsx b/apps/storybook/src/DataCurve.stories.tsx index 3ad154933..2410b5516 100644 --- a/apps/storybook/src/DataCurve.stories.tsx +++ b/apps/storybook/src/DataCurve.stories.tsx @@ -10,15 +10,15 @@ import { VisCanvas, } from '@h5web/lib'; import { assertDefined } from '@h5web/shared/guards'; -import { type Meta, type StoryObj } from '@storybook/react-vite'; import { range } from 'd3-array'; import { useState } from 'react'; +import preview from '../.storybook/preview'; import FillHeight from './decorators/FillHeight'; const oneD = mockValues.oneD(); -const meta = { +const meta = preview.meta({ title: 'Building Blocks/DataCurve', component: DataCurve, decorators: [FillHeight], @@ -26,30 +26,32 @@ const meta = { layout: 'fullscreen', controls: { sort: 'requiredFirst' }, }, - args: { - abscissas: range(oneD.size), - ordinates: oneD.data, - curveType: CurveType.LineOnly, - color: 'blue', - materialProps: {}, - visible: true, - }, argTypes: { abscissas: { control: false }, ordinates: { control: false }, errors: { control: false }, color: { control: { type: 'color' } }, + curveType: { + control: { type: 'inline-radio' }, + options: ['OnlyLine', 'OnlyGlyphs', 'LineAndGlyphs', undefined], + }, + interpolation: { + control: { type: 'inline-radio' }, + options: ['Linear', 'Constant', undefined], + }, + glyphType: { + control: { type: 'inline-radio' }, + options: ['Circle', 'Cross', 'Square', 'Cap', undefined], + }, + ignoreValue: { control: false }, materialProps: { control: 'object', description: 'Properties passed to the underlying Three.js material.', }, }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default = { +export const Default = meta.story({ render: (args) => { const { abscissas, ordinates, errors, ignoreValue } = args; @@ -72,75 +74,77 @@ export const Default = { ); }, -} satisfies Story; + args: { + abscissas: range(oneD.size), + ordinates: oneD.data, + color: 'blue', + }, +}); -export const Color = { - ...Default, +export const Color = Default.extend({ args: { color: 'black', }, -} satisfies Story; +}); -export const Width = { - ...Default, +export const GlyphsOnly = Default.extend({ args: { - width: 3, + curveType: CurveType.GlyphsOnly, }, -} satisfies Story; +}); -export const ConstantInterpolation = { - ...Default, +export const LineAndGlyphs = Default.extend({ args: { - interpolation: Interpolation.Constant, + curveType: CurveType.LineAndGlyphs, }, -} satisfies Story; +}); -export const ConstantWithWidth = { - ...Default, +export const Width = Default.extend({ args: { width: 3, + }, +}); + +export const ConstantInterpolation = Default.extend({ + args: { interpolation: Interpolation.Constant, }, -} satisfies Story; +}); -export const Glyphs = { - ...Default, +export const ConstantWithWidth = Default.extend({ args: { - curveType: CurveType.GlyphsOnly, + width: 3, + interpolation: Interpolation.Constant, }, -} satisfies Story; +}); -export const WithErrors = { - ...Default, +export const WithErrors = Default.extend({ args: { errors: oneD.data.map(() => 10), }, -} satisfies Story; +}); -export const GlyphType = { - ...Default, +export const GlyphType = Default.extend({ args: { - curveType: CurveType.LineAndGlyphs, - glyphType: GlyphTypeEnum.Circle, + curveType: CurveType.GlyphsOnly, + glyphType: GlyphTypeEnum.Square, }, -} satisfies Story; +}); -export const GlyphSize = { - ...Default, +export const GlyphSize = Default.extend({ args: { curveType: CurveType.LineAndGlyphs, glyphSize: 10, }, -} satisfies Story; +}); -export const IgnoreValue = { - ...Default, +export const IgnoreValue = Default.extend({ args: { ignoreValue: (val) => val % 5 === 0, }, -} satisfies Story; +}); -export const Interactive = { +export const Interactive = meta.story({ render: (args) => { const [index, setIndex] = useState(); const [hoveredIndex, setHoveredIndex] = useState(); @@ -160,7 +164,7 @@ export const Interactive = { ? `You clicked on point ${index} at (${abscissas[index]}, ${ordinates[index]})!` : 'Click on a point!' } - raycasterThreshold={6} + raycasterThreshold={20} > - + )} @@ -194,7 +198,10 @@ export const Interactive = { ); }, args: { + abscissas: range(oneD.size), + ordinates: oneD.data, + color: 'blue', curveType: CurveType.LineAndGlyphs, - glyphType: GlyphTypeEnum.Circle, + glyphSize: 10, }, -} satisfies Story; +}); diff --git a/apps/storybook/src/DefaultInteractions.stories.tsx b/apps/storybook/src/DefaultInteractions.stories.tsx index 3b647035b..a0a46bf3d 100644 --- a/apps/storybook/src/DefaultInteractions.stories.tsx +++ b/apps/storybook/src/DefaultInteractions.stories.tsx @@ -9,13 +9,13 @@ import { useDomain, VisCanvas, } from '@h5web/lib'; -import { type Meta, type StoryObj } from '@storybook/react-vite'; +import preview from '../.storybook/preview'; import FillHeight from './decorators/FillHeight'; const typedTwoD = toTypedNdArray(mockValues.twoD(), Float32Array); -const meta = { +const meta = preview.meta({ title: 'Building Blocks/Interactions/DefaultInteractions', component: DefaultInteractions, decorators: [FillHeight], @@ -29,12 +29,9 @@ const meta = { xSelectToZoom: { modifierKey: ['Control', 'Alt'] }, ySelectToZoom: { modifierKey: ['Control', 'Shift'] }, }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const InsideAutoAspectCanvas = { +export const InsideAutoAspectCanvas = meta.story({ render: (args) => { const [rows, cols] = typedTwoD.shape; const domain = useDomain(typedTwoD); @@ -58,9 +55,9 @@ export const InsideAutoAspectCanvas = { ); }, -} satisfies Story; +}); -export const InsideEqualAspectCanvas = { +export const InsideEqualAspectCanvas = meta.story({ render: (args) => { const [rows, cols] = typedTwoD.shape; const domain = useDomain(typedTwoD); @@ -84,4 +81,4 @@ export const InsideEqualAspectCanvas = { ); }, -} satisfies Story; +}); diff --git a/apps/storybook/src/DimensionMapper.stories.tsx b/apps/storybook/src/DimensionMapper.stories.tsx index 7e5754ae4..96008668e 100644 --- a/apps/storybook/src/DimensionMapper.stories.tsx +++ b/apps/storybook/src/DimensionMapper.stories.tsx @@ -1,27 +1,20 @@ import { DimensionMapper } from '@h5web/lib'; -import { type Meta, type StoryObj } from '@storybook/react-vite'; import { useState } from 'react'; +import preview from '../.storybook/preview'; import FillHeight from './decorators/FillHeight'; -const meta = { +const meta = preview.meta({ title: 'Building Blocks/DimensionMapper', component: DimensionMapper, decorators: [FillHeight], parameters: { layout: 'fullscreen' }, - args: { - dimMapping: [], - onChange: () => {}, - }, argTypes: { dimMapping: { control: false }, }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default = { +export const Default = meta.story({ render: (args) => { const { dimMapping: initialMapping, ...otherArgs } = args; const [dimMapping, setDimMapping] = useState(initialMapping); @@ -42,61 +35,51 @@ export const Default = { args: { dims: [5, 10, 15], dimMapping: [2, 5, 'x'], + onChange: () => {}, }, -} satisfies Story; +}); -export const DimensionHints = { - ...Default, +export const DimensionHints = Default.extend({ args: { - ...Default.args, dimHints: [undefined, 'Threshold', 'Position (mm)'], }, -} satisfies Story; +}); -export const FastSlicing = { - ...Default, +export const FastSlicing = Default.extend({ args: { - ...Default.args, canSliceFast: () => true, }, -} satisfies Story; +}); -export const TwoAxes = { - ...Default, +export const TwoAxes = Default.extend({ args: { - ...Default.args, dimMapping: ['x', 5, 'y'], }, -} satisfies Story; +}); -export const NoAxes = { - ...Default, +export const NoAxes = Default.extend({ args: { - ...Default.args, dimMapping: [0, 1, 2], }, -} satisfies Story; +}); -export const SmallDimensions = { - ...Default, +export const SmallDimensions = Default.extend({ args: { dims: [1, 2, 3], dimMapping: [0, 0, 0], }, -} satisfies Story; +}); -export const LargeDimensions = { - ...Default, +export const LargeDimensions = Default.extend({ args: { dims: [10_000, 100_000], dimMapping: [0, 99_999], }, -} satisfies Story; +}); -export const ExtraDimensions = { - ...Default, +export const LockedDimensions = Default.extend({ args: { dims: [5, 10, 15, 20], - dimMapping: [0, 'x'], + dimMapping: [0, 'x', null, null], }, -} satisfies Story; +}); diff --git a/apps/storybook/src/ErrorBars.stories.tsx b/apps/storybook/src/ErrorBars.stories.tsx index 2a78ec009..ae45c8935 100644 --- a/apps/storybook/src/ErrorBars.stories.tsx +++ b/apps/storybook/src/ErrorBars.stories.tsx @@ -7,14 +7,14 @@ import { } from '@h5web/lib'; import { assertDefined } from '@h5web/shared/guards'; import { ScaleType } from '@h5web/shared/vis-models'; -import { type Meta, type StoryObj } from '@storybook/react-vite'; import { range } from 'd3-array'; +import preview from '../.storybook/preview'; import FillHeight from './decorators/FillHeight'; const oneD = mockValues.oneD(); -const meta = { +const meta = preview.meta({ title: 'Building Blocks/ErrorBars', component: ErrorBars, decorators: [FillHeight], @@ -22,25 +22,15 @@ const meta = { layout: 'fullscreen', controls: { sort: 'requiredFirst' }, }, - args: { - abscissas: range(oneD.size), - ordinates: oneD.data, - errors: oneD.data.map(() => 10), - color: 'blue', - visible: true, - }, argTypes: { abscissas: { control: false }, ordinates: { control: false }, errors: { control: false }, color: { control: { type: 'color' } }, }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); -export const Default = { +export const Default = meta.story({ render: (args) => { const { abscissas, ordinates, errors, ignoreValue } = args; @@ -68,18 +58,22 @@ export const Default = { ); }, -} satisfies Story; + args: { + abscissas: range(oneD.size), + ordinates: oneD.data, + errors: oneD.data.map(() => 10), + color: 'blue', + }, +}); -export const Color = { - ...Default, +export const Color = Default.extend({ args: { color: 'red', }, -} satisfies Story; +}); -export const IgnoreValue = { - ...Default, +export const IgnoreValue = Default.extend({ args: { ignoreValue: (val) => val % 5 === 0, }, -} satisfies Story; +}); diff --git a/apps/storybook/src/FloatingControl.stories.tsx b/apps/storybook/src/FloatingControl.stories.tsx index f2d5d66db..889c35d67 100644 --- a/apps/storybook/src/FloatingControl.stories.tsx +++ b/apps/storybook/src/FloatingControl.stories.tsx @@ -1,20 +1,17 @@ import { DefaultInteractions, FloatingControl, VisCanvas } from '@h5web/lib'; import { useToggle } from '@react-hookz/web'; -import { type Meta, type StoryObj } from '@storybook/react-vite'; +import preview from '../.storybook/preview'; import FillHeight from './decorators/FillHeight'; -const meta = { +const meta = preview.meta({ title: 'Toolbar/FloatingControl', component: FloatingControl, decorators: [FillHeight], parameters: { layout: 'fullscreen' }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default = { +export const Default = meta.story({ render: () => { const [isToggled, toggle] = useToggle(false); const [withTitle, toggleTitle] = useToggle(false); @@ -43,4 +40,4 @@ export const Default = { ); }, -} satisfies Story; +}); diff --git a/apps/storybook/src/Glyphs.stories.tsx b/apps/storybook/src/Glyphs.stories.tsx index 5e57b5aab..a5c17f61b 100644 --- a/apps/storybook/src/Glyphs.stories.tsx +++ b/apps/storybook/src/Glyphs.stories.tsx @@ -7,14 +7,14 @@ import { VisCanvas, } from '@h5web/lib'; import { assertDefined } from '@h5web/shared/guards'; -import { type Meta, type StoryObj } from '@storybook/react-vite'; import { range } from 'd3-array'; +import preview from '../.storybook/preview'; import FillHeight from './decorators/FillHeight'; const oneD = mockValues.oneD(); -const meta = { +const meta = preview.meta({ title: 'Building Blocks/Glyphs', component: Glyphs, decorators: [FillHeight], @@ -22,14 +22,6 @@ const meta = { layout: 'fullscreen', controls: { sort: 'requiredFirst' }, }, - args: { - abscissas: range(oneD.size), - ordinates: oneD.data, - glyphType: GlyphTypeEnum.Cross, - color: 'blue', - size: 6, - visible: true, - }, argTypes: { abscissas: { control: false }, ordinates: { control: false }, @@ -39,12 +31,9 @@ const meta = { }, color: { control: { type: 'color' } }, }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); -export const Default = { +export const Default = meta.story({ render: (args) => { const { abscissas, ordinates, ignoreValue } = args; @@ -64,32 +53,33 @@ export const Default = { ); }, -} satisfies Story; + args: { + abscissas: range(oneD.size), + ordinates: oneD.data, + color: 'blue', + }, +}); -export const Color = { - ...Default, +export const Color = Default.extend({ args: { color: 'red', }, -} satisfies Story; +}); -export const GlyphType = { - ...Default, +export const GlyphType = Default.extend({ args: { glyphType: GlyphTypeEnum.Square, }, -} satisfies Story; +}); -export const Size = { - ...Default, +export const Size = Default.extend({ args: { size: 12, }, -} satisfies Story; +}); -export const IgnoreValue = { - ...Default, +export const IgnoreValue = Default.extend({ args: { ignoreValue: (val) => val % 5 === 0, }, -} satisfies Story; +}); diff --git a/apps/storybook/src/Guides.stories.tsx b/apps/storybook/src/Guides.stories.tsx index 7dcb0e3a3..92dfce616 100644 --- a/apps/storybook/src/Guides.stories.tsx +++ b/apps/storybook/src/Guides.stories.tsx @@ -5,21 +5,18 @@ import { VisCanvas, } from '@h5web/lib'; import { useToggle } from '@react-hookz/web'; -import { type Meta, type StoryObj } from '@storybook/react-vite'; +import preview from '../.storybook/preview'; import FillHeight from './decorators/FillHeight'; -const meta = { +const meta = preview.meta({ title: 'Building Blocks/Guides', component: Guides, decorators: [FillHeight], parameters: { layout: 'fullscreen' }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default = { +export const Default = meta.story({ render: (args) => { const [show, toggle] = useToggle(true); @@ -43,18 +40,18 @@ export const Default = { top: 50, left: 60, }, -} satisfies Story; +}); -export const HorizontalOnly = { - ...Default, +export const HorizontalOnly = Default.extend({ args: { top: 50, + left: undefined, }, -} satisfies Story; +}); -export const VerticalOnly = { - ...Default, +export const VerticalOnly = Default.extend({ args: { + top: undefined, left: 60, }, -} satisfies Story; +}); diff --git a/apps/storybook/src/HeatmapMesh.stories.tsx b/apps/storybook/src/HeatmapMesh.stories.tsx index e3688dec6..4210d4e13 100644 --- a/apps/storybook/src/HeatmapMesh.stories.tsx +++ b/apps/storybook/src/HeatmapMesh.stories.tsx @@ -9,11 +9,11 @@ import { import { assertDefined } from '@h5web/shared/guards'; import { ScaleType } from '@h5web/shared/vis-models'; import { COLOR_SCALE_TYPES, toTypedNdArray } from '@h5web/shared/vis-utils'; -import { type Meta, type StoryObj } from '@storybook/react-vite'; import { range } from 'd3-array'; import ndarray from 'ndarray'; import { LinearFilter, NearestFilter } from 'three'; +import preview from '../.storybook/preview'; import FillHeight from './decorators/FillHeight'; const twoD = mockValues.twoD(); @@ -32,16 +32,11 @@ const mask = ndarray( [20, 41], ); -const meta = { +const meta = preview.meta({ title: 'Building Blocks/HeatmapMesh', component: HeatmapMesh, decorators: [FillHeight], parameters: { layout: 'fullscreen', controls: { sort: 'requiredFirst' } }, - args: { - invertColorMap: false, - magFilter: NearestFilter, - minFilter: NearestFilter, - }, argTypes: { scaleType: { control: { type: 'inline-radio' }, @@ -52,22 +47,19 @@ const meta = { type: 'inline-radio', labels: { [NearestFilter]: 'nearest', [LinearFilter]: 'linear' }, }, - options: [NearestFilter, LinearFilter], + options: [NearestFilter, LinearFilter, undefined], }, minFilter: { control: { type: 'inline-radio', labels: { [NearestFilter]: 'nearest', [LinearFilter]: 'linear' }, }, - options: [NearestFilter, LinearFilter], + options: [NearestFilter, LinearFilter, undefined], }, }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); -export const Default = { +export const Default = meta.story({ render: (args) => { const [rows, cols] = args.values.shape; @@ -87,40 +79,33 @@ export const Default = { scaleType: ScaleType.SymLog, colorMap: 'Inferno', }, -} satisfies Story; +}); -export const HalfFloatTexture = { - ...Default, +export const HalfFloatTexture = Default.extend({ args: { values: uint16DataArray, domain: uint16Domain, scaleType: ScaleType.Linear, colorMap: 'Blues', }, -} satisfies Story; +}); -export const LinearMagFilter = { - ...Default, +export const LinearMagFilter = Default.extend({ args: { - ...Default.args, magFilter: LinearFilter, }, -} satisfies Story; +}); -export const BadColor = { - ...Default, +export const BadColor = Default.extend({ args: { - ...Default.args, domain: [0.1, 400], scaleType: ScaleType.Log, badColor: 'steelblue', }, -} satisfies Story; +}); -export const Mask = { - ...Default, +export const Mask = Default.extend({ args: { - ...Default.args, mask, }, -} satisfies Story; +}); diff --git a/packages/lib/src/interactions/SelectionTool.tsx b/packages/lib/src/interactions/SelectionTool.tsx index 90f150a51..170125539 100644 --- a/packages/lib/src/interactions/SelectionTool.tsx +++ b/packages/lib/src/interactions/SelectionTool.tsx @@ -39,7 +39,7 @@ interface Props extends CommonInteractionProps { ) => void; onSelectionEnd?: (selection: Selection | undefined, isValid: boolean) => void; onValidSelection?: (selection: Selection) => void; - children: ( + children?: ( selection: Selection, rawSelection: Selection, isValid: boolean, @@ -214,7 +214,7 @@ function SelectionTool(props: Props) { } assertDefined(rawSelection); - return children(selection, rawSelection, isValid); + return children?.(selection, rawSelection, isValid); } export type { Props as SelectionToolProps }; diff --git a/packages/lib/src/interactions/hooks.ts b/packages/lib/src/interactions/hooks.ts index a5731367c..3c5e05132 100644 --- a/packages/lib/src/interactions/hooks.ts +++ b/packages/lib/src/interactions/hooks.ts @@ -172,6 +172,7 @@ export function useModifierKeyPressed( function checkAllPressed() { const newAllPressed = modifierKeys.every((key) => pressedKeys.get(key)); + if (allPressed !== newAllPressed) { toggleAllPressed(newAllPressed); } diff --git a/packages/lib/src/vis/line/ErrorBars.tsx b/packages/lib/src/vis/line/ErrorBars.tsx index 987da5240..da38da78a 100644 --- a/packages/lib/src/vis/line/ErrorBars.tsx +++ b/packages/lib/src/vis/line/ErrorBars.tsx @@ -23,7 +23,7 @@ function ErrorBars(props: Props) { ordinates, errors, color, - visible = false, + visible = true, ignoreValue, } = props; const { abscissaScale, ordinateScale } = useVisCanvasContext();