@dreamtree-org/twreact-ui 1.3.0 → 1.3.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 (184) hide show
  1. package/README.md +179 -10
  2. package/ai-skills/dreamtree-ui.md +71 -12
  3. package/dist/ai-schema.json +452 -17
  4. package/dist/components/core/Accordion.d.ts.map +1 -1
  5. package/dist/components/core/Button.d.ts.map +1 -1
  6. package/dist/components/core/Checkbox.d.ts.map +1 -1
  7. package/dist/components/core/ColorPicker.d.ts.map +1 -1
  8. package/dist/components/core/DatePicker.d.ts.map +1 -1
  9. package/dist/components/core/DateRangePicker.d.ts.map +1 -1
  10. package/dist/components/core/Form.d.ts.map +1 -1
  11. package/dist/components/core/Input.d.ts.map +1 -1
  12. package/dist/components/core/LocationPicker.d.ts.map +1 -1
  13. package/dist/components/core/Popover.d.ts +4 -0
  14. package/dist/components/core/Popover.d.ts.map +1 -0
  15. package/dist/components/core/PriceRangePicker.d.ts.map +1 -1
  16. package/dist/components/core/ProgressBar.d.ts.map +1 -1
  17. package/dist/components/core/Radio.d.ts.map +1 -1
  18. package/dist/components/core/Rate.d.ts.map +1 -1
  19. package/dist/components/core/Select.d.ts.map +1 -1
  20. package/dist/components/core/Skeleton.d.ts.map +1 -1
  21. package/dist/components/core/Slider.d.ts +4 -0
  22. package/dist/components/core/Slider.d.ts.map +1 -0
  23. package/dist/components/core/SpeechToText.d.ts.map +1 -1
  24. package/dist/components/core/Switch.d.ts.map +1 -1
  25. package/dist/components/core/Table/ActionMenu.d.ts.map +1 -1
  26. package/dist/components/core/Table/ColumnMenu.d.ts +2 -1
  27. package/dist/components/core/Table/ColumnMenu.d.ts.map +1 -1
  28. package/dist/components/core/Table/MobileCard.d.ts +2 -2
  29. package/dist/components/core/Table/MobileCard.d.ts.map +1 -1
  30. package/dist/components/core/Table/Table.d.ts.map +1 -1
  31. package/dist/components/core/Table/TableRow.d.ts +4 -2
  32. package/dist/components/core/Table/TableRow.d.ts.map +1 -1
  33. package/dist/components/core/Tabs.d.ts.map +1 -1
  34. package/dist/components/core/Textarea.d.ts +4 -0
  35. package/dist/components/core/Textarea.d.ts.map +1 -0
  36. package/dist/components/core/ThreeDotPopover.d.ts.map +1 -1
  37. package/dist/components/core/Tooltip.d.ts.map +1 -1
  38. package/dist/components/feedback/Dialog.d.ts.map +1 -1
  39. package/dist/components/feedback/Drawer.d.ts +4 -0
  40. package/dist/components/feedback/Drawer.d.ts.map +1 -0
  41. package/dist/components/feedback/Toast.d.ts +14 -5
  42. package/dist/components/feedback/Toast.d.ts.map +1 -1
  43. package/dist/components/feedback/Tour.d.ts +4 -0
  44. package/dist/components/feedback/Tour.d.ts.map +1 -0
  45. package/dist/components/feedback/TourSpotlight.d.ts +9 -0
  46. package/dist/components/feedback/TourSpotlight.d.ts.map +1 -0
  47. package/dist/components/navigation/Breadcrumbs.d.ts.map +1 -1
  48. package/dist/components/navigation/FootNav.d.ts.map +1 -1
  49. package/dist/components/navigation/Navbar.d.ts.map +1 -1
  50. package/dist/components/navigation/Sidebar.d.ts +8 -2
  51. package/dist/components/navigation/Sidebar.d.ts.map +1 -1
  52. package/dist/components/utility/Badge.d.ts.map +1 -1
  53. package/dist/components/utility/FileUpload.d.ts.map +1 -1
  54. package/dist/components/utility/Sortable.d.ts +4 -0
  55. package/dist/components/utility/Sortable.d.ts.map +1 -0
  56. package/dist/esm/_vendor/object-assign/index.js +99 -0
  57. package/dist/esm/_vendor/prop-types/_vendor/react-is/cjs/react-is.development.js +190 -0
  58. package/dist/esm/_vendor/prop-types/_vendor/react-is/cjs/react-is.production.min.js +26 -0
  59. package/dist/esm/_vendor/prop-types/_vendor/react-is/index.js +19 -0
  60. package/dist/esm/_vendor/prop-types/checkPropTypes.js +115 -0
  61. package/dist/esm/_vendor/prop-types/factoryWithThrowingShims.js +74 -0
  62. package/dist/esm/_vendor/prop-types/factoryWithTypeCheckers.js +625 -0
  63. package/dist/esm/_vendor/prop-types/index.js +30 -0
  64. package/dist/esm/_vendor/prop-types/lib/ReactPropTypesSecret.js +21 -0
  65. package/dist/esm/_vendor/prop-types/lib/has.js +11 -0
  66. package/dist/esm/_virtual/_commonjsHelpers.js +5 -0
  67. package/dist/esm/_virtual/_rollupPluginBabelHelpers.js +329 -0
  68. package/dist/esm/_virtual/index.js +3 -0
  69. package/dist/esm/_virtual/index2.js +3 -0
  70. package/dist/esm/_virtual/react-is.development.js +3 -0
  71. package/dist/esm/_virtual/react-is.production.min.js +3 -0
  72. package/dist/esm/components/blocks/AppShell.js +205 -0
  73. package/dist/esm/components/blocks/ConfirmDialog.js +57 -0
  74. package/dist/esm/components/blocks/EmptyState.js +44 -0
  75. package/dist/esm/components/blocks/ErrorState.js +53 -0
  76. package/dist/esm/components/blocks/LoadingState.js +134 -0
  77. package/dist/esm/components/blocks/PageHeader.js +51 -0
  78. package/dist/esm/components/blocks/StatCard.js +79 -0
  79. package/dist/esm/components/blocks/StatusPill.js +55 -0
  80. package/dist/esm/components/core/Accordion.js +260 -0
  81. package/dist/esm/components/core/Button.js +59 -0
  82. package/dist/esm/components/core/Checkbox.js +188 -0
  83. package/dist/esm/components/core/ColorPicker.js +348 -0
  84. package/dist/esm/components/core/DatePicker.js +436 -0
  85. package/dist/esm/components/core/DateRangePicker.js +494 -0
  86. package/dist/esm/components/core/Form.js +522 -0
  87. package/dist/esm/components/core/Input.js +179 -0
  88. package/dist/esm/components/core/Loader.js +141 -0
  89. package/dist/esm/components/core/LocationPicker.js +161 -0
  90. package/dist/esm/components/core/Popover.js +171 -0
  91. package/dist/esm/components/core/PriceRangePicker.js +376 -0
  92. package/dist/esm/components/core/ProgressBar.js +152 -0
  93. package/dist/esm/components/core/Radio.js +156 -0
  94. package/dist/esm/components/core/Rate.js +197 -0
  95. package/dist/esm/components/core/RoundedTag.js +118 -0
  96. package/dist/esm/components/core/Select.js +857 -0
  97. package/dist/esm/components/core/Skeleton.js +100 -0
  98. package/dist/esm/components/core/Slider.js +134 -0
  99. package/dist/esm/components/core/SpeechToText.js +226 -0
  100. package/dist/esm/components/core/Switch.js +207 -0
  101. package/dist/esm/components/core/Table/ActionMenu.js +251 -0
  102. package/dist/esm/components/core/Table/ColumnMenu.js +55 -0
  103. package/dist/esm/components/core/Table/FieldInput.js +157 -0
  104. package/dist/esm/components/core/Table/MobileCard.js +187 -0
  105. package/dist/esm/components/core/Table/MobileFilters.js +72 -0
  106. package/dist/esm/components/core/Table/Pagination.js +157 -0
  107. package/dist/esm/components/core/Table/Table.js +1533 -0
  108. package/dist/esm/components/core/Table/TableRow.js +254 -0
  109. package/dist/esm/components/core/Table/constants.js +35 -0
  110. package/dist/esm/components/core/Table/helpers.js +124 -0
  111. package/dist/esm/components/core/Table/useClickOutside.js +26 -0
  112. package/dist/esm/components/core/Tabs.js +289 -0
  113. package/dist/esm/components/core/TextToSpeech.js +52 -0
  114. package/dist/esm/components/core/Textarea.js +125 -0
  115. package/dist/esm/components/core/ThreeDotPopover.js +160 -0
  116. package/dist/esm/components/core/Tooltip.js +372 -0
  117. package/dist/esm/components/feedback/Alert.js +96 -0
  118. package/dist/esm/components/feedback/Dialog.js +200 -0
  119. package/dist/esm/components/feedback/Drawer.js +171 -0
  120. package/dist/esm/components/feedback/Toast.js +362 -0
  121. package/dist/esm/components/feedback/Tour.js +214 -0
  122. package/dist/esm/components/feedback/TourSpotlight.js +71 -0
  123. package/dist/esm/components/navigation/Breadcrumbs.js +75 -0
  124. package/dist/esm/components/navigation/Dropdown.js +53 -0
  125. package/dist/esm/components/navigation/FootNav.js +51 -0
  126. package/dist/esm/components/navigation/Navbar.js +437 -0
  127. package/dist/esm/components/navigation/Sidebar.js +567 -0
  128. package/dist/esm/components/utility/Avatar.js +89 -0
  129. package/dist/esm/components/utility/Badge.js +47 -0
  130. package/dist/esm/components/utility/Card.js +85 -0
  131. package/dist/esm/components/utility/Carousel.js +97 -0
  132. package/dist/esm/components/utility/Condition.js +9 -0
  133. package/dist/esm/components/utility/FileUpload.js +177 -0
  134. package/dist/esm/components/utility/Pagination.js +111 -0
  135. package/dist/esm/components/utility/Sortable.js +190 -0
  136. package/dist/esm/components/utility/Stepper.js +101 -0
  137. package/dist/esm/hooks/useApi.js +169 -0
  138. package/dist/esm/hooks/useControllableState.js +32 -0
  139. package/dist/esm/hooks/useFocusTrap.js +85 -0
  140. package/dist/esm/hooks/useLatestRef.js +20 -0
  141. package/dist/esm/hooks/useMixins.js +100 -0
  142. package/dist/esm/hooks/useScrollLock.js +26 -0
  143. package/dist/esm/hooks/useSliderValues.js +135 -0
  144. package/dist/esm/hooks/useSortable.js +188 -0
  145. package/dist/esm/hooks/useTheme.js +53 -0
  146. package/dist/esm/hooks/useTourTarget.js +92 -0
  147. package/dist/esm/index.js +65 -0
  148. package/dist/esm/store/index.js +26 -0
  149. package/dist/esm/store/store.js +107 -0
  150. package/dist/esm/store/storeSlice.js +45 -0
  151. package/dist/esm/utils/cn.js +11 -0
  152. package/dist/esm/utils/emitter.js +169 -0
  153. package/dist/esm/utils/helpers.js +161 -0
  154. package/dist/esm/utils/position.js +134 -0
  155. package/dist/hooks/useApi.d.ts +2 -1
  156. package/dist/hooks/useApi.d.ts.map +1 -1
  157. package/dist/hooks/useControllableState.d.ts +11 -0
  158. package/dist/hooks/useControllableState.d.ts.map +1 -0
  159. package/dist/hooks/useFocusTrap.d.ts +15 -0
  160. package/dist/hooks/useFocusTrap.d.ts.map +1 -0
  161. package/dist/hooks/useLatestRef.d.ts +8 -0
  162. package/dist/hooks/useLatestRef.d.ts.map +1 -0
  163. package/dist/hooks/useMixins.d.ts.map +1 -1
  164. package/dist/hooks/useScrollLock.d.ts +2 -0
  165. package/dist/hooks/useScrollLock.d.ts.map +1 -0
  166. package/dist/hooks/useSliderValues.d.ts +43 -0
  167. package/dist/hooks/useSliderValues.d.ts.map +1 -0
  168. package/dist/hooks/useSortable.d.ts +32 -0
  169. package/dist/hooks/useSortable.d.ts.map +1 -0
  170. package/dist/hooks/useTheme.d.ts.map +1 -1
  171. package/dist/hooks/useTourTarget.d.ts +15 -0
  172. package/dist/hooks/useTourTarget.d.ts.map +1 -0
  173. package/dist/index.css +1 -1
  174. package/dist/index.d.ts +8 -2
  175. package/dist/index.esm.css +1 -1
  176. package/dist/index.esm.js +4800 -2212
  177. package/dist/index.js +4805 -2210
  178. package/dist/types/index.d.ts +193 -5
  179. package/dist/types/index.d.ts.map +1 -1
  180. package/dist/utils/position.d.ts +30 -0
  181. package/dist/utils/position.d.ts.map +1 -0
  182. package/doc/README.md +7 -1
  183. package/mcp/catalog.snapshot.json +911 -212
  184. package/package.json +14 -2
