dp-widgets-framework 1.7.0 → 1.7.2

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.
Files changed (3) hide show
  1. package/dist/index.esm.js +443 -221
  2. package/dist/index.js +442 -220
  3. package/package.json +2 -1
package/dist/index.esm.js CHANGED
@@ -7,7 +7,7 @@ import * as LabelPrimitive from '@radix-ui/react-label';
7
7
  import { cva } from 'class-variance-authority';
8
8
  import * as SwitchPrimitives from '@radix-ui/react-switch';
9
9
  import * as SelectPrimitive from '@radix-ui/react-select';
10
- import { ChevronDown, ChevronUp, Check, AlertCircle, MoveUp, MoveDown, Trash2, Plus, Bot, Type, Layout, LayoutGrid, BarChart as BarChart$1, Filter, Search, ArrowUp, ArrowDown, ChevronRight, RefreshCw, Send, Loader2, X, AlignVerticalSpaceAround, LineChart as LineChart$1, PieChart as PieChart$1, Table, FileText, SlidersHorizontal, GripHorizontal, Edit, MessageCircleX, ChevronLeft, Maximize2, Grid3X3, Edit2 } from 'lucide-react';
10
+ import { ChevronDown, ChevronUp, Check, AlertCircle, MoveUp, MoveDown, Trash2, Plus, Bot, Type, Layout, LayoutGrid, BarChart as BarChart$1, Filter, Search, ArrowUp, ArrowDown, ChevronRight, RefreshCw, Loader2, Download, Send, X, AlignVerticalSpaceAround, LineChart as LineChart$1, PieChart as PieChart$1, Table, FileText, SlidersHorizontal, GripHorizontal, Edit, MessageCircleX, ChevronLeft, Maximize2, Grid3X3, Edit2 } from 'lucide-react';
11
11
  import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
12
12
  import { Slot, createSlot, createSlottable } from '@radix-ui/react-slot';
13
13
  import { debounce as debounce$1 } from 'lodash';
@@ -17,6 +17,7 @@ import { v4 } from 'uuid';
17
17
  import * as ReactDOM from 'react-dom';
18
18
  import { TextMessage, Role } from '@copilotkit/runtime-client-gql';
19
19
  import { CopilotKit, useCopilotContext, useCoAgent, useCopilotChat } from '@copilotkit/react-core';
20
+ import jsPDF from 'jspdf';
20
21
  import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
21
22
  import * as DialogPrimitive from '@radix-ui/react-dialog';
22
23
  import { format } from 'date-fns';
@@ -3774,6 +3775,71 @@ function computeCoordsFromPlacement(_ref, placement, rtl) {
3774
3775
  return coords;
3775
3776
  }
3776
3777
 
