{{ lumx.helper }}
-
diff --git a/src/components/text-field/angularjs/text-field_directive.js b/src/components/text-field/angularjs/text-field_directive.js
index 3a1a70bff..8debe6800 100644
--- a/src/components/text-field/angularjs/text-field_directive.js
+++ b/src/components/text-field/angularjs/text-field_directive.js
@@ -1,7 +1,7 @@
import { CSS_PREFIX } from 'LumX/core/constants';
import { COMPONENT_PREFIX, MODULE_NAME } from 'LumX/angularjs/constants/common_constants';
-import { mdiAlertCircle, mdiCheckCircle } from 'LumX/icons';
+import { mdiAlertCircle, mdiCheckCircle, mdiCloseCircle } from 'LumX/icons';
import template from './text-field.html';
@@ -32,6 +32,20 @@ function TextFieldController(LumXUtilsService) {
// //
/////////////////////////////
+ /**
+ * Whether the directive has chips slot filled or not.
+ *
+ * @type {boolean}
+ */
+ lumx.hasChips = false;
+
+ /**
+ * Whether the directive has input slot filled or not.
+ *
+ * @type {boolean}
+ */
+ lumx.hasInput = false;
+
/**
* The text field icons.
*
@@ -40,6 +54,7 @@ function TextFieldController(LumXUtilsService) {
lumx.icons = {
mdiAlertCircle,
mdiCheckCircle,
+ mdiCloseCircle,
};
/**
@@ -55,13 +70,27 @@ function TextFieldController(LumXUtilsService) {
// //
/////////////////////////////
+ /**
+ * Clear the model on clear button click.
+ *
+ * @param {Event} [evt] The event that triggered the function.
+ */
+ function clearModel(evt) {
+ if (angular.isDefined(evt)) {
+ evt.stopPropagation();
+ }
+
+ _modelController.$setViewValue(undefined);
+ _modelController.$render();
+ }
+
/**
* Define if the model controller has a value or not.
*
* @return {boolean} Wether the model controller has a value or not.
*/
function hasValue() {
- if (angular.isUndefined(_modelController.$viewValue)) {
+ if (angular.isUndefined(_modelController) || angular.isUndefined(_modelController.$viewValue)) {
return false;
}
@@ -79,70 +108,81 @@ function TextFieldController(LumXUtilsService) {
/////////////////////////////
+ lumx.clearModel = clearModel;
lumx.hasValue = hasValue;
lumx.setModelController = setModelController;
}
/////////////////////////////
-function TextFieldDirective() {
+function TextFieldDirective($timeout) {
'ngInject';
- function link(scope, el, attrs, ctrl) {
- const _MIN_ROWS = 2;
+ function link(scope, el, attrs, ctrl, transclude) {
+ if (transclude.isSlotFilled('chips')) {
+ ctrl.hasChips = true;
+ }
- let input = el.find('input');
+ if (transclude.isSlotFilled('input')) {
+ ctrl.hasInput = true;
+ }
- if (input.length === 1) {
- el.addClass(`${CSS_PREFIX}-text-field--has-input`);
- } else {
- input = el.find('textarea');
+ $timeout(() => {
+ const _MIN_ROWS = 2;
- input.on('input', (evt) => {
- evt.target.rows = _MIN_ROWS;
- const currentRows = evt.target.scrollHeight / (evt.target.clientHeight / _MIN_ROWS);
- evt.target.rows = currentRows;
- });
+ let input = el.find('input');
- el.addClass(`${CSS_PREFIX}-text-field--has-textarea`);
- }
+ if (input.length === 1) {
+ el.addClass(`${CSS_PREFIX}-text-field--has-input`);
+ } else {
+ input = el.find('textarea');
- const modelController = input.data('$ngModelController');
+ input.on('input', (evt) => {
+ evt.target.rows = _MIN_ROWS;
+ const currentRows = evt.target.scrollHeight / (evt.target.clientHeight / _MIN_ROWS);
+ evt.target.rows = currentRows;
+ });
- ctrl.setModelController(modelController);
+ el.addClass(`${CSS_PREFIX}-text-field--has-textarea`);
+ }
- if (input.attr('id')) {
- ctrl.inputId = input.attr('id');
- } else {
- input.attr('id', ctrl.inputId);
- }
+ const modelController = input.data('$ngModelController');
- input
- .on('focus', function onFocus() {
- el.addClass(`${CSS_PREFIX}-text-field--is-focus`);
- })
- .on('blur', function onBlur() {
- el.removeClass(`${CSS_PREFIX}-text-field--is-focus`);
- });
+ ctrl.setModelController(modelController);
- modelController.$$attr.$observe('disabled', (isDisabled) => {
- if (isDisabled) {
- el.addClass(`${CSS_PREFIX}-text-field--is-disabled`);
+ if (input.attr('id')) {
+ ctrl.inputId = input.attr('id');
} else {
- el.removeClass(`${CSS_PREFIX}-text-field--is-disabled`);
+ input.attr('id', ctrl.inputId);
}
- });
- modelController.$$attr.$observe('placeholder', (placeholder) => {
- if (placeholder.length > 0) {
- el.addClass(`${CSS_PREFIX}-text-field--has-placeholder`);
- } else {
- el.removeClass(`${CSS_PREFIX}-text-field--has-placeholder`);
- }
- });
+ input
+ .on('focus', function onFocus() {
+ el.addClass(`${CSS_PREFIX}-text-field--is-focus`);
+ })
+ .on('blur', function onBlur() {
+ el.removeClass(`${CSS_PREFIX}-text-field--is-focus`);
+ });
+
+ modelController.$$attr.$observe('disabled', (isDisabled) => {
+ if (isDisabled) {
+ el.addClass(`${CSS_PREFIX}-text-field--is-disabled`);
+ } else {
+ el.removeClass(`${CSS_PREFIX}-text-field--is-disabled`);
+ }
+ });
- scope.$on('$destroy', () => {
- input.off();
+ modelController.$$attr.$observe('placeholder', (placeholder) => {
+ if (placeholder.length > 0) {
+ el.addClass(`${CSS_PREFIX}-text-field--has-placeholder`);
+ } else {
+ el.removeClass(`${CSS_PREFIX}-text-field--has-placeholder`);
+ }
+ });
+
+ scope.$on('$destroy', () => {
+ input.off();
+ });
});
}
@@ -158,12 +198,16 @@ function TextFieldDirective() {
hasError: '=?lumxHasError',
helper: '@?lumxHelper',
icon: '@?lumxIcon',
+ isClearable: '=?lumxIsClearable',
isValid: '=?lumxIsValid',
label: '@?lumxLabel',
theme: '@?lumxTheme',
},
template,
- transclude: true,
+ transclude: {
+ chips: `?${COMPONENT_PREFIX}TextFieldChips`,
+ input: `?${COMPONENT_PREFIX}TextFieldInput`,
+ },
};
}
diff --git a/src/components/text-field/react/TextField.tsx b/src/components/text-field/react/TextField.tsx
index b1668366c..377664880 100644
--- a/src/components/text-field/react/TextField.tsx
+++ b/src/components/text-field/react/TextField.tsx
@@ -1,15 +1,15 @@
-import React, { ReactElement, RefObject, useState } from 'react';
+import React, { ReactElement, ReactNode, RefObject, useState } from 'react';
import classNames from 'classnames';
import get from 'lodash/get';
import uuid from 'uuid/v4';
-import { Icon, Size, Theme } from 'LumX';
+import { Emphasis, Icon, IconButton, Size, Theme } from 'LumX';
import { CSS_PREFIX } from 'LumX/core/constants';
import { COMPONENT_PREFIX } from 'LumX/core/react/constants';
import { IGenericProps, getRootClassName } from 'LumX/core/react/utils';
import { handleBasicClasses } from 'LumX/core/utils';
-import { mdiAlertCircle, mdiCheckCircle } from 'LumX/icons';
+import { mdiAlertCircle, mdiCheckCircle, mdiCloseCircle } from 'LumX/icons';
/////////////////////////////
@@ -22,6 +22,9 @@ enum TextFieldType {
* Defines the props of the component.
*/
interface ITextFieldProps extends IGenericProps {
+ /** A Chip Group to be rendered before the main text input */
+ chips?: HTMLElement | ReactNode;
+
/** Whether the text field is displayed with error style or not. */
hasError?: boolean;
@@ -40,6 +43,9 @@ interface ITextFieldProps extends IGenericProps {
/** Whether the text field is displayed with valid style or not. */
isValid?: boolean;
+ /** Whether the text field shows a cross to clear its content or not. */
+ isClearable?: boolean;
+
/** Text field label displayed in a label tag. */
label?: string;
@@ -64,8 +70,17 @@ interface ITextFieldProps extends IGenericProps {
/** Text field type (input or textarea). */
type?: TextFieldType;
+ /** A ref that will be passed to the wrapper element. */
+ textFieldRef?: RefObject
;
+
/** Text field value change handler. */
onChange(value: string): void;
+
+ /** Text field focus change handler. */
+ onFocus?(event: React.FocusEvent): void;
+
+ /** Text field blur change handler. */
+ onBlur?(event: React.FocusEvent): void;
}
type TextFieldProps = ITextFieldProps;
@@ -97,6 +112,7 @@ const MIN_ROWS = 2;
*/
const DEFAULT_PROPS: Partial = {
hasError: false,
+ isClearable: false,
isDisabled: false,
isValid: false,
minimumRows: MIN_ROWS,
@@ -161,6 +177,8 @@ interface IInputNativeProps {
setFocus(focus: boolean): void;
recomputeNumberOfRows(event: React.ChangeEvent): void;
onChange(value: string): void;
+ onFocus?(value: React.FocusEvent): void;
+ onBlur?(value: React.FocusEvent): void;
}
const renderInputNative = (props: IInputNativeProps): ReactElement => {
@@ -172,13 +190,29 @@ const renderInputNative = (props: IInputNativeProps): ReactElement => {
value,
setFocus,
onChange,
+ onFocus,
+ onBlur,
inputRef,
rows,
recomputeNumberOfRows,
...forwardedProps
} = props;
- const onFocus = (): void => setFocus(true);
- const onBlur = (): void => setFocus(false);
+
+ const onTextFieldFocus = (event: React.FocusEvent): void => {
+ if (onFocus) {
+ onFocus(event);
+ }
+
+ return setFocus(true);
+ };
+
+ const onTextFieldBlur = (event: React.FocusEvent): void => {
+ if (onBlur) {
+ onBlur(event);
+ }
+
+ return setFocus(false);
+ };
const handleChange = (event: React.ChangeEvent): void => {
if (type === TextFieldType.textarea) {
@@ -195,11 +229,11 @@ const renderInputNative = (props: IInputNativeProps): ReactElement => {
disabled={isDisabled}
placeholder={placeholder}
value={value}
- ref={inputRef as RefObject}
- onFocus={onFocus}
- onBlur={onBlur}
- onChange={handleChange}
rows={rows}
+ onFocus={onTextFieldFocus}
+ onBlur={onTextFieldBlur}
+ onChange={handleChange}
+ ref={inputRef as RefObject}
{...forwardedProps}
/>
);
@@ -211,9 +245,10 @@ const renderInputNative = (props: IInputNativeProps): ReactElement => {
type="text"
placeholder={placeholder}
value={value}
- onFocus={onFocus}
- onBlur={onBlur}
+ onFocus={onTextFieldFocus}
+ onBlur={onTextFieldBlur}
onChange={handleChange}
+ ref={inputRef as RefObject}
{...forwardedProps}
/>
);
@@ -227,40 +262,63 @@ const renderInputNative = (props: IInputNativeProps): ReactElement => {
*/
const TextField: React.FC = (props: TextFieldProps): ReactElement => {
const {
+ chips,
className = '',
hasError,
helper,
icon,
id = uuid(),
isDisabled,
+ isClearable = DEFAULT_PROPS.isClearable,
isValid,
label,
onChange,
+ onFocus,
+ onBlur,
placeholder,
minimumRows = DEFAULT_PROPS.minimumRows as number,
inputRef = React.useRef(null),
theme = DEFAULT_PROPS.theme,
type = DEFAULT_PROPS.type,
useCustomColors,
+ textFieldRef,
value,
...forwardedProps
} = props;
const [isFocus, setFocus] = useState(false);
const { rows, recomputeNumberOfRows } = useComputeNumberOfRows(minimumRows);
+ const isNotEmpty = value && value.length > 0;
+
+ /**
+ * Function triggered when the Clear Button is clicked.
+ * The idea is to execute the `onChange` callback with an empty string
+ * and remove focus from the clear button.
+ * @param evt On clear event.
+ */
+ const onClear = (evt: React.ChangeEvent): void => {
+ evt.nativeEvent.preventDefault();
+ evt.nativeEvent.stopPropagation();
+ (evt.currentTarget as HTMLElement).blur();
+
+ onChange('');
+ };
return (
= (props: TextFieldProps): ReactElemen
}),
{ [`${CSS_PREFIX}-custom-colors`]: useCustomColors },
)}
+ ref={textFieldRef}
>
{label && (
diff --git a/src/components/text-field/style/lumapps/_index.scss b/src/components/text-field/style/lumapps/_index.scss
index 10a38a528..b70298220 100644
--- a/src/components/text-field/style/lumapps/_index.scss
+++ b/src/components/text-field/style/lumapps/_index.scss
@@ -25,26 +25,34 @@
}
}
- &__input-wrapper {
+ &__wrapper {
#{$self}--has-input#{$self}--theme-light & {
- @include lumx-text-field-input-wrapper('dark', false, false, 'input');
+ @include lumx-text-field-wrapper('dark', 'input');
}
#{$self}--has-input#{$self}--theme-dark & {
- @include lumx-text-field-input-wrapper('light', false, false, 'input');
+ @include lumx-text-field-wrapper('light', 'input');
}
#{$self}--has-textarea#{$self}--theme-light & {
- @include lumx-text-field-input-wrapper('dark', false, false, 'textarea');
+ @include lumx-text-field-wrapper('dark', 'textarea');
}
#{$self}--has-textarea#{$self}--theme-dark & {
- @include lumx-text-field-input-wrapper('light', false, false, 'textarea');
+ @include lumx-text-field-wrapper('light', 'textarea');
+ }
+
+ #{$self}--has-input-clear & {
+ @include lumx-text-field-wrapper-has-input-clear;
+ }
+
+ #{$self}--has-chips & {
+ @include lumx-text-field-wrapper-has-chips;
}
}
- &--has-label &__input-wrapper {
- margin-top: $lumx-spacing-unit;
+ &--has-label &__wrapper {
+ @include lumx-text-field-wrapper-has-label;
}
&__input-icon {
@@ -59,6 +67,10 @@
}
}
+ &__input-wrapper {
+ @include lumx-text-field-input-wrapper;
+ }
+
&__input-native {
flex: 1;
@@ -96,8 +108,12 @@
}
}
- &__input-validity {
- flex-shrink: 0;
+ &__input-clear {
+ @include lumx-text-field-input-clear;
+ }
+
+ &__chips {
+ @include lumx-text-field-chips;
}
}
@@ -106,7 +122,7 @@
// Disabled state
.#{$lumx-base-prefix}-text-field--is-disabled {
- .#{$lumx-base-prefix}-text-field__input-wrapper {
+ .#{$lumx-base-prefix}-text-field__wrapper {
@include lumx-state-disabled-input;
}
@@ -127,27 +143,27 @@
// Hover state
.#{$lumx-base-prefix}-text-field--theme-light {
- .#{$lumx-base-prefix}-text-field__input-wrapper:hover {
- @include lumx-text-field-input-wrapper-state('state-hover', 'dark');
+ .#{$lumx-base-prefix}-text-field__wrapper:hover {
+ @include lumx-text-field-wrapper-state('state-hover', 'dark');
}
}
.#{$lumx-base-prefix}-text-field--theme-dark {
- .#{$lumx-base-prefix}-text-field__input-wrapper:hover {
- @include lumx-text-field-input-wrapper-state('state-hover', 'light');
+ .#{$lumx-base-prefix}-text-field__wrapper:hover {
+ @include lumx-text-field-wrapper-state('state-hover', 'light');
}
}
// Focus state
.#{$lumx-base-prefix}-text-field--theme-light.#{$lumx-base-prefix}-text-field--is-focus {
- .#{$lumx-base-prefix}-text-field__input-wrapper {
- @include lumx-text-field-input-wrapper-state('state-focus', 'dark');
+ .#{$lumx-base-prefix}-text-field__wrapper {
+ @include lumx-text-field-wrapper-state('state-focus', 'dark');
}
}
.#{$lumx-base-prefix}-text-field--theme-dark.#{$lumx-base-prefix}-text-field--is-focus {
- .#{$lumx-base-prefix}-text-field__input-wrapper {
- @include lumx-text-field-input-wrapper-state('state-focus', 'light');
+ .#{$lumx-base-prefix}-text-field__wrapper {
+ @include lumx-text-field-wrapper-state('state-focus', 'light');
}
}
@@ -155,8 +171,8 @@
========================================================================== */
.#{$lumx-base-prefix}-text-field--theme-light.#{$lumx-base-prefix}-text-field--is-valid {
- .#{$lumx-base-prefix}-text-field__input-wrapper {
- @include lumx-text-field-input-wrapper-validity('valid', 'dark');
+ .#{$lumx-base-prefix}-text-field__wrapper {
+ @include lumx-text-field-wrapper-validity('valid', 'dark');
}
.#{$lumx-base-prefix}-text-field__input-validity {
@@ -165,8 +181,8 @@
}
.#{$lumx-base-prefix}-text-field--theme-light.#{$lumx-base-prefix}-text-field--has-error {
- .#{$lumx-base-prefix}-text-field__input-wrapper {
- @include lumx-text-field-input-wrapper-validity('error', 'dark');
+ .#{$lumx-base-prefix}-text-field__wrapper {
+ @include lumx-text-field-wrapper-validity('error', 'dark');
}
.#{$lumx-base-prefix}-text-field__input-validity {
@@ -175,8 +191,8 @@
}
.#{$lumx-base-prefix}-text-field--theme-dark.#{$lumx-base-prefix}-text-field--is-valid {
- .#{$lumx-base-prefix}-text-field__input-wrapper {
- @include lumx-text-field-input-wrapper-validity('valid', 'light');
+ .#{$lumx-base-prefix}-text-field__wrapper {
+ @include lumx-text-field-wrapper-validity('valid', 'light');
}
.#{$lumx-base-prefix}-text-field__input-validity {
@@ -185,8 +201,8 @@
}
.#{$lumx-base-prefix}-text-field--theme-dark.#{$lumx-base-prefix}-text-field--has-error {
- .#{$lumx-base-prefix}-text-field__input-wrapper {
- @include lumx-text-field-input-wrapper-validity('error', 'light');
+ .#{$lumx-base-prefix}-text-field__wrapper {
+ @include lumx-text-field-wrapper-validity('error', 'light');
}
.#{$lumx-base-prefix}-text-field__input-validity {
diff --git a/src/components/text-field/style/lumapps/_mixins.scss b/src/components/text-field/style/lumapps/_mixins.scss
index 27da28f71..79553d83f 100644
--- a/src/components/text-field/style/lumapps/_mixins.scss
+++ b/src/components/text-field/style/lumapps/_mixins.scss
@@ -1,6 +1,7 @@
-@mixin lumx-text-field-input-wrapper($theme, $has-indicator: false, $is-multiple: false, $type: 'input') {
+@mixin lumx-text-field-wrapper($theme, $type: 'input') {
position: relative;
display: flex;
+ flex-wrap: wrap;
align-items: center;
background-color: lumx-theme-color-variant($theme, 'L6');
border-radius: $lumx-theme-border-radius;
@@ -10,20 +11,30 @@
transition-property: background-color, box-shadow;
@if $type == 'input' {
- @if $is-multiple {
- min-height: $lumx-text-field-height;
- padding: 3px;
- } @else {
- height: $lumx-text-field-height;
- padding: 0 $lumx-text-field-horizontal-padding;
- }
+ height: $lumx-text-field-height;
+ padding: 0 $lumx-text-field-horizontal-padding;
} @else {
padding: $lumx-text-field-vertical-padding $lumx-text-field-horizontal-padding;
}
+}
- @if $has-indicator {
- padding-right: $lumx-spacing-unit * 1.5;
- }
+@mixin lumx-text-field-wrapper-has-label() {
+ margin-top: $lumx-spacing-unit;
+}
+
+@mixin lumx-text-field-wrapper-has-input-clear() {
+ padding-right: $lumx-spacing-unit !important;
+}
+
+@mixin lumx-text-field-wrapper-has-chips() {
+ height: auto !important;
+ min-height: $lumx-text-field-height;
+}
+
+@mixin lumx-text-field-input-wrapper() {
+ display: flex;
+ flex: 1;
+ align-items: center;
}
@mixin lumx-text-field-input-icon($theme) {
@@ -36,6 +47,7 @@
display: block;
width: 100%;
+ min-width: $lumx-text-field-min-width;
padding: 0;
border: none;
margin: 0;
@@ -50,6 +62,7 @@
}
@mixin lumx-text-field-input-validity($validity, $theme) {
+ flex-shrink: 0;
margin-left: $lumx-spacing-unit;
@if $theme == 'dark' {
@@ -63,11 +76,19 @@
}
}
+@mixin lumx-text-field-input-clear() {
+ margin-left: $lumx-spacing-unit / 2;
+}
+
+@mixin lumx-text-field-chips() {
+ margin: $lumx-chip-group-spacing 0;
+}
+
@mixin lumx-text-field-placeholder($theme) {
color: lumx-theme-color-variant($theme, 'L2');
}
-@mixin lumx-text-field-input-wrapper-state($state, $theme) {
+@mixin lumx-text-field-wrapper-state($state, $theme) {
@if $state == 'state-hover' {
background-color: lumx-theme-color-variant($theme, 'L5');
} @else if $state == 'state-focus' {
@@ -81,7 +102,7 @@
}
}
-@mixin lumx-text-field-input-wrapper-validity($validity, $theme) {
+@mixin lumx-text-field-wrapper-validity($validity, $theme) {
@if $theme == 'dark' {
@if $validity == 'valid' {
box-shadow: inset 0 0 0 2px lumx-theme-color-variant('green', 'N');
diff --git a/src/components/text-field/style/lumapps/_variables.scss b/src/components/text-field/style/lumapps/_variables.scss
index b624a6073..b547c9a24 100644
--- a/src/components/text-field/style/lumapps/_variables.scss
+++ b/src/components/text-field/style/lumapps/_variables.scss
@@ -1,4 +1,5 @@
$lumx-text-field-height: map-get($lumx-sizes, 'm') !default;
-$lumx-text-field-horizontal-padding: $lumx-spacing-unit * 2 !default;
+$lumx-text-field-horizontal-padding: $lumx-spacing-unit * 1.5 !default;
$lumx-text-field-vertical-padding: $lumx-spacing-unit * 1.5 !default;
$lumx-text-field-transition-duration: 100ms;
+$lumx-text-field-min-width: 150px;
diff --git a/src/components/text-field/style/material/_index.scss b/src/components/text-field/style/material/_index.scss
index f40c8ae4e..2538f101c 100644
--- a/src/components/text-field/style/material/_index.scss
+++ b/src/components/text-field/style/material/_index.scss
@@ -24,7 +24,8 @@
#{$self}--has-placeholder &,
#{$self}--has-value &,
- #{$self}--is-focus & {
+ #{$self}--is-focus &,
+ #{$self}--has-chips & {
transform: scale(0.75) translateY(0);
}
}
@@ -33,13 +34,17 @@
display: none !important;
}
- &__input-wrapper {
+ &__wrapper {
#{$self}--theme-light & {
- @include lumx-text-field-material-input-wrapper('dark');
+ @include lumx-text-field-material-wrapper('dark');
}
#{$self}--theme-dark & {
- @include lumx-text-field-material-input-wrapper('light');
+ @include lumx-text-field-material-wrapper('light');
+ }
+
+ #{$self}--has-input-clear & {
+ padding-right: 0 !important;
}
}
@@ -59,8 +64,8 @@
// Focus state
.#{$lumx-base-prefix}-text-field--is-focus {
- .#{$lumx-base-prefix}-text-field__input-wrapper {
- @include lumx-text-field-material-input-wrapper-focus;
+ .#{$lumx-base-prefix}-text-field__wrapper {
+ @include lumx-text-field-material-wrapper-focus;
}
}
@@ -84,8 +89,8 @@
@include lumx-text-field-material-label-validity('valid');
}
- .#{$lumx-base-prefix}-text-field__input-wrapper {
- @include lumx-text-field-material-input-wrapper-validity('valid');
+ .#{$lumx-base-prefix}-text-field__wrapper {
+ @include lumx-text-field-material-wrapper-validity('valid');
}
}
@@ -94,7 +99,7 @@
@include lumx-text-field-material-label-validity('error');
}
- .#{$lumx-base-prefix}-text-field__input-wrapper {
- @include lumx-text-field-material-input-wrapper-validity('error');
+ .#{$lumx-base-prefix}-text-field__wrapper {
+ @include lumx-text-field-material-wrapper-validity('error');
}
}
diff --git a/src/components/text-field/style/material/_mixins.scss b/src/components/text-field/style/material/_mixins.scss
index f7f69d5d8..1e8352ec3 100644
--- a/src/components/text-field/style/material/_mixins.scss
+++ b/src/components/text-field/style/material/_mixins.scss
@@ -27,7 +27,7 @@
}
}
-@mixin lumx-text-field-material-input-wrapper($theme) {
+@mixin lumx-text-field-material-wrapper($theme) {
position: relative;
margin-top: 0;
background-color: transparent !important;
@@ -64,7 +64,7 @@
}
}
-@mixin lumx-text-field-material-input-wrapper-validity($validity) {
+@mixin lumx-text-field-material-wrapper-validity($validity) {
&::after {
transform: scaleX(1);
}
@@ -80,7 +80,7 @@
}
}
-@mixin lumx-text-field-material-input-wrapper-focus() {
+@mixin lumx-text-field-material-wrapper-focus() {
&::after {
transform: scaleX(1);
}
diff --git a/src/core/custom-colors.js b/src/core/custom-colors.js
index 0acf048bf..64d812a3c 100644
--- a/src/core/custom-colors.js
+++ b/src/core/custom-colors.js
@@ -330,8 +330,8 @@ function _getSelectCSSRules(colorPalette, theme) {
selectRules = [
{
selector: `
- .${CSS_PREFIX}-custom-colors.${CSS_PREFIX}-select--theme-light.${CSS_PREFIX}-select--is-open .${CSS_PREFIX}-select__input-wrapper,
- .${CSS_PREFIX}-custom-colors.${CSS_PREFIX}-select--theme-light .${CSS_PREFIX}-select__input-wrapper:focus
+ .${CSS_PREFIX}-custom-colors.${CSS_PREFIX}-select--theme-light.${CSS_PREFIX}-select--is-open:not(.${CSS_PREFIX}-select--has-error):not(.${CSS_PREFIX}-select--is-valid) .${CSS_PREFIX}-select__wrapper,
+ .${CSS_PREFIX}-custom-colors.${CSS_PREFIX}-select--theme-light:not(.${CSS_PREFIX}-select--has-error):not(.${CSS_PREFIX}-select--is-valid) .${CSS_PREFIX}-select__wrapper:focus
`,
rule: `box-shadow: inset 0 0 0 2px ${colorPalette.primary.L2}`,
},
@@ -340,14 +340,14 @@ function _getSelectCSSRules(colorPalette, theme) {
selectRules = [
{
selector: `
- .${CSS_PREFIX}-custom-colors.${CSS_PREFIX}-select--theme-light.${CSS_PREFIX}-select--is-focus .${CSS_PREFIX}-select__label,
- .${CSS_PREFIX}-custom-colors.${CSS_PREFIX}-select--theme-light.${CSS_PREFIX}-select--is-open .${CSS_PREFIX}-select__label
+ .${CSS_PREFIX}-custom-colors.${CSS_PREFIX}-select--theme-light.${CSS_PREFIX}-select--is-focus:not(.${CSS_PREFIX}-select--has-error):not(.${CSS_PREFIX}-select--is-valid) .${CSS_PREFIX}-select__label,
+ .${CSS_PREFIX}-custom-colors.${CSS_PREFIX}-select--theme-light.${CSS_PREFIX}-select--is-open:not(.${CSS_PREFIX}-select--has-error):not(.${CSS_PREFIX}-select--is-valid) .${CSS_PREFIX}-select__label
`,
rule: `color: ${colorPalette.primary.N}`,
},
{
selector: `
- .${CSS_PREFIX}-custom-colors.${CSS_PREFIX}-select--theme-light .${CSS_PREFIX}-select__input-wrapper::after
+ .${CSS_PREFIX}-custom-colors.${CSS_PREFIX}-select--theme-light:not(.${CSS_PREFIX}-select--has-error):not(.${CSS_PREFIX}-select--is-valid) .${CSS_PREFIX}-select__wrapper::after
`,
rule: `background-color: ${colorPalette.primary.N}`,
},
@@ -554,7 +554,7 @@ function _getTextFieldCSSRules(colorPalette, theme) {
textFieldRules = [
{
selector: `
- .${CSS_PREFIX}-custom-colors.${CSS_PREFIX}-text-field--theme-light.${CSS_PREFIX}-text-field--is-focus .${CSS_PREFIX}-text-field__input-wrapper
+ .${CSS_PREFIX}-custom-colors.${CSS_PREFIX}-text-field--theme-light.${CSS_PREFIX}-text-field--is-focus:not(.${CSS_PREFIX}-text-field--has-error):not(.${CSS_PREFIX}-text-field--is-valid) .${CSS_PREFIX}-text-field__wrapper
`,
rule: `box-shadow: inset 0 0 0 2px ${colorPalette.primary.L2}`,
},
@@ -563,13 +563,13 @@ function _getTextFieldCSSRules(colorPalette, theme) {
textFieldRules = [
{
selector: `
- .${CSS_PREFIX}-custom-colors.${CSS_PREFIX}-text-field--theme-light.${CSS_PREFIX}-text-field--is-focus .${CSS_PREFIX}-text-field__label
+ .${CSS_PREFIX}-custom-colors.${CSS_PREFIX}-text-field--theme-light.${CSS_PREFIX}-text-field--is-focus:not(.${CSS_PREFIX}-text-field--has-error):not(.${CSS_PREFIX}-text-field--is-valid) .${CSS_PREFIX}-text-field__label
`,
rule: `color: ${colorPalette.primary.N}`,
},
{
selector: `
- .${CSS_PREFIX}-custom-colors.${CSS_PREFIX}-text-field--theme-light .${CSS_PREFIX}-text-field__input-wrapper::after
+ .${CSS_PREFIX}-custom-colors.${CSS_PREFIX}-text-field--theme-light:not(.${CSS_PREFIX}-text-field--has-error):not(.${CSS_PREFIX}-text-field--is-valid) .${CSS_PREFIX}-text-field__wrapper::after
`,
rule: `background-color: ${colorPalette.primary.N}`,
},
diff --git a/src/react.index.ts b/src/react.index.ts
index 1d5d510f9..c3246da0e 100644
--- a/src/react.index.ts
+++ b/src/react.index.ts
@@ -14,6 +14,8 @@ export { Checkbox, CheckboxProps } from './components/checkbox/react/Checkbox';
export { Chip, ChipProps } from './components/chip/react/Chip';
+export { ChipGroup, ChipGroupProps } from './components/chip/react/ChipGroup';
+
export { Divider, DividerProps } from './components/divider/react/Divider';
export { Dropdown, DropdownProps } from './components/dropdown/react/Dropdown';