tembro 6.1.0 → 6.1.1

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 (146) hide show
  1. package/dist/components/actions/action-menu.d.ts +11 -1
  2. package/dist/components/display/index.d.ts +0 -2
  3. package/dist/components/filters/index.d.ts +0 -1
  4. package/dist/components/inputs/time-picker.d.ts +11 -3
  5. package/dist/components/modern/file-manager.d.ts +1 -1
  6. package/dist/components/modern/index.d.ts +3 -1
  7. package/dist/components/modern/map.cjs +1 -0
  8. package/dist/components/modern/map.d.ts +29 -0
  9. package/dist/components/modern/map.js +1 -0
  10. package/dist/components/modern/media-player.cjs +1 -0
  11. package/dist/components/modern/media-player.d.ts +21 -0
  12. package/dist/components/modern/media-player.js +1 -0
  13. package/dist/components/modern/spreadsheet.cjs +1 -0
  14. package/dist/components/modern/spreadsheet.d.ts +35 -0
  15. package/dist/components/modern/spreadsheet.js +1 -0
  16. package/dist/components/overlay/drawer.d.ts +3 -1
  17. package/dist/index.d.ts +0 -2
  18. package/dist/src/components/actions/action-menu.cjs +1 -1
  19. package/dist/src/components/actions/action-menu.js +47 -39
  20. package/dist/src/components/actions/copy-button.cjs +1 -1
  21. package/dist/src/components/actions/copy-button.js +4 -1
  22. package/dist/src/components/calendar/date-picker.cjs +1 -1
  23. package/dist/src/components/calendar/date-picker.js +5 -8
  24. package/dist/src/components/calendar/date-range-picker.cjs +1 -1
  25. package/dist/src/components/calendar/date-range-picker.js +12 -27
  26. package/dist/src/components/data-table/data-table.cjs +1 -1
  27. package/dist/src/components/data-table/data-table.js +172 -171
  28. package/dist/src/components/display/index.cjs +1 -1
  29. package/dist/src/components/display/index.js +9 -11
  30. package/dist/src/components/filters/index.cjs +1 -1
  31. package/dist/src/components/filters/index.js +2 -3
  32. package/dist/src/components/inputs/color-picker.cjs +1 -1
  33. package/dist/src/components/inputs/color-picker.js +63 -46
  34. package/dist/src/components/inputs/slider.cjs +1 -1
  35. package/dist/src/components/inputs/slider.js +3 -3
  36. package/dist/src/components/inputs/tag-input.cjs +1 -1
  37. package/dist/src/components/inputs/tag-input.js +7 -4
  38. package/dist/src/components/inputs/time-picker.cjs +1 -1
  39. package/dist/src/components/inputs/time-picker.js +90 -34
  40. package/dist/src/components/modern/index.cjs +1 -1
  41. package/dist/src/components/modern/index.js +6 -4
  42. package/dist/src/components/modern/map.cjs +1 -0
  43. package/dist/src/components/modern/map.js +158 -0
  44. package/dist/src/components/modern/media-player.cjs +1 -0
  45. package/dist/src/components/modern/media-player.js +176 -0
  46. package/dist/src/components/modern/resizable-panel.cjs +1 -1
  47. package/dist/src/components/modern/resizable-panel.js +39 -32
  48. package/dist/src/components/modern/spreadsheet.cjs +1 -0
  49. package/dist/src/components/modern/spreadsheet.js +97 -0
  50. package/dist/src/components/navigation/pagination.cjs +1 -1
  51. package/dist/src/components/navigation/pagination.js +5 -5
  52. package/dist/src/components/notifications/toast.cjs +1 -1
  53. package/dist/src/components/notifications/toast.js +68 -63
  54. package/dist/src/components/overlay/alert-dialog.cjs +1 -1
  55. package/dist/src/components/overlay/alert-dialog.js +8 -6
  56. package/dist/src/components/overlay/drawer.cjs +1 -1
  57. package/dist/src/components/overlay/drawer.js +38 -20
  58. package/dist/src/components/ui/checkbox/index.cjs +1 -1
  59. package/dist/src/components/ui/checkbox/index.js +2 -1
  60. package/dist/src/components/ui/dialog/index.cjs +1 -1
  61. package/dist/src/components/ui/dialog/index.js +8 -8
  62. package/dist/src/components/ui/dropdown-menu/index.cjs +1 -1
  63. package/dist/src/components/ui/dropdown-menu/index.js +21 -19
  64. package/dist/src/components/ui/popover/index.cjs +1 -1
  65. package/dist/src/components/ui/popover/index.js +10 -10
  66. package/dist/src/components/ui/tabs/index.cjs +1 -1
  67. package/dist/src/components/ui/tabs/index.js +6 -6
  68. package/dist/src/components/ui/toggle-group/index.cjs +1 -1
  69. package/dist/src/components/ui/toggle-group/index.js +2 -2
  70. package/dist/src/index.cjs +1 -1
  71. package/dist/src/index.js +80 -83
  72. package/dist/src/public-component-surface.cjs +1 -1
  73. package/dist/src/public-component-surface.js +15 -20
  74. package/package.json +1 -2
  75. package/packages/cli/dist/index.cjs +58 -178
  76. package/packages/cli/vendor/src/components/actions/action-menu.tsx +47 -19
  77. package/packages/cli/vendor/src/components/actions/copy-button.tsx +2 -2
  78. package/packages/cli/vendor/src/components/calendar/date-picker.tsx +2 -5
  79. package/packages/cli/vendor/src/components/calendar/date-range-picker.tsx +5 -12
  80. package/packages/cli/vendor/src/components/data-table/data-table.tsx +45 -34
  81. package/packages/cli/vendor/src/components/display/index.ts +3 -5
  82. package/packages/cli/vendor/src/components/filters/index.ts +0 -1
  83. package/packages/cli/vendor/src/components/inputs/color-picker.tsx +15 -1
  84. package/packages/cli/vendor/src/components/inputs/slider.tsx +3 -3
  85. package/packages/cli/vendor/src/components/inputs/tag-input.tsx +4 -4
  86. package/packages/cli/vendor/src/components/inputs/time-picker.tsx +91 -38
  87. package/packages/cli/vendor/src/components/modern/file-manager.tsx +1 -1
  88. package/packages/cli/vendor/src/components/modern/index.ts +3 -1
  89. package/packages/cli/vendor/src/components/modern/map.tsx +146 -0
  90. package/packages/cli/vendor/src/components/modern/media-player.tsx +182 -0
  91. package/packages/cli/vendor/src/components/modern/resizable-panel.tsx +15 -5
  92. package/packages/cli/vendor/src/components/modern/spreadsheet.tsx +155 -0
  93. package/packages/cli/vendor/src/components/navigation/pagination.tsx +9 -5
  94. package/packages/cli/vendor/src/components/notifications/toast.tsx +20 -10
  95. package/packages/cli/vendor/src/components/overlay/alert-dialog.tsx +3 -5
  96. package/packages/cli/vendor/src/components/overlay/drawer.tsx +22 -11
  97. package/packages/cli/vendor/src/components/ui/checkbox/index.tsx +3 -1
  98. package/packages/cli/vendor/src/components/ui/dialog/index.tsx +4 -4
  99. package/packages/cli/vendor/src/components/ui/dropdown-menu/index.tsx +18 -22
  100. package/packages/cli/vendor/src/components/ui/popover/index.tsx +4 -4
  101. package/packages/cli/vendor/src/components/ui/tabs/index.tsx +8 -3
  102. package/packages/cli/vendor/src/components/ui/toggle-group/index.tsx +6 -6
  103. package/packages/cli/vendor/src/index.ts +0 -2
  104. package/packages/cli/vendor/src/public-component-surface.ts +3 -4
  105. package/packages/cli/vendor/templates/showcase/src/showcase/data/registry.ts +6 -6
  106. package/packages/cli/vendor/templates/showcase/src/showcase/layout/HeroSection.tsx +23 -8
  107. package/packages/cli/vendor/templates/showcase/src/showcase/layout/WorkbenchSidebar.tsx +1 -1
  108. package/packages/cli/vendor/templates/showcase/src/showcase/sections/PatternsSection.tsx +1 -1
  109. package/packages/cli/vendor/templates/styles/globals.css +0 -120
  110. package/registry.json +74 -141
  111. package/dist/components/display/info-card.cjs +0 -1
  112. package/dist/components/display/info-card.d.ts +0 -51
  113. package/dist/components/display/info-card.js +0 -1
  114. package/dist/components/display/statistic.cjs +0 -1
  115. package/dist/components/display/statistic.d.ts +0 -25
  116. package/dist/components/display/statistic.js +0 -1
  117. package/dist/components/filters/filter-bar.cjs +0 -1
  118. package/dist/components/filters/filter-bar.d.ts +0 -28
  119. package/dist/components/filters/filter-bar.js +0 -1
  120. package/dist/components/modern/image-cropper.cjs +0 -1
  121. package/dist/components/modern/image-cropper.d.ts +0 -39
  122. package/dist/components/modern/image-cropper.js +0 -1
  123. package/dist/components/ui/number-field/index.cjs +0 -1
  124. package/dist/components/ui/number-field/index.d.ts +0 -18
  125. package/dist/components/ui/number-field/index.js +0 -1
  126. package/dist/components/ui/toolbar/index.cjs +0 -1
  127. package/dist/components/ui/toolbar/index.d.ts +0 -14
  128. package/dist/components/ui/toolbar/index.js +0 -1
  129. package/dist/src/components/display/info-card.cjs +0 -1
  130. package/dist/src/components/display/info-card.js +0 -124
  131. package/dist/src/components/display/statistic.cjs +0 -1
  132. package/dist/src/components/display/statistic.js +0 -104
  133. package/dist/src/components/filters/filter-bar.cjs +0 -1
  134. package/dist/src/components/filters/filter-bar.js +0 -103
  135. package/dist/src/components/modern/image-cropper.cjs +0 -1
  136. package/dist/src/components/modern/image-cropper.js +0 -143
  137. package/dist/src/components/ui/number-field/index.cjs +0 -1
  138. package/dist/src/components/ui/number-field/index.js +0 -73
  139. package/dist/src/components/ui/toolbar/index.cjs +0 -1
  140. package/dist/src/components/ui/toolbar/index.js +0 -50
  141. package/packages/cli/vendor/src/components/display/info-card.tsx +0 -195
  142. package/packages/cli/vendor/src/components/display/statistic.tsx +0 -114
  143. package/packages/cli/vendor/src/components/filters/filter-bar.tsx +0 -163
  144. package/packages/cli/vendor/src/components/modern/image-cropper.tsx +0 -226
  145. package/packages/cli/vendor/src/components/ui/number-field/index.tsx +0 -89
  146. package/packages/cli/vendor/src/components/ui/toolbar/index.tsx +0 -67