3778
+ /**
3779
+ * Resolves with an object of overflow side offsets that determine how much the
3780
+ * element is overflowing a given clipping boundary on each side.
3781
+ * - positive = overflowing the boundary by that number of pixels
3782
+ * - negative = how many pixels left before it will overflow
3783
+ * - 0 = lies flush with the boundary
3784
+ * @see https://floating-ui.com/docs/detectOverflow
3785
+ */
3786
+ async function detectOverflow(state, options) {
3787
+ var _await$platform$isEle;
3788
+ if (options === void 0) {
3789
+ options = {};
3790
+ }
3791
+ const {
3792
+ x,
3793
+ y,
3794
+ platform,
3795
+ rects,
3796
+ elements,
3797
+ strategy
3798
+ } = state;
3799
+ const {
3800
+ boundary = 'clippingAncestors',
3801
+ rootBoundary = 'viewport',
3802
+ elementContext = 'floating',
3803
+ altBoundary = false,
3804
+ padding = 0
3805
+ } = evaluate(options, state);
3806
+ const paddingObject = getPaddingObject(padding);
3807
+ const altContext = elementContext === 'floating' ? 'reference' : 'floating';
3808
+ const element = elements[altBoundary ? altContext : elementContext];
3809
+ const clippingClientRect = rectToClientRect(await platform.getClippingRect({
3810
+ element: ((_await$platform$isEle = await (platform.isElement == null ? void 0 : platform.isElement(element))) != null ? _await$platform$isEle : true) ? element : element.contextElement || (await (platform.getDocumentElement == null ? void 0 : platform.getDocumentElement(elements.floating))),
3811
+ boundary,
3812
+ rootBoundary,
3813
+ strategy
3814
+ }));
3815
+ const rect = elementContext === 'floating' ? {
3816
+ x,
3817
+ y,
3818
+ width: rects.floating.width,
3819
+ height: rects.floating.height
3820
+ } : rects.reference;
3821
+ const offsetParent = await (platform.getOffsetParent == null ? void 0 : platform.getOffsetParent(elements.floating));
3822
+ const offsetScale = (await (platform.isElement == null ? void 0 : platform.isElement(offsetParent))) ? (await (platform.getScale == null ? void 0 : platform.getScale(offsetParent))) || {
3823
+ x: 1,
3824
+ y: 1
3825
+ } : {
3826
+ x: 1,
3827
+ y: 1
3828
+ };
3829
+ const elementClientRect = rectToClientRect(platform.convertOffsetParentRelativeRectToViewportRelativeRect ? await platform.convertOffsetParentRelativeRectToViewportRelativeRect({
3830
+ elements,
3831
+ rect,
3832
+ offsetParent,
3833
+ strategy
3834
+ }) : rect);
3835
+ return {
3836
+ top: (clippingClientRect.top - elementClientRect.top + paddingObject.top) / offsetScale.y,
3837
+ bottom: (elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom) / offsetScale.y,
3838
+ left: (clippingClientRect.left - elementClientRect.left + paddingObject.left) / offsetScale.x,
3839
+ right: (elementClientRect.right - clippingClientRect.right + paddingObject.right) / offsetScale.x
3840
+ };
3841
+ }
3842
+
3777
3843
  /**
3778
3844
  * Computes the `x` and `y` coordinates that will place the floating element
3779
3845
  * next to a given reference element.
@@ -3803,6 +3869,7 @@ const computePosition$1 = async (reference, floating, config) => {
3803
3869
  let middlewareData = {};
3804
3870
  let resetCount = 0;
3805
3871
  for (let i = 0; i < validMiddleware.length; i++) {
3872
+ var _platform$detectOverf;
3806
3873
  const {
3807
3874
  name,
3808
3875
  fn
@@ -3820,7 +3887,10 @@ const computePosition$1 = async (reference, floating, config) => {
3820
3887
  strategy,
3821
3888
  middlewareData,
3822
3889
  rects,
3823
- platform,
3890
+ platform: {
3891
+ ...platform,
3892
+ detectOverflow: (_platform$detectOverf = platform.detectOverflow) != null ? _platform$detectOverf : detectOverflow
3893
+ },
3824
3894
  elements: {
3825
3895
  reference,
3826
3896
  floating
@@ -3865,71 +3935,6 @@ const computePosition$1 = async (reference, floating, config) => {
3865
3935
  };
3866
3936
  };
3867
3937
 
3868
- /**
3869
- * Resolves with an object of overflow side offsets that determine how much the
3870
- * element is overflowing a given clipping boundary on each side.
3871
- * - positive = overflowing the boundary by that number of pixels
3872
- * - negative = how many pixels left before it will overflow
3873
- * - 0 = lies flush with the boundary
3874
- * @see https://floating-ui.com/docs/detectOverflow
3875
- */
3876
- async function detectOverflow(state, options) {
3877
- var _await$platform$isEle;
3878
- if (options === void 0) {
3879
- options = {};
3880
- }
3881
- const {
3882
- x,
3883
- y,
3884
- platform,
3885
- rects,
3886
- elements,
3887
- strategy
3888
- } = state;
3889
- const {
3890
- boundary = 'clippingAncestors',
3891
- rootBoundary = 'viewport',
3892
- elementContext = 'floating',
3893
- altBoundary = false,
3894
- padding = 0
3895
- } = evaluate(options, state);
3896
- const paddingObject = getPaddingObject(padding);
3897
- const altContext = elementContext === 'floating' ? 'reference' : 'floating';
3898
- const element = elements[altBoundary ? altContext : elementContext];
3899
- const clippingClientRect = rectToClientRect(await platform.getClippingRect({
3900
- element: ((_await$platform$isEle = await (platform.isElement == null ? void 0 : platform.isElement(element))) != null ? _await$platform$isEle : true) ? element : element.contextElement || (await (platform.getDocumentElement == null ? void 0 : platform.getDocumentElement(elements.floating))),
3901
- boundary,
3902
- rootBoundary,
3903
- strategy
3904
- }));
3905
- const rect = elementContext === 'floating' ? {
3906
- x,
3907
- y,
3908
- width: rects.floating.width,
3909
- height: rects.floating.height
3910
- } : rects.reference;
3911
- const offsetParent = await (platform.getOffsetParent == null ? void 0 : platform.getOffsetParent(elements.floating));
3912
- const offsetScale = (await (platform.isElement == null ? void 0 : platform.isElement(offsetParent))) ? (await (platform.getScale == null ? void 0 : platform.getScale(offsetParent))) || {
3913
- x: 1,
3914
- y: 1
3915
- } : {
3916
- x: 1,
3917
- y: 1
3918
- };
3919
- const elementClientRect = rectToClientRect(platform.convertOffsetParentRelativeRectToViewportRelativeRect ? await platform.convertOffsetParentRelativeRectToViewportRelativeRect({
3920
- elements,
3921
- rect,
3922
- offsetParent,
3923
- strategy
3924
- }) : rect);
3925
- return {
3926
- top: (clippingClientRect.top - elementClientRect.top + paddingObject.top) / offsetScale.y,
3927
- bottom: (elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom) / offsetScale.y,
3928
- left: (clippingClientRect.left - elementClientRect.left + paddingObject.left) / offsetScale.x,
3929
- right: (elementClientRect.right - clippingClientRect.right + paddingObject.right) / offsetScale.x
3930
- };
3931
- }
3932
-
3933
3938
  /**
3934
3939
  * Provides data to position an inner element of the floating element so that it
3935
3940
  * appears centered to the reference element.
@@ -4062,7 +4067,7 @@ const flip$2 = function (options) {
4062
4067
  fallbackPlacements.push(...getOppositeAxisPlacements(initialPlacement, flipAlignment, fallbackAxisSideDirection, rtl));
4063
4068
  }
4064
4069
  const placements = [initialPlacement, ...fallbackPlacements];
4065
- const overflow = await detectOverflow(state, detectOverflowOptions);
4070
+ const overflow = await platform.detectOverflow(state, detectOverflowOptions);
4066
4071
  const overflows = [];
4067
4072
  let overflowsData = ((_middlewareData$flip = middlewareData.flip) == null ? void 0 : _middlewareData$flip.overflows) || [];
4068
4073
  if (checkMainAxis) {
@@ -4169,7 +4174,8 @@ const hide$2 = function (options) {
4169
4174
  options,
4170
4175
  async fn(state) {
4171
4176
  const {
4172
- rects
4177
+ rects,
4178
+ platform
4173
4179
  } = state;
4174
4180
  const {
4175
4181
  strategy = 'referenceHidden',
@@ -4178,7 +4184,7 @@ const hide$2 = function (options) {
4178
4184
  switch (strategy) {
4179
4185
  case 'referenceHidden':
4180
4186
  {
4181
- const overflow = await detectOverflow(state, {
4187
+ const overflow = await platform.detectOverflow(state, {
4182
4188
  ...detectOverflowOptions,
4183
4189
  elementContext: 'reference'
4184
4190
  });
@@ -4192,7 +4198,7 @@ const hide$2 = function (options) {
4192
4198
  }
4193
4199
  case 'escaped':
4194
4200
  {
4195
- const overflow = await detectOverflow(state, {
4201
+ const overflow = await platform.detectOverflow(state, {
4196
4202
  ...detectOverflowOptions,
4197
4203
  altBoundary: true
4198
4204
  });
@@ -4315,7 +4321,8 @@ const shift$2 = function (options) {
4315
4321
  const {
4316
4322
  x,
4317
4323
  y,
4318
- placement
4324
+ placement,
4325
+ platform
4319
4326
  } = state;
4320
4327
  const {
4321
4328
  mainAxis: checkMainAxis = true,
@@ -4338,7 +4345,7 @@ const shift$2 = function (options) {
4338
4345
  x,
4339
4346
  y
4340
4347
  };
4341
- const overflow = await detectOverflow(state, detectOverflowOptions);
4348
+ const overflow = await platform.detectOverflow(state, detectOverflowOptions);
4342
4349
  const crossAxis = getSideAxis(getSide(placement));
4343
4350
  const mainAxis = getOppositeAxis(crossAxis);
4344
4351
  let mainAxisCoord = coords[mainAxis];
@@ -4470,7 +4477,7 @@ const size$2 = function (options) {
4470
4477
  apply = () => {},
4471
4478
  ...detectOverflowOptions
4472
4479
  } = evaluate(options, state);
4473
- const overflow = await detectOverflow(state, detectOverflowOptions);
4480
+ const overflow = await platform.detectOverflow(state, detectOverflowOptions);
4474
4481
  const side = getSide(placement);
4475
4482
  const alignment = getAlignment(placement);
4476
4483
  const isYAxis = getSideAxis(placement) === 'y';
@@ -44409,6 +44416,175 @@ function SpacerWidget({ widget }) {
44409
44416
  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full", style: styles });
44410
44417
  }
44411
44418
 
44419
+ const WISENBAKER_PRIMARY = "#8f002d";
44420
+ const WISENBAKER_GRAY = "#475569";
44421
+ function parseMarkdown(text) {
44422
+ const segments = [];
44423
+ const regex = /\*\*(.+?)\*\*/g;
44424
+ let lastIndex = 0;
44425
+ let match;
44426
+ while ((match = regex.exec(text)) !== null) {
44427
+ if (match.index > lastIndex) {
44428
+ segments.push({ text: text.slice(lastIndex, match.index), bold: false });
44429
+ }
44430
+ segments.push({ text: match[1], bold: true });
44431
+ lastIndex = regex.lastIndex;
44432
+ }
44433
+ if (lastIndex < text.length) {
44434
+ segments.push({ text: text.slice(lastIndex), bold: false });
44435
+ }
44436
+ return segments.length > 0 ? segments : [{ text, bold: false }];
44437
+ }
44438
+ function formatLine(line) {
44439
+ const bulletMatch = line.match(/^(\s*)[\*\-•]\s+(.*)$/);
44440
+ if (bulletMatch) {
44441
+ const indent = bulletMatch[1].length;
44442
+ return { text: bulletMatch[2], isBullet: true, indent };
44443
+ }
44444
+ const numberedMatch = line.match(/^(\s*)\d+\.\s+(.*)$/);
44445
+ if (numberedMatch) {
44446
+ const indent = numberedMatch[1].length;
44447
+ return { text: numberedMatch[2], isBullet: true, indent };
44448
+ }
44449
+ return { text: line, isBullet: false, indent: 0 };
44450
+ }
44451
+ function generateExportFilename(widgetId) {
44452
+ const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
44453
+ return `NSight_Chat_Export_${widgetId}_${date}.pdf`;
44454
+ }
44455
+ function exportChatToPDF(options) {
44456
+ const { widgetId, messages, dashboardName } = options;
44457
+ const doc = new jsPDF();
44458
+ let yPosition = 25;
44459
+ const pageHeight = doc.internal.pageSize.height;
44460
+ const pageWidth = doc.internal.pageSize.width;
44461
+ const margin = 20;
44462
+ const contentWidth = pageWidth - margin * 2;
44463
+ const maxWidth = contentWidth - 10;
44464
+ const checkPageBreak = (requiredSpace = 20) => {
44465
+ if (yPosition > pageHeight - requiredSpace) {
44466
+ doc.addPage();
44467
+ yPosition = 25;
44468
+ }
44469
+ };
44470
+ const renderFormattedText = (text, x, maxW, baseIndent = 0) => {
44471
+ const lines = text.split("\n");
44472
+ lines.forEach((line) => {
44473
+ const { text: lineText, isBullet, indent } = formatLine(line);
44474
+ const lineIndent = x + baseIndent + indent * 2;
44475
+ if (isBullet) {
44476
+ checkPageBreak(10);
44477
+ doc.setFont("helvetica", "normal");
44478
+ doc.text("\u2022", lineIndent, yPosition);
44479
+ }
44480
+ const textX = isBullet ? lineIndent + 5 : lineIndent;
44481
+ const textMaxWidth = maxW - (textX - x);
44482
+ const segments = parseMarkdown(lineText);
44483
+ let currentLine = "";
44484
+ let currentX = textX;
44485
+ segments.forEach((segment) => {
44486
+ doc.setFont("helvetica", segment.bold ? "bold" : "normal");
44487
+ const words = segment.text.split(" ");
44488
+ words.forEach((word, wordIndex) => {
44489
+ const testLine = currentLine + (currentLine ? " " : "") + word;
44490
+ const testWidth = doc.getTextWidth(testLine);
44491
+ if (testWidth > textMaxWidth && currentLine) {
44492
+ checkPageBreak(10);
44493
+ doc.text(currentLine, currentX, yPosition);
44494
+ yPosition += 5;
44495
+ currentLine = word;
44496
+ currentX = isBullet ? lineIndent + 5 : x + baseIndent;
44497
+ } else {
44498
+ currentLine = testLine;
44499
+ }
44500
+ });
44501
+ });
44502
+ if (currentLine) {
44503
+ checkPageBreak(10);
44504
+ const lastSegment = segments[segments.length - 1];
44505
+ doc.setFont("helvetica", (lastSegment == null ? void 0 : lastSegment.bold) ? "bold" : "normal");
44506
+ doc.text(currentLine, currentX, yPosition);
44507
+ yPosition += 5;
44508
+ }
44509
+ });
44510
+ };
44511
+ doc.setFontSize(18);
44512
+ doc.setFont("helvetica", "bold");
44513
+ doc.setTextColor(WISENBAKER_PRIMARY);
44514
+ doc.text("Wisenbaker AI Analytics", margin, yPosition);
44515
+ yPosition += 8;
44516
+ doc.setFontSize(11);
44517
+ doc.setFont("helvetica", "normal");
44518
+ doc.setTextColor(WISENBAKER_GRAY);
44519
+ doc.text("Chat Export", margin, yPosition);
44520
+ yPosition += 12;
44521
+ doc.setFontSize(9);
44522
+ doc.setTextColor("#666666");
44523
+ if (dashboardName) {
44524
+ doc.setFont("helvetica", "bold");
44525
+ doc.text("Dashboard:", margin, yPosition);
44526
+ doc.setFont("helvetica", "normal");
44527
+ doc.text(dashboardName, margin + 38, yPosition);
44528
+ yPosition += 5;
44529
+ }
44530
+ doc.setFont("helvetica", "bold");
44531
+ doc.text("Exported:", margin, yPosition);
44532
+ doc.setFont("helvetica", "normal");
44533
+ doc.text((/* @__PURE__ */ new Date()).toLocaleString(), margin + 38, yPosition);
44534
+ doc.setFont("helvetica", "bold");
44535
+ doc.text("Messages:", margin + 100, yPosition);
44536
+ doc.setFont("helvetica", "normal");
44537
+ doc.text(String(messages.length), margin + 130, yPosition);
44538
+ yPosition += 12;
44539
+ doc.setDrawColor(200, 200, 200);
44540
+ doc.setLineWidth(0.5);
44541
+ doc.line(margin, yPosition, pageWidth - margin, yPosition);
44542
+ yPosition += 8;
44543
+ messages.forEach((message, index) => {
44544
+ checkPageBreak(30);
44545
+ const isUser = message.role === "user";
44546
+ const roleLabel = isUser ? "You" : "AI Assistant";
44547
+ const timestamp = message.createdAt ? new Date(message.createdAt).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) : "";
44548
+ const bgColor = isUser ? [143, 0, 45] : [241, 243, 245];
44549
+ doc.setFillColor(bgColor[0], bgColor[1], bgColor[2]);
44550
+ doc.setFontSize(9);
44551
+ doc.setFont("helvetica", "bold");
44552
+ doc.setTextColor(isUser ? WISENBAKER_PRIMARY : WISENBAKER_GRAY);
44553
+ doc.text(roleLabel, margin, yPosition);
44554
+ if (timestamp) {
44555
+ doc.setFont("helvetica", "normal");
44556
+ doc.setTextColor("#888888");
44557
+ doc.text(timestamp, margin + doc.getTextWidth(roleLabel) + 5, yPosition);
44558
+ }
44559
+ yPosition += 6;
44560
+ doc.setFontSize(10);
44561
+ doc.setTextColor("#333333");
44562
+ doc.setFont("helvetica", "normal");
44563
+ renderFormattedText(message.content, margin + 5, maxWidth - 5, 0);
44564
+ yPosition += 8;
44565
+ if (index < messages.length - 1) {
44566
+ doc.setDrawColor(230, 230, 230);
44567
+ doc.setLineWidth(0.3);
44568
+ doc.line(margin + 10, yPosition - 4, pageWidth - margin - 10, yPosition - 4);
44569
+ }
44570
+ });
44571
+ const totalPages = doc.getNumberOfPages();
44572
+ for (let i = 1; i <= totalPages; i++) {
44573
+ doc.setPage(i);
44574
+ doc.setFontSize(8);
44575
+ doc.setTextColor("#999999");
44576
+ doc.setFont("helvetica", "normal");
44577
+ doc.text(
44578
+ `Wisenbaker AI Analytics \u2022 Page ${i} of ${totalPages}`,
44579
+ pageWidth / 2,
44580
+ pageHeight - 10,
44581
+ { align: "center" }
44582
+ );
44583
+ }
44584
+ const filename = generateExportFilename(widgetId);
44585
+ doc.save(filename);
44586
+ }
44587
+
44412
44588
  var __defProp$b = Object.defineProperty;
