2023-05-05 08:16:55 +09:00
|
|
|
<template>
|
|
|
|
<span :class="$style.container">
|
|
|
|
<span ref="content" :class="$style.content">
|
|
|
|
<slot/>
|
|
|
|
</span>
|
|
|
|
</span>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script lang="ts">
|
2023-05-07 19:08:43 +09:00
|
|
|
interface Props {
|
|
|
|
readonly minScale?: number;
|
|
|
|
}
|
|
|
|
|
2023-05-05 08:16:55 +09:00
|
|
|
const contentSymbol = Symbol();
|
|
|
|
const observer = new ResizeObserver((entries) => {
|
2023-06-05 18:06:33 +09:00
|
|
|
const results: {
|
|
|
|
container: HTMLSpanElement;
|
|
|
|
transform: string;
|
|
|
|
}[] = [];
|
2023-05-05 08:16:55 +09:00
|
|
|
for (const entry of entries) {
|
|
|
|
const content = (entry.target[contentSymbol] ? entry.target : entry.target.firstElementChild) as HTMLSpanElement;
|
2023-05-07 19:08:43 +09:00
|
|
|
const props: Required<Props> = content[contentSymbol];
|
2023-05-05 08:16:55 +09:00
|
|
|
const container = content.parentElement as HTMLSpanElement;
|
|
|
|
const contentWidth = content.getBoundingClientRect().width;
|
|
|
|
const containerWidth = container.getBoundingClientRect().width;
|
2023-06-05 18:06:33 +09:00
|
|
|
results.push({ container, transform: `scaleX(${Math.max(props.minScale, Math.min(1, containerWidth / contentWidth))})` });
|
|
|
|
}
|
|
|
|
for (const result of results) {
|
|
|
|
result.container.style.transform = result.transform;
|
2023-05-05 08:16:55 +09:00
|
|
|
}
|
|
|
|
});
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
import { ref, watch } from 'vue';
|
|
|
|
|
2023-05-07 19:08:43 +09:00
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
|
|
minScale: 0,
|
|
|
|
});
|
|
|
|
|
2023-05-05 08:16:55 +09:00
|
|
|
const content = ref<HTMLSpanElement>();
|
|
|
|
|
|
|
|
watch(content, (value, oldValue) => {
|
|
|
|
if (oldValue) {
|
|
|
|
delete oldValue[contentSymbol];
|
|
|
|
observer.unobserve(oldValue);
|
|
|
|
if (oldValue.parentElement) {
|
|
|
|
observer.unobserve(oldValue.parentElement);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (value) {
|
2023-05-07 19:08:43 +09:00
|
|
|
value[contentSymbol] = props;
|
2023-05-05 08:16:55 +09:00
|
|
|
observer.observe(value);
|
|
|
|
if (value.parentElement) {
|
|
|
|
observer.observe(value.parentElement);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style module lang="scss">
|
|
|
|
.container {
|
|
|
|
display: inline-block;
|
2023-05-07 19:21:55 +09:00
|
|
|
max-width: 100%;
|
2023-05-05 08:16:55 +09:00
|
|
|
transform-origin: 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
.content {
|
|
|
|
display: inline-block;
|
|
|
|
white-space: nowrap;
|
|
|
|
}
|
|
|
|
</style>
|