@lobehub/ui 5.58.0 → 5.59.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 (81) hide show
  1. package/es/Grid/style.mjs +8 -8
  2. package/es/Grid/style.mjs.map +1 -1
  3. package/es/base-ui/Input/style.mjs +8 -2
  4. package/es/base-ui/Input/style.mjs.map +1 -1
  5. package/es/dashboard/ChartGrid/ChartGrid.d.mts +10 -0
  6. package/es/dashboard/ChartGrid/ChartGrid.mjs +18 -0
  7. package/es/dashboard/ChartGrid/ChartGrid.mjs.map +1 -0
  8. package/es/dashboard/ChartGrid/index.d.mts +3 -0
  9. package/es/dashboard/ChartGrid/style.mjs +32 -0
  10. package/es/dashboard/ChartGrid/style.mjs.map +1 -0
  11. package/es/dashboard/ChartGrid/type.d.mts +9 -0
  12. package/es/dashboard/ConsoleShell/ConsoleShell.d.mts +1 -1
  13. package/es/dashboard/ConsoleShell/ConsoleShell.mjs +12 -4
  14. package/es/dashboard/ConsoleShell/ConsoleShell.mjs.map +1 -1
  15. package/es/dashboard/ConsoleShell/style.mjs +15 -0
  16. package/es/dashboard/ConsoleShell/style.mjs.map +1 -1
  17. package/es/dashboard/ConsoleShell/type.d.mts +2 -0
  18. package/es/dashboard/FilterStrip/FilterStrip.d.mts +11 -0
  19. package/es/dashboard/FilterStrip/FilterStrip.mjs +51 -0
  20. package/es/dashboard/FilterStrip/FilterStrip.mjs.map +1 -0
  21. package/es/dashboard/FilterStrip/index.d.mts +3 -0
  22. package/es/dashboard/FilterStrip/style.mjs +93 -0
  23. package/es/dashboard/FilterStrip/style.mjs.map +1 -0
  24. package/es/dashboard/FilterStrip/type.d.mts +26 -0
  25. package/es/dashboard/LabelWithKey/LabelWithKey.d.mts +10 -0
  26. package/es/dashboard/LabelWithKey/LabelWithKey.mjs +18 -0
  27. package/es/dashboard/LabelWithKey/LabelWithKey.mjs.map +1 -0
  28. package/es/dashboard/LabelWithKey/index.d.mts +3 -0
  29. package/es/dashboard/LabelWithKey/type.d.mts +12 -0
  30. package/es/dashboard/MetricStrip/MetricStrip.d.mts +10 -0
  31. package/es/dashboard/MetricStrip/MetricStrip.mjs +76 -0
  32. package/es/dashboard/MetricStrip/MetricStrip.mjs.map +1 -0
  33. package/es/dashboard/MetricStrip/index.d.mts +3 -0
  34. package/es/dashboard/MetricStrip/style.mjs +116 -0
  35. package/es/dashboard/MetricStrip/style.mjs.map +1 -0
  36. package/es/dashboard/MetricStrip/type.d.mts +25 -0
  37. package/es/dashboard/PageToolbar/PageToolbar.d.mts +10 -0
  38. package/es/dashboard/PageToolbar/PageToolbar.mjs +21 -0
  39. package/es/dashboard/PageToolbar/PageToolbar.mjs.map +1 -0
  40. package/es/dashboard/PageToolbar/index.d.mts +3 -0
  41. package/es/dashboard/PageToolbar/style.mjs +34 -0
  42. package/es/dashboard/PageToolbar/style.mjs.map +1 -0
  43. package/es/dashboard/PageToolbar/type.d.mts +12 -0
  44. package/es/dashboard/PanelSurface/PanelSurface.d.mts +10 -0
  45. package/es/dashboard/PanelSurface/PanelSurface.mjs +36 -0
  46. package/es/dashboard/PanelSurface/PanelSurface.mjs.map +1 -0
  47. package/es/dashboard/PanelSurface/index.d.mts +3 -0
  48. package/es/dashboard/PanelSurface/style.mjs +24 -0
  49. package/es/dashboard/PanelSurface/style.mjs.map +1 -0
  50. package/es/dashboard/PanelSurface/type.d.mts +18 -0
  51. package/es/dashboard/Section/Section.d.mts +10 -0
  52. package/es/dashboard/Section/Section.mjs +81 -0
  53. package/es/dashboard/Section/Section.mjs.map +1 -0
  54. package/es/dashboard/Section/index.d.mts +3 -0
  55. package/es/dashboard/Section/style.mjs +35 -0
  56. package/es/dashboard/Section/style.mjs.map +1 -0
  57. package/es/dashboard/Section/type.d.mts +24 -0
  58. package/es/dashboard/Surface/Surface.d.mts +4 -3
  59. package/es/dashboard/Surface/Surface.mjs +67 -7
  60. package/es/dashboard/Surface/Surface.mjs.map +1 -1
  61. package/es/dashboard/Surface/index.d.mts +3 -2
  62. package/es/dashboard/Surface/link.d.mts +14 -0
  63. package/es/dashboard/Surface/link.mjs +22 -0
  64. package/es/dashboard/Surface/link.mjs.map +1 -0
  65. package/es/dashboard/Surface/style.d.mts +23 -0
  66. package/es/dashboard/Surface/style.mjs +283 -2
  67. package/es/dashboard/Surface/style.mjs.map +1 -1
  68. package/es/dashboard/Surface/type.d.mts +30 -2
  69. package/es/dashboard/TableIconActions/TableIconActions.d.mts +17 -0
  70. package/es/dashboard/TableIconActions/TableIconActions.mjs +39 -0
  71. package/es/dashboard/TableIconActions/TableIconActions.mjs.map +1 -0
  72. package/es/dashboard/TableIconActions/index.d.mts +3 -0
  73. package/es/dashboard/TableIconActions/type.d.mts +18 -0
  74. package/es/dashboard/TitleWithTips/TitleWithTips.d.mts +10 -0
  75. package/es/dashboard/TitleWithTips/TitleWithTips.mjs +28 -0
  76. package/es/dashboard/TitleWithTips/TitleWithTips.mjs.map +1 -0
  77. package/es/dashboard/TitleWithTips/index.d.mts +3 -0
  78. package/es/dashboard/TitleWithTips/type.d.mts +11 -0
  79. package/es/dashboard/index.d.mts +30 -2
  80. package/es/dashboard/index.mjs +12 -2
  81. package/package.json +1 -1
package/es/Grid/style.mjs CHANGED
@@ -1,5 +1,11 @@
1
1
  import { createStaticStyles } from "antd-style";
2
2
  //#region src/Grid/style.ts
3
+ /**
4
+ * `--max-item-width` is the column's minimum width. Clamp it to the container,
5
+ * otherwise a value wider than a phone screen overflows the page instead of
6
+ * collapsing to one column.
7
+ */
8
+ const gridTemplateColumns = "repeat(auto-fill, minmax(max(min(var(--max-item-width), 100%), calc((100% - var(--gap) * (var(--rows) - 1)) / var(--rows))), 1fr))";
3
9
  const styles = createStaticStyles(({ css }) => {
4
10
  return css`
5
11
  --rows: var(--grid-rows, 3);
@@ -7,16 +13,10 @@ const styles = createStaticStyles(({ css }) => {
7
13
  --gap: var(--grid-gap, 1em);
8
14
 
9
15
  display: grid !important;
10
- grid-template-columns: repeat(
11
- auto-fill,
12
- minmax(
13
- max(var(--max-item-width), calc((100% - var(--gap) * (var(--rows) - 1)) / var(--rows))),
14
- 1fr
15
- )
16
- );
16
+ grid-template-columns: ${gridTemplateColumns};
17
17
  `;
18
18
  });
