Fix stories

Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
Charles de Dreuille
2025-03-31 11:23:35 +01:00
parent 18cd90d9ca
commit eb0a0d7fb3
4 changed files with 43 additions and 73 deletions
@@ -1,33 +0,0 @@
/*
* Copyright 2025 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 { PropDef, GetPropDefTypes } from '../../props/prop-def';
/** @public */
export const textFieldPropDefs = {
size: {
type: 'enum',
values: ['small', 'medium'],
className: 'canon-Button--size',
default: 'medium',
responsive: true,
},
} satisfies {
size: PropDef<'small' | 'medium'>;
};
/** @public */
export type TextFieldOwnProps = GetPropDefTypes<typeof textFieldPropDefs>;
@@ -89,26 +89,6 @@ export const Responsive: Story = {
},
};
async function submitForm(value: string) {
// Mimic a server response
await new Promise(resolve => {
setTimeout(resolve, 200);
});
try {
const url = new URL(value);
const allowedHosts = ['example.com', 'beta.example.com', 'www.example.com'];
if (!allowedHosts.includes(url.hostname)) {
return { error: 'The example domain is not allowed' };
}
} catch {
return { error: 'This is not a valid URL' };
}
return { success: true };
}
export const ShowErrorOnSubmit: Story = {
args: {
...WithLabel.args,
@@ -116,30 +96,54 @@ export const ShowErrorOnSubmit: Story = {
type: 'url',
required: true,
label: 'Homepage',
name: 'url',
},
decorators: [
Story => {
const [errors, setErrors] = useState({});
const [loading, setLoading] = useState(false);
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
const formData = new FormData(event.currentTarget);
setLoading(true);
await new Promise(resolve => {
setTimeout(resolve, 200);
});
try {
const url = new URL(formData.get('url') as string);
const allowedHosts = [
'backstage.io',
'beta.backstage.io',
'www.backstage.io',
];
if (!allowedHosts.includes(url.hostname)) {
setErrors({ url: 'The example domain is not allowed' });
setLoading(false);
return;
}
setErrors({});
setLoading(false);
return;
} catch {
setErrors({ url: 'This is not a valid URL' });
setLoading(false);
}
};
return (
<Form
errors={errors}
onClearErrors={setErrors}
onSubmit={async event => {
event.preventDefault();
const formData = new FormData(event.currentTarget);
const value = formData.get('url') as string;
setLoading(true);
const response = await submitForm(value);
const serverErrors = {
url: response.error,
};
setErrors(serverErrors);
setLoading(false);
}}
onClearErrors={() => setErrors({})}
onSubmit={handleSubmit}
>
<Story />
<Button
@@ -161,7 +165,7 @@ export const ShowErrorOnSubmit: Story = {
selector: 'input',
});
await userEvent.type(input, 'https://example.com', {
await userEvent.type(input, 'https://backstage-fake-site.com', {
delay: 20,
});
@@ -16,5 +16,3 @@
export * from './TextField';
export type { TextFieldProps } from './types';
export { textFieldPropDefs } from './TextField.props';
export type { TextFieldOwnProps } from './TextField.props';
@@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { TextFieldOwnProps } from './TextField.props';
import type { Breakpoint } from '../../types';
/** @public */
export interface TextFieldProps
@@ -27,7 +28,7 @@ export interface TextFieldProps
* The size of the text field
* @defaultValue 'medium'
*/
size?: TextFieldOwnProps['size'];
size?: 'small' | 'medium' | Partial<Record<Breakpoint, 'small' | 'medium'>>;
/**
* The label of the text field