Skip to content

Commit

Permalink
fixes combobox bug
Browse files Browse the repository at this point in the history
2 clicks were needed to show the combobox
  • Loading branch information
ChristianKienle committed Jan 12, 2019
1 parent 8280a50 commit bd4e533
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 43 deletions.
54 changes: 31 additions & 23 deletions src/components/Combobox/Combobox.tsx
Expand Up @@ -43,7 +43,6 @@ export class Combobox extends mixins(UidMixin) {

public togglePopoverVisible() {
this.currentPopoverVisible = !this.currentPopoverVisible;
this.$emit('update:currentPopoverVisible', this.currentPopoverVisible);
}

private setCurrentValue(newValue: string | number | null) {
Expand Down Expand Up @@ -73,29 +72,38 @@ export class Combobox extends mixins(UidMixin) {
on-click={this.handleMenuItemClick}
noArrow={true}
popoverVisible={this.currentPopoverVisible}
on-visible={(visible: boolean) => this.currentPopoverVisible = visible }
{...
{
scopedSlots: {
control: (scope: { toggle: () => (void) }) => {
return (<div staticClass='fd-combobox-control'>
<InputGroup
compact={this.compact}
afterClass='fd-input-group__addon--button'
>
<Input
id={this.uid}
value={this.value}
compact={this.compact}
nativeOn-click={scope.toggle}
nativeOn-keyup={this.handleKeyup}
on-input={this.setCurrentValue}
placeholder={this.placeholder}
/>
<Button
slot='after'
on-click={scope.toggle}
icon='navigation-down-arrow'
styling='light'
/>
</InputGroup></div>
);
},
},
}
}
>
<div class='fd-combobox-control' slot='control'>
<InputGroup
compact={this.compact}
afterClass='fd-input-group__addon--button'
>
<Input
id={this.uid}
value={this.value}
compact={this.compact}
nativeOn-click={() => this.currentPopoverVisible = true}
nativeOn-keyup={this.handleKeyup}
on-input={this.setCurrentValue}
placeholder={this.placeholder}
/>
<Button
slot='after'
on-click={this.togglePopoverVisible}
icon='navigation-down-arrow'
styling='light'
/>
</InputGroup>
</div>
{dropdown}
</Popover>
</div>
Expand Down
61 changes: 48 additions & 13 deletions src/components/Popover/Popover.tsx
Expand Up @@ -62,9 +62,55 @@ export class Popover extends mixins(UidMixin) {

private popoverTriggerControl: Element | null = null;

// There are three different ways a trigger control can be rendered.
// 1. $slots.control:
// If there is a slot called 'control' we simply render that and assume that
// the control rendered emits 'click'-events.
// 2. $scopedSlots.control:
// If there is a scoped slot 'control' we assume that the popover consumer
// has some kind of special needs. Thus, when rendering the scoped slot,
// we pass a little bit of context to the consumer. Shape of the scope/context
// passed to the consumer:
// {
// // Calling this will toggle the popover.
// toggle: () => (void);
// // whether the popover is currently visible.
// visible: bool;
// }
// Because of the fact that we assume that the consumer has special needs,
// we do not show the popover automatically. The consumer has to call `toggle`
// for example by binding it to @click/@click.native of some kind of control
// or by using v-model.
// 3. If there is no (scoped) control-slot we simply render a standard button
// on behalf of the consumer.
private renderTriggerControl() {
const control = this.$slots.control;
if(control != null) {
return <div on-click={this.toggle} role='button'>{control}</div>;
}
const renderControl = this.$scopedSlots.control;
if(renderControl != null) {
const context = {
toggle: this.toggle,
visible: this.currentPopoverVisible,
};
return renderControl(context);
}
return (
<Button
staticClass='fd-popover__control'
aria-controls={this.uid}
aria-expanded={this.currentPopoverVisible}
aria-haspopup='true'
on-click={this.toggle}
>
{this.title}
</Button>
);
}

public render() {
const dropdown = this.$slots.default || [];
const triggerControl = this.$slots.control;
const ignoredElementsHandler = () => {
const el = this.popoverTriggerControl;
if(el == null) { return []; }
Expand All @@ -74,18 +120,7 @@ export class Popover extends mixins(UidMixin) {
return (
<div class='fd-popover'>
<div class='fd-popover__control' ref={(el: Element) => this.popoverTriggerControl = el}>
{triggerControl && <div role='button' on-click={this.toggle}>{triggerControl}</div>}
{!triggerControl &&
<Button
class='fd-popover__control'
aria-controls={this.uid}
aria-expanded={this.currentPopoverVisible}
aria-haspopup='true'
on-click={this.toggle}
>
{this.title}
</Button>
}
{this.renderTriggerControl()}
</div>

<ClickAwayContainer
Expand Down
47 changes: 40 additions & 7 deletions src/docs/pages/Popover/2-custom-trigger.vue
@@ -1,14 +1,47 @@
<title>Popover with custom Trigger</title>
<tip>If you have special needs simply use `slot-scope`. This gives you access to the `toggle`-function and the current `visibility`. The second button is using this in order to customize the trigger event and styling.</tip>
<docs>
**Implementation Details**

There are three different ways a trigger control can be rendered.

1. `$slots.control`: If there is a slot called `control` we simply render that. This control should emit `click`-events.
2. `$scopedSlots.control`: If there is a scoped slot `control` we assume that the popover consumer (**you**) has some kind of special needs. Thus, when rendering the scoped slot, we pass a little bit of context to the consumer.

**The context looks like this:**:

```javascript
{
// Calling this will toggle the popover.
toggle: () => (void);
// whether the popover is currently visible.
visible: boolean;
}
```

Because of the fact that we assume that the consumer has special needs, we do not show the popover automatically. The consumer has to call `toggle` for example by binding it to `@click`/`@click.native` of some kind of control or by using `v-model`.

3. If there is no (scoped) control-slot we simply render a standard button on behalf of the consumer.
</docs>
<template><div>
<FdPopover>
<FdButton styling="emphasized" type="positive" slot="control">Custom Popover Trigger Control (automatic popover visibility)</FdButton>
<FdMenuItem>Option 1</FdMenuItem>
<FdMenuItem>Option 2</FdMenuItem>
<FdMenuItem>Option 3</FdMenuItem>
</FdPopover>

<br /><br />

<template>
<!-- div is needed: otherwise the popover will not be positioned correctly -->
<div>
<FdPopover>
<FdButton styling="emphasized" type="positive" slot="control">Custom Popover Trigger Control</FdButton>
<FdButton
slot-scope="popover"
slot="control"
:type="popover.visible ? 'negative' : 'warning'"
@click="popover.toggle"
>Custom Popover Trigger Control (manual popover visibility)</FdButton>
<FdMenuItem>Option 1</FdMenuItem>
<FdMenuItem>Option 2</FdMenuItem>
<FdMenuItem>Option 3</FdMenuItem>
<FdMenuItem>Option 4</FdMenuItem>
</FdPopover>
</div>
</template>
</div></template>

0 comments on commit bd4e533

Please sign in to comment.