UNPKG

@ionic/core

Version:
1,358 lines (1,271 loc) • 41 kB
/** * Convert a font size to a dynamic font size. * Fonts that participate in Dynamic Type should use * dynamic font sizes. * @param size - The initial font size including the unit (i.e. px or pt) * @param unit (optional) - The unit to convert to. Use this if you want to * convert to a unit other than $baselineUnit. */ /** * Convert a font size to a dynamic font size but impose * a maximum font size. * @param size - The initial font size including the unit (i.e. px or pt) * @param maxScale - The maximum scale of the font (i.e. 2.5 for a maximum 250% scale). * @param unit (optional) - The unit to convert the initial font size to. Use this if you want to * convert to a unit other than $baselineUnit. */ /** * Convert a font size to a dynamic font size but impose * a minimum font size. * @param size - The initial font size including the unit (i.e. px or pt) * @param minScale - The minimum scale of the font (i.e. 0.8 for a minimum 80% scale). * @param unit (optional) - The unit to convert the initial font size to. Use this if you want to * convert to a unit other than $baselineUnit. */ /** * Convert a font size to a dynamic font size but impose * maximum and minimum font sizes. * @param size - The initial font size including the unit (i.e. px or pt) * @param minScale - The minimum scale of the font (i.e. 0.8 for a minimum 80% scale). * @param maxScale - The maximum scale of the font (i.e. 2.5 for a maximum 250% scale). * @param unit (optional) - The unit to convert the initial font size to. Use this if you want to * convert to a unit other than $baselineUnit. */ /** * A heuristic that applies CSS to tablet * viewports. * * Usage: * @include tablet-viewport() { * :host { * background-color: green; * } * } */ /** * A heuristic that applies CSS to mobile * viewports (i.e. phones, not tablets). * * Usage: * @include mobile-viewport() { * :host { * background-color: blue; * } * } */ :host { /** * @prop --background: Background of the textarea * * @prop --border-radius: Border radius of the textarea * @prop --border-color: Color of the border below the textarea when using helper text, error text, or counter * @prop --border-radius: Radius of the textarea border. A large radius may display unevenly when using fill="outline"; if needed, use shape="round" instead or increase --padding-start. * @prop --border-style: Style of the border below the textarea when using helper text, error text, or counter * @prop --border-width: Width of the border below the textarea when using helper text, error text, or counter * * @prop --color: Color of the text * * @prop --placeholder-color: Color of the placeholder text * @prop --placeholder-font-style: Style of the placeholder text * @prop --placeholder-font-weight: Weight of the placeholder text * @prop --placeholder-opacity: Opacity of the placeholder text * * @prop --highlight-height: The height of the highlight on the textarea. Only applies to md mode. * @prop --highlight-color-focused: The color of the highlight on the textarea when focused * @prop --highlight-color-valid: The color of the highlight on the textarea when valid * @prop --highlight-color-invalid: The color of the highlight on the textarea when invalid * * @prop --padding-top: Top padding of the textarea * @prop --padding-end: Right padding if direction is left-to-right, and left padding if direction is right-to-left of the textarea * @prop --padding-bottom: Bottom padding of the textarea * @prop --padding-start: Left padding if direction is left-to-right, and right padding if direction is right-to-left of the textarea */ --background: initial; --color: initial; --placeholder-color: initial; --placeholder-font-style: initial; --placeholder-font-weight: initial; --placeholder-opacity: var(--ion-placeholder-opacity, 0.6); --padding-top: 0; --padding-end: 0; --padding-bottom: 8px; --padding-start: 0; --border-radius: 0; --border-style: solid; --highlight-color-focused: var(--ion-color-primary, #0054e9); --highlight-color-valid: var(--ion-color-success, #2dd55b); --highlight-color-invalid: var(--ion-color-danger, #c5000f); /** * This is a private API that is used to switch * out the highlight color based on the state * of the component without having to write * different selectors for different fill variants. */ --highlight-color: var(--highlight-color-focused); display: block; position: relative; width: 100%; min-height: 44px; color: var(--color); font-family: var(--ion-font-family, inherit); z-index: 2; box-sizing: border-box; } /** * Since the label sits on top of the element, * the component needs to be taller otherwise the * label will appear too close to the textarea text. * Also, floating and stacked labels should not * push the label down since it it * sits on top of the textarea. */ :host(.textarea-label-placement-floating), :host(.textarea-label-placement-stacked) { --padding-top: 0px; min-height: 56px; } /** * When the cols property is set we should * respect that width instead of defaulting * to taking up the entire line. * Requires both the cols and autoGrow * properties to be reflected as attributes * on the host. * * cols does not work with autoGrow because * autoGrow would prevent line breaks from naturally * occurring until the textarea takes up the entire line width. */ :host([cols]:not([auto-grow])) { width: fit-content; } :host(.ion-color) { --highlight-color-focused: var(--ion-color-base); background: initial; } :host-context(ion-item) { align-self: baseline; } :host-context(ion-item)[slot=start], :host-context(ion-item)[slot=end] { width: auto; } .native-textarea { margin-left: 0; margin-right: 0; margin-top: 0; margin-bottom: 0; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0; display: block; position: relative; flex: 1; width: 100%; max-width: 100%; max-height: 100%; border: 0; outline: none; background: transparent; white-space: pre-wrap; /** * This ensures the textarea * remains on top of any decoration * that we render (particularly the * outline border when fill="outline"). * If we did not do this then Axe would * be unable to determine the color * contrast of the textarea. */ z-index: 1; box-sizing: border-box; resize: none; appearance: none; } .native-textarea::placeholder { padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0; color: var(--placeholder-color); font-family: inherit; font-style: var(--placeholder-font-style); font-weight: var(--placeholder-font-weight); opacity: var(--placeholder-opacity); } .native-textarea { color: inherit; font-family: inherit; font-size: inherit; font-style: inherit; font-weight: inherit; letter-spacing: inherit; text-align: inherit; text-decoration: inherit; text-indent: inherit; text-overflow: inherit; text-transform: inherit; grid-area: 1/1/2/2; word-break: break-word; } .cloned-input { top: 0; bottom: 0; position: absolute; pointer-events: none; } .cloned-input { inset-inline-start: 0; } /** * The cloned input needs to be disabled on * Android otherwise the viewport will still * shift when running scroll assist. */ .cloned-input:disabled { opacity: 1; } :host([auto-grow]) .cloned-input { height: 100%; } :host([auto-grow]) .native-textarea { overflow: hidden; } .textarea-wrapper { -webkit-padding-start: var(--padding-start); padding-inline-start: var(--padding-start); -webkit-padding-end: var(--padding-end); padding-inline-end: var(--padding-end); padding-top: 0px; padding-bottom: 0px; border-radius: var(--border-radius); display: flex; position: relative; flex-grow: 1; align-items: flex-start; height: inherit; min-height: inherit; transition: background-color 15ms linear; background: var(--background); line-height: normal; } .native-wrapper { position: relative; width: 100%; height: 100%; } :host(.has-focus) textarea { caret-color: var(--highlight-color); } .native-wrapper textarea { -webkit-padding-start: 0px; padding-inline-start: 0px; -webkit-padding-end: 0px; padding-inline-end: 0px; padding-top: var(--padding-top); padding-bottom: var(--padding-bottom); } .native-wrapper { display: grid; min-width: inherit; max-width: inherit; min-height: inherit; max-height: inherit; /** * This avoids a WebKit bug where * the height of the inner textarea * is incorrect and flows outside the * parent container: https://bugs.webkit.org/show_bug.cgi?id=256781 * TODO FW-4734 */ grid-auto-rows: 100%; } .native-wrapper::after { white-space: pre-wrap; content: attr(data-replicated-value) " "; visibility: hidden; } .native-wrapper::after { padding-left: 0; padding-right: 0; padding-top: var(--padding-top); padding-bottom: var(--padding-bottom); margin-left: 0; margin-right: 0; margin-top: 0; margin-bottom: 0; border-radius: var(--border-radius); /** * Note: Do not use @include text-inherit() * as that sets white-space: inherit * Instead, we use white-space: pre-wrap above. */ color: inherit; font-family: inherit; font-size: inherit; font-style: inherit; font-weight: inherit; letter-spacing: inherit; text-align: inherit; text-decoration: inherit; text-indent: inherit; text-overflow: inherit; text-transform: inherit; grid-area: 1/1/2/2; word-break: break-word; } .textarea-wrapper-inner { display: flex; width: 100%; min-height: inherit; } :host(.ion-touched.ion-invalid) { --highlight-color: var(--highlight-color-invalid); } /** * The component highlight is only shown * on focus, so we can safely set the valid * color state when touched/valid. If we * set it when .has-focus is present then * the highlight color would change * from the valid color to the component's * color during the transition after the * component loses focus. */ :host(.ion-valid) { --highlight-color: var(--highlight-color-valid); } .textarea-bottom { /** * The bottom content should take on the start and end * padding so it is always aligned with either the label * or the start of the textarea. */ -webkit-padding-start: var(--padding-start); padding-inline-start: var(--padding-start); -webkit-padding-end: var(--padding-end); padding-inline-end: var(--padding-end); padding-top: 5px; padding-bottom: 0; display: flex; justify-content: space-between; border-top: var(--border-width) var(--border-style) var(--border-color); font-size: 0.75rem; white-space: normal; } /** * If the textarea has a validity state, the * border and label should reflect that as a color. */ :host(.has-focus.ion-valid), :host(.ion-touched.ion-invalid) { --border-color: var(--highlight-color); } /** * Error text should only be shown when .ion-invalid is * present on the textarea. Otherwise the helper text should * be shown. */ .textarea-bottom .error-text { display: none; color: var(--highlight-color-invalid); } .textarea-bottom .helper-text { display: block; color: var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d)); } :host(.ion-touched.ion-invalid) .textarea-bottom .error-text { display: block; } :host(.ion-touched.ion-invalid) .textarea-bottom .helper-text { display: none; } .textarea-bottom .counter { /** * Counter should always be at * the end of the container even * when no helper/error texts are used. */ -webkit-margin-start: auto; margin-inline-start: auto; color: var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d)); white-space: nowrap; padding-inline-start: 16px; } .label-text-wrapper { -webkit-padding-start: 0px; padding-inline-start: 0px; -webkit-padding-end: 0px; padding-inline-end: 0px; padding-top: var(--padding-top); padding-bottom: var(--padding-bottom); /** * Label text should not extend * beyond the bounds of the textarea. * However, we do not set the max * width to 100% because then * only the label would show and users * would not be able to see what they are typing. */ max-width: 200px; transition: color 150ms cubic-bezier(0.4, 0, 0.2, 1), transform 150ms cubic-bezier(0.4, 0, 0.2, 1); /** * This ensures that double tapping this text * clicks the <label> and focuses the textarea * when a screen reader is enabled. */ pointer-events: none; } /** * We need to use two elements instead of * one. The .label-text-wrapper is responsible * for centering the label text vertically regardless * of the textarea height using flexbox. * * The .label-text element is responsible for controlling * overflow when label-placement="fixed". * We want the ellipses to show up when the * fixed label overflows, but text-overflow: ellipsis only * works on block-level elements. A flex item is * considered blockified (https://www.w3.org/TR/css-display-3/#blockify). */ .label-text, ::slotted([slot=label]) { text-overflow: ellipsis; white-space: nowrap; overflow: hidden; } /** * If no label text is placed into the slot * then the element should be hidden otherwise * there will be additional margins added. */ .label-text-wrapper-hidden, .textarea-outline-notch-hidden { display: none; } .textarea-wrapper textarea { /** * When the floating label appears on top of the * textarea, we need to fade the textarea out so that the * label does not overlap with the placeholder. */ transition: opacity 150ms cubic-bezier(0.4, 0, 0.2, 1); } /** * Label is on the left of the textarea in LTR and * on the right in RTL. */ :host(.textarea-label-placement-start) .textarea-wrapper { flex-direction: row; } :host(.textarea-label-placement-start) .label-text-wrapper { /** * The margin between the label and * the textarea should be on the end * when the label sits at the start. */ -webkit-margin-start: 0; margin-inline-start: 0; -webkit-margin-end: 16px; margin-inline-end: 16px; margin-top: 0; margin-bottom: 0; } /** * Label is on the right of the textarea in LTR and * on the left in RTL. */ :host(.textarea-label-placement-end) .textarea-wrapper { flex-direction: row-reverse; } /** * The margin between the label and * the textarea should be on the start * when the label sits at the end. */ :host(.textarea-label-placement-end) .label-text-wrapper { -webkit-margin-start: 16px; margin-inline-start: 16px; -webkit-margin-end: 0; margin-inline-end: 0; margin-top: 0; margin-bottom: 0; } :host(.textarea-label-placement-fixed) .label-text-wrapper { /** * The margin between the label and * the textarea should be on the end * when the label sits at the start. */ -webkit-margin-start: 0; margin-inline-start: 0; -webkit-margin-end: 16px; margin-inline-end: 16px; margin-top: 0; margin-bottom: 0; } /** * Label is on the left of the textarea in LTR and * on the right in RTL. Label also has a fixed width. */ :host(.textarea-label-placement-fixed) .label-text { flex: 0 0 100px; width: 100px; min-width: 100px; max-width: 200px; } /** * Stacked: Label sits above the textarea and is scaled down. * Floating: Label sits over the textarea when the textarea has no * value and is blurred. Label sits above the textarea and is scaled * down when the textarea is focused or has a value. * */ :host(.textarea-label-placement-stacked) .textarea-wrapper, :host(.textarea-label-placement-floating) .textarea-wrapper { flex-direction: column; align-items: start; } /** * Ensures that the label animates * up and to the left in LTR or * up and to the right in RTL. */ :host(.textarea-label-placement-stacked) .label-text-wrapper, :host(.textarea-label-placement-floating) .label-text-wrapper { transform-origin: left top; -webkit-padding-start: 0px; padding-inline-start: 0px; -webkit-padding-end: 0px; padding-inline-end: 0px; padding-top: 0px; padding-bottom: 0px; max-width: 100%; /** * The 2 ensures the label * remains on top of any browser * autofill background too. */ z-index: 2; } :host-context([dir=rtl]):host(.textarea-label-placement-stacked) .label-text-wrapper, :host-context([dir=rtl]).textarea-label-placement-stacked .label-text-wrapper, :host-context([dir=rtl]):host(.textarea-label-placement-floating) .label-text-wrapper, :host-context([dir=rtl]).textarea-label-placement-floating .label-text-wrapper { transform-origin: right top; } @supports selector(:dir(rtl)) { :host(.textarea-label-placement-stacked:dir(rtl)) .label-text-wrapper, :host(.textarea-label-placement-floating:dir(rtl)) .label-text-wrapper { transform-origin: right top; } } /** * Ensures the textarea does not * overlap the label. */ :host(.textarea-label-placement-stacked) textarea, :host(.textarea-label-placement-floating) textarea, :host(.textarea-label-placement-stacked[auto-grow]) .native-wrapper::after, :host(.textarea-label-placement-floating[auto-grow]) .native-wrapper::after { -webkit-margin-start: 0px; margin-inline-start: 0px; -webkit-margin-end: 0px; margin-inline-end: 0px; margin-top: 8px; margin-bottom: 0px; } :host(.textarea-label-placement-stacked) ::slotted([slot=start]), :host(.textarea-label-placement-stacked) ::slotted([slot=end]), :host(.textarea-label-placement-floating) ::slotted([slot=start]), :host(.textarea-label-placement-floating) ::slotted([slot=end]) { margin-top: 8px; } /** * This makes the label sit over the textarea * when the textarea is blurred and has no value. */ :host(.textarea-label-placement-floating) .label-text-wrapper { transform: translateY(100%) scale(1); } /** * The textarea should be hidden when the label * is on top of the textarea. This prevents the label * from overlapping any placeholder value. */ :host(.textarea-label-placement-floating) textarea { opacity: 0; } :host(.has-focus.textarea-label-placement-floating) textarea, :host(.has-value.textarea-label-placement-floating) textarea { opacity: 1; } /** * This makes the label sit above the textarea. */ :host(.label-floating) .label-text-wrapper { transform: translateY(50%) scale(0.75); /** * Label text should not extend * beyond the bounds of the textarea. */ max-width: calc(100% / 0.75); } .start-slot-wrapper, .end-slot-wrapper { padding-left: 0; padding-right: 0; padding-top: var(--padding-top); padding-bottom: var(--padding-bottom); display: flex; flex-shrink: 0; align-self: start; } ::slotted([slot=start]), ::slotted([slot=end]) { margin-top: 0; } ::slotted([slot=start]:last-of-type) { margin-inline-end: 16px; margin-inline-start: 0; } ::slotted([slot=end]:first-of-type) { margin-inline-start: 16px; margin-inline-end: 0; } /** * Convert a font size to a dynamic font size. * Fonts that participate in Dynamic Type should use * dynamic font sizes. * @param size - The initial font size including the unit (i.e. px or pt) * @param unit (optional) - The unit to convert to. Use this if you want to * convert to a unit other than $baselineUnit. */ /** * Convert a font size to a dynamic font size but impose * a maximum font size. * @param size - The initial font size including the unit (i.e. px or pt) * @param maxScale - The maximum scale of the font (i.e. 2.5 for a maximum 250% scale). * @param unit (optional) - The unit to convert the initial font size to. Use this if you want to * convert to a unit other than $baselineUnit. */ /** * Convert a font size to a dynamic font size but impose * a minimum font size. * @param size - The initial font size including the unit (i.e. px or pt) * @param minScale - The minimum scale of the font (i.e. 0.8 for a minimum 80% scale). * @param unit (optional) - The unit to convert the initial font size to. Use this if you want to * convert to a unit other than $baselineUnit. */ /** * Convert a font size to a dynamic font size but impose * maximum and minimum font sizes. * @param size - The initial font size including the unit (i.e. px or pt) * @param minScale - The minimum scale of the font (i.e. 0.8 for a minimum 80% scale). * @param maxScale - The maximum scale of the font (i.e. 2.5 for a maximum 250% scale). * @param unit (optional) - The unit to convert the initial font size to. Use this if you want to * convert to a unit other than $baselineUnit. */ /** * A heuristic that applies CSS to tablet * viewports. * * Usage: * @include tablet-viewport() { * :host { * background-color: green; * } * } */ /** * A heuristic that applies CSS to mobile * viewports (i.e. phones, not tablets). * * Usage: * @include mobile-viewport() { * :host { * background-color: blue; * } * } */ /** * Convert a font size to a dynamic font size. * Fonts that participate in Dynamic Type should use * dynamic font sizes. * @param size - The initial font size including the unit (i.e. px or pt) * @param unit (optional) - The unit to convert to. Use this if you want to * convert to a unit other than $baselineUnit. */ /** * Convert a font size to a dynamic font size but impose * a maximum font size. * @param size - The initial font size including the unit (i.e. px or pt) * @param maxScale - The maximum scale of the font (i.e. 2.5 for a maximum 250% scale). * @param unit (optional) - The unit to convert the initial font size to. Use this if you want to * convert to a unit other than $baselineUnit. */ /** * Convert a font size to a dynamic font size but impose * a minimum font size. * @param size - The initial font size including the unit (i.e. px or pt) * @param minScale - The minimum scale of the font (i.e. 0.8 for a minimum 80% scale). * @param unit (optional) - The unit to convert the initial font size to. Use this if you want to * convert to a unit other than $baselineUnit. */ /** * Convert a font size to a dynamic font size but impose * maximum and minimum font sizes. * @param size - The initial font size including the unit (i.e. px or pt) * @param minScale - The minimum scale of the font (i.e. 0.8 for a minimum 80% scale). * @param maxScale - The maximum scale of the font (i.e. 2.5 for a maximum 250% scale). * @param unit (optional) - The unit to convert the initial font size to. Use this if you want to * convert to a unit other than $baselineUnit. */ /** * A heuristic that applies CSS to tablet * viewports. * * Usage: * @include tablet-viewport() { * :host { * background-color: green; * } * } */ /** * A heuristic that applies CSS to mobile * viewports (i.e. phones, not tablets). * * Usage: * @include mobile-viewport() { * :host { * background-color: blue; * } * } */ /** * Convert a font size to a dynamic font size. * Fonts that participate in Dynamic Type should use * dynamic font sizes. * @param size - The initial font size including the unit (i.e. px or pt) * @param unit (optional) - The unit to convert to. Use this if you want to * convert to a unit other than $baselineUnit. */ /** * Convert a font size to a dynamic font size but impose * a maximum font size. * @param size - The initial font size including the unit (i.e. px or pt) * @param maxScale - The maximum scale of the font (i.e. 2.5 for a maximum 250% scale). * @param unit (optional) - The unit to convert the initial font size to. Use this if you want to * convert to a unit other than $baselineUnit. */ /** * Convert a font size to a dynamic font size but impose * a minimum font size. * @param size - The initial font size including the unit (i.e. px or pt) * @param minScale - The minimum scale of the font (i.e. 0.8 for a minimum 80% scale). * @param unit (optional) - The unit to convert the initial font size to. Use this if you want to * convert to a unit other than $baselineUnit. */ /** * Convert a font size to a dynamic font size but impose * maximum and minimum font sizes. * @param size - The initial font size including the unit (i.e. px or pt) * @param minScale - The minimum scale of the font (i.e. 0.8 for a minimum 80% scale). * @param maxScale - The maximum scale of the font (i.e. 2.5 for a maximum 250% scale). * @param unit (optional) - The unit to convert the initial font size to. Use this if you want to * convert to a unit other than $baselineUnit. */ /** * A heuristic that applies CSS to tablet * viewports. * * Usage: * @include tablet-viewport() { * :host { * background-color: green; * } * } */ /** * A heuristic that applies CSS to mobile * viewports (i.e. phones, not tablets). * * Usage: * @include mobile-viewport() { * :host { * background-color: blue; * } * } */ /** * Convert a font size to a dynamic font size. * Fonts that participate in Dynamic Type should use * dynamic font sizes. * @param size - The initial font size including the unit (i.e. px or pt) * @param unit (optional) - The unit to convert to. Use this if you want to * convert to a unit other than $baselineUnit. */ /** * Convert a font size to a dynamic font size but impose * a maximum font size. * @param size - The initial font size including the unit (i.e. px or pt) * @param maxScale - The maximum scale of the font (i.e. 2.5 for a maximum 250% scale). * @param unit (optional) - The unit to convert the initial font size to. Use this if you want to * convert to a unit other than $baselineUnit. */ /** * Convert a font size to a dynamic font size but impose * a minimum font size. * @param size - The initial font size including the unit (i.e. px or pt) * @param minScale - The minimum scale of the font (i.e. 0.8 for a minimum 80% scale). * @param unit (optional) - The unit to convert the initial font size to. Use this if you want to * convert to a unit other than $baselineUnit. */ /** * Convert a font size to a dynamic font size but impose * maximum and minimum font sizes. * @param size - The initial font size including the unit (i.e. px or pt) * @param minScale - The minimum scale of the font (i.e. 0.8 for a minimum 80% scale). * @param maxScale - The maximum scale of the font (i.e. 2.5 for a maximum 250% scale). * @param unit (optional) - The unit to convert the initial font size to. Use this if you want to * convert to a unit other than $baselineUnit. */ /** * A heuristic that applies CSS to tablet * viewports. * * Usage: * @include tablet-viewport() { * :host { * background-color: green; * } * } */ /** * A heuristic that applies CSS to mobile * viewports (i.e. phones, not tablets). * * Usage: * @include mobile-viewport() { * :host { * background-color: blue; * } * } */ :host(.textarea-fill-solid) { --background: var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2)); --border-color: var(--ion-color-step-500, var(--ion-background-color-step-500, gray)); --border-radius: 4px; --padding-start: 16px; --padding-end: 16px; min-height: 56px; } /** * The solid fill style has a border * at the bottom of the textarea wrapper. * As a result, the border on the "bottom * content" is not needed. */ :host(.textarea-fill-solid) .textarea-wrapper { border-bottom: var(--border-width) var(--border-style) var(--border-color); } /** * If the textarea has a validity state, the * border should reflect that as a color. */ :host(.has-focus.textarea-fill-solid.ion-valid), :host(.textarea-fill-solid.ion-touched.ion-invalid) { --border-color: var(--highlight-color); } /** * The bottom content should never have * a border with the solid style. */ :host(.textarea-fill-solid) .textarea-bottom { border-top: none; } /** * Background and border should be * slightly darker on hover. */ @media (any-hover: hover) { :host(.textarea-fill-solid:hover) { --background: var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6)); --border-color: var(--ion-color-step-750, var(--ion-background-color-step-750, #404040)); } } /** * Background and border should be * much darker on focus. */ :host(.textarea-fill-solid.has-focus) { --background: var(--ion-color-step-150, var(--ion-background-color-step-150, #d9d9d9)); --border-color: var(--ion-color-step-750, var(--ion-background-color-step-750, #404040)); } :host(.textarea-fill-solid) .textarea-wrapper { /** * Only the top left and top right borders should. * have a radius when using a solid fill. */ border-start-start-radius: var(--border-radius); border-start-end-radius: var(--border-radius); border-end-end-radius: 0px; border-end-start-radius: 0px; } :host(.label-floating.textarea-fill-solid) .label-text-wrapper { /** * Label text should not extend * beyond the bounds of the textarea. */ max-width: calc(100% / 0.75); } /** * Convert a font size to a dynamic font size. * Fonts that participate in Dynamic Type should use * dynamic font sizes. * @param size - The initial font size including the unit (i.e. px or pt) * @param unit (optional) - The unit to convert to. Use this if you want to * convert to a unit other than $baselineUnit. */ /** * Convert a font size to a dynamic font size but impose * a maximum font size. * @param size - The initial font size including the unit (i.e. px or pt) * @param maxScale - The maximum scale of the font (i.e. 2.5 for a maximum 250% scale). * @param unit (optional) - The unit to convert the initial font size to. Use this if you want to * convert to a unit other than $baselineUnit. */ /** * Convert a font size to a dynamic font size but impose * a minimum font size. * @param size - The initial font size including the unit (i.e. px or pt) * @param minScale - The minimum scale of the font (i.e. 0.8 for a minimum 80% scale). * @param unit (optional) - The unit to convert the initial font size to. Use this if you want to * convert to a unit other than $baselineUnit. */ /** * Convert a font size to a dynamic font size but impose * maximum and minimum font sizes. * @param size - The initial font size including the unit (i.e. px or pt) * @param minScale - The minimum scale of the font (i.e. 0.8 for a minimum 80% scale). * @param maxScale - The maximum scale of the font (i.e. 2.5 for a maximum 250% scale). * @param unit (optional) - The unit to convert the initial font size to. Use this if you want to * convert to a unit other than $baselineUnit. */ /** * A heuristic that applies CSS to tablet * viewports. * * Usage: * @include tablet-viewport() { * :host { * background-color: green; * } * } */ /** * A heuristic that applies CSS to mobile * viewports (i.e. phones, not tablets). * * Usage: * @include mobile-viewport() { * :host { * background-color: blue; * } * } */ :host(.textarea-fill-outline) { --border-color: var(--ion-color-step-300, var(--ion-background-color-step-300, #b3b3b3)); --border-radius: 4px; --padding-start: 16px; --padding-end: 16px; min-height: 56px; } :host(.textarea-fill-outline.textarea-shape-round) { --border-radius: 28px; --padding-start: 32px; --padding-end: 32px; } /** * If the textarea has a validity state, the * border should reflect that as a color. */ :host(.has-focus.textarea-fill-outline.ion-valid), :host(.textarea-fill-outline.ion-touched.ion-invalid) { --border-color: var(--highlight-color); } /** * Border should be * slightly darker on hover. */ @media (any-hover: hover) { :host(.textarea-fill-outline:hover) { --border-color: var(--ion-color-step-750, var(--ion-background-color-step-750, #404040)); } } /** * The border should get thicker * and take on component color when * the textarea is focused. */ :host(.textarea-fill-outline.has-focus) { --border-width: var(--highlight-height); --border-color: var(--highlight-color); } /** * The bottom content should never have * a border with the outline style. */ :host(.textarea-fill-outline) .textarea-bottom { border-top: none; } /** * Outline textarea do not have a bottom border. * Instead, they have a border that wraps the * textarea + label. */ :host(.textarea-fill-outline) .textarea-wrapper { border-bottom: none; } :host(.textarea-fill-outline.textarea-label-placement-stacked) .label-text-wrapper, :host(.textarea-fill-outline.textarea-label-placement-floating) .label-text-wrapper { transform-origin: left top; position: absolute; /** * Label text should not extend * beyond the bounds of the textarea. */ max-width: calc(100% - var(--padding-start) - var(--padding-end)); } :host-context([dir=rtl]):host(.textarea-fill-outline.textarea-label-placement-stacked) .label-text-wrapper, :host-context([dir=rtl]).textarea-fill-outline.textarea-label-placement-stacked .label-text-wrapper, :host-context([dir=rtl]):host(.textarea-fill-outline.textarea-label-placement-floating) .label-text-wrapper, :host-context([dir=rtl]).textarea-fill-outline.textarea-label-placement-floating .label-text-wrapper { transform-origin: right top; } @supports selector(:dir(rtl)) { :host(.textarea-fill-outline.textarea-label-placement-stacked:dir(rtl)) .label-text-wrapper, :host(.textarea-fill-outline.textarea-label-placement-floating:dir(rtl)) .label-text-wrapper { transform-origin: right top; } } /** * The label should appear on top of an outline * container that overlaps it so it is always clickable. */ :host(.textarea-fill-outline) .label-text-wrapper, :host(.textarea-fill-outline) .label-text-wrapper { position: relative; } /** * This makes the label sit above the textarea. */ :host(.label-floating.textarea-fill-outline) .label-text-wrapper { transform: translateY(-32%) scale(0.75); margin-left: 0; margin-right: 0; margin-top: 0; margin-bottom: 0; /** * Label text should not extend * beyond the bounds of the textarea. */ max-width: calc( (100% - var(--padding-start) - var(--padding-end) - 8px) / 0.75 ); } /** * This ensures that the textarea does not * overlap the floating label while still * remaining visually centered. */ :host(.textarea-fill-outline.textarea-label-placement-stacked) textarea, :host(.textarea-fill-outline.textarea-label-placement-floating) textarea, :host(.textarea-fill-outline.textarea-label-placement-stacked[auto-grow]) .native-wrapper::after, :host(.textarea-fill-outline.textarea-label-placement-floating[auto-grow]) .native-wrapper::after { -webkit-margin-start: 0px; margin-inline-start: 0px; -webkit-margin-end: 0px; margin-inline-end: 0px; margin-top: 12px; margin-bottom: 0px; } :host(.textarea-fill-outline.textarea-label-placement-stacked) ::slotted([slot=start]), :host(.textarea-fill-outline.textarea-label-placement-stacked) ::slotted([slot=end]), :host(.textarea-fill-outline.textarea-label-placement-floating) ::slotted([slot=start]), :host(.textarea-fill-outline.textarea-label-placement-floating) ::slotted([slot=end]) { margin-top: 12px; } :host(.textarea-fill-outline) .textarea-outline-container { left: 0; right: 0; top: 0; bottom: 0; display: flex; position: absolute; width: 100%; height: 100%; } :host(.textarea-fill-outline) .textarea-outline-start, :host(.textarea-fill-outline) .textarea-outline-end { pointer-events: none; } /** * By default, each piece of the container should have * a top and bottom border. This gives the appearance * of a unified container with a border. */ :host(.textarea-fill-outline) .textarea-outline-start, :host(.textarea-fill-outline) .textarea-outline-notch, :host(.textarea-fill-outline) .textarea-outline-end { border-top: var(--border-width) var(--border-style) var(--border-color); border-bottom: var(--border-width) var(--border-style) var(--border-color); } /** * Ensures long labels do not cause the notch to flow * out of bounds. */ :host(.textarea-fill-outline) .textarea-outline-notch { max-width: calc(100% - var(--padding-start) - var(--padding-end)); } /** * This element ensures that the notch used * the size of the scaled text so that the * border cut out is the correct width. * The text in this element should not * be interactive. */ :host(.textarea-fill-outline) .notch-spacer { /** * We need $textarea-md-floating-label-padding of padding on the right. * However, we also subtracted $textarea-md-floating-label-padding from * the width of .textarea-outline-start * to create space, so we need to take * that into consideration here. */ -webkit-padding-end: 8px; padding-inline-end: 8px; font-size: calc(1em * 0.75); opacity: 0; pointer-events: none; /** * The spacer currently inherits * border-box sizing from the Ionic reset styles. * However, we do not want to include padding in * the calculation of the element dimensions. * This code can be removed if textarea is updated * to use the Shadow DOM. */ box-sizing: content-box; } :host(.textarea-fill-outline) .textarea-outline-start { border-start-start-radius: var(--border-radius); border-start-end-radius: 0px; border-end-end-radius: 0px; border-end-start-radius: var(--border-radius); -webkit-border-start: var(--border-width) var(--border-style) var(--border-color); border-inline-start: var(--border-width) var(--border-style) var(--border-color); /** * There should be spacing between the translated text * and .textarea-outline-start. However, we can't add this * spacing onto the notch because it would cause the * label to look like it is not aligned with the * text textarea. Instead, we subtract a few pixels from * this element. */ width: calc(var(--padding-start) - 4px); } :host(.textarea-fill-outline) .textarea-outline-end { -webkit-border-end: var(--border-width) var(--border-style) var(--border-color); border-inline-end: var(--border-width) var(--border-style) var(--border-color); border-start-start-radius: 0px; border-start-end-radius: var(--border-radius); border-end-end-radius: var(--border-radius); border-end-start-radius: 0px; /** * The ending outline fragment * should take up the remaining free space. */ flex-grow: 1; } /** * When the textarea either has focus or a value, * there should be a "cut out" at the top for * the floating/stacked label. We simulate this "cut out" * by removing the top border from the notch fragment. */ :host(.label-floating.textarea-fill-outline) .textarea-outline-notch { border-top: none; } :host { --border-width: 1px; --border-color: var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-150, var(--ion-background-color-step-150, rgba(0, 0, 0, 0.13))))); --padding-top: 18px; --padding-end: 0px; --padding-bottom: 8px; --padding-start: 0px; --highlight-height: 2px; font-size: inherit; } .textarea-bottom .counter { letter-spacing: 0.0333333333em; } /** * When the textarea is focused the label should * take on the highlight color. This should * only apply to floating or stacked labels. */ :host(.textarea-label-placement-floating.has-focus) .label-text-wrapper, :host(.textarea-label-placement-stacked.has-focus) .label-text-wrapper { color: var(--highlight-color); } :host(.has-focus.textarea-label-placement-floating.ion-valid) .label-text-wrapper, :host(.textarea-label-placement-floating.ion-touched.ion-invalid) .label-text-wrapper, :host(.has-focus.textarea-label-placement-stacked.ion-valid) .label-text-wrapper, :host(.textarea-label-placement-stacked.ion-touched.ion-invalid) .label-text-wrapper { color: var(--highlight-color); } :host(.textarea-disabled) { opacity: 0.38; } .textarea-highlight { bottom: -1px; position: absolute; width: 100%; height: var(--highlight-height); transform: scale(0); transition: transform 200ms; background: var(--highlight-color); } .textarea-highlight { inset-inline-start: 0; } :host(.has-focus) .textarea-highlight { transform: scale(1); } /** * Adjust the highlight up by 1px * so it is not cut off by the * the item's line (if one is present). */ :host(.in-item) .textarea-highlight { bottom: 0; } :host(.in-item) .textarea-highlight { inset-inline-start: 0; } :host(.textarea-shape-round) { --border-radius: 16px; } /** * Slotted buttons have a lot of default padding that can * cause them to look misaligned from other pieces such * as the control's label, especially when using a clear * fill. We also make them circular to ensure that non- * clear buttons and the focus/hover state on clear ones * don't look too crowded. */ ::slotted(ion-button[slot=start].button-has-icon-only), ::slotted(ion-button[slot=end].button-has-icon-only) { --border-radius: 50%; --padding-start: 8px; --padding-end: 8px; --padding-top: 8px; --padding-bottom: 8px; aspect-ratio: 1; min-height: 40px; }