@togo-framework/ui 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.
@@ -0,0 +1,184 @@
1
+ import * as React from 'react';
2
+ import { ReactNode } from 'react';
3
+
4
+ /**
5
+ * brand.ts — Sentra dynamic theming primitives.
6
+ *
7
+ * Pure utilities: no React, no app context, no bridge dependency.
8
+ * A product imports these and wires its own org-settings fetch,
9
+ * then calls applyBrand() to override the CSS var baseline at runtime.
10
+ *
11
+ * CSS variables written (same set as app/src/components/BrandingProvider.tsx):
12
+ * --primary HSL "H S% L%" — buttons, rings, active states
13
+ * --brand-primary HSL "H S% L%" — alias kept for Situation Room glow
14
+ * --brand-primary-glow HSL with +7 lightness — glow variant
15
+ * --ring same as --primary
16
+ * --sidebar-primary same as --primary
17
+ * --sidebar-ring same as --primary
18
+ * --ai-glow same as --primary
19
+ * --accent-muted accent HSL with -13 lightness
20
+ * --logo-url CSS url("…") string for background-image consumers
21
+ */
22
+ /** Returns true for the HSL string form "H S% L%". */
23
+ declare function isHSL(value: string): boolean;
24
+ /** Returns true for "#RRGGBB" or "#RGB". */
25
+ declare function isValidColor(value: string): boolean;
26
+ /**
27
+ * Converts "#RRGGBB" or "#RGB" to the HSL string form "H S% L%".
28
+ * Returns an empty string when the input is not a valid hex color.
29
+ */
30
+ declare function hexToHSL(hex: string): string;
31
+ /**
32
+ * Normalises a hex or HSL value to the "H S% L%" form.
33
+ * Returns null when the value is unrecognised — callers should skip setting
34
+ * the var rather than writing a broken value.
35
+ */
36
+ declare function toHSLSafe(color: string): string | null;
37
+ /**
38
+ * Nudges the lightness of an "H S% L%" string by `delta` percentage points,
39
+ * clamped to [0, 100].
40
+ */
41
+ declare function nudgeL(hsl: string, delta: number): string;
42
+ /**
43
+ * SENTRA_BRAND — the platform's own brand tokens.
44
+ *
45
+ * These are the values used when no tenant branding is configured.
46
+ * BrandingProvider applies them on first render so the first paint is always
47
+ * branded; a tenant override writes over them once org-settings resolves.
48
+ */
49
+ declare const SENTRA_BRAND: {
50
+ /** Brand primary: Sentra crimson (--primary 345 75% 33%). */
51
+ readonly primaryHex: "#931535";
52
+ /** Brand accent: Tailwind violet-500. */
53
+ readonly accentHex: "#daab4e";
54
+ /** Logo path — products serve this from their own /public directory. */
55
+ readonly logoUrl: "/sentra-logo-full.png";
56
+ };
57
+ interface BrandTokens {
58
+ /** Hex string ("#RRGGBB") or HSL string ("H S% L%") for the primary color. */
59
+ primaryHex?: string;
60
+ /** Hex string ("#RRGGBB") or HSL string ("H S% L%") for the accent color. */
61
+ accentHex?: string;
62
+ /** Absolute URL or relative path to the org logo image. */
63
+ logoUrl?: string;
64
+ }
65
+ /**
66
+ * applyBrand — writes brand CSS custom properties directly onto `root`
67
+ * (typically `document.documentElement`).
68
+ *
69
+ * Call this inside a useEffect whenever org-settings data changes.
70
+ * When a field is absent or invalid, the corresponding Sentra default fills
71
+ * the gap — the product always has a styled baseline.
72
+ *
73
+ * @param root The element to set properties on (usually document.documentElement).
74
+ * @param tokens The brand tokens from org-settings; all fields are optional.
75
+ */
76
+ declare function applyBrand(root: HTMLElement, tokens?: BrandTokens): void;
77
+
78
+ interface BrandContextValue extends Omit<BrandTokens, 'logoUrl'> {
79
+ /** The resolved primary hex/HSL that is currently active (may be the Sentra default). */
80
+ primaryHex: string;
81
+ /** The resolved accent hex/HSL that is currently active (may be the Sentra default). */
82
+ accentHex: string;
83
+ /**
84
+ * The RAW logo URL the tenant set, or null when none is configured.
85
+ * Intentionally NOT defaulted to the Sentra logo: consumers (AdminLayout,
86
+ * AuthCard) use null to decide "no logo → render the icon mark instead".
87
+ * (operator 2026-06-05: everything was showing /sentra-logo-full.png — the
88
+ * default — instead of the platform icon when no DB logo exists.)
89
+ * The `--logo-url` CSS var (set by applyBrand) still falls back to the Sentra
90
+ * default for pure background-image consumers; this context value does not.
91
+ */
92
+ logoUrl: string | null;
93
+ /** Lucide icon name (e.g. 'ShieldCheck') for the platform mark. Null if unset. */
94
+ iconName: string | null;
95
+ /** Resolved product/platform name (for the sidebar title). Empty if unset. */
96
+ productName: string;
97
+ }
98
+ /**
99
+ * useBrand — reads the currently-active brand tokens from context.
100
+ *
101
+ * Returns the Sentra defaults when no BrandingProvider is in the tree.
102
+ * Only use this when a component genuinely needs to read the color values
103
+ * (e.g. to pass them to a canvas API). For standard CSS theming the CSS
104
+ * vars (hsl(var(--primary)) etc.) are always preferred.
105
+ */
106
+ declare function useBrand(): BrandContextValue;
107
+ interface BrandingProviderProps extends BrandTokens {
108
+ /** Lucide icon name for the platform mark (from Fort branding.icon). */
109
+ iconName?: string | null;
110
+ /** Product/platform display name (from Fort branding.product_name_*). */
111
+ productName?: string;
112
+ children: ReactNode;
113
+ }
114
+ /**
115
+ * BrandingProvider — hot-applies org branding CSS vars and exposes the
116
+ * active tokens via BrandContext.
117
+ *
118
+ * Renders no additional DOM nodes — it is a pure side-effect + context provider.
119
+ *
120
+ * Props (all optional — Sentra defaults fill any missing value):
121
+ * primaryHex Hex "#RRGGBB" or HSL "H S% L%" for the brand primary color.
122
+ * accentHex Hex "#RRGGBB" or HSL "H S% L%" for the brand accent color.
123
+ * logoUrl Absolute URL or relative path to the org logo.
124
+ */
125
+ declare const BrandingProvider: {
126
+ ({ primaryHex, accentHex, logoUrl, iconName, productName, children, }: BrandingProviderProps): React.JSX.Element;
127
+ displayName: string;
128
+ };
129
+
130
+ type ThemeBase = "dark" | "light";
131
+ interface ThemeDef {
132
+ id: string;
133
+ label: string;
134
+ /** Whether this theme toggles the `.dark` class (keeps `dark:` utilities in sync). */
135
+ base: ThemeBase;
136
+ }
137
+ declare const themes: ThemeDef[];
138
+ declare function themeBase(id: string): ThemeBase;
139
+ declare const STORAGE_KEY = "togo-theme";
140
+ /**
141
+ * Inline this string in a <script> in <head> to set the theme before first paint
142
+ * (no flash of the wrong theme). The framework injects it server-side.
143
+ *
144
+ * <script dangerouslySetInnerHTML={{ __html: themeInitScript }} />
145
+ */
146
+ declare const themeInitScript: string;
147
+
148
+ type TogoTheme = "dark" | "light" | (string & {});
149
+ type Dir = "ltr" | "rtl";
150
+ /** Per-app brand overrides: any `--togo-*` (or bridged) custom property → value. */
151
+ type ThemeOverrides = Record<string, string>;
152
+ interface ThemeContextValue {
153
+ theme: TogoTheme;
154
+ setTheme: (t: TogoTheme) => void;
155
+ themes: ThemeDef[];
156
+ dir: Dir;
157
+ setDir: (d: Dir) => void;
158
+ }
159
+ interface ThemeProviderProps {
160
+ theme?: TogoTheme;
161
+ /** Per-app brand overrides applied as inline custom properties on the scope element. */
162
+ overrides?: ThemeOverrides;
163
+ dir?: Dir;
164
+ /** "html" (default) themes <html>; "self" themes a wrapper div (so themes can coexist on one page). */
165
+ scope?: "html" | "self";
166
+ themes?: ThemeDef[];
167
+ /** Persist theme/dir choice to localStorage and read it on first mount. */
168
+ persist?: boolean;
169
+ className?: string;
170
+ children: React.ReactNode;
171
+ }
172
+ /**
173
+ * ThemeProvider — runtime theming. Sets `data-theme` + toggles `.dark` + `dir` on its
174
+ * scope (the <html> element, or a wrapper when scope="self"), applies per-app `overrides`
175
+ * as inline custom properties, and exposes `useTheme()`. SSR-safe (no DOM access at module
176
+ * top level; all mutations run in effects). For no-flash, also inline `themeInitScript`.
177
+ */
178
+ declare function ThemeProvider({ theme: themeProp, overrides, dir: dirProp, scope, themes, persist, className, children, }: ThemeProviderProps): React.JSX.Element;
179
+ declare namespace ThemeProvider {
180
+ var displayName: string;
181
+ }
182
+ declare function useTheme(): ThemeContextValue;
183
+
184
+ export { type BrandContextValue, type BrandTokens, BrandingProvider, type BrandingProviderProps, type Dir, SENTRA_BRAND, STORAGE_KEY, type ThemeBase, type ThemeContextValue, type ThemeDef, type ThemeOverrides, ThemeProvider, type ThemeProviderProps, type TogoTheme, applyBrand, hexToHSL, isHSL, isValidColor, nudgeL, themeBase, themeInitScript, themes, toHSLSafe, useBrand, useTheme };
@@ -0,0 +1,36 @@
1
+ "use client";
2
+ import {
3
+ BrandingProvider,
4
+ SENTRA_BRAND,
5
+ STORAGE_KEY,
6
+ ThemeProvider,
7
+ applyBrand,
8
+ hexToHSL,
9
+ isHSL,
10
+ isValidColor,
11
+ nudgeL,
12
+ themeBase,
13
+ themeInitScript,
14
+ themes,
15
+ toHSLSafe,
16
+ useBrand,
17
+ useTheme
18
+ } from "../chunk-KD4MPGYQ.js";
19
+ export {
20
+ BrandingProvider,
21
+ SENTRA_BRAND,
22
+ STORAGE_KEY,
23
+ ThemeProvider,
24
+ applyBrand,
25
+ hexToHSL,
26
+ isHSL,
27
+ isValidColor,
28
+ nudgeL,
29
+ themeBase,
30
+ themeInitScript,
31
+ themes,
32
+ toHSLSafe,
33
+ useBrand,
34
+ useTheme
35
+ };
36
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,63 @@
1
+ /*
2
+ * ToGO Design System — PRIMITIVE tokens.
3
+ *
4
+ * The raw brand palette + non-color scales. This is the ONLY file in the kit
5
+ * allowed to contain literal hex values (enforced by the lint guardrail).
6
+ * Semantic role tokens (tokens.semantic.css) reference these; components
7
+ * reference the semantic roles — never these primitives directly.
8
+ *
9
+ * Palette source: the official ToGO brand guidelines (Gopher Cyan → Cobalt).
10
+ */
11
+
12
+ :root {
13
+ /* ── Brand ramp — Gopher Cyan → Stack Sky → Cobalt ── */
14
+ --togo-cyan-300: #5CDDEC;
15
+ --togo-cyan-400: #2FCFE2;
16
+ --togo-cyan-500: #1FC7DC; /* Gopher Cyan — primary accent */
17
+ --togo-sky-500: #2D8CE6; /* Stack Sky — secondary */
18
+ --togo-cobalt-500: #1659C8; /* Cobalt — deep */
19
+ --togo-cobalt-600: #1247A3;
20
+
21
+ /* ── Neutrals ── */
22
+ --togo-ink-900: #141A1D; /* Ink — text / dark surfaces */
23
+ --togo-ink-700: #2A363B;
24
+ --togo-slate-500: #5A6B72; /* Slate — muted body */
25
+ --togo-slate-300: #9BAAB0;
26
+ --togo-line-200: #E8EDEF; /* hairline borders (light) */
27
+ --togo-mist-100: #F4F7F8; /* Mist — surfaces (light) */
28
+ --togo-white: #FFFFFF;
29
+
30
+ /* ── Status ── */
31
+ --togo-success-500: #1F9D6B;
32
+ --togo-warn-500: #E0A11B;
33
+ --togo-danger-500: #D85563;
34
+
35
+ /* ── Brand gradient (ToGO Flow) ── */
36
+ --togo-flow: linear-gradient(110deg, var(--togo-cyan-500) 0%, var(--togo-sky-500) 52%, var(--togo-cobalt-500) 100%);
37
+
38
+ /* ── Non-color scales ── */
39
+ --togo-radius-sm: 6px;
40
+ --togo-radius-md: 12px;
41
+ --togo-radius-lg: 16px;
42
+ --togo-radius-pill: 999px;
43
+
44
+ --togo-space-1: 4px;
45
+ --togo-space-2: 8px;
46
+ --togo-space-3: 12px;
47
+ --togo-space-4: 16px;
48
+ --togo-space-6: 24px;
49
+ --togo-space-8: 32px;
50
+
51
+ --togo-shadow-sm: 0 1px 2px rgba(20, 26, 29, .06);
52
+ --togo-shadow-md: 0 8px 24px rgba(20, 26, 29, .10);
53
+ --togo-shadow-accent: 0 12px 24px rgba(22, 89, 200, .25);
54
+
55
+ /* ── Type families ──
56
+ * Latin display/body/mono. Lusail is the ARABIC face and is applied ONLY to
57
+ * RTL/Arabic content (see the [dir="rtl"], :lang(ar) rule in styles.css) — it is
58
+ * intentionally NOT in these Latin stacks, so if the brand fonts fail to load the
59
+ * fallback is clean system-ui, never Lusail rendering Latin (which looks heavy/wrong). */
60
+ --togo-font-display: "Sora", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
61
+ --togo-font-body: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
62
+ --togo-font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
63
+ }
@@ -0,0 +1,45 @@
1
+ /*
2
+ * ToGO Design System — SEMANTIC role tokens.
3
+ *
4
+ * The roles components actually consume. Each theme is a `[data-theme="…"]`
5
+ * block that re-points the same roles — this is the runtime-theming switch
6
+ * surface. Add a tenant/brand theme by adding one more block here; no
7
+ * component changes required.
8
+ *
9
+ * No hex lives here — every value references a primitive (tokens.primitive.css).
10
+ */
11
+
12
+ /* ── DARK (default) ── */
13
+ :root,
14
+ [data-theme="dark"] {
15
+ --togo-color-bg: var(--togo-ink-900);
16
+ --togo-color-surface: #1B2226;
17
+ --togo-color-surface-alt: #222B30;
18
+ --togo-color-border: #2C383E;
19
+ --togo-color-text: #E8EEF0;
20
+ --togo-color-text-muted: var(--togo-slate-300);
21
+ --togo-color-accent: var(--togo-cyan-500);
22
+ --togo-color-accent-strong: var(--togo-sky-500);
23
+ --togo-color-on-accent: var(--togo-ink-900);
24
+ --togo-color-focus-ring: var(--togo-cyan-400);
25
+ --togo-color-success: var(--togo-success-500);
26
+ --togo-color-warn: var(--togo-warn-500);
27
+ --togo-color-danger: var(--togo-danger-500);
28
+ }
29
+
30
+ /* ── LIGHT ── */
31
+ [data-theme="light"] {
32
+ --togo-color-bg: var(--togo-mist-100);
33
+ --togo-color-surface: var(--togo-white);
34
+ --togo-color-surface-alt: var(--togo-mist-100);
35
+ --togo-color-border: var(--togo-line-200);
36
+ --togo-color-text: var(--togo-ink-900);
37
+ --togo-color-text-muted: var(--togo-slate-500);
38
+ --togo-color-accent: var(--togo-cobalt-500);
39
+ --togo-color-accent-strong: var(--togo-sky-500);
40
+ --togo-color-on-accent: var(--togo-white);
41
+ --togo-color-focus-ring: var(--togo-sky-500);
42
+ --togo-color-success: var(--togo-success-500);
43
+ --togo-color-warn: var(--togo-warn-500);
44
+ --togo-color-danger: var(--togo-danger-500);
45
+ }
package/package.json ADDED
@@ -0,0 +1,123 @@
1
+ {
2
+ "name": "@togo-framework/ui",
3
+ "version": "0.1.0",
4
+ "description": "togo UI kit — the prism-style admin + auth component library (layout, data, charts, primitives). Framework-agnostic, RTL-ready, dark-first.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js"
14
+ },
15
+ "./styles.css": "./dist/styles.css",
16
+ "./shadcn": {
17
+ "types": "./dist/shadcn.d.ts",
18
+ "import": "./dist/shadcn.js"
19
+ },
20
+ "./shadcn.css": "./dist/shadcn.css",
21
+ "./theme": {
22
+ "types": "./dist/theme/index.d.ts",
23
+ "import": "./dist/theme/index.js"
24
+ }
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "public"
29
+ ],
30
+ "sideEffects": [
31
+ "**/*.css"
32
+ ],
33
+ "scripts": {
34
+ "build": "tsup",
35
+ "lint:tokens": "node scripts/check-tokens.mjs",
36
+ "dev": "tsup --watch",
37
+ "storybook": "storybook dev -p 6006",
38
+ "build-storybook": "storybook build",
39
+ "typecheck": "tsc --noEmit",
40
+ "prepare": "tsup"
41
+ },
42
+ "peerDependencies": {
43
+ "lucide-react": ">=0.400.0",
44
+ "react": ">=18",
45
+ "react-dom": ">=18"
46
+ },
47
+ "dependencies": {
48
+ "@dnd-kit/core": "^6.3.1",
49
+ "@dnd-kit/sortable": "^10.0.0",
50
+ "@dnd-kit/utilities": "^3.2.2",
51
+ "@radix-ui/react-accordion": "^1.2.11",
52
+ "@radix-ui/react-alert-dialog": "^1.1.14",
53
+ "@radix-ui/react-aspect-ratio": "^1.1.7",
54
+ "@radix-ui/react-avatar": "^1.1.10",
55
+ "@radix-ui/react-checkbox": "^1.3.2",
56
+ "@radix-ui/react-collapsible": "^1.1.11",
57
+ "@radix-ui/react-context-menu": "^2.2.15",
58
+ "@radix-ui/react-dialog": "^1.1.14",
59
+ "@radix-ui/react-dropdown-menu": "^2.1.15",
60
+ "@radix-ui/react-hover-card": "^1.1.14",
61
+ "@radix-ui/react-label": "^2.1.7",
62
+ "@radix-ui/react-menubar": "^1.1.15",
63
+ "@radix-ui/react-navigation-menu": "^1.2.13",
64
+ "@radix-ui/react-popover": "^1.1.14",
65
+ "@radix-ui/react-progress": "^1.1.7",
66
+ "@radix-ui/react-radio-group": "^1.3.7",
67
+ "@radix-ui/react-scroll-area": "^1.2.9",
68
+ "@radix-ui/react-select": "^2.2.5",
69
+ "@radix-ui/react-separator": "^1.1.7",
70
+ "@radix-ui/react-slider": "^1.3.5",
71
+ "@radix-ui/react-slot": "^1.2.3",
72
+ "@radix-ui/react-switch": "^1.2.5",
73
+ "@radix-ui/react-tabs": "^1.1.12",
74
+ "@radix-ui/react-toast": "^1.2.14",
75
+ "@radix-ui/react-toggle": "^1.1.9",
76
+ "@radix-ui/react-toggle-group": "^1.1.10",
77
+ "@radix-ui/react-tooltip": "^1.2.7",
78
+ "@tanstack/react-table": "^8.21.3",
79
+ "class-variance-authority": "^0.7.1",
80
+ "clsx": "^2.1.1",
81
+ "cmdk": "^1.1.1",
82
+ "date-fns": "^3.6.0",
83
+ "embla-carousel-react": "^8.6.0",
84
+ "highlight.js": "^11.11.1",
85
+ "html-to-image": "^1.11.13",
86
+ "i18next": "^24.2.3",
87
+ "input-otp": "^1.4.2",
88
+ "leaflet": "^1.9.4",
89
+ "mermaid": "^11.15.0",
90
+ "react-day-picker": "^8.10.1",
91
+ "react-hook-form": "^7.61.1",
92
+ "react-i18next": "^15.7.4",
93
+ "react-icons": "^5.6.0",
94
+ "react-markdown": "^10.1.0",
95
+ "react-resizable-panels": "^2.1.9",
96
+ "recharts": "^2.15.4",
97
+ "rehype-highlight": "^7.0.2",
98
+ "remark-gfm": "^4.0.1",
99
+ "sonner": "^1.7.4",
100
+ "tailwind-merge": "^2.6.0",
101
+ "tw-animate-css": "^1.4.0",
102
+ "vaul": "^0.9.9"
103
+ },
104
+ "devDependencies": {
105
+ "@storybook/addon-essentials": "^8.4.0",
106
+ "@storybook/addon-themes": "^8.4.0",
107
+ "@storybook/react": "^8.4.0",
108
+ "@storybook/react-vite": "^8.4.0",
109
+ "@storybook/test": "^8.4.0",
110
+ "@tailwindcss/vite": "^4.0.0",
111
+ "@types/leaflet": "^1.9.12",
112
+ "@types/react": "^19.0.0",
113
+ "@types/react-dom": "^19.0.0",
114
+ "lucide-react": "^0.462.0",
115
+ "react": "^19.0.0",
116
+ "react-dom": "^19.0.0",
117
+ "storybook": "^8.4.0",
118
+ "tailwindcss": "^4.0.0",
119
+ "tsup": "^8.3.0",
120
+ "typescript": "^5.6.0",
121
+ "vite": "^6.0.0"
122
+ }
123
+ }
Binary file