@forgeax/app-shell 0.49.0 → 0.51.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.
@@ -0,0 +1,35 @@
1
+ .fx-dock-tab-status-summary {
2
+ display: inline-flex;
3
+ align-items: center;
4
+ gap: 6px;
5
+ flex: 0 0 auto;
6
+ height: 100%;
7
+ font-size: 11px;
8
+ line-height: 1;
9
+ }
10
+
11
+ .fx-dock-tab-status-item {
12
+ display: inline-flex;
13
+ align-items: center;
14
+ gap: 2px;
15
+ height: 100%;
16
+ font-variant-numeric: tabular-nums;
17
+ }
18
+
19
+ .fx-dock-tab-status-icon {
20
+ display: inline-flex;
21
+ align-items: center;
22
+ justify-content: center;
23
+ width: 11px;
24
+ height: 11px;
25
+ font-size: 11px;
26
+ line-height: 11px;
27
+ transform: translateY(1.5px);
28
+ }
29
+
30
+ .fx-dock-tab-status-value {
31
+ display: inline-flex;
32
+ align-items: center;
33
+ height: 11px;
34
+ line-height: 11px;
35
+ }
package/dist/react.d.ts CHANGED
@@ -173,6 +173,24 @@ declare const DockTabFrame: react.ForwardRefExoticComponent<DockTabFrameProps &
173
173
  /** Product-neutral trailing-action wrapper for a Dock tab frame. */
174
174
  declare const DockTabAction: react.ForwardRefExoticComponent<DockTabActionProps & react.RefAttributes<HTMLDivElement>>;
175
175
 
176
+ type DockTabStatusTone = 'neutral' | 'error' | 'warning';
177
+ interface DockTabStatusSummaryItem {
178
+ id: string;
179
+ icon?: ReactNode;
180
+ tone?: DockTabStatusTone;
181
+ value: ReactNode;
182
+ }
183
+ interface DockTabStatusSummaryProps extends HTMLAttributes<HTMLSpanElement> {
184
+ items: readonly DockTabStatusSummaryItem[];
185
+ }
186
+ /**
187
+ * Product-neutral status-count presentation for a Dock tab.
188
+ *
189
+ * The caller owns the status source, labels, visibility policy, and product
190
+ * styling. App Shell only owns stable DOM hooks and item ordering.
191
+ */
192
+ declare const DockTabStatusSummary: react.ForwardRefExoticComponent<DockTabStatusSummaryProps & react.RefAttributes<HTMLSpanElement>>;
193
+
176
194
  type PanelContentPadding = 'none' | 'sm' | 'md';
177
195
  type PanelContentScroll = 'none' | 'auto';
178
196
  type PanelContentTone = 'default' | 'surface' | 'tool';
@@ -314,4 +332,4 @@ interface ShellSlotProps extends HTMLAttributes<HTMLElement> {
314
332
  /** Structural shell marker that preserves the caller's semantic element. */
315
333
  declare function ShellSlot({ as, name, ...props }: ShellSlotProps): ReactElement;
316
334
 
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 };
335
+ 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, DockTabStatusSummary, type DockTabStatusSummaryItem, type DockTabStatusSummaryProps, type DockTabStatusTone, 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
@@ -1486,22 +1486,54 @@ var DockTabAction = forwardRef(
1486
1486
  );
1487
1487
  DockTabAction.displayName = "DockTabAction";
1488
1488
 
1489
- // src/panel.tsx
1489
+ // src/dock-tab-status-summary.tsx
1490
+ import {
1491
+ forwardRef as forwardRef2
1492
+ } from "react";
1490
1493
  import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
