Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugin factory poc #2242

Open
wants to merge 28 commits into
base: master
Choose a base branch
from
Open

Plugin factory poc #2242

wants to merge 28 commits into from

Conversation

MaPoKen
Copy link
Contributor

@MaPoKen MaPoKen commented Feb 16, 2024

Plugin factory: Samle felles plugin logikk og gjør plugins mer debuggable

Kodemessig blir det ikke mindre kode men det skal heller ikke bli så mye mer!

Hovedtanken med factory er å gi oss bedre mulighet til å debugge koden ved normalization/keyevents, men også introdusere en enklere måte å lage felleskode til pluginsene våre.

Største forandringen er hvordan vi normaliserer. Før så ville vi ha en stor metode med ørten if setninger som gjorde readability dårlig, tanken nå er at vi har en array med et normalize objekt. Normalize objektet inneholder en funksjon normalize som er som regel en if funksjon og description som forklarer hva normalize metoden skal gjøre. Håpet er at dette enforcer forklaringer av normaliseringer og gjør normaliseringer litt mer readable.

Ideèr som har blitt innført:

  • Normaliseringen breaker ikke nå ved første "hit" for en gitt plugin den vil gjennomføre hele normaliseringen for et elementet før den eventuelt returnerer void. NB: dette må nok testes godt men jeg tenker nå at det burde spare oss noen iterasjoner gjennom koden å kunne normalisere alt, worst case er det en enkel fiks

KOM GJERNE MED IDEER 👯

