import { ReactiveControllerHost } from 'lit'; import { makeAutoObservable } from 'mobx'; import { createContext, RefObject } from 'js-widgets'; import { createRefFor } from 'js-widgets/util'; import { makeComponentsMobxAware } from 'js-widgets/mobx-tools'; import { useEffect, useState } from 'js-widgets/hooks'; import { opt, props, widget } from 'js-widgets'; import { atom, consume, create, createMemo, createTicker, effect, getRefresher, state, interval, handleMethods, handlePromise, preset } from '../main/ext'; export default { title: 'Demos' }; export const simpleCounterDemo = () => ; export const simpleCounterDemo2 = () => ; export const simpleCounterDemo3 = () => ; export const complexCounterDemo = () => ; export const clockDemo = () => ; export const memoDemo = () => ; export const intervalDemo = () => ; export const contextDemo = () => ; export const mousePositionDemo = () => ; export const promiseDemo = () => ; export const mobxDemo = () => ; // Auto-updating mobx store const store = makeAutoObservable({ count: 0, increment() { this.count++; } }); makeComponentsMobxAware(); setInterval(() => store.increment(), 1000); // === Simple counter demo =========================================== function SimpleCounterDemo(p: { initialCount?: number; // label?: string; }) { preset(p, () => ({ initialCount: 0, label: 'Counter' })); const [getCount, setCount] = atom(p.initialCount); const onIncrement = () => setCount((it) => it + 1); const onInput = (ev: any) => setCount(ev.currentTarget.valueAsNumber); // TODO effect( () => { console.log(`Value of "${p.label}": ${getCount()}`); }, () => [getCount()] ); return () => (

Simple counter demo:

); } // === Simple counter demo 2 ========================================= function SimpleCounterDemo2({ initialCount = 0, // label = 'Counter' }) { const [count, setCount] = useState(initialCount); const onIncrement = () => setCount((it) => it + 1); useEffect(() => { console.log(`Value of "${label}": ${count}`); }, [label, count]); return (

Simple counter demo 2:

); } // === Simple counter demo 3 ========================================= const x = widget('')( props({ initialCount: opt(0), label: opt('Counter') }) ); const SimpleCounterDemo3 = widget('SimpleCounterDemo3')( props({ initialCount: opt(0), label: opt('Counter') }) )((p) => { const [s, set] = state({ count: p.initialCount }); const onIncrement = () => set.count((it) => it + 1); return () => (

Simple counter demo 3:

); }); // === Complex counter demo ========================================== function ComplexCounter(p: { initialCount?: number; label?: string; ref?: RefObject<{ reset(n: number): void; }>; }) { preset(p, () => ({ initialCount: 0, label: 'Counter' })); const [getCount, setCount] = atom(p.initialCount); const onIncrement = () => setCount((it) => it + 1); const onDecrement = () => setCount((it) => it - 1); handleMethods(() => p.ref, { reset(n) { setCount(n); } }); return () => (

Complex counter demo:

{` ${getCount()} `}
); } function ComplexCounterDemo() { const counterRef = createRefFor(ComplexCounter); const onResetToZeroClick = () => counterRef.current!.reset(0); const onResetToOneHundredClick = () => counterRef.current!.reset(100); return () => (

); } // === Clock demo ==================================================== function ClockDemo() { const getTime = createTicker((it) => it.toLocaleTimeString()); return () => (

Clock demo:

Current time: {getTime()}
); } // === Memo demo ===================================================== function MemoDemo() { const [s, set] = state({ count: 0 }); const onButtonClick = () => set.count((it) => it + 1); const memo = createMemo( () => 'Last time the memoized value was calculated: ' + new Date().toLocaleTimeString(), () => [Math.floor(s.count / 5)] ); return () => (

Memoization demo:

{memo.value}

); } // === Interval demo ================================================= function IntervalDemo() { const [s, set] = state({ count: 0, delay: 1000 }); const onReset = () => set.delay(1000); interval( () => set.count((it) => it + 1), () => s.delay ); interval(() => { if (s.delay > 10) { set.delay((it) => (it /= 2)); } }, 1000); return () => (

Interval demo:

Counter: {s.count}
Delay: {s.delay}

); } // === Context demo ================================================== const translations = { en: { salutation: 'Hello, ladies and gentlemen!' }, de: { salutation: 'Hallo, meine Damen und Herren!' }, fr: { salutation: 'Salut, Mesdames, Messieurs!' } }; const [localeCtx, LocaleProvider] = createContext('locale', 'en'); function ContextDemo() { const [getLocale, setLocale] = atom('en'); const onLocaleChange = (ev: any) => setLocale(ev.target.value); return () => (

Context demo:

); } function LocaleText(p: { id: string }) { const getLocale = consume(localeCtx); return () => (

{(translations as any)[getLocale()][p.id]} {/* // TODO */}

); } // === mouse position demo / ReactiveController demo ================= class MousePosController { #valid = false; #x = -1; #y = -1; constructor(host: ReactiveControllerHost) { const mouseMoveListener = (ev: MouseEvent) => { this.#valid = true; this.#x = ev.clientX; this.#y = ev.clientY; host.requestUpdate(); }; host.addController({ hostConnected() { window.addEventListener('mousemove', mouseMoveListener); }, hostDisconnected() { window.removeEventListener('mousemove', mouseMoveListener); } }); } valid() { return this.#valid; } x() { return this.#x; } y() { return this.#y; } } function MousePositionDemo() { const mousePos = create(MousePosController); return () => (
{mousePos.valid() ? `Mouse position: ${mousePos.x()}x${mousePos.y()}` : 'Please move mouse ...'}
); } // === promise demo ================================================== function Loader(p: { loadingText?: string; finishText?: string }) { const res = handlePromise(() => wait(4000)); return () => res.state === 'pending' ? (
{p.loadingText}
) : (
{p.finishText}
); } function PromiseDemo() { const [s, set] = state({ key: 0, loadingText: 'Loading...', finishText: 'Finished!' }); const refresh = getRefresher(); const onRefresh = () => refresh(); const onRestart = () => set.key((it) => it + 1); // TODO const onToggleLoadingText = () => set.loadingText((it) => it === 'Loading...' ? 'Please wait...' : 'Loading...' ); const onToggleFinishText = () => set.finishText((it) => (it === 'Finished!' ? 'Done!' : 'Finished!')); return () => (

Promise demo (last update {new Date().toLocaleTimeString()})


); } function MobxCounterInfo1() { return (

Mobx counter info 1

Count: {store.count}
); } function MobxCounterInfo2() { return (

Mobx counter info 2

Count: {store.count}
); } function MobxDemo() { return (
); } // === utils ========================================================= function wait(ms: number) { return new Promise((resolve) => setTimeout(() => resolve(), ms)); }