ixfx
Version:
Bundle of ixfx libraries
556 lines (555 loc) • 17.7 kB
TypeScript
import { t as PathDataChange } from "./pathed-7exI3RzP.js";
import { r as RecursivePartial } from "./ts-utility-01VlmgFR.js";
import { i as Interval } from "./types-1oz6G7XR.js";
import { S as HslScalar } from "./index-AowvMaOR.js";
import { Ft as ReactiveInitial, Lt as ReactiveNonInitial, Nt as ReactiveDiff, Wt as ReactiveWritable, jt as Reactive, vt as EventSourceOptions, wt as ObjectFieldHandler } from "./index-BBXM3hX6.js";
//#region ../packages/ui/src/rx/browser-resize.d.ts
/**
* Observe when element resizes. Specify `interval` to debounce, uses 100ms by default.
*
* ```
* const o = resizeObservable(myEl, 500);
* o.subscribe(() => {
* // called 500ms after last resize
* });
* ```
* @param elem
* @param interval Tiemout before event gets triggered
* @returns
*/
declare const browserResizeObservable: (elem: Readonly<Element>, interval?: Interval) => any;
/**
* Returns an Reactive for window resize. Default 100ms debounce.
* @param elapsed
* @returns
*/
declare const windowResize: (elapsed?: Interval) => any;
//#endregion
//#region ../packages/ui/src/rx/browser-theme-change.d.ts
/**
* Observe when a class changes on a target element, by default the document.
* Useful for tracking theme changes.
*
* ```js
* const c = cssClassChange();
* c.on(msg => {
* // some class has changed on the document
* });
* ```
*/
declare const cssClassChange: (target?: HTMLElement) => Reactive<MutationRecord[]>;
//#endregion
//#region ../packages/ui/src/rx/colour.d.ts
type ReactiveColour = ReactiveWritable<HslScalar> & {
setHsl: (hsl: HslScalar) => void;
};
declare function colour(initialValue: HslScalar): ReactiveColour & ReactiveInitial<HslScalar>;
declare function colour(): ReactiveColour & ReactiveNonInitial<HslScalar>;
//#endregion
//#region ../packages/ui/src/rx/dom-types.d.ts
type DomBindValueTarget = {
/**
* If _true_ `innerHTML` is set (a shortcut for elField:`innerHTML`)
*/
htmlContent?: boolean;
/**
* If _true_, 'textContent' is set (a shortcut for elField:'textContext')
*/
textContent?: boolean;
/**
* If set, this DOM element field is set. Eg 'textContent'
*/
elField?: string;
/**
* If set, this DOM attribute is set, Eg 'width'
*/
attribName?: string;
/**
* If set, this CSS variable is set, Eg 'hue' (sets '--hue')
*/
cssVariable?: string;
/**
* If set, this CSS property is set, Eg 'background-color'
*/
cssProperty?: string;
};
type ElementBind = {
/**
* Tag name for this binding.
* Overrides `defaultTag`
*/
tagName?: string;
/**
* If _true_, sub-paths are appended to element, rather than `container`
*/
nestChildren?: boolean;
transform?: (value: any) => string;
};
type ElementsOptions = {
container: HTMLElement | string;
defaultTag: string;
binds: Record<string, DomBindValueTarget & ElementBind>;
};
type DomBindTargetNode = {
query?: string;
element?: HTMLElement;
};
type DomBindTargetNodeResolved = {
element: HTMLElement;
};
type DomBindUnresolvedSource<TSource, TDestination> = DomBindTargetNode & DomBindSourceValue<TSource, TDestination> & DomBindValueTarget;
type DomBindResolvedSource<TSource, TDestination> = DomBindTargetNodeResolved & DomBindSourceValue<TSource, TDestination> & DomBindValueTarget;
type DomBindSourceValue<TSource, TDestination> = {
twoway?: boolean;
/**
* Field from source value to pluck and use.
* This will also be the value passed to the transform
*/
sourceField?: keyof TSource;
transform?: (input: TSource) => TDestination;
transformValue?: (input: any) => TDestination;
};
type DomBindInputOptions<TSource, TDestination> = DomBindSourceValue<TSource, TDestination> & {
transformFromInput: (input: TDestination) => TSource;
};
type BindUpdateOpts<V> = {
initial: (v: V, el: HTMLElement) => void;
binds: Record<string, DomBindValueTarget & {
transform?: (value: any) => string;
}>;
};
type DomCreateOptions = {
tagName: string;
parentEl: string | HTMLElement;
};
type PipeDomBinding = {
/**
* Remove binding and optionally delete element(s) (false by default)
*/
remove(deleteElements: boolean): void;
};
type DomValueOptions = EventSourceOptions & {
/**
* If true, the current value will be emitted even though it wasn't
* triggered by an event.
* Default: false
*/
emitInitialValue: boolean;
attributeName: string;
fieldName: string;
/**
* Respond to when value has changed or when value is changing
* Default: `changed`
*/
when: `changed` | `changing`;
fallbackValue: string;
upstreamSource?: Reactive<unknown>;
upstreamFilter?: (value: unknown) => string;
};
type DomFormOptions<T extends Record<string, unknown>> = EventSourceOptions & {
/**
* If true, the current value will be emitted even though it wasn't
* triggered by an event.
* Default: false
*/
emitInitialValue: boolean;
/**
* Respond to when value has changed or when value is changing
* Default: `changed`
*/
when: `changed` | `changing`;
upstreamSource?: Reactive<T>;
upstreamFilter?: (name: string, value: unknown) => string;
};
type DomNumberInputValueOptions = DomValueOptions & {
/**
* If true, sets up INPUT element to operate with relative values
*/
relative?: boolean;
/**
* If true, when setting up, sets max to be on left side
*/
inverted?: boolean;
upstreamSource?: Reactive<number>;
};
//#endregion
//#region ../packages/ui/src/rx/dom-source.d.ts
/**
* Reactive getting/setting of values to a HTML INPUT element.
*
* Options:
* - relative: if _true_, values are 0..1 (default: false)
* - inverted: if _true_, values are 1..0 (default: false)
*
* If element is missing a 'type' attribute, this will be set to 'range'.
* @param targetOrQuery
* @param options
* @returns
*/
declare function domNumberInputValue(targetOrQuery: HTMLInputElement | string, options?: Partial<DomNumberInputValueOptions>): ReactiveInitial<number> & ReactiveWritable<number>;
declare function domHslInputValue(targetOrQuery: HTMLInputElement | string, options?: Partial<DomValueOptions>): ReactiveInitial<HslScalar> & Reactive<HslScalar> & ReactiveWritable<HslScalar>;
/**
* A stream of values when the a HTMLInputElement changes. Eg a <input type="range">
* ```js
* const r = Rx.From.domInputValue(`#myEl`);
* r.onValue(value => {
* // value will be string
* });
* ```
*
* Options:
* * emitInitialValue: If _true_ emits the HTML value of element (default: false)
* * attributeName: If set, this is the HTML attribute value is set to when writing to stream (default: 'value')
* * fieldName: If set, this is the DOM object field set when writing to stream (default: 'value')
* * when: 'changed'|'changing' when values are emitted. (default: 'changed')
* * fallbackValue: Fallback value to use if field/attribute cannot be read (default: '')
* @param targetOrQuery
* @param options
* @returns
*/
declare function domInputValue(targetOrQuery: HTMLInputElement | string, options?: Partial<DomValueOptions>): {
el: HTMLInputElement;
} & ReactiveInitial<string> & ReactiveWritable<string>;
/**
* Listens for data changes from elements within a HTML form element.
* Input elements must have a 'name' attribute.
*
* Simple usage:
* ```js
* const rx = Rx.From.domForm(`#my-form`);
* rx.onValue(value => {
* // Object containing values from form
* });
*
* rx.last(); // Read current values of form
* ```
*
* UI can be updated
* ```js
* // Set using an object of key-value pairs
* rx.set({
* size: 'large'
* });
*
* // Or set a single name-value pair
* rx.setNamedValue(`size`, `large`);
* ```
*
* If an 'upstream' reactive is provided, this is used to set initial values of the UI, overriding
* whatever may be in the HTML. Upstream changes modify UI elements, but UI changes do not modify the upstream
* source.
*
* ```js
* // Create a reactive object
* const obj = Rx.From.object({
* when: `2024-10-03`,
* size: 12,
* checked: true
* });
*
* // Use this as initial values for a HTML form
* // (assuming appropriate INPUT/SELECT elements exist)
* const rx = Rx.From.domForm(`form`, {
* upstreamSource: obj
* });
*
* // Listen for changes in the UI
* rx.onValue(value => {
*
* });
* ```
* @param formElOrQuery
* @param options
* @returns
*/
declare function domForm<T extends Record<string, any>>(formElOrQuery: HTMLFormElement | string, options?: Partial<DomFormOptions<T>>): {
setNamedValue: (name: string, value: any) => void;
el: HTMLFormElement;
} & ReactiveInitial<T> & ReactiveWritable<T>;
//#endregion
//#region ../packages/ui/src/rx/dom.d.ts
/**
* Reactive stream of array of elements that match `query`.
* @param query
* @returns
*/
declare function fromDomQuery(query: string): Reactive<HTMLElement[]> & {
set(value: HTMLElement[]): void;
} & {
onField(fieldName: string, handler: (result: ObjectFieldHandler) => void): () => void;
onDiff(changes: (changes: PathDataChange<any>[]) => void): () => void;
update(changedPart: (RecursivePartial<HTMLElement> | undefined)[]): HTMLElement[];
updateField(field: string, value: any): void;
} & {
last(): HTMLElement[];
};
/**
* Updates an element's `textContent` when the source value changes.
* ```js
* bindText(source, `#blah`);
* ```
* @param elOrQuery
* @param source
* @param bindOpts
*/
declare const bindText: <TSource>(source: Reactive<TSource>, elOrQuery: string | HTMLElement | null, bindOpts?: Partial<DomBindSourceValue<TSource, string>>) => PipeDomBinding;
/**
* Updates an element's `value` (as well as the 'value' attribute) when the source value changes.s
* @param source
* @param elOrQuery
* @param bindOpts
* @returns
*/
declare const bindValueText: <TSource>(source: Reactive<TSource>, elOrQuery: string | HTMLInputElement | null, bindOpts?: Partial<DomBindSourceValue<TSource, string>>) => PipeDomBinding;
/**
* Updates an element's `innerHTML` when the source value changes
* ```js
* bindHtml(source, `#blah`);
* ```
*
* Uses {@link bindElement}, with `{elField:'innerHTML'}` as the options.
* @param elOrQuery
* @param source
* @param bindOpts
* @returns
*/
declare const bindHtml: <TSource>(source: Reactive<TSource>, elOrQuery: string | HTMLElement | null, bindOpts?: DomBindSourceValue<TSource, string>) => PipeDomBinding;
/**
* Shortcut to bind to an elements attribute
* @param elOrQuery
* @param source
* @param attribute
* @param bindOpts
* @returns
*/
/**
* Shortcut to bind to a CSS variable
* @param elOrQuery
* @param source
* @param cssVariable
* @param bindOpts
* @returns
*/
/**
* Creates a new HTML element, calling {@link bind} on it to update when `source` emits new values.
*
*
* ```js
* // Set textContent of a SPAN with values from `source`
* create(source, { tagName: `span`, parentEl: document.body })
* ```
*
* If `parentEl` is not given in the options, the created element needs to be manually added
* ```js
* const b = create(source);
* someEl.append(b.el); // Append manually
* ```
*
* ```
* // Set 'title' attribute based on values from `source`
* create(source, { parentEl: document.body, attribName: `title` })
* ```
* @param source
* @param options
* @returns
*/
/**
* Update a DOM element's field, attribute or CSS variable when `source` produces a value.
*
* ```js
* // Access via DOM query. Binds to 'textContent' by default
* bind(readableSource, `#someEl`);
*
* // Set innerHTML instead
* bind(readableSource, someEl, { elField: `innerHTML` });
*
* // An attribute
* bind(readableSource, someEl, { attribName: `width` });
*
* // A css variable ('--' optiona)
* bind(readableSource, someEl, { cssVariable: `hue` });
*
* // Pluck a particular field from source data.
* // Ie someEl.textContent = value.colour
* bind(readableSource, someEl, { sourceField: `colour` });
*
* // Transform value before setting it to field
* bind(readableSource, someEl, {
* field: `innerHTML`,
* transform: (v) => `Colour: ${v.colour}`
* })
* ```
*
* If `source` has an initial value, this is used when first bound.
*
* Returns {@link PipeDomBinding} to control binding:
* ```js
* const bind = bind(source, `#someEl`);
* bind.remove(); // Unbind
* bind.remove(true); // Unbind and remove HTML element
* ```
*
* If several fields need to be updated based on a new value, consider using {@link bindUpdate} instead.
* @param elOrQuery Element to update to, or query string such as '#someid'
* @param source Source of data
* @param binds Bindings
*/
declare const bindElement: <TSource, TDestination>(source: Reactive<TSource>, elOrQuery: string | HTMLElement | null, ...binds: (DomBindSourceValue<TSource, TDestination> & DomBindValueTarget)[]) => PipeDomBinding;
/**
* Binds `source` to one or more element(s). One or more bindings for the same source
* can be provided.
*
* ```js
* bind(source,
* // Binds .name field of source values to textContent of #some-element
* { query: `#some-element`, sourceField: `name` },
* { query: `section`, }
* );
* ```
*
* Can update
* * CSS variables
* * CSS styles
* * textContent / innerHTML
* * HTML DOM attributes and object fields
*
* Can use a particular field on source values, or use the whole value. These can
* pass through `transformValue` or `transform` respectively.
*
* Returns a function to unbind from source and optionally remove HTML element
* ```js
* const unbind = bind( . . . );
* unbind(); // Unbind
* unbind(true); // Unbind and remove HTML element(s)
* ```
* @param source
* @param bindsUnresolvedElements
* @returns
*/
declare const bind: <TSource, TDestination>(source: Reactive<TSource>, ...bindsUnresolvedElements: DomBindUnresolvedSource<TSource, TDestination>[]) => PipeDomBinding;
/**
* Calls `updater` whenever `source` produces a value. Useful when several fields from a value
* are needed to update an element.
* ```js
* bindUpdate(source, `#someEl`, (v, el) => {
* el.setAttribute(`width`, v.width);
* el.setAttribute(`height`, v.height);
* });
* ```
*
* Returns a {@link PipeDomBinding} to manage binding
* ```js
* const b = bindUpdate(...);
* b.remove(); // Disconnect binding
* b.remove(true); // Disconnect binding and remove element
* b.el; // HTML element
* ```
* @param elOrQuery
* @param source
* @param updater
* @returns
*/
declare const bindUpdate: <V>(source: Reactive<V>, elOrQuery: string | HTMLElement, updater: (v: V, el: HTMLElement) => void) => PipeDomBinding;
/**
* Updates a HTML element based on diffs on an object.
* ```js
* // Wrap an object
* const o = Rx.object({ name: `Jane`, ticks: 0 });
* const b = bindDiffUpdate(`#test`, o, (diffs, el) => {
* // el = reference to #test
* // diff = Array of Changes,
* // eg [ { path: `ticks`, value: 797, previous: 0 } ]
* for (const diff of diffs) {
* if (diff.path === `ticks`) el.textContent = `${diff.previous} -> ${diff.value}`
* }
* })
*
* // Eg. update field
* o.updateField(`ticks`, Math.floor(Math.random()*1000));
* ```
*
* If `initial` is provided as an option, this will be called if `source` has an initial value. Without this, the DOM won't be updated until the first data
* update happens.
* ```js
* bindDiffUpdate(el, source, updater, {
* initial: (v, el) => {
* el.innerHTML = v.name;
* }
* })
* ```
* @param elOrQuery
* @param source
* @param updater
* @param opts
* @returns
*/
declare const bindDiffUpdate: <V>(source: ReactiveDiff<V>, elOrQuery: string | HTMLElement | null, updater: (diffs: PathDataChange<any>[], el: HTMLElement) => void, opts?: Partial<BindUpdateOpts<V>>) => PipeDomBinding & {
refresh: () => void;
};
/**
* Creates a new HTML element and calls `bindUpdate` so values from `source` can be used
* to update it.
*
*
* ```js
* // Creates a span, adding it to <body>
* const b = createUpdate(dataSource, (value, el) => {
* el.width = value.width;
* el.height = value.height;
* }, {
* tagName: `SPAN`,
* parentEl: document.body
* })
* ```
* @param source
* @param updater
* @param options
* @returns
*/
/**
* Creates, updates & deletes elements based on pathed values from a reactive.
*
* This means that elements are only manipulated if its associated data changes,
* and elements are not modified if there's no need to.
* @param source
* @param options
*/
declare const elements: <T>(source: ReactiveDiff<T> | (ReactiveDiff<T> & ReactiveInitial<T>), options: Partial<ElementsOptions>) => void;
declare function win(): {
dispose: (reason?: string) => void;
size: Reactive<{
lazy: string;
transform: () => {
width: number;
height: number;
};
}> & {
last(): {
lazy: string;
transform: () => {
width: number;
height: number;
};
};
};
pointer: Reactive<{
lazy: string;
transform: (args: Event | undefined) => {
x: number;
y: number;
};
}> & {
last(): {
lazy: string;
transform: (args: Event | undefined) => {
x: number;
y: number;
};
};
};
};
declare namespace index_d_exports {
export { BindUpdateOpts, DomBindInputOptions, DomBindResolvedSource, DomBindSourceValue, DomBindTargetNode, DomBindTargetNodeResolved, DomBindUnresolvedSource, DomBindValueTarget, DomCreateOptions, DomFormOptions, DomNumberInputValueOptions, DomValueOptions, ElementBind, ElementsOptions, PipeDomBinding, ReactiveColour, bind, bindDiffUpdate, bindElement, bindHtml, bindText, bindUpdate, bindValueText, browserResizeObservable, colour, cssClassChange, domForm, domHslInputValue, domInputValue, domNumberInputValue, elements, fromDomQuery, win, windowResize };
}
//#endregion
export { index_d_exports as RxUi };