ant-design-vue/site/src/components/antdv-token-previewer/token-panel/token-card/index.tsx

228 lines
7.4 KiB
Vue

import type { PropType } from 'vue';
import { defineComponent, toRefs, ref } from 'vue';
import {
AlignLeftOutlined,
BgColorsOutlined,
BorderHorizontalOutlined,
BulbOutlined,
CaretRightOutlined,
ControlOutlined,
FileUnknownOutlined,
FontColorsOutlined,
FontSizeOutlined,
FormatPainterOutlined,
HighlightOutlined,
RadiusSettingOutlined,
TabletOutlined,
} from '@ant-design/icons-vue';
import { Collapse, Space } from 'ant-design-vue';
import type { ThemeConfig } from 'ant-design-vue/es/config-provider/context';
import classNames from 'ant-design-vue/es/_util/classNames';
import PropTypes from 'ant-design-vue/es/_util/vue-types';
import { Motion, ShapeLine } from '../../icons';
import type { MutableTheme, TokenValue } from '../../interface';
import type { TokenType } from '../../utils/classifyToken';
import makeStyle from '../../utils/makeStyle';
import { getRelatedComponents } from '../../utils/statistic';
import TokenItem from '../token-item';
const { Panel } = Collapse;
export interface TokenCardProps {
title: string;
icon?: any;
tokenArr: string[];
tokenPath: string[];
keyword?: string;
hideUseless?: boolean;
defaultOpen?: boolean;
open?: boolean;
onOpenChange?: (open: boolean) => void;
activeToken?: string;
onActiveTokenChange?: (token: string | undefined) => void;
onTokenChange?: (theme: MutableTheme, tokenName: string, value: TokenValue) => void;
themes: MutableTheme[];
selectedTokens?: string[];
onTokenSelect?: (token: string) => void;
enableTokenSelect?: boolean;
hideUsageCount?: boolean;
placeholder?: any;
fallback?: (config: ThemeConfig) => Record<string, TokenValue>;
}
export const IconMap: Record<TokenType, any> = {
seed: <BulbOutlined />,
colorText: <FontColorsOutlined />,
colorBg: <BgColorsOutlined />,
colorSplit: <BorderHorizontalOutlined />,
colorFill: <HighlightOutlined />,
colorCommon: <FormatPainterOutlined />,
space: <ShapeLine />,
font: <FontSizeOutlined />,
line: <AlignLeftOutlined />,
screen: <TabletOutlined />,
motion: <Motion />,
radius: <RadiusSettingOutlined />,
control: <ControlOutlined />,
others: <FileUnknownOutlined />,
};
export const TextMap: Record<TokenType, string> = {
seed: 'Seed Token',
colorCommon: 'Common Color 通用颜色',
colorText: 'Text Color 文本颜色',
colorBg: 'Background Color 背景颜色',
colorFill: 'Fill Color 填充颜色',
colorSplit: 'Split Color 分割线颜色',
space: 'Space 间距',
font: 'Font 文本',
line: 'Line 线',
screen: 'Screen 屏幕',
motion: 'Motion 动画',
radius: 'Radius 圆角',
control: 'Control 控件',
others: 'Others 未分类',
};
const useStyle = makeStyle('TokenCard', token => ({
'.token-card': {
width: '100%',
height: 'auto',
borderRadius: token.borderRadiusLG,
border: `1px solid rgba(0,0,0,0.09)`,
marginBottom: token.marginSM,
[`${token.rootCls}-collapse.token-card-collapse`]: {
[`> ${token.rootCls}-collapse-item > ${token.rootCls}-collapse-content > ${token.rootCls}-collapse-content-box`]:
{
padding: {
_skip_check_: true,
value: `0 ${token.paddingXS}px 12px !important`,
},
},
},
},
[`.token-card ${token.rootCls}-input-group >${token.rootCls}-input:not(:first-child):not(:last-child)`]:
{
background: 'white',
borderRadius: token.borderRadiusLG,
},
}));
export default defineComponent({
name: 'TokenCard',
props: {
title: { type: String as PropType<string> },
icon: PropTypes.any,
tokenArr: { type: Array as PropType<string[]> },
tokenPath: { type: Array as PropType<string[]> },
keyword: { type: String as PropType<string> },
hideUseless: { type: Boolean },
defaultOpen: { type: Boolean },
open: { type: Boolean },
activeToken: { type: String as PropType<string> },
themes: { type: Array as PropType<MutableTheme[]> },
selectedTokens: { type: Array as PropType<string[]> },
enableTokenSelect: { type: Boolean },
hideUsageCount: { type: Boolean },
placeholder: PropTypes.any,
onOpenChange: { type: Function as PropType<(open: boolean) => void> },
onActiveTokenChange: { type: Function as PropType<(token: string | undefined) => void> },
onTokenChange: {
type: Function as PropType<
(theme: MutableTheme, tokenName: string, value: TokenValue) => void
>,
},
onTokenSelect: { type: Function as PropType<(token: string) => void> },
fallback: { type: Function as PropType<(config: ThemeConfig) => Record<string, TokenValue>> },
},
setup(props, { attrs, slots }) {
const {
title,
tokenArr,
keyword,
hideUseless,
defaultOpen,
activeToken,
tokenPath,
selectedTokens,
themes,
enableTokenSelect,
hideUsageCount,
} = toRefs(props);
const [wrapSSR, hashId] = useStyle();
const activeKeys = ref(!!defaultOpen.value ? ['1'] : []);
return () => {
const icon = slots.icon ? slots.icon() : props.icon;
const placeholder = slots.placeholder ? slots.placeholder() : props.placeholder;
return wrapSSR(
<div {...attrs} class={classNames('token-card', hashId.value)}>
<Collapse
ghost
v-slots={{
expandIcon: ({ isActive }) => (
<CaretRightOutlined
rotate={isActive ? 450 : 360}
style={{ fontSize: '12px', color: 'rgba(0,0,0,0.45)' }}
/>
),
}}
expandIconPosition="end"
class="token-card-collapse"
v-model={[activeKeys.value, 'activeKey']}
onChange={() => {
// onOpenChange?.(keys.length > 0);
props.onOpenChange(activeKeys.value.length > 0);
}}
>
<Panel
v-slots={{
header: () => (
<Space size="small">
<span>{title.value}</span>
<span>{icon}</span>
</Space>
),
}}
key="1"
>
{tokenArr.value
.filter(
tokenName =>
(!keyword.value ||
tokenName.toLowerCase().includes(keyword.value.toLowerCase())) &&
(!hideUseless.value || getRelatedComponents(tokenName).length > 0),
)
.map(tokenName => {
return (
<TokenItem
tokenPath={tokenPath.value}
onActiveChange={active =>
props.onActiveTokenChange?.(active ? tokenName : undefined)
}
active={activeToken.value === tokenName}
tokenName={tokenName}
key={tokenName}
onTokenChange={props.onTokenChange}
themes={themes.value}
selectedTokens={selectedTokens.value}
onTokenSelect={props.onTokenSelect}
enableTokenSelect={enableTokenSelect.value}
hideUsageCount={hideUsageCount.value}
fallback={props.fallback}
/>
);
})}
{tokenArr.value.length === 0 && placeholder}
</Panel>
</Collapse>
</div>,
);
};
},
});