From c9c90ae5d218a849f46b5a6a0b75eab2d0fb14af Mon Sep 17 00:00:00 2001 From: cupcakearmy Date: Mon, 6 Jan 2020 23:17:34 +0100 Subject: [PATCH] initial commit --- .gitignore | 7 +++++++ .npmignore | 2 ++ .prettierrc | 5 +++++ LICENSE | 21 +++++++++++++++++++ README.md | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/index.tsx | 52 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 ++ test/index.html | 36 +++++++++++++++++++++++++++++++++ test/index.styl | 38 ++++++++++++++++++++++++++++++++++ test/index.tsx | 52 +++++++++++++++++++++++++++++++++++++++++++++++ tsconfig.json | 25 +++++++++++++++++++++++ 11 files changed, 294 insertions(+) create mode 100755 .gitignore create mode 100755 .npmignore create mode 100755 .prettierrc create mode 100755 LICENSE create mode 100755 README.md create mode 100755 lib/index.tsx create mode 100644 test/index.html create mode 100644 test/index.styl create mode 100644 test/index.tsx create mode 100755 tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..cbf0ae8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +# Node +node_modules +yarn.lock + +# Generated +dist +.cache \ No newline at end of file diff --git a/.npmignore b/.npmignore new file mode 100755 index 0000000..ad6609c --- /dev/null +++ b/.npmignore @@ -0,0 +1,2 @@ +* +!dist/* \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100755 index 0000000..8bf0e67 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +semi: false +singleQuote: true +trailingComma: es5 +tabWidth: 4 +printWidth: 200 diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..cb98b7e --- /dev/null +++ b/LICENSE @@ -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. diff --git a/README.md b/README.md new file mode 100755 index 0000000..e04f80c --- /dev/null +++ b/README.md @@ -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 ( +
+
+ + + + +
+
+ ) +} +``` diff --git a/lib/index.tsx b/lib/index.tsx new file mode 100755 index 0000000..81a8b41 --- /dev/null +++ b/lib/index.tsx @@ -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 = (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 = ({ light, dark, unset }: { light?: A, dark?: B, unset?: C }): A | B | C | undefined => { + const mode = useLightSwitch() + + return modeSelector(mode, { light, dark, unset }) +} \ No newline at end of file diff --git a/package.json b/package.json index 8db96c7..1c5599f 100755 --- a/package.json +++ b/package.json @@ -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" } } diff --git a/test/index.html b/test/index.html new file mode 100644 index 0000000..57e9aa1 --- /dev/null +++ b/test/index.html @@ -0,0 +1,36 @@ + + + + + + + + +

CSS

+ + + + + + + + + + + + + + + + + +
LightDefaultDark
UpUpUp
DownDownDown
+ +

React

+
+ +
+ + + + \ No newline at end of file diff --git a/test/index.styl b/test/index.styl new file mode 100644 index 0000000..7e04aa7 --- /dev/null +++ b/test/index.styl @@ -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 + diff --git a/test/index.tsx b/test/index.tsx new file mode 100644 index 0000000..77929de --- /dev/null +++ b/test/index.tsx @@ -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
+

Simple

+
+ {name} +
+
+} + +const WithSelector: React.FC = () => { + const selected = useModeSelector({ + light: { color: 'green', name: 'Light' }, + dark: { color: 'red', name: 'Dark' }, + unset: { color: 'blue', name: 'Unset' }, + }) + + return
+

Selector

+
+ {selected.name} +
+
+} + +const App: React.FC = () => { + return
+ + +
+} + +ReactDOM.render(, window.document.getElementById('root')) diff --git a/tsconfig.json b/tsconfig.json new file mode 100755 index 0000000..98245cd --- /dev/null +++ b/tsconfig.json @@ -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" + ] +} \ No newline at end of file