Skip to content

Commit

Permalink
feat(ktoggle): adding ktoggle
Browse files Browse the repository at this point in the history
  • Loading branch information
adamdehaven committed Feb 5, 2022
1 parent d7d9f23 commit c202736
Show file tree
Hide file tree
Showing 6 changed files with 324 additions and 5 deletions.
1 change: 1 addition & 0 deletions docs/.vuepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export default defineUserConfig<DefaultThemeOptions, ViteBundlerOptions>({
text: 'Renderless',
children: [
'/components/renderless/komponent',
'/components/renderless/toggle',
]
}
]
Expand Down
8 changes: 4 additions & 4 deletions docs/components/icon.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,25 @@ The name of the icon. This required prop will only recognize icons from the
following list. It tells KIcon which svg to render.

<div>
<!-- <KToggle v-slot="{ isToggled, toggle }"> -->
<KToggle v-slot="{ isToggled, toggle }">
<div>
<KButton
appearance="outline"
class="mb-4"
@click="toggle">Toggle viewbox {{ isToggled ? 'off' : 'on' }}</KButton>
@click="toggle">Toggle viewbox {{ isToggled.value ? 'off' : 'on' }}</KButton>
<div class="icon-row">
<div
v-for="icon in $icons"
class="icon-cell"
:class="{ hasBg: isToggled }">
:class="{ hasBg: isToggled.value }">
<KIcon
size="24"
:icon="icon" />
<span>{{ icon }}</span>
</div>
</div>
</div>
<!-- </KToggle> -->
</KToggle>
</div>
&nbsp;

Expand Down
242 changes: 242 additions & 0 deletions docs/components/renderless/toggle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
# KToggle

Provide toggle functionality to components.

e.g.

- on / off
- enabled / disabled
- visible / not visible

<KCard>
<template v-slot:body>
<KToggle v-slot="{isToggled, toggle}">
<KButton @click="toggle">
{{ isToggled.value ? 'toggled' : 'not toggled' }}
</KButton>
</KToggle>
</template>
</KCard>

```vue
<KToggle v-slot="{isToggled, toggle}">
<KButton @click="toggle">
{{ isToggled.value ? 'toggled' : 'not toggled' }}
</KButton>
</KToggle>
```

## Props

### toggled

The toggled state that the component should begin with.

- Default: `false`

## Slots

- `default` - content to toggle.

### Slot Props

| Props | Type | Description |
| :---------- | :------- | :------------------------------ |
| `isToggled` | Ref(Boolean) | the component is toggled or not |
| `toggle` | Function | function to toggle! |

You can trigger the `toggle` function to switch the state in any way you'd like.
For instance, here we are toggling the state on `mouseover` and toggling back on
`mouseout`.

<KCard>
<template v-slot:body>
<KToggle :toggled="true" v-slot="{isToggled, toggle}">
<div
:style="{color: isToggled.value ? 'green' : 'red'}"
@mouseover="toggle"
@mouseout="toggle">
{{ isToggled.value ? 'yes' : 'no' }}
</div>
</KToggle>
</template>
</KCard>

```vue
<KToggle v-slot="{isToggled, toggle}" :toggled="true">
<div :style="{color: isToggled.value ? 'green' : 'red'}" @mouseover="toggle" @mouseout="toggle">
{{ isToggled.value ? 'yes' : 'no' }}
</div>
</KToggle>
```

## Events

| Event | returns |
| :-------- | :------------------ |
| `toggled` | `isToggled` Boolean |

<KCard>
<template v-slot:body>
<KToggle v-slot="{ toggle }" @toggled="sayHello">
<KButton @click="toggle">keep clicking me</KButton>
</KToggle>
</template>
</KCard>

```vue
<template>
<KToggle v-slot="{ toggle }" @toggled="sayHello">
<KButton @click="toggle">keep clicking me</KButton>
</KToggle>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
setup() {
const sayHello = (isToggled: boolean): void => {
alert('hello! the toggled is set to: ' + isToggled)
}
return { sayHello }
}
})
</script>
```

## Usage

KToggle is meant to be used to add behavior to other components, by wrapping
them and placing them inside `KToggle`'s default slot.

### KModal

<KCard class="mt-3">
<template v-slot:body>
<KToggle v-slot="{ isToggled, toggle }">
<div>
<KButton @click="toggle">
Show Modal
</KButton>
<KModal
:isVisible="isToggled.value"
title="Look Mah!"
content="I got toggles!"
@proceed="toggle"
@canceled="toggle" />
</div>
</KToggle>
</template>
</KCard>

