@locusgraph/blocks 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,7 +19,8 @@ pnpm add @locusgraph/blocks @locusgraph/components
19
19
  | `WalletPanel` | `balanceMicroUsd`, `debtMicroUsd`, `grants`. A Rule Grid cell |
20
20
  | `CreditPacks` | `packs`, `onBuy(packId)`, `pending`. A Rule Grid cell |
21
21
  | `PlanOptions` | `plans`, `actionFor(plan)` for plans that are not current |
22
- | `KeysTable` | `keys`, `actions(key)` |
22
+ | `KeysTable` | `keys`, `actions(key)`, `highlightedId` to flash a just-created key. Dates render in the viewer's time zone after hydration |
23
+ | `LocalDate` | `value` (ISO string): UTC on the server, the viewer's time zone after hydration |
23
24
  | `NoKeys` | `newKeyHref` (omit for read-only roles), `linkComponent` |
24
25
 
25
26
  `WalletPanel` and `CreditPacks` are cells, so put them in a `RuleGrid`:
@@ -1,4 +1,4 @@
1
- import type { CreditPack } from "../types";
1
+ import type { CreditPack } from "../types.js";
2
2
  type CreditPacksProps = {
3
3
  packs: CreditPack[];
4
4
  onBuy: (packId: string) => void;
@@ -1,5 +1,5 @@
1
1
  import type * as React from "react";
2
- import type { PlanOffer } from "../types";
2
+ import type { PlanOffer } from "../types.js";
3
3
  type PlanOptionsProps = {
4
4
  plans: PlanOffer[];
5
5
  actionFor?: (plan: PlanOffer) => React.ReactNode;
@@ -1,4 +1,4 @@
1
- import type { WalletGrant } from "../types";
1
+ import type { WalletGrant } from "../types.js";
2
2
  type WalletPanelProps = {
3
3
  balanceMicroUsd: number;
4
4
  debtMicroUsd?: number;
@@ -0,0 +1,3 @@
1
+ export declare function LocalDate({ value }: {
2
+ value: string;
3
+ }): import("react").JSX.Element;
@@ -0,0 +1,10 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { useEffect, useState } from "react";
4
+ const utcFormat = new Intl.DateTimeFormat("en-US", { dateStyle: "medium", timeZone: "UTC" });
5
+ const localFormat = new Intl.DateTimeFormat("en-US", { dateStyle: "medium" });
6
+ export function LocalDate({ value }) {
7
+ const [hydrated, setHydrated] = useState(false);
8
+ useEffect(() => setHydrated(true), []);
9
+ return (_jsx("time", { dateTime: value, children: (hydrated ? localFormat : utcFormat).format(new Date(value)) }));
10
+ }
package/dist/index.d.ts CHANGED
@@ -1,9 +1,10 @@
1
- export { CreditPacks } from "./billing/credit-packs";
2
- export { PlanOptions } from "./billing/plan-options";
3
- export { WalletPanel } from "./billing/wallet-panel";
4
- export { KeysTable } from "./keys/keys-table";
5
- export { NoKeys } from "./keys/no-keys";
6
- export * from "./types";
7
- export { QuotaMeter } from "./usage/quota-meter";
8
- export { UsageAttention } from "./usage/usage-attention";
9
- export { UsageSummary } from "./usage/usage-summary";
1
+ export { CreditPacks } from "./billing/credit-packs.js";
2
+ export { PlanOptions } from "./billing/plan-options.js";
3
+ export { WalletPanel } from "./billing/wallet-panel.js";
4
+ export { LocalDate } from "./dates/local-date.js";
5
+ export { KeysTable } from "./keys/keys-table.js";
6
+ export { NoKeys } from "./keys/no-keys.js";
7
+ export * from "./types.js";
8
+ export { QuotaMeter } from "./usage/quota-meter.js";
9
+ export { UsageAttention } from "./usage/usage-attention.js";
10
+ export { UsageSummary } from "./usage/usage-summary.js";
package/dist/index.js CHANGED
@@ -1,9 +1,10 @@
1
- export { CreditPacks } from "./billing/credit-packs";
2
- export { PlanOptions } from "./billing/plan-options";
3
- export { WalletPanel } from "./billing/wallet-panel";
4
- export { KeysTable } from "./keys/keys-table";
5
- export { NoKeys } from "./keys/no-keys";
6
- export * from "./types";
7
- export { QuotaMeter } from "./usage/quota-meter";
8
- export { UsageAttention } from "./usage/usage-attention";
9
- export { UsageSummary } from "./usage/usage-summary";
1
+ export { CreditPacks } from "./billing/credit-packs.js";
2
+ export { PlanOptions } from "./billing/plan-options.js";
3
+ export { WalletPanel } from "./billing/wallet-panel.js";
4
+ export { LocalDate } from "./dates/local-date.js";
5
+ export { KeysTable } from "./keys/keys-table.js";
6
+ export { NoKeys } from "./keys/no-keys.js";
7
+ export * from "./types.js";
8
+ export { QuotaMeter } from "./usage/quota-meter.js";
9
+ export { UsageAttention } from "./usage/usage-attention.js";
10
+ export { UsageSummary } from "./usage/usage-summary.js";
@@ -1,8 +1,9 @@
1
1
  import type * as React from "react";
2
- import type { ApiKeyRow } from "../types";
2
+ import type { ApiKeyRow } from "../types.js";
3
3
  type KeysTableProps = {
4
4
  keys: ApiKeyRow[];
5
5
  actions?: (key: ApiKeyRow) => React.ReactNode;
6
+ highlightedId?: string;
6
7
  };
7
- export declare function KeysTable({ keys, actions }: KeysTableProps): React.JSX.Element;
8
+ export declare function KeysTable({ keys, actions, highlightedId }: KeysTableProps): React.JSX.Element;
8
9
  export {};
@@ -1,6 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@locusgraph/components";
3
- import { formatDate } from "@locusgraph/utils";
4
- export function KeysTable({ keys, actions }) {
5
- return (_jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Name" }), _jsx(TableHead, { className: "hidden md:table-cell", children: "Key" }), _jsx(TableHead, { children: "Product" }), _jsx(TableHead, { className: "hidden md:table-cell", children: "Created by" }), _jsx(TableHead, { className: "hidden sm:table-cell", children: "Created" }), _jsx(TableHead, { children: "Expires" }), actions && _jsx(TableHead, { className: "w-0" })] }) }), _jsx(TableBody, { children: keys.map((key) => (_jsxs(TableRow, { children: [_jsx(TableCell, { className: "font-medium", children: key.name ?? "Untitled" }), _jsx(TableCell, { className: "hidden font-mono text-muted-foreground md:table-cell", children: key.maskedKey }), _jsx(TableCell, { children: key.productLabel }), _jsx(TableCell, { className: "hidden md:table-cell", children: key.createdBy }), _jsx(TableCell, { className: "hidden sm:table-cell", children: formatDate(key.createdAt) }), _jsx(TableCell, { children: formatDate(key.expiresAt, "Never") }), actions && _jsx(TableCell, { className: "text-right", children: actions(key) })] }, key.id))) })] }));
3
+ import { LocalDate } from "../dates/local-date.js";
4
+ function dateOr(value, empty) {
5
+ return value ? _jsx(LocalDate, { value: value }) : empty;
6
+ }
7
+ export function KeysTable({ keys, actions, highlightedId }) {
8
+ return (_jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Name" }), _jsx(TableHead, { className: "hidden md:table-cell", children: "Key" }), _jsx(TableHead, { children: "Product" }), _jsx(TableHead, { className: "hidden md:table-cell", children: "Created by" }), _jsx(TableHead, { className: "hidden sm:table-cell", children: "Created" }), _jsx(TableHead, { children: "Expires" }), actions && _jsx(TableHead, { className: "w-0" })] }) }), _jsx(TableBody, { children: keys.map((key) => (_jsxs(TableRow, { "data-new": key.id === highlightedId ? "" : undefined, className: "transition-colors duration-1000 data-new:bg-accent", children: [_jsx(TableCell, { className: "font-medium", children: key.name ?? "Untitled" }), _jsx(TableCell, { className: "hidden font-mono text-muted-foreground md:table-cell", children: key.maskedKey }), _jsx(TableCell, { children: key.productLabel }), _jsx(TableCell, { className: "hidden md:table-cell", children: key.createdBy }), _jsx(TableCell, { className: "hidden sm:table-cell", children: dateOr(key.createdAt, "") }), _jsx(TableCell, { children: dateOr(key.expiresAt, "Never") }), actions && _jsx(TableCell, { className: "text-right", children: actions(key) })] }, key.id))) })] }));
6
9
  }
@@ -1,4 +1,4 @@
1
- import type { LinkComponent } from "../types";
1
+ import type { LinkComponent } from "../types.js";
2
2
  type NoKeysProps = {
3
3
  newKeyHref?: string;
4
4
  description?: string;
@@ -1,4 +1,4 @@
1
- import { type Quota } from "../types";
1
+ import { type Quota } from "../types.js";
2
2
  export declare function QuotaMeter({ quota }: {
3
3
  quota: Quota;
4
4
  }): import("react").JSX.Element;
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Progress } from "@locusgraph/components";
3
3
  import { formatCount, quotaPercent, quotaStatus } from "@locusgraph/utils";
4
- import { periodLabel } from "../types";
4
+ import { periodLabel } from "../types.js";
5
5
  const statusIndicator = {
6
6
  ok: "",
7
7
  near: "[&_[data-slot=progress-indicator]]:bg-warn",
@@ -1,4 +1,4 @@
1
- import { type LinkComponent, type Quota } from "../types";
1
+ import { type LinkComponent, type Quota } from "../types.js";
2
2
  type UsageAttentionProps = {
3
3
  balanceMicroUsd: number | null;
4
4
  quotas: Quota[];
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Alert, AlertDescription, AlertTitle, Button } from "@locusgraph/components";
3
3
  import { balanceLevel, formatCount, formatMicroUsd, quotaStatus } from "@locusgraph/utils";
4
4
  import { CircleAlertIcon } from "lucide-react";
5
- import { periodLabel } from "../types";
5
+ import { periodLabel } from "../types.js";
6
6
  function attentionTitle(empty, overCount) {
7
7
  if (empty)
8
8
  return "Out of credits";
@@ -1,4 +1,4 @@
1
- import type { Quota } from "../types";
1
+ import type { Quota } from "../types.js";
2
2
  type UsageSummaryProps = {
3
3
  quotas: Quota[];
4
4
  label?: string;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { RuleGrid, RuleGridCell, RuleGridLabel } from "@locusgraph/components";
3
- import { QuotaMeter } from "./quota-meter";
3
+ import { QuotaMeter } from "./quota-meter.js";
4
4
  export function UsageSummary({ quotas, label = "Usage", emptyText = "No plan includes metered usage yet.", }) {
5
5
  return (_jsx(RuleGrid, { columns: 1, children: _jsxs(RuleGridCell, { className: "gap-5", children: [_jsx(RuleGridLabel, { children: label }), quotas.length > 0 ? (quotas.map((quota) => _jsx(QuotaMeter, { quota: quota }, quota.key))) : (_jsx("p", { className: "text-sm text-muted-foreground", children: emptyText }))] }) }));
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@locusgraph/blocks",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Product sections built from @locusgraph/components: usage meters and alerts, wallet, credit packs, plan options and API keys.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -29,17 +29,17 @@
29
29
  "provenance": true
30
30
  },
31
31
  "peerDependencies": {
32
- "@locusgraph/components": "^0.1.0",
32
+ "@locusgraph/components": "^0.1.1",
33
33
  "react": "^19.2.0",
34
34
  "react-dom": "^19.2.0"
35
35
  },
36
36
  "dependencies": {
37
- "@locusgraph/utils": "0.1.0",
37
+ "@locusgraph/utils": "0.1.1",
38
38
  "lucide-react": "^1.28.0"
39
39
  },
40
40
  "devDependencies": {
41
- "@locusgraph/components": "0.1.0",
42
- "@locusgraph/config": "0.1.0",
41
+ "@locusgraph/components": "0.1.1",
42
+ "@locusgraph/config": "0.1.1",
43
43
  "@types/node": "^22.0.0",
44
44
  "@types/react": "^19.2.0",
45
45
  "@types/react-dom": "^19.2.0",
@@ -49,7 +49,7 @@
49
49
  "vitest": "^5.0.3"
50
50
  },
51
51
  "scripts": {
52
- "build": "rm -rf dist && tsc -p tsconfig.build.json && cp src/sources.css dist/sources.css",
52
+ "build": "rm -rf dist && tsc -p tsconfig.build.json && cp src/sources.css dist/sources.css && node ../../scripts/esm-extensions.mjs dist",
53
53
  "typecheck": "tsc -p tsconfig.json --noEmit",
54
54
  "test": "vitest run"
55
55
  }