โปรแกรมแก้ไขที่ใช้ 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
, right
children
: จะต้องแสดงผลส่วนประกอบที่คำแนะนำเครื่องมือล้อมรอบ 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