Skip to content

Commit fea5607

Browse files
author
Amber Febbraro
authored
Merge pull request #3705 from sparkdesignsystem/staging
Publish December Jan 4th, 2020
2 parents 67127a4 + c13343b commit fea5607

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+2215
-102
lines changed

angular/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
"lint": "ng lint",
1111
"coverage": "jest --coverage --config ./projects/spark-angular/jest.config.js",
1212
"docs:json": "compodoc --disableLifeCycleHooks -p ./tsconfig.json -e json -d .",
13-
"build-styles": "cd '../styles/' && npm install && node build.js",
13+
"build-css": "node-sass ./_spark.scss web/css/spark.min.css --output-style compressed",
14+
"build-styles": "cd '../styles/' && npm install && node build.js && npm run build-css",
1415
"set-version": "PACKAGE_VERSION=$(node -p -e \"require('./projects/spark-angular/package.json').version\") && replace '(version).*' \"version: '$PACKAGE_VERSION'\" ./projects/spark-angular/src/environment/environment.ts",
1516
"sassdocmodifiers": "sassdoc '../styles/**/_*.scss' --parse > ../src/data/sass-modifiers.json",
1617
"prebuild:storybook": "npm run build-styles && npm run sassdocmodifiers && npm run test:generate-output && npm run docs:json",

angular/projects/spark-angular/package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

