hazo_ui 6.7.0 → 6.8.0

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/CHANGE_LOG.md CHANGED
@@ -5,6 +5,61 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## v6.8.0 (2026-08-03)
9
+
10
+ ### Added — text prefixes: `PrefixConfig.insert_as_text` + `CommandItem.insert_text`
11
+
12
+ A prefix can now be a snippet menu rather than an entity reference. With
13
+ `insert_as_text: true`, picking a command inserts plain editable characters
14
+ (`CommandItem.insert_text`, falling back to `action`) and consumes the trigger
15
+ character with the query — no pill node, no `InsertedCommand`, nothing for the
16
+ consumer to strip back out.
17
+
18
+ ```tsx
19
+ <HazoUiTextbox
20
+ prefixes={[
21
+ { char: "@", commands: variables }, // pills, unchanged
22
+ {
23
+ char: "/",
24
+ insert_as_text: true,
25
+ commands: [{ action: "SUM", action_label: "SUM(column)", insert_text: "SUM(" }],
26
+ },
27
+ ]}
28
+ />
29
+ ```
30
+
31
+ Motivated by hazo_collab_forms' formula editor, where `/` offers the grammar's
32
+ functions: what lands in the text has to be `SUM(`, valid formula source, not a
33
+ `/SUM` pill.
34
+
35
+ `parse_commands_from_text` (and therefore `text_to_tiptap_content`) now skips
36
+ text prefixes entirely. Without that, a controlled-value sync would re-read
37
+ `a/SUM(b)` and turn the division into a `/SUM` pill. Both `HazoUiTextbox` and
38
+ `HazoUiTextarea` honour the flag. New export: `insert_text_at_position`.
39
+
40
+ ## v6.7.1 (2026-08-03)
41
+
42
+ ### Fixed — `HazoUiTextbox` no longer warns "flushSync was called from inside a lifecycle method"
43
+
44
+ The controlled-value sync effect called `editor.commands.setContent(...)`
45
+ synchronously. That dispatches a ProseMirror transaction, and `@tiptap/react`
46
+ flushes the resulting re-render with `flushSync` — which, when the effect runs
47
+ while React is still rendering the owning tree, React reports as
48
+
49
+ ```
50
+ flushSync was called from inside a lifecycle method. React cannot flush when
51
+ React is already rendering.
52
+ ```
53
+
54
+ and then discards. Reported from a consumer that renders `HazoUiTextbox`
55
+ inside a large form tree (hazo_collab_forms' `TransformEditor`).
56
+
57
+ The write is now deferred to a `queueMicrotask` — after the commit, before
58
+ paint. The guard conditions (`isFocused`, value-still-differs, plus a new
59
+ `isDestroyed` check) are re-evaluated inside the microtask, because focus or
60
+ the controlled value can move between the effect and the flush. Behaviour is
61
+ otherwise unchanged; a cancelled/unmounted effect drops the pending write.
62
+
8
63
  ## v6.7.0 (2026-08-02)
9
64
 
10
65
  ### Added — `data-column-key` / `data-lane-key` on the kanban DOM
package/dist/index.cjs CHANGED
@@ -5655,6 +5655,9 @@ var insert_command_at_position = (editor, command, prefix, range, variant = "def
5655
5655
  color: color2
5656
5656
  }).run();
5657
5657
  };
5658
+ var insert_text_at_position = (editor, command, range) => {
5659
+ editor.chain().focus().deleteRange(range).insertContent(command.insert_text ?? command.action).run();
5660
+ };
5658
5661
  var get_variant_classes2 = (variant = "default") => {
5659
5662
  switch (variant) {
5660
5663
  case "outline":
@@ -5857,7 +5860,9 @@ var CommandPopover = ({
5857
5860
  CommandPopover.displayName = "CommandPopover";
5858
5861
 
5859
5862
  // src/components/hazo_ui_command/index.tsx
5860
- var parse_commands_from_text = (text, prefixes) => {
5863
+ var parse_commands_from_text = (text, all_prefixes) => {
5864
+ const prefixes = all_prefixes.filter((p) => !p.insert_as_text);
5865
+ if (prefixes.length === 0) return [];
5861
5866
  const result = [];
5862
5867
  const action_to_label = /* @__PURE__ */ new Map();
5863
5868
  for (const prefix_config of prefixes) {
@@ -6167,13 +6172,18 @@ var HazoUiTextbox = ({
6167
6172
  }
6168
6173
  }, [suggestion_state, editor]);
6169
6174
  React27__namespace.useEffect(() => {
6170
- if (is_controlled && editor && !editor.isFocused) {
6171
- const current_text = editor.getText();
6172
- if (value !== current_text) {
6173
- const content = text_to_tiptap_content(value || "", prefixes, pill_variant);
6174
- editor.commands.setContent(content, { emitUpdate: false });
6175
- }
6176
- }
6175
+ if (!is_controlled || !editor || editor.isFocused) return;
6176
+ if (value === editor.getText()) return;
6177
+ let cancelled = false;
6178
+ queueMicrotask(() => {
6179
+ if (cancelled || editor.isDestroyed || editor.isFocused) return;
6180
+ if (value === editor.getText()) return;
6181
+ const content = text_to_tiptap_content(value || "", prefixes, pill_variant);
6182
+ editor.commands.setContent(content, { emitUpdate: false });
6183
+ });
6184
+ return () => {
6185
+ cancelled = true;
6186
+ };
6177
6187
  }, [value, editor, is_controlled, prefixes, pill_variant]);
6178
6188
  React27__namespace.useEffect(() => {
6179
6189
  if (editor) {
@@ -6185,6 +6195,11 @@ var HazoUiTextbox = ({
6185
6195
  if (!editor || !suggestion_state) return;
6186
6196
  const prefix_config = prefixes.find((p) => p.char === suggestion_state.prefix);
6187
6197
  const prefix_color = prefix_config?.color;
6198
+ if (prefix_config?.insert_as_text) {
6199
+ insert_text_at_position(editor, command, suggestion_state.range);
6200
+ set_suggestion_state(null);
6201
+ return;
6202
+ }
6188
6203
  insert_command_at_position(
6189
6204
  editor,
6190
6205
  command,
@@ -6735,6 +6750,11 @@ var HazoUiTextarea = ({
6735
6750
  if (!editor || !suggestion_state) return;
6736
6751
  const prefix_config = prefixes.find((p) => p.char === suggestion_state.prefix);
6737
6752
  const prefix_color = prefix_config?.color;
6753
+ if (prefix_config?.insert_as_text) {
6754
+ insert_text_at_position(editor, command, suggestion_state.range);
6755
+ set_suggestion_state(null);
6756
+ return;
6757
+ }
6738
6758
  insert_command_at_position(
6739
6759
  editor,
6740
6760
  command,