Skip to content

Commit 86fe890

Browse files
committed
refactor: move Input.Affix to Field (#2714)
resolves #2640 - Did not create a changeset as this is unreleased/undocumented feature that has just been shifted around now. - Moved and renamed `Affix` & `AffixWrapper` from `Input` to `Field` - Added a story with example using other field types (input, textarea, select) - Created separate issue for further work on missing features #2715
1 parent 2e38fb7 commit 86fe890

File tree

10 files changed

+116
-94
lines changed

10 files changed

+116
-94
lines changed

packages/css/field.css

+37
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,40 @@
6767
}
6868
}
6969
}
70+
71+
/**
72+
* Affix
73+
*/
74+
.ds-field-affix {
75+
--dsc-field-affix-border: 1px solid var(--ds-color-neutral-border-default);
76+
--dsc-field-affix-padding-inline: var(--ds-spacing-4);
77+
78+
align-items: center;
79+
background: var(--ds-color-neutral-background-subtle);
80+
border-radius: var(--ds-border-radius-md);
81+
box-sizing: border-box;
82+
color: var(--ds-color-neutral-text-subtle);
83+
display: inline-flex; /* Using inline-flex to match native inline-block behaviour of <input> */
84+
gap: var(--dsc-field-affix-padding-inline);
85+
padding-inline: var(--dsc-field-affix-padding-inline);
86+
position: relative;
87+
white-space: nowrap;
88+
width: fit-content;
89+
90+
/* Using ::before to make input border overlap addons border */
91+
&::before {
92+
border-radius: inherit;
93+
border: var(--dsc-field-affix-border);
94+
content: '';
95+
inset: 0;
96+
pointer-events: none;
97+
position: absolute;
98+
}
99+
100+
/* Using double selector to ensure we win specificity */
101+
.ds-input.ds-input {
102+
border-radius: 0;
103+
border: var(--dsc-field-affix-border);
104+
flex: 1 1 auto;
105+
}
106+
}

packages/css/input.css

-37
Original file line numberDiff line numberDiff line change
@@ -180,40 +180,3 @@
180180
}
181181
}
182182
}
183-
184-
/**
185-
* Affix
186-
*/
187-
.ds-input-affix {
188-
--dsc-input-affix-border: 1px solid var(--ds-color-neutral-border-default);
189-
--dsc-input-affix-padding-inline: var(--ds-spacing-4);
190-
191-
align-items: center;
192-
background: var(--ds-color-neutral-background-subtle);
193-
border-radius: var(--ds-border-radius-md);
194-
box-sizing: border-box;
195-
color: var(--ds-color-neutral-text-subtle);
196-
display: inline-flex; /* Using inline-flex to match native inline-block behaviour of <input> */
197-
gap: var(--dsc-input-affix-padding-inline);
198-
padding-inline: var(--dsc-input-affix-padding-inline);
199-
position: relative;
200-
white-space: nowrap;
201-
width: fit-content;
202-
203-
/* Using ::before to make input border overlap addons border */
204-
&::before {
205-
border-radius: inherit;
206-
border: var(--dsc-input-affix-border);
207-
content: '';
208-
inset: 0;
209-
pointer-events: none;
210-
position: absolute;
211-
}
212-
213-
/* Using double selector to ensure we win specificity */
214-
.ds-input.ds-input {
215-
border-radius: 0;
216-
border: var(--dsc-input-affix-border);
217-
flex: 1 1 auto;
218-
}
219-
}
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
1-
import { Meta, Controls, Primary } from '@storybook/blocks';
1+
import { Meta, Controls, Primary, Canvas } from '@storybook/blocks';
22

33
import * as FieldStories from './Field.stories';
44

55
<Meta of={FieldStories} />
66

77
<Primary />
88
<Controls />
9+
10+
11+
## Prefix/Suffix
12+
13+
Prefixer og suffixer er nyttige for å vise enheter, valuta eller andre typer informasjon som er relevant for feltet.
14+
Du skal **ikke** bruke disse alene, siden skjermlesere ikke leser dem opp.
15+
Det er viktig at samme informasjon som vises i prefixet eller suffixet også er inkludert i ledeteksten.
16+
17+
<Canvas of={FieldStories.Adornments} />

packages/react/src/components/form/Field/Field.stories.tsx

