@omerdlw/base-framework 1.0.0 → 1.0.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 (71) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +121 -52
  3. package/dist/hooks/index.d.ts +1 -10
  4. package/dist/hooks/index.d.ts.map +1 -1
  5. package/dist/hooks/index.js +2 -538
  6. package/dist/hooks/index.js.map +1 -1
  7. package/dist/hooks/types.d.ts +0 -53
  8. package/dist/hooks/types.d.ts.map +1 -1
  9. package/dist/hooks/use-global-event.d.ts +0 -2
  10. package/dist/hooks/use-global-event.d.ts.map +1 -1
  11. package/dist/index.js +138 -742
  12. package/dist/index.js.map +1 -1
  13. package/dist/kernel/index.js +3 -3
  14. package/dist/kernel/index.js.map +1 -1
  15. package/dist/modules/ambient/index.js.map +1 -1
  16. package/dist/modules/background/index.js +5 -5
  17. package/dist/modules/background/index.js.map +1 -1
  18. package/dist/modules/context-menu/index.js +4 -4
  19. package/dist/modules/context-menu/index.js.map +1 -1
  20. package/dist/modules/controls/index.js +3 -3
  21. package/dist/modules/controls/index.js.map +1 -1
  22. package/dist/modules/dock/cards.d.ts +1 -1
  23. package/dist/modules/dock/hooks.d.ts +1 -1
  24. package/dist/modules/dock/index.js +3 -3
  25. package/dist/modules/dock/index.js.map +1 -1
  26. package/dist/modules/index.js +34 -115
  27. package/dist/modules/index.js.map +1 -1
  28. package/dist/modules/loading/index.js +3 -3
  29. package/dist/modules/loading/index.js.map +1 -1
  30. package/dist/modules/media/index.js.map +1 -1
  31. package/dist/modules/modal/index.js +11 -95
  32. package/dist/modules/modal/index.js.map +1 -1
  33. package/dist/modules/notification/index.js +7 -5
  34. package/dist/modules/notification/index.js.map +1 -1
  35. package/dist/provider.js.map +1 -1
  36. package/dist/utils/dom.d.ts +0 -2
  37. package/dist/utils/dom.d.ts.map +1 -1
  38. package/dist/utils/index.d.ts +5 -6
  39. package/dist/utils/index.d.ts.map +1 -1
  40. package/dist/utils/index.js +19 -84
  41. package/dist/utils/index.js.map +1 -1
  42. package/dist/utils/number.d.ts +0 -1
  43. package/dist/utils/number.d.ts.map +1 -1
  44. package/dist/utils/object.d.ts +0 -2
  45. package/dist/utils/object.d.ts.map +1 -1
  46. package/dist/utils/string.d.ts +0 -3
  47. package/dist/utils/string.d.ts.map +1 -1
  48. package/dist/utils/timing.d.ts +0 -1
  49. package/dist/utils/timing.d.ts.map +1 -1
  50. package/docs/README.md +124 -0
  51. package/docs/architecture-and-rules.md +129 -0
  52. package/docs/core-engine.md +196 -0
  53. package/docs/custom-modules.md +267 -0
  54. package/docs/getting-started.md +199 -0
  55. package/docs/modules/README.md +176 -0
  56. package/docs/modules/ambient.md +150 -0
  57. package/docs/modules/background.md +195 -0
  58. package/docs/modules/context-menu.md +248 -0
  59. package/docs/modules/controls.md +159 -0
  60. package/docs/modules/dock.md +734 -0
  61. package/docs/modules/error-boundary.md +160 -0
  62. package/docs/modules/kernel.md +266 -0
  63. package/docs/modules/loading.md +157 -0
  64. package/docs/modules/media.md +196 -0
  65. package/docs/modules/modal.md +229 -0
  66. package/docs/modules/notification.md +161 -0
  67. package/docs/modules/result.md +135 -0
  68. package/docs/testing.md +160 -0
  69. package/docs/theming.md +185 -0
  70. package/package.json +3 -1
  71. package/templates/AGENTS.md +165 -0
