Add Field + Input components

Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
Charles de Dreuille
2024-12-17 18:22:23 +00:00
parent 3011db034b
commit e1561c2ade
9 changed files with 223 additions and 2 deletions
-1
View File
@@ -75,7 +75,6 @@ const preview: Preview = {
},
},
},
defaultViewport: 'small',
},
},
decorators: [
+2 -1
View File
@@ -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:^",
@@ -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<typeof Field.Root>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => (
<Field.Root>
<Field.Label>Label</Field.Label>
<Input />
</Field.Root>
),
};
@@ -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<typeof FieldPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof FieldPrimitive.Root>
>(({ className, ...props }, ref) => (
<FieldPrimitive.Root
ref={ref}
className={clsx('canon-fieldRoot', className)}
{...props}
/>
));
FieldRoot.displayName = FieldPrimitive.Root.displayName;
const FieldLabel = React.forwardRef<
React.ElementRef<typeof FieldPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof FieldPrimitive.Label>
>(({ className, ...props }, ref) => (
<FieldPrimitive.Label
ref={ref}
className={clsx('canon-fieldLabel', className)}
{...props}
/>
));
FieldLabel.displayName = FieldPrimitive.Label.displayName;
const FieldDescription = React.forwardRef<
React.ElementRef<typeof FieldPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof FieldPrimitive.Description>
>(({ className, ...props }, ref) => (
<FieldPrimitive.Description
ref={ref}
className={clsx('canon-fieldDescription', className)}
{...props}
/>
));
FieldDescription.displayName = FieldPrimitive.Description.displayName;
const FieldError = React.forwardRef<
React.ElementRef<typeof FieldPrimitive.Error>,
React.ComponentPropsWithoutRef<typeof FieldPrimitive.Error>
>(({ className, ...props }, ref) => (
<FieldPrimitive.Error
ref={ref}
className={clsx('canon-fieldError', className)}
{...props}
/>
));
FieldError.displayName = FieldPrimitive.Error.displayName;
const FieldValidity = ({
children,
...props
}: React.ComponentPropsWithoutRef<typeof FieldPrimitive.Validity>) => (
<FieldPrimitive.Validity {...props}>
{validityState => children(validityState)}
</FieldPrimitive.Validity>
);
export const Field = {
Root: FieldRoot,
Label: FieldLabel,
Description: FieldDescription,
Error: FieldError,
Validity: FieldValidity,
};
@@ -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;
}
@@ -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<typeof Input>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Primary: Story = {
render: () => <Input />,
};
@@ -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<typeof InputPrimitive>,
React.ComponentPropsWithoutRef<typeof InputPrimitive>
>(({ className, ...props }, ref) => (
<InputPrimitive
ref={ref}
className={clsx('canon-input', className)}
{...props}
/>
));
Input.displayName = InputPrimitive.displayName;
export { Input };
+1
View File
@@ -25,3 +25,4 @@
@import '../components/Table/styles.css';
@import '../components/Text/styles.css';
@import '../components/Heading/styles.css';
@import '../components/Field/styles.css';
+1
View File
@@ -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