diff --git a/packages/calcite-components/src/components/input/input.scss b/packages/calcite-components/src/components/input/input.scss index c5890155d41..b6e19c31ee6 100755 --- a/packages/calcite-components/src/components/input/input.scss +++ b/packages/calcite-components/src/components/input/input.scss @@ -1,5 +1,55 @@ +/** + * CSS Custom Properties + * + * These properties can be overridden using the component's tag as selector. + * + * @prop --calcite-input-corner-radius: defines the border radius of the component. + * @prop --calcite-input-text-color: defines the text color of the component. + * @prop --calcite-input-border-color: defines the border color of the component. + * @prop --calcite-input-background-color: defines the background color of the component. + * @prop --calcite-input-button-background-color: defines the background color of a button element in the component. + * @prop --calcite-input-button-background-color-hover: defines the background color of a :hover-ed button element in the component. + * @prop --calcite-input-button-background-color-active: defines the background color of an :active button element in the component. + * @prop --calcite-input-icon-color: defines the color of an icon element in the component. + * @prop --calcite-input-button-icon-color-hover: defines the color of an icon element when it's parent is hovered in the component. + * @prop --calcite-input-prefix-text-color: defines the prefix text color in the component. + * @prop --calcite-input-prefix-background-color: defines the prefix background color in the component. + * @prop --calcite-input-suffix-text-color: defines the suffix text color in the component. + * @prop --calcite-input-suffix-background-color: defines the suffix background color in the component. + * @prop --calcite-input-placeholder-text-color: defines the color of placeholder text in the component. + * @prop --calcite-input-shadow: defines the box-shadow of the component. + * + */ + :host { + --calcite-input-corner-radius: var(--calcite-corner-radius); + --calcite-input-text-color: var(--calcite-color-text-1); + --calcite-input-border-color: var(--calcite-color-border-input); + --calcite-input-background-color: var(--calcite-color-foreground-1); + --calcite-input-shadow: none; + // Button + --calcite-input-button-background-color: var(--calcite-color-foreground-1); + --calcite-input-button-background-color-hover: var(--calcite-color-foreground-2); + --calcite-input-button-background-color-active: var(--calcite-color-foreground-3); + + // Icon + --calcite-input-icon-color: var(--calcite-color-text-3); + --calcite-input-button-icon-color-hover: var(--calcite-color-text-1); + + // Prefix/Suffix + --calcite-input-prefix-text-color: var(--calcite-color-text-2); + --calcite-input-prefix-background-color: var(--calcite-color-background); + --calcite-input-suffix-text-color: var(--calcite-color-text-2); + --calcite-input-suffix-background-color: var(--calcite-color-background); + + // Placeholder + --calcite-input-placeholder-text-color: var(--calcite-color-text-3); + + // For props that should follow the initial border-color but not change on statechange. + --calcite-internal-input-border-color-base: var(--calcite-color-border-input); + @apply block; + box-shadow: var(--calcite-input-shadow); } // scales @@ -99,24 +149,18 @@ textarea, input { + @apply border font-inherit relative m-0 + box-border flex max-h-full w-full max-w-full flex-1 font-normal; + transition: var(--calcite-animation-timing), block-size 0, outline-offset 0s; -webkit-appearance: none; - @apply font-inherit - text-color-1 - bg-foreground-1 - relative - m-0 - box-border - flex - max-h-full - w-full - max-w-full - flex-1 - rounded-none - font-normal; + border-radius: var(--calcite-input-corner-radius); + color: var(--calcite-input-text-color); + border-color: var(--calcite-input-border-color); + background-color: var(--calcite-input-background-color); } input[type="search"]::-webkit-search-decoration { @@ -126,34 +170,29 @@ input[type="search"]::-webkit-search-decoration { // states input, textarea { - @apply border - border-color-input + @apply border-spacing-1 border-solid - text-color-1 text-ellipsis; &::placeholder, &:-ms-input-placeholder, &::-ms-input-placeholder { - @apply text-color-3 font-normal; + @apply font-normal; + color: var(--calcite-input-placeholder-text-color); } &:placeholder-shown { @apply text-ellipsis; } } -input:focus, -textarea:focus { - @apply border-color-brand text-color-1; -} input[readonly], textarea[readonly] { - @apply bg-background font-medium; -} -input[readonly]:focus, -textarea[readonly]:focus { - @apply text-color-1; + @apply font-medium; } calcite-icon { - @apply text-color-3; + color: var(--calcite-input-icon-color); +} +button:hover, +button:active { + --calcite-input-icon-color: var(--calcite-input-button-icon-color-hover); } //focus @@ -167,10 +206,8 @@ input:focus { } :host([status="invalid"]) { - & input, - & textarea { - @apply border-color-danger; - } + --calcite-input-border-color: var(--calcite-color-status-danger); + & input:focus, & textarea:focus { @apply focus-inset-danger; @@ -249,8 +286,6 @@ input[type="time"]::-webkit-clear-button { .clear-button { pointer-events: initial; @apply focus-base - border-color-input - bg-foreground-1 order-4 m-0 box-border @@ -263,19 +298,20 @@ input[type="time"]::-webkit-clear-button { border border-solid; + background-color: var(--calcite-input-button-background-color); + border-color: var(--calcite-internal-input-border-color-base); border-inline-start-width: theme("borderWidth.0"); &:hover { - @apply bg-foreground-2 transition-default; + @apply transition-default; + --calcite-input-button-background-color: var(--calcite-input-button-background-color-hover); + calcite-icon { - @apply text-color-1 transition-default; + @apply transition-default; } } &:active { - @apply bg-foreground-3; - calcite-icon { - @apply text-color-1; - } + --calcite-input-button-background-color: var(--calcite-input-button-background-color-active); } &:focus { @apply focus-inset; @@ -294,6 +330,17 @@ input[type="time"]::-webkit-clear-button { block; } +:host(:not([suffix-text], [type="number"]):empty) { + .loader { + inset-inline-end: calc(var(--calcite-input-corner-radius, 0px) / 2); + } +} +:host(:not([prefix-text], [number-button-type="horizontal"][type="number"])) { + .loader { + inset-inline-start: calc(var(--calcite-input-corner-radius, 0px) / 2); + } +} + // slotted action .action-wrapper { @apply order-7 flex; @@ -302,10 +349,7 @@ input[type="time"]::-webkit-clear-button { // prefix and suffix .prefix, .suffix { - @apply border-color-input - bg-background - text-color-2 - box-border + @apply box-border flex h-auto min-h-full @@ -317,6 +361,15 @@ input[type="time"]::-webkit-clear-button { border-solid font-medium leading-none; + border-color: var(--calcite-internal-input-border-color-base); +} +.prefix { + color: var(--calcite-input-prefix-text-color); + background-color: var(--calcite-input-prefix-background-color); +} +.suffix { + color: var(--calcite-input-suffix-text-color); + background-color: var(--calcite-input-suffix-background-color); } .prefix { @@ -399,40 +452,13 @@ input[type="number"] { } .number-button-item.number-button-item--horizontal[data-adjustment="down"] { - @apply border-color-input - border + @apply border border-solid; border-inline-end-width: theme("borderWidth.0"); - &:hover { - @apply bg-foreground-2; - calcite-icon { - @apply text-color-1; - } - } } .number-button-item.number-button-item--horizontal[data-adjustment="up"] { @apply order-5; - &:hover { - @apply bg-foreground-2; - calcite-icon { - @apply text-color-1; - } - } -} - -:host([number-button-type="vertical"]) .number-button-item[data-adjustment="down"]:hover { - @apply bg-foreground-2; - calcite-icon { - @apply text-color-1; - } -} - -:host([number-button-type="vertical"]) .number-button-item[data-adjustment="up"]:hover { - @apply bg-foreground-2; - calcite-icon { - @apply text-color-1; - } } :host([number-button-type="vertical"]) .number-button-item[data-adjustment="down"] { @@ -443,9 +469,7 @@ input[type="number"] { max-block-size: 50%; min-block-size: 50%; pointer-events: initial; - @apply border-color-input - bg-foreground-1 - transition-default + @apply transition-default m-0 box-border flex @@ -456,18 +480,18 @@ input[type="number"] { border-solid py-0 px-2; + border-color: var(--calcite-internal-input-border-color-base); border-inline-start-width: theme("borderWidth.0"); + background-color: var(--calcite-input-button-background-color); & calcite-icon { @apply transition-default pointer-events-none; } - &:focus { - @apply bg-foreground-2; - calcite-icon { - @apply text-color-1; - } + &:focus, + &:hover { + --calcite-input-button-background-color: var(--calcite-input-button-background-color-hover); } &:active { - @apply bg-foreground-3; + --calcite-input-button-background-color: var(--calcite-input-button-background-color-active); } &:disabled { @apply pointer-events-none; @@ -503,10 +527,9 @@ textarea::-webkit-resizer { .resize-icon-wrapper { inset-block-end: 2px; inset-inline-end: 2px; + background-color: var(--calcite-input-button-background-color); - @apply bg-foreground-1 - text-color-3 - pointer-events-none + @apply pointer-events-none absolute h-3 w-3; @@ -532,9 +555,7 @@ textarea::-webkit-resizer { // file input :host([type="file"]) input { - @apply bg-foreground-1 - border-color-input - cursor-pointer + @apply cursor-pointer border border-dashed text-center; @@ -580,3 +601,118 @@ input { @include form-validation-message(); @include hidden-form-input(); @include base-component(); + +:host(:focus) { + --calcite-input-border-color: var(--calcite-color-brand); +} + +:host([read-only]) { + --calcite-input-background-color: var(--calcite-color-background); +} + +:host([number-button-type="horizontal"][type="number"]) { + .wrapper { + > button:first-child { + border-start-start-radius: var(--calcite-input-corner-radius); + border-end-start-radius: var(--calcite-input-corner-radius); + } + + > button:last-of-type { + border-start-end-radius: var(--calcite-input-corner-radius); + border-end-end-radius: var(--calcite-input-corner-radius); + } + } + + button + button, + input + button, + button + div, + input + div { + border-start-start-radius: 0; + border-end-start-radius: 0; + } + input { + border-radius: 0; + } +} +:host([number-button-type="vertical"][type="number"]) { + input, + textarea { + border-start-end-radius: 0; + border-end-end-radius: 0; + } + .number-button-item { + &:first-child { + border-start-end-radius: var(--calcite-input-corner-radius); + } + &:last-child { + border-end-end-radius: var(--calcite-input-corner-radius); + } + } +} +:host([prefix-text]) { + input, + textarea { + border-start-start-radius: 0; + border-end-start-radius: 0; + } +} +:host([suffix-text]) { + input, + textarea { + border-start-end-radius: 0; + border-end-end-radius: 0; + } +} +:host([suffix-text][type="number"]:not([read-only])) { + .suffix { + border-start-end-radius: 0; + border-end-end-radius: 0; + } +} + +:host([scale="l"]) { + .resize-icon-wrapper { + block-size: 18px; + inline-size: 18px; + } +} +:host(:not([clearable], [suffix-text], [type="number"]:not([read-only]))) { + .wrapper:has(+ .validation-container) { + input { + border-start-end-radius: var(--calcite-input-corner-radius); + border-end-end-radius: var(--calcite-input-corner-radius); + } + } +} +:host(:not([type="number"], [suffix-text])) { + input:has(+ .clear-button) { + border-start-end-radius: 0; + border-end-end-radius: 0; + } + .clear-button { + border-start-end-radius: var(--calcite-input-corner-radius); + border-end-end-radius: var(--calcite-input-corner-radius); + } +} + +.prefix { + border-start-start-radius: var(--calcite-input-corner-radius); + border-end-start-radius: var(--calcite-input-corner-radius); +} +.suffix { + border-start-end-radius: var(--calcite-input-corner-radius); + border-end-end-radius: var(--calcite-input-corner-radius); +} +:host(:not(:empty)) { + input, + .clear-button { + border-start-end-radius: 0; + border-end-end-radius: 0; + } +} +::slotted(*) { + border-start-start-radius: 0; + border-end-start-radius: 0; + border-start-end-radius: var(--calcite-input-corner-radius); + border-end-end-radius: var(--calcite-input-corner-radius); +} diff --git a/packages/calcite-components/src/components/input/input.stories.ts b/packages/calcite-components/src/components/input/input.stories.ts index 4398de7e7d8..337a66d798f 100644 --- a/packages/calcite-components/src/components/input/input.stories.ts +++ b/packages/calcite-components/src/components/input/input.stories.ts @@ -26,17 +26,18 @@ export const simple = (): string => html` min="${number("min", 0)}" max="${number("max", 100)}" step="${number("step", 1)}" - prefix-text="${text("prefix-text", "")}" - suffix-text="${text("suffix-text", "")}" + ${text("prefix-text", "") && `prefix-text="${text("prefix-text", "")}"`} + ${text("suffix-text", "") && `suffix-text="${text("suffix-text", "")}"`} ${boolean("loading", false)} ${boolean("clearable", false)} ${boolean("disabled", false)} - value="${text("value", "")}" + ${text("value", "") && `value="${text("value", "")}"`} scale="${select("scale", ["s", "m", "l"], "m")}" status="${select("status", ["idle", "invalid", "valid"], "idle")}" placeholder="${text("placeholder", "Placeholder text")}" - validation-message="${text("validation-message", "")}" - validation-icon="${select("validation-icon", ["", ...iconNames], "")}" + ${text("validation-message", "") && `validation-message="${text("validation-message", "")}"`} + ${select("validation-icon", ["", ...iconNames], "") && + `validation-icon="${select("validation-icon", ["", ...iconNames], "")}"`} > `; @@ -80,14 +81,16 @@ export const textarea_TestOnly = (): string => html` ${boolean("loading", false)} ${boolean("clearable", false)} ${boolean("disabled", false)} - prefix-text="${text("prefix-text", "")}" - suffix-text="${text("suffix-text", "")}" - value="${text("value", "")}" + ${text("prefix-text", "") && `prefix-text="${text("prefix-text", "")}"`} + ${text("suffix-text", "") && `suffix-text="${text("suffix-text", "")}"`} + ${text("value", "") && `value="${text("value", "")}"`} scale="${select("scale", ["s", "m", "l"], "m")}" status="${select("status", ["idle", "invalid", "valid"], "idle")}" placeholder="${text("placeholder", "Placeholder text")}" - validation-message="${text("validation-message", "My great input message")}" - validation-icon="${select("validation-icon", ["", ...iconNames], "")}" + ${text("validation-message", "My great input message") && + `validation-message="${text("validation-message", "My great input message")}"`} + ${select("validation-icon", ["", ...iconNames], "") && + `validation-icon="${select("validation-icon", ["", ...iconNames], "")}"`} > @@ -116,8 +119,8 @@ export const darkModeRTL_TestOnly = (): string => html` min="${number("min", 0)}" max="${number("max", 100)}" step="${number("step", 1)}" - prefix-text="${text("prefix-text", "")}" - suffix-text="${text("suffix-text", "")}" + ${text("prefix-text", "") && `prefix-text="${text("prefix-text", "")}"`} + ${text("suffix-text", "") && `suffix-text="${text("suffix-text", "")}"`} ${boolean("loading", false)} ${boolean("clearable", false)} ${boolean("disabled", false)}