@lambda-development/erp-core 0.1.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.
Files changed (67) hide show
  1. package/dist/App.d.ts +1 -0
  2. package/dist/api/client.d.ts +256 -0
  3. package/dist/assets/report-runtime.worker-DrBTCfV6.js +5 -0
  4. package/dist/assets/report-runtime.worker-DrBTCfV6.js.map +1 -0
  5. package/dist/bootstrap.d.ts +16 -0
  6. package/dist/components/auth/protected-route.d.ts +3 -0
  7. package/dist/components/chat/chat-provider.d.ts +62 -0
  8. package/dist/components/document/child-table-editor.d.ts +9 -0
  9. package/dist/components/document/document-actions.d.ts +14 -0
  10. package/dist/components/document/link-field.d.ts +9 -0
  11. package/dist/components/document/status-badge.d.ts +5 -0
  12. package/dist/components/layout/app-shell.d.ts +1 -0
  13. package/dist/components/layout/sidebar.d.ts +7 -0
  14. package/dist/components/ui/badge.d.ts +10 -0
  15. package/dist/components/ui/button.d.ts +11 -0
  16. package/dist/components/ui/card.d.ts +10 -0
  17. package/dist/components/ui/date-range-presets.d.ts +9 -0
  18. package/dist/components/ui/hint-tooltip.d.ts +3 -0
  19. package/dist/components/ui/input.d.ts +9 -0
  20. package/dist/components/ui/language-select.d.ts +8 -0
  21. package/dist/components/ui/select.d.ts +15 -0
  22. package/dist/contexts/auth-context.d.ts +19 -0
  23. package/dist/hooks/use-base-currency.d.ts +7 -0
  24. package/dist/hooks/use-currencies.d.ts +10 -0
  25. package/dist/hooks/use-document-list.d.ts +16 -0
  26. package/dist/hooks/use-document.d.ts +14 -0
  27. package/dist/hooks/use-report.d.ts +139 -0
  28. package/dist/hooks/use-url-state.d.ts +23 -0
  29. package/dist/i18n/index.d.ts +15 -0
  30. package/dist/i18n/locales/de.json.d.ts +542 -0
  31. package/dist/i18n/locales/en.json.d.ts +602 -0
  32. package/dist/i18n/locales/fr.json.d.ts +542 -0
  33. package/dist/index.d.ts +31 -0
  34. package/dist/index.js +6583 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/lib/branding.d.ts +28 -0
  37. package/dist/lib/component-registry.d.ts +4 -0
  38. package/dist/lib/doctypes.d.ts +56 -0
  39. package/dist/lib/nav.d.ts +21 -0
  40. package/dist/lib/utils.d.ts +10 -0
  41. package/dist/main.d.ts +0 -0
  42. package/dist/pages/admin/settings.d.ts +1 -0
  43. package/dist/pages/admin/users.d.ts +1 -0
  44. package/dist/pages/chat.d.ts +1 -0
  45. package/dist/pages/dashboard.d.ts +1 -0
  46. package/dist/pages/demo.d.ts +6 -0
  47. package/dist/pages/documents/document-form.d.ts +2 -0
  48. package/dist/pages/documents/document-list.d.ts +1 -0
  49. package/dist/pages/login.d.ts +1 -0
  50. package/dist/pages/masters/master-form.d.ts +1 -0
  51. package/dist/pages/masters/master-list.d.ts +1 -0
  52. package/dist/pages/opening-balances.d.ts +1 -0
  53. package/dist/pages/reports/analytics.d.ts +1 -0
  54. package/dist/pages/reports/ap-aging.d.ts +1 -0
  55. package/dist/pages/reports/ar-aging.d.ts +1 -0
  56. package/dist/pages/reports/balance-sheet.d.ts +1 -0
  57. package/dist/pages/reports/general-ledger.d.ts +1 -0
  58. package/dist/pages/reports/profit-loss.d.ts +1 -0
  59. package/dist/pages/reports/stock-balance.d.ts +1 -0
  60. package/dist/pages/reports/trial-balance.d.ts +1 -0
  61. package/dist/pages/setup.d.ts +1 -0
  62. package/dist/pages/tutorial.d.ts +1 -0
  63. package/dist/routes.d.ts +19 -0
  64. package/dist/workers/report-runtime.worker.d.ts +1 -0
  65. package/package.json +61 -0
  66. package/src/index.css +105 -0
  67. package/tailwind.preset.ts +70 -0
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Branding / theme configuration.
3
+ *
4
+ * The visual theme is already CSS-variable based (see index.css `:root`
5
+ * tokens, surfaced to Tailwind as `brand`, `surface`, `fg`, `line`, …). A
6
+ * customer deployment built on the published library rebrands by calling
7
+ * `configureBranding` at startup: override the product name, point at a logo,
8
+ * and/or override any of the `:root` design tokens at runtime.
9
+ *
10
+ * For deeper restyling the customer's own Tailwind build (which scans this
11
+ * package — the "consumer scans source" model) can add utilities freely; this
12
+ * helper covers the common case of swapping name/logo/colors without a custom
13
+ * stylesheet.
14
+ */
15
+ export interface Branding {
16
+ /** Product name — used for the document title and as the sidebar fallback. */
17
+ appName: string;
18
+ /** Optional logo URL (falls back to the core CSS-mask logo when unset). */
19
+ logoUrl?: string;
20
+ /**
21
+ * CSS custom properties to set on :root, e.g. { "--brand": "260 80% 55%" }.
22
+ * The leading "--" is optional. Values follow the token format in index.css
23
+ * (HSL channel triplets for color tokens).
24
+ */
25
+ tokens?: Record<string, string>;
26
+ }
27
+ export declare function configureBranding(next: Partial<Branding>): void;
28
+ export declare function getBranding(): Branding;
@@ -0,0 +1,4 @@
1
+ import { ComponentType } from 'react';
2
+ export declare function registerComponent(name: string, component: ComponentType<any>): void;
3
+ /** Resolve a registered override, falling back to the core default. */
4
+ export declare function getComponent<P>(name: string, fallback: ComponentType<P>): ComponentType<P>;
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Doctype metadata registry.
3
+ *
4
+ * This drives the generic list and form pages. Instead of coding 8 separate
5
+ * pages, a single registry defines the fields, columns, and actions for each
6
+ * document type.
7
+ */
8
+ export interface FieldDef {
9
+ name: string;
10
+ label: string;
11
+ type: "text" | "number" | "currency" | "date" | "link" | "select" | "textarea";
12
+ required?: boolean;
13
+ readOnly?: boolean;
14
+ linkDoctype?: string;
15
+ linkDoctypeField?: string;
16
+ options?: Array<string | {
17
+ value: string;
18
+ label: string;
19
+ }>;
20
+ optionsSource?: "currency";
21
+ default?: any;
22
+ hint?: string;
23
+ }
24
+ export interface ChildTableDef {
25
+ label: string;
26
+ key: string;
27
+ fields: FieldDef[];
28
+ }
29
+ export interface ConversionDef {
30
+ label: string;
31
+ targetDoctype: string;
32
+ }
33
+ export interface DoctypeConfig {
34
+ slug: string;
35
+ label: string;
36
+ dateField: string;
37
+ partyField?: string;
38
+ partyLabel?: string;
39
+ amountField?: string;
40
+ fields: FieldDef[];
41
+ childTables: ChildTableDef[];
42
+ listColumns: string[];
43
+ canSubmit: boolean;
44
+ canCancel: boolean;
45
+ conversions: ConversionDef[];
46
+ }
47
+ export declare function getDoctypeConfig(slug: string): DoctypeConfig | undefined;
48
+ /**
49
+ * Register (or override) a doctype config. A customer deployment built on the
50
+ * published library calls this at startup to add a new document type or swap
51
+ * the form/list schema of a core one. The list/form pages read CONFIGS live
52
+ * via getDoctypeConfig, so a registration takes effect immediately.
53
+ */
54
+ export declare function registerDoctype(config: DoctypeConfig): void;
55
+ export declare function getAllDoctypeConfigs(): DoctypeConfig[];
56
+ export declare const DOCTYPE_SLUGS: string[];
@@ -0,0 +1,21 @@
1
+ import { ReactNode } from 'react';
2
+ export interface NavItem {
3
+ label: string;
4
+ path: string;
5
+ }
6
+ export interface NavGroup {
7
+ label: string;
8
+ icon: ReactNode;
9
+ items: NavItem[];
10
+ }
11
+ /** Live list the sidebar renders from. */
12
+ export declare function getNavGroups(): NavGroup[];
13
+ /**
14
+ * Add a nav group, or replace an existing one with the same label. Pass
15
+ * `index` to control placement (default: appended at the end).
16
+ */
17
+ export declare function registerNavGroup(group: NavGroup, opts?: {
18
+ index?: number;
19
+ }): void;
20
+ /** Append an item to an existing group (creating the group if absent). */
21
+ export declare function registerNavItem(groupLabel: string, item: NavItem): void;
@@ -0,0 +1,10 @@
1
+ /** Merge class names (simplified clsx). */
2
+ export declare function cn(...classes: (string | false | null | undefined)[]): string;
3
+ /** Format a number as currency. */
4
+ export declare function formatCurrency(value: number | null | undefined, currency?: string): string;
5
+ /** Format a number with commas. */
6
+ export declare function formatNumber(value: number | null | undefined, decimals?: number): string;
7
+ /** Format a date string for display. */
8
+ export declare function formatDate(value: string | null | undefined): string;
9
+ /** Safely parse a float, defaulting to 0. */
10
+ export declare function flt(value: unknown, precision?: number): number;
package/dist/main.d.ts ADDED
File without changes
@@ -0,0 +1 @@
1
+ export default function SettingsPage(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export default function UsersPage(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export default function ChatPage(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export default function DashboardPage(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Shareable entry point that mirrors the "Enter Live Demo" button on /login.
3
+ * Creates a fresh chat session (as the public_manager fallback user if the
4
+ * visitor has no cookie) and redirects to /chat/{id}?demo=1 for replay.
5
+ */
6
+ export default function DemoPage(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ export declare function linkRefHref(linkDoctype: string | undefined | null, value: string): string | null;
2
+ export default function DocumentFormPage(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export default function DocumentListPage(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export default function LoginPage(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export default function MasterFormPage(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export default function MasterListPage(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export default function OpeningBalancesPage(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export default function AnalyticsPage(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export default function ApAgingPage(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export default function ArAgingPage(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export default function BalanceSheetPage(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export default function GeneralLedgerPage(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export default function ProfitLossPage(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export default function StockBalancePage(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export default function TrialBalancePage(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export default function SetupPage(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export default function TutorialPage(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,19 @@
1
+ import { RouteObject } from 'react-router-dom';
2
+ /**
3
+ * Register a route from a customer deployment.
4
+ * - area "app" (default): added under the protected app shell (sidebar +
5
+ * header), so it's an authenticated page like the core ones.
6
+ * - area "top": added at the root (e.g. a public/unauthenticated page).
7
+ *
8
+ * A registered route whose `path` (or index) matches a core route replaces
9
+ * it — that's how you override a core page wholesale.
10
+ */
11
+ export declare function registerRoute(route: RouteObject, opts?: {
12
+ area?: "app" | "top";
13
+ }): void;
14
+ /**
15
+ * Build the full route table, merging any customer-registered routes over the
16
+ * core ones. Call this when constructing the router (the demo does so via
17
+ * bootstrap) — after plugins have registered, so overrides take effect.
18
+ */
19
+ export declare function buildRoutes(): RouteObject[];
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@lambda-development/erp-core",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./styles.css": "./src/index.css",
14
+ "./tailwind-preset": "./tailwind.preset.ts"
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "src/index.css",
19
+ "tailwind.preset.ts"
20
+ ],
21
+ "sideEffects": [
22
+ "**/*.css"
23
+ ],
24
+ "scripts": {
25
+ "dev": "vite",
26
+ "build": "tsc -b && vite build",
27
+ "build:lib": "vite build --config vite.lib.config.ts",
28
+ "preview": "vite preview"
29
+ },
30
+ "peerDependencies": {
31
+ "@tanstack/react-query": "^5.60.0",
32
+ "@tanstack/react-table": "^8.20.0",
33
+ "i18next": "^26.2.0",
34
+ "lucide-react": "^0.460.0",
35
+ "react": "^19.0.0",
36
+ "react-dom": "^19.0.0",
37
+ "react-i18next": "^17.0.8",
38
+ "react-router-dom": "^7.0.0",
39
+ "recharts": "^3.8.1"
40
+ },
41
+ "devDependencies": {
42
+ "@tanstack/react-query": "^5.60.0",
43
+ "@tanstack/react-table": "^8.20.0",
44
+ "@types/react": "^19.0.0",
45
+ "@types/react-dom": "^19.0.0",
46
+ "@vitejs/plugin-react": "^4.3.0",
47
+ "autoprefixer": "^10.4.20",
48
+ "i18next": "^26.2.0",
49
+ "lucide-react": "^0.460.0",
50
+ "postcss": "^8.4.49",
51
+ "react": "^19.0.0",
52
+ "react-dom": "^19.0.0",
53
+ "react-i18next": "^17.0.8",
54
+ "react-router-dom": "^7.0.0",
55
+ "recharts": "^3.8.1",
56
+ "tailwindcss": "^3.4.0",
57
+ "typescript": "~5.6.0",
58
+ "vite": "^6.0.0",
59
+ "vite-plugin-dts": "^4.3.0"
60
+ }
61
+ }
package/src/index.css ADDED
@@ -0,0 +1,105 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ /* ───────────────────────────────────────────────────────────────────
6
+ Design tokens. Values are space-separated HSL components so they
7
+ plug into Tailwind via `hsl(var(--token) / <alpha-value>)` and
8
+ support opacity modifiers like `bg-brand/90`.
9
+
10
+ Anchored to the Lambda logo gradient: brand sits between the cyan
11
+ (#66D4FF) and pink (#ff6eb4) gradient stops.
12
+ ─────────────────────────────────────────────────────────────────── */
13
+ :root {
14
+ /* Brand */
15
+ --brand: 220 78% 57%; /* ≈ #2f6ff0 — saturated cobalt blue */
16
+ --brand-fg: 0 0% 100%;
17
+
18
+ /* Surfaces */
19
+ --surface: 0 0% 100%; /* primary card / panel */
20
+ --surface-muted: 220 14% 98%; /* page background — slightly cooler than white */
21
+ --surface-subtle: 220 14% 96%; /* hovered rows, secondary cards, sidebar active */
22
+
23
+ /* Lines & text */
24
+ --border: 220 13% 91%;
25
+ --text: 222 47% 11%;
26
+ --text-muted: 220 9% 46%;
27
+ }
28
+
29
+ @layer base {
30
+ body {
31
+ /* `bg-surface-muted` and `text-fg` are the new defaults but applying
32
+ them at the body level avoids touching every page component on
33
+ day 1. Tailwind's `bg-gray-50` on <body> is replaced here. */
34
+ @apply bg-surface-muted text-fg antialiased;
35
+ font-feature-settings: "cv02", "cv03", "cv04", "cv11"; /* Inter polish */
36
+ }
37
+
38
+ /* Fluid easing app-wide. Hover/transition properties feel less
39
+ mechanical with this curve. */
40
+ * {
41
+ transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
42
+ }
43
+ }
44
+
45
+ /* iOS Safari auto-zooms when a focused input/textarea has font-size
46
+ below 16px and doesn't zoom back out, making the whole page feel
47
+ broken after the keyboard closes. 16px is the minimum that
48
+ suppresses it. !important is needed because most of our inputs
49
+ use Tailwind's `text-sm` (14px), which is a class selector and
50
+ beats a plain element selector on specificity. Mobile-only — desktop
51
+ keeps its 14px. */
52
+ @media (max-width: 768px) {
53
+ input,
54
+ textarea,
55
+ select {
56
+ font-size: 16px !important;
57
+ }
58
+ }
59
+
60
+ /* Sidebar Lambda ERP logo — PNG silhouette used as a mask with an animated
61
+ multi-colour gradient showing through. */
62
+ .lambda-logo-icon {
63
+ width: 70px;
64
+ height: 15px;
65
+ flex-shrink: 0;
66
+ background: linear-gradient(135deg, #cbd5e1, #b0bacb, #c2ccd8, #94a3b8, #cbd5e1);
67
+ background-size: 300% 300%;
68
+ animation: lambda-logo-gradient 12s ease infinite;
69
+ -webkit-mask-image: url('/logo_lad_erp.png');
70
+ -webkit-mask-size: contain;
71
+ -webkit-mask-repeat: no-repeat;
72
+ -webkit-mask-position: center;
73
+ mask-image: url('/logo_lad_erp.png');
74
+ mask-size: contain;
75
+ mask-repeat: no-repeat;
76
+ mask-position: center;
77
+ }
78
+
79
+ @keyframes lambda-logo-gradient {
80
+ 0% { background-position: 0% 50%; }
81
+ 50% { background-position: 100% 50%; }
82
+ 100% { background-position: 0% 50%; }
83
+ }
84
+
85
+ /* Thin, Claude.ai-style scrollbar applied app-wide. Firefox honours
86
+ `scrollbar-width` / `scrollbar-color`; Chromium/Safari need the
87
+ `::-webkit-scrollbar-*` pseudo-elements to match. */
88
+ * {
89
+ scrollbar-width: thin;
90
+ scrollbar-color: rgba(31, 31, 30, 0.35) transparent;
91
+ }
92
+ *::-webkit-scrollbar {
93
+ width: 8px;
94
+ height: 8px;
95
+ }
96
+ *::-webkit-scrollbar-track {
97
+ background: transparent;
98
+ }
99
+ *::-webkit-scrollbar-thumb {
100
+ background-color: rgba(31, 31, 30, 0.35);
101
+ border-radius: 4px;
102
+ }
103
+ *::-webkit-scrollbar-thumb:hover {
104
+ background-color: rgba(31, 31, 30, 0.5);
105
+ }
@@ -0,0 +1,70 @@
1
+ import type { Config } from "tailwindcss";
2
+
3
+ // Shared Tailwind theme for the ERP core, published as a preset so the demo
4
+ // app and any customer deployment get identical design tokens. Add it with
5
+ // `presets: [erpPreset]` in tailwind.config. Colours are backed by the CSS
6
+ // variables defined in src/index.css (shipped as `@lambda-development/erp-core/styles.css`)
7
+ // — rebrand by overriding those variables, not by editing this preset.
8
+ const preset: Partial<Config> = {
9
+ theme: {
10
+ extend: {
11
+ // Token-backed colours. Values come from CSS variables in index.css,
12
+ // which means swapping themes (e.g. dark mode later) means changing
13
+ // the variables, not editing every component.
14
+ //
15
+ // Using `hsl(var(--x) / <alpha-value>)` lets Tailwind opacity
16
+ // modifiers work: `bg-brand/90`, `text-fg-muted/70`, etc.
17
+ colors: {
18
+ brand: {
19
+ DEFAULT: "hsl(var(--brand) / <alpha-value>)",
20
+ fg: "hsl(var(--brand-fg) / <alpha-value>)",
21
+ },
22
+ surface: {
23
+ DEFAULT: "hsl(var(--surface) / <alpha-value>)",
24
+ muted: "hsl(var(--surface-muted) / <alpha-value>)",
25
+ subtle: "hsl(var(--surface-subtle) / <alpha-value>)",
26
+ },
27
+ fg: {
28
+ DEFAULT: "hsl(var(--text) / <alpha-value>)",
29
+ muted: "hsl(var(--text-muted) / <alpha-value>)",
30
+ },
31
+ line: "hsl(var(--border) / <alpha-value>)",
32
+ },
33
+ fontFamily: {
34
+ sans: [
35
+ "Inter",
36
+ "system-ui",
37
+ "-apple-system",
38
+ "Segoe UI",
39
+ "Roboto",
40
+ "sans-serif",
41
+ ],
42
+ },
43
+ boxShadow: {
44
+ // Multi-layer soft shadows — closer in feel to Linear / Vercel
45
+ // than Tailwind's default. The card-hover variant is for
46
+ // interactive cards (hover, focus-within).
47
+ card: "0 1px 2px rgba(0,0,0,0.04), 0 4px 12px rgba(0,0,0,0.03)",
48
+ "card-hover": "0 1px 2px rgba(0,0,0,0.05), 0 8px 24px rgba(0,0,0,0.05)",
49
+ // Subtle inset highlight for primary buttons — gives the
50
+ // top edge a 1px lift that's almost invisible but reads as depth.
51
+ "button-highlight": "inset 0 1px 0 rgba(255,255,255,0.16)",
52
+ // Saturated colored surfaces (user chat bubble, brand CTAs) need
53
+ // a different shadow recipe than neutral cards: a black drop
54
+ // shadow alone barely registers on a vivid purple. Combining
55
+ // 1) a 1px inset top highlight — reads as polished glass,
56
+ // 2) a tight dark drop — defines the bubble edge,
57
+ // 3) a soft brand-tinted glow — makes the bubble feel like
58
+ // it's casting its own colour onto the page (kept subtle),
59
+ // gives the bubble physical presence without looking gimmicky.
60
+ "bubble-user": [
61
+ "inset 0 1px 0 rgba(255,255,255,0.22)",
62
+ "0 1px 2px rgba(0,0,0,0.05)",
63
+ "0 3px 8px -2px hsl(var(--brand) / 0.18)",
64
+ ].join(", "),
65
+ },
66
+ },
67
+ },
68
+ };
69
+
70
+ export default preset;