Some drop down fixes (#10337)

Fixes #10185

Fixed two bugs from above issue: multiple arrows and being unable to change value from numeric input. The first was just lack of implementation; the second was caused by WidgetNumeric not handling its edit handler properly - the numeric input blur was finishing edit before click at entry could be interpreted.

# Important Notes
There is still one issue with drop-down filtering; will file a bug report soon.
This commit is contained in:
Adam Obuchowicz 2024-06-21 17:14:46 +02:00 committed by GitHub
parent 38d7fbb94d
commit bcbdda5f70
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 44 additions and 8 deletions

View File

@ -14,6 +14,10 @@
For example, `locale` parameter of `Equal_Ignore_Case` kind in join component.
- [Node previews][10310]: Node may be previewed by hovering output port while
pressing <kbd>Ctrl</kbd> key (<kbd>Cmd</kbd> on macOS).
- [Fixed issue with two arrows being visible at once in drop-down
widget.][10337]
- [Fixed issue where picking "<Numeric literal>" variant in some ports
disallowed changing it again.][10337]
[10064]: https://github.com/enso-org/enso/pull/10064
[10179]: https://github.com/enso-org/enso/pull/10179
@ -23,6 +27,7 @@
[10243]: https://github.com/enso-org/enso/pull/10243
[10297]: https://github.com/enso-org/enso/pull/10297
[10310]: https://github.com/enso-org/enso/pull/10310
[10337]: https://github.com/enso-org/enso/pull/10337
#### Enso Standard Library

View File

@ -3,6 +3,8 @@ import NumericInputWidget from '@/components/widgets/NumericInputWidget.vue'
import { Score, WidgetInput, defineWidget, widgetProps } from '@/providers/widgetRegistry'
import { WidgetEditHandler } from '@/providers/widgetRegistry/editHandler'
import { Ast } from '@/util/ast'
import { targetIsOutside } from '@/util/autoBlur'
import { unrefElement } from '@vueuse/core'
import { computed, ref, type ComponentInstance } from 'vue'
const props = defineProps(widgetProps(widgetDefinition))
@ -38,6 +40,10 @@ const limits = computed(() => {
const editHandler = WidgetEditHandler.New('WidgetNumber', props.input, {
cancel: () => inputComponent.value?.cancel(),
start: () => inputComponent.value?.focus(),
pointerdown(event) {
if (targetIsOutside(event, unrefElement(inputComponent))) editHandler.end()
return false
},
end: () => inputComponent.value?.blur(),
})
</script>
@ -78,7 +84,6 @@ export const widgetDefinition = defineWidget(
@update:modelValue="setValue"
@click.stop
@focus="editHandler.start()"
@blur="editHandler.end()"
@input="editHandler.edit($event)"
/>
</template>

View File

@ -4,8 +4,8 @@ import SizeTransition from '@/components/SizeTransition.vue'
import SvgIcon from '@/components/SvgIcon.vue'
import DropdownWidget, { type DropdownEntry } from '@/components/widgets/DropdownWidget.vue'
import { unrefElement } from '@/composables/events'
import { provideSelectionArrow } from '@/providers/selectionArrow.ts'
import { defineWidget, Score, WidgetInput, widgetProps } from '@/providers/widgetRegistry'
import { injectSelectionArrow, provideSelectionArrow } from '@/providers/selectionArrow.ts'
import { Score, WidgetInput, defineWidget, widgetProps } from '@/providers/widgetRegistry'
import {
multipleChoiceConfiguration,
singleChoiceConfiguration,
@ -27,7 +27,7 @@ import { arrayEquals } from '@/util/data/array'
import type { Opt } from '@/util/data/opt'
import { qnLastSegment, tryQualifiedName } from '@/util/qualifiedName'
import { autoUpdate, offset, shift, size, useFloating } from '@floating-ui/vue'
import { computed, proxyRefs, ref, type ComponentInstance, type RendererNode } from 'vue'
import { computed, proxyRefs, ref, watch, type ComponentInstance, type RendererNode } from 'vue'
const props = defineProps(widgetProps(widgetDefinition))
const suggestions = useSuggestionDbStore()
@ -221,6 +221,9 @@ const innerWidgetInput = computed<WidgetInput>(() => {
}
})
const parentSelectionArrow = injectSelectionArrow(true)
const arrowSuppressed = ref(false)
const showArrow = computed(() => isHovered.value && !arrowSuppressed.value)
provideSelectionArrow(
proxyRefs({
id: computed(() => {
@ -231,7 +234,11 @@ provideSelectionArrow(
if (node instanceof Ast.AutoscopedIdentifier) return node.identifier.id
if (node instanceof Ast.PropertyAccess) return node.rhs.id
if (node instanceof Ast.App) node = node.function
else break
else {
const wrapped = node.wrappedExpression()
if (wrapped != null) node = wrapped
else break
}
}
return null
}),
@ -239,9 +246,21 @@ provideSelectionArrow(
arrowLocation.value = target
},
handled: false,
get suppressArrow() {
return arrowSuppressed.value
},
set suppressArrow(value) {
arrowSuppressed.value = value
},
}),
)
watch(showArrow, (arrowShown) => {
if (parentSelectionArrow) {
parentSelectionArrow.suppressArrow = arrowShown
}
})
const isMulti = computed(() => props.input.dynamicConfig?.kind === 'Multiple_Choice')
const dropDownInteraction = WidgetEditHandler.New('WidgetSelection', props.input, {
cancel: () => {},
@ -399,9 +418,9 @@ declare module '@/providers/widgetRegistry' {
must be already in the DOM when the <Teleport> component is mounted.
So the Teleport itself can be instantiated only when `arrowLocation` is already available. -->
<Teleport v-if="arrowLocation" :to="arrowLocation">
<SvgIcon v-if="isHovered" name="arrow_right_head_only" class="arrow" />
<SvgIcon v-if="showArrow" name="arrow_right_head_only" class="arrow" />
</Teleport>
<SvgIcon v-else-if="isHovered" name="arrow_right_head_only" class="arrow" />
<SvgIcon v-else-if="showArrow" name="arrow_right_head_only" class="arrow" />
<Teleport v-if="tree.nodeElement" :to="tree.nodeElement">
<SizeTransition height :duration="100">
<DropdownWidget

View File

@ -2,7 +2,7 @@ import { createContextStore } from '@/providers'
import type { PortId } from '@/providers/portInfo.ts'
import type { AstId, TokenId } from '@/util/ast/abstract.ts'
import { identity } from '@vueuse/core'
import type { RendererElement } from 'vue'
import type { Ref, RendererElement } from 'vue'
interface SelectionArrowInfo {
/** Id of the subexpression that should display arrow underneath. */
@ -12,6 +12,13 @@ interface SelectionArrowInfo {
/** Whether or not the arrow provided by this context instance was already requested.
* Do not request the arrow twice, it will be stolen from other elements! */
handled: boolean
/**
* Child widget may set this flag to suppress arrow displaying.
*
* A usage example is a child suppressing arrow on hover, because interactions with this child
* will not open the drop-down (because the child is drop-down itself, for examle).
*/
suppressArrow: boolean
}
export { injectFn as injectSelectionArrow, provideFn as provideSelectionArrow }