angular/projects/spark-angular/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@sparkdesignsystem/spark-angular",
33
"description": "A collection of Spark Design System components in Angular 6+",
4-
"version": "12.0.1",
4+
"version": "12.0.2",
55
"author": "Quicken Loans",
66
"license": "MIT",
77
"scripts": {
@@ -23,7 +23,7 @@
2323
"@angular/router": ">=7.0.0 < 9.2.0"
2424
},
2525
"dependencies": {
26-
"@sparkdesignsystem/spark-styles": "^1.0.0",
26+
"@sparkdesignsystem/spark-styles": "^1.1.0",
2727
"focus-visible": "5.0.2",
2828
"lodash": "^4.17.20",
2929
"tiny-date-picker": "github:sparkdesignsystem/tiny-date-picker#v3.2.9"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export const environment = {
2-
version: '12.0.1',
2+
version: '12.0.2-beta.0',
33
};

html/components/autocomplete.js

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/* global document */
2+
import getElements from '../utilities/getElements';
3+
import {
4+
isEscPressed,
5+
isUpPressed,
6+
isDownPressed,
7+
} from '../utilities/keypress';
8+
import generateAriaControls from '../utilities/generateAriaControls';
9+
import generateAriaOwns from '../utilities/generateAriaOwns';
10+
import resetListItems from '../utilities/resetListItems';
11+
import isElementVisible from '../utilities/isElementVisible';
12+
13+
const activeClass = 'sprk-c-Autocomplete__result--active';
14+
15+
const hideList = (autocompleteContainer, inputEl) => {
16+
if (
17+
isElementVisible(
18+
'[data-sprk-autocomplete="results"]',
19+
autocompleteContainer,
20+
)
21+
) {
22+
const listEl = autocompleteContainer.querySelector(
23+
'[data-sprk-autocomplete="results"]',
24+
);
25+
resetListItems(
26+
listEl.querySelectorAll('[data-sprk-autocomplete="result"]'),
27+
activeClass,
28+
);
29+
listEl.classList.add('sprk-u-Display--none');
30+
inputEl.removeAttribute('aria-activedescendant');
31+
inputEl.parentNode.setAttribute('aria-expanded', false);
32+
}
33+
};
34+
35+
const highlightListItem = (result, inputEl) => {
36+
inputEl.setAttribute('aria-activedescendant', result.id);
37+
result.classList.add(activeClass);
38+
result.setAttribute('aria-selected', true);
39+
40+
const listItemTop = result.getBoundingClientRect().top;
41+
const listItemBottom = result.getBoundingClientRect().bottom;
42+
43+
const listTop = result.parentNode.getBoundingClientRect().top;
44+
const listBottom = result.parentNode.getBoundingClientRect().bottom;
45+
46+
// if the list item is not vertically contained within the list
47+
if (listItemTop < listTop || listItemBottom > listBottom) {
48+
// the distance from the top of the <li> to the top of the <ul>
49+
const childTop = result.offsetTop;
50+
51+
// eslint-disable-next-line no-param-reassign
52+
result.parentNode.scrollTop = childTop;
53+
}
54+
};
55+
56+
const getActiveItemIndex = (listEl) => {
57+
let activeIndex = null;
58+
listEl.forEach((listItem, index) => {
59+
if (listItem.classList.contains(activeClass)) {
60+
activeIndex = index;
61+
}
62+
});
63+
64+
return activeIndex;
65+
};
66+
67+
const advanceHighlightedItem = (results, inputEl) => {
68+
const activeIndex = getActiveItemIndex(results);
69+
resetListItems(results, activeClass);
70+
71+
if (activeIndex === null) {
72+
highlightListItem(results[0], inputEl);
73+
} else if (activeIndex + 1 <= results.length - 1) {
74+
highlightListItem(results[activeIndex + 1], inputEl);
75+
} else {
76+
highlightListItem(results[0], inputEl);
77+
}
78+
};
79+
80+
const retreatHighlightedItem = (results, inputEl) => {
81+
const activeIndex = getActiveItemIndex(results);
82+
resetListItems(results, activeClass);
83+
84+
if (activeIndex === null || activeIndex - 1 === -1) {
85+
highlightListItem(results[results.length - 1], inputEl);
86+
} else {
87+
highlightListItem(results[activeIndex - 1], inputEl);
88+
}
89+
};
90+
91+
const calculateListWidth = (listEl, inputEl) => {
92+
const currentInputWidth = inputEl.offsetWidth;
93+
listEl.setAttribute('style', `max-width:${currentInputWidth}px`);
94+
};
95+
96+
const bindUIEvents = (autocompleteContainer) => {
97+
const inputEl = autocompleteContainer.querySelector(
98+
'[data-sprk-autocomplete="input"]',
99+
);
100+
const listEl = autocompleteContainer.querySelector(
101+
'[data-sprk-autocomplete="results"]',
102+
);
103+
104+
generateAriaControls(inputEl, listEl, 'autocomplete');
105+
generateAriaOwns(inputEl.parentNode, listEl, 'autocomplete');
106+
107+
inputEl.addEventListener('keydown', (e) => {
108+
const selectableListItems = listEl.querySelectorAll(
109+
'li:not([data-sprk-autocomplete-no-select])',
110+
);
111+
112+
if (isUpPressed(e)) {
113+
e.stopPropagation();
114+
e.preventDefault();
115+
116+
if (
117+
isElementVisible(
118+
'[data-sprk-autocomplete="results"]',
119+
autocompleteContainer,
120+
)
121+
) {
122+
retreatHighlightedItem(selectableListItems, inputEl);
123+
}
124+
} else if (isDownPressed(e)) {
125+
e.stopPropagation();
126+
e.preventDefault();
127+
128+
if (
129+
isElementVisible(
130+
'[data-sprk-autocomplete="results"]',
131+
autocompleteContainer,
132+
)
133+
) {
134+
advanceHighlightedItem(selectableListItems, inputEl);
135+
}
136+
}
137+
});
138+
139+
// Hide results if Escape is pressed
140+
document.addEventListener('keydown', (e) => {
141+
if (isEscPressed(e)) {
142+
hideList(autocompleteContainer, inputEl);
143+
}
144+
});
145+
146+
// Hide results if the document body is clicked
147+
document.addEventListener('click', (e) => {
148+
if (!(inputEl.contains(e.target) || listEl.contains(e.target))) {
149+
hideList(autocompleteContainer, inputEl);
150+
}
151+
});
152+
153+
// when the window resizes, reset the max-width of the list
154+
window.addEventListener('resize', () => {
155+
calculateListWidth(listEl, inputEl);
156+
});
157+
158+
// calculate the max-width on init
159+
calculateListWidth(listEl, inputEl);
160+
};
161+
162+
const autocomplete = () => {
163+
getElements('[data-sprk-autocomplete="container"]', bindUIEvents);
164+
};
165+
166+
export { autocomplete, bindUIEvents };

0 commit comments

Comments
 (0)