/* * (c) Copyright 2026 Palantir Technologies Inc. All rights reserved. */ import type { Meta, StoryObj } from "@storybook/react-vite"; import { StoryLabel } from "@storybook-common"; import { useCallback, useState } from "react"; import { Flex } from "@blueprintjs/labs"; import { Intent, Position, Size } from "../../common"; import { NumericInput } from "./numericInput"; const meta: Meta = { title: "Core/Form/Inputs/NumericInput", component: NumericInput, decorators: [ Story => ( ), ], tags: ["autodocs"], args: { intent: "none", size: "medium", placeholder: "Enter a number...", disabled: false, readOnly: false, fill: false, min: 0, max: 100, stepSize: 1, }, argTypes: { intent: { control: "select", options: Object.values(Intent), }, size: { control: "select", options: Object.values(Size), }, placeholder: { control: "text", }, disabled: { control: "boolean", }, readOnly: { control: "boolean", }, fill: { control: "boolean", }, min: { control: "number", }, max: { control: "number", }, stepSize: { control: "number", }, buttonPosition: { control: "select", options: [Position.LEFT, Position.RIGHT, "none"], }, leftIcon: { control: "text", }, onValueChange: { action: "valueChanged" }, // deprecated props large: { table: { disable: true } }, small: { table: { disable: true } }, }, } satisfies Meta; export default meta; type Story = StoryObj; /** * A basic numeric input with default styling and increment/decrement buttons. */ export const Default: Story = {}; /** * Use the `intent` prop to apply a semantic color that conveys the purpose or status of the input. */ export const IntentExample: Story = { name: "Intent", argTypes: { intent: { table: { disable: true } }, }, render: args => ( {Object.values(Intent).map(intent => ( ))} ), }; /** * Use the `size` prop to adjust the input dimensions. */ export const SizeExample: Story = { name: "Size", argTypes: { size: { table: { disable: true } }, }, render: args => ( {Object.values(Size).map(size => ( ))} ), }; /** * NumericInput supports `disabled` and `readOnly` states. */ export const StateExample: Story = { name: "State", argTypes: { disabled: { table: { disable: true } }, readOnly: { table: { disable: true } }, }, render: args => ( ), }; /** * Use `buttonPosition` to control the placement of increment/decrement buttons. */ export const ButtonPositionExample: Story = { name: "Button Position", argTypes: { buttonPosition: { table: { disable: true } }, }, render: args => ( ), }; /** * Use `leftIcon` to add an icon to the left side of the input. */ export const IconExample: Story = { name: "Icons", argTypes: { leftIcon: { table: { disable: true } }, }, render: args => ( ), }; /** * Use the `fill` prop to make the input expand to the full width of its container. */ export const FillExample: Story = { name: "Fill", argTypes: { fill: { table: { disable: true } }, }, decorators: [ Story => (
), ], render: args => ( ), }; /** * A numeric input in the focused state, showing the focus ring. Use controls to change the intent. */ export const FocusedExample: Story = { name: "Focused", play: async ({ canvas, userEvent }) => { const input = canvas.getByPlaceholderText("Click to focus..."); await userEvent.click(input); }, render: args => ( ), }; /** * Interactive playground with all props togglable via Storybook controls. */ export const Playground: Story = { render: function Render(args) { const [value, setValue] = useState("0"); const handleValueChange = useCallback( (_valueAsNumber: number, valueAsString: string) => { setValue(valueAsString); args.onValueChange?.(_valueAsNumber, valueAsString, null); }, [args], ); return ( ); }, args: { leftIcon: "dollar", placeholder: "Enter amount...", min: 0, max: 1000, stepSize: 1, }, };