@heymantle/litho 0.0.10 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/Banner.js +6 -1
- package/dist/cjs/components/Button.js +33 -4
- package/dist/cjs/components/ButtonGroup.js +19 -4
- package/dist/cjs/components/Card.js +39 -3
- package/dist/cjs/components/ChoiceList.js +3 -2
- package/dist/cjs/components/Code.js +227 -0
- package/dist/cjs/components/Filters.js +1 -1
- package/dist/cjs/components/Frame.js +2 -2
- package/dist/cjs/components/Layout.js +16 -4
- package/dist/cjs/components/Link.js +35 -4
- package/dist/cjs/components/Modal.js +4 -0
- package/dist/cjs/components/Page.js +5 -2
- package/dist/cjs/components/Pane.js +669 -84
- package/dist/cjs/components/ResourceList.js +2 -2
- package/dist/cjs/components/TabNavigation.js +300 -0
- package/dist/cjs/components/TextField.js +3 -0
- package/dist/cjs/components/Tip.js +3 -0
- package/dist/cjs/components/Tooltip.js +12 -13
- package/dist/cjs/index.js +4 -0
- package/dist/cjs/stories/Pane.stories.js +352 -3
- package/dist/cjs/utilities/useBodyScrollLock.js +63 -0
- package/dist/cjs/utilities/useKeyboardAction.js +19 -0
- package/dist/cjs/utilities/useLocalStorage.js +126 -0
- package/dist/cjs/utilities/useMobile.js +92 -0
- package/dist/cjs/utilities/usePaneState.js +340 -0
- package/dist/cjs/utilities/useTabStorage.js +325 -0
- package/dist/esm/components/Banner.js +7 -2
- package/dist/esm/components/Button.js +33 -4
- package/dist/esm/components/ButtonGroup.js +19 -4
- package/dist/esm/components/Card.js +39 -3
- package/dist/esm/components/ChoiceList.js +3 -2
- package/dist/esm/components/Code.js +212 -0
- package/dist/esm/components/Filters.js +2 -2
- package/dist/esm/components/Frame.js +2 -2
- package/dist/esm/components/Layout.js +16 -4
- package/dist/esm/components/Link.js +31 -5
- package/dist/esm/components/Modal.js +4 -0
- package/dist/esm/components/Page.js +5 -2
- package/dist/esm/components/Pane.js +619 -83
- package/dist/esm/components/ResourceList.js +2 -2
- package/dist/esm/components/TabNavigation.js +285 -0
- package/dist/esm/components/TextField.js +4 -1
- package/dist/esm/components/Tip.js +4 -1
- package/dist/esm/components/Tooltip.js +12 -13
- package/dist/esm/index.js +1 -0
- package/dist/esm/stories/Pane.stories.js +346 -3
- package/dist/esm/utilities/useBodyScrollLock.js +53 -0
- package/dist/esm/utilities/useKeyboardAction.js +25 -0
- package/dist/esm/utilities/useLocalStorage.js +115 -0
- package/dist/esm/utilities/useMobile.js +79 -0
- package/dist/esm/utilities/usePaneState.js +334 -0
- package/dist/esm/utilities/useTabStorage.js +311 -0
- package/dist/types/components/Banner.d.ts.map +1 -1
- package/dist/types/components/Button.d.ts +2 -2
- package/dist/types/components/Button.d.ts.map +1 -1
- package/dist/types/components/ButtonGroup.d.ts.map +1 -1
- package/dist/types/components/Card.d.ts +34 -1
- package/dist/types/components/Card.d.ts.map +1 -1
- package/dist/types/components/Code.d.ts +28 -0
- package/dist/types/components/Code.d.ts.map +1 -0
- package/dist/types/components/Filters.d.ts.map +1 -1
- package/dist/types/components/Layout.d.ts +2 -0
- package/dist/types/components/Layout.d.ts.map +1 -1
- package/dist/types/components/Link.d.ts +4 -0
- package/dist/types/components/Link.d.ts.map +1 -1
- package/dist/types/components/Modal.d.ts +2 -0
- package/dist/types/components/Modal.d.ts.map +1 -1
- package/dist/types/components/Page.d.ts.map +1 -1
- package/dist/types/components/Pane.d.ts +2 -0
- package/dist/types/components/Pane.d.ts.map +1 -1
- package/dist/types/components/TabNavigation.d.ts +3 -0
- package/dist/types/components/TabNavigation.d.ts.map +1 -0
- package/dist/types/components/TextField.d.ts.map +1 -1
- package/dist/types/components/Tip.d.ts.map +1 -1
- package/dist/types/components/Tooltip.d.ts +2 -0
- package/dist/types/components/Tooltip.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/utilities/useBodyScrollLock.d.ts +12 -0
- package/dist/types/utilities/useBodyScrollLock.d.ts.map +1 -0
- package/dist/types/utilities/useKeyboardAction.d.ts +2 -0
- package/dist/types/utilities/useKeyboardAction.d.ts.map +1 -0
- package/dist/types/utilities/useLocalStorage.d.ts +13 -0
- package/dist/types/utilities/useLocalStorage.d.ts.map +1 -0
- package/dist/types/utilities/useMobile.d.ts +9 -0
- package/dist/types/utilities/useMobile.d.ts.map +1 -0
- package/dist/types/utilities/usePaneState.d.ts +2 -0
- package/dist/types/utilities/usePaneState.d.ts.map +1 -0
- package/dist/types/utilities/useTabStorage.d.ts +8 -0
- package/dist/types/utilities/useTabStorage.d.ts.map +1 -0
- package/index.css +77 -6
- package/package.json +2 -2
|
@@ -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
|
|
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;
|