-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(mox:theme): add theme switcher component
- Loading branch information
Showing
7 changed files
with
244 additions
and
2 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,25 @@ | ||
<div class="mox-theme-switch" ...attributes> | ||
<div class="flex items-center space-x-2 relative {{if this.isChecked "text-gray-800"}}"> | ||
<input | ||
id={{this.fieldId}} | ||
aria-label={{this.label}} | ||
type="checkbox" | ||
class="transform appearance-none outline-none | ||
flex items-center rounded-full p-1 cursor-pointer transition" | ||
checked={{this.isChecked}} | ||
{{on 'change' (fn this.switchTheme this.otherTheme)}} | ||
data-test-mox-theme-switch | ||
/> | ||
<div class="mox-theme-switch-icon pointer-events-none {{if this.isChecked "is-checked"}}"> | ||
{{#if (eq this.currentTheme "dark")}} | ||
<div class="text-white" data-test-mox-theme-switch-current="dark"> | ||
{{yield to="dark-icon"}} | ||
</div> | ||
{{else}} | ||
<div class="text-gray-900" data-test-mox-theme-switch-current="light"> | ||
{{yield to="light-icon"}} | ||
</div> | ||
{{/if}} | ||
</div> | ||
</div> | ||
</div> |
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,42 @@ | ||
import Component from '@glimmer/component'; | ||
import { action } from '@ember/object'; | ||
import { dasherize } from '@ember/string'; | ||
import { tracked } from '@glimmer/tracking'; | ||
|
||
export default class MoxThemeSwitchComponent extends Component { | ||
@tracked | ||
isChecked = false; | ||
|
||
allThemes = ['dark', 'light']; | ||
|
||
constructor() { | ||
super(...arguments); | ||
this.isChecked = this.args.isChecked || false; | ||
} | ||
|
||
get currentTheme() { | ||
return this.isChecked ? 'dark' : 'light'; | ||
} | ||
|
||
get otherTheme() { | ||
return this.allThemes.filter(theme => theme !== this.currentTheme)[0]; | ||
} | ||
|
||
get label() { | ||
if (this.args.label) { | ||
return this.args.label; | ||
} | ||
|
||
return `Use ${this.otherTheme} mode`; | ||
} | ||
|
||
get fieldId() { | ||
return this.args.id ? this.args.id : dasherize(this.label); | ||
} | ||
|
||
@action | ||
switchTheme(newTheme, event) { | ||
this.isChecked = !this.isChecked; | ||
this.args.toggleAction(newTheme, event); | ||
} | ||
} |
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 @@ | ||
export { default } from 'mx-ui-components/components/mox/theme-switch'; |
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,35 @@ | ||
import { hbs } from 'ember-cli-htmlbars'; | ||
|
||
export default { | ||
title: 'Mox Dark/Mox::ThemeSwitch', | ||
parameters: { | ||
backgrounds: { | ||
default: 'Dark', | ||
}, | ||
}, | ||
}; | ||
|
||
const Template = (args) => ({ | ||
template: hbs` | ||
<Mox::ThemeSwitch @isChecked={{this.isChecked}}> | ||
<:light-icon> | ||
<Mox::Icon @iconName="sun" @size="small" /> | ||
</:light-icon> | ||
<:dark-icon> | ||
<Mox::Icon @iconName="moon" @size="small" /> | ||
</:dark-icon> | ||
</Mox::ThemeSwitch>`, | ||
context: args, | ||
}); | ||
|
||
export const DefaultTheme = Template.bind({}); | ||
DefaultTheme.args = { | ||
message: '', | ||
isChecked: false, | ||
}; | ||
|
||
export const Checked = Template.bind({}); | ||
Checked.args = { | ||
message: '', | ||
isChecked: true, | ||
}; |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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,79 @@ | ||
import { module, test } from 'qunit'; | ||
import { setupRenderingTest } from 'dummy/tests/helpers'; | ||
import { click, render } from '@ember/test-helpers'; | ||
import { hbs } from 'ember-cli-htmlbars'; | ||
|
||
import sinon from 'sinon'; | ||
|
||
import { a11yAudit } from 'ember-a11y-testing/test-support'; | ||
|
||
module('Integration | Component | mox/theme-switch', function (hooks) { | ||
setupRenderingTest(hooks); | ||
|
||
hooks.beforeEach(async function() { | ||
this.set('toggleAction', sinon.spy()); | ||
this.set('label', 'Paradis'); | ||
}); | ||
|
||
test('it displays a label for screenreader users (set via argument)', async function(assert) { | ||
await render(hbs`<Mox::ThemeSwitch @toggleAction={{this.toggleAction}} @label={{this.label}} />`); | ||
assert.dom('[data-test-mox-theme-switch]').hasAttribute('aria-label', 'Paradis'); | ||
}); | ||
|
||
test('it displays a label for screenreader users (fallback)', async function(assert) { | ||
await render(hbs`<Mox::ThemeSwitch @toggleAction={{this.toggleAction}} />`); | ||
assert.dom('[data-test-mox-theme-switch]').hasAttribute('aria-label', 'Use dark mode'); | ||
}); | ||
|
||
test('it is accessible with an external label', async function(assert) { | ||
await render(hbs` | ||
<label for="my-field-id">Toggle 1</label> | ||
<Mox::ThemeSwitch @toggleAction={{this.toggleAction}} @id="my-field-id" /> | ||
`); | ||
await a11yAudit(); | ||
assert.ok(true, 'no a11y detected'); | ||
}); | ||
|
||
test('it is accessible with the default label', async function(assert) { | ||
await render(hbs`<Mox::ThemeSwitch @toggleAction={{this.toggleAction}} />`); | ||
await a11yAudit(); | ||
assert.ok(true, 'no a11y detected'); | ||
}); | ||
|
||
test('it allows unchecking the component externally', async function(assert) { | ||
await render(hbs`<Mox::ThemeSwitch @toggleAction={{this.toggleAction}} @isChecked={{false}} />`); | ||
|
||
assert.dom('[data-test-mox-theme-switch-current="dark"]').doesNotExist(); | ||
assert.dom('[data-test-mox-theme-switch-current="light"]').exists(); | ||
assert.dom('[data-test-mox-theme-switch]').hasAttribute('aria-label', 'Use dark mode'); | ||
}); | ||
|
||
test('it allows checking the component externally', async function(assert) { | ||
await render(hbs`<Mox::ThemeSwitch @toggleAction={{this.toggleAction}} @isChecked={{true}} />`); | ||
|
||
assert.dom('[data-test-mox-theme-switch-current="light"]').doesNotExist(); | ||
assert.dom('[data-test-mox-theme-switch-current="dark"]').exists(); | ||
assert.dom('[data-test-mox-theme-switch]').hasAttribute('aria-label', 'Use light mode'); | ||
}); | ||
|
||
test('it triggers the external action when switching the toggle', async function(assert) { | ||
await render(hbs`<Mox::ThemeSwitch @toggleAction={{this.toggleAction}} />`); | ||
await click('[data-test-mox-theme-switch]'); | ||
|
||
assert.true(this.toggleAction.calledOnce); | ||
}); | ||
|
||
test('it updates the UI when switching the toggle', async function(assert) { | ||
await render(hbs`<Mox::ThemeSwitch @toggleAction={{this.toggleAction}} />`); | ||
|
||
assert.dom('[data-test-mox-theme-switch-current="dark"]').doesNotExist(); | ||
assert.dom('[data-test-mox-theme-switch-current="light"]').exists(); | ||
assert.dom('[data-test-mox-theme-switch]').hasAttribute('aria-label', 'Use dark mode'); | ||
|
||
await click('[data-test-mox-theme-switch]'); | ||
|
||
assert.dom('[data-test-mox-theme-switch-current="light"]').doesNotExist(); | ||
assert.dom('[data-test-mox-theme-switch-current="dark"]').exists(); | ||
assert.dom('[data-test-mox-theme-switch]').hasAttribute('aria-label', 'Use light mode'); | ||
}); | ||
}); |