@lobehub/ui 5.58.0 → 5.60.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 (135) hide show
  1. package/es/ActionIcon/style.mjs +8 -2
  2. package/es/ActionIcon/style.mjs.map +1 -1
  3. package/es/Grid/style.mjs +8 -8
  4. package/es/Grid/style.mjs.map +1 -1
  5. package/es/awesome/Grainient/Grainient.d.mts +11 -0
  6. package/es/awesome/Grainient/Grainient.mjs +311 -0
  7. package/es/awesome/Grainient/Grainient.mjs.map +1 -0
  8. package/es/awesome/Grainient/index.d.mts +3 -0
  9. package/es/awesome/Grainient/style.mjs +25 -0
  10. package/es/awesome/Grainient/style.mjs.map +1 -0
  11. package/es/awesome/Grainient/type.d.mts +122 -0
  12. package/es/awesome/index.d.mts +4 -1
  13. package/es/awesome/index.mjs +2 -1
  14. package/es/base-ui/ActionIcon/style.mjs +8 -2
  15. package/es/base-ui/ActionIcon/style.mjs.map +1 -1
  16. package/es/base-ui/Input/style.mjs +8 -2
  17. package/es/base-ui/Input/style.mjs.map +1 -1
  18. package/es/dashboard/AuthLayout/Aside.d.mts +10 -0
  19. package/es/dashboard/AuthLayout/Aside.mjs +30 -0
  20. package/es/dashboard/AuthLayout/Aside.mjs.map +1 -0
  21. package/es/dashboard/AuthLayout/AuthLayout.d.mts +3 -1
  22. package/es/dashboard/AuthLayout/AuthLayout.mjs +93 -37
  23. package/es/dashboard/AuthLayout/AuthLayout.mjs.map +1 -1
  24. package/es/dashboard/AuthLayout/index.d.mts +3 -2
  25. package/es/dashboard/AuthLayout/style.mjs +120 -1
  26. package/es/dashboard/AuthLayout/style.mjs.map +1 -1
  27. package/es/dashboard/AuthLayout/type.d.mts +39 -3
  28. package/es/dashboard/AuthTools/AuthLocaleSwitch.d.mts +10 -0
  29. package/es/dashboard/AuthTools/AuthLocaleSwitch.mjs +32 -0
  30. package/es/dashboard/AuthTools/AuthLocaleSwitch.mjs.map +1 -0
  31. package/es/dashboard/AuthTools/AuthThemeSwitch.d.mts +10 -0
  32. package/es/dashboard/AuthTools/AuthThemeSwitch.mjs +59 -0
  33. package/es/dashboard/AuthTools/AuthThemeSwitch.mjs.map +1 -0
  34. package/es/dashboard/AuthTools/index.d.mts +4 -0
  35. package/es/dashboard/AuthTools/style.mjs +63 -0
  36. package/es/dashboard/AuthTools/style.mjs.map +1 -0
  37. package/es/dashboard/AuthTools/type.d.mts +30 -0
  38. package/es/dashboard/ChartGrid/ChartGrid.d.mts +10 -0
  39. package/es/dashboard/ChartGrid/ChartGrid.mjs +18 -0
  40. package/es/dashboard/ChartGrid/ChartGrid.mjs.map +1 -0
  41. package/es/dashboard/ChartGrid/index.d.mts +3 -0
  42. package/es/dashboard/ChartGrid/style.mjs +32 -0
  43. package/es/dashboard/ChartGrid/style.mjs.map +1 -0
  44. package/es/dashboard/ChartGrid/type.d.mts +9 -0
  45. package/es/dashboard/ConsoleNav/Skeleton.d.mts +15 -0
  46. package/es/dashboard/ConsoleNav/Skeleton.mjs +81 -0
  47. package/es/dashboard/ConsoleNav/Skeleton.mjs.map +1 -0
  48. package/es/dashboard/ConsoleNav/index.d.mts +3 -2
  49. package/es/dashboard/ConsoleNav/style.mjs +15 -0
  50. package/es/dashboard/ConsoleNav/style.mjs.map +1 -1
  51. package/es/dashboard/ConsoleNav/type.d.mts +14 -1
  52. package/es/dashboard/ConsoleShell/ConsoleShell.d.mts +1 -1
  53. package/es/dashboard/ConsoleShell/ConsoleShell.mjs +22 -6
  54. package/es/dashboard/ConsoleShell/ConsoleShell.mjs.map +1 -1
  55. package/es/dashboard/ConsoleShell/style.mjs +21 -0
  56. package/es/dashboard/ConsoleShell/style.mjs.map +1 -1
  57. package/es/dashboard/ConsoleShell/type.d.mts +11 -0
  58. package/es/dashboard/FilterSidebar/FilterSidebar.mjs +18 -17
  59. package/es/dashboard/FilterSidebar/FilterSidebar.mjs.map +1 -1
  60. package/es/dashboard/FilterStrip/FilterStrip.d.mts +11 -0
  61. package/es/dashboard/FilterStrip/FilterStrip.mjs +55 -0
  62. package/es/dashboard/FilterStrip/FilterStrip.mjs.map +1 -0
  63. package/es/dashboard/FilterStrip/index.d.mts +3 -0
  64. package/es/dashboard/FilterStrip/style.mjs +94 -0
  65. package/es/dashboard/FilterStrip/style.mjs.map +1 -0
  66. package/es/dashboard/FilterStrip/type.d.mts +26 -0
  67. package/es/dashboard/LabelWithKey/LabelWithKey.d.mts +10 -0
  68. package/es/dashboard/LabelWithKey/LabelWithKey.mjs +18 -0
  69. package/es/dashboard/LabelWithKey/LabelWithKey.mjs.map +1 -0
  70. package/es/dashboard/LabelWithKey/index.d.mts +3 -0
  71. package/es/dashboard/LabelWithKey/type.d.mts +12 -0
  72. package/es/dashboard/MetricStrip/MetricCell.mjs +81 -0
  73. package/es/dashboard/MetricStrip/MetricCell.mjs.map +1 -0
  74. package/es/dashboard/MetricStrip/MetricStrip.d.mts +13 -0
  75. package/es/dashboard/MetricStrip/MetricStrip.mjs +47 -0
  76. package/es/dashboard/MetricStrip/MetricStrip.mjs.map +1 -0
  77. package/es/dashboard/MetricStrip/index.d.mts +3 -0
  78. package/es/dashboard/MetricStrip/style.mjs +161 -0
  79. package/es/dashboard/MetricStrip/style.mjs.map +1 -0
  80. package/es/dashboard/MetricStrip/type.d.mts +37 -0
  81. package/es/dashboard/PageSkeleton/PageSkeleton.mjs +20 -18
  82. package/es/dashboard/PageSkeleton/PageSkeleton.mjs.map +1 -1
  83. package/es/dashboard/PageSkeleton/style.mjs +1 -1
  84. package/es/dashboard/PageSkeleton/style.mjs.map +1 -1
  85. package/es/dashboard/PageToolbar/PageToolbar.d.mts +10 -0
  86. package/es/dashboard/PageToolbar/PageToolbar.mjs +21 -0
  87. package/es/dashboard/PageToolbar/PageToolbar.mjs.map +1 -0
  88. package/es/dashboard/PageToolbar/index.d.mts +3 -0
  89. package/es/dashboard/PageToolbar/style.mjs +34 -0
  90. package/es/dashboard/PageToolbar/style.mjs.map +1 -0
  91. package/es/dashboard/PageToolbar/type.d.mts +12 -0
  92. package/es/dashboard/PanelSurface/PanelSurface.d.mts +10 -0
  93. package/es/dashboard/PanelSurface/PanelSurface.mjs +39 -0
  94. package/es/dashboard/PanelSurface/PanelSurface.mjs.map +1 -0
  95. package/es/dashboard/PanelSurface/index.d.mts +3 -0
  96. package/es/dashboard/PanelSurface/style.mjs +24 -0
  97. package/es/dashboard/PanelSurface/style.mjs.map +1 -0
  98. package/es/dashboard/PanelSurface/type.d.mts +18 -0
  99. package/es/dashboard/Section/Section.d.mts +10 -0
  100. package/es/dashboard/Section/Section.mjs +81 -0
  101. package/es/dashboard/Section/Section.mjs.map +1 -0
  102. package/es/dashboard/Section/index.d.mts +3 -0
  103. package/es/dashboard/Section/style.mjs +35 -0
  104. package/es/dashboard/Section/style.mjs.map +1 -0
  105. package/es/dashboard/Section/type.d.mts +24 -0
  106. package/es/dashboard/StatCard/StatCard.d.mts +2 -1
  107. package/es/dashboard/StatCard/StatCard.mjs +24 -72
  108. package/es/dashboard/StatCard/StatCard.mjs.map +1 -1
  109. package/es/dashboard/StatCard/type.d.mts +16 -5
  110. package/es/dashboard/Surface/Surface.d.mts +4 -3
  111. package/es/dashboard/Surface/Surface.mjs +83 -7
  112. package/es/dashboard/Surface/Surface.mjs.map +1 -1
  113. package/es/dashboard/Surface/index.d.mts +3 -2
  114. package/es/dashboard/Surface/link.d.mts +19 -0
  115. package/es/dashboard/Surface/link.mjs +33 -0
  116. package/es/dashboard/Surface/link.mjs.map +1 -0
  117. package/es/dashboard/Surface/style.d.mts +45 -3
  118. package/es/dashboard/Surface/style.mjs +358 -8
  119. package/es/dashboard/Surface/style.mjs.map +1 -1
  120. package/es/dashboard/Surface/type.d.mts +30 -2
  121. package/es/dashboard/TableIconActions/TableIconActions.d.mts +17 -0
  122. package/es/dashboard/TableIconActions/TableIconActions.mjs +39 -0
  123. package/es/dashboard/TableIconActions/TableIconActions.mjs.map +1 -0
  124. package/es/dashboard/TableIconActions/index.d.mts +3 -0
  125. package/es/dashboard/TableIconActions/type.d.mts +18 -0
  126. package/es/dashboard/TitleWithTips/TitleWithTips.d.mts +10 -0
  127. package/es/dashboard/TitleWithTips/TitleWithTips.mjs +28 -0
  128. package/es/dashboard/TitleWithTips/TitleWithTips.mjs.map +1 -0
  129. package/es/dashboard/TitleWithTips/index.d.mts +3 -0
  130. package/es/dashboard/TitleWithTips/type.d.mts +11 -0
  131. package/es/dashboard/index.d.mts +38 -4
  132. package/es/dashboard/index.mjs +17 -3
  133. package/package.json +1 -1
  134. package/es/dashboard/StatCard/style.mjs +0 -135
  135. package/es/dashboard/StatCard/style.mjs.map +0 -1
