@doist/typist 6.0.11 → 7.0.1

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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,29 @@
1
+ ## [7.0.1](https://github.com/Doist/typist/compare/v7.0.0...v7.0.1) (2024-09-19)
2
+
3
+ ### Bug Fixes
4
+
5
+ - Destroy React renderer and dropdown on Escape ([4f8d5be](https://github.com/Doist/typist/commit/4f8d5beadfd1235a8f4d4c032905ecb07fccf785))
6
+
7
+ ## [7.0.0](https://github.com/Doist/typist/compare/v6.0.11...v7.0.0) (2024-08-28)
8
+
9
+ ### ⚠ BREAKING CHANGES
10
+
11
+ - Fix TypeScript types for the Suggestion plugin
12
+ `command` function (allowing for generic override).
13
+
14
+ Although this was not causing any issues for us due to the convoluted
15
+ implementation, the same fix was recently applied to Tiptap, and this
16
+ aligns our suggestion factory function implementation with the original
17
+ one. Unfortunately, this comes as a breaking change (examples were also
18
+ updated to reflect the required changes).
19
+
20
+ Additionally, other smaller TypeScript types were refactored for
21
+ consistency and clarity, but these are safe changes.
22
+
23
+ ### Code Refactoring
24
+
25
+ - General improvements for TypeScript types ([#883](https://github.com/Doist/typist/issues/883)) ([b235eaf](https://github.com/Doist/typist/commit/b235eaf9506c5bf8ed0a94e863f9262b9735ad7e))
26
+
1
27
  ## [6.0.11](https://github.com/Doist/typist/compare/v6.0.10...v6.0.11) (2024-08-23)
2
28
 
3
29
  ### Bug Fixes
@@ -1,3 +1,8 @@
1
+ import type { CodeOptions } from '@tiptap/extension-code';
2
+ /**
3
+ * The options available to customize the `RichTextCode` extension.
4
+ */
5
+ type RichTextCodeOptions = CodeOptions;
1
6
  /**
2
7
  * Custom extension that extends the built-in `Code` extension to allow all marks (e.g., Bold,
3
8
  * Italic, and Strikethrough) to coexist with the `Code` mark (as opposed to disallowing all any
@@ -6,6 +11,7 @@
6
11
  * @see https://tiptap.dev/api/schema#excludes
7
12
  * @see https://prosemirror.net/docs/ref/#model.MarkSpec.excludes
8
13
  */
9
- declare const RichTextCode: import("@tiptap/core").Mark<import("@tiptap/extension-code").CodeOptions, any>;
14
+ declare const RichTextCode: import("@tiptap/core").Mark<CodeOptions, any>;
10
15
  export { RichTextCode };
16
+ export type { RichTextCodeOptions };
11
17
  //# sourceMappingURL=rich-text-code.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rich-text-code.d.ts","sourceRoot":"","sources":["../../../src/extensions/rich-text/rich-text-code.ts"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AACH,QAAA,MAAM,YAAY,gFAGhB,CAAA;AAEF,OAAO,EAAE,YAAY,EAAE,CAAA"}
1
+ {"version":3,"file":"rich-text-code.d.ts","sourceRoot":"","sources":["../../../src/extensions/rich-text/rich-text-code.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAEzD;;GAEG;AACH,KAAK,mBAAmB,GAAG,WAAW,CAAA;AAEtC;;;;;;;GAOG;AACH,QAAA,MAAM,YAAY,+CAGhB,CAAA;AAEF,OAAO,EAAE,YAAY,EAAE,CAAA;AAEvB,YAAY,EAAE,mBAAmB,EAAE,CAAA"}
@@ -1,4 +1,8 @@
1
1
  import type { LinkOptions } from '@tiptap/extension-link';
2
+ /**
3
+ * The options available to customize the `RichTextLink` extension.
4
+ */
5
+ type RichTextLinkOptions = LinkOptions;
2
6
  /**
3
7
  * Custom extension that extends the built-in `Link` extension to add additional input/paste rules
4
8
  * for converting the Markdown link syntax (i.e. `[Doist](https://doist.com)`) into links, and also
@@ -6,5 +10,5 @@ import type { LinkOptions } from '@tiptap/extension-link';
6
10
  */
7
11
  declare const RichTextLink: import("@tiptap/core").Mark<LinkOptions, any>;
8
12
  export { RichTextLink };
9
- export type { LinkOptions as RichTextLinkOptions };
13
+ export type { RichTextLinkOptions };
10
14
  //# sourceMappingURL=rich-text-link.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rich-text-link.d.ts","sourceRoot":"","sources":["../../../src/extensions/rich-text/rich-text-link.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAuDzD;;;;GAIG;AACH,QAAA,MAAM,YAAY,+CAoDhB,CAAA;AAEF,OAAO,EAAE,YAAY,EAAE,CAAA;AAEvB,YAAY,EAAE,WAAW,IAAI,mBAAmB,EAAE,CAAA"}
1
+ {"version":3,"file":"rich-text-link.d.ts","sourceRoot":"","sources":["../../../src/extensions/rich-text/rich-text-link.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAuDzD;;GAEG;AACH,KAAK,mBAAmB,GAAG,WAAW,CAAA;AAEtC;;;;GAIG;AACH,QAAA,MAAM,YAAY,+CAoDhB,CAAA;AAEF,OAAO,EAAE,YAAY,EAAE,CAAA;AAEvB,YAAY,EAAE,mBAAmB,EAAE,CAAA"}
@@ -1,8 +1,12 @@
1
1
  import type { StrikeOptions } from '@tiptap/extension-strike';
2
+ /**
3
+ * The options available to customize the `RichTextStrikethrough` extension.
4
+ */
5
+ type RichTextStrikethroughOptions = StrikeOptions;
2
6
  /**
3
7
  * Custom extension that extends the built-in `Strike` extension to overwrite the default keyboard.
4
8
  */
5
9
  declare const RichTextStrikethrough: import("@tiptap/core").Mark<StrikeOptions, any>;
6
10
  export { RichTextStrikethrough };
7
- export type { StrikeOptions as RichTextStrikethroughOptions };
11
+ export type { RichTextStrikethroughOptions };
8
12
  //# sourceMappingURL=rich-text-strikethrough.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rich-text-strikethrough.d.ts","sourceRoot":"","sources":["../../../src/extensions/rich-text/rich-text-strikethrough.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAE7D;;GAEG;AACH,QAAA,MAAM,qBAAqB,iDAMzB,CAAA;AAEF,OAAO,EAAE,qBAAqB,EAAE,CAAA;AAEhC,YAAY,EAAE,aAAa,IAAI,4BAA4B,EAAE,CAAA"}
1
+ {"version":3,"file":"rich-text-strikethrough.d.ts","sourceRoot":"","sources":["../../../src/extensions/rich-text/rich-text-strikethrough.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAE7D;;GAEG;AACH,KAAK,4BAA4B,GAAG,aAAa,CAAA;AAEjD;;GAEG;AACH,QAAA,MAAM,qBAAqB,iDAMzB,CAAA;AAEF,OAAO,EAAE,qBAAqB,EAAE,CAAA;AAEhC,YAAY,EAAE,4BAA4B,EAAE,CAAA"}
@@ -1,10 +1,10 @@
1
1
  import { Node } from '@tiptap/core';
2
- import type { SuggestionKeyDownProps as CoreSuggestionKeyDownProps, SuggestionOptions as CoreSuggestionOptions } from '@tiptap/suggestion';
2
+ import type { SuggestionKeyDownProps as CoreSuggestionKeyDownProps, SuggestionOptions as CoreSuggestionOptions, SuggestionProps as CoreSuggestionProps } from '@tiptap/suggestion';
3
3
  import type { ConditionalKeys, RequireAtLeastOne } from 'type-fest';
4
4
  /**
5
- * The properties that describe the suggestion node attributes.
5
+ * A type that describes the suggestion node attributes.
6
6
  */
7
- type SuggestionAttributes = {
7
+ type SuggestionNodeAttributes = {
8
8
  /**
9
9
  * The suggestion node unique identifier to be rendered by the editor as a `data-id` attribute.
10
10
  */
@@ -16,21 +16,21 @@ type SuggestionAttributes = {
16
16
  label: string;
17
17
  };
18
18
  /**
19
- * The properties that describe the minimal props that an autocomplete dropdown must receive.
19
+ * A type that describes the minimal props that an autocomplete dropdown must receive.
20
20
  */
21
- type SuggestionRendererProps<SuggestionItemType> = {
21
+ type SuggestionRendererProps<TSuggestionItem> = {
22
22
  /**
23
- * The function that must be invoked when a suggestion item is selected.
23
+ * The list of suggestion items to be rendered by the autocomplete dropdown.
24
24
  */
25
- command: (item: SuggestionItemType) => void;
25
+ items: CoreSuggestionProps<TSuggestionItem>['items'];
26
26
  /**
27
- * The list of suggestion items to be rendered by the autocomplete dropdown.
27
+ * The function that must be invoked when a suggestion item is selected.
28
28
  */
29
- items: SuggestionItemType[];
29
+ command: CoreSuggestionProps<TSuggestionItem, SuggestionNodeAttributes>['command'];
30
30
  };
31
31
  /**
32
32
  * A type that describes the forwarded ref that an autocomplete dropdown must implement with
33
- * `useImperativeHandle` to receive `keyDown` events from the render function.
33
+ * `useImperativeHandle` to handle `keydown` events in the dropdown render function.
34
34
  */
35
35
  type SuggestionRendererRef = {
36
36
  onKeyDown: (props: CoreSuggestionKeyDownProps) => boolean;
@@ -38,11 +38,11 @@ type SuggestionRendererRef = {
38
38
  /**
39
39
  * The options available to customize the extension created by the factory function.
40
40
  */
41
- type SuggestionOptions<SuggestionItemType> = {
41
+ type SuggestionOptions<TSuggestionItem> = {
42
42
  /**
43
43
  * The character that triggers the autocomplete dropdown.
44
44
  */
45
- triggerChar: '@' | '#' | '+';
45
+ triggerChar: string;
46
46
  /**
47
47
  * Allows or disallows spaces in suggested items.
48
48
  */
@@ -58,39 +58,39 @@ type SuggestionOptions<SuggestionItemType> = {
58
58
  /**
59
59
  * Define how the suggestion item `aria-label` attribute should be rendered.
60
60
  */
61
- renderAriaLabel?: (attrs: SuggestionAttributes) => string;
61
+ renderAriaLabel?: (attrs: SuggestionNodeAttributes) => string;
62
62
  /**
63
63
  * A render function for the autocomplete dropdown.
64
64
  */
65
- dropdownRenderFn?: CoreSuggestionOptions<SuggestionItemType>['render'];
65
+ dropdownRenderFn?: CoreSuggestionOptions<TSuggestionItem>['render'];
66
66
  /**
67
67
  * The event handler that is fired when the search string has changed.
68
68
  */
69
- onSearchChange?: (query: string, storage: SuggestionStorage<SuggestionItemType>) => SuggestionItemType[] | Promise<SuggestionItemType[]>;
69
+ onSearchChange?: (query: string, storage: SuggestionStorage<TSuggestionItem>) => TSuggestionItem[] | Promise<TSuggestionItem[]>;
70
70
  /**
71
71
  * The event handler that is fired when a suggestion item is selected.
72
72
  */
73
- onItemSelect?: (item: SuggestionItemType) => void;
73
+ onItemSelect?: (item: TSuggestionItem) => void;
74
74
  };
75
75
  /**
76
76
  * The storage holding the suggestion items original array, and a collection indexed by the item id.
77
77
  */
78
- type SuggestionStorage<SuggestionItemType> = Readonly<{
78
+ type SuggestionStorage<TSuggestionItem> = Readonly<{
79
79
  /**
80
80
  * The original array of suggestion items.
81
81
  */
82
- items: SuggestionItemType[];
82
+ items: TSuggestionItem[];
83
83
  /**
84
84
  * A collection of suggestion items indexed by the item id.
85
85
  */
86
86
  itemsById: {
87
- readonly [id: SuggestionAttributes['id']]: SuggestionItemType | undefined;
87
+ readonly [id: SuggestionNodeAttributes['id']]: TSuggestionItem | undefined;
88
88
  };
89
89
  }>;
90
90
  /**
91
91
  * The return type for a suggestion extension created by the factory function.
92
92
  */
93
- type SuggestionExtensionResult<SuggestionItemType> = Node<SuggestionOptions<SuggestionItemType>>;
93
+ type SuggestionExtensionResult<TSuggestionItem> = Node<SuggestionOptions<TSuggestionItem>>;
94
94
  /**
95
95
  * A factory function responsible for creating different types of suggestion extensions with
96
96
  * flexibility and customizability in mind.
@@ -102,20 +102,28 @@ type SuggestionExtensionResult<SuggestionItemType> = Node<SuggestionOptions<Sugg
102
102
  * specify the source item type, and use the optional `attributesMapping` option to map the
103
103
  * source properties to the internal `data-id` and `data-label` attributes.
104
104
  *
105
+ * This factory function also stores the suggestion items internally in the editor storage (as-is,
106
+ * and indexed by an identifier), as a way to make sure that if a previously referenced suggestion
107
+ * changes its label, the editor will always render the most up-to-date label for the suggestion by
108
+ * reading it from the storage. An example use case for this is when a user mention is added to the
109
+ * editor, and the user changed its name afterwards, the editor will always render the most
110
+ * up-to-date user name for the mention.
111
+ *
105
112
  * @param type A unique identifier for the suggestion extension type.
113
+ * @param items An array of suggestion items to be stored in the editor storage.
106
114
  * @param attributesMapping An object to map the `data-id` and `data-label` attributes with the
107
115
  * source item type properties.
108
116
  *
109
117
  * @returns A new suggestion extension tailored to a specific use case.
110
118
  */
111
- declare function createSuggestionExtension<SuggestionItemType extends {
112
- [id: SuggestionAttributes['id']]: unknown;
113
- } = SuggestionAttributes>(type: string, items?: SuggestionItemType[], ...attributesMapping: SuggestionItemType extends SuggestionAttributes ? [] : [
119
+ declare function createSuggestionExtension<TSuggestionItem extends {
120
+ [id: SuggestionNodeAttributes['id']]: unknown;
121
+ } = SuggestionNodeAttributes>(type: string, items?: TSuggestionItem[], ...attributesMapping: TSuggestionItem extends SuggestionNodeAttributes ? [] : [
114
122
  RequireAtLeastOne<{
115
- id: ConditionalKeys<SuggestionItemType, SuggestionAttributes['id']>;
116
- label: ConditionalKeys<SuggestionItemType, SuggestionAttributes['label']>;
123
+ id: ConditionalKeys<TSuggestionItem, SuggestionNodeAttributes['id']>;
124
+ label: ConditionalKeys<TSuggestionItem, SuggestionNodeAttributes['label']>;
117
125
  }>
118
- ]): SuggestionExtensionResult<SuggestionItemType>;
126
+ ]): SuggestionExtensionResult<TSuggestionItem>;
119
127
  export { createSuggestionExtension };
120
128
  export type { SuggestionExtensionResult, SuggestionOptions, SuggestionRendererProps, SuggestionRendererRef, SuggestionStorage, };
121
129
  //# sourceMappingURL=create-suggestion-extension.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-suggestion-extension.d.ts","sourceRoot":"","sources":["../../src/factories/create-suggestion-extension.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,IAAI,EAAE,MAAM,cAAc,CAAA;AASpD,OAAO,KAAK,EACR,sBAAsB,IAAI,0BAA0B,EACpD,iBAAiB,IAAI,qBAAqB,EAC7C,MAAM,oBAAoB,CAAA;AAC3B,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAEnE;;GAEG;AACH,KAAK,oBAAoB,GAAG;IACxB;;OAEG;IACH,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IAEnB;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAA;CAChB,CAAA;AAED;;GAEG;AACH,KAAK,uBAAuB,CAAC,kBAAkB,IAAI;IAC/C;;OAEG;IACH,OAAO,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAA;IAE3C;;OAEG;IACH,KAAK,EAAE,kBAAkB,EAAE,CAAA;CAC9B,CAAA;AAED;;;GAGG;AACH,KAAK,qBAAqB,GAAG;IACzB,SAAS,EAAE,CAAC,KAAK,EAAE,0BAA0B,KAAK,OAAO,CAAA;CAC5D,CAAA;AAED;;GAEG;AACH,KAAK,iBAAiB,CAAC,kBAAkB,IAAI;IACzC;;OAEG;IACH,WAAW,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;IAE5B;;OAEG;IACH,WAAW,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAA;IAEjD;;OAEG;IACH,eAAe,EAAE,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAEzD;;OAEG;IACH,WAAW,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAA;IAEjD;;OAEG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,MAAM,CAAA;IAEzD;;OAEG;IACH,gBAAgB,CAAC,EAAE,qBAAqB,CAAC,kBAAkB,CAAC,CAAC,QAAQ,CAAC,CAAA;IAEtE;;OAEG;IACH,cAAc,CAAC,EAAE,CACb,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,iBAAiB,CAAC,kBAAkB,CAAC,KAC7C,kBAAkB,EAAE,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAA;IAEzD;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAA;CACpD,CAAA;AAED;;GAEG;AACH,KAAK,iBAAiB,CAAC,kBAAkB,IAAI,QAAQ,CAAC;IAClD;;OAEG;IACH,KAAK,EAAE,kBAAkB,EAAE,CAAA;IAE3B;;OAEG;IACH,SAAS,EAAE;QAAE,QAAQ,EAAE,EAAE,EAAE,oBAAoB,CAAC,IAAI,CAAC,GAAG,kBAAkB,GAAG,SAAS,CAAA;KAAE,CAAA;CAC3F,CAAC,CAAA;AAEF;;GAEG;AACH,KAAK,yBAAyB,CAAC,kBAAkB,IAAI,IAAI,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,CAAC,CAAA;AAEhG;;;;;;;;;;;;;;;;GAgBG;AACH,iBAAS,yBAAyB,CAC9B,kBAAkB,SAAS;IAAE,CAAC,EAAE,EAAE,oBAAoB,CAAC,IAAI,CAAC,GAAG,OAAO,CAAA;CAAE,GAAG,oBAAoB,EAE/F,IAAI,EAAE,MAAM,EACZ,KAAK,GAAE,kBAAkB,EAAO,EAKhC,GAAG,iBAAiB,EAAE,kBAAkB,SAAS,oBAAoB,GAC/D,EAAE,GACF;IACI,iBAAiB,CAAC;QACd,EAAE,EAAE,eAAe,CAAC,kBAAkB,EAAE,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAA;QACnE,KAAK,EAAE,eAAe,CAAC,kBAAkB,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC,CAAA;KAC5E,CAAC;CACL,GACR,yBAAyB,CAAC,kBAAkB,CAAC,CAwJ/C;AAED,OAAO,EAAE,yBAAyB,EAAE,CAAA;AAEpC,YAAY,EACR,yBAAyB,EACzB,iBAAiB,EACjB,uBAAuB,EACvB,qBAAqB,EACrB,iBAAiB,GACpB,CAAA"}
1
+ {"version":3,"file":"create-suggestion-extension.d.ts","sourceRoot":"","sources":["../../src/factories/create-suggestion-extension.ts"],"names":[],"mappings":"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"}
@@ -16,7 +16,15 @@ import { canInsertSuggestion } from '../utilities/can-insert-suggestion';
16
16
  * specify the source item type, and use the optional `attributesMapping` option to map the
17
17
  * source properties to the internal `data-id` and `data-label` attributes.
18
18
  *
19
+ * This factory function also stores the suggestion items internally in the editor storage (as-is,
20
+ * and indexed by an identifier), as a way to make sure that if a previously referenced suggestion
21
+ * changes its label, the editor will always render the most up-to-date label for the suggestion by
22
+ * reading it from the storage. An example use case for this is when a user mention is added to the
23
+ * editor, and the user changed its name afterwards, the editor will always render the most
24
+ * up-to-date user name for the mention.
25
+ *
19
26
  * @param type A unique identifier for the suggestion extension type.
27
+ * @param items An array of suggestion items to be stored in the editor storage.
20
28
  * @param attributesMapping An object to map the `data-id` and `data-label` attributes with the
21
29
  * source item type properties.
22
30
  *
@@ -61,24 +69,26 @@ function createSuggestionExtension(type, items = [],
61
69
  },
62
70
  addAttributes() {
63
71
  return {
64
- [idAttribute]: {
72
+ id: {
65
73
  default: null,
66
74
  parseHTML: (element) => element.getAttribute('data-id'),
67
75
  renderHTML: (attributes) => ({
68
- 'data-id': String(attributes[idAttribute]),
76
+ 'data-id': String(attributes.id),
69
77
  }),
70
78
  },
71
- [labelAttribute]: {
79
+ label: {
72
80
  default: null,
73
81
  parseHTML: (element) => {
74
82
  const id = String(element.getAttribute('data-id'));
75
83
  const item = this.storage.itemsById[id];
76
- // Read the latest item label from the storage, if available, otherwise
77
- // fallback to the item label in the `data-label` attribute
84
+ // Attempt to read the item label from the storage first (as a way to make
85
+ // sure that a previously referenced suggestion always renders the most
86
+ // up-to-date label for the suggestion), and fallback to the `data-label`
87
+ // attribute if the item is not found in the storage
78
88
  return String(item?.[labelAttribute] ?? element.getAttribute('data-label'));
79
89
  },
80
90
  renderHTML: (attributes) => ({
81
- 'data-label': String(attributes[labelAttribute]),
91
+ 'data-label': String(attributes.label),
82
92
  }),
83
93
  },
84
94
  };
@@ -92,18 +102,18 @@ function createSuggestionExtension(type, items = [],
92
102
  mergeAttributes({
93
103
  [`data-${attributeType}`]: '',
94
104
  'aria-label': this.options.renderAriaLabel?.({
95
- id: String(node.attrs[idAttribute]),
96
- label: String(node.attrs[labelAttribute]),
105
+ id: String(node.attrs.id),
106
+ label: String(node.attrs.label),
97
107
  }),
98
108
  }, HTMLAttributes),
99
- `${String(this.options.triggerChar)}${String(node.attrs[labelAttribute])}`,
109
+ `${String(this.options.triggerChar)}${String(node.attrs.label)}`,
100
110
  ];
101
111
  },
102
112
  renderText({ node }) {
103
- return `${String(this.options.triggerChar)}${String(node.attrs[labelAttribute])}`;
113
+ return `${String(this.options.triggerChar)}${String(node.attrs.label)}`;
104
114
  },
105
115
  addProseMirrorPlugins() {
106
- const { triggerChar, allowSpaces, allowedPrefixes, startOfLine, onSearchChange, onItemSelect, dropdownRenderFn, } = this.options;
116
+ const { options: { triggerChar, allowSpaces, allowedPrefixes, startOfLine, onSearchChange, onItemSelect, dropdownRenderFn, }, storage, } = this;
107
117
  return [
108
118
  TiptapSuggestion({
109
119
  pluginKey: new PluginKey(nodeType),
@@ -139,7 +149,10 @@ function createSuggestionExtension(type, items = [],
139
149
  },
140
150
  ])
141
151
  .run();
142
- onItemSelect?.(props);
152
+ const item = storage.itemsById[props.id];
153
+ if (item) {
154
+ onItemSelect?.(item);
155
+ }
143
156
  },
144
157
  render: dropdownRenderFn,
145
158
  }),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@doist/typist",
3
3
  "description": "The mighty Tiptap-based rich-text editor React component that powers Doist products.",
4
- "version": "6.0.11",
4
+ "version": "7.0.1",
5
5
  "license": "MIT",
6
6
  "homepage": "https://typist.doist.dev/",
7
7
  "repository": "https://github.com/Doist/typist",
@@ -81,34 +81,34 @@
81
81
  "devDependencies": {
82
82
  "@doist/eslint-config": "11.1.0",
83
83
  "@doist/prettier-config": "4.0.0",
84
- "@doist/reactist": "25.0.0",
84
+ "@doist/reactist": "25.2.0",
85
85
  "@mdx-js/react": "3.0.1",
86
86
  "@semantic-release/changelog": "6.0.3",
87
87
  "@semantic-release/exec": "6.0.3",
88
88
  "@semantic-release/git": "10.0.1",
89
- "@storybook/addon-a11y": "8.2.9",
90
- "@storybook/addon-essentials": "8.2.9",
91
- "@storybook/blocks": "8.2.9",
89
+ "@storybook/addon-a11y": "8.3.0",
90
+ "@storybook/addon-essentials": "8.3.0",
91
+ "@storybook/blocks": "8.3.0",
92
92
  "@storybook/csf": "0.1.11",
93
- "@storybook/manager-api": "8.2.9",
93
+ "@storybook/manager-api": "8.3.0",
94
94
  "@storybook/mdx2-csf": "1.1.0",
95
- "@storybook/react": "8.2.9",
96
- "@storybook/react-vite": "8.2.9",
95
+ "@storybook/react": "8.3.0",
96
+ "@storybook/react-vite": "8.3.0",
97
97
  "@testing-library/dom": "10.4.0",
98
- "@testing-library/jest-dom": "6.4.8",
99
- "@testing-library/react": "16.0.0",
98
+ "@testing-library/jest-dom": "6.5.0",
99
+ "@testing-library/react": "16.0.1",
100
100
  "@types/hast": "3.0.4",
101
101
  "@types/lodash-es": "4.17.12",
102
- "@types/react": "18.3.4",
102
+ "@types/react": "18.3.5",
103
103
  "@types/react-dom": "18.3.0",
104
104
  "@types/react-syntax-highlighter": "15.5.13",
105
105
  "@types/turndown": "5.0.5",
106
106
  "@types/unist": "3.0.3",
107
107
  "@vitejs/plugin-react": "4.3.1",
108
- "boring-avatars": "1.10.2",
108
+ "boring-avatars": "1.11.1",
109
109
  "classnames": "2.5.1",
110
110
  "conventional-changelog-conventionalcommits": "8.0.0",
111
- "emoji-regex": "10.3.0",
111
+ "emoji-regex": "10.4.0",
112
112
  "eslint": "8.57.0",
113
113
  "eslint-formatter-codeframe": "7.32.1",
114
114
  "eslint-import-resolver-typescript": "3.6.1",
@@ -118,29 +118,30 @@
118
118
  "eslint-plugin-vitest": "0.4.1",
119
119
  "eslint-plugin-vitest-globals": "1.5.0",
120
120
  "github-markdown-css": "5.6.1",
121
- "husky": "9.1.5",
121
+ "husky": "9.1.6",
122
122
  "ignore-sync": "7.0.1",
123
123
  "is-ci": "3.0.1",
124
- "jsdom": "24.1.1",
125
- "lint-staged": "15.2.9",
126
- "npm-run-all2": "6.2.2",
124
+ "jsdom": "24.1.3",
125
+ "lint-staged": "15.2.10",
126
+ "npm-run-all2": "6.2.3",
127
127
  "prettier": "3.2.5",
128
128
  "react": "18.3.1",
129
129
  "react-dom": "18.3.1",
130
130
  "react-icons": "5.3.0",
131
131
  "react-markdown": "9.0.1",
132
132
  "react-syntax-highlighter": "15.5.0",
133
+ "react-use-event-hook": "0.9.6",
133
134
  "rehype-raw": "7.0.0",
134
135
  "remark-gfm": "4.0.0",
135
136
  "rimraf": "6.0.1",
136
- "semantic-release": "24.1.0",
137
- "storybook": "8.2.9",
137
+ "semantic-release": "24.1.1",
138
+ "storybook": "8.3.0",
138
139
  "storybook-css-modules": "1.0.8",
139
140
  "tippy.js": "6.3.7",
140
- "type-fest": "4.25.0",
141
- "typescript": "5.5.4",
141
+ "type-fest": "4.26.1",
142
+ "typescript": "5.6.2",
142
143
  "typescript-plugin-css-modules": "5.1.0",
143
- "vitest": "2.0.5"
144
+ "vitest": "2.1.1"
144
145
  },
145
146
  "peerDependencies": {
146
147
  "emoji-regex": "^10.2.1",