Skip to content

Commit f197a30

Browse files
Jeffrey Lauwersclaude
andcommitted
feat(TelephoneInput): opschonen CSS en Storybook toevoegen
- Verwijder dode dsn-telephone-input CSS klassen (component gebruikt dsn-text-input) - Voeg width variants tests toe - Voeg Storybook story, docs.mdx en docs.md toe Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 81a4c1a commit f197a30

5 files changed

Lines changed: 259 additions & 81 deletions

File tree

Lines changed: 1 addition & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,4 @@
11
/**
22
* TelephoneInput Component Styles
3-
* Extends base text input styles for telephone input
3+
* Uses dsn-text-input styles from TextInput.css — no additional styles needed
44
*/
5-
6-
.dsn-telephone-input {
7-
font-family: var(--dsn-form-control-font-family);
8-
font-size: var(--dsn-form-control-font-size);
9-
font-weight: var(--dsn-form-control-font-weight);
10-
line-height: var(--dsn-form-control-line-height);
11-
color: var(--dsn-form-control-text-color);
12-
background-color: var(--dsn-form-control-bg);
13-
border: var(--dsn-form-control-border-width) solid
14-
var(--dsn-form-control-border-color);
15-
border-radius: var(--dsn-form-control-border-radius);
16-
padding-block: var(--dsn-form-control-padding-block);
17-
padding-inline: var(--dsn-form-control-padding-inline);
18-
transition:
19-
border-color var(--dsn-form-control-transition-speed)
20-
var(--dsn-form-control-transition-easing),
21-
background-color var(--dsn-form-control-transition-speed)
22-
var(--dsn-form-control-transition-easing),
23-
box-shadow var(--dsn-form-control-transition-speed)
24-
var(--dsn-form-control-transition-easing);
25-
}
26-
27-
.dsn-telephone-input::placeholder {
28-
color: var(--dsn-form-control-placeholder-text-color);
29-
opacity: 1;
30-
}
31-
32-
.dsn-telephone-input:hover:not(:disabled):not(:read-only) {
33-
border-color: var(--dsn-form-control-hover-border-color);
34-
background-color: var(--dsn-form-control-hover-bg);
35-
}
36-
37-
.dsn-telephone-input:focus {
38-
outline: var(--dsn-focus-outline-width) solid var(--dsn-focus-outline-color);
39-
outline-offset: var(--dsn-focus-outline-offset);
40-
border-color: var(--dsn-form-control-focus-border-color);
41-
background-color: var(--dsn-form-control-focus-bg);
42-
}
43-
44-
.dsn-telephone-input:disabled {
45-
border-color: var(--dsn-form-control-disabled-border-color);
46-
background-color: var(--dsn-form-control-disabled-bg);
47-
color: var(--dsn-form-control-disabled-text-color);
48-
opacity: var(--dsn-form-control-disabled-opacity);
49-
cursor: not-allowed;
50-
}
51-
52-
.dsn-telephone-input:read-only {
53-
border-color: var(--dsn-form-control-readonly-border-color);
54-
background-color: var(--dsn-form-control-readonly-bg);
55-
cursor: default;
56-
}
57-
58-
.dsn-telephone-input--invalid {
59-
border-color: var(--dsn-form-control-invalid-border-color);
60-
}
61-
62-
.dsn-telephone-input--invalid:focus {
63-
outline-color: var(--dsn-form-control-invalid-border-color);
64-
}
65-
66-
/* Width variants */
67-
.dsn-telephone-input--width-xs {
68-
width: var(--dsn-form-control-width-xs);
69-
}
70-
.dsn-telephone-input--width-sm {
71-
width: var(--dsn-form-control-width-sm);
72-
}
73-
.dsn-telephone-input--width-md {
74-
width: var(--dsn-form-control-width-md);
75-
}
76-
.dsn-telephone-input--width-lg {
77-
width: var(--dsn-form-control-width-lg);
78-
}
79-
.dsn-telephone-input--width-xl {
80-
width: var(--dsn-form-control-width-xl);
81-
}
82-
.dsn-telephone-input--width-full {
83-
width: 100%;
84-
}

packages/components-react/src/TelephoneInput/TelephoneInput.test.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,18 @@ describe('TelephoneInput', () => {
8686
expect(screen.getByTestId('input')).toHaveAttribute('autocomplete', 'off');
8787
});
8888

