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.js CHANGED
@@ -18,6 +18,7 @@ var uuid = require('uuid');
18
18
  var ReactDOM = require('react-dom');
19
19
  var runtimeClientGql = require('@copilotkit/runtime-client-gql');
20
20
  var reactCore = require('@copilotkit/react-core');
21
+ var jsPDF = require('jspdf');
21
22
  var CheckboxPrimitive = require('@radix-ui/react-checkbox');
22
23
  var DialogPrimitive = require('@radix-ui/react-dialog');
23
24
  var dateFns = require('date-fns');
@@ -3802,6 +3803,71 @@ function computeCoordsFromPlacement(_ref, placement, rtl) {
3802
3803
  return coords;
3803
3804
  }
3804
3805
 
3806
+ /**
3807
+ * Resolves with an object of overflow side offsets that determine how much the
3808
+ * element is overflowing a given clipping boundary on each side.
3809
+ * - positive = overflowing the boundary by that number of pixels
3810
+ * - negative = how many pixels left before it will overflow
3811
+ * - 0 = lies flush with the boundary
3812
+ * @see https://floating-ui.com/docs/detectOverflow
3813
+ */
3814
+ async function detectOverflow(state, options) {
3815
+ var _await$platform$isEle;
3816
+ if (options === void 0) {
3817
+ options = {};
3818
+ }
3819
+ const {
3820
+ x,
3821
+ y,
3822
+ platform,
3823
+ rects,
3824
+ elements,
3825
+ strategy
3826
+ } = state;
3827
+ const {
3828
+ boundary = 'clippingAncestors',
3829
+ rootBoundary = 'viewport',
3830
+ elementContext = 'floating',
3831
+ altBoundary = false,
3832
+ padding = 0
3833
+ } = evaluate(options, state);
3834
+ const paddingObject = getPaddingObject(padding);
3835
+ const altContext = elementContext === 'floating' ? 'reference' : 'floating';
3836
+ const element = elements[altBoundary ? altContext : elementContext];
3837
+ const clippingClientRect = rectToClientRect(await platform.getClippingRect({
3838
+ 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))),
3839
+ boundary,
3840
+ rootBoundary,
3841
+ strategy
3842
+ }));
3843
+ const rect = elementContext === 'floating' ? {
3844
+ x,
3845
+ y,
3846
+ width: rects.floating.width,
3847
+ height: rects.floating.height
3848
+ } : rects.reference;
3849
+ const offsetParent = await (platform.getOffsetParent == null ? void 0 : platform.getOffsetParent(elements.floating));
3850
+ const offsetScale = (await (platform.isElement == null ? void 0 : platform.isElement(offsetParent))) ? (await (platform.getScale == null ? void 0 : platform.getScale(offsetParent))) || {
3851
+ x: 1,
3852
+ y: 1
3853
+ } : {
3854
+ x: 1,
3855
+ y: 1
3856
+ };
3857
+ const elementClientRect = rectToClientRect(platform.convertOffsetParentRelativeRectToViewportRelativeRect ? await platform.convertOffsetParentRelativeRectToViewportRelativeRect({
3858
+ elements,
3859
+ rect,
3860
+ offsetParent,
3861
+ strategy
3862
+ }) : rect);
3863
+ return {
3864
+ top: (clippingClientRect.top - elementClientRect.top + paddingObject.top) / offsetScale.y,
3865
+ bottom: (elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom) / offsetScale.y,
3866
+ left: (clippingClientRect.left - elementClientRect.left + paddingObject.left) / offsetScale.x,
3867
+ right: (elementClientRect.right - clippingClientRect.right + paddingObject.right) / offsetScale.x
3868
+ };
3869
+ }
3870
+
3805
3871
  /**
3806
3872
  * Computes the `x` and `y` coordinates that will place the floating element
3807
3873
  * next to a given reference element.
@@ -3831,6 +3897,7 @@ const computePosition$1 = async (reference, floating, config) => {
3831
3897
  let middlewareData = {};
3832
3898
  let resetCount = 0;
3833
3899
  for (let i = 0; i < validMiddleware.length; i++) {
3900
+ var _platform$detectOverf;
3834
3901
  const {
3835
3902
  name,
3836
3903
  fn
@@ -3848,7 +3915,10 @@ const computePosition$1 = async (reference, floating, config) => {
3848
3915
  strategy,
3849
3916
  middlewareData,
3850
3917
  rects,
3851
- platform,
3918
+ platform: {
3919
+ ...platform,
3920
+ detectOverflow: (_platform$detectOverf = platform.detectOverflow) != null ? _platform$detectOverf : detectOverflow
3921
+ },
3852
3922
  elements: {
3853
3923
  reference,
3854
3924
  floating
@@ -3893,71 +3963,6 @@ const computePosition$1 = async (reference, floating, config) => {
3893
3963
  };
3894
3964
  };
3895
3965
 
3896
- /**
3897
- * Resolves with an object of overflow side offsets that determine how much the
3898
- * element is overflowing a given clipping boundary on each side.
3899
- * - positive = overflowing the boundary by that number of pixels
3900
- * - negative = how many pixels left before it will overflow
3901
- * - 0 = lies flush with the boundary
3902
- * @see https://floating-ui.com/docs/detectOverflow
3903
- */
3904
- async function detectOverflow(state, options) {
3905
- var _await$platform$isEle;
3906
- if (options === void 0) {
3907
- options = {};
3908
- }
3909
- const {
3910
- x,
3911
- y,
3912
- platform,
3913
- rects,
3914
- elements,
3915
- strategy
3916
- } = state;
3917
- const {
3918
- boundary = 'clippingAncestors',
3919
- rootBoundary = 'viewport',
3920
- elementContext = 'floating',
3921
- altBoundary = false,
3922
- padding = 0
3923
- } = evaluate(options, state);
3924
- const paddingObject = getPaddingObject(padding);
3925
- const altContext = elementContext === 'floating' ? 'reference' : 'floating';
3926
- const element = elements[altBoundary ? altContext : elementContext];
3927
- const clippingClientRect = rectToClientRect(await platform.getClippingRect({
3928
- 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))),
3929
- boundary,
3930
- rootBoundary,
3931
- strategy
3932
- }));
3933
- const rect = elementContext === 'floating' ? {
3934
- x,
3935
- y,
3936
- width: rects.floating.width,
3937
- height: rects.floating.height
3938
- } : rects.reference;
3939
- const offsetParent = await (platform.getOffsetParent == null ? void 0 : platform.getOffsetParent(elements.floating));
3940
- const offsetScale = (await (platform.isElement == null ? void 0 : platform.isElement(offsetParent))) ? (await (platform.getScale == null ? void 0 : platform.getScale(offsetParent))) || {
3941
- x: 1,
3942
- y: 1
3943
- } : {
3944
- x: 1,
3945
- y: 1
3946
- };
3947
- const elementClientRect = rectToClientRect(platform.convertOffsetParentRelativeRectToViewportRelativeRect ? await platform.convertOffsetParentRelativeRectToViewportRelativeRect({
3948
- elements,
3949
- rect,
3950
- offsetParent,
3951
- strategy
3952
- }) : rect);
3953
- return {
3954
- top: (clippingClientRect.top - elementClientRect.top + paddingObject.top) / offsetScale.y,
3955
- bottom: (elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom) / offsetScale.y,
3956
- left: (clippingClientRect.left - elementClientRect.left + paddingObject.left) / offsetScale.x,
3957
- right: (elementClientRect.right - clippingClientRect.right + paddingObject.right) / offsetScale.x
3958
- };
3959
- }
3960
-
3961
3966
  /**
3962
3967
  * Provides data to position an inner element of the floating element so that it
3963
3968
  * appears centered to the reference element.
@@ -4090,7 +4095,7 @@ const flip$2 = function (options) {
4090
4095
  fallbackPlacements.push(...getOppositeAxisPlacements(initialPlacement, flipAlignment, fallbackAxisSideDirection, rtl));
4091
4096
  }
4092
4097
  const placements = [initialPlacement, ...fallbackPlacements];
4093
- const overflow = await detectOverflow(state, detectOverflowOptions);
4098
+ const overflow = await platform.detectOverflow(state, detectOverflowOptions);
4094
4099
  const overflows = [];
4095
4100
  let overflowsData = ((_middlewareData$flip = middlewareData.flip) == null ? void 0 : _middlewareData$flip.overflows) || [];
4096
4101
  if (checkMainAxis) {
@@ -4197,7 +4202,8 @@ const hide$2 = function (options) {
4197
4202
  options,
4198
4203
  async fn(state) {
4199
4204
  const {
4200
- rects
4205
+ rects,
4206
+ platform
4201
4207
  } = state;
4202
4208
  const {
4203
4209
  strategy = 'referenceHidden',
@@ -4206,7 +4212,7 @@ const hide$2 = function (options) {
4206
4212
  switch (strategy) {
4207
4213
  case 'referenceHidden':
4208
4214
  {
4209
- const overflow = await detectOverflow(state, {
4215
+ const overflow = await platform.detectOverflow(state, {
4210
4216
  ...detectOverflowOptions,
4211
4217
  elementContext: 'reference'
4212
4218
  });
@@ -4220,7 +4226,7 @@ const hide$2 = function (options) {
4220
4226
  }
4221
4227
  case 'escaped':
4222
4228
  {
4223
- const overflow = await detectOverflow(state, {
4229
+ const overflow = await platform.detectOverflow(state, {
4224
4230
  ...detectOverflowOptions,
4225
4231
  altBoundary: true
4226
4232
  });
@@ -4343,7 +4349,8 @@ const shift$2 = function (options) {
4343
4349
  const {
4344
4350
  x,
4345
4351
  y,
4346
- placement
4352
+ placement,
4353
+ platform
4347
4354
  } = state;
4348
4355
  const {
4349
4356
  mainAxis: checkMainAxis = true,
@@ -4366,7 +4373,7 @@ const shift$2 = function (options) {
4366
4373
  x,
4367
4374
  y
4368
4375
  };
4369
- const overflow = await detectOverflow(state, detectOverflowOptions);
4376
+ const overflow = await platform.detectOverflow(state, detectOverflowOptions);
4370
4377
  const crossAxis = getSideAxis(getSide(placement));
4371
4378
  const mainAxis = getOppositeAxis(crossAxis);
4372
4379
  let mainAxisCoord = coords[mainAxis];
@@ -4498,7 +4505,7 @@ const size$2 = function (options) {
4498
4505
  apply = () => {},
4499
4506
  ...detectOverflowOptions
4500
4507
  } = evaluate(options, state);
4501
- const overflow = await detectOverflow(state, detectOverflowOptions);
4508
+ const overflow = await platform.detectOverflow(state, detectOverflowOptions);
4502
4509
  const side = getSide(placement);
4503
4510
  const alignment = getAlignment(placement);
4504
4511
  const isYAxis = getSideAxis(placement) === 'y';
@@ -44437,6 +44444,175 @@ function SpacerWidget({ widget }) {
44437
44444
  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full", style: styles });
44438
44445
  }
44439
44446
 
44447
+ const WISENBAKER_PRIMARY = "#8f002d";
44448
+ const WISENBAKER_GRAY = "#475569";
44449
+ function parseMarkdown(text) {
44450
+ const segments = [];
44451
+ const regex = /\*\*(.+?)\*\*/g;
44452
+ let lastIndex = 0;
44453
+ let match;
44454
+ while ((match = regex.exec(text)) !== null) {
44455
+ if (match.index > lastIndex) {
44456
+ segments.push({ text: text.slice(lastIndex, match.index), bold: false });
44457
+ }
44458
+ segments.push({ text: match[1], bold: true });
44459
+ lastIndex = regex.lastIndex;
44460
+ }
44461
+ if (lastIndex < text.length) {
44462
+ segments.push({ text: text.slice(lastIndex), bold: false });
44463
+ }
44464
+ return segments.length > 0 ? segments : [{ text, bold: false }];
44465
+ }
44466
+ function formatLine(line) {
44467
+ const bulletMatch = line.match(/^(\s*)[\*\-•]\s+(.*)$/);
44468
+ if (bulletMatch) {
44469
+ const indent = bulletMatch[1].length;
44470
+ return { text: bulletMatch[2], isBullet: true, indent };
44471
+ }
44472
+ const numberedMatch = line.match(/^(\s*)\d+\.\s+(.*)$/);
44473
+ if (numberedMatch) {
44474
+ const indent = numberedMatch[1].length;
44475
+ return { text: numberedMatch[2], isBullet: true, indent };
44476
+ }
44477
+ return { text: line, isBullet: false, indent: 0 };
44478
+ }
44479
+ function generateExportFilename(widgetId) {
44480
+ const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
44481
+ return `NSight_Chat_Export_${widgetId}_${date}.pdf`;
44482
+ }
44483
+ function exportChatToPDF(options) {
44484
+ const { widgetId, messages, dashboardName } = options;
44485
+ const doc = new jsPDF();
44486
+ let yPosition = 25;
44487
+ const pageHeight = doc.internal.pageSize.height;
44488
+ const pageWidth = doc.internal.pageSize.width;
44489
+ const margin = 20;
44490
+ const contentWidth = pageWidth - margin * 2;
44491
+ const maxWidth = contentWidth - 10;
44492
+ const checkPageBreak = (requiredSpace = 20) => {
44493
+ if (yPosition > pageHeight - requiredSpace) {
44494
+ doc.addPage();
44495
+ yPosition = 25;
44496
+ }
44497
+ };
44498
+ const renderFormattedText = (text, x, maxW, baseIndent = 0) => {
44499
+ const lines = text.split("\n");
44500
+ lines.forEach((line) => {
44501
+ const { text: lineText, isBullet, indent } = formatLine(line);
44502
+ const lineIndent = x + baseIndent + indent * 2;
44503
+ if (isBullet) {
44504
+ checkPageBreak(10);
44505
+ doc.setFont("helvetica", "normal");
44506
+ doc.text("\u2022", lineIndent, yPosition);
44507
+ }
44508
+ const textX = isBullet ? lineIndent + 5 : lineIndent;
44509
+ const textMaxWidth = maxW - (textX - x);
44510
+ const segments = parseMarkdown(lineText);
44511
+ let currentLine = "";
44512
+ let currentX = textX;
44513
+ segments.forEach((segment) => {
44514
+ doc.setFont("helvetica", segment.bold ? "bold" : "normal");
44515
+ const words = segment.text.split(" ");
44516
+ words.forEach((word, wordIndex) => {
44517
+ const testLine = currentLine + (currentLine ? " " : "") + word;
44518
+ const testWidth = doc.getTextWidth(testLine);
44519
+ if (testWidth > textMaxWidth && currentLine) {
44520
+ checkPageBreak(10);
44521
+ doc.text(currentLine, currentX, yPosition);
44522
+ yPosition += 5;
44523
+ currentLine = word;
44524
+ currentX = isBullet ? lineIndent + 5 : x + baseIndent;
44525
+ } else {
44526
+ currentLine = testLine;
44527
+ }
44528
+ });
44529
+ });
44530
+ if (currentLine) {
44531
+ checkPageBreak(10);
44532
+ const lastSegment = segments[segments.length - 1];
44533
+ doc.setFont("helvetica", (lastSegment == null ? void 0 : lastSegment.bold) ? "bold" : "normal");
44534
+ doc.text(currentLine, currentX, yPosition);
44535
+ yPosition += 5;
44536
+ }
44537
+ });
44538
+ };
44539
+ doc.setFontSize(18);
44540
+ doc.setFont("helvetica", "bold");
44541
+ doc.setTextColor(WISENBAKER_PRIMARY);
44542
+ doc.text("Wisenbaker AI Analytics", margin, yPosition);
44543
+ yPosition += 8;
44544
+ doc.setFontSize(11);
44545
+ doc.setFont("helvetica", "normal");
44546
+ doc.setTextColor(WISENBAKER_GRAY);
44547
+ doc.text("Chat Export", margin, yPosition);
44548
+ yPosition += 12;
44549
+ doc.setFontSize(9);
44550
+ doc.setTextColor("#666666");
44551
+ if (dashboardName) {
44552
+ doc.setFont("helvetica", "bold");
44553
+ doc.text("Dashboard:", margin, yPosition);
44554
+ doc.setFont("helvetica", "normal");
44555
+ doc.text(dashboardName, margin + 38, yPosition);
44556
+ yPosition += 5;
44557
+ }
44558
+ doc.setFont("helvetica", "bold");
44559
+ doc.text("Exported:", margin, yPosition);
44560
+ doc.setFont("helvetica", "normal");
44561
+ doc.text((/* @__PURE__ */ new Date()).toLocaleString(), margin + 38, yPosition);
44562
+ doc.setFont("helvetica", "bold");
44563
+ doc.text("Messages:", margin + 100, yPosition);
44564
+ doc.setFont("helvetica", "normal");
44565
+ doc.text(String(messages.length), margin + 130, yPosition);
44566
+ yPosition += 12;
44567
+ doc.setDrawColor(200, 200, 200);
44568
+ doc.setLineWidth(0.5);
44569
+ doc.line(margin, yPosition, pageWidth - margin, yPosition);
44570
+ yPosition += 8;
44571
+ messages.forEach((message, index) => {
44572
+ checkPageBreak(30);
44573
+ const isUser = message.role === "user";
44574
+ const roleLabel = isUser ? "You" : "AI Assistant";
44575
+ const timestamp = message.createdAt ? new Date(message.createdAt).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) : "";
44576
+ const bgColor = isUser ? [143, 0, 45] : [241, 243, 245];
44577
+ doc.setFillColor(bgColor[0], bgColor[1], bgColor[2]);
44578
+ doc.setFontSize(9);
44579
+ doc.setFont("helvetica", "bold");
44580
+ doc.setTextColor(isUser ? WISENBAKER_PRIMARY : WISENBAKER_GRAY);
44581
+ doc.text(roleLabel, margin, yPosition);
44582
+ if (timestamp) {
44583
+ doc.setFont("helvetica", "normal");
44584
+ doc.setTextColor("#888888");
44585
+ doc.text(timestamp, margin + doc.getTextWidth(roleLabel) + 5, yPosition);
44586
+ }
44587
+ yPosition += 6;
44588
+ doc.setFontSize(10);
44589
+ doc.setTextColor("#333333");
44590
+ doc.setFont("helvetica", "normal");
44591
+ renderFormattedText(message.content, margin + 5, maxWidth - 5, 0);
44592
+ yPosition += 8;
44593
+ if (index < messages.length - 1) {
44594
+ doc.setDrawColor(230, 230, 230);
44595
+ doc.setLineWidth(0.3);
44596
+ doc.line(margin + 10, yPosition - 4, pageWidth - margin - 10, yPosition - 4);
44597
+ }
44598
+ });
44599
+ const totalPages = doc.getNumberOfPages();
44600
+ for (let i = 1; i <= totalPages; i++) {
44601
+ doc.setPage(i);
44602
+ doc.setFontSize(8);
44603
+ doc.setTextColor("#999999");
44604
+ doc.setFont("helvetica", "normal");
44605
+ doc.text(
44606
+ `Wisenbaker AI Analytics \u2022 Page ${i} of ${totalPages}`,
44607
+ pageWidth / 2,
44608
+ pageHeight - 10,
44609
+ { align: "center" }
44610
+ );
44611
+ }
44612
+ const filename = generateExportFilename(widgetId);
44613
+ doc.save(filename);
44614
+ }
44615
+
44440
44616
  var __defProp$b = Object.defineProperty;
