aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--input/example.ts45
-rw-r--r--input/option.d.ts4
-rw-r--r--input/option.ts4
-rw-r--r--input/select.d.ts33
-rw-r--r--input/select.ts171
5 files changed, 254 insertions, 3 deletions
diff --git a/input/example.ts b/input/example.ts
index aa26d2d..f6a0647 100644
--- a/input/example.ts
+++ b/input/example.ts
@@ -1,5 +1,6 @@
import { WuiInputString, WuiInputStringOpts } from "./string.js"
import { WuiInputNumber, WuiInputNumberOpts } from "./number.js"
+import { WuiInputSelect, WuiInputSelectOpts } from "./select.js"
function exampleInputString() {
let el_example = document.createElement("div")
@@ -15,7 +16,7 @@ function exampleInputString() {
hint: "The input ID is 'my_input_string'",
onChangeHandler: (new_value: string) => {
console.log("input string new value: ", new_value)
- }
+ },
}
let el_input_string = new WuiInputString(opts)
el_example.appendChild(el_input_string.el)
@@ -27,7 +28,7 @@ function exampleInputString() {
hint: "The input string is disabled",
onChangeHandler: (new_value: string) => {
console.log("input string new value: ", new_value)
- }
+ },
}
el_input_string = new WuiInputString(opts)
el_example.appendChild(el_input_string.el)
@@ -37,7 +38,7 @@ function exampleInputString() {
value: "Hello, input string without hint",
onChangeHandler: (new_value: string) => {
console.log("input string without hint: new value: ", new_value)
- }
+ },
}
el_input_string = new WuiInputString(opts)
el_example.appendChild(el_input_string.el)
@@ -111,5 +112,43 @@ function exampleInputNumber() {
document.body.appendChild(el_example)
}
+function exampleInputSelect() {
+ let el_example = document.createElement("div")
+ document.body.appendChild(el_example)
+
+ let el_title = document.createElement("h3")
+ el_title.innerText = "Input select"
+ el_example.appendChild(el_title)
+
+ let el_log = document.createElement("div")
+
+ let opts: WuiInputSelectOpts = {
+ name: "my_fruit_price",
+ label: "Input select",
+ options: {
+ mango: {
+ value: "1000",
+ selected: false,
+ },
+ papaya: {
+ value: "200",
+ selected: false,
+ },
+ rambutan: {
+ value: "100",
+ selected: true,
+ },
+ },
+ hint: "Select on of the option to see the price.",
+ onChangeHandler: (key: string, value: string) => {
+ el_log.innerText = `The select input changes to '${key}' with price '${value}'`
+ },
+ }
+ let input = new WuiInputSelect(opts)
+ el_example.appendChild(input.el)
+ el_example.appendChild(el_log)
+}
+
exampleInputString()
exampleInputNumber()
+exampleInputSelect()
diff --git a/input/option.d.ts b/input/option.d.ts
new file mode 100644
index 0000000..ac723d2
--- /dev/null
+++ b/input/option.d.ts
@@ -0,0 +1,4 @@
+export interface WuiInputOption {
+ value: string;
+ selected: boolean;
+}
diff --git a/input/option.ts b/input/option.ts
new file mode 100644
index 0000000..b13af53
--- /dev/null
+++ b/input/option.ts
@@ -0,0 +1,4 @@
+export interface WuiInputOption {
+ value: string
+ selected: boolean
+}
diff --git a/input/select.d.ts b/input/select.d.ts
new file mode 100644
index 0000000..6a568f3
--- /dev/null
+++ b/input/select.d.ts
@@ -0,0 +1,33 @@
+import { WuiInputOption } from "./option.js";
+export interface WuiKeyValue {
+ [key: string]: string;
+}
+export interface WuiKeySelectOption {
+ [key: string]: WuiInputOption;
+}
+export interface WuiInputSelectOpts {
+ label: string;
+ name: string;
+ options: WuiKeySelectOption;
+ id?: string;
+ hint?: string;
+ is_disabled?: boolean;
+ onChangeHandler?: (key: string, value: string) => void;
+}
+export declare class WuiInputSelect {
+ opts: WuiInputSelectOpts;
+ el: HTMLElement;
+ private el_label;
+ private el_input;
+ private el_hint;
+ private el_hint_toggler;
+ private value_key;
+ private value;
+ constructor(opts: WuiInputSelectOpts);
+ private generateLabel;
+ private generateInput;
+ private generateHintToggler;
+ private generateHint;
+ private onClickHintToggler;
+ private onClickInput;
+}
diff --git a/input/select.ts b/input/select.ts
new file mode 100644
index 0000000..1989c06
--- /dev/null
+++ b/input/select.ts
@@ -0,0 +1,171 @@
+import { WuiInputOption } from "./option.js"
+
+export interface WuiKeyValue {
+ [key: string]: string
+}
+
+export interface WuiKeySelectOption {
+ [key: string]: WuiInputOption
+}
+
+export interface WuiInputSelectOpts {
+ label: string
+ name: string
+ options: WuiKeySelectOption
+ id?: string
+ hint?: string
+ is_disabled?: boolean
+ onChangeHandler?: (key: string, value: string) => void
+}
+
+const WUI_INPUT_SELECT_CLASS = "wui_input_select"
+const WUI_INPUT_SELECT_CLASS_HINT = "wui_input_select_hint"
+const WUI_INPUT_SELECT_CLASS_HINT_TOGGLER = "wui_input_select_hint_toggler"
+const WUI_INPUT_SELECT_CLASS_INPUT = "wui_input_select_input"
+const WUI_INPUT_SELECT_CLASS_LABEL = "wui_input_select_label"
+
+//
+// WuiInputSelect create an HTML input for selecting one more item.
+//
+// Format of generated HTML output,
+//
+// <div [id=${id}] class="${WUI_INPUT_SELECT_CLASS}">
+// <div>
+// <label class="${WUI_INPUT_SELECT_CLASS_LABEL}">${label}</label>
+// <select
+// name=${name}
+// class="${WUI_INPUT_SELECT_CLASS_INPUT}"
+// [disabled=${is_disabled}]
+// >
+// <option value="${options[key].value}">${key in options}</option>
+// </select>
+// [<span class="${WUI_INPUT_SELECT_CLASS_HINT_TOGGLER}">i </span>]
+// </div>
+// [<div class="${WUI_INPUT_SELECT_CLASS_HINT}">${hint}</div>]
+// </div>
+//
+// The "hint" option is optional, if it set the input will have a hint toggler
+// to display or hide the input information.
+//
+// User can set onChangeHandler to receive new value when the input value
+// changes.
+//
+export class WuiInputSelect {
+ el: HTMLElement
+ private el_label!: HTMLElement
+ private el_input!: HTMLSelectElement
+ private el_hint!: HTMLElement
+ private el_hint_toggler!: HTMLElement
+ private value_key: WuiKeyValue = {} // The reverse of options.options
+ private value: string = ""
+
+ constructor(public opts: WuiInputSelectOpts) {
+ this.el = document.createElement("div")
+ if (opts.id) {
+ this.el.id = opts.id
+ }
+ this.el.classList.add(WUI_INPUT_SELECT_CLASS)
+ this.el.style.padding = "2px"
+
+ let wrapper = document.createElement("div")
+ this.generateLabel(wrapper)
+ this.generateInput(wrapper)
+ if (opts.hint) {
+ this.generateHintToggler(wrapper)
+ }
+ this.el.appendChild(wrapper)
+
+ if (opts.hint) {
+ this.generateHint()
+ }
+ }
+
+ private generateLabel(wrapper: HTMLElement) {
+ this.el_label = document.createElement("label")
+ this.el_label.classList.add(WUI_INPUT_SELECT_CLASS_LABEL)
+ this.el_label.innerHTML = `${this.opts.label} `
+ wrapper.appendChild(this.el_label)
+ }
+
+ private generateInput(wrapper: HTMLElement) {
+ this.el_input = document.createElement("select")
+ this.el_input.name = this.opts.name
+ this.el_input.classList.add(WUI_INPUT_SELECT_CLASS_INPUT)
+
+ for (let key in this.opts.options) {
+ let option = this.opts.options[key]
+
+ let el_option = document.createElement("option")
+ el_option.value = option.value
+ el_option.innerHTML = key
+
+ if (option.selected) {
+ el_option.selected = true
+ }
+
+ this.el_input.appendChild(el_option)
+
+ this.value_key[option.value] = key
+ }
+
+ if (this.opts.is_disabled) {
+ this.el_input.disabled = true
+ }
+
+ if (this.opts.onChangeHandler) {
+ this.el_input.onclick = (ev: Event) => {
+ ev.preventDefault()
+ ev.stopPropagation()
+ this.onClickInput()
+ }
+ }
+
+ wrapper.appendChild(this.el_input)
+ }
+
+ private generateHintToggler(wrapper: HTMLElement) {
+ this.el_hint_toggler = document.createElement("span")
+ this.el_hint_toggler.classList.add(WUI_INPUT_SELECT_CLASS_HINT_TOGGLER)
+ this.el_hint_toggler.innerHTML = " &#x2139;"
+
+ this.el_hint_toggler.onmouseover = () => {
+ this.el_hint_toggler.style.cursor = "pointer"
+ }
+ this.el_hint_toggler.onclick = () => {
+ this.onClickHintToggler()
+ }
+ wrapper.appendChild(this.el_hint_toggler)
+ }
+
+ private generateHint() {
+ this.el_hint = document.createElement("div")
+ this.el_hint.classList.add(WUI_INPUT_SELECT_CLASS_HINT)
+ this.el_hint.innerHTML = this.opts.hint || ""
+ this.el_hint.style.display = "none"
+ this.el_hint.style.backgroundColor = "gainsboro"
+ this.el_hint.style.borderRadius = "2px"
+ this.el_hint.style.padding = "4px"
+ this.el.appendChild(this.el_hint)
+ }
+
+ private onClickHintToggler() {
+ if (this.el_hint.style.display === "none") {
+ this.el_hint.style.display = "block"
+ } else {
+ this.el_hint.style.display = "none"
+ }
+ }
+
+ private onClickInput() {
+ if (!this.opts.onChangeHandler) {
+ return false
+ }
+
+ let value = this.el_input.value
+ let key = this.value_key[value]
+ if (this.value !== value) {
+ this.opts.onChangeHandler(key, value)
+ this.value = value
+ }
+ }
+}