Skip to content

Commit

Permalink
feat(sbb-form-field): introduce size s (#2995)
Browse files Browse the repository at this point in the history
Closes #2545
Closes #2764
Replaces #2610
---------

Co-authored-by: Davide Mininni <[email protected]>
  • Loading branch information
jeripeierSBB and Davide Mininni committed Aug 14, 2024
1 parent fbb6ca6 commit 9abb131
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 21 deletions.
68 changes: 53 additions & 15 deletions src/elements/form-field/form-field/form-field.scss
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,25 @@
var(--sbb-icon-svg-width) + var(--sbb-form-field-gap)
);
--sbb-form-field-overflow: hidden;
--sbb-form-field-input-text-size: var(--sbb-font-size-text-m);
--sbb-form-field-label-text-size: var(--sbb-font-size-text-xs);
--sbb-form-field-label-size: calc(
var(--sbb-font-size-text-xs) * var(--sbb-typo-line-height-body-text)
var(--sbb-form-field-label-text-size) * var(--sbb-typo-line-height-body-text)
);
--sbb-form-field-input-size: calc(
var(--sbb-font-size-text-m) * var(--sbb-typo-line-height-body-text)
--sbb-form-field-text-line-height: calc(
var(--sbb-form-field-input-text-size) * var(--sbb-typo-line-height-body-text)
);
--sbb-form-field-margin-block-start: calc(
(
var(--sbb-form-field-min-height) - var(--sbb-form-field-label-size) - var(
--sbb-form-field-input-size
--sbb-form-field-text-line-height
) + var(--sbb-form-field-label-to-input-overlapping)
) / 2
);
--sbb-form-field-spacer-margin-block-end: calc(
-1 * var(--sbb-form-field-label-to-input-overlapping)
);
--sbb-form-field-floating-label-transform: #{sbb.px-to-rem-build(8.5)};

// Lock sbb-icon size
--sbb-icon-svg-width: var(--sbb-size-icon-ui-small);
Expand All @@ -47,6 +53,10 @@
// to default color for cases where the form field is used in a negative context.
--sbb-focus-outline-color: var(--sbb-focus-outline-color-default);

@include sbb.mq($from: medium) {
--sbb-form-field-floating-label-transform: #{sbb.px-to-rem-build(10.5)};
}

@include sbb.if-forced-colors {
--sbb-form-field-border-color: ButtonBorder;
}
Expand All @@ -71,6 +81,25 @@
}
}

:host([size='s']) {
--sbb-form-field-min-height: var(--sbb-size-element-xs);
--sbb-form-field-padding-inline: var(--sbb-spacing-fixed-2x);
--sbb-form-field-input-text-size: var(--sbb-font-size-text-s);
--sbb-form-field-label-text-size: var(--sbb-font-size-text-xxs);

// Values found by try and error
--sbb-form-field-label-to-input-overlapping: #{sbb.px-to-rem-build(10)};
--sbb-form-field-floating-label-transform: #{sbb.px-to-rem-build(5.5)};
--sbb-form-field-spacer-margin-block-end: #{sbb.px-to-rem-build(-8.5)};

@include sbb.mq($from: medium) {
// Values found by try and error
--sbb-form-field-label-to-input-overlapping: #{sbb.px-to-rem-build(11)};
--sbb-form-field-floating-label-transform: #{sbb.px-to-rem-build(5)};
--sbb-form-field-spacer-margin-block-end: #{sbb.px-to-rem-build(-8)};
}
}

:host([size='l']) {
--sbb-form-field-min-height: var(--sbb-size-element-l);
--sbb-form-field-padding-inline: var(--sbb-spacing-responsive-xxxs);
Expand Down Expand Up @@ -284,10 +313,10 @@

.sbb-form-field__label-spacer {
display: flex;
height: calc(var(--sbb-font-size-text-xs) * var(--sbb-typo-line-height-body-text));
height: calc(var(--sbb-form-field-label-text-size) * var(--sbb-typo-line-height-body-text));

// Moves label down and input up to meet positioning requirements
margin-block-end: calc(-1 * var(--sbb-form-field-label-to-input-overlapping));
margin-block-end: var(--sbb-form-field-spacer-margin-block-end);
}

// To avoid doubled payload, we group the rules.
Expand All @@ -302,15 +331,22 @@
}