44441
44617
  var __defProps$9 = Object.defineProperties;
44442
44618
  var __getOwnPropDescs$9 = Object.getOwnPropertyDescriptors;
@@ -44485,7 +44661,8 @@ function CopilotKitChatbot({
44485
44661
  styles,
44486
44662
  onResetReady,
44487
44663
  widgetIds,
44488
- datasetId
44664
+ datasetId,
44665
+ dashboardName
44489
44666
  }) {
44490
44667
  var _a, _b, _c, _d;
44491
44668
  const { threadId, setThreadId } = reactCore.useCopilotContext();
@@ -44502,7 +44679,24 @@ function CopilotKitChatbot({
44502
44679
  const { reset, visibleMessages, appendMessage, isLoading } = reactCore.useCopilotChat();
44503
44680
  const [inputValue, setInputValue] = React.useState("");
44504
44681
  const [chatMessages, setChatMessages] = React.useState([]);
44682
+ const [isExporting, setIsExporting] = React.useState(false);
44505
44683
  const messagesEndRef = React.useRef(null);
44684
+ const handleExport = async () => {
44685
+ if (chatMessages.length === 0) return;
44686
+ setIsExporting(true);
44687
+ try {
44688
+ exportChatToPDF({
44689
+ widgetId: widget.id,
44690
+ widgetTitle: widget.title,
44691
+ messages: chatMessages,
44692
+ dashboardName
44693
+ });
44694
+ } catch (error) {
44695
+ console.error("Export failed:", error);
44696
+ } finally {
44697
+ setIsExporting(false);
44698
+ }
44699
+ };
44506
44700
  const scrollToBottom = () => {
44507
44701
  var _a2;
44508
44702
  const el = messagesEndRef.current;
@@ -44577,6 +44771,25 @@ function CopilotKitChatbot({
44577
44771
  /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-medium", children: widget.title })
44578
44772
  ] }) }),
44579
44773
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 h-full flex flex-col", children: [
44774
+ 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(
44775
+ "button",
44776
+ {
44777
+ onClick: handleExport,
44778
+ disabled: isExporting,
44779
+ className: cn(
44780
+ "flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md",
44781
+ "bg-gray-100 border border-gray-200",
44782
+ "text-gray-700 hover:bg-gray-200 hover:border-gray-300",
44783
+ "disabled:opacity-50 disabled:cursor-not-allowed",
44784
+ "transition-colors duration-150"
44785
+ ),
44786
+ title: "Export conversation as PDF",
44787
+ children: [
44788
+ isExporting ? /* @__PURE__ */ jsxRuntimeExports.jsx(lucideReact.Loader2, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(lucideReact.Download, { className: "h-3.5 w-3.5" }),
44789
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Export PDF" })
44790
+ ]
44791
+ }
44792
+ ) }),
44580
44793
  /* @__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: [
44581
44794
  chatMessages.map((message) => /* @__PURE__ */ jsxRuntimeExports.jsx(
44582
44795
  "div",
@@ -44652,7 +44865,8 @@ function ChatbotWidget({
44652
44865
  widgetBackendUrl,
44653
44866
  onResetReady,
44654
44867
  widgetIds,
44655
- datasetId
44868
+ datasetId,
44869
+ dashboardName
44656
44870
  }) {
44657
44871
  var _a, _b;
44658
44872
  const styles = getStyleValues$4((_a = widget.config) == null ? void 0 : _a.styles);
@@ -44676,7 +44890,8 @@ function ChatbotWidget({
44676
44890
  styles,
44677
44891
  onResetReady,
44678
44892
  widgetIds,
44679
- datasetId
44893
+ datasetId,
44894
+ dashboardName
44680
44895
  }
44681
44896
  )
44682
44897
  }
@@ -47193,7 +47408,8 @@ function WidgetRenderer({
47193
47408
  datasetId,
47194
47409
  pageId,
47195
47410
  onApplyFilters,
47196
- isEditing = false
47411
+ isEditing = false,
47412
+ dashboardName
47197
47413
  }) {
47198
47414
  const handleConfigUpdate = (config) => {
47199
47415
  if (onConfigUpdate) {
@@ -47225,7 +47441,7 @@ function WidgetRenderer({
47225
47441
  }
47226
47442
  );
47227
47443
  case "chatbot":
47228
- return /* @__PURE__ */ jsxRuntimeExports.jsx(ChatbotWidget, { widget, showHeader: false, widgetBackendUrl, onResetReady, widgetIds, datasetId });
47444
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(ChatbotWidget, { widget, showHeader: false, widgetBackendUrl, onResetReady, widgetIds, datasetId, dashboardName });
47229
47445
  case "filters":
47230
47446
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
47231
47447
  FiltersWidget,
@@ -48834,7 +49050,7 @@ function WidgetDashboard({
48834
49050
  containerPadding: [0, 0],
48835
49051
  margin: [16, 16],
48836
49052
  children: displayWidgets.map((w) => {
48837
- var _a, _b;
49053
+ var _a, _b, _c;
48838
49054
  const filterStatus = w.type === "agent" ? getWidgetFilterStatus(w.id) : null;
48839
49055
  const badgeInfo = filterStatus ? getFilterStatusBadge(filterStatus.status) : null;
48840
49056
  const isFocusMode = focusWidgetId && w.id === focusWidgetId;
@@ -48873,7 +49089,7 @@ function WidgetDashboard({
48873
49089
  /* @__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(lucideReact.MessageCircleX, { className: "w-5 h-5" }) }),
48874
49090
  /* @__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" })
48875
49091
  ] }),
48876
- /* @__PURE__ */ jsxRuntimeExports.jsx(WidgetRenderer, { widget: w, widgetBackendUrl, onResetReady: handleResetReady, widgetIds: widgets.filter((widget) => widget.type !== "chatbot").map((widget) => widget.id), datasetId, pageId, onApplyFilters, isEditing })
49092
+ /* @__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) })
48877
49093
  ] })
48878
49094
  ] }, w.id);
48879
49095
  })
@@ -48974,7 +49190,7 @@ function PresentationMode({
48974
49190
  return;
48975
49191
  }
48976
49192
  item.style.cursor = "pointer";
48977
- item.style.boxShadow = "0 0 0 3px var(--primary-500, #3b82f6), 0 10px 30px -5px rgba(0, 0, 0, 0.2)";
49193
+ item.style.boxShadow = "0 0 0 3px var(--primary-500), 0 10px 30px -5px rgba(0, 0, 0, 0.2)";
48978
49194
  item.style.transition = "box-shadow 0.2s ease-out";
48979
49195
  item.style.zIndex = "10";
48980
49196
  };
@@ -49092,156 +49308,162 @@ function PresentationMode({
49092
49308
  }, [isOpen]);
49093
49309
  if (!isOpen) return null;
49094
49310
  const currentFocusWidget = focusableWidgets[currentFocusIndex];
49095
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fixed inset-0 z-50 bg-white flex flex-col", children: [
49096
- /* @__PURE__ */ jsxRuntimeExports.jsxs("header", { className: "flex items-center justify-between px-6 py-4 border-b border-gray-200 bg-white shrink-0", children: [
49097
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col", children: [
49098
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xl font-bold text-primary-700 tracking-wide", children: branding.title }),
49099
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-primary-500 tracking-[0.2em] -mt-1", children: branding.subtitle })
49100
- ] }) }),
49101
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute left-1/2 transform -translate-x-1/2 text-center", children: [
49102
- /* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "text-lg font-bold text-gray-900 uppercase tracking-wide", children: dashboardTitle }),
49103
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-12 h-1 bg-primary-600 mx-auto mt-1 rounded" })
49104
- ] }),
49105
- /* @__PURE__ */ jsxRuntimeExports.jsx(
49106
- "button",
49107
- {
49108
- onClick: onClose,
49109
- className: "p-2 hover:bg-gray-100 rounded-lg transition-colors",
49110
- "aria-label": "Close presentation",
49111
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(lucideReact.X, { className: "w-6 h-6 text-gray-600" })
49112
- }
49113
- )
49114
- ] }),
49115
- /* @__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: [
49116
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-8 h-8 border-4 border-primary-600 border-t-transparent rounded-full animate-spin" }),
49117
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-gray-600", children: "Loading widgets..." })
49118
- ] }) }) : viewMode === "grid" ? (
49119
- /* Grid View - Show all widgets using WidgetDashboard */
49120
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-full relative", ref: gridContainerRef, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
49121
- WidgetDashboard,
49122
- {
49123
- pageId,
49124
- isEditing: false,
49125
- selectedWidget: null,
49126
- onWidgetSelect: () => {
49127
- },
49128
- openWidgetPallete: false,
49129
- onCloseWidgetPallete: () => {
49130
- },
49131
- onApplyFilters: () => {
49132
- },
49133
- isApplyingFilters: false,
49134
- onSaveLayoutReady: () => {
49135
- },
49136
- widgetBackendUrl
49137
- },
49138
- `presentation-grid-${pageId}`
49139
- ) })
49140
- ) : (
49141
- /* Focus View - Show one widget at a time */
49142
- /* @__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: [
49143
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "shrink-0 bg-white border-b border-gray-200 px-6 py-3 flex items-center justify-between", children: [
49144
- /* @__PURE__ */ jsxRuntimeExports.jsx(
49145
- "button",
49146
- {
49147
- onClick: () => setCurrentFocusIndex((prev) => prev > 0 ? prev - 1 : focusableWidgets.length - 1),
49148
- className: "p-2 rounded-full hover:bg-gray-100 transition-colors disabled:opacity-30",
49149
- disabled: focusableWidgets.length <= 1,
49150
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(lucideReact.ChevronLeft, { className: "w-5 h-5 text-gray-600" })
49151
- }
49152
- ),
49153
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-sm text-gray-500", children: [
49154
- currentFocusIndex + 1,
49155
- " of ",
49156
- focusableWidgets.length
49311
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
49312
+ "div",
49313
+ {
49314
+ className: `fixed inset-0 z-50 bg-white flex flex-col ${laserPointerActive ? "[&_*]:!cursor-none !cursor-none" : ""}`,
49315
+ children: [
49316
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("header", { className: "flex items-center justify-between px-6 py-4 border-b border-gray-200 bg-white shrink-0", children: [
49317
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col", children: [
49318
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xl font-bold text-primary-700 tracking-wide", children: branding.title }),
49319
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-primary-500 tracking-[0.2em] -mt-1", children: branding.subtitle })
49157
49320
  ] }) }),
49321
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute left-1/2 transform -translate-x-1/2 text-center", children: [
49322
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "text-lg font-bold text-gray-900 uppercase tracking-wide", children: dashboardTitle }),
49323
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-12 h-1 bg-primary-600 mx-auto mt-1 rounded" })
49324
+ ] }),
49158
49325
  /* @__PURE__ */ jsxRuntimeExports.jsx(
49159
49326
  "button",
49160
49327
  {
49161
- onClick: () => setCurrentFocusIndex((prev) => prev < focusableWidgets.length - 1 ? prev + 1 : 0),
49162
- className: "p-2 rounded-full hover:bg-gray-100 transition-colors disabled:opacity-30",
49163
- disabled: focusableWidgets.length <= 1,
49164
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(lucideReact.ChevronRight, { className: "w-5 h-5 text-gray-600" })
49328
+ onClick: onClose,
49329
+ className: "p-2 hover:bg-gray-100 rounded-lg transition-colors",
49330
+ "aria-label": "Close presentation",
49331
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(lucideReact.X, { className: "w-6 h-6 text-gray-600" })
49165
49332
  }
49166
49333
  )
