@boostdev/design-system-components 1.2.0 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +46 -4
- package/README.md +15 -15
- package/dist/client.cjs +149 -124
- package/dist/client.css +503 -525
- package/dist/client.d.cts +71 -96
- package/dist/client.d.ts +71 -96
- package/dist/client.js +149 -124
- package/dist/index.cjs +149 -124
- package/dist/index.css +503 -525
- package/dist/index.d.cts +71 -96
- package/dist/index.d.ts +71 -96
- package/dist/index.js +149 -124
- package/dist/web-components/{chunk-6MH5UWUD.js → chunk-2FGATTGT.js} +5 -0
- package/dist/web-components/{chunk-5IPHEONG.js → chunk-6I2DBFQ7.js} +1 -0
- package/dist/web-components/{chunk-DI46Q2EA.js → chunk-OCODKRVZ.js} +57 -82
- package/dist/web-components/index.d.ts +571 -1
- package/dist/web-components/index.js +1501 -4
- package/dist/web-components/interaction/bds-collapsible.js +1 -1
- package/dist/web-components/interaction/bds-drawer.js +1 -1
- package/dist/web-components/interaction/form/bds-segmented-control.js +1 -1
- package/package.json +1 -1
- package/src/components/interaction/Command/Command.tsx +4 -3
- package/src/components/interaction/Dialog/Dialog.tsx +4 -5
- package/src/components/interaction/Drawer/Drawer.module.css +37 -62
- package/src/components/interaction/Drawer/Drawer.spec.tsx +3 -3
- package/src/components/interaction/Drawer/Drawer.tsx +25 -24
- package/src/components/interaction/DropdownMenu/DropdownMenu.tsx +4 -2
- package/src/components/interaction/Popover/Popover.tsx +4 -3
- package/src/components/interaction/Rating/Rating.tsx +4 -2
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.tsx +4 -6
- package/src/components/interaction/form/Combobox/Combobox.tsx +4 -2
- package/src/components/interaction/form/FileInput/FileInput.tsx +4 -3
- package/src/components/interaction/form/NumberInput/NumberInput.tsx +4 -3
- package/src/components/interaction/form/RadioGroup/RadioGroup.tsx +4 -6
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.mdx +8 -4
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.module.css +13 -6
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.tsx +4 -6
- package/src/components/interaction/form/atoms/InputContainer.tsx +2 -2
- package/src/components/layout/ButtonGroup/ButtonGroup.tsx +4 -6
- package/src/components/layout/Card/Card.tsx +4 -10
- package/src/components/layout/IconWrapper/IconWrapper.tsx +4 -5
- package/src/components/layout/SectionHeader/SectionHeader.tsx +5 -4
- package/src/components/ui/Accordion/Accordion.tsx +4 -3
- package/src/components/ui/Alert/Alert.tsx +4 -3
- package/src/components/ui/Avatar/Avatar.tsx +5 -3
- package/src/components/ui/Badge/Badge.tsx +4 -5
- package/src/components/ui/Breadcrumb/Breadcrumb.tsx +4 -3
- package/src/components/ui/Calendar/Calendar.tsx +4 -4
- package/src/components/ui/Carousel/Carousel.tsx +4 -4
- package/src/components/ui/DescriptionList/DescriptionList.tsx +4 -4
- package/src/components/ui/Loading/Loading.tsx +4 -3
- package/src/components/ui/NotificationBanner/NotificationBanner.tsx +4 -2
- package/src/components/ui/Pagination/Pagination.tsx +4 -2
- package/src/components/ui/Progress/Progress.tsx +4 -2
- package/src/components/ui/ProgressCircle/ProgressCircle.tsx +4 -1
- package/src/components/ui/Separator/Separator.tsx +5 -3
- package/src/components/ui/Skeleton/Skeleton.tsx +4 -3
- package/src/components/ui/SkipLink/SkipLink.tsx +4 -5
- package/src/components/ui/Tabs/Tabs.tsx +4 -4
- package/src/components/ui/Tooltip/Tooltip.tsx +4 -2
- package/src/components/ui/Typography/Typography.tsx +4 -5
- package/src/stories/DesignSystem/Grid.mdx +2 -0
- package/src/stories/Introduction.mdx +2 -1
- package/src/web-components/index.ts +12 -0
- package/src/web-components/interaction/BdsAccordion.mdx +80 -28
- package/src/web-components/interaction/BdsAccordion.stories.tsx +67 -58
- package/src/web-components/interaction/BdsCollapsible.mdx +93 -23
- package/src/web-components/interaction/BdsCollapsible.stories.tsx +29 -48
- package/src/web-components/interaction/BdsDialog.mdx +88 -27
- package/src/web-components/interaction/BdsDialog.stories.tsx +129 -47
- package/src/web-components/interaction/BdsDrawer.mdx +85 -27
- package/src/web-components/interaction/BdsDrawer.stories.tsx +161 -31
- package/src/web-components/interaction/BdsDropdownMenu.mdx +108 -0
- package/src/web-components/interaction/BdsDropdownMenu.stories.tsx +91 -0
- package/src/web-components/interaction/BdsSkipLink.mdx +72 -16
- package/src/web-components/interaction/BdsSkipLink.stories.tsx +47 -34
- package/src/web-components/interaction/BdsTabs.mdx +97 -27
- package/src/web-components/interaction/BdsTabs.stories.tsx +69 -55
- package/src/web-components/interaction/BdsTooltip.mdx +84 -18
- package/src/web-components/interaction/BdsTooltip.stories.tsx +49 -30
- package/src/web-components/interaction/bds-collapsible.ts +1 -0
- package/src/web-components/interaction/bds-drawer.ts +59 -82
- package/src/web-components/interaction/bds-dropdown-menu-item.ts +124 -0
- package/src/web-components/interaction/bds-dropdown-menu.spec.ts +102 -0
- package/src/web-components/interaction/bds-dropdown-menu.ts +200 -0
- package/src/web-components/interaction/form/BdsCheckbox.mdx +57 -20
- package/src/web-components/interaction/form/BdsCheckbox.stories.tsx +35 -36
- package/src/web-components/interaction/form/BdsCheckboxGroup.mdx +70 -0
- package/src/web-components/interaction/form/BdsCheckboxGroup.stories.tsx +81 -0
- package/src/web-components/interaction/form/BdsCombobox.mdx +52 -33
- package/src/web-components/interaction/form/BdsCombobox.stories.tsx +55 -53
- package/src/web-components/interaction/form/BdsFileInput.mdx +59 -24
- package/src/web-components/interaction/form/BdsFileInput.stories.tsx +38 -53
- package/src/web-components/interaction/form/BdsFormInput.mdx +98 -0
- package/src/web-components/interaction/form/BdsFormInput.stories.tsx +139 -0
- package/src/web-components/interaction/form/BdsNumberInput.mdx +51 -22
- package/src/web-components/interaction/form/BdsNumberInput.stories.tsx +24 -46
- package/src/web-components/interaction/form/BdsRadio.mdx +53 -22
- package/src/web-components/interaction/form/BdsRadio.stories.tsx +19 -51
- package/src/web-components/interaction/form/BdsRadioGroup.mdx +73 -0
- package/src/web-components/interaction/form/BdsRadioGroup.stories.tsx +88 -0
- package/src/web-components/interaction/form/BdsSegmentedControl.mdx +76 -23
- package/src/web-components/interaction/form/BdsSegmentedControl.stories.tsx +64 -54
- package/src/web-components/interaction/form/BdsSelect.mdx +59 -21
- package/src/web-components/interaction/form/BdsSelect.stories.tsx +47 -56
- package/src/web-components/interaction/form/BdsSlider.mdx +55 -27
- package/src/web-components/interaction/form/BdsSlider.stories.tsx +23 -44
- package/src/web-components/interaction/form/BdsSwitch.mdx +53 -20
- package/src/web-components/interaction/form/BdsSwitch.stories.tsx +22 -37
- package/src/web-components/interaction/form/BdsTextarea.mdx +54 -22
- package/src/web-components/interaction/form/BdsTextarea.stories.tsx +35 -44
- package/src/web-components/interaction/form/bds-checkbox-group.spec.ts +55 -0
- package/src/web-components/interaction/form/bds-checkbox-group.ts +117 -0
- package/src/web-components/interaction/form/bds-form-input.spec.ts +83 -0
- package/src/web-components/interaction/form/bds-form-input.ts +268 -0
- package/src/web-components/interaction/form/bds-radio-group.spec.ts +62 -0
- package/src/web-components/interaction/form/bds-radio-group.ts +142 -0
- package/src/web-components/interaction/form/bds-segmented-control.ts +5 -0
- package/src/web-components/ui/BdsAvatar.mdx +29 -20
- package/src/web-components/ui/BdsAvatar.stories.tsx +14 -28
- package/src/web-components/ui/BdsBreadcrumb.mdx +22 -19
- package/src/web-components/ui/BdsBreadcrumb.stories.tsx +11 -21
- package/src/web-components/ui/BdsButtonGroup.mdx +69 -0
- package/src/web-components/ui/BdsButtonGroup.stories.tsx +66 -0
- package/src/web-components/ui/BdsCalendar.mdx +93 -0
- package/src/web-components/ui/BdsCalendar.stories.tsx +63 -0
- package/src/web-components/ui/BdsCard.mdx +30 -25
- package/src/web-components/ui/BdsCard.stories.tsx +19 -42
- package/src/web-components/ui/BdsCarousel.mdx +83 -0
- package/src/web-components/ui/BdsCarousel.stories.tsx +96 -0
- package/src/web-components/ui/BdsDescriptionList.mdx +13 -16
- package/src/web-components/ui/BdsDescriptionList.stories.tsx +34 -49
- package/src/web-components/ui/BdsIconWrapper.mdx +20 -20
- package/src/web-components/ui/BdsIconWrapper.stories.tsx +46 -41
- package/src/web-components/ui/BdsLink.mdx +21 -17
- package/src/web-components/ui/BdsLink.stories.tsx +19 -20
- package/src/web-components/ui/BdsLoading.mdx +9 -13
- package/src/web-components/ui/BdsLoading.stories.tsx +8 -10
- package/src/web-components/ui/BdsNotificationBanner.mdx +32 -37
- package/src/web-components/ui/BdsNotificationBanner.stories.tsx +38 -47
- package/src/web-components/ui/BdsPagination.mdx +74 -0
- package/src/web-components/ui/BdsPagination.stories.tsx +36 -0
- package/src/web-components/ui/BdsProgress.mdx +24 -17
- package/src/web-components/ui/BdsProgress.stories.tsx +55 -29
- package/src/web-components/ui/BdsProgressCircle.mdx +24 -18
- package/src/web-components/ui/BdsProgressCircle.stories.tsx +17 -29
- package/src/web-components/ui/BdsRating.mdx +22 -22
- package/src/web-components/ui/BdsRating.stories.tsx +19 -13
- package/src/web-components/ui/BdsSectionHeader.mdx +31 -28
- package/src/web-components/ui/BdsSectionHeader.stories.tsx +21 -23
- package/src/web-components/ui/BdsSeparator.mdx +22 -8
- package/src/web-components/ui/BdsSeparator.stories.tsx +27 -19
- package/src/web-components/ui/BdsSkeleton.mdx +20 -26
- package/src/web-components/ui/BdsSkeleton.stories.tsx +23 -23
- package/src/web-components/ui/BdsTable.mdx +81 -0
- package/src/web-components/ui/BdsTable.stories.tsx +83 -0
- package/src/web-components/ui/BdsTypography.mdx +20 -29
- package/src/web-components/ui/BdsTypography.stories.tsx +19 -18
- package/src/web-components/ui/bds-button-group.spec.ts +40 -0
- package/src/web-components/ui/bds-button-group.ts +78 -0
- package/src/web-components/ui/bds-calendar.spec.ts +91 -0
- package/src/web-components/ui/bds-calendar.ts +427 -0
- package/src/web-components/ui/bds-carousel.spec.ts +64 -0
- package/src/web-components/ui/bds-carousel.ts +296 -0
- package/src/web-components/ui/bds-pagination.spec.ts +67 -0
- package/src/web-components/ui/bds-pagination.ts +197 -0
- package/src/web-components/ui/bds-table.spec.ts +45 -0
- package/src/web-components/ui/bds-table.ts +96 -0
|
@@ -3,42 +3,77 @@ import * as Stories from './BdsFileInput.stories';
|
|
|
3
3
|
|
|
4
4
|
<Meta of={Stories} />
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# <bds-file-input>
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Form-associated file upload zone with drag-and-drop support. Renders a styled drop zone that opens the native file picker on click or keyboard activation.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
> **Status: experimental** — API may change before stable release.
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
import '@boostdev/components/web-components';
|
|
14
16
|
```
|
|
15
17
|
|
|
16
|
-
##
|
|
18
|
+
## When to use
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|------------|-----------|---------|------------------------------------------|
|
|
20
|
-
| `name` | `string` | `""` | Form field name |
|
|
21
|
-
| `accept` | `string` | `""` | File types to accept (e.g. `"image/*"`) |
|
|
22
|
-
| `multiple` | `boolean` | `false` | Allow selecting multiple files |
|
|
23
|
-
| `disabled` | `boolean` | `false` | Disables the drop zone |
|
|
20
|
+
Use `<bds-file-input>` wherever users need to attach one or more files to a form. It provides drag-and-drop as a progressive enhancement on top of the native file picker.
|
|
24
21
|
|
|
25
|
-
##
|
|
22
|
+
## Examples
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
| `bds-change` | `FileList` | Fired when files are selected or dropped |
|
|
24
|
+
### Default
|
|
25
|
+
<Canvas of={Stories.Default} />
|
|
30
26
|
|
|
31
|
-
|
|
27
|
+
### Multiple files
|
|
28
|
+
<Canvas of={Stories.Multiple} />
|
|
32
29
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
| (default) | Custom label text for the zone |
|
|
30
|
+
### Accept images only
|
|
31
|
+
<Canvas of={Stories.WithAccept} />
|
|
36
32
|
|
|
37
|
-
|
|
33
|
+
### Accept PDFs and Word documents
|
|
34
|
+
<Canvas of={Stories.WithPDFAccept} />
|
|
38
35
|
|
|
39
|
-
|
|
40
|
-
<Canvas of={Stories.
|
|
36
|
+
### Disabled
|
|
37
|
+
<Canvas of={Stories.Disabled} />
|
|
41
38
|
|
|
42
|
-
##
|
|
39
|
+
## Props
|
|
43
40
|
|
|
44
41
|
<ArgTypes of={Stories} />
|
|
42
|
+
|
|
43
|
+
## Attributes
|
|
44
|
+
|
|
45
|
+
| Attribute | Type | Default | Description |
|
|
46
|
+
|------------|---------|---------|------------------------------------------------------|
|
|
47
|
+
| `name` | string | `""` | Form field name |
|
|
48
|
+
| `accept` | string | `""` | File types to accept (e.g. `"image/*"`, `".pdf"`) |
|
|
49
|
+
| `multiple` | boolean | `false` | Allow selecting multiple files |
|
|
50
|
+
| `disabled` | boolean | `false` | Disables the file input |
|
|
51
|
+
|
|
52
|
+
## Slots
|
|
53
|
+
|
|
54
|
+
| Slot | Description |
|
|
55
|
+
|-------------|------------------------------------------------|
|
|
56
|
+
| `(default)` | Drop zone call-to-action text. Defaults to "Drag & drop or click to browse" |
|
|
57
|
+
|
|
58
|
+
## Events
|
|
59
|
+
|
|
60
|
+
| Event | Detail | Description |
|
|
61
|
+
|--------------|--------------|-----------------------------------------|
|
|
62
|
+
| `bds-change` | `FileList` | Fired when files are selected or dropped |
|
|
63
|
+
|
|
64
|
+
## Usage in plain HTML
|
|
65
|
+
|
|
66
|
+
```html
|
|
67
|
+
<bds-file-input name="avatar" accept="image/*">Upload photo</bds-file-input>
|
|
68
|
+
|
|
69
|
+
<!-- Multiple files -->
|
|
70
|
+
<bds-file-input name="documents" accept=".pdf,.docx" multiple></bds-file-input>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Accessibility
|
|
74
|
+
|
|
75
|
+
- The drop zone has `role="button"` and `tabindex="0"` so it is keyboard-reachable
|
|
76
|
+
- `aria-label="Upload file"` is set on the zone for screen reader identification
|
|
77
|
+
- `Enter` and `Space` open the native file picker from keyboard focus
|
|
78
|
+
- `disabled` sets `tabindex="-1"` and `pointer-events: none`
|
|
79
|
+
- Participates in HTML forms via the Form-Associated Custom Elements API; files are submitted as `FormData` entries
|
|
@@ -1,84 +1,69 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
-
import '../../index';
|
|
3
|
+
import '../../index'; // auto-registers all custom elements
|
|
4
4
|
|
|
5
5
|
function BdsFileInput({
|
|
6
|
+
name,
|
|
6
7
|
accept,
|
|
7
8
|
multiple,
|
|
8
9
|
disabled,
|
|
10
|
+
children,
|
|
9
11
|
}: {
|
|
12
|
+
name?: string;
|
|
10
13
|
accept?: string;
|
|
11
14
|
multiple?: boolean;
|
|
12
15
|
disabled?: boolean;
|
|
16
|
+
children?: React.ReactNode;
|
|
13
17
|
}) {
|
|
14
|
-
return React.createElement(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
return React.createElement(
|
|
19
|
+
'bds-file-input',
|
|
20
|
+
{
|
|
21
|
+
name,
|
|
22
|
+
accept,
|
|
23
|
+
multiple: multiple || undefined,
|
|
24
|
+
disabled: disabled || undefined,
|
|
25
|
+
},
|
|
26
|
+
children,
|
|
27
|
+
);
|
|
20
28
|
}
|
|
21
29
|
|
|
22
30
|
const meta = {
|
|
23
31
|
title: 'Web Components/Interaction/Form/FileInput',
|
|
24
32
|
component: BdsFileInput,
|
|
25
33
|
tags: ['!stable', 'experimental'],
|
|
26
|
-
parameters: { layout: '
|
|
34
|
+
parameters: { layout: 'centered' },
|
|
27
35
|
argTypes: {
|
|
28
36
|
multiple: { control: 'boolean' },
|
|
29
37
|
disabled: { control: 'boolean' },
|
|
30
38
|
},
|
|
39
|
+
decorators: [
|
|
40
|
+
(Story: React.ComponentType) => (
|
|
41
|
+
<div style={{ width: '360px' }}>
|
|
42
|
+
<Story />
|
|
43
|
+
</div>
|
|
44
|
+
),
|
|
45
|
+
],
|
|
31
46
|
} satisfies Meta<typeof BdsFileInput>;
|
|
32
47
|
|
|
33
48
|
export default meta;
|
|
34
49
|
type Story = StoryObj<typeof meta>;
|
|
35
50
|
|
|
36
|
-
export const Default: Story = {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
export const Disabled: Story = { args: { disabled: true } };
|
|
51
|
+
export const Default: Story = {
|
|
52
|
+
args: { name: 'file' },
|
|
53
|
+
};
|
|
40
54
|
|
|
41
|
-
export const
|
|
42
|
-
|
|
43
|
-
<div style={{ display: 'flex', flexDirection: 'column', gap: '24px', maxInlineSize: '480px' }}>
|
|
44
|
-
<div>
|
|
45
|
-
<p style={{ margin: '0 0 8px', fontSize: '0.75rem', color: '#888' }}>Any file type</p>
|
|
46
|
-
{React.createElement('bds-file-input', { style: { display: 'block' } })}
|
|
47
|
-
</div>
|
|
48
|
-
<div>
|
|
49
|
-
<p style={{ margin: '0 0 8px', fontSize: '0.75rem', color: '#888' }}>Images only</p>
|
|
50
|
-
{React.createElement('bds-file-input', { accept: 'image/*', style: { display: 'block' } })}
|
|
51
|
-
</div>
|
|
52
|
-
<div>
|
|
53
|
-
<p style={{ margin: '0 0 8px', fontSize: '0.75rem', color: '#888' }}>Multiple files</p>
|
|
54
|
-
{React.createElement('bds-file-input', { multiple: true, style: { display: 'block' } })}
|
|
55
|
-
</div>
|
|
56
|
-
<div>
|
|
57
|
-
<p style={{ margin: '0 0 8px', fontSize: '0.75rem', color: '#888' }}>Disabled</p>
|
|
58
|
-
{React.createElement('bds-file-input', { disabled: true, style: { display: 'block' } })}
|
|
59
|
-
</div>
|
|
60
|
-
</div>
|
|
61
|
-
),
|
|
55
|
+
export const Multiple: Story = {
|
|
56
|
+
args: { name: 'files', multiple: true },
|
|
62
57
|
};
|
|
63
58
|
|
|
64
|
-
export const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
},
|
|
75
|
-
})}
|
|
76
|
-
{files.length > 0 && (
|
|
77
|
-
<ul style={{ margin: 0, padding: '0 0 0 16px', fontSize: '0.875rem' }}>
|
|
78
|
-
{files.map(name => <li key={name}>{name}</li>)}
|
|
79
|
-
</ul>
|
|
80
|
-
)}
|
|
81
|
-
</div>
|
|
82
|
-
);
|
|
83
|
-
},
|
|
59
|
+
export const WithAccept: Story = {
|
|
60
|
+
args: { name: 'avatar', accept: 'image/*' },
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const WithPDFAccept: Story = {
|
|
64
|
+
args: { name: 'document', accept: '.pdf,.docx' },
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const Disabled: Story = {
|
|
68
|
+
args: { name: 'file', disabled: true },
|
|
84
69
|
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
|
|
2
|
+
import * as Stories from './BdsFormInput.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={Stories} />
|
|
5
|
+
|
|
6
|
+
# <bds-form-input>
|
|
7
|
+
|
|
8
|
+
Form-associated text input with label, hint, error, and prefix/suffix slot support. Participates in HTML forms via the Form-Associated Custom Elements API.
|
|
9
|
+
|
|
10
|
+
> **Status: experimental** — API may change before stable release.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
import '@boostdev/components/web-components';
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## When to use
|
|
19
|
+
|
|
20
|
+
Use `<bds-form-input>` for single-line text fields in forms. It handles label association, validation states, and prefix/suffix adornments in a single element.
|
|
21
|
+
|
|
22
|
+
## Examples
|
|
23
|
+
|
|
24
|
+
### Default
|
|
25
|
+
<Canvas of={Stories.Default} />
|
|
26
|
+
|
|
27
|
+
### With label
|
|
28
|
+
<Canvas of={Stories.WithLabel} />
|
|
29
|
+
|
|
30
|
+
### With hint
|
|
31
|
+
<Canvas of={Stories.WithHint} />
|
|
32
|
+
|
|
33
|
+
### With error
|
|
34
|
+
<Canvas of={Stories.WithError} />
|
|
35
|
+
|
|
36
|
+
### With prefix (currency symbol)
|
|
37
|
+
<Canvas of={Stories.WithPrefix} />
|
|
38
|
+
|
|
39
|
+
### With suffix (unit)
|
|
40
|
+
<Canvas of={Stories.WithSuffix} />
|
|
41
|
+
|
|
42
|
+
### Email type
|
|
43
|
+
<Canvas of={Stories.Email} />
|
|
44
|
+
|
|
45
|
+
### Disabled
|
|
46
|
+
<Canvas of={Stories.Disabled} />
|
|
47
|
+
|
|
48
|
+
## Props
|
|
49
|
+
|
|
50
|
+
<ArgTypes of={Stories} />
|
|
51
|
+
|
|
52
|
+
## Attributes
|
|
53
|
+
|
|
54
|
+
| Attribute | Type | Default | Description |
|
|
55
|
+
|---------------|---------|----------|----------------------------------------------------------------|
|
|
56
|
+
| `name` | string | `""` | Form field name |
|
|
57
|
+
| `type` | string | `"text"` | Input type: `text`, `email`, `password`, `search`, `url`, `tel` |
|
|
58
|
+
| `value` | string | `""` | Current input value |
|
|
59
|
+
| `placeholder` | string | `""` | Placeholder text |
|
|
60
|
+
| `label` | string | `""` | Visible label text |
|
|
61
|
+
| `hint` | string | — | Helper text shown below the input |
|
|
62
|
+
| `error` | string | — | Error message; when set the input enters error state |
|
|
63
|
+
| `disabled` | boolean | `false` | Disables the input |
|
|
64
|
+
| `required` | boolean | `false` | Marks the field as required |
|
|
65
|
+
|
|
66
|
+
## Slots
|
|
67
|
+
|
|
68
|
+
| Slot | Description |
|
|
69
|
+
|----------|-------------------------------------------|
|
|
70
|
+
| `prefix` | Icon or text rendered before the input |
|
|
71
|
+
| `suffix` | Icon or text rendered after the input |
|
|
72
|
+
|
|
73
|
+
## Events
|
|
74
|
+
|
|
75
|
+
| Event | Detail | Description |
|
|
76
|
+
|--------------|-------------------------|-------------------------------------|
|
|
77
|
+
| `bds-input` | `{ value: string }` | Fired on every keystroke |
|
|
78
|
+
| `bds-change` | `{ value: string }` | Fired when the value is committed |
|
|
79
|
+
|
|
80
|
+
## Usage in plain HTML
|
|
81
|
+
|
|
82
|
+
```html
|
|
83
|
+
<bds-form-input name="email" type="email" label="Email address" required></bds-form-input>
|
|
84
|
+
|
|
85
|
+
<!-- With prefix -->
|
|
86
|
+
<bds-form-input name="price" label="Price">
|
|
87
|
+
<span slot="prefix">€</span>
|
|
88
|
+
</bds-form-input>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Accessibility
|
|
92
|
+
|
|
93
|
+
- `<label>` is associated with the inner `<input>` via matching `id`/`for` attributes
|
|
94
|
+
- `required` adds `aria-required="true"` and a visual asterisk
|
|
95
|
+
- `error` sets `aria-invalid="true"` and links the error message via `aria-describedby`
|
|
96
|
+
- `hint` is linked via `aria-describedby` for screen reader announcement
|
|
97
|
+
- Error messages use `role="alert"` so they are announced immediately
|
|
98
|
+
- The focus ring is applied to the wrapper element, not the inner input
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import '../../index'; // auto-registers all custom elements
|
|
4
|
+
|
|
5
|
+
function BdsFormInput({
|
|
6
|
+
name,
|
|
7
|
+
type,
|
|
8
|
+
value,
|
|
9
|
+
placeholder,
|
|
10
|
+
label,
|
|
11
|
+
hint,
|
|
12
|
+
error,
|
|
13
|
+
disabled,
|
|
14
|
+
required,
|
|
15
|
+
prefix,
|
|
16
|
+
suffix,
|
|
17
|
+
}: {
|
|
18
|
+
name?: string;
|
|
19
|
+
type?: string;
|
|
20
|
+
value?: string;
|
|
21
|
+
placeholder?: string;
|
|
22
|
+
label?: string;
|
|
23
|
+
hint?: string;
|
|
24
|
+
error?: string;
|
|
25
|
+
disabled?: boolean;
|
|
26
|
+
required?: boolean;
|
|
27
|
+
prefix?: React.ReactNode;
|
|
28
|
+
suffix?: React.ReactNode;
|
|
29
|
+
}) {
|
|
30
|
+
const prefixSlot = prefix
|
|
31
|
+
? React.createElement('span', { slot: 'prefix' }, prefix)
|
|
32
|
+
: undefined;
|
|
33
|
+
const suffixSlot = suffix
|
|
34
|
+
? React.createElement('span', { slot: 'suffix' }, suffix)
|
|
35
|
+
: undefined;
|
|
36
|
+
|
|
37
|
+
return React.createElement(
|
|
38
|
+
'bds-form-input',
|
|
39
|
+
{
|
|
40
|
+
name,
|
|
41
|
+
type,
|
|
42
|
+
value,
|
|
43
|
+
placeholder,
|
|
44
|
+
label,
|
|
45
|
+
hint,
|
|
46
|
+
error,
|
|
47
|
+
disabled: disabled || undefined,
|
|
48
|
+
required: required || undefined,
|
|
49
|
+
},
|
|
50
|
+
prefixSlot,
|
|
51
|
+
suffixSlot,
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const meta = {
|
|
56
|
+
title: 'Web Components/Interaction/Form/FormInput',
|
|
57
|
+
component: BdsFormInput,
|
|
58
|
+
tags: ['!stable', 'experimental'],
|
|
59
|
+
parameters: { layout: 'centered' },
|
|
60
|
+
argTypes: {
|
|
61
|
+
type: {
|
|
62
|
+
control: 'select',
|
|
63
|
+
options: ['text', 'email', 'password', 'search', 'url', 'tel'],
|
|
64
|
+
},
|
|
65
|
+
disabled: { control: 'boolean' },
|
|
66
|
+
required: { control: 'boolean' },
|
|
67
|
+
},
|
|
68
|
+
decorators: [
|
|
69
|
+
(Story: React.ComponentType) => (
|
|
70
|
+
<div style={{ width: '320px' }}>
|
|
71
|
+
<Story />
|
|
72
|
+
</div>
|
|
73
|
+
),
|
|
74
|
+
],
|
|
75
|
+
} satisfies Meta<typeof BdsFormInput>;
|
|
76
|
+
|
|
77
|
+
export default meta;
|
|
78
|
+
type Story = StoryObj<typeof meta>;
|
|
79
|
+
|
|
80
|
+
export const Default: Story = {
|
|
81
|
+
args: { name: 'text', placeholder: 'Enter text…' },
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const WithLabel: Story = {
|
|
85
|
+
args: { name: 'username', label: 'Username', placeholder: 'e.g. johndoe' },
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export const WithHint: Story = {
|
|
89
|
+
args: {
|
|
90
|
+
name: 'username',
|
|
91
|
+
label: 'Username',
|
|
92
|
+
placeholder: 'e.g. johndoe',
|
|
93
|
+
hint: 'Must be 3–20 characters.',
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export const WithError: Story = {
|
|
98
|
+
args: {
|
|
99
|
+
name: 'username',
|
|
100
|
+
label: 'Username',
|
|
101
|
+
placeholder: 'e.g. johndoe',
|
|
102
|
+
error: 'Username is already taken.',
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export const WithPrefix: Story = {
|
|
107
|
+
render: () => (
|
|
108
|
+
<div style={{ width: '320px' }}>
|
|
109
|
+
<BdsFormInput name="price" label="Price" placeholder="0.00" prefix="€" />
|
|
110
|
+
</div>
|
|
111
|
+
),
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
export const WithSuffix: Story = {
|
|
115
|
+
render: () => (
|
|
116
|
+
<div style={{ width: '320px' }}>
|
|
117
|
+
<BdsFormInput name="weight" label="Weight" placeholder="0" suffix="kg" />
|
|
118
|
+
</div>
|
|
119
|
+
),
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export const Email: Story = {
|
|
123
|
+
args: {
|
|
124
|
+
name: 'email',
|
|
125
|
+
type: 'email',
|
|
126
|
+
label: 'Email address',
|
|
127
|
+
placeholder: 'you@example.com',
|
|
128
|
+
required: true,
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
export const Disabled: Story = {
|
|
133
|
+
args: {
|
|
134
|
+
name: 'username',
|
|
135
|
+
label: 'Username',
|
|
136
|
+
value: 'johndoe',
|
|
137
|
+
disabled: true,
|
|
138
|
+
},
|
|
139
|
+
};
|
|
@@ -3,39 +3,68 @@ import * as Stories from './BdsNumberInput.stories';
|
|
|
3
3
|
|
|
4
4
|
<Meta of={Stories} />
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# <bds-number-input>
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Form-associated number input with increment and decrement stepper buttons. Hides the browser's native spinners and provides styled stepper controls instead.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
> **Status: experimental** — API may change before stable release.
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
import '@boostdev/components/web-components';
|
|
14
16
|
```
|
|
15
17
|
|
|
18
|
+
## When to use
|
|
19
|
+
|
|
20
|
+
Use `<bds-number-input>` for quantity selectors, counters, or any numeric field where step-by-step incrementing is a common interaction pattern.
|
|
21
|
+
|
|
22
|
+
## Examples
|
|
23
|
+
|
|
24
|
+
### Default
|
|
25
|
+
<Canvas of={Stories.Default} />
|
|
26
|
+
|
|
27
|
+
### With min and max
|
|
28
|
+
<Canvas of={Stories.WithMinMax} />
|
|
29
|
+
|
|
30
|
+
### With custom step (5)
|
|
31
|
+
<Canvas of={Stories.WithStep} />
|
|
32
|
+
|
|
33
|
+
### Disabled
|
|
34
|
+
<Canvas of={Stories.Disabled} />
|
|
35
|
+
|
|
36
|
+
## Props
|
|
37
|
+
|
|
38
|
+
<ArgTypes of={Stories} />
|
|
39
|
+
|
|
16
40
|
## Attributes
|
|
17
41
|
|
|
18
|
-
| Attribute | Type
|
|
19
|
-
|
|
20
|
-
| `name` |
|
|
21
|
-
| `value` |
|
|
22
|
-
| `min` |
|
|
23
|
-
| `max` |
|
|
24
|
-
| `step` |
|
|
25
|
-
| `disabled` |
|
|
42
|
+
| Attribute | Type | Default | Description |
|
|
43
|
+
|------------|---------|-------------|------------------------------------------|
|
|
44
|
+
| `name` | string | `""` | Form field name |
|
|
45
|
+
| `value` | number | `0` | Current numeric value |
|
|
46
|
+
| `min` | number | — | Minimum allowed value |
|
|
47
|
+
| `max` | number | — | Maximum allowed value |
|
|
48
|
+
| `step` | number | `1` | Increment/decrement step |
|
|
49
|
+
| `disabled` | boolean | `false` | Disables the input and steppers |
|
|
26
50
|
|
|
27
51
|
## Events
|
|
28
52
|
|
|
29
|
-
| Event | Description
|
|
30
|
-
|
|
31
|
-
| `input` | Fired on stepper click and native input
|
|
32
|
-
| `change` | Native change event
|
|
53
|
+
| Event | Detail | Description |
|
|
54
|
+
|----------|--------|-------------------------------------------------------|
|
|
55
|
+
| `input` | — | Fired on stepper click and native input |
|
|
56
|
+
| `change` | — | Native change event from the inner `<input type="number">` |
|
|
33
57
|
|
|
34
|
-
##
|
|
58
|
+
## Usage in plain HTML
|
|
35
59
|
|
|
36
|
-
|
|
37
|
-
<
|
|
60
|
+
```html
|
|
61
|
+
<bds-number-input name="qty" value="1" min="0" max="99" step="1"></bds-number-input>
|
|
62
|
+
```
|
|
38
63
|
|
|
39
|
-
##
|
|
64
|
+
## Accessibility
|
|
40
65
|
|
|
41
|
-
|
|
66
|
+
- Decrement button has `aria-label="Decrease"` and increment has `aria-label="Increase"`
|
|
67
|
+
- Stepper buttons are disabled when the value is at `min` or `max`
|
|
68
|
+
- The stepper buttons use `tabindex="-1"` so keyboard users navigate directly to the numeric input
|
|
69
|
+
- `disabled` disables both the input and the stepper buttons
|
|
70
|
+
- Participates in HTML forms via the Form-Associated Custom Elements API
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
-
import '../../index';
|
|
3
|
+
import '../../index'; // auto-registers all custom elements
|
|
4
4
|
|
|
5
5
|
function BdsNumberInput({
|
|
6
|
+
name,
|
|
6
7
|
value,
|
|
7
8
|
min,
|
|
8
9
|
max,
|
|
9
10
|
step,
|
|
10
11
|
disabled,
|
|
11
12
|
}: {
|
|
13
|
+
name?: string;
|
|
12
14
|
value?: number;
|
|
13
15
|
min?: number;
|
|
14
16
|
max?: number;
|
|
@@ -16,12 +18,12 @@ function BdsNumberInput({
|
|
|
16
18
|
disabled?: boolean;
|
|
17
19
|
}) {
|
|
18
20
|
return React.createElement('bds-number-input', {
|
|
21
|
+
name,
|
|
19
22
|
value,
|
|
20
23
|
min,
|
|
21
24
|
max,
|
|
22
25
|
step,
|
|
23
26
|
disabled: disabled || undefined,
|
|
24
|
-
style: { display: 'block', maxInlineSize: '160px' },
|
|
25
27
|
});
|
|
26
28
|
}
|
|
27
29
|
|
|
@@ -29,62 +31,38 @@ const meta = {
|
|
|
29
31
|
title: 'Web Components/Interaction/Form/NumberInput',
|
|
30
32
|
component: BdsNumberInput,
|
|
31
33
|
tags: ['!stable', 'experimental'],
|
|
32
|
-
parameters: { layout: '
|
|
34
|
+
parameters: { layout: 'centered' },
|
|
33
35
|
argTypes: {
|
|
36
|
+
disabled: { control: 'boolean' },
|
|
34
37
|
value: { control: 'number' },
|
|
35
38
|
min: { control: 'number' },
|
|
36
39
|
max: { control: 'number' },
|
|
37
40
|
step: { control: 'number' },
|
|
38
|
-
disabled: { control: 'boolean' },
|
|
39
41
|
},
|
|
42
|
+
decorators: [
|
|
43
|
+
(Story: React.ComponentType) => (
|
|
44
|
+
<div style={{ width: '200px' }}>
|
|
45
|
+
<Story />
|
|
46
|
+
</div>
|
|
47
|
+
),
|
|
48
|
+
],
|
|
40
49
|
} satisfies Meta<typeof BdsNumberInput>;
|
|
41
50
|
|
|
42
51
|
export default meta;
|
|
43
52
|
type Story = StoryObj<typeof meta>;
|
|
44
53
|
|
|
45
|
-
export const Default: Story = {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
export const Disabled: Story = { args: { value: 42, disabled: true } };
|
|
54
|
+
export const Default: Story = {
|
|
55
|
+
args: { name: 'quantity', value: 0 },
|
|
56
|
+
};
|
|
49
57
|
|
|
50
|
-
export const
|
|
51
|
-
|
|
52
|
-
<div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
|
|
53
|
-
<div>
|
|
54
|
-
<p style={{ margin: '0 0 4px', fontSize: '0.75rem', color: '#888' }}>Default</p>
|
|
55
|
-
{React.createElement('bds-number-input', { value: 0, style: { display: 'block', maxInlineSize: '160px' } })}
|
|
56
|
-
</div>
|
|
57
|
-
<div>
|
|
58
|
-
<p style={{ margin: '0 0 4px', fontSize: '0.75rem', color: '#888' }}>Bounded (0–10)</p>
|
|
59
|
-
{React.createElement('bds-number-input', { value: 5, min: 0, max: 10, style: { display: 'block', maxInlineSize: '160px' } })}
|
|
60
|
-
</div>
|
|
61
|
-
<div>
|
|
62
|
-
<p style={{ margin: '0 0 4px', fontSize: '0.75rem', color: '#888' }}>Step 5</p>
|
|
63
|
-
{React.createElement('bds-number-input', { value: 50, min: 0, max: 100, step: 5, style: { display: 'block', maxInlineSize: '160px' } })}
|
|
64
|
-
</div>
|
|
65
|
-
<div>
|
|
66
|
-
<p style={{ margin: '0 0 4px', fontSize: '0.75rem', color: '#888' }}>Disabled</p>
|
|
67
|
-
{React.createElement('bds-number-input', { value: 7, disabled: true, style: { display: 'block', maxInlineSize: '160px' } })}
|
|
68
|
-
</div>
|
|
69
|
-
</div>
|
|
70
|
-
),
|
|
58
|
+
export const WithMinMax: Story = {
|
|
59
|
+
args: { name: 'quantity', value: 5, min: 0, max: 10 },
|
|
71
60
|
};
|
|
72
61
|
|
|
73
|
-
export const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
{React.createElement('bds-number-input', {
|
|
80
|
-
value: qty,
|
|
81
|
-
min: 1,
|
|
82
|
-
max: 99,
|
|
83
|
-
step: 1,
|
|
84
|
-
style: { display: 'block', maxInlineSize: '160px' },
|
|
85
|
-
onInput: (e: Event) => setQty(parseInt((e.target as HTMLInputElement).value, 10) || 1),
|
|
86
|
-
})}
|
|
87
|
-
</div>
|
|
88
|
-
);
|
|
89
|
-
},
|
|
62
|
+
export const WithStep: Story = {
|
|
63
|
+
args: { name: 'quantity', value: 0, step: 5, min: 0, max: 100 },
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const Disabled: Story = {
|
|
67
|
+
args: { name: 'quantity', value: 3, disabled: true },
|
|
90
68
|
};
|