@@ -0,0 +1,135 @@
1
+ # Result — `@omerdlw/base-framework/result`
2
+
3
+ > **Read this first if you need to:** write a Server Action (or any function that crosses the network), handle success/failure without `try/catch`, validate input in one place, or understand how failures reach the user.
4
+
5
+ ## 1. At a glance
6
+
7
+ | | |
8
+ | :-------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
9
+ | **Import** | `import { ok, err, type Result, createSafeAction } from "@omerdlw/base-framework/result"` |
10
+ | **Layer** | `src/core` foundation. **Server-safe**: no React, no `next/*`; imports only `@omerdlw/base-framework/utils` (`UserError`, `toUserMessage`, `report`). |
11
+ | **Enforced by** | [Rule 6](../architecture-and-rules.md#rule-6-result-pattern-returns): Server Actions (`"use server"`) must return `Result<T, E>`. Never throw across the network. |
12
+ | **Tests** | `tests/core/result.test.ts` |
13
+
14
+ ## 2. Why
15
+
16
+ Next.js serializes thrown errors poorly and strips their details in production. A returned `Result` arrives intact and forces the caller to handle both branches:
17
+
18
+ ```ts
19
+ type Result<T, E = string> =
20
+ | { success: true; data: T; code?: string }
21
+ | { success: false; error: E; code?: string };
22
+ ```
23
+
24
+ `data` exists only on success and `error` only on failure (`never` on the other branch), so TypeScript narrows on `result.success`.
25
+
26
+ ## 3. Quick start
27
+
28
+ ```ts
29
+ "use server";
30
+ import { ok, err, type Result } from "@omerdlw/base-framework/result";
31
+ import { UserError, toUserMessage } from "@omerdlw/base-framework/utils";
32
+ import { createServerSupabaseClient } from "@/infrastructure/supabase/server";
33
+
34
+ export async function renameProjectAction(
35
+ id: string,
36
+ name: string,
37
+ ): Promise<Result<{ id: string }>> {
38
+ if (!name.trim()) return err("Name is required", "VALIDATION");
39
+ try {
40
+ const supabase = await createServerSupabaseClient();
41
+ const { error } = await supabase
42
+ .from("projects")
43
+ .update({ name })
44
+ .eq("id", id);
45
+ if (error) throw new UserError("Couldn't rename this project"); // shown as written
46
+ return ok({ id });
47
+ } catch (e) {
48
+ return err(toUserMessage(e, { fallback: "Couldn't rename this project" })); // never e.message
49
+ }
50
+ }
51
+ ```
52
+
53
+ ```ts
54
+ // Same guarantees, less boilerplate
55
+ export const renameProject = createSafeAction(
56
+ async (input: { id: string; name: string }) => updateProject(input), // may throw; may return a Result or a plain value
57
+ { schema: RenameSchema, errorCode: "RENAME_FAILED" },
58
+ );
59
+ ```
60
+
61
+ ```tsx
62
+ // Client: branch explicitly, or let toast.fromResult handle feedback
63
+ const result = await renameProjectAction(id, name);
64
+ if (isErr(result)) return; // result.error is user-safe text
65
+ toast.fromResult(result, { success: "Project renamed successfully!" }); // see notification.md
66
+ ```
67
+
68
+ ## 4. API
69
+
70
+ | Export | Signature | Description |
71
+ | :------------------------------------------------------------ | :------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------- |
72
+ | `Result<T, E = string>`, `SuccessResult<T>`, `ErrorResult<E>` | types | `readonly` fields; both carry an optional `code`. |
73
+ | `ok(data, code?)` | `→ SuccessResult<T>` | `code` is included only when given. |
74
+ | `err(error, code?)` | `→ ErrorResult<E>` | |
75
+ | `isResult(value)` | `(unknown) → value is Result` | True for objects with a boolean `success` **and** a matching `data` (success) / `error` (failure) key. Used by `toast.promise` and `toast.fromResult`. |
76
+ | `isOk(r)`, `isErr(r)` | type guards | |
77
+ | `unwrap(r)` | `→ T` | Returns `data`, or **throws** (the error itself if it is an `Error`, otherwise `new Error(String(error))`). Trusted internal code only. |
78
+ | `unwrapOr(r, fallback)` | `→ T` | `data` or the fallback. |
79
+ | `map(r, fn)`, `mapErr(r, fn)` | `→ Result` | Transform one branch; `code` is preserved. |
80
+ | `match(r, { ok, err })` | `→ R` | Branch handling returning a value. |
81
+ | `tryCatch(promiseOrFn, mapError?)` | `→ Promise<Result<T, E>>` | Awaits a promise (or an async function); thrown/rejected → `err(...)`. |
82
+ | `createSafeAction(handler, options?)` | `→ (...args) => Promise<Result<TOutput, E>>` | See below. |
83
+
84
+ ### 4.1 How thrown errors become messages
85
+
86
+ `tryCatch` and `createSafeAction` convert a caught error with `mapError(error)` if you pass one, otherwise `toUserMessage(error)`:
87
+
88
+ - a `UserError`, a string, or a 4xx payload from our own API is used **as written**;
89
+ - anything else maps to a fixed sentence from `USER_MESSAGES` (`generic`, `network`, `timeout`, `unauthorized`, `forbidden`, `notFound`, `rateLimited`, `server`) so database/SDK wording never reaches the UI;
90
+ - unless it is a `UserError`, the original error is **reported** via `report("Result", error)` (see [error-boundary.md](./error-boundary.md#7-user-facing-messages-and-report)).
91
+
92
+ ### 4.2 `createSafeAction(handler, options)`
93
+
94
+ | Option | Meaning |
95
+ | :------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
96
+ | `schema` | Anything with `safeParse(input)` (e.g. Zod). Applied to the **first argument**; on success the parsed value replaces it. Failure → `err(firstIssueMessage \| message \| "Invalid input", errorCode ?? "VALIDATION_ERROR")`. |
97
+ | `validate(...args)` | Extra synchronous check on the (parsed) args. Return an `ErrorResult` to fail with it, `false` → `"Validation failed"`, a non-empty string → that message, anything else passes. |
98
+ | `mapError(error)` | Maps both validation messages and thrown errors to your error type `E`. |
99
+ | `errorCode` | `code` set on failures (validation default: `"VALIDATION_ERROR"`). |
100
+
101
+ The handler may return a `Result` (returned as is), or a plain value (wrapped in `ok(value)`), or throw (→ `err`). The wrapper itself never throws.
102
+
103
+ ## 5. Where Results flow
104
+
105
+ | Consumer | Behaviour |
106
+ | :----------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
107
+ | `toast.fromResult` / `toast.promise` | Toasts `success(data)` or `error` (falling back to `toUserMessage`). |
108
+ | Notification module | Shows `APP_ERROR` / `STATE_CHANGE` events that have `notify: true`. |
109
+ | Dock | Shows **every** `APP_ERROR` as its error status card (regardless of `notify`). |
110
+
111
+ So a failed `useServerAction` produces a dock error card, plus a toast if you passed `toast: true`.
112
+
113
+ ## 6. Recipes and gotchas
114
+
115
+ | I want to… | Do this |
116
+ | :--------------------------- | :---------------------------------------------------------------------------------------------------- |
117
+ | Return a validation error | `return err("Name is required", "VALIDATION")`. |
118
+ | Show server text to the user | Throw `new UserError("…")` (or return `err("…")`) with text you wrote; never forward `error.message`. |
119
+ | Custom error shape | `Result<T, MyError>` and pass `mapError` to `createSafeAction` / `tryCatch`. |
120
+ | Narrow in TypeScript | `if (r.success) r.data else r.error`, or `isOk` / `isErr`. |
121
+ | Chain transformations | `map(r, fn)` / `mapErr(r, fn)`. |
122
+
123
+ - A Server Action must return plain serializable data: do not put `Error` instances, class instances or functions in a `Result` that crosses the network.
124
+ - `unwrap` throws: never use it in a `"use server"` function's return path.
125
+ - `createSafeAction`'s `schema` validates only the **first** argument.
126
+ - `isResult` requires the matching data/error key: `{ success: true }` without `data` is **not** a Result (use `ok(undefined)`).
127
+
128
+ ## 7. File map
129
+
130
+ A single file, `src/core/result.ts`. It depends only on `./utils/user-message` and `./utils/report`, so it is safe on both server and client (and is one of the server-safe core entries that must not import React or `next/*`).
131
+
132
+ ## 8. Dependencies
133
+
134
+ - **Uses:** `@omerdlw/base-framework/utils` (`UserError`, `toUserMessage`, `report`) only.
135
+ - **Used by:** every `server/actions.ts` in `src/features/**`, `@omerdlw/base-framework/hooks` (`useServerAction`, `useAsyncAction`), `@omerdlw/base-framework/modules/notification` (`isResult` for `toast.fromResult` / `promise`), and route-level helpers that return `Result`.
@@ -0,0 +1,160 @@
1
+ # Testing Guide
2
+
3
+ > **Read this first if you need to:** run package tests, understand the test harness (`happy-dom`, `renderHook`, `Themed`), write tests for new modules, or test downstream components that consume `@omerdlw/base-framework`.
4
+ >
5
+ > **Stack:** Node's built-in test runner (`node:test`) + `node:assert/strict`, TypeScript executed directly through a resolver hook (`register.mjs`), `happy-dom` for React components and hooks, zero external framework overhead.
6
+
7
+ ---
8
+
9
+ ## 1. Running Tests
10
+
11
+ | Command | Purpose |
12
+ | :--- | :--- |
13
+ | `npm test` | Runs the full 520+ test suite (`tests/**/*.test.ts`) in ~1 second. |
14
+ | `npm run test:coverage` | Runs the suite with complete line, branch, and function coverage reporting for `src/**`. |
15
+ | `npm run type-check` | Full TypeScript compiler validation (`tsc --noEmit`). |
16
+ | `npm run check:architecture` | Static AST validation checking for 0 circular dependencies and verified `uses` peer declarations. |
17
+ | `node --import ./tests/support/register.mjs --test tests/core/kernel.test.ts` | Run a single test file. |
18
+ | `node --import ./tests/support/register.mjs --test --test-name-pattern="surface" tests/modules/dock.test.ts` | Run tests matching a specific pattern. |
19
+
20
+ **Pre-flight Verification:**
21
+ `npm run type-check && npm run lint && npm run check:architecture && npm test && npm run build`
22
+
23
+ ---
24
+
25
+ ## 2. Test Suite Layout
26
+
27
+ Tests mirror the package's architecture, **one TypeScript test file per unit**:
28
+
29
+ ```
30
+ tests/
31
+ architecture.test.ts Layer boundaries, module contracts, barrel exports, cyclical imports
32
+ core/ Microkernel, error handling, hooks, atoms, tokens, utils, events, result, theme
33
+ modules/ ambient, background, context-menu, controls, dock, loading, media, modal, notification
34
+ support/ Test harness: happy-dom, render, themed wrapper, stubs (§3)
35
+ tsconfig.json TypeScript compilation rules for tests
36
+ ```
37
+
38
+ ---
39
+
40
+ ## 3. Test Harness (`tests/support`)
41
+
42
+ | File | Provides |
43
+ | :--- | :--- |
44
+ | `register.mjs` | Node module loader hook: resolves `@omerdlw/base-framework` imports on the fly and transpiles TypeScript. |
45
+ | `dom.ts` | Configures a **`happy-dom`** browser environment (`window`, `document`, `matchMedia`, observers) for React component and hook testing. |
46
+ | `render.ts` | React 19 testing primitives: `render(element)`, `renderHook(hook, { wrapper })`, `flush()`. Automatically unmounts trees after every test to prevent leaks. |
47
+ | `themes.ts` | `Themed` (`ThemeProvider` loaded with test themes) and `withThemes()`. Required when testing any module view or atom that consumes theme slots. |
48
+ | `registry.ts` | Test registry with `builtInModules` for microkernel and module integration testing. |
49
+
50
+ ---
51
+
52
+ ## 4. Testing Patterns
53
+
54
+ ### 4.1 Testing Pure Utils & Math
55
+
56
+ Import the utility directly and assert deterministic behavior:
57
+
58
+ ```ts
59
+ import { describe, test } from "node:test";
60
+ import assert from "node:assert/strict";
61
+ import { clamp, toFiniteNumber } from "@omerdlw/base-framework/utils";
62
+
63
+ describe("math utils", () => {
64
+ test("clamp restricts numbers within min and max boundaries", () => {
65
+ assert.equal(clamp(5, 0, 10), 5);
66
+ assert.equal(clamp(-5, 0, 10), 0);
67
+ assert.equal(clamp(15, 0, 10), 10);
68
+ });
69
+
70
+ test("toFiniteNumber handles non-numeric fallbacks", () => {
71
+ assert.equal(toFiniteNumber("123"), 123);
72
+ assert.equal(toFiniteNumber(NaN, 0), 0);
73
+ });
74
+ });
75
+ ```
76
+
77
+ ### 4.2 Testing Hooks & Subscriptions
78
+
79
+ Render hooks inside `Themed` or `CoreProvider` using `renderHook`:
80
+
81
+ ```ts
82
+ import { describe, test } from "node:test";
83
+ import assert from "node:assert/strict";
84
+ import { renderHook } from "../support/render.ts";
85
+ import { useGlobalEvent } from "@omerdlw/base-framework/hooks";
86
+ import { globalEvents, EVENT_TYPES } from "@omerdlw/base-framework/events";
87
+
88
+ describe("useGlobalEvent", () => {
89
+ test("receives published event payloads", () => {
90
+ let received = null;
91
+ const { unmount } = renderHook(() => {
92
+ useGlobalEvent(EVENT_TYPES.STATE_CHANGE, (payload) => {
93
+ received = payload;
94
+ });
95
+ });
96
+
97
+ globalEvents.publish(EVENT_TYPES.STATE_CHANGE, { key: "auth", value: true });
98
+ assert.deepEqual(received, { key: "auth", value: true });
99
+
100
+ unmount();
101
+ });
102
+ });
103
+ ```
104
+
105
+ ### 4.3 Testing Diagnostics & Error Reports
106
+
107
+ Install an ephemeral report sink with `setReportSink` and release it in cleanup:
108
+
109
+ ```ts
110
+ import { describe, test } from "node:test";
111
+ import assert from "node:assert/strict";
112
+ import { report, setReportSink } from "@omerdlw/base-framework/utils";
113
+
114
+ describe("error reporter", () => {
115
+ test("routes diagnostic messages to the configured sink", () => {
116
+ const logs: any[] = [];
117
+ const release = setReportSink((scope, err, level) => {
118
+ logs.push({ scope, err, level });
119
+ });
120
+
121
+ report("dock", new Error("Invalid surface state"), "warning");
122
+ release();
123
+
124
+ assert.equal(logs.length, 1);
125
+ assert.equal(logs[0].scope, "dock");
126
+ assert.equal(logs[0].level, "warning");
127
+ });
128
+ });
129
+ ```
130
+
131
+ ---
132
+
133
+ ## 5. Testing Downstream Applications
134
+
135
+ When testing Next.js components or pages that consume `@omerdlw/base-framework`:
136
+
137
+ 1. **Wrapping with `CoreProvider`:** Provide a test wrapper with the required modules:
138
+ ```tsx
139
+ import { CoreProvider } from "@omerdlw/base-framework/provider";
140
+ import { dockModule } from "@omerdlw/base-framework/modules/dock";
141
+ import { notificationModule } from "@omerdlw/base-framework/modules/notification";
142
+
143
+ export function TestProviders({ children }: { children: React.ReactNode }) {
144
+ return <CoreProvider modules={[dockModule, notificationModule]}>{children}</CoreProvider>;
145
+ }
146
+ ```
147
+ 2. **Testing Declarative Routes (`usePage`):** Since `usePage()` accepts a static or reactive configuration object, verify that components invoke `usePage()` with the expected metadata, loading flags, or dock card configs.
148
+ 3. **Asserting Server Action Results:** Verify that Server Actions return `Result<T, E>` (`ok()` or `err()`) rather than throwing raw unhandled exceptions.
149
+
150
+ ---
151
+
152
+ ## 6. What the Suite Protects
153
+
154
+ | Layer | Enforced Invariants |
155
+ | :--- | :--- |
156
+ | **Architecture** | 0 circular dependencies, downward-only imports, clean barrel exports |
157
+ | **Microkernel** | Registry ordering, topological provider nesting, `usePage` atomic reconciliation |
158
+ | **Modules** | Dock flows/surfaces/guards/status, modal stack order, context-menu scoring, controls rails, notification queues, media sessions |
159
+ | **Atoms** | Accessibility contracts (ARIA), keyboard navigation, deterministic `cn()` class merging |
160
+ | **Tokens & Theme** | GPU-accelerated motion presets, OKLCH token boundaries, Z-index hierarchy |
@@ -0,0 +1,185 @@
1
+ # Theming System Guide — `@omerdlw/base-framework/theme`
2
+
3
+ > **Read this first if you need to:** customize the visual design of any first-party module (`dock`, `modal`, `notification`, etc.), supply custom Tailwind styles, or understand the theme slot contract.
4
+
5
+ ---
6
+
7
+ ## 1. Philosophy: Logic Decoupled from Aesthetics
8
+
9
+ `@omerdlw/base-framework` enforces a strict rule: **Modules own interaction mechanics, accessibility, and state machines; consumer applications own visual design.**
10
+
11
+ Modules ship with **zero hardcoded visual Tailwind colors or aesthetic choices**. Instead, each module declares a typed **Theme Spec** defining required "slots" (e.g. `card`, `backdrop`, `header`, `item`).
12
+
13
+ If a required theme is not provided to `<ThemeProvider>`, `useTheme()` throws an informative error at mount time:
14
+ ```
15
+ Theme "dock" is missing. Add its theme configuration to your ThemeProvider.
16
+ ```
17
+
18
+ ---
19
+
20
+ ## 2. The Theme API
21
+
22
+ Import the theming primitives from `@omerdlw/base-framework/theme`:
23
+
24
+ ```ts
25
+ import {
26
+ defineThemeSpec,
27
+ defineTheme,
28
+ ThemeProvider,
29
+ useTheme,
30
+ type ThemeSpec,
31
+ type ThemeConfig,
32
+ type ThemeEntry,
33
+ } from "@omerdlw/base-framework/theme";
34
+ ```
35
+
36
+ ### 2.1 `defineThemeSpec<Slots>(id)`
37
+ Used by module authors to define the contract:
38
+ ```ts
39
+ export type DockThemeSlot = "card" | "header" | "title" | "description" | "icon" | "surface";
40
+ export const dockTheme = defineThemeSpec<DockThemeSlot>("dock");
41
+ ```
42
+
43
+ ### 2.2 `defineTheme(spec, { slots, styles? })`
44
+ Used by application developers to implement the styling contract. TypeScript enforces that **every required slot** is provided:
45
+ ```ts
46
+ export const dockThemeConfig = defineTheme(dockTheme, {
47
+ slots: {
48
+ card: "rounded-[28px] bg-neutral-900/80 backdrop-blur-xl border border-white/10 shadow-2xl p-4",
49
+ header: "flex items-center gap-3",
50
+ title: "text-sm font-medium text-white",
51
+ description: "text-xs text-white/50",
52
+ icon: "text-white/80",
53
+ surface: "rounded-3xl bg-neutral-900 border border-white/10 p-6",
54
+ },
55
+ styles: {
56
+ // Optional inline CSS styles (e.g. tokenized Z-Index)
57
+ card: { zIndex: 100 },
58
+ },
59
+ });
60
+ ```
61
+
62
+ ### 2.3 `ThemeProvider({ themes, children })`
63
+ Wraps your application or `CoreProvider` to supply the theme map:
64
+ ```tsx
65
+ <ThemeProvider themes={[dockThemeConfig, modalThemeConfig, notificationThemeConfig]}>
66
+ <CoreProvider modules={modules}>
67
+ {children}
68
+ </CoreProvider>
69
+ </ThemeProvider>
70
+ ```
71
+
72
+ ### 2.4 `useTheme(spec)`
73
+ Consumed internally by module overlays to read the active slots:
74
+ ```tsx
75
+ const { slots, styles } = useTheme(dockTheme);
76
+ return <div className={slots.card} style={styles.card} />;
77
+ ```
78
+
79
+ ---
80
+
81
+ ## 3. Module Theme Slot Reference
82
+
83
+ Below is the complete reference of theme specs exported by the 9 first-party modules:
84
+
85
+ | Module | Spec Export | Import Path | Primary Slots |
86
+ | :--- | :--- | :--- | :--- |
87
+ | **Dock** | `dockTheme` | `@omerdlw/base-framework/modules/dock` | `card`, `header`, `title`, `description`, `icon`, `surface`, `status` |
88
+ | **Modal** | `modalTheme` | `@omerdlw/base-framework/modules/modal` | `backdrop`, `dialog`, `header`, `title`, `body`, `footer`, `close` |
89
+ | **Notification** | `notificationTheme` | `@omerdlw/base-framework/modules/notification` | `viewport`, `toast`, `title`, `description`, `icon`, `action`, `close` |
90
+ | **Ambient** | `ambientTheme` | `@omerdlw/base-framework/modules/ambient` | `container`, `canvas` |
91
+ | **Background** | `backgroundTheme` | `@omerdlw/base-framework/modules/background` | `layer`, `overlay`, `fades` |
92
+ | **Controls** | `controlsTheme` | `@omerdlw/base-framework/modules/controls` | `rail`, `button`, `icon` |
93
+ | **Loading** | `loadingTheme` | `@omerdlw/base-framework/modules/loading` | `overlay`, `spinner`, `message` |
94
+ | **Context Menu** | `contextMenuTheme` | `@omerdlw/base-framework/modules/context-menu` | `menu`, `item`, `separator`, `label`, `shortcut` |
95
+ | **Error Boundary** | `errorTheme` | `@omerdlw/base-framework/error` | `boundary`, `card`, `title`, `message`, `retryButton` |
96
+
97
+ ---
98
+
99
+ ## 4. Complete Starter Theme Configuration
100
+
101
+ Create a theme definitions file in your project (e.g. `src/config/themes.ts`):
102
+
103
+ ```ts
104
+ import { defineTheme } from "@omerdlw/base-framework/theme";
105
+ import { dockTheme } from "@omerdlw/base-framework/modules/dock";
106
+ import { modalTheme } from "@omerdlw/base-framework/modules/modal";
107
+ import { notificationTheme } from "@omerdlw/base-framework/modules/notification";
108
+ import { loadingTheme } from "@omerdlw/base-framework/modules/loading";
109
+ import { errorTheme } from "@omerdlw/base-framework/error";
110
+
111
+ export const appThemes = [
112
+ defineTheme(dockTheme, {
113
+ slots: {
114
+ card: "rounded-[24px] bg-neutral-900/90 backdrop-blur-2xl border border-white/10 shadow-2xl p-4 text-white",
115
+ header: "flex items-center gap-3",
116
+ title: "text-sm font-semibold tracking-tight",
117
+ description: "text-xs text-white/50",
118
+ icon: "text-white/80",
119
+ surface: "rounded-3xl bg-neutral-900/95 border border-white/10 p-6 backdrop-blur-3xl",
120
+ status: "rounded-xl bg-white/5 px-3 py-1.5 text-xs text-white/70",
121
+ },
122
+ }),
123
+
124
+ defineTheme(modalTheme, {
125
+ slots: {
126
+ backdrop: "fixed inset-0 bg-black/60 backdrop-blur-sm",
127
+ dialog: "rounded-2xl bg-neutral-900 border border-white/10 shadow-2xl p-6 text-white max-w-lg w-full",
128
+ header: "mb-4",
129
+ title: "text-lg font-bold",
130
+ body: "text-sm text-white/80",
131
+ footer: "mt-6 flex justify-end gap-3",
132
+ close: "size-8 center rounded-full hover:bg-white/10 text-white/60 hover:text-white",
133
+ },
134
+ }),
135
+
136
+ defineTheme(notificationTheme, {
137
+ slots: {
138
+ viewport: "fixed bottom-6 right-6 flex flex-col gap-2 z-50 pointer-events-none",
139
+ toast: "pointer-events-auto flex items-center gap-3 rounded-xl bg-neutral-900 border border-white/10 shadow-xl px-4 py-3 text-sm text-white",
140
+ title: "font-medium text-white",
141
+ description: "text-xs text-white/60",
142
+ icon: "shrink-0",
143
+ action: "text-xs font-semibold text-sky-400 hover:text-sky-300",
144
+ close: "text-white/40 hover:text-white",
145
+ },
146
+ }),
147
+
148
+ defineTheme(loadingTheme, {
149
+ slots: {
150
+ overlay: "center fixed inset-0 h-screen w-screen bg-black/40 backdrop-blur-xs",
151
+ spinner: "animate-spin text-white/80",
152
+ message: "text-xs font-medium text-white/60 mt-3",
153
+ },
154
+ }),
155
+
156
+ defineTheme(errorTheme, {
157
+ slots: {
158
+ boundary: "center min-h-[300px] w-full p-6",
159
+ card: "rounded-2xl bg-red-950/20 border border-red-500/20 p-6 max-w-md text-center",
160
+ title: "text-base font-semibold text-red-400",
161
+ message: "text-xs text-red-200/70 mt-2",
162
+ retryButton: "mt-4 inline-flex h-8 items-center px-3 rounded-lg bg-red-500/20 text-red-300 text-xs font-medium hover:bg-red-500/30",
163
+ },
164
+ }),
165
+ ];
166
+ ```
167
+
168
+ Then in `src/app/providers.tsx`:
169
+
170
+ ```tsx
171
+ "use client";
172
+
173
+ import { ThemeProvider } from "@omerdlw/base-framework/theme";
174
+ import { CoreProvider } from "@omerdlw/base-framework/provider";
175
+ import { appThemes } from "@/config/themes";
176
+ import { modules } from "@/config/modules";
177
+
178
+ export function Providers({ children }: { children: React.ReactNode }) {
179
+ return (
180
+ <ThemeProvider themes={appThemes}>
181
+ <CoreProvider modules={modules}>{children}</CoreProvider>
182
+ </ThemeProvider>
183
+ );
184
+ }
185
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omerdlw/base-framework",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Microkernel engine and first-party declarative UI modules for app-like Next.js products.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -74,6 +74,8 @@
74
74
  },
75
75
  "files": [
76
76
  "dist",
77
+ "docs",
78
+ "templates",
77
79
  "README.md",
78
80
  "LICENSE"
79
81
  ],
@@ -0,0 +1,165 @@
1
+ # Base Framework — AI Agent & Developer Mastery Guide
2
+
3
+ > **This project is powered by `@omerdlw/base-framework`.**
4
+ > Read this file first before reading or modifying any code. It contains the exact architectural boundaries, rules, patterns, and code recipes you must follow without exception.
5
+
6
+ ---
7
+
8
+ ## 1. Quick Tech Stack & Foundations
9
+
10
+ - **Engine:** Next.js 16 (App Router), React 19
11
+ - **Core Framework:** `@omerdlw/base-framework` (Microkernel & Declarative UI Modules)
12
+ - **Styling:** Tailwind CSS v4 (`@theme`, OKLCH semantic color tokens, `.center`, `.skeleton-block`)
13
+ - **Motion:** Motion (v13) with hardware GPU acceleration (`translate3d`, `scale`)
14
+ - **Icons:** `@iconify-icon/react` via `<Icon icon="solar:..." />`
15
+
16
+ ---
17
+
18
+ ## 2. The 4-Layer Architectural Hierarchy
19
+
20
+ Code in this project strictly follows a four-layer dependency hierarchy:
21
+
22
+ ```
23
+ Layer 4: src/app (Routing, Next.js page composition & layout orchestration)
24
+ ↓ imports
25
+ Layer 3: src/features (Domain capabilities: auth, account, social, checkout)
26
+ ↓ imports
27
+ Layer 2: src/infrastructure (Adapters: database, HTTP client, proxy, rate limiting)
28
+ ↓ imports
29
+ Layer 1: @omerdlw/base-framework (Microkernel, first-party modules, atoms, tokens, result)
30
+ ```
31
+
32
+ ### Strict Architectural Boundaries:
33
+ - `src/features/*` must **never** import from `src/app/*`.
34
+ - `src/infrastructure/*` must **never** import from `src/features/*` or `src/app/*`.
35
+ - Every feature in `src/features/` **must** have an `index.ts` barrel export.
36
+ - Server database and adapter files **must** begin with `import "server-only";`.
37
+ - Server Actions **must** begin with `"use server";` and return `Result<T, E>` (`ok()` or `err()`).
38
+
39
+ ---
40
+
41
+ ## 3. The 5 Golden Rules of Base Framework
42
+
43
+ ### Rule 1: Declarative Chrome (`usePage`)
44
+ **Never** build custom top navigation bars, ad-hoc sticky headers, or scattered floating buttons.
45
+ All route-level visual state (title, dock card, loading state, background, modals) **must** be declared using `usePage()` from `@omerdlw/base-framework/kernel`:
46
+
47
+ ```tsx
48
+ "use client";
49
+
50
+ import { usePage } from "@omerdlw/base-framework/kernel";
51
+
52
+ export default function MyPage() {
53
+ const page = usePage({
54
+ title: "Dashboard",
55
+ dock: {
56
+ description: "Project metrics and activity",
57
+ icon: "solar:widget-bold",
58
+ },
59
+ loading: false,
60
+ });
61
+
62
+ return <main>...</main>;
63
+ }
64
+ ```
65
+
66
+ ### Rule 2: Result Pattern for All Async Operations
67
+ Never return raw unchecked errors or throw unhandled exceptions from server actions or infrastructure operations. Always wrap return values with `Result<T, E>` from `@omerdlw/base-framework/result`:
68
+
69
+ ```tsx
70
+ "use server";
71
+
72
+ import "server-only";
73
+ import { ok, err, type Result } from "@omerdlw/base-framework/result";
74
+
75
+ export async function updateProfile(username: string): Promise<Result<{ id: string }, string>> {
76
+ if (!username) return err("Username is required");
77
+ // Save to DB...
78
+ return ok({ id: "user_123" });
79
+ }
80
+ ```
81
+
82
+ ### Rule 3: Bridge Server Actions to Feedback with `toast.fromResult`
83
+ When consuming Server Actions in the UI, do not write manual `try/catch` and `if (res.error)` blocks. Use `toast.fromResult()`:
84
+
85
+ ```tsx
86
+ "use client";
87
+
88
+ import { useToast } from "@omerdlw/base-framework/modules/notification";
89
+ import { updateProfile } from "@/features/account/actions";
90
+
91
+ export function ProfileForm() {
92
+ const { toast } = useToast();
93
+
94
+ const handleSubmit = async (name: string) => {
95
+ const result = await updateProfile(name);
96
+ toast.fromResult(result, {
97
+ success: "Profile updated successfully!",
98
+ });
99
+ };
100
+
101
+ return <form>...</form>;
102
+ }
103
+ ```
104
+
105
+ ### Rule 4: Subpath Imports Only
106
+ Always import from the exact subpaths exposed by `@omerdlw/base-framework`:
107
+
108
+ | What you need | Where to import it |
109
+ | :--- | :--- |
110
+ | `usePage`, `defineModule` | `@omerdlw/base-framework/kernel` |
111
+ | `CoreProvider` | `@omerdlw/base-framework/provider` |
112
+ | `ok`, `err`, `isResult`, `type Result` | `@omerdlw/base-framework/result` |
113
+ | `globalEvents`, `EVENT_TYPES` | `@omerdlw/base-framework/events` |
114
+ | `useToast` | `@omerdlw/base-framework/modules/notification` |
115
+ | `useDockActions`, `useDockStatus` | `@omerdlw/base-framework/modules/dock` |
116
+ | `useModal`, `useModalContext` | `@omerdlw/base-framework/modules/modal` |
117
+ | `useAmbientTheme` | `@omerdlw/base-framework/modules/ambient` |
118
+ | `cn`, `report`, `createStore` | `@omerdlw/base-framework/utils` |
119
+ | `useClickOutside`, `useGlobalEvent` | `@omerdlw/base-framework/hooks` |
120
+ | `Button`, `Icon`, `Spinner`, `Tooltip` | `@omerdlw/base-framework/atoms` |
121
+
122
+ ### Rule 5: Modals and Surfaces Must Be Declared or Scoped
123
+ Do not create floating unmanaged `fixed z-50` dialog div wrappers.
124
+ - For sheets/drawers sliding up from the dock: use `useDockActions().openSurface(...)`.
125
+ - For standard dialogs: register them in `usePage({ modal: { ... } })` or trigger with `useModal().openModal(...)`.
126
+
127
+ ---
128
+
129
+ ## 4. Standard Next.js Root Layout Recipe
130
+
131
+ In `src/app/providers.tsx`:
132
+
133
+ ```tsx
134
+ "use client";
135
+
136
+ import { CoreProvider } from "@omerdlw/base-framework/provider";
137
+ import { dockModule } from "@omerdlw/base-framework/modules/dock";
138
+ import { modalModule } from "@omerdlw/base-framework/modules/modal";
139
+ import { notificationModule } from "@omerdlw/base-framework/modules/notification";
140
+ import { ambientModule } from "@omerdlw/base-framework/modules/ambient";
141
+ import { backgroundModule } from "@omerdlw/base-framework/modules/background";
142
+ import { controlsModule } from "@omerdlw/base-framework/modules/controls";
143
+ import { loadingModule } from "@omerdlw/base-framework/modules/loading";
144
+
145
+ const modules = [
146
+ dockModule,
147
+ modalModule,
148
+ notificationModule,
149
+ ambientModule,
150
+ backgroundModule,
151
+ controlsModule,
152
+ loadingModule,
153
+ ];
154
+
155
+ export function Providers({ children }: { children: React.ReactNode }) {
156
+ return <CoreProvider modules={modules}>{children}</CoreProvider>;
157
+ }
158
+ ```
159
+
160
+ In `src/app/globals.css`:
161
+
162
+ ```css
163
+ @import "tailwindcss";
164
+ @source "../node_modules/@omerdlw/base-framework";
165
+ ```