@ramme-io/ui 4.1.0 → 4.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 (33) hide show
  1. package/README.md +4 -3
  2. package/dist/component-registry.js +55 -52
  3. package/dist/components/ai/AIChatThread/AIChatThread.js +3 -3
  4. package/dist/components/ai/NewsSummaryCard/NewsSummaryCard.js +17 -17
  5. package/dist/components/ai/StockChart/StockChart.js +4 -4
  6. package/dist/components/auth/LoginPage.d.ts +22 -0
  7. package/dist/components/auth/LoginPage.js +50 -42
  8. package/dist/components/forms/ComboBox.js +2 -2
  9. package/dist/components/forms/DatePicker.js +37 -32
  10. package/dist/components/forms/FileUpload.js +39 -37
  11. package/dist/components/forms/Input.js +19 -18
  12. package/dist/components/forms/MultiSelect.js +9 -8
  13. package/dist/components/forms/Select.js +9 -8
  14. package/dist/components/forms/Textarea.d.ts +13 -11
  15. package/dist/components/forms/Textarea.js +36 -16
  16. package/dist/components/layout/Accordion.js +25 -32
  17. package/dist/components/layout/Card.js +38 -21
  18. package/dist/components/layout/DetailDrawer.js +36 -37
  19. package/dist/components/layout/SettingsContainer.js +23 -13
  20. package/dist/components/layout/Sheet.d.ts +58 -0
  21. package/dist/components/layout/Sheet.js +144 -0
  22. package/dist/components/navigation/MobileNav.d.ts +44 -1
  23. package/dist/components/navigation/MobileNav.js +96 -70
  24. package/dist/components/navigation/Tabs.js +19 -12
  25. package/dist/components/ui/icon-loader.d.ts +1 -1
  26. package/dist/index.d.ts +2 -0
  27. package/dist/index.js +218 -211
  28. package/dist/lib/hooks/useSheetGesture.d.ts +81 -0
  29. package/dist/lib/hooks/useSheetGesture.js +70 -0
  30. package/dist/setupTests.d.ts +1 -0
  31. package/dist/wizardManifest.js +130 -10
  32. package/package.json +9 -2
  33. package/src/wizardManifest.ts +130 -10
package/README.md CHANGED
@@ -225,7 +225,7 @@ Props, variants and live examples are in Storybook (`pnpm run storybook`) and at
225
225
  | `MenuDivider` | `@atom/primitive/menu-divider` | A visual separator for grouping MenuItems within a Menu. |
226
226
  | `MenuItem` | `@atom/primitive/menu-item` | An individual selectable item within a Menu component. |
227
227
  | `Message` | `@molecule/ai/message` | Displays a single message in a conversation, including an avatar, author, content, and optional suggestions. |
228
- | `MobileNav` | `@molecule/nav/mobile-nav` | A fixed bottom tab bar for mobile screens, providing native-feeling navigation with primary icon+label tabs and a "More" drawer for secondary links. |
228
+ | `MobileNav` | `@molecule/nav/mobile-nav` | Mobile navigation, in two shapes. |
229
229
  | `MultiSelect` | `@molecule/form/multi-select` | A searchable dropdown for picking several options at once, rendering selections as removable chips. |
230
230
  | `NewsSummaryCard` | `@molecule/ai/news-summary-card` | AI-generated news summary card with recent headlines |
231
231
  | `PageHeader` | `@atom/templates-patterns/page-header` | Displays the main header section of a page, including a title, optional description, and a slot for action buttons. |
@@ -253,7 +253,7 @@ Props, variants and live examples are in Storybook (`pnpm run storybook`) and at
253
253
  | `Tabs` | `@molecule/nav/tabs` | A navigation component that allows users to switch between different content panels within the same area. |
254
254
  | `TelemetryGraph` | `@molecule/ai/telemetry-graph` | AI-generated telemetry visualization component |
255
255
  | `TelemetryLog` | `@molecule/iot/telemetry-log` | A scrolling, newest-first table of raw sensor readings with a bounded row count. |
256
- | `Textarea` | `@atom/form/textarea` | A theme-aware textarea component for multi-line text input. |
256
+ | `Textarea` | `@atom/form/textarea` | A theme-aware multi-line text input with label, helper text, and validation state support. |
257
257
  | `TippyTooltip` | `@molecule/feedback/tippy-tooltip` | A flexible and theme-aware tooltip component that displays additional information on hover. |
258
258
  | `Toast` | `@molecule/feedback/toast` | A single, transient notification message that appears briefly to provide feedback. |
259
259
  | `ToastProvider` | `@molecule/feedback/toast-provider` | Provides a context for displaying transient notifications (toasts). |
@@ -262,7 +262,7 @@ Props, variants and live examples are in Storybook (`pnpm run storybook`) and at
262
262
  | `WatchlistEngine` | `@molecule/block/watchlist-engine` | A self-contained financial watchlist showing tickers with live price, day change, market cap, and a risk grade. |
263
263
  | `WaterPumpControl` | `@molecule/iot/water-pump-control` | An irrigation control block: choose automatic or manual operation and set the soil-moisture target the controller should hold. |
