mirror of
https://github.com/enso-org/enso.git
synced 2024-09-11 13:15:52 +03:00
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:
parent
38d7fbb94d
commit
bcbdda5f70
@ -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
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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 }
|
||||
|
Loading…
Reference in New Issue
Block a user