Skip to content

Commit

Permalink
Support empty and non-numeric default values in number picker (#10251)
Browse files Browse the repository at this point in the history
Numeric default (unchanged):
<img width="400" alt="Screenshot 2024-06-11 at 10 19 21" src="https://github.com/enso-org/enso/assets/1047859/24549125-f7bd-4017-b04f-b9e8715203b1">

Non-numeric default:

https://github.com/enso-org/enso/assets/1047859/bfe812e2-4d1c-477b-9500-f384fa499890

No default:
<img width="400" alt="Screenshot 2024-06-11 at 10 19 36" src="https://github.com/enso-org/enso/assets/1047859/e99dcb0f-f146-4005-b4e5-79223fbe7744">

Closes #9449.
  • Loading branch information
kazcw authored Jun 13, 2024
1 parent b053ab5 commit 904ffe1
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 29 deletions.
31 changes: 20 additions & 11 deletions app/gui2/src/components/GraphEditor/widgets/WidgetNumber.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,25 @@ import { computed, ref, type ComponentInstance } from 'vue'
const props = defineProps(widgetProps(widgetDefinition))
const inputComponent = ref<ComponentInstance<typeof NumericInputWidget>>()
const value = computed({
get() {
const valueStr = WidgetInput.valueRepr(props.input)
return valueStr ? parseFloat(valueStr) : 0
},
set(value) {
props.onUpdate({
portUpdate: { value: value.toString(), origin: props.input.portId },
})
},
function setValue(value: number | string) {
props.onUpdate({
portUpdate: { value: value.toString(), origin: props.input.portId },
})
}
const value = computed<number | undefined>(() => {
const inputValue = WidgetInput.valueRepr(props.input)
if (inputValue == null) return undefined
const inputNumber = parseFloat(inputValue)
if (Number.isNaN(inputNumber)) return undefined
return inputNumber
})
const placeholder = computed<string | undefined>(() =>
value.value == null ? WidgetInput.valueRepr(props.input) : undefined,
)
const limits = computed(() => {
const config = props.input.dynamicConfig
if (config?.kind === 'Numeric_Input' && config?.minimum != null && config?.maximum != null) {
Expand Down Expand Up @@ -64,9 +71,11 @@ export const widgetDefinition = defineWidget(
<template>
<NumericInputWidget
ref="inputComponent"
v-model="value"
class="WidgetNumber r-24"
:limits="limits"
:placeholder="placeholder"
:modelValue="value"
@update:modelValue="setValue"
@click.stop
@focus="editHandler.start()"
@blur="editHandler.end()"
Expand Down
16 changes: 11 additions & 5 deletions app/gui2/src/components/widgets/AutoSizedInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import { getTextWidthByFont } from '@/util/measurement'
import { computed, ref, watch, type StyleValue } from 'vue'
const [model, modifiers] = defineModel<string>()
const props = defineProps<{ autoSelect?: boolean }>()
const props = defineProps<{
autoSelect?: boolean
placeholder?: string | undefined
}>()
const emit = defineEmits<{
input: [value: string | undefined]
change: [value: string | undefined]
Expand Down Expand Up @@ -35,7 +38,9 @@ const cssFont = computed(() => {
const ADDED_WIDTH_PX = 2
const getTextWidth = (text: string) => getTextWidthByFont(text, cssFont.value)
const inputWidth = computed(() => getTextWidth(`${innerModel.value}`) + ADDED_WIDTH_PX)
const inputWidth = computed(
() => getTextWidth(innerModel.value || (props.placeholder ?? '')) + ADDED_WIDTH_PX,
)
const inputStyle = computed<StyleValue>(() => ({ width: `${inputWidth.value}px` }))
function onEnterDown() {
Expand All @@ -59,7 +64,8 @@ defineExpose({
<input
ref="inputNode"
v-model="innerModel"
class="AutoSizedInput"
class="AutoSizedInput input"
:placeholder="placeholder ?? ''"
:style="inputStyle"
@pointerdown.stop
@click.stop
Expand Down Expand Up @@ -93,8 +99,8 @@ defineExpose({
}
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
.input::-webkit-outer-spin-button,
.input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
Expand Down
26 changes: 13 additions & 13 deletions app/gui2/src/components/widgets/NumericInputWidget.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { computed, ref, watch, type CSSProperties, type ComponentInstance } from
import AutoSizedInput from './AutoSizedInput.vue'
const props = defineProps<{
modelValue: number | string
modelValue: number | undefined
placeholder?: string | undefined
limits?: { min: number; max: number } | undefined
}>()
const emit = defineEmits<{
Expand All @@ -14,16 +15,15 @@ const emit = defineEmits<{
input: [content: string]
}>()
const inputFieldActive = ref(false)
// Edited value reflects the `modelValue`, but does not update it until the user defocuses the field.
const editedValue = ref(`${props.modelValue}`)
watch(
() => props.modelValue,
(newValue) => {
editedValue.value = `${newValue}`
},
)
const DEFAULT_PLACEHOLDER = ''
const SLIDER_INPUT_THRESHOLD = 4.0
const MIN_CONTENT_WIDTH = 56
// Edited value reflects the `modelValue`, but does not update it until the user defocuses the field.
const editedValue = ref('')
const valueString = computed(() => (props.modelValue != null ? props.modelValue.toString() : ''))
watch(valueString, (newValue) => (editedValue.value = newValue), { immediate: true })
const inputFieldActive = ref(false)
let dragState: { thresholdMet: boolean } | undefined = undefined
const dragPointer = usePointer(
Expand Down Expand Up @@ -68,7 +68,6 @@ const sliderWidth = computed(() => {
})
const inputComponent = ref<ComponentInstance<typeof AutoSizedInput>>()
const MIN_CONTENT_WIDTH = 56
const inputStyle = computed<CSSProperties>(() => {
const value = `${editedValue.value}`
Expand All @@ -92,7 +91,7 @@ const inputStyle = computed<CSSProperties>(() => {
})
function emitUpdate() {
if (`${props.modelValue}` !== editedValue.value) {
if (valueString.value !== editedValue.value) {
emit('update:modelValue', editedValue.value)
}
}
Expand All @@ -110,7 +109,7 @@ function focused() {
defineExpose({
cancel: () => {
editedValue.value = `${props.modelValue}`
editedValue.value = valueString.value
inputComponent.value?.blur()
},
blur: () => inputComponent.value?.blur(),
Expand All @@ -126,6 +125,7 @@ defineExpose({
class="NumericInputWidget"
:class="{ slider: sliderWidth != null }"
:style="{ ...inputStyle, '--slider-width': sliderWidth }"
:placeholder="placeholder ?? DEFAULT_PLACEHOLDER"
v-on="dragPointer.events"
@click.stop
@blur="blurred"
Expand Down

0 comments on commit 904ffe1

Please sign in to comment.