@heymantle/litho 0.0.10 → 0.0.12

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 (91) hide show
  1. package/dist/cjs/components/Banner.js +6 -1
  2. package/dist/cjs/components/Button.js +33 -4
  3. package/dist/cjs/components/ButtonGroup.js +19 -4
  4. package/dist/cjs/components/Card.js +39 -3
  5. package/dist/cjs/components/ChoiceList.js +3 -2
  6. package/dist/cjs/components/Code.js +227 -0
  7. package/dist/cjs/components/Filters.js +1 -1
  8. package/dist/cjs/components/Frame.js +2 -2
  9. package/dist/cjs/components/Layout.js +16 -4
  10. package/dist/cjs/components/Link.js +35 -4
  11. package/dist/cjs/components/Modal.js +4 -0
  12. package/dist/cjs/components/Page.js +5 -2
  13. package/dist/cjs/components/Pane.js +669 -84
  14. package/dist/cjs/components/ResourceList.js +2 -2
  15. package/dist/cjs/components/TabNavigation.js +300 -0
  16. package/dist/cjs/components/TextField.js +3 -0
  17. package/dist/cjs/components/Tip.js +3 -0
  18. package/dist/cjs/components/Tooltip.js +12 -13
  19. package/dist/cjs/index.js +4 -0
  20. package/dist/cjs/stories/Pane.stories.js +352 -3
  21. package/dist/cjs/utilities/useBodyScrollLock.js +63 -0
  22. package/dist/cjs/utilities/useKeyboardAction.js +19 -0
  23. package/dist/cjs/utilities/useLocalStorage.js +126 -0
  24. package/dist/cjs/utilities/useMobile.js +92 -0
  25. package/dist/cjs/utilities/usePaneState.js +340 -0
  26. package/dist/cjs/utilities/useTabStorage.js +325 -0
  27. package/dist/esm/components/Banner.js +7 -2
  28. package/dist/esm/components/Button.js +33 -4
  29. package/dist/esm/components/ButtonGroup.js +19 -4
  30. package/dist/esm/components/Card.js +39 -3
  31. package/dist/esm/components/ChoiceList.js +3 -2
  32. package/dist/esm/components/Code.js +212 -0
  33. package/dist/esm/components/Filters.js +2 -2
  34. package/dist/esm/components/Frame.js +2 -2
  35. package/dist/esm/components/Layout.js +16 -4
  36. package/dist/esm/components/Link.js +31 -5
  37. package/dist/esm/components/Modal.js +4 -0
  38. package/dist/esm/components/Page.js +5 -2
  39. package/dist/esm/components/Pane.js +619 -83
  40. package/dist/esm/components/ResourceList.js +2 -2
  41. package/dist/esm/components/TabNavigation.js +285 -0
  42. package/dist/esm/components/TextField.js +4 -1
  43. package/dist/esm/components/Tip.js +4 -1
  44. package/dist/esm/components/Tooltip.js +12 -13
  45. package/dist/esm/index.js +1 -0
  46. package/dist/esm/stories/Pane.stories.js +346 -3
  47. package/dist/esm/utilities/useBodyScrollLock.js +53 -0
  48. package/dist/esm/utilities/useKeyboardAction.js +25 -0
  49. package/dist/esm/utilities/useLocalStorage.js +115 -0
  50. package/dist/esm/utilities/useMobile.js +79 -0
  51. package/dist/esm/utilities/usePaneState.js +334 -0
  52. package/dist/esm/utilities/useTabStorage.js +311 -0
  53. package/dist/types/components/Banner.d.ts.map +1 -1
  54. package/dist/types/components/Button.d.ts +2 -2
  55. package/dist/types/components/Button.d.ts.map +1 -1
  56. package/dist/types/components/ButtonGroup.d.ts.map +1 -1
  57. package/dist/types/components/Card.d.ts +34 -1
  58. package/dist/types/components/Card.d.ts.map +1 -1
  59. package/dist/types/components/Code.d.ts +28 -0
  60. package/dist/types/components/Code.d.ts.map +1 -0
  61. package/dist/types/components/Filters.d.ts.map +1 -1
  62. package/dist/types/components/Layout.d.ts +2 -0
  63. package/dist/types/components/Layout.d.ts.map +1 -1
  64. package/dist/types/components/Link.d.ts +4 -0
  65. package/dist/types/components/Link.d.ts.map +1 -1
  66. package/dist/types/components/Modal.d.ts +2 -0
  67. package/dist/types/components/Modal.d.ts.map +1 -1
  68. package/dist/types/components/Page.d.ts.map +1 -1
  69. package/dist/types/components/Pane.d.ts +2 -0
  70. package/dist/types/components/Pane.d.ts.map +1 -1
  71. package/dist/types/components/TabNavigation.d.ts +3 -0
  72. package/dist/types/components/TabNavigation.d.ts.map +1 -0
  73. package/dist/types/components/TextField.d.ts.map +1 -1
  74. package/dist/types/components/Tip.d.ts.map +1 -1
  75. package/dist/types/components/Tooltip.d.ts +2 -0
  76. package/dist/types/components/Tooltip.d.ts.map +1 -1
  77. package/dist/types/index.d.ts +1 -0
  78. package/dist/types/utilities/useBodyScrollLock.d.ts +12 -0
  79. package/dist/types/utilities/useBodyScrollLock.d.ts.map +1 -0
  80. package/dist/types/utilities/useKeyboardAction.d.ts +2 -0
  81. package/dist/types/utilities/useKeyboardAction.d.ts.map +1 -0
  82. package/dist/types/utilities/useLocalStorage.d.ts +13 -0
  83. package/dist/types/utilities/useLocalStorage.d.ts.map +1 -0
  84. package/dist/types/utilities/useMobile.d.ts +9 -0
  85. package/dist/types/utilities/useMobile.d.ts.map +1 -0
  86. package/dist/types/utilities/usePaneState.d.ts +2 -0
  87. package/dist/types/utilities/usePaneState.d.ts.map +1 -0
  88. package/dist/types/utilities/useTabStorage.d.ts +8 -0
  89. package/dist/types/utilities/useTabStorage.d.ts.map +1 -0
  90. package/index.css +77 -6
  91. package/package.json +1 -1
