Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(sbb-form-field): introduce size s #2995

Merged
merged 8 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 52 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.125)};
--sbb-form-field-spacer-margin-block-end: #{sbb.px-to-rem-build(-11)};

@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(6.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,19 @@
}

.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);

@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,19 +373,23 @@
)[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));
}
}

.sbb-form-field__label-ellipsis {
@include sbb.ellipsis;
}

.sbb-form-field__input {
: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.
height: var(--sbb-spacing-fixed-6x);
}
}

// Input

.sbb-form-field__input ::slotted(:where(input, select, textarea, sbb-select)) {
Expand All @@ -375,7 +412,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
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@
.app-scroll-container {
@include sbb.scrollbar;

overflow: auto;
& {
overflow: auto;
}
}
Loading