-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
504 additions
and
56 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
@import './ActionButton.scss'; | ||
@import '../../sass/Variables.scss'; | ||
|
||
$disable-color: $primary-color-light; | ||
|
||
button.CoveoActionButton.coveo-actionbutton.coveo-actionbutton-disabled { | ||
background-color: $activated-color; | ||
border-color: $disable-color; | ||
|
||
.coveo-actionbutton_icon { | ||
svg { | ||
fill: $disable-color; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { StatefulActionButton, IStatefulActionButtonOptionsWithIcon } from './StatefulActionButton'; | ||
|
||
export interface IDisableableButtonOptions { | ||
disabledIcon: string; | ||
disabledTooltip: string; | ||
} | ||
|
||
export interface IDisableableButton { | ||
options: IDisableableButtonOptions; | ||
} | ||
|
||
export class DisabledState implements IStatefulActionButtonOptionsWithIcon { | ||
static DISABLED_CLASS_NAME = 'coveo-actionbutton-disabled'; | ||
public readonly onStateEntry: (this: StatefulActionButton) => void; | ||
public readonly onStateExit: (this: StatefulActionButton) => void; | ||
public readonly click: () => void; | ||
public readonly icon: string; | ||
public readonly tooltip: string; | ||
public readonly name = 'DisabledState'; | ||
|
||
constructor(disabledButton: IDisableableButton) { | ||
this.onStateEntry = function () { | ||
this.element.classList.add(DisabledState.DISABLED_CLASS_NAME); | ||
this.element.setAttribute('disabled', ''); | ||
}; | ||
this.onStateExit = function () { | ||
this.element.classList.remove(DisabledState.DISABLED_CLASS_NAME); | ||
this.element.removeAttribute('disabled'); | ||
}; | ||
this.click = () => {}; | ||
this.icon = disabledButton.options.disabledIcon; | ||
this.tooltip = disabledButton.options.disabledTooltip; | ||
} | ||
} |
120 changes: 120 additions & 0 deletions
120
src/components/ActionButton/DisableableToggleActionButton.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import { ComponentOptions, IResultsComponentBindings, Component, Initialization } from 'coveo-search-ui'; | ||
import { StatefulActionButton } from './StatefulActionButton'; | ||
import { | ||
ToggleActivatedState as ActivatedState, | ||
ToggleUnactivatedState as UnactivatedState, | ||
IToggleableButton, | ||
IToggleableButtonOptions, | ||
} from './ToggleableButton'; | ||
import { IDisableableButton, IDisableableButtonOptions, DisabledState } from './DisableableButton'; | ||
import { ToggleActionButton } from './ToggleActionButton'; | ||
|
||
export interface IDisableableToggleActionButtonOptions extends IToggleableButtonOptions, IDisableableButtonOptions {} | ||
|
||
export class DisableableToggleActionButton extends Component implements IToggleableButton, IDisableableButton { | ||
static ID = 'DisableableToggleActionButton'; | ||
static ACTIVATED_CLASS_NAME = 'coveo-toggleactionbutton-activated'; | ||
|
||
private innerStatefulActionButton: StatefulActionButton; | ||
private activatedState: ActivatedState; | ||
private deactivatedState: UnactivatedState; | ||
private disabledState: DisabledState; | ||
|
||
static options: IDisableableToggleActionButtonOptions = { | ||
...ToggleActionButton.options, | ||
disabledTooltip: ComponentOptions.buildStringOption(), | ||
disabledIcon: ComponentOptions.buildStringOption(), | ||
}; | ||
|
||
constructor(public element: HTMLElement, public options: IDisableableToggleActionButtonOptions, public bindings?: IResultsComponentBindings) { | ||
super(element, DisableableToggleActionButton.ID, bindings); | ||
this.options = ComponentOptions.initComponentOptions(element, DisableableToggleActionButton, options); | ||
|
||
this.createInnerButton(bindings); | ||
} | ||
|
||
/** | ||
* Indicates whether the toggle button is in the activated state. | ||
*/ | ||
public isActivated(): boolean { | ||
return this.innerStatefulActionButton.getCurrentState() === this.activatedState; | ||
} | ||
|
||
/** | ||
* Indicates whether the disableable toggle button is in the disable state. | ||
*/ | ||
public isDisabled(): boolean { | ||
return this.innerStatefulActionButton.getCurrentState() === this.disabledState; | ||
} | ||
|
||
/** | ||
* Sets the toggle button to the specified state. | ||
* @param activated Whether the button is activated. | ||
*/ | ||
public setActivated(activated: boolean): void { | ||
if (this.isDisabled() && !activated) { | ||
this.innerStatefulActionButton.switchTo(this.deactivatedState); | ||
} | ||
if (!this.isDisabled() && activated !== this.isActivated()) { | ||
this.innerStatefulActionButton.switchTo(activated ? this.activatedState : this.deactivatedState); | ||
} | ||
} | ||
|
||
public setEnabled(enabled: boolean): void { | ||
if (enabled) { | ||
this.enable(); | ||
} else { | ||
this.disable(); | ||
} | ||
} | ||
|
||
public disable(): void { | ||
if (this.isDisabled()) { | ||
return; | ||
} | ||
if (this.isActivated()) { | ||
this.innerStatefulActionButton.switchTo(this.deactivatedState); | ||
} | ||
this.innerStatefulActionButton.switchTo(this.disabledState); | ||
} | ||
|
||
public enable(): void { | ||
if (this.isDisabled()) { | ||
this.innerStatefulActionButton.switchTo(this.deactivatedState); | ||
} | ||
} | ||
|
||
public onClick(): void { | ||
if (this.isDisabled()) { | ||
return; | ||
} | ||
this.setActivated(!this.isActivated()); | ||
|
||
if (this.options.click) { | ||
this.options.click(); | ||
} | ||
} | ||
|
||
private createInnerButton(bindings?: IResultsComponentBindings): void { | ||
this.deactivatedState = new UnactivatedState(this); | ||
this.disabledState = new DisabledState(this); | ||
this.activatedState = new ActivatedState(this); | ||
|
||
this.innerStatefulActionButton = new StatefulActionButton( | ||
this.element, | ||
{ | ||
initialState: this.deactivatedState, | ||
states: [this.deactivatedState, this.activatedState, this.disabledState], | ||
allowedTransitions: [ | ||
{ from: this.deactivatedState, to: this.disabledState }, | ||
{ from: this.disabledState, to: this.deactivatedState }, | ||
{ from: this.deactivatedState, to: this.activatedState }, | ||
{ from: this.activatedState, to: this.deactivatedState }, | ||
], | ||
}, | ||
bindings | ||
); | ||
} | ||
} | ||
|
||
Initialization.registerAutoCreateComponent(ToggleActionButton); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { StatefulActionButton, IStatefulActionButtonOptionsWithIcon } from './StatefulActionButton'; | ||
|
||
export interface IToggleableButtonOptions { | ||
activateIcon: string; | ||
activateTooltip: string; | ||
deactivateIcon: string; | ||
deactivateTooltip: string; | ||
click?: () => void; | ||
activate?: () => void; | ||
deactivate?: () => void; | ||
} | ||
|
||
export interface IToggleableButton { | ||
options: IToggleableButtonOptions; | ||
onClick: () => void; | ||
} | ||
|
||
export class ToggleUnactivatedState implements IStatefulActionButtonOptionsWithIcon { | ||
public readonly name = 'ToggleUnactivatedState'; | ||
public readonly icon: string; | ||
public readonly tooltip: string; | ||
public readonly click: { (): void; (): void; (): void }; | ||
constructor(toggleableButton: IToggleableButton) { | ||
this.icon = toggleableButton.options.activateIcon; | ||
this.tooltip = toggleableButton.options.activateTooltip; | ||
this.click = () => toggleableButton.onClick(); | ||
} | ||
} | ||
|
||
export class ToggleActivatedState implements IStatefulActionButtonOptionsWithIcon { | ||
static ACTIVATED_CLASS_NAME = 'coveo-toggleactionbutton-activated'; | ||
public readonly name = 'ToggleActivatedState'; | ||
public readonly onStateEntry: (this: StatefulActionButton) => void; | ||
public readonly onStateExit: (this: StatefulActionButton) => void; | ||
public readonly click: () => void; | ||
public readonly icon: string; | ||
public readonly tooltip: string; | ||
constructor(toggleableButton: IToggleableButton) { | ||
this.onStateEntry = function () { | ||
this.element.classList.add(ToggleActivatedState.ACTIVATED_CLASS_NAME); | ||
this.element.setAttribute('aria-pressed', 'true'); | ||
toggleableButton.options.activate?.apply(toggleableButton); | ||
}; | ||
this.onStateExit = function () { | ||
this.element.classList.remove(ToggleActivatedState.ACTIVATED_CLASS_NAME); | ||
this.element.setAttribute('aria-pressed', 'false'); | ||
toggleableButton.options.deactivate?.apply(toggleableButton); | ||
}; | ||
this.click = () => toggleableButton.onClick(); | ||
this.icon = toggleableButton.options.deactivateIcon; | ||
this.tooltip = toggleableButton.options.deactivateTooltip; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { DisabledState } from '../../../src/components/ActionButton/DisableableButton'; | ||
|
||
describe('DisabledState', () => { | ||
let testElement: HTMLElement; | ||
let testSubject: DisabledState; | ||
let fakeStatefulActionButton: { element: HTMLElement }; | ||
|
||
beforeEach(() => { | ||
testElement = document.createElement('div'); | ||
fakeStatefulActionButton = { element: testElement }; | ||
testSubject = new DisabledState({ options: { disabledIcon: 'someSvgIcon', disabledTooltip: 'someTooltip' } }); | ||
}); | ||
|
||
describe('constructor', () => { | ||
it('should use the icon and tooltip from the option of the disabledButton', () => { | ||
expect(testSubject.icon).toBe('someSvgIcon'); | ||
expect(testSubject.tooltip).toBe('someTooltip'); | ||
}); | ||
}); | ||
|
||
describe('onStateEntry', () => { | ||
beforeEach(() => { | ||
testSubject.onStateEntry.apply(fakeStatefulActionButton); | ||
}); | ||
|
||
it('should add coveo-actionbutton-disabled to the classlist on this.element of the caller', () => { | ||
expect(testElement.classList.value).toBe('coveo-actionbutton-disabled'); | ||
}); | ||
|
||
it('should add the attribute disabled to this.element of the caller', () => { | ||
expect(testElement.hasAttribute('disabled')).toBeTrue(); | ||
}); | ||
}); | ||
|
||
describe('onStateExit', () => { | ||
beforeEach(() => { | ||
testElement.classList.value = 'coveo-actionbutton-disabled'; | ||
testElement.setAttribute('disabled', ''); | ||
testSubject.onStateExit.apply(fakeStatefulActionButton); | ||
}); | ||
|
||
it('should remove coveo-actionbutton-disabled to the classlist on this.element of the caller', () => { | ||
expect(testElement.classList.value).toBe(''); | ||
}); | ||
|
||
it('should remove the attribute disabled to this.element of the caller', () => { | ||
expect(testElement.hasAttribute('disabled')).toBeFalse(); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.