Skip to content

Scale & Centering API

comp-hub Only

$onScaleChange is injected by comp-hub's preview environment. It is NOT a standard framework API and does not exist outside comp-hub. For Vue components it is added to the Vue instance (this.$onScaleChange), and for React components it is passed as a prop onScaleChange. If you use this API in your component, make sure to guard against it being undefined when running outside comp-hub.

$onScaleChange subscribes to container size changes and automatically computes scale & centering styles, helping content adapt to the preview container.

Why Scaling?

The mini preview panel has limited space (typically around 300×200), but some components display rich content (charts, tables, complex form layouts, etc.). Without scaling, only a partial area is visible in the mini panel, making it impossible to see the full component. The scale API lets you define a preset content size (e.g., 800×500) and automatically scales it to fit the mini container, keeping everything visible.

ts
type ScaleMode = "widthFirst" | "heightFirst" | "contain" | "cover"

interface ScaleStyle {
  transform: string       // e.g. "translate(100px, 50px) scale(0.75)"
  transformOrigin: string // always "left top"
}

Scaling Modes

ModeBehavior
"widthFirst"Scale to fit container width, height may overflow
"heightFirst"Scale to fit container height, width may overflow
"contain"Scale proportionally, content fully visible within container (recommended default)
"cover"Scale proportionally, content fills container (may clip excess)

All modes center the content inside the container via translate.

$onScaleChange(params, callback) → unsubscribe

Subscribes to container size changes. The callback is invoked immediately with the current scale, then again whenever the container is resized.

ts
const unsubscribe = this.$onScaleChange(
  params: { mode: ScaleMode, width: number, height: number },
  callback: (style: ScaleStyle) => void
): () => void

Usage (React)

The React version of the scale API is passed as a prop onScaleChange to your demo component:

jsx
import React, { useEffect, useState } from "react";

const DemoMini = ({ onScaleChange }) => {
  const [scaleStyle, setScaleStyle] = useState({});

  useEffect(() => {
    if (onScaleChange) {
      const unsubscribe = onScaleChange(
        { mode: "contain", width: 800, height: 500 },
        (style) => setScaleStyle(style)
      );
      return unsubscribe; // cleanup on unmount
    }
  }, [onScaleChange]);

  return (
    <div style={scaleStyle}>
      {/* your content */}
    </div>
  );
};

export default DemoMini;

Usage (Vue 2 Options API)

vue
<script>
export default {
  data() {
    return { scaleStyle: {} }
  },
  mounted() {
    // Subscribe — auto-recalculates on container resize
    this._unsub = this.$onScaleChange(
      { mode: "contain", width: 800, height: 500 },
      (style) => { this.scaleStyle = style }
    )
  },
  beforeDestroy() {
    this._unsub?.() // Clean up subscription
  }
}
</script>

Usage (Vue 3 Composition API)

vue
<script setup>
import { ref, getCurrentInstance, onBeforeUnmount } from "vue"

const instance = getCurrentInstance()
const scaleStyle = ref({})

const unsub = instance.proxy.$onScaleChange(
  { mode: "contain", width: 800, height: 500 },
  (style) => { scaleStyle.value = style }
)

onBeforeUnmount(() => unsub())
</script>

Common Patterns

Demo Component with Fixed Content Size

Preview demo components typically declare a fixed content area, then use the scale API to fill the preview panel:

vue
<template>
  <div class="demo-wrapper" :style="scaleStyle">
    <!-- Content designed to 800×500 -->
    <div class="demo-content">...</div>
  </div>
</template>

<script>
export default {
  data() {
    return { scaleStyle: {} }
  },
  mounted() {
    this._unsub = this.$onScaleChange(
      { mode: "contain", width: 800, height: 500 },
      (style) => { this.scaleStyle = style }
    )
  },
  beforeDestroy() {
    this._unsub?.()
  }
}
</script>

<style scoped>
.demo-wrapper {
  transform-origin: left top;
}
.demo-content {
  width: 800px;
  height: 500px;
  overflow: hidden;
}
</style>

Best Practices

  1. Clean up subscriptions — always call unsubscribe() in beforeDestroy / onBeforeUnmount to prevent memory leaks
  2. Fixed content size — design your demo with a specific width × height (e.g., 800×500) and let the scale API handle the rest
  3. contain is the safe default — it ensures all content is visible even in small panels
  4. Guard for non-comp-hub environments — since this API only exists inside comp-hub preview, always check if it's available before calling:
js
// Safe calling pattern
if (this.$onScaleChange) {
  this._unsub = this.$onScaleChange(
    { mode: "contain", width: 800, height: 500 },
    (style) => { this.scaleStyle = style }
  )
}

Components uploaded by users are open source