264
264
 
265
- ### Layouts (32)
265
+ ### Layouts (33)
266
266
 
267
267
  | Name | SKU | What it is |
268
268
  | --- | --- | --- |
@@ -294,6 +294,7 @@ Props, variants and live examples are in Storybook (`pnpm run storybook`) and at
294
294
  | `Modal` | `@chassis/layout/modal` | A centered dialog that blocks interaction with the page until dismissed. |
295
295
  | `PageContainer` | `@chassis/layout/page-container` | Standard responsive padding wrapper for the content inside a page. |
296
296
  | `SettingsContainer` | `@chassis/layout/settings-container` | The canonical settings page arrangement, with a fixed slot per section so every app's settings read the same way. |
297
+ | `Sheet` | `@chassis/layout/sheet` | A bottom sheet that opens at a partial height and grows to full screen as you drag or scroll it up. |
297
298
  | `Sidebar` | `@chassis/layout/sidebar` | A collapsible, theme-aware application navigation rail. |
298
299
  | `Statusbar` | `@chassis/layout/statusbar` | The persistent strip pinned to the bottom of the app shell. |
299
300
  | `Toolbar` | `@chassis/layout/toolbar` | The secondary action strip that sits beneath the header. |
@@ -22,8 +22,8 @@ import { AuthLayout as g } from "./components/auth/AuthLayout.js";
22
22
  import { LoginPage as b } from "./components/auth/LoginPage.js";
23
23
  import { SignupPage as C } from "./components/auth/SignupPage.js";
24
24
  import { ActivityFeed as y } from "./components/data-display/ActivityFeed.js";
25
- import { AreaChart as v } from "./components/data-display/AreaChart.js";
26
- import { BarChart as S } from "./components/data-display/BarChart.js";
25
+ import { AreaChart as S } from "./components/data-display/AreaChart.js";
26
+ import { BarChart as v } from "./components/data-display/BarChart.js";
27
27
  import { ChartWithTable as T } from "./components/data-display/ChartWithTable.js";
28
28
  import { CodeBlock as D } from "./components/data-display/CodeBlock.js";
29
29
  import { DataTable as A } from "./components/data-display/DataTable.js";
@@ -77,25 +77,26 @@ import { PageContainer as dr } from "./components/layout/PageContainer.js";
77
77
  import { PageHeader as lr } from "./components/layout/PageHeader.js";
78
78
  import { SectionHeader as fr } from "./components/layout/SectionHeader.js";
79
79
  import { SettingsContainer as sr } from "./components/layout/SettingsContainer.js";
80
- import { Sidebar as zr } from "./components/layout/Sidebar.js";
81
- import { Statusbar as Jr } from "./components/layout/Statusbar.js";
82
- import { Toolbar as Vr } from "./components/layout/Toolbar.js";
80
+ import { Sheet as zr } from "./components/layout/Sheet.js";
81
+ import { Sidebar as Jr } from "./components/layout/Sidebar.js";
82
+ import { Statusbar as Vr } from "./components/layout/Statusbar.js";
83
+ import { Toolbar as Xr } from "./components/layout/Toolbar.js";
83
84
  import { ButtonItem as ur, UserNav as hr } from "./components/layout/UserNav.js";
84
85
  import { ConnectorOverlay as gr } from "./components/molecular/ConnectorOverlay.js";
85
86
  import { DataCard as br } from "./components/molecular/DataCard.js";
86
87
  import { StateMatrix as Cr } from "./components/molecular/StateMatrix.js";
87
- import { Breadcrumbs as Xr, BreadcrumbItem as yr } from "./components/navigation/Breadcrumbs.js";
88
- import { Menu as Zr, MenuItem as vr, MenuDivider as Sr } from "./components/navigation/Menu.js";
88
+ import { Breadcrumbs as Zr, BreadcrumbItem as yr } from "./components/navigation/Breadcrumbs.js";
89
+ import { Menu as $r, MenuItem as Sr, MenuDivider as vr } from "./components/navigation/Menu.js";
89
90
  import { MobileNav as Tr } from "./components/navigation/MobileNav.js";
90
- import { Pagination as $r } from "./components/navigation/Pagination.js";
91
- import { Stepper as rt } from "./components/navigation/Stepper.js";
92
- import { Tabs as tt, TabPanel as Dr } from "./components/navigation/Tabs.js";
93
- import { Avatar as et } from "./components/ui/Avatar.js";
94
- import { Badge as ot } from "./components/ui/Badge.js";
91
+ import { Pagination as rt } from "./components/navigation/Pagination.js";
92
+ import { Stepper as tt } from "./components/navigation/Stepper.js";
93
+ import { Tabs as et, TabPanel as Dr } from "./components/navigation/Tabs.js";
94
+ import { Avatar as ot } from "./components/ui/Avatar.js";
95
+ import { Badge as at } from "./components/ui/Badge.js";
95
96
  import { BrandLogo as Ar } from "./components/ui/BrandLogo.js";
