محرر قائم على React وProsemirror يعمل على تشغيل Outline ويمكن استخدامه أيضًا لعرض المحتوى بطريقة القراءة فقط. المحرر هو WYSIWYG ويتضمن أدوات التنسيق مع الاحتفاظ بالقدرة على كتابة اختصارات تخفيض السعر مضمنة وإخراج Markdown عادي. شاهد كتاب القصص التجريبي المباشر .
ملاحظة مهمة: هذا المشروع لا يحاول أن يكون محرر 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!"
/>
انسخ هذا الريبو وقم بتشغيل 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"]
لتعطيل النص المائل وعلامات الاقتباس.
theme
يسمح بتجاوز السمة المضمنة لتمييز المحرر، على سبيل المثال، استخدم وجه الخط وألوان العلامة التجارية الخاصة بك حتى يتناسب المحرر مع تطبيقك. راجع السمة المضمنة للحصول على مثال للمفاتيح التي ينبغي توفيرها.
dictionary
يسمح بتجاوز قاموس النسخ المدمج، على سبيل المثال لتدويل المحرر. راجع القاموس المدمج للحصول على مثال للمفاتيح التي ينبغي توفيرها.
dark
مع ضبط الوضع dark
على true
، سيستخدم المحرر المظهر الداكن الافتراضي المضمن. انظر المصدر هنا.
dir
الافتراضي: auto
يتحكم في اتجاه الوثيقة. القيم المحتملة هي:
ltr
: تم تحسين تخطيط المحرر لمستندات LTR وتم وضع علامة واضحة على المحتوى على أنه LTR.rtl
: تم تحسين تخطيط المحرر لمستندات RTL وتم وضع علامة واضحة على المحتوى على أنه RTL.auto
: يتم تحديد تخطيط المحرر بواسطة المتصفح بناءً على محتوى المستند. tooltip
مكون React الذي سيتم تغليفه حول العناصر التي تحتوي على تلميح أدوات اختياري. يمكنك استخدام هذا لإدخال مكتبة تلميحات الأدوات الخاصة بك في المحرر - سيتم تمرير المكون الدعائم التالية:
tooltip
: عقدة React مع محتوى تلميح الأداةplacement
: التعداد top
، bottom
، left
، right
children
: يجب أن يتم عرض المكون الذي يغلفه تلميح الأداة headingsOffset
رقم سيعوض عناوين المستند بعدد من المستويات. على سبيل المثال، إذا قمت بالفعل بدمج المحرر تحت عنوان h1
رئيسي، فقد ترغب في أن يتمكن المستخدم فقط من إنشاء عناوين h2
وما دونها، وفي هذه الحالة يمكنك تعيين الدعامة إلى 1
.
scrollTo
سلسلة تمثل رابط العنوان - سيتم تمرير المستند بشكل سلس بحيث يكون العنوان مرئيًا في إطار العرض.
embeds
اختياريًا، حدد التضمينات التي سيتم إدراجها بدلاً من الروابط عندما تقوم وظيفة 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
يتم تشغيل رد الاتصال هذا عندما يفقد المستخدم التركيز على محتوى المحرر القابل للتحرير وجميع عناصر واجهة المستخدم المرتبطة به مثل قائمة الحظر وأشرطة الأدوات العائمة. إذا كنت تريد الاستماع إلى أحداث التمويه في المنطقة القابلة للتحرير فقط ، فاستخدم خاصية handleDOMEvents
.
onFocus(): void
يتم تشغيل رد الاتصال هذا عندما يكتسب المستخدم التركيز على محتوى المحرر القابل للتحرير أو أي عناصر واجهة مستخدم مرتبطة مثل قائمة الحظر أو أشرطة الأدوات العائمة. إذا كنت تريد الاستماع إلى أحداث التركيز على المنطقة القابلة للتحرير فقط ، فاستخدم خاصية handleDOMEvents
.
onSave({ done: boolean }): void
يتم تشغيل رد الاتصال هذا عندما يطلب المستخدم صراحةً الحفظ باستخدام اختصار لوحة المفاتيح، Cmd+S
أو Cmd+Enter
. يمكنك استخدام هذا كإشارة لحفظ المستند على خادم بعيد.
onCancel(): void
يتم تشغيل رد الاتصال هذا عند الضغط على Cmd+Escape
داخل المحرر. يمكنك استخدامه لإلغاء التحرير.
onChange(() => value): void
يتم تشغيل رد الاتصال هذا عندما تتغير محتويات المحرر، عادةً بسبب إدخال المستخدم مثل ضغطة المفاتيح أو استخدام خيارات التنسيق. يمكنك استخدام هذا للاستمرار في حالة المحررين محليًا.
تقوم بإرجاع دالة تقوم عند استدعائها بإرجاع القيمة النصية الحالية للمستند. تم إجراء هذا التحسين لتجنب إجراء تسلسل لحالة المستند إلى نص في كل حدث تغيير، مما يسمح للتطبيق المضيف باختيار الوقت الذي يحتاج فيه إلى القيمة المتسلسلة.
onImageUploadStart(): void
يتم تشغيل رد الاتصال هذا قبل uploadImage
ويمكن استخدامه لإظهار بعض واجهة المستخدم التي تشير إلى أن التحميل قيد التقدم.
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)
بشكل مبسط. المعلمة الثانية هي نوع الخبز المحمص: "خطأ" أو "معلومات".
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 install
عند التشغيل في مرحلة التطوير، يتم تضمين Storybook في أمثلة المحررين الذين يقومون بإعادة التحميل السريع. بعد تثبيت التبعيات، قم بتشغيل yarn start
للبدء.
عند التطوير باستخدام yarn link
، يمكنك استخدام yarn watch
لإعادة البناء بشكل مستمر عند التغيير إلى dist
أثناء إجراء التغييرات.
هذا المشروع مرخص من BSD.