Skip to content

Commit

Permalink
feat: Merge pull request #222 from BrightspaceUILabs/clabatt/US156307…
Browse files Browse the repository at this point in the history
…-Additional-Validation

US156307 Attribute Picker Invalid State
  • Loading branch information
ChrisLabattD2L authored Aug 14, 2023
2 parents 02c7113 + 7268e6d commit 8810055
Show file tree
Hide file tree
Showing 30 changed files with 221 additions and 14 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ jobs:
- name: Lint
run: npm run lint
- name: Unit Tests (cross-browser)
run: npx web-test-runner --config web-test-runner.config.js --group default --playwright --browsers chromium firefox webkit
run: npx web-test-runner --config web-test-runner.config.js --group all-browsers
6 changes: 1 addition & 5 deletions .github/workflows/lang.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,12 @@ on:
jobs:
test:
timeout-minutes: 5
runs-on: [self-hosted, Linux, AWS]
runs-on: ubuntu-latest
steps:
- uses: Brightspace/third-party-actions@actions/checkout
- uses: Brightspace/third-party-actions@actions/setup-node
with:
node-version-file: .nvmrc
- name: Add CodeArtifact npm registry
uses: Brightspace/codeartifact-actions/npm/add-registry@main
with:
auth-token: ${{ secrets.CODEARTIFACT_AUTH_TOKEN }}
- name: Install MessageFormat-Validator
run: npm install messageformat-validator
- name: Run MessageFormat-Validator
Expand Down
79 changes: 75 additions & 4 deletions attribute-picker.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import '@brightspace-ui/core/components/colors/colors.js';
import '@brightspace-ui/core/components/tooltip/tooltip.js';
import './multi-select-list.js';
import './multi-select-list-item.js';
import { css, html, LitElement } from 'lit';
import { classMap } from 'lit-html/directives/class-map.js';
import { ifDefined } from 'lit-html/directives/if-defined.js';
import { inputStyles } from '@brightspace-ui/core/components/inputs/input-styles.js';
import { Localizer } from './localization.js';
import { repeat } from 'lit/directives/repeat.js';
Expand Down Expand Up @@ -36,20 +39,32 @@ class AttributePicker extends RtlMixin(Localizer(LitElement)) {
/* When true, the autocomplete dropdown will not be displayed to the user. */
hideDropdown: { type: Boolean, attribute: 'hide-dropdown', reflect: true },

/*
The text that will appear in the tooltip that informs a user that the state is invalid
The default value is: 'At least one attribute must be set'
*/
invalidTooltipText: { type: String, attribute: 'invalid-tooltip-text', reflect: true },

/* The maximum number of attributes permitted. */
limit: { type: Number, attribute: 'limit', reflect: true },

/* The inner text of the input. */
_text: { type: String, attribute: 'text', reflect: true },
/* When true, an error state will appear if no attributes are set. */
required: { type: Boolean, attribute: 'required', reflect: true },

/* Represents the index of the currently focused attribute. If no attribute is focused, equals -1. */
_activeAttributeIndex: { type: Number, reflect: false },

/* Represents the index of the currently focused dropdown list item. If no item is focused, equals -1. */
_dropdownIndex: { type: Number, reflect: false },

/* When true, the user has yet to lose focus for the first time, meaning the validation won't be shown until they've lost focus for the first time. */
_initialFocus: { type: Boolean, reflect: false },

/* When true, the user currently has focus within the input. */
_inputFocused: { type: Boolean, reflect: false },

/* The inner text of the input. */
_text: { type: String, attribute: 'text', reflect: true }
};
}

