diff --git a/src/Snippet/demos/index.tsx b/src/Snippet/demos/index.tsx new file mode 100644 index 00000000..a5019aad --- /dev/null +++ b/src/Snippet/demos/index.tsx @@ -0,0 +1,5 @@ +import { Snippet } from '@ant-design/pro-editor'; + +export default () => { + return ; +}; diff --git a/src/Snippet/index.md b/src/Snippet/index.md new file mode 100644 index 00000000..ecd2f49a --- /dev/null +++ b/src/Snippet/index.md @@ -0,0 +1,14 @@ +--- +nav: 组件 +group: Content +title: Snippet +description: The Snippet component is used to display a code snippet with syntax highlighting. It can be customized with a symbol before the content and a language for syntax highlighting. The component is also copyable with a CopyButton included by default. +--- + +## Default + + + +## APIs + + diff --git a/src/Snippet/index.tsx b/src/Snippet/index.tsx new file mode 100644 index 00000000..c4045e0c --- /dev/null +++ b/src/Snippet/index.tsx @@ -0,0 +1,61 @@ +import { memo } from 'react'; + +import { Highlight } from '@ant-design/pro-editor'; + +import { DivProps } from 'react-layout-kit'; +import { useStyles } from './style'; + +export interface SnippetProps extends DivProps { + /** + * @description The content to be displayed inside the Snippet component + */ + children: string; + /** + * @description Whether the Snippet component is copyable or not + * @default true + */ + copyable?: boolean; + /** + * @description The language of the content inside the Snippet component + * @default 'tsx' + */ + language?: string; + /** + * @description Whether add spotlight background + * @default false + */ + spotlight?: boolean; + /** + * @description The symbol to be displayed before the content inside the Snippet component + */ + symbol?: string; + /** + * @description The type of the Snippet component + * @default 'ghost' + */ + type?: 'ghost' | 'block'; +} + +const Snippet = memo( + ({ + symbol, + language = 'tsx', + children, + // copyable = true, + type = 'ghost', + spotlight, + className, + ...props + }) => { + const { styles, cx } = useStyles(type); + return ( +
+ {/* {spotlight && } */} + {[symbol, children].filter(Boolean).join(' ')} + {/* {copyable && } */} +
+ ); + }, +); + +export { Snippet }; diff --git a/src/Snippet/style.ts b/src/Snippet/style.ts new file mode 100644 index 00000000..54e67c0e --- /dev/null +++ b/src/Snippet/style.ts @@ -0,0 +1,63 @@ +import { createStyles } from 'antd-style'; + +export const useStyles = createStyles(({ css, cx, token, prefixCls }, type: 'ghost' | 'block') => { + const typeStylish = css` + background-color: ${type === 'block' ? token.colorFillTertiary : 'transparent'}; + border: 1px solid ${type === 'block' ? 'transparent' : token.colorBorder}; + `; + + return { + container: cx( + typeStylish, + css` + position: relative; + + overflow: hidden; + display: flex; + gap: 8px; + align-items: center; + + max-width: 100%; + height: 38px; + padding: 0 8px 0 12px; + + border-radius: ${token.borderRadius}px; + + transition: background-color 100ms ${token.motionEaseOut}; + + &:hover { + background-color: ${token.colorFillTertiary}; + } + + .${prefixCls}-highlighter-shiki { + position: relative; + overflow: hidden; + flex: 1; + } + + .prism-code { + background: none !important; + } + + pre { + overflow-x: auto !important; + overflow-y: hidden !important; + display: flex; + align-items: center; + + width: 100%; + height: 36px !important; + margin: 0 !important; + + line-height: 1; + + background: none !important; + } + + code[class*='language-'] { + background: none !important; + } + `, + ), + }; +}); diff --git a/src/index.ts b/src/index.ts index bc81c741..517b94c1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -27,6 +27,7 @@ export type { CanvasInteractRule, InteractStatus, InteractStatusNode } from './I export { default as LevaPanel } from './LevaPanel'; export type { LevaPanelProps } from './LevaPanel'; export * from './ProBuilder'; +export * from './Snippet'; export * from './SortableList'; export * from './SortableTree'; export { default as TipGuide } from './TipGuide';