Created
March 18, 2025 18:31
-
-
Save sirisian/ff534c72496fe40be8b874deffbe6aa2 to your computer and use it in GitHub Desktop.
input web component interface
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type Option<T> = { | |
label: string; | |
value: T; | |
} | |
type Options<T> = | |
| Record<string, T> | |
| Option<T>[] | |
| (() => Option<T>[]); | |
type Node = { | |
id: number; | |
type: number; | |
name: string; | |
}; | |
/** | |
* Inputs of type 'int', 'float', and 'string' can have tree pickers | |
* All options in this type propagate through the input to the tree picker | |
* This is like {@link OptionsInput.options} but for nested arrays more or less. | |
* Not going to comment all of this unless requested. | |
*/ | |
export type TreeOptions<T> = { | |
tree?: string; | |
source?: () => []; | |
fullSelect?: false; | |
checkbox?: boolean; | |
groupTypes?: () => number[]; | |
groupIcon?: (node: Node) => string; | |
leafIcon?: (node: Node) => string; | |
nodeTooltip?: (node: Node) => string; | |
disable?: () => boolean; | |
filter?: (() => boolean)[]; | |
dragAppendTo?: string | object; | |
deleteConfirmation?: () => boolean; | |
clickNode?: () => void; | |
dblClickNode?: () => void; | |
saveState?: boolean; | |
thumbnail?: boolean; | |
overrideThumbnailDimensions?: (node: Node) => { width: number, height: number }; | |
editable?: (node: Node) => boolean; | |
showRoot?: boolean; | |
defaultOptions?: []; | |
largeImages?: boolean; | |
filterDraggable?: (node: Node) => boolean; | |
filterDroppable?: (node: Node) => boolean; | |
dragHelper?: (e: any, dropClass: string) => Element | undefined; | |
showMinimizeMaximizeAll?: boolean; | |
showSmallLargeThumbnail?: boolean; | |
nameTransform?: (node: Node) => string; | |
dispatchChangeOnLoad?: boolean; | |
getValue?: () => T | T[]; | |
setValue?: () => void; | |
disableDrag?: boolean; | |
dispatchChangeOnUpDown?: boolean; | |
emptyValue?: boolean; | |
processNode?: (node: Node) => void; | |
setText?: (node: Node) => void; | |
} | |
type InputDefaultPart<T> = { | |
/** | |
* Default value for the input | |
*/ | |
default?: T; | |
/** | |
* Value to use when opening picker in indeterminate state | |
*/ | |
defaultOnOpen?: T; | |
} | |
/** | |
* {@link InputDefaults.multiple} will make the type T[] | |
* {@link InputDefaults.emptyValue} will make the type T | null | |
* {@link undefinedToIndeterminate} will make the type T | undefined | |
* This results in 8 possible configurations | |
*/ | |
type InputDefaults<T> = | |
| ( | |
& InputDefaultPart<T> | |
& { | |
/** Enable multiple value selection, transforms value into an array | |
* @default false | |
*/ | |
multiple?: false; | |
/** Text to display when value is null. If set, enables null values | |
* @default false | |
*/ | |
emptyValue?: false; | |
/** Controls whether undefined values set the input to an indeterminate state | |
* @default true | |
*/ | |
undefinedToIndeterminate: false; | |
} | |
) | |
| ( | |
& { | |
multiple?: false; | |
emptyValue?: false; | |
undefinedToIndeterminate?: true; | |
} | |
& InputDefaultPart<T | undefined> | |
) | |
| ( | |
& { | |
multiple?: false; | |
emptyValue: string; | |
undefinedToIndeterminate: false; | |
} | |
& InputDefaultPart<T | null> | |
) | |
| ( | |
& { | |
multiple?: false; | |
emptyValue: string; | |
undefinedToIndeterminate?: true; | |
} | |
& InputDefaultPart<T | null | undefined> | |
) | |
| ( | |
& { | |
multiple: true; | |
emptyValue?: false; | |
undefinedToIndeterminate: false; | |
} | |
& InputDefaultPart<T[]> | |
) | |
| ( | |
& { | |
multiple: true; | |
emptyValue?: false; | |
undefinedToIndeterminate?: true; | |
} | |
& InputDefaultPart<T[] | undefined> | |
) | |
| ( | |
& { | |
multiple: true; | |
emptyValue: string; | |
undefinedToIndeterminate: false; | |
} | |
& InputDefaultPart<T[] | null> | |
) | |
| ( | |
& { | |
multiple: true; | |
emptyValue: string; | |
undefinedToIndeterminate?: true; | |
} | |
& InputDefaultPart<T[] | null | undefined> | |
); | |
type InputOptions<T> = { | |
/** | |
* Attaches a picker with options. One of: | |
* - Record: An enumeration. Use enumLabels symbol to map labels | |
* - Array: An explicit array of options | |
* - Function: A function to call to get an array of options. See {@link refreshOnShow} to load new options on picker open | |
*/ | |
options?: Options<T>; | |
/** | |
* Enables custom inputs when {@link options} is set | |
*/ | |
customValue?: boolean; | |
/** | |
* Allows a custom rendering for each option. e.g. to render font family options as their font family | |
*/ | |
processOption?: ( | |
$option: Element, | |
option: { | |
label: string; | |
value: T; | |
} | |
) => void; | |
/** | |
* By default the {@link options} function is evaluated once. Set this to true to reload when the picker is opened | |
*/ | |
refreshOnShow?: boolean; | |
/** | |
* {@link options} are displayed as radio buttons | |
* {@link multiple} cannot be set at the same time. See {@link groupedButton} for that | |
*/ | |
radio?: boolean; | |
/** | |
* {@link options} are displayed as grouped buttons. e.g. [A|B|C] | |
* multiple makes the buttons toggleable | |
*/ | |
groupedButton?: boolean; | |
/** | |
* {@link options} are displayed in a list rather than a picker | |
*/ | |
inlinePicker?: boolean; | |
/** | |
* The minimum height in option items. If {@link multiple} is enabled and size is not 0 then the picker is displayed as if {@link inlinePicker} is set | |
*/ | |
size?: number; | |
/** | |
* If true then this records the last 10 entered values. Use a number for a custom history amount | |
*/ | |
history?: boolean | number; | |
/** | |
* localStorage key used to hold the {@link history} values. Can be used to share histories between inputs of the same {@link type} | |
*/ | |
historyKey?: string; | |
/** | |
* Enables autocomplete for {@link options} and {@link history} | |
*/ | |
search?: boolean; | |
} | |
type InputProgress = { | |
/** | |
* Turns this into a progress bar | |
*/ | |
progress?: boolean; | |
/** | |
* If progress is set, this customizes the color | |
*/ | |
progressColor?: string; | |
} | |
type InputMasked = { | |
/** | |
* Enables masked input mode | |
*/ | |
masked?: boolean; | |
/** | |
* Used in masked inputs for up key | |
*/ | |
increment?: () => void; | |
/** | |
* Used in masked inputs for down key | |
*/ | |
decrement?: () => void; | |
} | |
type InputDisplay = { | |
/** | |
* When not focused this can transform the value into a custom string. On focus it will show the value | |
* As an example if you want to display a value as '100%' | |
*/ | |
display?: () => string; | |
} | |
/** | |
* An input for storing a boolean | |
*/ | |
export type BooleanInput = | |
& { | |
type: 'boolean'; | |
} | |
& InputDefaults<boolean>; | |
/** | |
* An input for storing an integer. Disallows decimals | |
*/ | |
export type IntInput = | |
& { | |
type: 'int'; | |
/** | |
* Turns this into a slider input | |
*/ | |
slider?: boolean; | |
/** | |
* Minimum inclusive value | |
*/ | |
min?: number; | |
/** | |
* Maximum inclusive value | |
*/ | |
max?: number; | |
/** | |
* The step size when incrementing/decrementing | |
*/ | |
step?: number; | |
} | |
& InputDefaults<number> | |
& InputOptions<number> | |
& InputProgress | |
& InputMasked | |
& InputDisplay | |
& TreeOptions<number>; | |
/** | |
* An input for storing a number. Allow decimals | |
*/ | |
export type FloatInput = | |
& { | |
type: 'number'; | |
/** | |
* Turns this into a slider input | |
*/ | |
slider?: boolean; | |
/** | |
* Minimum inclusive value | |
*/ | |
min?: number; | |
/** | |
* Maximum inclusive value | |
*/ | |
max?: number; | |
/** | |
* The step size when incrementing/decrementing | |
*/ | |
step?: number; | |
} | |
& InputDefaults<number> | |
& InputOptions<number> | |
& InputProgress | |
& InputMasked | |
& InputDisplay | |
& TreeOptions<number>; | |
/** | |
* An input for storing a string | |
*/ | |
export type StringInput = | |
& { | |
type: 'string'; | |
/** | |
* A placeholder when equal to clearValue | |
*/ | |
placeholder?: string; | |
/** | |
* Creates a pseudo textarea control | |
*/ | |
multiline?: boolean; | |
/** | |
* Controls the height when multiline is used. lines === 0 creates a picker, lines >= 1 is resizable, default is lines === 1 | |
*/ | |
lines?: number; | |
/** | |
* Turns this into a password input | |
*/ | |
password?: boolean; | |
/** | |
* Enables spellcheck | |
*/ | |
spellcheck?: boolean; | |
/** | |
* The value must match this pattern to validate | |
*/ | |
pattern?: RegExp | string; | |
} | |
& InputDefaults<string> | |
& InputOptions<string> | |
& InputMasked | |
& InputDisplay | |
& TreeOptions<string>; | |
/** | |
* This is a container for constructing custom objects | |
* Implement {@link getValue} and {@link setValue} | |
*/ | |
export type ObjectInput = { | |
type: 'object'; | |
default?: Object; | |
/** | |
* Called when the input value is accessed | |
*/ | |
getValue: () => Object; | |
/** | |
* Called when the input value is set. Use this to update the input rendering | |
*/ | |
setValue: (value: Object) => void; | |
}; | |
/** | |
* This is a container for constructing custom arrays | |
* Implement {@link getValue} and {@link setValue} | |
*/ | |
export type ArrayInput = { | |
type: 'array'; | |
default?: []; | |
/** | |
* Called when the input value is accessed | |
*/ | |
getValue: () => []; | |
/** | |
* Called when the input value is set. Use this to update the input rendering | |
*/ | |
setValue: (value: []) => void; | |
}; | |
export type ColorInput = InputDefaults<string> | { | |
type: 'color'; | |
/** | |
* Enables opacity | |
*/ | |
opacity?: boolean; | |
/** | |
* A custom set of colors that user can pick. This is similar to options in other input types | |
*/ | |
palette?: string[]; | |
/** | |
* Only shows palette colors listed in palette | |
*/ | |
showPaletteOnly?: boolean; | |
/** | |
* Renders in a compact width form that only displays the color, not the text value | |
*/ | |
compact?: boolean; | |
/** | |
* If true then this records the last 10 entered values. Use a number for a custom history amount | |
*/ | |
history?: boolean | number; | |
/** | |
* localStorage key used to hold the history values. Can be used to share histories between inputs | |
*/ | |
historyKey?: string; | |
/** | |
* Create a palette option for transparent | |
*/ | |
transparentButton?: boolean; | |
/** | |
* Called as the user previews colors by either selecting a color or by hovering over a palette color | |
* This uses a 100 ms bounce | |
*/ | |
previewChange?: () => void; | |
}; | |
export type FileInput = { | |
type: 'file'; | |
/** | |
* Allow multiple files to be selected | |
*/ | |
multiple?: boolean; | |
/** | |
* | |
*/ | |
fileType?: string; | |
} | |
export type CustomInput = InputDefaults<unknown> | { | |
type: 'custom'; | |
}; | |
/** | |
* WIP | |
*/ | |
export type FontInput = { | |
propertyContainer: string; | |
type: string; | |
/** | |
* Enables font family selector | |
*/ | |
fontFamily?: boolean; | |
/** | |
* Enables font size selector | |
*/ | |
fontSize?: boolean; | |
/** | |
* The minimum font size | |
* default: 1 | |
*/ | |
fontSizeMin?: number; | |
/** | |
* The maximum font size | |
* default: 300 | |
*/ | |
fontSizeMax?: number; | |
/** | |
* Enables font style selector | |
*/ | |
fontStyle?: boolean; | |
/** | |
* Enables font weight selector | |
*/ | |
fontWeight?: boolean; | |
/** | |
* Enables font color selector | |
*/ | |
fontColor?: boolean; | |
/** | |
* Enables font decorator selector | |
*/ | |
fontDecoration?: boolean; | |
} | |
/** | |
* value: Temporal.PlainDate | |
*/ | |
export type DateInput = | |
& { | |
type: 'date'; | |
/** | |
* The inclusive minimum date | |
*/ | |
min?: string; | |
/** | |
* The inclusive minimum date | |
*/ | |
max?: string; | |
} | |
& InputDefaults<Temporal.PlainDate> | |
/** | |
* value: Temporal.PlainTime | |
*/ | |
export type TimeInput = | |
& { | |
type: 'time'; | |
/** | |
* The inclusive minimum time | |
*/ | |
min?: string; | |
/** | |
* The inclusive maximum time | |
*/ | |
max?: string; | |
} | |
& InputDefaults<Temporal.PlainTime> | |
/** | |
* value: Temporal.PlainDateTime | |
*/ | |
export type DateTimeInput = | |
& { | |
type: 'datetime'; | |
/** | |
* The inclusive minimum datetime | |
*/ | |
min?: string; | |
/** | |
* The inclusive maximum datetime | |
*/ | |
max?: string; | |
} | |
& InputDefaults<Temporal.PlainDateTime> | |
export type GeneralInput = { | |
/** | |
* Hides the input | |
*/ | |
hidden?: boolean; | |
/** | |
* Renders in a readonly state that allows selection | |
*/ | |
readonly?: boolean; | |
/** | |
* Renders in a disabled state, disabling selection | |
*/ | |
disabled?: boolean; | |
/** | |
* Whether this will trigger form validation when equal to clearValue | |
*/ | |
required?: boolean; | |
/** | |
* Whether to show a clear value button. The clear displays if not equal to the default | |
*/ | |
clearValue?: boolean; | |
/** | |
* Hides the clear button | |
*/ | |
hideClearValue?: boolean; | |
/** | |
* Requires the user to double-click to begin editing | |
*/ | |
doubleClickToEdit?: boolean; | |
/** | |
* Convert input to change events | |
*/ | |
inputToChange?: boolean; | |
/** | |
* Sets the input to display: contents so the input can use the parent layout | |
*/ | |
displayContents?: boolean; | |
/** | |
* Default position for the picker relative to the input | |
*/ | |
pickerAnchor?: 'left' | 'right' | 'bottom' | 'top'; | |
/** | |
* By default the picker is anchored to the input, but it can be anchored to any element | |
*/ | |
pickerAnchorElement?: Element; | |
/** | |
* Emits 'dblclick' and 'tripleclick' events blocking single click events for both previous events | |
*/ | |
tripleClick?: boolean; | |
/** | |
* Tooltip | |
*/ | |
tooltip?: string; | |
} | |
export type Input = GeneralInput | |
& ( | |
| BooleanInput | |
| IntInput | |
| FloatInput | |
| StringInput | |
| ObjectInput | |
| ArrayInput | |
| ColorInput | |
| FileInput | |
| DateInput | |
| TimeInput | |
| DateTimeInput | |
); | |
export type Property = { | |
label: string; | |
property: string; | |
} & Input; | |
const input1: Input = { type: 'string', password: true, placeholder: 'Password' }; // Config for a basic password input | |
const input2: Input = { type: 'int', min: 0, max: 100 }; // 'int' just makes value accessors an integer which will automatically parse using parseInt(n, 10) | |
const input3: Input = { type: 'int', default: 0 }; | |
const input4: Input = { // select with two options | |
type: 'number', | |
options: [ | |
{ label: 'Option 1', value: 1 }, | |
{ label: 'Option 2', value: 2 } | |
] | |
}; | |
const input5: Input = { | |
type: 'string', | |
options: [ | |
{ label: 'Landscape', value: 'landscape' }, | |
{ label: 'Portrait', value: 'portrait' } | |
], | |
radio: true // Displays the options in a radio input | |
}; | |
const input6: Input = { type: 'date', min: '2024-01-01' }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment