2022-03-04 03:39:48 +00:00
|
|
|
import Decimal from "util/bignum";
|
2022-05-11 00:39:39 +00:00
|
|
|
import { DoNotCache } from "util/computed";
|
2022-06-27 00:17:22 +00:00
|
|
|
import type { CSSProperties, DefineComponent } from "vue";
|
|
|
|
import { isRef } from "vue";
|
2022-01-14 04:25:47 +00:00
|
|
|
|
2022-05-11 01:04:08 +00:00
|
|
|
/**
|
|
|
|
* A symbol to use as a key for a vue component a feature can be rendered with
|
|
|
|
* @see {@link VueFeature}
|
|
|
|
*/
|
2022-01-14 04:25:47 +00:00
|
|
|
export const Component = Symbol("Component");
|
2022-05-11 01:04:08 +00:00
|
|
|
/**
|
|
|
|
* A symbol to use as a key for a prop gathering function that a feature can use to send to its component
|
|
|
|
* @see {@link VueFeature}
|
|
|
|
*/
|
2022-02-27 19:49:34 +00:00
|
|
|
export const GatherProps = Symbol("GatherProps");
|
2022-01-14 04:25:47 +00:00
|
|
|
|
2022-05-11 01:04:08 +00:00
|
|
|
/**
|
|
|
|
* A type referring to a function that returns JSX and is marked that it shouldn't be wrapped in a ComputedRef
|
|
|
|
* @see {@link jsx}
|
|
|
|
*/
|
2022-02-27 19:49:34 +00:00
|
|
|
export type JSXFunction = (() => JSX.Element) & { [DoNotCache]: true };
|
2022-05-11 01:04:08 +00:00
|
|
|
/**
|
|
|
|
* Any value that can be coerced into (or is) a vue component
|
|
|
|
*/
|
2022-02-27 19:49:34 +00:00
|
|
|
export type CoercableComponent = string | DefineComponent | JSXFunction;
|
2022-05-11 01:04:08 +00:00
|
|
|
/**
|
|
|
|
* Any value that can be passed into an HTML element's style attribute.
|
|
|
|
* Note that Profectus uses its own StyleValue and CSSProperties that are extended,
|
|
|
|
* in order to have additional properties added to them, such as variable CSS variables.
|
|
|
|
*/
|
2022-01-25 04:23:30 +00:00
|
|
|
export type StyleValue = string | CSSProperties | Array<string | CSSProperties>;
|
2022-01-14 04:25:47 +00:00
|
|
|
|
2022-05-11 01:04:08 +00:00
|
|
|
/** A type that refers to any vue component */
|
2022-01-14 04:25:47 +00:00
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
|
export type GenericComponent = DefineComponent<any, any, any>;
|
|
|
|
|
2022-05-11 01:04:08 +00:00
|
|
|
/** Utility type that is S, with any properties from T that aren't already present in S */
|
2022-01-14 04:25:47 +00:00
|
|
|
export type Replace<T, S> = S & Omit<T, keyof S>;
|
|
|
|
|
2022-05-11 01:04:08 +00:00
|
|
|
/**
|
|
|
|
* Utility function for a function that returns an object of a given type,
|
|
|
|
* with "this" bound to what the type will eventually be processed into.
|
|
|
|
* Intended for making lazily evaluated objects.
|
|
|
|
*/
|
2022-06-26 03:34:18 +00:00
|
|
|
export type OptionsFunc<T, R = Record<string, unknown>, S = R> = () => T & Partial<R> & ThisType<S>;
|
2022-04-11 00:04:56 +00:00
|
|
|
|
2022-01-14 04:25:47 +00:00
|
|
|
let id = 0;
|
2022-05-11 01:04:08 +00:00
|
|
|
/**
|
|
|
|
* Gets a unique ID to give to each feature, used for any sort of system that needs to identify
|
|
|
|
* elements in the DOM rather than references to the feature itself. (For example, branches)
|
|
|
|
* IDs are guaranteed unique, but _NOT_ persistent - they likely will change between updates.
|
|
|
|
* @param prefix A string to prepend to the id to make it more readable in the inspector tools
|
|
|
|
*/
|
2022-01-14 04:25:47 +00:00
|
|
|
export function getUniqueID(prefix = "feature-"): string {
|
|
|
|
return prefix + id++;
|
|
|
|
}
|
|
|
|
|
2022-05-11 01:04:08 +00:00
|
|
|
/** Enum for what the visibility of a feature or component should be */
|
2022-01-14 04:25:47 +00:00
|
|
|
export enum Visibility {
|
2022-05-11 01:04:08 +00:00
|
|
|
/** The feature or component should be visible */
|
2022-01-14 04:25:47 +00:00
|
|
|
Visible,
|
2022-05-11 01:04:08 +00:00
|
|
|
/** The feature or component should not appear but still take up space */
|
2022-01-14 04:25:47 +00:00
|
|
|
Hidden,
|
2022-05-11 01:04:08 +00:00
|
|
|
/** The feature or component should not appear not take up space */
|
2022-01-14 04:25:47 +00:00
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2022-05-11 01:04:08 +00:00
|
|
|
/**
|
|
|
|
* Takes a function and marks it as JSX so it won't get auto-wrapped into a ComputedRef.
|
|
|
|
* The function may also return empty string as empty JSX tags cause issues.
|
|
|
|
*/
|
2022-02-27 19:49:34 +00:00
|
|
|
export function jsx(func: () => JSX.Element | ""): JSXFunction {
|
|
|
|
(func as Partial<JSXFunction>)[DoNotCache] = true;
|
|
|
|
return func as JSXFunction;
|
|
|
|
}
|
|
|
|
|
2022-05-11 01:04:08 +00:00
|
|
|
/** Utility function to convert a boolean value into a Visbility value */
|
2022-01-14 04:25:47 +00:00
|
|
|
export function showIf(condition: boolean, otherwise = Visibility.None): Visibility {
|
|
|
|
return condition ? Visibility.Visible : otherwise;
|
|
|
|
}
|
|
|
|
|
2022-05-11 01:04:08 +00:00
|
|
|
/** Utility function to set a property on an object if and only if it doesn't already exist */
|
2022-01-14 04:25:47 +00:00
|
|
|
export function setDefault<T, K extends keyof T>(
|
|
|
|
object: T,
|
|
|
|
key: K,
|
|
|
|
value: T[K]
|
|
|
|
): asserts object is Exclude<T, K> & Required<Pick<T, K>> {
|
|
|
|
if (object[key] === undefined && value != undefined) {
|
|
|
|
object[key] = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-11 01:04:08 +00:00
|
|
|
/**
|
|
|
|
* Traverses an object and returns all features of the given type(s)
|
|
|
|
* @param obj The object to traverse
|
|
|
|
* @param types The feature types that will be searched for
|
|
|
|
*/
|
2022-05-11 00:08:16 +00:00
|
|
|
export function findFeatures(obj: Record<string, unknown>, ...types: symbol[]): unknown[] {
|
2022-01-14 04:25:47 +00:00
|
|
|
const objects: unknown[] = [];
|
|
|
|
const handleObject = (obj: Record<string, unknown>) => {
|
|
|
|
Object.keys(obj).forEach(key => {
|
|
|
|
const value = obj[key];
|
|
|
|
if (value && typeof value === "object") {
|
2022-05-11 00:08:16 +00:00
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
|
if (types.includes((value as Record<string, any>).type)) {
|
|
|
|
objects.push(value);
|
|
|
|
} else if (!(value instanceof Decimal) && !isRef(value)) {
|
|
|
|
handleObject(value as Record<string, unknown>);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
handleObject(obj);
|
|
|
|
return objects;
|
|
|
|
}
|
|
|
|
|
2022-05-11 01:04:08 +00:00
|
|
|
/**
|
|
|
|
* Traverses an object and returns all features that are _not_ any of the given types.
|
|
|
|
* Features are any object with a "type" property that has a symbol value.
|
|
|
|
* @param obj The object to traverse
|
|
|
|
* @param types The feature types that will be skipped over
|
|
|
|
*/
|
2022-05-11 00:08:16 +00:00
|
|
|
export function excludeFeatures(obj: Record<string, unknown>, ...types: symbol[]): unknown[] {
|
|
|
|
const objects: unknown[] = [];
|
|
|
|
const handleObject = (obj: Record<string, unknown>) => {
|
|
|
|
Object.keys(obj).forEach(key => {
|
|
|
|
const value = obj[key];
|
|
|
|
if (value && typeof value === "object") {
|
|
|
|
if (
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
|
typeof (value as Record<string, any>).type == "symbol" &&
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
|
!types.includes((value as Record<string, any>).type)
|
|
|
|
) {
|
2022-01-14 04:25:47 +00:00
|
|
|
objects.push(value);
|
2022-02-27 19:49:34 +00:00
|
|
|
} else if (!(value instanceof Decimal) && !isRef(value)) {
|
2022-01-14 04:25:47 +00:00
|
|
|
handleObject(value as Record<string, unknown>);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
handleObject(obj);
|
|
|
|
return objects;
|
|
|
|
}
|