From b33bb24b5a230605d8559dc28c5cd76a95a24e55 Mon Sep 17 00:00:00 2001 From: James Brooks <52410024+jabrks@users.noreply.github.com> Date: Wed, 27 May 2026 16:20:27 +0100 Subject: [PATCH] Add NumberField component to @backstage/ui (#34264) * Add NumberField component to @backstage/ui Signed-off-by: James Brooks * Address review feedback on NumberField Signed-off-by: James Brooks * Fix NumberField CSS formatting Signed-off-by: James Brooks * Add increment/decrement buttons to NumberField Signed-off-by: James Brooks * Fix NumberField looking disabled at min/max bounds Signed-off-by: James Brooks --------- Signed-off-by: James Brooks --- .changeset/tall-spies-invite.md | 7 + .../components/number-field/components.tsx | 51 ++++ .../src/app/components/number-field/page.mdx | 70 ++++++ .../number-field/props-definition.tsx | 100 ++++++++ .../app/components/number-field/snippets.ts | 31 +++ docs-ui/src/utils/data.ts | 4 + packages/ui/report.api.md | 50 ++++ .../NumberField/NumberField.module.css | 140 +++++++++++ .../NumberField/NumberField.stories.tsx | 218 ++++++++++++++++++ .../components/NumberField/NumberField.tsx | 121 ++++++++++ .../src/components/NumberField/definition.ts | 45 ++++ .../ui/src/components/NumberField/index.ts | 19 ++ .../ui/src/components/NumberField/types.ts | 50 ++++ packages/ui/src/definitions.ts | 1 + packages/ui/src/index.ts | 1 + 15 files changed, 908 insertions(+) create mode 100644 .changeset/tall-spies-invite.md create mode 100644 docs-ui/src/app/components/number-field/components.tsx create mode 100644 docs-ui/src/app/components/number-field/page.mdx create mode 100644 docs-ui/src/app/components/number-field/props-definition.tsx create mode 100644 docs-ui/src/app/components/number-field/snippets.ts create mode 100644 packages/ui/src/components/NumberField/NumberField.module.css create mode 100644 packages/ui/src/components/NumberField/NumberField.stories.tsx create mode 100644 packages/ui/src/components/NumberField/NumberField.tsx create mode 100644 packages/ui/src/components/NumberField/definition.ts create mode 100644 packages/ui/src/components/NumberField/index.ts create mode 100644 packages/ui/src/components/NumberField/types.ts diff --git a/.changeset/tall-spies-invite.md b/.changeset/tall-spies-invite.md new file mode 100644 index 0000000000..357bd953c9 --- /dev/null +++ b/.changeset/tall-spies-invite.md @@ -0,0 +1,7 @@ +--- +'@backstage/ui': patch +--- + +Added a new `NumberField` component for numeric input with support for min, max, step, and keyboard increment/decrement. + +**Affected components:** NumberField diff --git a/docs-ui/src/app/components/number-field/components.tsx b/docs-ui/src/app/components/number-field/components.tsx new file mode 100644 index 0000000000..986216226c --- /dev/null +++ b/docs-ui/src/app/components/number-field/components.tsx @@ -0,0 +1,51 @@ +'use client'; + +import { NumberField } from '../../../../../packages/ui/src/components/NumberField/NumberField'; +import { Flex } from '../../../../../packages/ui/src/components/Flex/Flex'; +import { RiTimeLine } from '@remixicon/react'; + +export const WithLabel = () => { + return ( + + ); +}; + +export const Sizes = () => { + return ( + + } + /> + } + /> + + ); +}; + +export const WithDescription = () => { + return ( + + ); +}; diff --git a/docs-ui/src/app/components/number-field/page.mdx b/docs-ui/src/app/components/number-field/page.mdx new file mode 100644 index 0000000000..ab1418f609 --- /dev/null +++ b/docs-ui/src/app/components/number-field/page.mdx @@ -0,0 +1,70 @@ +import { PropsTable } from '@/components/PropsTable'; +import { Snippet } from '@/components/Snippet'; +import { numberFieldPropDefs } from './props-definition'; +import { + numberFieldUsageSnippet, + withLabelSnippet, + sizesSnippet, + withDescriptionSnippet, +} from './snippets'; +import { WithLabel, Sizes, WithDescription } from './components'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { NumberFieldDefinition } from '../../../utils/definitions'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; +import { CodeBlock } from '@/components/CodeBlock'; +import { ReactAriaLink } from '@/components/ReactAriaLink'; + +export const reactAriaUrls = { + numberField: 'https://react-aria.adobe.com/NumberField', +}; + + + +} + code={withLabelSnippet} +/> + +## Usage + + + +## API reference + + + + + +## Examples + +### Sizes + +} + code={sizesSnippet} + layout="side-by-side" +/> + +### With description + +} + code={withDescriptionSnippet} + layout="side-by-side" +/> + + + + diff --git a/docs-ui/src/app/components/number-field/props-definition.tsx b/docs-ui/src/app/components/number-field/props-definition.tsx new file mode 100644 index 0000000000..3149f222bf --- /dev/null +++ b/docs-ui/src/app/components/number-field/props-definition.tsx @@ -0,0 +1,100 @@ +import { + classNamePropDefs, + stylePropDefs, + type PropDef, +} from '@/utils/propDefs'; +import { Chip } from '@/components/Chip'; + +export const numberFieldPropDefs: Record = { + size: { + type: 'enum', + values: ['small', 'medium'], + default: 'small', + responsive: true, + description: ( + <> + Visual size of the input. Use small for dense layouts,{' '} + medium for prominent fields. + + ), + }, + label: { + type: 'string', + description: 'Visible label displayed above the input.', + }, + secondaryLabel: { + type: 'string', + description: ( + <> + Secondary text shown next to the label. If not provided and isRequired + is true, displays Required. + + ), + }, + description: { + type: 'string', + description: 'Help text displayed below the label.', + }, + icon: { + type: 'enum', + values: ['ReactNode'], + description: 'Icon rendered before the input.', + }, + placeholder: { + type: 'string', + description: 'Text displayed when the input is empty.', + }, + name: { + type: 'string', + description: 'Form field name for submission.', + }, + minValue: { + type: 'number', + description: 'Minimum allowed value.', + }, + maxValue: { + type: 'number', + description: 'Maximum allowed value.', + }, + step: { + type: 'number', + description: 'Step increment for arrow key changes.', + }, + formatOptions: { + type: 'enum', + values: ['Intl.NumberFormatOptions'], + description: ( + <> + Number formatting options. Defaults to{' '} + {'useGrouping: false'}. + + ), + }, + isRequired: { + type: 'boolean', + description: 'Whether the field is required for form submission.', + }, + isDisabled: { + type: 'boolean', + description: 'Whether the input is disabled.', + }, + isReadOnly: { + type: 'boolean', + description: 'Whether the input is read-only.', + }, + value: { + type: 'number', + description: 'Controlled value of the input.', + }, + defaultValue: { + type: 'number', + description: 'Default value for uncontrolled usage.', + }, + onChange: { + type: 'enum', + values: ['(value: number) => void'], + description: 'Handler called when the input value changes.', + }, + ...classNamePropDefs, + ...stylePropDefs, +}; diff --git a/docs-ui/src/app/components/number-field/snippets.ts b/docs-ui/src/app/components/number-field/snippets.ts new file mode 100644 index 0000000000..533d4b3897 --- /dev/null +++ b/docs-ui/src/app/components/number-field/snippets.ts @@ -0,0 +1,31 @@ +export const numberFieldUsageSnippet = `import { NumberField } from '@backstage/ui'; + +`; + +export const withLabelSnippet = ``; + +export const sizesSnippet = ` + } + /> + } + /> +`; + +export const withDescriptionSnippet = ``; diff --git a/docs-ui/src/utils/data.ts b/docs-ui/src/utils/data.ts index 515deacb13..3d1cfa54d3 100644 --- a/docs-ui/src/utils/data.ts +++ b/docs-ui/src/utils/data.ts @@ -98,6 +98,10 @@ export const components: Page[] = [ title: 'Menu', slug: 'menu', }, + { + title: 'NumberField', + slug: 'number-field', + }, { title: 'PasswordField', slug: 'password-field', diff --git a/packages/ui/report.api.md b/packages/ui/report.api.md index ff864a658a..1e07bdf0b1 100644 --- a/packages/ui/report.api.md +++ b/packages/ui/report.api.md @@ -37,6 +37,7 @@ import type { MenuProps as MenuProps_2 } from 'react-aria-components'; import type { MenuSectionProps as MenuSectionProps_2 } from 'react-aria-components'; import type { MenuTriggerProps as MenuTriggerProps_2 } from 'react-aria-components'; import type { ModalOverlayProps } from 'react-aria-components'; +import type { NumberFieldProps as NumberFieldProps_2 } from 'react-aria-components'; import { PopoverProps as PopoverProps_2 } from 'react-aria-components'; import type { RadioGroupProps as RadioGroupProps_2 } from 'react-aria-components'; import type { RadioProps as RadioProps_2 } from 'react-aria-components'; @@ -2329,6 +2330,55 @@ export interface NoPagination { type: 'none'; } +// @public +export const NumberField: ForwardRefExoticComponent< + NumberFieldProps & RefAttributes +>; + +// @public +export const NumberFieldDefinition: { + readonly styles: { + readonly [key: string]: string; + }; + readonly classNames: { + readonly root: 'bui-NumberField'; + readonly inputWrapper: 'bui-InputWrapper'; + readonly input: 'bui-Input'; + readonly inputIcon: 'bui-InputIcon'; + readonly stepperButtons: 'bui-StepperButtons'; + readonly stepperButton: 'bui-StepperButton'; + }; + readonly bg: 'consumer'; + readonly propDefs: { + readonly size: { + readonly dataAttribute: true; + readonly default: 'small'; + }; + readonly className: {}; + readonly icon: {}; + readonly placeholder: {}; + readonly label: {}; + readonly description: {}; + readonly secondaryLabel: {}; + }; +}; + +// @public (undocumented) +export type NumberFieldOwnProps = { + size?: 'small' | 'medium' | Partial>; + className?: string; + icon?: ReactNode; + placeholder?: string; + label?: FieldLabelProps['label']; + description?: FieldLabelProps['description']; + secondaryLabel?: FieldLabelProps['secondaryLabel']; +}; + +// @public (undocumented) +export interface NumberFieldProps + extends Omit, + NumberFieldOwnProps {} + // @public (undocumented) export interface OffsetParams { // (undocumented) diff --git a/packages/ui/src/components/NumberField/NumberField.module.css b/packages/ui/src/components/NumberField/NumberField.module.css new file mode 100644 index 0000000000..70696695d7 --- /dev/null +++ b/packages/ui/src/components/NumberField/NumberField.module.css @@ -0,0 +1,140 @@ +/* + * Copyright 2026 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@layer tokens, base, components, utilities; + +@layer components { + .bui-NumberField { + display: flex; + flex-direction: column; + font-family: var(--bui-font-regular); + width: 100%; + flex-shrink: 0; + + &[data-on-bg='neutral-1'] .bui-Input { + background-color: var(--bui-bg-neutral-2); + } + + &[data-on-bg='neutral-2'] .bui-Input { + background-color: var(--bui-bg-neutral-3); + } + + &[data-on-bg='neutral-3'] .bui-Input { + background-color: var(--bui-bg-neutral-4); + } + } + + .bui-InputWrapper { + position: relative; + + &[data-size='small'] .bui-Input { + height: 2rem; + padding-right: 3.5rem; + } + + &[data-size='medium'] .bui-Input { + height: 2.5rem; + padding-right: 4.5rem; + } + + &[data-size='small'] .bui-Input[data-icon] { + padding-left: var(--bui-space-8); + } + + &[data-size='medium'] .bui-Input[data-icon] { + padding-left: var(--bui-space-9); + } + + &[data-disabled] { + opacity: 0.5; + cursor: not-allowed; + } + } + + .bui-InputIcon { + position: absolute; + left: var(--bui-space-3); + top: 50%; + transform: translateY(-50%); + margin-right: var(--bui-space-1); + color: var(--bui-fg-primary); + flex-shrink: 0; + pointer-events: none; + /* To animate the icon when the input is collapsed */ + transition: left 0.2s ease-in-out; + + &[data-size='small'], + &[data-size='small'] svg { + width: 1rem; + height: 1rem; + } + + &[data-size='medium'], + &[data-size='medium'] svg { + width: 1.25rem; + height: 1.25rem; + } + } + + .bui-Input { + display: flex; + align-items: center; + padding: 0 var(--bui-space-3); + border-radius: var(--bui-radius-2); + border: none; + background-color: var(--bui-bg-neutral-1); + font-size: var(--bui-font-size-3); + font-family: var(--bui-font-regular); + font-weight: var(--bui-font-weight-regular); + color: var(--bui-fg-primary); + transition: box-shadow 0.2s ease-in-out; + width: 100%; + height: 100%; + cursor: inherit; + + &[data-focused] { + outline: none; + box-shadow: inset 0 0 0 1px var(--bui-ring); + } + + &::placeholder { + color: var(--bui-fg-secondary); + } + + &[data-invalid] { + box-shadow: inset 0 0 0 1px var(--bui-border-danger); + } + } + + .bui-StepperButtons { + position: absolute; + right: var(--bui-space-1); + top: 50%; + transform: translateY(-50%); + display: flex; + align-items: center; + } + + .bui-NumberField .bui-StepperButton { + width: 1.5rem; + height: 1.5rem; + } + + .bui-NumberField[data-size='medium'] .bui-StepperButton { + width: 2rem; + height: 2rem; + } +} diff --git a/packages/ui/src/components/NumberField/NumberField.stories.tsx b/packages/ui/src/components/NumberField/NumberField.stories.tsx new file mode 100644 index 0000000000..d395a0abe0 --- /dev/null +++ b/packages/ui/src/components/NumberField/NumberField.stories.tsx @@ -0,0 +1,218 @@ +/* + * Copyright 2026 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import preview from '../../../../../.storybook/preview'; +import { NumberField } from './NumberField'; +import { Form } from 'react-aria-components'; +import { Flex } from '../Flex'; +import { Box } from '../Box'; +import { Text } from '../Text'; +import { FieldLabel } from '../FieldLabel'; +import { RiTimeLine, RiSparklingLine } from '@remixicon/react'; + +const meta = preview.meta({ + title: 'Backstage UI/NumberField', + component: NumberField, + argTypes: { + isRequired: { + control: 'boolean', + }, + icon: { + control: 'object', + }, + }, +}); + +export const Default = meta.story({ + args: { + name: 'quantity', + placeholder: 'Enter a number', + style: { + maxWidth: '300px', + }, + }, +}); + +export const Sizes = meta.story({ + args: { + ...Default.input.args, + }, + render: args => ( + + } /> + } /> + + ), +}); + +export const DefaultValue = meta.story({ + args: { + ...Default.input.args, + defaultValue: 42, + }, +}); + +export const WithLabel = meta.story({ + args: { + ...Default.input.args, + label: 'Label', + }, +}); + +export const WithDescription = meta.story({ + args: { + ...WithLabel.input.args, + description: 'Description', + }, +}); + +export const Required = meta.story({ + args: { + ...WithLabel.input.args, + isRequired: true, + }, +}); + +export const Disabled = meta.story({ + args: { + ...Default.input.args, + isDisabled: true, + }, +}); + +export const WithIcon = meta.story({ + args: { + ...Default.input.args, + }, + render: args => } />, +}); + +export const DisabledWithIcon = WithIcon.extend({ + args: { + isDisabled: true, + }, +}); + +export const ShowError = meta.story({ + args: { + ...WithLabel.input.args, + }, + render: args => ( +
+ + + ), +}); + +export const Validation = meta.story({ + args: { + ...WithLabel.input.args, + validate: (value: number) => (value < 0 ? 'Must be positive' : null), + }, +}); + +export const MinMaxStep = meta.story({ + args: { + ...Default.input.args, + label: 'Minutes', + minValue: 0, + maxValue: 59, + step: 1, + }, + render: args => ( + } + style={{ maxWidth: '200px' }} + /> + ), +}); + +export const CustomField = meta.story({ + render: () => ( + <> + + + + ), +}); + +export const StepIncrement = meta.story({ + args: { + ...WithLabel.input.args, + label: 'Quantity', + defaultValue: 5, + minValue: 0, + maxValue: 20, + step: 5, + }, + render: args => , +}); + +export const AutoBg = meta.story({ + render: () => ( + +
+ NumberField automatically detects its parent bg context and increments + the neutral level by 1. No prop is needed — it's fully automatic. +
+ + Neutral 1 container + + + + + + + Neutral 2 container + + + + + + + + + Neutral 3 container + + + + + + +
+ ), +}); diff --git a/packages/ui/src/components/NumberField/NumberField.tsx b/packages/ui/src/components/NumberField/NumberField.tsx new file mode 100644 index 0000000000..d909909c7a --- /dev/null +++ b/packages/ui/src/components/NumberField/NumberField.tsx @@ -0,0 +1,121 @@ +/* + * Copyright 2026 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { forwardRef, useEffect, useMemo } from 'react'; +import { + Group, + Input, + NumberField as AriaNumberField, +} from 'react-aria-components'; +import { RiAddLine, RiSubtractLine } from '@remixicon/react'; +import { FieldLabel } from '../FieldLabel'; +import { FieldError } from '../FieldError'; +import { ButtonIcon } from '../ButtonIcon'; +import type { NumberFieldProps } from './types'; +import { useDefinition } from '../../hooks/useDefinition'; +import { NumberFieldDefinition } from './definition'; + +/** + * A numeric input with an integrated label, optional icon, and inline error display. + * + * @public + */ +export const NumberField = forwardRef( + (props, ref) => { + const { ownProps, restProps, dataAttributes } = useDefinition( + NumberFieldDefinition, + props, + ); + const { classes, label, icon, secondaryLabel, placeholder, description } = + ownProps; + + useEffect(() => { + if (!label && !restProps['aria-label'] && !restProps['aria-labelledby']) { + console.warn( + 'NumberField requires either a visible label, aria-label, or aria-labelledby for accessibility', + ); + } + }, [label, restProps['aria-label'], restProps['aria-labelledby']]); + + const secondaryLabelText = + secondaryLabel || (restProps.isRequired ? 'Required' : null); + + const formatOptions = useMemo( + () => ({ + useGrouping: false, + ...restProps.formatOptions, + }), + [restProps.formatOptions], + ); + + return ( + + + + {icon && ( + + )} + +
+ } + aria-label="Decrease" + /> + } + aria-label="Increase" + /> +
+
+ +
+ ); + }, +); + +NumberField.displayName = 'NumberField'; diff --git a/packages/ui/src/components/NumberField/definition.ts b/packages/ui/src/components/NumberField/definition.ts new file mode 100644 index 0000000000..fe06bd4d28 --- /dev/null +++ b/packages/ui/src/components/NumberField/definition.ts @@ -0,0 +1,45 @@ +/* + * Copyright 2026 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { defineComponent } from '../../hooks/useDefinition'; +import type { NumberFieldOwnProps } from './types'; +import styles from './NumberField.module.css'; + +/** + * Component definition for NumberField + * @public + */ +export const NumberFieldDefinition = defineComponent()({ + styles, + classNames: { + root: 'bui-NumberField', + inputWrapper: 'bui-InputWrapper', + input: 'bui-Input', + inputIcon: 'bui-InputIcon', + stepperButtons: 'bui-StepperButtons', + stepperButton: 'bui-StepperButton', + }, + bg: 'consumer', + propDefs: { + size: { dataAttribute: true, default: 'small' }, + className: {}, + icon: {}, + placeholder: {}, + label: {}, + description: {}, + secondaryLabel: {}, + }, +}); diff --git a/packages/ui/src/components/NumberField/index.ts b/packages/ui/src/components/NumberField/index.ts new file mode 100644 index 0000000000..2d0be52512 --- /dev/null +++ b/packages/ui/src/components/NumberField/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2026 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './NumberField'; +export * from './types'; +export { NumberFieldDefinition } from './definition'; diff --git a/packages/ui/src/components/NumberField/types.ts b/packages/ui/src/components/NumberField/types.ts new file mode 100644 index 0000000000..b4b223587d --- /dev/null +++ b/packages/ui/src/components/NumberField/types.ts @@ -0,0 +1,50 @@ +/* + * Copyright 2026 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { NumberFieldProps as AriaNumberFieldProps } from 'react-aria-components'; +import type { ReactNode } from 'react'; +import type { Breakpoint } from '../../types'; +import type { FieldLabelProps } from '../FieldLabel/types'; + +/** @public */ +export type NumberFieldOwnProps = { + /** + * The size of the number field + * @defaultValue 'small' + */ + size?: 'small' | 'medium' | Partial>; + + className?: string; + + /** + * An icon to render before the input + */ + icon?: ReactNode; + + /** + * Text to display in the input when it has no value + */ + placeholder?: string; + + label?: FieldLabelProps['label']; + description?: FieldLabelProps['description']; + secondaryLabel?: FieldLabelProps['secondaryLabel']; +}; + +/** @public */ +export interface NumberFieldProps + extends Omit, + NumberFieldOwnProps {} diff --git a/packages/ui/src/definitions.ts b/packages/ui/src/definitions.ts index cb71f5062e..31ebea86a5 100644 --- a/packages/ui/src/definitions.ts +++ b/packages/ui/src/definitions.ts @@ -62,6 +62,7 @@ export { ListRowDefinition, } from './components/List/definition'; export { MenuDefinition } from './components/Menu/definition'; +export { NumberFieldDefinition } from './components/NumberField/definition'; export { PasswordFieldDefinition } from './components/PasswordField/definition'; export { PopoverDefinition } from './components/Popover/definition'; export { RadioGroupDefinition } from './components/RadioGroup/definition'; diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index bc29073767..371edde1d1 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -53,6 +53,7 @@ export * from './components/Tabs'; export * from './components/TagGroup'; export * from './components/Text'; export * from './components/TextField'; +export * from './components/NumberField'; export * from './components/PasswordField'; export * from './components/Tooltip'; export * from './components/Menu';