44413
44589
  var __defProps$9 = Object.defineProperties;
44414
44590
  var __getOwnPropDescs$9 = Object.getOwnPropertyDescriptors;
@@ -44457,7 +44633,8 @@ function CopilotKitChatbot({
44457
44633
  styles,
44458
44634
  onResetReady,
44459
44635
  widgetIds,
44460
- datasetId
44636
+ datasetId,
44637
+ dashboardName
44461
44638
  }) {
44462
44639
  var _a, _b, _c, _d;
44463
44640
  const { threadId, setThreadId } = useCopilotContext();
@@ -44474,7 +44651,24 @@ function CopilotKitChatbot({
44474
44651
  const { reset, visibleMessages, appendMessage, isLoading } = useCopilotChat();
44475
44652
  const [inputValue, setInputValue] = useState("");
44476
44653
  const [chatMessages, setChatMessages] = useState([]);
44654
+ const [isExporting, setIsExporting] = useState(false);
44477
44655
  const messagesEndRef = React__default.useRef(null);
44656
+ const handleExport = async () => {
44657
+ if (chatMessages.length === 0) return;
44658
+ setIsExporting(true);
44659
+ try {
44660
+ exportChatToPDF({
44661
+ widgetId: widget.id,
44662
+ widgetTitle: widget.title,
44663
+ messages: chatMessages,
44664
+ dashboardName
44665
+ });
44666
+ } catch (error) {
44667
+ console.error("Export failed:", error);
44668
+ } finally {
44669
+ setIsExporting(false);
44670
+ }
44671
+ };
44478
44672
  const scrollToBottom = () => {
44479
44673
  var _a2;
44480
44674
  const el = messagesEndRef.current;
@@ -44549,6 +44743,25 @@ function CopilotKitChatbot({
44549
44743
  /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-medium", children: widget.title })
44550
44744
  ] }) }),
44551
44745
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 h-full flex flex-col", children: [
44746
+ chatMessages.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-start px-4 py-2 border-b border-gray-100", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
44747
+ "button",
44748
+ {
44749
+ onClick: handleExport,
44750
+ disabled: isExporting,
44751
+ className: cn(
44752
+ "flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md",
44753
+ "bg-gray-100 border border-gray-200",
44754
+ "text-gray-700 hover:bg-gray-200 hover:border-gray-300",
44755
+ "disabled:opacity-50 disabled:cursor-not-allowed",
44756
+ "transition-colors duration-150"
44757
+ ),
44758
+ title: "Export conversation as PDF",
44759
+ children: [
44760
+ isExporting ? /* @__PURE__ */ jsxRuntimeExports.jsx(Loader2, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Download, { className: "h-3.5 w-3.5" }),
44761
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Export PDF" })
44762
+ ]
44763
+ }
44764
+ ) }),
44552
44765
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-y-auto p-4 space-y-4", children: chatMessages.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center text-gray-500 text-xs mt-8", children: ((_b = widget.config) == null ? void 0 : _b.copilotInitialMessage) || ((_c = widget.config) == null ? void 0 : _c.placeholder) || "How can I help you today?" }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
44553
44766
  chatMessages.map((message) => /* @__PURE__ */ jsxRuntimeExports.jsx(
44554
44767
  "div",
@@ -44624,7 +44837,8 @@ function ChatbotWidget({
44624
44837
  widgetBackendUrl,
44625
44838
  onResetReady,
44626
44839
  widgetIds,
44627
- datasetId
44840
+ datasetId,
44841
+ dashboardName
44628
44842
  }) {
44629
44843
  var _a, _b;
44630
44844
  const styles = getStyleValues$4((_a = widget.config) == null ? void 0 : _a.styles);
@@ -44648,7 +44862,8 @@ function ChatbotWidget({
44648
44862
  styles,
44649
44863
  onResetReady,
44650
44864
  widgetIds,
44651
- datasetId
44865
+ datasetId,
44866
+ dashboardName
44652
44867
  }
44653
44868
  )
44654
44869
  }
@@ -47165,7 +47380,8 @@ function WidgetRenderer({
47165
47380
  datasetId,
47166
47381
  pageId,
47167
47382
  onApplyFilters,
47168
- isEditing = false
47383
+ isEditing = false,
47384
+ dashboardName
47169
47385
  }) {
47170
47386
  const handleConfigUpdate = (config) => {
47171
47387
  if (onConfigUpdate) {
@@ -47197,7 +47413,7 @@ function WidgetRenderer({
47197
47413
  }
47198
47414
  );
47199
47415
  case "chatbot":
47200
- return /* @__PURE__ */ jsxRuntimeExports.jsx(ChatbotWidget, { widget, showHeader: false, widgetBackendUrl, onResetReady, widgetIds, datasetId });
47416
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(ChatbotWidget, { widget, showHeader: false, widgetBackendUrl, onResetReady, widgetIds, datasetId, dashboardName });
47201
47417
  case "filters":
47202
47418
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
47203
47419
  FiltersWidget,
@@ -48806,7 +49022,7 @@ function WidgetDashboard({
48806
49022
  containerPadding: [0, 0],
48807
49023
  margin: [16, 16],
48808
49024
  children: displayWidgets.map((w) => {
48809
- var _a, _b;
49025
+ var _a, _b, _c;
48810
49026
  const filterStatus = w.type === "agent" ? getWidgetFilterStatus(w.id) : null;
48811
49027
  const badgeInfo = filterStatus ? getFilterStatusBadge(filterStatus.status) : null;
48812
49028
  const isFocusMode = focusWidgetId && w.id === focusWidgetId;
@@ -48845,7 +49061,7 @@ function WidgetDashboard({
48845
49061
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { onClick: () => handleClearChat(w == null ? void 0 : w.id), onMouseOver: () => setVisibleClearButton(w == null ? void 0 : w.id), onMouseLeave: () => setVisibleClearButton(""), className: "absolute top-[12px] right-0 z-40 flex align-middle justify-center gap-2 text-sm px-4 py-2 border-primary-300 rounded-l-sm w-fit bg-primary-700 text-white cursor-pointer shadow-md transition-all", children: /* @__PURE__ */ jsxRuntimeExports.jsx(MessageCircleX, { className: "w-5 h-5" }) }),
48846
49062
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `absolute top-[56px] right-[16px] z-50 w-max py-1 text-xs px-2 rounded-sm text-white bg-gray-950 ${visibleClearButton === (w == null ? void 0 : w.id) ? "block" : "hidden"}`, children: "Clear Chat" })
48847
49063
  ] }),
48848
- /* @__PURE__ */ jsxRuntimeExports.jsx(WidgetRenderer, { widget: w, widgetBackendUrl, onResetReady: handleResetReady, widgetIds: widgets.filter((widget) => widget.type !== "chatbot").map((widget) => widget.id), datasetId, pageId, onApplyFilters, isEditing })
49064
+ /* @__PURE__ */ jsxRuntimeExports.jsx(WidgetRenderer, { widget: w, widgetBackendUrl, onResetReady: handleResetReady, widgetIds: widgets.filter((widget) => widget.type !== "chatbot").map((widget) => widget.id), datasetId, pageId, onApplyFilters, isEditing, dashboardName: ((_c = pageData == null ? void 0 : pageData.basic) == null ? void 0 : _c.title) || (pageData == null ? void 0 : pageData.name) || (pageData == null ? void 0 : pageData.title) })
48849
49065
  ] })
48850
49066
  ] }, w.id);
