diff --git a/e2e/shim.d.ts b/e2e/shim.d.ts index 52d0db12ec7..42c61640b9e 100644 --- a/e2e/shim.d.ts +++ b/e2e/shim.d.ts @@ -1,4 +1,3 @@ -/// /// import type { Editor } from '@milkdown/core' diff --git a/e2e/tests/crepe/latex.spec.ts b/e2e/tests/crepe/latex.spec.ts index 60618409fce..cc17ed2e8a0 100644 --- a/e2e/tests/crepe/latex.spec.ts +++ b/e2e/tests/crepe/latex.spec.ts @@ -1,5 +1,5 @@ import { expect, test } from '@playwright/test' -import { focusEditor, getMarkdown } from 'tests/misc' +import { focusEditor, getMarkdown } from '../misc' test.beforeEach(async ({ page }) => { await page.goto('/crepe/') @@ -10,7 +10,7 @@ test('latex block preview toggle', async ({ page }) => { await page.keyboard.type('$$') await page.keyboard.press('Enter') - const codeBlock = page.locator('milkdown-code-block') + const codeBlock = page.locator('.milkdown-code-block') const codemirror = codeBlock.locator('.codemirror-host') const preview = codeBlock.locator('.preview') const codeTools = codeBlock.locator('.tools') diff --git a/e2e/tests/crepe/listener.spec.ts b/e2e/tests/crepe/listener.spec.ts index 42c73821c96..48d6c300909 100644 --- a/e2e/tests/crepe/listener.spec.ts +++ b/e2e/tests/crepe/listener.spec.ts @@ -1,5 +1,5 @@ import { expect, test } from '@playwright/test' -import { focusEditor } from 'tests/misc' +import { focusEditor } from '../misc' test('listen change before editor is created', async ({ page }) => { await page.addInitScript(() => { diff --git a/packages/components/src/__internal__/components/icon.tsx b/packages/components/src/__internal__/components/icon.tsx index 58b5aa2082c..5b0a82e4ab8 100644 --- a/packages/components/src/__internal__/components/icon.tsx +++ b/packages/components/src/__internal__/components/icon.tsx @@ -14,7 +14,7 @@ export function Icon({ icon, class: className }: IconProps) { class={clsx('milkdown-icon', className)} ref={(el) => { if (el && icon) { - ;(el as HTMLElement).innerHTML = icon + ;(el as HTMLElement).innerHTML = icon.trim() } }} /> diff --git a/packages/components/src/code-block/config.ts b/packages/components/src/code-block/config.ts index 18dbb4a50f6..bee50318cf0 100644 --- a/packages/components/src/code-block/config.ts +++ b/packages/components/src/code-block/config.ts @@ -1,27 +1,23 @@ import { $ctx } from '@milkdown/utils' import type { Extension } from '@codemirror/state' import type { LanguageDescription } from '@codemirror/language' -import { html } from 'atomico' import { withMeta } from '../__internal__/meta' export interface CodeBlockConfig { extensions: Extension[] languages: LanguageDescription[] - expandIcon: () => ReturnType | string - searchIcon: () => ReturnType | string - clearSearchIcon: () => ReturnType | string + expandIcon: () => string + searchIcon: () => string + clearSearchIcon: () => string searchPlaceholder: string noResultText: string - renderLanguage: ( - language: string, - selected: boolean - ) => ReturnType + renderLanguage: (language: string, selected: boolean) => string renderPreview: ( language: string, content: string ) => null | string | HTMLElement - previewToggleButton: (previewOnlyMode: boolean) => ReturnType - previewLabel: () => ReturnType + previewToggleButton: (previewOnlyMode: boolean) => string + previewLabel: () => string } export const defaultConfig: CodeBlockConfig = { @@ -32,7 +28,7 @@ export const defaultConfig: CodeBlockConfig = { clearSearchIcon: () => '⌫', searchPlaceholder: 'Search language', noResultText: 'No result', - renderLanguage: (language) => html`${language}`, + renderLanguage: (language) => language, renderPreview: () => null, previewToggleButton: (previewOnlyMode) => (previewOnlyMode ? 'Edit' : 'Hide'), previewLabel: () => 'Preview', diff --git a/packages/components/src/code-block/view/component.ts b/packages/components/src/code-block/view/component.ts deleted file mode 100644 index d3b13c6f5cd..00000000000 --- a/packages/components/src/code-block/view/component.ts +++ /dev/null @@ -1,282 +0,0 @@ -import type { EditorView as CodeMirror } from '@codemirror/view' -import type { Component } from 'atomico' -import { - c, - h, - html, - useEffect, - useHost, - useLayoutEffect, - useMemo, - useRef, - useState, -} from 'atomico' -import { computePosition } from '@floating-ui/dom' -import clsx from 'clsx' -import type { CodeBlockConfig } from '../config' -import type { LanguageInfo } from './loader' - -export interface CodeComponentProps { - text: string - selected: boolean - codemirror: CodeMirror - language: string - getAllLanguages: () => Array - setLanguage: (language: string) => void - isEditorReadonly: () => boolean - config: Omit -} - -export const codeComponent: Component = ({ - selected = false, - codemirror, - getAllLanguages, - setLanguage, - language, - config, - isEditorReadonly, - text, -}) => { - const host = useHost() - const triggerRef = useRef() - const pickerRef = useRef() - const searchRef = useRef() - const previewRef = useRef() - const [filter, setFilter] = useState('') - const [showPicker, setShowPicker] = useState(false) - const [previewOnlyMode, setPreviewOnlyMode] = useState(false) - - const root = useMemo(() => host.current.getRootNode() as HTMLElement, [host]) - - useEffect(() => { - const lang = getAllLanguages?.()?.find((languageInfo) => - languageInfo.alias.some( - (alias) => alias.toLowerCase() === language?.toLowerCase() - ) - ) - - if (lang && lang.name !== language) setLanguage?.(lang.name) - }, [language]) - - useEffect(() => { - setShowPicker(false) - }, [language]) - - useEffect(() => { - const clickHandler = (e: MouseEvent) => { - const target = e.target as HTMLElement - - if (triggerRef.current && triggerRef.current.contains(target)) return - - const picker = pickerRef.current - if (!picker) return - - if (picker.dataset.expanded !== 'true') return - - if (!picker.contains(target)) setShowPicker(false) - } - - root.addEventListener('click', clickHandler) - - return () => { - root.removeEventListener('click', clickHandler) - } - }, []) - - useLayoutEffect(() => { - setFilter('') - const picker = triggerRef.current - const languageList = pickerRef.current - if (!picker || !languageList) return - - computePosition(picker, languageList, { - placement: 'bottom-start', - }).then(({ x, y }) => { - Object.assign(languageList.style, { - left: `${x}px`, - top: `${y}px`, - }) - }) - }, [showPicker]) - - const languages = useMemo(() => { - if (!showPicker) return [] - - const all = getAllLanguages?.() ?? [] - - const selected = all.find( - (languageInfo) => - languageInfo.name.toLowerCase() === language?.toLowerCase() - ) - - const filtered = all.filter((languageInfo) => { - return ( - (languageInfo.name.toLowerCase().includes(filter.toLowerCase()) || - languageInfo.alias.some((alias) => - alias.toLowerCase().includes(filter.toLowerCase()) - )) && - languageInfo !== selected - ) - }) - - if (filtered.length === 0) return [] - - if (!selected) return filtered - - return [selected, ...filtered] - }, [filter, showPicker, language]) - - const changeFilter = (e: InputEvent) => { - const target = e.target as HTMLInputElement - setFilter(target.value) - } - - const onTogglePicker = (e: Event) => { - e.preventDefault() - e.stopPropagation() - if (isEditorReadonly?.()) return - - setShowPicker((show) => { - if (!show) { - setTimeout(() => searchRef.current?.focus(), 0) - } - return !show - }) - } - - const onClear = (e: MouseEvent) => { - e.preventDefault() - setFilter('') - } - - const onSearchKeydown = (e: KeyboardEvent) => { - if (e.key === 'Escape') setFilter('') - } - - const onListKeydown = (e: KeyboardEvent) => { - if (e.key === 'Enter') { - const active = document.activeElement - if (active instanceof HTMLElement && active.dataset.language) - setLanguage?.(active.dataset.language) - } - } - - const renderedLanguageList = useMemo(() => { - if (!languages?.length) - return html`
  • - ${config?.noResultText} -
  • ` - - return languages.map( - (languageInfo) => - html`
  • setLanguage?.(languageInfo.name)} - > - ${config?.renderLanguage?.( - languageInfo.name, - languageInfo.name.toLowerCase() === language?.toLowerCase() - )} -
  • ` - ) - }, [languages]) - - const preview = useMemo(() => { - const preview = config?.renderPreview?.(language ?? '', text ?? '') - return preview - }, [language, text]) - - useEffect(() => { - if (!previewRef.current) { - return - } - - while (previewRef.current.firstChild) { - previewRef.current.removeChild(previewRef.current.firstChild) - } - if (typeof preview === 'string') { - previewRef.current.innerHTML = preview - } else if (preview instanceof HTMLElement) { - previewRef.current.appendChild(preview) - } - }, [preview]) - - return html` -
    - -
    -
    - -
      - ${renderedLanguageList} -
    -
    -
    - -
    -
    - ${h(codemirror?.dom, {})} -
    -
    -
    -
    - ${config?.previewLabel?.()} -
    -
    -
    -
    ` -} - -codeComponent.props = { - selected: Boolean, - codemirror: Object, - language: String, - getAllLanguages: Function, - setLanguage: Function, - isEditorReadonly: Function, - config: Object, - text: String, -} - -export const CodeElement = c(codeComponent) diff --git a/packages/components/src/code-block/view/components/code-block.tsx b/packages/components/src/code-block/view/components/code-block.tsx new file mode 100644 index 00000000000..32734157607 --- /dev/null +++ b/packages/components/src/code-block/view/components/code-block.tsx @@ -0,0 +1,128 @@ +import type { EditorView as CodeMirror } from '@codemirror/view' +import { + defineComponent, + ref, + type Ref, + h, + Fragment, + computed, + onMounted, +} from 'vue' +import type { CodeBlockConfig } from '../../config' +import type { LanguageInfo } from '../loader' +import { PreviewPanel } from './preview-panel' +import { LanguagePicker } from './language-picker' +import { Icon } from '../../../__internal__/components/icon' +import clsx from 'clsx' + +h +Fragment + +export type CodeBlockProps = { + text: Ref + selected: Ref + readonly: Ref + codemirror: CodeMirror + language: Ref + getAllLanguages: () => Array + setLanguage: (language: string) => void + config: Omit +} + +export const CodeBlock = defineComponent({ + props: { + text: { + type: Object, + required: true, + }, + selected: { + type: Object, + required: true, + }, + readonly: { + type: Object, + required: true, + }, + codemirror: { + type: Object, + required: true, + }, + language: { + type: Object, + required: true, + }, + getAllLanguages: { + type: Function, + required: true, + }, + setLanguage: { + type: Function, + required: true, + }, + config: { + type: Object, + required: true, + }, + }, + setup(props) { + const previewOnlyMode = ref(false) + const codemirrorHostRef = ref() + + onMounted(() => { + while (codemirrorHostRef.value?.firstChild) { + codemirrorHostRef.value.removeChild(codemirrorHostRef.value.firstChild) + } + + if (codemirrorHostRef.value) { + codemirrorHostRef.value.appendChild(props.codemirror.dom) + } + }) + + const preview = computed(() => { + const text = props.text.value + const language = props.language.value + + return props.config.renderPreview(language, text) + }) + + return () => { + return ( + <> +
    + + {preview.value ? ( + + ) : null} +
    +
    + + + ) + } + }, +}) diff --git a/packages/components/src/code-block/view/components/language-picker.tsx b/packages/components/src/code-block/view/components/language-picker.tsx new file mode 100644 index 00000000000..792629b2b9c --- /dev/null +++ b/packages/components/src/code-block/view/components/language-picker.tsx @@ -0,0 +1,235 @@ +import { + computed, + defineComponent, + ref, + h, + Fragment, + onMounted, + onUnmounted, + watch, +} from 'vue' +import type { CodeBlockProps } from './code-block' +import clsx from 'clsx' +import { computePosition } from '@floating-ui/dom' +import { Icon } from '../../../__internal__/components/icon' + +type LanguagePickerProps = Pick< + CodeBlockProps, + 'language' | 'readonly' | 'config' | 'setLanguage' | 'getAllLanguages' +> + +h +Fragment +export const LanguagePicker = defineComponent({ + props: { + language: { + type: Object, + required: true, + }, + readonly: { + type: Object, + required: true, + }, + config: { + type: Object, + required: true, + }, + getAllLanguages: { + type: Function, + required: true, + }, + setLanguage: { + type: Function, + required: true, + }, + }, + setup({ readonly, language, config, setLanguage, getAllLanguages }) { + const triggerRef = ref() + const showPicker = ref(false) + const searchRef = ref() + const pickerRef = ref() + const filter = ref('') + + watch([showPicker, triggerRef, pickerRef], () => { + filter.value = '' + const picker = triggerRef.value + const languageList = pickerRef.value + if (!picker || !languageList) return + + computePosition(picker, languageList, { + placement: 'bottom-start', + }).then(({ x, y }) => { + Object.assign(languageList.style, { + left: `${x}px`, + top: `${y}px`, + }) + }) + }) + + const onTogglePicker = (e: Event) => { + e.preventDefault() + e.stopPropagation() + if (readonly.value) return + + const next = !showPicker.value + showPicker.value = next + if (next) { + setTimeout(() => searchRef.value?.focus(), 0) + } + } + + const changeFilter = (e: Event) => { + const target = e.target as HTMLInputElement + filter.value = target.value + } + + const onSearchKeydown = (e: Event) => { + if ((e as KeyboardEvent).key === 'Escape') filter.value = '' + } + + const languages = computed(() => { + if (!showPicker.value) return [] + + const all = getAllLanguages() ?? [] + + const selected = all.find( + (languageInfo) => + languageInfo.name.toLowerCase() === language.value.toLowerCase() + ) + + const filtered = all.filter((languageInfo) => { + const currentValue = filter.value.toLowerCase() + + return ( + (languageInfo.name.toLowerCase().includes(currentValue) || + languageInfo.alias.some((alias) => + alias.toLowerCase().includes(currentValue) + )) && + languageInfo !== selected + ) + }) + + if (filtered.length === 0) return [] + + if (!selected) return filtered + + return [selected, ...filtered] + }) + + const clickHandler = (e: MouseEvent) => { + const target = e.target as HTMLElement + + if (triggerRef.value && triggerRef.value.contains(target)) return + + const picker = pickerRef.value + const trigger = triggerRef.value + if (!trigger || !picker) return + + if (trigger.dataset.expanded !== 'true') return + + if (!picker.contains(target)) showPicker.value = false + } + + onMounted(() => { + window.addEventListener('click', clickHandler) + }) + + onUnmounted(() => { + window.removeEventListener('click', clickHandler) + }) + + return () => { + return ( + <> + +
    + {showPicker.value ? ( +
    + +
      { + if (e.key === 'Enter') { + const active = document.activeElement + if ( + active instanceof HTMLElement && + active.dataset.language + ) + setLanguage(active.dataset.language) + } + }} + > + {!languages.value.length ? ( +
    • + {config.noResultText} +
    • + ) : ( + languages.value.map((languageInfo) => ( +
    • { + setLanguage(languageInfo.name) + showPicker.value = false + }} + > + {config.renderLanguage( + languageInfo.name, + languageInfo.name.toLowerCase() === + language.value.toLowerCase() + )} +
    • + )) + )} +
    +
    + ) : null} +
    + + ) + } + }, +}) diff --git a/packages/components/src/code-block/view/components/preview-panel.tsx b/packages/components/src/code-block/view/components/preview-panel.tsx new file mode 100644 index 00000000000..1cec6a5ad99 --- /dev/null +++ b/packages/components/src/code-block/view/components/preview-panel.tsx @@ -0,0 +1,86 @@ +import { + defineComponent, + ref, + watchEffect, + type Ref, + h, + Fragment, + type ComputedRef, +} from 'vue' +import type { CodeBlockProps } from './code-block' +import clsx from 'clsx' + +h +Fragment + +type PreviewPanelProps = Pick< + CodeBlockProps, + 'text' | 'language' | 'config' +> & { + previewOnlyMode: Ref + preview: ComputedRef +} + +export const PreviewPanel = defineComponent({ + props: { + text: { + type: Object, + required: true, + }, + language: { + type: Object, + required: true, + }, + config: { + type: Object, + required: true, + }, + previewOnlyMode: { + type: Object, + required: true, + }, + preview: { + type: Object, + required: true, + }, + }, + setup(props) { + const { previewOnlyMode, config, preview } = props + const previewRef = ref() + + watchEffect(() => { + const previewContainer = previewRef.value + if (!previewContainer) return + + while (previewContainer.firstChild) { + previewContainer.removeChild(previewContainer.firstChild) + } + + const previewContent = preview.value + + if (typeof previewContent === 'string') { + previewContainer.innerHTML = previewContent + } else if (previewContent instanceof HTMLElement) { + previewContainer.appendChild(previewContent) + } + }) + + return () => { + if (!preview.value) return null + + return ( +
    + {!previewOnlyMode.value && ( + <> +
    +
    + {config.previewLabel()} +
    + + )} +
    +
    + ) + } + }, +}) diff --git a/packages/components/src/code-block/view/index.ts b/packages/components/src/code-block/view/index.ts index d29f42928db..f532e71bb94 100644 --- a/packages/components/src/code-block/view/index.ts +++ b/packages/components/src/code-block/view/index.ts @@ -3,12 +3,9 @@ import { codeBlockSchema } from '@milkdown/preset-commonmark' import type { NodeViewConstructor } from '@milkdown/prose/view' import { codeBlockConfig } from '../config' import { withMeta } from '../../__internal__/meta' -import { defIfNotExists } from '../../__internal__/helper' import { CodeMirrorBlock } from './node-view' import { LanguageLoader } from './loader' -import { CodeElement } from './component' -defIfNotExists('milkdown-code-block', CodeElement) export const codeBlockView = $view( codeBlockSchema.node, (ctx): NodeViewConstructor => { diff --git a/packages/components/src/code-block/view/node-view.ts b/packages/components/src/code-block/view/node-view.ts index 72c7bd99569..0a544e60f03 100644 --- a/packages/components/src/code-block/view/node-view.ts +++ b/packages/components/src/code-block/view/node-view.ts @@ -11,17 +11,24 @@ import { Compartment, EditorState } from '@codemirror/state' import type { Line, SelectionRange } from '@codemirror/state' import { exitCode } from '@milkdown/prose/commands' import { TextSelection } from '@milkdown/prose/state' +import { createApp, ref, watchEffect, type WatchHandle } from 'vue' import type { CodeBlockConfig } from '../config' -import type { CodeComponentProps } from './component' import type { LanguageLoader } from './loader' +import { CodeBlock } from './components/code-block' export class CodeMirrorBlock implements NodeView { - dom: HTMLElement & CodeComponentProps + dom: HTMLElement cm: CodeMirror + readonly = ref(false) + selected = ref(false) + language = ref('') + text = ref('') + private updating = false private languageName: string = '' + private disposeSelectedWatcher: WatchHandle private readonly languageConf: Compartment private readonly readOnlyConf: Compartment @@ -50,6 +57,15 @@ export class CodeMirrorBlock implements NodeView { this.dom = this.createDom() + this.disposeSelectedWatcher = watchEffect(() => { + const isSelected = this.selected.value + if (isSelected) { + this.dom.classList.add('selected') + } else { + this.dom.classList.remove('selected') + } + }) + this.updateLanguage() } @@ -78,19 +94,20 @@ export class CodeMirrorBlock implements NodeView { } private createDom() { - const dom = document.createElement('milkdown-code-block') as HTMLElement & - CodeComponentProps - dom.codemirror = this.cm - dom.getAllLanguages = this.getAllLanguages - dom.setLanguage = this.setLanguage - dom.isEditorReadonly = () => !this.view.editable - dom.text = this.node.textContent - const { - languages: _languages, - extensions: _extensions, - ...viewConfig - } = this.config - dom.config = viewConfig + const dom = document.createElement('div') + dom.className = 'milkdown-code-block' + this.text.value = this.node.textContent + const app = createApp(CodeBlock, { + text: this.text, + selected: this.selected, + readonly: this.readonly, + codemirror: this.cm, + language: this.language, + getAllLanguages: this.getAllLanguages, + setLanguage: this.setLanguage, + config: this.config, + }) + app.mount(dom) return dom } @@ -99,7 +116,7 @@ export class CodeMirrorBlock implements NodeView { if (languageName === this.languageName) return - this.dom.language = languageName + this.language.value = languageName const language = this.loader.load(languageName ?? '') language.then((lang) => { @@ -196,7 +213,7 @@ export class CodeMirrorBlock implements NodeView { if (this.updating) return true this.node = node - this.dom.text = node.textContent + this.text.value = node.textContent this.updateLanguage() if (this.view.editable === this.cm.state.readOnly) { this.cm.dispatch({ @@ -218,12 +235,12 @@ export class CodeMirrorBlock implements NodeView { } selectNode() { - this.dom.selected = true + this.selected.value = true this.cm.focus() } deselectNode() { - this.dom.selected = false + this.selected.value = false } stopEvent() { @@ -232,6 +249,7 @@ export class CodeMirrorBlock implements NodeView { destroy() { this.cm.destroy() + this.disposeSelectedWatcher() } setLanguage = (language: string) => { diff --git a/packages/crepe/src/feature/code-mirror/index.ts b/packages/crepe/src/feature/code-mirror/index.ts index 6826b9793e8..0ee58557b3e 100644 --- a/packages/crepe/src/feature/code-mirror/index.ts +++ b/packages/crepe/src/feature/code-mirror/index.ts @@ -7,7 +7,6 @@ import type { Extension } from '@codemirror/state' import { basicSetup } from 'codemirror' import { keymap } from '@codemirror/view' import { defaultKeymap, indentWithTab } from '@codemirror/commands' -import { html } from 'atomico' import type { DefineFeature, Icon } from '../shared' import { chevronDownIcon, clearIcon, editIcon, searchIcon } from '../../icons' import { visibilityOffIcon } from '../../icons/visibility-off' @@ -24,10 +23,7 @@ interface CodeMirrorConfig { searchPlaceholder: string noResultText: string - renderLanguage: ( - language: string, - selected: boolean - ) => ReturnType | string + renderLanguage: (language: string, selected: boolean) => string renderPreview: ( language: string, @@ -35,8 +31,8 @@ interface CodeMirrorConfig { ) => string | HTMLElement | null previewToggleIcon: (previewOnlyMode: boolean) => ReturnType - previewToggleText: (previewOnlyMode: boolean) => ReturnType - previewLabel: () => ReturnType + previewToggleText: (previewOnlyMode: boolean) => string + previewLabel: () => string } export type CodeMirrorFeatureConfig = Partial @@ -66,20 +62,21 @@ export const defineFeature: DefineFeature = ( ], languages, - expandIcon: config.expandIcon || (() => chevronDownIcon), - searchIcon: config.searchIcon || (() => searchIcon), - clearSearchIcon: config.clearSearchIcon || (() => clearIcon), + expandIcon: () => config.expandIcon?.() || chevronDownIcon, + searchIcon: () => config.searchIcon?.() || searchIcon, + clearSearchIcon: () => config.clearSearchIcon?.() || clearIcon, searchPlaceholder: config.searchPlaceholder || 'Search language', noResultText: config.noResultText || 'No result', renderLanguage: config.renderLanguage || defaultConfig.renderLanguage, renderPreview: config.renderPreview || defaultConfig.renderPreview, previewToggleButton: (previewOnlyMode) => { - return html` - ${config.previewToggleIcon?.(previewOnlyMode) || - (previewOnlyMode ? editIcon : visibilityOffIcon)} - ${config.previewToggleText?.(previewOnlyMode) || - (previewOnlyMode ? 'Edit' : 'Hide')} - ` + const icon = + config.previewToggleIcon?.(previewOnlyMode) || + (previewOnlyMode ? editIcon : visibilityOffIcon) + const text = + config.previewToggleText?.(previewOnlyMode) || + (previewOnlyMode ? 'Edit' : 'Hide') + return [icon, text].map((v) => v.trim()).join(' ') }, previewLabel: config.previewLabel || defaultConfig.previewLabel, })) diff --git a/packages/crepe/src/feature/link-tooltip/index.ts b/packages/crepe/src/feature/link-tooltip/index.ts index 9d1dc11789b..49627d04674 100644 --- a/packages/crepe/src/feature/link-tooltip/index.ts +++ b/packages/crepe/src/feature/link-tooltip/index.ts @@ -4,7 +4,12 @@ import { linkTooltipPlugin, } from '@milkdown/kit/component/link-tooltip' import type { DefineFeature, Icon } from '../shared' -import { legacyConfirmIcon, copyIcon, editIcon, removeIcon } from '../../icons' +import { + legacyConfirmIcon, + copyIcon, + removeIcon, + legacyEditIcon, +} from '../../icons' interface LinkTooltipConfig { linkIcon: Icon @@ -27,7 +32,7 @@ export const defineFeature: DefineFeature = ( ctx.update(linkTooltipConfig.key, (prev) => ({ ...prev, linkIcon: config?.linkIcon ?? (() => copyIcon), - editButton: config?.editButton ?? (() => editIcon), + editButton: config?.editButton ?? (() => legacyEditIcon), removeButton: config?.removeButton ?? (() => removeIcon), confirmButton: config?.confirmButton ?? (() => legacyConfirmIcon), inputPlaceholder: config?.inputPlaceholder ?? 'Paste link...', diff --git a/packages/crepe/src/icons/chevron-down.ts b/packages/crepe/src/icons/chevron-down.ts index 1dacec35378..08e45c669df 100644 --- a/packages/crepe/src/icons/chevron-down.ts +++ b/packages/crepe/src/icons/chevron-down.ts @@ -1,6 +1,4 @@ -import { html } from 'atomico' - -export const chevronDownIcon = html` +export const chevronDownIcon = ` + + + + + + + + + +` + +export const legacyEditIcon = html` = { ...defaultConfig, languages, extensions: [basicSetup, oneDark, keymap.of(defaultKeymap)], - renderLanguage: (language, selected) => { - return html`${selected ? check : null}${language}` - }, + renderLanguage: (language, selected) => + `${selected ? '✓' : ' '} ${language}`, })) }) .use(codeBlockComponent)