web_lib

Common web application libraries
git clone https://radroots.dev/git/web_lib.git
Log | Files | Refs | LICENSE

commit fbf61316973df84f5f4ffff8d01f4e686280ec59
parent 19f4309617f7bb90cfbd57a50a57a37198c3da3b
Author: triesap <137732411+triesap@users.noreply.github.com>
Date:   Sun,  1 Sep 2024 10:03:07 +0000

apps-lib: add input form component, add kv store, use cacheadapter with ndk store, edit types

Diffstat:
Aapps-lib/src/lib/components/input_form.svelte | 42++++++++++++++++++++++++++++++++++++++++++
Aapps-lib/src/lib/global.d.ts | 132+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mapps-lib/src/lib/index.ts | 1+
Mapps-lib/src/lib/stores/client.ts | 4++++
Mapps-lib/src/lib/stores/ndk.ts | 2+-
Mapps-lib/src/lib/types/components.ts | 18+++++++++++++++++-
Mapps-lib/src/lib/types/ui.ts | 1+
Mapps-lib/src/lib/utils/client.ts | 5+++++
8 files changed, 203 insertions(+), 2 deletions(-)

diff --git a/apps-lib/src/lib/components/input_form.svelte b/apps-lib/src/lib/components/input_form.svelte @@ -0,0 +1,42 @@ +<script lang="ts"> + import { kv, type IInputFormBasis } from "$lib"; + import type { ThemeLayer } from "@radroots/theme"; + import { onMount } from "svelte"; + + export let basis: IInputFormBasis; + $: basis = basis; + + let layer: ThemeLayer = 0; + $: layer = basis.layer; + + let el: HTMLInputElement | null; + + onMount(async () => { + try { + if (basis.sync) await $kv.set(basis.id, ""); + } catch (e) { + console.log(`e `, e); + } + }); +</script> + +<input + bind:this={el} + type="text" + class={`form-input text-layer-${layer}-glyph placeholder:text-layer-${layer}-glyph_pl placeholder:font-[300] caret-layer-${layer}-glyph`} + id={basis.id} + placeholder={basis.placeholder || ""} + on:input={async ({ currentTarget: el }) => { + const val = el.value + .split("") + .filter((char) => basis.field.charset.test(char)) + .join(""); + if (!basis.field.validate.test(val) && basis.field.validateKeypress) + el.classList.add(`form-input-invalid`); + else el.classList.remove("form-entry-invalid"); + el.value = val; + if (basis.sync) { + await $kv.set(basis.id, val); + } + }} +/> diff --git a/apps-lib/src/lib/global.d.ts b/apps-lib/src/lib/global.d.ts @@ -0,0 +1,132 @@ +declare class Keyva { + /** + * An IDBKeyRange that has no upper or lower bounding. + */ + static readonly unbound: IDBKeyRange; + /** + * Returns an IDBKeyRange that matches all keys that start + * with the specified string prefix. + */ + static prefix(prefix: string): IDBKeyRange; + /** + * @returns An array of strings that contain the names of all + * Keyva-created IndexedDB databases. + */ + static each(): Promise<string[]>; + /** + * Deletes Keyva-created IndexedDB databases with the + * specified names. + * + * @param names The names of the databases to delete. + * If no names are provided, all Keyva IndexedDB databases + * are deleted. + */ + static delete(...names: string[]): Promise<void>; + /** Stores the prefix that is added to every IndexedDB database created by Keyva. */ + private static readonly kvPrefix; + /** + * Creates a new IndexedDB-backed database + */ + constructor(options?: Keyva.IConstructorOptions); + private readonly indexes; + private readonly name; + /** + * Get a value by its key. + * @param key The key of the value to get. + */ + get<T = any>(key: Keyva.Key): Promise<T>; + /** + * Get a series of values from the keys specified. + * @param keys The key of the value to get. + */ + get<T = any>(keys: Keyva.Key[]): Promise<T[]>; + /** + * Gets all keys and values from the Keyva database. + * @param key The key of the value to get. + */ + each<T = any>(): Promise<[Keyva.Key, T][]>; + /** + * Gets a series of keys and values that match the specified + * set of options. + */ + each<T = any>(options: Keyva.IQuery): Promise<[Keyva.Key, T][]>; + /** + * Gets a series of keys only that match the specified set of options. + */ + each(options: Keyva.IQuery, only: "keys"): Promise<Keyva.Key[]>; + /** + * Gets a series of values only that match the specified set of options. + */ + each<T = any>(options: Keyva.IQuery, only: "values"): Promise<T[]>; + /** + * Set a value with a key. + */ + set(key: Keyva.Key, value: any): Promise<void>; + /** + * Set multiple values at once. This is faster than calling set() multiple times. + * It's also atomic – if one of the pairs can't be added, none will be added. + * @param entries Array of entries, where each entry is an array of `[key, value]`. + */ + set(entries: [Keyva.Key, any][]): Promise<void>; + /** + * Deletes all objects from this Keyva database + * (but keeps the Keyva database itself is kept). + */ + delete(): Promise<void>; + /** + * Delete a single object from the store with the specified key. + */ + delete(range: IDBKeyRange): Promise<void>; + /** + * Delete a single object from the store with the specified key. + */ + delete(key: Keyva.Key): Promise<void>; + /** + * Delete a series of objects from the store at once, with the specified keys. + */ + delete(keys: Keyva.Key[]): Promise<void>; + /** */ + private getStore; + /** */ + private getDatabase; + private database; + /** + * Works around a Safari 14 bug. + * + * Safari has a bug where IDB requests can hang while the browser is + * starting up. https://bugs.webkit.org/show_bug.cgi?id=226547 + * The only solution is to keep nudging it until it's awake. + */ + private maybeFixSafari; + /** */ + private static asPromise; +} +declare namespace Keyva { + /** */ + interface IConstructorOptions { + /** + * Defines the name of the IndexedDB database as it is stored in the browser. + * Note that the name is prefixed with the Keyva database prefix constant. + */ + name?: string | number; + /** + * Defines the name or names of the index or indexes to define on the database. + */ + indexes?: string | string[]; + } + /** */ + interface IQuery { + /** + * A standard IDBKeyRange to use for the query. Worth noting that the methods + * in the static Keyva.* namespace contain utility functions to ease the creation + * of IDBKeyRange objects. + */ + range?: IDBKeyRange; + /** The name of the index to use for the query. */ + index?: string; + /** A number which indicates the maximum number of objects to return from a query. */ + limit?: number; + } + /** */ + type Key = string | number | Date | BufferSource; +} diff --git a/apps-lib/src/lib/index.ts b/apps-lib/src/lib/index.ts @@ -1,4 +1,5 @@ export * from "./locales/i18n" +export { default as input_form } from "./components/input_form.svelte" export { default as tabs } from "./components/tabs.svelte" export { default as trellis } from "./components/trellis.svelte" export { default as trellis_default_label } from "./components/trellis_default_label.svelte" diff --git a/apps-lib/src/lib/stores/client.ts b/apps-lib/src/lib/stores/client.ts @@ -1,3 +1,7 @@ import { queryParameters } from "@radroots/sveltekit-search-params"; +import { writable } from "svelte/store"; export const app_qp = queryParameters(); + +export const kv = writable<Keyva>(); +if (typeof window !== 'undefined') kv.set(new Keyva({ name: 'app-kv' })); diff --git a/apps-lib/src/lib/stores/ndk.ts b/apps-lib/src/lib/stores/ndk.ts @@ -7,7 +7,7 @@ let cacheAdapter: NDKCacheAdapter | undefined; if (typeof window !== `undefined`) cacheAdapter = new NDKCacheAdapterDexie({ dbName: "-radroots-app-ndk" }); const _ndk = new NDKSvelte({ - //cacheAdapter, + cacheAdapter, clientName: "»--`--,---", }); diff --git a/apps-lib/src/lib/types/components.ts b/apps-lib/src/lib/types/components.ts @@ -1,4 +1,4 @@ -import type { CallbackPromiseGeneric } from "./client"; +import type { CallbackPromiseGeneric, IClOpt, ILy } from "./client"; import type { GlyphKey, GlyphWeight } from "./ui"; export type ITabsBasisList = { @@ -16,3 +16,19 @@ export type ITabsBasis = { app_layout: string; }; +export type IFormField = { + validate: RegExp; + charset: RegExp; + validateKeypress?: boolean; +}; + +export type IInputFormBasis = IClOpt & ILy & { + id: string; + placeholder?: string; + label?: string; + hidden?: boolean; + validate?: RegExp; + sync?: boolean; + field: IFormField +}; + diff --git a/apps-lib/src/lib/types/ui.ts b/apps-lib/src/lib/types/ui.ts @@ -2,6 +2,7 @@ import type { ThemeLayer } from "@radroots/theme"; import type { GeometryCardinalDirection, GeometryGlyphDimension, ICbOpt } from "./client"; export type GlyphKey = | + `handbag-simple` | `devices` | `lock-key` | `gear-fine` | diff --git a/apps-lib/src/lib/utils/client.ts b/apps-lib/src/lib/utils/client.ts @@ -63,4 +63,9 @@ export function parse_qp(param: string): NavigationRouteParamKey | undefined { export function time_now_ms(): number { return Math.floor(new Date().getTime() / 1000); +}; + +export const fmt_id = (id: string): string => { + const pref = location.pathname.slice(1, -1).replaceAll(`-`, `_`).replaceAll(`/`, `-`).replaceAll(`--`, `-`) + return `${pref}-${id}` }; \ No newline at end of file