mirror of
https://github.com/cupcakearmy/use-light-switch.git
synced 2024-12-21 15:36:26 +00:00
initial commit
This commit is contained in:
parent
4f7354c78e
commit
c9c90ae5d2
7
.gitignore
vendored
Executable file
7
.gitignore
vendored
Executable file
@ -0,0 +1,7 @@
|
||||
# Node
|
||||
node_modules
|
||||
yarn.lock
|
||||
|
||||
# Generated
|
||||
dist
|
||||
.cache
|
2
.npmignore
Executable file
2
.npmignore
Executable file
@ -0,0 +1,2 @@
|
||||
*
|
||||
!dist/*
|
5
.prettierrc
Executable file
5
.prettierrc
Executable file
@ -0,0 +1,5 @@
|
||||
semi: false
|
||||
singleQuote: true
|
||||
trailingComma: es5
|
||||
tabWidth: 4
|
||||
printWidth: 200
|
21
LICENSE
Executable file
21
LICENSE
Executable file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Nicco
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
54
README.md
Executable file
54
README.md
Executable file
@ -0,0 +1,54 @@
|
||||
# use-light-switch
|
||||
|
||||
![Version](https://badgen.net/npm/v/use-light-switch)
|
||||
![Dependencies](https://badgen.net/david/dep/cupcakearmy/use-light-switch)
|
||||
![Size Badge](https://badgen.net/bundlephobia/minzip/use-light-switch)
|
||||
|
||||
**React hook for dark mode.**
|
||||
|
||||
## 🌈 Features
|
||||
|
||||
- Typescript compatible
|
||||
- **0** Dependencies
|
||||
- Tiny **~0.7kB**
|
||||
- React Hooks
|
||||
|
||||
###### Installation
|
||||
|
||||
```
|
||||
npm i use-light-switch
|
||||
```
|
||||
|
||||
## 🤔 Motivation
|
||||
|
||||
There was no library with typings 🤕
|
||||
|
||||
## 🚀 Quickstart
|
||||
|
||||
```typescript
|
||||
import ReactDOM from 'react-dom'
|
||||
import { useForm } from 'formhero'
|
||||
|
||||
const Form = () => {
|
||||
const { field, form } = useForm({
|
||||
username: '',
|
||||
password: '',
|
||||
})
|
||||
|
||||
const _submit = (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
console.log(form)
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<form onSubmit={_submit}>
|
||||
<input {...field('username')} />
|
||||
<input {...field('password')} />
|
||||
|
||||
<button type="submit">Go 🚀</button>
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
52
lib/index.tsx
Executable file
52
lib/index.tsx
Executable file
@ -0,0 +1,52 @@
|
||||
import React, { useState, useEffect } from 'react'
|
||||
|
||||
export enum Mode {
|
||||
Light,
|
||||
Dark,
|
||||
Unset,
|
||||
}
|
||||
|
||||
export const useLightSwitch = (): Mode => {
|
||||
|
||||
const darkMedia = window.matchMedia('(prefers-color-scheme: dark)')
|
||||
const lightMedia = window.matchMedia('(prefers-color-scheme: light)')
|
||||
|
||||
const [dark, setDark] = useState(darkMedia.matches)
|
||||
const [light, setLight] = useState(lightMedia.matches)
|
||||
const unsed = !dark && !light
|
||||
|
||||
useEffect(() => {
|
||||
const darkFn = (e: MediaQueryListEvent) => { setDark(e.matches) }
|
||||
const lightFn = (e: MediaQueryListEvent) => { setLight(e.matches) }
|
||||
darkMedia.addListener(darkFn)
|
||||
lightMedia.addListener(lightFn)
|
||||
|
||||
return () => {
|
||||
darkMedia.removeListener(darkFn)
|
||||
lightMedia.removeListener(lightFn)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return unsed
|
||||
? Mode.Unset
|
||||
: dark
|
||||
? Mode.Dark
|
||||
: Mode.Light
|
||||
}
|
||||
|
||||
export const modeSelector = <A, B, C>(mode: Mode, { light, dark, unset }: { light?: A, dark?: B, unset?: C }): A | B | C | undefined => {
|
||||
switch (mode) {
|
||||
case Mode.Light:
|
||||
return light
|
||||
case Mode.Dark:
|
||||
return dark
|
||||
case Mode.Unset:
|
||||
return unset
|
||||
}
|
||||
}
|
||||
|
||||
export const useModeSelector = <A, B, C>({ light, dark, unset }: { light?: A, dark?: B, unset?: C }): A | B | C | undefined => {
|
||||
const mode = useLightSwitch()
|
||||
|
||||
return modeSelector<A, B, C>(mode, { light, dark, unset })
|
||||
}
|
@ -18,8 +18,10 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^16.8",
|
||||
"parcel-bundler": "^1.12.4",
|
||||
"react": "^16.8",
|
||||
"react-dom": "^16.8",
|
||||
"stylus": "^0.54.7",
|
||||
"typescript": "^3.7"
|
||||
}
|
||||
}
|
||||
|
36
test/index.html
Normal file
36
test/index.html
Normal file
@ -0,0 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<link href="./index.styl" rel="stylesheet" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>CSS</h2>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Light</th>
|
||||
<th>Default</th>
|
||||
<th>Dark</th>
|
||||
</tr>
|
||||
<tr class="up">
|
||||
<td class="light">Up</td>
|
||||
<td>Up</td>
|
||||
<td class="dark">Up</td>
|
||||
</tr>
|
||||
<tr class="down">
|
||||
<td class="light">Down</td>
|
||||
<td>Down</td>
|
||||
<td class="dark">Down</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2>React</h2>
|
||||
<div id="root">
|
||||
|
||||
</div>
|
||||
<script src="./index.tsx"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
38
test/index.styl
Normal file
38
test/index.styl
Normal file
@ -0,0 +1,38 @@
|
||||
$white = #ffffff
|
||||
$light = #dddddd
|
||||
$dark = #444444
|
||||
$black = #000000
|
||||
|
||||
table
|
||||
text-align: center
|
||||
|
||||
.up
|
||||
background: $light
|
||||
color: $black
|
||||
|
||||
@media (prefers-color-scheme: dark)
|
||||
.dark
|
||||
background: $dark
|
||||
color: $white
|
||||
@media (prefers-color-scheme: light)
|
||||
.light
|
||||
background: $white
|
||||
color: $black
|
||||
|
||||
.down
|
||||
background: $dark
|
||||
color: $white
|
||||
|
||||
@media (prefers-color-scheme: dark)
|
||||
.dark
|
||||
background: $black
|
||||
color: $white
|
||||
@media (prefers-color-scheme: light)
|
||||
.light
|
||||
background: $light
|
||||
color: $black
|
||||
|
||||
td,th
|
||||
padding: 1em 2em
|
||||
border: 1px solid blue
|
||||
|
52
test/index.tsx
Normal file
52
test/index.tsx
Normal file
@ -0,0 +1,52 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { Mode, useLightSwitch, modeSelector, useModeSelector } from '../'
|
||||
|
||||
|
||||
const Simple: React.FC = () => {
|
||||
const mode = useLightSwitch()
|
||||
|
||||
let color = 'green'
|
||||
let name = 'Light'
|
||||
if (mode === Mode.Dark) {
|
||||
color = 'red'
|
||||
name = 'Dark'
|
||||
}
|
||||
|
||||
return <div>
|
||||
<h3>Simple</h3>
|
||||
<div style={{
|
||||
padding: '1em 2em',
|
||||
backgroundColor: color
|
||||
}}>
|
||||
{name}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
const WithSelector: React.FC = () => {
|
||||
const selected = useModeSelector({
|
||||
light: { color: 'green', name: 'Light' },
|
||||
dark: { color: 'red', name: 'Dark' },
|
||||
unset: { color: 'blue', name: 'Unset' },
|
||||
})
|
||||
|
||||
return <div>
|
||||
<h3>Selector</h3>
|
||||
<div style={{
|
||||
padding: '1em 2em',
|
||||
backgroundColor: selected.color
|
||||
}}>
|
||||
{selected.name}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
const App: React.FC = () => {
|
||||
return <div>
|
||||
<Simple />
|
||||
<WithSelector />
|
||||
</div>
|
||||
}
|
||||
|
||||
ReactDOM.render(<App />, window.document.getElementById('root'))
|
25
tsconfig.json
Executable file
25
tsconfig.json
Executable file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2017",
|
||||
"module": "commonjs",
|
||||
"jsx": "react",
|
||||
"outDir": "./dist",
|
||||
"declaration": true,
|
||||
"strict": true,
|
||||
"noImplicitAny": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"strictBindCallApply": true,
|
||||
"strictPropertyInitialization": true,
|
||||
"noImplicitThis": true,
|
||||
"alwaysStrict": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"esModuleInterop": true,
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true
|
||||
},
|
||||
"include": [
|
||||
"./lib"
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user