@pattern-stack/frontend-patterns 0.2.0-alpha.15 → 0.2.0-alpha.18

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 (28) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/atoms/components/data/Duration/Duration.d.ts +11 -0
  3. package/dist/atoms/components/data/Duration/Duration.d.ts.map +1 -0
  4. package/dist/atoms/components/data/Duration/index.d.ts +2 -0
  5. package/dist/atoms/components/data/Duration/index.d.ts.map +1 -0
  6. package/dist/atoms/components/data/LiveIndicator/LiveIndicator.d.ts +12 -0
  7. package/dist/atoms/components/data/LiveIndicator/LiveIndicator.d.ts.map +1 -0
  8. package/dist/atoms/components/data/LiveIndicator/index.d.ts +2 -0
  9. package/dist/atoms/components/data/LiveIndicator/index.d.ts.map +1 -0
  10. package/dist/atoms/components/data/Sparkline/Sparkline.d.ts +16 -0
  11. package/dist/atoms/components/data/Sparkline/Sparkline.d.ts.map +1 -0
  12. package/dist/atoms/components/data/Sparkline/index.d.ts +2 -0
  13. package/dist/atoms/components/data/Sparkline/index.d.ts.map +1 -0
  14. package/dist/atoms/components/data/Timestamp/Timestamp.d.ts +13 -0
  15. package/dist/atoms/components/data/Timestamp/Timestamp.d.ts.map +1 -0
  16. package/dist/atoms/components/data/Timestamp/index.d.ts +2 -0
  17. package/dist/atoms/components/data/Timestamp/index.d.ts.map +1 -0
  18. package/dist/atoms/components/data/index.d.ts +4 -0
  19. package/dist/atoms/components/data/index.d.ts.map +1 -1
  20. package/dist/atoms/types/navigation.d.ts +9 -2
  21. package/dist/atoms/types/navigation.d.ts.map +1 -1
  22. package/dist/index.es.js +239 -22
  23. package/dist/index.es.js.map +1 -1
  24. package/dist/index.js +239 -22
  25. package/dist/index.js.map +1 -1
  26. package/dist/molecules/layout/Sidebar.d.ts.map +1 -1
  27. package/dist/templates/factory.d.ts.map +1 -1
  28. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7793,6 +7793,201 @@ const TruncatedText = ({
7793
7793
  }
7794
7794
  );
7795
7795
  };