const defaultNormalized = normalizerConfig ? defaultBlockNormalizer(editor, entry, normalizerConfig) : false;
const normalized = normalize?.reduceRight((acc, { description, normalize }) => {
const isNormalized = normalize(entry as NodeEntry<T>, editor);
if (process.env.DEBUG_SLATE && isNormalized) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Legg heller dette inn i config. Process er egentlig ikke definert på klient. Denne pakken skulle egentlig vært fjernet.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eller, kanskje vi kan tåle at denne ligger i import.meta.env? Har prøvd å holde meg unna den, men i dette tilfellet er det jo forsåvidt et "build time-flagg"


type KeyDown = (e: KeyboardEvent, editor: Editor, nextOnKeyDown?: (event: KeyboardEvent) => void) => void;

const createPluginFactory =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kan heller exporte denne. Ser at du har importert den med stor C


editor.normalizeNode = (entry) => {
const [node] = entry;
if (Element.isElement(node) && node.type === type) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mistenker at dette ikke kommer til å holde. Når vi sjekker etter eksterne embeds sjekker vi for eksempel etter både external og iframe

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, det er jo mega kjipt.
Men ser at de er mega minimalistiske, kan vi ikke bare evt. lage plugins for de?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nei, egentlig ikke. Man vet ikke om noe er en external eller iframe før man prøver å lagre de.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Det kommer ikke til å bli et problem. Vi kan bare lage External plugin med en child plugin som dekker casene for enten iframe eller external. Bing smack.

},
},
{
description: "Unrwap sibling paragraphs if either has serializeAsText",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skriveleif

Comment on lines 45 to 54
normalizerConfig: {
previous: {
allowed: afterOrBeforeTextBlockElement,
defaultType: TYPE_PARAGRAPH,
},
next: {
allowed: afterOrBeforeTextBlockElement,
defaultType: TYPE_PARAGRAPH,
},
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forsåvidt litt ryddig å ikke inline all config. Denne kan fint fortsatt ligge utenfor selve funksjonskallet som den gjorde før. Da blir den litt lettere å lese

type: Element["type"];
normalize?: Normalize<T>[];
normalizerConfig?: NormalizerConfig;
onKeyDown?: Record<string, KeyDown>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finnes det ikke noe keycode-enum i TypeScript?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, de håndterer det som string...

@MaPoKen MaPoKen marked this pull request as ready for review February 22, 2024 09:15
@MaPoKen MaPoKen requested review from a team February 22, 2024 09:15
@gunnarvelle
Copy link
Member

Lurt å merge inn master igjen for å være sikker på at vi ikkje gjeninnfører ting vi har fiksa tidligere.

@MaPoKen MaPoKen requested a review from Jonas-C February 28, 2024 13:16
editor.onKeyDown = (e) => {
const [entry] = Editor.nodes(editor, { match: (node) => Element.isElement(node) && node.type === type });
if (entry) {
if (onKeyDown?.[e.key]) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tror det blir penere å lagre denne som en variabel, kanskje?

};

editor.onKeyDown = (e) => {
const [entry] = Editor.nodes(editor, { match: (node) => Element.isElement(node) && node.type === type });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dette synes jeg er en degradering fra nåværende løsning. Da henter vi først ut en verdi dersom vi finner en match på onKeyDown. Nå vil vi hente ut en verdi uavhengig av om en onKeyDown er registrert. Vil tro dette kommer til å påvirke ytelse. I og med at vi jobber med en generator her burde det være en måte å skrive dette på som først utfører arbeidet når vi faktisk trenger verdien.


if (detailsNode) {
const summaryEntry = getCurrentBlock(editor, TYPE_SUMMARY);
const onBackspace: KeyDown<DetailsElement["type"]> = (e, editor, entry) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kanskje like greit å slenge inn litt kommentarer her når du først er i gang?

export const detailsPlugin = createPlugin<DetailsElement["type"]>({
type: TYPE_DETAILS,
normalizerConfig: detailsNormalizerConfig,
renderLeaf: ({ attributes, children, text }, editor) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Denne burde egentlig flyttes til render-delen av pluginen

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Med på det 👯

}
}
}
return undefined;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trenger vi å returnere noe her da?

return !!summaryEntry;
},
onKeyDown: {
[KEY_ENTER]: onEnter,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ikke fan av navngivning på funksjonene. Det burde være åpenbart at de tilhører to forskjellige plugins.

[KEY_ENTER]: onEnter,
},
normalize: [
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Er det egentlig noe særlig å tjene på at dette ikke bare er en lang funksjon?

@MaPoKen
Copy link
Contributor Author

MaPoKen commented Mar 27, 2024

Legger til noen plugins for å sjekke om det gir noen forskjeller på performance

@MaPoKen MaPoKen force-pushed the plugin-factory-poc branch from f244f31 to 55737a4 Compare April 2, 2024 12:18
Copy link
Contributor

@katrinewi katrinewi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jeg syntes denne logikken gjør det litt mer oversiktlig og lettere å se hvilke deler som trengs for å lage en ny plugin når man ikke er bestevenn med slate! 😄

Jeg har ikke testet forskjell i hastigheten, så det burde sikkert bli gjort ganske nøye før man lander på å eventuelt ta det videre

Ellers er det en del ubrukte imports rundt om

Comment on lines 22 to 23
normalize?: Normalize<Extract<Element, { type: T }>>[];
normalizerConfig?: NormalizerConfig;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Burde forskjellen på normalize og normalizerConfig vært tydeligere i navngivningen? Jeg syntes ikke det er intuitivt at normalize er spesifikk normaliserings-logikk for en plugin mens normalizerConfig er bruk av default block normalizer ..

[K in ElementType]: Plugin<K>;
};

interface Plugin<T extends ElementType = ElementType> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

En tanke: jeg tror det hadde blitt enda mer forståelig ved å legge på en kommentar med beskrivelse av noen av feltene under her, feks isVoid, childPlugins, shouldHideBlockPicker, renderLeaf ..

Gjerne med denne kommentar-syntaxen: /** Kommentar */, så får man hvertfall i vs-code opp beskrivelsen ved hover

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jeg prøvde å legge til noen kommentare, kan hende noen er litt vage men kan jo eventuelt legge til link til info i slate doc 👯

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Par av kommentarene kan kanskje utbedres:

  • isVoid: Denne er upresis. Void elements kan ha children nodes, men forskjellen er om elementet renderes av Slate eller av Elements' render kode. Første setning er good, men kanskje 2. setning istedet burde sagt "A void element is not rendered by Slate, but by the Element's render kode..." og ev. med en henvisning til doc
  • renderLeaf: Burde kommentaren istedet reflektert at den er for å overstyre heller enn å gjøre et valg? Dersom renderLeaf ikke er satt, vil default node brukes? Så noe i retning av Assign to have the leafNode rendered by a specific JSX.element. Otherwise, a default node will be used

event: NodeEntry<Extract<Element, { type: T }>>,
) => boolean;

export const createPluginFactory =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trenger ikke eksporteres!

};

export const createPlugin = <T extends ElementType>(data: Plugin<T>) => {
const plugins: any[] = [data];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Må denne være any? blir ikke Plugin<T>[] mer riktig?

if (entry) {
if (onKeyDown?.[e.key]) {
if (onKeyDown?.[e.key](e, editor, entry as NodeEntry<Extract<Element, { type: T }>>)) {
if (config.debugSlate) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Er det en grunn til at if-sjekken her er nestet 4 nivåer? (linje 97-100)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Klarte å fjerne en men 3 av de trengs :D 👯

/**
* A method to control if the BlockPickerTrigger should be shown or not given the selection is in a node for this plugin.
*/
shouldHideBlockPicker?: (editor: Editor) => boolean;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Er litt usikker på om jeg liker navnet på denne, synes det fort ser mer komplisert og omstendelig ut når attributter, variabler og lignende begynner på ord som should. Personlig ville jeg gått for showBlockPicker med defaultverdi true, altså motsatt tankegang. Men hideBlockPicker vil også fungere (så logikk ellers ikke må snus) og vil være kortere. Og, imo, hakket mer lesbart når det begynner rett på hide eller show.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants