diff --git a/py/examples/textbox.py b/py/examples/textbox.py
index 39c29bdee3..1a51bcbe0d 100644
--- a/py/examples/textbox.py
+++ b/py/examples/textbox.py
@@ -22,6 +22,8 @@ async def serve(q: Q):
ui.text(f'textbox_disabled_placeholder={q.args.textbox_disabled_placeholder}'),
ui.text(f'textbox_multiline={q.args.textbox_multiline}'),
ui.text(f'textbox_spellcheck_disabled={q.args.textbox_spellcheck_disabled}'),
+ ui.text(f'textbox_numeric={q.args.textbox_numeric}'),
+ ui.text(f'textbox_tel={q.args.textbox_tel}'),
ui.button(name='show_form', label='Back', primary=True),
]
else:
@@ -40,6 +42,8 @@ async def serve(q: Q):
placeholder='I am disabled'),
ui.textbox(name='textbox_multiline', label='Multiline textarea', multiline=True),
ui.textbox(name='textbox_spellcheck_disabled', label='Spellcheck disabled', spellcheck=False),
+ ui.textbox(name='textbox_numeric', label='With numeric keyboard (iOS, Android)', type='number'),
+ ui.textbox(name='textbox_tel', label='With telephone keyboard (iOS, Android)', type='tel'),
ui.button(name='show_inputs', label='Submit', primary=True),
])
await q.page.save()
diff --git a/py/h2o_lightwave/h2o_lightwave/types.py b/py/h2o_lightwave/h2o_lightwave/types.py
index c7dc22ce29..80f892cd71 100644
--- a/py/h2o_lightwave/h2o_lightwave/types.py
+++ b/py/h2o_lightwave/h2o_lightwave/types.py
@@ -969,6 +969,15 @@ def load(__d: Dict) -> 'MessageBar':
)
+_TextboxType = ['text', 'number', 'tel']
+
+
+class TextboxType:
+ TEXT = 'text'
+ NUMBER = 'number'
+ TEL = 'tel'
+
+
class Textbox:
"""Create a text box.
@@ -998,6 +1007,7 @@ def __init__(
visible: Optional[bool] = None,
tooltip: Optional[str] = None,
spellcheck: Optional[bool] = None,
+ type: Optional[str] = None,
):
_guard_scalar('Textbox.name', name, (str,), True, False, False)
_guard_scalar('Textbox.label', label, (str,), False, True, False)
@@ -1019,6 +1029,7 @@ def __init__(
_guard_scalar('Textbox.visible', visible, (bool,), False, True, False)
_guard_scalar('Textbox.tooltip', tooltip, (str,), False, True, False)
_guard_scalar('Textbox.spellcheck', spellcheck, (bool,), False, True, False)
+ _guard_enum('Textbox.type', type, _TextboxType, True)
self.name = name
"""An identifying name for this component."""
self.label = label
@@ -1059,6 +1070,8 @@ def __init__(
"""An optional tooltip message displayed when a user clicks the help icon to the right of the component."""
self.spellcheck = spellcheck
"""True if the text may be checked for spelling errors. Defaults to True."""
+ self.type = type
+ """Keyboard to be shown on mobile devices. Defaults to 'text'. One of 'text', 'number', 'tel'. See enum h2o_wave.ui.TextboxType."""
def dump(self) -> Dict:
"""Returns the contents of this object as a dict."""
@@ -1082,6 +1095,7 @@ def dump(self) -> Dict:
_guard_scalar('Textbox.visible', self.visible, (bool,), False, True, False)
_guard_scalar('Textbox.tooltip', self.tooltip, (str,), False, True, False)
_guard_scalar('Textbox.spellcheck', self.spellcheck, (bool,), False, True, False)
+ _guard_enum('Textbox.type', self.type, _TextboxType, True)
return _dump(
name=self.name,
label=self.label,
@@ -1103,6 +1117,7 @@ def dump(self) -> Dict:
visible=self.visible,
tooltip=self.tooltip,
spellcheck=self.spellcheck,
+ type=self.type,
)
@staticmethod
@@ -1148,6 +1163,8 @@ def load(__d: Dict) -> 'Textbox':
_guard_scalar('Textbox.tooltip', __d_tooltip, (str,), False, True, False)
__d_spellcheck: Any = __d.get('spellcheck')
_guard_scalar('Textbox.spellcheck', __d_spellcheck, (bool,), False, True, False)
+ __d_type: Any = __d.get('type')
+ _guard_enum('Textbox.type', __d_type, _TextboxType, True)
name: str = __d_name
label: Optional[str] = __d_label
placeholder: Optional[str] = __d_placeholder
@@ -1168,6 +1185,7 @@ def load(__d: Dict) -> 'Textbox':
visible: Optional[bool] = __d_visible
tooltip: Optional[str] = __d_tooltip
spellcheck: Optional[bool] = __d_spellcheck
+ type: Optional[str] = __d_type
return Textbox(
name,
label,
@@ -1189,6 +1207,7 @@ def load(__d: Dict) -> 'Textbox':
visible,
tooltip,
spellcheck,
+ type,
)
diff --git a/py/h2o_lightwave/h2o_lightwave/ui.py b/py/h2o_lightwave/h2o_lightwave/ui.py
index 89bafb8628..13c88404c2 100644
--- a/py/h2o_lightwave/h2o_lightwave/ui.py
+++ b/py/h2o_lightwave/h2o_lightwave/ui.py
@@ -398,6 +398,7 @@ def textbox(
visible: Optional[bool] = None,
tooltip: Optional[str] = None,
spellcheck: Optional[bool] = None,
+ type: Optional[str] = None,
) -> Component:
"""Create a text box.
@@ -426,6 +427,7 @@ def textbox(
visible: True if the component should be visible. Defaults to True.
tooltip: An optional tooltip message displayed when a user clicks the help icon to the right of the component.
spellcheck: True if the text may be checked for spelling errors. Defaults to True.
+ type: Keyboard to be shown on mobile devices. Defaults to 'text'. One of 'text', 'number', 'tel'. See enum h2o_wave.ui.TextboxType.
Returns:
A `h2o_wave.types.Textbox` instance.
"""
@@ -450,6 +452,7 @@ def textbox(
visible,
tooltip,
spellcheck,
+ type,
))
diff --git a/py/h2o_wave/h2o_wave/types.py b/py/h2o_wave/h2o_wave/types.py
index c7dc22ce29..80f892cd71 100644
--- a/py/h2o_wave/h2o_wave/types.py
+++ b/py/h2o_wave/h2o_wave/types.py
@@ -969,6 +969,15 @@ def load(__d: Dict) -> 'MessageBar':
)
+_TextboxType = ['text', 'number', 'tel']
+
+
+class TextboxType:
+ TEXT = 'text'
+ NUMBER = 'number'
+ TEL = 'tel'
+
+
class Textbox:
"""Create a text box.
@@ -998,6 +1007,7 @@ def __init__(
visible: Optional[bool] = None,
tooltip: Optional[str] = None,
spellcheck: Optional[bool] = None,
+ type: Optional[str] = None,
):
_guard_scalar('Textbox.name', name, (str,), True, False, False)
_guard_scalar('Textbox.label', label, (str,), False, True, False)
@@ -1019,6 +1029,7 @@ def __init__(
_guard_scalar('Textbox.visible', visible, (bool,), False, True, False)
_guard_scalar('Textbox.tooltip', tooltip, (str,), False, True, False)
_guard_scalar('Textbox.spellcheck', spellcheck, (bool,), False, True, False)
+ _guard_enum('Textbox.type', type, _TextboxType, True)
self.name = name
"""An identifying name for this component."""
self.label = label
@@ -1059,6 +1070,8 @@ def __init__(
"""An optional tooltip message displayed when a user clicks the help icon to the right of the component."""
self.spellcheck = spellcheck
"""True if the text may be checked for spelling errors. Defaults to True."""
+ self.type = type
+ """Keyboard to be shown on mobile devices. Defaults to 'text'. One of 'text', 'number', 'tel'. See enum h2o_wave.ui.TextboxType."""
def dump(self) -> Dict:
"""Returns the contents of this object as a dict."""
@@ -1082,6 +1095,7 @@ def dump(self) -> Dict:
_guard_scalar('Textbox.visible', self.visible, (bool,), False, True, False)
_guard_scalar('Textbox.tooltip', self.tooltip, (str,), False, True, False)
_guard_scalar('Textbox.spellcheck', self.spellcheck, (bool,), False, True, False)
+ _guard_enum('Textbox.type', self.type, _TextboxType, True)
return _dump(
name=self.name,
label=self.label,
@@ -1103,6 +1117,7 @@ def dump(self) -> Dict:
visible=self.visible,
tooltip=self.tooltip,
spellcheck=self.spellcheck,
+ type=self.type,
)
@staticmethod
@@ -1148,6 +1163,8 @@ def load(__d: Dict) -> 'Textbox':
_guard_scalar('Textbox.tooltip', __d_tooltip, (str,), False, True, False)
__d_spellcheck: Any = __d.get('spellcheck')
_guard_scalar('Textbox.spellcheck', __d_spellcheck, (bool,), False, True, False)
+ __d_type: Any = __d.get('type')
+ _guard_enum('Textbox.type', __d_type, _TextboxType, True)
name: str = __d_name
label: Optional[str] = __d_label
placeholder: Optional[str] = __d_placeholder
@@ -1168,6 +1185,7 @@ def load(__d: Dict) -> 'Textbox':
visible: Optional[bool] = __d_visible
tooltip: Optional[str] = __d_tooltip
spellcheck: Optional[bool] = __d_spellcheck
+ type: Optional[str] = __d_type
return Textbox(
name,
label,
@@ -1189,6 +1207,7 @@ def load(__d: Dict) -> 'Textbox':
visible,
tooltip,
spellcheck,
+ type,
)
diff --git a/py/h2o_wave/h2o_wave/ui.py b/py/h2o_wave/h2o_wave/ui.py
index 89bafb8628..13c88404c2 100644
--- a/py/h2o_wave/h2o_wave/ui.py
+++ b/py/h2o_wave/h2o_wave/ui.py
@@ -398,6 +398,7 @@ def textbox(
visible: Optional[bool] = None,
tooltip: Optional[str] = None,
spellcheck: Optional[bool] = None,
+ type: Optional[str] = None,
) -> Component:
"""Create a text box.
@@ -426,6 +427,7 @@ def textbox(
visible: True if the component should be visible. Defaults to True.
tooltip: An optional tooltip message displayed when a user clicks the help icon to the right of the component.
spellcheck: True if the text may be checked for spelling errors. Defaults to True.
+ type: Keyboard to be shown on mobile devices. Defaults to 'text'. One of 'text', 'number', 'tel'. See enum h2o_wave.ui.TextboxType.
Returns:
A `h2o_wave.types.Textbox` instance.
"""
@@ -450,6 +452,7 @@ def textbox(
visible,
tooltip,
spellcheck,
+ type,
))
diff --git a/r/R/ui.R b/r/R/ui.R
index d3ae9aa868..a5f9a1e518 100644
--- a/r/R/ui.R
+++ b/r/R/ui.R
@@ -485,6 +485,8 @@ ui_message_bar <- function(
#' @param visible True if the component should be visible. Defaults to True.
#' @param tooltip An optional tooltip message displayed when a user clicks the help icon to the right of the component.
#' @param spellcheck True if the text may be checked for spelling errors. Defaults to True.
+#' @param type Keyboard to be shown on mobile devices. Defaults to 'text'.
+#' One of 'text', 'number', 'tel'. See enum h2o_wave.ui.TextboxType.
#' @return A Textbox instance.
#' @export
ui_textbox <- function(
@@ -507,7 +509,8 @@ ui_textbox <- function(
width = NULL,
visible = NULL,
tooltip = NULL,
- spellcheck = NULL) {
+ spellcheck = NULL,
+ type = NULL) {
.guard_scalar("name", "character", name)
.guard_scalar("label", "character", label)
.guard_scalar("placeholder", "character", placeholder)
@@ -528,6 +531,7 @@ ui_textbox <- function(
.guard_scalar("visible", "logical", visible)
.guard_scalar("tooltip", "character", tooltip)
.guard_scalar("spellcheck", "logical", spellcheck)
+ # TODO Validate type
.o <- list(textbox=list(
name=name,
label=label,
@@ -548,7 +552,8 @@ ui_textbox <- function(
width=width,
visible=visible,
tooltip=tooltip,
- spellcheck=spellcheck))
+ spellcheck=spellcheck,
+ type=type))
class(.o) <- append(class(.o), c(.wave_obj, "WaveComponent"))
return(.o)
}
diff --git a/tools/intellij-plugin/src/main/resources/templates/wave-components.xml b/tools/intellij-plugin/src/main/resources/templates/wave-components.xml
index 149e668f93..cbd7a92848 100644
--- a/tools/intellij-plugin/src/main/resources/templates/wave-components.xml
+++ b/tools/intellij-plugin/src/main/resources/templates/wave-components.xml
@@ -2620,7 +2620,7 @@
-
+
@@ -2641,6 +2641,7 @@
+
diff --git a/tools/vscode-extension/component-snippets.json b/tools/vscode-extension/component-snippets.json
index 2e60ea8139..0d868dbd38 100644
--- a/tools/vscode-extension/component-snippets.json
+++ b/tools/vscode-extension/component-snippets.json
@@ -1906,7 +1906,7 @@
"Wave Full Textbox": {
"prefix": "w_full_textbox",
"body": [
- "ui.textbox(name='$1', label='$2', placeholder='$3', value='$4', mask='$5', icon='$6', prefix='$7', suffix='$8', error='$9', required=${10:False}, disabled=${11:False}, readonly=${12:False}, multiline=${13:False}, password=${14:False}, trigger=${15:False}, height='$16', width='${17:100%}', visible=${18:True}, tooltip='$19', spellcheck=${20:True}),$0"
+ "ui.textbox(name='$1', label='$2', placeholder='$3', value='$4', mask='$5', icon='$6', prefix='$7', suffix='$8', error='$9', required=${10:False}, disabled=${11:False}, readonly=${12:False}, multiline=${13:False}, password=${14:False}, trigger=${15:False}, height='$16', width='${17:100%}', visible=${18:True}, tooltip='$19', spellcheck=${20:True}, type='${21:text}'),$0"
],
"description": "Create a full Wave Textbox."
},
diff --git a/ui/src/textbox.tsx b/ui/src/textbox.tsx
index bd270aaae5..259e5adc02 100644
--- a/ui/src/textbox.tsx
+++ b/ui/src/textbox.tsx
@@ -65,6 +65,8 @@ export interface Textbox {
tooltip?: S
/** True if the text may be checked for spelling errors. Defaults to True. */
spellcheck?: B
+ /** Keyboard to be shown on mobile devices. Defaults to 'text'. */
+ type?: 'text' | 'number' | 'tel'
}
const DEBOUNCE_TIMEOUT = 500
@@ -96,7 +98,7 @@ export const
suffix: m.suffix,
multiline: m.multiline,
spellCheck: m.spellcheck,
- type: m.password ? 'password' : undefined,
+ type: m.password ? 'password' : (m.type || 'text'),
}
React.useEffect(() => {
diff --git a/website/widgets/form/textbox.md b/website/widgets/form/textbox.md
index 68cca3a668..29c3e841b4 100644
--- a/website/widgets/form/textbox.md
+++ b/website/widgets/form/textbox.md
@@ -137,3 +137,28 @@ q.page['example'] = ui.form_card(
value="I have spellcheck disabld", spellcheck=False)]
)
```
+
+## Mobile keyboard layout
+
+Show proper keyboard layout on mobile devices with `type` attribute. Defaults to `text`.
+This does not prevent user from typing any character.
+
+```py
+q.page['example'] = ui.form_card(
+ box='1 1 2 2',
+ items=[
+ ui.textbox(
+ name='textbox_keyboard_numeric',
+ label='With numeric keyboard (iOS, Android)',
+ # Show numeric keyboard
+ type='number'
+ ),
+ ui.textbox(
+ name='textbox_keyboard_telephone',
+ label='With numeric keyboard (iOS, Android)',
+ # Show telephone keyboard
+ type='tel'
+ )
+ ]
+)
+```