89+
describe('width variants', () => {
90+
it.each(['xs', 'sm', 'md', 'lg', 'xl', 'full'] as const)(
91+
'applies width class for %s',
92+
(w) => {
93+
render(<TelephoneInput width={w} data-testid="input" />);
94+
expect(screen.getByTestId('input')).toHaveClass(
95+
`dsn-text-input--width-${w}`
96+
);
97+
}
98+
);
99+
});
100+
89101
describe('invalid state', () => {
90102
it('sets aria-invalid when invalid prop is true', () => {
91103
render(<TelephoneInput invalid data-testid="input" />);
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# TelephoneInput
2+
3+
Een invoerveld specifiek voor telefoonnummers.
4+
5+
## Doel
6+
7+
De TelephoneInput component is een gespecialiseerd invoerveld voor telefoonnummers. Het gebruikt `type="tel"` voor een geoptimaliseerd toetsenbord op mobiel (met cijfers en koppeltekens direct beschikbaar) en `autocomplete="tel"` zodat de browser opgeslagen telefoonnummers kan aanbieden. Er wordt geen format-validatie afgedwongen — gebruikers kunnen zowel nationale (06 12345678) als internationale (+31 6 12345678) nummers invoeren.
8+
9+
<!-- VOORBEELD -->
10+
11+
## Use when
12+
13+
- Je een telefoonnummer van de gebruiker nodig hebt, bijv. voor een contactformulier of registratie.
14+
- Je wilt dat mobiele gebruikers direct het juiste toetsenbord krijgen.
15+
16+
## Don't use when
17+
18+
- Het om een vrij tekstveld gaat — gebruik dan [TextInput](/docs/components-textinput--docs).
19+
- Je strikte format-validatie wilt afdwingen — doe dit via formuliervalidatie, niet via het inputtype.
20+
21+
## Best practices
22+
23+
- **Gebruik een duidelijke placeholder.** Geef een voorbeeld in het verwachte formaat (bijv. `06 12345678` of `+31 6 12345678`).
24+
- **Dwing geen specifiek formaat af.** Gebruikers typen telefoonnummers op verschillende manieren. Valideer lengte en tekens, maar accepteer variaties in opmaak.
25+
- **Laat browser-autocomplete aan.** De standaard `autocomplete="tel"` helpt gebruikers snel invullen.
26+
- **Combineer met FormField.** Gebruik altijd een label via `FormField` of `FormFieldLabel` voor toegankelijkheid.
27+
- **Geef validatie feedback.** Gebruik de `invalid` prop in combinatie met `aria-invalid` en een `FormFieldErrorMessage`.
28+
29+
## Accessibility
30+
31+
- `type="tel"` geeft op mobiel een toetsenbord met cijfers, koppeltekens en plusteken.
32+
- `autocomplete="tel"` maakt het voor gebruikers eenvoudig om hun telefoonnummer in te vullen.
33+
- Er wordt geen native browservalidatie afgedwongen — valideer zelf in het formulier.
34+
35+
## States
36+
37+
- **Default**: Leeg, klaar voor invoer
38+
- **Filled**: Bevat een telefoonnummer
39+
- **Focus**: Actief, gebruiker typt
40+
- **Hover**: Muis over het veld
41+
- **Disabled**: Niet beschikbaar voor invoer
42+
- **Read-only**: Waarde is zichtbaar maar niet aanpasbaar
43+
- **Invalid**: Validatiefout (bijv. ongeldig telefoonnummer)
44+
45+
## Design tokens
46+
47+
TelephoneInput erft alle tokens van [TextInput](/docs/components-textinput--docs):
48+
49+
| Token | Beschrijving |
50+
| -------------------------------------------- | ------------------------- |
51+
| `--dsn-text-input-font-family` | Lettertypefamilie |
52+
| `--dsn-text-input-font-size` | Font size |
53+
| `--dsn-text-input-font-weight` | Font weight |
54+
| `--dsn-text-input-line-height` | Line height |
55+
| `--dsn-text-input-color` | Tekstkleur |
56+
| `--dsn-text-input-background-color` | Achtergrondkleur |
57+
| `--dsn-text-input-border-color` | Borderkleur default state |
58+
| `--dsn-text-input-border-width` | Dikte van de border |
59+
| `--dsn-text-input-border-radius` | Border radius |
60+
| `--dsn-text-input-padding-block-start` | Padding boven |
61+
| `--dsn-text-input-padding-block-end` | Padding onder |
62+
| `--dsn-text-input-hover-border-color` | Borderkleur hover state |
63+
| `--dsn-text-input-focus-border-color` | Borderkleur focus state |
64+
| `--dsn-text-input-disabled-background-color` | Achtergrondkleur disabled |
65+
| `--dsn-text-input-disabled-color` | Tekstkleur disabled |
66+
| `--dsn-text-input-invalid-border-color` | Borderkleur invalid state |
67+
| `--dsn-text-input-placeholder-color` | Placeholder tekstkleur |
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Meta, Story, Controls, Markdown } from '@storybook/blocks';
2+
import * as TelephoneInputStories from './TelephoneInput.stories';
3+
import docs from './TelephoneInput.docs.md?raw';
4+
5+
export const [intro, rest] = docs.split('<!-- VOORBEELD -->');
6+
7+
<Meta of={TelephoneInputStories} />
8+
9+
<Markdown>{intro}</Markdown>
10+
11+
## Voorbeeld
12+
13+
<Story of={TelephoneInputStories.Default} />
14+
15+
<Controls of={TelephoneInputStories.Default} />
16+
17+
<Markdown>{rest}</Markdown>
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import type { Meta, StoryObj } from '@storybook/react';
2+
import { TelephoneInput } from '@dsn/components-react';
3+
import DocsPage from './TelephoneInput.docs.mdx';
4+
5+
const meta: Meta<typeof TelephoneInput> = {
6+
title: 'Components/TelephoneInput',
7+
component: TelephoneInput,
8+
parameters: {
9+
docs: {
10+
page: DocsPage,
11+
},
12+
},
13+
argTypes: {
14+
placeholder: { control: 'text' },
15+
disabled: { control: 'boolean' },
16+
readOnly: { control: 'boolean' },
17+
invalid: { control: 'boolean' },
18+
required: { control: 'boolean' },
19+
width: {
20+
control: 'select',
21+
options: [undefined, 'xs', 'sm', 'md', 'lg', 'xl', 'full'],
22+
},
23+
},
24+
args: {
25+
placeholder: '06 12345678',
26+
disabled: false,
27+
readOnly: false,
28+
invalid: false,
29+
required: false,
30+
},
31+
};
32+
33+
export default meta;
34+
type Story = StoryObj<typeof TelephoneInput>;
35+
36+
export const Default: Story = {};
37+
38+
export const WithValue: Story = {
39+
name: 'With value',
40+
args: {
41+
defaultValue: '06 12345678',
42+
},
43+
};
44+
45+
export const International: Story = {
46+
name: 'International format',
47+
args: {
48+
defaultValue: '+31 6 12345678',
49+
placeholder: '+31 6 12345678',
50+
},
51+
};
52+
53+
export const Disabled: Story = {
54+
args: {
55+
disabled: true,
56+
value: '06 12345678',
57+
},
58+
};
59+
60+
export const ReadOnly: Story = {
61+
name: 'Read-only',
62+
args: {
63+
readOnly: true,
64+
value: '06 12345678',
65+
},
66+
};
67+
68+
export const Invalid: Story = {
69+
args: {
70+
invalid: true,
71+
value: 'geen nummer',
72+
},
73+
};
74+
75+
export const Widths: Story = {
76+
name: 'Width variants',
77+
render: () => (
78+
<div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
79+
<TelephoneInput width="xs" placeholder="xs" />
80+
<TelephoneInput width="sm" placeholder="sm" />
81+
<TelephoneInput width="md" placeholder="md" />
82+
<TelephoneInput width="lg" placeholder="lg" />
83+
<TelephoneInput width="xl" placeholder="xl" />
84+
<TelephoneInput width="full" placeholder="full" />
85+
</div>
86+
),
87+
};
88+
89+
export const AllStates: Story = {
90+
name: 'All states',
91+
render: () => (
92+
<div
93+
style={{
94+
display: 'flex',
95+
flexDirection: 'column',
96+
gap: '1rem',
97+
maxWidth: '400px',
98+
}}
99+
>
100+
<div>
101+
<label
102+
style={{
103+
display: 'block',
104+
marginBottom: '0.5rem',
105+
fontWeight: 'bold',
106+
}}
107+
>
108+
Default
109+
</label>
110+
<TelephoneInput placeholder="06 12345678" />
111+
</div>
112+
<div>
113+
<label
114+
style={{
115+
display: 'block',
116+
marginBottom: '0.5rem',
117+
fontWeight: 'bold',
118+
}}
119+
>
120+
With value
121+
</label>
122+
<TelephoneInput defaultValue="06 12345678" />
123+
</div>
124+
<div>
125+
<label
126+
style={{
127+
display: 'block',
128+
marginBottom: '0.5rem',
129+
fontWeight: 'bold',
130+
}}
131+
>
132+
Disabled
133+
</label>
134+
<TelephoneInput disabled value="06 12345678" />
135+
</div>
136+
<div>
137+
<label
138+
style={{
139+
display: 'block',
140+
marginBottom: '0.5rem',
141+
fontWeight: 'bold',
142+
}}
143+
>
144+
Read-only
145+
</label>
146+
<TelephoneInput readOnly value="06 12345678" />
147+
</div>
148+
<div>
149+
<label
150+
style={{
151+
display: 'block',
152+
marginBottom: '0.5rem',
153+
fontWeight: 'bold',
154+
}}
155+
>
156+
Invalid
157+
</label>
158+
<TelephoneInput invalid value="geen nummer" />
159+
</div>
160+
</div>
161+
),
162+
};

0 commit comments

Comments
 (0)