Skip to content

Commit

Permalink
feat(aspect-ratio): handle element resize
Browse files Browse the repository at this point in the history
  • Loading branch information
adenvt committed Nov 1, 2022
1 parent 3cd4107 commit 2ea0739
Show file tree
Hide file tree
Showing 17 changed files with 179 additions and 28 deletions.
2 changes: 1 addition & 1 deletion packages/tailwind-extended/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ module.exports = plugin(
'@supports not (aspect-ratio: 1/1)': {
'&::before': {
float : 'left',
paddingTop: `calc(100% * ${value})`,
paddingTop: `calc(100% / (${value}))`,
content : '""',
},
'&::after': {
Expand Down
4 changes: 4 additions & 0 deletions src/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,10 @@ export default defineConfig({
text : 'Directive',
collapsible: true,
items : [
{
text: 'Aspect Ratio',
link: '/components/aspect-ratio/',
},
{
text: 'Markdown',
link: '/components/markdown/',
Expand Down
2 changes: 1 addition & 1 deletion src/.vitepress/theme/components/Home.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
</div>
</div>

<div class="flex flex-col items-center justify-center gap-2 mt-10 md:flex-row">
<div class="flex flex-col items-center justify-center pt-10 space-gap-2 md:flex-row">
<Button
size="lg"
@click="gettingStarted">
Expand Down
84 changes: 84 additions & 0 deletions src/components/aspect-ratio/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<script setup>
import { vPAspectRatio } from '.'
</script>

# Aspect Ratio
> CSS Aspect-Ratio alternative using JS
## Usage

### Simple Usage

<preview class="items-start space-x-3">
<div
class="p-4 text-white w-28 bg-primary"
v-p-aspect-ratio="1 / 1">
1 / 1
</div>
<div
class="p-4 text-white w-28 bg-primary"
v-p-aspect-ratio="4 / 3">
4 / 3
</div>
<div
class="p-4 text-white w-28 bg-primary"
v-p-aspect-ratio="16 / 9">
16 / 9
</div>
</preview>

```vue
<template>
<div
class="p-4 text-white w-28 bg-primary"
v-p-aspect-ratio="1 / 1">
1 / 1
</div>
<div
class="p-4 text-white w-28 bg-primary"
v-p-aspect-ratio="4 / 3">
4 / 3
</div>
<div
class="p-4 text-white w-28 bg-primary"
v-p-aspect-ratio="16 / 9">
16 / 9
</div>
</template>
<script setup>
import { vPAspectRatio } from '@privyid/persona/directive'
</script>
```

## Fixed Size

Add modifier `.fixed` to enable fixed size, it's using style `height` instead of `min-height`

<preview class="space-x-3">
<div class="p-4 text-white w-28 bg-primary" v-p-aspect-ratio="1">
Lorem ipsum dolor sit amet, consectetur adipisicing elit.
</div>
<div class="p-4 text-white w-28 bg-primary" v-p-aspect-ratio.fixed="1">
Lorem ipsum dolor sit amet, consectetur adipisicing elit.
</div>
</preview>

```vue
<template>
<div class="p-4 text-white w-28 bg-primary" v-p-aspect-ratio="1">
Lorem ipsum dolor sit amet, consectetur adipisicing elit.
</div>
<div class="p-4 text-white w-28 bg-primary" v-p-aspect-ratio.fixed="1">
Lorem ipsum dolor sit amet, consectetur adipisicing elit.
</div>
</template>
```

## API

### Modifiers

| Modifiers | Description |
|-----------|--------------------|
| `fixed` | Enable fixed sized |
59 changes: 51 additions & 8 deletions src/components/aspect-ratio/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,54 @@
import { Directive } from 'vue-demi'

export const pAspectRatio: Directive<HTMLElement, number> = (el, { value, modifiers }) => {
const width = el.clientWidth
const height = width / value

if (modifiers.fixed)
el.style.height = `${height}px`
else
el.style.minHeight = `${height}px`
let observer: ResizeObserver

function getObserver () {
if (!observer) {
observer = new ResizeObserver((entries) => {
for (const entry of entries) {
const target = entry.target as HTMLElement
const ratio = Number.parseFloat(target.dataset.aspectRatio)
const fixed = target.dataset.aspectFixed === 'true'

calculateSize(target, ratio, fixed)
}
})
}

return observer
}

function calculateSize (el: HTMLElement, ratio: number, fixed = false): void {
if (Number.isFinite(ratio)) {
const width = el.clientWidth
const height = width / ratio

if (fixed)
el.style.height = `${height}px`
else
el.style.minHeight = `${height}px`
}
}

export const pAspectRatio: Directive<HTMLElement, number> = {
mounted (el, { value, modifiers }) {
el.dataset.aspectRatio = `${value}`
el.dataset.aspectFixed = modifiers.fixed ? 'true' : 'false'

calculateSize(el, value, modifiers.fixed)
getObserver().observe(el)
},

updated (el, { value, modifiers }) {
el.dataset.aspectRatio = `${value}`
el.dataset.aspectFixed = modifiers.fixed ? 'true' : 'false'

calculateSize(el, value, modifiers.fixed)
},

beforeUnmount (el) {
getObserver().unobserve(el)
},
}

export const vPAspectRatio = pAspectRatio
4 changes: 2 additions & 2 deletions src/components/calendar/Calendar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -245,10 +245,10 @@ export default defineComponent({

<style lang="postcss">
.calendar {
@apply p-2 md:p-4 bg-white flex flex-col gap-2 text-sm;
@apply p-2 md:p-4 bg-white flex flex-col space-y-2 text-sm;
&__nav {
@apply flex justify-between gap-2;
@apply flex justify-between space-x-2;
&-title {
@apply flex-grow;
Expand Down
12 changes: 6 additions & 6 deletions src/components/camera/Camera.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div
v-p-aspect-ratio="4/3"
v-p-aspect-ratio.fixed="4/3"
class="camera"
data-testid="camera"
:data-deviceid="deviceId"
Expand Down Expand Up @@ -373,7 +373,7 @@ export default defineComponent({
}
&__mask-container {
@apply absolute top-0 left-0 right-0 bottom-0 w-full h-full overflow-hidden pointer-events-none;
@apply absolute inset-0 w-full h-full overflow-hidden pointer-events-none;
}
&__mask {
Expand All @@ -384,20 +384,20 @@ export default defineComponent({
}
&--square & {
@apply aspect-compat-square w-1/2;
@apply aspect-compat-square w-[55%] md:w-1/2;
}
&--round & {
@apply aspect-compat-square rounded-full w-1/2;
@apply aspect-compat-square rounded-full w-[55%] md:w-1/2;
}
&--card & {
@apply aspect-compat-[85.60/53.98] w-2/3 rounded-md;
@apply aspect-compat-[85.60/53.98] w-3/4 rounded-md;
}
}
&__result {
@apply max-w-full h-auto;
@apply w-full h-full object-cover absolute inset-0;
}
&__off-info {
Expand Down
2 changes: 2 additions & 0 deletions src/components/camera/utils/take-picture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ export function takePicture (video: HTMLVideoElement, mirror = false): string {
canvas.height = video.videoHeight

if (mirror) {
context.save()
context.scale(-1, 1)
context.drawImage(video, 0, 0, canvas.width * -1, canvas.height)
context.restore()
} else
context.drawImage(video, 0, 0, canvas.width, canvas.height)

Expand Down
2 changes: 1 addition & 1 deletion src/components/contextual-bar/ContextualBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ import {
onMounted,
watch,
} from 'vue-demi'
import { AlignVariant } from '../nav/Nav.vue'
import { AlignVariant } from '../nav'
import { useVModel } from '../input'
import pCaption from '../caption/Caption.vue'
import pSubheading from '../subheading/Subheading.vue'
Expand Down
4 changes: 2 additions & 2 deletions src/components/cropper/Cropper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ export default defineComponent({
&__mask {
@apply pointer-events-none touch-none select-none;
@apply border border-white border-dashed box-border shadow-mask absolute top-0 left-0 right-0 bottom-0 m-auto max-w-[66.666667%];
@apply border border-white border-dashed box-border shadow-mask absolute inset-0 m-auto max-w-[66.666667%];
}
&__image {
Expand All @@ -451,7 +451,7 @@ export default defineComponent({
@apply touch-none h-auto origin-center object-contain select-none outline-none;
&-container {
@apply w-full h-full absolute top-0 left-0 bottom-0 right-0 flex items-center justify-center;
@apply w-full h-full absolute inset-0 flex items-center justify-center;
}
}
Expand Down
5 changes: 4 additions & 1 deletion src/components/label/Label.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@

<script lang="ts">
import {
defineComponent, PropType, computed, ref,
defineComponent,
PropType,
computed,
ref,
} from 'vue-demi'
import Dot from '../dot/Dot.vue'
import IconClose from '@carbon/icons-vue/lib/close/16'
Expand Down
2 changes: 1 addition & 1 deletion src/components/navbar-menu/NavbarNavMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export default defineComponent({
props : {
menus: {
type : Array as PropType<Menu[]>,
default: () => ([]),
default: () => ([] as Menu[]),
},
},
setup () {},
Expand Down
2 changes: 1 addition & 1 deletion src/components/navbar/Navbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
provide,
toRef,
} from 'vue-demi'
import { StyleVariant } from '../nav/Nav.vue'
import { StyleVariant } from '../nav'
import {
templateRef,
useElementBounding,
Expand Down
3 changes: 2 additions & 1 deletion src/components/navbar/NavbarNav.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
import {
defineComponent, inject, PropType,
} from 'vue-demi'
import Nav, { AlignVariant } from '../nav/Nav.vue'
import Nav from '../nav/Nav.vue'
import { AlignVariant } from '../nav'
import { NAVBAR_SETTINGS } from '.'
export default defineComponent({
Expand Down
9 changes: 7 additions & 2 deletions src/components/navbar/NavbarToggle.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@

<script lang="ts">
import {
defineComponent, inject, ref, computed,
defineComponent,
inject,
ref,
computed,
} from 'vue-demi'
import Button from '../button/Button.vue'
import IconMenu from '@carbon/icons-vue/lib/menu/20'
Expand All @@ -25,7 +28,9 @@ import { NAVBAR_SETTINGS } from '.'
export default defineComponent({
components: {
Button, IconMenu, IconClose,
Button,
IconMenu,
IconClose,
},
setup () {
const expand = ref(false)
Expand Down
6 changes: 5 additions & 1 deletion src/components/tabs/Tabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ import {
computed,
Slots,
} from 'vue-demi'
import Nav, { StyleVariant as TabsStyleVariant, AlignVariant as TabsAlignVariant } from '../nav/Nav.vue'
import Nav from '../nav/Nav.vue'
import {
StyleVariant as TabsStyleVariant,
AlignVariant as TabsAlignVariant,
} from '../nav'
import NavItem from '../nav/NavItem.vue'
import TabContent from './TabContent.vue'
import { useVModel } from '../input'
Expand Down
5 changes: 5 additions & 0 deletions src/directive/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,8 @@ export {
vPMd,
pMd,
} from '../components/markdown'

export {
vPAspectRatio,
pAspectRatio,
} from '../components/aspect-ratio'

0 comments on commit 2ea0739

Please sign in to comment.