import { useRef } from 'react'
import * as React from 'react'
import styled, { css } from 'styled-components'
import { useElementSize } from '../../foundation/hooks'
export interface Props {
children?: React.ReactNode
icon: React.ReactNode
/**
* アイコンを表示。デフォルトがtrueなので、非表示にするときに使います。 (アイコン自体の幅を維持します)
*/
show?: boolean | 'collapse'
/**
* アイコンを前にする
*/
prefix?: boolean
/**
* アイコンの高さが文字の高さよりも大きいケースで有効。アイコンの高さをゼロにしてインラインの高さに関与させないようにします。
*/
fit?: boolean
/**
* `fit`と併用した時にのみ有効な最適化オプション。アイコンの幅の自動計算を行わず指定した数値を利用します。
*/
width?: number
/**
* 親要素のサイズに合わせるのではなく、コンテンツのサイズを優先する
*/
fixed?: boolean
}
export default React.memo(function WithIcon({
children,
icon,
show = true,
prefix: pre = false,
width,
fit = false,
fixed = false,
}: Props) {
const node = fit ? (
width === undefined ? (
{icon}
) : (
{icon}
)
) : (
{icon}
)
return (
{pre && node}
{children}
{!pre && node}
)
})
const Root = styled.div`
display: flex;
align-items: center;
`
const Text = styled.div<{ fixed: boolean }>`
${(p) =>
!p.fixed &&
css`
min-width: 0;
overflow: hidden;
`}
white-space: nowrap;
text-overflow: ellipsis;
`
function AutoWidthIconAnchor({
children,
show,
pre,
}: {
children: React.ReactNode
show: boolean | 'collapse'
pre: boolean
}) {
const ref = useRef(null)
// depsを空配列にしないことで初回だけ同期で幅を計算させるテクニック
const width = useElementSize(ref, [null])?.width ?? 0
return (
{children}
)
}
const forceCenteringCss = css`
> svg {
display: block;
}
`
type IconAnchorProps = {
show: boolean | 'collapse'
pre: boolean
}
const iconAnchorCss = css`
${(p) =>
p.show === 'collapse'
? css`
display: none;
`
: css`
visibility: ${p.show ? 'visible' : 'hidden'};
`};
${(p) =>
p.pre
? css`
margin-right: 4px;
`
: css`
margin-left: 4px;
`}
`
const IconAnchorNaive = styled.div`
display: flex;
align-items: center;
${iconAnchorCss}
`
const IconNaive = styled.div`
display: inline-flex;
${forceCenteringCss}
`
const IconAnchor = styled.div<{
width: number
show: boolean | 'collapse'
pre: boolean
}>`
display: flex;
position: relative;
/* Iconをline-heightに関与させない */
height: 0;
/* 横方向の領域は確保する */
width: ${(p) => p.width}px;
${iconAnchorCss}
`
const Icon = styled.div`
display: inline-flex;
position: absolute;
transform: translateY(-50%);
${forceCenteringCss}
`