@unhingged/vizu-core 0.1.14 → 0.1.16

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.cjs CHANGED
@@ -3272,7 +3272,9 @@ var STYLES = `
3272
3272
  .vz-ref:hover { background: color-mix(in srgb, var(--vz-accent) 30%, var(--vz-bg-hover)); transform: translateY(-1px); }
3273
3273
  .vz-ref::before { content: ''; width: 5px; height: 5px; border-radius: 50%; background: var(--vz-accent); flex-shrink: 0; }
3274
3274
 
3275
- /* Inline @mention chip (rendered inside displayed comments) */
3275
+ /* Inline @mention chip (rendered inside displayed comments). user-select
3276
+ * prevents the user from selecting the chip's text and editing it; the
3277
+ * displayed comment is intentionally read-only after save. */
3276
3278
  .vz-mention {
3277
3279
  display: inline-flex; align-items: center;
3278
3280
  padding: 1px 8px 1px 8px;
@@ -3282,13 +3284,21 @@ var STYLES = `
3282
3284
  font-size: 12px; font-weight: 600;
3283
3285
  vertical-align: baseline;
3284
3286
  margin: 0 1px;
3287
+ user-select: none;
3288
+ -webkit-user-select: none;
3289
+ cursor: default;
3285
3290
  }
3286
3291
 
3287
- /* Mention chip inside the editor (contenteditable=false token) */
3292
+ /* Mention chip inside the editor (contenteditable=false token). Same
3293
+ * non-selection rules as .vz-mention so the chip stays atomic even
3294
+ * inside the editable surface \u2014 caret can land before/after but not
3295
+ * inside, no partial-text edit. */
3288
3296
  .vz-chip-mention {
3289
3297
  background: color-mix(in srgb, var(--vz-accent) 16%, var(--vz-bg-hover));
3290
3298
  color: var(--vz-accent);
3291
3299
  font-weight: 600;
3300
+ user-select: none;
3301
+ -webkit-user-select: none;
3292
3302
  }
3293
3303
  .vz-chip-mention::before { display: none; }
3294
3304
 
@@ -3368,6 +3378,10 @@ var STYLES = `
3368
3378
  pointer-events: none;
3369
3379
  z-index: 1;
3370
3380
  }
3381
+ /* Opt-in only during an active dragover. The explicit display:flex
3382
+ * above out-specifics the browser default for [hidden], so we restate
3383
+ * the hide rule here to make the attribute toggle effective. */
3384
+ .vz-attachment-drop-hint[hidden] { display: none; }
3371
3385
 
3372
3386
  /* Pending attachments (uploaded but not yet saved) */
3373
3387
  .vz-attachment-list {
@@ -3764,10 +3778,25 @@ var Vizu = class {
3764
3778
  /**
3765
3779
  * Fetch the list of users who can be @-mentioned on the current
3766
3780
  * workspace. Used by the popover's mention dropdown; hosts can also
3767
- * call this directly to build their own picker. Returns [] for
3768
- * non-cloud adapters (no workspace, no member list to fetch from).
3781
+ * call this directly to build their own picker.
3782
+ *
3783
+ * Resolution order:
3784
+ * 1. `options.mentionable` if provided — host-supplied static or
3785
+ * custom resolver. Wins over everything else.
3786
+ * 2. Cloud adapter's API call if running cloud mode.
3787
+ * 3. Empty array (non-cloud, no override).
3769
3788
  */
3770
3789
  async searchMentionable() {
3790
+ if (this.opts.mentionable) {
3791
+ try {
3792
+ return await this.opts.mentionable();
3793
+ } catch (err) {
3794
+ if (typeof console !== "undefined") {
3795
+ console.warn("[vizu] options.mentionable threw", err);
3796
+ }
3797
+ return [];
3798
+ }
3799
+ }
3771
3800
  if (this.storage instanceof CloudStorageAdapter) {
3772
3801
  return this.storage.searchMentionable();
3773
3802
  }
@@ -3982,10 +4011,29 @@ var Vizu = class {
3982
4011
  replies: [...this.comments[idx].replies ?? [], reply]
3983
4012
  };
3984
4013
  this.comments[idx] = updated;
3985
- if (this.storage.addReply) {
3986
- await this.storage.addReply(this.opts.namespace, commentId, reply);
3987
- } else {
3988
- await this.storage.updateComment(this.opts.namespace, commentId, { replies: updated.replies });
4014
+ try {
4015
+ if (this.storage.addReply) {
4016
+ await this.storage.addReply(this.opts.namespace, commentId, reply);
4017
+ } else {
4018
+ await this.storage.updateComment(this.opts.namespace, commentId, { replies: updated.replies });
4019
+ }
4020
+ } catch (err) {
4021
+ const cur = this.comments[idx];
4022
+ this.comments[idx] = {
4023
+ ...cur,
4024
+ replies: (cur.replies ?? []).filter((r) => r.id !== reply.id)
4025
+ };
4026
+ const code = err?.code ?? "";
4027
+ const status = err?.status;
4028
+ const msg = status === 403 || code === "forbidden" ? "Reply failed \u2014 you don't have permission." : status === 401 || code === "auth_required" ? "Reply failed \u2014 please sign in again." : "Reply failed. Please try again.";
4029
+ this.pill?.toast(msg);
4030
+ this.refreshUi();
4031
+ if (this.popover?.isOpen()) {
4032
+ const anchors = this.popover.getAnchors();
4033
+ if (anchors[0]) this.popover.update(this.commentsForElement(anchors[0]));
4034
+ }
4035
+ if (typeof console !== "undefined") console.warn("[vizu] addReply failed", err);
4036
+ return null;
3989
4037
  }
3990
4038
  this.bus.emit("comment:updated", { comment: updated });
3991
4039
  this.refreshUi();