@@ -228,6 +228,7 @@ import TextField from "../components/TextField.js";
228
228
  import Page from "../components/Page.js";
229
229
  import Box from "../components/Box.js";
230
230
  import Grid from "../components/Grid.js";
231
+ import { useTabStorage } from "../utilities/useTabStorage.js";
231
232
  import { EditMajor, DeleteMajor, ShareIosMinor, DuplicateMinor } from "@shopify/polaris-icons";
232
233
  export default {
233
234
  title: 'Litho/Pane',
@@ -264,6 +265,7 @@ export default {
264
265
  export var Default = {
265
266
  render: function(args) {
266
267
  var _useState = _sliced_to_array(useState(false), 2), paneOpen = _useState[0], setPaneOpen = _useState[1];
268
+ var tabStorage = useTabStorage();
267
269
  return /*#__PURE__*/ _jsxs(Page, {
268
270
  title: "Pane Demo",
269
271
  children: [
@@ -274,7 +276,7 @@ export var Default = {
274
276
  /*#__PURE__*/ _jsx(Box, {
275
277
  paddingBlockEnd: "4",
276
278
  children: /*#__PURE__*/ _jsx(Text, {
277
- children: "Click the button below to open a basic pane with header, content, and footer sections."
279
+ children: "Click the button below to open a basic pane with header, content, and footer sections. The pane now includes tabbed functionality with automatic tab creation."
278
280
  })
279
281
  }),
280
282
  /*#__PURE__*/ _jsx(Button, {
@@ -291,6 +293,9 @@ export var Default = {
291
293
  onClose: function() {
292
294
  return setPaneOpen(false);
293
295
  },
296
+ tabStorage: tabStorage,
297
+ tabId: "basic-pane",
298
+ tabTitle: "Basic Pane",
294
299
  children: [
295
300
  /*#__PURE__*/ _jsx(Pane.Header, {
296
301
  children: /*#__PURE__*/ _jsx(Text, {
@@ -309,7 +314,7 @@ export var Default = {
309
314
  })
310
315
  }),
311
316
  /*#__PURE__*/ _jsx(Text, {
312
- children: "The pane can be closed by clicking the close button in the header, pressing the Escape key, or programmatically."
317
+ children: "The pane can be closed by clicking the close button in the tab, pressing the Escape key, or programmatically."
313
318
  })
314
319
  ]
315
320
  })
@@ -347,6 +352,7 @@ export var Default = {
347
352
  export var WithActions = {
348
353
  render: function() {
349
354
  var _useState = _sliced_to_array(useState(false), 2), paneOpen = _useState[0], setPaneOpen = _useState[1];
355
+ var tabStorage = useTabStorage();
350
356
  var headerActions = [
351
357
  {
352
358
  icon: EditMajor,
@@ -398,6 +404,9 @@ export var WithActions = {
398
404
  onClose: function() {
399
405
  return setPaneOpen(false);
400
406
  },
407
+ tabStorage: tabStorage,
408
+ tabId: "product-details",
409
+ tabTitle: "Product Details",
401
410
  children: [
402
411
  /*#__PURE__*/ _jsx(Pane.Header, {
403
412
  actions: headerActions,
@@ -530,6 +539,7 @@ export var WithActions = {
530
539
  export var FormPane = {
531
540
  render: function() {
532
541
  var _useState = _sliced_to_array(useState(false), 2), paneOpen = _useState[0], setPaneOpen = _useState[1];
542
+ var tabStorage = useTabStorage();
533
543
  var _useState1 = _sliced_to_array(useState({
534
544
  name: '',
535
545
  email: '',
@@ -595,6 +605,9 @@ export var FormPane = {
595
605
  onClose: function() {
596
606
  return setPaneOpen(false);
597
607
  },
608
+ tabStorage: tabStorage,
609
+ tabId: "add-contact",
610
+ tabTitle: "Add New Contact",
598
611
  children: [
599
612
  /*#__PURE__*/ _jsx(Pane.Header, {
600
613
  children: /*#__PURE__*/ _jsx(Text, {
@@ -695,6 +708,7 @@ export var FormPane = {
695
708
  export var DetailViewPane = {
696
709
  render: function() {
697
710
  var _useState = _sliced_to_array(useState(false), 2), paneOpen = _useState[0], setPaneOpen = _useState[1];
711
+ var tabStorage = useTabStorage();
698
712
  var _useState1 = _sliced_to_array(useState(null), 2), selectedOrder = _useState1[0], setSelectedOrder = _useState1[1];
699
713
  var orders = [
700
714
  {
@@ -843,6 +857,9 @@ export var DetailViewPane = {
843
857
  onClose: function() {
844
858
  return setPaneOpen(false);
845
859
  },
860
+ tabStorage: tabStorage,
861
+ tabId: "order-".concat(selectedOrder === null || selectedOrder === void 0 ? void 0 : selectedOrder.id),
862
+ tabTitle: "Order ".concat(selectedOrder === null || selectedOrder === void 0 ? void 0 : selectedOrder.id),
846
863
  children: [
847
864
  /*#__PURE__*/ _jsx(Pane.Header, {
848
865
  actions: headerActions,
@@ -1089,6 +1106,8 @@ export var StackedPanes = {
1089
1106
  render: function() {
1090
1107
  var _useState = _sliced_to_array(useState(false), 2), firstPaneOpen = _useState[0], setFirstPaneOpen = _useState[1];
1091
1108
  var _useState1 = _sliced_to_array(useState(false), 2), secondPaneOpen = _useState1[0], setSecondPaneOpen = _useState1[1];
1109
+ var firstPaneTabStorage = useTabStorage('stacked-pane-first');
1110
+ var secondPaneTabStorage = useTabStorage('stacked-pane-second');
1092
1111
  return /*#__PURE__*/ _jsxs(Page, {
1093
1112
  title: "Stacked Panes",
1094
1113
  children: [
@@ -1115,6 +1134,9 @@ export var StackedPanes = {
1115
1134
  onClose: function() {
1116
1135
  return setFirstPaneOpen(false);
1117
1136
  },
1137
+ tabStorage: firstPaneTabStorage,
1138
+ tabId: "categories",
1139
+ tabTitle: "Categories",
1118
1140
  children: [
1119
1141
  /*#__PURE__*/ _jsx(Pane.Header, {
1120
1142
  children: /*#__PURE__*/ _jsx(Text, {
@@ -1189,6 +1211,9 @@ export var StackedPanes = {
1189
1211
  onClose: function() {
1190
1212
  return setSecondPaneOpen(false);
1191
1213
  },
1214
+ tabStorage: secondPaneTabStorage,
1215
+ tabId: "category-details",
1216
+ tabTitle: "Category Details",
1192
1217
  children: [
1193
1218
  /*#__PURE__*/ _jsx(Pane.Header, {
1194
1219
  children: /*#__PURE__*/ _jsx(Text, {
@@ -1311,9 +1336,325 @@ export var StackedPanes = {
1311
1336
  }
1312
1337
  }
1313
1338
  };
1339
+ export var AskModal = {
1340
+ render: function() {
1341
+ var _useState = _sliced_to_array(useState(false), 2), paneOpen = _useState[0], setPaneOpen = _useState[1];
1342
+ var _useState1 = _sliced_to_array(useState("ask"), 2), askContext = _useState1[0], setAskContext = _useState1[1];
1343
+ var tabStorage = useTabStorage();
1344
+ return /*#__PURE__*/ _jsxs(Page, {
1345
+ title: "Ask Modal Pane",
1346
+ children: [
1347
+ /*#__PURE__*/ _jsx(Card, {
1348
+ title: "Ask Modal Example",
1349
+ padded: true,
1350
+ children: /*#__PURE__*/ _jsxs(Stack, {
1351
+ gap: "4",
1352
+ children: [
1353
+ /*#__PURE__*/ _jsx(Text, {
1354
+ children: 'This example demonstrates the AskModal pane type. It creates a single "Ask" tab that can be reused. Opening multiple times will switch to the existing tab instead of creating new ones. The tab title is always "Ask" regardless of the context.'
1355
+ }),
1356
+ /*#__PURE__*/ _jsxs(Stack, {
1357
+ horizontal: true,
1358
+ gap: "4",
1359
+ children: [
1360
+ /*#__PURE__*/ _jsx(Button, {
1361
+ primary: askContext === "ask",
1362
+ onClick: function() {
1363
+ return setAskContext("ask");
1364
+ },
1365
+ children: "Ask Mode"
1366
+ }),
1367
+ /*#__PURE__*/ _jsx(Button, {
1368
+ primary: askContext === "search",
1369
+ onClick: function() {
1370
+ return setAskContext("search");
1371
+ },
1372
+ children: "Search Mode"
1373
+ })
1374
+ ]
1375
+ }),
1376
+ /*#__PURE__*/ _jsx(Button, {
1377
+ primary: true,
1378
+ onClick: function() {
1379
+ return setPaneOpen(true);
1380
+ },
1381
+ children: "Open Ask Modal"
1382
+ })
1383
+ ]
1384
+ })
1385
+ }),
1386
+ /*#__PURE__*/ _jsxs(Pane, {
1387
+ open: paneOpen,
1388
+ onClose: function() {
1389
+ return setPaneOpen(false);
1390
+ },
1391
+ tabStorage: tabStorage,
1392
+ tabId: "ask-tab",
1393
+ tabTitle: askContext === "search" ? "Search" : "Ask",
1394
+ tabKey: "ask",
1395
+ children: [
1396
+ /*#__PURE__*/ _jsx(Pane.Header, {
1397
+ children: /*#__PURE__*/ _jsx(Text, {
1398
+ variant: "headingMd",
1399
+ children: askContext === "search" ? "Search" : "Ask"
1400
+ })
1401
+ }),
1402
+ /*#__PURE__*/ _jsx(Pane.Content, {
1403
+ children: /*#__PURE__*/ _jsx(Box, {
1404
+ padding: "4",
1405
+ children: /*#__PURE__*/ _jsxs(Stack, {
1406
+ gap: "4",
1407
+ children: [
1408
+ /*#__PURE__*/ _jsxs(Text, {
1409
+ children: [
1410
+ "This is the ",
1411
+ askContext === "search" ? "Search" : "Ask",
1412
+ ' modal pane. The tab title will be "',
1413
+ askContext === "search" ? "Search" : "Ask",
1414
+ '" based on the context.'
1415
+ ]
1416
+ }),
1417
+ /*#__PURE__*/ _jsx(Text, {
1418
+ variant: "bodySm",
1419
+ color: "subdued",
1420
+ children: "Try switching between Ask and Search modes to see the tab title change. Opening multiple times will switch to the existing tab instead of creating duplicates."
1421
+ })
1422
+ ]
1423
+ })
1424
+ })
1425
+ }),
1426
+ /*#__PURE__*/ _jsx(Pane.Footer, {
1427
+ children: /*#__PURE__*/ _jsx(Box, {
1428
+ padding: "4",
1429
+ children: /*#__PURE__*/ _jsxs(Stack, {
1430
+ horizontal: true,
1431
+ gap: "4",
1432
+ align: "end",
1433
+ children: [
1434
+ /*#__PURE__*/ _jsx(Button, {
1435
+ onClick: function() {
1436
+ return setPaneOpen(false);
1437
+ },
1438
+ children: "Close"
1439
+ }),
1440
+ /*#__PURE__*/ _jsxs(Button, {
1441
+ primary: true,
1442
+ onClick: function() {
1443
+ return alert("".concat(askContext, " functionality"));
1444
+ },
1445
+ children: [
1446
+ askContext === "search" ? "Search" : "Ask",
1447
+ " Question"
1448
+ ]
1449
+ })
1450
+ ]
1451
+ })
1452
+ })
1453
+ })
1454
+ ]
1455
+ })
1456
+ ]
1457
+ });
1458
+ },
1459
+ parameters: {
1460
+ docs: {
1461
+ description: {
1462
+ story: 'AskModal pane type that creates a reusable "Ask" or "Search" tab based on context. Multiple opens will switch to the existing tab.'
1463
+ }
1464
+ }
1465
+ }
1466
+ };
1467
+ export var PinnedTickets = {
1468
+ render: function() {
1469
+ var _useState = _sliced_to_array(useState(false), 2), paneOpen = _useState[0], setPaneOpen = _useState[1];
1470
+ var _useState1 = _sliced_to_array(useState('TICKET-001'), 2), ticketId = _useState1[0], setTicketId = _useState1[1];
1471
+ var _useState2 = _sliced_to_array(useState('John Smith'), 2), customerName = _useState2[0], setCustomerName = _useState2[1];
1472
+ var tabStorage = useTabStorage();
1473
+ var tickets = [
1474
+ {
1475
+ id: 'TICKET-001',
1476
+ customer: 'John Smith',
1477
+ subject: 'Login Issues'
1478
+ },
1479
+ {
1480
+ id: 'TICKET-002',
1481
+ customer: 'Sarah Johnson',
1482
+ subject: 'Billing Question'
1483
+ },
1484
+ {
1485
+ id: 'TICKET-003',
1486
+ customer: 'Mike Wilson',
1487
+ subject: 'Feature Request'
1488
+ },
1489
+ {
1490
+ id: 'TICKET-004',
1491
+ customer: 'Emily Davis',
1492
+ subject: 'Password Reset'
1493
+ },
1494
+ {
1495
+ id: 'TICKET-005',
1496
+ customer: 'Robert Brown',
1497
+ subject: 'Account Locked'
1498
+ },
1499
+ {
1500
+ id: 'TICKET-006',
1501
+ customer: 'Lisa Anderson',
1502
+ subject: 'Payment Failed'
1503
+ },
1504
+ {
1505
+ id: 'TICKET-007',
1506
+ customer: 'David Miller',
1507
+ subject: 'Refund Request'
1508
+ },
1509
+ {
1510
+ id: 'TICKET-008',
1511
+ customer: 'Jennifer Taylor',
1512
+ subject: 'Shipping Delay'
1513
+ },
1514
+ {
1515
+ id: 'TICKET-009',
1516
+ customer: 'Michael Garcia',
1517
+ subject: 'Product Defect'
1518
+ },
1519
+ {
1520
+ id: 'TICKET-010',
1521
+ customer: 'Amanda White',
1522
+ subject: 'Subscription Cancel'
1523
+ },
1524
+ {
1525
+ id: 'TICKET-011',
1526
+ customer: 'Christopher Lee',
1527
+ subject: 'Data Export'
1528
+ },
1529
+ {
1530
+ id: 'TICKET-012',
1531
+ customer: 'Jessica Martinez',
1532
+ subject: 'API Integration'
1533
+ }
1534
+ ];
1535
+ var handleOpenTicket = function(ticket) {
1536
+ setTicketId(ticket.id);
1537
+ setCustomerName(ticket.customer);
1538
+ setPaneOpen(true);
1539
+ };
1540
+ return /*#__PURE__*/ _jsxs(Page, {
1541
+ title: "Pinned Tickets Pane",
1542
+ children: [
1543
+ /*#__PURE__*/ _jsx(Card, {
1544
+ title: "Pinned Tickets Example",
1545
+ padded: true,
1546
+ children: /*#__PURE__*/ _jsxs(Stack, {
1547
+ gap: "4",
1548
+ children: [
1549
+ /*#__PURE__*/ _jsx(Text, {
1550
+ children: "This example demonstrates the PinnedTicketsPane type. Each ticket creates its own tab with the customer name. Multiple tickets can be pinned simultaneously, each getting their own tab. Opening the same ticket multiple times will switch to the existing tab instead of creating duplicates."
1551
+ }),
1552
+ /*#__PURE__*/ _jsx(Text, {
1553
+ variant: "bodySm",
1554
+ color: "subdued",
1555
+ children: "Try clicking the same ticket multiple times - it will switch to the existing tab instead of creating duplicates."
1556
+ }),
1557
+ /*#__PURE__*/ _jsx(Stack, {
1558
+ gap: "2",
1559
+ children: tickets.map(function(ticket) {
1560
+ return /*#__PURE__*/ _jsxs(Button, {
1561
+ onClick: function() {
1562
+ return handleOpenTicket(ticket);
1563
+ },
1564
+ children: [
1565
+ "Open ",
1566
+ ticket.customer,
1567
+ " - ",
1568
+ ticket.subject
1569
+ ]
1570
+ }, ticket.id);
1571
+ })
1572
+ })
1573
+ ]
1574
+ })
1575
+ }),
1576
+ /*#__PURE__*/ _jsxs(Pane, {
1577
+ open: paneOpen,
1578
+ onClose: function() {
1579
+ return setPaneOpen(false);
1580
+ },
1581
+ tabStorage: tabStorage,
1582
+ tabId: "ticket-".concat(ticketId),
1583
+ tabTitle: customerName,
1584
+ tabKey: "ticket-".concat(ticketId),
1585
+ children: [
1586
+ /*#__PURE__*/ _jsx(Pane.Header, {
1587
+ children: /*#__PURE__*/ _jsx(Text, {
1588
+ variant: "headingMd",
1589
+ children: customerName
1590
+ })
1591
+ }),
1592
+ /*#__PURE__*/ _jsx(Pane.Content, {
1593
+ children: /*#__PURE__*/ _jsx(Box, {
1594
+ padding: "4",
1595
+ children: /*#__PURE__*/ _jsxs(Stack, {
1596
+ gap: "4",
1597
+ children: [
1598
+ /*#__PURE__*/ _jsxs(Text, {
1599
+ children: [
1600
+ "This is a pinned ticket for ",
1601
+ customerName,
1602
+ " (Ticket ID: ",
1603
+ ticketId,
1604
+ ")."
1605
+ ]
1606
+ }),
1607
+ /*#__PURE__*/ _jsx(Text, {
1608
+ variant: "bodySm",
1609
+ color: "subdued",
1610
+ children: "Each pinned ticket gets its own tab with the customer name as the tab label. Opening the same ticket multiple times will switch to the existing tab instead of creating duplicates."
1611
+ })
1612
+ ]
1613
+ })
1614
+ })
1615
+ }),
1616
+ /*#__PURE__*/ _jsx(Pane.Footer, {
1617
+ children: /*#__PURE__*/ _jsx(Box, {
1618
+ padding: "4",
1619
+ children: /*#__PURE__*/ _jsxs(Stack, {
1620
+ horizontal: true,
1621
+ gap: "4",
1622
+ align: "end",
1623
+ children: [
1624
+ /*#__PURE__*/ _jsx(Button, {
1625
+ onClick: function() {
1626
+ return setPaneOpen(false);
1627
+ },
1628
+ children: "Close Ticket"
1629
+ }),
1630
+ /*#__PURE__*/ _jsx(Button, {
1631
+ primary: true,
1632
+ onClick: function() {
1633
+ return alert('Reply to ticket');
1634
+ },
1635
+ children: "Reply"
1636
+ })
1637
+ ]
1638
+ })
1639
+ })
1640
+ })
1641
+ ]
1642
+ })
1643
+ ]
1644
+ });
1645
+ },
1646
+ parameters: {
1647
+ docs: {
1648
+ description: {
1649
+ story: 'PinnedTicketsPane type that creates a separate tab for each pinned ticket with customer name as tab label. Prevents duplicate tabs for the same ticket.'
1650
+ }
1651
+ }
1652
+ }
1653
+ };
1314
1654
  export var CustomLayout = {
1315
1655
  render: function() {
1316
1656
  var _useState = _sliced_to_array(useState(false), 2), paneOpen = _useState[0], setPaneOpen = _useState[1];
1657
+ var tabStorage = useTabStorage();
1317
1658
  return /*#__PURE__*/ _jsxs(Page, {
1318
1659
  title: "Custom Pane Layout",
1319
1660
  children: [
@@ -1340,10 +1681,12 @@ export var CustomLayout = {
1340
1681
  onClose: function() {
1341
1682
  return setPaneOpen(false);
1342
1683
  },
1684
+ tabStorage: tabStorage,
1685
+ tabId: "live-chat",
1686
+ tabTitle: "Live Chat Support",
1343
1687
  children: [
1344
1688
  /*#__PURE__*/ _jsxs(Pane.Header, {
1345
1689
  bottomBorder: false,
1346
- showCloseButton: false,
1347
1690
  children: [
1348
1691
  /*#__PURE__*/ _jsxs(Stack, {
1349
1692
  horizontal: true,
@@ -0,0 +1,53 @@
1
+ "use client";
2
+ import { useEffect, useRef } from "react";
3
+ // Reference counter for body scroll lock (shared across all components)
4
+ var bodyScrollLockCount = 0;
5
+ /**
6
+ * Locks body scrolling by adding overflow-hidden class
7
+ * Uses reference counting to coordinate between multiple components
8
+ */ var lockBodyScroll = function() {
9
+ if (typeof document === 'undefined') return;
10
+ bodyScrollLockCount++;
11
+ if (bodyScrollLockCount === 1) {
12
+ document.body.classList.add('overflow-hidden');
13
+ }
14
+ };
15
+ /**
16
+ * Unlocks body scrolling by removing overflow-hidden class
17
+ * Uses reference counting to coordinate between multiple components
18
+ */ var unlockBodyScroll = function() {
19
+ if (typeof document === 'undefined') return;
20
+ bodyScrollLockCount = Math.max(0, bodyScrollLockCount - 1);
21
+ if (bodyScrollLockCount === 0) {
22
+ document.body.classList.remove('overflow-hidden');
23
+ }
24
+ };
25
+ /**
26
+ * Custom hook for managing body scroll lock
27
+ * Uses reference counting to coordinate between multiple components (panes, modals, etc.)
28
+ *
29
+ * @param {boolean} shouldLock - Whether to lock body scrolling
30
+ * @example
31
+ * // In a component:
32
+ * useBodyScrollLock(open && isMobile);
33
+ */ export function useBodyScrollLock(shouldLock) {
34
+ var hasLockedRef = useRef(false);
35
+ useEffect(function() {
36
+ if (shouldLock && !hasLockedRef.current) {
37
+ lockBodyScroll();
38
+ hasLockedRef.current = true;
39
+ } else if (!shouldLock && hasLockedRef.current) {
40
+ unlockBodyScroll();
41
+ hasLockedRef.current = false;
42
+ }
43
+ return function() {
44
+ if (hasLockedRef.current) {
45
+ unlockBodyScroll();
46
+ hasLockedRef.current = false;
47
+ }
48
+ };
49
+ }, [
50
+ shouldLock
51
+ ]);
52
+ }
53
+ export default useBodyScrollLock;
@@ -0,0 +1,25 @@
1
+ import { useCallback } from "react";
2
+ /**
3
+ * Hook that provides a keyboard action handler for Enter and Space keys.
4
+ * Useful for making interactive elements keyboard accessible.
5
+ *
6
+ * @returns {Function} A callback function that takes (event, action) and triggers the action on Enter/Space
7
+ *
8
+ * @example
9
+ * const handleKeyboardAction = useKeyboardAction();
10
+ *
11
+ * <div
12
+ * role="button"
13
+ * tabIndex={0}
14
+ * onKeyDown={(e) => handleKeyboardAction(e, () => doSomething())}
15
+ * >
16
+ * Click me
17
+ * </div>
18
+ */ export var useKeyboardAction = function() {
19
+ return useCallback(function(e, action) {
20
+ if (e.key === 'Enter' || e.key === ' ') {
21
+ e.preventDefault();
22
+ action();
23
+ }
24
+ }, []);
25
+ };
@@ -0,0 +1,115 @@
1
+ "use client";
2
+ function _array_like_to_array(arr, len) {
3
+ if (len == null || len > arr.length) len = arr.length;
4
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
5
+ return arr2;
6
+ }
7
+ function _array_with_holes(arr) {
8
+ if (Array.isArray(arr)) return arr;
9
+ }
10
+ function _instanceof(left, right) {
11
+ if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
12
+ return !!right[Symbol.hasInstance](left);
13
+ } else {
14
+ return left instanceof right;
15
+ }
16
+ }
17
+ function _iterable_to_array_limit(arr, i) {
18
+ var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
19
+ if (_i == null) return;
20
+ var _arr = [];
21
+ var _n = true;
22
+ var _d = false;
23
+ var _s, _e;
24
+ try {
25
+ for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
26
+ _arr.push(_s.value);
27
+ if (i && _arr.length === i) break;
28
+ }
29
+ } catch (err) {
30
+ _d = true;
31
+ _e = err;
32
+ } finally{
33
+ try {
34
+ if (!_n && _i["return"] != null) _i["return"]();
35
+ } finally{
36
+ if (_d) throw _e;
37
+ }
38
+ }
39
+ return _arr;
40
+ }
41
+ function _non_iterable_rest() {
42
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
43
+ }
44
+ function _sliced_to_array(arr, i) {
45
+ return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
46
+ }
47
+ function _unsupported_iterable_to_array(o, minLen) {
48
+ if (!o) return;
49
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
50
+ var n = Object.prototype.toString.call(o).slice(8, -1);
51
+ if (n === "Object" && o.constructor) n = o.constructor.name;
52
+ if (n === "Map" || n === "Set") return Array.from(n);
53
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
54
+ }
55
+ import { useState, useCallback } from "react";
56
+ /**
57
+ * Custom hook for managing localStorage with React state
58
+ * @param {string} key - The localStorage key
59
+ * @param {any} initialValue - The initial value if key doesn't exist
60
+ * @param {Object} options - Optional configuration
61
+ * @param {boolean} options.serialize - Whether to serialize/deserialize JSON (default: true)
62
+ * @returns {[any, Function]} - [storedValue, setValue]
63
+ */ export function useLocalStorage(key, initialValue) {
64
+ var options = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : {};
65
+ var _options_serialize = options.serialize, serialize = _options_serialize === void 0 ? true : _options_serialize;
66
+ // State to store our value
67
+ var _useState = _sliced_to_array(useState(function() {
68
+ if (typeof window === 'undefined') {
69
+ return initialValue;
70
+ }
71
+ try {
72
+ var item = window.localStorage.getItem(key);
73
+ if (item === null) {
74
+ return initialValue;
75
+ }
76
+ if (serialize) {
77
+ return JSON.parse(item);
78
+ }
79
+ return item;
80
+ } catch (error) {
81
+ console.warn('Error reading localStorage key "'.concat(key, '":'), error);
82
+ return initialValue;
83
+ }
84
+ }), 2), storedValue = _useState[0], setStoredValue = _useState[1];
85
+ // Return a wrapped version of useState's setter function that
86
+ // persists the new value to localStorage.
87
+ var setValue = useCallback(function(value) {
88
+ try {
89
+ // Use functional update to get current value without needing it in dependencies
90
+ setStoredValue(function(currentValue) {
91
+ // Allow value to be a function so we have the same API as useState
92
+ var valueToStore = _instanceof(value, Function) ? value(currentValue) : value;
93
+ // Save to local storage
94
+ if (typeof window !== 'undefined') {
95
+ if (serialize) {
96
+ window.localStorage.setItem(key, JSON.stringify(valueToStore));
97
+ } else {
98
+ window.localStorage.setItem(key, valueToStore);
99
+ }
100
+ }
101
+ return valueToStore;
102
+ });
103
+ } catch (error) {
104
+ console.warn('Error setting localStorage key "'.concat(key, '":'), error);
105
+ }
106
+ }, [
107
+ key,
108
+ serialize
109
+ ]);
110
+ return [
111
+ storedValue,
112
+ setValue
113
+ ];
114
+ }
115
+ export default useLocalStorage;