@almadar/ui 5.9.1 → 5.9.3

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.
@@ -27446,6 +27446,7 @@ function DataList({
27446
27446
  fields,
27447
27447
  columns,
27448
27448
  itemActions,
27449
+ itemClickEvent,
27449
27450
  gap = "none",
27450
27451
  variant = "default",
27451
27452
  groupBy,
@@ -27535,6 +27536,14 @@ function DataList({
27535
27536
  };
27536
27537
  eventBus.emit(`UI:${action.event}`, payload);
27537
27538
  };
27539
+ const handleRowClick = (itemData) => () => {
27540
+ if (!itemClickEvent) return;
27541
+ const payload = {
27542
+ id: itemData.id,
27543
+ row: itemData
27544
+ };
27545
+ eventBus.emit(`UI:${itemClickEvent}`, payload);
27546
+ };
27538
27547
  if (isLoading) {
27539
27548
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") || "Loading..." }) });
27540
27549
  }
@@ -27583,7 +27592,7 @@ function DataList({
27583
27592
  ),
27584
27593
  children: [
27585
27594
  !isSent && senderField && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "font-semibold mb-0.5", children: sender }),
27586
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: content !== void 0 && content !== null ? String(content) : "" }),
27595
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: cn(isSent && "text-primary-foreground"), children: content !== void 0 && content !== null ? String(content) : "" }),
27587
27596
  timestamp != null ? /* @__PURE__ */ jsxRuntime.jsx(
27588
27597
  Typography,
27589
27598
  {
@@ -27613,7 +27622,7 @@ function DataList({
27613
27622
  if (hasRenderProp) {
27614
27623
  const id2 = itemData.id || String(index);
27615
27624
  return wrapDnd(
27616
- /* @__PURE__ */ jsxRuntime.jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, children: [
27625
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, onClick: itemClickEvent ? handleRowClick(itemData) : void 0, className: cn(itemClickEvent && "cursor-pointer"), children: [
27617
27626
  /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "group flex items-stretch gap-2", children: [
27618
27627
  /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex-1 min-w-0", children: children(itemData, index) }),
27619
27628
  itemActions && itemActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
@@ -27649,7 +27658,7 @@ function DataList({
27649
27658
  const id = itemData.id || String(index);
27650
27659
  const titleValue = getNestedValue(itemData, titleField?.name ?? "");
27651
27660
  return wrapDnd(
27652
- /* @__PURE__ */ jsxRuntime.jsxs(Box, { "data-entity-row": true, "data-entity-id": id, children: [
27661
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { "data-entity-row": true, "data-entity-id": id, onClick: itemClickEvent ? handleRowClick(itemData) : void 0, className: cn(itemClickEvent && "cursor-pointer"), children: [
27653
27662
  /* @__PURE__ */ jsxRuntime.jsxs(
27654
27663
  Box,
27655
27664
  {
@@ -37088,6 +37097,8 @@ var init_ReplyTree = __esm({
37088
37097
  const hasReplies = !!node.replies && node.replies.length > 0;
37089
37098
  const isCollapsed = collapsedSet.has(node.id);
37090
37099
  const atMaxDepth = depth >= maxDepth;
37100
+ const [replyOpen, setReplyOpen] = React98.useState(false);
37101
+ const [draft, setDraft] = React98.useState("");
37091
37102
  const handleVote = React98.useCallback(
37092
37103
  (next) => {
37093
37104
  onVote?.(node.id, next);
@@ -37097,8 +37108,19 @@ var init_ReplyTree = __esm({
37097
37108
  );
37098
37109
  const handleReply = React98.useCallback(() => {
37099
37110
  onReply?.(node.id);
37100
- if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId: node.id });
37101
- }, [node.id, onReply, replyEvent, eventBus]);
37111
+ setReplyOpen((open) => !open);
37112
+ }, [node.id, onReply]);
37113
+ const handleSubmitReply = React98.useCallback(() => {
37114
+ const content = draft.trim();
37115
+ if (!content) return;
37116
+ if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId: node.id, content });
37117
+ setDraft("");
37118
+ setReplyOpen(false);
37119
+ }, [node.id, draft, replyEvent, eventBus]);
37120
+ const handleCancelReply = React98.useCallback(() => {
37121
+ setDraft("");
37122
+ setReplyOpen(false);
37123
+ }, []);
37102
37124
  const handleFlag = React98.useCallback(() => {
37103
37125
  onFlag?.(node.id);
37104
37126
  if (flagEvent) eventBus.emit(`UI:${flagEvent}`, { nodeId: node.id });
@@ -37185,6 +37207,33 @@ var init_ReplyTree = __esm({
37185
37207
  }
37186
37208
  )
37187
37209
  ] }),
37210
+ replyOpen && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-col gap-2 mt-1", children: [
37211
+ /* @__PURE__ */ jsxRuntime.jsx(
37212
+ Input,
37213
+ {
37214
+ inputType: "textarea",
37215
+ rows: 2,
37216
+ value: draft,
37217
+ placeholder: `Reply to ${node.authorName}\u2026`,
37218
+ onChange: (e) => setDraft(e.target.value),
37219
+ "aria-label": `Reply to ${node.authorName}`
37220
+ }
37221
+ ),
37222
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-row gap-2 items-center", children: [
37223
+ /* @__PURE__ */ jsxRuntime.jsx(
37224
+ Button,
37225
+ {
37226
+ variant: "primary",
37227
+ size: "sm",
37228
+ leftIcon: "send",
37229
+ onClick: handleSubmitReply,
37230
+ disabled: !draft.trim(),
37231
+ children: "Send"
37232
+ }
37233
+ ),
37234
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", onClick: handleCancelReply, children: "Cancel" })
37235
+ ] })
37236
+ ] }),
37188
37237
  hasReplies && !isCollapsed && (atMaxDepth ? /* @__PURE__ */ jsxRuntime.jsx(
37189
37238
  Button,
37190
37239
  {
package/dist/avl/index.js CHANGED
@@ -27397,6 +27397,7 @@ function DataList({
27397
27397
  fields,
27398
27398
  columns,
27399
27399
  itemActions,
27400
+ itemClickEvent,
27400
27401
  gap = "none",
27401
27402
  variant = "default",
27402
27403
  groupBy,
@@ -27486,6 +27487,14 @@ function DataList({
27486
27487
  };
27487
27488
  eventBus.emit(`UI:${action.event}`, payload);
27488
27489
  };
27490
+ const handleRowClick = (itemData) => () => {
27491
+ if (!itemClickEvent) return;
27492
+ const payload = {
27493
+ id: itemData.id,
27494
+ row: itemData
27495
+ };
27496
+ eventBus.emit(`UI:${itemClickEvent}`, payload);
27497
+ };
27489
27498
  if (isLoading) {
27490
27499
  return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") || "Loading..." }) });
27491
27500
  }
@@ -27534,7 +27543,7 @@ function DataList({
27534
27543
  ),
27535
27544
  children: [
27536
27545
  !isSent && senderField && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "font-semibold mb-0.5", children: sender }),
27537
- /* @__PURE__ */ jsx(Typography, { variant: "body", children: content !== void 0 && content !== null ? String(content) : "" }),
27546
+ /* @__PURE__ */ jsx(Typography, { variant: "body", className: cn(isSent && "text-primary-foreground"), children: content !== void 0 && content !== null ? String(content) : "" }),
27538
27547
  timestamp != null ? /* @__PURE__ */ jsx(
27539
27548
  Typography,
27540
27549
  {
@@ -27564,7 +27573,7 @@ function DataList({
27564
27573
  if (hasRenderProp) {
27565
27574
  const id2 = itemData.id || String(index);
27566
27575
  return wrapDnd(
27567
- /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, children: [
27576
+ /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, onClick: itemClickEvent ? handleRowClick(itemData) : void 0, className: cn(itemClickEvent && "cursor-pointer"), children: [
27568
27577
  /* @__PURE__ */ jsxs(Box, { className: "group flex items-stretch gap-2", children: [
27569
27578
  /* @__PURE__ */ jsx(Box, { className: "flex-1 min-w-0", children: children(itemData, index) }),
27570
27579
  itemActions && itemActions.length > 0 && /* @__PURE__ */ jsx(
@@ -27600,7 +27609,7 @@ function DataList({
27600
27609
  const id = itemData.id || String(index);
27601
27610
  const titleValue = getNestedValue(itemData, titleField?.name ?? "");
27602
27611
  return wrapDnd(
27603
- /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id, children: [
27612
+ /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id, onClick: itemClickEvent ? handleRowClick(itemData) : void 0, className: cn(itemClickEvent && "cursor-pointer"), children: [
27604
27613
  /* @__PURE__ */ jsxs(
27605
27614
  Box,
27606
27615
  {
@@ -37039,6 +37048,8 @@ var init_ReplyTree = __esm({
37039
37048
  const hasReplies = !!node.replies && node.replies.length > 0;
37040
37049
  const isCollapsed = collapsedSet.has(node.id);
37041
37050
  const atMaxDepth = depth >= maxDepth;
37051
+ const [replyOpen, setReplyOpen] = useState(false);
37052
+ const [draft, setDraft] = useState("");
37042
37053
  const handleVote = useCallback(
37043
37054
  (next) => {
37044
37055
  onVote?.(node.id, next);
@@ -37048,8 +37059,19 @@ var init_ReplyTree = __esm({
37048
37059
  );
37049
37060
  const handleReply = useCallback(() => {
37050
37061
  onReply?.(node.id);
37051
- if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId: node.id });
37052
- }, [node.id, onReply, replyEvent, eventBus]);
37062
+ setReplyOpen((open) => !open);
37063
+ }, [node.id, onReply]);
37064
+ const handleSubmitReply = useCallback(() => {
37065
+ const content = draft.trim();
37066
+ if (!content) return;
37067
+ if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId: node.id, content });
37068
+ setDraft("");
37069
+ setReplyOpen(false);
37070
+ }, [node.id, draft, replyEvent, eventBus]);
37071
+ const handleCancelReply = useCallback(() => {
37072
+ setDraft("");
37073
+ setReplyOpen(false);
37074
+ }, []);
37053
37075
  const handleFlag = useCallback(() => {
37054
37076
  onFlag?.(node.id);
37055
37077
  if (flagEvent) eventBus.emit(`UI:${flagEvent}`, { nodeId: node.id });
@@ -37136,6 +37158,33 @@ var init_ReplyTree = __esm({
37136
37158
  }
37137
37159
  )
37138
37160
  ] }),
37161
+ replyOpen && /* @__PURE__ */ jsxs(Box, { className: "flex flex-col gap-2 mt-1", children: [
37162
+ /* @__PURE__ */ jsx(
37163
+ Input,
37164
+ {
37165
+ inputType: "textarea",
37166
+ rows: 2,
37167
+ value: draft,
37168
+ placeholder: `Reply to ${node.authorName}\u2026`,
37169
+ onChange: (e) => setDraft(e.target.value),
37170
+ "aria-label": `Reply to ${node.authorName}`
37171
+ }
37172
+ ),
37173
+ /* @__PURE__ */ jsxs(Box, { className: "flex flex-row gap-2 items-center", children: [
37174
+ /* @__PURE__ */ jsx(
37175
+ Button,
37176
+ {
37177
+ variant: "primary",
37178
+ size: "sm",
37179
+ leftIcon: "send",
37180
+ onClick: handleSubmitReply,
37181
+ disabled: !draft.trim(),
37182
+ children: "Send"
37183
+ }
37184
+ ),
37185
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: handleCancelReply, children: "Cancel" })
37186
+ ] })
37187
+ ] }),
37139
37188
  hasReplies && !isCollapsed && (atMaxDepth ? /* @__PURE__ */ jsx(
37140
37189
  Button,
37141
37190
  {
@@ -22613,6 +22613,7 @@ function DataList({
22613
22613
  fields,
22614
22614
  columns,
22615
22615
  itemActions,
22616
+ itemClickEvent,
22616
22617
  gap = "none",
22617
22618
  variant = "default",
22618
22619
  groupBy,
@@ -22702,6 +22703,14 @@ function DataList({
22702
22703
  };
22703
22704
  eventBus.emit(`UI:${action.event}`, payload);
22704
22705
  };
22706
+ const handleRowClick = (itemData) => () => {
22707
+ if (!itemClickEvent) return;
22708
+ const payload = {
22709
+ id: itemData.id,
22710
+ row: itemData
22711
+ };
22712
+ eventBus.emit(`UI:${itemClickEvent}`, payload);
22713
+ };
22705
22714
  if (isLoading) {
22706
22715
  return /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "text-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", color: "secondary", children: t("loading.items") || "Loading..." }) });
22707
22716
  }
@@ -22750,7 +22759,7 @@ function DataList({
22750
22759
  ),
22751
22760
  children: [
22752
22761
  !isSent && senderField && /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", className: "font-semibold mb-0.5", children: sender }),
22753
- /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", children: content !== void 0 && content !== null ? String(content) : "" }),
22762
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", className: cn(isSent && "text-primary-foreground"), children: content !== void 0 && content !== null ? String(content) : "" }),
22754
22763
  timestamp != null ? /* @__PURE__ */ jsxRuntime.jsx(
22755
22764
  exports.Typography,
22756
22765
  {
@@ -22780,7 +22789,7 @@ function DataList({
22780
22789
  if (hasRenderProp) {
22781
22790
  const id2 = itemData.id || String(index);
22782
22791
  return wrapDnd(
22783
- /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { "data-entity-row": true, "data-entity-id": id2, children: [
22792
+ /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { "data-entity-row": true, "data-entity-id": id2, onClick: itemClickEvent ? handleRowClick(itemData) : void 0, className: cn(itemClickEvent && "cursor-pointer"), children: [
22784
22793
  /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: "group flex items-stretch gap-2", children: [
22785
22794
  /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "flex-1 min-w-0", children: children(itemData, index) }),
22786
22795
  itemActions && itemActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
@@ -22816,7 +22825,7 @@ function DataList({
22816
22825
  const id = itemData.id || String(index);
22817
22826
  const titleValue = getNestedValue(itemData, titleField?.name ?? "");
22818
22827
  return wrapDnd(
22819
- /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { "data-entity-row": true, "data-entity-id": id, children: [
22828
+ /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { "data-entity-row": true, "data-entity-id": id, onClick: itemClickEvent ? handleRowClick(itemData) : void 0, className: cn(itemClickEvent && "cursor-pointer"), children: [
22820
22829
  /* @__PURE__ */ jsxRuntime.jsxs(
22821
22830
  exports.Box,
22822
22831
  {
@@ -32547,6 +32556,8 @@ var init_ReplyTree = __esm({
32547
32556
  const hasReplies = !!node.replies && node.replies.length > 0;
32548
32557
  const isCollapsed = collapsedSet.has(node.id);
32549
32558
  const atMaxDepth = depth >= maxDepth;
32559
+ const [replyOpen, setReplyOpen] = React80.useState(false);
32560
+ const [draft, setDraft] = React80.useState("");
32550
32561
  const handleVote = React80.useCallback(
32551
32562
  (next) => {
32552
32563
  onVote?.(node.id, next);
@@ -32556,8 +32567,19 @@ var init_ReplyTree = __esm({
32556
32567
  );
32557
32568
  const handleReply = React80.useCallback(() => {
32558
32569
  onReply?.(node.id);
32559
- if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId: node.id });
32560
- }, [node.id, onReply, replyEvent, eventBus]);
32570
+ setReplyOpen((open) => !open);
32571
+ }, [node.id, onReply]);
32572
+ const handleSubmitReply = React80.useCallback(() => {
32573
+ const content = draft.trim();
32574
+ if (!content) return;
32575
+ if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId: node.id, content });
32576
+ setDraft("");
32577
+ setReplyOpen(false);
32578
+ }, [node.id, draft, replyEvent, eventBus]);
32579
+ const handleCancelReply = React80.useCallback(() => {
32580
+ setDraft("");
32581
+ setReplyOpen(false);
32582
+ }, []);
32561
32583
  const handleFlag = React80.useCallback(() => {
32562
32584
  onFlag?.(node.id);
32563
32585
  if (flagEvent) eventBus.emit(`UI:${flagEvent}`, { nodeId: node.id });
@@ -32644,6 +32666,33 @@ var init_ReplyTree = __esm({
32644
32666
  }
32645
32667
  )
32646
32668
  ] }),
32669
+ replyOpen && /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: "flex flex-col gap-2 mt-1", children: [
32670
+ /* @__PURE__ */ jsxRuntime.jsx(
32671
+ exports.Input,
32672
+ {
32673
+ inputType: "textarea",
32674
+ rows: 2,
32675
+ value: draft,
32676
+ placeholder: `Reply to ${node.authorName}\u2026`,
32677
+ onChange: (e) => setDraft(e.target.value),
32678
+ "aria-label": `Reply to ${node.authorName}`
32679
+ }
32680
+ ),
32681
+ /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: "flex flex-row gap-2 items-center", children: [
32682
+ /* @__PURE__ */ jsxRuntime.jsx(
32683
+ exports.Button,
32684
+ {
32685
+ variant: "primary",
32686
+ size: "sm",
32687
+ leftIcon: "send",
32688
+ onClick: handleSubmitReply,
32689
+ disabled: !draft.trim(),
32690
+ children: "Send"
32691
+ }
32692
+ ),
32693
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Button, { variant: "ghost", size: "sm", onClick: handleCancelReply, children: "Cancel" })
32694
+ ] })
32695
+ ] }),
32647
32696
  hasReplies && !isCollapsed && (atMaxDepth ? /* @__PURE__ */ jsxRuntime.jsx(
32648
32697
  exports.Button,
32649
32698
  {
@@ -22564,6 +22564,7 @@ function DataList({
22564
22564
  fields,
22565
22565
  columns,
22566
22566
  itemActions,
22567
+ itemClickEvent,
22567
22568
  gap = "none",
22568
22569
  variant = "default",
22569
22570
  groupBy,
@@ -22653,6 +22654,14 @@ function DataList({
22653
22654
  };
22654
22655
  eventBus.emit(`UI:${action.event}`, payload);
22655
22656
  };
22657
+ const handleRowClick = (itemData) => () => {
22658
+ if (!itemClickEvent) return;
22659
+ const payload = {
22660
+ id: itemData.id,
22661
+ row: itemData
22662
+ };
22663
+ eventBus.emit(`UI:${itemClickEvent}`, payload);
22664
+ };
22656
22665
  if (isLoading) {
22657
22666
  return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") || "Loading..." }) });
22658
22667
  }
@@ -22701,7 +22710,7 @@ function DataList({
22701
22710
  ),
22702
22711
  children: [
22703
22712
  !isSent && senderField && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "font-semibold mb-0.5", children: sender }),
22704
- /* @__PURE__ */ jsx(Typography, { variant: "body", children: content !== void 0 && content !== null ? String(content) : "" }),
22713
+ /* @__PURE__ */ jsx(Typography, { variant: "body", className: cn(isSent && "text-primary-foreground"), children: content !== void 0 && content !== null ? String(content) : "" }),
22705
22714
  timestamp != null ? /* @__PURE__ */ jsx(
22706
22715
  Typography,
22707
22716
  {
@@ -22731,7 +22740,7 @@ function DataList({
22731
22740
  if (hasRenderProp) {
22732
22741
  const id2 = itemData.id || String(index);
22733
22742
  return wrapDnd(
22734
- /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, children: [
22743
+ /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, onClick: itemClickEvent ? handleRowClick(itemData) : void 0, className: cn(itemClickEvent && "cursor-pointer"), children: [
22735
22744
  /* @__PURE__ */ jsxs(Box, { className: "group flex items-stretch gap-2", children: [
22736
22745
  /* @__PURE__ */ jsx(Box, { className: "flex-1 min-w-0", children: children(itemData, index) }),
22737
22746
  itemActions && itemActions.length > 0 && /* @__PURE__ */ jsx(
@@ -22767,7 +22776,7 @@ function DataList({
22767
22776
  const id = itemData.id || String(index);
22768
22777
  const titleValue = getNestedValue(itemData, titleField?.name ?? "");
22769
22778
  return wrapDnd(
22770
- /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id, children: [
22779
+ /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id, onClick: itemClickEvent ? handleRowClick(itemData) : void 0, className: cn(itemClickEvent && "cursor-pointer"), children: [
22771
22780
  /* @__PURE__ */ jsxs(
22772
22781
  Box,
22773
22782
  {
@@ -32498,6 +32507,8 @@ var init_ReplyTree = __esm({
32498
32507
  const hasReplies = !!node.replies && node.replies.length > 0;
32499
32508
  const isCollapsed = collapsedSet.has(node.id);
32500
32509
  const atMaxDepth = depth >= maxDepth;
32510
+ const [replyOpen, setReplyOpen] = useState(false);
32511
+ const [draft, setDraft] = useState("");
32501
32512
  const handleVote = useCallback(
32502
32513
  (next) => {
32503
32514
  onVote?.(node.id, next);
@@ -32507,8 +32518,19 @@ var init_ReplyTree = __esm({
32507
32518
  );
32508
32519
  const handleReply = useCallback(() => {
32509
32520
  onReply?.(node.id);
32510
- if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId: node.id });
32511
- }, [node.id, onReply, replyEvent, eventBus]);
32521
+ setReplyOpen((open) => !open);
32522
+ }, [node.id, onReply]);
32523
+ const handleSubmitReply = useCallback(() => {
32524
+ const content = draft.trim();
32525
+ if (!content) return;
32526
+ if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId: node.id, content });
32527
+ setDraft("");
32528
+ setReplyOpen(false);
32529
+ }, [node.id, draft, replyEvent, eventBus]);
32530
+ const handleCancelReply = useCallback(() => {
32531
+ setDraft("");
32532
+ setReplyOpen(false);
32533
+ }, []);
32512
32534
  const handleFlag = useCallback(() => {
32513
32535
  onFlag?.(node.id);
32514
32536
  if (flagEvent) eventBus.emit(`UI:${flagEvent}`, { nodeId: node.id });
@@ -32595,6 +32617,33 @@ var init_ReplyTree = __esm({
32595
32617
  }
32596
32618
  )
32597
32619
  ] }),
32620
+ replyOpen && /* @__PURE__ */ jsxs(Box, { className: "flex flex-col gap-2 mt-1", children: [
32621
+ /* @__PURE__ */ jsx(
32622
+ Input,
32623
+ {
32624
+ inputType: "textarea",
32625
+ rows: 2,
32626
+ value: draft,
32627
+ placeholder: `Reply to ${node.authorName}\u2026`,
32628
+ onChange: (e) => setDraft(e.target.value),
32629
+ "aria-label": `Reply to ${node.authorName}`
32630
+ }
32631
+ ),
32632
+ /* @__PURE__ */ jsxs(Box, { className: "flex flex-row gap-2 items-center", children: [
32633
+ /* @__PURE__ */ jsx(
32634
+ Button,
32635
+ {
32636
+ variant: "primary",
32637
+ size: "sm",
32638
+ leftIcon: "send",
32639
+ onClick: handleSubmitReply,
32640
+ disabled: !draft.trim(),
32641
+ children: "Send"
32642
+ }
32643
+ ),
32644
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: handleCancelReply, children: "Cancel" })
32645
+ ] })
32646
+ ] }),
32598
32647
  hasReplies && !isCollapsed && (atMaxDepth ? /* @__PURE__ */ jsx(
32599
32648
  Button,
32600
32649
  {
@@ -56,6 +56,9 @@ export interface DataListProps<T extends EntityRow = EntityRow> extends DataDndP
56
56
  columns?: readonly DataListField[];
57
57
  /** Per-item action buttons */
58
58
  itemActions?: readonly DataListItemAction[];
59
+ /** When set, the whole row is clickable and emits UI:{itemClickEvent} with
60
+ * { id, row } (action-button clicks stopPropagation so they still win). */
61
+ itemClickEvent?: EventKey;
59
62
  /** Gap between rows */
60
63
  gap?: 'none' | 'sm' | 'md' | 'lg';
61
64
  /** Visual variant */
@@ -122,7 +125,7 @@ export interface DataListProps<T extends EntityRow = EntityRow> extends DataDndP
122
125
  */
123
126
  look?: "dense" | "spacious" | "striped" | "borderless" | "card-rows";
124
127
  }
125
- export declare function DataList<T extends EntityRow = EntityRow>({ entity, fields, columns, itemActions, gap, variant, groupBy, senderField, currentUser, className, isLoading, error, reorderable: _reorderable, reorderEvent: _reorderEvent, swipeLeftEvent: _swipeLeftEvent, swipeLeftActions: _swipeLeftActions, swipeRightEvent: _swipeRightEvent, swipeRightActions: _swipeRightActions, longPressEvent: _longPressEvent, infiniteScroll, loadMoreEvent, hasMore, children, pageSize, renderItem: schemaRenderItem, dragGroup, accepts, sortable: sortableProp, dropEvent, reorderEvent: dndReorderEvent, positionEvent, dndItemIdField, dndRoot, look, }: DataListProps<T>): string | number | bigint | boolean | import("react/jsx-runtime").JSX.Element | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | null | undefined;
128
+ export declare function DataList<T extends EntityRow = EntityRow>({ entity, fields, columns, itemActions, itemClickEvent, gap, variant, groupBy, senderField, currentUser, className, isLoading, error, reorderable: _reorderable, reorderEvent: _reorderEvent, swipeLeftEvent: _swipeLeftEvent, swipeLeftActions: _swipeLeftActions, swipeRightEvent: _swipeRightEvent, swipeRightActions: _swipeRightActions, longPressEvent: _longPressEvent, infiniteScroll, loadMoreEvent, hasMore, children, pageSize, renderItem: schemaRenderItem, dragGroup, accepts, sortable: sortableProp, dropEvent, reorderEvent: dndReorderEvent, positionEvent, dndItemIdField, dndRoot, look, }: DataListProps<T>): string | number | bigint | boolean | import("react/jsx-runtime").JSX.Element | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | null | undefined;
126
129
  export declare namespace DataList {
127
130
  var displayName: string;
128
131
  }
@@ -31,6 +31,7 @@ export interface ReplyTreeProps {
31
31
  }>;
32
32
  replyEvent?: EventEmit<{
33
33
  parentNodeId: string;
34
+ content: string;
34
35
  }>;
35
36
  flagEvent?: EventEmit<{
36
37
  nodeId: string;
@@ -23858,6 +23858,7 @@ function DataList({
23858
23858
  fields,
23859
23859
  columns,
23860
23860
  itemActions,
23861
+ itemClickEvent,
23861
23862
  gap = "none",
23862
23863
  variant = "default",
23863
23864
  groupBy,
@@ -23947,6 +23948,14 @@ function DataList({
23947
23948
  };
23948
23949
  eventBus.emit(`UI:${action.event}`, payload);
23949
23950
  };
23951
+ const handleRowClick = (itemData) => () => {
23952
+ if (!itemClickEvent) return;
23953
+ const payload = {
23954
+ id: itemData.id,
23955
+ row: itemData
23956
+ };
23957
+ eventBus.emit(`UI:${itemClickEvent}`, payload);
23958
+ };
23950
23959
  if (isLoading) {
23951
23960
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") || "Loading..." }) });
23952
23961
  }
@@ -23995,7 +24004,7 @@ function DataList({
23995
24004
  ),
23996
24005
  children: [
23997
24006
  !isSent && senderField && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "font-semibold mb-0.5", children: sender }),
23998
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: content !== void 0 && content !== null ? String(content) : "" }),
24007
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: cn(isSent && "text-primary-foreground"), children: content !== void 0 && content !== null ? String(content) : "" }),
23999
24008
  timestamp != null ? /* @__PURE__ */ jsxRuntime.jsx(
24000
24009
  Typography,
24001
24010
  {
@@ -24025,7 +24034,7 @@ function DataList({
24025
24034
  if (hasRenderProp) {
24026
24035
  const id2 = itemData.id || String(index);
24027
24036
  return wrapDnd(
24028
- /* @__PURE__ */ jsxRuntime.jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, children: [
24037
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, onClick: itemClickEvent ? handleRowClick(itemData) : void 0, className: cn(itemClickEvent && "cursor-pointer"), children: [
24029
24038
  /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "group flex items-stretch gap-2", children: [
24030
24039
  /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex-1 min-w-0", children: children(itemData, index) }),
24031
24040
  itemActions && itemActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
@@ -24061,7 +24070,7 @@ function DataList({
24061
24070
  const id = itemData.id || String(index);
24062
24071
  const titleValue = getNestedValue(itemData, titleField?.name ?? "");
24063
24072
  return wrapDnd(
24064
- /* @__PURE__ */ jsxRuntime.jsxs(Box, { "data-entity-row": true, "data-entity-id": id, children: [
24073
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { "data-entity-row": true, "data-entity-id": id, onClick: itemClickEvent ? handleRowClick(itemData) : void 0, className: cn(itemClickEvent && "cursor-pointer"), children: [
24065
24074
  /* @__PURE__ */ jsxRuntime.jsxs(
24066
24075
  Box,
24067
24076
  {
@@ -33500,6 +33509,8 @@ var init_ReplyTree = __esm({
33500
33509
  const hasReplies = !!node.replies && node.replies.length > 0;
33501
33510
  const isCollapsed = collapsedSet.has(node.id);
33502
33511
  const atMaxDepth = depth >= maxDepth;
33512
+ const [replyOpen, setReplyOpen] = React86.useState(false);
33513
+ const [draft, setDraft] = React86.useState("");
33503
33514
  const handleVote = React86.useCallback(
33504
33515
  (next) => {
33505
33516
  onVote?.(node.id, next);
@@ -33509,8 +33520,19 @@ var init_ReplyTree = __esm({
33509
33520
  );
33510
33521
  const handleReply = React86.useCallback(() => {
33511
33522
  onReply?.(node.id);
33512
- if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId: node.id });
33513
- }, [node.id, onReply, replyEvent, eventBus]);
33523
+ setReplyOpen((open) => !open);
33524
+ }, [node.id, onReply]);
33525
+ const handleSubmitReply = React86.useCallback(() => {
33526
+ const content = draft.trim();
33527
+ if (!content) return;
33528
+ if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId: node.id, content });
33529
+ setDraft("");
33530
+ setReplyOpen(false);
33531
+ }, [node.id, draft, replyEvent, eventBus]);
33532
+ const handleCancelReply = React86.useCallback(() => {
33533
+ setDraft("");
33534
+ setReplyOpen(false);
33535
+ }, []);
33514
33536
  const handleFlag = React86.useCallback(() => {
33515
33537
  onFlag?.(node.id);
33516
33538
  if (flagEvent) eventBus.emit(`UI:${flagEvent}`, { nodeId: node.id });
@@ -33597,6 +33619,33 @@ var init_ReplyTree = __esm({
33597
33619
  }
33598
33620
  )
33599
33621
  ] }),
33622
+ replyOpen && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-col gap-2 mt-1", children: [
33623
+ /* @__PURE__ */ jsxRuntime.jsx(
33624
+ Input,
33625
+ {
33626
+ inputType: "textarea",
33627
+ rows: 2,
33628
+ value: draft,
33629
+ placeholder: `Reply to ${node.authorName}\u2026`,
33630
+ onChange: (e) => setDraft(e.target.value),
33631
+ "aria-label": `Reply to ${node.authorName}`
33632
+ }
33633
+ ),
33634
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-row gap-2 items-center", children: [
33635
+ /* @__PURE__ */ jsxRuntime.jsx(
33636
+ Button,
33637
+ {
33638
+ variant: "primary",
33639
+ size: "sm",
33640
+ leftIcon: "send",
33641
+ onClick: handleSubmitReply,
33642
+ disabled: !draft.trim(),
33643
+ children: "Send"
33644
+ }
33645
+ ),
33646
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", onClick: handleCancelReply, children: "Cancel" })
33647
+ ] })
33648
+ ] }),
33600
33649
  hasReplies && !isCollapsed && (atMaxDepth ? /* @__PURE__ */ jsxRuntime.jsx(
33601
33650
  Button,
33602
33651
  {
@@ -23809,6 +23809,7 @@ function DataList({
23809
23809
  fields,
23810
23810
  columns,
23811
23811
  itemActions,
23812
+ itemClickEvent,
23812
23813
  gap = "none",
23813
23814
  variant = "default",
23814
23815
  groupBy,
@@ -23898,6 +23899,14 @@ function DataList({
23898
23899
  };
23899
23900
  eventBus.emit(`UI:${action.event}`, payload);
23900
23901
  };
23902
+ const handleRowClick = (itemData) => () => {
23903
+ if (!itemClickEvent) return;
23904
+ const payload = {
23905
+ id: itemData.id,
23906
+ row: itemData
23907
+ };
23908
+ eventBus.emit(`UI:${itemClickEvent}`, payload);
23909
+ };
23901
23910
  if (isLoading) {
23902
23911
  return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") || "Loading..." }) });
23903
23912
  }
@@ -23946,7 +23955,7 @@ function DataList({
23946
23955
  ),
23947
23956
  children: [
23948
23957
  !isSent && senderField && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "font-semibold mb-0.5", children: sender }),
23949
- /* @__PURE__ */ jsx(Typography, { variant: "body", children: content !== void 0 && content !== null ? String(content) : "" }),
23958
+ /* @__PURE__ */ jsx(Typography, { variant: "body", className: cn(isSent && "text-primary-foreground"), children: content !== void 0 && content !== null ? String(content) : "" }),
23950
23959
  timestamp != null ? /* @__PURE__ */ jsx(
23951
23960
  Typography,
23952
23961
  {
@@ -23976,7 +23985,7 @@ function DataList({
23976
23985
  if (hasRenderProp) {
23977
23986
  const id2 = itemData.id || String(index);
23978
23987
  return wrapDnd(
23979
- /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, children: [
23988
+ /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, onClick: itemClickEvent ? handleRowClick(itemData) : void 0, className: cn(itemClickEvent && "cursor-pointer"), children: [
23980
23989
  /* @__PURE__ */ jsxs(Box, { className: "group flex items-stretch gap-2", children: [
23981
23990
  /* @__PURE__ */ jsx(Box, { className: "flex-1 min-w-0", children: children(itemData, index) }),
23982
23991
  itemActions && itemActions.length > 0 && /* @__PURE__ */ jsx(
@@ -24012,7 +24021,7 @@ function DataList({
24012
24021
  const id = itemData.id || String(index);
24013
24022
  const titleValue = getNestedValue(itemData, titleField?.name ?? "");
24014
24023
  return wrapDnd(
24015
- /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id, children: [
24024
+ /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id, onClick: itemClickEvent ? handleRowClick(itemData) : void 0, className: cn(itemClickEvent && "cursor-pointer"), children: [
24016
24025
  /* @__PURE__ */ jsxs(
24017
24026
  Box,
24018
24027
  {
@@ -33451,6 +33460,8 @@ var init_ReplyTree = __esm({
33451
33460
  const hasReplies = !!node.replies && node.replies.length > 0;
33452
33461
  const isCollapsed = collapsedSet.has(node.id);
33453
33462
  const atMaxDepth = depth >= maxDepth;
33463
+ const [replyOpen, setReplyOpen] = useState(false);
33464
+ const [draft, setDraft] = useState("");
33454
33465
  const handleVote = useCallback(
33455
33466
  (next) => {
33456
33467
  onVote?.(node.id, next);
@@ -33460,8 +33471,19 @@ var init_ReplyTree = __esm({
33460
33471
  );
33461
33472
  const handleReply = useCallback(() => {
33462
33473
  onReply?.(node.id);
33463
- if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId: node.id });
33464
- }, [node.id, onReply, replyEvent, eventBus]);
33474
+ setReplyOpen((open) => !open);
33475
+ }, [node.id, onReply]);
33476
+ const handleSubmitReply = useCallback(() => {
33477
+ const content = draft.trim();
33478
+ if (!content) return;
33479
+ if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId: node.id, content });
33480
+ setDraft("");
33481
+ setReplyOpen(false);
33482
+ }, [node.id, draft, replyEvent, eventBus]);
33483
+ const handleCancelReply = useCallback(() => {
33484
+ setDraft("");
33485
+ setReplyOpen(false);
33486
+ }, []);
33465
33487
  const handleFlag = useCallback(() => {
33466
33488
  onFlag?.(node.id);
33467
33489
  if (flagEvent) eventBus.emit(`UI:${flagEvent}`, { nodeId: node.id });
@@ -33548,6 +33570,33 @@ var init_ReplyTree = __esm({
33548
33570
  }
33549
33571
  )
33550
33572
  ] }),
33573
+ replyOpen && /* @__PURE__ */ jsxs(Box, { className: "flex flex-col gap-2 mt-1", children: [
33574
+ /* @__PURE__ */ jsx(
33575
+ Input,
33576
+ {
33577
+ inputType: "textarea",
33578
+ rows: 2,
33579
+ value: draft,
33580
+ placeholder: `Reply to ${node.authorName}\u2026`,
33581
+ onChange: (e) => setDraft(e.target.value),
33582
+ "aria-label": `Reply to ${node.authorName}`
33583
+ }
33584
+ ),
33585
+ /* @__PURE__ */ jsxs(Box, { className: "flex flex-row gap-2 items-center", children: [
33586
+ /* @__PURE__ */ jsx(
33587
+ Button,
33588
+ {
33589
+ variant: "primary",
33590
+ size: "sm",
33591
+ leftIcon: "send",
33592
+ onClick: handleSubmitReply,
33593
+ disabled: !draft.trim(),
33594
+ children: "Send"
33595
+ }
33596
+ ),
33597
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: handleCancelReply, children: "Cancel" })
33598
+ ] })
33599
+ ] }),
33551
33600
  hasReplies && !isCollapsed && (atMaxDepth ? /* @__PURE__ */ jsx(
33552
33601
  Button,
33553
33602
  {
@@ -23627,6 +23627,7 @@ function DataList({
23627
23627
  fields,
23628
23628
  columns,
23629
23629
  itemActions,
23630
+ itemClickEvent,
23630
23631
  gap = "none",
23631
23632
  variant = "default",
23632
23633
  groupBy,
@@ -23716,6 +23717,14 @@ function DataList({
23716
23717
  };
23717
23718
  eventBus.emit(`UI:${action.event}`, payload);
23718
23719
  };
23720
+ const handleRowClick = (itemData) => () => {
23721
+ if (!itemClickEvent) return;
23722
+ const payload = {
23723
+ id: itemData.id,
23724
+ row: itemData
23725
+ };
23726
+ eventBus.emit(`UI:${itemClickEvent}`, payload);
23727
+ };
23719
23728
  if (isLoading) {
23720
23729
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") || "Loading..." }) });
23721
23730
  }
@@ -23764,7 +23773,7 @@ function DataList({
23764
23773
  ),
23765
23774
  children: [
23766
23775
  !isSent && senderField && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "font-semibold mb-0.5", children: sender }),
23767
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: content !== void 0 && content !== null ? String(content) : "" }),
23776
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: cn(isSent && "text-primary-foreground"), children: content !== void 0 && content !== null ? String(content) : "" }),
23768
23777
  timestamp != null ? /* @__PURE__ */ jsxRuntime.jsx(
23769
23778
  Typography,
23770
23779
  {
@@ -23794,7 +23803,7 @@ function DataList({
23794
23803
  if (hasRenderProp) {
23795
23804
  const id2 = itemData.id || String(index);
23796
23805
  return wrapDnd(
23797
- /* @__PURE__ */ jsxRuntime.jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, children: [
23806
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, onClick: itemClickEvent ? handleRowClick(itemData) : void 0, className: cn(itemClickEvent && "cursor-pointer"), children: [
23798
23807
  /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "group flex items-stretch gap-2", children: [
23799
23808
  /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex-1 min-w-0", children: children(itemData, index) }),
23800
23809
  itemActions && itemActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
@@ -23830,7 +23839,7 @@ function DataList({
23830
23839
  const id = itemData.id || String(index);
23831
23840
  const titleValue = getNestedValue(itemData, titleField?.name ?? "");
23832
23841
  return wrapDnd(
23833
- /* @__PURE__ */ jsxRuntime.jsxs(Box, { "data-entity-row": true, "data-entity-id": id, children: [
23842
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { "data-entity-row": true, "data-entity-id": id, onClick: itemClickEvent ? handleRowClick(itemData) : void 0, className: cn(itemClickEvent && "cursor-pointer"), children: [
23834
23843
  /* @__PURE__ */ jsxRuntime.jsxs(
23835
23844
  Box,
23836
23845
  {
@@ -33067,6 +33076,8 @@ var init_ReplyTree = __esm({
33067
33076
  const hasReplies = !!node.replies && node.replies.length > 0;
33068
33077
  const isCollapsed = collapsedSet.has(node.id);
33069
33078
  const atMaxDepth = depth >= maxDepth;
33079
+ const [replyOpen, setReplyOpen] = React85.useState(false);
33080
+ const [draft, setDraft] = React85.useState("");
33070
33081
  const handleVote = React85.useCallback(
33071
33082
  (next) => {
33072
33083
  onVote?.(node.id, next);
@@ -33076,8 +33087,19 @@ var init_ReplyTree = __esm({
33076
33087
  );
33077
33088
  const handleReply = React85.useCallback(() => {
33078
33089
  onReply?.(node.id);
33079
- if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId: node.id });
33080
- }, [node.id, onReply, replyEvent, eventBus]);
33090
+ setReplyOpen((open) => !open);
33091
+ }, [node.id, onReply]);
33092
+ const handleSubmitReply = React85.useCallback(() => {
33093
+ const content = draft.trim();
33094
+ if (!content) return;
33095
+ if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId: node.id, content });
33096
+ setDraft("");
33097
+ setReplyOpen(false);
33098
+ }, [node.id, draft, replyEvent, eventBus]);
33099
+ const handleCancelReply = React85.useCallback(() => {
33100
+ setDraft("");
33101
+ setReplyOpen(false);
33102
+ }, []);
33081
33103
  const handleFlag = React85.useCallback(() => {
33082
33104
  onFlag?.(node.id);
33083
33105
  if (flagEvent) eventBus.emit(`UI:${flagEvent}`, { nodeId: node.id });
@@ -33164,6 +33186,33 @@ var init_ReplyTree = __esm({
33164
33186
  }
33165
33187
  )
33166
33188
  ] }),
33189
+ replyOpen && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-col gap-2 mt-1", children: [
33190
+ /* @__PURE__ */ jsxRuntime.jsx(
33191
+ Input,
33192
+ {
33193
+ inputType: "textarea",
33194
+ rows: 2,
33195
+ value: draft,
33196
+ placeholder: `Reply to ${node.authorName}\u2026`,
33197
+ onChange: (e) => setDraft(e.target.value),
33198
+ "aria-label": `Reply to ${node.authorName}`
33199
+ }
33200
+ ),
33201
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-row gap-2 items-center", children: [
33202
+ /* @__PURE__ */ jsxRuntime.jsx(
33203
+ Button,
33204
+ {
33205
+ variant: "primary",
33206
+ size: "sm",
33207
+ leftIcon: "send",
33208
+ onClick: handleSubmitReply,
33209
+ disabled: !draft.trim(),
33210
+ children: "Send"
33211
+ }
33212
+ ),
33213
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", onClick: handleCancelReply, children: "Cancel" })
33214
+ ] })
33215
+ ] }),
33167
33216
  hasReplies && !isCollapsed && (atMaxDepth ? /* @__PURE__ */ jsxRuntime.jsx(
33168
33217
  Button,
33169
33218
  {
@@ -23578,6 +23578,7 @@ function DataList({
23578
23578
  fields,
23579
23579
  columns,
23580
23580
  itemActions,
23581
+ itemClickEvent,
23581
23582
  gap = "none",
23582
23583
  variant = "default",
23583
23584
  groupBy,
@@ -23667,6 +23668,14 @@ function DataList({
23667
23668
  };
23668
23669
  eventBus.emit(`UI:${action.event}`, payload);
23669
23670
  };
23671
+ const handleRowClick = (itemData) => () => {
23672
+ if (!itemClickEvent) return;
23673
+ const payload = {
23674
+ id: itemData.id,
23675
+ row: itemData
23676
+ };
23677
+ eventBus.emit(`UI:${itemClickEvent}`, payload);
23678
+ };
23670
23679
  if (isLoading) {
23671
23680
  return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") || "Loading..." }) });
23672
23681
  }
@@ -23715,7 +23724,7 @@ function DataList({
23715
23724
  ),
23716
23725
  children: [
23717
23726
  !isSent && senderField && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "font-semibold mb-0.5", children: sender }),
23718
- /* @__PURE__ */ jsx(Typography, { variant: "body", children: content !== void 0 && content !== null ? String(content) : "" }),
23727
+ /* @__PURE__ */ jsx(Typography, { variant: "body", className: cn(isSent && "text-primary-foreground"), children: content !== void 0 && content !== null ? String(content) : "" }),
23719
23728
  timestamp != null ? /* @__PURE__ */ jsx(
23720
23729
  Typography,
23721
23730
  {
@@ -23745,7 +23754,7 @@ function DataList({
23745
23754
  if (hasRenderProp) {
23746
23755
  const id2 = itemData.id || String(index);
23747
23756
  return wrapDnd(
23748
- /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, children: [
23757
+ /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, onClick: itemClickEvent ? handleRowClick(itemData) : void 0, className: cn(itemClickEvent && "cursor-pointer"), children: [
23749
23758
  /* @__PURE__ */ jsxs(Box, { className: "group flex items-stretch gap-2", children: [
23750
23759
  /* @__PURE__ */ jsx(Box, { className: "flex-1 min-w-0", children: children(itemData, index) }),
23751
23760
  itemActions && itemActions.length > 0 && /* @__PURE__ */ jsx(
@@ -23781,7 +23790,7 @@ function DataList({
23781
23790
  const id = itemData.id || String(index);
23782
23791
  const titleValue = getNestedValue(itemData, titleField?.name ?? "");
23783
23792
  return wrapDnd(
23784
- /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id, children: [
23793
+ /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id, onClick: itemClickEvent ? handleRowClick(itemData) : void 0, className: cn(itemClickEvent && "cursor-pointer"), children: [
23785
23794
  /* @__PURE__ */ jsxs(
23786
23795
  Box,
23787
23796
  {
@@ -33018,6 +33027,8 @@ var init_ReplyTree = __esm({
33018
33027
  const hasReplies = !!node.replies && node.replies.length > 0;
33019
33028
  const isCollapsed = collapsedSet.has(node.id);
33020
33029
  const atMaxDepth = depth >= maxDepth;
33030
+ const [replyOpen, setReplyOpen] = useState(false);
33031
+ const [draft, setDraft] = useState("");
33021
33032
  const handleVote = useCallback(
33022
33033
  (next) => {
33023
33034
  onVote?.(node.id, next);
@@ -33027,8 +33038,19 @@ var init_ReplyTree = __esm({
33027
33038
  );
33028
33039
  const handleReply = useCallback(() => {
33029
33040
  onReply?.(node.id);
33030
- if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId: node.id });
33031
- }, [node.id, onReply, replyEvent, eventBus]);
33041
+ setReplyOpen((open) => !open);
33042
+ }, [node.id, onReply]);
33043
+ const handleSubmitReply = useCallback(() => {
33044
+ const content = draft.trim();
33045
+ if (!content) return;
33046
+ if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId: node.id, content });
33047
+ setDraft("");
33048
+ setReplyOpen(false);
33049
+ }, [node.id, draft, replyEvent, eventBus]);
33050
+ const handleCancelReply = useCallback(() => {
33051
+ setDraft("");
33052
+ setReplyOpen(false);
33053
+ }, []);
33032
33054
  const handleFlag = useCallback(() => {
33033
33055
  onFlag?.(node.id);
33034
33056
  if (flagEvent) eventBus.emit(`UI:${flagEvent}`, { nodeId: node.id });
@@ -33115,6 +33137,33 @@ var init_ReplyTree = __esm({
33115
33137
  }
33116
33138
  )
33117
33139
  ] }),
33140
+ replyOpen && /* @__PURE__ */ jsxs(Box, { className: "flex flex-col gap-2 mt-1", children: [
33141
+ /* @__PURE__ */ jsx(
33142
+ Input,
33143
+ {
33144
+ inputType: "textarea",
33145
+ rows: 2,
33146
+ value: draft,
33147
+ placeholder: `Reply to ${node.authorName}\u2026`,
33148
+ onChange: (e) => setDraft(e.target.value),
33149
+ "aria-label": `Reply to ${node.authorName}`
33150
+ }
33151
+ ),
33152
+ /* @__PURE__ */ jsxs(Box, { className: "flex flex-row gap-2 items-center", children: [
33153
+ /* @__PURE__ */ jsx(
33154
+ Button,
33155
+ {
33156
+ variant: "primary",
33157
+ size: "sm",
33158
+ leftIcon: "send",
33159
+ onClick: handleSubmitReply,
33160
+ disabled: !draft.trim(),
33161
+ children: "Send"
33162
+ }
33163
+ ),
33164
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: handleCancelReply, children: "Cancel" })
33165
+ ] })
33166
+ ] }),
33118
33167
  hasReplies && !isCollapsed && (atMaxDepth ? /* @__PURE__ */ jsx(
33119
33168
  Button,
33120
33169
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/ui",
3
- "version": "5.9.1",
3
+ "version": "5.9.3",
4
4
  "description": "React UI components, hooks, and providers for Almadar",
5
5
  "type": "module",
6
6
  "sideEffects": [