```vue
<KToggle v-slot="{ isToggled, toggle }">
<div>
<KButton @click="toggle">
Show Modal
</KButton>
<KModal :isVisible="isToggled.value" title="Look Mah!" content="I got toggles!" @proceed="toggle" @canceled="toggle" />
</div>
</KToggle>
```

### Collapse/Expand

<KCard class="mt-2" style="min-height: 100px;">
<template v-slot:body>
<KToggle v-slot="{isToggled, toggle}">
<div>
<KButton @click="toggle">
{{ isToggled.value ? 'collapse' : 'expand' }}
</KButton>
<KAlert
v-if="isToggled.value"
class="mt-3"
alertMessage="Every day, once a day, give yourself a present." />
</div>
</KToggle>
</template>
</KCard>

```vue
<KToggle v-slot="{isToggled, toggle}">
<div>
<KButton @click="toggle">
{{ isToggled.value ? 'collapse' : 'expand' }}
</KButton>
<KAlert v-if="isToggled.value" class="mt-3" alertMessage="Every day, once a day, give yourself a present." />
</div>
</KToggle>
```

#### Toggle with Animation

<KCard class="mt-2" style="min-height: 100px;">
<template v-slot:body>
<KToggle v-slot="{isToggled, toggle}">
<div>
<KButton @click="toggle">
{{ isToggled.value ? 'collapse' : 'expand' }}
</KButton>
<transition name="expand">
<KAlert
v-if="isToggled.value"
class="mt-3"
alertMessage="Every day, once a day, give yourself a present." />
</transition>
</div>
</KToggle>
</template>
</KCard>

```vue
<KToggle v-slot="{isToggled, toggle}">
<div>
<KButton @click="toggle">
{{ isToggled.value ? 'collapse' : 'expand' }}
</KButton>
<transition name="expand">
<KAlert v-if="isToggled.value" class="mt-3" alertMessage="Every day, once a day, give yourself a present." />
</transition>
</div>
</KToggle>
```

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
setup() {
const sayHello = (isToggled: boolean): void => {
alert('hello! the toggled is set to: ' + isToggled)
}

return { sayHello }
}
})
</script>

<style>
.expand-enter-active {
transform-origin: top left;
animation: expand-in 0.5s;
}
.expand-leave-active {
animation: expand-in 0.5s;
animation-direction: reverse;
transform-origin: top left;
}

@keyframes expand-in {
0% {
transform: scaleY(0);
opacity: 0;
}
100% {
transform: scaleY(1);
opacity: 1;
}
}
</style>
27 changes: 27 additions & 0 deletions src/components/KToggle/KToggle.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { mount } from '@cypress/vue'
import KToggle from '@/components/KToggle'
import { h } from 'vue'

describe('KToggle', () => {
it('toggles content', () => {
mount(KToggle, {
slots: {
default: (props) => {
return h('button',
{
...props,
// bind emits onClick = @click, onUpdate = @update, etc.
onClick: () => props.toggle(),
}, 'click me ' + (props.isToggled.value ? 'yes' : 'no'),
)
},
},
})

const button = cy.get('button')

button.should('have.text', 'click me no')
button.click()
button.should('have.text', 'click me yes')
})
})
46 changes: 46 additions & 0 deletions src/components/KToggle/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { defineComponent, ref } from 'vue'

export default defineComponent({
name: 'KToggle',
props: {
toggled: {
type: Boolean,
default: false,
},
},
emits: ['toggled'],

setup(props, { slots, emit }) {
const isToggled = ref(props.toggled)

const toggle = (): void => {
isToggled.value = !isToggled.value

emit('toggled', isToggled.value)
}

try {
if (!slots.default) {
throw new Error('KToggle expects slot content')
}

return () => slots?.default && slots.default({
isToggled: isToggled,
toggle: toggle,
})
} catch (_) {
console.error(`KToggle expects to have slot content.
Example usage:
<KToggle>
<button v-slot:default="{isToggled, toggle}" @click="toggle">
{{ isToggled ? 'hello' : 'goodbye' }}
</button>
^^------add slotted content
</KToggle>
`)
return () => null
}
},
})
5 changes: 4 additions & 1 deletion src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
// Export all components
// NOTE: The 'create-kongponent' CLI automatically appends exports to the bottom of the list

// Renderless
export { default as Komponent } from './Komponent'
export { default as KToggle } from './KToggle'
// Regular Kongponents (ensure you import from '*.vue`)
export { default as KIcon } from './KIcon/KIcon.vue'
export { default as KButton } from './KButton/KButton.vue'
export { default as Komponent } from './Komponent'
export { default as KCard } from './KCard/KCard.vue'
export { default as KAlert } from './KAlert/KAlert.vue'

0 comments on commit c202736

Please sign in to comment.