@unhingged/vizu-core 0.1.15 → 0.1.17

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/dist/index.d.cts CHANGED
@@ -319,6 +319,16 @@ interface VizuOptions {
319
319
  */
320
320
  onCommentAdded?: (c: VizuComment) => void;
321
321
  onCommentRemoved?: (id: string) => void;
322
+ /**
323
+ * Optional override for the @ mention picker's member list. When set,
324
+ * the popover dropdown calls this instead of going to the cloud
325
+ * `/api/workspaces/[slug]/mentionable` route. Useful for non-cloud
326
+ * hosts (local / memory storage) that still want @-mentions, and for
327
+ * tests / playgrounds that need a static teammate list.
328
+ *
329
+ * Return an empty array to suppress the dropdown.
330
+ */
331
+ mentionable?: () => MentionableUser[] | Promise<MentionableUser[]>;
322
332
  }
323
333
  /**
324
334
  * Typed event map. Every event payload is an object (never bare values) so the
@@ -680,8 +690,13 @@ declare class Vizu {
680
690
  /**
681
691
  * Fetch the list of users who can be @-mentioned on the current
682
692
  * workspace. Used by the popover's mention dropdown; hosts can also
683
- * call this directly to build their own picker. Returns [] for
684
- * non-cloud adapters (no workspace, no member list to fetch from).
693
+ * call this directly to build their own picker.
694
+ *
695
+ * Resolution order:
696
+ * 1. `options.mentionable` if provided — host-supplied static or
697
+ * custom resolver. Wins over everything else.
698
+ * 2. Cloud adapter's API call if running cloud mode.
699
+ * 3. Empty array (non-cloud, no override).
685
700
  */
686
701
  searchMentionable(): Promise<MentionableUser[]>;
687
702
  /**
package/dist/index.d.ts CHANGED
@@ -319,6 +319,16 @@ interface VizuOptions {
319
319
  */
320
320
  onCommentAdded?: (c: VizuComment) => void;
321
321
  onCommentRemoved?: (id: string) => void;
322
+ /**
323
+ * Optional override for the @ mention picker's member list. When set,
324
+ * the popover dropdown calls this instead of going to the cloud
325
+ * `/api/workspaces/[slug]/mentionable` route. Useful for non-cloud
326
+ * hosts (local / memory storage) that still want @-mentions, and for
327
+ * tests / playgrounds that need a static teammate list.
328
+ *
329
+ * Return an empty array to suppress the dropdown.
330
+ */
331
+ mentionable?: () => MentionableUser[] | Promise<MentionableUser[]>;
322
332
  }
323
333
  /**
324
334
  * Typed event map. Every event payload is an object (never bare values) so the
@@ -680,8 +690,13 @@ declare class Vizu {
680
690
  /**
681
691
  * Fetch the list of users who can be @-mentioned on the current
682
692
  * workspace. Used by the popover's mention dropdown; hosts can also
683
- * call this directly to build their own picker. Returns [] for
684
- * non-cloud adapters (no workspace, no member list to fetch from).
693
+ * call this directly to build their own picker.
694
+ *
695
+ * Resolution order:
696
+ * 1. `options.mentionable` if provided — host-supplied static or
697
+ * custom resolver. Wins over everything else.
698
+ * 2. Cloud adapter's API call if running cloud mode.
699
+ * 3. Empty array (non-cloud, no override).
685
700
  */
686
701
  searchMentionable(): Promise<MentionableUser[]>;
687
702
  /**
package/dist/index.js CHANGED
@@ -86,6 +86,9 @@ function renderAttachmentsHtml(attachments) {
86
86
  function migrateComment(raw) {
87
87
  if (!raw || typeof raw !== "object") return raw;
88
88
  const next = { ...raw };
89
+ if (next.id == null && next._id != null) {
90
+ next.id = next._id;
91
+ }
89
92
  if (!Array.isArray(next.fingerprints) || next.fingerprints.length === 0) {
90
93
  if (next.fingerprint) {
91
94
  next.fingerprints = [next.fingerprint];
@@ -3342,6 +3345,10 @@ var STYLES = `
3342
3345
  pointer-events: none;
3343
3346
  z-index: 1;
3344
3347
  }
3348
+ /* Opt-in only during an active dragover. The explicit display:flex
3349
+ * above out-specifics the browser default for [hidden], so we restate
3350
+ * the hide rule here to make the attribute toggle effective. */
3351
+ .vz-attachment-drop-hint[hidden] { display: none; }
3345
3352
 
3346
3353
  /* Pending attachments (uploaded but not yet saved) */
3347
3354
  .vz-attachment-list {
@@ -3738,10 +3745,25 @@ var Vizu = class {
3738
3745
  /**
3739
3746
  * Fetch the list of users who can be @-mentioned on the current
3740
3747
  * workspace. Used by the popover's mention dropdown; hosts can also
3741
- * call this directly to build their own picker. Returns [] for
3742
- * non-cloud adapters (no workspace, no member list to fetch from).
3748
+ * call this directly to build their own picker.
3749
+ *
3750
+ * Resolution order:
3751
+ * 1. `options.mentionable` if provided — host-supplied static or
3752
+ * custom resolver. Wins over everything else.
3753
+ * 2. Cloud adapter's API call if running cloud mode.
3754
+ * 3. Empty array (non-cloud, no override).
3743
3755
  */
3744
3756
  async searchMentionable() {
3757
+ if (this.opts.mentionable) {
3758
+ try {
3759
+ return await this.opts.mentionable();
3760
+ } catch (err) {
3761
+ if (typeof console !== "undefined") {
3762
+ console.warn("[vizu] options.mentionable threw", err);
3763
+ }
3764
+ return [];
3765
+ }
3766
+ }
3745
3767
  if (this.storage instanceof CloudStorageAdapter) {
3746
3768
  return this.storage.searchMentionable();
3747
3769
  }
@@ -4262,10 +4284,26 @@ var Vizu = class {
4262
4284
  this.refreshUi();
4263
4285
  }
4264
4286
  async removeComment(id) {
4265
- const comment = this.comments.find((c) => c.id === id);
4266
- if (!comment) return;
4287
+ const idx = this.comments.findIndex((c) => c.id === id);
4288
+ if (idx === -1) return;
4289
+ const comment = this.comments[idx];
4267
4290
  this.comments = this.comments.filter((c) => c.id !== id);
4268
- await this.storage.removeComment(this.opts.namespace, id);
4291
+ try {
4292
+ await this.storage.removeComment(this.opts.namespace, id);
4293
+ } catch (err) {
4294
+ this.comments.splice(idx, 0, comment);
4295
+ const status = err?.status;
4296
+ const code = err?.code ?? "";
4297
+ const msg = status === 403 || code === "forbidden" ? "Delete failed \u2014 you don't have permission." : status === 401 || code === "auth_required" ? "Delete failed \u2014 please sign in again." : "Delete failed. Please try again.";
4298
+ this.pill?.toast(msg);
4299
+ if (this.popover?.isOpen()) {
4300
+ const anchors = this.popover.getAnchors();
4301
+ if (anchors[0]) this.popover.update(this.commentsForElement(anchors[0]));
4302
+ }
4303
+ this.refreshUi();
4304
+ if (typeof console !== "undefined") console.warn("[vizu] removeComment failed", err);
4305
+ return;
4306
+ }
4269
4307
  this.bus.emit("comment:removed", { id, comment });
4270
4308
  if (this.popover?.isOpen()) {
4271
4309
  const anchors = this.popover.getAnchors();