feat(SW-3636): Storybook structure * New sections in Storybook sidebar * Group Storybook content files and add token files for spacing, border radius and shadows Approved-by: Joakim Jäderberg
129 lines
4.0 KiB
TypeScript
129 lines
4.0 KiB
TypeScript
/* eslint-disable formatjs/no-literal-string-in-jsx */
|
|
import copy from 'copy-to-clipboard'
|
|
|
|
import { kebabify } from '../../generate/utils'
|
|
|
|
import tableStyles from './tokens.module.css'
|
|
|
|
type ThemeValue = {
|
|
resolved: string | number
|
|
alias?: string | number
|
|
}
|
|
|
|
type Theme = Record<string, ThemeValue>
|
|
|
|
type SpacingProps = {
|
|
theme: Theme
|
|
}
|
|
|
|
function copyToClipboard(text: string) {
|
|
copy(text)
|
|
}
|
|
|
|
// Extract base unit multiplier from token name
|
|
function getBaseUnitMultiplier(tokenName: string): string {
|
|
// Token names are like "Space/x0", "Space/x025", "Space/x05", "Space/x1", "Space/x15", etc.
|
|
const match = tokenName.match(/Space\/x(\d+)/)
|
|
if (!match) return '0x'
|
|
|
|
const num = match[1]
|
|
|
|
// Handle special cases
|
|
if (num === '0') return '0x'
|
|
if (num === '025') return '0.25x'
|
|
if (num === '05') return '0.5x'
|
|
if (num === '15') return '1.5x'
|
|
|
|
// For other numbers, they're already the multiplier (x1 = 1x, x2 = 2x, etc.)
|
|
return `${num}x`
|
|
}
|
|
|
|
export function Spacing({ theme }: SpacingProps) {
|
|
// Filter spacing tokens
|
|
const spacingTokens: Theme = {}
|
|
for (const [k, v] of Object.entries(theme)) {
|
|
if (k.startsWith('Space/')) {
|
|
spacingTokens[k] = v as ThemeValue
|
|
}
|
|
}
|
|
|
|
// Sort by value
|
|
const sortedTokens = Object.entries(spacingTokens).sort((a, b) => {
|
|
const aValue = typeof a[1].resolved === 'number' ? a[1].resolved : 0
|
|
const bValue = typeof b[1].resolved === 'number' ? b[1].resolved : 0
|
|
return aValue - bValue
|
|
})
|
|
|
|
return (
|
|
<div>
|
|
<div className={tableStyles.tableContainer}>
|
|
<table className={tableStyles.table}>
|
|
<thead className={tableStyles.tableHeader}>
|
|
<tr>
|
|
<th className={tableStyles.tableHeaderCell}>Token</th>
|
|
<th className={tableStyles.tableHeaderCell}>
|
|
Base unit multiplier
|
|
</th>
|
|
<th className={tableStyles.tableHeaderCell}>Pixels</th>
|
|
<th className={tableStyles.tableHeaderCell}>
|
|
Visual representation
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{sortedTokens.map(([k, v]) => {
|
|
const value = typeof v.resolved === 'number' ? v.resolved : 0
|
|
const valuePx = `${value}px`
|
|
const multiplier = getBaseUnitMultiplier(k)
|
|
|
|
return (
|
|
<tr key={k} className={tableStyles.tableRow}>
|
|
<td className={tableStyles.tableCell}>
|
|
<code
|
|
className={tableStyles.tokenName}
|
|
onClick={() => {
|
|
copyToClipboard(`var(--${kebabify(k)})`)
|
|
}}
|
|
title="Click to copy CSS variable"
|
|
>
|
|
{kebabify(k)}
|
|
</code>
|
|
</td>
|
|
<td className={tableStyles.tableCell}>
|
|
<span className={tableStyles.value}>{multiplier}</span>
|
|
</td>
|
|
<td className={tableStyles.tableCell}>
|
|
<code
|
|
className={tableStyles.value}
|
|
onClick={() => {
|
|
copyToClipboard(valuePx)
|
|
}}
|
|
title="Click to copy"
|
|
>
|
|
{valuePx}
|
|
</code>
|
|
</td>
|
|
<td className={tableStyles.tableCell}>
|
|
<div className={tableStyles.visualBarContainer}>
|
|
<span className={tableStyles.visualBarLabel}>
|
|
{valuePx}
|
|
</span>
|
|
<div
|
|
className={tableStyles.visualBar}
|
|
style={{
|
|
width: `${value}px`,
|
|
minWidth: value > 0 ? '2px' : '0',
|
|
}}
|
|
/>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
)
|
|
})}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|