@djangocfg/ui-tools 2.1.290 → 2.1.292

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,49 @@
1
+ import type { MentionMarkdownRenderer } from './types';
2
+
3
+ /**
4
+ * Escape characters that have meaning in markdown link/inline contexts.
5
+ * Conservative — covers the chars that would break `[text](url)` and
6
+ * inline emphasis when a label contains them.
7
+ */
8
+ const escapeMd = (s: string): string => s.replace(/([\\\[\]()_*~`])/g, '\\$1');
9
+
10
+ /**
11
+ * Built-in serializers for the `MentionConfig.renderMarkdown` callback.
12
+ *
13
+ * Pick one based on what consumes the markdown:
14
+ *
15
+ * - LLM / chat composer → `plainAt` (the default)
16
+ * - Plain text export → `plainLabel`
17
+ * - Web app with deep-link → `markdownLink(baseUrl)`
18
+ * - Notion / Linear-style → `customUri(scheme, kind)`
19
+ * - Slack-style id refs → `slackStyle`
20
+ * - HTML-allowing renderer → `htmlSpan(className?)`
21
+ *
22
+ * Or pass a custom function — the type is just `(attrs) => string`.
23
+ */
24
+ export const mentionPresets = {
25
+ /** "@Label" — default, ideal for chat where LLMs read the text. */
26
+ plainAt: (({ label, id }) => `@${label || id}`) as MentionMarkdownRenderer,
27
+
28
+ /** "Label" — bare label, no @ prefix. */
29
+ plainLabel: (({ label, id }) => label || id) as MentionMarkdownRenderer,
30
+
31
+ /** "[@Label](baseUrl/id)" — clickable markdown link. */
32
+ markdownLink: (baseUrl: string): MentionMarkdownRenderer =>
33
+ ({ label, id }) =>
34
+ `[@${escapeMd(label || id)}](${baseUrl}${encodeURIComponent(id)})`,
35
+
36
+ /** "@[Label](scheme://kind/id)" — Notion / Linear-style custom URI. */
37
+ customUri: (scheme: string, kind: string): MentionMarkdownRenderer =>
38
+ ({ label, id }) =>
39
+ `@[${escapeMd(label || id)}](${scheme}://${kind}/${encodeURIComponent(id)})`,
40
+
41
+ /** "<@id>" — Slack-style id-only reference (label dropped — receivers resolve it). */
42
+ slackStyle: (({ id }) => `<@${id}>`) as MentionMarkdownRenderer,
43
+
44
+ /** Inline HTML span — for products that consume markdown with raw HTML allowed. */
45
+ htmlSpan:
46
+ (className = 'mention'): MentionMarkdownRenderer =>
47
+ ({ label, id }) =>
48
+ `<span class="${className}" data-mention-id="${encodeURIComponent(id)}">@${escapeMd(label || id)}</span>`,
49
+ };
@@ -1,5 +1,3 @@
1
- import type { ReactNode } from 'react';
2
-
3
1
  /** Item that can be mentioned via @ trigger */
4
2
  export interface MentionItem {
5
3
  id: string;
@@ -8,6 +6,27 @@ export interface MentionItem {
8
6
  thumbnail?: string;
9
7
  }
10
8
 
9
+ /**
10
+ * Attributes available when rendering a mention to markdown.
11
+ *
12
+ * Same shape Tiptap stores on the `mention` node — `id` is the stable
13
+ * identifier the suggestion popover injected, `label` is the human text
14
+ * shown to the user. Either field may be empty if the upstream config
15
+ * never populated it; renderers should fall back accordingly.
16
+ */
17
+ export interface MentionAttrs {
18
+ id: string;
19
+ label: string;
20
+ }
21
+
22
+ /**
23
+ * Function that converts a mention node into its markdown serialization.
24
+ *
25
+ * The returned string is what `@tiptap/markdown` writes into the markdown
26
+ * output of `MarkdownEditor.getMarkdown()`.
27
+ */
28
+ export type MentionMarkdownRenderer = (attrs: MentionAttrs) => string;
29
+
11
30
  /** Mention configuration */
12
31
  export interface MentionConfig {
13
32
  /** Trigger character (default: '@') */
@@ -16,4 +35,16 @@ export interface MentionConfig {
16
35
  items: MentionItem[];
17
36
  /** Max dropdown items (default: 5) */
18
37
  maxItems?: number;
38
+ /**
39
+ * Custom serializer for mentions when `MarkdownEditor.getMarkdown()` runs.
40
+ *
41
+ * Defaults to `mentionPresets.plainAt` which yields `@<label>` (or `@<id>`
42
+ * when `label` is missing). Use one of `mentionPresets`, or supply your
43
+ * own function for full control over how mentions appear in the output
44
+ * markdown string.
45
+ *
46
+ * Note: this only affects the *markdown* output. `editor.getText()` and
47
+ * the rendered DOM still go through `renderText` (`@<label>` by default).
48
+ */
49
+ renderMarkdown?: MentionMarkdownRenderer;
19
50
  }
@@ -251,7 +251,8 @@ interface PlaygroundConfig {
251
251
  * the longread as top-level sections. */
252
252
  schemaGrouping?: 'selector' | 'sections';
253
253
  /** Sync the active endpoint anchor to ``window.location.hash`` as
254
- * the user scrolls (sections mode). Default: off. */
254
+ * the user scrolls (sections mode). Default: on. Pass ``false`` to
255
+ * opt out if the host page manages the hash itself. */
255
256
  urlSync?: boolean;
256
257
  }
257
258
 
@@ -31,7 +31,11 @@ export const DocsLayout: React.FC = () => {
31
31
  const grouping = config.schemaGrouping ?? 'selector';
32
32
  const preloadAll = grouping === 'sections';
33
33
  const urlSyncEnabled =
34
- typeof config.urlSync === 'boolean' ? config.urlSync : Boolean(config.urlSync?.enabled);
34
+ config.urlSync === undefined
35
+ ? true
36
+ : typeof config.urlSync === 'boolean'
37
+ ? config.urlSync
38
+ : Boolean(config.urlSync.enabled);
35
39
 
36
40
  const {
37
41
  endpoints,
@@ -114,11 +114,11 @@ export interface PlaygroundConfig {
114
114
  * rendered back-to-back in the docs column. Scrollspy picks the
115
115
  * active schema based on what's visible. */
116
116
  schemaGrouping?: 'selector' | 'sections';
117
- /** Optional URL-hash sync. When enabled, the viewer reads/writes
118
- * ``#<schemaId>/<anchor>`` on the browser location. Falsy value (the
119
- * default) keeps the viewer hash-free. Set to an object with
120
- * ``{ enabled: true }`` to opt in; future fields (e.g. a custom
121
- * adapter) stay backwards compatible. */
117
+ /** URL-hash sync. When enabled, the viewer reads/writes
118
+ * ``#<schemaId>/<anchor>`` on the browser location so deep-links
119
+ * to a specific endpoint work out of the box. Defaults to ``true``
120
+ * pass ``false`` (or ``{ enabled: false }``) to opt out if the host
121
+ * page already manages the hash itself. */
122
122
  urlSync?: boolean | { enabled: boolean };
123
123
  }
124
124
 
@@ -223,8 +223,14 @@ export type {
223
223
  } from './CodeEditor/types';
224
224
 
225
225
  // Export MarkdownEditor (Tiptap ~200KB)
226
- export { MarkdownEditor } from './MarkdownEditor';
227
- export type { MarkdownEditorProps, MentionItem, MentionConfig } from './MarkdownEditor';
226
+ export { MarkdownEditor, mentionPresets } from './MarkdownEditor';
227
+ export type {
228
+ MarkdownEditorProps,
229
+ MentionItem,
230
+ MentionConfig,
231
+ MentionAttrs,
232
+ MentionMarkdownRenderer,
233
+ } from './MarkdownEditor';
228
234
 
229
235
  // Export Media Cache Store
230
236
  export {