Expand Down Expand Up @@ -77,12 +92,20 @@ class AttributePicker extends RtlMixin(Localizer(LitElement)) {
position: relative;
vertical-align: middle;
}
.d2l-attribute-picker-container:hover,
.d2l-attribute-picker-container-focused {
border-color: var(--d2l-color-celestine);
border-width: 2px;
outline-width: 0;
padding: 4px 4px 4px 4px;
}
.d2l-attribute-picker-container-error,
.d2l-attribute-picker-container-error:hover {
border-color: var(--d2l-color-cinnabar);
}
.d2l-attribute-picker-content {
cursor: text;
display: flex;
Expand Down Expand Up @@ -134,6 +157,23 @@ class AttributePicker extends RtlMixin(Localizer(LitElement)) {
width: 100%;
z-index: 1;
}
.d2l-input-text-invalid-icon {
background-image: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjIiIGhlaWdodD0iMjIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxwYXRoIGZpbGw9IiNGRkYiIGQ9Ik0wIDBoMjJ2MjJIMHoiLz4KICAgIDxwYXRoIGQ9Ik0xOC44NjQgMTYuNDdMMTIuNjIzIDMuOTg5YTEuNzgzIDEuNzgzIDAgMDAtMy4xOTIgMEwzLjE4OSAxNi40N2ExLjc2MSAxLjc2MSAwIDAwLjA4IDEuNzNjLjMyNS41MjUuODk4Ljc5OCAxLjUxNi43OTloMTIuNDgzYy42MTggMCAxLjE5Mi0uMjczIDEuNTE2LS44LjIzNy0uMzM1LjI2NS0xLjM3LjA4LTEuNzN6IiBmaWxsPSIjQ0QyMDI2IiBmaWxsLXJ1bGU9Im5vbnplcm8iLz4KICAgIDxwYXRoIGQ9Ik0xMS4wMjcgMTcuMjY0YTEuMzM3IDEuMzM3IDAgMTEwLTIuNjc1IDEuMzM3IDEuMzM3IDAgMDEwIDIuNjc1ek0xMS45IDEyLjk4YS44OTIuODkyIDAgMDEtMS43NDcgMEw5LjI3IDguNTJhLjg5Mi44OTIgMCAwMS44NzQtMS4wNjRoMS43NjhhLjg5Mi44OTIgMCAwMS44NzQgMS4wNjVsLS44ODYgNC40NTh6IiBmaWxsPSIjRkZGIi8+CiAgPC9nPgo8L3N2Zz4K");
display: flex;
height: 22px;
left: unset;
position: absolute;
right: 8px;
top: 50%;
transform: translateY(-50%);
width: 22px;
}
:host([dir='rtl']) .d2l-input-text-invalid-icon {
left: 8px;
right: unset;
}
`];
}

Expand All @@ -146,6 +186,8 @@ class AttributePicker extends RtlMixin(Localizer(LitElement)) {
this._inputFocused = false;
this._activeAttributeIndex = -1;
this._dropdownIndex = -1;
this._initialFocus = true;
this.required = false;
}

render() {
Expand All @@ -155,8 +197,19 @@ class AttributePicker extends RtlMixin(Localizer(LitElement)) {
const comparableText = this._text.toLowerCase();
const availableAttributes = this.assignableAttributes.filter(x => hash[x.name] !== true && (comparableText === '' || x.name?.toLowerCase().includes(comparableText)));

const isValid = this._initialFocus || !this.required || this.attributeList.length;

const containerClasses = {
'd2l-attribute-picker-container': true,
'd2l-attribute-picker-container-focused' : this._inputFocused,
'd2l-attribute-picker-container-error' : !isValid
};

const ariaInvalid = !isValid ? true : undefined;
const ariaRequired = this.required ? true : undefined;

return html`
<div role="application" class="d2l-attribute-picker-container ${this._inputFocused ? 'd2l-attribute-picker-container-focused' : ''}">
<div role="application" id="d2l-attribute-picker-container" class="${classMap(containerClasses)}" aria-invalid="${ifDefined(ariaInvalid)}" aria-required=${ifDefined(ariaRequired)}>
<div class="d2l-attribute-picker-content" aria-busy="${this._isNotActive()}" role="${this.attributeList.length > 0 ? 'list' : ''}">
${this.attributeList.map((item, index) => html`
<d2l-labs-multi-select-list-item
Expand All @@ -175,19 +228,22 @@ class AttributePicker extends RtlMixin(Localizer(LitElement)) {
<input
aria-activedescendant="${this._dropdownIndex > -1 ? `attribute-dropdown-list-item-${this._dropdownIndex}` : ''}"
aria-autocomplete="list"
aria-haspopup="true"
aria-expanded="${this._inputFocused}"
aria-haspopup="true"
aria-label="${this.ariaLabel}"
aria-owns="attribute-dropdown-list"
class="d2l-input d2l-attribute-picker-input"
enterkeyhint="enter"
@blur="${this._onInputBlur}"
@focus="${this._onInputFocus}"
@focusout="${this._onInputLoseFocus}"
@keydown="${this._onInputKeydown}"
@input="${this._onInputTextChanged}"
role="combobox"
type="text"
.value="${this._text}">
${(!isValid && !this._inputFocused) ? html`<div class="d2l-input-text-invalid-icon" @click="${this._handleInvalidIconClick}"></div>` : null}
</div>
<div class="d2l-attribute-picker-absolute-container">
Expand All @@ -212,6 +268,10 @@ class AttributePicker extends RtlMixin(Localizer(LitElement)) {
</ul>
</div>
</div>
${!isValid ? html`
<d2l-tooltip for="d2l-attribute-picker-container" state="error" announced position="top" ?force-show=${this._inputFocused}>${this.invalidTooltipText || this.localize('oneAttributeRequired')}</d2l-tooltip>
` : null}
`;
}

Expand Down Expand Up @@ -299,6 +359,13 @@ class AttributePicker extends RtlMixin(Localizer(LitElement)) {
selectedAttributes[index].focus();
}

_handleInvalidIconClick() {
const input = this.shadowRoot && this.shadowRoot.querySelector('input');
if (!input) return;
this._inputFocused = true;
input.focus();
}

_isNotActive() {
return this._activeAttributeIndex === -1 && this._dropdownIndex === -1 && !this._inputFocused;
}
Expand Down Expand Up @@ -452,6 +519,10 @@ class AttributePicker extends RtlMixin(Localizer(LitElement)) {
}
}

_onInputLoseFocus() {
this._initialFocus = false;
}

_onInputTextChanged(event) {
this._text = event.target.value;
if (this._dropdownIndex >= 0) {
Expand Down
10 changes: 10 additions & 0 deletions demo/attribute-picker.html
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ <h2>d2l-labs-attribute-picker - wrapped</h2>
assignable-attributes='[{"name":"one","value":1},{"name":"two","value":2},{"name":"three","value":3},{"name":"four","value":4},{"name":"five","value":5},{"name":"six","value":6},{"name":"seven","value":7}]'
></d2l-labs-attribute-picker>
</d2l-demo-snippet>

<h2>d2l-labs-attribute-picker - required (with validation)</h2>
<d2l-demo-snippet>
<d2l-labs-attribute-picker aria-label="attributes"
invalid-tooltip-text="You're missing something"
required
allow-freeform
assignable-attributes='[{"name":"one","value":1},{"name":"two","value":2},{"name":"three","value":3},{"name":"four","value":4},{"name":"five","value":5},{"name":"six","value":6},{"name":"seven","value":7}]'
></d2l-labs-attribute-picker>
</d2l-demo-snippet>
</d2l-demo-page>
</body>
</html>
Expand Down
1 change: 1 addition & 0 deletions lang/ar.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
delete: "حذف",
hide: "إخفاء",
hiddenChildren: "+ {num} أكثر",
oneAttributeRequired: "At least one value must be set", // Tooltip that appears when no values have been set and we need to inform the user that this is an invalid state
picker_remove_value: "انقر لإزالة القيمة {value}",
picker_add_value: "انقر لإضافة القيمة {value}"
};
1 change: 1 addition & 0 deletions lang/cy-gb.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
delete: "Delete",
hide: "Cuddio",
hiddenChildren: "+ {num} arall",
oneAttributeRequired: "At least one value must be set", // Tooltip that appears when no values have been set and we need to inform the user that this is an invalid state
picker_remove_value: "Cliciwch i dynnu'r gwerth {value}",
picker_add_value: "Cliciwch i ychwanegu'r gwerth {value}"
};
1 change: 1 addition & 0 deletions lang/cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
delete: "Dileu",
hide: "Hide",
hiddenChildren: "+ {num} more",
oneAttributeRequired: "At least one value must be set", // Tooltip that appears when no values have been set and we need to inform the user that this is an invalid state
picker_remove_value: "Click to remove value {value}",
picker_add_value: "Click to add value {value}"
};
1 change: 1 addition & 0 deletions lang/da-dk.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
delete: "Delete",
hide: "Skjul",
hiddenChildren: "+ {num} mere",
oneAttributeRequired: "At least one value must be set", // Tooltip that appears when no values have been set and we need to inform the user that this is an invalid state
picker_remove_value: "Klik for at fjerne værdi {value}",
picker_add_value: "Klik for at tilføje værdi {value}"
};
1 change: 1 addition & 0 deletions lang/da.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
delete: "Slet",
hide: "Hide",
hiddenChildren: "+ {num} more",
oneAttributeRequired: "At least one value must be set", // Tooltip that appears when no values have been set and we need to inform the user that this is an invalid state
picker_remove_value: "Click to remove value {value}",
picker_add_value: "Click to add value {value}"
};
1 change: 1 addition & 0 deletions lang/de.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
delete: "Löschen",
hide: "Ausblenden",
hiddenChildren: "+ {num} weitere",
oneAttributeRequired: "At least one value must be set", // Tooltip that appears when no values have been set and we need to inform the user that this is an invalid state
picker_remove_value: "Klicken Sie, um den Wert {value} zu entfernen",
picker_add_value: "Klicken Sie, um den Wert {value} hinzuzufügen"
};
1 change: 1 addition & 0 deletions lang/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
delete: "Delete",
hide: "Hide",
hiddenChildren: "+ {num} more",
oneAttributeRequired: "At least one value must be set", // Tooltip that appears when no values have been set and we need to inform the user that this is an invalid state
picker_remove_value: "Click to remove value {value}",
picker_add_value: "Click to add value {value}"
};
1 change: 1 addition & 0 deletions lang/es-es.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
delete: "Eliminar",
hide: "Ocultar",
hiddenChildren: "+ {num} más",
oneAttributeRequired: "At least one value must be set", // Tooltip that appears when no values have been set and we need to inform the user that this is an invalid state
picker_remove_value: "Haga clic para eliminar el valor {value}",
picker_add_value: "Haga clic para agregar el valor {value}"
};
1 change: 1 addition & 0 deletions lang/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
delete: "Eliminar",
hide: "Ocultar",
hiddenChildren: "Más de {num} más",
oneAttributeRequired: "At least one value must be set", // Tooltip that appears when no values have been set and we need to inform the user that this is an invalid state
picker_remove_value: "Haga clic para eliminar el valor {value}",
picker_add_value: "Haga clic para agregar el valor {value}"
};
1 change: 1 addition & 0 deletions lang/fr-fr.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
delete: "Supprimer",
hide: "Masquer",
hiddenChildren: "+ {num} de plus",
oneAttributeRequired: "At least one value must be set", // Tooltip that appears when no values have been set and we need to inform the user that this is an invalid state
picker_remove_value: "Cliquer pour supprimer la valeur {value}",
picker_add_value: "Cliquer pour ajouter la valeur {value}"
};
1 change: 1 addition & 0 deletions lang/fr-on.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
delete: "Supprimer",
hide: "Masquer",
hiddenChildren: "+ {num} plus",
oneAttributeRequired: "At least one value must be set", // Tooltip that appears when no values have been set and we need to inform the user that this is an invalid state
picker_remove_value: "Cliquer pour supprimer la valeur {value}",
picker_add_value: "Cliquer pour ajouter la valeur {value}"
};
1 change: 1 addition & 0 deletions lang/fr.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
delete: "Supprimer",
hide: "Masquer",
hiddenChildren: "+ {num} plus",
oneAttributeRequired: "At least one value must be set", // Tooltip that appears when no values have been set and we need to inform the user that this is an invalid state
picker_remove_value: "Cliquer pour supprimer la valeur {value}",
picker_add_value: "Cliquer pour ajouter la valeur {value}"
};
1 change: 1 addition & 0 deletions lang/hi.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
delete: "हटाएँ",
hide: "छुपाएँ",
hiddenChildren: "+ {num} और",
oneAttributeRequired: "At least one value must be set", // Tooltip that appears when no values have been set and we need to inform the user that this is an invalid state
picker_remove_value: "मान {value} निकालने के लिए क्लिक करें",
picker_add_value: "मान {value} जोड़ने के लिए क्लिक करें"
};
1 change: 1 addition & 0 deletions lang/ja.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
delete: "削除",
hide: "表示しない",
hiddenChildren: "他 {num} 件",
oneAttributeRequired: "At least one value must be set", // Tooltip that appears when no values have been set and we need to inform the user that this is an invalid state
picker_remove_value: "クリックして値 {value} を削除",
picker_add_value: "クリックして値 {value} を追加"
};
1 change: 1 addition & 0 deletions lang/ko.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
delete: "삭제",
hide: "숨기기",
hiddenChildren: "{num}개 이상",
oneAttributeRequired: "At least one value must be set", // Tooltip that appears when no values have been set and we need to inform the user that this is an invalid state
picker_remove_value: "클릭하여 {value} 값을 제거합니다.",
picker_add_value: "클릭하여 값 {value}을(를) 추가합니다."
};
1 change: 1 addition & 0 deletions lang/nl.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
delete: "Verwijderen",
hide: "Verbergen",
hiddenChildren: "+ nog {num}",
oneAttributeRequired: "At least one value must be set", // Tooltip that appears when no values have been set and we need to inform the user that this is an invalid state
picker_remove_value: "Klik om waarde {value} te verwijderen",
picker_add_value: "Klik om waarde {value} toe te voegen"
};
1 change: 1 addition & 0 deletions lang/pt.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
delete: "Excluir",
hide: "Ocultar",
hiddenChildren: "+ {num} mais",
oneAttributeRequired: "At least one value must be set", // Tooltip that appears when no values have been set and we need to inform the user that this is an invalid state
picker_remove_value: "Clique para remover valor {value}",
picker_add_value: "Clique para adicionar valor {value}"
};
1 change: 1 addition & 0 deletions lang/sv.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
delete: "Ta bort",
hide: "Dölj",
hiddenChildren: "+ {num} till",
oneAttributeRequired: "At least one value must be set", // Tooltip that appears when no values have been set and we need to inform the user that this is an invalid state
picker_remove_value: "Klicka för att ta bort värde {value}",
picker_add_value: "Klicka för att lägga till värde {value}"
};
1 change: 1 addition & 0 deletions lang/tr.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
delete: "Sil",
hide: "Gizle",
hiddenChildren: "+ {num} adet daha",
oneAttributeRequired: "At least one value must be set", // Tooltip that appears when no values have been set and we need to inform the user that this is an invalid state
picker_remove_value: "{value} değerini kaldırmak için tıklayın",
picker_add_value: "{value} değeri eklemek için tıklayın"
};
1 change: 1 addition & 0 deletions lang/zh-cn.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
delete: "删除",
hide: "隐藏",
hiddenChildren: "+ {num} 更多",
oneAttributeRequired: "At least one value must be set", // Tooltip that appears when no values have been set and we need to inform the user that this is an invalid state
picker_remove_value: "Click to remove value {value}",
picker_add_value: "Click to add value {value}"
};
1 change: 1 addition & 0 deletions lang/zh-tw.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
delete: "刪除",
hide: "隱藏",
hiddenChildren: "還有 {num} 個",
oneAttributeRequired: "At least one value must be set", // Tooltip that appears when no values have been set and we need to inform the user that this is an invalid state
picker_remove_value: "按一下以移除值 {value}",
picker_add_value: "按一下以新增值 {value}"
};
1 change: 1 addition & 0 deletions lang/zh.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
delete: "删除",
hide: "隐藏",
hiddenChildren: "还有 {num} 个",
oneAttributeRequired: "At least one value must be set", // Tooltip that appears when no values have been set and we need to inform the user that this is an invalid state
picker_remove_value: "单击以删除值 {value}",
picker_add_value: "单击以添加值 {value}"
};
Loading

0 comments on commit 8810055

Please sign in to comment.