@@ -23,6 +23,11 @@ const styles = createStaticStyles(({ css, cssVar, responsive }) => ({
23
23
  ${responsive.laptop} {
24
24
  margin-block-start: 0;
25
25
  }
26
+ `,
27
+ /** Close button in the drawer's brand row: right edge, vertically centred with the brand. */
28
+ brandClose: css`
29
+ flex: none;
30
+ margin-inline: auto -7px;
26
31
  `,
27
32
  brandAnchor: css`
28
33
  display: flex;
@@ -87,6 +92,16 @@ const styles = createStaticStyles(({ css, cssVar, responsive }) => ({
87
92
  gap: 16px;
88
93
  padding: 16px;
89
94
  }
95
+ `,
96
+ /**
97
+ * The drawer body is the scroll container. Without its default padding the scrollbar sits on
98
+ * the panel edge; the brand row, nav and footer keep their own insets.
99
+ */
100
+ drawerBody: css`
101
+ && {
102
+ min-block-size: 100%;
103
+ padding: 0;
104
+ }
90
105
  `,
91
106
  navSlot: css`
92
107
  display: flex;
@@ -182,6 +197,12 @@ const styles = createStaticStyles(({ css, cssVar, responsive }) => ({
182
197
  align-items: center;
183
198
 
184
199
  margin-inline-start: auto;
200
+ `,
201
+ /** Light only: the content area sits midway between the layout canvas and container white. */
202
+ workspaceLight: css`
203
+ && {
204
+ background: color-mix(in srgb, ${cssVar.colorBgLayout} 50%, ${cssVar.colorBgContainer});
205
+ }
185
206
  `,
186
207
  workspace: css`
187
208
  overflow: hidden;
@@ -1 +1 @@
1
- {"version":3,"file":"style.mjs","names":[],"sources":["../../../src/dashboard/ConsoleShell/style.ts"],"sourcesContent":["import { createStaticStyles } from 'antd-style';\n\nconst SIDEBAR_INLINE_SIZE = 248;\n// Twice the nav icon inset (8px nav padding + 10px item padding) plus the 18px icon, so the icons\n// land centered on the rail without moving sideways.\nconst SIDEBAR_RAIL_INLINE_SIZE = 54;\nconst WORKSPACE_INSET = 8;\n\n/**\n * `responsive.laptop`, not `responsive.tablet`. The aliases are named for\n * devices, and only `laptop` (max-width 991px) lines up with `useIsCompact`.\n */\nexport const styles = createStaticStyles(({ css, cssVar, responsive }) => ({\n brand: css`\n display: flex;\n flex: none;\n align-items: center;\n\n block-size: 56px;\n margin-block-start: ${WORKSPACE_INSET}px;\n padding-inline: 15px;\n\n color: ${cssVar.colorText};\n white-space: nowrap;\n\n ${responsive.laptop} {\n margin-block-start: 0;\n }\n `,\n brandAnchor: css`\n display: flex;\n align-items: center;\n\n inline-size: 100%;\n min-inline-size: 0;\n\n color: inherit;\n text-decoration: none;\n `,\n brandLockup: css`\n display: flex;\n gap: 10px;\n align-items: center;\n min-inline-size: 0;\n `,\n brandName: css`\n overflow: hidden;\n\n font-size: 14px;\n font-weight: 600;\n line-height: 1.3;\n color: ${cssVar.colorText};\n text-overflow: ellipsis;\n white-space: nowrap;\n\n transition: opacity 120ms ease 80ms;\n\n [data-collapsed='true'] & {\n text-overflow: clip;\n opacity: 0;\n transition-delay: 0s;\n }\n\n @media (prefers-reduced-motion: reduce) {\n transition: none;\n }\n `,\n main: css`\n overflow: auto;\n display: flex;\n flex: 1;\n flex-direction: column;\n gap: 20px;\n\n min-inline-size: 0;\n min-block-size: 0;\n padding: 24px;\n\n /*\n * A page that owns a full-height split sets data-page-layout=\"flush\" and\n * takes over padding and scrolling, so its sidebar can sit on the card edge.\n */\n &:has([data-page-layout='flush']) {\n overflow: hidden;\n gap: 0;\n padding: 0;\n }\n\n ${responsive.mobile} {\n gap: 16px;\n padding: 16px;\n }\n `,\n navSlot: css`\n display: flex;\n flex: 1;\n flex-direction: column;\n min-block-size: 0;\n `,\n shell: css`\n overflow: hidden;\n display: flex;\n flex: 1;\n\n block-size: 100%;\n min-block-size: 0;\n\n background: ${cssVar.colorBgLayout};\n `,\n sidebar: css`\n overflow: hidden;\n display: flex;\n flex: none;\n flex-direction: column;\n\n inline-size: ${SIDEBAR_INLINE_SIZE}px;\n block-size: 100%;\n min-block-size: 0;\n\n transition: inline-size 200ms ease;\n\n &[data-collapsed='true'] {\n inline-size: ${SIDEBAR_RAIL_INLINE_SIZE}px;\n }\n\n &[data-instant='true'] {\n transition: none;\n }\n\n ${responsive.laptop} {\n display: none;\n }\n `,\n sidebarBottom: css`\n flex: none;\n padding: 8px;\n `,\n skipLink: css`\n position: fixed;\n z-index: 2000;\n inset-block-start: -100px;\n inset-inline-start: 12px;\n\n padding-block: 8px;\n padding-inline: 12px;\n border-radius: ${cssVar.borderRadius};\n\n color: ${cssVar.colorText};\n\n background: ${cssVar.colorBgElevated};\n\n &:focus {\n inset-block-start: 12px;\n }\n `,\n topbar: css`\n display: flex;\n flex: none;\n gap: 8px;\n align-items: center;\n\n block-size: 56px;\n padding-inline: 12px;\n border-block-end: 1px solid ${cssVar.colorBorderSecondary};\n `,\n topbarDivider: css`\n flex: none;\n\n inline-size: 1px;\n block-size: 18px;\n margin-inline: 2px;\n\n background: ${cssVar.colorBorderSecondary};\n `,\n topbarMain: css`\n display: flex;\n flex: 1;\n align-items: center;\n min-inline-size: 0;\n `,\n tools: css`\n display: flex;\n flex: none;\n gap: 6px;\n align-items: center;\n\n margin-inline-start: auto;\n `,\n workspace: css`\n overflow: hidden;\n display: flex;\n flex: 1;\n flex-direction: column;\n\n min-inline-size: 0;\n min-block-size: 0;\n margin-block: ${WORKSPACE_INSET}px;\n margin-inline: 0 ${WORKSPACE_INSET}px;\n border: 1px solid ${cssVar.colorBorderSecondary};\n border-radius: ${cssVar.borderRadiusLG};\n\n background: ${cssVar.colorBgContainer};\n box-shadow: ${cssVar.boxShadowTertiary};\n\n ${responsive.laptop} {\n margin: 0;\n border: none;\n border-radius: 0;\n box-shadow: none;\n }\n `,\n}));\n"],"mappings":";;AAEA,MAAM,sBAAsB;AAG5B,MAAM,2BAA2B;AACjC,MAAM,kBAAkB;;;;;AAMxB,MAAa,SAAS,oBAAoB,EAAE,KAAK,QAAQ,kBAAkB;CACzE,OAAO,GAAG;;;;;;0BAMc,gBAAgB;;;aAG7B,OAAO,UAAU;;;MAGxB,WAAW,OAAO;;;;CAItB,aAAa,GAAG;;;;;;;;;;CAUhB,aAAa,GAAG;;;;;;CAMhB,WAAW,GAAG;;;;;;aAMH,OAAO,UAAU;;;;;;;;;;;;;;;;CAgB5B,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;MAqBL,WAAW,OAAO;;;;;CAKtB,SAAS,GAAG;;;;;;CAMZ,OAAO,GAAG;;;;;;;;kBAQM,OAAO,cAAc;;CAErC,SAAS,GAAG;;;;;;mBAMK,oBAAoB;;;;;;;qBAOlB,yBAAyB;;;;;;;MAOxC,WAAW,OAAO;;;;CAItB,eAAe,GAAG;;;;CAIlB,UAAU,GAAG;;;;;;;;qBAQM,OAAO,aAAa;;aAE5B,OAAO,UAAU;;kBAEZ,OAAO,gBAAgB;;;;;;CAMvC,QAAQ,GAAG;;;;;;;;kCAQqB,OAAO,qBAAqB;;CAE5D,eAAe,GAAG;;;;;;;kBAOF,OAAO,qBAAqB;;CAE5C,YAAY,GAAG;;;;;;CAMf,OAAO,GAAG;;;;;;;;CAQV,WAAW,GAAG;;;;;;;;oBAQI,gBAAgB;uBACb,gBAAgB;wBACf,OAAO,qBAAqB;qBAC/B,OAAO,eAAe;;kBAEzB,OAAO,iBAAiB;kBACxB,OAAO,kBAAkB;;MAErC,WAAW,OAAO;;;;;;;AAOxB,EAAE"}
1
+ {"version":3,"file":"style.mjs","names":[],"sources":["../../../src/dashboard/ConsoleShell/style.ts"],"sourcesContent":["import { createStaticStyles } from 'antd-style';\n\nconst SIDEBAR_INLINE_SIZE = 248;\n// Twice the nav icon inset (8px nav padding + 10px item padding) plus the 18px icon, so the icons\n// land centered on the rail without moving sideways.\nconst SIDEBAR_RAIL_INLINE_SIZE = 54;\nconst WORKSPACE_INSET = 8;\n\n/**\n * `responsive.laptop`, not `responsive.tablet`. The aliases are named for\n * devices, and only `laptop` (max-width 991px) lines up with `useIsCompact`.\n */\nexport const styles = createStaticStyles(({ css, cssVar, responsive }) => ({\n brand: css`\n display: flex;\n flex: none;\n align-items: center;\n\n block-size: 56px;\n margin-block-start: ${WORKSPACE_INSET}px;\n padding-inline: 15px;\n\n color: ${cssVar.colorText};\n white-space: nowrap;\n\n ${responsive.laptop} {\n margin-block-start: 0;\n }\n `,\n /** Close button in the drawer's brand row: right edge, vertically centred with the brand. */\n brandClose: css`\n flex: none;\n margin-inline: auto -7px;\n `,\n brandAnchor: css`\n display: flex;\n align-items: center;\n\n inline-size: 100%;\n min-inline-size: 0;\n\n color: inherit;\n text-decoration: none;\n `,\n brandLockup: css`\n display: flex;\n gap: 10px;\n align-items: center;\n min-inline-size: 0;\n `,\n brandName: css`\n overflow: hidden;\n\n font-size: 14px;\n font-weight: 600;\n line-height: 1.3;\n color: ${cssVar.colorText};\n text-overflow: ellipsis;\n white-space: nowrap;\n\n transition: opacity 120ms ease 80ms;\n\n [data-collapsed='true'] & {\n text-overflow: clip;\n opacity: 0;\n transition-delay: 0s;\n }\n\n @media (prefers-reduced-motion: reduce) {\n transition: none;\n }\n `,\n main: css`\n overflow: auto;\n display: flex;\n flex: 1;\n flex-direction: column;\n gap: 20px;\n\n min-inline-size: 0;\n min-block-size: 0;\n padding: 24px;\n\n /*\n * A page that owns a full-height split sets data-page-layout=\"flush\" and\n * takes over padding and scrolling, so its sidebar can sit on the card edge.\n */\n &:has([data-page-layout='flush']) {\n overflow: hidden;\n gap: 0;\n padding: 0;\n }\n\n ${responsive.mobile} {\n gap: 16px;\n padding: 16px;\n }\n `,\n /**\n * The drawer body is the scroll container. Without its default padding the scrollbar sits on\n * the panel edge; the brand row, nav and footer keep their own insets.\n */\n drawerBody: css`\n && {\n min-block-size: 100%;\n padding: 0;\n }\n `,\n navSlot: css`\n display: flex;\n flex: 1;\n flex-direction: column;\n min-block-size: 0;\n `,\n shell: css`\n overflow: hidden;\n display: flex;\n flex: 1;\n\n block-size: 100%;\n min-block-size: 0;\n\n background: ${cssVar.colorBgLayout};\n `,\n sidebar: css`\n overflow: hidden;\n display: flex;\n flex: none;\n flex-direction: column;\n\n inline-size: ${SIDEBAR_INLINE_SIZE}px;\n block-size: 100%;\n min-block-size: 0;\n\n transition: inline-size 200ms ease;\n\n &[data-collapsed='true'] {\n inline-size: ${SIDEBAR_RAIL_INLINE_SIZE}px;\n }\n\n &[data-instant='true'] {\n transition: none;\n }\n\n ${responsive.laptop} {\n display: none;\n }\n `,\n sidebarBottom: css`\n flex: none;\n padding: 8px;\n `,\n skipLink: css`\n position: fixed;\n z-index: 2000;\n inset-block-start: -100px;\n inset-inline-start: 12px;\n\n padding-block: 8px;\n padding-inline: 12px;\n border-radius: ${cssVar.borderRadius};\n\n color: ${cssVar.colorText};\n\n background: ${cssVar.colorBgElevated};\n\n &:focus {\n inset-block-start: 12px;\n }\n `,\n topbar: css`\n display: flex;\n flex: none;\n gap: 8px;\n align-items: center;\n\n block-size: 56px;\n padding-inline: 12px;\n border-block-end: 1px solid ${cssVar.colorBorderSecondary};\n `,\n topbarDivider: css`\n flex: none;\n\n inline-size: 1px;\n block-size: 18px;\n margin-inline: 2px;\n\n background: ${cssVar.colorBorderSecondary};\n `,\n topbarMain: css`\n display: flex;\n flex: 1;\n align-items: center;\n min-inline-size: 0;\n `,\n tools: css`\n display: flex;\n flex: none;\n gap: 6px;\n align-items: center;\n\n margin-inline-start: auto;\n `,\n /** Light only: the content area sits midway between the layout canvas and container white. */\n workspaceLight: css`\n && {\n background: color-mix(in srgb, ${cssVar.colorBgLayout} 50%, ${cssVar.colorBgContainer});\n }\n `,\n workspace: css`\n overflow: hidden;\n display: flex;\n flex: 1;\n flex-direction: column;\n\n min-inline-size: 0;\n min-block-size: 0;\n margin-block: ${WORKSPACE_INSET}px;\n margin-inline: 0 ${WORKSPACE_INSET}px;\n border: 1px solid ${cssVar.colorBorderSecondary};\n border-radius: ${cssVar.borderRadiusLG};\n\n background: ${cssVar.colorBgContainer};\n box-shadow: ${cssVar.boxShadowTertiary};\n\n ${responsive.laptop} {\n margin: 0;\n border: none;\n border-radius: 0;\n box-shadow: none;\n }\n `,\n}));\n"],"mappings":";;AAEA,MAAM,sBAAsB;AAG5B,MAAM,2BAA2B;AACjC,MAAM,kBAAkB;;;;;AAMxB,MAAa,SAAS,oBAAoB,EAAE,KAAK,QAAQ,kBAAkB;CACzE,OAAO,GAAG;;;;;;0BAMc,gBAAgB;;;aAG7B,OAAO,UAAU;;;MAGxB,WAAW,OAAO;;;;;CAKtB,YAAY,GAAG;;;;CAIf,aAAa,GAAG;;;;;;;;;;CAUhB,aAAa,GAAG;;;;;;CAMhB,WAAW,GAAG;;;;;;aAMH,OAAO,UAAU;;;;;;;;;;;;;;;;CAgB5B,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;MAqBL,WAAW,OAAO;;;;;;;;;CAStB,YAAY,GAAG;;;;;;CAMf,SAAS,GAAG;;;;;;CAMZ,OAAO,GAAG;;;;;;;;kBAQM,OAAO,cAAc;;CAErC,SAAS,GAAG;;;;;;mBAMK,oBAAoB;;;;;;;qBAOlB,yBAAyB;;;;;;;MAOxC,WAAW,OAAO;;;;CAItB,eAAe,GAAG;;;;CAIlB,UAAU,GAAG;;;;;;;;qBAQM,OAAO,aAAa;;aAE5B,OAAO,UAAU;;kBAEZ,OAAO,gBAAgB;;;;;;CAMvC,QAAQ,GAAG;;;;;;;;kCAQqB,OAAO,qBAAqB;;CAE5D,eAAe,GAAG;;;;;;;kBAOF,OAAO,qBAAqB;;CAE5C,YAAY,GAAG;;;;;;CAMf,OAAO,GAAG;;;;;;;;;CASV,gBAAgB,GAAG;;uCAEkB,OAAO,cAAc,QAAQ,OAAO,iBAAiB;;;CAG1F,WAAW,GAAG;;;;;;;;oBAQI,gBAAgB;uBACb,gBAAgB;wBACf,OAAO,qBAAqB;qBAC/B,OAAO,eAAe;;kBAEzB,OAAO,iBAAiB;kBACxB,OAAO,kBAAkB;;MAErC,WAAW,OAAO;;;;;;;AAOxB,EAAE"}
@@ -38,6 +38,8 @@ interface ConsoleShellProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'
38
38
  /** Location shown in the top bar, usually a `Breadcrumb`. */
39
39
  breadcrumb?: ReactNode;
40
40
  children?: ReactNode;
41
+ /** Accessible name of the close button in the compact navigation drawer. */
42
+ closeNavigationLabel?: string;
41
43
  /** Collapse the sidebar to an icon rail. Ignored while compact. */
42
44
  collapsed?: boolean;
43
45
  collapseLabel?: string;
@@ -50,6 +52,15 @@ interface ConsoleShellProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'
50
52
  * @default true
51
53
  */
52
54
  hotkey?: boolean;
55
+ /**
56
+ * Swap navigation and footer for skeletons, and render `loadingContent` (default `PageLoading`)
57
+ * in place of children. Brand, tools and `storageKey` still come from the caller.
58
+ */
59
+ loading?: boolean;
60
+ /** Body while `loading`. Defaults to `<PageLoading />`. */
61
+ loadingContent?: ReactNode;
62
+ /** Skeleton nav shape while `loading`. Pass the real groups to mirror their row counts. */
63
+ loadingNavigation?: ReactNode;
53
64
  /** Grouped navigation. Collapsed state comes from the shell. */
54
65
  navigation?: ReactNode;
55
66
  onCollapsedChange?: (collapsed: boolean) => void;
@@ -2,10 +2,10 @@
2
2
  import Button from "../../base-ui/Button/Button.mjs";
3
3
  import Drawer from "../../base-ui/Drawer/Drawer.mjs";
4
4
  import DraggablePanel from "../../base-ui/DraggablePanel/DraggablePanel.mjs";
5
- import { styles } from "../Surface/style.mjs";
5
+ import { useSurfaceCardClassName } from "../Surface/link.mjs";
6
6
  import { useIsCompact, useLocalStorage } from "../hooks.mjs";
7
7
  import { FilterSplitProvider } from "./context.mjs";
8
- import { styles as styles$1 } from "./style.mjs";
8
+ import { styles } from "./style.mjs";
9
9
  import { clampSidebarWidth, sidebarWidth } from "./width.mjs";
10
10
  import { useState } from "react";
11
11
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -34,6 +34,7 @@ function usePageSidebar(wide, storageKey) {
34
34
  };
35
35
  }
36
36
  function FilterSidebar({ body, children, flush, head, header, label, storageKey, summary, wide }) {
37
+ const cardClassName = useSurfaceCardClassName();
37
38
  const isCompact = useIsCompact();
38
39
  const [drawerOpen, setDrawerOpen] = useState(false);
39
40
  const sidebar = usePageSidebar(wide, storageKey);
@@ -41,7 +42,7 @@ function FilterSidebar({ body, children, flush, head, header, label, storageKey,
41
42
  if (isCompact) return /* @__PURE__ */ jsx(FilterSplitProvider, {
42
43
  active: !flush,
43
44
  children: /* @__PURE__ */ jsxs("div", {
44
- className: styles$1.layout,
45
+ className: styles.layout,
45
46
  children: [
46
47
  header,
47
48
  /* @__PURE__ */ jsx(Button, {
@@ -57,12 +58,12 @@ function FilterSidebar({ body, children, flush, head, header, label, storageKey,
57
58
  width: 300,
58
59
  onClose: close,
59
60
  children: /* @__PURE__ */ jsxs("div", {
60
- className: styles$1.drawerPanel,
61
+ className: styles.drawerPanel,
61
62
  children: [head?.(close), body(close)]
62
63
  })
63
64
  }),
64
65
  /* @__PURE__ */ jsx("div", {
65
- className: styles$1.content,
66
+ className: styles.content,
66
67
  children
67
68
  })
68
69
  ]
@@ -71,7 +72,7 @@ function FilterSidebar({ body, children, flush, head, header, label, storageKey,
71
72
  return /* @__PURE__ */ jsx(FilterSplitProvider, {
72
73
  active: !flush,
73
74
  children: /* @__PURE__ */ jsxs("div", {
74
- className: flush ? styles$1.layout : `${styles$1.layout} ${styles.card}`,
75
+ className: flush ? styles.layout : `${styles.layout} ${cardClassName}`,
75
76
  "data-flush": flush ? true : void 0,
76
77
  "data-page-layout": flush ? "flush" : void 0,
77
78
  "data-split-card": flush ? void 0 : true,
@@ -79,8 +80,8 @@ function FilterSidebar({ body, children, flush, head, header, label, storageKey,
79
80
  expandable: true,
80
81
  showHandleWhenCollapsed: true,
81
82
  "aria-label": label,
82
- className: styles$1.sidebar,
83
- classNames: { content: styles$1.panel },
83
+ className: styles.sidebar,
84
+ classNames: { content: styles.panel },
84
85
  collapseThreshold: sidebarWidth.collapse,
85
86
  "data-flush": flush ? true : void 0,
86
87
  defaultSize: { width: wide ? sidebarWidth.wide : sidebarWidth.narrow },
@@ -94,15 +95,15 @@ function FilterSidebar({ body, children, flush, head, header, label, storageKey,
94
95
  onExpandChange: sidebar.onExpandChange,
95
96
  onSizeChange: (_delta, size) => sidebar.onSizeChange(size),
96
97
  children: [head ? /* @__PURE__ */ jsx("div", {
97
- className: styles$1.head,
98
+ className: styles.head,
98
99
  children: head(close)
99
100
  }) : null, /* @__PURE__ */ jsx("div", {
100
- className: styles$1.body,
101
+ className: styles.body,
101
102
  "data-flush": flush ? true : void 0,
102
103
  children: body(close)
103
104
  })]
104
105
  }), /* @__PURE__ */ jsxs("div", {
105
- className: styles$1.content,
106
+ className: styles.content,
106
107
  "data-flush": flush ? true : void 0,
107
108
  children: [header, children]
108
109
  })]
@@ -112,12 +113,12 @@ function FilterSidebar({ body, children, flush, head, header, label, storageKey,
112
113
  FilterSidebar.displayName = "FilterSidebar";
113
114
  function FilterRow({ count, name }) {
114
115
  return /* @__PURE__ */ jsxs("span", {
115
- className: styles$1.row,
116
+ className: styles.row,
116
117
  children: [/* @__PURE__ */ jsx("span", {
117
- className: styles$1.name,
118
+ className: styles.name,
118
119
  children: name
119
120
  }), count !== void 0 ? /* @__PURE__ */ jsx("span", {
120
- className: styles$1.count,
121
+ className: styles.count,
121
122
  children: count
122
123
  }) : null]
123
124
  });
@@ -127,18 +128,18 @@ function FilterOption({ count, icon, label, name, onClick, selected, title }) {
127
128
  return /* @__PURE__ */ jsxs("button", {
128
129
  "aria-label": label,
129
130
  "aria-pressed": selected,
130
- className: styles$1.option,
131
+ className: styles.option,
131
132
  title,
132
133
  type: "button",
133
134
  onClick,
134
135
  children: [
135
136
  icon,
136
137
  /* @__PURE__ */ jsx("span", {
137
- className: styles$1.name,
138
+ className: styles.name,
138
139
  children: name
139
140
  }),
140
141
  count !== void 0 ? /* @__PURE__ */ jsx("span", {
141
- className: styles$1.count,
142
+ className: styles.count,
142
143
  children: count
143
144
  }) : null
144
145
  ]
@@ -1 +1 @@
1
- {"version":3,"file":"FilterSidebar.mjs","names":["styles","surfaceStyles"],"sources":["../../../src/dashboard/FilterSidebar/FilterSidebar.tsx"],"sourcesContent":["'use client';\n\nimport { Filter } from 'lucide-react';\nimport { useState } from 'react';\n\nimport Button from '@/base-ui/Button';\nimport { DraggablePanel } from '@/base-ui/DraggablePanel';\nimport { Drawer } from '@/base-ui/Drawer';\n\nimport { useIsCompact, useLocalStorage } from '../hooks';\nimport { styles as surfaceStyles } from '../Surface/style';\nimport { FilterSplitProvider } from './context';\nimport { styles } from './style';\nimport type { FilterOptionProps, FilterRowProps, FilterSidebarProps } from './type';\nimport { clampSidebarWidth, sidebarWidth } from './width';\n\nfunction usePageSidebar(wide: boolean | undefined, storageKey: string | undefined) {\n const fallback = wide ? sidebarWidth.wide : sidebarWidth.narrow;\n const [prefs, setPrefs] = useLocalStorage<{ expand?: boolean; width?: number }>(storageKey, {\n expand: true,\n width: fallback,\n });\n return {\n expand: prefs.expand !== false,\n onExpandChange: (expand: boolean) => setPrefs((current) => ({ ...current, expand })),\n onSizeChange: (size: { width?: number | string }) => {\n const next = typeof size.width === 'number' ? size.width : fallback;\n setPrefs((current) => ({ ...current, width: clampSidebarWidth(next, fallback) }));\n },\n width: clampSidebarWidth(Number(prefs.width), fallback),\n };\n}\n\nfunction FilterSidebar({\n body,\n children,\n flush,\n head,\n header,\n label,\n storageKey,\n summary,\n wide,\n}: FilterSidebarProps) {\n const isCompact = useIsCompact();\n const [drawerOpen, setDrawerOpen] = useState(false);\n const sidebar = usePageSidebar(wide, storageKey);\n const close = () => setDrawerOpen(false);\n\n if (isCompact) {\n return (\n <FilterSplitProvider active={!flush}>\n <div className={styles.layout}>\n {header}\n <Button block icon={Filter} onClick={() => setDrawerOpen(true)}>\n {summary}\n </Button>\n <Drawer open={drawerOpen} placement=\"left\" title={label} width={300} onClose={close}>\n <div className={styles.drawerPanel}>\n {head?.(close)}\n {body(close)}\n </div>\n </Drawer>\n <div className={styles.content}>{children}</div>\n </div>\n </FilterSplitProvider>\n );\n }\n\n return (\n <FilterSplitProvider active={!flush}>\n <div\n className={flush ? styles.layout : `${styles.layout} ${surfaceStyles.card}`}\n data-flush={flush ? true : undefined}\n data-page-layout={flush ? 'flush' : undefined}\n data-split-card={flush ? undefined : true}\n >\n <DraggablePanel\n expandable\n showHandleWhenCollapsed\n aria-label={label}\n className={styles.sidebar}\n classNames={{ content: styles.panel }}\n collapseThreshold={sidebarWidth.collapse}\n data-flush={flush ? true : undefined}\n defaultSize={{ width: wide ? sidebarWidth.wide : sidebarWidth.narrow }}\n expand={sidebar.expand}\n maxWidth={sidebarWidth.max}\n minWidth={sidebarWidth.min}\n mode=\"fixed\"\n placement=\"left\"\n showBorder={false}\n size={{ width: sidebar.width }}\n onExpandChange={sidebar.onExpandChange}\n onSizeChange={(_delta, size) => sidebar.onSizeChange(size)}\n >\n {head ? <div className={styles.head}>{head(close)}</div> : null}\n <div className={styles.body} data-flush={flush ? true : undefined}>\n {body(close)}\n </div>\n </DraggablePanel>\n <div className={styles.content} data-flush={flush ? true : undefined}>\n {header}\n {children}\n </div>\n </div>\n </FilterSplitProvider>\n );\n}\n\nFilterSidebar.displayName = 'FilterSidebar';\n\nfunction FilterRow({ count, name }: FilterRowProps) {\n return (\n <span className={styles.row}>\n <span className={styles.name}>{name}</span>\n {count !== undefined ? <span className={styles.count}>{count}</span> : null}\n </span>\n );\n}\n\nFilterRow.displayName = 'FilterRow';\n\nfunction FilterOption({ count, icon, label, name, onClick, selected, title }: FilterOptionProps) {\n return (\n <button\n aria-label={label}\n aria-pressed={selected}\n className={styles.option}\n title={title}\n type=\"button\"\n onClick={onClick}\n >\n {icon}\n <span className={styles.name}>{name}</span>\n {count !== undefined ? <span className={styles.count}>{count}</span> : null}\n </button>\n );\n}\n\nFilterOption.displayName = 'FilterOption';\n\nexport { FilterOption, FilterRow };\nexport default FilterSidebar;\n"],"mappings":"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"}
1
+ {"version":3,"file":"FilterSidebar.mjs","names":[],"sources":["../../../src/dashboard/FilterSidebar/FilterSidebar.tsx"],"sourcesContent":["'use client';\n\nimport { Filter } from 'lucide-react';\nimport { useState } from 'react';\n\nimport Button from '@/base-ui/Button';\nimport { DraggablePanel } from '@/base-ui/DraggablePanel';\nimport { Drawer } from '@/base-ui/Drawer';\n\nimport { useIsCompact, useLocalStorage } from '../hooks';\nimport { useSurfaceCardClassName } from '../Surface/link';\nimport { FilterSplitProvider } from './context';\nimport { styles } from './style';\nimport type { FilterOptionProps, FilterRowProps, FilterSidebarProps } from './type';\nimport { clampSidebarWidth, sidebarWidth } from './width';\n\nfunction usePageSidebar(wide: boolean | undefined, storageKey: string | undefined) {\n const fallback = wide ? sidebarWidth.wide : sidebarWidth.narrow;\n const [prefs, setPrefs] = useLocalStorage<{ expand?: boolean; width?: number }>(storageKey, {\n expand: true,\n width: fallback,\n });\n return {\n expand: prefs.expand !== false,\n onExpandChange: (expand: boolean) => setPrefs((current) => ({ ...current, expand })),\n onSizeChange: (size: { width?: number | string }) => {\n const next = typeof size.width === 'number' ? size.width : fallback;\n setPrefs((current) => ({ ...current, width: clampSidebarWidth(next, fallback) }));\n },\n width: clampSidebarWidth(Number(prefs.width), fallback),\n };\n}\n\nfunction FilterSidebar({\n body,\n children,\n flush,\n head,\n header,\n label,\n storageKey,\n summary,\n wide,\n}: FilterSidebarProps) {\n const cardClassName = useSurfaceCardClassName();\n const isCompact = useIsCompact();\n const [drawerOpen, setDrawerOpen] = useState(false);\n const sidebar = usePageSidebar(wide, storageKey);\n const close = () => setDrawerOpen(false);\n\n if (isCompact) {\n return (\n <FilterSplitProvider active={!flush}>\n <div className={styles.layout}>\n {header}\n <Button block icon={Filter} onClick={() => setDrawerOpen(true)}>\n {summary}\n </Button>\n <Drawer open={drawerOpen} placement=\"left\" title={label} width={300} onClose={close}>\n <div className={styles.drawerPanel}>\n {head?.(close)}\n {body(close)}\n </div>\n </Drawer>\n <div className={styles.content}>{children}</div>\n </div>\n </FilterSplitProvider>\n );\n }\n\n return (\n <FilterSplitProvider active={!flush}>\n <div\n className={flush ? styles.layout : `${styles.layout} ${cardClassName}`}\n data-flush={flush ? true : undefined}\n data-page-layout={flush ? 'flush' : undefined}\n data-split-card={flush ? undefined : true}\n >\n <DraggablePanel\n expandable\n showHandleWhenCollapsed\n aria-label={label}\n className={styles.sidebar}\n classNames={{ content: styles.panel }}\n collapseThreshold={sidebarWidth.collapse}\n data-flush={flush ? true : undefined}\n defaultSize={{ width: wide ? sidebarWidth.wide : sidebarWidth.narrow }}\n expand={sidebar.expand}\n maxWidth={sidebarWidth.max}\n minWidth={sidebarWidth.min}\n mode=\"fixed\"\n placement=\"left\"\n showBorder={false}\n size={{ width: sidebar.width }}\n onExpandChange={sidebar.onExpandChange}\n onSizeChange={(_delta, size) => sidebar.onSizeChange(size)}\n >\n {head ? <div className={styles.head}>{head(close)}</div> : null}\n <div className={styles.body} data-flush={flush ? true : undefined}>\n {body(close)}\n </div>\n </DraggablePanel>\n <div className={styles.content} data-flush={flush ? true : undefined}>\n {header}\n {children}\n </div>\n </div>\n </FilterSplitProvider>\n );\n}\n\nFilterSidebar.displayName = 'FilterSidebar';\n\nfunction FilterRow({ count, name }: FilterRowProps) {\n return (\n <span className={styles.row}>\n <span className={styles.name}>{name}</span>\n {count !== undefined ? <span className={styles.count}>{count}</span> : null}\n </span>\n );\n}\n\nFilterRow.displayName = 'FilterRow';\n\nfunction FilterOption({ count, icon, label, name, onClick, selected, title }: FilterOptionProps) {\n return (\n <button\n aria-label={label}\n aria-pressed={selected}\n className={styles.option}\n title={title}\n type=\"button\"\n onClick={onClick}\n >\n {icon}\n <span className={styles.name}>{name}</span>\n {count !== undefined ? <span className={styles.count}>{count}</span> : null}\n </button>\n );\n}\n\nFilterOption.displayName = 'FilterOption';\n\nexport { FilterOption, FilterRow };\nexport default FilterSidebar;\n"],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { FilterStripProps } from "./type.mjs";
2
+ //#region src/dashboard/FilterStrip/FilterStrip.d.ts
3
+ declare const formatInteger: (count: number) => string;
4
+ /** One surface of selectable counts. Peer filters share a seam instead of a row of equal cards. */
5
+ declare const FilterStrip: {
6
+ ({ emptyText, formatCount, items, label, onChange, value }: FilterStripProps): import("react").JSX.Element;
7
+ displayName: string;
8
+ };
9
+ //#endregion
10
+ export { FilterStrip as default, formatInteger };
11
+ //# sourceMappingURL=FilterStrip.d.mts.map
@@ -0,0 +1,55 @@
1
+ "use client";
2
+ import Skeleton from "../../base-ui/Skeleton/index.mjs";
3
+ import { styles } from "../Surface/style.mjs";
4
+ import Surface from "../Surface/Surface.mjs";
5
+ import { styles as styles$1 } from "./style.mjs";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ import { cx } from "antd-style";
8
+ //#region src/dashboard/FilterStrip/FilterStrip.tsx
9
+ const countClass = {
10
+ danger: styles$1.countDanger,
11
+ warning: styles$1.countWarning
12
+ };
13
+ const integerFormat = new Intl.NumberFormat("en-US", { maximumFractionDigits: 0 });
14
+ const formatInteger = (count) => integerFormat.format(count);
15
+ /** One surface of selectable counts. Peer filters share a seam instead of a row of equal cards. */
16
+ const FilterStrip = ({ emptyText = "--", formatCount = formatInteger, items, label, onChange, value }) => /* @__PURE__ */ jsx(Surface, {
17
+ className: styles.clip,
18
+ children: /* @__PURE__ */ jsx("div", {
19
+ "aria-label": label,
20
+ className: styles$1.frame,
21
+ role: "radiogroup",
22
+ children: /* @__PURE__ */ jsx("div", {
23
+ className: styles$1.grid,
24
+ children: items.map((item) => {
25
+ const active = item.key === value;
26
+ const missing = item.count === void 0 || item.count === null;
27
+ const emphasize = item.tone && typeof item.count === "number" && item.count > 0;
28
+ return /* @__PURE__ */ jsxs("button", {
29
+ "aria-checked": active,
30
+ className: cx(styles$1.cell, active && styles$1.cellActive),
31
+ role: "radio",
32
+ title: item.hint,
33
+ type: "button",
34
+ onClick: () => onChange(item.key),
35
+ children: [/* @__PURE__ */ jsx("span", {
36
+ className: cx(styles$1.label, active && styles$1.labelActive),
37
+ children: item.label
38
+ }), /* @__PURE__ */ jsx("span", {
39
+ className: cx(styles$1.count, emphasize && countClass[item.tone]),
40
+ children: item.loading ? /* @__PURE__ */ jsx(Skeleton, {
41
+ height: 22,
42
+ radius: 6,
43
+ width: 48
44
+ }) : missing ? emptyText : formatCount(item.count)
45
+ })]
46
+ }, item.key);
47
+ })
48
+ })
49
+ })
50
+ });
51
+ FilterStrip.displayName = "FilterStrip";
52
+ //#endregion
53
+ export { FilterStrip as default, formatInteger };
54
+
55
+ //# sourceMappingURL=FilterStrip.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FilterStrip.mjs","names":["styles","surfaceStyles"],"sources":["../../../src/dashboard/FilterStrip/FilterStrip.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\n\nimport Skeleton from '@/base-ui/Skeleton';\n\nimport { styles as surfaceStyles } from '../Surface/style';\nimport Surface from '../Surface/Surface';\nimport { styles } from './style';\nimport type { FilterStripProps } from './type';\n\nconst countClass = {\n danger: styles.countDanger,\n warning: styles.countWarning,\n} as const;\n\nconst integerFormat = new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 });\n\nexport const formatInteger = (count: number) => integerFormat.format(count);\n\n/** One surface of selectable counts. Peer filters share a seam instead of a row of equal cards. */\nconst FilterStrip = ({\n emptyText = '--',\n formatCount = formatInteger,\n items,\n label,\n onChange,\n value,\n}: FilterStripProps) => (\n <Surface className={surfaceStyles.clip}>\n <div aria-label={label} className={styles.frame} role=\"radiogroup\">\n <div className={styles.grid}>\n {items.map((item) => {\n const active = item.key === value;\n const missing = item.count === undefined || item.count === null;\n const emphasize = item.tone && typeof item.count === 'number' && item.count > 0;\n\n return (\n <button\n aria-checked={active}\n className={cx(styles.cell, active && styles.cellActive)}\n key={item.key}\n role=\"radio\"\n title={item.hint}\n type=\"button\"\n onClick={() => onChange(item.key)}\n >\n <span className={cx(styles.label, active && styles.labelActive)}>{item.label}</span>\n <span className={cx(styles.count, emphasize && countClass[item.tone!])}>\n {item.loading ? (\n <Skeleton height={22} radius={6} width={48} />\n ) : missing ? (\n emptyText\n ) : (\n formatCount(item.count!)\n )}\n </span>\n </button>\n );\n })}\n </div>\n </div>\n </Surface>\n);\n\nFilterStrip.displayName = 'FilterStrip';\n\nexport default FilterStrip;\n"],"mappings":";;;;;;;;AAWA,MAAM,aAAa;CACjB,QAAQA,SAAO;CACf,SAASA,SAAO;AAClB;AAEA,MAAM,gBAAgB,IAAI,KAAK,aAAa,SAAS,EAAE,uBAAuB,EAAE,CAAC;AAEjF,MAAa,iBAAiB,UAAkB,cAAc,OAAO,KAAK;;AAG1E,MAAM,eAAe,EACnB,YAAY,MACZ,cAAc,eACd,OACA,OACA,UACA,YAEA,oBAAC,SAAD;CAAS,WAAWC,OAAc;CAChC,UAAA,oBAAC,OAAD;EAAK,cAAY;EAAO,WAAWD,SAAO;EAAO,MAAK;EACpD,UAAA,oBAAC,OAAD;GAAK,WAAWA,SAAO;GACpB,UAAA,MAAM,KAAK,SAAS;IACnB,MAAM,SAAS,KAAK,QAAQ;IAC5B,MAAM,UAAU,KAAK,UAAU,KAAA,KAAa,KAAK,UAAU;IAC3D,MAAM,YAAY,KAAK,QAAQ,OAAO,KAAK,UAAU,YAAY,KAAK,QAAQ;IAE9E,OACE,qBAAC,UAAD;KACE,gBAAc;KACd,WAAW,GAAGA,SAAO,MAAM,UAAUA,SAAO,UAAU;KAEtD,MAAK;KACL,OAAO,KAAK;KACZ,MAAK;KACL,eAAe,SAAS,KAAK,GAAG;KAPlC,UAAA,CASE,oBAAC,QAAD;MAAM,WAAW,GAAGA,SAAO,OAAO,UAAUA,SAAO,WAAW;MAAI,UAAA,KAAK;KAAY,CAAA,GACnF,oBAAC,QAAD;MAAM,WAAW,GAAGA,SAAO,OAAO,aAAa,WAAW,KAAK,KAAM;MAClE,UAAA,KAAK,UACJ,oBAAC,UAAD;OAAU,QAAQ;OAAI,QAAQ;OAAG,OAAO;MAAK,CAAA,IAC3C,UACF,YAEA,YAAY,KAAK,KAAM;KAErB,CAAA,CACA;IAhBD,GAAA,KAAK,GAgBJ;GAEZ,CAAC;EACE,CAAA;CACF,CAAA;AACE,CAAA;AAGX,YAAY,cAAc"}
@@ -0,0 +1,3 @@
1
+ import { FilterStripItem, FilterStripProps } from "./type.mjs";
2
+ import FilterStrip, { formatInteger } from "./FilterStrip.mjs";
3
+ export { type FilterStripItem, type FilterStripProps, FilterStrip as default, formatInteger };
@@ -0,0 +1,94 @@
1
+ import { createStaticStyles } from "antd-style";
2
+ //#region src/dashboard/FilterStrip/style.ts
3
+ const styles = createStaticStyles(({ css, cssVar }) => ({
4
+ cell: css`
5
+ cursor: pointer;
6
+
7
+ position: relative;
8
+
9
+ display: flex;
10
+ flex-direction: column;
11
+ gap: 6px;
12
+ align-items: flex-start;
13
+
14
+ min-inline-size: 0;
15
+ margin: 0;
16
+ padding-block: 14px 16px;
17
+ padding-inline: 16px;
18
+ border: 0;
19
+
20
+ font: inherit;
21
+ color: inherit;
22
+ text-align: start;
23
+
24
+ background: transparent;
25
+ box-shadow:
26
+ inset -1px 0 0 var(--filter-seam),
27
+ inset 0 -1px 0 var(--filter-seam);
28
+
29
+ &::after {
30
+ content: '';
31
+
32
+ position: absolute;
33
+ inset-block-end: 1px;
34
+ inset-inline: 0;
35
+
36
+ block-size: 3px;
37
+
38
+ background: transparent;
39
+ }
40
+
41
+ &:hover {
42
+ background: ${cssVar.colorFillQuaternary};
43
+ }
44
+ `,
45
+ cellActive: css`
46
+ background: ${cssVar.colorFillTertiary};
47
+
48
+ &::after {
49
+ background: ${cssVar.colorText};
50
+ }
51
+
52
+ &:hover {
53
+ background: ${cssVar.colorFillTertiary};
54
+ }
55
+ `,
56
+ count: css`
57
+ font-size: ${cssVar.fontSizeHeading4};
58
+ font-weight: 600;
59
+ font-variant-numeric: tabular-nums;
60
+ line-height: 1.15;
61
+ color: ${cssVar.colorText};
62
+ `,
63
+ countDanger: css`
64
+ color: ${cssVar.colorError};
65
+ `,
66
+ countWarning: css`
67
+ color: ${cssVar.colorWarning};
68
+ `,
69
+ frame: css`
70
+ --filter-seam: ${cssVar.colorFillSecondary};
71
+
72
+ overflow: hidden;
73
+ border-radius: inherit;
74
+ `,
75
+ grid: css`
76
+ display: grid;
77
+ grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
78
+ inline-size: calc(100% + 1px);
79
+ margin-block-end: -1px;
80
+ `,
81
+ label: css`
82
+ font-size: 13px;
83
+ font-weight: 500;
84
+ line-height: 1.4;
85
+ color: ${cssVar.colorTextSecondary};
86
+ `,
87
+ labelActive: css`
88
+ color: ${cssVar.colorText};
89
+ `
90
+ }));
91
+ //#endregion
92
+ export { styles };
93
+
94
+ //# sourceMappingURL=style.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style.mjs","names":[],"sources":["../../../src/dashboard/FilterStrip/style.ts"],"sourcesContent":["import { createStaticStyles } from 'antd-style';\n\nexport const styles = createStaticStyles(({ css, cssVar }) => ({\n cell: css`\n cursor: pointer;\n\n position: relative;\n\n display: flex;\n flex-direction: column;\n gap: 6px;\n align-items: flex-start;\n\n min-inline-size: 0;\n margin: 0;\n padding-block: 14px 16px;\n padding-inline: 16px;\n border: 0;\n\n font: inherit;\n color: inherit;\n text-align: start;\n\n background: transparent;\n box-shadow:\n inset -1px 0 0 var(--filter-seam),\n inset 0 -1px 0 var(--filter-seam);\n\n &::after {\n content: '';\n\n position: absolute;\n inset-block-end: 1px;\n inset-inline: 0;\n\n block-size: 3px;\n\n background: transparent;\n }\n\n &:hover {\n background: ${cssVar.colorFillQuaternary};\n }\n `,\n cellActive: css`\n background: ${cssVar.colorFillTertiary};\n\n &::after {\n background: ${cssVar.colorText};\n }\n\n &:hover {\n background: ${cssVar.colorFillTertiary};\n }\n `,\n count: css`\n font-size: ${cssVar.fontSizeHeading4};\n font-weight: 600;\n font-variant-numeric: tabular-nums;\n line-height: 1.15;\n color: ${cssVar.colorText};\n `,\n countDanger: css`\n color: ${cssVar.colorError};\n `,\n countWarning: css`\n color: ${cssVar.colorWarning};\n `,\n frame: css`\n --filter-seam: ${cssVar.colorFillSecondary};\n\n overflow: hidden;\n border-radius: inherit;\n `,\n grid: css`\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));\n inline-size: calc(100% + 1px);\n margin-block-end: -1px;\n `,\n label: css`\n font-size: 13px;\n font-weight: 500;\n line-height: 1.4;\n color: ${cssVar.colorTextSecondary};\n `,\n labelActive: css`\n color: ${cssVar.colorText};\n `,\n}));\n"],"mappings":";;AAEA,MAAa,SAAS,oBAAoB,EAAE,KAAK,cAAc;CAC7D,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oBAsCS,OAAO,oBAAoB;;;CAG7C,YAAY,GAAG;kBACC,OAAO,kBAAkB;;;oBAGvB,OAAO,UAAU;;;;oBAIjB,OAAO,kBAAkB;;;CAG3C,OAAO,GAAG;iBACK,OAAO,iBAAiB;;;;aAI5B,OAAO,UAAU;;CAE5B,aAAa,GAAG;aACL,OAAO,WAAW;;CAE7B,cAAc,GAAG;aACN,OAAO,aAAa;;CAE/B,OAAO,GAAG;qBACS,OAAO,mBAAmB;;;;;CAK7C,MAAM,GAAG;;;;;;CAMT,OAAO,GAAG;;;;aAIC,OAAO,mBAAmB;;CAErC,aAAa,GAAG;aACL,OAAO,UAAU;;AAE9B,EAAE"}
@@ -0,0 +1,26 @@
1
+ import { ReactNode } from "react";
2
+ //#region src/dashboard/FilterStrip/type.d.ts
3
+ interface FilterStripItem {
4
+ count?: number;
5
+ /** Shown as the control's title. Definitions stay off the number so the row can be scanned. */
6
+ hint?: string;
7
+ key: string;
8
+ label: ReactNode;
9
+ loading?: boolean;
10
+ /** Colors the count only when it is greater than zero; a zero is not an incident. */
11
+ tone?: 'danger' | 'warning';
12
+ }
13
+ interface FilterStripProps {
14
+ /** Shown when an item has no count. Defaults to `--`. */
15
+ emptyText?: ReactNode;
16
+ /** Formats a count. Defaults to a grouped integer, e.g. `12,345`. */
17
+ formatCount?: (count: number) => ReactNode;
18
+ items: FilterStripItem[];
19
+ /** Accessible name for the radio group. */
20
+ label: string;
21
+ onChange: (key: string) => void;
22
+ value: string;
23
+ }
24
+ //#endregion
25
+ export { FilterStripItem, FilterStripProps };
26
+ //# sourceMappingURL=type.d.mts.map
@@ -0,0 +1,10 @@
1
+ import { LabelWithKeyProps } from "./type.mjs";
2
+ //#region src/dashboard/LabelWithKey/LabelWithKey.d.ts
3
+ /** A human label followed by its machine key as a tag. */
4
+ declare const LabelWithKey: {
5
+ ({ tag, title, ...rest }: LabelWithKeyProps): import("react").JSX.Element;
6
+ displayName: string;
7
+ };
8
+ //#endregion
9
+ export { LabelWithKey as default };
10
+ //# sourceMappingURL=LabelWithKey.d.mts.map
@@ -0,0 +1,18 @@
1
+ "use client";
2
+ import FlexBasic_default from "../../Flex/FlexBasic.mjs";
3
+ import Tag from "../../base-ui/Tag/Tag.mjs";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ //#region src/dashboard/LabelWithKey/LabelWithKey.tsx
6
+ /** A human label followed by its machine key as a tag. */
7
+ const LabelWithKey = ({ tag, title, ...rest }) => /* @__PURE__ */ jsxs(FlexBasic_default, {
8
+ horizontal: true,
9
+ align: "center",
10
+ gap: 8,
11
+ ...rest,
12
+ children: [title, /* @__PURE__ */ jsx(Tag, { children: tag })]
13
+ });
14
+ LabelWithKey.displayName = "LabelWithKey";
15
+ //#endregion
16
+ export { LabelWithKey as default };
17
+
18
+ //# sourceMappingURL=LabelWithKey.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LabelWithKey.mjs","names":["Flexbox"],"sources":["../../../src/dashboard/LabelWithKey/LabelWithKey.tsx"],"sourcesContent":["'use client';\n\nimport Tag from '@/base-ui/Tag';\nimport { Flexbox } from '@/Flex';\n\nimport type { LabelWithKeyProps } from './type';\n\n/** A human label followed by its machine key as a tag. */\nconst LabelWithKey = ({ tag, title, ...rest }: LabelWithKeyProps) => (\n <Flexbox horizontal align={'center'} gap={8} {...rest}>\n {title}\n <Tag>{tag}</Tag>\n </Flexbox>\n);\n\nLabelWithKey.displayName = 'LabelWithKey';\n\nexport default LabelWithKey;\n"],"mappings":";;;;;;AAQA,MAAM,gBAAgB,EAAE,KAAK,OAAO,GAAG,WACrC,qBAACA,mBAAD;CAAS,YAAA;CAAW,OAAO;CAAU,KAAK;CAAG,GAAI;CAAjD,UAAA,CACG,OACD,oBAAC,KAAD,EAAA,UAAM,IAAS,CAAA,CACR;;AAGX,aAAa,cAAc"}
@@ -0,0 +1,3 @@
1
+ import { LabelWithKeyProps } from "./type.mjs";
2
+ import LabelWithKey from "./LabelWithKey.mjs";
3
+ export { type LabelWithKeyProps, LabelWithKey as default };
@@ -0,0 +1,12 @@
1
+ import { FlexboxProps } from "../../Flex/type.mjs";
2
+ import "../../Flex/index.mjs";
3
+ import { ReactNode } from "react";
4
+ //#region src/dashboard/LabelWithKey/type.d.ts
5
+ interface LabelWithKeyProps extends Omit<FlexboxProps, 'title'> {
6
+ /** The machine key shown as a tag after the label, e.g. a config or permission id. */
7
+ tag: ReactNode;
8
+ title: ReactNode;
9
+ }
10
+ //#endregion
11
+ export { LabelWithKeyProps };
12
+ //# sourceMappingURL=type.d.mts.map
@@ -0,0 +1,81 @@
1
+ "use client";
2
+ import Icon from "../../Icon/Icon.mjs";
3
+ import Skeleton from "../../base-ui/Skeleton/index.mjs";
4
+ import { useSurfaceLink } from "../Surface/link.mjs";
5
+ import { styles } from "./style.mjs";
6
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+ import { cx } from "antd-style";
8
+ //#region src/dashboard/MetricStrip/MetricCell.tsx
9
+ const deltaClass = {
10
+ down: styles.deltaDown,
11
+ flat: styles.deltaFlat,
12
+ up: styles.deltaUp
13
+ };
14
+ const MetricBody = ({ item, loading }) => /* @__PURE__ */ jsxs(Fragment, { children: [
15
+ /* @__PURE__ */ jsxs("div", {
16
+ className: styles.head,
17
+ children: [/* @__PURE__ */ jsxs("div", {
18
+ className: styles.headCopy,
19
+ children: [/* @__PURE__ */ jsx("div", {
20
+ className: styles.label,
21
+ children: item.label
22
+ }), item.action]
23
+ }), item.mark ? /* @__PURE__ */ jsx("span", {
24
+ "aria-hidden": true,
25
+ className: styles.mark,
26
+ children: /* @__PURE__ */ jsx(Icon, {
27
+ icon: item.mark,
28
+ size: 14
29
+ })
30
+ }) : null]
31
+ }),
32
+ loading ? /* @__PURE__ */ jsx(Skeleton, {
33
+ height: 28,
34
+ radius: 6,
35
+ width: 88
36
+ }) : /* @__PURE__ */ jsx("div", {
37
+ className: cx(styles.value, item.valueTone === "danger" && styles.valueDanger, item.valueTone === "warning" && styles.valueWarning),
38
+ children: item.value
39
+ }),
40
+ !loading && (item.delta || item.hint) ? /* @__PURE__ */ jsxs("div", {
41
+ className: styles.foot,
42
+ children: [item.delta ? /* @__PURE__ */ jsx("span", {
43
+ className: cx(styles.delta, deltaClass[item.direction ?? "flat"]),
44
+ children: item.delta
45
+ }) : null, item.hint ? /* @__PURE__ */ jsx("span", {
46
+ className: styles.hint,
47
+ children: item.hint
48
+ }) : null]
49
+ }) : null
50
+ ] });
51
+ /** One metric: label row, figure, delta and hint. Shared by MetricStrip and StatCard. */
52
+ const MetricCell = ({ item, loading, renderLink, seam = false }) => {
53
+ const link = useSurfaceLink(renderLink);
54
+ const body = /* @__PURE__ */ jsx(MetricBody, {
55
+ item,
56
+ loading: item.loading ?? loading
57
+ });
58
+ const cell = cx(styles.cell, seam && styles.cellSeam);
59
+ if (item.href) return /* @__PURE__ */ jsx("div", {
60
+ className: styles.slot,
61
+ children: link({
62
+ children: body,
63
+ className: cx(cell, styles.link),
64
+ href: item.href
65
+ })
66
+ });
67
+ if (item.onClick) return /* @__PURE__ */ jsx("button", {
68
+ className: cx(cell, styles.press),
69
+ type: "button",
70
+ onClick: item.onClick,
71
+ children: body
72
+ });
73
+ return /* @__PURE__ */ jsx("div", {
74
+ className: cell,
75
+ children: body
76
+ });
77
+ };
78
+ //#endregion
79
+ export { MetricCell as default };
80
+
81
+ //# sourceMappingURL=MetricCell.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MetricCell.mjs","names":[],"sources":["../../../src/dashboard/MetricStrip/MetricCell.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\n\nimport Skeleton from '@/base-ui/Skeleton';\nimport Icon from '@/Icon';\n\nimport { useSurfaceLink } from '../Surface/link';\nimport type { SurfaceRenderLink } from '../Surface/type';\nimport { styles } from './style';\nimport type { MetricItem } from './type';\n\nconst deltaClass = {\n down: styles.deltaDown,\n flat: styles.deltaFlat,\n up: styles.deltaUp,\n} as const;\n\nconst MetricBody = ({ item, loading }: { item: MetricItem; loading?: boolean }) => (\n <>\n <div className={styles.head}>\n <div className={styles.headCopy}>\n <div className={styles.label}>{item.label}</div>\n {item.action}\n </div>\n {item.mark ? (\n <span aria-hidden className={styles.mark}>\n <Icon icon={item.mark} size={14} />\n </span>\n ) : null}\n </div>\n {loading ? (\n <Skeleton height={28} radius={6} width={88} />\n ) : (\n <div\n className={cx(\n styles.value,\n item.valueTone === 'danger' && styles.valueDanger,\n item.valueTone === 'warning' && styles.valueWarning,\n )}\n >\n {item.value}\n </div>\n )}\n {!loading && (item.delta || item.hint) ? (\n <div className={styles.foot}>\n {item.delta ? (\n <span className={cx(styles.delta, deltaClass[item.direction ?? 'flat'])}>\n {item.delta}\n </span>\n ) : null}\n {item.hint ? <span className={styles.hint}>{item.hint}</span> : null}\n </div>\n ) : null}\n </>\n);\n\nexport interface MetricCellProps {\n item: MetricItem;\n loading?: boolean;\n renderLink?: SurfaceRenderLink;\n /** Draw the joined-strip divider on the trailing and bottom edges. */\n seam?: boolean;\n}\n\n/** One metric: label row, figure, delta and hint. Shared by MetricStrip and StatCard. */\nconst MetricCell = ({ item, loading, renderLink, seam = false }: MetricCellProps) => {\n const link = useSurfaceLink(renderLink);\n const body = <MetricBody item={item} loading={item.loading ?? loading} />;\n const cell = cx(styles.cell, seam && styles.cellSeam);\n\n if (item.href) {\n return (\n <div className={styles.slot}>\n {link({ children: body, className: cx(cell, styles.link), href: item.href })}\n </div>\n );\n }\n if (item.onClick) {\n return (\n <button className={cx(cell, styles.press)} type=\"button\" onClick={item.onClick}>\n {body}\n </button>\n );\n }\n return <div className={cell}>{body}</div>;\n};\n\nexport default MetricCell;\n"],"mappings":";;;;;;;;AAYA,MAAM,aAAa;CACjB,MAAM,OAAO;CACb,MAAM,OAAO;CACb,IAAI,OAAO;AACb;AAEA,MAAM,cAAc,EAAE,MAAM,cAC1B,qBAAA,UAAA,EAAA,UAAA;CACE,qBAAC,OAAD;EAAK,WAAW,OAAO;EAAvB,UAAA,CACE,qBAAC,OAAD;GAAK,WAAW,OAAO;GAAvB,UAAA,CACE,oBAAC,OAAD;IAAK,WAAW,OAAO;IAAQ,UAAA,KAAK;GAAW,CAAA,GAC9C,KAAK,MACH;EACJ,CAAA,GAAA,KAAK,OACJ,oBAAC,QAAD;GAAM,eAAA;GAAY,WAAW,OAAO;GAClC,UAAA,oBAAC,MAAD;IAAM,MAAM,KAAK;IAAM,MAAM;GAAK,CAAA;EAC9B,CAAA,IACJ,IACD;;CACJ,UACC,oBAAC,UAAD;EAAU,QAAQ;EAAI,QAAQ;EAAG,OAAO;CAAK,CAAA,IAE7C,oBAAC,OAAD;EACE,WAAW,GACT,OAAO,OACP,KAAK,cAAc,YAAY,OAAO,aACtC,KAAK,cAAc,aAAa,OAAO,YACzC;EAEC,UAAA,KAAK;CACH,CAAA;CAEN,CAAC,YAAY,KAAK,SAAS,KAAK,QAC/B,qBAAC,OAAD;EAAK,WAAW,OAAO;EAAvB,UAAA,CACG,KAAK,QACJ,oBAAC,QAAD;GAAM,WAAW,GAAG,OAAO,OAAO,WAAW,KAAK,aAAa,OAAO;GACnE,UAAA,KAAK;EACF,CAAA,IACJ,MACH,KAAK,OAAO,oBAAC,QAAD;GAAM,WAAW,OAAO;GAAO,UAAA,KAAK;EAAW,CAAA,IAAI,IAC7D;CACH,CAAA,IAAA;AACJ,EAAA,CAAA;;AAYJ,MAAM,cAAc,EAAE,MAAM,SAAS,YAAY,OAAO,YAA6B;CACnF,MAAM,OAAO,eAAe,UAAU;CACtC,MAAM,OAAO,oBAAC,YAAD;EAAkB;EAAM,SAAS,KAAK,WAAW;CAAU,CAAA;CACxE,MAAM,OAAO,GAAG,OAAO,MAAM,QAAQ,OAAO,QAAQ;CAEpD,IAAI,KAAK,MACP,OACE,oBAAC,OAAD;EAAK,WAAW,OAAO;EACpB,UAAA,KAAK;GAAE,UAAU;GAAM,WAAW,GAAG,MAAM,OAAO,IAAI;GAAG,MAAM,KAAK;EAAK,CAAC;CACxE,CAAA;CAGT,IAAI,KAAK,SACP,OACE,oBAAC,UAAD;EAAQ,WAAW,GAAG,MAAM,OAAO,KAAK;EAAG,MAAK;EAAS,SAAS,KAAK;EACpE,UAAA;CACK,CAAA;CAGZ,OAAO,oBAAC,OAAD;EAAK,WAAW;EAAO,UAAA;CAAU,CAAA;AAC1C"}
@@ -0,0 +1,13 @@
1
+ import { MetricStripProps } from "./type.mjs";
2
+ //#region src/dashboard/MetricStrip/MetricStrip.d.ts
3
+ /**
4
+ * Peer metrics. `joined` shares one card divided into cells; `split` gives each item its own card,
5
+ * identical to StatCard.
6
+ */
7
+ declare const MetricStrip: {
8
+ ({ items, loading, renderLink, variant }: MetricStripProps): import("react").JSX.Element;
9
+ displayName: string;
10
+ };
11
+ //#endregion
12
+ export { MetricStrip as default };
13
+ //# sourceMappingURL=MetricStrip.d.mts.map