@elevasis/sdk 1.44.2 → 1.45.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/dist/cli.cjs +1001 -652
- package/dist/index.d.ts +1045 -509
- package/dist/index.js +748 -690
- package/dist/node/index.d.ts +105 -97
- package/dist/test-utils/index.d.ts +42 -28
- package/dist/test-utils/index.js +549 -732
- package/dist/worker/index.d.ts +12112 -0
- package/dist/worker/index.js +211 -186
- package/package.json +6 -9
- package/reference/_navigation.md +151 -21
- package/reference/_reference-manifest.json +186 -4
- package/reference/claude-config.md +8 -0
- package/reference/core/index.mdx +3 -3
- package/reference/examples/organization-model.ts +117 -111
- package/reference/index.mdx +4 -4
- package/reference/rules/active-change-index.md +40 -54
- package/reference/rules/agent-runtime.md +81 -0
- package/reference/rules/agent-start-here.md +71 -163
- package/reference/rules/deployment.md +33 -10
- package/reference/rules/error-handling.md +26 -0
- package/reference/rules/execution.md +13 -0
- package/reference/rules/frontend.md +10 -3
- package/reference/rules/observability.md +9 -1
- package/reference/rules/operations.md +26 -17
- package/reference/rules/organization-model.md +74 -88
- package/reference/rules/organization-os.md +71 -88
- package/reference/rules/package-taxonomy.md +11 -2
- package/reference/rules/platform.md +13 -7
- package/reference/rules/shared-types.md +15 -0
- package/reference/rules/task-tracking.md +30 -5
- package/reference/rules/ui.md +145 -3
- package/reference/rules/vibe-intents.md +271 -0
- package/reference/rules/vibe.md +17 -243
- package/reference/scaffold/core/organization-graph.mdx +111 -97
- package/reference/scaffold/core/organization-model.mdx +234 -214
- package/reference/scaffold/operations/propagation-pipeline.md +1 -1
- package/reference/scaffold/operations/scaffold-maintenance.md +19 -18
- package/reference/scaffold/operations/workflow-recipes.md +71 -19
- package/reference/scaffold/recipes/add-a-feature.md +156 -146
- package/reference/scaffold/recipes/add-a-resource.md +123 -117
- package/reference/scaffold/recipes/customize-crm-actions.md +25 -10
- package/reference/scaffold/recipes/customize-knowledge-browser.md +52 -117
- package/reference/scaffold/recipes/customize-organization-model.md +161 -149
- package/reference/scaffold/recipes/extend-a-base-entity.md +156 -140
- package/reference/scaffold/recipes/extend-crm.md +16 -11
- package/reference/scaffold/recipes/extend-lead-gen.md +25 -7
- package/reference/scaffold/recipes/gate-by-feature-or-admin.md +160 -118
- package/reference/scaffold/recipes/index.md +2 -2
- package/reference/scaffold/recipes/query-the-knowledge-graph.md +23 -23
- package/reference/scaffold/reference/contracts.md +12 -1
- package/reference/scaffold/reference/glossary.md +3 -3
- package/reference/scaffold/reference/system-interface-capabilities.md +5 -4
- package/reference/scaffold/ui/composition-extensibility.mdx +271 -232
- package/reference/scaffold/ui/feature-flags-and-gating.md +14 -6
- package/reference/scaffold/ui/feature-shell.mdx +279 -62
- package/reference/scaffold/ui/recipes.md +229 -197
- package/reference/sdk/cli-management.mdx +77 -29
- package/reference/sdk/concepts.mdx +2 -0
- package/reference/sdk/define-builders.mdx +76 -0
- package/reference/sdk/deployment/command-center.mdx +6 -2
- package/reference/sdk/deployment/execution-reference.mdx +64 -186
- package/reference/sdk/deployment/index.mdx +2 -0
- package/reference/sdk/exports.mdx +4 -4
- package/reference/sdk/framework/agent.mdx +49 -119
- package/reference/sdk/framework/index.mdx +46 -65
- package/reference/sdk/framework/project-structure.mdx +150 -205
- package/reference/sdk/framework/tutorial-system.mdx +2 -2
- package/reference/sdk/human-in-the-loop.mdx +152 -0
- package/reference/sdk/index.mdx +6 -7
- package/reference/sdk/platform-tools/index.mdx +12 -0
- package/reference/sdk/platform-tools/type-safety.mdx +4 -0
- package/reference/sdk/project-deployment-spec.mdx +131 -0
- package/reference/sdk/resources/index.mdx +23 -7
- package/reference/sdk/resources/patterns.mdx +54 -24
- package/reference/sdk/resources/types.mdx +7 -4
- package/reference/sdk/templates/data-enrichment.mdx +7 -3
- package/reference/sdk/templates/email-sender.mdx +139 -135
- package/reference/sdk/templates/lead-scorer.mdx +5 -1
- package/reference/sdk/templates/pdf-generator.mdx +155 -151
- package/reference/sdk/templates/recurring-job.mdx +195 -189
- package/reference/sdk/templates/text-classifier.mdx +4 -0
- package/reference/sdk/templates/web-scraper.mdx +139 -135
- package/reference/spine/spine-primer.md +135 -96
- package/reference/ui/index.mdx +14 -7
- package/dist/types/worker/adapters/anymailfinder.d.ts +0 -14
- package/dist/types/worker/adapters/apify.d.ts +0 -14
- package/dist/types/worker/adapters/approval.d.ts +0 -23
- package/dist/types/worker/adapters/attio.d.ts +0 -22
- package/dist/types/worker/adapters/clickup.d.ts +0 -22
- package/dist/types/worker/adapters/create-adapter.d.ts +0 -41
- package/dist/types/worker/adapters/crm.d.ts +0 -20
- package/dist/types/worker/adapters/dropbox.d.ts +0 -14
- package/dist/types/worker/adapters/email.d.ts +0 -25
- package/dist/types/worker/adapters/execution.d.ts +0 -22
- package/dist/types/worker/adapters/gmail.d.ts +0 -14
- package/dist/types/worker/adapters/google-sheets.d.ts +0 -14
- package/dist/types/worker/adapters/index.d.ts +0 -33
- package/dist/types/worker/adapters/instantly.d.ts +0 -14
- package/dist/types/worker/adapters/lead.d.ts +0 -28
- package/dist/types/worker/adapters/list.d.ts +0 -9
- package/dist/types/worker/adapters/llm.d.ts +0 -45
- package/dist/types/worker/adapters/millionverifier.d.ts +0 -14
- package/dist/types/worker/adapters/notification.d.ts +0 -28
- package/dist/types/worker/adapters/pdf.d.ts +0 -22
- package/dist/types/worker/adapters/projects.d.ts +0 -20
- package/dist/types/worker/adapters/resend.d.ts +0 -14
- package/dist/types/worker/adapters/scheduler.d.ts +0 -25
- package/dist/types/worker/adapters/signature-api.d.ts +0 -14
- package/dist/types/worker/adapters/storage.d.ts +0 -33
- package/dist/types/worker/adapters/stripe.d.ts +0 -14
- package/dist/types/worker/adapters/tomba.d.ts +0 -14
- package/dist/types/worker/index.d.ts +0 -60
- package/dist/types/worker/platform.d.ts +0 -90
- package/dist/types/worker/utils.d.ts +0 -9
- package/reference/claude-config/Overview.md +0 -230
- package/reference/claude-config/hooks/post-edit-validate.mjs +0 -98
- package/reference/claude-config/hooks/scaffold-registry-reminder.mjs +0 -187
- package/reference/claude-config/hooks/tool-failure-recovery.mjs +0 -73
- package/reference/claude-config/registries/graph-skills.json +0 -4
- package/reference/claude-config/registries/knowledge-flags.json +0 -154
- package/reference/claude-config/registries/skill-coverage.json +0 -20
- package/reference/claude-config/rules/active-change-index.md +0 -22
- package/reference/claude-config/rules/agent-start-here.md +0 -22
- package/reference/claude-config/rules/deployment.md +0 -22
- package/reference/claude-config/rules/error-handling.md +0 -22
- package/reference/claude-config/rules/execution.md +0 -22
- package/reference/claude-config/rules/frontend.md +0 -22
- package/reference/claude-config/rules/observability.md +0 -22
- package/reference/claude-config/rules/operations.md +0 -22
- package/reference/claude-config/rules/organization-model.md +0 -22
- package/reference/claude-config/rules/organization-os.md +0 -22
- package/reference/claude-config/rules/package-taxonomy.md +0 -22
- package/reference/claude-config/rules/platform.md +0 -22
- package/reference/claude-config/rules/shared-types.md +0 -22
- package/reference/claude-config/rules/task-tracking.md +0 -22
- package/reference/claude-config/rules/topbar-actions.md +0 -70
- package/reference/claude-config/rules/ui.md +0 -22
- package/reference/claude-config/rules/vibe.md +0 -22
- package/reference/claude-config/scripts/statusline-command.js +0 -18
- package/reference/claude-config/settings.json +0 -30
- package/reference/claude-config/skills/client/SKILL.md +0 -201
- package/reference/claude-config/skills/deploy/SKILL.md +0 -159
- package/reference/claude-config/skills/dsp/SKILL.md +0 -66
- package/reference/claude-config/skills/elevasis/SKILL.md +0 -251
- package/reference/claude-config/skills/explore/SKILL.md +0 -78
- package/reference/claude-config/skills/git-sync/SKILL.md +0 -166
- package/reference/claude-config/skills/om/SKILL.md +0 -475
- package/reference/claude-config/skills/om/operations/build.md +0 -237
- package/reference/claude-config/skills/om/operations/codify-level-a.md +0 -109
- package/reference/claude-config/skills/om/operations/codify-level-b.md +0 -159
- package/reference/claude-config/skills/om/operations/customers.md +0 -114
- package/reference/claude-config/skills/om/operations/features.md +0 -88
- package/reference/claude-config/skills/om/operations/goals.md +0 -123
- package/reference/claude-config/skills/om/operations/identity.md +0 -97
- package/reference/claude-config/skills/om/operations/labels.md +0 -110
- package/reference/claude-config/skills/om/operations/offerings.md +0 -114
- package/reference/claude-config/skills/om/operations/roles.md +0 -104
- package/reference/claude-config/skills/om/operations/scaffold.md +0 -163
- package/reference/claude-config/skills/om/operations/techStack.md +0 -38
- package/reference/claude-config/skills/project/SKILL.md +0 -1114
- package/reference/claude-config/skills/run-ui/SKILL.md +0 -73
- package/reference/claude-config/skills/save/SKILL.md +0 -183
- package/reference/claude-config/skills/setup/SKILL.md +0 -290
- package/reference/claude-config/skills/status/SKILL.md +0 -59
- package/reference/claude-config/skills/submit-request/SKILL.md +0 -180
- package/reference/claude-config/skills/sync/SKILL.md +0 -47
- package/reference/claude-config/skills/tutorial/SKILL.md +0 -259
- package/reference/claude-config/skills/tutorial/progress-template.md +0 -74
- package/reference/claude-config/skills/tutorial/technical.md +0 -1303
- package/reference/claude-config/skills/tutorial/vibe-coder.md +0 -890
- package/reference/claude-config/sync-notes/2026-04-22-git-sync-and-sync-notes.md +0 -27
- package/reference/claude-config/sync-notes/2026-04-22-lead-gen-deliverability-removal.md +0 -30
- package/reference/claude-config/sync-notes/2026-04-24-test-utils-and-template-tests.md +0 -73
- package/reference/claude-config/sync-notes/2026-04-24-ui-consolidation-and-sdk-cli-train.md +0 -86
- package/reference/claude-config/sync-notes/2026-04-25-auth-role-system-and-settings-roles.md +0 -55
- package/reference/claude-config/sync-notes/2026-04-27-crm-hitl-action-layer-cutover.md +0 -97
- package/reference/claude-config/sync-notes/2026-04-27-lead-gen-substrate-train.md +0 -112
- package/reference/claude-config/sync-notes/2026-04-29-crm-state-and-lead-gen-processing-status.md +0 -93
- package/reference/claude-config/sync-notes/2026-05-02-crm-ownership-next-action.md +0 -58
- package/reference/claude-config/sync-notes/2026-05-02-template-hardcode-workos-config.md +0 -56
- package/reference/claude-config/sync-notes/2026-05-04-elevasis-workspace.md +0 -71
- package/reference/claude-config/sync-notes/2026-05-04-knowledge-bundle.md +0 -83
- package/reference/claude-config/sync-notes/2026-05-04-template-skills-run-ui-and-tutorial.md +0 -59
- package/reference/claude-config/sync-notes/2026-05-05-list-builder.md +0 -42
- package/reference/claude-config/sync-notes/2026-05-06-crm-spine.md +0 -60
- package/reference/claude-config/sync-notes/2026-05-06-sdk-changes-release-train.md +0 -37
- package/reference/claude-config/sync-notes/2026-05-07-sdk-changes-release-train.md +0 -34
- package/reference/claude-config/sync-notes/2026-05-08-resource-governance-scaffold-guidance.md +0 -38
- package/reference/claude-config/sync-notes/2026-05-09-clients-domain.md +0 -32
- package/reference/claude-config/sync-notes/2026-05-09-command-system.md +0 -33
- package/reference/claude-config/sync-notes/2026-05-09-resource-governance-and-misc.md +0 -69
- package/reference/claude-config/sync-notes/2026-05-12-sdk-ready-release-train.md +0 -30
- package/reference/claude-config/sync-notes/2026-05-14-organization-model-ontology-refactor.md +0 -45
- package/reference/claude-config/sync-notes/2026-05-15-om-skill-rename-and-write-family.md +0 -52
- package/reference/claude-config/sync-notes/2026-05-17-sdk-boundary-consolidation.md +0 -33
- package/reference/claude-config/sync-notes/2026-05-20-om-define-helpers.md +0 -32
- package/reference/claude-config/sync-notes/2026-05-22-access-model-and-right-panel.md +0 -43
- package/reference/claude-config/sync-notes/2026-05-22-lead-gen-tenant-config.md +0 -40
- package/reference/claude-config/sync-notes/2026-05-22-org-model-multi-file-split.md +0 -61
- package/reference/claude-config/sync-notes/2026-05-23-branding-names-to-identity.md +0 -49
- package/reference/claude-config/sync-notes/2026-05-23-lead-gen-manage-access.md +0 -31
- package/reference/claude-config/sync-notes/2026-05-23-om-deployment-drift-detection.md +0 -42
- package/reference/claude-config/sync-notes/2026-05-23-om-full-model-deploy-contract.md +0 -33
- package/reference/claude-config/sync-notes/2026-05-23-ui-sdk-package-fixes.md +0 -37
- package/reference/claude-config/sync-notes/2026-05-24-platform-invite-router-core-baseline.md +0 -28
- package/reference/claude-config/sync-notes/2026-05-24-system-interface-readiness.md +0 -43
- package/reference/claude-config/sync-notes/2026-05-25-invitation-login-loader.md +0 -26
- package/reference/claude-config/sync-notes/2026-05-25-om-topbar-requests.md +0 -33
- package/reference/claude-config/sync-notes/2026-05-25-system-interface-profile-registry-and-substrate.md +0 -35
- package/reference/claude-config/sync-notes/2026-05-25-tenant-om-scaffold-cli.md +0 -49
- package/reference/claude-config/sync-notes/2026-05-25-vibe-operate-intent.md +0 -47
- package/reference/claude-config/sync-notes/2026-05-28-om-snapshot-sdk-workflow-config.md +0 -33
- package/reference/claude-config/sync-notes/2026-05-30-client-source-and-om-profiles.md +0 -39
- package/reference/claude-config/sync-notes/2026-06-02-knowledge-nested-group-routing.md +0 -27
- package/reference/claude-config/sync-notes/2026-06-02-nest-projects-under-platform.md +0 -45
- package/reference/claude-config/sync-notes/2026-06-03-skill-autogen-and-client-skill.md +0 -34
- package/reference/claude-config/sync-notes/2026-06-04-scaffold-registry-lane-severity.md +0 -34
- package/reference/claude-config/sync-notes/2026-06-05-appearance-app-mode-decouple.md +0 -29
- package/reference/claude-config/sync-notes/2026-06-05-ontology-endpoint-rename-and-knowledge-browser-ui.md +0 -86
- package/reference/claude-config/sync-notes/2026-06-06-om-build-systems-scaffold.md +0 -47
- package/reference/claude-config/sync-notes/2026-06-06-om-item-copy-references.md +0 -50
- package/reference/claude-config/sync-notes/2026-06-08-knowledge-base-page-not-found-fix.md +0 -76
- package/reference/claude-config/sync-notes/2026-06-09-agent-sessions-public-agent-chat-route.md +0 -75
- package/reference/claude-config/sync-notes/2026-06-09-sdk-cli-load-org-model-resolution.md +0 -42
- package/reference/claude-config/sync-notes/2026-06-12-agent-grants-visualizer-operations.md +0 -30
- package/reference/claude-config/sync-notes/2026-06-14-session-ux-and-project-cli-json.md +0 -33
- package/reference/claude-config/sync-notes/2026-06-14-shared-session-conversation-view.md +0 -26
- package/reference/claude-config/sync-notes/2026-06-15-session-chat-zero-wiring.md +0 -46
- package/reference/claude-config/sync-notes/2026-06-17-agent-session-ux-features.md +0 -34
- package/reference/claude-config/sync-notes/2026-06-25-shared-page-scroll-contract-guard.md +0 -52
- package/reference/claude-config/sync-notes/2026-06-26-leadgen-overview-om-telemetry.md +0 -47
- package/reference/claude-config/sync-notes/2026-07-21-agent-scaffold-hardening.md +0 -75
- package/reference/claude-config/sync-notes/2026-07-23-agent-session-memory.md +0 -49
- package/reference/claude-config/sync-notes/2026-07-23-workos-org-marker.md +0 -50
- package/reference/claude-config/sync-notes/2026-07-24-claude-5-models-and-session-surface-fixes.md +0 -116
- package/reference/claude-config/sync-notes/2026-07-27-agent-strict-output-and-turn-drift.md +0 -73
- package/reference/claude-config/sync-notes/2026-07-28-agent-reply-is-its-own-field.md +0 -84
- package/reference/claude-config/sync-notes/2026-07-30-login-screen-and-member-provisioning-state.md +0 -114
- package/reference/claude-config/sync-notes/2026-08-02-auth-guard-defaults-and-truncation-fix.md +0 -122
- package/reference/claude-config/sync-notes/2026-08-03-cli-gateway-errors-and-request-timeout.md +0 -120
- package/reference/claude-config/sync-notes/README.md +0 -43
- package/reference/sdk/framework/interaction-guidance.mdx +0 -182
- package/reference/sdk/framework/memory.mdx +0 -326
- package/reference/sdk/framework/resource-documentation.mdx +0 -90
- package/reference/sdk/roadmap.mdx +0 -164
|
@@ -1,236 +1,275 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Composition & Extensibility
|
|
3
|
-
description: Organization OS Toolkit layer guidance for customizing shared shell systems without forking, including exported nav arrays, optional sidebar props, composable layout primitives,
|
|
4
|
-
---
|
|
1
|
+
---
|
|
2
|
+
title: Composition & Extensibility
|
|
3
|
+
description: Organization OS Toolkit layer guidance for customizing shared shell systems without forking, including exported nav arrays, optional sidebar props, composable layout primitives, the manifest.sidebar override pattern, and the render-prop slot + zero-wiring default pattern for the shared session-chat surface.
|
|
4
|
+
---
|
|
5
5
|
<!-- @generated by packages/sdk/scripts/copy-reference-docs.mjs -- DO NOT EDIT -->
|
|
6
6
|
<!-- Regenerate: pnpm scaffold:sync -->
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
## Overview
|
|
10
|
-
|
|
11
|
-
Within Organization OS, this doc covers the **Toolkit** layer: the primitives consumers use to customize shared shell systems by composition instead of fork. Consumers extend nav items, inject panels, or wrap pages by combining published primitives and assigning a custom component to `manifest.sidebar`. Copying source is physically possible but unsupported -- a fork owns upstream drift forever.
|
|
12
|
-
|
|
13
|
-
The core pattern: set `sidebar` on your manifest to a component that composes the system's published pieces. If the published pieces can't express what you need, the missing export is a bug. File an issue instead of forking.
|
|
14
|
-
|
|
15
|
-
Shipped in `@elevasis/ui >= 2.8.1`.
|
|
16
|
-
|
|
17
|
-
## The Override Pattern
|
|
18
|
-
|
|
19
|
-
Every `SystemModule.sidebar` is a `ComponentType`. Consumers customize by:
|
|
20
|
-
|
|
21
|
-
1. Importing the system's published sidebar wrapper and middle component.
|
|
22
|
-
2. Wrapping or replacing the middle with custom content.
|
|
23
|
-
3. Spreading the stock manifest and setting `sidebar` to their component.
|
|
24
|
-
4. Passing the customized manifest to `ElevasisSystemsProvider`.
|
|
25
|
-
|
|
26
|
-
No new manifest fields. No discriminated unions. No runtime machinery.
|
|
27
|
-
|
|
28
|
-
## Decision Tree
|
|
29
|
-
|
|
30
|
-
- **Adding or changing nav items?** -> Extend the exported item array and pass to `<*SidebarMiddle items={...}>`.
|
|
31
|
-
- **Structural changes (injecting panels, wrapping sections)?** -> Compose `SidebarTop`, `SidebarMiddle`, and exported panels directly in your own component.
|
|
32
|
-
- **Wrapping pages?** -> Import the system's page component and wrap with custom chrome in a route file.
|
|
33
|
-
- **None of these fits?** -> Missing export is the bug. File an issue.
|
|
34
|
-
|
|
35
|
-
## Exported Primitives
|
|
36
|
-
|
|
37
|
-
### Nav item arrays
|
|
38
|
-
|
|
39
|
-
Re-exported from each system sidebar barrel:
|
|
40
|
-
|
|
41
|
-
- `CRM_ITEMS` from `@elevasis/ui/features/crm`
|
|
42
|
-
- `LEAD_GEN_ITEMS` from `@elevasis/ui/features/lead-gen`
|
|
43
|
-
- `DELIVERY_PROJECT_ITEMS`, `DELIVERY_WORK_ITEMS`, `DELIVERY_COMMUNICATION_ITEMS` from `@elevasis/ui/features/delivery`
|
|
44
|
-
|
|
45
|
-
Shape is the shared `NavItem` type exported from `@elevasis/ui/layout`.
|
|
46
|
-
|
|
47
|
-
### Sidebar wrappers
|
|
48
|
-
|
|
49
|
-
Thin Top+Middle composers. Each accepts optional `children?: ReactNode` that replaces the default middle:
|
|
50
|
-
|
|
51
|
-
- `CrmSidebar`, `LeadGenSidebar`, `ProjectsSidebar`
|
|
52
|
-
|
|
53
|
-
### Middle components with optional item props
|
|
54
|
-
|
|
55
|
-
- `CrmSidebarMiddle` -- `items?: NavItem[]` (defaults to `CRM_ITEMS`)
|
|
56
|
-
- `LeadGenSidebarMiddle` -- `items?: NavItem[]` (defaults to `LEAD_GEN_ITEMS`)
|
|
57
|
-
- `ProjectsSidebarMiddle` -- `projectItems?`, `workItems?`, `communicationItems?` (each defaults to its respective exported array)
|
|
58
|
-
|
|
59
|
-
Delivery's three sections are preserved intentionally -- a real UX pattern consumers may want to extend with additional sections.
|
|
60
|
-
|
|
61
|
-
### Composable layout primitives
|
|
62
|
-
|
|
63
|
-
From `@elevasis/ui/layout`:
|
|
64
|
-
|
|
65
|
-
- `SubshellNavItem` -- individual nav link
|
|
66
|
-
- `SubshellNavList` -- router-context-aware list renderer (accepts `items: NavItem[]`, derives active state via `useRouterContext()`)
|
|
67
|
-
- `SubshellSidebarSection` -- section header with icon, label, optional top border
|
|
68
|
-
- `NavItem` -- shared item shape type
|
|
69
|
-
- `SubshellContainer` -- full-width, full-height flex wrapper that composes sidebar and content side by side
|
|
70
|
-
- `SubshellRightSideContainer` -- content area column (`flex: 1`, `minWidth: 0`) that prevents sidebar from squeezing content
|
|
71
|
-
- `SubshellContentContainer` -- scrollable content area with standard `md` padding and automatic topbar offset applied via `paddingTop`
|
|
72
|
-
- `SubshellLoader` -- loading placeholder centered in the subshell viewport; reads the active loader from `AppearanceContext`
|
|
73
|
-
|
|
74
|
-
`SystemShell` wires these together at `width={250}` as the default sidebar width. Consumers composing their own shell layout can pass a different `width` prop to `SubshellSidebar`.
|
|
75
|
-
|
|
76
|
-
### SubshellSidebar behavior
|
|
77
|
-
|
|
78
|
-
`SubshellSidebar` is more than a thin wrapper. Key behaviors verified in source:
|
|
79
|
-
|
|
80
|
-
- **Collapsible** -- controlled by `collapsible` prop (defaults to `true`) and `defaultOpen` prop (defaults to `true`). When collapsed, the sidebar animates to zero width and a small toggle button remains visible at the bottom-right edge.
|
|
81
|
-
- **Glass morphism** -- applies `color-mix(in srgb, var(--glass-background) 80%, transparent)` as background and `var(--glass-blur)` as `backdropFilter`, consistent with the theme token system.
|
|
82
|
-
- **Animated transitions** -- width and opacity animate on collapse/expand using `sidebarTransitionDuration` from the layout constants.
|
|
83
|
-
- **Width** -- no built-in default; the caller supplies `width`. `SystemShell` passes `250` and this is the canonical default for stock system sidebars.
|
|
84
|
-
|
|
85
|
-
From `@elevasis/ui/router/context`:
|
|
86
|
-
|
|
87
|
-
- `useRouterContext` -- access route state for custom active-state logic
|
|
88
|
-
|
|
89
|
-
### RouterAdapter interface
|
|
90
|
-
|
|
91
|
-
`RouterAdapter` is the interface that bridges any router implementation to the shared layout primitives. Defined in `packages/ui/src/router/context.ts`:
|
|
92
|
-
|
|
93
|
-
- `currentPath: string` -- current pathname, used by `SubshellNavList` to derive active state
|
|
94
|
-
- `currentSearch?: string` -- current search string (optional)
|
|
95
|
-
- `navigate: (to: string) => void` -- imperative navigation
|
|
96
|
-
- `Link: ElementType<LinkProps>` -- router-aware anchor component; `LinkProps` extends `AnchorHTMLAttributes\<HTMLAnchorElement>` with a required `to: string` field
|
|
97
|
-
|
|
98
|
-
Consumers calling `useRouterContext()` get back a `RouterAdapter`. Any component that needs to read `currentPath` or call `navigate` can use the hook directly rather than prop-drilling from a parent.
|
|
99
|
-
|
|
100
|
-
### TanStackRouterBridge
|
|
101
|
-
|
|
102
|
-
`TanStackRouterBridge` is the concrete `RouterAdapter` implementation for TanStack Router. Exported from `packages/ui/src/router/providers/TanStackRouterBridge.tsx` and available via `@elevasis/ui/router`.
|
|
103
|
-
|
|
104
|
-
It wraps `RouterProvider` and supplies the adapter by reading `useLocation` and `useRouter` from `@tanstack/react-router`. The adapter value is stabilized with `useMemo` to prevent unnecessary re-renders in downstream consumers. Place it inside TanStack's `RouterProvider`:
|
|
105
|
-
|
|
106
|
-
```tsx
|
|
107
|
-
<TanStackRouterBridge>
|
|
108
|
-
<ElevasisSystemsProvider ...>
|
|
109
|
-
<SystemShell>...</SystemShell>
|
|
110
|
-
</ElevasisSystemsProvider>
|
|
111
|
-
</TanStackRouterBridge>
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
Consumers using a different router can implement `RouterAdapter` directly and pass it to `RouterProvider` instead of using this bridge.
|
|
115
|
-
|
|
116
|
-
### System panels (CRM)
|
|
117
|
-
|
|
118
|
-
- `MyTasksPanel`, `QuickCreateActions` -- exported from `@elevasis/ui/features/crm`, included by default in `CrmSidebarMiddle`; consumers composing their own middle can re-include them explicitly.
|
|
119
|
-
|
|
120
|
-
### System pages
|
|
121
|
-
|
|
122
|
-
Every page each system renders is exported from its system barrel, so consumers can wrap with custom chrome without forking:
|
|
123
|
-
|
|
124
|
-
- CRM: `DealsListPage`, `DealDetailPage`
|
|
125
|
-
- Lead-gen: `LeadGenOverviewPage`, `LeadGenListsPage`, `LeadGenListDetailPage`, `LeadGenCompaniesPage`, `LeadGenContactsPage`
|
|
126
|
-
- Delivery: `AllTasksPage`, `UpcomingMilestonesPage`, `ProjectsListPage`, `ProjectDetailPage`
|
|
127
|
-
- Operations, monitoring, settings -- full page inventories exported from their system barrels
|
|
128
|
-
|
|
129
|
-
## Consumer Patterns
|
|
130
|
-
|
|
131
|
-
### 1. Extend nav items (shortest path)
|
|
132
|
-
|
|
133
|
-
```tsx
|
|
134
|
-
import { CrmSidebar, CrmSidebarMiddle, CRM_ITEMS } from '@elevasis/ui/features/crm'
|
|
135
|
-
import { IconFileText } from '@tabler/icons-react'
|
|
136
|
-
|
|
137
|
-
const customItems = [
|
|
138
|
-
...CRM_ITEMS,
|
|
139
|
-
{ label: 'Reports', to: '/crm/reports', icon: IconFileText, exact: false },
|
|
140
|
-
]
|
|
141
|
-
|
|
142
|
-
const MyCrmSidebar = () => (
|
|
143
|
-
<CrmSidebar>
|
|
144
|
-
<CrmSidebarMiddle items={customItems} />
|
|
145
|
-
</CrmSidebar>
|
|
146
|
-
)
|
|
147
|
-
|
|
148
|
-
const customCrmManifest = { ...crmManifest, sidebar: MyCrmSidebar }
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
### 2. Inject a new delivery section (compose from primitives)
|
|
152
|
-
|
|
153
|
-
```tsx
|
|
154
|
-
import {
|
|
155
|
-
ProjectsSidebar,
|
|
156
|
-
DELIVERY_PROJECT_ITEMS,
|
|
157
|
-
DELIVERY_WORK_ITEMS,
|
|
158
|
-
DELIVERY_COMMUNICATION_ITEMS,
|
|
159
|
-
} from '@elevasis/ui/features/delivery'
|
|
160
|
-
import { SubshellSidebarSection, SubshellNavList } from '@elevasis/ui/layout'
|
|
161
|
-
import { Stack } from '@mantine/core'
|
|
162
|
-
import { IconChartBar, IconListCheck, IconMessageCircle } from '@tabler/icons-react'
|
|
163
|
-
|
|
164
|
-
const ANALYTICS_ITEMS = [
|
|
165
|
-
{ label: 'Dashboard', to: '/projects/analytics', icon: IconChartBar, exact: true },
|
|
166
|
-
]
|
|
167
|
-
|
|
168
|
-
const MyDeliveryMiddle = () => (
|
|
169
|
-
<Stack gap={0} style={{ flex: 1, overflowY: 'auto' }}>
|
|
170
|
-
<Stack gap={0} p="sm"><SubshellNavList items={DELIVERY_PROJECT_ITEMS} /></Stack>
|
|
171
|
-
<SubshellSidebarSection icon={IconListCheck} label="Work" withTopBorder />
|
|
172
|
-
<Stack gap={0} p="sm"><SubshellNavList items={DELIVERY_WORK_ITEMS} /></Stack>
|
|
173
|
-
<SubshellSidebarSection icon={IconMessageCircle} label="Communication" withTopBorder />
|
|
174
|
-
<Stack gap={0} p="sm"><SubshellNavList items={DELIVERY_COMMUNICATION_ITEMS} /></Stack>
|
|
175
|
-
<SubshellSidebarSection icon={IconChartBar} label="Analytics" withTopBorder />
|
|
176
|
-
<Stack gap={0} p="sm"><SubshellNavList items={ANALYTICS_ITEMS} /></Stack>
|
|
177
|
-
</Stack>
|
|
178
|
-
)
|
|
179
|
-
|
|
180
|
-
const MyDeliverySidebar = () => (
|
|
181
|
-
<ProjectsSidebar>
|
|
182
|
-
<MyDeliveryMiddle />
|
|
183
|
-
</ProjectsSidebar>
|
|
184
|
-
)
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
### 3. Wrap a page with custom chrome
|
|
188
|
-
|
|
189
|
-
```tsx
|
|
190
|
-
// in a route file
|
|
191
|
-
import { DealsListPage } from '@elevasis/ui/features/crm'
|
|
192
|
-
|
|
193
|
-
export default function CustomDealsRoute() {
|
|
194
|
-
return (
|
|
195
|
-
<MyChromeWrapper>
|
|
196
|
-
<DealsListPage />
|
|
197
|
-
</MyChromeWrapper>
|
|
198
|
-
)
|
|
199
|
-
}
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
## Operations & Unmodified Systems
|
|
203
|
-
|
|
204
|
-
- **Operations** -- uses `sidebar?: ComponentType` with route-aware dispatch; the items-prop pattern does not apply.
|
|
205
|
-
- **Monitoring, Settings** -- no subshell sidebar. No customization surface needed.
|
|
206
|
-
- **SEO** -- has sidebar components (`SEOSidebar`, `SEOSidebarTop`, `SEOSidebarMiddle`) but no page inventory in `@elevasis/ui`.
|
|
207
|
-
|
|
208
|
-
## Publish-Surface Discipline
|
|
209
|
-
|
|
210
|
-
All primitives above flow through published subpaths (`@elevasis/ui/features/<system>`, `@elevasis/ui/layout`, `@elevasis/ui/router/context`). Any new primitive must sync four files per `.claude/rules/ui-package.md`: `package.json` `exports`, `publishConfig.exports`, `rollup.dts.config.mjs`, and `tsup.config.ts`.
|
|
211
|
-
|
|
212
|
-
The published barrel (`packages/ui/src/provider/published.ts`) remains headless -- no Mantine-dependent visual pieces leak into the external contract.
|
|
213
|
-
|
|
214
|
-
##
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
-
|
|
219
|
-
|
|
220
|
-
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
-
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
Within Organization OS, this doc covers the **Toolkit** layer: the primitives consumers use to customize shared shell systems by composition instead of fork. Consumers extend nav items, inject panels, or wrap pages by combining published primitives and assigning a custom component to `manifest.sidebar`. Copying source is physically possible but unsupported -- a fork owns upstream drift forever.
|
|
12
|
+
|
|
13
|
+
The core pattern: set `sidebar` on your manifest to a component that composes the system's published pieces. If the published pieces can't express what you need, the missing export is a bug. File an issue instead of forking.
|
|
14
|
+
|
|
15
|
+
Shipped in `@elevasis/ui >= 2.8.1`.
|
|
16
|
+
|
|
17
|
+
## The Override Pattern
|
|
18
|
+
|
|
19
|
+
Every `SystemModule.sidebar` is a `ComponentType`. Consumers customize by:
|
|
20
|
+
|
|
21
|
+
1. Importing the system's published sidebar wrapper and middle component.
|
|
22
|
+
2. Wrapping or replacing the middle with custom content.
|
|
23
|
+
3. Spreading the stock manifest and setting `sidebar` to their component.
|
|
24
|
+
4. Passing the customized manifest to `ElevasisSystemsProvider`.
|
|
25
|
+
|
|
26
|
+
No new manifest fields. No discriminated unions. No runtime machinery.
|
|
27
|
+
|
|
28
|
+
## Decision Tree
|
|
29
|
+
|
|
30
|
+
- **Adding or changing nav items?** -> Extend the exported item array and pass to `<*SidebarMiddle items={...}>`.
|
|
31
|
+
- **Structural changes (injecting panels, wrapping sections)?** -> Compose `SidebarTop`, `SidebarMiddle`, and exported panels directly in your own component.
|
|
32
|
+
- **Wrapping pages?** -> Import the system's page component and wrap with custom chrome in a route file.
|
|
33
|
+
- **None of these fits?** -> Missing export is the bug. File an issue.
|
|
34
|
+
|
|
35
|
+
## Exported Primitives
|
|
36
|
+
|
|
37
|
+
### Nav item arrays
|
|
38
|
+
|
|
39
|
+
Re-exported from each system sidebar barrel:
|
|
40
|
+
|
|
41
|
+
- `CRM_ITEMS` from `@elevasis/ui/features/crm`
|
|
42
|
+
- `LEAD_GEN_ITEMS` from `@elevasis/ui/features/lead-gen`
|
|
43
|
+
- `DELIVERY_PROJECT_ITEMS`, `DELIVERY_WORK_ITEMS`, `DELIVERY_COMMUNICATION_ITEMS` from `@elevasis/ui/features/delivery`
|
|
44
|
+
|
|
45
|
+
Shape is the shared `NavItem` type exported from `@elevasis/ui/layout`.
|
|
46
|
+
|
|
47
|
+
### Sidebar wrappers
|
|
48
|
+
|
|
49
|
+
Thin Top+Middle composers. Each accepts optional `children?: ReactNode` that replaces the default middle:
|
|
50
|
+
|
|
51
|
+
- `CrmSidebar`, `LeadGenSidebar`, `ProjectsSidebar`
|
|
52
|
+
|
|
53
|
+
### Middle components with optional item props
|
|
54
|
+
|
|
55
|
+
- `CrmSidebarMiddle` -- `items?: NavItem[]` (defaults to `CRM_ITEMS`)
|
|
56
|
+
- `LeadGenSidebarMiddle` -- `items?: NavItem[]` (defaults to `LEAD_GEN_ITEMS`)
|
|
57
|
+
- `ProjectsSidebarMiddle` -- `projectItems?`, `workItems?`, `communicationItems?` (each defaults to its respective exported array)
|
|
58
|
+
|
|
59
|
+
Delivery's three sections are preserved intentionally -- a real UX pattern consumers may want to extend with additional sections.
|
|
60
|
+
|
|
61
|
+
### Composable layout primitives
|
|
62
|
+
|
|
63
|
+
From `@elevasis/ui/layout`:
|
|
64
|
+
|
|
65
|
+
- `SubshellNavItem` -- individual nav link
|
|
66
|
+
- `SubshellNavList` -- router-context-aware list renderer (accepts `items: NavItem[]`, derives active state via `useRouterContext()`)
|
|
67
|
+
- `SubshellSidebarSection` -- section header with icon, label, optional top border
|
|
68
|
+
- `NavItem` -- shared item shape type
|
|
69
|
+
- `SubshellContainer` -- full-width, full-height flex wrapper that composes sidebar and content side by side
|
|
70
|
+
- `SubshellRightSideContainer` -- content area column (`flex: 1`, `minWidth: 0`) that prevents sidebar from squeezing content
|
|
71
|
+
- `SubshellContentContainer` -- scrollable content area with standard `md` padding and automatic topbar offset applied via `paddingTop`
|
|
72
|
+
- `SubshellLoader` -- loading placeholder centered in the subshell viewport; reads the active loader from `AppearanceContext`
|
|
73
|
+
|
|
74
|
+
`SystemShell` wires these together at `width={250}` as the default sidebar width. Consumers composing their own shell layout can pass a different `width` prop to `SubshellSidebar`.
|
|
75
|
+
|
|
76
|
+
### SubshellSidebar behavior
|
|
77
|
+
|
|
78
|
+
`SubshellSidebar` is more than a thin wrapper. Key behaviors verified in source:
|
|
79
|
+
|
|
80
|
+
- **Collapsible** -- controlled by `collapsible` prop (defaults to `true`) and `defaultOpen` prop (defaults to `true`). When collapsed, the sidebar animates to zero width and a small toggle button remains visible at the bottom-right edge.
|
|
81
|
+
- **Glass morphism** -- applies `color-mix(in srgb, var(--glass-background) 80%, transparent)` as background and `var(--glass-blur)` as `backdropFilter`, consistent with the theme token system.
|
|
82
|
+
- **Animated transitions** -- width and opacity animate on collapse/expand using `sidebarTransitionDuration` from the layout constants.
|
|
83
|
+
- **Width** -- no built-in default; the caller supplies `width`. `SystemShell` passes `250` and this is the canonical default for stock system sidebars.
|
|
84
|
+
|
|
85
|
+
From `@elevasis/ui/router/context`:
|
|
86
|
+
|
|
87
|
+
- `useRouterContext` -- access route state for custom active-state logic
|
|
88
|
+
|
|
89
|
+
### RouterAdapter interface
|
|
90
|
+
|
|
91
|
+
`RouterAdapter` is the interface that bridges any router implementation to the shared layout primitives. Defined in `packages/ui/src/router/context.ts`:
|
|
92
|
+
|
|
93
|
+
- `currentPath: string` -- current pathname, used by `SubshellNavList` to derive active state
|
|
94
|
+
- `currentSearch?: string` -- current search string (optional)
|
|
95
|
+
- `navigate: (to: string) => void` -- imperative navigation
|
|
96
|
+
- `Link: ElementType<LinkProps>` -- router-aware anchor component; `LinkProps` extends `AnchorHTMLAttributes\<HTMLAnchorElement>` with a required `to: string` field
|
|
97
|
+
|
|
98
|
+
Consumers calling `useRouterContext()` get back a `RouterAdapter`. Any component that needs to read `currentPath` or call `navigate` can use the hook directly rather than prop-drilling from a parent.
|
|
99
|
+
|
|
100
|
+
### TanStackRouterBridge
|
|
101
|
+
|
|
102
|
+
`TanStackRouterBridge` is the concrete `RouterAdapter` implementation for TanStack Router. Exported from `packages/ui/src/router/providers/TanStackRouterBridge.tsx` and available via `@elevasis/ui/router`.
|
|
103
|
+
|
|
104
|
+
It wraps `RouterProvider` and supplies the adapter by reading `useLocation` and `useRouter` from `@tanstack/react-router`. The adapter value is stabilized with `useMemo` to prevent unnecessary re-renders in downstream consumers. Place it inside TanStack's `RouterProvider`:
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
<TanStackRouterBridge>
|
|
108
|
+
<ElevasisSystemsProvider ...>
|
|
109
|
+
<SystemShell>...</SystemShell>
|
|
110
|
+
</ElevasisSystemsProvider>
|
|
111
|
+
</TanStackRouterBridge>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Consumers using a different router can implement `RouterAdapter` directly and pass it to `RouterProvider` instead of using this bridge.
|
|
115
|
+
|
|
116
|
+
### System panels (CRM)
|
|
117
|
+
|
|
118
|
+
- `MyTasksPanel`, `QuickCreateActions` -- exported from `@elevasis/ui/features/crm`, included by default in `CrmSidebarMiddle`; consumers composing their own middle can re-include them explicitly.
|
|
119
|
+
|
|
120
|
+
### System pages
|
|
121
|
+
|
|
122
|
+
Every page each system renders is exported from its system barrel, so consumers can wrap with custom chrome without forking:
|
|
123
|
+
|
|
124
|
+
- CRM: `DealsListPage`, `DealDetailPage`
|
|
125
|
+
- Lead-gen: `LeadGenOverviewPage`, `LeadGenListsPage`, `LeadGenListDetailPage`, `LeadGenCompaniesPage`, `LeadGenContactsPage`
|
|
126
|
+
- Delivery: `AllTasksPage`, `UpcomingMilestonesPage`, `ProjectsListPage`, `ProjectDetailPage`
|
|
127
|
+
- Operations, monitoring, settings -- full page inventories exported from their system barrels
|
|
128
|
+
|
|
129
|
+
## Consumer Patterns
|
|
130
|
+
|
|
131
|
+
### 1. Extend nav items (shortest path)
|
|
132
|
+
|
|
133
|
+
```tsx
|
|
134
|
+
import { CrmSidebar, CrmSidebarMiddle, CRM_ITEMS } from '@elevasis/ui/features/crm'
|
|
135
|
+
import { IconFileText } from '@tabler/icons-react'
|
|
136
|
+
|
|
137
|
+
const customItems = [
|
|
138
|
+
...CRM_ITEMS,
|
|
139
|
+
{ label: 'Reports', to: '/crm/reports', icon: IconFileText, exact: false },
|
|
140
|
+
]
|
|
141
|
+
|
|
142
|
+
const MyCrmSidebar = () => (
|
|
143
|
+
<CrmSidebar>
|
|
144
|
+
<CrmSidebarMiddle items={customItems} />
|
|
145
|
+
</CrmSidebar>
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
const customCrmManifest = { ...crmManifest, sidebar: MyCrmSidebar }
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### 2. Inject a new delivery section (compose from primitives)
|
|
152
|
+
|
|
153
|
+
```tsx
|
|
154
|
+
import {
|
|
155
|
+
ProjectsSidebar,
|
|
156
|
+
DELIVERY_PROJECT_ITEMS,
|
|
157
|
+
DELIVERY_WORK_ITEMS,
|
|
158
|
+
DELIVERY_COMMUNICATION_ITEMS,
|
|
159
|
+
} from '@elevasis/ui/features/delivery'
|
|
160
|
+
import { SubshellSidebarSection, SubshellNavList } from '@elevasis/ui/layout'
|
|
161
|
+
import { Stack } from '@mantine/core'
|
|
162
|
+
import { IconChartBar, IconListCheck, IconMessageCircle } from '@tabler/icons-react'
|
|
163
|
+
|
|
164
|
+
const ANALYTICS_ITEMS = [
|
|
165
|
+
{ label: 'Dashboard', to: '/projects/analytics', icon: IconChartBar, exact: true },
|
|
166
|
+
]
|
|
167
|
+
|
|
168
|
+
const MyDeliveryMiddle = () => (
|
|
169
|
+
<Stack gap={0} style={{ flex: 1, overflowY: 'auto' }}>
|
|
170
|
+
<Stack gap={0} p="sm"><SubshellNavList items={DELIVERY_PROJECT_ITEMS} /></Stack>
|
|
171
|
+
<SubshellSidebarSection icon={IconListCheck} label="Work" withTopBorder />
|
|
172
|
+
<Stack gap={0} p="sm"><SubshellNavList items={DELIVERY_WORK_ITEMS} /></Stack>
|
|
173
|
+
<SubshellSidebarSection icon={IconMessageCircle} label="Communication" withTopBorder />
|
|
174
|
+
<Stack gap={0} p="sm"><SubshellNavList items={DELIVERY_COMMUNICATION_ITEMS} /></Stack>
|
|
175
|
+
<SubshellSidebarSection icon={IconChartBar} label="Analytics" withTopBorder />
|
|
176
|
+
<Stack gap={0} p="sm"><SubshellNavList items={ANALYTICS_ITEMS} /></Stack>
|
|
177
|
+
</Stack>
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
const MyDeliverySidebar = () => (
|
|
181
|
+
<ProjectsSidebar>
|
|
182
|
+
<MyDeliveryMiddle />
|
|
183
|
+
</ProjectsSidebar>
|
|
184
|
+
)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### 3. Wrap a page with custom chrome
|
|
188
|
+
|
|
189
|
+
```tsx
|
|
190
|
+
// in a route file
|
|
191
|
+
import { DealsListPage } from '@elevasis/ui/features/crm'
|
|
192
|
+
|
|
193
|
+
export default function CustomDealsRoute() {
|
|
194
|
+
return (
|
|
195
|
+
<MyChromeWrapper>
|
|
196
|
+
<DealsListPage />
|
|
197
|
+
</MyChromeWrapper>
|
|
198
|
+
)
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Operations & Unmodified Systems
|
|
203
|
+
|
|
204
|
+
- **Operations** -- uses `sidebar?: ComponentType` with route-aware dispatch; the items-prop pattern does not apply.
|
|
205
|
+
- **Monitoring, Settings** -- no subshell sidebar. No customization surface needed.
|
|
206
|
+
- **SEO** -- has sidebar components (`SEOSidebar`, `SEOSidebarTop`, `SEOSidebarMiddle`) but no page inventory in `@elevasis/ui`.
|
|
207
|
+
|
|
208
|
+
## Publish-Surface Discipline
|
|
209
|
+
|
|
210
|
+
All primitives above flow through published subpaths (`@elevasis/ui/features/<system>`, `@elevasis/ui/layout`, `@elevasis/ui/router/context`). Any new primitive must sync four files per `.claude/rules/ui-package.md`: `package.json` `exports`, `publishConfig.exports`, `rollup.dts.config.mjs`, and `tsup.config.ts`.
|
|
211
|
+
|
|
212
|
+
The published barrel (`packages/ui/src/provider/published.ts`) remains headless -- no Mantine-dependent visual pieces leak into the external contract.
|
|
213
|
+
|
|
214
|
+
## Render-Prop Slots and Zero-Wiring Defaults
|
|
215
|
+
|
|
216
|
+
Some shared pages expose a render-prop slot rather than rendering a concrete child directly. This keeps the package decoupled from host-specific details (API base URLs, router params) while still letting hosts customize the body.
|
|
217
|
+
|
|
218
|
+
### Session-Chat Surface
|
|
219
|
+
|
|
220
|
+
`SessionChatPage` (`@elevasis/ui/features/operations`) is the canonical example. It exposes `renderConversationView(args: ConversationViewSlotArgs)` as a render-prop slot threaded through `SessionChatInterface`. The slot was introduced so the package would not need to know a host's WebSocket base URL.
|
|
221
|
+
|
|
222
|
+
**Zero-wiring default:** `renderConversationView` is optional. When omitted, `SessionChatPage` internally calls `useDefaultConversationViewRenderer`, which reads `apiUrl` from `useElevasisServices()` and returns `<SessionConversationView apiUrl={apiUrl} {...args} />`. Hosts that need a custom body pass the prop explicitly; customization is opt-in rather than mandatory.
|
|
223
|
+
|
|
224
|
+
**Why `apiUrl` must come from context, not a prop.** `useSessionWebSocket` needs the raw base URL to derive the `ws(s)://` endpoint. `ElevasisServiceContextValue` exposes `apiRequest` (a closure), not the raw URL. The fix was adding `apiUrl: string` to `ElevasisServiceContextValue` so the package-level default renderer could construct the WebSocket URL without any host involvement. `ElevasisServiceProviderProps` accepts `apiUrl?: string` (defaults to `''`) for standalone and test usage; the guard inside `useDefaultConversationViewRenderer` throws clearly when `apiUrl` is empty in non-service-stack paths.
|
|
225
|
+
|
|
226
|
+
**Shared component.** `SessionConversationView` (`packages/ui/src/features/operations/sessions/SessionConversationView.tsx`) is the concrete implementation: accepts `apiUrl: string` plus the four `ConversationViewSlotArgs` fields (`onConnectionStateChange`, `emptyStateText`, `emptyStateSubtext`, `placeholder`), calls `useSessionWebSocket(sessionId, apiUrl)`, merges history via `useSessionMessages` + `mergeSessionMessages`, and renders `ChatInterface`. Exported from `packages/ui/src/features/operations/index.ts` under the `// Sessions` block and available via `@elevasis/ui/features/operations`. `SessionConversationViewProps` is also exported.
|
|
227
|
+
|
|
228
|
+
**Project-local route wrapper stays.** The thin host `SessionChatPage.tsx` wrapper still extracts the router param (`useParams`) and `isReady`/`organizationName` from host-owned auth context. These cannot move into the package without the package owning the host's route tree. The win is removing the mandatory conversation-view slot and the local stub, not the route wrapper itself.
|
|
229
|
+
|
|
230
|
+
**Scope boundary.** `SessionConversationView` covers the session-detail/plain path only. The command-center `AssistantPanel` has a richer local `ConversationView` (`handleAssistantEvents`, `pageContext`, `sendMessageRef`, `onTokenUsage`, `onMessagesChange`, `messageAreaVariant`) that is left untouched -- that component is CC-only and out of scope for the shared surface.
|
|
231
|
+
|
|
232
|
+
### The Slot-vs-Default Decision
|
|
233
|
+
|
|
234
|
+
When deciding whether a render-prop slot needs a zero-wiring default:
|
|
235
|
+
|
|
236
|
+
- **Provide a default** when most hosts want the same behaviour and only need to customize rarely. Make customization opt-in.
|
|
237
|
+
- **Keep the slot required** only when every host genuinely needs to supply a different implementation and there is no sensible shared fallback.
|
|
238
|
+
- **Expose context values** (like `apiUrl`) when the package-level default needs host-configured state that was previously consumed internally but not re-exposed.
|
|
239
|
+
|
|
240
|
+
The `optional prop + self-default` pattern (one component, one mental model) is preferred over a separate `StandardizedXPage` wrapper, which would duplicate plumbing and invite drift.
|
|
241
|
+
|
|
242
|
+
## Chat Surface Theme Integration
|
|
243
|
+
|
|
244
|
+
The shared session-chat surface (`ChatInterface` and `ChatInputArea` in `packages/ui/src/components/chat/`) follows the same Mantine token system as all other `@repo/ui` panels.
|
|
245
|
+
|
|
246
|
+
**Unified panel.** `ChatInterface` renders a single Mantine `<Paper withBorder p={0}>` that wraps both the message scroll area and the input bar. The `ScrollableContainer` inside is transparent and scrolls; `ChatInputArea` is inset at the bottom (`px="sm" pb="sm" flexShrink: 0`). This matches the surface, border, radius, and shadow of sibling `<Paper withBorder p="sm">` panels (for example, `ResourceDefinitionSection` in `packages/ui/src/components/resource-definition/ResourceDefinitionSection.tsx`).
|
|
247
|
+
|
|
248
|
+
**Opaque input.** `ChatInputArea` uses `color-mix(in srgb, var(--color-text) 7%, var(--color-background))` as its fill instead of the translucent `--color-surface` token (`rgba(18,19,21,0.2)`). This makes the input bar read as a solid element rather than a glassy void.
|
|
249
|
+
|
|
250
|
+
**`messageAreaVariant` semantics.** The prop on `ChatInterface` now toggles paneled-vs-transparent on the scroll area. The grid/gradient/radial background is removed. The `variant` prop was dropped from `ScrollableContainer` (internal component) as it is no longer needed.
|
|
251
|
+
|
|
252
|
+
**Token guidance.** Never use hardcoded hex values or `mantine-gray-*` tokens for chat surface backgrounds. Use semantic tokens (`--color-background`, `--color-text`, `--glass-background`, `--glass-blur`) per `.claude/rules/theme-system.md`. A bare `<Paper>` is not automatically opaque in this theme -- several Paper variants render `rgba(0,0,0,0)`; the glass look comes from `withBorder` combined with the theme defaults.
|
|
253
|
+
|
|
254
|
+
## Knowledge Browser Customization
|
|
255
|
+
|
|
256
|
+
The Knowledge Browser follows the same pattern described in this document. The three tiers map directly:
|
|
257
|
+
|
|
258
|
+
- **Tier 1** -- import `knowledgeManifest` from `@elevasis/ui/features/knowledge` and pass it to `ElevasisSystemsProvider`. No further code required.
|
|
259
|
+
- **Tier 2** -- spread the manifest and override `sidebar` with a project-owned component. Same shape as the CRM example above. Note that the Knowledge Browser's own sidebar parts are internal: `@elevasis/ui/features/knowledge` publishes `knowledgeManifest` and nothing else, so compose from the published knowledge primitives instead.
|
|
260
|
+
- **Tier 3** -- skip the manifest, own the route, call `bySystem` / `byKind` / `byOwner` from `@elevasis/core/knowledge` directly.
|
|
261
|
+
|
|
262
|
+
One additional wiring step is required for Knowledge Browser that does not apply to CRM or Lead Gen: add `knowledgePlugin()` from `@elevasis/ui/vite-plugin-knowledge` to `vite.config.ts`. The plugin runs build-time MDX codegen so rendered body components are available at runtime.
|
|
263
|
+
|
|
264
|
+
See [recipes/customize-knowledge-browser.md](../recipes/customize-knowledge-browser.md) for the full walkthrough including code examples, the CSS import requirement, and the full exports reference.
|
|
265
|
+
|
|
266
|
+
Phase 1.5 adds a further extension surface documented in the same recipe file under the "Phase 1.5" section:
|
|
267
|
+
|
|
229
268
|
- **Replacing `DescribeNodeView`** -- override the `/knowledge/:nodeId` route component to swap the entire main-pane dispatcher, or wrap `DescribeNodeView` from `@elevasis/ui/knowledge` to intercept specific node-kind views while falling back to the platform defaults for the rest.
|
|
230
|
-
|
|
231
|
-
## What Not to Do
|
|
232
|
-
|
|
233
|
-
- **Don't fork sidebar files into your app tree.** You own upstream drift forever.
|
|
234
|
-
- **Don't redefine `NavItem` locally.** Import it from `@elevasis/ui/layout` so future shape changes stay coherent.
|
|
235
|
-
- **Don't monkey-patch `SYSTEM_MANIFESTS`.** It's a published convenience constant; consumers build their own manifest array and pass it to the provider.
|
|
236
|
-
- **Don't add discriminated-union sidebar configuration to manifests.** The single pattern (assign a component to `manifest.sidebar`) is intentional.
|
|
269
|
+
|
|
270
|
+
## What Not to Do
|
|
271
|
+
|
|
272
|
+
- **Don't fork sidebar files into your app tree.** You own upstream drift forever.
|
|
273
|
+
- **Don't redefine `NavItem` locally.** Import it from `@elevasis/ui/layout` so future shape changes stay coherent.
|
|
274
|
+
- **Don't monkey-patch `SYSTEM_MANIFESTS`.** It's a published convenience constant; consumers build their own manifest array and pass it to the provider.
|
|
275
|
+
- **Don't add discriminated-union sidebar configuration to manifests.** The single pattern (assign a component to `manifest.sidebar`) is intentional.
|
|
@@ -43,18 +43,26 @@ import { AccessGuard } from '@elevasis/ui/auth'
|
|
|
43
43
|
|
|
44
44
|
## Adding A Gated System
|
|
45
45
|
|
|
46
|
+
<!-- doc-snippet:skip: illustrative excerpt, not a standalone compilable file -->
|
|
47
|
+
|
|
46
48
|
```ts
|
|
47
|
-
{
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
systems: {
|
|
50
|
+
analytics: {
|
|
51
|
+
id: 'analytics',
|
|
52
|
+
order: 70,
|
|
53
|
+
label: 'Analytics',
|
|
54
|
+
lifecycle: 'active',
|
|
55
|
+
ui: { path: '/analytics' }
|
|
56
|
+
}
|
|
53
57
|
}
|
|
54
58
|
```
|
|
55
59
|
|
|
60
|
+
`order` is required. Sidebar placement is authored in `navigation.sidebar`, not via the deprecated top-level `uiPosition`.
|
|
61
|
+
|
|
56
62
|
Use the same System path in `AccessGuard accessKey` and `SystemModule.systemId`. For action-level checks, use the structured key shape:
|
|
57
63
|
|
|
64
|
+
<!-- doc-snippet:skip: illustrative excerpt, not a standalone compilable file -->
|
|
65
|
+
|
|
58
66
|
```ts
|
|
59
67
|
{ systemPath: 'analytics', action: 'manage' }
|
|
60
68
|
```
|