Skip to content

Commit

Permalink
refactor: move rt segmenter to inside posts
Browse files Browse the repository at this point in the history
  • Loading branch information
mary-ext committed Dec 13, 2023
1 parent 6d5cef7 commit 4a44fb3
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 42 deletions.
22 changes: 22 additions & 0 deletions app/api/richtext/renderer.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
import { createRoot } from 'solid-js';

import { createLazyMemo } from '~/utils/hooks.ts';

import { segmentRichText } from './segmentize.ts';
import type { Facet } from './types.ts';

const TRIM_HOST_RE = /^www\./;
const TRIM_URLTEXT_RE = /^\s*(https?:\/\/)?(?:www\.)?/;
const PATH_MAX_LENGTH = 18;
Expand Down Expand Up @@ -67,3 +74,18 @@ export const isLinkValid = (uri: string, text: string) => {
normalized.startsWith(expectedHost)
);
};

export interface RtReturn {
t: string;
f: Facet[] | undefined;
}

export const createRichTextSegmenter = (accessor: () => RtReturn) => {
return createRoot(() => {
return createLazyMemo(() => {
const { t: text, f: facets } = accessor();

return segmentRichText(text, facets);
});
});
};
11 changes: 11 additions & 0 deletions app/api/stores/posts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { type Signal, signal } from '~/utils/signals.ts';

import type { DID, Records, RefOf } from '../atp-schema.ts';

import { createRichTextSegmenter } from '../richtext/renderer.ts';
import type { RichTextSegment } from '../richtext/types.ts';

import { type SignalizedProfile, mergeProfile } from './profiles.ts';

type Post = RefOf<'app.bsky.feed.defs#postView'>;
Expand Down Expand Up @@ -39,6 +42,8 @@ export class SignalizedPost {
readonly replyDisabled: Signal<NonNullable<Post['viewer']>['replyDisabled']>;
};

readonly rtSegments: () => RichTextSegment[];

$truncated?: boolean;

constructor(uid: DID, post: Post, key?: number) {
Expand All @@ -61,6 +66,12 @@ export class SignalizedPost {
repost: signal(post.viewer?.repost),
replyDisabled: signal(post.viewer?.replyDisabled),
};

this.rtSegments = createRichTextSegmenter(() => {
const record = this.record.value;

return { t: record.text, f: record.facets };
});
}
}

Expand Down
53 changes: 11 additions & 42 deletions app/com/components/RichTextRenderer.tsx
Original file line number Diff line number Diff line change
@@ -1,45 +1,20 @@
import { type JSX, createRoot } from 'solid-js';
import { type JSX } from 'solid-js';

import { isLinkValid } from '~/api/richtext/renderer.ts';
import { segmentRichText } from '~/api/richtext/segmentize.ts';
import type { Facet, RichTextSegment } from '~/api/richtext/types.ts';

import { createLazyMemo } from '~/utils/hooks.ts';
import type { RichTextSegment } from '~/api/richtext/types.ts';

import { type Linking, LINK_EXTERNAL, LINK_PROFILE, LINK_TAG, useLinking } from './Link.tsx';

export interface RichTextReturn {
t: string;
f: Facet[] | undefined;
export interface RtExpectedObject {
rtSegments: () => RichTextSegment[];
}

export interface RichTextRendererProps<T extends object> {
export interface RichTextRendererProps<T extends RtExpectedObject> {
item: T;
/** Expected to be static */
get: (item: T) => RichTextReturn;
}

interface RichTextUiSegment {
text: string;
to: Linking | undefined;
}

const richtexts = new WeakMap<WeakKey, () => RichTextUiSegment[]>();

const RichTextRenderer = <T extends object>(props: RichTextRendererProps<T>) => {
const RichTextRenderer = <T extends RtExpectedObject>(props: RichTextRendererProps<T>) => {
const linking = useLinking();
const get = props.get;

const segments = () => {
const item = props.item;

let segmenter = richtexts.get(item);
if (!segmenter) {
richtexts.set(item, (segmenter = createSegmenter(item, get)));
}

return segmenter();
};

const navigateLink = (ev: MouseEvent | KeyboardEvent) => {
const enum ShouldLink {
Expand Down Expand Up @@ -67,7 +42,7 @@ const RichTextRenderer = <T extends object>(props: RichTextRendererProps<T>) =>
};

const render = () => {
const ui = segments();
const ui = renderRichText(props.item.rtSegments());
const nodes: JSX.Element = [];

for (let idx = 0, len = ui.length; idx < len; idx++) {
Expand Down Expand Up @@ -115,16 +90,10 @@ const RichTextRenderer = <T extends object>(props: RichTextRendererProps<T>) =>

export default RichTextRenderer;

const createSegmenter = <T extends object>(item: T, get: (item: T) => RichTextReturn) => {
return createRoot(() => {
return createLazyMemo((): RichTextUiSegment[] => {
const { t: text, f: facets } = get(item);

const segments = segmentRichText(text, facets);
return renderRichText(segments);
});
});
};
interface RichTextUiSegment {
text: string;
to: Linking | undefined;
}

const renderRichText = (segments: RichTextSegment[]): RichTextUiSegment[] => {
const ui: RichTextUiSegment[] = [];
Expand Down

0 comments on commit 4a44fb3

Please sign in to comment.