From e1561c2ade32994baf2f9198f15b4756513c28fc Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Tue, 17 Dec 2024 18:22:23 +0000 Subject: [PATCH] Add Field + Input components Signed-off-by: Charles de Dreuille --- packages/canon/.storybook/preview.tsx | 1 - packages/canon/package.json | 3 +- .../src/components/Field/Field.stories.tsx | 39 +++++++++ packages/canon/src/components/Field/Field.tsx | 84 +++++++++++++++++++ .../canon/src/components/Field/styles.css | 29 +++++++ .../src/components/Input/Input.stories.tsx | 34 ++++++++ packages/canon/src/components/Input/Input.tsx | 33 ++++++++ packages/canon/src/css/components.css | 1 + yarn.lock | 1 + 9 files changed, 223 insertions(+), 2 deletions(-) create mode 100644 packages/canon/src/components/Field/Field.stories.tsx create mode 100644 packages/canon/src/components/Field/Field.tsx create mode 100644 packages/canon/src/components/Field/styles.css create mode 100644 packages/canon/src/components/Input/Input.stories.tsx create mode 100644 packages/canon/src/components/Input/Input.tsx diff --git a/packages/canon/.storybook/preview.tsx b/packages/canon/.storybook/preview.tsx index bb8bbea4ef..1ac53acd86 100644 --- a/packages/canon/.storybook/preview.tsx +++ b/packages/canon/.storybook/preview.tsx @@ -75,7 +75,6 @@ const preview: Preview = { }, }, }, - defaultViewport: 'small', }, }, decorators: [ diff --git a/packages/canon/package.json b/packages/canon/package.json index e151680d5d..f32e559263 100644 --- a/packages/canon/package.json +++ b/packages/canon/package.json @@ -38,7 +38,8 @@ }, "dependencies": { "@base-ui-components/react": "^1.0.0-alpha.4", - "@remixicon/react": "^4.5.0" + "@remixicon/react": "^4.5.0", + "clsx": "^2.1.1" }, "devDependencies": { "@backstage/cli": "workspace:^", diff --git a/packages/canon/src/components/Field/Field.stories.tsx b/packages/canon/src/components/Field/Field.stories.tsx new file mode 100644 index 0000000000..d6f061ac05 --- /dev/null +++ b/packages/canon/src/components/Field/Field.stories.tsx @@ -0,0 +1,39 @@ +/* + * Copyright 2024 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 React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import { Field } from './Field'; +import { Input } from '../Input/Input'; +const meta = { + title: 'Components/Field', + component: Field.Root, + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + Label + + + ), +}; diff --git a/packages/canon/src/components/Field/Field.tsx b/packages/canon/src/components/Field/Field.tsx new file mode 100644 index 0000000000..78cc638662 --- /dev/null +++ b/packages/canon/src/components/Field/Field.tsx @@ -0,0 +1,84 @@ +/* + * Copyright 2024 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 React from 'react'; +import { Field as FieldPrimitive } from '@base-ui-components/react/field'; +import clsx from 'clsx'; + +const FieldRoot = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +FieldRoot.displayName = FieldPrimitive.Root.displayName; + +const FieldLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +FieldLabel.displayName = FieldPrimitive.Label.displayName; + +const FieldDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +FieldDescription.displayName = FieldPrimitive.Description.displayName; + +const FieldError = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +FieldError.displayName = FieldPrimitive.Error.displayName; + +const FieldValidity = ({ + children, + ...props +}: React.ComponentPropsWithoutRef) => ( + + {validityState => children(validityState)} + +); + +export const Field = { + Root: FieldRoot, + Label: FieldLabel, + Description: FieldDescription, + Error: FieldError, + Validity: FieldValidity, +}; diff --git a/packages/canon/src/components/Field/styles.css b/packages/canon/src/components/Field/styles.css new file mode 100644 index 0000000000..728ee87f31 --- /dev/null +++ b/packages/canon/src/components/Field/styles.css @@ -0,0 +1,29 @@ +.canon-fieldRoot { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.canon-fieldLabel { + font-size: 0.875rem; + font-weight: 500; + line-height: 1.25rem; +} + +.canon-fieldControl { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.canon-fieldDescription { + font-size: 0.875rem; + font-weight: 400; + line-height: 1.25rem; +} + +.canon-fieldError { + font-size: 0.875rem; + font-weight: 400; + line-height: 1.25rem; +} diff --git a/packages/canon/src/components/Input/Input.stories.tsx b/packages/canon/src/components/Input/Input.stories.tsx new file mode 100644 index 0000000000..54f8a86768 --- /dev/null +++ b/packages/canon/src/components/Input/Input.stories.tsx @@ -0,0 +1,34 @@ +/* + * Copyright 2024 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 React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import { Input } from './Input'; + +const meta = { + title: 'Components/Input', + component: Input, + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Primary: Story = { + render: () => , +}; diff --git a/packages/canon/src/components/Input/Input.tsx b/packages/canon/src/components/Input/Input.tsx new file mode 100644 index 0000000000..c5b3aad5f5 --- /dev/null +++ b/packages/canon/src/components/Input/Input.tsx @@ -0,0 +1,33 @@ +/* + * Copyright 2024 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 React from 'react'; + +import { Input as InputPrimitive } from '@base-ui-components/react/input'; +import clsx from 'clsx'; + +const Input = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +Input.displayName = InputPrimitive.displayName; + +export { Input }; diff --git a/packages/canon/src/css/components.css b/packages/canon/src/css/components.css index ed602b7ab7..2dc13a7677 100644 --- a/packages/canon/src/css/components.css +++ b/packages/canon/src/css/components.css @@ -25,3 +25,4 @@ @import '../components/Table/styles.css'; @import '../components/Text/styles.css'; @import '../components/Heading/styles.css'; +@import '../components/Field/styles.css'; diff --git a/yarn.lock b/yarn.lock index 1b9fd0a972..6f107b08a6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3826,6 +3826,7 @@ __metadata: "@vanilla-extract/rollup-plugin": ^1.3.10 "@vanilla-extract/sprinkles": ^1.6.3 "@vanilla-extract/webpack-plugin": ^2.3.14 + clsx: ^2.1.1 eslint-plugin-storybook: ^0.11.1 globals: ^15.11.0 mini-css-extract-plugin: ^2.9.2