reactbridge-sdk 0.1.21 → 0.2.0

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 (29) hide show
  1. package/dist/components/analytics/AnalyticsDrawer.d.ts +13 -0
  2. package/dist/components/analytics/AnalyticsDrawer.d.ts.map +1 -0
  3. package/dist/components/analytics/AnalyticsReport.d.ts +13 -0
  4. package/dist/components/analytics/AnalyticsReport.d.ts.map +1 -0
  5. package/dist/components/analytics/AnalyticsWidget.d.ts +10 -0
  6. package/dist/components/analytics/AnalyticsWidget.d.ts.map +1 -0
  7. package/dist/components/analytics/DirectivesPanel.d.ts +11 -0
  8. package/dist/components/analytics/DirectivesPanel.d.ts.map +1 -0
  9. package/dist/components/analytics/MetricsPanel.d.ts +9 -0
  10. package/dist/components/analytics/MetricsPanel.d.ts.map +1 -0
  11. package/dist/components/analytics/ObservationsPanel.d.ts +9 -0
  12. package/dist/components/analytics/ObservationsPanel.d.ts.map +1 -0
  13. package/dist/hooks/analytics/useAnalyticsConfigs.d.ts +8 -0
  14. package/dist/hooks/analytics/useAnalyticsConfigs.d.ts.map +1 -0
  15. package/dist/hooks/analytics/useAnalyticsResult.d.ts +8 -0
  16. package/dist/hooks/analytics/useAnalyticsResult.d.ts.map +1 -0
  17. package/dist/hooks/analytics/useDirectiveAction.d.ts +7 -0
  18. package/dist/hooks/analytics/useDirectiveAction.d.ts.map +1 -0
  19. package/dist/index.d.ts +15 -0
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.esm.js +717 -3
  22. package/dist/index.esm.js.map +1 -1
  23. package/dist/index.js +725 -2
  24. package/dist/index.js.map +1 -1
  25. package/dist/types/analytics.d.ts +63 -0
  26. package/dist/types/analytics.d.ts.map +1 -0
  27. package/dist/utils/analytics-api.d.ts +23 -0
  28. package/dist/utils/analytics-api.d.ts.map +1 -0
  29. package/package.json +1 -1
package/dist/index.esm.js CHANGED
@@ -32,14 +32,14 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
32
32
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
33
33
  };
34
34
 