48851
49067
  })
@@ -48946,7 +49162,7 @@ function PresentationMode({
48946
49162
  return;
48947
49163
  }
48948
49164
  item.style.cursor = "pointer";
48949
- item.style.boxShadow = "0 0 0 3px var(--primary-500, #3b82f6), 0 10px 30px -5px rgba(0, 0, 0, 0.2)";
49165
+ item.style.boxShadow = "0 0 0 3px var(--primary-500), 0 10px 30px -5px rgba(0, 0, 0, 0.2)";
48950
49166
  item.style.transition = "box-shadow 0.2s ease-out";
48951
49167
  item.style.zIndex = "10";
48952
49168
  };
@@ -49064,156 +49280,162 @@ function PresentationMode({
49064
49280
  }, [isOpen]);
49065
49281
  if (!isOpen) return null;
49066
49282
  const currentFocusWidget = focusableWidgets[currentFocusIndex];
49067
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fixed inset-0 z-50 bg-white flex flex-col", children: [
49068
- /* @__PURE__ */ jsxRuntimeExports.jsxs("header", { className: "flex items-center justify-between px-6 py-4 border-b border-gray-200 bg-white shrink-0", children: [
49069
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col", children: [
49070
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xl font-bold text-primary-700 tracking-wide", children: branding.title }),
49071
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-primary-500 tracking-[0.2em] -mt-1", children: branding.subtitle })
49072
- ] }) }),
49073
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute left-1/2 transform -translate-x-1/2 text-center", children: [
49074
- /* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "text-lg font-bold text-gray-900 uppercase tracking-wide", children: dashboardTitle }),
49075
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-12 h-1 bg-primary-600 mx-auto mt-1 rounded" })
49076
- ] }),
49077
- /* @__PURE__ */ jsxRuntimeExports.jsx(
49078
- "button",
49079
- {
49080
- onClick: onClose,
49081
- className: "p-2 hover:bg-gray-100 rounded-lg transition-colors",
49082
- "aria-label": "Close presentation",
49083
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(X, { className: "w-6 h-6 text-gray-600" })
49084
- }
49085
- )
49086
- ] }),
49087
- /* @__PURE__ */ jsxRuntimeExports.jsx("main", { className: `flex-1 min-h-0 ${viewMode === "grid" ? "overflow-auto bg-gray-50 p-6" : "overflow-hidden bg-gray-100"}`, children: loading ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center gap-3", children: [
49088
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-8 h-8 border-4 border-primary-600 border-t-transparent rounded-full animate-spin" }),
49089
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-gray-600", children: "Loading widgets..." })
49090
- ] }) }) : viewMode === "grid" ? (
49091
- /* Grid View - Show all widgets using WidgetDashboard */
49092
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-full relative", ref: gridContainerRef, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
49093
- WidgetDashboard,
49094
- {
49095
- pageId,
49096
- isEditing: false,
49097
- selectedWidget: null,
49098
- onWidgetSelect: () => {
49099
- },
49100
- openWidgetPallete: false,
49101
- onCloseWidgetPallete: () => {
49102
- },
49103
- onApplyFilters: () => {
49104
- },
49105
- isApplyingFilters: false,
49106
- onSaveLayoutReady: () => {
49107
- },
49108
- widgetBackendUrl
49109
- },
49110
- `presentation-grid-${pageId}`
49111
- ) })
49112
- ) : (
49113
- /* Focus View - Show one widget at a time */
49114
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-full flex flex-col", ref: focusContainerRef, children: focusableWidgets.length > 0 && currentFocusWidget ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col min-h-0", children: [
49115
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "shrink-0 bg-white border-b border-gray-200 px-6 py-3 flex items-center justify-between", children: [
49116
- /* @__PURE__ */ jsxRuntimeExports.jsx(
49117
- "button",
49118
- {
49119
- onClick: () => setCurrentFocusIndex((prev) => prev > 0 ? prev - 1 : focusableWidgets.length - 1),
49120
- className: "p-2 rounded-full hover:bg-gray-100 transition-colors disabled:opacity-30",
49121
- disabled: focusableWidgets.length <= 1,
49122
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronLeft, { className: "w-5 h-5 text-gray-600" })
49123
- }
49124
- ),
49125
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-sm text-gray-500", children: [
49126
- currentFocusIndex + 1,
49127
- " of ",
49128
- focusableWidgets.length
49283
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
49284
+ "div",
49285
+ {
49286
+ className: `fixed inset-0 z-50 bg-white flex flex-col ${laserPointerActive ? "[&_*]:!cursor-none !cursor-none" : ""}`,
49287
+ children: [
49288
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("header", { className: "flex items-center justify-between px-6 py-4 border-b border-gray-200 bg-white shrink-0", children: [
49289
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col", children: [
49290
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xl font-bold text-primary-700 tracking-wide", children: branding.title }),
49291
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-primary-500 tracking-[0.2em] -mt-1", children: branding.subtitle })
49129
49292
  ] }) }),
49293
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute left-1/2 transform -translate-x-1/2 text-center", children: [
49294
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "text-lg font-bold text-gray-900 uppercase tracking-wide", children: dashboardTitle }),
49295
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-12 h-1 bg-primary-600 mx-auto mt-1 rounded" })
49296
+ ] }),
49130
49297
  /* @__PURE__ */ jsxRuntimeExports.jsx(
49131
49298
  "button",
49132
49299
  {
49133
- onClick: () => setCurrentFocusIndex((prev) => prev < focusableWidgets.length - 1 ? prev + 1 : 0),
49134
- className: "p-2 rounded-full hover:bg-gray-100 transition-colors disabled:opacity-30",
49135
- disabled: focusableWidgets.length <= 1,
49136
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "w-5 h-5 text-gray-600" })
49300
+ onClick: onClose,
49301
+ className: "p-2 hover:bg-gray-100 rounded-lg transition-colors",
49302
+ "aria-label": "Close presentation",
49303
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(X, { className: "w-6 h-6 text-gray-600" })
49137
49304
  }
