useScale

Remember the elastic scaling feature mentioned in the scale subsection, which gave the Geist components amazing imagination and extensibility, and now you can add elastic scaling features to your own components with the help of the useScale hooks.

Scale the width

As a first example, let's prepare a simple component with a fixed width:

const MyComponent = ({ width: string = '20px' }) => {
  return <div style={{ width }}>Scale Component</div>
}

Although the component accepts a string parameter to define the width, we can't control the multiplier of the width, say 1.35 times the width, unless it's manually calculated and then filled in, which seems fine, but when our component can set more than 10 styles, the calculation of these values is very tedious.

Now we try to bind the component to the scale of Geist:

import { withScale, useScale } from 'himalaya'

const MyComponent = () => {
  const { SCALES } = useScale()
  return <div style={{ width: SCALES.width(1.25) }}>Scale Component</div>
}

export default withScale(MyComponent)

withScale can transform any component into a dynamically scaled component and automatically add props and types to the component. You just need to set useScale within the component to get the SCALES, and then add the bindings for the SCALES for each style.

The default unit of Scale is 16px, when we need to set the default width to 20px, Obviously 20px is 1.25 times more than 16px, so we get SCALES.width(1.25).

The components of the above example should be used as follows:

<MyComponent width={0.5} />
<MyComponent width="10px" />
<MyComponent width="auto" />
<MyComponent unit="10rem" />

Unconventional defaults

In a few components where we want the default width to be auto (or others), and allow user-defined width to override this value, then within the Scale component we want to follow the following rules:

  • When the initial value is a special character (initial etc.), the component cannot be scaled by a factor of.
  • The user can still override the initial value with the specified value.

For a simple component, the following example can be used to illustrate:

const MyComponent = () => {
  const { SCALES } = useScale()
  return <div style={{ width: SCALES.width(1, 'auto') }}>Fixed Component</div>
}

export default withScale(MyComponent)

When we use this component, the width cannot be scaled by a multiple anymore:

<MyComponent width={0.1} />

// -> The width is still "auto"
// -> "auto" cannot be calculated mathematically

When we enter specific values to override, it still works well:

<MyComponent width="100px" />

// -> The width is "100px"

Get native props

When a component is combined with withScale, multiple props and corresponding types are automatically added, we can use the useScale function to get the corresponding value. Note, however, that the value obtained from the useScale function is computed, not the native value.

const MyComponent = () => {
  const { SCALES } = useScale()

  console.log(SCALES.width(1))

  return null
}

<MyComponent width={2} />  // output -> 'calc(2 * 16px)'
<MyComponent />            // output -> '16px'

The value obtained from SCALES.width is not exactly equal to the user input (width=), because we want to make sure that the component works even if the user does nothing. So, if you need to get the native value of the user input, use a separate function to get:

const MyComponent = () => {
  const { getScaleProps } = useScale()

  console.log(getScaleProps('width'))

  return null
}

<MyComponent width={2} />     // output -> 2
<MyComponent width="20px" />  // output -> '20px'
<MyComponent />               // output -> undefined

APIs

withScale

type withScale = (Render: React.ComponentType) => React.ComponentType

useScale

type useScale = () => ScaleConfig

type ScaleConfig = {
  SCALES: DynamicScales
  // Get the native value of scale prop
  getScaleProps: GetScalePropsFunction
  // Base value of the current component
  unit: string
}