โปรแกรมแก้ไขที่ใช้ React และ Prosemirror ซึ่งขับเคลื่อน Outline และยังสามารถใช้เพื่อแสดงเนื้อหาในรูปแบบอ่านอย่างเดียวได้อีกด้วย ตัวแก้ไขเป็นแบบ WYSIWYG และมีเครื่องมือการจัดรูปแบบในขณะที่ยังคงความสามารถในการเขียนทางลัดมาร์กดาวน์แบบอินไลน์และเอาต์พุตมาร์กดาวน์ธรรมดา ดู หนังสือนิทานสาธิตสด
หมายเหตุสำคัญ: โปรเจ็กต์นี้ ไม่ได้พยายามที่จะเป็นตัวแก้ไข Markdown อเนกประสงค์ สร้างขึ้นสำหรับฐานความรู้ Outline และในขณะที่ผู้อื่นสามารถแยกหรือใช้แพ็คเกจนี้ในผลิตภัณฑ์ของคุณเองได้ การตัดสินใจในการพัฒนาจะมุ่งเน้นไปที่ความต้องการของ Outline
yarn add rich-markdown-editorหรือ
npm install rich-markdown-editor โปรดทราบว่า react , react-dom และ styled-components จำเป็นต้องมี การพึ่งพาเพียร์
import Editor from "rich-markdown-editor" ;
< Editor
defaultValue = "Hello world!"
/> โคลน repo นี้และรัน Storybook ด้วย yarn start เห็นตัวอย่างการใช้งานที่หลากหลาย
id รหัสเฉพาะสำหรับตัวแก้ไขนี้ ใช้เพื่อคงการตั้งค่าไว้ในที่จัดเก็บในตัวเครื่อง หากไม่มีการส่ง id ตัวแก้ไขจะตั้งค่าเริ่มต้นให้ใช้ชื่อพาธของตำแหน่ง
defaultValueสตริงมาร์กดาวน์ที่แสดงถึงค่าเริ่มต้นของเอดิเตอร์ ใช้สิ่งนี้เพื่อค้ำยันเพื่อกู้คืนเนื้อหาที่บันทึกไว้ก่อนหน้านี้เพื่อให้ผู้ใช้แก้ไขต่อไป
value สตริงมาร์กดาวน์ที่แสดงถึงค่าของเอดิเตอร์ ใช้เสานี้เพื่อเปลี่ยนค่าของตัวแก้ไขเมื่อติดตั้งแล้ว ซึ่งจะเรนเดอร์ตัวแก้ไขทั้งหมดอีกครั้ง และด้วยเหตุนี้จึงเหมาะสมเมื่ออยู่ในโหมด readOnly อย่างเดียวเท่านั้น อย่าไปป์ค่าของ onChange กลับเข้าไปใน value ตัวแก้ไขจะคงสถานะภายในของตัวเองไว้ และจะส่งผลให้เกิดผลข้างเคียงที่ไม่คาดคิด
placeholderอนุญาตให้แทนที่ตัวยึดตำแหน่ง ค่าเริ่มต้นคือ "เขียนสิ่งที่ดี…"
readOnly เมื่อตั้ง readOnly เป็น false ตัวแก้ไขจะได้รับการปรับให้เหมาะสมสำหรับการจัดองค์ประกอบ เมื่อ true สามารถใช้ตัวแก้ไขเพื่อแสดงเนื้อหาที่เขียนไว้ก่อนหน้านี้ - ส่วนหัวจะมีจุดยึดและลิงก์สามารถคลิกได้
readOnlyWriteCheckboxes ด้วย readOnlyWriteCheckboxes ที่ตั้งค่าเป็น true กล่องกาเครื่องหมายยังคงสามารถเลือกหรือยกเลิกการเลือกเป็นกรณีพิเศษได้ ในขณะที่ readOnly ถูกตั้งค่าเป็น true และตัวแก้ไขจะไม่สามารถแก้ไขได้
autoFocus เมื่อตั้งค่า true ร่วมกับตั้ง readOnly เป็น false ให้โฟกัสที่ส่วนท้ายของเอกสารโดยอัตโนมัติ
maxLengthเมื่อตั้งค่าบังคับใช้ความยาวอักขระสูงสุดในเอกสาร ไม่รวมไวยากรณ์มาร์กดาวน์
extensionsอนุญาตให้ส่งปลั๊กอิน Prosemirror เพิ่มเติมไปยังอินสแตนซ์ Prosemirror พื้นฐาน
disableExtensions รายการชื่อส่วนขยายที่รวมไว้เพื่อปิดใช้งาน ลบรายการเมนูและคำสั่งที่เกี่ยวข้อง เช่น ตั้งค่าเป็น ["em", "blockquote"] เพื่อปิดการใช้งานข้อความตัวเอียงและ blockquotes
themeอนุญาตให้แทนที่ธีมที่ฝังไว้เพื่อสร้างแบรนด์ให้กับตัวแก้ไข เช่น ใช้แบบอักษรและสีของแบรนด์ของคุณเองเพื่อให้ตัวแก้ไขพอดีกับแอปพลิเคชันของคุณ ดูธีมในตัวสำหรับตัวอย่างคีย์ที่ควรระบุ
dictionaryอนุญาตให้แทนที่พจนานุกรมคัดลอกแบบ inbuilt เช่น ทำให้เอดิเตอร์เป็นสากล ดูพจนานุกรมในตัวสำหรับตัวอย่างคีย์ที่ควรระบุ
dark เมื่อตั้งค่า dark เป็น true ตัวแก้ไขจะใช้ธีมสีเข้มเริ่มต้นที่รวมอยู่ด้วย ดูแหล่งที่มาที่นี่
dir ค่าเริ่มต้น: auto
ควบคุมทิศทางของเอกสาร ค่าที่เป็นไปได้คือ:
ltr : เค้าโครงของตัวแก้ไขได้รับการปรับให้เหมาะสมสำหรับเอกสาร LTR และเนื้อหาถูกทำเครื่องหมายอย่างชัดเจนว่าเป็น LTRrtl : เค้าโครงตัวแก้ไขได้รับการปรับให้เหมาะสมสำหรับเอกสาร RTL และเนื้อหาถูกทำเครื่องหมายอย่างชัดเจนว่าเป็น RTLauto : เค้าโครงของตัวแก้ไขถูกกำหนดโดยเบราว์เซอร์ตามเนื้อหาเอกสาร tooltipส่วนประกอบ React ที่จะพันรอบรายการที่มีคำแนะนำเครื่องมือเสริม คุณสามารถใช้สิ่งนี้เพื่อแทรกไลบรารีคำแนะนำเครื่องมือของคุณเองลงในตัวแก้ไข - ส่วนประกอบจะถูกส่งผ่านอุปกรณ์ประกอบฉากต่อไปนี้:
tooltip : โหนด React พร้อมเนื้อหาคำแนะนำเครื่องมือplacement : Enum top , bottom , left , rightchildren : จะต้องแสดงผลส่วนประกอบที่คำแนะนำเครื่องมือล้อมรอบ headingsOffset ตัวเลขที่จะชดเชยส่วนหัวของเอกสารตามระดับต่างๆ ตัวอย่างเช่น หากคุณซ้อนเอดิเตอร์ไว้ใต้ชื่อหลัก h1 คุณอาจต้องการให้ผู้ใช้สร้างได้เฉพาะส่วนหัว h2 และต่ำกว่านั้น ในกรณีนี้ คุณจะตั้งค่า prop เป็น 1
scrollToสตริงที่แสดงถึงจุดยึดส่วนหัว เอกสารจะเลื่อนได้อย่างราบรื่นเพื่อให้มองเห็นส่วนหัวได้ในวิวพอร์ต
embeds คุณสามารถเลือกกำหนดการฝังซึ่งจะถูกแทรกแทนลิงก์เมื่อฟังก์ชัน matcher ส่งกลับค่าความจริง ค่าที่ส่งคืนของเมธอด matcher จะมีอยู่ในส่วนประกอบภายใต้ props.attrs.matches หากมีการระบุ title และ icon การฝังจะปรากฏในเมนูบล็อกด้วย
< Editor
embeds = { [
{
title : "Google Doc" ,
keywords : "google docs gdocs" ,
icon : < GoogleDocIcon /> ,
defaultHidden : false ,
matcher : href => href . matches ( / docs.google.com / i ) ,
component : GoogleDocEmbed
}
] }
/>uploadImage(file: Blob): Promise<string> หากคุณต้องการให้โปรแกรมแก้ไขสนับสนุนรูปภาพ จะต้องจัดให้มีการติดต่อกลับนี้ การโทรกลับควรยอมรับออบเจ็กต์ File เดียวและส่งคืนสัญญาว่าจะแก้ไขเป็น url เมื่อรูปภาพถูกอัพโหลดไปยังตำแหน่งที่เก็บข้อมูล เช่น S3 เช่น:
< Editor
uploadImage = { async file => {
const result = await s3 . upload ( file ) ;
return result . url ;
} }
/> onBlur(): void การเรียกกลับนี้จะถูกทริกเกอร์เมื่อผู้ใช้สูญเสียความสนใจไปที่ตัวแก้ไขที่สามารถแก้ไขได้และองค์ประกอบ UI ที่เกี่ยวข้องทั้งหมด เช่น เมนูบล็อกและแถบเครื่องมือแบบลอย หากคุณต้องการฟังเหตุการณ์เบลอ เฉพาะ ในพื้นที่ที่แก้ไขเนื้อหาได้ ให้ใช้อุปกรณ์ประกอบฉาก handleDOMEvents
onFocus(): void การเรียกกลับนี้จะถูกทริกเกอร์เมื่อผู้ใช้มุ่งเน้นไปที่ตัวแก้ไขที่แก้ไขเนื้อหาได้หรือองค์ประกอบ UI ที่เกี่ยวข้อง เช่น เมนูบล็อกหรือแถบเครื่องมือแบบลอย หากคุณต้องการฟังเหตุการณ์โฟกัส เฉพาะ ในพื้นที่ที่แก้ไขเนื้อหาได้ ให้ใช้อุปกรณ์ประกอบฉาก handleDOMEvents
onSave({ done: boolean }): void การเรียกกลับนี้จะถูกทริกเกอร์เมื่อผู้ใช้ร้องขออย่างชัดเจนให้บันทึกโดยใช้แป้นพิมพ์ลัด Cmd+S หรือ Cmd+Enter คุณสามารถใช้สิ่งนี้เป็นสัญญาณในการบันทึกเอกสารไปยังเซิร์ฟเวอร์ระยะไกล
onCancel(): void การเรียกกลับนี้จะถูกทริกเกอร์เมื่อมีการกด Cmd+Escape ภายในตัวแก้ไข คุณสามารถใช้มันเพื่อยกเลิกการแก้ไข
onChange(() => value): voidการโทรกลับนี้จะถูกทริกเกอร์เมื่อเนื้อหาของตัวแก้ไขเปลี่ยนแปลง โดยปกติเนื่องจากการป้อนข้อมูลของผู้ใช้ เช่น การกดแป้นพิมพ์หรือการใช้ตัวเลือกการจัดรูปแบบ คุณสามารถใช้สิ่งนี้เพื่อคงสถานะบรรณาธิการไว้ในเครื่องได้
มันจะส่งคืนฟังก์ชันซึ่งเมื่อถูกเรียกจะส่งกลับค่าข้อความปัจจุบันของเอกสาร การเพิ่มประสิทธิภาพนี้จัดทำขึ้นเพื่อหลีกเลี่ยงการทำให้สถานะของเอกสารเป็นอนุกรมเป็นข้อความในทุกเหตุการณ์การเปลี่ยนแปลง ช่วยให้แอปโฮสต์สามารถเลือกได้เมื่อต้องการค่าซีเรียลไลซ์
onImageUploadStart(): void การเรียกกลับนี้จะถูกทริกเกอร์ก่อน uploadImage และสามารถใช้เพื่อแสดง UI บางส่วนที่ระบุว่ากำลังอัปโหลดอยู่
onImageUploadStop(): voidทริกเกอร์เมื่อการอัปโหลดรูปภาพสำเร็จหรือล้มเหลว
onSearchLink(term: string): Promise<{ title: string, subtitle?: string, url: string }[]>ตัวแก้ไขให้ความสามารถในการค้นหาลิงก์เพื่อแทรกจากแถบเครื่องมือการจัดรูปแบบ หากมีการระบุการเรียกกลับนี้ ควรยอมรับคำค้นหาเป็นพารามิเตอร์เดียว และส่งคืนสัญญาที่แก้ไขเป็นอาร์เรย์ของอ็อบเจ็กต์ เช่น:
< Editor
onSearchLink = { async searchTerm => {
const results = await MyAPI . search ( searchTerm ) ;
return results . map ( result => {
title : result . name ,
subtitle : `Created ${ result . createdAt } ` ,
url : result . url
} )
} }
/> onCreateLink(title: string): Promise<string>ตัวแก้ไขให้ความสามารถในการสร้างลิงก์จากแถบเครื่องมือการจัดรูปแบบสำหรับการสร้างเอกสารได้ทันที หากมีการระบุการเรียกกลับนี้ ควรยอมรับลิงก์ "ชื่อ" เป็นพารามิเตอร์เดียว และส่งคืนสัญญาที่แก้ไขเป็น URL สำหรับลิงก์ที่สร้างขึ้น เช่น:
< Editor
onCreateLink = { async title => {
const url = await MyAPI . create ( {
title
} ) ;
return url ;
} }
/> onShowToast(message: string, type: ToastType): void ทริกเกอร์เมื่อตัวแก้ไขต้องการแสดงข้อความถึงผู้ใช้ เชื่อมต่อระบบการแจ้งเตือนของแอปของคุณ หรือใช้ window.alert(message) ง่ายๆ พารามิเตอร์ตัวที่สองคือประเภทของขนมปังปิ้ง: 'error' หรือ 'info'
onClickLink(href: string, event: MouseEvent): void การโทรกลับนี้ช่วยให้สามารถแทนที่การจัดการลิงก์ได้ มักเป็นกรณีที่คุณต้องการให้ลิงก์ภายนอกเปิดหน้าต่างใหม่ และมีลิงก์ภายในใช้บางอย่างเช่น react-router เพื่อนำทาง หากไม่มีการระบุการโทรกลับ พฤติกรรมเริ่มต้นของการเปิดแท็บใหม่จะมีผลกับลิงก์ทั้งหมด เช่น:
import { history } from "react-router" ;
< Editor
onClickLink = { ( href , event ) => {
if ( isInternalLink ( href ) ) {
history . push ( href ) ;
} else {
window . location . href = href ;
}
} }
/> onHoverLink(event: MouseEvent): booleanการโทรกลับนี้ช่วยให้ตรวจจับเมื่อผู้ใช้วางเมาส์เหนือลิงก์ในเอกสาร
< Editor
onHoverLink = { event => {
console . log ( `Hovered link ${ event . target . href } ` ) ;
} }
/> onClickHashtag(tag: string, event: MouseEvent): voidการโทรกลับนี้ช่วยให้สามารถจัดการการคลิกแฮชแท็กในข้อความในเอกสารได้ หากไม่มีการติดต่อกลับ แฮชแท็กจะแสดงเป็นข้อความปกติ ดังนั้นคุณจึงสามารถเลือกได้ว่าจะสนับสนุนหรือไม่โดยการส่งพร็อพนี้
import { history } from "react-router" ;
< Editor
onClickHashtag = { tag => {
history . push ( `/hashtags/ ${ tag } ` ) ;
} }
/> handleDOMEvents: {[name: string]: (view: EditorView, event: Event) => boolean;} ออบเจ็กต์นี้จับคู่ชื่อเหตุการณ์ ( focus , paste , touchstart ฯลฯ ) กับฟังก์ชันโทรกลับ
< Editor
handleDOMEvents = { {
focus : ( ) => console . log ( "FOCUS" ) ,
blur : ( ) => console . log ( "BLUR" ) ,
paste : ( ) => console . log ( "PASTE" ) ,
touchstart : ( ) => console . log ( "TOUCH START" ) ,
} }
/>ส่วนประกอบตัวแก้ไขจะแสดงวิธีการโต้ตอบกับตัวแก้ไขที่เมาท์
focusAtStart(): voidวางเคอร์เซอร์ที่จุดเริ่มต้นของเอกสารแล้วโฟกัส
focusAtEnd(): voidวางเคอร์เซอร์ที่ส่วนท้ายของเอกสารแล้วโฟกัส
getHeadings(): { title: string, level: number, id: string }[] ส่งกลับอาร์เรย์ของออบเจ็กต์ที่มีเนื้อหาข้อความของส่วนหัวทั้งหมดในเอกสาร ระดับในลำดับชั้น และรหัสจุดยึด สิ่งนี้มีประโยชน์ในการสร้างสารบัญของคุณเอง เนื่องจากตัวเลือก toc ถูกลบออกในเวอร์ชัน 10
โปรเจ็กต์นี้ใช้เส้นด้ายเพื่อจัดการการขึ้นต่อกัน คุณสามารถใช้ npm ได้ แต่จะไม่เคารพไฟล์ Yarn Lock และอาจติดตั้งเวอร์ชันที่แตกต่างกันเล็กน้อย
yarn install
เมื่อรันในการพัฒนา Storybook จะถูกรวมไว้ในตัวอย่างบรรณาธิการพร้อมการโหลดซ้ำแบบร้อนแรง หลังจากติดตั้งการพึ่งพาแล้วให้ yarn start ดำเนินการ
เมื่อพัฒนาโดยใช้ yarn link คุณสามารถใช้ yarn watch เพื่อสร้างการเปลี่ยนแปลงอย่างต่อเนื่องเป็น dist ในขณะที่คุณทำการเปลี่ยนแปลง
โครงการนี้ได้รับอนุญาตจาก BSD