@forgeax/app-shell 0.47.0 → 0.49.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.
package/dist/react.d.ts CHANGED
@@ -154,6 +154,25 @@ interface LiveTabPlacementSource {
154
154
  /** Observe one tab's live edge/group placement without owning host identities. */
155
155
  declare function useLiveTabPlacement(source: LiveTabPlacementSource): LiveTabPlacement | undefined;
156
156
 
157
+ interface TabPinnedStateSource {
158
+ pinnedIn(groupId: string): string | undefined;
159
+ subscribe(listener: () => void): () => void;
160
+ }
161
+ /** Observe whether one product-supplied panel identity is pinned in a group. */
162
+ declare function useTabPinnedState(source: TabPinnedStateSource, groupId: string, panelId: string): boolean;
163
+
164
+ interface DockTabFrameProps extends HTMLAttributes<HTMLDivElement> {
165
+ /** Caller-owned leading presentation, such as a product icon. */
166
+ leading?: ReactNode;
167
+ /** Caller-owned trailing action; App Shell only fixes its slot position. */
168
+ action?: ReactNode;
169
+ }
170
+ type DockTabActionProps = HTMLAttributes<HTMLDivElement>;
171
+ /** Product-neutral Dock tab frame with stable Dockview-compatible DOM hooks. */
172
+ declare const DockTabFrame: react.ForwardRefExoticComponent<DockTabFrameProps & react.RefAttributes<HTMLDivElement>>;
173
+ /** Product-neutral trailing-action wrapper for a Dock tab frame. */
174
+ declare const DockTabAction: react.ForwardRefExoticComponent<DockTabActionProps & react.RefAttributes<HTMLDivElement>>;
175
+
157
176
  type PanelContentPadding = 'none' | 'sm' | 'md';
158
177
  type PanelContentScroll = 'none' | 'auto';
159
178
  type PanelContentTone = 'default' | 'surface' | 'tool';
@@ -295,4 +314,4 @@ interface ShellSlotProps extends HTMLAttributes<HTMLElement> {
295
314
  /** Structural shell marker that preserves the caller's semantic element. */
296
315
  declare function ShellSlot({ as, name, ...props }: ShellSlotProps): ReactElement;
297
316
 
298
- export { type AnchoredResizeDirection, AnchoredResizeHandle, type AnchoredResizeHandleProps, type AnchoredResizeSession, DetachedPanelBoundary, type DetachedPanelBoundaryProps, DetachedSurfaceFrame, type DetachedSurfaceFrameProps, DetachedSurfaceStatus, type DetachedSurfaceStatusProps, type DetachedSurfaceStatusTone, type DockLayoutControlBinding, type DockLayoutControlBindingOptions, DockLayoutMenu, type DockLayoutMenuPanel, type DockLayoutMenuProps, FloatingMenu, type FloatingMenuAnchor, type FloatingMenuPoint, type FloatingMenuProps, type LiveTabPlacement, type LiveTabPlacementSource, type LiveTabTitleSource, type PanelContentPadding, type PanelContentPolicy, type PanelContentScroll, type PanelContentTone, PanelEmptyState, type PanelEmptyStateProps, PanelSurface, type PanelSurfaceProps, type PersistentSizeStorage, type PersistentSizeStore, type PersistentSizeStoreOptions, type PersistentSizeUpdate, type PointerDragFinishReason, type PointerDragSessionOptions, type PointerReorderFinishReason, type PointerReorderSession, type PointerReorderSessionOptions, ResizeHandle, type ResizeHandleProps, ShellSlot, type ShellSlotElement, type ShellSlotProps, SlotDebugOverlay, SurfacePlaceholder, type SurfacePlaceholderProps, SurfaceRegion, type SurfaceRegionProps, type TabCloseInteractions, type TabCloseInteractionsOptions, type ThresholdPointerDragFinishReason, type ThresholdPointerDragSession, type ThresholdPointerDragSessionOptions, applyAnchoredResizeDelta, beginAnchoredResize, createPersistentSizeStore, hashSlotHue, installPointerDragSession, installPointerReorderSession, installThresholdPointerDragSession, isSlotDebugEnabled, useDockLayoutControlBinding, useLiveTabPlacement, useLiveTabTitle, useLocalSize, usePersistentSizeStore, useTabCloseInteractions };
317
+ export { type AnchoredResizeDirection, AnchoredResizeHandle, type AnchoredResizeHandleProps, type AnchoredResizeSession, DetachedPanelBoundary, type DetachedPanelBoundaryProps, DetachedSurfaceFrame, type DetachedSurfaceFrameProps, DetachedSurfaceStatus, type DetachedSurfaceStatusProps, type DetachedSurfaceStatusTone, type DockLayoutControlBinding, type DockLayoutControlBindingOptions, DockLayoutMenu, type DockLayoutMenuPanel, type DockLayoutMenuProps, DockTabAction, type DockTabActionProps, DockTabFrame, type DockTabFrameProps, FloatingMenu, type FloatingMenuAnchor, type FloatingMenuPoint, type FloatingMenuProps, type LiveTabPlacement, type LiveTabPlacementSource, type LiveTabTitleSource, type PanelContentPadding, type PanelContentPolicy, type PanelContentScroll, type PanelContentTone, PanelEmptyState, type PanelEmptyStateProps, PanelSurface, type PanelSurfaceProps, type PersistentSizeStorage, type PersistentSizeStore, type PersistentSizeStoreOptions, type PersistentSizeUpdate, type PointerDragFinishReason, type PointerDragSessionOptions, type PointerReorderFinishReason, type PointerReorderSession, type PointerReorderSessionOptions, ResizeHandle, type ResizeHandleProps, ShellSlot, type ShellSlotElement, type ShellSlotProps, SlotDebugOverlay, SurfacePlaceholder, type SurfacePlaceholderProps, SurfaceRegion, type SurfaceRegionProps, type TabCloseInteractions, type TabCloseInteractionsOptions, type TabPinnedStateSource, type ThresholdPointerDragFinishReason, type ThresholdPointerDragSession, type ThresholdPointerDragSessionOptions, applyAnchoredResizeDelta, beginAnchoredResize, createPersistentSizeStore, hashSlotHue, installPointerDragSession, installPointerReorderSession, installThresholdPointerDragSession, isSlotDebugEnabled, useDockLayoutControlBinding, useLiveTabPlacement, useLiveTabTitle, useLocalSize, usePersistentSizeStore, useTabCloseInteractions, useTabPinnedState };
package/dist/react.js CHANGED
@@ -1372,22 +1372,136 @@ function useLiveTabPlacement(source) {
1372
1372
  );
1373
1373
  }
1374
1374
 
1375
- // src/panel.tsx
1375
+ // src/tab-pinned-state.tsx
1376
+ import { useMemo as useMemo3, useSyncExternalStore as useSyncExternalStore4 } from "react";
1377
+ function stabilizeTabPinnedStateSource(source, groupId, panelId) {
1378
+ let snapshot = false;
1379
+ try {
1380
+ snapshot = source.pinnedIn(groupId) === panelId;
1381
+ } catch {
1382
+ }
1383
+ const synchronize = () => {
1384
+ let next;
1385
+ try {
1386
+ next = source.pinnedIn(groupId) === panelId;
1387
+ } catch {
1388
+ return false;
1389
+ }
1390
+ if (next === snapshot) return false;
1391
+ snapshot = next;
1392
+ return true;
1393
+ };
1394
+ return {
1395
+ getSnapshot: () => {
1396
+ synchronize();
1397
+ return snapshot;
1398
+ },
1399
+ subscribe: (listener) => {
1400
+ let active = true;
1401
+ const notify = () => {
1402
+ if (!active || !synchronize()) return;
1403
+ try {
1404
+ listener();
1405
+ } catch {
1406
+ }
1407
+ };
1408
+ let dispose = () => {
1409
+ };
1410
+ try {
1411
+ dispose = source.subscribe(notify);
1412
+ } catch {
1413
+ notify();
1414
+ return () => {
1415
+ if (!active) return;
1416
+ active = false;
1417
+ };
1418
+ }
1419
+ notify();
1420
+ return () => {
1421
+ if (!active) return;
1422
+ active = false;
1423
+ try {
1424
+ dispose();
1425
+ } catch {
1426
+ }
1427
+ };
1428
+ }
1429
+ };
1430
+ }
1431
+ function useTabPinnedState(source, groupId, panelId) {
1432
+ const stable = useMemo3(
1433
+ () => stabilizeTabPinnedStateSource(source, groupId, panelId),
1434
+ [source, groupId, panelId]
1435
+ );
1436
+ return useSyncExternalStore4(
1437
+ stable.subscribe,
1438
+ stable.getSnapshot,
1439
+ stable.getSnapshot
1440
+ );
1441
+ }
1442
+
1443
+ // src/dock-tab-frame.tsx
1444
+ import {
1445
+ forwardRef
1446
+ } from "react";
1376
1447
  import { jsx as jsx3, jsxs } from "react/jsx-runtime";
1448
+ function joinClassName(owned, caller) {
1449
+ return caller ? `${owned} ${caller}` : owned;
1450
+ }
1451
+ var DockTabFrame = forwardRef(
1452
+ function DockTabFrame2({
1453
+ leading,
1454
+ action,
1455
+ children,
1456
+ className,
1457
+ ...props
1458
+ }, ref) {
1459
+ return /* @__PURE__ */ jsxs(
1460
+ "div",
1461
+ {
1462
+ ...props,
1463
+ ref,
1464
+ className: joinClassName("dv-default-tab", className),
1465
+ children: [
1466
+ leading,
1467
+ /* @__PURE__ */ jsx3("span", { className: "dv-default-tab-content", children }),
1468
+ action
1469
+ ]
1470
+ }
1471
+ );
1472
+ }
1473
+ );
1474
+ DockTabFrame.displayName = "DockTabFrame";
1475
+ var DockTabAction = forwardRef(
1476
+ function DockTabAction2({ className, ...props }, ref) {
1477
+ return /* @__PURE__ */ jsx3(
1478
+ "div",
1479
+ {
1480
+ ...props,
1481
+ ref,
1482
+ className: joinClassName("dv-default-tab-action", className)
1483
+ }
1484
+ );
1485
+ }
1486
+ );
1487
+ DockTabAction.displayName = "DockTabAction";
1488
+
1489
+ // src/panel.tsx
1490
+ import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
1377
1491
  function PanelEmptyState({
1378
1492
  title,
1379
1493
  detail,
1380
1494
  className,
1381
1495
  ...props
1382
1496
  }) {
1383
- return /* @__PURE__ */ jsxs(
1497
+ return /* @__PURE__ */ jsxs2(
1384
1498
  "div",
1385
1499
  {
1386
1500
  ...props,
1387
1501
  className: className ? `fx-panel-empty ${className}` : "fx-panel-empty",
1388
1502
  children: [
1389
- /* @__PURE__ */ jsx3("div", { className: "fx-panel-empty-title", children: title }),
1390
- detail == null ? null : /* @__PURE__ */ jsx3("div", { className: "fx-panel-empty-detail", children: detail })
1503
+ /* @__PURE__ */ jsx4("div", { className: "fx-panel-empty-title", children: title }),
1504
+ detail == null ? null : /* @__PURE__ */ jsx4("div", { className: "fx-panel-empty-detail", children: detail })
1391
1505
  ]
1392
1506
  }
1393
1507
  );
@@ -1402,7 +1516,7 @@ function PanelSurface({
1402
1516
  className,
1403
1517
  ...props
1404
1518
  }) {
1405
- return /* @__PURE__ */ jsxs(
1519
+ return /* @__PURE__ */ jsxs2(
1406
1520
  "section",
1407
1521
  {
1408
1522
  ...props,
@@ -1413,7 +1527,7 @@ function PanelSurface({
1413
1527
  "data-fx-slot": `DockPanel:${id}`,
1414
1528
  children: [
1415
1529
  header,
1416
- /* @__PURE__ */ jsx3(
1530
+ /* @__PURE__ */ jsx4(
1417
1531
  "div",
1418
1532
  {
1419
1533
  className: "fx-panel-content",
@@ -1447,7 +1561,7 @@ function DetachedPanelBoundary({
1447
1561
  }
1448
1562
 
1449
1563
  // src/detached-surface-frame.tsx
1450
- import { jsx as jsx4 } from "react/jsx-runtime";
1564
+ import { jsx as jsx5 } from "react/jsx-runtime";
1451
1565
  var fill = { position: "fixed", inset: 0 };
1452
1566
  var centeredContent = {
1453
1567
  display: "flex",
@@ -1459,12 +1573,12 @@ function DetachedSurfaceFrame({
1459
1573
  panel = false,
1460
1574
  centered = false
1461
1575
  }) {
1462
- return /* @__PURE__ */ jsx4(
1576
+ return /* @__PURE__ */ jsx5(
1463
1577
  "div",
1464
1578
  {
1465
1579
  className: panel ? "fx-detached-surface fx-detached-panel main-area" : "fx-detached-surface",
1466
1580
  style: fill,
1467
- children: centered ? /* @__PURE__ */ jsx4("div", { className: "fx-detached-surface-status", style: centeredContent, children }) : children
1581
+ children: centered ? /* @__PURE__ */ jsx5("div", { className: "fx-detached-surface-status", style: centeredContent, children }) : children
1468
1582
  }
1469
1583
  );
1470
1584
  }
@@ -1472,25 +1586,25 @@ function DetachedSurfaceStatus({
1472
1586
  children,
1473
1587
  tone = "neutral"
1474
1588
  }) {
1475
- return /* @__PURE__ */ jsx4("span", { className: "fx-detached-surface-status-text", "data-tone": tone, children });
1589
+ return /* @__PURE__ */ jsx5("span", { className: "fx-detached-surface-status-text", "data-tone": tone, children });
1476
1590
  }
1477
1591
 
1478
1592
  // src/surface-placeholder.tsx
1479
- import { jsx as jsx5 } from "react/jsx-runtime";
1593
+ import { jsx as jsx6 } from "react/jsx-runtime";
1480
1594
  function SurfacePlaceholder({
1481
1595
  title,
1482
1596
  className
1483
1597
  }) {
1484
- return /* @__PURE__ */ jsx5("div", { className: className ? `surface-placeholder ${className}` : "surface-placeholder", children: /* @__PURE__ */ jsx5("div", { className: "surface-placeholder-title", children: title }) });
1598
+ return /* @__PURE__ */ jsx6("div", { className: className ? `surface-placeholder ${className}` : "surface-placeholder", children: /* @__PURE__ */ jsx6("div", { className: "surface-placeholder-title", children: title }) });
1485
1599
  }
1486
1600
 
1487
1601
  // src/surface-region.tsx
1488
1602
  import {
1489
- forwardRef
1603
+ forwardRef as forwardRef2
1490
1604
  } from "react";
1491
- import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
1605
+ import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
1492
1606
  var joinClassNames = (base, modifier) => modifier ? `${base} ${modifier}` : base;
1493
- var SurfaceRegion = forwardRef(
1607
+ var SurfaceRegion = forwardRef2(
1494
1608
  function SurfaceRegion2({
1495
1609
  children,
1496
1610
  overlay,
@@ -1498,15 +1612,15 @@ var SurfaceRegion = forwardRef(
1498
1612
  bodyClassName,
1499
1613
  ...props
1500
1614
  }, ref) {
1501
- return /* @__PURE__ */ jsxs2(
1615
+ return /* @__PURE__ */ jsxs3(
1502
1616
  "div",
1503
1617
  {
1504
1618
  ...props,
1505
1619
  ref,
1506
1620
  className: joinClassNames("fx-surface-region", className),
1507
1621
  children: [
1508
- overlay == null ? null : /* @__PURE__ */ jsx6("div", { className: "fx-surface-region-overlay", children: overlay }),
1509
- /* @__PURE__ */ jsx6("div", { className: joinClassNames("fx-surface-region-body", bodyClassName), children })
1622
+ overlay == null ? null : /* @__PURE__ */ jsx7("div", { className: "fx-surface-region-overlay", children: overlay }),
1623
+ /* @__PURE__ */ jsx7("div", { className: joinClassNames("fx-surface-region-body", bodyClassName), children })
1510
1624
  ]
1511
1625
  }
1512
1626
  );
@@ -1514,7 +1628,7 @@ var SurfaceRegion = forwardRef(
1514
1628
  );
1515
1629
 
1516
1630
  // src/dock-layout-control.ts
1517
- import { useEffect as useEffect4, useMemo as useMemo3, useSyncExternalStore as useSyncExternalStore4 } from "react";
1631
+ import { useEffect as useEffect4, useMemo as useMemo4, useSyncExternalStore as useSyncExternalStore5 } from "react";
1518
1632
  function useDockLayoutControlBinding({
1519
1633
  state,
1520
1634
  onToggle,
@@ -1522,24 +1636,24 @@ function useDockLayoutControlBinding({
1522
1636
  closePanel,
1523
1637
  reopenPanel
1524
1638
  }) {
1525
- const snapshot = useSyncExternalStore4(
1639
+ const snapshot = useSyncExternalStore5(
1526
1640
  state.subscribe,
1527
1641
  state.getSnapshot,
1528
1642
  state.getSnapshot
1529
1643
  );
1530
1644
  useEffect4(() => installDockLayoutControlToggle({ onToggle }, state), [onToggle, state]);
1531
- const panelControl = useMemo3(() => createDockLayoutPanelControl({
1645
+ const panelControl = useMemo4(() => createDockLayoutPanelControl({
1532
1646
  isOpen: isPanelOpen,
1533
1647
  close: closePanel,
1534
1648
  reopen: reopenPanel
1535
1649
  }), [closePanel, isPanelOpen, reopenPanel]);
1536
- return useMemo3(() => ({ snapshot, panelControl }), [panelControl, snapshot]);
1650
+ return useMemo4(() => ({ snapshot, panelControl }), [panelControl, snapshot]);
1537
1651
  }
1538
1652
 
1539
1653
  // src/floating-menu.tsx
1540
1654
  var import_react_dom = __toESM(require_react_dom(), 1);
1541
1655
  import { useEffect as useEffect5, useLayoutEffect, useRef as useRef3, useState as useState3 } from "react";
1542
- import { Fragment, jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
1656
+ import { Fragment, jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
1543
1657
  var VIEWPORT_PADDING = 8;
1544
1658
  function FloatingMenu({
1545
1659
  open,
@@ -1598,8 +1712,8 @@ function FloatingMenu({
1598
1712
  }, [onClose, open]);
1599
1713
  if (!open) return null;
1600
1714
  return (0, import_react_dom.createPortal)(
1601
- /* @__PURE__ */ jsxs3(Fragment, { children: [
1602
- /* @__PURE__ */ jsx7(
1715
+ /* @__PURE__ */ jsxs4(Fragment, { children: [
1716
+ /* @__PURE__ */ jsx8(
1603
1717
  "div",
1604
1718
  {
1605
1719
  "data-app-shell-floating-menu-backdrop": "",
@@ -1611,7 +1725,7 @@ function FloatingMenu({
1611
1725
  }
1612
1726
  }
1613
1727
  ),
1614
- /* @__PURE__ */ jsx7(
1728
+ /* @__PURE__ */ jsx8(
1615
1729
  "div",
1616
1730
  {
1617
1731
  ref: menuRef,
@@ -1635,7 +1749,7 @@ function FloatingMenu({
1635
1749
  }
1636
1750
 
1637
1751
  // src/dock-layout-menu.tsx
1638
- import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
1752
+ import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
1639
1753
  function DockLayoutMenu({
1640
1754
  state,
1641
1755
  onToggle,
@@ -1656,7 +1770,7 @@ function DockLayoutMenu({
1656
1770
  closePanel,
1657
1771
  reopenPanel
1658
1772
  });
1659
- return /* @__PURE__ */ jsxs4(
1773
+ return /* @__PURE__ */ jsxs5(
1660
1774
  FloatingMenu,
1661
1775
  {
1662
1776
  open: snapshot.open,
@@ -1665,7 +1779,7 @@ function DockLayoutMenu({
1665
1779
  align: "end",
1666
1780
  className: "fx-dl-menu",
1667
1781
  children: [
1668
- /* @__PURE__ */ jsxs4(
1782
+ /* @__PURE__ */ jsxs5(
1669
1783
  "button",
1670
1784
  {
1671
1785
  type: "button",
@@ -1680,16 +1794,16 @@ function DockLayoutMenu({
1680
1794
  }
1681
1795
  },
1682
1796
  children: [
1683
- resetIcon ? /* @__PURE__ */ jsx8("span", { "aria-hidden": "true", children: resetIcon }) : null,
1797
+ resetIcon ? /* @__PURE__ */ jsx9("span", { "aria-hidden": "true", children: resetIcon }) : null,
1684
1798
  resetLabel
1685
1799
  ]
1686
1800
  }
1687
1801
  ),
1688
- /* @__PURE__ */ jsx8("div", { className: "fx-dl-sep", role: "separator" }),
1689
- /* @__PURE__ */ jsx8("div", { className: "fx-dl-head", children: sectionLabel }),
1690
- panels.length === 0 ? /* @__PURE__ */ jsx8("div", { className: "fx-dl-head", "data-app-shell-dock-layout-empty": "", children: emptyLabel }) : panels.map((panel) => {
1802
+ /* @__PURE__ */ jsx9("div", { className: "fx-dl-sep", role: "separator" }),
1803
+ /* @__PURE__ */ jsx9("div", { className: "fx-dl-head", children: sectionLabel }),
1804
+ panels.length === 0 ? /* @__PURE__ */ jsx9("div", { className: "fx-dl-head", "data-app-shell-dock-layout-empty": "", children: emptyLabel }) : panels.map((panel) => {
1691
1805
  const isOpen = panelControl.isOpen(panel.id);
1692
- return /* @__PURE__ */ jsxs4(
1806
+ return /* @__PURE__ */ jsxs5(
1693
1807
  "button",
1694
1808
  {
1695
1809
  type: "button",
@@ -1700,8 +1814,8 @@ function DockLayoutMenu({
1700
1814
  panelControl.toggle(panel.id);
1701
1815
  },
1702
1816
  children: [
1703
- /* @__PURE__ */ jsx8("span", { className: "fx-dl-check", "aria-hidden": "true", children: isOpen ? "\u2713" : "\uFF0B" }),
1704
- panel.icon ? /* @__PURE__ */ jsx8("span", { className: "fx-dl-icon", "aria-hidden": "true", children: panel.icon }) : null,
1817
+ /* @__PURE__ */ jsx9("span", { className: "fx-dl-check", "aria-hidden": "true", children: isOpen ? "\u2713" : "\uFF0B" }),
1818
+ panel.icon ? /* @__PURE__ */ jsx9("span", { className: "fx-dl-icon", "aria-hidden": "true", children: panel.icon }) : null,
1705
1819
  panel.title
1706
1820
  ]
1707
1821
  },
@@ -1727,6 +1841,8 @@ export {
1727
1841
  DetachedSurfaceFrame,
1728
1842
  DetachedSurfaceStatus,
1729
1843
  DockLayoutMenu,
1844
+ DockTabAction,
1845
+ DockTabFrame,
1730
1846
  FloatingMenu,
1731
1847
  PanelEmptyState,
1732
1848
  PanelSurface,
@@ -1748,7 +1864,8 @@ export {
1748
1864
  useLiveTabTitle,
1749
1865
  useLocalSize,
1750
1866
  usePersistentSizeStore,
1751
- useTabCloseInteractions
1867
+ useTabCloseInteractions,
1868
+ useTabPinnedState
1752
1869
  };
1753
1870
  /*! Bundled license information:
1754
1871
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forgeax/app-shell",
3
- "version": "0.47.0",
3
+ "version": "0.49.0",
4
4
  "description": "Generic Dock, Panel, Window, and Slot composition primitives",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",