Skip to content

Commit

Permalink
Big refactoring 0.0.14 and more sync utils (#16)
Browse files Browse the repository at this point in the history
* rename

* serial done, renaming debounce

* renaming

* refactor debounce

* debounce doc, rename latest

* renaming

* add cell and persist and refactor
  • Loading branch information
Pistonight authored Dec 20, 2024
1 parent 479e432 commit 2a998f1
Show file tree
Hide file tree
Showing 22 changed files with 1,341 additions and 412 deletions.
7 changes: 6 additions & 1 deletion Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ tasks:
test:
desc: Run the tests
cmds:
- echo "No tests"
- npx -w packages/pure vitest run

fix:
desc: Fix the code
Expand All @@ -33,3 +33,8 @@ tasks:
desc: Generate the documentation
cmds:
- npx typedoc

serve:
desc: Serve the documentation
cmds:
- npx serve docs
4 changes: 2 additions & 2 deletions packages/pure-react/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pistonite/pure-react",
"version": "0.0.4",
"version": "0.0.5",
"description": "React binding for pure library",
"homepage": "https://github.com/Pistonite/pure",
"bugs": {
Expand All @@ -20,7 +20,7 @@
"directory": "packages/pure-react"
},
"dependencies": {
"@pistonite/pure": "^0.0.12"
"@pistonite/pure": "^0.0.14"
},
"peerDependencies": {
"react": "^18"
Expand Down
36 changes: 3 additions & 33 deletions packages/pure-react/src/pref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,55 +33,25 @@
* @module
*/

import { useState, useEffect } from "react";
import { useSyncExternalStore } from "react";

import {
addDarkSubscriber,
addLocaleSubscriber,
getLocale,
isDark,
removeDarkSubscriber,
removeLocaleSubscriber,
} from "@pistonite/pure/pref";

/**
* Hook to get the current dark mode state
*/
export const useDark = (): boolean => {
const [value, setValue] = useState(isDark);
useEffect(() => {
const dark = isDark();
if (dark !== value) {
setValue(dark);
}
const subscriber = (dark: boolean) => {
setValue(dark);
};
addDarkSubscriber(subscriber);
return () => {
removeDarkSubscriber(subscriber);
};
}, []);
return value;
return useSyncExternalStore(addDarkSubscriber, isDark);
};

/**
* Hook to get the current locale
*/
export const useLocale = (): string => {
const [locale, setLocale] = useState(getLocale);
useEffect(() => {
const l = getLocale();
if (l !== locale) {
setLocale(l);
}
const subscriber = (locale: string) => {
setLocale(locale);
};
addLocaleSubscriber(subscriber);
return () => {
removeLocaleSubscriber(subscriber);
};
}, []);
return locale;
return useSyncExternalStore(addLocaleSubscriber, getLocale);
};
2 changes: 2 additions & 0 deletions packages/pure/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.test.ts
/node_modules
5 changes: 4 additions & 1 deletion packages/pure/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pistonite/pure",
"version": "0.0.13",
"version": "0.0.14",
"description": "Pure TypeScript libraries for my projects",
"homepage": "https://github.com/Pistonite/pure",
"bugs": {
Expand All @@ -27,5 +27,8 @@
"@types/file-saver": "^2.0.7",
"denque": "2.1.0",
"file-saver": "2.0.5"
},
"devDependencies": {
"vitest": "^2.1.8"
}
}
68 changes: 21 additions & 47 deletions packages/pure/src/pref/dark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,16 @@
* @module
*/

import { persist } from "../sync/persist.ts";
import { injectStyle } from "./injectStyle.ts";

const KEY = "Pure.Dark";

let dark = false;
const subscribers: ((dark: boolean) => void)[] = [];
const dark = persist({
initial: false,
key: "Pure.Dark",
storage: localStorage,
serialize: (value) => (value ? "1" : ""),
deserialize: (value) => !!value,
});

/**
* Returns if dark mode is prefered in the browser environment
Expand Down Expand Up @@ -96,27 +100,19 @@ export type DarkOptions = {
export const initDark = (options: DarkOptions = {}): void => {
let _dark = options.initial || prefersDarkMode();

if (options.persist) {
const value = localStorage.getItem(KEY);
if (value !== null) {
_dark = !!value;
}
addDarkSubscriber((dark: boolean) => {
localStorage.setItem(KEY, dark ? "1" : "");
});
} else {
localStorage.removeItem(KEY);
}

setDark(_dark);

const selector = options.selector ?? ":root";
if (selector) {
// notify immediately to update the style initially
addDarkSubscriber((dark: boolean) => {
updateStyle(dark, selector);
}, true /* notify */);
}

if (options.persist) {
dark.init(_dark);
} else {
dark.disable();
}
};