19
19
  //#endregion
20
- export { styles };
20
+ export { gridTemplateColumns, styles };
21
21
 
22
22
  //# sourceMappingURL=style.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"style.mjs","names":[],"sources":["../../src/Grid/style.ts"],"sourcesContent":["import { createStaticStyles } from 'antd-style';\n\nexport const styles = createStaticStyles(({ css }) => {\n return css`\n --rows: var(--grid-rows, 3);\n --max-item-width: var(--grid-max-item-width, 240px);\n --gap: var(--grid-gap, 1em);\n\n display: grid !important;\n grid-template-columns: repeat(\n auto-fill,\n minmax(\n max(var(--max-item-width), calc((100% - var(--gap) * (var(--rows) - 1)) / var(--rows))),\n 1fr\n )\n );\n `;\n});\n"],"mappings":";;AAEA,MAAa,SAAS,oBAAoB,EAAE,UAAU;CACpD,OAAO,GAAG;;;;;;;;;;;;;;AAcZ,CAAC"}
1
+ {"version":3,"file":"style.mjs","names":[],"sources":["../../src/Grid/style.ts"],"sourcesContent":["import { createStaticStyles } from 'antd-style';\n\n/**\n * `--max-item-width` is the column's minimum width. Clamp it to the container,\n * otherwise a value wider than a phone screen overflows the page instead of\n * collapsing to one column.\n */\nexport const gridTemplateColumns =\n 'repeat(auto-fill, minmax(max(min(var(--max-item-width), 100%), calc((100% - var(--gap) * (var(--rows) - 1)) / var(--rows))), 1fr))';\n\nexport const styles = createStaticStyles(({ css }) => {\n return css`\n --rows: var(--grid-rows, 3);\n --max-item-width: var(--grid-max-item-width, 240px);\n --gap: var(--grid-gap, 1em);\n\n display: grid !important;\n grid-template-columns: ${gridTemplateColumns};\n `;\n});\n"],"mappings":";;;;;;;AAOA,MAAa,sBACX;AAEF,MAAa,SAAS,oBAAoB,EAAE,UAAU;CACpD,OAAO,GAAG;;;;;;6BAMiB,oBAAoB;;AAEjD,CAAC"}
@@ -3,6 +3,12 @@ import { controlHeight } from "../controlSize.mjs";
3
3
  import { createStaticStyles } from "antd-style";
4
4
  import { cva } from "class-variance-authority";
5
5
  //#region src/base-ui/Input/style.ts