1494
+ var DockTabStatusSummary = forwardRef2(function DockTabStatusSummary2({ className, items, ...props }, ref) {
1495
+ return /* @__PURE__ */ jsx4(
1496
+ "span",
1497
+ {
1498
+ ref,
1499
+ className: [
1500
+ "fx-dock-tab-status-summary",
1501
+ className
1502
+ ].filter(Boolean).join(" "),
1503
+ ...props,
1504
+ children: items.map(({ id, icon, tone = "neutral", value }) => /* @__PURE__ */ jsxs2(
1505
+ "span",
1506
+ {
1507
+ className: `fx-dock-tab-status-item fx-dock-tab-status-item--${tone}`,
1508
+ "data-status-id": id,
1509
+ children: [
1510
+ icon !== void 0 && /* @__PURE__ */ jsx4("span", { className: "fx-dock-tab-status-icon", "aria-hidden": true, children: icon }),
1511
+ /* @__PURE__ */ jsx4("span", { className: "fx-dock-tab-status-value", children: value })
1512
+ ]
1513
+ },
1514
+ id
1515
+ ))
1516
+ }
1517
+ );
1518
+ });
1519
+ DockTabStatusSummary.displayName = "DockTabStatusSummary";
1520
+
1521
+ // src/panel.tsx
1522
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1491
1523
  function PanelEmptyState({
1492
1524
  title,
1493
1525
  detail,
1494
1526
  className,
1495
1527
  ...props
1496
1528
  }) {
1497
- return /* @__PURE__ */ jsxs2(
1529
+ return /* @__PURE__ */ jsxs3(
1498
1530
  "div",
1499
1531
  {
1500
1532
  ...props,
1501
1533
  className: className ? `fx-panel-empty ${className}` : "fx-panel-empty",
1502
1534
  children: [
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 })
1535
+ /* @__PURE__ */ jsx5("div", { className: "fx-panel-empty-title", children: title }),
1536
+ detail == null ? null : /* @__PURE__ */ jsx5("div", { className: "fx-panel-empty-detail", children: detail })
1505
1537
  ]
1506
1538
  }
1507
1539
  );