+33
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,36 @@ export const Preview: Story = (args) => {
7979

8080
// @ts-expect-error ts2559: Preview.args uses more properties for testing than what is supported by <Field>
8181
Preview.args = toggles;
82+
83+
export const Adornments: Story = () => (
84+
<div>
85+
<Field>
86+
<Label>Hvor mange kroner koster det per måned?</Label>
87+
<Field.AffixWrapper>
88+
<Field.Affix>NOK</Field.Affix>
89+
<Input />
90+
<Field.Affix>pr.mnd</Field.Affix>
91+
</Field.AffixWrapper>
92+
</Field>
93+
<Field>
94+
<Label>Hvor mange kilo veier eplene du har valgt?</Label>
95+
<Field.AffixWrapper>
96+
<Textarea rows={2} cols={4} />
97+
<Field.Affix>NOK</Field.Affix>
98+
</Field.AffixWrapper>
99+
</Field>
100+
101+
<Field>
102+
<Label>Hvor mange kroner koster det per måned?</Label>
103+
<Field.AffixWrapper>
104+
<Select>
105+
<Select.Option value='-1'>Velg &hellip;</Select.Option>
106+
<Select.Option value='10'>10kr</Select.Option>
107+
<Select.Option value='20'>20kr</Select.Option>
108+
<Select.Option value='30'>30kr</Select.Option>
109+
</Select>
110+
<Field.Affix>pr.mnd</Field.Affix>
111+
</Field.AffixWrapper>
112+
</Field>
113+
</div>
114+
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import cl from 'clsx/lite';
2+
import type { HTMLAttributes } from 'react';
3+
import { forwardRef } from 'react';
4+
5+
export type FieldAffixWrapperProps = Omit<
6+
HTMLAttributes<HTMLDivElement>,
7+
'prefix'
8+
>;
9+
10+
export const FieldAffixWrapper = forwardRef<
11+
HTMLDivElement,
12+
FieldAffixWrapperProps
13+
>(function FieldAffixWrapper({ className, ...rest }, ref) {
14+
return (
15+
<div className={cl('ds-field-affix', className)} ref={ref} {...rest} />
16+
);
17+
});
18+
19+
export type FieldAffixProps = Omit<HTMLAttributes<HTMLDivElement>, 'prefix'>;
20+
21+
export const FieldAffix = forwardRef<HTMLSpanElement, FieldAffixProps>(
22+
function FieldAffix(rest, ref) {
23+
return <span aria-hidden='true' ref={ref} {...rest} />;
24+
},
25+
);

packages/react/src/components/form/Field/index.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Field as FieldParent } from './Field';
2+
import { FieldAffix, FieldAffixWrapper } from './FieldAffix';
23
import { FieldDescription } from './FieldDescription';
34

45
/**
@@ -12,10 +13,18 @@ import { FieldDescription } from './FieldDescription';
1213
*/
1314
const Field = Object.assign(FieldParent, {
1415
Description: FieldDescription,
16+
AffixWrapper: FieldAffixWrapper,
17+
Affix: FieldAffix,
1518
});
1619

1720
Field.Description.displayName = 'Field.Description';
21+
Field.AffixWrapper.displayName = 'Field.AffixWrapper';
22+
Field.Affix.displayName = 'Field.Affix';
1823

24+
export type {
25+
FieldAffixProps,
26+
FieldAffixWrapperProps,
27+
} from './FieldAffix';
1928
export type { FieldProps } from './Field';
2029
export type { FieldDescriptionProps } from './FieldDescription';
21-
export { Field, FieldDescription };
30+
export { Field, FieldDescription, FieldAffix, FieldAffixWrapper };

packages/react/src/components/form/Input/Input.mdx

-8
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,6 @@ import * as InputStories from './Input.stories';
1616
<Primary />
1717
<Controls />
1818

19-
## Prefix/Suffix
20-
21-
Prefixer og suffixer er nyttige for å vise enheter, valuta eller andre typer informasjon som er relevant for feltet.
22-
Du skal **ikke** bruke disse alene, siden skjermlesere ikke leser dem opp.
23-
Det er viktig at samme informasjon som vises i prefixet eller suffixet også er inkludert i ledeteksten.
24-
25-
<Canvas of={InputStories.Adornments} />
26-
2719
## Kontrollert
2820

2921
<Canvas of={InputStories.Controlled} />

packages/react/src/components/form/Input/Input.stories.tsx

-11
Original file line numberDiff line numberDiff line change
@@ -114,17 +114,6 @@ export const HtmlSize: Story = {
114114
),
115115
};
116116

117-
export const Adornments: StoryFn<typeof Input> = (args) => (
118-
<Field>
119-
<Label>Hvor mange kroner koster det per måned?</Label>
120-
<Input.AffixWrapper>
121-
<Input.Affix>NOK</Input.Affix>
122-
<Input {...args} />
123-
<Input.Affix>pr.mnd</Input.Affix>
124-
</Input.AffixWrapper>
125-
</Field>
126-
);
127-
128117
export const Controlled: StoryFn<typeof Input> = (args) => {
129118
const [value, setValue] = useState<string>();
130119

packages/react/src/components/form/Input/InputAffix.tsx

-23
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,2 @@
1-
import { Input as InputComp } from './Input';
2-
import { InputAffix, InputAffixWrapper } from './InputAffix';
3-
4-
const Input = Object.assign(InputComp, {
5-
Affix: InputAffix,
6-
AffixWrapper: InputAffixWrapper,
7-
});
8-
9-
Input.Affix.displayName = 'Input.Affix';
10-
Input.AffixWrapper.displayName = 'Input.AffixWrapper';
11-
1+
export { Input } from './Input';
122
export type { InputProps } from './Input';
13-
export type { InputAffixProps, InputAffixWrapperProps } from './InputAffix';
14-
export { Input, InputAffix, InputAffixWrapper };

0 commit comments

Comments
 (0)