6
+ /**
7
+ * Only the field's own control counts as disabled. NumberField disables its
8
+ * increment / decrement buttons at max / min, and a bare `:has(:disabled)` greyed
9
+ * the whole root whenever the value sat on a bound.
10
+ */
11
+ const disabledControl = "input:disabled, textarea:disabled";
6
12
  const styles = createStaticStyles(({ css, cssVar }) => ({
7
13
  clear: css`
8
14
  cursor: pointer;
@@ -140,7 +146,7 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
140
146
  box-shadow 150ms ${cssVar.motionEaseOut};
141
147
 
142
148
  &[data-disabled],
143
- &:has(:disabled) {
149
+ &:has(${disabledControl}) {
144
150
  cursor: not-allowed;
145
151
  color: ${cssVar.colorTextQuaternary};
146
152
  opacity: 0.66;
@@ -306,6 +312,6 @@ const rootVariants = cva([styles.root, styles.invalid], {
306
312
  }
307
313
  });
308
314
  //#endregion
309
- export { rootVariants, styles };
315
+ export { disabledControl, rootVariants, styles };
310
316
 
311
317
  //# sourceMappingURL=style.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"style.mjs","names":["lobeStaticStylish"],"sources":["../../../src/base-ui/Input/style.ts"],"sourcesContent":["import { createStaticStyles } from 'antd-style';\nimport { cva } from 'class-variance-authority';\n\nimport { controlHeight } from '@/base-ui/controlSize';\nimport { lobeStaticStylish } from '@/styles';\n\nexport const styles = createStaticStyles(({ css, cssVar }) => ({\n clear: css`\n cursor: pointer;\n\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n\n width: 16px;\n height: 16px;\n padding: 0;\n border: 0;\n border-radius: 50%;\n\n color: ${cssVar.colorBgContainer};\n\n visibility: hidden;\n background: ${cssVar.colorTextQuaternary};\n\n &:hover {\n background: ${cssVar.colorTextTertiary};\n }\n `,\n count: css`\n pointer-events: none;\n\n position: absolute;\n inset-block-end: 6px;\n inset-inline-end: 8px;\n\n display: inline-flex;\n align-items: center;\n\n height: 20px;\n padding-inline: 8px;\n border-radius: 999px;\n\n font-size: 11px;\n font-weight: 600;\n font-variant-numeric: tabular-nums;\n color: ${cssVar.colorTextSecondary};\n\n background: ${cssVar.colorFillTertiary};\n\n &[data-over] {\n color: ${cssVar.colorWhite};\n background: ${cssVar.colorError};\n }\n `,\n textareaClear: css`\n position: absolute;\n inset-block-start: 10px;\n inset-inline-end: 10px;\n `,\n textareaWithCount: css`\n padding-block-end: 30px;\n `,\n borderless: css`\n border: 1px solid transparent;\n background: none;\n `,\n filled: css`\n border: 1px solid transparent;\n background: ${cssVar.colorFillTertiary};\n\n &:hover:not(:focus-within, [data-disabled]) {\n background: ${cssVar.colorFillSecondary};\n }\n `,\n input: css`\n flex: 1;\n\n min-width: 0;\n padding: 0;\n border: none;\n\n font: inherit;\n color: inherit;\n\n appearance: none;\n background: transparent;\n outline: none;\n\n &::placeholder {\n color: ${cssVar.colorTextPlaceholder};\n }\n\n /* the root shows focus via its border; outrank global :focus-visible rings */\n &:focus-visible {\n outline: none;\n }\n `,\n invalid: css`\n &:has([data-invalid], [aria-invalid='true']) {\n border-color: ${cssVar.colorError};\n\n &:focus-within {\n border-color: ${cssVar.colorError};\n box-shadow: 0 0 0 2px ${cssVar.colorErrorBg};\n }\n }\n `,\n outlined: css`\n border: 1px solid ${cssVar.colorBorderSecondary};\n background: ${cssVar.colorBgContainer};\n\n &:hover:not(:focus-within, [data-disabled]) {\n border-color: ${cssVar.colorBorder};\n }\n\n &:focus-within {\n border-color: ${cssVar.colorPrimary};\n box-shadow: 0 0 0 2px ${cssVar.colorPrimaryBg};\n }\n `,\n root: css`\n cursor: text;\n\n display: inline-flex;\n gap: 8px;\n align-items: center;\n\n box-sizing: border-box;\n width: 100%;\n padding-inline: 12px;\n border-radius: ${cssVar.borderRadius};\n\n font-size: 14px;\n color: ${cssVar.colorText};\n\n transition:\n background 150ms ${cssVar.motionEaseOut},\n border-color 150ms ${cssVar.motionEaseOut},\n box-shadow 150ms ${cssVar.motionEaseOut};\n\n &[data-disabled],\n &:has(:disabled) {\n cursor: not-allowed;\n color: ${cssVar.colorTextQuaternary};\n opacity: 0.66;\n }\n\n &:hover [data-lobe-input-clear],\n &:focus-within [data-lobe-input-clear] {\n visibility: visible;\n }\n `,\n shadow: lobeStaticStylish.shadow,\n sizeLarge: css`\n min-height: ${controlHeight.large}px;\n border-radius: ${cssVar.borderRadiusLG};\n font-size: 16px;\n `,\n sizeMiddle: css`\n min-height: ${controlHeight.middle}px;\n `,\n sizeSmall: css`\n min-height: ${controlHeight.small}px;\n padding-inline: 8px;\n border-radius: ${cssVar.borderRadiusSM};\n font-size: 12px;\n `,\n numberControl: css`\n cursor: pointer;\n\n display: flex;\n align-items: center;\n justify-content: center;\n\n width: 20px;\n height: 13px;\n margin: 0;\n padding: 0;\n border: none;\n border-radius: 4px;\n\n color: ${cssVar.colorTextTertiary};\n\n background: none;\n outline: none;\n\n transition:\n color 150ms ${cssVar.motionEaseOut},\n background 150ms ${cssVar.motionEaseOut};\n\n &:hover:not(:disabled) {\n color: ${cssVar.colorText};\n background: ${cssVar.colorFillSecondary};\n }\n\n &:disabled {\n cursor: not-allowed;\n opacity: 0.3;\n }\n `,\n numberControlLarge: css`\n width: 22px;\n height: 15px;\n `,\n numberControlSmall: css`\n width: 16px;\n height: 10px;\n border-radius: 3px;\n `,\n numberControls: css`\n display: flex;\n flex: none;\n flex-direction: column;\n margin-inline-end: -6px;\n `,\n numberControlsSmall: css`\n margin-inline-end: -4px;\n `,\n numberInput: css`\n font-variant-numeric: tabular-nums;\n `,\n otpCell: css`\n flex: none;\n width: ${controlHeight.middle}px;\n padding-inline: 0;\n text-align: center;\n `,\n otpRoot: css`\n display: inline-flex;\n gap: 8px;\n align-items: center;\n `,\n passwordToggle: css`\n cursor: pointer;\n\n display: inline-flex;\n align-items: center;\n justify-content: center;\n\n margin: 0;\n padding: 0;\n border: none;\n\n color: ${cssVar.colorTextTertiary};\n\n background: none;\n outline: none;\n\n transition: color 150ms ${cssVar.motionEaseOut};\n\n &:hover {\n color: ${cssVar.colorText};\n }\n `,\n slot: css`\n display: inline-flex;\n flex: none;\n align-items: center;\n color: ${cssVar.colorTextTertiary};\n `,\n textarea: css`\n position: relative;\n height: auto;\n padding-block: 8px;\n\n textarea {\n resize: none;\n min-height: calc(1.5em * var(--textarea-min-rows, 2));\n max-height: var(--textarea-max-height, none);\n line-height: 1.5;\n }\n `,\n textareaAutoSize: css`\n textarea {\n field-sizing: content;\n }\n `,\n textareaResize: css`\n textarea {\n resize: vertical;\n }\n `,\n}));\n\nexport const rootVariants = cva([styles.root, styles.invalid], {\n defaultVariants: {\n shadow: false,\n size: 'middle',\n variant: 'outlined',\n },\n variants: {\n shadow: {\n false: null,\n true: styles.shadow,\n },\n size: {\n large: styles.sizeLarge,\n middle: styles.sizeMiddle,\n small: styles.sizeSmall,\n },\n variant: {\n borderless: styles.borderless,\n filled: styles.filled,\n outlined: styles.outlined,\n },\n },\n});\n"],"mappings":";;;;;AAMA,MAAa,SAAS,oBAAoB,EAAE,KAAK,cAAc;CAC7D,OAAO,GAAG;;;;;;;;;;;;;;aAcC,OAAO,iBAAiB;;;kBAGnB,OAAO,oBAAoB;;;oBAGzB,OAAO,kBAAkB;;;CAG3C,OAAO,GAAG;;;;;;;;;;;;;;;;;aAiBC,OAAO,mBAAmB;;kBAErB,OAAO,kBAAkB;;;eAG5B,OAAO,WAAW;oBACb,OAAO,WAAW;;;CAGpC,eAAe,GAAG;;;;;CAKlB,mBAAmB,GAAG;;;CAGtB,YAAY,GAAG;;;;CAIf,QAAQ,GAAG;;kBAEK,OAAO,kBAAkB;;;oBAGvB,OAAO,mBAAmB;;;CAG5C,OAAO,GAAG;;;;;;;;;;;;;;;eAeG,OAAO,qBAAqB;;;;;;;;CAQzC,SAAS,GAAG;;sBAEQ,OAAO,WAAW;;;wBAGhB,OAAO,WAAW;gCACV,OAAO,aAAa;;;;CAIlD,UAAU,GAAG;wBACS,OAAO,qBAAqB;kBAClC,OAAO,iBAAiB;;;sBAGpB,OAAO,YAAY;;;;sBAInB,OAAO,aAAa;8BACZ,OAAO,eAAe;;;CAGlD,MAAM,GAAG;;;;;;;;;;qBAUU,OAAO,aAAa;;;aAG5B,OAAO,UAAU;;;yBAGL,OAAO,cAAc;2BACnB,OAAO,cAAc;yBACvB,OAAO,cAAc;;;;;eAK/B,OAAO,oBAAoB;;;;;;;;;CASxC,QAAQA,cAAkB;CAC1B,WAAW,GAAG;kBACE,cAAc,MAAM;qBACjB,OAAO,eAAe;;;CAGzC,YAAY,GAAG;kBACC,cAAc,OAAO;;CAErC,WAAW,GAAG;kBACE,cAAc,MAAM;;qBAEjB,OAAO,eAAe;;;CAGzC,eAAe,GAAG;;;;;;;;;;;;;;aAcP,OAAO,kBAAkB;;;;;;oBAMlB,OAAO,cAAc;yBAChB,OAAO,cAAc;;;eAG/B,OAAO,UAAU;oBACZ,OAAO,mBAAmB;;;;;;;;CAQ5C,oBAAoB,GAAG;;;;CAIvB,oBAAoB,GAAG;;;;;CAKvB,gBAAgB,GAAG;;;;;;CAMnB,qBAAqB,GAAG;;;CAGxB,aAAa,GAAG;;;CAGhB,SAAS,GAAG;;aAED,cAAc,OAAO;;;;CAIhC,SAAS,GAAG;;;;;CAKZ,gBAAgB,GAAG;;;;;;;;;;;aAWR,OAAO,kBAAkB;;;;;8BAKR,OAAO,cAAc;;;eAGpC,OAAO,UAAU;;;CAG9B,MAAM,GAAG;;;;aAIE,OAAO,kBAAkB;;CAEpC,UAAU,GAAG;;;;;;;;;;;;CAYb,kBAAkB,GAAG;;;;;CAKrB,gBAAgB,GAAG;;;;;AAKrB,EAAE;AAEF,MAAa,eAAe,IAAI,CAAC,OAAO,MAAM,OAAO,OAAO,GAAG;CAC7D,iBAAiB;EACf,QAAQ;EACR,MAAM;EACN,SAAS;CACX;CACA,UAAU;EACR,QAAQ;GACN,OAAO;GACP,MAAM,OAAO;EACf;EACA,MAAM;GACJ,OAAO,OAAO;GACd,QAAQ,OAAO;GACf,OAAO,OAAO;EAChB;EACA,SAAS;GACP,YAAY,OAAO;GACnB,QAAQ,OAAO;GACf,UAAU,OAAO;EACnB;CACF;AACF,CAAC"}
1
+ {"version":3,"file":"style.mjs","names":["lobeStaticStylish"],"sources":["../../../src/base-ui/Input/style.ts"],"sourcesContent":["import { createStaticStyles } from 'antd-style';\nimport { cva } from 'class-variance-authority';\n\nimport { controlHeight } from '@/base-ui/controlSize';\nimport { lobeStaticStylish } from '@/styles';\n\n/**\n * Only the field's own control counts as disabled. NumberField disables its\n * increment / decrement buttons at max / min, and a bare `:has(:disabled)` greyed\n * the whole root whenever the value sat on a bound.\n */\nexport const disabledControl = 'input:disabled, textarea:disabled';\n\nexport const styles = createStaticStyles(({ css, cssVar }) => ({\n clear: css`\n cursor: pointer;\n\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n\n width: 16px;\n height: 16px;\n padding: 0;\n border: 0;\n border-radius: 50%;\n\n color: ${cssVar.colorBgContainer};\n\n visibility: hidden;\n background: ${cssVar.colorTextQuaternary};\n\n &:hover {\n background: ${cssVar.colorTextTertiary};\n }\n `,\n count: css`\n pointer-events: none;\n\n position: absolute;\n inset-block-end: 6px;\n inset-inline-end: 8px;\n\n display: inline-flex;\n align-items: center;\n\n height: 20px;\n padding-inline: 8px;\n border-radius: 999px;\n\n font-size: 11px;\n font-weight: 600;\n font-variant-numeric: tabular-nums;\n color: ${cssVar.colorTextSecondary};\n\n background: ${cssVar.colorFillTertiary};\n\n &[data-over] {\n color: ${cssVar.colorWhite};\n background: ${cssVar.colorError};\n }\n `,\n textareaClear: css`\n position: absolute;\n inset-block-start: 10px;\n inset-inline-end: 10px;\n `,\n textareaWithCount: css`\n padding-block-end: 30px;\n `,\n borderless: css`\n border: 1px solid transparent;\n background: none;\n `,\n filled: css`\n border: 1px solid transparent;\n background: ${cssVar.colorFillTertiary};\n\n &:hover:not(:focus-within, [data-disabled]) {\n background: ${cssVar.colorFillSecondary};\n }\n `,\n input: css`\n flex: 1;\n\n min-width: 0;\n padding: 0;\n border: none;\n\n font: inherit;\n color: inherit;\n\n appearance: none;\n background: transparent;\n outline: none;\n\n &::placeholder {\n color: ${cssVar.colorTextPlaceholder};\n }\n\n /* the root shows focus via its border; outrank global :focus-visible rings */\n &:focus-visible {\n outline: none;\n }\n `,\n invalid: css`\n &:has([data-invalid], [aria-invalid='true']) {\n border-color: ${cssVar.colorError};\n\n &:focus-within {\n border-color: ${cssVar.colorError};\n box-shadow: 0 0 0 2px ${cssVar.colorErrorBg};\n }\n }\n `,\n outlined: css`\n border: 1px solid ${cssVar.colorBorderSecondary};\n background: ${cssVar.colorBgContainer};\n\n &:hover:not(:focus-within, [data-disabled]) {\n border-color: ${cssVar.colorBorder};\n }\n\n &:focus-within {\n border-color: ${cssVar.colorPrimary};\n box-shadow: 0 0 0 2px ${cssVar.colorPrimaryBg};\n }\n `,\n root: css`\n cursor: text;\n\n display: inline-flex;\n gap: 8px;\n align-items: center;\n\n box-sizing: border-box;\n width: 100%;\n padding-inline: 12px;\n border-radius: ${cssVar.borderRadius};\n\n font-size: 14px;\n color: ${cssVar.colorText};\n\n transition:\n background 150ms ${cssVar.motionEaseOut},\n border-color 150ms ${cssVar.motionEaseOut},\n box-shadow 150ms ${cssVar.motionEaseOut};\n\n &[data-disabled],\n &:has(${disabledControl}) {\n cursor: not-allowed;\n color: ${cssVar.colorTextQuaternary};\n opacity: 0.66;\n }\n\n &:hover [data-lobe-input-clear],\n &:focus-within [data-lobe-input-clear] {\n visibility: visible;\n }\n `,\n shadow: lobeStaticStylish.shadow,\n sizeLarge: css`\n min-height: ${controlHeight.large}px;\n border-radius: ${cssVar.borderRadiusLG};\n font-size: 16px;\n `,\n sizeMiddle: css`\n min-height: ${controlHeight.middle}px;\n `,\n sizeSmall: css`\n min-height: ${controlHeight.small}px;\n padding-inline: 8px;\n border-radius: ${cssVar.borderRadiusSM};\n font-size: 12px;\n `,\n numberControl: css`\n cursor: pointer;\n\n display: flex;\n align-items: center;\n justify-content: center;\n\n width: 20px;\n height: 13px;\n margin: 0;\n padding: 0;\n border: none;\n border-radius: 4px;\n\n color: ${cssVar.colorTextTertiary};\n\n background: none;\n outline: none;\n\n transition:\n color 150ms ${cssVar.motionEaseOut},\n background 150ms ${cssVar.motionEaseOut};\n\n &:hover:not(:disabled) {\n color: ${cssVar.colorText};\n background: ${cssVar.colorFillSecondary};\n }\n\n &:disabled {\n cursor: not-allowed;\n opacity: 0.3;\n }\n `,\n numberControlLarge: css`\n width: 22px;\n height: 15px;\n `,\n numberControlSmall: css`\n width: 16px;\n height: 10px;\n border-radius: 3px;\n `,\n numberControls: css`\n display: flex;\n flex: none;\n flex-direction: column;\n margin-inline-end: -6px;\n `,\n numberControlsSmall: css`\n margin-inline-end: -4px;\n `,\n numberInput: css`\n font-variant-numeric: tabular-nums;\n `,\n otpCell: css`\n flex: none;\n width: ${controlHeight.middle}px;\n padding-inline: 0;\n text-align: center;\n `,\n otpRoot: css`\n display: inline-flex;\n gap: 8px;\n align-items: center;\n `,\n passwordToggle: css`\n cursor: pointer;\n\n display: inline-flex;\n align-items: center;\n justify-content: center;\n\n margin: 0;\n padding: 0;\n border: none;\n\n color: ${cssVar.colorTextTertiary};\n\n background: none;\n outline: none;\n\n transition: color 150ms ${cssVar.motionEaseOut};\n\n &:hover {\n color: ${cssVar.colorText};\n }\n `,\n slot: css`\n display: inline-flex;\n flex: none;\n align-items: center;\n color: ${cssVar.colorTextTertiary};\n `,\n textarea: css`\n position: relative;\n height: auto;\n padding-block: 8px;\n\n textarea {\n resize: none;\n min-height: calc(1.5em * var(--textarea-min-rows, 2));\n max-height: var(--textarea-max-height, none);\n line-height: 1.5;\n }\n `,\n textareaAutoSize: css`\n textarea {\n field-sizing: content;\n }\n `,\n textareaResize: css`\n textarea {\n resize: vertical;\n }\n `,\n}));\n\nexport const rootVariants = cva([styles.root, styles.invalid], {\n defaultVariants: {\n shadow: false,\n size: 'middle',\n variant: 'outlined',\n },\n variants: {\n shadow: {\n false: null,\n true: styles.shadow,\n },\n size: {\n large: styles.sizeLarge,\n middle: styles.sizeMiddle,\n small: styles.sizeSmall,\n },\n variant: {\n borderless: styles.borderless,\n filled: styles.filled,\n outlined: styles.outlined,\n },\n },\n});\n"],"mappings":";;;;;;;;;;AAWA,MAAa,kBAAkB;AAE/B,MAAa,SAAS,oBAAoB,EAAE,KAAK,cAAc;CAC7D,OAAO,GAAG;;;;;;;;;;;;;;aAcC,OAAO,iBAAiB;;;kBAGnB,OAAO,oBAAoB;;;oBAGzB,OAAO,kBAAkB;;;CAG3C,OAAO,GAAG;;;;;;;;;;;;;;;;;aAiBC,OAAO,mBAAmB;;kBAErB,OAAO,kBAAkB;;;eAG5B,OAAO,WAAW;oBACb,OAAO,WAAW;;;CAGpC,eAAe,GAAG;;;;;CAKlB,mBAAmB,GAAG;;;CAGtB,YAAY,GAAG;;;;CAIf,QAAQ,GAAG;;kBAEK,OAAO,kBAAkB;;;oBAGvB,OAAO,mBAAmB;;;CAG5C,OAAO,GAAG;;;;;;;;;;;;;;;eAeG,OAAO,qBAAqB;;;;;;;;CAQzC,SAAS,GAAG;;sBAEQ,OAAO,WAAW;;;wBAGhB,OAAO,WAAW;gCACV,OAAO,aAAa;;;;CAIlD,UAAU,GAAG;wBACS,OAAO,qBAAqB;kBAClC,OAAO,iBAAiB;;;sBAGpB,OAAO,YAAY;;;;sBAInB,OAAO,aAAa;8BACZ,OAAO,eAAe;;;CAGlD,MAAM,GAAG;;;;;;;;;;qBAUU,OAAO,aAAa;;;aAG5B,OAAO,UAAU;;;yBAGL,OAAO,cAAc;2BACnB,OAAO,cAAc;yBACvB,OAAO,cAAc;;;YAGlC,gBAAgB;;eAEb,OAAO,oBAAoB;;;;;;;;;CASxC,QAAQA,cAAkB;CAC1B,WAAW,GAAG;kBACE,cAAc,MAAM;qBACjB,OAAO,eAAe;;;CAGzC,YAAY,GAAG;kBACC,cAAc,OAAO;;CAErC,WAAW,GAAG;kBACE,cAAc,MAAM;;qBAEjB,OAAO,eAAe;;;CAGzC,eAAe,GAAG;;;;;;;;;;;;;;aAcP,OAAO,kBAAkB;;;;;;oBAMlB,OAAO,cAAc;yBAChB,OAAO,cAAc;;;eAG/B,OAAO,UAAU;oBACZ,OAAO,mBAAmB;;;;;;;;CAQ5C,oBAAoB,GAAG;;;;CAIvB,oBAAoB,GAAG;;;;;CAKvB,gBAAgB,GAAG;;;;;;CAMnB,qBAAqB,GAAG;;;CAGxB,aAAa,GAAG;;;CAGhB,SAAS,GAAG;;aAED,cAAc,OAAO;;;;CAIhC,SAAS,GAAG;;;;;CAKZ,gBAAgB,GAAG;;;;;;;;;;;aAWR,OAAO,kBAAkB;;;;;8BAKR,OAAO,cAAc;;;eAGpC,OAAO,UAAU;;;CAG9B,MAAM,GAAG;;;;aAIE,OAAO,kBAAkB;;CAEpC,UAAU,GAAG;;;;;;;;;;;;CAYb,kBAAkB,GAAG;;;;;CAKrB,gBAAgB,GAAG;;;;;AAKrB,EAAE;AAEF,MAAa,eAAe,IAAI,CAAC,OAAO,MAAM,OAAO,OAAO,GAAG;CAC7D,iBAAiB;EACf,QAAQ;EACR,MAAM;EACN,SAAS;CACX;CACA,UAAU;EACR,QAAQ;GACN,OAAO;GACP,MAAM,OAAO;EACf;EACA,MAAM;GACJ,OAAO,OAAO;GACd,QAAQ,OAAO;GACf,OAAO,OAAO;EAChB;EACA,SAAS;GACP,YAAY,OAAO;GACnB,QAAQ,OAAO;GACf,UAAU,OAAO;EACnB;CACF;AACF,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { ChartGridProps } from "./type.mjs";
2
+ //#region src/dashboard/ChartGrid/ChartGrid.d.ts
3
+ /** Peer charts and ranked lists, two-up, one column below 640px. Not for label/value rows. */
4
+ declare const ChartGrid: {
5
+ ({ children, className }: ChartGridProps): import("react").JSX.Element;
6
+ displayName: string;
7
+ };
8
+ //#endregion
9
+ export { ChartGrid as default };
10
+ //# sourceMappingURL=ChartGrid.d.mts.map
@@ -0,0 +1,18 @@
1
+ "use client";
2
+ import { styles } from "./style.mjs";
3
+ import { jsx } from "react/jsx-runtime";
4
+ import { cx } from "antd-style";
5
+ //#region src/dashboard/ChartGrid/ChartGrid.tsx
6
+ /** Peer charts and ranked lists, two-up, one column below 640px. Not for label/value rows. */
7
+ const ChartGrid = ({ children, className }) => /* @__PURE__ */ jsx("div", {
8
+ className: styles.frame,
9
+ children: /* @__PURE__ */ jsx("div", {
10
+ className: cx(styles.root, className),
11
+ children
12
+ })
13
+ });
14
+ ChartGrid.displayName = "ChartGrid";
15
+ //#endregion
16
+ export { ChartGrid as default };
17
+
18
+ //# sourceMappingURL=ChartGrid.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChartGrid.mjs","names":[],"sources":["../../../src/dashboard/ChartGrid/ChartGrid.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\n\nimport { styles } from './style';\nimport type { ChartGridProps } from './type';\n\n/** Peer charts and ranked lists, two-up, one column below 640px. Not for label/value rows. */\nconst ChartGrid = ({ children, className }: ChartGridProps) => (\n <div className={styles.frame}>\n <div className={cx(styles.root, className)}>{children}</div>\n </div>\n);\n\nChartGrid.displayName = 'ChartGrid';\n\nexport default ChartGrid;\n"],"mappings":";;;;;;AAQA,MAAM,aAAa,EAAE,UAAU,gBAC7B,oBAAC,OAAD;CAAK,WAAW,OAAO;CACrB,UAAA,oBAAC,OAAD;EAAK,WAAW,GAAG,OAAO,MAAM,SAAS;EAAI;CAAc,CAAA;AACxD,CAAA;AAGP,UAAU,cAAc"}
@@ -0,0 +1,3 @@
1
+ import { ChartGridProps } from "./type.mjs";
2
+ import ChartGrid from "./ChartGrid.mjs";
3
+ export { type ChartGridProps, ChartGrid as default };
@@ -0,0 +1,32 @@
1
+ import { createStaticStyles } from "antd-style";
2
+ //#region src/dashboard/ChartGrid/style.ts
3
+ const styles = createStaticStyles(({ css }) => ({
4
+ /**
5
+ * The frame is the container. A query on the grid itself would not see its own width.
6
+ * Charts stay two-up so a trend and its switch stay readable; one child does not
7
+ * stretch across the page.
8
+ */
9
+ frame: css`
10
+ container-type: inline-size;
11
+
12
+ @container (max-width: 640px) {
13
+ & > * {
14
+ grid-template-columns: minmax(0, 1fr);
15
+ }
16
+ }
17
+ `,
18
+ root: css`
19
+ display: grid;
20
+ grid-template-columns: repeat(2, minmax(0, 1fr));
21
+ gap: 16px;
22
+ align-items: stretch;
23
+
24
+ &:has(> :only-child) {
25
+ grid-template-columns: minmax(0, min(100%, 560px));
26
+ }
27
+ `
28
+ }));
29
+ //#endregion
30
+ export { styles };
31
+
32
+ //# sourceMappingURL=style.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style.mjs","names":[],"sources":["../../../src/dashboard/ChartGrid/style.ts"],"sourcesContent":["import { createStaticStyles } from 'antd-style';\n\nexport const styles = createStaticStyles(({ css }) => ({\n /**\n * The frame is the container. A query on the grid itself would not see its own width.\n * Charts stay two-up so a trend and its switch stay readable; one child does not\n * stretch across the page.\n */\n frame: css`\n container-type: inline-size;\n\n @container (max-width: 640px) {\n & > * {\n grid-template-columns: minmax(0, 1fr);\n }\n }\n `,\n root: css`\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 16px;\n align-items: stretch;\n\n &:has(> :only-child) {\n grid-template-columns: minmax(0, min(100%, 560px));\n }\n `,\n}));\n"],"mappings":";;AAEA,MAAa,SAAS,oBAAoB,EAAE,WAAW;;;;;;CAMrD,OAAO,GAAG;;;;;;;;;CASV,MAAM,GAAG;;;;;;;;;;AAUX,EAAE"}
@@ -0,0 +1,9 @@
1
+ import { ReactNode } from "react";
2
+ //#region src/dashboard/ChartGrid/type.d.ts
3
+ interface ChartGridProps {
4
+ children?: ReactNode;
5
+ className?: string;
6
+ }
7
+ //#endregion
8
+ export { ChartGridProps };
9
+ //# sourceMappingURL=type.d.mts.map
@@ -1,6 +1,6 @@
1
1
  import { ConsoleShellProps } from "./type.mjs";
2
2
  //#region src/dashboard/ConsoleShell/ConsoleShell.d.ts
3
- declare function ConsoleShell({ brand, breadcrumb, children, className, collapsed, collapseLabel, defaultCollapsed, expandLabel, footer, hotkey, navigation, onCollapsedChange, openNavigationLabel, skipToContentLabel, storageKey, tools, ...rest }: ConsoleShellProps): import("react").JSX.Element;
3
+ declare function ConsoleShell({ brand, breadcrumb, children, className, collapsed, closeNavigationLabel, collapseLabel, defaultCollapsed, expandLabel, footer, hotkey, navigation, onCollapsedChange, openNavigationLabel, skipToContentLabel, storageKey, tools, ...rest }: ConsoleShellProps): import("react").JSX.Element;
4
4
  declare namespace ConsoleShell {
5
5
  var displayName: string;
6
6
  }
@@ -7,14 +7,14 @@ import { useIsCompact, useLocalStorage, usePrefersReducedMotion } from "../hooks
7
7
  import { styles } from "./style.mjs";
8
8
  import { useEffect, useId, useRef, useState } from "react";
9
9
  import { jsx, jsxs } from "react/jsx-runtime";
10
- import { PanelLeft } from "lucide-react";
10
+ import { PanelLeft, X } from "lucide-react";
11
11
  //#region src/dashboard/ConsoleShell/ConsoleShell.tsx
12
12
  function isTypingTarget(target) {
13
13
  if (!(target instanceof HTMLElement)) return false;
14
14
  const tag = target.tagName;
15
15
  return tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT" || target.isContentEditable;
16
16
  }
17
- function ConsoleShell({ brand, breadcrumb, children, className, collapsed, collapseLabel = "Collapse sidebar", defaultCollapsed = false, expandLabel = "Expand sidebar", footer, hotkey = true, navigation, onCollapsedChange, openNavigationLabel = "Open navigation", skipToContentLabel = "Skip to content", storageKey, tools, ...rest }) {
17
+ function ConsoleShell({ brand, breadcrumb, children, className, collapsed, closeNavigationLabel = "Close navigation", collapseLabel = "Collapse sidebar", defaultCollapsed = false, expandLabel = "Expand sidebar", footer, hotkey = true, navigation, onCollapsedChange, openNavigationLabel = "Open navigation", skipToContentLabel = "Skip to content", storageKey, tools, ...rest }) {
18
18
  const mainId = `console-main-${useId().replaceAll(":", "")}`;
19
19
  const shellRef = useRef(null);
20
20
  const isCompact = useIsCompact();
@@ -60,10 +60,16 @@ function ConsoleShell({ brand, breadcrumb, children, className, collapsed, colla
60
60
  const sidebar = (rail) => /* @__PURE__ */ jsxs(ConsoleShellContext, {
61
61
  value: stateFor(rail),
62
62
  children: [
63
- brand ? /* @__PURE__ */ jsx("div", {
63
+ brand || isCompact ? /* @__PURE__ */ jsxs("div", {
64
64
  className: styles.brand,
65
65
  "data-collapsed": rail,
66
- children: brand
66
+ children: [brand, isCompact ? /* @__PURE__ */ jsx(Button, {
67
+ "aria-label": closeNavigationLabel,
68
+ className: styles.brandClose,
69
+ icon: X,
70
+ type: "text",
71
+ onClick: closeNavigation
72
+ }) : null]
67
73
  }) : null,
68
74
  navigation ? /* @__PURE__ */ jsx("div", {
69
75
  className: styles.navSlot,
@@ -99,6 +105,8 @@ function ConsoleShell({ brand, breadcrumb, children, className, collapsed, colla
99
105
  }),
100
106
  isCompact ? /* @__PURE__ */ jsx(Drawer, {
101
107
  noHeader: true,
108
+ classNames: { bodyContent: styles.drawerBody },
109
+ closable: false,
102
110
  open: drawerOpen,
103
111
  placement: "left",
104
112
  width: 272,
@@ -1 +1 @@
1
- {"version":3,"file":"ConsoleShell.mjs","names":["Flexbox"],"sources":["../../../src/dashboard/ConsoleShell/ConsoleShell.tsx"],"sourcesContent":["'use client';\n\nimport { PanelLeft } from 'lucide-react';\nimport { useEffect, useId, useRef, useState } from 'react';\n\nimport Button from '@/base-ui/Button';\nimport { Drawer } from '@/base-ui/Drawer';\nimport { Flexbox } from '@/Flex';\n\nimport { useIsCompact, useLocalStorage, usePrefersReducedMotion } from '../hooks';\nimport { ConsoleShellContext } from './context';\nimport { styles } from './style';\nimport type { ConsoleShellProps, ConsoleShellState } from './type';\n\nfunction isTypingTarget(target: EventTarget | null) {\n if (!(target instanceof HTMLElement)) return false;\n const tag = target.tagName;\n return tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' || target.isContentEditable;\n}\n\nfunction ConsoleShell({\n brand,\n breadcrumb,\n children,\n className,\n collapsed,\n collapseLabel = 'Collapse sidebar',\n defaultCollapsed = false,\n expandLabel = 'Expand sidebar',\n footer,\n hotkey = true,\n navigation,\n onCollapsedChange,\n openNavigationLabel = 'Open navigation',\n skipToContentLabel = 'Skip to content',\n storageKey,\n tools,\n ...rest\n}: ConsoleShellProps) {\n const mainId = `console-main-${useId().replaceAll(':', '')}`;\n const shellRef = useRef<HTMLDivElement>(null);\n const isCompact = useIsCompact();\n const reducedMotion = usePrefersReducedMotion();\n const [storedCollapsed, setStoredCollapsed] = useLocalStorage(storageKey, defaultCollapsed);\n const [drawerOpen, setDrawerOpen] = useState(false);\n const isControlled = collapsed !== undefined;\n const railCollapsed = isControlled ? collapsed : storedCollapsed;\n const railed = railCollapsed && !isCompact;\n\n const setCollapsed = (next: boolean) => {\n if (!isControlled) setStoredCollapsed(next);\n onCollapsedChange?.(next);\n };\n\n const closeNavigation = () => setDrawerOpen(false);\n const toggleNavigation = () => {\n if (isCompact) {\n setDrawerOpen((open) => !open);\n return;\n }\n setCollapsed(!railCollapsed);\n };\n const toggleRef = useRef(toggleNavigation);\n toggleRef.current = toggleNavigation;\n\n useEffect(() => {\n if (!hotkey) return;\n const node = shellRef.current;\n if (!node) return;\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key.toLowerCase() !== 'b' || !(event.metaKey || event.ctrlKey) || event.altKey) {\n return;\n }\n if (event.repeat || isTypingTarget(event.target)) return;\n if (!node.contains(event.target as Node)) return;\n event.preventDefault();\n toggleRef.current();\n };\n\n document.addEventListener('keydown', onKeyDown);\n return () => document.removeEventListener('keydown', onKeyDown);\n }, [hotkey]);\n\n const stateFor = (rail: boolean): ConsoleShellState => ({\n closeNavigation,\n collapsed: rail,\n compact: isCompact,\n });\n\n const sidebar = (rail: boolean) => (\n <ConsoleShellContext value={stateFor(rail)}>\n {brand ? (\n <div className={styles.brand} data-collapsed={rail}>\n {brand}\n </div>\n ) : null}\n {navigation ? <div className={styles.navSlot}>{navigation}</div> : null}\n {footer ? <div className={styles.sidebarBottom}>{footer}</div> : null}\n </ConsoleShellContext>\n );\n\n const toggleLabel = isCompact ? openNavigationLabel : railed ? expandLabel : collapseLabel;\n\n return (\n <div\n className={className ? `${styles.shell} ${className}` : styles.shell}\n data-console-shell=\"\"\n ref={shellRef}\n {...rest}\n >\n <a\n className={styles.skipLink}\n href={`#${mainId}`}\n onClick={(event) => {\n event.preventDefault();\n document.getElementById(mainId)?.focus();\n }}\n >\n {skipToContentLabel}\n </a>\n <aside className={styles.sidebar} data-collapsed={railed} data-instant={reducedMotion}>\n {!isCompact && sidebar(railed)}\n </aside>\n {isCompact ? (\n <Drawer noHeader open={drawerOpen} placement=\"left\" width={272} onClose={closeNavigation}>\n <Flexbox height=\"100%\">{sidebar(false)}</Flexbox>\n </Drawer>\n ) : null}\n <div className={styles.workspace}>\n <header className={styles.topbar}>\n <Button\n aria-label={toggleLabel}\n icon={PanelLeft}\n type=\"text\"\n onClick={toggleNavigation}\n />\n <span aria-hidden className={styles.topbarDivider} />\n <div className={styles.topbarMain}>{breadcrumb}</div>\n {tools ? <div className={styles.tools}>{tools}</div> : null}\n </header>\n <main className={styles.main} id={mainId} tabIndex={-1}>\n {children}\n </main>\n </div>\n </div>\n );\n}\n\nConsoleShell.displayName = 'ConsoleShell';\n\nexport default ConsoleShell;\n"],"mappings":"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"}
1
+ {"version":3,"file":"ConsoleShell.mjs","names":["Flexbox"],"sources":["../../../src/dashboard/ConsoleShell/ConsoleShell.tsx"],"sourcesContent":["'use client';\n\nimport { PanelLeft, X } from 'lucide-react';\nimport { useEffect, useId, useRef, useState } from 'react';\n\nimport Button from '@/base-ui/Button';\nimport { Drawer } from '@/base-ui/Drawer';\nimport { Flexbox } from '@/Flex';\n\nimport { useIsCompact, useLocalStorage, usePrefersReducedMotion } from '../hooks';\nimport { ConsoleShellContext } from './context';\nimport { styles } from './style';\nimport type { ConsoleShellProps, ConsoleShellState } from './type';\n\nfunction isTypingTarget(target: EventTarget | null) {\n if (!(target instanceof HTMLElement)) return false;\n const tag = target.tagName;\n return tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' || target.isContentEditable;\n}\n\nfunction ConsoleShell({\n brand,\n breadcrumb,\n children,\n className,\n collapsed,\n closeNavigationLabel = 'Close navigation',\n collapseLabel = 'Collapse sidebar',\n defaultCollapsed = false,\n expandLabel = 'Expand sidebar',\n footer,\n hotkey = true,\n navigation,\n onCollapsedChange,\n openNavigationLabel = 'Open navigation',\n skipToContentLabel = 'Skip to content',\n storageKey,\n tools,\n ...rest\n}: ConsoleShellProps) {\n const mainId = `console-main-${useId().replaceAll(':', '')}`;\n const shellRef = useRef<HTMLDivElement>(null);\n const isCompact = useIsCompact();\n const reducedMotion = usePrefersReducedMotion();\n const [storedCollapsed, setStoredCollapsed] = useLocalStorage(storageKey, defaultCollapsed);\n const [drawerOpen, setDrawerOpen] = useState(false);\n const isControlled = collapsed !== undefined;\n const railCollapsed = isControlled ? collapsed : storedCollapsed;\n const railed = railCollapsed && !isCompact;\n\n const setCollapsed = (next: boolean) => {\n if (!isControlled) setStoredCollapsed(next);\n onCollapsedChange?.(next);\n };\n\n const closeNavigation = () => setDrawerOpen(false);\n const toggleNavigation = () => {\n if (isCompact) {\n setDrawerOpen((open) => !open);\n return;\n }\n setCollapsed(!railCollapsed);\n };\n const toggleRef = useRef(toggleNavigation);\n toggleRef.current = toggleNavigation;\n\n useEffect(() => {\n if (!hotkey) return;\n const node = shellRef.current;\n if (!node) return;\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key.toLowerCase() !== 'b' || !(event.metaKey || event.ctrlKey) || event.altKey) {\n return;\n }\n if (event.repeat || isTypingTarget(event.target)) return;\n if (!node.contains(event.target as Node)) return;\n event.preventDefault();\n toggleRef.current();\n };\n\n document.addEventListener('keydown', onKeyDown);\n return () => document.removeEventListener('keydown', onKeyDown);\n }, [hotkey]);\n\n const stateFor = (rail: boolean): ConsoleShellState => ({\n closeNavigation,\n collapsed: rail,\n compact: isCompact,\n });\n\n const sidebar = (rail: boolean) => (\n <ConsoleShellContext value={stateFor(rail)}>\n {brand || isCompact ? (\n <div className={styles.brand} data-collapsed={rail}>\n {brand}\n {isCompact ? (\n // In the drawer the close button sits in the brand row's flow, so it never\n // overlaps a brand switcher the way the drawer's floating close button did.\n <Button\n aria-label={closeNavigationLabel}\n className={styles.brandClose}\n icon={X}\n type=\"text\"\n onClick={closeNavigation}\n />\n ) : null}\n </div>\n ) : null}\n {navigation ? <div className={styles.navSlot}>{navigation}</div> : null}\n {footer ? <div className={styles.sidebarBottom}>{footer}</div> : null}\n </ConsoleShellContext>\n );\n\n const toggleLabel = isCompact ? openNavigationLabel : railed ? expandLabel : collapseLabel;\n\n return (\n <div\n className={className ? `${styles.shell} ${className}` : styles.shell}\n data-console-shell=\"\"\n ref={shellRef}\n {...rest}\n >\n <a\n className={styles.skipLink}\n href={`#${mainId}`}\n onClick={(event) => {\n event.preventDefault();\n document.getElementById(mainId)?.focus();\n }}\n >\n {skipToContentLabel}\n </a>\n <aside className={styles.sidebar} data-collapsed={railed} data-instant={reducedMotion}>\n {!isCompact && sidebar(railed)}\n </aside>\n {isCompact ? (\n <Drawer\n noHeader\n classNames={{ bodyContent: styles.drawerBody }}\n closable={false}\n open={drawerOpen}\n placement=\"left\"\n width={272}\n onClose={closeNavigation}\n >\n <Flexbox height=\"100%\">{sidebar(false)}</Flexbox>\n </Drawer>\n ) : null}\n <div className={styles.workspace}>\n <header className={styles.topbar}>\n <Button\n aria-label={toggleLabel}\n icon={PanelLeft}\n type=\"text\"\n onClick={toggleNavigation}\n />\n <span aria-hidden className={styles.topbarDivider} />\n <div className={styles.topbarMain}>{breadcrumb}</div>\n {tools ? <div className={styles.tools}>{tools}</div> : null}\n </header>\n <main className={styles.main} id={mainId} tabIndex={-1}>\n {children}\n </main>\n </div>\n </div>\n );\n}\n\nConsoleShell.displayName = 'ConsoleShell';\n\nexport default ConsoleShell;\n"],"mappings":"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"}
@@ -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;
@@ -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 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;;;;;;;;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"}
@@ -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;
@@ -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,51 @@
1
+ "use client";
2
+ import Skeleton from "../../base-ui/Skeleton/index.mjs";
3
+ import Surface from "../Surface/Surface.mjs";
4
+ import { styles } from "./style.mjs";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ import { cx } from "antd-style";
7
+ //#region src/dashboard/FilterStrip/FilterStrip.tsx
8
+ const countClass = {
9
+ danger: styles.countDanger,
10
+ warning: styles.countWarning
11
+ };
12
+ const integerFormat = new Intl.NumberFormat("en-US", { maximumFractionDigits: 0 });
13
+ const formatInteger = (count) => integerFormat.format(count);
14
+ /** One surface of selectable counts. Peer filters share a seam instead of a row of equal cards. */
15
+ const FilterStrip = ({ emptyText = "--", formatCount = formatInteger, items, label, onChange, value }) => /* @__PURE__ */ jsx(Surface, { children: /* @__PURE__ */ jsx("div", {
16
+ "aria-label": label,
17
+ className: styles.frame,
18
+ role: "radiogroup",
19
+ children: /* @__PURE__ */ jsx("div", {
20
+ className: styles.grid,
21
+ children: items.map((item) => {
22
+ const active = item.key === value;
23
+ const missing = item.count === void 0 || item.count === null;
24
+ const emphasize = item.tone && typeof item.count === "number" && item.count > 0;
25
+ return /* @__PURE__ */ jsxs("button", {
26
+ "aria-checked": active,
27
+ className: cx(styles.cell, active && styles.cellActive),
28
+ role: "radio",
29
+ title: item.hint,
30
+ type: "button",
31
+ onClick: () => onChange(item.key),
32
+ children: [/* @__PURE__ */ jsx("span", {
33
+ className: cx(styles.label, active && styles.labelActive),
34
+ children: item.label
35
+ }), /* @__PURE__ */ jsx("span", {
36
+ className: cx(styles.count, emphasize && countClass[item.tone]),
37
+ children: item.loading ? /* @__PURE__ */ jsx(Skeleton, {
38
+ height: 22,
39
+ radius: 6,
40
+ width: 48
41
+ }) : missing ? emptyText : formatCount(item.count)
42
+ })]
43
+ }, item.key);
44
+ })
45
+ })
46
+ }) });
47
+ FilterStrip.displayName = "FilterStrip";
48
+ //#endregion
49
+ export { FilterStrip as default, formatInteger };
50
+
51
+ //# sourceMappingURL=FilterStrip.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FilterStrip.mjs","names":[],"sources":["../../../src/dashboard/FilterStrip/FilterStrip.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\n\nimport Skeleton from '@/base-ui/Skeleton';\n\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>\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":";;;;;;;AAUA,MAAM,aAAa;CACjB,QAAQ,OAAO;CACf,SAAS,OAAO;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,EAAA,UACE,oBAAC,OAAD;CAAK,cAAY;CAAO,WAAW,OAAO;CAAO,MAAK;CACpD,UAAA,oBAAC,OAAD;EAAK,WAAW,OAAO;EACpB,UAAA,MAAM,KAAK,SAAS;GACnB,MAAM,SAAS,KAAK,QAAQ;GAC5B,MAAM,UAAU,KAAK,UAAU,KAAA,KAAa,KAAK,UAAU;GAC3D,MAAM,YAAY,KAAK,QAAQ,OAAO,KAAK,UAAU,YAAY,KAAK,QAAQ;GAE9E,OACE,qBAAC,UAAD;IACE,gBAAc;IACd,WAAW,GAAG,OAAO,MAAM,UAAU,OAAO,UAAU;IAEtD,MAAK;IACL,OAAO,KAAK;IACZ,MAAK;IACL,eAAe,SAAS,KAAK,GAAG;IAPlC,UAAA,CASE,oBAAC,QAAD;KAAM,WAAW,GAAG,OAAO,OAAO,UAAU,OAAO,WAAW;KAAI,UAAA,KAAK;IAAY,CAAA,GACnF,oBAAC,QAAD;KAAM,WAAW,GAAG,OAAO,OAAO,aAAa,WAAW,KAAK,KAAM;KAClE,UAAA,KAAK,UACJ,oBAAC,UAAD;MAAU,QAAQ;MAAI,QAAQ;MAAG,OAAO;KAAK,CAAA,IAC3C,UACF,YAEA,YAAY,KAAK,KAAM;IAErB,CAAA,CACA;GAhBD,GAAA,KAAK,GAgBJ;EAEZ,CAAC;CACE,CAAA;AACF,CAAA,EACE,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,93 @@
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: color-mix(in srgb, ${cssVar.colorText} 10%, transparent);
71
+
72
+ overflow: hidden;
73
+ `,
74
+ grid: css`
75
+ display: grid;
76
+ grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
77
+ inline-size: calc(100% + 1px);
78
+ margin-block-end: -1px;
79
+ `,
80
+ label: css`
81
+ font-size: 13px;
82
+ font-weight: 500;
83
+ line-height: 1.4;
84
+ color: ${cssVar.colorTextSecondary};
85
+ `,
86
+ labelActive: css`
87
+ color: ${cssVar.colorText};
88
+ `
89
+ }));
90
+ //#endregion
91
+ export { styles };
92
+
93
+ //# 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: color-mix(in srgb, ${cssVar.colorText} 10%, transparent);\n\n overflow: hidden;\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;wCAC4B,OAAO,UAAU;;;;CAIvD,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