49138
49305
  )
49139
49306
  ] }),
49140
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 bg-white p-6 min-h-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-full w-full rounded-xl border border-gray-200 bg-white shadow-sm overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
49141
- WidgetRenderer,
49142
- {
49143
- widget: currentFocusWidget,
49144
- widgetBackendUrl,
49145
- pageId,
49146
- isEditing: false
49147
- },
49148
- `focus-widget-${currentFocusWidget.id}`
49149
- ) }) })
49150
- ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center text-gray-500", children: [
49151
- /* @__PURE__ */ jsxRuntimeExports.jsx(Maximize2, { className: "w-12 h-12 mx-auto mb-4 text-gray-300" }),
49152
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-lg font-medium", children: "No widgets available for focus view" }),
49153
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm mt-2", children: "Text, Spacer, and Filter widgets are excluded." })
49154
- ] }) }) })
49155
- ) }),
49156
- /* @__PURE__ */ jsxRuntimeExports.jsx("footer", { className: "bg-white border-t border-gray-200 py-4 shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center gap-3", children: [
49157
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 bg-gray-100 rounded-full p-1", children: [
49158
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
49159
- "button",
49160
- {
49161
- onClick: () => setViewMode("grid"),
49162
- className: `flex items-center gap-2 px-4 py-2 rounded-full text-sm font-medium transition-all ${viewMode === "grid" ? "bg-primary-700 text-white shadow-md" : "text-gray-600 hover:text-gray-900"}`,
49163
- children: [
49164
- /* @__PURE__ */ jsxRuntimeExports.jsx(Grid3X3, { className: "w-4 h-4" }),
49165
- "Grid"
49166
- ]
49167
- }
49168
- ),
49169
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
49170
- "button",
49307
+ /* @__PURE__ */ jsxRuntimeExports.jsx("main", { className: `flex-1 min-h-0 ${viewMode === "grid" ? "overflow-auto bg-gray-50 p-6" : "overflow-hidden bg-gray-100"}`, children: loading ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center gap-3", children: [
49308
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-8 h-8 border-4 border-primary-600 border-t-transparent rounded-full animate-spin" }),
49309
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-gray-600", children: "Loading widgets..." })
49310
+ ] }) }) : viewMode === "grid" ? (
49311
+ /* Grid View - Show all widgets using WidgetDashboard */
49312
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-full relative", ref: gridContainerRef, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
49313
+ WidgetDashboard,
49314
+ {
49315
+ pageId,
49316
+ isEditing: false,
49317
+ selectedWidget: null,
49318
+ onWidgetSelect: () => {
49319
+ },
49320
+ openWidgetPallete: false,
49321
+ onCloseWidgetPallete: () => {
49322
+ },
49323
+ onApplyFilters: () => {
49324
+ },
49325
+ isApplyingFilters: false,
49326
+ onSaveLayoutReady: () => {
49327
+ },
49328
+ widgetBackendUrl
49329
+ },
49330
+ `presentation-grid-${pageId}`
49331
+ ) })
49332
+ ) : (
49333
+ /* Focus View - Show one widget at a time */
49334
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-full flex flex-col", ref: focusContainerRef, children: focusableWidgets.length > 0 && currentFocusWidget ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col min-h-0", children: [
49335
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "shrink-0 bg-white border-b border-gray-200 px-6 py-3 flex items-center justify-between", children: [
49336
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
49337
+ "button",
49338
+ {
49339
+ onClick: () => setCurrentFocusIndex((prev) => prev > 0 ? prev - 1 : focusableWidgets.length - 1),
49340
+ className: "p-2 rounded-full hover:bg-gray-100 transition-colors disabled:opacity-30",
49341
+ disabled: focusableWidgets.length <= 1,
49342
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronLeft, { className: "w-5 h-5 text-gray-600" })
49343
+ }
49344
+ ),
49345
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-sm text-gray-500", children: [
49346
+ currentFocusIndex + 1,
49347
+ " of ",
49348
+ focusableWidgets.length
49349
+ ] }) }),
49350
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
49351
+ "button",
49352
+ {
49353
+ onClick: () => setCurrentFocusIndex((prev) => prev < focusableWidgets.length - 1 ? prev + 1 : 0),
49354
+ className: "p-2 rounded-full hover:bg-gray-100 transition-colors disabled:opacity-30",
49355
+ disabled: focusableWidgets.length <= 1,
49356
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "w-5 h-5 text-gray-600" })
49357
+ }
49358
+ )
49359
+ ] }),
49360
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 bg-white p-6 min-h-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-full w-full rounded-xl border border-gray-200 bg-white shadow-sm overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
49361
+ WidgetRenderer,
49362
+ {
49363
+ widget: currentFocusWidget,
49364
+ widgetBackendUrl,
49365
+ pageId,
49366
+ isEditing: false
49367
+ },
49368
+ `focus-widget-${currentFocusWidget.id}`
49369
+ ) }) })
49370
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center text-gray-500", children: [
49371
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Maximize2, { className: "w-12 h-12 mx-auto mb-4 text-gray-300" }),
49372
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-lg font-medium", children: "No widgets available for focus view" }),
49373
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm mt-2", children: "Text, Spacer, and Filter widgets are excluded." })
49374
+ ] }) }) })
49375
+ ) }),
49376
+ /* @__PURE__ */ jsxRuntimeExports.jsx("footer", { className: "bg-white border-t border-gray-200 py-4 shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center gap-3", children: [
49377
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 bg-gray-100 rounded-full p-1", children: [
49378
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
49379
+ "button",
49380
+ {
49381
+ onClick: () => setViewMode("grid"),
49382
+ className: `flex items-center gap-2 px-4 py-2 rounded-full text-sm font-medium transition-all ${viewMode === "grid" ? "bg-primary-700 text-white shadow-md" : "text-gray-600 hover:text-gray-900"}`,
49383
+ children: [
49384
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Grid3X3, { className: "w-4 h-4" }),
49385
+ "Grid"
49386
+ ]
49387
+ }
49388
+ ),
49389
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
49390
+ "button",
49391
+ {
49392
+ onClick: () => setViewMode("focus"),
49393
+ className: `flex items-center gap-2 px-4 py-2 rounded-full text-sm font-medium transition-all ${viewMode === "focus" ? "bg-primary-700 text-white shadow-md" : "text-gray-600 hover:text-gray-900"}`,
49394
+ children: [
49395
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Maximize2, { className: "w-4 h-4" }),
49396
+ "Focus"
49397
+ ]
49398
+ }
49399
+ ),
49400
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-px h-6 bg-gray-300 mx-2" }),
49401
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
49402
+ "button",
49403
+ {
49404
+ onClick: () => setLaserPointerActive((prev) => !prev),
49405
+ className: `p-2 transition-colors rounded-full ${laserPointerActive ? "bg-primary-600 text-white" : "text-gray-600 hover:text-gray-900 hover:bg-gray-200"}`,
49406
+ "aria-label": "Toggle laser pointer (L)",
49407
+ title: "Toggle laser pointer (L)",
49408
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(LaserPointerIcon, { className: "w-4 h-4" })
49409
+ }
49410
+ ),
49411
+ viewMode === "focus" && focusableWidgets.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
49412
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-px h-6 bg-gray-300 mx-2" }),
49413
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-sm text-gray-600 px-2", children: [
49414
+ currentFocusIndex + 1,
49415
+ " / ",
49416
+ focusableWidgets.length
49417
+ ] })
49418
+ ] })
49419
+ ] }),
49420
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-gray-400 uppercase tracking-wider", children: "ESC TO EXIT \u2022 F TO TOGGLE \u2022 L FOR LASER \u2022 ARROWS TO NAVIGATE" })
49421
+ ] }) }),
49422
+ laserPointerActive && /* @__PURE__ */ jsxRuntimeExports.jsxs(
49423
+ "div",
49171
49424
  {
49172
- onClick: () => setViewMode("focus"),
49173
- className: `flex items-center gap-2 px-4 py-2 rounded-full text-sm font-medium transition-all ${viewMode === "focus" ? "bg-primary-700 text-white shadow-md" : "text-gray-600 hover:text-gray-900"}`,
49425
+ className: "fixed pointer-events-none z-[100] transform -translate-x-1/2 -translate-y-1/2",
49426
+ style: {
49427
+ left: mousePosition.x,
49428
+ top: mousePosition.y
49429
+ },
49174
49430
  children: [
49175
- /* @__PURE__ */ jsxRuntimeExports.jsx(Maximize2, { className: "w-4 h-4" }),
49176
- "Focus"
49431
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 w-8 h-8 -translate-x-1/2 -translate-y-1/2 bg-red-500/20 rounded-full blur-md" }),
49432
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute w-4 h-4 -translate-x-1/2 -translate-y-1/2 bg-red-500 rounded-full shadow-lg shadow-red-500/50" })
49177
49433
  ]
49178
49434
  }
49179
- ),
49180
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-px h-6 bg-gray-300 mx-2" }),
49181
- /* @__PURE__ */ jsxRuntimeExports.jsx(
49182
- "button",
49183
- {
49184
- onClick: () => setLaserPointerActive((prev) => !prev),
49185
- className: `p-2 transition-colors rounded-full ${laserPointerActive ? "bg-primary-600 text-white" : "text-gray-600 hover:text-gray-900 hover:bg-gray-200"}`,
49186
- "aria-label": "Toggle laser pointer (L)",
49187
- title: "Toggle laser pointer (L)",
49188
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(LaserPointerIcon, { className: "w-4 h-4" })
49189
- }
49190
- ),
49191
- viewMode === "focus" && focusableWidgets.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
49192
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-px h-6 bg-gray-300 mx-2" }),
49193
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-sm text-gray-600 px-2", children: [
49194
- currentFocusIndex + 1,
49195
- " / ",
49196
- focusableWidgets.length
49197
- ] })
49198
- ] })
49199
- ] }),
49200
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-gray-400 uppercase tracking-wider", children: "ESC TO EXIT \u2022 F TO TOGGLE \u2022 L FOR LASER \u2022 ARROWS TO NAVIGATE" })
49201
- ] }) }),
49202
- laserPointerActive && /* @__PURE__ */ jsxRuntimeExports.jsxs(
49203
- "div",
49204
- {
49205
- className: "fixed pointer-events-none z-[100] transform -translate-x-1/2 -translate-y-1/2",
49206
- style: {
49207
- left: mousePosition.x,
49208
- top: mousePosition.y
49209
- },
49210
- children: [
49211
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 w-8 h-8 -translate-x-1/2 -translate-y-1/2 bg-red-500/20 rounded-full blur-md" }),
49212
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute w-4 h-4 -translate-x-1/2 -translate-y-1/2 bg-red-500 rounded-full shadow-lg shadow-red-500/50" })
49213
- ]
49214
- }
49215
- )
49216
- ] });
49435
+ )
49436
+ ]
49437
+ }
49438
+ );
49217
49439
  }
49218
49440
 
49219
49441
  var __defProp = Object.defineProperty;