96
- import { Button as at } from "./components/ui/Button.js";
97
- import { Icon as it } from "./components/ui/Icon.js";
98
- const Je = {
97
+ import { Button as it } from "./components/ui/Button.js";
98
+ import { Icon as mt } from "./components/ui/Icon.js";
99
+ const Xe = {
99
100
  Suggestion: Pr,
100
101
  suggestion: Pr,
101
102
  Actions: Br,
@@ -166,12 +167,12 @@ const Je = {
166
167
  ActivityFeed: y,
167
168
  "activity-feed": y,
168
169
  activityfeed: y,
169
- AreaChart: v,
170
- "area-chart": v,
171
- areachart: v,
172
- BarChart: S,
173
- "bar-chart": S,
174
- barchart: S,
170
+ AreaChart: S,
171
+ "area-chart": S,
172
+ areachart: S,
173
+ BarChart: v,
174
+ "bar-chart": v,
175
+ barchart: v,
175
176
  ChartWithTable: T,
176
177
  "chart-with-table": T,
177
178
  chartwithtable: T,
@@ -346,12 +347,14 @@ const Je = {
346
347
  SettingsContainer: sr,
347
348
  "settings-container": sr,
348
349
  settingscontainer: sr,
349
- Sidebar: zr,
350
- sidebar: zr,
351
- Statusbar: Jr,
352
- statusbar: Jr,
353
- Toolbar: Vr,
354
- toolbar: Vr,
350
+ Sheet: zr,
351
+ sheet: zr,
352
+ Sidebar: Jr,
353
+ sidebar: Jr,
354
+ Statusbar: Vr,
355
+ statusbar: Vr,
356
+ Toolbar: Xr,
357
+ toolbar: Xr,
355
358
  UserNav: hr,
356
359
  "user-nav": hr,
357
360
  usernav: hr,
@@ -370,40 +373,40 @@ const Je = {
370
373
  BreadcrumbItem: yr,
371
374
  "breadcrumb-item": yr,
372
375
  breadcrumbitem: yr,
373
- Breadcrumbs: Xr,
374
- breadcrumbs: Xr,
375
- MenuDivider: Sr,
376
- "menu-divider": Sr,
377
- menudivider: Sr,
378
- MenuItem: vr,
379
- "menu-item": vr,
380
- menuitem: vr,
381
- Menu: Zr,
382
- menu: Zr,
376
+ Breadcrumbs: Zr,
377
+ breadcrumbs: Zr,
378
+ MenuDivider: vr,
379
+ "menu-divider": vr,
380
+ menudivider: vr,
381
+ MenuItem: Sr,
382
+ "menu-item": Sr,
383
+ menuitem: Sr,
384
+ Menu: $r,
385
+ menu: $r,
383
386
  MobileNav: Tr,
384
387
  "mobile-nav": Tr,
385
388
  mobilenav: Tr,
386
- Pagination: $r,
387
- pagination: $r,
388
- Stepper: rt,
389
- stepper: rt,
389
+ Pagination: rt,
390
+ pagination: rt,
391
+ Stepper: tt,
392
+ stepper: tt,
390
393
  TabPanel: Dr,
391
394
  "tab-panel": Dr,
392
395
  tabpanel: Dr,
393
- Tabs: tt,
394
- tabs: tt,
395
- Avatar: et,
396
- avatar: et,
397
- Badge: ot,
398
- badge: ot,
396
+ Tabs: et,
397
+ tabs: et,
398
+ Avatar: ot,
399
+ avatar: ot,
400
+ Badge: at,
401
+ badge: at,
399
402
  BrandLogo: Ar,
400
403
  "brand-logo": Ar,
401
404
  brandlogo: Ar,
402
- Button: at,
403
- button: at,
404
- Icon: it,
405
- icon: it
405
+ Button: it,
406
+ button: it,
407
+ Icon: mt,
408
+ icon: mt
406
409
  };
407
410
  export {
408
- Je as AUTO_REGISTRY
411
+ Xe as AUTO_REGISTRY
409
412
  };
@@ -1,5 +1,5 @@
1
1
  import { jsxs as c, jsx as t, Fragment as w } from "react/jsx-runtime";
2
- import { useState as R, useRef as B, useEffect as D, useCallback as N } from "react";
2
+ import { useState as B, useRef as R, useEffect as D, useCallback as N } from "react";
3
3
  import { CodeBlock as G } from "../../data-display/CodeBlock.js";
4
4
  import { Icon as C } from "../../ui/Icon.js";
5
5
  import { PromptInput as $ } from "../../../blocks/ai/PromptInput.js";
@@ -91,12 +91,12 @@ const W = () => /* @__PURE__ */ t("div", { className: "flex items-center gap-1 p
91
91
  activeModel: i,
92
92
  connectionStatus: d,
93
93
  renderMessage: u,
94
- placeholder: f = "Ask Ramme AI...",
94
+ placeholder: f = "Ask AI…",
95
95
  className: h,
96
96
  suggestions: s,
97
97
  onSuggestionClick: k
98
98
  }) => {
99
- const _ = d ?? (a ? "error" : l ? "streaming" : "idle"), [b, y] = R(""), v = B(null);
99
+ const _ = d ?? (a ? "error" : l ? "streaming" : "idle"), [b, y] = B(""), v = R(null);
100
100
  D(() => {
101
101
  var r;
102
102
  (r = v.current) == null || r.scrollIntoView({ behavior: "smooth", block: "end" });
@@ -1,41 +1,41 @@
1
1
  import { jsxs as t, jsx as e } from "react/jsx-runtime";
2
2
  import { useState as i, useEffect as g } from "react";
3
3
  import { Card as N, CardHeader as b, CardTitle as w, CardContent as y } from "../../layout/Card.js";
4
- import { Icon as a } from "../../ui/Icon.js";
4
+ import { Icon as s } from "../../ui/Icon.js";
5
5
  const d = { BASE_URL: "/", DEV: !1, MODE: "production", PROD: !0, SSR: !1 }, k = ({ params: u }) => {
6
- const { ticker: n } = u, [c, x] = i([]), [l, m] = i(!0), [o, p] = i(null);
6
+ const { ticker: a } = u, [c, x] = i([]), [l, m] = i(!0), [n, p] = i(null);
7
7
  return g(() => {
8
8
  (async () => {
9
9
  try {
10
10
  m(!0), p(null);
11
- const s = (d == null ? void 0 : d.VITE_API_URL) ?? "http://localhost:8000", f = await fetch(`${s}/companies/${n.toUpperCase()}/news?limit=5`);
11
+ const o = (d == null ? void 0 : d.VITE_API_URL) ?? "http://localhost:8000", f = await fetch(`${o}/companies/${a.toUpperCase()}/news?limit=5`);
12
12
  if (!f.ok)
13
- throw new Error(`No news available for ${n.toUpperCase()}`);
13
+ throw new Error(`No news available for ${a.toUpperCase()}`);
14
14
  const h = await f.json();
15
15
  x(h);
16
- } catch (s) {
17
- p(s instanceof Error ? s.message : "Failed to fetch news");
16
+ } catch (o) {
17
+ p(o instanceof Error ? o.message : "Failed to fetch news");
18
18
  } finally {
19
19
  m(!1);
20
20
  }
21
21
  })();
22
- }, [n]), /* @__PURE__ */ t(N, { className: "w-full min-w-[320px] max-w-2xl shadow-lg border-primary/20", children: [
22
+ }, [a]), /* @__PURE__ */ t(N, { className: "w-full min-w-[320px] max-w-2xl shadow-lg border-primary/20", children: [
23
23
  /* @__PURE__ */ e(b, { className: "pb-3", children: /* @__PURE__ */ t(w, { className: "text-sm font-medium text-muted-foreground flex items-center gap-2", children: [
24
- /* @__PURE__ */ e(a, { name: "newspaper", size: 14 }),
24
+ /* @__PURE__ */ e(s, { name: "newspaper", size: 14 }),
25
25
  "Recent News · ",
26
- n.toUpperCase()
26
+ a.toUpperCase()
27
27
  ] }) }),
28
28
  /* @__PURE__ */ t(y, { className: "pt-0", children: [
29
- l && /* @__PURE__ */ e("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ e(a, { name: "loader", size: 24, className: "animate-spin text-muted-foreground" }) }),
30
- o && /* @__PURE__ */ t("div", { className: "flex items-start gap-2 rounded-lg border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: [
31
- /* @__PURE__ */ e(a, { name: "alert-circle", size: 14, className: "mt-px shrink-0" }),
32
- /* @__PURE__ */ e("span", { children: o })
29
+ l && /* @__PURE__ */ e("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ e(s, { name: "loader", size: 24, className: "animate-spin text-muted-foreground" }) }),
30
+ n && /* @__PURE__ */ t("div", { className: "flex items-start gap-2 rounded-lg border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: [
31
+ /* @__PURE__ */ e(s, { name: "alert-circle", size: 14, className: "mt-px shrink-0" }),
32
+ /* @__PURE__ */ e("span", { children: n })
33
33
  ] }),
34
- c.length === 0 && !l && !o && /* @__PURE__ */ t("div", { className: "flex flex-col items-center justify-center py-8 gap-2 text-muted-foreground", children: [
35
- /* @__PURE__ */ e(a, { name: "inbox", size: 24, opacity: 0.5 }),
34
+ c.length === 0 && !l && !n && /* @__PURE__ */ t("div", { className: "flex flex-col items-center justify-center py-8 gap-2 text-muted-foreground", children: [
35
+ /* @__PURE__ */ e(s, { name: "inbox", size: 24, opacity: 0.5 }),
36
36
  /* @__PURE__ */ e("p", { className: "text-sm", children: "No recent news available" })
37
37
  ] }),
38
- c.length > 0 && !l && !o && /* @__PURE__ */ e("div", { className: "space-y-3", children: c.map((r, s) => /* @__PURE__ */ e(
38
+ c.length > 0 && !l && !n && /* @__PURE__ */ e("div", { className: "space-y-3", children: c.map((r) => /* @__PURE__ */ e(
39
39
  "div",
40
40
  {
41
41
  className: "border-b border-border/50 pb-3 last:border-0 last:pb-0",
@@ -64,7 +64,7 @@ const d = { BASE_URL: "/", DEV: !1, MODE: "production", PROD: !0, SSR: !1 }, k =
64
64
  ] })
65
65
  ] })
66
66
  ] }),
67
- r.url && /* @__PURE__ */ e(a, { name: "external-link", size: 12, className: "text-muted-foreground/50 flex-shrink-0 mt-0.5" })
67
+ r.url && /* @__PURE__ */ e(s, { name: "external-link", size: 12, className: "text-muted-foreground/50 flex-shrink-0 mt-0.5" })
68
68
  ] })
69
69
  },
70
70
  r.id
@@ -1,6 +1,6 @@
1
1
  import { jsxs as a, jsx as e } from "react/jsx-runtime";
2
- import F from "react";
3
- import { ResponsiveContainer as W, ComposedChart as _, CartesianGrid as K, XAxis as U, YAxis as A, Tooltip as $, Legend as j, Line as S, Bar as z } from "recharts";
2
+ import _ from "react";
3
+ import { ResponsiveContainer as F, ComposedChart as W, CartesianGrid as K, XAxis as U, YAxis as A, Tooltip as $, Legend as j, Line as S, Bar as z } from "recharts";
4
4
  import { Card as E, CardHeader as H, CardTitle as L, CardContent as V } from "../../layout/Card.js";
5
5
  import { useChartTheme as Y } from "../../../lib/hooks/useChartTheme.js";
6
6
  function G(s, p, C) {
@@ -59,7 +59,7 @@ const b = {
59
59
  data: C
60
60
  }) => {
61
61
  var y, k;
62
- const { ticker: N, timeRange: M, metrics: c } = s, { textColor: g, gridColor: l } = Y(), h = N || s.symbol || "UNKNOWN", r = M || "1M", o = c && Array.isArray(c) && c.length > 0 ? c : ["price", "volume"], x = F.useMemo(
62
+ const { ticker: N, timeRange: M, metrics: c } = s, { textColor: g, gridColor: l } = Y(), h = N || s.symbol || "UNKNOWN", r = M || "1M", o = c && Array.isArray(c) && c.length > 0 ? c : ["price", "volume"], x = _.useMemo(
63
63
  () => {
64
64
  const t = C || G(r, o);
65
65
  return console.log("[StockChart] Data generated:", {
@@ -98,7 +98,7 @@ const b = {
98
98
  ] })
99
99
  ] }) }),
100
100
  /* @__PURE__ */ a(V, { className: "pt-0", children: [
101
- /* @__PURE__ */ e("div", { className: "h-64 w-full bg-background", style: { minHeight: "256px", minWidth: "350px" }, children: /* @__PURE__ */ e(W, { width: "100%", height: 256, children: /* @__PURE__ */ a(_, { data: x, margin: { top: 5, right: 20, bottom: 5, left: 0 }, children: [
101
+ /* @__PURE__ */ e("div", { className: "h-64 w-full bg-background", style: { minHeight: "256px", minWidth: "350px" }, children: /* @__PURE__ */ e(F, { width: "100%", height: 256, children: /* @__PURE__ */ a(W, { data: x, margin: { top: 5, right: 20, bottom: 5, left: 0 }, children: [
102
102
  /* @__PURE__ */ e(K, { strokeDasharray: "3 3", stroke: l, opacity: 0.3 }),
103
103
  /* @__PURE__ */ e(
104
104
  U,
@@ -10,6 +10,9 @@ import React from 'react';
10
10
  * @param {string} error - Message shown above the form when sign-in fails.
11
11
  * @param {boolean} loading - Disables the form and shows progress while authenticating.
12
12
  * @param {QuickProfile[]} quickProfiles - Optional one-click demo identities, each `{ name, email, role }`.
13
+ * @param {string} signupHref - Where "Create one" points. Pass `null` to hide that line entirely, which is what an invite-only product wants. Defaults to `/auth/signup`.
14
+ * @param {string} signupLabel - Text for that link. Defaults to "Create one".
15
+ * @param {string} forgotHref - Where "Forgot?" points. Pass `null` to hide it — a product with no reset email has nothing to link to. Defaults to `#`.
13
16
  */
14
17
  export interface QuickProfile {
15
18
  name: string;
@@ -21,5 +24,24 @@ export interface LoginPageProps {
21
24
  error?: string | null;
22
25
  loading?: boolean;
23
26
  quickProfiles?: QuickProfile[];
27
+ /**
28
+ * Where "Create one" goes, or `null` to hide the line.
29
+ *
30
+ * Defaults to `/auth/signup` so every product that already renders this keeps
31
+ * exactly what it has. Invite-only products pass `null`: ramme.io deleted its
32
+ * signup route when accounts became invite-only, and this link kept pointing at
33
+ * it — a dead end offered to everyone who could not get in.
34
+ */
35
+ signupHref?: string | null;
36
+ signupLabel?: string;
37
+ /**
38
+ * Where "Forgot?" goes, or `null` to hide it.
39
+ *
40
+ * Defaults to `#`, which is what it has always been — a link that does nothing.
41
+ * Worth being able to remove: on a product with no reset email, offering a
42
+ * recovery link that goes nowhere is worse than saying so in plain words
43
+ * underneath the form.
44
+ */
45
+ forgotHref?: string | null;
24
46
  }
25
47
  export declare const LoginPage: React.FC<LoginPageProps>;
@@ -1,98 +1,106 @@
1
- import { jsxs as t, jsx as e } from "react/jsx-runtime";
2
- import { useState as u } from "react";
3
- import { Link as p } from "react-router-dom";
4
- import { Button as g } from "../ui/Button.js";
5
- import { Input as h } from "../forms/Input.js";
6
- import { Alert as b } from "../feedback/Alert.js";
1
+ import { jsxs as a, jsx as e } from "react/jsx-runtime";
2
+ import { useState as h } from "react";
3
+ import { Link as x } from "react-router-dom";
4
+ import { Button as v } from "../ui/Button.js";
5
+ import { Input as f } from "../forms/Input.js";
6
+ import { Alert as y } from "../feedback/Alert.js";
7
7
  import { Icon as s } from "../ui/Icon.js";
8
- const S = ({ onLogin: f, error: l, loading: i, quickProfiles: r }) => {
9
- const [n, o] = u(""), [c, d] = u(""), x = (a) => {
10
- a.preventDefault(), f(n, c);
11
- }, m = "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 mb-2 block text-foreground/90";
12
- return /* @__PURE__ */ t("div", { className: "w-full max-w-[400px] space-y-6 animate-in fade-in zoom-in-95 duration-300", children: [
13
- /* @__PURE__ */ t("div", { className: "flex flex-col items-center space-y-2 text-center mb-8", children: [
8
+ const A = ({
9
+ onLogin: g,
10
+ error: l,
11
+ loading: i,
12
+ quickProfiles: r,
13
+ signupHref: n = "/auth/signup",
14
+ signupLabel: b = "Create one",
15
+ forgotHref: o = "#"
16
+ }) => {
17
+ const [c, d] = h(""), [m, u] = h(""), N = (t) => {
18
+ t.preventDefault(), g(c, m);
19
+ }, p = "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 mb-2 block text-foreground/90";
20
+ return /* @__PURE__ */ a("div", { className: "w-full max-w-[400px] space-y-6 animate-in fade-in zoom-in-95 duration-300", children: [
21
+ /* @__PURE__ */ a("div", { className: "flex flex-col items-center space-y-2 text-center mb-8", children: [
14
22
  /* @__PURE__ */ e("div", { className: "h-10 w-10 bg-primary/10 rounded-xl flex items-center justify-center mb-2 border border-primary/20", children: /* @__PURE__ */ e(s, { name: "hexagon", className: "text-primary fill-primary/20", size: 24, strokeWidth: 2.5 }) }),
15
23
  /* @__PURE__ */ e("h1", { className: "text-2xl font-bold tracking-tight", children: "Welcome back" }),
16
24
  /* @__PURE__ */ e("p", { className: "text-sm text-muted-foreground", children: "Enter your credentials to access your workspace" })
17
25
  ] }),
18
- /* @__PURE__ */ t("div", { className: "bg-card text-card-foreground border shadow-sm rounded-xl overflow-hidden", children: [
19
- /* @__PURE__ */ e("div", { className: "p-6 pt-6", children: /* @__PURE__ */ t("form", { onSubmit: x, className: "space-y-4", children: [
20
- l && /* @__PURE__ */ e(b, { variant: "danger", title: "Authentication Error", className: "mb-4", children: l }),
21
- /* @__PURE__ */ t("div", { className: "space-y-1", children: [
22
- /* @__PURE__ */ e("label", { htmlFor: "email", className: m, children: "Email" }),
23
- /* @__PURE__ */ t("div", { className: "relative group", children: [
26
+ /* @__PURE__ */ a("div", { className: "bg-card text-card-foreground border shadow-sm rounded-xl overflow-hidden", children: [
27
+ /* @__PURE__ */ e("div", { className: "p-6 pt-6", children: /* @__PURE__ */ a("form", { onSubmit: N, className: "space-y-4", children: [
28
+ l && /* @__PURE__ */ e(y, { variant: "danger", title: "Authentication Error", className: "mb-4", children: l }),
29
+ /* @__PURE__ */ a("div", { className: "space-y-1", children: [
30
+ /* @__PURE__ */ e("label", { htmlFor: "email", className: p, children: "Email" }),
31
+ /* @__PURE__ */ a("div", { className: "relative group", children: [
24
32
  /* @__PURE__ */ e(s, { name: "mail", className: "absolute left-3 top-2.5 h-4 w-4 text-muted-foreground group-focus-within:text-primary transition-colors" }),
25
33
  /* @__PURE__ */ e(
26
- h,
34
+ f,
27
35
  {
28
36
  id: "email",
29
37
  type: "email",
30
38
  placeholder: "name@example.com",
31
39
  className: "pl-9 h-10 bg-background/50",
32
- value: n,
33
- onChange: (a) => o(a.target.value),
40
+ value: c,
41
+ onChange: (t) => d(t.target.value),
34
42
  required: !0
35
43
  }
36
44
  )
37
45
  ] })
38
46
  ] }),
39
- /* @__PURE__ */ t("div", { className: "space-y-1", children: [
40
- /* @__PURE__ */ t("div", { className: "flex items-center justify-between", children: [
41
- /* @__PURE__ */ e("label", { htmlFor: "password", className: m, children: "Password" }),
42
- /* @__PURE__ */ e(p, { to: "#", className: "text-xs text-primary hover:underline font-medium", children: "Forgot?" })
47
+ /* @__PURE__ */ a("div", { className: "space-y-1", children: [
48
+ /* @__PURE__ */ a("div", { className: "flex items-center justify-between", children: [
49
+ /* @__PURE__ */ e("label", { htmlFor: "password", className: p, children: "Password" }),
50
+ o !== null && /* @__PURE__ */ e(x, { to: o, className: "text-xs text-primary hover:underline font-medium", children: "Forgot?" })
43
51
  ] }),
44
- /* @__PURE__ */ t("div", { className: "relative group", children: [
52
+ /* @__PURE__ */ a("div", { className: "relative group", children: [
45
53
  /* @__PURE__ */ e(s, { name: "lock", className: "absolute left-3 top-2.5 h-4 w-4 text-muted-foreground group-focus-within:text-primary transition-colors" }),
46
54
  /* @__PURE__ */ e(
47
- h,
55
+ f,
48
56
  {
49
57
  id: "password",
50
58
  type: "password",
51
59
  className: "pl-9 h-10 bg-background/50",
52
- value: c,
53
- onChange: (a) => d(a.target.value),
60
+ value: m,
61
+ onChange: (t) => u(t.target.value),
54
62
  required: !0
55
63
  }
56
64
  )
57
65
  ] })
58
66
  ] }),
59
- /* @__PURE__ */ e(g, { type: "submit", className: "w-full mt-2", size: "lg", disabled: i, children: i ? "Authenticating..." : "Sign In" })
67
+ /* @__PURE__ */ e(v, { type: "submit", className: "w-full mt-2", size: "lg", disabled: i, children: i ? "Authenticating..." : "Sign In" })
60
68
  ] }) }),
61
- r && r.length > 0 && /* @__PURE__ */ t("div", { className: "px-6 pb-6 space-y-3", children: [
62
- /* @__PURE__ */ t("div", { className: "relative mb-4", children: [
69
+ r && r.length > 0 && /* @__PURE__ */ a("div", { className: "px-6 pb-6 space-y-3", children: [
70
+ /* @__PURE__ */ a("div", { className: "relative mb-4", children: [
63
71
  /* @__PURE__ */ e("div", { className: "absolute inset-0 flex items-center", children: /* @__PURE__ */ e("span", { className: "w-full border-t border-border/50" }) }),
64
72
  /* @__PURE__ */ e("div", { className: "relative flex justify-center text-xs uppercase", children: /* @__PURE__ */ e("span", { className: "bg-card px-2 text-muted-foreground", children: "Quick Select Profiles" }) })
65
73
  ] }),
66
- /* @__PURE__ */ e("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3", children: r.map((a) => /* @__PURE__ */ t(
74
+ /* @__PURE__ */ e("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3", children: r.map((t) => /* @__PURE__ */ a(
67
75
  "button",
68
76
  {
69
77
  type: "button",
70
78
  onClick: () => {
71
- o(a.email), d("demo");
79
+ d(t.email), u("demo");
72
80
  },
73
81
  className: "flex flex-col items-start p-3 text-left border rounded-lg hover:border-primary hover:bg-primary/5 transition-all w-full focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-1 focus:ring-offset-card",
74
82
  children: [
75
- /* @__PURE__ */ e("span", { className: "font-medium text-sm text-foreground", children: a.name }),
76
- /* @__PURE__ */ e("span", { className: "text-xs text-muted-foreground", children: a.role })
83
+ /* @__PURE__ */ e("span", { className: "font-medium text-sm text-foreground", children: t.name }),
84
+ /* @__PURE__ */ e("span", { className: "text-xs text-muted-foreground", children: t.role })
77
85
  ]
78
86
  },
79
- a.email
87
+ t.email
80
88
  )) })
81
89
  ] }),
82
- /* @__PURE__ */ t("div", { className: "p-6 pt-0 text-center", children: [
83
- /* @__PURE__ */ t("div", { className: "relative mb-4", children: [
90
+ n !== null && /* @__PURE__ */ a("div", { className: "p-6 pt-0 text-center", children: [
91
+ /* @__PURE__ */ a("div", { className: "relative mb-4", children: [
84
92
  /* @__PURE__ */ e("div", { className: "absolute inset-0 flex items-center", children: /* @__PURE__ */ e("span", { className: "w-full border-t" }) }),
85
93
  /* @__PURE__ */ e("div", { className: "relative flex justify-center text-xs uppercase", children: /* @__PURE__ */ e("span", { className: "bg-card px-2 text-muted-foreground", children: "Or continue with" }) })
86
94
  ] }),
87
- /* @__PURE__ */ t("p", { className: "text-sm text-muted-foreground", children: [
95
+ /* @__PURE__ */ a("p", { className: "text-sm text-muted-foreground", children: [
88
96
  "Don't have an account?",
89
97
  " ",
90
- /* @__PURE__ */ e(p, { to: "/auth/signup", className: "font-semibold text-primary hover:underline transition-all", children: "Create one" })
98
+ /* @__PURE__ */ e(x, { to: n, className: "font-semibold text-primary hover:underline transition-all", children: b })
91
99
  ] })
92
100
  ] })
93
101
  ] })
94
102
  ] });
95
103
  };
96
104
  export {
97
- S as LoginPage
105
+ A as LoginPage
98
106
  };
@@ -2,7 +2,7 @@ import { jsxs as D, jsx as i } from "react/jsx-runtime";
2
2
  import { useState as l, useRef as g, useEffect as f, useCallback as K } from "react";
3
3
  import { Input as q } from "./Input.js";
4
4
  import { cn as p } from "../../utils/cn.js";
5
- const $ = ({
5
+ const _ = ({
6
6
  options: t,
7
7
  label: v,
8
8
  value: a,
@@ -73,5 +73,5 @@ const $ = ({
73
73
  ] });
74
74
  };
75
75
  export {
76
- $ as ComboBox
76
+ _ as ComboBox
77
77
  };
@@ -1,9 +1,10 @@
1
- import { jsxs as c, jsx as r } from "react/jsx-runtime";
2
- import n from "react-datepicker";
1
+ import { jsxs as d, jsx as r } from "react/jsx-runtime";
2
+ import s from "react";
3
+ import b from "react-datepicker";
3
4
  import { cn as e } from "../../utils/cn.js";
4
- import { Icon as s } from "../ui/Icon.js";
5
+ import { Icon as u } from "../ui/Icon.js";
5
6
  import "react-datepicker/dist/react-datepicker.css";
6
- const m = `
7
+ const f = `
7
8
  .react-datepicker {
8
9
  font-family: inherit !important;
9
10
  background-color: rgb(var(--app-card-bg-color)) !important;
@@ -28,36 +29,40 @@ const m = `
28
29
  .react-datepicker__navigation-icon::before {
29
30
  border-color: rgb(var(--app-text-color)) !important;
30
31
  }
31
- `, x = ({
32
+ `, y = ({
32
33
  label: o,
33
- selected: i,
34
- onChange: d,
35
- className: l,
34
+ selected: l,
35
+ onChange: n,
36
+ className: p,
36
37
  error: t,
37
38
  helperText: a,
38
- ...p
39
- }) => /* @__PURE__ */ c("div", { className: e("w-full flex flex-col", l), children: [
40
- /* @__PURE__ */ r("style", { children: m }),
41
- o && /* @__PURE__ */ r("label", { className: "block text-sm font-medium text-foreground mb-1.5", children: o }),
42
- /* @__PURE__ */ c("div", { className: "relative", children: [
43
- /* @__PURE__ */ r(
44
- n,
45
- {
46
- selected: i,
47
- onChange: d,
48
- className: e(
49
- "flex h-10 w-full rounded-md border bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
50
- t ? "border-destructive" : "border-input"
51
- ),
52
- wrapperClassName: "w-full",
53
- showPopperArrow: !1,
54
- ...p
55
- }
56
- ),
57
- /* @__PURE__ */ r("div", { className: "absolute right-3 top-2.5 pointer-events-none text-muted-foreground", children: /* @__PURE__ */ r(s, { name: "calendar", className: "h-4 w-4" }) })
58
- ] }),
59
- a && /* @__PURE__ */ r("p", { className: e("mt-1.5 text-xs", t ? "text-destructive" : "text-muted-foreground"), children: a })
60
- ] });
39
+ ...c
40
+ }) => {
41
+ const m = s.useId(), i = c.id || m;
42
+ return /* @__PURE__ */ d("div", { className: e("w-full flex flex-col", p), children: [
43
+ /* @__PURE__ */ r("style", { children: f }),
44
+ o && /* @__PURE__ */ r("label", { htmlFor: i, className: "block text-sm font-medium text-foreground mb-1.5", children: o }),
45
+ /* @__PURE__ */ d("div", { className: "relative", children: [
46
+ /* @__PURE__ */ r(
47
+ b,
48
+ {
49
+ id: i,
50
+ selected: l,
51
+ onChange: n,
52
+ className: e(
53
+ "flex h-10 w-full rounded-md border bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
54
+ t ? "border-destructive" : "border-input"
55
+ ),
56
+ wrapperClassName: "w-full",
57
+ showPopperArrow: !1,
58
+ ...c
59
+ }
60
+ ),
61
+ /* @__PURE__ */ r("div", { className: "absolute right-3 top-2.5 pointer-events-none text-muted-foreground", children: /* @__PURE__ */ r(u, { name: "calendar", className: "h-4 w-4" }) })
62
+ ] }),
63
+ a && /* @__PURE__ */ r("p", { className: e("mt-1.5 text-xs", t ? "text-destructive" : "text-muted-foreground"), children: a })
64
+ ] });
65
+ };
61
66
  export {
62
- x as DatePicker
67
+ y as DatePicker
63
68
  };