@@ -1516,7 +1548,7 @@ function PanelSurface({
1516
1548
  className,
1517
1549
  ...props
1518
1550
  }) {
1519
- return /* @__PURE__ */ jsxs2(
1551
+ return /* @__PURE__ */ jsxs3(
1520
1552
  "section",
1521
1553
  {
1522
1554
  ...props,
@@ -1527,7 +1559,7 @@ function PanelSurface({
1527
1559
  "data-fx-slot": `DockPanel:${id}`,
1528
1560
  children: [
1529
1561
  header,
1530
- /* @__PURE__ */ jsx4(
1562
+ /* @__PURE__ */ jsx5(
1531
1563
  "div",
1532
1564
  {
1533
1565
  className: "fx-panel-content",
@@ -1561,7 +1593,7 @@ function DetachedPanelBoundary({
1561
1593
  }
1562
1594
 
1563
1595
  // src/detached-surface-frame.tsx
1564
- import { jsx as jsx5 } from "react/jsx-runtime";
1596
+ import { jsx as jsx6 } from "react/jsx-runtime";
1565
1597
  var fill = { position: "fixed", inset: 0 };
1566
1598
  var centeredContent = {
1567
1599
  display: "flex",
@@ -1573,12 +1605,12 @@ function DetachedSurfaceFrame({
1573
1605
  panel = false,
1574
1606
  centered = false
1575
1607
  }) {
1576
- return /* @__PURE__ */ jsx5(
1608
+ return /* @__PURE__ */ jsx6(
1577
1609
  "div",
1578
1610
  {
1579
1611
  className: panel ? "fx-detached-surface fx-detached-panel main-area" : "fx-detached-surface",
1580
1612
  style: fill,
1581
- children: centered ? /* @__PURE__ */ jsx5("div", { className: "fx-detached-surface-status", style: centeredContent, children }) : children
1613
+ children: centered ? /* @__PURE__ */ jsx6("div", { className: "fx-detached-surface-status", style: centeredContent, children }) : children
1582
1614
  }
1583
1615
  );
1584
1616
  }
@@ -1586,25 +1618,25 @@ function DetachedSurfaceStatus({
1586
1618
  children,
1587
1619
  tone = "neutral"
1588
1620
  }) {
1589
- return /* @__PURE__ */ jsx5("span", { className: "fx-detached-surface-status-text", "data-tone": tone, children });
1621
+ return /* @__PURE__ */ jsx6("span", { className: "fx-detached-surface-status-text", "data-tone": tone, children });
1590
1622
  }
1591
1623
 
1592
1624
  // src/surface-placeholder.tsx
1593
- import { jsx as jsx6 } from "react/jsx-runtime";
1625
+ import { jsx as jsx7 } from "react/jsx-runtime";
1594
1626
  function SurfacePlaceholder({
1595
1627
  title,
1596
1628
  className
1597
1629
  }) {
1598
- return /* @__PURE__ */ jsx6("div", { className: className ? `surface-placeholder ${className}` : "surface-placeholder", children: /* @__PURE__ */ jsx6("div", { className: "surface-placeholder-title", children: title }) });
1630
+ return /* @__PURE__ */ jsx7("div", { className: className ? `surface-placeholder ${className}` : "surface-placeholder", children: /* @__PURE__ */ jsx7("div", { className: "surface-placeholder-title", children: title }) });
1599
1631
  }
1600
1632
 
1601
1633
  // src/surface-region.tsx
1602
1634
  import {
1603
- forwardRef as forwardRef2
1635
+ forwardRef as forwardRef3
1604
1636
  } from "react";
1605
- import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
1637
+ import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
1606
1638
  var joinClassNames = (base, modifier) => modifier ? `${base} ${modifier}` : base;
1607
- var SurfaceRegion = forwardRef2(
1639
+ var SurfaceRegion = forwardRef3(
1608
1640
  function SurfaceRegion2({
1609
1641
  children,
1610
1642
  overlay,
@@ -1612,15 +1644,15 @@ var SurfaceRegion = forwardRef2(
1612
1644
  bodyClassName,
1613
1645
  ...props
1614
1646
  }, ref) {
1615
- return /* @__PURE__ */ jsxs3(
1647
+ return /* @__PURE__ */ jsxs4(
1616
1648
  "div",
1617
1649
  {
1618
1650
  ...props,
1619
1651
  ref,
1620
1652
  className: joinClassNames("fx-surface-region", className),
1621
1653
  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 })
1654
+ overlay == null ? null : /* @__PURE__ */ jsx8("div", { className: "fx-surface-region-overlay", children: overlay }),
1655
+ /* @__PURE__ */ jsx8("div", { className: joinClassNames("fx-surface-region-body", bodyClassName), children })
1624
1656
  ]
1625
1657
  }
1626
1658
  );
@@ -1653,7 +1685,7 @@ function useDockLayoutControlBinding({
1653
1685
  // src/floating-menu.tsx
1654
1686
  var import_react_dom = __toESM(require_react_dom(), 1);
1655
1687
  import { useEffect as useEffect5, useLayoutEffect, useRef as useRef3, useState as useState3 } from "react";
1656
- import { Fragment, jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
1688
+ import { Fragment, jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
1657
1689
  var VIEWPORT_PADDING = 8;
1658
1690
  function FloatingMenu({
1659
1691
  open,
@@ -1712,8 +1744,8 @@ function FloatingMenu({
1712
1744
  }, [onClose, open]);
1713
1745
  if (!open) return null;
1714
1746
  return (0, import_react_dom.createPortal)(
1715
- /* @__PURE__ */ jsxs4(Fragment, { children: [
1716
- /* @__PURE__ */ jsx8(
1747
+ /* @__PURE__ */ jsxs5(Fragment, { children: [
1748
+ /* @__PURE__ */ jsx9(
1717
1749
  "div",
1718
1750
  {
1719
1751
  "data-app-shell-floating-menu-backdrop": "",
@@ -1725,7 +1757,7 @@ function FloatingMenu({
1725
1757
  }
1726
1758
  }
1727
1759
  ),
1728
- /* @__PURE__ */ jsx8(
1760
+ /* @__PURE__ */ jsx9(
1729
1761
  "div",
1730
1762
  {
1731
1763
  ref: menuRef,
@@ -1749,7 +1781,7 @@ function FloatingMenu({
1749
1781
  }
1750
1782
 
1751
1783
  // src/dock-layout-menu.tsx
1752
- import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
1784
+ import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
1753
1785
  function DockLayoutMenu({
1754
1786
  state,
1755
1787
  onToggle,
@@ -1770,7 +1802,7 @@ function DockLayoutMenu({
1770
1802
  closePanel,
1771
1803
  reopenPanel
1772
1804
  });
1773
- return /* @__PURE__ */ jsxs5(
1805
+ return /* @__PURE__ */ jsxs6(
1774
1806
  FloatingMenu,
1775
1807
  {
1776
1808
  open: snapshot.open,
@@ -1779,7 +1811,7 @@ function DockLayoutMenu({
1779
1811
  align: "end",
1780
1812
  className: "fx-dl-menu",
1781
1813
  children: [
1782
- /* @__PURE__ */ jsxs5(
1814
+ /* @__PURE__ */ jsxs6(
1783
1815
  "button",
1784
1816
  {
1785
1817
  type: "button",
@@ -1794,16 +1826,16 @@ function DockLayoutMenu({
1794
1826
  }
1795
1827
  },
1796
1828
  children: [
1797
- resetIcon ? /* @__PURE__ */ jsx9("span", { "aria-hidden": "true", children: resetIcon }) : null,
1829
+ resetIcon ? /* @__PURE__ */ jsx10("span", { "aria-hidden": "true", children: resetIcon }) : null,
1798
1830
  resetLabel
1799
1831
  ]
1800
1832
  }
1801
1833
  ),
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) => {
1834
+ /* @__PURE__ */ jsx10("div", { className: "fx-dl-sep", role: "separator" }),
1835
+ /* @__PURE__ */ jsx10("div", { className: "fx-dl-head", children: sectionLabel }),
1836
+ panels.length === 0 ? /* @__PURE__ */ jsx10("div", { className: "fx-dl-head", "data-app-shell-dock-layout-empty": "", children: emptyLabel }) : panels.map((panel) => {
1805
1837
  const isOpen = panelControl.isOpen(panel.id);
1806
- return /* @__PURE__ */ jsxs5(
1838
+ return /* @__PURE__ */ jsxs6(
1807
1839
  "button",
1808
1840
  {
1809
1841
  type: "button",
@@ -1814,8 +1846,8 @@ function DockLayoutMenu({
1814
1846
  panelControl.toggle(panel.id);
1815
1847
  },
1816
1848
  children: [
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,
1849
+ /* @__PURE__ */ jsx10("span", { className: "fx-dl-check", "aria-hidden": "true", children: isOpen ? "\u2713" : "\uFF0B" }),
1850
+ panel.icon ? /* @__PURE__ */ jsx10("span", { className: "fx-dl-icon", "aria-hidden": "true", children: panel.icon }) : null,
1819
1851
  panel.title
1820
1852
  ]
1821
1853
  },
@@ -1843,6 +1875,7 @@ export {
1843
1875
  DockLayoutMenu,
1844
1876
  DockTabAction,
1845
1877
  DockTabFrame,
1878
+ DockTabStatusSummary,
1846
1879
  FloatingMenu,
1847
1880
  PanelEmptyState,
1848
1881
  PanelSurface,
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@forgeax/app-shell",
3
- "version": "0.49.0",
3
+ "version": "0.51.0",
4
4
  "description": "Generic Dock, Panel, Window, and Slot composition primitives",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
7
- "sideEffects": ["./dist/resize.css", "./dist/panel.css", "./dist/detached.css", "./dist/surface.css"],
7
+ "sideEffects": ["./dist/resize.css", "./dist/panel.css", "./dist/detached.css", "./dist/surface.css", "./dist/dock-tab.css"],
8
8
  "files": ["dist"],
9
9
  "main": "./dist/index.js",
10
10
  "types": "./dist/index.d.ts",
@@ -28,12 +28,13 @@
28
28
  "./resize.css": "./dist/resize.css",
29
29
  "./panel.css": "./dist/panel.css",
30
30
  "./detached.css": "./dist/detached.css",
31
- "./surface.css": "./dist/surface.css"
31
+ "./surface.css": "./dist/surface.css",
32
+ "./dock-tab.css": "./dist/dock-tab.css"
32
33
  },
33
34
  "scripts": {
34
35
  "typecheck": "tsc --noEmit",
35
36
  "test": "bun test test",
36
- "build": "tsup src/index.ts src/dock.ts src/window.ts src/react.tsx --format esm --dts --outDir dist && bun run scripts/copy-resize-css.ts && bun run scripts/copy-panel-css.ts && bun run scripts/copy-detached-surface-css.ts && bun run scripts/copy-surface-css.ts",
37
+ "build": "tsup src/index.ts src/dock.ts src/window.ts src/react.tsx --format esm --dts --outDir dist && bun run scripts/copy-resize-css.ts && bun run scripts/copy-panel-css.ts && bun run scripts/copy-detached-surface-css.ts && bun run scripts/copy-surface-css.ts && bun run scripts/copy-dock-tab-css.ts",
37
38
  "check": "bun run typecheck && bun run test && bun run build",
38
39
  "release:preflight": "bun run scripts/release-preflight.ts"
39
40
  },