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));
}