@@ -1 +0,0 @@
1
- "use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../../_virtual/_rolldown/runtime.cjs"),t=require("../../../lib/utils.cjs");let n=require("react");n=e.__toESM(n,1);let r=require("lucide-react"),i=require("react/jsx-runtime"),a=require("@base-ui/react/number-field");function o({className:e,...n}){return(0,i.jsx)(a.NumberField.Root,{"data-slot":`number-field`,className:t.cn(`grid gap-2`,e),...n})}function s({className:e,...n}){return(0,i.jsx)(a.NumberField.Group,{"data-slot":`number-field-group`,className:t.cn(`flex min-h-10 w-full overflow-hidden rounded-[var(--radius-md)] border border-input bg-background text-foreground shadow-xs transition-[border-color,box-shadow] focus-within:border-ring focus-within:ring-2 focus-within:ring-ring/35 has-[:disabled]:cursor-not-allowed has-[:disabled]:opacity-50`,e),...n})}function c({className:e,...n}){return(0,i.jsx)(a.NumberField.Input,{"data-slot":`number-field-input`,className:t.cn(`min-w-0 flex-1 bg-transparent px-3 py-2 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed`,e),...n})}function l({className:e,children:n,...o}){return(0,i.jsx)(a.NumberField.Increment,{"data-slot":`number-field-increment`,className:t.cn(`flex h-5 w-8 items-center justify-center border-l border-border text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:pointer-events-none disabled:opacity-40`,e),...o,children:n??(0,i.jsx)(r.ChevronUpIcon,{"aria-hidden":`true`,className:`size-3.5`})})}function u({className:e,children:n,...o}){return(0,i.jsx)(a.NumberField.Decrement,{"data-slot":`number-field-decrement`,className:t.cn(`flex h-5 w-8 items-center justify-center border-l border-t border-border text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:pointer-events-none disabled:opacity-40`,e),...o,children:n??(0,i.jsx)(r.ChevronDownIcon,{"aria-hidden":`true`,className:`size-3.5`})})}function d({className:e,...n}){return(0,i.jsx)(`div`,{"data-slot":`number-field-stepper`,className:t.cn(`grid shrink-0 grid-rows-2`,e),...n})}function f({className:e,...n}){return(0,i.jsx)(a.NumberField.ScrubArea,{"data-slot":`number-field-scrub-area`,className:t.cn(`cursor-ew-resize select-none`,e),...n})}function p({className:e,...n}){return(0,i.jsx)(a.NumberField.ScrubAreaCursor,{"data-slot":`number-field-scrub-area-cursor`,className:t.cn(`fixed z-50 rounded bg-foreground px-2 py-1 text-xs text-background shadow-lg`,e),...n})}exports.NumberField=o,exports.NumberFieldDecrement=u,exports.NumberFieldGroup=s,exports.NumberFieldIncrement=l,exports.NumberFieldInput=c,exports.NumberFieldScrubArea=f,exports.NumberFieldScrubAreaCursor=p,exports.NumberFieldStepper=d;
@@ -1,73 +0,0 @@
1
- "use client";
2
- import { cn as e } from "../../../lib/utils.js";
3
- import "react";
4
- import { ChevronDownIcon as t, ChevronUpIcon as n } from "lucide-react";
5
- import { jsx as r } from "react/jsx-runtime";
6
- import { NumberField as i } from "@base-ui/react/number-field";
7
- //#region src/components/ui/number-field/index.tsx
8
- function a({ className: t, ...n }) {
9
- return /* @__PURE__ */ r(i.Root, {
10
- "data-slot": "number-field",
11
- className: e("grid gap-2", t),
12
- ...n
13
- });
14
- }
15
- function o({ className: t, ...n }) {
16
- return /* @__PURE__ */ r(i.Group, {
17
- "data-slot": "number-field-group",
18
- className: e("flex min-h-10 w-full overflow-hidden rounded-[var(--radius-md)] border border-input bg-background text-foreground shadow-xs transition-[border-color,box-shadow] focus-within:border-ring focus-within:ring-2 focus-within:ring-ring/35 has-[:disabled]:cursor-not-allowed has-[:disabled]:opacity-50", t),
19
- ...n
20
- });
21
- }
22
- function s({ className: t, ...n }) {
23
- return /* @__PURE__ */ r(i.Input, {
24
- "data-slot": "number-field-input",
25
- className: e("min-w-0 flex-1 bg-transparent px-3 py-2 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed", t),
26
- ...n
27
- });
28
- }
29
- function c({ className: t, children: a, ...o }) {
30
- return /* @__PURE__ */ r(i.Increment, {
31
- "data-slot": "number-field-increment",
32
- className: e("flex h-5 w-8 items-center justify-center border-l border-border text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:pointer-events-none disabled:opacity-40", t),
33
- ...o,
34
- children: a ?? /* @__PURE__ */ r(n, {
35
- "aria-hidden": "true",
36
- className: "size-3.5"
37
- })
38
- });
39
- }
40
- function l({ className: n, children: a, ...o }) {
41
- return /* @__PURE__ */ r(i.Decrement, {
42
- "data-slot": "number-field-decrement",
43
- className: e("flex h-5 w-8 items-center justify-center border-l border-t border-border text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:pointer-events-none disabled:opacity-40", n),
44
- ...o,
45
- children: a ?? /* @__PURE__ */ r(t, {
46
- "aria-hidden": "true",
47
- className: "size-3.5"
48
- })
49
- });
50
- }
51
- function u({ className: t, ...n }) {
52
- return /* @__PURE__ */ r("div", {
53
- "data-slot": "number-field-stepper",
54
- className: e("grid shrink-0 grid-rows-2", t),
55
- ...n
56
- });
57
- }
58
- function d({ className: t, ...n }) {
59
- return /* @__PURE__ */ r(i.ScrubArea, {
60
- "data-slot": "number-field-scrub-area",
61
- className: e("cursor-ew-resize select-none", t),
62
- ...n
63
- });
64
- }
65
- function f({ className: t, ...n }) {
66
- return /* @__PURE__ */ r(i.ScrubAreaCursor, {
67
- "data-slot": "number-field-scrub-area-cursor",
68
- className: e("fixed z-50 rounded bg-foreground px-2 py-1 text-xs text-background shadow-lg", t),
69
- ...n
70
- });
71
- }
72
- //#endregion
73
- export { a as NumberField, l as NumberFieldDecrement, o as NumberFieldGroup, c as NumberFieldIncrement, s as NumberFieldInput, d as NumberFieldScrubArea, f as NumberFieldScrubAreaCursor, u as NumberFieldStepper };
@@ -1 +0,0 @@
1
- "use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../lib/utils.cjs");let t=require("react/jsx-runtime"),n=require("@base-ui/react/toolbar");function r({className:r,orientation:i=`horizontal`,...a}){return(0,t.jsx)(n.Toolbar.Root,{"data-slot":`toolbar`,orientation:i,className:e.cn(`flex min-w-0 items-center gap-1 rounded-[var(--radius-lg)] border border-border bg-card p-1 text-card-foreground shadow-xs`,i===`vertical`&&`w-max flex-col items-stretch`,r),...a})}function i({className:r,...i}){return(0,t.jsx)(n.Toolbar.Group,{"data-slot":`toolbar-group`,className:e.cn(`flex min-w-0 items-center gap-1`,r),...i})}function a({className:r,...i}){return(0,t.jsx)(n.Toolbar.Button,{"data-slot":`toolbar-button`,className:e.cn(`inline-flex h-8 min-w-8 items-center justify-center gap-1.5 rounded-[var(--radius-md)] px-2.5 text-sm font-medium text-muted-foreground outline-none transition-colors hover:bg-muted hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[pressed]:bg-muted data-[pressed]:text-foreground [&_svg]:size-4 [&_svg]:shrink-0`,r),...i})}function o({className:r,...i}){return(0,t.jsx)(n.Toolbar.Link,{"data-slot":`toolbar-link`,className:e.cn(`inline-flex h-8 items-center justify-center gap-1.5 rounded-[var(--radius-md)] px-2.5 text-sm font-medium text-muted-foreground outline-none transition-colors hover:bg-muted hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring`,r),...i})}function s({className:r,...i}){return(0,t.jsx)(n.Toolbar.Input,{"data-slot":`toolbar-input`,className:e.cn(`h-8 min-w-32 rounded-[var(--radius-md)] border border-input bg-background px-2.5 text-sm outline-none placeholder:text-muted-foreground focus-visible:ring-2 focus-visible:ring-ring`,r),...i})}function c({className:r,...i}){return(0,t.jsx)(n.Toolbar.Separator,{"data-slot":`toolbar-separator`,className:e.cn(`mx-1 h-5 w-px bg-border data-[orientation=vertical]:h-px data-[orientation=vertical]:w-full`,r),...i})}exports.Toolbar=r,exports.ToolbarButton=a,exports.ToolbarGroup=i,exports.ToolbarInput=s,exports.ToolbarLink=o,exports.ToolbarSeparator=c;
@@ -1,50 +0,0 @@
1
- "use client";
2
- import { cn as e } from "../../../lib/utils.js";
3
- import { jsx as t } from "react/jsx-runtime";
4
- import { Toolbar as n } from "@base-ui/react/toolbar";
5
- //#region src/components/ui/toolbar/index.tsx
6
- function r({ className: r, orientation: i = "horizontal", ...a }) {
7
- return /* @__PURE__ */ t(n.Root, {
8
- "data-slot": "toolbar",
9
- orientation: i,
10
- className: e("flex min-w-0 items-center gap-1 rounded-[var(--radius-lg)] border border-border bg-card p-1 text-card-foreground shadow-xs", i === "vertical" && "w-max flex-col items-stretch", r),
11
- ...a
12
- });
13
- }
14
- function i({ className: r, ...i }) {
15
- return /* @__PURE__ */ t(n.Group, {
16
- "data-slot": "toolbar-group",
17
- className: e("flex min-w-0 items-center gap-1", r),
18
- ...i
19
- });
20
- }
21
- function a({ className: r, ...i }) {
22
- return /* @__PURE__ */ t(n.Button, {
23
- "data-slot": "toolbar-button",
24
- className: e("inline-flex h-8 min-w-8 items-center justify-center gap-1.5 rounded-[var(--radius-md)] px-2.5 text-sm font-medium text-muted-foreground outline-none transition-colors hover:bg-muted hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[pressed]:bg-muted data-[pressed]:text-foreground [&_svg]:size-4 [&_svg]:shrink-0", r),
25
- ...i
26
- });
27
- }
28
- function o({ className: r, ...i }) {
29
- return /* @__PURE__ */ t(n.Link, {
30
- "data-slot": "toolbar-link",
31
- className: e("inline-flex h-8 items-center justify-center gap-1.5 rounded-[var(--radius-md)] px-2.5 text-sm font-medium text-muted-foreground outline-none transition-colors hover:bg-muted hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring", r),
32
- ...i
33
- });
34
- }
35
- function s({ className: r, ...i }) {
36
- return /* @__PURE__ */ t(n.Input, {
37
- "data-slot": "toolbar-input",
38
- className: e("h-8 min-w-32 rounded-[var(--radius-md)] border border-input bg-background px-2.5 text-sm outline-none placeholder:text-muted-foreground focus-visible:ring-2 focus-visible:ring-ring", r),
39
- ...i
40
- });
41
- }
42
- function c({ className: r, ...i }) {
43
- return /* @__PURE__ */ t(n.Separator, {
44
- "data-slot": "toolbar-separator",
45
- className: e("mx-1 h-5 w-px bg-border data-[orientation=vertical]:h-px data-[orientation=vertical]:w-full", r),
46
- ...i
47
- });
48
- }
49
- //#endregion
50
- export { r as Toolbar, a as ToolbarButton, i as ToolbarGroup, s as ToolbarInput, o as ToolbarLink, c as ToolbarSeparator };
@@ -1,195 +0,0 @@
1
- import * as React from "react"
2
-
3
- import { Card } from "@/components/ui/card"
4
- import { Skeleton, SkeletonText } from "@/components/ui/skeleton"
5
- import { cn, stopInteractivePropagation } from "@/lib/utils"
6
-
7
- export type InfoCardVariant = "default" | "outline" | "elevated" | "ghost"
8
- export type InfoCardSize = "sm" | "md" | "lg"
9
- export type InfoCardDensity = "compact" | "default" | "comfortable"
10
- export type InfoCardOrientation = "vertical" | "horizontal"
11
-
12
- export type InfoCardClassNames = {
13
- root?: string
14
- media?: string
15
- header?: string
16
- icon?: string
17
- body?: string
18
- eyebrow?: string
19
- title?: string
20
- description?: string
21
- content?: string
22
- footer?: string
23
- actions?: string
24
- meta?: string
25
- status?: string
26
- }
27
-
28
- export type InfoCardRenderContext = {
29
- title?: React.ReactNode
30
- description?: React.ReactNode
31
- eyebrow?: React.ReactNode
32
- media?: React.ReactNode
33
- icon?: React.ReactNode
34
- status?: React.ReactNode
35
- actions?: React.ReactNode
36
- meta?: React.ReactNode
37
- content?: React.ReactNode
38
- footer?: React.ReactNode
39
- }
40
-
41
- export type InfoCardProps = Omit<React.ComponentProps<typeof Card>, "title" | "content" | "size" | "orientation"> & InfoCardRenderContext & {
42
- orientation?: InfoCardOrientation
43
- variant?: InfoCardVariant
44
- size?: InfoCardSize
45
- density?: InfoCardDensity
46
- compact?: boolean
47
- loading?: boolean
48
- disabled?: boolean
49
- selected?: boolean
50
- interactive?: boolean
51
- classNames?: InfoCardClassNames
52
- renderHeader?: (ctx: InfoCardRenderContext) => React.ReactNode
53
- renderMedia?: (ctx: InfoCardRenderContext) => React.ReactNode
54
- renderContent?: (ctx: InfoCardRenderContext) => React.ReactNode
55
- renderFooter?: (ctx: InfoCardRenderContext) => React.ReactNode
56
- }
57
-
58
- const densityClassName: Record<InfoCardDensity, string> = {
59
- compact: "gap-2",
60
- default: "gap-3",
61
- comfortable: "gap-4",
62
- }
63
-
64
- const titleClassName: Record<InfoCardSize, string> = {
65
- sm: "text-sm font-semibold",
66
- md: "text-base font-semibold",
67
- lg: "text-lg font-semibold",
68
- }
69
-
70
- function InfoCard({
71
- eyebrow,
72
- title,
73
- description,
74
- media,
75
- icon,
76
- status,
77
- actions,
78
- meta,
79
- content,
80
- footer,
81
- orientation = "vertical",
82
- variant = "outline",
83
- size = "md",
84
- density,
85
- compact,
86
- loading = false,
87
- disabled = false,
88
- selected = false,
89
- interactive,
90
- className,
91
- classNames,
92
- renderHeader,
93
- renderMedia,
94
- renderContent,
95
- renderFooter,
96
- children,
97
- onClick,
98
- ...props
99
- }: InfoCardProps) {
100
- const ctx: InfoCardRenderContext = { eyebrow, title, description, media, icon, status, actions, meta, content, footer }
101
- const clickable = Boolean(onClick || interactive)
102
- const resolvedDensity = compact ? "compact" : density ?? "default"
103
-
104
- return (
105
- <Card
106
- data-slot="info-card"
107
- data-selected={selected || undefined}
108
- data-disabled={disabled || undefined}
109
- data-loading={loading || undefined}
110
- data-info-variant={variant}
111
- data-info-size={size}
112
- data-info-density={resolvedDensity}
113
- data-orientation={orientation}
114
- variant={variant}
115
- size={size === "md" ? "default" : size}
116
- density={resolvedDensity}
117
- interactive={clickable}
118
- selected={selected}
119
- disabled={disabled}
120
- className={cn(
121
- "overflow-hidden",
122
- orientation === "horizontal" && "flex",
123
- className,
124
- classNames?.root
125
- )}
126
- onClick={disabled ? undefined : onClick}
127
- {...props}
128
- >
129
- {loading ? (
130
- <div data-slot="info-card-loading" className="grid gap-3">
131
- <Skeleton className="h-5 w-1/2" />
132
- <SkeletonText rows={3} />
133
- </div>
134
- ) : (
135
- <>
136
- {media &&
137
- (renderMedia?.(ctx) ?? (
138
- <div
139
- data-slot="info-card-media"
140
- className={cn(
141
- orientation === "horizontal" ? "w-40 shrink-0" : "aspect-video",
142
- classNames?.media
143
- )}
144
- >
145
- {media}
146
- </div>
147
- ))}
148
- <div data-slot="info-card-body" className={cn("grid min-w-0 flex-1 gap-3", densityClassName[resolvedDensity], classNames?.body)}>
149
- {renderHeader?.(ctx) ?? (
150
- <div data-slot="info-card-header" className={cn("flex items-start justify-between gap-3", classNames?.header)}>
151
- <div className="flex min-w-0 items-start gap-3">
152
- {icon && (
153
- <div
154
- data-slot="info-card-icon"
155
- className={cn(
156
- "flex shrink-0 items-center justify-center",
157
- classNames?.icon
158
- )}
159
- >
160
- {icon}
161
- </div>
162
- )}
163
- <div className="grid min-w-0 gap-1">
164
- {eyebrow && <div data-slot="info-card-eyebrow" className={classNames?.eyebrow}>{eyebrow}</div>}
165
- <div className="flex flex-wrap items-center gap-2">
166
- {title && <div data-slot="info-card-title" className={cn("truncate", titleClassName[size], classNames?.title)}>{title}</div>}
167
- {status && <div data-slot="info-card-status" className={classNames?.status}>{status}</div>}
168
- </div>
169
- {description && <div data-slot="info-card-description" className={cn("line-clamp-2", classNames?.description)}>{description}</div>}
170
- </div>
171
- </div>
172
- {actions && (
173
- <div
174
- data-slot="info-card-actions"
175
- className={cn("shrink-0", classNames?.actions)}
176
- onClick={stopInteractivePropagation}
177
- onMouseDown={stopInteractivePropagation}
178
- onDoubleClick={stopInteractivePropagation}
179
- >
180
- {actions}
181
- </div>
182
- )}
183
- </div>
184
- )}
185
- {meta && <div data-slot="info-card-meta" className={classNames?.meta}>{meta}</div>}
186
- {(content || children) && (renderContent?.(ctx) ?? <div data-slot="info-card-content" className={classNames?.content}>{content ?? children}</div>)}
187
- {footer && (renderFooter?.(ctx) ?? <div data-slot="info-card-footer" className={classNames?.footer}>{footer}</div>)}
188
- </div>
189
- </>
190
- )}
191
- </Card>
192
- )
193
- }
194
-
195
- export { InfoCard }
@@ -1,114 +0,0 @@
1
- import * as React from "react"
2
- import { ArrowDownIcon, ArrowUpIcon } from "lucide-react"
3
-
4
- import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
5
- import { cn } from "@/lib/utils"
6
-
7
- export type StatisticTrend = "up" | "down" | "neutral"
8
-
9
- export type StatisticProps = React.ComponentProps<"div"> & {
10
- label: React.ReactNode
11
- value: React.ReactNode
12
- prefix?: React.ReactNode
13
- suffix?: React.ReactNode
14
- description?: React.ReactNode
15
- trend?: StatisticTrend
16
- change?: React.ReactNode
17
- loading?: boolean
18
- }
19
-
20
- function Statistic({ label, value, prefix, suffix, description, trend = "neutral", change, loading = false, className, ...props }: StatisticProps) {
21
- const trendIcon = trend === "up" ? <ArrowUpIcon className="size-3" /> : trend === "down" ? <ArrowDownIcon className="size-3" /> : null
22
-
23
- return (
24
- <div data-slot="statistic" data-loading={loading || undefined} data-trend={trend} aria-busy={loading || undefined} className={cn("grid gap-1", className)} {...props}>
25
- <div data-slot="statistic-label" className="text-sm text-muted-foreground">{label}</div>
26
- <div data-slot="statistic-value-row" className="flex flex-wrap items-baseline gap-1.5">
27
- {loading ? (
28
- <div data-slot="statistic-skeleton" className="h-8 w-28 animate-pulse rounded-md bg-muted" />
29
- ) : (
30
- <>
31
- {prefix && <span data-slot="statistic-prefix" className="text-base text-muted-foreground">{prefix}</span>}
32
- <span data-slot="statistic-value" className="text-2xl font-semibold tracking-tight">{value}</span>
33
- {suffix && <span data-slot="statistic-suffix" className="text-sm text-muted-foreground">{suffix}</span>}
34
- </>
35
- )}
36
- </div>
37
- {(description || change) && (
38
- <div data-slot="statistic-meta" className="flex flex-wrap items-center gap-2 text-xs text-muted-foreground">
39
- {change && (
40
- <span
41
- data-slot="statistic-change"
42
- data-trend={trend}
43
- className={cn(
44
- "inline-flex items-center gap-1 rounded-full px-1.5 py-0.5 font-medium",
45
- trend === "up" && "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400",
46
- trend === "down" && "bg-destructive/10 text-destructive",
47
- trend === "neutral" && "bg-muted text-muted-foreground"
48
- )}
49
- >
50
- {trendIcon}
51
- {change}
52
- </span>
53
- )}
54
- {description && <span data-slot="statistic-description">{description}</span>}
55
- </div>
56
- )}
57
- </div>
58
- )
59
- }
60
-
61
- export type StatisticCardProps = React.ComponentProps<typeof Card> & StatisticProps & {
62
- action?: React.ReactNode
63
- density?: "compact" | "default"
64
- }
65
-
66
- function StatisticCard({ action, density = "default", label, value, prefix, suffix, description, trend, change, loading, className, ...props }: StatisticCardProps) {
67
- return (
68
- <Card data-slot="statistic-card" data-density={density} className={className} {...props}>
69
- <CardHeader data-slot="statistic-card-header" className={cn("flex flex-row items-center justify-between gap-3 pb-2", density === "compact" && "px-4 pt-4 pb-1")}>
70
- <CardTitle className="text-sm font-medium text-muted-foreground">{label}</CardTitle>
71
- {action ? <div data-slot="statistic-card-action">{action}</div> : null}
72
- </CardHeader>
73
- <CardContent className={cn(density === "compact" && "px-4 pb-4")}>
74
- <Statistic
75
- label={<span className="sr-only">{label}</span>}
76
- value={value}
77
- prefix={prefix}
78
- suffix={suffix}
79
- description={description}
80
- trend={trend}
81
- change={change}
82
- loading={loading}
83
- />
84
- </CardContent>
85
- </Card>
86
- )
87
- }
88
-
89
- export type StatisticGridProps = React.ComponentProps<"div"> & {
90
- columns?: 1 | 2 | 3 | 4
91
- gap?: "sm" | "default" | "lg"
92
- }
93
-
94
- function StatisticGrid({ columns = 4, gap = "default", className, ...props }: StatisticGridProps) {
95
- return (
96
- <div
97
- data-slot="statistic-grid"
98
- className={cn(
99
- "grid",
100
- gap === "sm" && "gap-3",
101
- gap === "default" && "gap-4",
102
- gap === "lg" && "gap-6",
103
- columns === 1 && "grid-cols-1",
104
- columns === 2 && "grid-cols-1 sm:grid-cols-2",
105
- columns === 3 && "grid-cols-1 sm:grid-cols-2 xl:grid-cols-3",
106
- columns === 4 && "grid-cols-1 sm:grid-cols-2 xl:grid-cols-4",
107
- className
108
- )}
109
- {...props}
110
- />
111
- )
112
- }
113
-
114
- export { Statistic, StatisticCard, StatisticGrid }
@@ -1,163 +0,0 @@
1
- "use client"
2
-
3
- import * as React from "react"
4
- import { SlidersHorizontalIcon, XIcon } from "lucide-react"
5
-
6
- import { Badge } from "@/components/ui/badge"
7
- import { Button } from "@/components/ui/button"
8
- import { cn, stopInteractivePropagation } from "@/lib/utils"
9
-
10
- export type FilterBarChip = {
11
- key: string
12
- label: React.ReactNode
13
- value?: React.ReactNode
14
- tone?: "default" | "success" | "warning" | "danger" | "info" | "muted"
15
- disabled?: boolean
16
- hidden?: boolean
17
- }
18
-
19
- export type FilterBarProps = React.ComponentProps<"div"> & {
20
- search?: React.ReactNode
21
- filters?: React.ReactNode
22
- actions?: React.ReactNode
23
- chips?: FilterBarChip[]
24
- activeCount?: number
25
- activeLabel?: (count: number) => React.ReactNode
26
- resetLabel?: React.ReactNode
27
- clearChipLabel?: React.ReactNode
28
- onReset?: () => void
29
- onRemoveChip?: (key: string) => void
30
- collapsible?: boolean
31
- defaultExpanded?: boolean
32
- emptyChips?: React.ReactNode
33
- chipLimit?: number
34
- chipOverflowLabel?: (hiddenCount: number) => React.ReactNode
35
- }
36
-
37
- const chipVariant: Record<NonNullable<FilterBarChip["tone"]>, React.ComponentProps<typeof Badge>["variant"]> = {
38
- default: "secondary",
39
- success: "secondary",
40
- warning: "outline",
41
- danger: "destructive",
42
- info: "outline",
43
- muted: "outline",
44
- }
45
-
46
- function FilterBar({
47
- className,
48
- search,
49
- filters,
50
- actions,
51
- chips,
52
- activeCount,
53
- activeLabel = (count) => `${count} active`,
54
- resetLabel = "Reset",
55
- clearChipLabel,
56
- onReset,
57
- onRemoveChip,
58
- collapsible = false,
59
- defaultExpanded = false,
60
- emptyChips,
61
- chipLimit,
62
- chipOverflowLabel = (hiddenCount) => `+${hiddenCount} more`,
63
- children,
64
- ...props
65
- }: FilterBarProps) {
66
- const [expanded, setExpanded] = React.useState(defaultExpanded)
67
- const visibleChips = chips?.filter((chip) => !chip.hidden) ?? []
68
- const renderedChips = chipLimit && chipLimit > 0 ? visibleChips.slice(0, chipLimit) : visibleChips
69
- const hiddenChipCount = Math.max(visibleChips.length - renderedChips.length, 0)
70
- const resolvedActiveCount = activeCount ?? visibleChips.length
71
- const hasFilters = Boolean(filters || children)
72
- const hasChips = Boolean(chips)
73
- const shouldShowFilters = !collapsible || expanded
74
- const shouldShowChipRow = visibleChips.length > 0 || (hasChips && emptyChips)
75
-
76
- return (
77
- <div
78
- data-slot="filter-bar"
79
- className={cn("flex flex-col gap-3 rounded-lg border bg-card p-3", className)}
80
- {...props}
81
- >
82
- <div className="flex flex-col gap-2 lg:flex-row lg:items-center lg:justify-between">
83
- <div className="flex min-w-0 flex-1 flex-col gap-2 sm:flex-row sm:items-center">
84
- {search && <div className="min-w-0 flex-1">{search}</div>}
85
-
86
- {collapsible && hasFilters && (
87
- <Button
88
- type="button"
89
- variant={expanded ? "secondary" : "outline"}
90
- size="sm"
91
- onClick={() => setExpanded((value) => !value)}
92
- >
93
- <SlidersHorizontalIcon data-icon="inline-start" />
94
- Filters
95
- {resolvedActiveCount > 0 && (
96
- <span className="ml-1 rounded-full bg-background px-1.5 text-xs">
97
- {resolvedActiveCount}
98
- </span>
99
- )}
100
- </Button>
101
- )}
102
- </div>
103
-
104
- <div className="flex shrink-0 flex-wrap items-center gap-2">
105
- {resolvedActiveCount > 0 && (
106
- <span className="text-sm text-muted-foreground">{activeLabel(resolvedActiveCount)}</span>
107
- )}
108
- {resolvedActiveCount > 0 && onReset && (
109
- <Button type="button" variant="ghost" size="sm" onClick={onReset}>
110
- <XIcon data-icon="inline-start" />
111
- {resetLabel}
112
- </Button>
113
- )}
114
- {actions}
115
- </div>
116
- </div>
117
-
118
- {hasFilters && shouldShowFilters && (
119
- <div className="flex flex-col gap-2 sm:flex-row sm:flex-wrap sm:items-center">
120
- {filters}
121
- {children}
122
- </div>
123
- )}
124
-
125
- {shouldShowChipRow && (
126
- <div data-slot="filter-bar-chips" className="flex flex-wrap items-center gap-2">
127
- {visibleChips.length > 0 ? (
128
- <>
129
- {renderedChips.map((chip) => (
130
- <Badge key={chip.key} variant={chipVariant[chip.tone ?? "default"]} className={cn("gap-1.5", chip.disabled && "opacity-60")}>
131
- <span>{chip.label}</span>
132
- {chip.value !== undefined && <span className="text-muted-foreground">{chip.value}</span>}
133
- {onRemoveChip && !chip.disabled && (
134
- <button
135
- type="button"
136
- aria-label={typeof clearChipLabel === "string" ? clearChipLabel : "Remove filter"}
137
- className="rounded-full p-0.5 hover:bg-muted"
138
- onClick={(event) => {
139
- stopInteractivePropagation(event)
140
- onRemoveChip(chip.key)
141
- }}
142
- onMouseDown={stopInteractivePropagation}
143
- onDoubleClick={stopInteractivePropagation}
144
- >
145
- <XIcon className="size-3" />
146
- </button>
147
- )}
148
- </Badge>
149
- ))}
150
- {hiddenChipCount > 0 ? (
151
- <Badge variant="outline">{chipOverflowLabel(hiddenChipCount)}</Badge>
152
- ) : null}
153
- </>
154
- ) : (
155
- <span className="text-sm text-muted-foreground">{emptyChips}</span>
156
- )}
157
- </div>
158
- )}
159
- </div>
160
- )
161
- }
162
-
163
- export { FilterBar }