49167
49334
  ] }),
49168
- /* @__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(
49169
- WidgetRenderer,
49170
- {
49171
- widget: currentFocusWidget,
49172
- widgetBackendUrl,
49173
- pageId,
49174
- isEditing: false
49175
- },
49176
- `focus-widget-${currentFocusWidget.id}`
49177
- ) }) })
49178
- ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center text-gray-500", children: [
49179
- /* @__PURE__ */ jsxRuntimeExports.jsx(lucideReact.Maximize2, { className: "w-12 h-12 mx-auto mb-4 text-gray-300" }),
49180
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-lg font-medium", children: "No widgets available for focus view" }),
49181
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm mt-2", children: "Text, Spacer, and Filter widgets are excluded." })
49182
- ] }) }) })
49183
- ) }),
49184
- /* @__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: [
49185
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 bg-gray-100 rounded-full p-1", children: [
49186
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
49187
- "button",
49188
- {
49189
- onClick: () => setViewMode("grid"),
49190
- 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"}`,
49191
- children: [
49192
- /* @__PURE__ */ jsxRuntimeExports.jsx(lucideReact.Grid3X3, { className: "w-4 h-4" }),
49193
- "Grid"
49194
- ]
49195
- }
49196
- ),
49197
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
49198
- "button",
49335
+ /* @__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: [
49336
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-8 h-8 border-4 border-primary-600 border-t-transparent rounded-full animate-spin" }),
49337
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-gray-600", children: "Loading widgets..." })
49338
+ ] }) }) : viewMode === "grid" ? (
49339
+ /* Grid View - Show all widgets using WidgetDashboard */
49340
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-full relative", ref: gridContainerRef, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
49341
+ WidgetDashboard,
49342
+ {
49343
+ pageId,
49344
+ isEditing: false,
49345
+ selectedWidget: null,
49346
+ onWidgetSelect: () => {
49347
+ },
49348
+ openWidgetPallete: false,
49349
+ onCloseWidgetPallete: () => {
49350
+ },
49351
+ onApplyFilters: () => {
49352
+ },
49353
+ isApplyingFilters: false,
49354
+ onSaveLayoutReady: () => {
49355
+ },
49356
+ widgetBackendUrl
49357
+ },
49358
+ `presentation-grid-${pageId}`
49359
+ ) })
49360
+ ) : (
49361
+ /* Focus View - Show one widget at a time */
49362
+ /* @__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: [
49363
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "shrink-0 bg-white border-b border-gray-200 px-6 py-3 flex items-center justify-between", children: [
49364
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
49365
+ "button",
49366
+ {
49367
+ onClick: () => setCurrentFocusIndex((prev) => prev > 0 ? prev - 1 : focusableWidgets.length - 1),
49368
+ className: "p-2 rounded-full hover:bg-gray-100 transition-colors disabled:opacity-30",
49369
+ disabled: focusableWidgets.length <= 1,
49370
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(lucideReact.ChevronLeft, { className: "w-5 h-5 text-gray-600" })
49371
+ }
49372
+ ),
49373
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-sm text-gray-500", children: [
49374
+ currentFocusIndex + 1,
49375
+ " of ",
49376
+ focusableWidgets.length
49377
+ ] }) }),
49378
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
49379
+ "button",
49380
+ {
49381
+ onClick: () => setCurrentFocusIndex((prev) => prev < focusableWidgets.length - 1 ? prev + 1 : 0),
49382
+ className: "p-2 rounded-full hover:bg-gray-100 transition-colors disabled:opacity-30",
49383
+ disabled: focusableWidgets.length <= 1,
49384
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(lucideReact.ChevronRight, { className: "w-5 h-5 text-gray-600" })
49385
+ }
49386
+ )
49387
+ ] }),
49388
+ /* @__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(
49389
+ WidgetRenderer,
49390
+ {
49391
+ widget: currentFocusWidget,
49392
+ widgetBackendUrl,
49393
+ pageId,
49394
+ isEditing: false
49395
+ },
49396
+ `focus-widget-${currentFocusWidget.id}`
49397
+ ) }) })
49398
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center text-gray-500", children: [
49399
+ /* @__PURE__ */ jsxRuntimeExports.jsx(lucideReact.Maximize2, { className: "w-12 h-12 mx-auto mb-4 text-gray-300" }),
49400
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-lg font-medium", children: "No widgets available for focus view" }),
49401
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm mt-2", children: "Text, Spacer, and Filter widgets are excluded." })
49402
+ ] }) }) })
49403
+ ) }),
49404
+ /* @__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: [
49405
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 bg-gray-100 rounded-full p-1", children: [
49406
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
49407
+ "button",
49408
+ {
49409
+ onClick: () => setViewMode("grid"),
49410
+ 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"}`,
49411
+ children: [
49412
+ /* @__PURE__ */ jsxRuntimeExports.jsx(lucideReact.Grid3X3, { className: "w-4 h-4" }),
49413
+ "Grid"
49414
+ ]
49415
+ }
49416
+ ),
49417
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
49418
+ "button",
49419
+ {
49420
+ onClick: () => setViewMode("focus"),
49421
+ 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"}`,
49422
+ children: [
49423
+ /* @__PURE__ */ jsxRuntimeExports.jsx(lucideReact.Maximize2, { className: "w-4 h-4" }),
49424
+ "Focus"
49425
+ ]
49426
+ }
49427
+ ),
49428
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-px h-6 bg-gray-300 mx-2" }),
49429
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
49430
+ "button",
49431
+ {
49432
+ onClick: () => setLaserPointerActive((prev) => !prev),
49433
+ className: `p-2 transition-colors rounded-full ${laserPointerActive ? "bg-primary-600 text-white" : "text-gray-600 hover:text-gray-900 hover:bg-gray-200"}`,
49434
+ "aria-label": "Toggle laser pointer (L)",
49435
+ title: "Toggle laser pointer (L)",
49436
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(LaserPointerIcon, { className: "w-4 h-4" })
49437
+ }
49438
+ ),
49439
+ viewMode === "focus" && focusableWidgets.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
49440
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-px h-6 bg-gray-300 mx-2" }),
49441
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-sm text-gray-600 px-2", children: [
49442
+ currentFocusIndex + 1,
49443
+ " / ",
49444
+ focusableWidgets.length
49445
+ ] })
49446
+ ] })
49447
+ ] }),
49448
+ /* @__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" })
49449
+ ] }) }),
49450
+ laserPointerActive && /* @__PURE__ */ jsxRuntimeExports.jsxs(
49451
+ "div",
49199
49452
  {
49200
- onClick: () => setViewMode("focus"),
49201
- 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"}`,
49453
+ className: "fixed pointer-events-none z-[100] transform -translate-x-1/2 -translate-y-1/2",
49454
+ style: {
49455
+ left: mousePosition.x,
49456
+ top: mousePosition.y
49457
+ },
49202
49458
  children: [
49203
- /* @__PURE__ */ jsxRuntimeExports.jsx(lucideReact.Maximize2, { className: "w-4 h-4" }),
49204
- "Focus"
49459
+ /* @__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" }),
49460
+ /* @__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" })
49205
49461
  ]
49206
49462
  }
49207
- ),
49208
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-px h-6 bg-gray-300 mx-2" }),
49209
- /* @__PURE__ */ jsxRuntimeExports.jsx(
49210
- "button",
49211
- {
49212
- onClick: () => setLaserPointerActive((prev) => !prev),
49213
- className: `p-2 transition-colors rounded-full ${laserPointerActive ? "bg-primary-600 text-white" : "text-gray-600 hover:text-gray-900 hover:bg-gray-200"}`,
49214
- "aria-label": "Toggle laser pointer (L)",
49215
- title: "Toggle laser pointer (L)",
49216
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(LaserPointerIcon, { className: "w-4 h-4" })
49217
- }
49218
- ),
49219
- viewMode === "focus" && focusableWidgets.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
49220
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-px h-6 bg-gray-300 mx-2" }),
49221
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-sm text-gray-600 px-2", children: [
49222
- currentFocusIndex + 1,
49223
- " / ",
49224
- focusableWidgets.length
49225
- ] })
49226
- ] })
49227
- ] }),
49228
- /* @__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" })
49229
- ] }) }),
49230
- laserPointerActive && /* @__PURE__ */ jsxRuntimeExports.jsxs(
49231
- "div",
49232
- {
49233
- className: "fixed pointer-events-none z-[100] transform -translate-x-1/2 -translate-y-1/2",
49234
- style: {
49235
- left: mousePosition.x,
49236
- top: mousePosition.y
49237
- },
49238
- children: [
49239
- /* @__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" }),
49240
- /* @__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" })
49241
- ]
49242
- }
49243
- )
49244
- ] });
49463
+ )
49464
+ ]
49465
+ }
49466
+ );
49245
49467
  }
49246
49468
 
49247
49469
  var __defProp = Object.defineProperty;