.sbb-form-field__label {
@include sbb.text-xs--regular;

display: flex;
max-width: 100%;
cursor: default;
position: absolute;
inset-block-start: 0;
color: var(--sbb-form-field-label-color);

// Textarea with forced colors active needs to have the label a level higher
z-index: 1;

@include sbb.text-xs--regular;

:host([size='s']) & {
@include sbb.text-xxs--regular;
}

:host([data-input-type='select']) &,
:host([data-input-type='sbb-select']) & {
padding-inline-end: var(--sbb-form-field-select-inline-padding-end);
Expand Down Expand Up @@ -340,12 +376,8 @@
)[data-input-empty]
)
& {
font-size: var(--sbb-font-size-text-m);
transform: translateY(#{sbb.px-to-rem-build(8.5)});

@include sbb.mq($from: medium) {
transform: translateY(#{sbb.px-to-rem-build(10.5)});
}
font-size: var(--sbb-form-field-input-text-size);
transform: translateY(var(--sbb-form-field-floating-label-transform));
}
}

Expand All @@ -355,6 +387,12 @@

.sbb-form-field__input {
display: flex;

:host([size='s']:is([data-input-type='input'], [data-input-type='select'])) & {
// In size s, the natural height of the text input is too small.
// To not reserve too much space, we decrease the height.
margin-block-end: #{sbb.px-to-rem-build(-2)};
}
}

// Input
Expand All @@ -379,7 +417,7 @@

// To be more specific than the styles in normalize.scss we need to use !important
// TODO: Find a better solution
font-size: var(--sbb-font-size-text-m) !important;
font-size: var(--sbb-form-field-input-text-size) !important;
font-family: var(--sbb-typo-font-family) !important;
line-height: var(--sbb-typo-line-height-body-text) !important;

Expand Down
84 changes: 81 additions & 3 deletions src/elements/form-field/form-field/form-field.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ const size: InputType = {
control: {
type: 'inline-radio',
},
options: ['m', 'l'],
options: ['s', 'm', 'l'],
table: {
category: 'Form-field',
},
Expand Down Expand Up @@ -458,7 +458,7 @@ const basicArgs: Args = {
'floating-label': false,
optional: false,
borderless: false,
size: size.options![0],
size: size.options![1],
negative: false,
cssClass: '',
placeholder: 'Input placeholder',
Expand All @@ -482,10 +482,16 @@ export const InputSizeL: StoryObj = {
args: {
...basicArgs,
value: 'This input value is so long that it needs ellipsis to fit.',
size: 'l',
size: size.options![2],
},
};

export const InputSizeS: StoryObj = {
render: TemplateInput,
argTypes: basicArgTypes,
args: { ...basicArgs, size: size.options![0] },
};

export const InputNoLabel: StoryObj = {
render: TemplateInput,
argTypes: basicArgTypes,
Expand Down Expand Up @@ -528,6 +534,18 @@ export const InputOptionalAndIcons: StoryObj = {
args: { ...basicArgs, optional: true },
};

export const InputOptionalAndIconsSizeS: StoryObj = {
render: TemplateInputWithIcons,
argTypes: basicArgTypes,
args: { ...basicArgs, optional: true, size: size.options![0] },
};

export const InputOptionalAndIconsSizeL: StoryObj = {
render: TemplateInputWithIcons,
argTypes: basicArgTypes,
args: { ...basicArgs, optional: true, size: size.options![2] },
};

export const InputWithMiniButton: StoryObj = {
render: TemplateInputWithMiniButton,
argTypes: basicArgTypes,
Expand Down Expand Up @@ -639,6 +657,18 @@ export const SelectOptionalAndIcons: StoryObj = {
args: { ...basicArgs, optional: true },
};

export const SelectOptionalAndIconsSizeS: StoryObj = {
render: TemplateSelectWithIcons,
argTypes: basicArgTypes,
args: { ...basicArgs, optional: true, size: size.options![0] },
};

export const SelectOptionalAndIconsSizeL: StoryObj = {
render: TemplateSelectWithIcons,
argTypes: basicArgTypes,
args: { ...basicArgs, optional: true, size: size.options![2] },
};

export const Textarea: StoryObj = {
render: TemplateTextarea,
argTypes: basicArgTypes,
Expand Down Expand Up @@ -675,6 +705,18 @@ export const TextareaOptionalAndIcon: StoryObj = {
args: { ...basicArgs, optional: true },
};

export const TextareaOptionalAndIconSizeS: StoryObj = {
render: TemplateTextareaWithIcon,
argTypes: basicArgTypes,
args: { ...basicArgs, optional: true, size: size.options![0] },
};

export const TextareaOptionalAndIconSizeL: StoryObj = {
render: TemplateTextareaWithIcon,
argTypes: basicArgTypes,
args: { ...basicArgs, optional: true, size: size.options![2] },
};

export const TextareaFloatingLabel: StoryObj = {
render: TemplateTextarea,
argTypes: basicArgTypes,
Expand Down Expand Up @@ -754,6 +796,18 @@ export const InputOptionalAndIconsNegative: StoryObj = {
args: { ...basicArgs, optional: true, negative: true },
};

export const InputOptionalAndIconsNegativeSizeS: StoryObj = {
render: TemplateInputWithIcons,
argTypes: basicArgTypes,
args: { ...basicArgs, optional: true, negative: true, size: size.options![0] },
};

export const InputOptionalAndIconsNegativeSizeL: StoryObj = {
render: TemplateInputWithIcons,
argTypes: basicArgTypes,
args: { ...basicArgs, optional: true, negative: true, size: size.options![2] },
};

export const InputWithMiniButtonNegative: StoryObj = {
render: TemplateInputWithMiniButton,
argTypes: basicArgTypes,
Expand Down Expand Up @@ -868,6 +922,18 @@ export const SelectOptionalAndIconsNegative: StoryObj = {
args: { ...basicArgs, optional: true, negative: true },
};

export const SelectOptionalAndIconsNegativeSizeS: StoryObj = {
render: TemplateSelectWithIcons,
argTypes: basicArgTypes,
args: { ...basicArgs, optional: true, negative: true, size: size.options![0] },
};

export const SelectOptionalAndIconsNegativeSizeL: StoryObj = {
render: TemplateSelectWithIcons,
argTypes: basicArgTypes,
args: { ...basicArgs, optional: true, negative: true, size: size.options![2] },
};

export const InputCollapsedWidthNegative: StoryObj = {
render: TemplateInput,
argTypes: basicArgTypes,
Expand Down Expand Up @@ -916,6 +982,18 @@ export const TextareaOptionalAndIconNegative: StoryObj = {
args: { ...basicArgs, optional: true, negative: true },
};

export const TextareaOptionalAndIconNegativeSizeS: StoryObj = {
render: TemplateTextareaWithIcon,
argTypes: basicArgTypes,
args: { ...basicArgs, optional: true, negative: true, size: size.options![0] },
};

export const TextareaOptionalAndIconNegativeSizeL: StoryObj = {
render: TemplateTextareaWithIcon,
argTypes: basicArgTypes,
args: { ...basicArgs, optional: true, negative: true, size: size.options![2] },
};

export const TextareaFloatingLabelNegative: StoryObj = {
render: TemplateTextarea,
argTypes: basicArgTypes,
Expand Down
2 changes: 1 addition & 1 deletion src/elements/form-field/form-field/form-field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export class SbbFormFieldElement extends SbbNegativeMixin(SbbHydrationMixin(LitE
@property({ type: Boolean }) public optional?: boolean;

/** Size variant, either l or m. */
@property({ reflect: true }) public size?: 'l' | 'm' = 'm';
@property({ reflect: true }) public size?: 'l' | 'm' | 's' = 'm';

/** Whether to display the form field without a border. */
@property({ reflect: true, type: Boolean }) public borderless = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ describe(`sbb-form-field`, () => {
};

const visualProp = {
size: ['m', 'l'],
size: ['s', 'm', 'l'],
width: ['default', 'collapse'],
errorText: [true, false],
};
Expand Down
17 changes: 16 additions & 1 deletion src/elements/form-field/form-field/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,21 @@ Please refer to their documentation for more details.

## Style

The component has a `size` property, which accepts three different values: `s`, `m` (default) and `l`.

```html
<sbb-form-field size="s">
<label>Example</label>
<input />
</sbb-form-field>

<sbb-form-field size="l">
<label>Example</label>
<input required />
<sbb-form-error>This field is required!</sbb-form-error>
</sbb-form-field>
```

By default, the component has a defined width and min-width. However, this behavior can be overridden by setting
the `width` property to `collapse`: in this way the component adapts its width to the inner slotted input component.
This is useful, for example, for the [sbb-time-input](/docs/elements-sbb-time-input--docs) component.
Expand Down Expand Up @@ -142,7 +157,7 @@ technology will announce errors when they appear.
| `inputElement` | - | public | `HTMLInputElement \| HTMLSelectElement \| HTMLElement \| undefined` | | Returns the input element. |
| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. |
| `optional` | `optional` | public | `boolean \| undefined` | | Indicates whether the input is optional. |
| `size` | `size` | public | `'l' \| 'm' \| undefined` | `'m'` | Size variant, either l or m. |
| `size` | `size` | public | `'l' \| 'm' \| 's' \| undefined` | `'m'` | Size variant, either l or m. |
| `width` | `width` | public | `'default' \| 'collapse'` | `'default'` | Defines the width of the component: - `default`: the component has defined width and min-width; - `collapse`: the component adapts itself to its inner input content. |

## Methods
Expand Down

0 comments on commit 9abb131

Please sign in to comment.