monkeeShark/packages/frontend/src/components/global/MkSpacer.vue

108 lines
2.4 KiB
Vue
Raw Normal View History

2021-10-14 11:55:59 +00:00
<template>
<div ref="root" :class="$style.root" :style="{ padding: margin + 'px' }">
<div ref="content" :class="$style.content">
<slot></slot>
</div>
</div>
</template>
2022-06-22 07:29:31 +00:00
<script lang="ts" setup>
import { inject, onMounted, onUnmounted, ref } from 'vue';
2022-02-11 13:16:20 +00:00
import { deviceKind } from '@/scripts/device-kind';
2021-10-14 11:55:59 +00:00
2022-06-22 07:29:31 +00:00
const props = withDefaults(defineProps<{
contentMax?: number | null;
marginMin?: number;
marginMax?: number;
2022-12-30 06:40:29 +00:00
// MkFolderとかで開閉アニメーションの際にheightを正しく伝えるため
container?: HTMLElement,
2022-06-22 07:29:31 +00:00
}>(), {
contentMax: null,
marginMin: 12,
marginMax: 24,
});
2021-10-14 11:55:59 +00:00
2022-06-22 07:29:31 +00:00
let ro: ResizeObserver;
let root = $shallowRef<HTMLElement>();
let content = $shallowRef<HTMLElement>();
2022-12-30 06:40:29 +00:00
let margin = $ref(props.marginMin);
const widthHistory = [null, null] as [number | null, number | null];
const heightHistory = [null, null] as [number | null, number | null];
2022-06-22 07:29:31 +00:00
const shouldSpacerMin = inject('shouldSpacerMin', false);
2021-12-03 04:52:57 +00:00
2022-06-22 07:29:31 +00:00
const adjust = (rect: { width: number; height: number; }) => {
if (shouldSpacerMin || deviceKind === 'smartphone') {
margin = props.marginMin;
return;
}
2021-10-14 11:55:59 +00:00
2022-06-22 07:29:31 +00:00
if (rect.width > (props.contentMax ?? 0) || (rect.width > 360 && window.innerWidth > 400)) {
margin = props.marginMax;
} else {
margin = props.marginMin;
}
};
2021-10-14 11:55:59 +00:00
2022-12-30 06:40:29 +00:00
if (props.container) {
const width = props.container.offsetWidth;
const height = props.container.offsetHeight;
adjust({
width,
height,
});
}
2022-06-22 07:29:31 +00:00
onMounted(() => {
ro = new ResizeObserver((entries) => {
/* iOS
adjust({
width: entries[0].borderBoxSize[0].inlineSize,
height: entries[0].borderBoxSize[0].blockSize,
2021-10-14 11:55:59 +00:00
});
2022-06-22 07:29:31 +00:00
*/
2022-12-30 06:40:29 +00:00
const width = props.container ? props.container.offsetWidth : root!.offsetWidth;
const height = props.container ? props.container.offsetHeight : root!.offsetHeight;
//#region Prevent infinite resizing
// https://github.com/misskey-dev/misskey/issues/9076
const pastWidth = widthHistory.pop();
widthHistory.unshift(width);
const pastHeight = heightHistory.pop();
heightHistory.unshift(height);
if (pastWidth === width && pastHeight === height) {
return;
}
//#endregion
2022-06-22 07:29:31 +00:00
adjust({
width,
height,
2021-10-14 11:55:59 +00:00
});
2022-06-22 07:29:31 +00:00
});
ro.observe(root!);
if (props.contentMax) {
content!.style.maxWidth = `${props.contentMax}px`;
}
});
2021-10-14 11:55:59 +00:00
2022-06-22 07:29:31 +00:00
onUnmounted(() => {
ro.disconnect();
2021-10-14 11:55:59 +00:00
});
</script>
<style lang="scss" module>
.root {
box-sizing: border-box;
width: 100%;
}
.content {
margin: 0 auto;
container-type: inline-size;
2021-10-14 11:55:59 +00:00
}
</style>