From bd5036296e0970bb7a027fd0d7cb3ec2582aa231 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Murat=20=C3=87orlu?=
<127687+muratcorlu@users.noreply.github.com>
Date: Fri, 27 Jan 2023 11:28:53 +0100
Subject: [PATCH] fix(input): disabled style and small size fixes (#389)
* fix(icon): safari overflow issue fixed
* fix(input): various visual fixes for input
* disabled style fixed
* small size added
* vertical alignments fixed
* internal component structure refactored for creating extra flexibility
for upcoming features (like trailing/leading text), better reliability and
maintainability
* fix(input): placeholder color fix
* ci: extra padding has been added for chromatic
* fix(input): label max width with icon
* ci: clean forgotten style
* fix(input): positioning issues are fixed
* fix(input): variable name fix
* docs(input): small size added for storybook canvas
* docs(input): label fixed attribute in canvas fix
---
.storybook/preview.js | 27 ++-
src/components/icon/bl-icon.css | 13 +-
src/components/input/bl-input.css | 212 +++++++++++++---------
src/components/input/bl-input.stories.mdx | 69 +++++--
src/components/input/bl-input.test.ts | 27 ++-
src/components/input/bl-input.ts | 61 ++++---
src/themes/default.css | 2 +-
7 files changed, 270 insertions(+), 141 deletions(-)
diff --git a/.storybook/preview.js b/.storybook/preview.js
index 3704b646..753a7503 100644
--- a/.storybook/preview.js
+++ b/.storybook/preview.js
@@ -30,8 +30,33 @@ const withNoAnimationOnChromaticLayout = makeDecorator({
}
});
+
+const extraPaddingForChromatic = makeDecorator({
+ name: 'extraPaddingForChromatic',
+ parameterName: 'extraPaddingForChromatic',
+ skipIfNoParametersOrOptions: true,
+ wrapper: (getStory, context) => {
+ const story = getStory(context);
+ const decoratedStory = html`
+ ${isChromatic() ? html`` : html``}
+
+
+ ${ story }
+
+ `;
+
+ // return the modified story
+ return decoratedStory;
+ }
+});
+
export const decorators = [
- withNoAnimationOnChromaticLayout
+ withNoAnimationOnChromaticLayout,
+ extraPaddingForChromatic
]
export const parameters = {
diff --git a/src/components/icon/bl-icon.css b/src/components/icon/bl-icon.css
index ce7e7353..f504dfd5 100644
--- a/src/components/icon/bl-icon.css
+++ b/src/components/icon/bl-icon.css
@@ -1,14 +1,19 @@
:host {
display: inline-block;
- position: relative;
+}
+
+:host div {
+ display: flex;
+ align-items: stretch;
width: 1em;
height: 1em;
min-width: 1em;
min-height: 1em;
+ overflow: hidden;
+ transform: translateZ(0);
}
-:host div,
:host svg {
- width: 100%;
- height: 100%;
+ width: 1em;
+ height: 1em;
}
diff --git a/src/components/input/bl-input.css b/src/components/input/bl-input.css
index 01261db3..cec0abc4 100644
--- a/src/components/input/bl-input.css
+++ b/src/components/input/bl-input.css
@@ -2,111 +2,162 @@
display: inline-block;
width: 200px;
position: relative;
+}
+
+.wrapper {
+ --border-color: var(--bl-color-border);
+ --icon-color: var(--bl-color-content-tertiary);
+ --text-color: var(--bl-color-content-primary);
+ --height: var(--bl-size-2xl);
+ --input-font: var(--bl-font-body-text-2);
+ --line-height: var(--bl-font-body-text-2-line-height);
+ --icon-size: var(--line-height);
+ --padding-vertical: calc((var(--height) - var(--line-height)) / 2);
+ --padding-horizontal: var(--bl-size-xs);
- --bl-input-padding-vertical: var(--bl-size-2xs);
- --bl-input-padding-horizontal: var(--bl-size-xs);
- --bl-input-border-color: var(--bl-color-border);
- --bl-input-icon-color: var(--bl-color-content-tertiary);
- --bl-input-text-color: var(--bl-color-content-primary);
- --bl-input-height: var(--bl-size-2xl);
+ display: flex;
+ flex-direction: column;
+ position: relative;
+ gap: var(--bl-size-3xs);
}
-input {
- outline: none;
+.wrapper:focus-within {
+ --border-color: var(--bl-color-primary);
+ --icon-color: var(--bl-color-primary);
+}
+
+.wrapper.dirty.invalid {
+ --border-color: var(--bl-color-danger);
+ --icon-color: var(--bl-color-danger);
+}
+
+:host([size='large']) .wrapper {
+ --height: var(--bl-size-3xl);
+ --padding-vertical: var(--bl-size-xs);
+ --padding-horizontal: var(--bl-size-m);
+}
+
+:host([size='small']) .wrapper {
+ --height: var(--bl-size-xl);
+ --input-font: var(--bl-font-body-text-3);
+ --padding-vertical: var(--bl-size-3xs);
+ --icon-size: var(--bl-font-body-text-3-line-height);
+}
+
+label {
+ position: absolute;
+ top: var(--padding-vertical);
+ left: var(--padding-horizontal);
+ right: var(--padding-horizontal);
+ max-width: max-content;
+ transition: all ease-in 0.2s;
+ pointer-events: none;
+ font: var(--input-font);
+ color: var(--bl-color-content-tertiary);
+ padding: 0;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.input-wrapper {
+ --border-size: 1px;
+
+ display: flex;
box-sizing: border-box;
- height: var(--bl-input-height);
- border: solid 1px var(--bl-input-border-color);
- width: 100%;
- font: var(--bl-font-title-3-regular);
- padding: 0 var(--bl-input-padding-horizontal);
- margin: 0;
+ gap: var(--padding-vertical);
+ height: var(--height);
+ border: solid var(--border-size) var(--border-color);
+ padding: 0 calc(var(--padding-horizontal) - var(--border-size));
border-radius: 4px;
- color: var(--bl-input-text-color);
}
-bl-icon {
- position: absolute;
- top: var(--bl-input-padding-vertical);
- right: var(--bl-input-padding-horizontal);
- font-size: var(--bl-size-m);
- z-index: 1;
- color: var(--bl-input-icon-color);
+input {
+ width: 100%;
+ align-self: stretch;
+ outline: 0;
+ border: 0;
+ padding: 0;
+ font: var(--input-font);
+ color: var(--text-color);
+ -webkit-text-fill-color: var(--text-color);
+ background-color: transparent;
}
-input:focus {
- --bl-input-border-color: var(--bl-color-primary);
+.icon {
+ flex-basis: var(--icon-size);
+ align-self: center;
+ height: var(--icon-size);
}
-:host([label-fixed]) bl-icon {
- top: calc(var(--bl-input-padding-vertical) + var(--bl-size-m));
+.wrapper:not(.has-icon) .icon {
+ display: none;
+}
+
+.hint {
+ display: none;
+ font: var(--bl-font-body-text-3);
+ padding: 0 var(--padding-horizontal);
+}
+
+.hint p {
+ padding: 0;
+ margin: 0;
}
-input:focus ~ bl-icon {
- --bl-input-icon-color: var(--bl-color-primary);
+bl-icon {
+ font-size: var(--icon-size);
+ color: var(--icon-color);
+ height: var(--icon-size);
}
-:host ::placeholder {
+::placeholder {
color: var(--bl-color-content-tertiary);
+ -webkit-text-fill-color: var(--bl-color-content-tertiary);
}
:host([label]) ::placeholder {
color: transparent;
+ -webkit-text-fill-color: transparent;
transition: color ease-out 0.4s;
}
-:host input:focus::placeholder,
-:host([label-fixed]) ::placeholder {
+:host([label-fixed]) ::placeholder,
+:host .wrapper:focus-within ::placeholder {
color: var(--bl-color-content-tertiary);
+ -webkit-text-fill-color: var(--bl-color-content-tertiary);
}
-input:disabled {
- background-color: var(--bl-color-primary-background);
-
- --bl-input-text-color: var(--bl-color-content-tertiary);
-}
+:host([disabled]) .input-wrapper {
+ cursor: not-allowed;
+ background-color: var(--bl-color-secondary-background);
-input.dirty:invalid {
- --bl-input-border-color: var(--bl-color-danger);
+ --text-color: var(--bl-color-content-passive);
}
-input.has-icon {
- padding-right: calc(var(--bl-size-xs) * 2 + var(--bl-size-m));
-}
-
-.error-icon,
-.invalid-text {
- display: none;
+input:disabled {
+ cursor: not-allowed;
}
-label {
- position: absolute;
- top: var(--bl-input-padding-vertical);
- left: var(--bl-input-padding-horizontal);
- transition: all ease-in 0.2s;
- pointer-events: none;
- font: var(--bl-font-title-3-regular);
- color: var(--bl-color-content-tertiary);
- padding: 0;
-}
+:where(.wrapper:focus-within, .wrapper.has-value) label {
+ --label-padding: var(--bl-size-3xs);
-:where(input:focus, input.has-value) ~ label {
top: 0;
- left: var(--bl-size-2xs);
+ left: calc(var(--padding-horizontal) - var(--label-padding));
transform: translateY(-50%);
font: var(--bl-font-caption);
color: var(--bl-color-content-secondary);
- padding: 0 var(--bl-size-3xs);
+ padding: 0 var(--label-padding);
background-color: var(--bl-color-primary-background);
pointer-events: initial;
}
-:host([label-fixed]) {
- padding-top: var(--bl-size-m);
+:where(.has-icon:not(:focus-within), .has-icon:not(.has-value)) label {
+ right: calc(var(--padding-horizontal) + var(--icon-size) + var(--padding-vertical));
}
:host([label-fixed]) label {
- top: 0;
- left: 0;
+ position: static;
transition: none;
transform: none;
pointer-events: initial;
@@ -115,18 +166,14 @@ label {
padding: 0;
}
-.dirty:invalid ~ label {
- color: var(--bl-color-danger);
+.error-icon,
+.invalid-text {
+ display: none;
}
+.dirty.invalid label,
.invalid-text,
-.help-text {
- font: var(--bl-font-title-4-regular);
- padding: var(--bl-size-3xs) var(--bl-input-padding-horizontal);
- margin: 0;
-}
-
-.invalid-text {
+.error-icon {
color: var(--bl-color-danger);
}
@@ -134,32 +181,23 @@ label {
color: var(--bl-color-content-secondary);
}
-.error-icon {
- color: var(--bl-color-danger);
+:host([help-text]) .hint,
+.dirty.invalid .hint {
+ display: block;
}
-.dirty:invalid ~ .invalid-text {
+.dirty.invalid .invalid-text {
display: block;
}
-.dirty:invalid ~ .help-text {
+.dirty.invalid .help-text {
display: none;
}
-.dirty:invalid ~ .error-icon {
+.dirty.invalid .error-icon {
display: inline-block;
}
-.dirty:invalid ~ .custom-icon ~ .error-icon {
+.dirty.invalid .custom-icon ~ .error-icon {
display: none;
}
-
-.dirty:invalid ~ .custom-icon {
- --bl-input-icon-color: var(--bl-color-danger);
-}
-
-:host([size='large']) {
- --bl-input-height: var(--bl-size-3xl);
- --bl-input-padding-vertical: var(--bl-size-xs);
- --bl-input-padding-horizontal: var(--bl-size-m);
-}
diff --git a/src/components/input/bl-input.stories.mdx b/src/components/input/bl-input.stories.mdx
index 5400be2d..ce1be704 100644
--- a/src/components/input/bl-input.stories.mdx
+++ b/src/components/input/bl-input.stories.mdx
@@ -10,6 +10,9 @@ import {
html``
-export const LabelStylesTemplate = args => html`
- ${SingleInputTemplate({ labelFixed: true, ...args })}
- ${SingleInputTemplate({ labelFixed: false, ...args })}
- ${BlButton()}
+export const SizeVariantsTemplate = args => html`
+${SingleInputTemplate({ size: 'large', ...args })}
+${SingleInputTemplate({ size: 'medium', ...args })}
+${SingleInputTemplate({ size: 'small', ...args })}
`
# Input
@@ -107,8 +110,6 @@ export const LabelStylesTemplate = args => html`
Input component is the component for taking text input from user.
-Inline styles in examples are only for **demo purposes**. Use regular CSS classes or tag selectors to set styles.
-
## Basic Usage
Currently, input component supports `text` and `number` types, which default is `text`.
@@ -148,6 +149,20 @@ If you want to use always it on top of the input, then you can use `label-fixed`
+Input component will cut-out long labels those doesn't width of input, with ellipsis char.
+
+
+
## Input Help Text
You can give extra information to user with `help-text` attribute.
@@ -201,11 +216,43 @@ Validation error messages are used from default browser error messages by defaul
## Input Sizes
-Inputs have 2 size options: `medium` and `large`. `medium` size is default and if you want to show a large input you can set `size` attribute to `large`.
+Inputs have 3 size options: `large`, `medium` and `small`. `medium` size is default and if you want to show a large or small input you can set `size` attribute.
+
+## Disabled Input
+
+Input can be set as disabled by adding `disabled` attribute.
+
+