@salesforcedevs/dx-components
Advanced tools
Comparing version 0.0.4 to 0.0.5
{ | ||
"modules": [{ "dir": "src/modules" }], | ||
"expose": [ | ||
"dx/cta", | ||
"dx/button", | ||
"dx/dropdown", | ||
"dx/footer", | ||
"dx/header", | ||
"dx/icon", | ||
"dx/input", | ||
"dx/textSection" | ||
] | ||
} |
{ | ||
"name": "@salesforcedevs/dx-components", | ||
"version": "0.0.4", | ||
"version": "0.0.5", | ||
"description": "DX Lightning web components", | ||
@@ -5,0 +5,0 @@ "license": "UNLICENSED", |
@@ -13,3 +13,3 @@ import mockOptions from "./__tests__/mockOptions"; | ||
const makeButton = (label: string) => ` | ||
<dx-cta variant="secondary" icon-symbol="chevrondown">${label}</dx-cta> | ||
<dx-button variant="secondary" icon-symbol="chevrondown">${label}</dx-button> | ||
`; | ||
@@ -16,0 +16,0 @@ |
import { LightningElement, api } from "lwc"; | ||
import cx from "classnames"; | ||
import { createPopper } from "@popperjs/core"; | ||
import debounce from "debounce"; | ||
import cx from "ext/classnames"; | ||
import { createPopper } from "ext/popperjs"; | ||
import debounce from "ext/debounce"; | ||
import { | ||
@@ -24,5 +24,2 @@ Option, | ||
/** | ||
* @element dx-dropdown | ||
*/ | ||
export default class Dropdown extends LightningElement { | ||
@@ -70,3 +67,5 @@ @api value: string | null = null; // "active option" id | ||
addControlListeners() { | ||
if (!this.control) return; | ||
if (!this.control) { | ||
return; | ||
} | ||
this.control.addEventListener("click", this.onControlClick); | ||
@@ -78,3 +77,5 @@ this.control.addEventListener("keydown", this.onControlKeydown); | ||
removeControlListeners() { | ||
if (!this.control) return; | ||
if (!this.control) { | ||
return; | ||
} | ||
this.control.removeEventListener("click", this.onControlClick); | ||
@@ -120,3 +121,5 @@ this.control.removeEventListener("keydown", this.onControlKeydown); | ||
private _interactOutsideListener = (e: Event) => { | ||
if (!this.isOpen || !this.menu) return; | ||
if (!this.isOpen || !this.menu) { | ||
return; | ||
} | ||
const isOutside = isEventOutsideElements(e, this.control, this.menu); | ||
@@ -132,3 +135,5 @@ if (isOutside) { | ||
private onControlMouseEnter = () => { | ||
if (this.useHover) this.open(); | ||
if (this.useHover) { | ||
this.open(); | ||
} | ||
}; | ||
@@ -175,9 +180,14 @@ | ||
private onOptionClick(e: CustomEvent) { | ||
if (e.detail !== this.value) | ||
if (e.detail !== this.value) { | ||
this.dispatchEvent(new CustomEvent("change", { detail: e.detail })); | ||
if (!this.stayOpenAfterChange) this.close(true); | ||
} | ||
if (!this.stayOpenAfterChange) { | ||
this.close(true); | ||
} | ||
} | ||
private onOptionFocus(e: PointerEvent) { | ||
if (!e.target) return; | ||
if (!e.target) { | ||
return; | ||
} | ||
// @ts-ignore | ||
@@ -199,3 +209,5 @@ this.focusedValue = e.target.option.id; | ||
private incrementOptionFocus(indexChange: number) { | ||
if (!this.focusedValue) return; | ||
if (!this.focusedValue) { | ||
return; | ||
} | ||
@@ -207,7 +219,13 @@ const focusedOptionIndex = this.findOptionElementIndex( | ||
let nextIndex = focusedOptionIndex + indexChange; | ||
if (nextIndex < 0) nextIndex = this.optionsElements.length - 1; | ||
if (nextIndex >= this.optionsElements.length) nextIndex = 0; | ||
if (nextIndex < 0) { | ||
nextIndex = this.optionsElements.length - 1; | ||
} | ||
if (nextIndex >= this.optionsElements.length) { | ||
nextIndex = 0; | ||
} | ||
const element = this.optionsElements[nextIndex]; | ||
if (element) element.focus(); | ||
if (element) { | ||
element.focus(); | ||
} | ||
} | ||
@@ -231,3 +249,3 @@ | ||
document.addEventListener("click", this.interactOutsideListener); | ||
if (this.useHover) | ||
if (this.useHover) { | ||
document.addEventListener( | ||
@@ -237,2 +255,3 @@ "mousemove", | ||
); | ||
} | ||
this.dispatchEvent(new CustomEvent("open")); | ||
@@ -249,5 +268,7 @@ | ||
} | ||
if (this.control) this.control.setAttribute("aria-expanded", "false"); | ||
if (this.control) { | ||
this.control.setAttribute("aria-expanded", "false"); | ||
} | ||
document.removeEventListener("click", this.interactOutsideListener); | ||
if (this.useHover) | ||
if (this.useHover) { | ||
document.removeEventListener( | ||
@@ -257,2 +278,3 @@ "mousemove", | ||
); | ||
} | ||
this.dispatchEvent(new CustomEvent("close")); | ||
@@ -262,3 +284,5 @@ } | ||
private setPosition() { | ||
if (!this.menu || !this.control) return; | ||
if (!this.menu || !this.control) { | ||
return; | ||
} | ||
createPopper(this.control, this.menu, { | ||
@@ -265,0 +289,0 @@ placement: this.placement, |
import { LightningElement, api } from "lwc"; | ||
import cx from "classnames"; | ||
import cx from "ext/classnames"; | ||
import { Option } from "../../../../../../../typings/custom-new"; | ||
/** | ||
* @element dx-dropdown-option | ||
*/ | ||
export default class DropdownOption extends LightningElement { | ||
@@ -14,3 +11,5 @@ @api option!: Option; | ||
const option = this.template.querySelector(".option"); | ||
if (!option) return; | ||
if (!option) { | ||
return; | ||
} | ||
option.focus(); | ||
@@ -17,0 +16,0 @@ } |
@@ -5,3 +5,3 @@ import { createElement } from "lwc"; | ||
describe("dx-header", () => { | ||
it("renders all components", () => { | ||
it("renders the nav", () => { | ||
const element = createElement("dx-header", { | ||
@@ -8,0 +8,0 @@ is: Header |
@@ -5,5 +5,2 @@ import { LightningElement, api } from "lwc"; | ||
/** | ||
* @element dx-header | ||
*/ | ||
export default class Header extends LightningElement { | ||
@@ -10,0 +7,0 @@ @api title = "Salesforce"; |
@@ -6,5 +6,2 @@ import { LightningElement, api } from "lwc"; | ||
/** | ||
* @element dx-header-nav | ||
*/ | ||
export default class HeaderNav extends LightningElement { | ||
@@ -21,3 +18,3 @@ @api | ||
private options: Option[] = appsDevelopers; | ||
private _type: String; | ||
@@ -24,0 +21,0 @@ // TODO: keeping this here as a reminder in case we need similar functionality |
@@ -15,26 +15,6 @@ import { createElement } from "lwc"; | ||
const inputEl = element.shadowRoot.querySelector("input"); | ||
const inputEl = element.shadowRoot.querySelector("dx-input"); | ||
expect(inputEl).not.toBeNull(); | ||
}); | ||
it("renders the search icon", () => { | ||
const element = create(); | ||
document.body.appendChild(element); | ||
const icons = element.shadowRoot.querySelectorAll("dx-icon"); | ||
const searchIcon = Array.from(icons).filter( | ||
// @ts-ignore | ||
(icon) => icon.symbol === "search" | ||
); | ||
expect(searchIcon).not.toBeNull(); | ||
}); | ||
it("renders the search shortcut img", () => { | ||
const element = create(); | ||
document.body.appendChild(element); | ||
const shortcut = element.shadowRoot.querySelector("img"); | ||
const shortcutSrc = shortcut.getAttribute("src"); | ||
expect(shortcutSrc).toContain("control-k"); | ||
}); | ||
it("can select and display another scope", async () => { | ||
@@ -60,16 +40,4 @@ const element = create(); | ||
it("blurs input on escape", () => { | ||
it("fires onsearch after input onsubmit", async () => { | ||
const element = create(); | ||
document.body.appendChild(element); | ||
const inputEl = element.shadowRoot.querySelector("input"); | ||
const blurMock = jest.fn(); | ||
inputEl.onblur = blurMock; | ||
inputEl.focus(); | ||
inputEl.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape" })); | ||
expect(blurMock).toHaveBeenCalled(); | ||
}); | ||
it("fires onsearch with the correct values", async () => { | ||
const element = create(); | ||
const searchMock = jest.fn(); | ||
@@ -79,8 +47,7 @@ element.addEventListener("search", searchMock); | ||
const inputEl = element.shadowRoot.querySelector("input"); | ||
inputEl.focus(); | ||
inputEl.dispatchEvent(new KeyboardEvent("keydown", { key: "Enter" })); | ||
const inputEl = element.shadowRoot.querySelector("dx-input"); | ||
inputEl.dispatchEvent(new CustomEvent("submit", { detail: "test" })); | ||
await Promise.resolve(); | ||
expect(searchMock.mock.calls[0][0].detail).toEqual({ | ||
value: null, | ||
value: "test", | ||
scope: "all" | ||
@@ -87,0 +54,0 @@ }); |
import { LightningElement } from "lwc"; | ||
import { InputValue, Option } from "../../../../../../../typings/custom-new"; | ||
import { Option } from "typings/custom-new"; | ||
import scopes from "./scopes"; | ||
/** | ||
* @element dx-header-search | ||
*/ | ||
export default class HeaderSearch extends LightningElement { | ||
private scopes: Option[] = scopes; | ||
private scope: string = "all"; | ||
private value: InputValue = null; | ||
private input: HTMLElement | null = null; | ||
@@ -23,13 +19,12 @@ | ||
renderedCallback() { | ||
if (!this.input) this.input = this.template.querySelector("input"); | ||
if (!this.input) { | ||
this.input = this.template.querySelector("lwc-dx-input"); | ||
} | ||
} | ||
private onInputChange(e: KeyboardEvent) { | ||
if (!e.target) return; | ||
this.value = (<HTMLTextAreaElement>e.target).value; | ||
} | ||
private get scopeLabel() { | ||
const scope = this.scopes.find(({ id }) => id === this.scope); | ||
if (!scope) return ""; | ||
if (!scope) { | ||
return ""; | ||
} | ||
return scope.label; | ||
@@ -60,24 +55,14 @@ } | ||
private shortcutListener = (e: KeyboardEvent) => { | ||
if (e.metaKey && e.key === "k" && this.input) this.input.focus(); | ||
if (e.metaKey && e.key === "k" && this.input) { | ||
this.input.focus(); | ||
} | ||
}; | ||
private onSearch() { | ||
private onSearch(e: CustomEvent) { | ||
this.dispatchEvent( | ||
new CustomEvent("search", { | ||
detail: { value: this.value, scope: this.scope } | ||
detail: { value: e.detail, scope: this.scope } | ||
}) | ||
); | ||
} | ||
private onKeyDown(e: KeyboardEvent) { | ||
switch (e.key) { | ||
case "Escape": | ||
if (this.input) this.input.blur(); | ||
break; | ||
case "Enter": | ||
this.onSearch(); | ||
break; | ||
default: | ||
} | ||
} | ||
} |
@@ -10,5 +10,2 @@ import { LightningElement, api } from "lwc"; | ||
/** | ||
* @element dx-icon | ||
*/ | ||
export default class Icon extends LightningElement { | ||
@@ -39,3 +36,5 @@ @api sprite: IconSprite = "utility"; | ||
let { symbolId } = this; | ||
if (this.node && this.node.id === symbolId) return; | ||
if (this.node && this.node.id === symbolId) { | ||
return; | ||
} | ||
await this.fetchSprite(this.sprite); | ||
@@ -48,4 +47,8 @@ let svg = this.template.querySelector("svg")!; | ||
.cloneNode(true) as SVGSymbolElement; | ||
while (svg.firstChild) svg.removeChild(svg.firstChild); | ||
for (let n of Array.from(node.childNodes)) svg.appendChild(n); | ||
while (svg.firstChild) { | ||
svg.removeChild(svg.firstChild); | ||
} | ||
for (let n of Array.from(node.childNodes)) { | ||
svg.appendChild(n); | ||
} | ||
svg.setAttribute("viewBox", node.getAttribute("viewBox")!); | ||
@@ -55,3 +58,5 @@ } | ||
private async fetchSprite(sprite: IconSprite) { | ||
if (fetches.has(sprite)) return fetches.get(sprite); | ||
if (fetches.has(sprite)) { | ||
return fetches.get(sprite); | ||
} | ||
let promise = fetch(this.assetUrl) | ||
@@ -58,0 +63,0 @@ .then((res) => res.text()) |
import { createElement } from "lwc"; | ||
import TextSection from "../textSection"; | ||
import mockSection from "./mockSectionProps"; | ||
import Button from "dx/cta"; | ||
import Button from "dx/button"; | ||
@@ -44,3 +44,3 @@ const create = (props: object = {}) => { | ||
const buttonsList: Array<Button> = element.shadowRoot.querySelectorAll( | ||
"dx-cta" | ||
"dx-button" | ||
); | ||
@@ -47,0 +47,0 @@ expect(buttonsList).toHaveLength(3); |
@@ -7,5 +7,2 @@ import { LightningElement, api } from "lwc"; | ||
/** | ||
* @element dx-text-section | ||
*/ | ||
export default class TextSection extends LightningElement { | ||
@@ -12,0 +9,0 @@ @api title!: string; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
205914
127
5590