@@ -0,0 +1,53 @@
1
+ 'use client';
2
+ import { objectWithoutProperties as _objectWithoutProperties, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+ import React from 'react';
5
+ import { AlertCircle, RotateCw } from 'lucide-react';
6
+ import { cn } from '../../utils/cn.js';
7
+ import Button from '../core/Button.js';
8
+
9
+ var _excluded = ["title", "description", "onRetry", "retryLabel", "className"];
10
+ // Extracted from CampaignPro/components/app/page-error.tsx (7 products hand-roll one).
11
+ // Neutral copy and a retry; never shows a raw error.message.
12
+ var ErrorState = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
13
+ var _ref$title = _ref.title,
14
+ title = _ref$title === void 0 ? "We couldn't load this" : _ref$title,
15
+ _ref$description = _ref.description,
16
+ description = _ref$description === void 0 ? 'Your data is safe. Try again, and if it keeps happening, contact support.' : _ref$description,
17
+ onRetry = _ref.onRetry,
18
+ _ref$retryLabel = _ref.retryLabel,
19
+ retryLabel = _ref$retryLabel === void 0 ? 'Try again' : _ref$retryLabel,
20
+ className = _ref.className,
21
+ props = _objectWithoutProperties(_ref, _excluded);
22
+ return jsxs("div", _objectSpread2(_objectSpread2({
23
+ ref: ref,
24
+ role: "alert",
25
+ className: cn('flex flex-col items-center justify-center gap-2 px-6 py-12 text-center', className)
26
+ }, props), {}, {
27
+ children: [jsx("span", {
28
+ className: "mb-1 grid h-12 w-12 place-items-center rounded-full bg-error-50 text-error-600",
29
+ "aria-hidden": "true",
30
+ children: jsx(AlertCircle, {
31
+ className: "h-6 w-6"
32
+ })
33
+ }), jsx("h3", {
34
+ className: "text-base font-semibold text-foreground",
35
+ children: title
36
+ }), description && jsx("p", {
37
+ className: "max-w-sm text-sm text-muted",
38
+ children: description
39
+ }), onRetry && jsx(Button, {
40
+ variant: "outline",
41
+ className: "mt-3",
42
+ onClick: onRetry,
43
+ leftIcon: jsx(RotateCw, {
44
+ className: "h-4 w-4",
45
+ "aria-hidden": "true"
46
+ }),
47
+ children: retryLabel
48
+ })]
49
+ }));
50
+ });
51
+ ErrorState.displayName = 'ErrorState';
52
+
53
+ export { ErrorState as default };
@@ -0,0 +1,134 @@
1
+ 'use client';
2
+ import { objectWithoutProperties as _objectWithoutProperties, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+ import React from 'react';
5
+ import { cn } from '../../utils/cn.js';
6
+
7
+ var _excluded = ["variant", "rows", "label", "className"];
8
+ // Extracted from venturepro/client/src/components/States.jsx (6 products hand-roll loaders).
9
+ // A skeleton shaped like the content that replaces it; no page-level spinners.
10
+ // Plain bars rather than twreact Skeleton: Skeleton gives every bar its own role="status" and an
11
+ // inline colour, which would nest live regions inside this one.
12
+ var Bone = function Bone(_ref) {
13
+ var _ref$width = _ref.width,
14
+ width = _ref$width === void 0 ? '100%' : _ref$width,
15
+ _ref$height = _ref.height,
16
+ height = _ref$height === void 0 ? 14 : _ref$height,
17
+ className = _ref.className;
18
+ return jsx("span", {
19
+ "aria-hidden": "true",
20
+ className: cn('block animate-pulse rounded-control bg-gray-200 motion-reduce:animate-none', className),
21
+ style: {
22
+ width: width,
23
+ height: height
24
+ }
25
+ });
26
+ };
27
+ var Line = Bone;
28
+ var shapes = {
29
+ table: function table(rows) {
30
+ return jsx("div", {
31
+ className: "divide-y divide-gray-200",
32
+ children: Array.from({
33
+ length: rows
34
+ }, function (_, i) {
35
+ return jsxs("div", {
36
+ className: "flex items-center gap-4 px-4 py-3",
37
+ children: [jsx(Line, {
38
+ width: "30%"
39
+ }), jsx(Line, {
40
+ width: "20%"
41
+ }), jsx(Line, {
42
+ width: "15%"
43
+ }), jsx(Line, {
44
+ width: "10%"
45
+ })]
46
+ }, i);
47
+ })
48
+ });
49
+ },
50
+ cards: function cards(rows) {
51
+ return jsx("div", {
52
+ className: "grid gap-4 p-4 sm:grid-cols-2 lg:grid-cols-3",
53
+ children: Array.from({
54
+ length: rows
55
+ }, function (_, i) {
56
+ return jsxs("div", {
57
+ className: "flex flex-col gap-3 rounded-card border border-gray-200 p-4",
58
+ children: [jsx(Line, {
59
+ width: "60%",
60
+ height: 16
61
+ }), jsx(Line, {}), jsx(Line, {
62
+ width: "80%"
63
+ })]
64
+ }, i);
65
+ })
66
+ });
67
+ },
68
+ stats: function stats(rows) {
69
+ return jsx("div", {
70
+ className: "grid grid-cols-2 gap-4 lg:grid-cols-4",
71
+ children: Array.from({
72
+ length: rows
73
+ }, function (_, i) {
74
+ return jsxs("div", {
75
+ className: "flex items-center gap-4 rounded-card border border-gray-200 bg-surface p-5",
76
+ children: [jsx(Bone, {
77
+ width: 48,
78
+ height: 48
79
+ }), jsxs("div", {
80
+ className: "flex flex-1 flex-col gap-2",
81
+ children: [jsx(Line, {
82
+ width: "60%"
83
+ }), jsx(Line, {
84
+ width: "40%",
85
+ height: 24
86
+ })]
87
+ })]
88
+ }, i);
89
+ })
90
+ });
91
+ },
92
+ detail: function detail(rows) {
93
+ return jsx("div", {
94
+ className: "grid grid-cols-[minmax(8rem,auto)_1fr] gap-x-6 gap-y-3 p-4",
95
+ children: Array.from({
96
+ length: rows
97
+ }, function (_, i) {
98
+ return jsxs(React.Fragment, {
99
+ children: [jsx(Line, {
100
+ width: "70%"
101
+ }), jsx(Line, {
102
+ width: "".concat(50 + i * 17 % 40, "%")
103
+ })]
104
+ }, i);
105
+ })
106
+ });
107
+ }
108
+ };
109
+ var LoadingState = /*#__PURE__*/React.forwardRef(function (_ref2, ref) {
110
+ var _ref2$variant = _ref2.variant,
111
+ variant = _ref2$variant === void 0 ? 'table' : _ref2$variant,
112
+ rows = _ref2.rows,
113
+ _ref2$label = _ref2.label,
114
+ label = _ref2$label === void 0 ? 'Loading…' : _ref2$label,
115
+ className = _ref2.className,
116
+ props = _objectWithoutProperties(_ref2, _excluded);
117
+ var count = rows !== null && rows !== void 0 ? rows : variant === 'stats' ? 4 : variant === 'cards' ? 3 : 5;
118
+ var render = shapes[variant] || shapes.table;
119
+ return jsxs("div", _objectSpread2(_objectSpread2({
120
+ ref: ref,
121
+ role: "status",
122
+ "aria-busy": "true",
123
+ "aria-live": "polite",
124
+ className: cn(className)
125
+ }, props), {}, {
126
+ children: [jsx("span", {
127
+ className: "sr-only",
128
+ children: label
129
+ }), render(count)]
130
+ }));
131
+ });
132
+ LoadingState.displayName = 'LoadingState';
133
+
134
+ export { Bone, LoadingState as default };
@@ -0,0 +1,51 @@
1
+ 'use client';
2
+ import { objectWithoutProperties as _objectWithoutProperties, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+ import React from 'react';
5
+ import { ArrowLeft } from 'lucide-react';
6
+ import { cn } from '../../utils/cn.js';
7
+
8
+ var _excluded = ["title", "subtitle", "actions", "back", "linkAs", "className"];
9
+ // Extracted from taskpro/client/src/features/shared/PageHeader.jsx (31 imports) and the
10
+ // CampaignPro UX guide's page anatomy: one h1, a muted subtitle, actions top right.
11
+ var PageHeader = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
12
+ var title = _ref.title,
13
+ subtitle = _ref.subtitle,
14
+ actions = _ref.actions,
15
+ back = _ref.back,
16
+ _ref$linkAs = _ref.linkAs,
17
+ Link = _ref$linkAs === void 0 ? 'a' : _ref$linkAs,
18
+ className = _ref.className,
19
+ props = _objectWithoutProperties(_ref, _excluded);
20
+ return jsxs("div", _objectSpread2(_objectSpread2({
21
+ ref: ref,
22
+ className: cn('flex flex-col gap-3', className)
23
+ }, props), {}, {
24
+ children: [back && jsxs(Link, {
25
+ href: back.href,
26
+ className: "inline-flex w-fit items-center gap-1.5 rounded-control text-sm text-muted hover:text-foreground focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2",
27
+ children: [jsx(ArrowLeft, {
28
+ className: "h-4 w-4",
29
+ "aria-hidden": "true"
30
+ }), back.label]
31
+ }), jsxs("div", {
32
+ className: "flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between",
33
+ children: [jsxs("div", {
34
+ className: "min-w-0",
35
+ children: [jsx("h1", {
36
+ className: "text-xl font-semibold tracking-tight text-foreground sm:text-2xl",
37
+ children: title
38
+ }), subtitle && jsx("p", {
39
+ className: "mt-1 max-w-2xl text-sm text-muted",
40
+ children: subtitle
41
+ })]
42
+ }), actions && jsx("div", {
43
+ className: "flex flex-wrap items-center gap-3",
44
+ children: actions
45
+ })]
46
+ })]
47
+ }));
48
+ });
49
+ PageHeader.displayName = 'PageHeader';
50
+
51
+ export { PageHeader as default };
@@ -0,0 +1,79 @@
1
+ 'use client';
2
+ import { objectWithoutProperties as _objectWithoutProperties, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
+ import { jsx, jsxs } from 'react/jsx-runtime';
4
+ import React from 'react';
5
+ import { ArrowUp, ArrowDown } from 'lucide-react';
6
+ import { cn } from '../../utils/cn.js';
7
+ import Card from '../utility/Card.js';
8
+ import { Bone } from './LoadingState.js';
9
+
10
+ var _excluded = ["label", "value", "icon", "tone", "change", "loading", "className"];
11
+ // Extracted from PracticePro/components/ui/StatCard.tsx (28 imports), with tones mapped to the
12
+ // semantic scales instead of product colours. Class names are written out in full so Tailwind keeps them.
13
+ var TONES = {
14
+ primary: 'bg-primary-50 text-primary-600',
15
+ secondary: 'bg-secondary-100 text-secondary-600',
16
+ success: 'bg-success-50 text-success-600',
17
+ warning: 'bg-warning-50 text-warning-600',
18
+ error: 'bg-error-50 text-error-600',
19
+ info: 'bg-info-50 text-info-600'
20
+ };
21
+ var StatCard = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
22
+ var _change$goodWhenUp, _change$unit;
23
+ var label = _ref.label,
24
+ value = _ref.value,
25
+ icon = _ref.icon,
26
+ _ref$tone = _ref.tone,
27
+ tone = _ref$tone === void 0 ? 'primary' : _ref$tone,
28
+ change = _ref.change,
29
+ _ref$loading = _ref.loading,
30
+ loading = _ref$loading === void 0 ? false : _ref$loading,
31
+ className = _ref.className,
32
+ props = _objectWithoutProperties(_ref, _excluded);
33
+ var up = change ? change.value >= 0 : false;
34
+ var good = change ? ((_change$goodWhenUp = change.goodWhenUp) !== null && _change$goodWhenUp !== void 0 ? _change$goodWhenUp : true) === up : false;
35
+ return jsx(Card, _objectSpread2(_objectSpread2({
36
+ ref: ref,
37
+ className: cn('h-full', className)
38
+ }, props), {}, {
39
+ children: jsxs("div", {
40
+ className: "flex items-start gap-4 p-5",
41
+ children: [icon && jsx("span", {
42
+ className: cn('grid h-12 w-12 shrink-0 place-items-center rounded-card', TONES[tone] || TONES.primary),
43
+ "aria-hidden": "true",
44
+ children: icon
45
+ }), jsxs("div", {
46
+ className: "min-w-0",
47
+ children: [jsx("p", {
48
+ className: "text-sm text-muted",
49
+ children: label
50
+ }), loading ? jsx(Bone, {
51
+ height: 32,
52
+ width: 72,
53
+ className: "mt-1"
54
+ }) : jsx("p", {
55
+ className: "mt-0.5 text-2xl font-semibold tracking-tight text-foreground tabular-nums sm:text-3xl",
56
+ children: value
57
+ }), change && !loading && jsxs("p", {
58
+ className: "mt-1 flex items-center gap-1 text-xs text-muted",
59
+ children: [jsxs("span", {
60
+ className: cn('inline-flex items-center gap-0.5 font-semibold', good ? 'text-success-600' : 'text-error-600'),
61
+ children: [up ? jsx(ArrowUp, {
62
+ className: "h-3.5 w-3.5",
63
+ "aria-hidden": "true"
64
+ }) : jsx(ArrowDown, {
65
+ className: "h-3.5 w-3.5",
66
+ "aria-hidden": "true"
67
+ }), jsxs("span", {
68
+ className: "sr-only",
69
+ children: [up ? 'Up' : 'Down', " "]
70
+ }), Math.abs(change.value), (_change$unit = change.unit) !== null && _change$unit !== void 0 ? _change$unit : '%']
71
+ }), change.period]
72
+ })]
73
+ })]
74
+ })
75
+ }));
76
+ });
77
+ StatCard.displayName = 'StatCard';
78
+
79
+ export { StatCard as default };
@@ -0,0 +1,55 @@
1
+ 'use client';
2
+ import { objectWithoutProperties as _objectWithoutProperties, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+ import React from 'react';
5
+ import { cn } from '../../utils/cn.js';
6
+ import Badge from '../utility/Badge.js';
7
+
8
+ var _excluded = ["status", "map", "tone", "icon", "children", "className"];
9
+ // Extracted from billpro/client/src/components/StatusPill.jsx (10 products hand-roll one).
10
+ // One map from domain state to tone + human label; unknown states are humanized, never shown raw.
11
+ var TONE_TO_VARIANT = {
12
+ neutral: 'secondary',
13
+ info: 'primary',
14
+ success: 'success',
15
+ warning: 'warning',
16
+ danger: 'error',
17
+ muted: 'outline',
18
+ // Semantic tones are accepted too.
19
+ primary: 'primary',
20
+ secondary: 'secondary',
21
+ error: 'error'
22
+ };
23
+ var humanizeStatus = function humanizeStatus(status) {
24
+ var words = String(status).replace(/[_-]+/g, ' ').trim().toLowerCase();
25
+ return words.charAt(0).toUpperCase() + words.slice(1);
26
+ };
27
+ var StatusPill = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
28
+ var _ref2;
29
+ var status = _ref.status,
30
+ map = _ref.map,
31
+ tone = _ref.tone,
32
+ icon = _ref.icon,
33
+ children = _ref.children,
34
+ className = _ref.className,
35
+ props = _objectWithoutProperties(_ref, _excluded);
36
+ var entry = status != null && map ? map[status] : undefined;
37
+ var resolvedTone = (entry === null || entry === void 0 ? void 0 : entry.tone) || tone || 'neutral';
38
+ var label = (_ref2 = children !== null && children !== void 0 ? children : entry === null || entry === void 0 ? void 0 : entry.label) !== null && _ref2 !== void 0 ? _ref2 : status != null ? humanizeStatus(status) : null;
39
+ var resolvedIcon = icon !== null && icon !== void 0 ? icon : entry === null || entry === void 0 ? void 0 : entry.icon;
40
+ return jsxs(Badge, _objectSpread2(_objectSpread2({
41
+ ref: ref,
42
+ variant: TONE_TO_VARIANT[resolvedTone] || 'secondary',
43
+ size: "sm",
44
+ className: cn('gap-1.5 whitespace-nowrap', className)
45
+ }, props), {}, {
46
+ children: [resolvedIcon && jsx("span", {
47
+ className: "inline-flex h-3.5 w-3.5 items-center",
48
+ "aria-hidden": "true",
49
+ children: resolvedIcon
50
+ }), label]
51
+ }));
52
+ });
53
+ StatusPill.displayName = 'StatusPill';
54
+
55
+ export { StatusPill as default, humanizeStatus };
@@ -0,0 +1,260 @@
1
+ 'use client';
2
+ import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2, toConsumableArray as _toConsumableArray } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
+ import { jsx, jsxs } from 'react/jsx-runtime';
4
+ import { forwardRef, useState, useRef, useEffect, useLayoutEffect } from 'react';
5
+ import { cn } from '../../utils/cn.js';
6
+ import { useLatestRef } from '../../hooks/useLatestRef.js';
7
+
8
+ var _excluded = ["items", "allowMultiple", "defaultOpenIndexes", "onChange", "className", "headerClassName", "contentClassName", "chevronPosition", "chevronIcon", "bordered", "rounded", "size", "transitionDuration"];
9
+ /**
10
+ * item.leftIcon may be:
11
+ * - ReactNode (e.g. <svg/>)
12
+ * - (index: number, item: any) => ReactNode
13
+ */
14
+ var Accordion = /*#__PURE__*/forwardRef(function Accordion(_ref, ref) {
15
+ var _ref$items = _ref.items,
16
+ items = _ref$items === void 0 ? [] : _ref$items,
17
+ _ref$allowMultiple = _ref.allowMultiple,
18
+ allowMultiple = _ref$allowMultiple === void 0 ? false : _ref$allowMultiple,
19
+ _ref$defaultOpenIndex = _ref.defaultOpenIndexes,
20
+ defaultOpenIndexes = _ref$defaultOpenIndex === void 0 ? [] : _ref$defaultOpenIndex,
21
+ onChange = _ref.onChange,
22
+ _ref$className = _ref.className,
23
+ className = _ref$className === void 0 ? "" : _ref$className,
24
+ _ref$headerClassName = _ref.headerClassName,
25
+ headerClassName = _ref$headerClassName === void 0 ? "" : _ref$headerClassName,
26
+ _ref$contentClassName = _ref.contentClassName,
27
+ contentClassName = _ref$contentClassName === void 0 ? "" : _ref$contentClassName,
28
+ _ref$chevronPosition = _ref.chevronPosition,
29
+ chevronPosition = _ref$chevronPosition === void 0 ? "right" : _ref$chevronPosition,
30
+ _ref$chevronIcon = _ref.chevronIcon,
31
+ chevronIcon = _ref$chevronIcon === void 0 ? null : _ref$chevronIcon,
32
+ _ref$bordered = _ref.bordered,
33
+ bordered = _ref$bordered === void 0 ? true : _ref$bordered,
34
+ _ref$rounded = _ref.rounded,
35
+ rounded = _ref$rounded === void 0 ? "md" : _ref$rounded,
36
+ _ref$size = _ref.size,
37
+ size = _ref$size === void 0 ? "md" : _ref$size,
38
+ _ref$transitionDurati = _ref.transitionDuration,
39
+ transitionDuration = _ref$transitionDurati === void 0 ? 220 : _ref$transitionDurati,
40
+ rest = _objectWithoutProperties(_ref, _excluded);
41
+ var saneDefault = Array.isArray(defaultOpenIndexes) ? defaultOpenIndexes.filter(function (i) {
42
+ return Number.isFinite(i) && i >= 0 && i < items.length;
43
+ }) : [];
44
+ var _useState = useState(saneDefault),
45
+ _useState2 = _slicedToArray(_useState, 2),
46
+ openIndexes = _useState2[0],
47
+ setOpenIndexes = _useState2[1];
48
+ var headerRefs = useRef([]);
49
+ var panelRefs = useRef([]);
50
+ // Drop out-of-range indexes when the item count changes
51
+ // (adjust-during-render pattern).
52
+ var _useState3 = useState(items.length),
53
+ _useState4 = _slicedToArray(_useState3, 2),
54
+ prevItemCount = _useState4[0],
55
+ setPrevItemCount = _useState4[1];
56
+ if (items.length !== prevItemCount) {
57
+ setPrevItemCount(items.length);
58
+ setOpenIndexes(function (prev) {
59
+ return prev.filter(function (i) {
60
+ return i >= 0 && i < items.length;
61
+ });
62
+ });
63
+ }
64
+ var onChangeRef = useLatestRef(onChange);
65
+ useEffect(function () {
66
+ if (typeof onChangeRef.current === "function") onChangeRef.current(openIndexes);
67
+ }, [openIndexes, onChangeRef]);
68
+ // Size panels from their measured content before paint. Done imperatively
69
+ // (not via the style prop) so render never reads refs / the DOM.
70
+ useLayoutEffect(function () {
71
+ panelRefs.current.forEach(function (panelEl, idx) {
72
+ if (!panelEl) return;
73
+ var open = openIndexes.includes(idx);
74
+ panelEl.style.maxHeight = open ? panelEl.scrollHeight + "px" : "0px";
75
+ });
76
+ }, [openIndexes, items]);
77
+ var isOpen = function isOpen(index) {
78
+ return openIndexes.includes(index);
79
+ };
80
+ var toggleIndex = function toggleIndex(index) {
81
+ var _items$index;
82
+ if ((_items$index = items[index]) !== null && _items$index !== void 0 && _items$index.disabled) return;
83
+ setOpenIndexes(function (prev) {
84
+ if (allowMultiple) {
85
+ return prev.includes(index) ? prev.filter(function (i) {
86
+ return i !== index;
87
+ }) : [].concat(_toConsumableArray(prev), [index]);
88
+ } else {
89
+ return prev.includes(index) ? [] : [index];
90
+ }
91
+ });
92
+ };
93
+ var handleHeaderKeyDown = function handleHeaderKeyDown(e, index) {
94
+ var max = items.length - 1;
95
+ if (e.key === "ArrowDown") {
96
+ var _headerRefs$current$n;
97
+ e.preventDefault();
98
+ var next = index === max ? 0 : index + 1;
99
+ (_headerRefs$current$n = headerRefs.current[next]) === null || _headerRefs$current$n === void 0 || _headerRefs$current$n.focus();
100
+ } else if (e.key === "ArrowUp") {
101
+ var _headerRefs$current$p;
102
+ e.preventDefault();
103
+ var prev = index === 0 ? max : index - 1;
104
+ (_headerRefs$current$p = headerRefs.current[prev]) === null || _headerRefs$current$p === void 0 || _headerRefs$current$p.focus();
105
+ } else if (e.key === "Home") {
106
+ var _headerRefs$current$;
107
+ e.preventDefault();
108
+ (_headerRefs$current$ = headerRefs.current[0]) === null || _headerRefs$current$ === void 0 || _headerRefs$current$.focus();
109
+ } else if (e.key === "End") {
110
+ var _headerRefs$current$m;
111
+ e.preventDefault();
112
+ (_headerRefs$current$m = headerRefs.current[max]) === null || _headerRefs$current$m === void 0 || _headerRefs$current$m.focus();
113
+ } else if (e.key === "Enter" || e.key === " ") {
114
+ e.preventDefault();
115
+ toggleIndex(index);
116
+ }
117
+ };
118
+ // header sizes keep vertical padding; content only px (py moved inside inner wrapper)
119
+ var sizeMap = {
120
+ sm: {
121
+ header: "py-2 px-3 text-sm",
122
+ content: "px-3 text-sm"
123
+ },
124
+ md: {
125
+ header: "py-3 px-4 text-base",
126
+ content: "px-4 text-sm"
127
+ },
128
+ lg: {
129
+ header: "py-4 px-5 text-lg",
130
+ content: "px-5 text-base"
131
+ }
132
+ };
133
+ var innerPaddingMap = {
134
+ sm: "py-2",
135
+ md: "py-3",
136
+ lg: "py-4"
137
+ };
138
+ var roundedMap = {
139
+ none: "",
140
+ sm: "rounded-sm",
141
+ md: "rounded-md",
142
+ lg: "rounded-lg",
143
+ xl: "rounded-xl"
144
+ };
145
+ var wrapperClasses = cn(bordered ? "bg-white" : "bg-transparent", bordered ? "divide-y divide-gray-200" : "", roundedMap[rounded] || roundedMap.md, "shadow-sm", className);
146
+ var renderLeftIcon = function renderLeftIcon(item, index) {
147
+ var left = item === null || item === void 0 ? void 0 : item.leftIcon;
148
+ if (!left) return null;
149
+ if (typeof left === "function") {
150
+ try {
151
+ return left(index, item);
152
+ } catch (err) {
153
+ // don't crash the component if the function throws
154
+ // you could also console.error here in dev
155
+ return null;
156
+ }
157
+ }
158
+ return left; // assume ReactNode
159
+ };
160
+ return jsx("div", _objectSpread2(_objectSpread2({
161
+ ref: ref,
162
+ className: wrapperClasses,
163
+ role: "presentation"
164
+ }, rest), {}, {
165
+ children: items.map(function (item, index) {
166
+ var _item$id;
167
+ var id = (_item$id = item.id) !== null && _item$id !== void 0 ? _item$id : index;
168
+ var open = isOpen(index);
169
+ var headerId = "accordion-header-".concat(id);
170
+ var panelId = "accordion-panel-".concat(id);
171
+ var leftIconEl = renderLeftIcon(item, index);
172
+ return jsxs("div", {
173
+ className: "bg-white",
174
+ children: [jsx("h3", {
175
+ children: jsx("button", {
176
+ ref: function ref(el) {
177
+ return headerRefs.current[index] = el;
178
+ },
179
+ id: headerId,
180
+ "aria-controls": panelId,
181
+ "aria-expanded": open,
182
+ disabled: item.disabled,
183
+ onClick: function onClick() {
184
+ return toggleIndex(index);
185
+ },
186
+ onKeyDown: function onKeyDown(e) {
187
+ return handleHeaderKeyDown(e, index);
188
+ },
189
+ type: "button",
190
+ className: "w-full flex items-center ".concat(sizeMap[size].header, " justify-between focus:outline-none focus:ring-2 focus:ring-indigo-500 ").concat(headerClassName, " ").concat(item.disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"),
191
+ children: jsxs("div", {
192
+ className: "flex items-center gap-3 w-full",
193
+ children: [chevronPosition === "left" ? jsx("span", {
194
+ className: "flex-shrink-0 transform transition-transform duration-150 ".concat(open ? "rotate-180" : "rotate-0"),
195
+ children: chevronIcon !== null && chevronIcon !== void 0 ? chevronIcon : jsx("svg", {
196
+ xmlns: "http://www.w3.org/2000/svg",
197
+ className: "h-5 w-5",
198
+ viewBox: "0 0 20 20",
199
+ fill: "currentColor",
200
+ children: jsx("path", {
201
+ fillRule: "evenodd",
202
+ d: "M5.23 7.21a.75.75 0 011.06.02L10 10.94l3.71-3.71a.75.75 0 111.06 1.06l-4.24 4.24a.75.75 0 01-1.06 0L5.21 8.29a.75.75 0 01.02-1.08z",
203
+ clipRule: "evenodd"
204
+ })
205
+ })
206
+ }) : leftIconEl ? jsx("span", {
207
+ className: "flex-shrink-0",
208
+ children: leftIconEl
209
+ }) : null, jsx("div", {
210
+ className: "flex-1 text-left",
211
+ children: jsxs("div", {
212
+ className: "flex items-center gap-2",
213
+ children: [jsx("span", {
214
+ className: "font-medium",
215
+ children: item.title
216
+ }), item.subtitle ? jsx("span", {
217
+ className: "text-primary-500 text-sm",
218
+ children: item.subtitle
219
+ }) : null]
220
+ })
221
+ }), chevronPosition === "right" ? jsx("span", {
222
+ className: "flex-shrink-0 transform transition-transform duration-150 ".concat(open ? "rotate-180" : "rotate-0"),
223
+ children: chevronIcon !== null && chevronIcon !== void 0 ? chevronIcon : jsx("svg", {
224
+ xmlns: "http://www.w3.org/2000/svg",
225
+ className: "h-5 w-5",
226
+ viewBox: "0 0 20 20",
227
+ fill: "currentColor",
228
+ children: jsx("path", {
229
+ fillRule: "evenodd",
230
+ d: "M5.23 7.21a.75.75 0 011.06.02L10 10.94l3.71-3.71a.75.75 0 111.06 1.06l-4.24 4.24a.75.75 0 01-1.06 0L5.21 8.29a.75.75 0 01.02-1.08z",
231
+ clipRule: "evenodd"
232
+ })
233
+ })
234
+ }) : null]
235
+ })
236
+ })
237
+ }), jsx("div", {
238
+ id: panelId,
239
+ role: "region",
240
+ "aria-labelledby": headerId,
241
+ ref: function ref(el) {
242
+ return panelRefs.current[index] = el;
243
+ },
244
+ style: {
245
+ transition: "max-height ".concat(transitionDuration, "ms ease"),
246
+ overflow: "hidden"
247
+ },
248
+ className: "".concat(contentClassName, " ").concat(sizeMap[size].content),
249
+ children: jsx("div", {
250
+ className: "".concat(innerPaddingMap[size]),
251
+ children: item.content
252
+ })
253
+ })]
254
+ }, id);
255
+ })
256
+ }));
257
+ });
258
+ Accordion.displayName = "Accordion";
259
+
260
+ export { Accordion as default };