35
- const DEFAULT_BASE_URL = 'https://react-bridge-api-14089992360.northamerica-northeast2.run.app'; // 'http://localhost:5093';
35
+ const DEFAULT_BASE_URL$1 = 'https://react-bridge-api-14089992360.northamerica-northeast2.run.app'; // 'http://localhost:5093';
36
36
  class ReactBridgeAPI {
37
37
  constructor(config) {
38
38
  this.config = config;
39
39
  }
40
40
  sendMessage(request) {
41
41
  return __awaiter(this, void 0, void 0, function* () {
42
- const baseURL = this.config.baseURL || DEFAULT_BASE_URL;
42
+ const baseURL = this.config.baseURL || DEFAULT_BASE_URL$1;
43
43
  const url = `${baseURL}/api/orchestrator/process`;
44
44
  try {
45
45
  // Configure abort signal for fetch with robust fallback.
@@ -1437,5 +1437,719 @@ function createCustomTheme(baseTheme, overrides) {
1437
1437
  return Object.assign(Object.assign(Object.assign({}, baseTheme), overrides), { colors: Object.assign(Object.assign({}, baseTheme.colors), (overrides.colors || {})), spacing: Object.assign(Object.assign({}, baseTheme.spacing), (overrides.spacing || {})), fontSizes: Object.assign(Object.assign({}, baseTheme.fontSizes), (overrides.fontSizes || {})) });
1438
1438
  }
1439
1439
 
1440
- export { ReactBridgeAPI, ReactBridgeChatbox, ReactBridgeProvider, ReactBridgeSearch, WebSpeechSTTProvider, WebSpeechTTSProvider, createCustomTheme, darkTheme, getTheme, lightTheme, useReactBridge, useReactBridgeContext };
1440
+ const DEFAULT_BASE_URL = 'https://react-bridge-api-14089992360.northamerica-northeast2.run.app';
1441
+ class AnalyticsAPI {
1442
+ constructor(config) {
1443
+ this.config = config;
1444
+ }
1445
+ /**
1446
+ * Fetch all analytics configurations for the client
1447
+ */
1448
+ getConfigs() {
1449
+ return __awaiter(this, void 0, void 0, function* () {
1450
+ const baseURL = this.config.baseURL || DEFAULT_BASE_URL;
1451
+ const url = `${baseURL}/api/client/analytics/configs`;
1452
+ const response = yield fetch(url, {
1453
+ method: 'GET',
1454
+ headers: Object.assign({ 'X-API-Key': this.config.apiKey }, this.config.headers),
1455
+ });
1456
+ if (!response.ok) {
1457
+ throw new Error(`Failed to fetch analytics configs: ${response.statusText}`);
1458
+ }
1459
+ return response.json();
1460
+ });
1461
+ }
1462
+ /**
1463
+ * Fetch the latest analytics result for a specific type
1464
+ */
1465
+ getLatestResult(analyticsType) {
1466
+ return __awaiter(this, void 0, void 0, function* () {
1467
+ const baseURL = this.config.baseURL || DEFAULT_BASE_URL;
1468
+ const url = `${baseURL}/api/analytics/${analyticsType}/latest`;
1469
+ const response = yield fetch(url, {
1470
+ method: 'POST',
1471
+ headers: Object.assign({ 'X-API-Key': this.config.apiKey, 'Content-Type': 'application/json' }, this.config.headers),
1472
+ });
1473
+ if (!response.ok) {
1474
+ if (response.status === 404) {
1475
+ throw new Error(`No results found for analytics type: ${analyticsType}`);
1476
+ }
1477
+ throw new Error(`Failed to fetch analytics result: ${response.statusText}`);
1478
+ }
1479
+ return response.json();
1480
+ });
1481
+ }
1482
+ /**
1483
+ * Update directive status (executed, declined, failed)
1484
+ */
1485
+ updateDirectiveStatus(directiveId, status) {
1486
+ return __awaiter(this, void 0, void 0, function* () {
1487
+ const baseURL = this.config.baseURL || DEFAULT_BASE_URL;
1488
+ const url = `${baseURL}/api/analytics/directives/${directiveId}/status`;
1489
+ const response = yield fetch(url, {
1490
+ method: 'PATCH',
1491
+ headers: Object.assign({ 'X-API-Key': this.config.apiKey, 'Content-Type': 'application/json' }, this.config.headers),
1492
+ body: JSON.stringify({ status }),
1493
+ });
1494
+ if (!response.ok) {
1495
+ throw new Error(`Failed to update directive status: ${response.statusText}`);
1496
+ }
1497
+ return response.json();
1498
+ });
1499
+ }
1500
+ }
1501
+
1502
+ function useAnalyticsConfigs() {
1503
+ const { config } = useReactBridgeContext();
1504
+ const [configs, setConfigs] = useState([]);
1505
+ const [isLoading, setIsLoading] = useState(true);
1506
+ const [error, setError] = useState(null);
1507
+ const fetchConfigs = () => __awaiter(this, void 0, void 0, function* () {
1508
+ try {
1509
+ setIsLoading(true);
1510
+ setError(null);
1511
+ const api = new AnalyticsAPI(config);
1512
+ const data = yield api.getConfigs();
1513
+ setConfigs(data);
1514
+ }
1515
+ catch (err) {
1516
+ setError(err);
1517
+ }
1518
+ finally {
1519
+ setIsLoading(false);
1520
+ }
1521
+ });
1522
+ useEffect(() => {
1523
+ fetchConfigs();
1524
+ }, [config]);
1525
+ return {
1526
+ configs,
1527
+ isLoading,
1528
+ error,
1529
+ refetch: fetchConfigs,
1530
+ };
1531
+ }
1532
+
1533
+ function useAnalyticsResult(analyticsType) {
1534
+ const { config } = useReactBridgeContext();
1535
+ const [result, setResult] = useState(null);
1536
+ const [isLoading, setIsLoading] = useState(false);
1537
+ const [error, setError] = useState(null);
1538
+ const fetchResult = () => __awaiter(this, void 0, void 0, function* () {
1539
+ if (!analyticsType)
1540
+ return;
1541
+ try {
1542
+ setIsLoading(true);
1543
+ setError(null);
1544
+ const api = new AnalyticsAPI(config);
1545
+ const data = yield api.getLatestResult(analyticsType);
1546
+ setResult(data);
1547
+ }
1548
+ catch (err) {
1549
+ setError(err);
1550
+ setResult(null);
1551
+ }
1552
+ finally {
1553
+ setIsLoading(false);
1554
+ }
1555
+ });
1556
+ useEffect(() => {
1557
+ fetchResult();
1558
+ }, [analyticsType, config]);
1559
+ return {
1560
+ result,
1561
+ isLoading,
1562
+ error,
1563
+ refetch: fetchResult,
1564
+ };
1565
+ }
1566
+
1567
+ const MetricsPanel = ({ metrics, theme }) => {
1568
+ const getStatusColor = (status) => {
1569
+ switch (status) {
1570
+ case 'ok':
1571
+ return theme.colors.success;
1572
+ case 'warning':
1573
+ return '#FFA500'; // Orange
1574
+ case 'critical':
1575
+ return theme.colors.error;
1576
+ default:
1577
+ return theme.colors.textSecondary;
1578
+ }
1579
+ };
1580
+ return (React.createElement("div", null,
1581
+ React.createElement("h3", { style: {
1582
+ margin: 0,
1583
+ marginBottom: theme.spacing.md,
1584
+ fontSize: theme.fontSizes.lg,
1585
+ color: theme.colors.text,
1586
+ } }, "Metrics"),
1587
+ React.createElement("div", { style: {
1588
+ display: 'grid',
1589
+ gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))',
1590
+ gap: theme.spacing.md,
1591
+ } }, metrics.map((metric, index) => (React.createElement("div", { key: index, style: {
1592
+ padding: theme.spacing.md,
1593
+ backgroundColor: theme.colors.surface,
1594
+ borderRadius: theme.borderRadius,
1595
+ border: `2px solid ${getStatusColor(metric.status)}`,
1596
+ } },
1597
+ React.createElement("div", { style: {
1598
+ display: 'flex',
1599
+ justifyContent: 'space-between',
1600
+ alignItems: 'center',
1601
+ marginBottom: theme.spacing.xs,
1602
+ } },
1603
+ React.createElement("span", { style: {
1604
+ fontSize: theme.fontSizes.sm,
1605
+ color: theme.colors.textSecondary,
1606
+ textTransform: 'uppercase',
1607
+ letterSpacing: '0.5px',
1608
+ } }, metric.name.replace(/_/g, ' ')),
1609
+ React.createElement("span", { style: {
1610
+ fontSize: theme.fontSizes.xs,
1611
+ padding: '2px 8px',
1612
+ borderRadius: '12px',
1613
+ backgroundColor: getStatusColor(metric.status),
1614
+ color: '#fff',
1615
+ textTransform: 'uppercase',
1616
+ } }, metric.status)),
1617
+ React.createElement("div", { style: {
1618
+ fontSize: theme.fontSizes.xl,
1619
+ fontWeight: 'bold',
1620
+ color: theme.colors.text,
1621
+ marginBottom: theme.spacing.xs,
1622
+ } },
1623
+ metric.value,
1624
+ " ",
1625
+ metric.unit),
1626
+ React.createElement("div", { style: {
1627
+ fontSize: theme.fontSizes.sm,
1628
+ color: theme.colors.textSecondary,
1629
+ } }, metric.explanation)))))));
1630
+ };
1631
+
1632
+ const ObservationsPanel = ({ observations, theme, }) => {
1633
+ const getSeverityColor = (severity) => {
1634
+ switch (severity) {
1635
+ case 'low':
1636
+ return theme.colors.success;
1637
+ case 'medium':
1638
+ return '#FFA500'; // Orange
1639
+ case 'high':
1640
+ return theme.colors.error;
1641
+ default:
1642
+ return theme.colors.textSecondary;
1643
+ }
1644
+ };
1645
+ return (React.createElement("div", null,
1646
+ React.createElement("h3", { style: {
1647
+ margin: 0,
1648
+ marginBottom: theme.spacing.md,
1649
+ fontSize: theme.fontSizes.lg,
1650
+ color: theme.colors.text,
1651
+ } }, "Observations"),
1652
+ React.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: theme.spacing.md } }, observations.map((observation, index) => (React.createElement("div", { key: index, style: {
1653
+ padding: theme.spacing.md,
1654
+ backgroundColor: theme.colors.surface,
1655
+ borderRadius: theme.borderRadius,
1656
+ border: `1px solid ${theme.colors.border}`,
1657
+ borderLeft: `4px solid ${getSeverityColor(observation.severity)}`,
1658
+ } },
1659
+ React.createElement("div", { style: {
1660
+ display: 'flex',
1661
+ justifyContent: 'space-between',
1662
+ alignItems: 'center',
1663
+ marginBottom: theme.spacing.xs,
1664
+ } },
1665
+ React.createElement("span", { style: {
1666
+ fontSize: theme.fontSizes.xs,
1667
+ padding: '2px 8px',
1668
+ borderRadius: '12px',
1669
+ backgroundColor: getSeverityColor(observation.severity),
1670
+ color: '#fff',
1671
+ textTransform: 'uppercase',
1672
+ } }, observation.severity),
1673
+ React.createElement("span", { style: {
1674
+ fontSize: theme.fontSizes.xs,
1675
+ color: theme.colors.textSecondary,
1676
+ } }, observation.scope)),
1677
+ React.createElement("div", { style: {
1678
+ fontSize: theme.fontSizes.md,
1679
+ color: theme.colors.text,
1680
+ lineHeight: '1.5',
1681
+ } }, observation.text)))))));
1682
+ };
1683
+
1684
+ function useDirectiveAction(onDirectiveAction) {
1685
+ const { config } = useReactBridgeContext();
1686
+ const [isProcessing, setIsProcessing] = useState(false);
1687
+ const [error, setError] = useState(null);
1688
+ const handleAction = (directive, action) => __awaiter(this, void 0, void 0, function* () {
1689
+ try {
1690
+ setIsProcessing(true);
1691
+ setError(null);
1692
+ const api = new AnalyticsAPI(config);
1693
+ // If onDirectiveAction callback is provided, execute it first
1694
+ if (onDirectiveAction) {
1695
+ const result = yield onDirectiveAction(directive, action);
1696
+ if (result.success) {
1697
+ // Update status to 'executed' if action succeeded
1698
+ yield api.updateDirectiveStatus(directive.directiveId, 'executed');
1699
+ }
1700
+ else {
1701
+ // Update status to 'failed' if action failed
1702
+ yield api.updateDirectiveStatus(directive.directiveId, 'failed');
1703
+ throw new Error(result.error || 'Directive execution failed');
1704
+ }
1705
+ return { success: true };
1706
+ }
1707
+ else {
1708
+ // No callback provided, just update status to 'declined'
1709
+ if (action === 'decline') {
1710
+ yield api.updateDirectiveStatus(directive.directiveId, 'declined');
1711
+ }
1712
+ return { success: true };
1713
+ }
1714
+ }
1715
+ catch (err) {
1716
+ setError(err);
1717
+ return { success: false, error: err.message };
1718
+ }
1719
+ finally {
1720
+ setIsProcessing(false);
1721
+ }
1722
+ });
1723
+ return {
1724
+ handleAction,
1725
+ isProcessing,
1726
+ error,
1727
+ };
1728
+ }
1729
+
1730
+ const DirectivesPanel = ({ directives, theme, onDirectiveAction, onUpdate, }) => {
1731
+ const { handleAction, isProcessing } = useDirectiveAction(onDirectiveAction);
1732
+ const [processingId, setProcessingId] = useState(null);
1733
+ const getPriorityColor = (priority) => {
1734
+ if (priority >= 3)
1735
+ return theme.colors.error; // High/Critical
1736
+ if (priority === 2)
1737
+ return '#FFA500'; // Medium
1738
+ return theme.colors.success; // Low
1739
+ };
1740
+ const getPriorityLabel = (priority) => {
1741
+ if (priority >= 3)
1742
+ return 'Critical';
1743
+ if (priority === 2)
1744
+ return 'High';
1745
+ if (priority === 1)
1746
+ return 'Medium';
1747
+ return 'Low';
1748
+ };
1749
+ const getStatusLabel = (status) => {
1750
+ switch (status) {
1751
+ case 'proposed':
1752
+ return 'Pending';
1753
+ case 'executed':
1754
+ return 'Executed ✓';
1755
+ case 'declined':
1756
+ return 'Declined';
1757
+ case 'failed':
1758
+ return 'Failed ✗';
1759
+ default:
1760
+ return status;
1761
+ }
1762
+ };
1763
+ const handleDirectiveAction = (directive, action) => __awaiter(void 0, void 0, void 0, function* () {
1764
+ setProcessingId(directive.directiveId);
1765
+ yield handleAction(directive, action);
1766
+ setProcessingId(null);
1767
+ if (onUpdate) {
1768
+ onUpdate();
1769
+ }
1770
+ });
1771
+ return (React.createElement("div", null,
1772
+ React.createElement("h3", { style: {
1773
+ margin: 0,
1774
+ marginBottom: theme.spacing.md,
1775
+ fontSize: theme.fontSizes.lg,
1776
+ color: theme.colors.text,
1777
+ } }, "Directives"),
1778
+ React.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: theme.spacing.md } }, directives.map((directive) => {
1779
+ const isDisabled = directive.status !== 'proposed' ||
1780
+ isProcessing ||
1781
+ processingId === directive.directiveId;
1782
+ return (React.createElement("div", { key: directive.directiveId, style: {
1783
+ padding: theme.spacing.md,
1784
+ backgroundColor: theme.colors.surface,
1785
+ borderRadius: theme.borderRadius,
1786
+ border: `1px solid ${theme.colors.border}`,
1787
+ } },
1788
+ React.createElement("div", { style: {
1789
+ display: 'flex',
1790
+ justifyContent: 'space-between',
1791
+ alignItems: 'center',
1792
+ marginBottom: theme.spacing.sm,
1793
+ } },
1794
+ React.createElement("span", { style: {
1795
+ fontSize: theme.fontSizes.xs,
1796
+ padding: '2px 8px',
1797
+ borderRadius: '12px',
1798
+ backgroundColor: getPriorityColor(directive.priority),
1799
+ color: '#fff',
1800
+ textTransform: 'uppercase',
1801
+ } }, getPriorityLabel(directive.priority)),
1802
+ React.createElement("span", { style: {
1803
+ fontSize: theme.fontSizes.xs,
1804
+ padding: '2px 8px',
1805
+ borderRadius: '12px',
1806
+ backgroundColor: theme.colors.textSecondary,
1807
+ color: '#fff',
1808
+ } }, getStatusLabel(directive.status))),
1809
+ React.createElement("div", { style: {
1810
+ fontSize: theme.fontSizes.lg,
1811
+ fontWeight: 'bold',
1812
+ color: theme.colors.text,
1813
+ marginBottom: theme.spacing.xs,
1814
+ } }, directive.action.replace(/_/g, ' ').toUpperCase()),
1815
+ directive.targets.length > 0 && (React.createElement("div", { style: {
1816
+ fontSize: theme.fontSizes.sm,
1817
+ color: theme.colors.textSecondary,
1818
+ marginBottom: theme.spacing.xs,
1819
+ } },
1820
+ React.createElement("strong", null, "Targets:"),
1821
+ " ",
1822
+ directive.targets.join(', '))),
1823
+ directive.parameters.length > 0 && (React.createElement("div", { style: {
1824
+ marginBottom: theme.spacing.sm,
1825
+ padding: theme.spacing.sm,
1826
+ backgroundColor: theme.colors.background,
1827
+ borderRadius: theme.borderRadius,
1828
+ } }, directive.parameters.map((param, index) => (React.createElement("div", { key: index, style: {
1829
+ fontSize: theme.fontSizes.sm,
1830
+ color: theme.colors.text,
1831
+ marginBottom: '4px',
1832
+ } },
1833
+ React.createElement("strong", null,
1834
+ param.name,
1835
+ ":"),
1836
+ " ",
1837
+ param.value,
1838
+ " (",
1839
+ param.valueType,
1840
+ ")"))))),
1841
+ React.createElement("div", { style: {
1842
+ fontSize: theme.fontSizes.sm,
1843
+ color: theme.colors.textSecondary,
1844
+ marginBottom: theme.spacing.md,
1845
+ lineHeight: '1.5',
1846
+ } }, directive.rationale),
1847
+ directive.status === 'proposed' && (React.createElement("div", { style: { display: 'flex', gap: theme.spacing.sm } },
1848
+ React.createElement("button", { onClick: () => handleDirectiveAction(directive, 'execute'), disabled: isDisabled, style: {
1849
+ flex: 1,
1850
+ padding: theme.spacing.sm,
1851
+ backgroundColor: isDisabled
1852
+ ? theme.colors.textSecondary
1853
+ : theme.colors.success,
1854
+ color: '#fff',
1855
+ border: 'none',
1856
+ borderRadius: theme.borderRadius,
1857
+ cursor: isDisabled ? 'not-allowed' : 'pointer',
1858
+ fontSize: theme.fontSizes.sm,
1859
+ fontWeight: 'bold',
1860
+ opacity: isDisabled ? 0.6 : 1,
1861
+ } }, processingId === directive.directiveId ? 'Processing...' : 'Execute'),
1862
+ React.createElement("button", { onClick: () => handleDirectiveAction(directive, 'decline'), disabled: isDisabled, style: {
1863
+ flex: 1,
1864
+ padding: theme.spacing.sm,
1865
+ backgroundColor: isDisabled
1866
+ ? theme.colors.textSecondary
1867
+ : theme.colors.error,
1868
+ color: '#fff',
1869
+ border: 'none',
1870
+ borderRadius: theme.borderRadius,
1871
+ cursor: isDisabled ? 'not-allowed' : 'pointer',
1872
+ fontSize: theme.fontSizes.sm,
1873
+ fontWeight: 'bold',
1874
+ opacity: isDisabled ? 0.6 : 1,
1875
+ } }, "Decline")))));
1876
+ }))));
1877
+ };
1878
+
1879
+ // Refresh Icon SVG
1880
+ const REFRESH_ICON_SVG = (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "currentColor" },
1881
+ React.createElement("path", { d: "M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z" })));
1882
+ // Back Arrow Icon SVG
1883
+ const BACK_ICON_SVG = (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "currentColor" },
1884
+ React.createElement("path", { d: "M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z" })));
1885
+ // Close Icon SVG
1886
+ const CLOSE_ICON_SVG$1 = (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "currentColor" },
1887
+ React.createElement("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" })));
1888
+ const AnalyticsReport = ({ analyticsType, theme: customTheme, onDirectiveAction, onRefresh, onBack, onClose, }) => {
1889
+ const { result, isLoading, error, refetch } = useAnalyticsResult(analyticsType);
1890
+ const handleRefresh = () => {
1891
+ refetch();
1892
+ if (onRefresh) {
1893
+ onRefresh();
1894
+ }
1895
+ };
1896
+ // Use a default theme if none provided
1897
+ const theme = customTheme || {
1898
+ colors: {
1899
+ background: '#ffffff',
1900
+ surface: '#f5f5f5',
1901
+ text: '#333333',
1902
+ textSecondary: '#666666',
1903
+ border: '#e0e0e0',
1904
+ primary: '#007bff',
1905
+ success: '#28a745',
1906
+ error: '#dc3545',
1907
+ secondary: '#6c757d',
1908
+ },
1909
+ spacing: {
1910
+ xs: '4px',
1911
+ sm: '8px',
1912
+ md: '16px',
1913
+ lg: '24px',
1914
+ xl: '32px',
1915
+ },
1916
+ fontSizes: {
1917
+ xs: '12px',
1918
+ sm: '14px',
1919
+ md: '16px',
1920
+ lg: '20px',
1921
+ xl: '24px',
1922
+ },
1923
+ borderRadius: '8px',
1924
+ boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
1925
+ name: 'default',
1926
+ };
1927
+ return (React.createElement("div", { style: {
1928
+ height: '100%',
1929
+ display: 'flex',
1930
+ flexDirection: 'column',
1931
+ backgroundColor: theme.colors.background,
1932
+ } },
1933
+ React.createElement("div", { style: {
1934
+ padding: theme.spacing.lg,
1935
+ borderBottom: `1px solid ${theme.colors.border}`,
1936
+ display: 'flex',
1937
+ justifyContent: 'space-between',
1938
+ alignItems: 'center',
1939
+ } },
1940
+ React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: theme.spacing.sm } },
1941
+ onBack && (React.createElement("button", { onClick: onBack, style: {
1942
+ background: 'none',
1943
+ border: 'none',
1944
+ cursor: 'pointer',
1945
+ fontSize: '24px',
1946
+ color: theme.colors.text,
1947
+ padding: 0,
1948
+ } }, BACK_ICON_SVG)),
1949
+ React.createElement("div", null,
1950
+ React.createElement("h2", { style: {
1951
+ margin: 0,
1952
+ fontSize: theme.fontSizes.xl,
1953
+ color: theme.colors.text,
1954
+ } }, analyticsType),
1955
+ result && (React.createElement("div", { style: {
1956
+ fontSize: theme.fontSizes.xs,
1957
+ color: theme.colors.textSecondary,
1958
+ marginTop: '4px',
1959
+ } },
1960
+ "Last updated: ",
1961
+ new Date(result.createdAt).toLocaleString())))),
1962
+ React.createElement("div", { style: { display: 'flex', gap: theme.spacing.sm } },
1963
+ React.createElement("button", { onClick: handleRefresh, disabled: isLoading, style: {
1964
+ background: 'none',
1965
+ border: 'none',
1966
+ cursor: isLoading ? 'not-allowed' : 'pointer',
1967
+ fontSize: '24px',
1968
+ color: theme.colors.text,
1969
+ padding: 0,
1970
+ opacity: isLoading ? 0.5 : 1,
1971
+ } }, REFRESH_ICON_SVG),
1972
+ onClose && (React.createElement("button", { onClick: onClose, style: {
1973
+ background: 'none',
1974
+ border: 'none',
1975
+ cursor: 'pointer',
1976
+ fontSize: '24px',
1977
+ color: theme.colors.text,
1978
+ padding: 0,
1979
+ } }, CLOSE_ICON_SVG$1)))),
1980
+ React.createElement("div", { style: {
1981
+ flex: 1,
1982
+ overflowY: 'auto',
1983
+ padding: theme.spacing.lg,
1984
+ } }, isLoading ? (React.createElement("div", { style: { textAlign: 'center', color: theme.colors.textSecondary } }, "Loading analytics result...")) : error ? (React.createElement("div", { style: {
1985
+ padding: theme.spacing.md,
1986
+ backgroundColor: theme.colors.surface,
1987
+ borderRadius: theme.borderRadius,
1988
+ border: `1px solid ${theme.colors.error}`,
1989
+ color: theme.colors.error,
1990
+ } },
1991
+ "Error: ",
1992
+ error.message)) : result ? (React.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: theme.spacing.xl } },
1993
+ result.metrics.length > 0 && (React.createElement(MetricsPanel, { metrics: result.metrics, theme: theme })),
1994
+ result.observations.length > 0 && (React.createElement(ObservationsPanel, { observations: result.observations, theme: theme })),
1995
+ result.directives.length > 0 && (React.createElement(DirectivesPanel, { directives: result.directives, theme: theme, onDirectiveAction: onDirectiveAction, onUpdate: refetch })))) : (React.createElement("div", { style: { textAlign: 'center', color: theme.colors.textSecondary } }, "No results available")))));
1996
+ };
1997
+
1998
+ // Close Icon SVG
1999
+ const CLOSE_ICON_SVG = (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "currentColor" },
2000
+ React.createElement("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" })));
2001
+ const AnalyticsDrawer = ({ isOpen, onClose, configs, isLoading, theme, onDirectiveAction, }) => {
2002
+ const [selectedAnalytics, setSelectedAnalytics] = useState(null);
2003
+ // Check if mobile
2004
+ const isMobile = typeof window !== 'undefined' && window.innerWidth < 768;
2005
+ const drawerStyles = {
2006
+ position: 'fixed',
2007
+ top: 0,
2008
+ right: 0,
2009
+ width: isMobile ? '100%' : '400px',
2010
+ height: '100%',
2011
+ backgroundColor: theme.colors.background,
2012
+ boxShadow: theme.boxShadow,
2013
+ zIndex: 1001,
2014
+ display: 'flex',
2015
+ flexDirection: 'column',
2016
+ transform: isOpen ? 'translateX(0)' : 'translateX(100%)',
2017
+ transition: 'transform 0.3s ease',
2018
+ };
2019
+ const overlayStyles = {
2020
+ position: 'fixed',
2021
+ top: 0,
2022
+ left: 0,
2023
+ width: '100%',
2024
+ height: '100%',
2025
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
2026
+ zIndex: 1000,
2027
+ opacity: isOpen ? 1 : 0,
2028
+ pointerEvents: isOpen ? 'auto' : 'none',
2029
+ transition: 'opacity 0.3s ease',
2030
+ };
2031
+ if (selectedAnalytics) {
2032
+ return (React.createElement(React.Fragment, null,
2033
+ React.createElement("div", { style: overlayStyles, onClick: onClose }),
2034
+ React.createElement("div", { style: drawerStyles },
2035
+ React.createElement(AnalyticsReport, { analyticsType: selectedAnalytics, theme: theme, onDirectiveAction: onDirectiveAction, onBack: () => setSelectedAnalytics(null), onClose: onClose }))));
2036
+ }
2037
+ return (React.createElement(React.Fragment, null,
2038
+ React.createElement("div", { style: overlayStyles, onClick: onClose }),
2039
+ React.createElement("div", { style: drawerStyles },
2040
+ React.createElement("div", { style: {
2041
+ padding: theme.spacing.lg,
2042
+ borderBottom: `1px solid ${theme.colors.border}`,
2043
+ display: 'flex',
2044
+ justifyContent: 'space-between',
2045
+ alignItems: 'center',
2046
+ } },
2047
+ React.createElement("h2", { style: {
2048
+ margin: 0,
2049
+ fontSize: theme.fontSizes.xl,
2050
+ color: theme.colors.text,
2051
+ } }, "Analytics"),
2052
+ React.createElement("button", { onClick: onClose, style: {
2053
+ background: 'none',
2054
+ border: 'none',
2055
+ cursor: 'pointer',
2056
+ fontSize: '24px',
2057
+ color: theme.colors.text,
2058
+ padding: 0,
2059
+ } }, CLOSE_ICON_SVG)),
2060
+ React.createElement("div", { style: {
2061
+ flex: 1,
2062
+ overflowY: 'auto',
2063
+ padding: theme.spacing.lg,
2064
+ } }, isLoading ? (React.createElement("div", { style: { textAlign: 'center', color: theme.colors.textSecondary } }, "Loading analytics...")) : configs.length === 0 ? (React.createElement("div", { style: { textAlign: 'center', color: theme.colors.textSecondary } }, "No analytics configured")) : (React.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: theme.spacing.md } }, configs.map((config) => (React.createElement("div", { key: config.configId, onClick: () => config.isEnabled && setSelectedAnalytics(config.analyticsType), style: {
2065
+ padding: theme.spacing.md,
2066
+ backgroundColor: theme.colors.surface,
2067
+ borderRadius: theme.borderRadius,
2068
+ border: `1px solid ${theme.colors.border}`,
2069
+ cursor: config.isEnabled ? 'pointer' : 'not-allowed',
2070
+ opacity: config.isEnabled ? 1 : 0.6,
2071
+ transition: 'transform 0.2s ease',
2072
+ }, onMouseEnter: (e) => {
2073
+ if (config.isEnabled) {
2074
+ e.currentTarget.style.transform = 'translateX(5px)';
2075
+ }
2076
+ }, onMouseLeave: (e) => {
2077
+ e.currentTarget.style.transform = 'translateX(0)';
2078
+ } },
2079
+ React.createElement("div", { style: {
2080
+ display: 'flex',
2081
+ justifyContent: 'space-between',
2082
+ alignItems: 'center',
2083
+ marginBottom: theme.spacing.xs,
2084
+ } },
2085
+ React.createElement("h3", { style: {
2086
+ margin: 0,
2087
+ fontSize: theme.fontSizes.md,
2088
+ color: theme.colors.text,
2089
+ } }, config.analyticsType),
2090
+ React.createElement("span", { style: {
2091
+ fontSize: theme.fontSizes.xs,
2092
+ padding: '2px 8px',
2093
+ borderRadius: '12px',
2094
+ backgroundColor: config.isEnabled
2095
+ ? theme.colors.success
2096
+ : theme.colors.textSecondary,
2097
+ color: '#fff',
2098
+ } }, config.isEnabled ? 'Enabled' : 'Disabled')),
2099
+ React.createElement("p", { style: {
2100
+ margin: 0,
2101
+ fontSize: theme.fontSizes.sm,
2102
+ color: theme.colors.textSecondary,
2103
+ marginBottom: theme.spacing.xs,
2104
+ } }, config.templateDescription),
2105
+ React.createElement("div", { style: {
2106
+ fontSize: theme.fontSizes.xs,
2107
+ color: theme.colors.textSecondary,
2108
+ } },
2109
+ React.createElement("div", null,
2110
+ "Frequency: ",
2111
+ config.frequency),
2112
+ config.lastExecutedAt && (React.createElement("div", null,
2113
+ "Last run: ",
2114
+ new Date(config.lastExecutedAt).toLocaleString()))))))))))));
2115
+ };
2116
+
2117
+ // Analytics Icon SVG
2118
+ const ANALYTICS_ICON_SVG = (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "currentColor" },
2119
+ React.createElement("path", { d: "M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z" })));
2120
+ const AnalyticsWidget = ({ position = 'bottom-right', theme: customTheme, onDirectiveAction, }) => {
2121
+ const { theme: contextTheme } = useReactBridgeContext();
2122
+ const theme = customTheme || contextTheme;
2123
+ const { configs, isLoading } = useAnalyticsConfigs();
2124
+ const [isOpen, setIsOpen] = useState(false);
2125
+ const enabledCount = configs.filter((c) => c.isEnabled).length;
2126
+ const positionStyles = position === 'bottom-right'
2127
+ ? { right: theme.spacing.lg, bottom: theme.spacing.lg }
2128
+ : { left: theme.spacing.lg, bottom: theme.spacing.lg };
2129
+ return (React.createElement(React.Fragment, null,
2130
+ React.createElement("button", { onClick: () => setIsOpen(!isOpen), style: Object.assign(Object.assign({ position: 'fixed' }, positionStyles), { width: '60px', height: '60px', borderRadius: '50%', backgroundColor: theme.colors.primary, color: '#fff', border: 'none', boxShadow: theme.boxShadow, cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '24px', zIndex: 1000, transition: 'transform 0.2s ease' }), onMouseEnter: (e) => {
2131
+ e.currentTarget.style.transform = 'scale(1.1)';
2132
+ }, onMouseLeave: (e) => {
2133
+ e.currentTarget.style.transform = 'scale(1)';
2134
+ } },
2135
+ ANALYTICS_ICON_SVG,
2136
+ !isLoading && enabledCount > 0 && (React.createElement("span", { style: {
2137
+ position: 'absolute',
2138
+ top: '-5px',
2139
+ right: '-5px',
2140
+ backgroundColor: theme.colors.error,
2141
+ color: '#fff',
2142
+ borderRadius: '50%',
2143
+ width: '24px',
2144
+ height: '24px',
2145
+ display: 'flex',
2146
+ alignItems: 'center',
2147
+ justifyContent: 'center',
2148
+ fontSize: '12px',
2149
+ fontWeight: 'bold',
2150
+ } }, enabledCount))),
2151
+ isOpen && (React.createElement(AnalyticsDrawer, { isOpen: isOpen, onClose: () => setIsOpen(false), configs: configs, isLoading: isLoading, theme: theme, onDirectiveAction: onDirectiveAction }))));
2152
+ };
2153
+
2154
+ export { AnalyticsAPI, AnalyticsReport, AnalyticsWidget, DirectivesPanel, MetricsPanel, ObservationsPanel, ReactBridgeAPI, ReactBridgeChatbox, ReactBridgeProvider, ReactBridgeSearch, WebSpeechSTTProvider, WebSpeechTTSProvider, createCustomTheme, darkTheme, getTheme, lightTheme, useAnalyticsConfigs, useAnalyticsResult, useDirectiveAction, useReactBridge, useReactBridgeContext };
1441
2155
  //# sourceMappingURL=index.esm.js.map