/**
Expand All @@ -130,55 +126,33 @@ export const initDark = (options: DarkOptions = {}): void => {
* subsequence `setDark` calls will still persist the value.
*/
export const clearPersistedDarkPerference = (): void => {
localStorage.removeItem(KEY);
dark.clear();
};

/**
* Gets the current value of dark mode
*/
export const isDark = (): boolean => dark;
export const isDark = (): boolean => dark.get();

/**
* Set the value of dark mode
*/
export const setDark = (value: boolean): void => {
if (dark === value) {
return;
}
dark = value;
const len = subscribers.length;
for (let i = 0; i < len; i++) {
subscribers[i](dark);
}
dark.set(value);
};
/**
* Add a subscriber to dark mode changes
* Add a subscriber to dark mode changes and return a function to remove the subscriber
*
* If `notifyImmediately` is `true`, the subscriber will be called immediately with the current value
*/
export const addDarkSubscriber = (
subscriber: (dark: boolean) => void,
notifyImmediately?: boolean,
): void => {
subscribers.push(subscriber);
if (notifyImmediately) {
subscriber(dark);
}
};

/**
* Remove a subscriber from dark mode changes
*/
export const removeDarkSubscriber = (
subscriber: (dark: boolean) => void,
): void => {
const index = subscribers.indexOf(subscriber);
if (index >= 0) {
subscribers.splice(index, 1);
}
): (() => void) => {
return dark.subscribe(subscriber, notifyImmediately);
};

const updateStyle = (dark: boolean, selector: string) => {
const text = `${selector} { color-scheme: ${dark ? "dark" : "light"}; }`;
injectStyle(KEY, text);
injectStyle("pure-pref-dark", text);
};
64 changes: 20 additions & 44 deletions packages/pure/src/pref/locale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,20 @@
* @module
*/

const KEY = "Pure.Locale";
import { persist } from "../sync/persist.ts";

let supportedLocales: readonly string[] = [];
let locale: string = "";
let defaultLocale: string = "";
const subscribers: ((locale: string) => void)[] = [];
const locale = persist<string>({
initial: "",
key: "Pure.Locale",
storage: localStorage,
serialize: (value) => value,
deserialize: (value) => {
const supported = convertToSupportedLocale(value);
return supported || null;
},
});

/**
* Use browser API to guess user's preferred locale
Expand Down Expand Up @@ -120,21 +128,10 @@ export const initLocale = <TLocale extends string>(
}
defaultLocale = options.default;
if (options.persist) {
const value = localStorage.getItem(KEY);
if (value !== null) {
const supported = convertToSupportedLocale(value);
if (supported) {
_locale = supported;
}
}
addLocaleSubscriber((locale: string) => {
localStorage.setItem(KEY, locale);
});
locale.init(_locale);
} else {
localStorage.removeItem(KEY);
locale.disable();
}

setLocale(_locale);
};

/**
Expand All @@ -149,13 +146,11 @@ export const initLocale = <TLocale extends string>(
* subsequence `setLocale` calls will still persist the value.
*/
export const clearPersistedLocalePreference = (): void => {
localStorage.removeItem(KEY);
locale.clear();
};

/** Get the current selected locale */
export const getLocale = (): string => {
return locale;
};
export const getLocale = (): string => locale.get();

/** Get the default locale when initialized */
export const getDefaultLocale = (): string => {
Expand All @@ -172,14 +167,7 @@ export const setLocale = (newLocale: string): boolean => {
if (!supported) {
return false;
}
if (supported === locale) {
return true;
}
locale = supported;
const len = subscribers.length;
for (let i = 0; i < len; i++) {
subscribers[i](locale);
}
locale.set(supported);
return true;
};

Expand Down Expand Up @@ -235,28 +223,16 @@ export const convertToSupportedLocaleOrDefault = (
};

/**
* Add a subscriber to be notified when the locale changes
* Add a subscriber to be notified when the locale changes.
* Returns a function to remove the subscriber
*
* If `notifyImmediately` is `true`, the subscriber will be called immediately with the current locale
*/
export const addLocaleSubscriber = (
fn: (locale: string) => void,
notifyImmediately?: boolean,
): void => {
subscribers.push(fn);
if (notifyImmediately) {
fn(locale);
}
};

/**
* Remove a subscriber from locale changes
*/
export const removeLocaleSubscriber = (fn: (locale: string) => void): void => {
const index = subscribers.indexOf(fn);
if (index !== -1) {
subscribers.splice(index, 1);
}
): (() => void) => {
return locale.subscribe(fn, notifyImmediately);
};

/**
Expand Down
35 changes: 0 additions & 35 deletions packages/pure/src/sync/Debounce.ts

This file was deleted.

Loading

0 comments on commit 2a998f1

Please sign in to comment.