7796
+ function formatAuto(ms) {
7797
+ if (ms < 1e3) {
7798
+ return { visible: `${ms}ms`, spoken: `${ms} milliseconds` };
7799
+ }
7800
+ if (ms < 6e4) {
7801
+ const secs = ms / 1e3;
7802
+ return {
7803
+ visible: `${secs.toFixed(1)}s`,
7804
+ spoken: `${secs.toFixed(1)} seconds`
7805
+ };
7806
+ }
7807
+ if (ms < 36e5) {
7808
+ const m = Math.floor(ms / 6e4);
7809
+ const s = Math.round(ms % 6e4 / 1e3);
7810
+ return { visible: `${m}m ${s}s`, spoken: `${m} minutes ${s} seconds` };
7811
+ }
7812
+ if (ms < 864e5) {
7813
+ const h2 = Math.floor(ms / 36e5);
7814
+ const m = Math.round(ms % 36e5 / 6e4);
7815
+ return { visible: `${h2}h ${m}m`, spoken: `${h2} hours ${m} minutes` };
7816
+ }
7817
+ const d = Math.floor(ms / 864e5);
7818
+ const h = Math.round(ms % 864e5 / 36e5);
7819
+ return { visible: `${d}d ${h}h`, spoken: `${d} days ${h} hours` };
7820
+ }
7821
+ function formatS(ms) {
7822
+ const secs = ms / 1e3;
7823
+ return {
7824
+ visible: `${secs.toFixed(1)}s`,
7825
+ spoken: `${secs.toFixed(1)} seconds`
7826
+ };
7827
+ }
7828
+ function formatMs(ms) {
7829
+ return { visible: `${ms}ms`, spoken: `${ms} milliseconds` };
7830
+ }
7831
+ function Duration({ ms, precision = "auto", className }) {
7832
+ const { visible, spoken } = precision === "s" ? formatS(ms) : precision === "ms" ? formatMs(ms) : formatAuto(ms);
7833
+ return /* @__PURE__ */ jsxRuntime.jsx(
7834
+ "span",
7835
+ {
7836
+ "aria-label": spoken,
7837
+ className: cn("font-mono text-xs text-muted-foreground", className),
7838
+ children: visible
7839
+ }
7840
+ );
7841
+ }
7842
+ function toDate(v) {
7843
+ return v instanceof Date ? v : new Date(v);
7844
+ }
7845
+ function formatRelative(date, now) {
7846
+ const diffMs = now.getTime() - date.getTime();
7847
+ const abs = Math.abs(diffMs);
7848
+ const suffix = diffMs >= 0 ? "ago" : "from now";
7849
+ if (abs < 6e4) return "just now";
7850
+ if (abs < 36e5) {
7851
+ const m = Math.floor(abs / 6e4);
7852
+ return `${m}m ${suffix}`;
7853
+ }
7854
+ if (abs < 864e5) {
7855
+ const h = Math.floor(abs / 36e5);
7856
+ return `${h}h ${suffix}`;
7857
+ }
7858
+ if (abs < 6048e5) {
7859
+ const d = Math.floor(abs / 864e5);
7860
+ return d === 1 ? "yesterday" : `${d}d ${suffix}`;
7861
+ }
7862
+ return date.toLocaleDateString(void 0);
7863
+ }
7864
+ function formatAbsolute(date, tz) {
7865
+ return date.toLocaleString(void 0, {
7866
+ dateStyle: "short",
7867
+ timeStyle: "short",
7868
+ timeZone: tz
7869
+ });
7870
+ }
7871
+ function Timestamp({
7872
+ value,
7873
+ format = "relative",
7874
+ tz,
7875
+ className
7876
+ }) {
7877
+ const date = toDate(value);
7878
+ const iso = date.toISOString();
7879
+ const [now, setNow] = React.useState(() => /* @__PURE__ */ new Date());
7880
+ React.useEffect(() => {
7881
+ if (format === "absolute") return;
7882
+ const id = setInterval(() => setNow(/* @__PURE__ */ new Date()), 3e4);
7883
+ return () => clearInterval(id);
7884
+ }, [format]);
7885
+ const absolute = formatAbsolute(date, tz);
7886
+ const relative = formatRelative(date, now);
7887
+ const display = format === "relative" ? relative : absolute;
7888
+ const title = format === "both" ? relative : void 0;
7889
+ return /* @__PURE__ */ jsxRuntime.jsx(
7890
+ "time",
7891
+ {
7892
+ dateTime: iso,
7893
+ title,
7894
+ className: cn("font-mono text-xs text-muted-foreground", className),
7895
+ children: display
7896
+ }
7897
+ );
7898
+ }
7899
+ function Sparkline({
7900
+ data,
7901
+ width = 140,
7902
+ height = 28,
7903
+ color = "hsl(var(--muted-foreground))",
7904
+ fill,
7905
+ strokeWidth = 1.2,
7906
+ markLast = false
7907
+ }) {
7908
+ if (data.length < 2) {
7909
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { width, height, "aria-hidden": true });
7910
+ }
7911
+ const min = Math.min(...data);
7912
+ const max = Math.max(...data);
7913
+ const range = max - min || 1;
7914
+ const pad = strokeWidth;
7915
+ const innerW = width - pad * 2;
7916
+ const innerH = height - pad * 2;
7917
+ const points = data.map((v, i) => {
7918
+ const x = pad + i / (data.length - 1) * innerW;
7919
+ const y = pad + innerH - (v - min) / range * innerH;
7920
+ return [x, y];
7921
+ });
7922
+ const polyline = points.map(([x, y]) => `${x.toFixed(2)},${y.toFixed(2)}`).join(" ");
7923
+ const firstPt = points[0];
7924
+ const lastPt = points[points.length - 1];
7925
+ let fillPath;
7926
+ if (fill) {
7927
+ fillPath = [
7928
+ `${firstPt[0].toFixed(2)},${(pad + innerH).toFixed(2)}`,
7929
+ ...points.map(([x, y]) => `${x.toFixed(2)},${y.toFixed(2)}`),
7930
+ `${lastPt[0].toFixed(2)},${(pad + innerH).toFixed(2)}`
7931
+ ].join(" ");
7932
+ }
7933
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7934
+ "svg",
7935
+ {
7936
+ width,
7937
+ height,
7938
+ viewBox: `0 0 ${width} ${height}`,
7939
+ "aria-hidden": true,
7940
+ style: { display: "block", overflow: "visible" },
7941
+ children: [
7942
+ fillPath && /* @__PURE__ */ jsxRuntime.jsx("polygon", { points: fillPath, fill, stroke: "none" }),
7943
+ /* @__PURE__ */ jsxRuntime.jsx(
7944
+ "polyline",
7945
+ {
7946
+ points: polyline,
7947
+ fill: "none",
7948
+ stroke: color,
7949
+ strokeWidth,
7950
+ strokeLinejoin: "round",
7951
+ strokeLinecap: "round"
7952
+ }
7953
+ ),
7954
+ markLast && /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: lastPt[0], cy: lastPt[1], r: strokeWidth * 2, fill: color })
7955
+ ]
7956
+ }
7957
+ );
7958
+ }
7959
+ function LiveIndicator({
7960
+ active,
7961
+ label = "Live",
7962
+ className
7963
+ }) {
7964
+ const ariaLabel = active ? `${label} — connected` : `${label} — paused`;
7965
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7966
+ "span",
7967
+ {
7968
+ role: "status",
7969
+ "aria-live": "polite",
7970
+ "aria-label": ariaLabel,
7971
+ className: cn(
7972
+ "inline-flex items-center gap-2 text-xs font-mono",
7973
+ active ? "text-primary" : "text-muted-foreground",
7974
+ className
7975
+ ),
7976
+ children: [
7977
+ /* @__PURE__ */ jsxRuntime.jsx(
7978
+ "span",
7979
+ {
7980
+ className: cn(
7981
+ "inline-block w-2 h-2 rounded-full",
7982
+ active ? "bg-primary animate-pulse" : "bg-muted-foreground/40"
7983
+ )
7984
+ }
7985
+ ),
7986
+ label
7987
+ ]
7988
+ }
7989
+ );
7990
+ }
7796
7991
  const defaultActivityIconMap = {
7797
7992
  user: {
7798
7993
  icon: lucideReact.Users,
@@ -10644,7 +10839,7 @@ const SidebarButton = ({
10644
10839
  "span",
10645
10840
  {
10646
10841
  className: cn(
10647
- "text-sm font-medium flex-1 text-left",
10842
+ "text-sm font-medium flex-1 text-left whitespace-nowrap",
10648
10843
  active ? `text-category-${category}` : "text-foreground"
10649
10844
  ),
10650
10845
  children: label
@@ -10727,23 +10922,43 @@ const Sidebar = ({
10727
10922
  "data-component-name": "Sidebar",
10728
10923
  "data-collapsed": !isExpanded,
10729
10924
  children: [
10730
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center p-3 pt-4", children: /* @__PURE__ */ jsxRuntime.jsx(
10731
- "button",
10925
+ /* @__PURE__ */ jsxRuntime.jsxs(
10926
+ "div",
10732
10927
  {
10733
- onClick: toggleSidebar,
10734
10928
  className: cn(
10735
- "w-7 h-7 rounded-md",
10736
- "bg-muted/50 text-muted-foreground",
10737
- "flex items-center justify-center",
10738
- "hover:bg-muted hover:text-foreground",
10739
- "active:scale-95",
10740
- "transition-all duration-150 ease-out"
10929
+ "flex items-center p-3 pt-4",
10930
+ isExpanded ? "justify-between gap-2" : "justify-center"
10741
10931
  ),
10742
- "data-component-name": "SidebarToggle",
10743
- title: !isExpanded ? "Expand sidebar" : "Collapse sidebar",
10744
- children: !isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Menu, { className: "w-3.5 h-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3.5 h-3.5" })
10932
+ "data-component-name": "SidebarHeader",
10933
+ children: [
10934
+ isExpanded && (navigation == null ? void 0 : navigation.logo) != null && /* @__PURE__ */ jsxRuntime.jsx(
10935
+ "div",
10936
+ {
10937
+ className: "flex-1 min-w-0 flex items-center",
10938
+ "data-component-name": "SidebarLogo",
10939
+ children: typeof navigation.logo === "string" ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold text-foreground truncate", children: navigation.logo }) : navigation.logo
10940
+ }
10941
+ ),
10942
+ /* @__PURE__ */ jsxRuntime.jsx(
10943
+ "button",
10944
+ {
10945
+ onClick: toggleSidebar,
10946
+ className: cn(
10947
+ "w-7 h-7 rounded-md shrink-0",
10948
+ "bg-muted/50 text-muted-foreground",
10949
+ "flex items-center justify-center",
10950
+ "hover:bg-muted hover:text-foreground",
10951
+ "active:scale-95",
10952
+ "transition-all duration-150 ease-out"
10953
+ ),
10954
+ "data-component-name": "SidebarToggle",
10955
+ title: !isExpanded ? "Expand sidebar" : "Collapse sidebar",
10956
+ children: !isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Menu, { className: "w-3.5 h-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3.5 h-3.5" })
10957
+ }
10958
+ )
10959
+ ]
10745
10960
  }
10746
- ) }),
10961
+ ),
10747
10962
  /* @__PURE__ */ jsxRuntime.jsx("nav", { className: "flex-1 p-3 space-y-2", "data-component-name": "SidebarNav", children: items.map((item) => {
10748
10963
  const [itemBasePath, itemQuery] = item.path.split("?");
10749
10964
  const currentPath = location.pathname;
@@ -15720,14 +15935,12 @@ function createReactApp(config) {
15720
15935
  if (enableRouting) {
15721
15936
  tree = /* @__PURE__ */ jsxRuntime.jsx(NavigationProvider, { initialNavigation: navigation, children: /* @__PURE__ */ jsxRuntime.jsx(SidebarProvider, { children: tree }) });
15722
15937
  }
15723
- if (enableAuth) {
15724
- const authMode = (auth == null ? void 0 : auth.mode) || "pattern-stack";
15725
- if (authMode === "none") {
15726
- setGlobalAuthService(null);
15727
- tree = /* @__PURE__ */ jsxRuntime.jsx(NoAuthProvider, { children: tree });
15728
- } else {
15729
- tree = /* @__PURE__ */ jsxRuntime.jsx(AuthProvider, { config: auth, children: tree });
15730
- }
15938
+ const authMode = (auth == null ? void 0 : auth.mode) || "pattern-stack";
15939
+ if (enableAuth && authMode !== "none") {
15940
+ tree = /* @__PURE__ */ jsxRuntime.jsx(AuthProvider, { config: auth, children: tree });
15941
+ } else {
15942
+ setGlobalAuthService(null);
15943
+ tree = /* @__PURE__ */ jsxRuntime.jsx(NoAuthProvider, { children: tree });
15731
15944
  }
15732
15945
  if (enableQuery) {
15733
15946
  tree = /* @__PURE__ */ jsxRuntime.jsxs(reactQuery.QueryClientProvider, { client: queryClient, children: [
@@ -19193,6 +19406,7 @@ exports.DropdownMenuSub = DropdownMenuSub;
19193
19406
  exports.DropdownMenuSubContent = DropdownMenuSubContent;
19194
19407
  exports.DropdownMenuSubTrigger = DropdownMenuSubTrigger;
19195
19408
  exports.DropdownMenuTrigger = DropdownMenuTrigger;
19409
+ exports.Duration = Duration;
19196
19410
  exports.EmptyState = EmptyState;
19197
19411
  exports.EnhancedDataTemplate = EnhancedDataTemplate;
19198
19412
  exports.EntityIcon = EntityIcon;
@@ -19212,6 +19426,7 @@ exports.Label = Label;
19212
19426
  exports.ListCard = ListCard;
19213
19427
  exports.ListPageTemplate = ListPageTemplate;
19214
19428
  exports.ListToolbar = ListToolbar;
19429
+ exports.LiveIndicator = LiveIndicator;
19215
19430
  exports.Loading = Loading;
19216
19431
  exports.LoginForm = LoginForm;
19217
19432
  exports.LogoutButton = LogoutButton;
@@ -19256,6 +19471,7 @@ exports.SkeletonAvatar = SkeletonAvatar;
19256
19471
  exports.SkeletonButton = SkeletonButton;
19257
19472
  exports.SkeletonCard = SkeletonCard;
19258
19473
  exports.SkeletonText = SkeletonText;
19474
+ exports.Sparkline = Sparkline;
19259
19475
  exports.Spinner = Spinner;
19260
19476
  exports.StatCard = StatCard;
19261
19477
  exports.StyleGuide = StyleGuide;
@@ -19273,6 +19489,7 @@ exports.Tabs = Tabs;
19273
19489
  exports.TabsContent = TabsContent;
19274
19490
  exports.TabsList = TabsList;
19275
19491
  exports.TabsTrigger = TabsTrigger;
19492
+ exports.Timestamp = Timestamp;
19276
19493
  exports.Toast = Toast;
19277
19494
  exports.ToastContainer = ToastContainer;
19278
19495
  exports.Tooltip = Tooltip;