kimu-core 0.4.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.
- package/.editorconfig +30 -0
- package/.gitattributes +11 -0
- package/.github/FUNDING.yml +8 -0
- package/.github/copilot-instructions.md +103 -0
- package/.github/kimu-copilot-instructions.md +3779 -0
- package/.github/workflows/deploy-demo.yml +39 -0
- package/AUTHORS.md +20 -0
- package/CHANGELOG.md +20 -0
- package/CODE_GUIDELINES.md +165 -0
- package/CODE_OF_CONDUCT.md +47 -0
- package/CONTRIBUTING.md +62 -0
- package/FUNDING.md +31 -0
- package/ISSUE_GUIDELINES.md +74 -0
- package/LICENSE +17 -0
- package/LICENSE.it.md +17 -0
- package/MPL-2.0.txt +373 -0
- package/NOTICE +65 -0
- package/README-KIMU.md +40 -0
- package/README.it.md +208 -0
- package/README.md +266 -0
- package/SECURITY.md +64 -0
- package/docs/get-started-en.md +207 -0
- package/docs/images/icon.svg +64 -0
- package/docs/images/logo_kimu.png +0 -0
- package/docs/index.md +29 -0
- package/env/dev.config.json +6 -0
- package/env/local.config.json +6 -0
- package/env/prod.config.json +6 -0
- package/env/staging.config.json +6 -0
- package/env/test.config.json +4 -0
- package/icon.svg +10 -0
- package/logo_kimu.png +0 -0
- package/package.json +79 -0
- package/public/favicon.svg +64 -0
- package/public/logo_kimu.svg +1 -0
- package/scripts/build-all-config.js +59 -0
- package/scripts/build-all-core.js +65 -0
- package/scripts/build-all-extensions.js +64 -0
- package/scripts/build-all-modules.js +99 -0
- package/scripts/build-extension.js +60 -0
- package/scripts/clear-kimu-build.js +31 -0
- package/scripts/generate-kimu-build-config.js +79 -0
- package/scripts/install-module.js +162 -0
- package/scripts/list-modules.js +109 -0
- package/scripts/minify-css-assets.js +82 -0
- package/scripts/remove-module.js +122 -0
- package/scripts/utils/fix-imports.js +85 -0
- package/src/assets/index.css +43 -0
- package/src/assets/kimu-style.css +84 -0
- package/src/assets/style.css +116 -0
- package/src/config/kimu-base-config.json +5 -0
- package/src/core/index.ts +47 -0
- package/src/core/kimu-app.ts +76 -0
- package/src/core/kimu-asset-manager.ts +167 -0
- package/src/core/kimu-component-element.ts +325 -0
- package/src/core/kimu-component.ts +33 -0
- package/src/core/kimu-engine.ts +188 -0
- package/src/core/kimu-extension-manager.ts +281 -0
- package/src/core/kimu-global-styles.ts +136 -0
- package/src/core/kimu-module-manager.ts +69 -0
- package/src/core/kimu-module.ts +21 -0
- package/src/core/kimu-path-config.ts +127 -0
- package/src/core/kimu-reactive.ts +196 -0
- package/src/core/kimu-render.ts +91 -0
- package/src/core/kimu-store.ts +147 -0
- package/src/core/kimu-types.ts +65 -0
- package/src/extensions/.gitkeep +0 -0
- package/src/extensions/extensions-manifest.json +13 -0
- package/src/extensions/kimu-home/component.ts +80 -0
- package/src/extensions/kimu-home/lang/en.json +5 -0
- package/src/extensions/kimu-home/lang/it.json +5 -0
- package/src/extensions/kimu-home/style.css +61 -0
- package/src/extensions/kimu-home/view.html +51 -0
- package/src/index.html +26 -0
- package/src/main.ts +68 -0
- package/src/modules/.gitkeep +0 -0
- package/src/modules/README.md +79 -0
- package/src/modules/i18n/README.it.md +63 -0
- package/src/modules/i18n/README.md +63 -0
- package/src/modules/i18n/kimu-global-lang.ts +26 -0
- package/src/modules/i18n/kimu-i18n-service.ts +108 -0
- package/src/modules/i18n/manifest.json +22 -0
- package/src/modules/i18n/module.ts +39 -0
- package/src/modules/modules-manifest.json +12 -0
- package/src/modules-repository/README.md +108 -0
- package/src/modules-repository/api-axios/CHANGELOG.md +48 -0
- package/src/modules-repository/api-axios/QUICK-REFERENCE.md +178 -0
- package/src/modules-repository/api-axios/README.md +304 -0
- package/src/modules-repository/api-axios/api-axios-service.ts +355 -0
- package/src/modules-repository/api-axios/examples.ts +293 -0
- package/src/modules-repository/api-axios/index.ts +19 -0
- package/src/modules-repository/api-axios/interfaces.ts +71 -0
- package/src/modules-repository/api-axios/module.ts +41 -0
- package/src/modules-repository/api-core/CHANGELOG.md +42 -0
- package/src/modules-repository/api-core/QUICK-REFERENCE.md +192 -0
- package/src/modules-repository/api-core/README.md +435 -0
- package/src/modules-repository/api-core/api-core-service.ts +289 -0
- package/src/modules-repository/api-core/examples.ts +432 -0
- package/src/modules-repository/api-core/index.ts +8 -0
- package/src/modules-repository/api-core/interfaces.ts +83 -0
- package/src/modules-repository/api-core/module.ts +30 -0
- package/src/modules-repository/event-bus/README.md +273 -0
- package/src/modules-repository/event-bus/event-bus-service.ts +176 -0
- package/src/modules-repository/event-bus/module.ts +30 -0
- package/src/modules-repository/i18n/README.it.md +63 -0
- package/src/modules-repository/i18n/README.md +63 -0
- package/src/modules-repository/i18n/kimu-global-lang.ts +26 -0
- package/src/modules-repository/i18n/kimu-i18n-service.ts +108 -0
- package/src/modules-repository/i18n/manifest.json +22 -0
- package/src/modules-repository/i18n/module.ts +39 -0
- package/src/modules-repository/notification/README.md +423 -0
- package/src/modules-repository/notification/module.ts +30 -0
- package/src/modules-repository/notification/notification-service.ts +436 -0
- package/src/modules-repository/router/README.it.md +39 -0
- package/src/modules-repository/router/README.md +39 -0
- package/src/modules-repository/router/manifest.json +21 -0
- package/src/modules-repository/router/module.ts +23 -0
- package/src/modules-repository/router/router.ts +144 -0
- package/src/modules-repository/state/README.md +409 -0
- package/src/modules-repository/state/module.ts +30 -0
- package/src/modules-repository/state/state-service.ts +296 -0
- package/src/modules-repository/theme/README.md +267 -0
- package/src/modules-repository/theme/module.ts +30 -0
- package/src/modules-repository/theme/pre-build.js +40 -0
- package/src/modules-repository/theme/theme-service.ts +389 -0
- package/src/modules-repository/theme/themes/theme-cherry-blossom.css +78 -0
- package/src/modules-repository/theme/themes/theme-cozy.css +111 -0
- package/src/modules-repository/theme/themes/theme-cyberpunk.css +150 -0
- package/src/modules-repository/theme/themes/theme-dark.css +79 -0
- package/src/modules-repository/theme/themes/theme-forest.css +171 -0
- package/src/modules-repository/theme/themes/theme-gold.css +100 -0
- package/src/modules-repository/theme/themes/theme-high-contrast.css +126 -0
- package/src/modules-repository/theme/themes/theme-lava.css +101 -0
- package/src/modules-repository/theme/themes/theme-lavender.css +90 -0
- package/src/modules-repository/theme/themes/theme-light.css +79 -0
- package/src/modules-repository/theme/themes/theme-matrix.css +103 -0
- package/src/modules-repository/theme/themes/theme-midnight.css +81 -0
- package/src/modules-repository/theme/themes/theme-nord.css +94 -0
- package/src/modules-repository/theme/themes/theme-ocean.css +84 -0
- package/src/modules-repository/theme/themes/theme-retro80s.css +343 -0
- package/src/modules-repository/theme/themes/theme-sunset.css +62 -0
- package/src/modules-repository/theme/themes-config.d.ts +27 -0
- package/src/modules-repository/theme/themes-config.json +213 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +33 -0
- package/vite.config.ts +99 -0
|
@@ -0,0 +1,3779 @@
|
|
|
1
|
+
# KIMU Framework - Complete AI Agent Reference Guide
|
|
2
|
+
|
|
3
|
+
> **Purpose:** This file provides **comprehensive and complete** instructions for AI agents (GitHub Copilot, Claude, ChatGPT, etc.) to understand and work with the KIMU framework. This is a **self-contained, complete reference** - you should not need any other documentation to work effectively with KIMU.
|
|
4
|
+
|
|
5
|
+
> **Agent Training Note:** To generate correct, robust, and maintainable code, you MUST read and follow not only the main guidelines below, but also all subchapters such as **Practical Examples**, **FAQ & Troubleshooting**, **Testing & Quality Assurance**, **Advanced Usage**, **Glossary**, **Modules**, **Router**, and **i18n** in **KIMU-Core**.. These sections contain essential rules, conventions, edge cases, and best practices. Always consult them when generating or modifying code.
|
|
6
|
+
|
|
7
|
+
This document provides direct, actionable instructions for Copilot and AI agents to support development and extension of the kimu-core framework. All content is specific to kimu-core.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## 📋 Quick Start for New Projects
|
|
12
|
+
|
|
13
|
+
### ⚡ Simple Setup (Recommended)
|
|
14
|
+
|
|
15
|
+
**Clone kimu-core as your project base:**
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Clone kimu-core repository with all files
|
|
19
|
+
git clone https://github.com/UnicoVerso/kimu-core.git my-kimu-app
|
|
20
|
+
cd my-kimu-app
|
|
21
|
+
|
|
22
|
+
# Remove git history (optional, to start fresh)
|
|
23
|
+
rm -rf .git
|
|
24
|
+
git init
|
|
25
|
+
|
|
26
|
+
# Install dependencies
|
|
27
|
+
npm install
|
|
28
|
+
|
|
29
|
+
# Start developing
|
|
30
|
+
npm start
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**What you get:**
|
|
34
|
+
- ✅ Complete project structure already set up
|
|
35
|
+
- ✅ `.github/kimu-copilot-instructions.md` already present (this file - for AI training)
|
|
36
|
+
- ✅ `.github/copilot-instructions.md` for project-specific rules (you can customize)
|
|
37
|
+
- ✅ All framework code in `src/`
|
|
38
|
+
- ✅ Example extensions to learn from
|
|
39
|
+
- ✅ **AI agent immediately trained on KIMU!**
|
|
40
|
+
|
|
41
|
+
**Then customize:**
|
|
42
|
+
```bash
|
|
43
|
+
# Update package.json with your project name
|
|
44
|
+
# Create your extensions in src/extensions/
|
|
45
|
+
# Modify .github/copilot-instructions.md for project rules
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 🎯 What Happens After Setup
|
|
49
|
+
|
|
50
|
+
Your AI agent will automatically:
|
|
51
|
+
- Read `.github/kimu-copilot-instructions.md` (this file) for complete KIMU knowledge
|
|
52
|
+
- Understand all framework concepts, patterns, and best practices
|
|
53
|
+
- Generate correct KIMU code with proper lifecycle methods
|
|
54
|
+
- Follow extension and module creation guidelines
|
|
55
|
+
|
|
56
|
+
**You can immediately:**
|
|
57
|
+
- Customize `.github/copilot-instructions.md` for project-specific rules
|
|
58
|
+
- Start creating extensions in `src/extensions/`
|
|
59
|
+
- Use reactive properties with `@property` decorator for automatic re-rendering
|
|
60
|
+
- Add modules in `src/modules/`
|
|
61
|
+
- Run `npm start` to see your app
|
|
62
|
+
|
|
63
|
+
**Quick example - Create a reactive component:**
|
|
64
|
+
```typescript
|
|
65
|
+
import { property } from '../core/kimu-reactive';
|
|
66
|
+
|
|
67
|
+
@KimuComponent({
|
|
68
|
+
tag: 'my-counter',
|
|
69
|
+
name: 'Counter',
|
|
70
|
+
// ... metadata
|
|
71
|
+
})
|
|
72
|
+
export class CounterComponent extends KimuComponentElement {
|
|
73
|
+
@property({ type: Number })
|
|
74
|
+
count: number = 0;
|
|
75
|
+
|
|
76
|
+
increment() {
|
|
77
|
+
this.count++; // Auto-renders, no manual onRender() needed!
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
### 🔧 Alternative: Use as Dependency (Advanced)
|
|
85
|
+
|
|
86
|
+
If you want to keep kimu-core as a separate dependency:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
mkdir my-kimu-app && cd my-kimu-app
|
|
90
|
+
npm init -y
|
|
91
|
+
npm install git+https://github.com/UnicoVerso/kimu-core.git
|
|
92
|
+
npm install --save-dev typescript vite @types/node
|
|
93
|
+
|
|
94
|
+
# Copy framework documentation for AI agent
|
|
95
|
+
mkdir -p .github
|
|
96
|
+
cp node_modules/kimu-core/.github/kimu-copilot-instructions.md .github/
|
|
97
|
+
|
|
98
|
+
# Create your project structure
|
|
99
|
+
mkdir -p src/extensions public
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
This approach keeps kimu-core separate but requires manual project setup.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## How Copilot & AI Agents Should Use This File
|
|
107
|
+
|
|
108
|
+
> **Agent Training Note:** This file is your primary and complete reference for generating code, understanding conventions, and following best practices in KIMU-Core. It contains all essential guidelines, examples, and patterns that you must follow to ensure consistency, maintainability, and correctness in all generated code.
|
|
109
|
+
|
|
110
|
+
### Critical Reading Instructions
|
|
111
|
+
- **Use English** for all code comments, documentation, and metadata.
|
|
112
|
+
- **Read the entire document** to understand the project structure, conventions, and best practices for KIMU-Core.
|
|
113
|
+
- **Use the provided examples** as templates for creating new components and extensions.
|
|
114
|
+
- **Follow the coding conventions** and best practices described here and outlined in `CODE_GUIDELINES.md` and `CONTRIBUTING.md`.
|
|
115
|
+
- **Follow the guidelines** for component creation, extension development, and API usage.
|
|
116
|
+
- **Refer to the Practical Examples** section for implementation patterns, data binding, and best practices.
|
|
117
|
+
- **Use the FAQ & Troubleshooting** section for common issues and edge cases.
|
|
118
|
+
- **Use the Glossary** for precise definitions of key concepts and terminology.
|
|
119
|
+
- **Use the Modules in KIMU-Core** section to understand how to structure, document, and import reusable modules in the framework.
|
|
120
|
+
- **Use the Router Module Guide** for implementing routing functionality.
|
|
121
|
+
- **Use the Internationalization (i18n)** section for multi-language support.
|
|
122
|
+
- **Use the Extension Creation Guide** to ensure correct extension structure and registration.
|
|
123
|
+
- **Use concise, readable code** and clear documentation in all generated code.
|
|
124
|
+
- **Prefer modularity and reusability** in all components and extensions.
|
|
125
|
+
- **Propose changes** to this file if you identify missing patterns, conventions or best practices.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Project Overview & Structure
|
|
130
|
+
|
|
131
|
+
### What is KIMU-Core?
|
|
132
|
+
- KIMU-Core is a modular TypeScript framework for building web applications using Web Components. Organize your project as described below.
|
|
133
|
+
- All documentation, code comments, and metadata must be in English.
|
|
134
|
+
- Use the provided examples and templates for new components and extensions.
|
|
135
|
+
- Follow coding conventions described in this guide and in `CODE_GUIDELINES.md` and `CONTRIBUTING.md`.
|
|
136
|
+
|
|
137
|
+
### Core Philosophy
|
|
138
|
+
- **Minimal footprint**: Small bundle sizes and fast loading
|
|
139
|
+
- **Web Components**: Standards-based custom elements
|
|
140
|
+
- **TypeScript-first**: Type safety and developer experience
|
|
141
|
+
- **Modular architecture**: Install only what you need
|
|
142
|
+
- **Developer productivity**: Simple APIs and clear patterns
|
|
143
|
+
|
|
144
|
+
## Project Structure
|
|
145
|
+
|
|
146
|
+
Organize your kimu-core project as follows:
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
project-root/
|
|
150
|
+
│
|
|
151
|
+
├── src/ # Main source code
|
|
152
|
+
│ ├── main.ts # Application entry point
|
|
153
|
+
│ │
|
|
154
|
+
│ ├── core/ # Core framework extensions, Base classes, decorators, and core APIs (if any)
|
|
155
|
+
│ │ └── ... # Custom base classes or utilities
|
|
156
|
+
│ │
|
|
157
|
+
│ ├── extensions/ # Application extensions (components). Custom extensions and scenarios
|
|
158
|
+
│ │ ├── my-extension/
|
|
159
|
+
│ │ │ ├── component.ts # Extension logic (required)
|
|
160
|
+
│ │ │ ├── style.css # Extension styles (required)
|
|
161
|
+
│ │ │ └── view.html # Extension template (required)
|
|
162
|
+
│ │ └── ...
|
|
163
|
+
│ │
|
|
164
|
+
│ ├── modules/ # Optional modules (services, utilities)
|
|
165
|
+
│ │ ├── router/ # Router module (if using)
|
|
166
|
+
│ │ ├── i18n/ # Internationalization
|
|
167
|
+
│ │ ├── theme/ # Theme management
|
|
168
|
+
│ │ └── ...
|
|
169
|
+
│ │
|
|
170
|
+
│ ├── utils/ # Utility/helper functions
|
|
171
|
+
│ │ └── helpers.ts
|
|
172
|
+
│ │
|
|
173
|
+
│ ├── models/ # Data models and types (if needed)
|
|
174
|
+
│ │ └── types.ts
|
|
175
|
+
│ │
|
|
176
|
+
│ └── assets/ # Static assets
|
|
177
|
+
│ ├── images/
|
|
178
|
+
│ ├── fonts/
|
|
179
|
+
│ └── styles/
|
|
180
|
+
│
|
|
181
|
+
├── public/ # Public static files
|
|
182
|
+
│ ├── favicon.ico
|
|
183
|
+
│ └── assets/
|
|
184
|
+
│
|
|
185
|
+
├── tests/ # Unit and integration tests
|
|
186
|
+
│ ├── extensions/
|
|
187
|
+
│ └── modules/
|
|
188
|
+
│
|
|
189
|
+
├── scripts/ # Utility scripts and CLI tools
|
|
190
|
+
│
|
|
191
|
+
├── docs/ # Documentation and guides
|
|
192
|
+
│
|
|
193
|
+
├── dist/ # Production build output (generated)
|
|
194
|
+
│
|
|
195
|
+
├── .github/ # GitHub configuration. GitHub workflows, Copilot instructions, etc.
|
|
196
|
+
│ ├── kimu-copilot-instructions.md # This guide for kimu-core framework specific instructions
|
|
197
|
+
│ ├── copilot-instructions.md # Project-specific instructions
|
|
198
|
+
│ └── workflows/ # CI/CD workflows
|
|
199
|
+
│
|
|
200
|
+
├── extension-manifest.json # Extension registry
|
|
201
|
+
├── package.json # NPM configuration and scripts
|
|
202
|
+
├── tsconfig.json # TypeScript configuration
|
|
203
|
+
├── vite.config.ts # Vite build configuration
|
|
204
|
+
├── .env # Environment variables (if needed)
|
|
205
|
+
├── .gitignore # Git ignore rules
|
|
206
|
+
├── README.md # Project documentation, overview and usage
|
|
207
|
+
├── CODE_GUIDELINES.md # Coding standards, conventions and style rules (optional)
|
|
208
|
+
├── CONTRIBUTING.md # Contribution guidelines (optional)
|
|
209
|
+
├── LICENSE # License file
|
|
210
|
+
├── SECURITY.md # Security policy (optional)
|
|
211
|
+
└── ... # Other project files
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Key Directories Explained
|
|
215
|
+
|
|
216
|
+
- **`src/extensions/`**: Contains all UI components/extensions. Each extension must have `component.ts`, `style.css`, and `view.html`.
|
|
217
|
+
- **`src/modules/`**: Reusable services and utilities (router, i18n, theme, etc.). Each module exports a service class.
|
|
218
|
+
- **`src/core/`**: Framework-specific code or custom base classes (usually empty in application projects).
|
|
219
|
+
- **`src/utils/`**: Helper functions and shared utilities.
|
|
220
|
+
- **`public/`**: Static assets served directly without processing.
|
|
221
|
+
- **`dist/`**: Build output directory (automatically generated, should be in `.gitignore`).
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## Core Concepts
|
|
226
|
+
|
|
227
|
+
### 1. Components and Extensions
|
|
228
|
+
|
|
229
|
+
**Component**: The base unit of UI in KIMU. All components extend `KimuComponentElement`.
|
|
230
|
+
|
|
231
|
+
**Extension**: A complete feature or page, consisting of three files:
|
|
232
|
+
- `component.ts`: Logic and lifecycle methods
|
|
233
|
+
- `style.css`: Component-specific styles
|
|
234
|
+
- `view.html`: HTML template with interpolation
|
|
235
|
+
|
|
236
|
+
### 2. Lifecycle Methods
|
|
237
|
+
|
|
238
|
+
Every KIMU component has these lifecycle hooks:
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
export class MyComponent extends KimuComponentElement {
|
|
242
|
+
// Called when component is created
|
|
243
|
+
onInit() {
|
|
244
|
+
// Initialize data, set up state
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Called to render/update UI
|
|
248
|
+
onRender() {
|
|
249
|
+
// Update DOM, bind data to template
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Called when component is destroyed
|
|
253
|
+
onDestroy() {
|
|
254
|
+
// Clean up resources, remove listeners
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### 3. Template Engine
|
|
260
|
+
|
|
261
|
+
KIMU uses simple string interpolation in `view.html`:
|
|
262
|
+
|
|
263
|
+
```html
|
|
264
|
+
<div>
|
|
265
|
+
<h1>${title}</h1>
|
|
266
|
+
<p>${description}</p>
|
|
267
|
+
<button onclick="${handleClick}">Click me</button>
|
|
268
|
+
</div>
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Variables are provided by the `getData()` method in `component.ts`:
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
getData() {
|
|
275
|
+
return {
|
|
276
|
+
title: this.title,
|
|
277
|
+
description: this.description,
|
|
278
|
+
handleClick: () => this.onClick()
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### 4. Component Decorator
|
|
284
|
+
|
|
285
|
+
Every extension must use the `@KimuComponent` decorator:
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
@KimuComponent({
|
|
289
|
+
tag: 'my-component', // HTML tag name
|
|
290
|
+
name: 'My Component', // Display name
|
|
291
|
+
version: '1.0.0', // Semantic version
|
|
292
|
+
description: 'A sample component', // Short description
|
|
293
|
+
author: 'Your Name', // Author name
|
|
294
|
+
icon: '🧩', // Emoji icon
|
|
295
|
+
internal: false, // Is internal component?
|
|
296
|
+
path: 'my-component', // File path (folder name)
|
|
297
|
+
dependencies: [] // Child extension tags
|
|
298
|
+
})
|
|
299
|
+
export class MyComponent extends KimuComponentElement {
|
|
300
|
+
// ...
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### 5. DOM Selection and Manipulation
|
|
305
|
+
|
|
306
|
+
Use `this.$()` method for safe DOM selection within your component:
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
onRender() {
|
|
310
|
+
// Select element by ID
|
|
311
|
+
const button = this.$('#myButton');
|
|
312
|
+
|
|
313
|
+
// Select element by class
|
|
314
|
+
const header = this.$('.header');
|
|
315
|
+
|
|
316
|
+
// Update content
|
|
317
|
+
if (button) {
|
|
318
|
+
button.textContent = 'Updated!';
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### 6. Event Handling
|
|
324
|
+
|
|
325
|
+
Bind events in the template or in code:
|
|
326
|
+
|
|
327
|
+
**In template:**
|
|
328
|
+
```html
|
|
329
|
+
<button onclick="${handleClick}">Click</button>
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
**In component:**
|
|
333
|
+
```typescript
|
|
334
|
+
onInit() {
|
|
335
|
+
const button = this.$('#myButton');
|
|
336
|
+
button?.addEventListener('click', () => this.handleClick());
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### 7. Modules
|
|
341
|
+
|
|
342
|
+
Modules are services that provide reusable functionality. All modules:
|
|
343
|
+
- Extend `KimuModule`
|
|
344
|
+
- Provide a service via `getService()`
|
|
345
|
+
- Are imported and initialized in `main.ts`
|
|
346
|
+
|
|
347
|
+
Example module structure:
|
|
348
|
+
```
|
|
349
|
+
src/modules/my-module/
|
|
350
|
+
├── module.ts # Module class
|
|
351
|
+
├── my-module-service.ts # Service implementation
|
|
352
|
+
└── types.ts # Type definitions
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### 8. Reactive Properties
|
|
356
|
+
|
|
357
|
+
KIMU provides a reactive property system inspired by Lit and Vue 3. Reactive properties automatically trigger component re-renders when their values change, eliminating the need for manual `onRender()` calls.
|
|
358
|
+
|
|
359
|
+
#### Using the @property Decorator
|
|
360
|
+
|
|
361
|
+
The `@property` decorator makes class properties reactive:
|
|
362
|
+
|
|
363
|
+
```typescript
|
|
364
|
+
import { property } from '../core/kimu-reactive';
|
|
365
|
+
|
|
366
|
+
@KimuComponent({
|
|
367
|
+
tag: 'counter-component',
|
|
368
|
+
name: 'Counter',
|
|
369
|
+
// ... other metadata
|
|
370
|
+
})
|
|
371
|
+
export class CounterComponent extends KimuComponentElement {
|
|
372
|
+
// Reactive property with type conversion
|
|
373
|
+
@property({ type: Number })
|
|
374
|
+
count: number = 0;
|
|
375
|
+
|
|
376
|
+
// Reactive property with attribute reflection
|
|
377
|
+
@property({ type: String, reflect: true })
|
|
378
|
+
message: string = 'Hello';
|
|
379
|
+
|
|
380
|
+
// Reactive property without auto-render
|
|
381
|
+
@property({ type: Boolean, noRender: false })
|
|
382
|
+
isActive: boolean = false;
|
|
383
|
+
|
|
384
|
+
increment() {
|
|
385
|
+
this.count++; // Automatically triggers re-render
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
#### Property Options
|
|
391
|
+
|
|
392
|
+
Configure reactive properties with these options:
|
|
393
|
+
|
|
394
|
+
```typescript
|
|
395
|
+
interface PropertyOptions {
|
|
396
|
+
type?: PropertyType; // String | Number | Boolean | Array | Object
|
|
397
|
+
reflect?: boolean; // Reflect property to attribute (default: false)
|
|
398
|
+
attribute?: string | false; // Custom attribute name or disable sync
|
|
399
|
+
converter?: PropertyConverter; // Custom type converter
|
|
400
|
+
noRender?: boolean; // Skip auto-render (default: false)
|
|
401
|
+
}
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
**Example with all options:**
|
|
405
|
+
|
|
406
|
+
```typescript
|
|
407
|
+
@property({
|
|
408
|
+
type: Number,
|
|
409
|
+
reflect: true, // Sync to HTML attribute
|
|
410
|
+
attribute: 'data-count', // Use custom attribute name
|
|
411
|
+
converter: { // Custom converter
|
|
412
|
+
fromAttribute: (value) => parseInt(value || '0'),
|
|
413
|
+
toAttribute: (value) => value.toString()
|
|
414
|
+
},
|
|
415
|
+
noRender: false // Enable auto-render
|
|
416
|
+
})
|
|
417
|
+
count: number = 0;
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
#### Using the reactive() Function
|
|
421
|
+
|
|
422
|
+
For Vue-style reactivity with objects and arrays:
|
|
423
|
+
|
|
424
|
+
```typescript
|
|
425
|
+
import { reactive, isReactive, toRaw } from '../core/kimu-reactive';
|
|
426
|
+
|
|
427
|
+
export class DataComponent extends KimuComponentElement {
|
|
428
|
+
// Create reactive object
|
|
429
|
+
private state = reactive({
|
|
430
|
+
user: { name: 'John', age: 30 },
|
|
431
|
+
items: [1, 2, 3]
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
onInit() {
|
|
435
|
+
// Deep reactivity - nested changes trigger re-render
|
|
436
|
+
this.state.user.name = 'Jane'; // ✅ Triggers re-render
|
|
437
|
+
this.state.items.push(4); // ✅ Triggers re-render
|
|
438
|
+
|
|
439
|
+
// Check if object is reactive
|
|
440
|
+
console.log(isReactive(this.state)); // true
|
|
441
|
+
|
|
442
|
+
// Get original non-reactive object
|
|
443
|
+
const original = toRaw(this.state);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
#### Attribute Reflection
|
|
449
|
+
|
|
450
|
+
Properties can sync with HTML attributes:
|
|
451
|
+
|
|
452
|
+
```typescript
|
|
453
|
+
@property({ type: String, reflect: true, attribute: 'user-name' })
|
|
454
|
+
userName: string = 'John';
|
|
455
|
+
|
|
456
|
+
// HTML usage:
|
|
457
|
+
// <my-component user-name="Jane"></my-component>
|
|
458
|
+
// Component receives: this.userName = "Jane"
|
|
459
|
+
|
|
460
|
+
// Changing property updates attribute:
|
|
461
|
+
this.userName = "Bob"; // Attribute becomes: user-name="Bob"
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
#### Type Conversion
|
|
465
|
+
|
|
466
|
+
Built-in converters handle common types:
|
|
467
|
+
|
|
468
|
+
```typescript
|
|
469
|
+
@property({ type: Number })
|
|
470
|
+
age: number = 0; // "25" (string) → 25 (number)
|
|
471
|
+
|
|
472
|
+
@property({ type: Boolean })
|
|
473
|
+
active: boolean = false; // "true" → true, "" → true, null → false
|
|
474
|
+
|
|
475
|
+
@property({ type: Array })
|
|
476
|
+
tags: string[] = []; // '["a","b"]' → ["a", "b"]
|
|
477
|
+
|
|
478
|
+
@property({ type: Object })
|
|
479
|
+
config: object = {}; // '{"key":"value"}' → { key: "value" }
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
#### Best Practices
|
|
483
|
+
|
|
484
|
+
**✅ DO:**
|
|
485
|
+
- Use `@property` for all component state that affects rendering
|
|
486
|
+
- Use `reflect: true` for properties that should sync with HTML attributes
|
|
487
|
+
- Use appropriate `type` option for automatic type conversion
|
|
488
|
+
- Use `noRender: true` for properties that don't affect UI
|
|
489
|
+
|
|
490
|
+
```typescript
|
|
491
|
+
@property({ type: String, reflect: true })
|
|
492
|
+
userName: string = ''; // ✅ Good: automatic render + attribute sync
|
|
493
|
+
|
|
494
|
+
@property({ type: Number })
|
|
495
|
+
private count: number = 0; // ✅ Good: reactive internal state
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
**❌ DON'T:**
|
|
499
|
+
- Don't call `onRender()` manually when using reactive properties
|
|
500
|
+
- Don't use `@property` on methods or getters
|
|
501
|
+
- Don't mutate reactive objects directly if you need the original
|
|
502
|
+
|
|
503
|
+
```typescript
|
|
504
|
+
@property({ type: Number })
|
|
505
|
+
count: number = 0;
|
|
506
|
+
|
|
507
|
+
increment() {
|
|
508
|
+
this.count++;
|
|
509
|
+
this.onRender(); // ❌ BAD: redundant, auto-render already happens
|
|
510
|
+
}
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
#### Performance Optimization
|
|
514
|
+
|
|
515
|
+
Reactive properties use requestAnimationFrame batching:
|
|
516
|
+
|
|
517
|
+
```typescript
|
|
518
|
+
// Multiple property changes in one cycle = single render
|
|
519
|
+
this.count = 1;
|
|
520
|
+
this.message = 'Hello';
|
|
521
|
+
this.active = true;
|
|
522
|
+
// Only one re-render happens after this frame
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
Disable auto-render for performance-critical properties:
|
|
526
|
+
|
|
527
|
+
```typescript
|
|
528
|
+
@property({ type: Number, noRender: true })
|
|
529
|
+
internalCounter: number = 0;
|
|
530
|
+
|
|
531
|
+
updateCounter() {
|
|
532
|
+
this.internalCounter++; // No re-render
|
|
533
|
+
// Manually trigger render when ready
|
|
534
|
+
if (this.internalCounter % 10 === 0) {
|
|
535
|
+
this.onRender();
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
#### Migration from Manual Rendering
|
|
541
|
+
|
|
542
|
+
**Before (manual refresh):**
|
|
543
|
+
```typescript
|
|
544
|
+
export class OldComponent extends KimuComponentElement {
|
|
545
|
+
private count: number = 0;
|
|
546
|
+
|
|
547
|
+
increment() {
|
|
548
|
+
this.count++;
|
|
549
|
+
this.onRender(); // Manual render call
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
**After (reactive properties):**
|
|
555
|
+
```typescript
|
|
556
|
+
export class NewComponent extends KimuComponentElement {
|
|
557
|
+
@property({ type: Number })
|
|
558
|
+
count: number = 0;
|
|
559
|
+
|
|
560
|
+
increment() {
|
|
561
|
+
this.count++; // Auto-render, no manual call needed
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
**Benefits:**
|
|
567
|
+
- ✅ ~40% less boilerplate code
|
|
568
|
+
- ✅ Automatic re-rendering
|
|
569
|
+
- ✅ Better developer experience
|
|
570
|
+
- ✅ Type-safe with TypeScript
|
|
571
|
+
- ✅ Attribute synchronization
|
|
572
|
+
|
|
573
|
+
---
|
|
574
|
+
|
|
575
|
+
## Development Guidelines
|
|
576
|
+
|
|
577
|
+
|
|
578
|
+
For details and advanced usage of component methods and APIs, refer to the Practical Examples and FAQ sections below.
|
|
579
|
+
- Use TypeScript for all source code.
|
|
580
|
+
- Follow naming conventions and style rules in `CODE_GUIDELINES.md`.
|
|
581
|
+
- Keep business logic separate from UI code.
|
|
582
|
+
- Document all public classes, methods, and APIs in English.
|
|
583
|
+
- Use clear, concise comments for complex logic.
|
|
584
|
+
- Prefer modular, reusable code.
|
|
585
|
+
- Use lifecycle methods (`onInit`, `onRender`, etc.) for component logic.
|
|
586
|
+
- Use provided APIs for DOM selection, event handling, data binding, and state management (see Practical Examples section).
|
|
587
|
+
- Avoid direct DOM manipulation; always use framework APIs for rendering and events.
|
|
588
|
+
- Write unit and integration tests for all new features and extensions.
|
|
589
|
+
- Run `npm run lint` and use a code formatter before each commit.
|
|
590
|
+
- Follow semantic commit messages and update the changelog for every release.
|
|
591
|
+
- Document edge cases and expected behaviors in code and tests.
|
|
592
|
+
- When using external dependencies (e.g., Three.js, MediaPipe), follow modular patterns and update documentation accordingly.
|
|
593
|
+
- Update documentation and this guide with every new feature or convention.
|
|
594
|
+
- Use the `@KimuComponent` decorator for all components in `/src/extensions/`.
|
|
595
|
+
- Use `KimuComponentElement` as the base class for all UI components.
|
|
596
|
+
- Use `@KimuComponent` metadata to define component properties (tag, name, version, description, author, icon, internal status, path, dependencies).
|
|
597
|
+
- Use `onInit`, `onRender`, and other lifecycle methods for component logic.
|
|
598
|
+
- Use `this.$('#elementId')` for DOM element selection within components.
|
|
599
|
+
- Use `this.onRender()` to trigger UI updates.
|
|
600
|
+
- Use `this.onEvent('eventName', callback)` for event handling.
|
|
601
|
+
- Use `this.trackEvent('eventName', data)` for tracking events.
|
|
602
|
+
- Use `this.bindData('propertyName', elementId)` for data binding.
|
|
603
|
+
- Use `this.setState({ key: value })` for reactive state management.
|
|
604
|
+
- Use `this.getState('key')` to retrieve reactive state values.
|
|
605
|
+
- Use `this.$emit('eventName', data)` to emit custom events.
|
|
606
|
+
- Use `this.$on('eventName', callback)` to listen for custom events.
|
|
607
|
+
- Use `this.$off('eventName', callback)` to remove event listeners.
|
|
608
|
+
- Use `this.$watch('propertyName', callback)` for reactive property changes.
|
|
609
|
+
- Use `this.$destroy()` to clean up resources when a component is removed.
|
|
610
|
+
- Use `this.$refs['refName']` to access DOM elements with refs.
|
|
611
|
+
- Use `this.$slots['slotName']` to access named slots in components.
|
|
612
|
+
- Use `this.$children` to access child components.
|
|
613
|
+
- Use `this.$parent` to access the parent component.
|
|
614
|
+
- Use `this.$root` to access the root component.
|
|
615
|
+
- Use `this.$emit('update:modelValue', value)` for two-way data binding with v-model.
|
|
616
|
+
- Use `this.$nextTick(callback)` to execute code after the next DOM update cycle.
|
|
617
|
+
- Use `this.$forceUpdate()` to force a re-render of the component.
|
|
618
|
+
- Use `this.$set(object, key, value)` to set a property on an object reactively.
|
|
619
|
+
- Use `this.$delete(object, key)` to delete a property from an object reactively.
|
|
620
|
+
- Use `this.$refs` to access DOM elements or child components by reference.
|
|
621
|
+
- Use `this.$watchEffect(callback)` for reactive effects that run on data changes.
|
|
622
|
+
- Use `this.$computed` to define computed properties in components.
|
|
623
|
+
- Use `this.$provide(key, value)` to provide values to child components.
|
|
624
|
+
- Use `this.$inject(key)` to inject values from parent components.
|
|
625
|
+
- Use `this.$emit('hook:beforeDestroy')` to run cleanup logic before the component is destroyed.
|
|
626
|
+
- Use `this.$emit('hook:mounted')` to run logic after the component is mounted.
|
|
627
|
+
- Use `this.$emit('hook:updated')` to run logic after the component is updated.
|
|
628
|
+
- Use `this.$emit('hook:created')` to run logic when the component is created.
|
|
629
|
+
- Use `this.$emit('hook:activated')` for components that can be activated.
|
|
630
|
+
- Use `this.$emit('hook:deactivated')` for components that can be deactivated.
|
|
631
|
+
- Use `this.$emit('hook:errorCaptured', error)` to capture errors in child components.
|
|
632
|
+
- Use `this.$emit('hook:renderTracked', event)` to track rendering events.
|
|
633
|
+
- Use `this.$emit('hook:renderTriggered', event)` to trigger rendering events.
|
|
634
|
+
- Use `this.$emit('hook:beforeMount')` to run logic before the component is mounted.
|
|
635
|
+
- Use `this.$emit('hook:beforeUpdate')` to run logic before the component is updated.
|
|
636
|
+
- Use `this.$emit('hook:beforeDestroy')` to run logic before the component is destroyed.
|
|
637
|
+
- Use reactive properties and methods for data binding in components.
|
|
638
|
+
- Avoid direct DOM manipulation; use provided APIs for rendering and event handling.
|
|
639
|
+
|
|
640
|
+
### Code Style
|
|
641
|
+
- **Use TypeScript strict mode** for all code
|
|
642
|
+
- **Follow naming conventions**: camelCase for variables/functions, PascalCase for classes
|
|
643
|
+
- **Use explicit types**: Avoid `any`, prefer interfaces and type annotations
|
|
644
|
+
- **Keep functions small**: Max 50 lines, single responsibility
|
|
645
|
+
- **Use async/await**: Prefer over promises for readability
|
|
646
|
+
- **Document public APIs**: Use JSDoc comments for all exported functions/classes
|
|
647
|
+
|
|
648
|
+
### Component Best Practices
|
|
649
|
+
- **Separation of concerns**: Keep logic in `.ts`, styles in `.css`, markup in `.html`
|
|
650
|
+
- **Minimize state**: Only store what's necessary
|
|
651
|
+
- **Use reactive properties**: Prefer `@property` decorator and `reactive()` over manual `onRender()` calls
|
|
652
|
+
- **Avoid direct DOM manipulation**: Use `this.$()` and framework APIs
|
|
653
|
+
- **Clean up resources**: Always implement `onDestroy()` for cleanup
|
|
654
|
+
- **Use lifecycle methods**: Don't put initialization logic in constructor
|
|
655
|
+
|
|
656
|
+
### Reactive State Management Best Practices
|
|
657
|
+
- **Use @property for simple values**: Numbers, strings, booleans that may sync with attributes
|
|
658
|
+
- **Use reactive() for complex state**: Objects and arrays that need deep reactivity
|
|
659
|
+
- **Enable attribute reflection when needed**: Use `reflect: true` for properties that should sync with HTML attributes
|
|
660
|
+
- **Optimize performance**: Use `noRender: true` for properties that don't affect UI
|
|
661
|
+
- **Avoid manual onRender()**: Let reactive properties handle re-rendering automatically
|
|
662
|
+
- **Batch updates**: Multiple property changes in one frame = single render (automatic)
|
|
663
|
+
|
|
664
|
+
```typescript
|
|
665
|
+
// ✅ Good: Using reactive properties
|
|
666
|
+
@property({ type: Number })
|
|
667
|
+
count = 0;
|
|
668
|
+
|
|
669
|
+
increment() {
|
|
670
|
+
this.count++; // Auto-render
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// ❌ Bad: Manual state management
|
|
674
|
+
private count = 0;
|
|
675
|
+
|
|
676
|
+
increment() {
|
|
677
|
+
this.count++;
|
|
678
|
+
this.onRender(); // Manual, verbose
|
|
679
|
+
}
|
|
680
|
+
```
|
|
681
|
+
|
|
682
|
+
### File Organization
|
|
683
|
+
- **One component per folder**: Each extension has its own folder with three files
|
|
684
|
+
- **Group related code**: Keep related utilities and helpers together
|
|
685
|
+
- **Avoid deep nesting**: Max 3-4 levels of directory depth
|
|
686
|
+
- **Use index files**: Export public APIs from `index.ts` files
|
|
687
|
+
|
|
688
|
+
### Error Handling
|
|
689
|
+
- **Validate inputs**: Check all user inputs and external data
|
|
690
|
+
- **Provide helpful errors**: Include context in error messages
|
|
691
|
+
- **Use try-catch**: Wrap risky operations in try-catch blocks
|
|
692
|
+
- **Log appropriately**: Use console.log/warn/error with meaningful messages
|
|
693
|
+
|
|
694
|
+
### Performance
|
|
695
|
+
- **Lazy load**: Load components only when needed
|
|
696
|
+
- **Use reactive properties**: Automatic batching prevents excessive re-renders
|
|
697
|
+
- **Minimize manual re-renders**: Use `@property` and `reactive()` instead of manual `onRender()` calls
|
|
698
|
+
- **Use efficient selectors**: Cache DOM queries when possible
|
|
699
|
+
- **Debounce/throttle**: For frequently called functions (scroll, resize, input)
|
|
700
|
+
- **Use noRender option**: For properties that change frequently but don't affect UI
|
|
701
|
+
|
|
702
|
+
```typescript
|
|
703
|
+
// Reactive properties automatically batch updates
|
|
704
|
+
this.count = 1;
|
|
705
|
+
this.message = 'Hello';
|
|
706
|
+
this.active = true;
|
|
707
|
+
// Only ONE render happens (automatic batching via RAF)
|
|
708
|
+
|
|
709
|
+
// Use noRender for performance-critical properties
|
|
710
|
+
@property({ type: Number, noRender: true })
|
|
711
|
+
private fps: number = 0;
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
---
|
|
715
|
+
|
|
716
|
+
## Getting Started
|
|
717
|
+
1. Clone the repository from GitHub:
|
|
718
|
+
```sh
|
|
719
|
+
git clone https://github.com/UnicoVerso/kimu-core.git
|
|
720
|
+
```
|
|
721
|
+
2. Run `npm install` to install dependencies.
|
|
722
|
+
3. Use `npm start` to launch the development server.
|
|
723
|
+
4. Run `npm test` to execute tests.
|
|
724
|
+
5. Review `/docs/` for framework usage and extension examples.
|
|
725
|
+
|
|
726
|
+
## Installation & Configuration
|
|
727
|
+
- Node.js >= 18 required.
|
|
728
|
+
- Install dependencies: `npm install`
|
|
729
|
+
- Configure environment variables in `.env` if needed.
|
|
730
|
+
- For custom builds, use scripts in `/scripts/` or npm scripts in `package.json`.
|
|
731
|
+
|
|
732
|
+
## CLI Commands & Scripts
|
|
733
|
+
- `npm start`: Start development server
|
|
734
|
+
- `npm run build`: Build production bundle
|
|
735
|
+
- `npm test`: Run all tests
|
|
736
|
+
- `npm run lint`: Run linter
|
|
737
|
+
- Custom scripts in `/scripts/` (see script headers for usage)
|
|
738
|
+
|
|
739
|
+
## Build & Deployment
|
|
740
|
+
- Use `npm run build` for production builds.
|
|
741
|
+
- Output is in `/dist/`.
|
|
742
|
+
- Deploy static files as needed.
|
|
743
|
+
|
|
744
|
+
## Build & Script Commands Reference
|
|
745
|
+
> **Agent Reminder:** Use this section to understand and correctly use the available build, compile, and utility scripts in KIMU-Core projects.
|
|
746
|
+
|
|
747
|
+
### Common NPM Scripts
|
|
748
|
+
|
|
749
|
+
| Command | Description | When to Use |
|
|
750
|
+
|--------------------|------------------------------------------------------------------|--------------------------------------------------|
|
|
751
|
+
| `npm start` | Starts the development server with hot reload. | During development for live preview and testing. |
|
|
752
|
+
| `npm run build` | Builds the project for production (output in `/dist/`). | Before deployment or to generate production files.|
|
|
753
|
+
| `npm test` | Runs all unit and integration tests. | To validate code before commit or release. |
|
|
754
|
+
| `npm run lint` | Runs the linter to check code style and errors. | Before commit, after major changes, or regularly. |
|
|
755
|
+
| `npm run format` | Formats code using the configured formatter (if available). | To ensure code style consistency. |
|
|
756
|
+
| `npm run docs` | Generates or serves documentation (if configured). | When updating or reviewing project docs. |
|
|
757
|
+
| `npm run clean` | Cleans build artifacts and temporary files. | Before a fresh build or troubleshooting issues. |
|
|
758
|
+
|
|
759
|
+
### How to Use Each Script
|
|
760
|
+
- **Development (`npm start`)**: Use this to launch the local dev server. Supports hot reload for rapid iteration. Stop and restart if you change major config files.
|
|
761
|
+
- **Build (`npm run build`)**: Generates optimized production files. Run before deploying to production or sharing a release build.
|
|
762
|
+
- **Test (`npm test`)**: Validates all logic and integration. Run before pushing changes or merging PRs. Add new tests for new features.
|
|
763
|
+
- **Lint (`npm run lint`)**: Ensures code quality and style. Run after major edits and before commits. Fix all reported issues.
|
|
764
|
+
- **Format (`npm run format`)**: Applies code formatting rules. Use before commit or after resolving merge conflicts.
|
|
765
|
+
- **Docs (`npm run docs`)**: Builds or serves documentation. Use when updating docs or reviewing API changes.
|
|
766
|
+
- **Clean (`npm run clean`)**: Removes build output and temp files. Use before a new build or if you encounter build errors.
|
|
767
|
+
|
|
768
|
+
### Best Practices
|
|
769
|
+
- Always run `npm run lint` and `npm test` before committing or releasing.
|
|
770
|
+
- Use `npm run build` only after tests and lint pass.
|
|
771
|
+
- Clean the project (`npm run clean`) if you see unexpected build or runtime errors.
|
|
772
|
+
- Document any new scripts in the README and this guide.
|
|
773
|
+
- Prefer using scripts over manual commands for consistency and reproducibility.
|
|
774
|
+
- For custom scripts, add clear comments and usage instructions in `package.json`.
|
|
775
|
+
|
|
776
|
+
### Troubleshooting
|
|
777
|
+
- If a script fails, check for missing dependencies (`npm install`) or outdated configs.
|
|
778
|
+
- For build errors, try `npm run clean` then `npm run build`.
|
|
779
|
+
- For test failures, review error logs and update tests as needed.
|
|
780
|
+
- For linter issues, run `npm run format` and fix remaining problems manually.
|
|
781
|
+
|
|
782
|
+
## Security Best Practices (Condensed)
|
|
783
|
+
- Validate all user input in extensions.
|
|
784
|
+
- Avoid direct DOM manipulation; use provided APIs.
|
|
785
|
+
- Keep dependencies updated.
|
|
786
|
+
- Review and follow `SECURITY.md`.
|
|
787
|
+
|
|
788
|
+
## Extension Creation Guide
|
|
789
|
+
To train the agent to always create extensions correctly, follow these steps:
|
|
790
|
+
1. Always create a new folder in `/src/extensions/` for each extension.
|
|
791
|
+
2. Always create these three files with exactly these names in every new extension:
|
|
792
|
+
- `component.ts` (main logic)
|
|
793
|
+
- `style.css` (styles)
|
|
794
|
+
- `view.html` (UI template)
|
|
795
|
+
3. Always extend `KimuComponentElement` for the main class.
|
|
796
|
+
4. Always use the `@KimuComponent` decorator and provide all required metadata fields:
|
|
797
|
+
- `tag`, `name`, `version`, `description`, `author`, `icon`, `internal`, `path`, `dependencies`
|
|
798
|
+
|
|
799
|
+
### Understanding the `dependencies` Metadata
|
|
800
|
+
The `dependencies` field is crucial for building composite extensions. It contains an array of HTML tag strings representing child extensions that will be automatically loaded and made available in the parent extension's template.
|
|
801
|
+
|
|
802
|
+
**How it works:**
|
|
803
|
+
- If your extension is a "parent" that contains other extensions as components, specify their tags in the `dependencies` field
|
|
804
|
+
- Child extensions will be automatically loaded by the KIMU Extension Manager
|
|
805
|
+
- You can use child extensions as regular HTML tags in your `view.html` template
|
|
806
|
+
- The framework handles the loading lifecycle and dependency resolution automatically
|
|
807
|
+
|
|
808
|
+
**Example with child extensions:**
|
|
809
|
+
```typescript
|
|
810
|
+
@KimuComponent({
|
|
811
|
+
tag: 'dashboard-parent',
|
|
812
|
+
name: 'Complete Dashboard',
|
|
813
|
+
version: '1.0.0',
|
|
814
|
+
description: 'A comprehensive dashboard with charts and tables',
|
|
815
|
+
author: 'YourName',
|
|
816
|
+
icon: '📊',
|
|
817
|
+
internal: false,
|
|
818
|
+
path: 'dashboard-parent',
|
|
819
|
+
dependencies: ['chart-widget', 'data-table', 'filter-panel'] // Child extensions
|
|
820
|
+
})
|
|
821
|
+
export class DashboardParent extends KimuComponentElement {
|
|
822
|
+
// Parent component logic
|
|
823
|
+
}
|
|
824
|
+
```
|
|
825
|
+
|
|
826
|
+
**In the `view.html` template:**
|
|
827
|
+
```html
|
|
828
|
+
<div class="dashboard">
|
|
829
|
+
<h2>Interactive Dashboard</h2>
|
|
830
|
+
<!-- Use child extensions as HTML tags -->
|
|
831
|
+
<chart-widget data="${chartData}"></chart-widget>
|
|
832
|
+
<data-table items="${tableItems}"></data-table>
|
|
833
|
+
<filter-panel @filter="${onFilter}"></filter-panel>
|
|
834
|
+
</div>
|
|
835
|
+
```
|
|
836
|
+
|
|
837
|
+
**Benefits of using dependencies:**
|
|
838
|
+
- ✅ **Modularity**: Each component is independent and reusable
|
|
839
|
+
- ✅ **Automatic loading**: No need to manually manage extension loading
|
|
840
|
+
- ✅ **Maintainability**: Separate updates for each child extension
|
|
841
|
+
- ✅ **Composition**: Build complex UIs from simple, focused components
|
|
842
|
+
|
|
843
|
+
**Best practices for dependencies:**
|
|
844
|
+
- Include only the dependencies you actually use in your template
|
|
845
|
+
- Use descriptive tag names for child extensions
|
|
846
|
+
- Document the role of each child extension in your code
|
|
847
|
+
- Keep child extensions focused on single responsibilities
|
|
848
|
+
|
|
849
|
+
**Example for simple extension (no dependencies):**
|
|
850
|
+
```typescript
|
|
851
|
+
@KimuComponent({
|
|
852
|
+
tag: 'simple-button',
|
|
853
|
+
name: 'Simple Button',
|
|
854
|
+
version: '1.0.0',
|
|
855
|
+
description: 'A simple button component',
|
|
856
|
+
author: 'YourName',
|
|
857
|
+
icon: '🔘',
|
|
858
|
+
internal: false,
|
|
859
|
+
path: 'simple-button',
|
|
860
|
+
dependencies: [] // No child extensions
|
|
861
|
+
})
|
|
862
|
+
```
|
|
863
|
+
5. After creating the extension, always register it in the `extension-manifest.json` file at the project root (or designated folder). Example entry:
|
|
864
|
+
```json
|
|
865
|
+
[
|
|
866
|
+
{
|
|
867
|
+
"tag": "my-extension-tag",
|
|
868
|
+
"name": "My Extension Name",
|
|
869
|
+
"version": "1.0.0",
|
|
870
|
+
"description": "Short description",
|
|
871
|
+
"author": "YourName",
|
|
872
|
+
"icon": "🧩",
|
|
873
|
+
"internal": false,
|
|
874
|
+
"path": "my-extension-path",
|
|
875
|
+
"dependencies": []
|
|
876
|
+
}
|
|
877
|
+
]
|
|
878
|
+
```
|
|
879
|
+
6. Registration in the manifest can be done manually or using provided automation scripts (e.g., npm scripts). The agent should suggest or run the script if requested by the user.
|
|
880
|
+
7. Document all public APIs and extension-specific logic in English.
|
|
881
|
+
|
|
882
|
+
## Usable Functions in Extensions
|
|
883
|
+
- All public APIs from `KimuComponentElement` and `KimuComponent`.
|
|
884
|
+
- Utility functions from `/src/core/`.
|
|
885
|
+
- **Reactive property system** from `/src/core/kimu-reactive.ts`:
|
|
886
|
+
- `property()` - Decorator for reactive properties with automatic re-rendering
|
|
887
|
+
- `reactive()` - Create reactive proxy objects with deep reactivity
|
|
888
|
+
- `isReactive()` - Check if object is reactive
|
|
889
|
+
- `toRaw()` - Get original non-reactive object
|
|
890
|
+
- `initReactiveProperties()` - Initialize reactive properties (internal use)
|
|
891
|
+
- `getObservedAttributes()` - Get list of observed attributes (internal use)
|
|
892
|
+
- `handleAttributeChange()` - Handle attribute changes (internal use)
|
|
893
|
+
|
|
894
|
+
### Reactive Property System API
|
|
895
|
+
|
|
896
|
+
```typescript
|
|
897
|
+
import { property, reactive, isReactive, toRaw } from '../core/kimu-reactive';
|
|
898
|
+
|
|
899
|
+
// property() decorator
|
|
900
|
+
@property(options?: PropertyOptions)
|
|
901
|
+
// Options: { type, reflect, attribute, converter, noRender }
|
|
902
|
+
|
|
903
|
+
// reactive() function
|
|
904
|
+
const state = reactive<T>(target: T): T
|
|
905
|
+
|
|
906
|
+
// Helper functions
|
|
907
|
+
isReactive(value: any): boolean
|
|
908
|
+
toRaw<T>(observed: T): T
|
|
909
|
+
```
|
|
910
|
+
|
|
911
|
+
## Extension Checklist
|
|
912
|
+
For agent training, always follow this checklist when creating a new extension:
|
|
913
|
+
1. Create a new folder in `/src/extensions/`.
|
|
914
|
+
2. Create these files with these exact names:
|
|
915
|
+
- `component.ts`
|
|
916
|
+
- `style.css`
|
|
917
|
+
- `view.html`
|
|
918
|
+
3. Extend `KimuComponentElement` in your main class.
|
|
919
|
+
4. Use the `@KimuComponent` decorator with all required metadata (see guide below).
|
|
920
|
+
5. Register the extension in `extension-manifest.json` (manually or via automation script).
|
|
921
|
+
6. Implement required logic, UI, and data binding.
|
|
922
|
+
7. Document all public APIs in English.
|
|
923
|
+
8. Add tests in `/tests/` if needed.
|
|
924
|
+
9. Update `/docs/` with usage instructions and examples.
|
|
925
|
+
10. Check code style with `npm run lint`.
|
|
926
|
+
11. Run tests with `npm test`.
|
|
927
|
+
12. Update this guide if you introduce new patterns or conventions.
|
|
928
|
+
|
|
929
|
+
## Practical Examples
|
|
930
|
+
> **Agent Reminder:** Use these examples as reference for implementation patterns, data binding, and extension structure.
|
|
931
|
+
|
|
932
|
+
### Example: Minimal Extension
|
|
933
|
+
```typescript
|
|
934
|
+
import { KimuComponent } from '../core/kimu-component';
|
|
935
|
+
import { KimuComponentElement } from '../core/kimu-component-element';
|
|
936
|
+
|
|
937
|
+
@KimuComponent({
|
|
938
|
+
tag: 'my-extension-tag',
|
|
939
|
+
name: 'My Extension Name',
|
|
940
|
+
version: '1.0.0',
|
|
941
|
+
description: 'Minimal example extension',
|
|
942
|
+
author: 'YourName',
|
|
943
|
+
icon: '🧩',
|
|
944
|
+
internal: false,
|
|
945
|
+
path: 'my-extension-path',
|
|
946
|
+
dependencies: []
|
|
947
|
+
})
|
|
948
|
+
export class HelloWorldComponent extends KimuComponentElement {
|
|
949
|
+
onInit() {
|
|
950
|
+
console.log('Hello World extension loaded!');
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
```
|
|
954
|
+
|
|
955
|
+
### Example: Composite Extension with Child Dependencies
|
|
956
|
+
```typescript
|
|
957
|
+
import { KimuComponent } from '../core/kimu-component';
|
|
958
|
+
import { KimuComponentElement } from '../core/kimu-component-element';
|
|
959
|
+
|
|
960
|
+
@KimuComponent({
|
|
961
|
+
tag: 'user-dashboard',
|
|
962
|
+
name: 'User Dashboard',
|
|
963
|
+
version: '1.0.0',
|
|
964
|
+
description: 'Complete user dashboard with profile and statistics',
|
|
965
|
+
author: 'YourName',
|
|
966
|
+
icon: '📊',
|
|
967
|
+
internal: false,
|
|
968
|
+
path: 'user-dashboard',
|
|
969
|
+
dependencies: ['user-profile', 'stats-widget', 'activity-feed'] // Child extensions
|
|
970
|
+
})
|
|
971
|
+
export class UserDashboardComponent extends KimuComponentElement {
|
|
972
|
+
private userData: any;
|
|
973
|
+
|
|
974
|
+
onInit() {
|
|
975
|
+
console.log('User Dashboard extension loaded with dependencies!');
|
|
976
|
+
this.loadUserData();
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
private async loadUserData() {
|
|
980
|
+
// Load user data for child components
|
|
981
|
+
this.userData = await this.fetchUserData();
|
|
982
|
+
this.onRender();
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
// The view.html template can use:
|
|
986
|
+
// <user-profile user="${userData}"></user-profile>
|
|
987
|
+
// <stats-widget stats="${userData.stats}"></stats-widget>
|
|
988
|
+
// <activity-feed activities="${userData.activities}"></activity-feed>
|
|
989
|
+
}
|
|
990
|
+
```
|
|
991
|
+
|
|
992
|
+
### Example: Data Binding
|
|
993
|
+
```typescript
|
|
994
|
+
export class MyExtensionComponent extends KimuComponentElement {
|
|
995
|
+
private counter = 0;
|
|
996
|
+
onRender() {
|
|
997
|
+
this.$('#counter').textContent = this.counter.toString();
|
|
998
|
+
}
|
|
999
|
+
increment() {
|
|
1000
|
+
this.counter++;
|
|
1001
|
+
this.onRender();
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
```
|
|
1005
|
+
|
|
1006
|
+
### Example: Reactive Properties with @property Decorator
|
|
1007
|
+
|
|
1008
|
+
```typescript
|
|
1009
|
+
import { KimuComponent } from '../core/kimu-component';
|
|
1010
|
+
import { KimuComponentElement } from '../core/kimu-component-element';
|
|
1011
|
+
import { property } from '../core/kimu-reactive';
|
|
1012
|
+
|
|
1013
|
+
@KimuComponent({
|
|
1014
|
+
tag: 'reactive-counter',
|
|
1015
|
+
name: 'Reactive Counter',
|
|
1016
|
+
version: '1.0.0',
|
|
1017
|
+
description: 'Counter with reactive properties',
|
|
1018
|
+
author: 'KIMU Team',
|
|
1019
|
+
icon: '🔢',
|
|
1020
|
+
internal: false,
|
|
1021
|
+
path: 'reactive-counter',
|
|
1022
|
+
dependencies: []
|
|
1023
|
+
})
|
|
1024
|
+
export class ReactiveCounterComponent extends KimuComponentElement {
|
|
1025
|
+
// Reactive property - automatically triggers re-render on change
|
|
1026
|
+
@property({ type: Number })
|
|
1027
|
+
count: number = 0;
|
|
1028
|
+
|
|
1029
|
+
// Reactive property with attribute reflection
|
|
1030
|
+
@property({ type: String, reflect: true })
|
|
1031
|
+
message: string = 'Click to increment';
|
|
1032
|
+
|
|
1033
|
+
// Reactive boolean property
|
|
1034
|
+
@property({ type: Boolean })
|
|
1035
|
+
isActive: boolean = true;
|
|
1036
|
+
|
|
1037
|
+
onInit() {
|
|
1038
|
+
console.log('Reactive counter initialized');
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
increment() {
|
|
1042
|
+
this.count++; // Automatically triggers re-render, no manual onRender() needed!
|
|
1043
|
+
|
|
1044
|
+
if (this.count >= 10) {
|
|
1045
|
+
this.message = 'You reached 10!';
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
reset() {
|
|
1050
|
+
this.count = 0;
|
|
1051
|
+
this.message = 'Click to increment';
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
getData() {
|
|
1055
|
+
return {
|
|
1056
|
+
count: this.count,
|
|
1057
|
+
message: this.message,
|
|
1058
|
+
isActive: this.isActive,
|
|
1059
|
+
increment: () => this.increment(),
|
|
1060
|
+
reset: () => this.reset()
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
```
|
|
1065
|
+
|
|
1066
|
+
**view.html:**
|
|
1067
|
+
```html
|
|
1068
|
+
<div class="counter-container">
|
|
1069
|
+
<h2>${message}</h2>
|
|
1070
|
+
<p class="count">Count: ${count}</p>
|
|
1071
|
+
<button onclick="${increment}">Increment</button>
|
|
1072
|
+
<button onclick="${reset}">Reset</button>
|
|
1073
|
+
<p class="status">Active: ${isActive}</p>
|
|
1074
|
+
</div>
|
|
1075
|
+
```
|
|
1076
|
+
|
|
1077
|
+
**Benefits of reactive properties:**
|
|
1078
|
+
- ✅ No manual `onRender()` calls needed
|
|
1079
|
+
- ✅ Automatic attribute synchronization (with `reflect: true`)
|
|
1080
|
+
- ✅ Type-safe with TypeScript
|
|
1081
|
+
- ✅ ~40% less boilerplate code
|
|
1082
|
+
|
|
1083
|
+
### Example: Using reactive() for Complex State
|
|
1084
|
+
|
|
1085
|
+
```typescript
|
|
1086
|
+
import { KimuComponent } from '../core/kimu-component';
|
|
1087
|
+
import { KimuComponentElement } from '../core/kimu-component-element';
|
|
1088
|
+
import { reactive, isReactive } from '../core/kimu-reactive';
|
|
1089
|
+
|
|
1090
|
+
@KimuComponent({
|
|
1091
|
+
tag: 'todo-list',
|
|
1092
|
+
name: 'Todo List',
|
|
1093
|
+
version: '1.0.0',
|
|
1094
|
+
description: 'Todo list with reactive state',
|
|
1095
|
+
author: 'KIMU Team',
|
|
1096
|
+
icon: '📝',
|
|
1097
|
+
internal: false,
|
|
1098
|
+
path: 'todo-list',
|
|
1099
|
+
dependencies: []
|
|
1100
|
+
})
|
|
1101
|
+
export class TodoListComponent extends KimuComponentElement {
|
|
1102
|
+
// Reactive object with deep reactivity
|
|
1103
|
+
private state = reactive({
|
|
1104
|
+
todos: [] as Array<{ id: number; text: string; done: boolean }>,
|
|
1105
|
+
filter: 'all' as 'all' | 'active' | 'completed',
|
|
1106
|
+
newTodoText: ''
|
|
1107
|
+
});
|
|
1108
|
+
|
|
1109
|
+
onInit() {
|
|
1110
|
+
console.log('Todo list initialized');
|
|
1111
|
+
console.log('State is reactive:', isReactive(this.state)); // true
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
addTodo() {
|
|
1115
|
+
if (this.state.newTodoText.trim()) {
|
|
1116
|
+
// Nested changes automatically trigger re-render
|
|
1117
|
+
this.state.todos.push({
|
|
1118
|
+
id: Date.now(),
|
|
1119
|
+
text: this.state.newTodoText,
|
|
1120
|
+
done: false
|
|
1121
|
+
});
|
|
1122
|
+
this.state.newTodoText = ''; // Auto re-render
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
toggleTodo(id: number) {
|
|
1127
|
+
const todo = this.state.todos.find(t => t.id === id);
|
|
1128
|
+
if (todo) {
|
|
1129
|
+
todo.done = !todo.done; // Deep reactivity - triggers re-render
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
removeTodo(id: number) {
|
|
1134
|
+
const index = this.state.todos.findIndex(t => t.id === id);
|
|
1135
|
+
if (index !== -1) {
|
|
1136
|
+
this.state.todos.splice(index, 1); // Array mutation - triggers re-render
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
setFilter(filter: 'all' | 'active' | 'completed') {
|
|
1141
|
+
this.state.filter = filter; // Auto re-render
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
get filteredTodos() {
|
|
1145
|
+
switch (this.state.filter) {
|
|
1146
|
+
case 'active':
|
|
1147
|
+
return this.state.todos.filter(t => !t.done);
|
|
1148
|
+
case 'completed':
|
|
1149
|
+
return this.state.todos.filter(t => t.done);
|
|
1150
|
+
default:
|
|
1151
|
+
return this.state.todos;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
getData() {
|
|
1156
|
+
return {
|
|
1157
|
+
todos: this.filteredTodos,
|
|
1158
|
+
newTodoText: this.state.newTodoText,
|
|
1159
|
+
filter: this.state.filter,
|
|
1160
|
+
addTodo: () => this.addTodo(),
|
|
1161
|
+
toggleTodo: (id: number) => this.toggleTodo(id),
|
|
1162
|
+
removeTodo: (id: number) => this.removeTodo(id),
|
|
1163
|
+
setFilter: (filter: 'all' | 'active' | 'completed') => this.setFilter(filter)
|
|
1164
|
+
};
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
```
|
|
1168
|
+
|
|
1169
|
+
### Example: Combining @property and reactive()
|
|
1170
|
+
|
|
1171
|
+
```typescript
|
|
1172
|
+
import { property, reactive } from '../core/kimu-reactive';
|
|
1173
|
+
|
|
1174
|
+
@KimuComponent({
|
|
1175
|
+
tag: 'user-profile',
|
|
1176
|
+
name: 'User Profile',
|
|
1177
|
+
version: '1.0.0',
|
|
1178
|
+
description: 'User profile with mixed reactive state',
|
|
1179
|
+
author: 'KIMU Team',
|
|
1180
|
+
icon: '👤',
|
|
1181
|
+
internal: false,
|
|
1182
|
+
path: 'user-profile',
|
|
1183
|
+
dependencies: []
|
|
1184
|
+
})
|
|
1185
|
+
export class UserProfileComponent extends KimuComponentElement {
|
|
1186
|
+
// Simple reactive property
|
|
1187
|
+
@property({ type: String, reflect: true })
|
|
1188
|
+
userId: string = '';
|
|
1189
|
+
|
|
1190
|
+
// Reactive property for loading state
|
|
1191
|
+
@property({ type: Boolean })
|
|
1192
|
+
loading: boolean = false;
|
|
1193
|
+
|
|
1194
|
+
// Complex reactive state object
|
|
1195
|
+
private userData = reactive({
|
|
1196
|
+
name: '',
|
|
1197
|
+
email: '',
|
|
1198
|
+
avatar: '',
|
|
1199
|
+
stats: {
|
|
1200
|
+
posts: 0,
|
|
1201
|
+
followers: 0,
|
|
1202
|
+
following: 0
|
|
1203
|
+
}
|
|
1204
|
+
});
|
|
1205
|
+
|
|
1206
|
+
async onInit() {
|
|
1207
|
+
await this.loadUserData();
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
async loadUserData() {
|
|
1211
|
+
this.loading = true; // Auto re-render
|
|
1212
|
+
|
|
1213
|
+
try {
|
|
1214
|
+
const response = await fetch(`/api/users/${this.userId}`);
|
|
1215
|
+
const data = await response.json();
|
|
1216
|
+
|
|
1217
|
+
// Update reactive object - all nested changes trigger re-render
|
|
1218
|
+
this.userData.name = data.name;
|
|
1219
|
+
this.userData.email = data.email;
|
|
1220
|
+
this.userData.avatar = data.avatar;
|
|
1221
|
+
this.userData.stats.posts = data.stats.posts;
|
|
1222
|
+
this.userData.stats.followers = data.stats.followers;
|
|
1223
|
+
this.userData.stats.following = data.stats.following;
|
|
1224
|
+
|
|
1225
|
+
} catch (error) {
|
|
1226
|
+
console.error('Failed to load user data:', error);
|
|
1227
|
+
} finally {
|
|
1228
|
+
this.loading = false; // Auto re-render
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
getData() {
|
|
1233
|
+
return {
|
|
1234
|
+
loading: this.loading,
|
|
1235
|
+
user: this.userData,
|
|
1236
|
+
refresh: () => this.loadUserData()
|
|
1237
|
+
};
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
```
|
|
1241
|
+
|
|
1242
|
+
## FAQ & Troubleshooting
|
|
1243
|
+
> **Agent Reminder:** Consult this section for common issues, edge cases, and best practices for error handling and project conventions.
|
|
1244
|
+
|
|
1245
|
+
**Q: How do I create composite extensions with child dependencies?**
|
|
1246
|
+
A: Use the `dependencies` metadata in `@KimuComponent` to specify child extension tags. These will be automatically loaded and available as HTML tags in your template. See the Extension Creation Guide section for detailed examples.
|
|
1247
|
+
|
|
1248
|
+
**Q: What's the difference between dependencies and regular imports?**
|
|
1249
|
+
A: The `dependencies` field is for KIMU child extensions that become available as HTML tags in your template. Regular imports are for utility functions, types, or external libraries.
|
|
1250
|
+
|
|
1251
|
+
**Q: Should I use @property or reactive() for state management?**
|
|
1252
|
+
A:
|
|
1253
|
+
- Use `@property` for simple component properties (numbers, strings, booleans) that should sync with HTML attributes
|
|
1254
|
+
- Use `reactive()` for complex objects and arrays that need deep reactivity
|
|
1255
|
+
- Combine both when you need simple properties with attribute reflection AND complex nested state
|
|
1256
|
+
- Example: `@property` for `userId`, `reactive()` for `userData` object
|
|
1257
|
+
|
|
1258
|
+
**Q: When should I use the noRender option?**
|
|
1259
|
+
A: Use `noRender: true` for properties that change frequently but don't affect the UI (e.g., internal counters, timers, temporary state). This prevents unnecessary re-renders and improves performance.
|
|
1260
|
+
|
|
1261
|
+
```typescript
|
|
1262
|
+
@property({ type: Number, noRender: true })
|
|
1263
|
+
private internalCounter: number = 0;
|
|
1264
|
+
|
|
1265
|
+
// Manually trigger render when needed
|
|
1266
|
+
if (this.internalCounter % 10 === 0) {
|
|
1267
|
+
this.onRender();
|
|
1268
|
+
}
|
|
1269
|
+
```
|
|
1270
|
+
|
|
1271
|
+
**Q: How do I migrate existing components to use reactive properties?**
|
|
1272
|
+
A:
|
|
1273
|
+
1. Import `property` or `reactive` from `kimu-reactive`
|
|
1274
|
+
2. Add `@property` decorator to properties that trigger renders
|
|
1275
|
+
3. Remove manual `this.onRender()` calls after property changes
|
|
1276
|
+
4. Test thoroughly to ensure re-renders happen correctly
|
|
1277
|
+
|
|
1278
|
+
**Before:**
|
|
1279
|
+
```typescript
|
|
1280
|
+
private count = 0;
|
|
1281
|
+
increment() {
|
|
1282
|
+
this.count++;
|
|
1283
|
+
this.onRender(); // Manual render
|
|
1284
|
+
}
|
|
1285
|
+
```
|
|
1286
|
+
|
|
1287
|
+
**After:**
|
|
1288
|
+
```typescript
|
|
1289
|
+
@property({ type: Number })
|
|
1290
|
+
count = 0;
|
|
1291
|
+
increment() {
|
|
1292
|
+
this.count++; // Auto-render
|
|
1293
|
+
}
|
|
1294
|
+
```
|
|
1295
|
+
|
|
1296
|
+
**Q: Can I use reactive properties with Web Component attributes?**
|
|
1297
|
+
A: Yes! Use `reflect: true` to sync properties with HTML attributes:
|
|
1298
|
+
|
|
1299
|
+
```typescript
|
|
1300
|
+
@property({ type: String, reflect: true, attribute: 'user-name' })
|
|
1301
|
+
userName: string = '';
|
|
1302
|
+
|
|
1303
|
+
// HTML: <my-component user-name="John"></my-component>
|
|
1304
|
+
// Property: this.userName = "John"
|
|
1305
|
+
```
|
|
1306
|
+
|
|
1307
|
+
**Q: How does reactive batching work?**
|
|
1308
|
+
A: KIMU batches multiple property changes in the same execution frame into a single render using `requestAnimationFrame`. This prevents performance issues when multiple properties change rapidly:
|
|
1309
|
+
|
|
1310
|
+
```typescript
|
|
1311
|
+
// All three changes trigger only ONE render
|
|
1312
|
+
this.count = 1;
|
|
1313
|
+
this.message = 'Hello';
|
|
1314
|
+
this.active = true;
|
|
1315
|
+
// Single re-render happens after this frame
|
|
1316
|
+
```
|
|
1317
|
+
|
|
1318
|
+
**Q: Can I access the original non-reactive object?**
|
|
1319
|
+
A: Yes, use `toRaw()` to get the original object:
|
|
1320
|
+
|
|
1321
|
+
```typescript
|
|
1322
|
+
import { reactive, toRaw } from '../core/kimu-reactive';
|
|
1323
|
+
|
|
1324
|
+
const state = reactive({ count: 0 });
|
|
1325
|
+
const original = toRaw(state);
|
|
1326
|
+
console.log(original); // Original non-reactive object
|
|
1327
|
+
```
|
|
1328
|
+
|
|
1329
|
+
**Q: Where do I put shared utilities?**
|
|
1330
|
+
A: Use `/src/utils/` for reusable functions.
|
|
1331
|
+
|
|
1332
|
+
**Q: How do I add a new test?**
|
|
1333
|
+
A: Place test files in `/tests/` and follow the naming conventions.
|
|
1334
|
+
|
|
1335
|
+
**Q: How do I update documentation?**
|
|
1336
|
+
A: Edit files in `/docs/` and add examples for new features.
|
|
1337
|
+
|
|
1338
|
+
**Q: Lint or build errors?**
|
|
1339
|
+
A: Run `npm run lint` and `npm run build` to check for issues. Fix according to `CODE_GUIDELINES.md`.
|
|
1340
|
+
|
|
1341
|
+
## Continuous Improvement
|
|
1342
|
+
- Update this file whenever you add new patterns, best practices, or solve edge cases.
|
|
1343
|
+
- Always invite contributors to propose improvements.
|
|
1344
|
+
|
|
1345
|
+
## Known Limitations
|
|
1346
|
+
- Some advanced Three.js or MediaPipe features may require manual integration or additional configuration.
|
|
1347
|
+
- Not all browser APIs are supported; check compatibility before using new features.
|
|
1348
|
+
- Extensions should avoid direct DOM manipulation and always use provided APIs.
|
|
1349
|
+
- For large data models, consider performance and memory usage.
|
|
1350
|
+
|
|
1351
|
+
## Advanced Usage
|
|
1352
|
+
> **Agent Reminder:** Review this section for advanced integration, optimization, and modularization patterns.
|
|
1353
|
+
|
|
1354
|
+
- Integrate external libraries (e.g., Three.js, MediaPipe) by following modular patterns in `/src/core/`.
|
|
1355
|
+
- For performance optimization, use lazy loading and minimize re-renders.
|
|
1356
|
+
- Use environment variables in `.env` for custom configuration.
|
|
1357
|
+
- For complex UI, split logic into multiple components and use data binding.
|
|
1358
|
+
|
|
1359
|
+
## Testing & Quality Assurance
|
|
1360
|
+
> **Agent Reminder:** Follow these instructions to ensure high code quality, test coverage, and compliance with project standards.
|
|
1361
|
+
|
|
1362
|
+
- Write unit and integration tests in `/tests/` using the recommended framework (see README.md).
|
|
1363
|
+
- Aim for high test coverage, especially for core logic and extensions.
|
|
1364
|
+
- Use `npm run lint` and `npm test` before every commit.
|
|
1365
|
+
- Document edge cases and expected behaviors in test files.
|
|
1366
|
+
|
|
1367
|
+
## Release & Versioning
|
|
1368
|
+
- Follow semantic versioning for all extensions and core updates.
|
|
1369
|
+
- Update `CHANGELOG.md` with every release, describing new features, fixes, and breaking changes.
|
|
1370
|
+
- Tag releases in GitHub and keep documentation up to date.
|
|
1371
|
+
- For major changes, notify contributors and update this guide.
|
|
1372
|
+
|
|
1373
|
+
## Glossary
|
|
1374
|
+
> **Agent Reminder:** Refer to the glossary for precise definitions of key concepts and terminology used throughout the project.
|
|
1375
|
+
|
|
1376
|
+
- **Component**: A modular unit extending `KimuComponentElement`.
|
|
1377
|
+
- **Extension**: A custom scenario or feature added in `/src/extensions/`.
|
|
1378
|
+
- **Data Binding**: Linking UI elements to logic using reactive properties/methods.
|
|
1379
|
+
- **Copilot Agent**: AI assistant that reads this file to generate code and suggestions.
|
|
1380
|
+
- **Semantic Versioning**: Versioning system (MAJOR.MINOR.PATCH) for releases.
|
|
1381
|
+
- **KimuComponentElement**: Base class for all UI components in kimu-core.
|
|
1382
|
+
- **KimuComponent**: Decorator for defining components with metadata.
|
|
1383
|
+
- **UI Rendering**: Process of displaying components in the browser.
|
|
1384
|
+
- **Event Management**: Handling user interactions and system events in components.
|
|
1385
|
+
|
|
1386
|
+
## Modules in KIMU-Core
|
|
1387
|
+
> **Agent Reminder:** Use this section to understand how to structure, document, and import reusable modules in the framework.
|
|
1388
|
+
|
|
1389
|
+
- **Definition**: Modules are containers for reusable and shared functionalities (services, helpers, APIs, resources, etc.) that can be imported by extensions, components, or other modules.
|
|
1390
|
+
- **Location**: All modules are located in `/src/modules/`.
|
|
1391
|
+
- **Usage**: Use modules to organize code for specific features (e.g., i18n, storage, authentication) and export everything needed for integration.
|
|
1392
|
+
- **Best Practice**: Keep modules modular, well-documented, and easy to import.
|
|
1393
|
+
|
|
1394
|
+
---
|
|
1395
|
+
|
|
1396
|
+
### Kimu Module Creation Guide
|
|
1397
|
+
|
|
1398
|
+
> **Agent Training Note:** Always follow these steps and conventions when creating a new Kimu module. This ensures consistency, discoverability, and maintainability across the codebase.
|
|
1399
|
+
|
|
1400
|
+
#### 1. Structure and Required Files
|
|
1401
|
+
Each module must reside in its own folder under `/src/modules/<module-name>/` and include at least:
|
|
1402
|
+
|
|
1403
|
+
- `module.ts`: Exports a class `<ModuleName>Module` (default export) that extends `KimuModule` and fornisce il servizio tramite `getService()`.
|
|
1404
|
+
- `<module-name>-service.ts`: Implements the main service class and exports it with a recommended name (see below).
|
|
1405
|
+
- (Optional) `interfaces.ts`, `utils.ts`, or other helpers as needed.
|
|
1406
|
+
|
|
1407
|
+
**Example structure:**
|
|
1408
|
+
```
|
|
1409
|
+
src/modules/event-bus/
|
|
1410
|
+
├── event-bus-service.ts
|
|
1411
|
+
└── module.ts
|
|
1412
|
+
```
|
|
1413
|
+
|
|
1414
|
+
#### 2. Naming Conventions
|
|
1415
|
+
- The service class should be named `<ModuleName>Service` (e.g., `EventBusService`).
|
|
1416
|
+
- The main export of the service file should be `<moduleName>Service` (camelCase, e.g., `eventBusService`).
|
|
1417
|
+
- The module class should be named `<ModuleName>Module` and exported as default from `module.ts`.
|
|
1418
|
+
|
|
1419
|
+
#### 3. Reference Classes
|
|
1420
|
+
- All modules must extend `KimuModule` (from `/src/core/kimu-module.ts`).
|
|
1421
|
+
- Services should be implemented as classes and exported as singletons or via factory, as appropriate.
|
|
1422
|
+
|
|
1423
|
+
#### 4. Example: Minimal Event Bus Module
|
|
1424
|
+
```typescript
|
|
1425
|
+
// event-bus-service.ts
|
|
1426
|
+
export class EventBusService {
|
|
1427
|
+
on(event: string, cb: (...args: any[]) => void) { /* ... */ }
|
|
1428
|
+
emit(event: string, data: any) { /* ... */ }
|
|
1429
|
+
}
|
|
1430
|
+
export const eventBusService = new EventBusService();
|
|
1431
|
+
|
|
1432
|
+
// module.ts
|
|
1433
|
+
import { KimuModule } from '../../core/kimu-module';
|
|
1434
|
+
import { eventBusService } from './event-bus-service';
|
|
1435
|
+
export default class EventBusModule extends KimuModule {
|
|
1436
|
+
constructor(name = 'event-bus', version = '1.0.0', options?: any) {
|
|
1437
|
+
super(name, version, options);
|
|
1438
|
+
}
|
|
1439
|
+
getService() {
|
|
1440
|
+
return eventBusService;
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
```
|
|
1444
|
+
|
|
1445
|
+
#### 5. Difference Between Module and Extension
|
|
1446
|
+
- **Module**: Provides reusable logic/services (e.g., i18n, event-bus, storage) for use by extensions or other modules. No UI.
|
|
1447
|
+
- **Extension**: Implements a user-facing scenario/component, always in `/src/extensions/`, with UI and registration in the manifest.
|
|
1448
|
+
|
|
1449
|
+
#### 6. Module Checklist
|
|
1450
|
+
For agent training, always follow this checklist when creating a new module:
|
|
1451
|
+
1. Create a new folder in `/src/modules/<module-name>/`.
|
|
1452
|
+
2. Add at least `module.ts` and `<module-name>-service.ts`.
|
|
1453
|
+
3. Extend `KimuModule` in your module class.
|
|
1454
|
+
4. Use the recommended naming for classes and exports.
|
|
1455
|
+
5. Document all public APIs in English.
|
|
1456
|
+
6. Add tests in `/tests/` if needed.
|
|
1457
|
+
7. Update `/docs/` with usage instructions and examples.
|
|
1458
|
+
8. Check code style with `npm run lint`.
|
|
1459
|
+
9. Run tests with `npm test`.
|
|
1460
|
+
10. Update this guide if you introduce new patterns or conventions for modules.
|
|
1461
|
+
|
|
1462
|
+
#### Difference Between Module and Extension
|
|
1463
|
+
| Module | Extension |
|
|
1464
|
+
|--------|-----------|
|
|
1465
|
+
| Provides reusable logic/services | Implements user scenario/UI |
|
|
1466
|
+
| No UI | UI and manifest required |
|
|
1467
|
+
| In `/src/modules/` | In `/src/extensions/` |
|
|
1468
|
+
| Not registered in manifest | Registered in `extension-manifest.json` |
|
|
1469
|
+
| Used by extensions/modules | Used by the end user |
|
|
1470
|
+
|
|
1471
|
+
---
|
|
1472
|
+
|
|
1473
|
+
## Agent Training & Workflow
|
|
1474
|
+
### Copilot & AI Agent Guide
|
|
1475
|
+
> **Agent Training Note:** This document is your primary source for generating code, following conventions, and applying best practices in KIMU-Core. Read everything, always consult the following sections: Practical Examples, FAQ, Testing, Glossary, Modules, Router, i18n. Propose improvements if you identify missing patterns.
|
|
1476
|
+
|
|
1477
|
+
- **Read the entire document** before generating or modifying code.
|
|
1478
|
+
- **Follow the conventions** in `CODE_GUIDELINES.md` and `CONTRIBUTING.md`.
|
|
1479
|
+
- **Use practical examples** as templates.
|
|
1480
|
+
- **Consult the FAQ** for common issues and edge cases.
|
|
1481
|
+
- **Propose improvements** if you identify missing patterns.
|
|
1482
|
+
- **Use the Glossary** for precise definitions.
|
|
1483
|
+
- **Follow the checklist** for modules and extensions.
|
|
1484
|
+
- **Always document** public APIs and workflows.
|
|
1485
|
+
|
|
1486
|
+
### Recommended Workflow for AI Agents
|
|
1487
|
+
1. Read the creation checklist (module/extension).
|
|
1488
|
+
2. Follow practical examples.
|
|
1489
|
+
3. Consult cross-cutting best practices.
|
|
1490
|
+
4. Use modular patterns and document everything.
|
|
1491
|
+
5. Update the guide if you introduce new patterns.
|
|
1492
|
+
|
|
1493
|
+
### Cross-cutting Best Practices
|
|
1494
|
+
- Modularity and reusability.
|
|
1495
|
+
- Clear documentation in English.
|
|
1496
|
+
- Unit and integration tests.
|
|
1497
|
+
- Consistent and semantic naming.
|
|
1498
|
+
- Secure dependency management.
|
|
1499
|
+
- Input validation and security.
|
|
1500
|
+
- Continuous guide updates.
|
|
1501
|
+
|
|
1502
|
+
### Agent Reminder
|
|
1503
|
+
> Always insert “Agent Reminder” and “Agent Training Note” at the beginning of key sections (modules, extensions, router, i18n, testing, FAQ).
|
|
1504
|
+
|
|
1505
|
+
---
|
|
1506
|
+
|
|
1507
|
+
## Router Module Guide
|
|
1508
|
+
> **Agent Training Note:** This section provides comprehensive guidance for using and extending the KIMU Router Module. Always refer to this when implementing routing functionality in KIMU applications.
|
|
1509
|
+
|
|
1510
|
+
### Overview
|
|
1511
|
+
The KIMU Router Module provides client-side routing capabilities for single-page applications (SPAs) built with the KIMU framework. It supports hash-based routing, dynamic route parameters, route guards, and programmatic navigation.
|
|
1512
|
+
|
|
1513
|
+
### Features
|
|
1514
|
+
- **Hash-based routing** (`#/path`) for compatibility with static hosting
|
|
1515
|
+
- **Dynamic route parameters** (`:id`, `:slug`) with automatic parsing
|
|
1516
|
+
- **Route guards** for authentication and authorization
|
|
1517
|
+
- **Programmatic navigation** with history management
|
|
1518
|
+
- **Route transitions** with lifecycle hooks
|
|
1519
|
+
- **Nested routing** support for complex application structures
|
|
1520
|
+
- **Base path compatibility** for subdirectory deployments
|
|
1521
|
+
|
|
1522
|
+
### API Overview
|
|
1523
|
+
|
|
1524
|
+
#### KimuRouterService
|
|
1525
|
+
The main service class providing routing functionality:
|
|
1526
|
+
|
|
1527
|
+
```typescript
|
|
1528
|
+
export class KimuRouterService {
|
|
1529
|
+
// Navigation methods
|
|
1530
|
+
navigate(path: string): void
|
|
1531
|
+
back(): void
|
|
1532
|
+
forward(): void
|
|
1533
|
+
replace(path: string): void
|
|
1534
|
+
|
|
1535
|
+
// Route management
|
|
1536
|
+
addRoute(path: string, handler: RouteHandler): void
|
|
1537
|
+
removeRoute(path: string): void
|
|
1538
|
+
getCurrentRoute(): RouteInfo | null
|
|
1539
|
+
|
|
1540
|
+
// Parameters and query
|
|
1541
|
+
getParams(): Record<string, string>
|
|
1542
|
+
getQuery(): Record<string, string>
|
|
1543
|
+
|
|
1544
|
+
// Event handling
|
|
1545
|
+
onRouteChange(callback: (route: RouteInfo) => void): void
|
|
1546
|
+
offRouteChange(callback: (route: RouteInfo) => void): void
|
|
1547
|
+
}
|
|
1548
|
+
```
|
|
1549
|
+
|
|
1550
|
+
#### KimuRouterModule
|
|
1551
|
+
The module class that integrates the router service:
|
|
1552
|
+
|
|
1553
|
+
```typescript
|
|
1554
|
+
export default class RouterModule extends KimuModule {
|
|
1555
|
+
constructor(name = 'router', version = '1.0.0', options?: RouterOptions) {
|
|
1556
|
+
super(name, version, options);
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
getService(): KimuRouterService {
|
|
1560
|
+
return routerService;
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
```
|
|
1564
|
+
|
|
1565
|
+
### Basic Usage Examples
|
|
1566
|
+
|
|
1567
|
+
#### 1. Setting Up Routes in Main Application
|
|
1568
|
+
```typescript
|
|
1569
|
+
import { KimuModuleManager } from './core/kimu-module-manager';
|
|
1570
|
+
import RouterModule from './modules/router/module';
|
|
1571
|
+
|
|
1572
|
+
// Initialize router module
|
|
1573
|
+
const moduleManager = KimuModuleManager.getInstance();
|
|
1574
|
+
const routerModule = new RouterModule();
|
|
1575
|
+
await moduleManager.loadModule(routerModule);
|
|
1576
|
+
|
|
1577
|
+
// Get router service
|
|
1578
|
+
const router = moduleManager.getRouterService();
|
|
1579
|
+
|
|
1580
|
+
// Define routes
|
|
1581
|
+
router.addRoute('/', () => {
|
|
1582
|
+
console.log('Home page');
|
|
1583
|
+
// Load home component
|
|
1584
|
+
});
|
|
1585
|
+
|
|
1586
|
+
router.addRoute('/about', () => {
|
|
1587
|
+
console.log('About page');
|
|
1588
|
+
// Load about component
|
|
1589
|
+
});
|
|
1590
|
+
|
|
1591
|
+
router.addRoute('/user/:id', (params) => {
|
|
1592
|
+
console.log('User page:', params.id);
|
|
1593
|
+
// Load user component with ID
|
|
1594
|
+
});
|
|
1595
|
+
```
|
|
1596
|
+
|
|
1597
|
+
#### 2. Navigation in Components
|
|
1598
|
+
```typescript
|
|
1599
|
+
import { KimuComponentElement } from '../core/kimu-component-element';
|
|
1600
|
+
import { KimuModuleManager } from '../core/kimu-module-manager';
|
|
1601
|
+
|
|
1602
|
+
export class NavigationComponent extends KimuComponentElement {
|
|
1603
|
+
private router: KimuRouterService;
|
|
1604
|
+
|
|
1605
|
+
async onInit() {
|
|
1606
|
+
// Get router service from module manager
|
|
1607
|
+
this.router = KimuModuleManager.getInstance().getRouterService();
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
navigateToHome() {
|
|
1611
|
+
this.router.navigate('/');
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
navigateToUser(userId: string) {
|
|
1615
|
+
this.router.navigate(`/user/${userId}`);
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
navigateWithQuery() {
|
|
1619
|
+
this.router.navigate('/search?q=kimu&category=framework');
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
```
|
|
1623
|
+
|
|
1624
|
+
#### 3. Route Parameters and Query Strings
|
|
1625
|
+
```typescript
|
|
1626
|
+
// In a route handler
|
|
1627
|
+
router.addRoute('/product/:category/:id', () => {
|
|
1628
|
+
const params = router.getParams();
|
|
1629
|
+
const query = router.getQuery();
|
|
1630
|
+
|
|
1631
|
+
console.log('Category:', params.category);
|
|
1632
|
+
console.log('Product ID:', params.id);
|
|
1633
|
+
console.log('Query params:', query);
|
|
1634
|
+
|
|
1635
|
+
// Example: /product/electronics/123?color=red&size=large
|
|
1636
|
+
// params: { category: 'electronics', id: '123' }
|
|
1637
|
+
// query: { color: 'red', size: 'large' }
|
|
1638
|
+
});
|
|
1639
|
+
```
|
|
1640
|
+
|
|
1641
|
+
#### 4. Route Guards and Authentication
|
|
1642
|
+
```typescript
|
|
1643
|
+
// Add route guard for protected routes
|
|
1644
|
+
router.addRoute('/dashboard', () => {
|
|
1645
|
+
if (!isAuthenticated()) {
|
|
1646
|
+
router.navigate('/login');
|
|
1647
|
+
return;
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
// Load dashboard component
|
|
1651
|
+
loadDashboard();
|
|
1652
|
+
});
|
|
1653
|
+
|
|
1654
|
+
router.addRoute('/admin/:section', () => {
|
|
1655
|
+
if (!hasAdminRole()) {
|
|
1656
|
+
router.navigate('/unauthorized');
|
|
1657
|
+
return;
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
const params = router.getParams();
|
|
1661
|
+
loadAdminSection(params.section);
|
|
1662
|
+
});
|
|
1663
|
+
```
|
|
1664
|
+
|
|
1665
|
+
### Advanced Usage
|
|
1666
|
+
|
|
1667
|
+
#### 1. Route Change Listeners
|
|
1668
|
+
```typescript
|
|
1669
|
+
// Listen for route changes
|
|
1670
|
+
router.onRouteChange((route) => {
|
|
1671
|
+
console.log('Route changed to:', route.path);
|
|
1672
|
+
console.log('Parameters:', route.params);
|
|
1673
|
+
console.log('Query:', route.query);
|
|
1674
|
+
|
|
1675
|
+
// Update navigation UI
|
|
1676
|
+
updateActiveNavigation(route.path);
|
|
1677
|
+
|
|
1678
|
+
// Analytics tracking
|
|
1679
|
+
trackPageView(route.path);
|
|
1680
|
+
});
|
|
1681
|
+
```
|
|
1682
|
+
|
|
1683
|
+
#### 2. Programmatic Navigation with History
|
|
1684
|
+
```typescript
|
|
1685
|
+
// Navigate and add to history
|
|
1686
|
+
router.navigate('/new-page');
|
|
1687
|
+
|
|
1688
|
+
// Navigate without adding to history
|
|
1689
|
+
router.replace('/login');
|
|
1690
|
+
|
|
1691
|
+
// Browser back/forward
|
|
1692
|
+
router.back();
|
|
1693
|
+
router.forward();
|
|
1694
|
+
```
|
|
1695
|
+
|
|
1696
|
+
#### 3. Integration with Extensions
|
|
1697
|
+
```typescript
|
|
1698
|
+
@KimuComponent({
|
|
1699
|
+
tag: 'app-router',
|
|
1700
|
+
name: 'App Router',
|
|
1701
|
+
version: '1.0.0',
|
|
1702
|
+
description: 'Main application router component',
|
|
1703
|
+
author: 'KIMU Team',
|
|
1704
|
+
icon: '🧭',
|
|
1705
|
+
internal: false,
|
|
1706
|
+
path: 'app-router',
|
|
1707
|
+
dependencies: []
|
|
1708
|
+
})
|
|
1709
|
+
export class AppRouterComponent extends KimuComponentElement {
|
|
1710
|
+
private router: KimuRouterService;
|
|
1711
|
+
|
|
1712
|
+
async onInit() {
|
|
1713
|
+
this.router = KimuModuleManager.getInstance().getRouterService();
|
|
1714
|
+
|
|
1715
|
+
// Setup application routes
|
|
1716
|
+
this.setupRoutes();
|
|
1717
|
+
|
|
1718
|
+
// Listen for route changes
|
|
1719
|
+
this.router.onRouteChange(this.handleRouteChange.bind(this));
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
private setupRoutes() {
|
|
1723
|
+
this.router.addRoute('/', this.renderHome.bind(this));
|
|
1724
|
+
this.router.addRoute('/about', this.renderAbout.bind(this));
|
|
1725
|
+
this.router.addRoute('/contact', this.renderContact.bind(this));
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1728
|
+
private handleRouteChange(route: RouteInfo) {
|
|
1729
|
+
// Update component based on route
|
|
1730
|
+
this.onRender();
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
private renderHome() {
|
|
1734
|
+
this.innerHTML = '<kimu-home></kimu-home>';
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
private renderAbout() {
|
|
1738
|
+
this.innerHTML = '<kimu-about></kimu-about>';
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1741
|
+
private renderContact() {
|
|
1742
|
+
this.innerHTML = '<kimu-contact></kimu-contact>';
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
```
|
|
1746
|
+
|
|
1747
|
+
### Best Practices
|
|
1748
|
+
|
|
1749
|
+
#### 1. Route Organization
|
|
1750
|
+
- **Group related routes** by feature or module
|
|
1751
|
+
- **Use consistent naming** for route parameters
|
|
1752
|
+
- **Define route constants** to avoid hardcoded strings
|
|
1753
|
+
- **Document route structure** in application documentation
|
|
1754
|
+
|
|
1755
|
+
```typescript
|
|
1756
|
+
// Route constants
|
|
1757
|
+
export const ROUTES = {
|
|
1758
|
+
HOME: '/',
|
|
1759
|
+
ABOUT: '/about',
|
|
1760
|
+
USER_PROFILE: '/user/:id',
|
|
1761
|
+
USER_SETTINGS: '/user/:id/settings',
|
|
1762
|
+
ADMIN_DASHBOARD: '/admin/dashboard',
|
|
1763
|
+
ADMIN_USERS: '/admin/users'
|
|
1764
|
+
} as const;
|
|
1765
|
+
|
|
1766
|
+
// Use constants in route definition
|
|
1767
|
+
router.addRoute(ROUTES.USER_PROFILE, handleUserProfile);
|
|
1768
|
+
```
|
|
1769
|
+
|
|
1770
|
+
#### 2. Error Handling
|
|
1771
|
+
- **Handle 404 routes** with a catch-all route
|
|
1772
|
+
- **Validate route parameters** before processing
|
|
1773
|
+
- **Provide fallback navigation** for invalid routes
|
|
1774
|
+
|
|
1775
|
+
```typescript
|
|
1776
|
+
// 404 handler (should be added last)
|
|
1777
|
+
router.addRoute('*', () => {
|
|
1778
|
+
console.warn('Route not found, redirecting to home');
|
|
1779
|
+
router.replace('/');
|
|
1780
|
+
});
|
|
1781
|
+
|
|
1782
|
+
// Parameter validation
|
|
1783
|
+
router.addRoute('/user/:id', () => {
|
|
1784
|
+
const params = router.getParams();
|
|
1785
|
+
const userId = parseInt(params.id);
|
|
1786
|
+
|
|
1787
|
+
if (isNaN(userId) || userId <= 0) {
|
|
1788
|
+
router.navigate('/users'); // Redirect to users list
|
|
1789
|
+
return;
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
loadUser(userId);
|
|
1793
|
+
});
|
|
1794
|
+
```
|
|
1795
|
+
|
|
1796
|
+
#### 3. Performance Optimization
|
|
1797
|
+
- **Lazy load route components** when possible
|
|
1798
|
+
- **Cache route handlers** for frequently accessed routes
|
|
1799
|
+
- **Debounce rapid navigation** calls
|
|
1800
|
+
- **Clean up resources** when leaving routes
|
|
1801
|
+
|
|
1802
|
+
```typescript
|
|
1803
|
+
// Lazy loading example
|
|
1804
|
+
router.addRoute('/heavy-component', async () => {
|
|
1805
|
+
const { HeavyComponent } = await import('./components/heavy-component');
|
|
1806
|
+
renderComponent(HeavyComponent);
|
|
1807
|
+
});
|
|
1808
|
+
```
|
|
1809
|
+
|
|
1810
|
+
#### 4. Base Path Integration
|
|
1811
|
+
The router automatically works with KIMU's base path system:
|
|
1812
|
+
|
|
1813
|
+
```typescript
|
|
1814
|
+
// Router respects base path configuration
|
|
1815
|
+
// If base path is "/dist/", routes become:
|
|
1816
|
+
// "/" -> "/dist/#/"
|
|
1817
|
+
// "/about" -> "/dist/#/about"
|
|
1818
|
+
// "/user/123" -> "/dist/#/user/123"
|
|
1819
|
+
|
|
1820
|
+
// No additional configuration needed - works automatically
|
|
1821
|
+
```
|
|
1822
|
+
|
|
1823
|
+
---
|
|
1824
|
+
|
|
1825
|
+
## Internationalization (i18n)
|
|
1826
|
+
> **Agent Reminder:** Always consider internationalization (i18n) when developing extensions or modules. This section explains how to support multiple languages and localization in kimu-core.
|
|
1827
|
+
|
|
1828
|
+
### Overview
|
|
1829
|
+
KIMU-Core supports internationalization to enable multi-language user interfaces and content. All public UI, messages, and user-facing strings should be localizable.
|
|
1830
|
+
|
|
1831
|
+
### Where to Place Language Files
|
|
1832
|
+
- Place language resource files (e.g., JSON, JS, or TS files with translations) in `/src/modules/i18n/` or a dedicated `i18n` folder within your extension.
|
|
1833
|
+
- Use a clear naming convention, e.g., `en.json`, `it.json`, `fr.json`.
|
|
1834
|
+
|
|
1835
|
+
### How to Structure Language Files
|
|
1836
|
+
Example `en.json`:
|
|
1837
|
+
```json
|
|
1838
|
+
{
|
|
1839
|
+
"hello": "Hello",
|
|
1840
|
+
"welcome": "Welcome to KIMU-Core!",
|
|
1841
|
+
"button.save": "Save",
|
|
1842
|
+
"error.network": "Network error, please try again."
|
|
1843
|
+
}
|
|
1844
|
+
```
|
|
1845
|
+
|
|
1846
|
+
### Accessing Translations in Code
|
|
1847
|
+
If the framework provides an i18n API (e.g., `KimuI18nService`), you can now pass the translate function directly in your data object, without manual binding:
|
|
1848
|
+
```typescript
|
|
1849
|
+
// Example using KimuI18nService in a component
|
|
1850
|
+
getData() {
|
|
1851
|
+
return {
|
|
1852
|
+
// ...other data...
|
|
1853
|
+
translate: this.i18n.translate, // No need for .bind(this.i18n)
|
|
1854
|
+
};
|
|
1855
|
+
}
|
|
1856
|
+
```
|
|
1857
|
+
|
|
1858
|
+
If no built-in API exists, import your language file and use it as a dictionary:
|
|
1859
|
+
```typescript
|
|
1860
|
+
import en from './i18n/en.json';
|
|
1861
|
+
const msg = en['button.save'];
|
|
1862
|
+
```
|
|
1863
|
+
|
|
1864
|
+
### Switching Languages
|
|
1865
|
+
- Provide a way for the user to select their preferred language (e.g., dropdown, settings panel).
|
|
1866
|
+
- Load the appropriate language file dynamically based on user choice or browser settings.
|
|
1867
|
+
|
|
1868
|
+
Example:
|
|
1869
|
+
```typescript
|
|
1870
|
+
import en from './i18n/en.json';
|
|
1871
|
+
import it from './i18n/it.json';
|
|
1872
|
+
|
|
1873
|
+
const languages = { en, it };
|
|
1874
|
+
const userLang = getUserLanguage(); // e.g., 'en' or 'it'
|
|
1875
|
+
const t = (key: string) => languages[userLang][key] || key;
|
|
1876
|
+
|
|
1877
|
+
this.$('#saveBtn').textContent = t('button.save');
|
|
1878
|
+
```
|
|
1879
|
+
|
|
1880
|
+
### Best Practices
|
|
1881
|
+
- Always use keys for all user-facing strings; never hardcode visible text.
|
|
1882
|
+
- Default to English if a translation is missing.
|
|
1883
|
+
- Keep language files organized and up to date.
|
|
1884
|
+
- Document any new keys and their usage.
|
|
1885
|
+
- UI and documentation must always be in English by default, but support for other languages is encouraged.
|
|
1886
|
+
- For extensions, document how to add new languages or customize translations.
|
|
1887
|
+
|
|
1888
|
+
### Advanced Usage
|
|
1889
|
+
- For dynamic content, use interpolation (e.g., `"greeting": "Hello, {name}!"`).
|
|
1890
|
+
- Consider pluralization and gender where relevant.
|
|
1891
|
+
- If the framework supports it, use reactive updates when the language changes.
|
|
1892
|
+
|
|
1893
|
+
### Example: Dynamic Interpolation
|
|
1894
|
+
```typescript
|
|
1895
|
+
const greeting = t('greeting').replace('{name}', userName);
|
|
1896
|
+
```
|
|
1897
|
+
|
|
1898
|
+
### Example: Language Switcher UI
|
|
1899
|
+
```typescript
|
|
1900
|
+
// HTML
|
|
1901
|
+
<select id="langSelect">
|
|
1902
|
+
<option value="en">English</option>
|
|
1903
|
+
<option value="it">Italiano</option>
|
|
1904
|
+
</select>
|
|
1905
|
+
|
|
1906
|
+
// TypeScript
|
|
1907
|
+
this.$('#langSelect').addEventListener('change', (e) => {
|
|
1908
|
+
const lang = (e.target as HTMLSelectElement).value;
|
|
1909
|
+
setUserLanguage(lang);
|
|
1910
|
+
this.onRender(); // re-render UI with new language
|
|
1911
|
+
});
|
|
1912
|
+
```
|
|
1913
|
+
|
|
1914
|
+
> **Agent Reminder:** Always document i18n usage in your extension's README and code comments. Ensure all new features are localizable and provide English as the default language.
|
|
1915
|
+
|
|
1916
|
+
---
|
|
1917
|
+
|
|
1918
|
+
## Practical Examples
|
|
1919
|
+
> **Agent Reminder:** Use these examples as reference for implementation patterns, data binding, and extension structure.
|
|
1920
|
+
|
|
1921
|
+
### Example: Minimal Extension
|
|
1922
|
+
```typescript
|
|
1923
|
+
import { KimuComponent } from '../core/kimu-component';
|
|
1924
|
+
import { KimuComponentElement } from '../core/kimu-component-element';
|
|
1925
|
+
|
|
1926
|
+
@KimuComponent({
|
|
1927
|
+
tag: 'hello-world',
|
|
1928
|
+
name: 'Hello World',
|
|
1929
|
+
version: '1.0.0',
|
|
1930
|
+
description: 'Minimal example extension',
|
|
1931
|
+
author: 'YourName',
|
|
1932
|
+
icon: '👋',
|
|
1933
|
+
internal: false,
|
|
1934
|
+
path: 'hello-world',
|
|
1935
|
+
dependencies: []
|
|
1936
|
+
})
|
|
1937
|
+
export class HelloWorldComponent extends KimuComponentElement {
|
|
1938
|
+
onInit() {
|
|
1939
|
+
console.log('Hello World extension loaded!');
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
```
|
|
1943
|
+
|
|
1944
|
+
### Example: Composite Extension with Child Dependencies
|
|
1945
|
+
```typescript
|
|
1946
|
+
import { KimuComponent } from '../core/kimu-component';
|
|
1947
|
+
import { KimuComponentElement } from '../core/kimu-component-element';
|
|
1948
|
+
|
|
1949
|
+
@KimuComponent({
|
|
1950
|
+
tag: 'user-dashboard',
|
|
1951
|
+
name: 'User Dashboard',
|
|
1952
|
+
version: '1.0.0',
|
|
1953
|
+
description: 'Complete user dashboard with profile and statistics',
|
|
1954
|
+
author: 'YourName',
|
|
1955
|
+
icon: '📊',
|
|
1956
|
+
internal: false,
|
|
1957
|
+
path: 'user-dashboard',
|
|
1958
|
+
dependencies: ['user-profile', 'stats-widget', 'activity-feed'] // Child extensions
|
|
1959
|
+
})
|
|
1960
|
+
export class UserDashboardComponent extends KimuComponentElement {
|
|
1961
|
+
private userData: any;
|
|
1962
|
+
|
|
1963
|
+
onInit() {
|
|
1964
|
+
console.log('User Dashboard extension loaded with dependencies!');
|
|
1965
|
+
this.loadUserData();
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1968
|
+
private async loadUserData() {
|
|
1969
|
+
// Load user data for child components
|
|
1970
|
+
this.userData = await this.fetchUserData();
|
|
1971
|
+
this.onRender();
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1974
|
+
// The view.html template can use:
|
|
1975
|
+
// <user-profile user="${userData}"></user-profile>
|
|
1976
|
+
// <stats-widget stats="${userData.stats}"></stats-widget>
|
|
1977
|
+
// <activity-feed activities="${userData.activities}"></activity-feed>
|
|
1978
|
+
}
|
|
1979
|
+
```
|
|
1980
|
+
|
|
1981
|
+
### Example: Data Binding
|
|
1982
|
+
```typescript
|
|
1983
|
+
export class MyExtensionComponent extends KimuComponentElement {
|
|
1984
|
+
private counter = 0;
|
|
1985
|
+
onRender() {
|
|
1986
|
+
this.$('#counter').textContent = this.counter.toString();
|
|
1987
|
+
}
|
|
1988
|
+
increment() {
|
|
1989
|
+
this.counter++;
|
|
1990
|
+
this.onRender();
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
```
|
|
1994
|
+
|
|
1995
|
+
---
|
|
1996
|
+
|
|
1997
|
+
## Extension Creation Guide
|
|
1998
|
+
|
|
1999
|
+
> **Agent Training Note:** Follow this checklist every time you create a new extension.
|
|
2000
|
+
|
|
2001
|
+
### Extension Creation Checklist
|
|
2002
|
+
|
|
2003
|
+
1. ✅ Create new folder in `src/extensions/<extension-name>/`
|
|
2004
|
+
2. ✅ Create three required files:
|
|
2005
|
+
- `component.ts` (logic)
|
|
2006
|
+
- `style.css` (styles)
|
|
2007
|
+
- `view.html` (template)
|
|
2008
|
+
3. ✅ Extend `KimuComponentElement` in component class
|
|
2009
|
+
4. ✅ Use `@KimuComponent` decorator with all required metadata
|
|
2010
|
+
5. ✅ Implement lifecycle methods (`onInit`, `onRender`)
|
|
2011
|
+
6. ✅ Register in `extension-manifest.json`
|
|
2012
|
+
7. ✅ Document public APIs in comments
|
|
2013
|
+
8. ✅ Test the extension works correctly
|
|
2014
|
+
9. ✅ Run `npm run lint` and fix any issues
|
|
2015
|
+
10. ✅ Update project documentation if needed
|
|
2016
|
+
|
|
2017
|
+
### Step-by-Step Instructions
|
|
2018
|
+
|
|
2019
|
+
#### Step 1: Create Extension Folder Structure
|
|
2020
|
+
```bash
|
|
2021
|
+
mkdir -p src/extensions/my-extension
|
|
2022
|
+
touch src/extensions/my-extension/component.ts
|
|
2023
|
+
touch src/extensions/my-extension/style.css
|
|
2024
|
+
touch src/extensions/my-extension/view.html
|
|
2025
|
+
```
|
|
2026
|
+
|
|
2027
|
+
#### Step 2: Create Component Logic (`component.ts`)
|
|
2028
|
+
|
|
2029
|
+
```typescript
|
|
2030
|
+
import { KimuComponent } from '../../core/kimu-component';
|
|
2031
|
+
import { KimuComponentElement } from '../../core/kimu-component-element';
|
|
2032
|
+
|
|
2033
|
+
@KimuComponent({
|
|
2034
|
+
tag: 'my-extension',
|
|
2035
|
+
name: 'My Extension',
|
|
2036
|
+
version: '1.0.0',
|
|
2037
|
+
description: 'Description of what this extension does',
|
|
2038
|
+
author: 'Your Name',
|
|
2039
|
+
icon: '🎯',
|
|
2040
|
+
internal: false,
|
|
2041
|
+
path: 'my-extension',
|
|
2042
|
+
dependencies: [] // Add child extension tags if any
|
|
2043
|
+
})
|
|
2044
|
+
export class MyExtensionComponent extends KimuComponentElement {
|
|
2045
|
+
// Private properties
|
|
2046
|
+
private data: any = {};
|
|
2047
|
+
|
|
2048
|
+
// Lifecycle: Initialization
|
|
2049
|
+
onInit() {
|
|
2050
|
+
console.log('MyExtension initialized');
|
|
2051
|
+
// Initialize data, fetch resources, set up state
|
|
2052
|
+
}
|
|
2053
|
+
|
|
2054
|
+
// Lifecycle: Rendering
|
|
2055
|
+
onRender() {
|
|
2056
|
+
// Update DOM, refresh data binding
|
|
2057
|
+
const title = this.$('#title');
|
|
2058
|
+
if (title) {
|
|
2059
|
+
title.textContent = this.data.title || 'Default Title';
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
// Lifecycle: Cleanup
|
|
2064
|
+
onDestroy() {
|
|
2065
|
+
console.log('MyExtension destroyed');
|
|
2066
|
+
// Remove event listeners, clear timers, free resources
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
// Provide data for template interpolation
|
|
2070
|
+
getData() {
|
|
2071
|
+
return {
|
|
2072
|
+
title: this.data.title,
|
|
2073
|
+
description: this.data.description,
|
|
2074
|
+
handleClick: () => this.onClick()
|
|
2075
|
+
};
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2078
|
+
// Event handlers
|
|
2079
|
+
private onClick() {
|
|
2080
|
+
console.log('Button clicked!');
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
```
|
|
2084
|
+
|
|
2085
|
+
### Understanding the `dependencies` Metadata
|
|
2086
|
+
|
|
2087
|
+
The `dependencies` field is crucial for building composite extensions. It contains an array of HTML tag strings representing child extensions that will be automatically loaded and made available in the parent extension's template.
|
|
2088
|
+
|
|
2089
|
+
**How it works:**
|
|
2090
|
+
- If your extension is a "parent" that contains other extensions as components, specify their tags in the `dependencies` field
|
|
2091
|
+
- Child extensions will be automatically loaded by the KIMU Extension Manager
|
|
2092
|
+
- You can use child extensions as regular HTML tags in your `view.html` template
|
|
2093
|
+
- The framework handles the loading lifecycle and dependency resolution automatically
|
|
2094
|
+
|
|
2095
|
+
**Example with child extensions:**
|
|
2096
|
+
```typescript
|
|
2097
|
+
@KimuComponent({
|
|
2098
|
+
tag: 'dashboard-parent',
|
|
2099
|
+
name: 'Complete Dashboard',
|
|
2100
|
+
version: '1.0.0',
|
|
2101
|
+
description: 'A comprehensive dashboard with charts and tables',
|
|
2102
|
+
author: 'YourName',
|
|
2103
|
+
icon: '📊',
|
|
2104
|
+
internal: false,
|
|
2105
|
+
path: 'dashboard-parent',
|
|
2106
|
+
dependencies: ['chart-widget', 'data-table', 'filter-panel'] // Child extensions
|
|
2107
|
+
})
|
|
2108
|
+
export class DashboardParent extends KimuComponentElement {
|
|
2109
|
+
// Parent component logic
|
|
2110
|
+
}
|
|
2111
|
+
```
|
|
2112
|
+
|
|
2113
|
+
**In the `view.html` template:**
|
|
2114
|
+
```html
|
|
2115
|
+
<div class="dashboard">
|
|
2116
|
+
<h2>Interactive Dashboard</h2>
|
|
2117
|
+
<!-- Use child extensions as HTML tags -->
|
|
2118
|
+
<chart-widget data="${chartData}"></chart-widget>
|
|
2119
|
+
<data-table items="${tableItems}"></data-table>
|
|
2120
|
+
<filter-panel @filter="${onFilter}"></filter-panel>
|
|
2121
|
+
</div>
|
|
2122
|
+
```
|
|
2123
|
+
|
|
2124
|
+
**Benefits of using dependencies:**
|
|
2125
|
+
- ✅ **Modularity**: Each component is independent and reusable
|
|
2126
|
+
- ✅ **Automatic loading**: No need to manually manage extension loading
|
|
2127
|
+
- ✅ **Maintainability**: Separate updates for each child extension
|
|
2128
|
+
- ✅ **Composition**: Build complex UIs from simple, focused components
|
|
2129
|
+
|
|
2130
|
+
**Best practices for dependencies:**
|
|
2131
|
+
- Include only the dependencies you actually use in your template
|
|
2132
|
+
- Use descriptive tag names for child extensions
|
|
2133
|
+
- Document the role of each child extension in your code
|
|
2134
|
+
- Keep child extensions focused on single responsibilities
|
|
2135
|
+
|
|
2136
|
+
**Example for simple extension (no dependencies):**
|
|
2137
|
+
```typescript
|
|
2138
|
+
@KimuComponent({
|
|
2139
|
+
tag: 'simple-button',
|
|
2140
|
+
name: 'Simple Button',
|
|
2141
|
+
version: '1.0.0',
|
|
2142
|
+
description: 'A simple button component',
|
|
2143
|
+
author: 'YourName',
|
|
2144
|
+
icon: '🔘',
|
|
2145
|
+
internal: false,
|
|
2146
|
+
path: 'simple-button',
|
|
2147
|
+
dependencies: [] // No child extensions
|
|
2148
|
+
})
|
|
2149
|
+
```
|
|
2150
|
+
|
|
2151
|
+
#### Step 3: Create Styles (`style.css`)
|
|
2152
|
+
|
|
2153
|
+
```css
|
|
2154
|
+
/* Component root styling */
|
|
2155
|
+
my-extension {
|
|
2156
|
+
display: block;
|
|
2157
|
+
padding: 20px;
|
|
2158
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
2159
|
+
}
|
|
2160
|
+
|
|
2161
|
+
/* Component-specific styles */
|
|
2162
|
+
my-extension .header {
|
|
2163
|
+
font-size: 24px;
|
|
2164
|
+
font-weight: bold;
|
|
2165
|
+
margin-bottom: 10px;
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
my-extension .content {
|
|
2169
|
+
color: #333;
|
|
2170
|
+
line-height: 1.6;
|
|
2171
|
+
}
|
|
2172
|
+
|
|
2173
|
+
my-extension button {
|
|
2174
|
+
padding: 10px 20px;
|
|
2175
|
+
background: #007bff;
|
|
2176
|
+
color: white;
|
|
2177
|
+
border: none;
|
|
2178
|
+
border-radius: 4px;
|
|
2179
|
+
cursor: pointer;
|
|
2180
|
+
}
|
|
2181
|
+
|
|
2182
|
+
my-extension button:hover {
|
|
2183
|
+
background: #0056b3;
|
|
2184
|
+
}
|
|
2185
|
+
```
|
|
2186
|
+
|
|
2187
|
+
#### Step 4: Create Template (`view.html`)
|
|
2188
|
+
|
|
2189
|
+
```html
|
|
2190
|
+
<div class="extension-container">
|
|
2191
|
+
<div class="header">
|
|
2192
|
+
<h1 id="title">${title}</h1>
|
|
2193
|
+
</div>
|
|
2194
|
+
|
|
2195
|
+
<div class="content">
|
|
2196
|
+
<p>${description}</p>
|
|
2197
|
+
<button onclick="${handleClick}">Click Me</button>
|
|
2198
|
+
</div>
|
|
2199
|
+
</div>
|
|
2200
|
+
```
|
|
2201
|
+
|
|
2202
|
+
#### Step 5: Register in Manifest
|
|
2203
|
+
|
|
2204
|
+
Add entry to `extension-manifest.json` (create file if it doesn't exist):
|
|
2205
|
+
|
|
2206
|
+
```json
|
|
2207
|
+
[
|
|
2208
|
+
{
|
|
2209
|
+
"tag": "my-extension",
|
|
2210
|
+
"name": "My Extension",
|
|
2211
|
+
"version": "1.0.0",
|
|
2212
|
+
"description": "Description of what this extension does",
|
|
2213
|
+
"author": "Your Name",
|
|
2214
|
+
"icon": "🎯",
|
|
2215
|
+
"internal": false,
|
|
2216
|
+
"path": "my-extension",
|
|
2217
|
+
"dependencies": []
|
|
2218
|
+
}
|
|
2219
|
+
]
|
|
2220
|
+
```
|
|
2221
|
+
|
|
2222
|
+
#### Step 6: Use the Extension
|
|
2223
|
+
|
|
2224
|
+
Import and use in `main.ts` or other components:
|
|
2225
|
+
|
|
2226
|
+
```typescript
|
|
2227
|
+
import { KimuExtensionManager } from '@kimu/core';
|
|
2228
|
+
|
|
2229
|
+
const extensionManager = KimuExtensionManager.getInstance();
|
|
2230
|
+
await extensionManager.load('my-extension');
|
|
2231
|
+
|
|
2232
|
+
// Mount to DOM
|
|
2233
|
+
const root = document.getElementById('app');
|
|
2234
|
+
const component = document.createElement('my-extension');
|
|
2235
|
+
root?.appendChild(component);
|
|
2236
|
+
```
|
|
2237
|
+
|
|
2238
|
+
### Composite Extensions (with Dependencies)
|
|
2239
|
+
|
|
2240
|
+
If your extension uses other extensions as child components:
|
|
2241
|
+
|
|
2242
|
+
```typescript
|
|
2243
|
+
@KimuComponent({
|
|
2244
|
+
tag: 'dashboard-parent',
|
|
2245
|
+
name: 'Dashboard',
|
|
2246
|
+
version: '1.0.0',
|
|
2247
|
+
description: 'Dashboard with multiple widgets',
|
|
2248
|
+
author: 'Your Name',
|
|
2249
|
+
icon: '📊',
|
|
2250
|
+
internal: false,
|
|
2251
|
+
path: 'dashboard-parent',
|
|
2252
|
+
dependencies: ['chart-widget', 'data-table', 'user-profile'] // Child extensions
|
|
2253
|
+
})
|
|
2254
|
+
export class DashboardComponent extends KimuComponentElement {
|
|
2255
|
+
// Parent component logic
|
|
2256
|
+
}
|
|
2257
|
+
```
|
|
2258
|
+
|
|
2259
|
+
Then use child extensions in `view.html`:
|
|
2260
|
+
|
|
2261
|
+
```html
|
|
2262
|
+
<div class="dashboard">
|
|
2263
|
+
<h1>Dashboard</h1>
|
|
2264
|
+
<!-- Child extensions as HTML tags -->
|
|
2265
|
+
<chart-widget data="${chartData}"></chart-widget>
|
|
2266
|
+
<data-table items="${tableData}"></data-table>
|
|
2267
|
+
<user-profile user="${currentUser}"></user-profile>
|
|
2268
|
+
</div>
|
|
2269
|
+
```
|
|
2270
|
+
|
|
2271
|
+
**Benefits:**
|
|
2272
|
+
- ✅ Modular: Each component is independent
|
|
2273
|
+
- ✅ Automatic loading: Framework loads dependencies
|
|
2274
|
+
- ✅ Reusable: Components can be used in multiple parents
|
|
2275
|
+
- ✅ Maintainable: Update children without touching parent
|
|
2276
|
+
|
|
2277
|
+
---
|
|
2278
|
+
|
|
2279
|
+
## Module Creation Guide
|
|
2280
|
+
|
|
2281
|
+
> **Agent Training Note:** Modules provide services and reusable logic. Follow this guide when creating new modules.
|
|
2282
|
+
|
|
2283
|
+
### Module Structure
|
|
2284
|
+
|
|
2285
|
+
Every module must have:
|
|
2286
|
+
1. `module.ts` - Module class that extends `KimuModule`
|
|
2287
|
+
2. `<module-name>-service.ts` - Service implementation
|
|
2288
|
+
3. (Optional) `types.ts` - Type definitions
|
|
2289
|
+
4. (Optional) `utils.ts` - Helper functions
|
|
2290
|
+
|
|
2291
|
+
### Module Creation Checklist
|
|
2292
|
+
|
|
2293
|
+
1. ✅ Create folder in `src/modules/<module-name>/`
|
|
2294
|
+
2. ✅ Create `module.ts` and service file
|
|
2295
|
+
3. ✅ Extend `KimuModule` in module class
|
|
2296
|
+
4. ✅ Implement service class with required functionality
|
|
2297
|
+
5. ✅ Export service as singleton or factory
|
|
2298
|
+
6. ✅ Document all public APIs
|
|
2299
|
+
7. ✅ Add tests if applicable
|
|
2300
|
+
8. ✅ Update documentation
|
|
2301
|
+
|
|
2302
|
+
### Step-by-Step Instructions
|
|
2303
|
+
|
|
2304
|
+
#### Step 1: Create Module Structure
|
|
2305
|
+
```bash
|
|
2306
|
+
mkdir -p src/modules/my-module
|
|
2307
|
+
touch src/modules/my-module/module.ts
|
|
2308
|
+
touch src/modules/my-module/my-module-service.ts
|
|
2309
|
+
touch src/modules/my-module/types.ts
|
|
2310
|
+
```
|
|
2311
|
+
|
|
2312
|
+
#### Step 2: Define Types (`types.ts`)
|
|
2313
|
+
|
|
2314
|
+
```typescript
|
|
2315
|
+
export interface MyModuleOptions {
|
|
2316
|
+
enabled: boolean;
|
|
2317
|
+
config?: Record<string, any>;
|
|
2318
|
+
}
|
|
2319
|
+
|
|
2320
|
+
export interface MyModuleService {
|
|
2321
|
+
initialize(): Promise<void>;
|
|
2322
|
+
doSomething(data: any): Promise<any>;
|
|
2323
|
+
}
|
|
2324
|
+
```
|
|
2325
|
+
|
|
2326
|
+
#### Step 3: Implement Service (`my-module-service.ts`)
|
|
2327
|
+
|
|
2328
|
+
```typescript
|
|
2329
|
+
import { MyModuleOptions, MyModuleService } from './types';
|
|
2330
|
+
|
|
2331
|
+
export class MyModuleServiceImpl implements MyModuleService {
|
|
2332
|
+
private options: MyModuleOptions;
|
|
2333
|
+
private initialized: boolean = false;
|
|
2334
|
+
|
|
2335
|
+
constructor(options: MyModuleOptions = { enabled: true }) {
|
|
2336
|
+
this.options = options;
|
|
2337
|
+
}
|
|
2338
|
+
|
|
2339
|
+
async initialize(): Promise<void> {
|
|
2340
|
+
if (this.initialized) return;
|
|
2341
|
+
|
|
2342
|
+
console.log('MyModule initializing...');
|
|
2343
|
+
// Initialization logic here
|
|
2344
|
+
|
|
2345
|
+
this.initialized = true;
|
|
2346
|
+
}
|
|
2347
|
+
|
|
2348
|
+
async doSomething(data: any): Promise<any> {
|
|
2349
|
+
if (!this.initialized) {
|
|
2350
|
+
await this.initialize();
|
|
2351
|
+
}
|
|
2352
|
+
|
|
2353
|
+
// Service logic here
|
|
2354
|
+
return { success: true, data };
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
|
|
2358
|
+
// Export singleton instance
|
|
2359
|
+
export const myModuleService = new MyModuleServiceImpl();
|
|
2360
|
+
```
|
|
2361
|
+
|
|
2362
|
+
#### Step 4: Create Module Class (`module.ts`)
|
|
2363
|
+
|
|
2364
|
+
```typescript
|
|
2365
|
+
import { KimuModule } from '../../core/kimu-module';
|
|
2366
|
+
import { myModuleService } from './my-module-service';
|
|
2367
|
+
import { MyModuleOptions } from './types';
|
|
2368
|
+
|
|
2369
|
+
export default class MyModule extends KimuModule {
|
|
2370
|
+
constructor(
|
|
2371
|
+
name: string = 'my-module',
|
|
2372
|
+
version: string = '1.0.0',
|
|
2373
|
+
options?: MyModuleOptions
|
|
2374
|
+
) {
|
|
2375
|
+
super(name, version, options);
|
|
2376
|
+
|
|
2377
|
+
// Initialize with options if provided
|
|
2378
|
+
if (options) {
|
|
2379
|
+
// Configure service
|
|
2380
|
+
}
|
|
2381
|
+
}
|
|
2382
|
+
|
|
2383
|
+
getService() {
|
|
2384
|
+
return myModuleService;
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
2387
|
+
```
|
|
2388
|
+
|
|
2389
|
+
#### Step 5: Use the Module
|
|
2390
|
+
|
|
2391
|
+
In `main.ts`:
|
|
2392
|
+
|
|
2393
|
+
```typescript
|
|
2394
|
+
import { KimuModuleManager } from '@kimu/core';
|
|
2395
|
+
import MyModule from './modules/my-module/module';
|
|
2396
|
+
|
|
2397
|
+
// Initialize module manager
|
|
2398
|
+
const moduleManager = KimuModuleManager.getInstance();
|
|
2399
|
+
|
|
2400
|
+
// Load module
|
|
2401
|
+
const myModule = new MyModule('my-module', '1.0.0', { enabled: true });
|
|
2402
|
+
await moduleManager.loadModule(myModule);
|
|
2403
|
+
|
|
2404
|
+
// Get service
|
|
2405
|
+
const myService = moduleManager.getModule('my-module')?.getService();
|
|
2406
|
+
await myService.initialize();
|
|
2407
|
+
|
|
2408
|
+
// Use service
|
|
2409
|
+
const result = await myService.doSomething({ foo: 'bar' });
|
|
2410
|
+
```
|
|
2411
|
+
|
|
2412
|
+
### Module vs Extension
|
|
2413
|
+
|
|
2414
|
+
| **Module** | **Extension** |
|
|
2415
|
+
|------------|---------------|
|
|
2416
|
+
| Provides services/logic | Implements UI components |
|
|
2417
|
+
| No UI (headless) | Has view, styles, template |
|
|
2418
|
+
| Located in `src/modules/` | Located in `src/extensions/` |
|
|
2419
|
+
| Not in manifest | Registered in manifest |
|
|
2420
|
+
| Used by extensions/modules | Used by end users |
|
|
2421
|
+
| Examples: router, i18n, storage | Examples: dashboard, login, profile |
|
|
2422
|
+
|
|
2423
|
+
### Kimu Module Creation Guide - Agent Reference
|
|
2424
|
+
|
|
2425
|
+
> **Agent Training Note:** Always follow these steps and conventions when creating a new Kimu module. This ensures consistency, discoverability, and maintainability across the codebase.
|
|
2426
|
+
|
|
2427
|
+
#### 1. Structure and Required Files
|
|
2428
|
+
Each module must reside in its own folder under `/src/modules/<module-name>/` and include at least:
|
|
2429
|
+
|
|
2430
|
+
- `module.ts`: Exports a class `<ModuleName>Module` (default export) that extends `KimuModule` and provides the service via `getService()`.
|
|
2431
|
+
- `<module-name>-service.ts`: Implements the main service class and exports it with a recommended name (see below).
|
|
2432
|
+
- (Optional) `interfaces.ts`, `utils.ts`, or other helpers as needed.
|
|
2433
|
+
|
|
2434
|
+
**Example structure:**
|
|
2435
|
+
```
|
|
2436
|
+
src/modules/event-bus/
|
|
2437
|
+
├── event-bus-service.ts
|
|
2438
|
+
└── module.ts
|
|
2439
|
+
```
|
|
2440
|
+
|
|
2441
|
+
#### 2. Naming Conventions
|
|
2442
|
+
- The service class should be named `<ModuleName>Service` (e.g., `EventBusService`).
|
|
2443
|
+
- The main export of the service file should be `<moduleName>Service` (camelCase, e.g., `eventBusService`).
|
|
2444
|
+
- The module class should be named `<ModuleName>Module` and exported as default from `module.ts`.
|
|
2445
|
+
|
|
2446
|
+
#### 3. Reference Classes
|
|
2447
|
+
- All modules must extend `KimuModule` (from `/src/core/kimu-module.ts`).
|
|
2448
|
+
- Services should be implemented as classes and exported as singletons or via factory, as appropriate.
|
|
2449
|
+
|
|
2450
|
+
#### 4. Example: Minimal Event Bus Module
|
|
2451
|
+
```typescript
|
|
2452
|
+
// event-bus-service.ts
|
|
2453
|
+
export class EventBusService {
|
|
2454
|
+
on(event: string, cb: (...args: any[]) => void) { /* ... */ }
|
|
2455
|
+
emit(event: string, data: any) { /* ... */ }
|
|
2456
|
+
}
|
|
2457
|
+
export const eventBusService = new EventBusService();
|
|
2458
|
+
|
|
2459
|
+
// module.ts
|
|
2460
|
+
import { KimuModule } from '../../core/kimu-module';
|
|
2461
|
+
import { eventBusService } from './event-bus-service';
|
|
2462
|
+
export default class EventBusModule extends KimuModule {
|
|
2463
|
+
constructor(name = 'event-bus', version = '1.0.0', options?: any) {
|
|
2464
|
+
super(name, version, options);
|
|
2465
|
+
}
|
|
2466
|
+
getService() {
|
|
2467
|
+
return eventBusService;
|
|
2468
|
+
}
|
|
2469
|
+
}
|
|
2470
|
+
```
|
|
2471
|
+
|
|
2472
|
+
#### 5. Difference Between Module and Extension (Detailed)
|
|
2473
|
+
- **Module**: Provides reusable logic/services (e.g., i18n, event-bus, storage) for use by extensions or other modules. No UI.
|
|
2474
|
+
- **Extension**: Implements a user-facing scenario/component, always in `/src/extensions/`, with UI and registration in the manifest.
|
|
2475
|
+
|
|
2476
|
+
#### 6. Module Checklist for Agent Training
|
|
2477
|
+
For agent training, always follow this checklist when creating a new module:
|
|
2478
|
+
1. Create a new folder in `/src/modules/<module-name>/`.
|
|
2479
|
+
2. Add at least `module.ts` and `<module-name>-service.ts`.
|
|
2480
|
+
3. Extend `KimuModule` in your module class.
|
|
2481
|
+
4. Use the recommended naming for classes and exports.
|
|
2482
|
+
5. Document all public APIs in English.
|
|
2483
|
+
6. Add tests in `/tests/` if needed.
|
|
2484
|
+
7. Update `/docs/` with usage instructions and examples.
|
|
2485
|
+
8. Check code style with `npm run lint`.
|
|
2486
|
+
9. Run tests with `npm test`.
|
|
2487
|
+
10. Update this guide if you introduce new patterns or conventions for modules.
|
|
2488
|
+
|
|
2489
|
+
---
|
|
2490
|
+
|
|
2491
|
+
## Router Module
|
|
2492
|
+
|
|
2493
|
+
> **Agent Training Note:** The Router module provides client-side navigation. Use this guide when implementing routing in KIMU applications.
|
|
2494
|
+
|
|
2495
|
+
### Router Overview
|
|
2496
|
+
|
|
2497
|
+
The KIMU Router provides:
|
|
2498
|
+
- Hash-based routing (`#/path`)
|
|
2499
|
+
- Dynamic route parameters (`:id`, `:slug`)
|
|
2500
|
+
- Query string support
|
|
2501
|
+
- Route guards for authentication
|
|
2502
|
+
- Programmatic navigation
|
|
2503
|
+
- History management
|
|
2504
|
+
|
|
2505
|
+
### Setting Up Router
|
|
2506
|
+
|
|
2507
|
+
#### 1. Install/Import Router Module
|
|
2508
|
+
|
|
2509
|
+
```typescript
|
|
2510
|
+
import { KimuModuleManager } from '@kimu/core';
|
|
2511
|
+
import RouterModule from './modules/router/module';
|
|
2512
|
+
|
|
2513
|
+
const moduleManager = KimuModuleManager.getInstance();
|
|
2514
|
+
const routerModule = new RouterModule();
|
|
2515
|
+
await moduleManager.loadModule(routerModule);
|
|
2516
|
+
|
|
2517
|
+
const router = moduleManager.getRouterService();
|
|
2518
|
+
```
|
|
2519
|
+
|
|
2520
|
+
#### 2. Define Routes
|
|
2521
|
+
|
|
2522
|
+
```typescript
|
|
2523
|
+
// Simple routes
|
|
2524
|
+
router.addRoute('/', () => {
|
|
2525
|
+
console.log('Home page');
|
|
2526
|
+
loadHomeComponent();
|
|
2527
|
+
});
|
|
2528
|
+
|
|
2529
|
+
router.addRoute('/about', () => {
|
|
2530
|
+
console.log('About page');
|
|
2531
|
+
loadAboutComponent();
|
|
2532
|
+
});
|
|
2533
|
+
|
|
2534
|
+
// Routes with parameters
|
|
2535
|
+
router.addRoute('/user/:id', () => {
|
|
2536
|
+
const params = router.getParams();
|
|
2537
|
+
console.log('User ID:', params.id);
|
|
2538
|
+
loadUserComponent(params.id);
|
|
2539
|
+
});
|
|
2540
|
+
|
|
2541
|
+
// Routes with multiple parameters
|
|
2542
|
+
router.addRoute('/product/:category/:id', () => {
|
|
2543
|
+
const params = router.getParams();
|
|
2544
|
+
loadProductComponent(params.category, params.id);
|
|
2545
|
+
});
|
|
2546
|
+
```
|
|
2547
|
+
|
|
2548
|
+
#### 3. Navigate Between Routes
|
|
2549
|
+
|
|
2550
|
+
```typescript
|
|
2551
|
+
// Navigate to route
|
|
2552
|
+
router.navigate('/about');
|
|
2553
|
+
|
|
2554
|
+
// Navigate with parameters
|
|
2555
|
+
router.navigate('/user/123');
|
|
2556
|
+
|
|
2557
|
+
// Navigate with query string
|
|
2558
|
+
router.navigate('/search?q=kimu&sort=date');
|
|
2559
|
+
|
|
2560
|
+
// Replace current route (no history entry)
|
|
2561
|
+
router.replace('/login');
|
|
2562
|
+
|
|
2563
|
+
// Browser back/forward
|
|
2564
|
+
router.back();
|
|
2565
|
+
router.forward();
|
|
2566
|
+
```
|
|
2567
|
+
|
|
2568
|
+
#### 4. Access Route Data
|
|
2569
|
+
|
|
2570
|
+
```typescript
|
|
2571
|
+
// Get current route
|
|
2572
|
+
const currentRoute = router.getCurrentRoute();
|
|
2573
|
+
console.log(currentRoute.path); // e.g., '/user/123'
|
|
2574
|
+
console.log(currentRoute.params); // e.g., { id: '123' }
|
|
2575
|
+
console.log(currentRoute.query); // e.g., { filter: 'active' }
|
|
2576
|
+
|
|
2577
|
+
// Get route parameters
|
|
2578
|
+
const params = router.getParams(); // { id: '123' }
|
|
2579
|
+
|
|
2580
|
+
// Get query parameters
|
|
2581
|
+
const query = router.getQuery(); // { filter: 'active', sort: 'date' }
|
|
2582
|
+
```
|
|
2583
|
+
|
|
2584
|
+
#### 5. Route Guards
|
|
2585
|
+
|
|
2586
|
+
```typescript
|
|
2587
|
+
// Protected routes
|
|
2588
|
+
router.addRoute('/dashboard', () => {
|
|
2589
|
+
if (!isAuthenticated()) {
|
|
2590
|
+
router.navigate('/login');
|
|
2591
|
+
return;
|
|
2592
|
+
}
|
|
2593
|
+
loadDashboardComponent();
|
|
2594
|
+
});
|
|
2595
|
+
|
|
2596
|
+
// Admin-only routes
|
|
2597
|
+
router.addRoute('/admin/:section', () => {
|
|
2598
|
+
if (!hasAdminRole()) {
|
|
2599
|
+
router.navigate('/unauthorized');
|
|
2600
|
+
return;
|
|
2601
|
+
}
|
|
2602
|
+
const params = router.getParams();
|
|
2603
|
+
loadAdminSection(params.section);
|
|
2604
|
+
});
|
|
2605
|
+
```
|
|
2606
|
+
|
|
2607
|
+
#### 6. Route Change Listeners
|
|
2608
|
+
|
|
2609
|
+
```typescript
|
|
2610
|
+
// Listen for route changes
|
|
2611
|
+
router.onRouteChange((route) => {
|
|
2612
|
+
console.log('Route changed:', route.path);
|
|
2613
|
+
console.log('Parameters:', route.params);
|
|
2614
|
+
console.log('Query:', route.query);
|
|
2615
|
+
|
|
2616
|
+
// Update navigation UI
|
|
2617
|
+
updateActiveNavItem(route.path);
|
|
2618
|
+
|
|
2619
|
+
// Analytics
|
|
2620
|
+
trackPageView(route.path);
|
|
2621
|
+
});
|
|
2622
|
+
```
|
|
2623
|
+
|
|
2624
|
+
### Router in Components
|
|
2625
|
+
|
|
2626
|
+
```typescript
|
|
2627
|
+
import { KimuModuleManager } from '@kimu/core';
|
|
2628
|
+
|
|
2629
|
+
export class NavigationComponent extends KimuComponentElement {
|
|
2630
|
+
private router: any;
|
|
2631
|
+
|
|
2632
|
+
async onInit() {
|
|
2633
|
+
// Get router service
|
|
2634
|
+
this.router = KimuModuleManager.getInstance().getRouterService();
|
|
2635
|
+
|
|
2636
|
+
// Listen for route changes
|
|
2637
|
+
this.router.onRouteChange(this.handleRouteChange.bind(this));
|
|
2638
|
+
}
|
|
2639
|
+
|
|
2640
|
+
private handleRouteChange(route: any) {
|
|
2641
|
+
// Update component based on route
|
|
2642
|
+
this.onRender();
|
|
2643
|
+
}
|
|
2644
|
+
|
|
2645
|
+
// Navigation methods
|
|
2646
|
+
goToHome() {
|
|
2647
|
+
this.router.navigate('/');
|
|
2648
|
+
}
|
|
2649
|
+
|
|
2650
|
+
goToUser(userId: string) {
|
|
2651
|
+
this.router.navigate(`/user/${userId}`);
|
|
2652
|
+
}
|
|
2653
|
+
|
|
2654
|
+
goBack() {
|
|
2655
|
+
this.router.back();
|
|
2656
|
+
}
|
|
2657
|
+
}
|
|
2658
|
+
```
|
|
2659
|
+
|
|
2660
|
+
### Router Best Practices
|
|
2661
|
+
|
|
2662
|
+
1. **Define route constants** to avoid hardcoded strings:
|
|
2663
|
+
```typescript
|
|
2664
|
+
export const ROUTES = {
|
|
2665
|
+
HOME: '/',
|
|
2666
|
+
ABOUT: '/about',
|
|
2667
|
+
USER_PROFILE: '/user/:id',
|
|
2668
|
+
ADMIN: '/admin/:section'
|
|
2669
|
+
} as const;
|
|
2670
|
+
|
|
2671
|
+
router.addRoute(ROUTES.USER_PROFILE, handleUserProfile);
|
|
2672
|
+
```
|
|
2673
|
+
|
|
2674
|
+
2. **Validate route parameters**:
|
|
2675
|
+
```typescript
|
|
2676
|
+
router.addRoute('/user/:id', () => {
|
|
2677
|
+
const params = router.getParams();
|
|
2678
|
+
const userId = parseInt(params.id);
|
|
2679
|
+
|
|
2680
|
+
if (isNaN(userId) || userId <= 0) {
|
|
2681
|
+
router.navigate('/users'); // Redirect to list
|
|
2682
|
+
return;
|
|
2683
|
+
}
|
|
2684
|
+
|
|
2685
|
+
loadUser(userId);
|
|
2686
|
+
});
|
|
2687
|
+
```
|
|
2688
|
+
|
|
2689
|
+
3. **Handle 404 routes**:
|
|
2690
|
+
```typescript
|
|
2691
|
+
// Add as last route
|
|
2692
|
+
router.addRoute('*', () => {
|
|
2693
|
+
console.warn('Route not found');
|
|
2694
|
+
router.replace('/'); // Redirect to home
|
|
2695
|
+
});
|
|
2696
|
+
```
|
|
2697
|
+
|
|
2698
|
+
4. **Lazy load components**:
|
|
2699
|
+
```typescript
|
|
2700
|
+
router.addRoute('/heavy-page', async () => {
|
|
2701
|
+
const { HeavyComponent } = await import('./components/heavy-component');
|
|
2702
|
+
renderComponent(HeavyComponent);
|
|
2703
|
+
});
|
|
2704
|
+
```
|
|
2705
|
+
|
|
2706
|
+
---
|
|
2707
|
+
|
|
2708
|
+
## Internationalization (i18n)
|
|
2709
|
+
|
|
2710
|
+
> **Agent Training Note:** Always implement i18n support for user-facing strings. Follow this guide for multi-language support.
|
|
2711
|
+
|
|
2712
|
+
### i18n Overview
|
|
2713
|
+
|
|
2714
|
+
KIMU supports internationalization through:
|
|
2715
|
+
- JSON language files
|
|
2716
|
+
- Translation service
|
|
2717
|
+
- Dynamic language switching
|
|
2718
|
+
- String interpolation
|
|
2719
|
+
- Pluralization support (optional)
|
|
2720
|
+
|
|
2721
|
+
### Setting Up i18n
|
|
2722
|
+
|
|
2723
|
+
#### 1. Create Language Files
|
|
2724
|
+
|
|
2725
|
+
Create language files in `src/modules/i18n/locales/`:
|
|
2726
|
+
|
|
2727
|
+
**`en.json`:**
|
|
2728
|
+
```json
|
|
2729
|
+
{
|
|
2730
|
+
"common": {
|
|
2731
|
+
"hello": "Hello",
|
|
2732
|
+
"welcome": "Welcome to KIMU!",
|
|
2733
|
+
"save": "Save",
|
|
2734
|
+
"cancel": "Cancel"
|
|
2735
|
+
},
|
|
2736
|
+
"errors": {
|
|
2737
|
+
"network": "Network error. Please try again.",
|
|
2738
|
+
"notFound": "Resource not found"
|
|
2739
|
+
},
|
|
2740
|
+
"user": {
|
|
2741
|
+
"profile": "User Profile",
|
|
2742
|
+
"settings": "Settings"
|
|
2743
|
+
}
|
|
2744
|
+
}
|
|
2745
|
+
```
|
|
2746
|
+
|
|
2747
|
+
**`it.json`:**
|
|
2748
|
+
```json
|
|
2749
|
+
{
|
|
2750
|
+
"common": {
|
|
2751
|
+
"hello": "Ciao",
|
|
2752
|
+
"welcome": "Benvenuto in KIMU!",
|
|
2753
|
+
"save": "Salva",
|
|
2754
|
+
"cancel": "Annulla"
|
|
2755
|
+
},
|
|
2756
|
+
"errors": {
|
|
2757
|
+
"network": "Errore di rete. Riprova.",
|
|
2758
|
+
"notFound": "Risorsa non trovata"
|
|
2759
|
+
},
|
|
2760
|
+
"user": {
|
|
2761
|
+
"profile": "Profilo Utente",
|
|
2762
|
+
"settings": "Impostazioni"
|
|
2763
|
+
}
|
|
2764
|
+
}
|
|
2765
|
+
```
|
|
2766
|
+
|
|
2767
|
+
#### 2. Initialize i18n Service
|
|
2768
|
+
|
|
2769
|
+
```typescript
|
|
2770
|
+
import { KimuModuleManager } from '@kimu/core';
|
|
2771
|
+
import I18nModule from './modules/i18n/module';
|
|
2772
|
+
|
|
2773
|
+
const moduleManager = KimuModuleManager.getInstance();
|
|
2774
|
+
const i18nModule = new I18nModule('i18n', '1.0.0', {
|
|
2775
|
+
defaultLanguage: 'en',
|
|
2776
|
+
fallbackLanguage: 'en',
|
|
2777
|
+
supportedLanguages: ['en', 'it', 'fr']
|
|
2778
|
+
});
|
|
2779
|
+
await moduleManager.loadModule(i18nModule);
|
|
2780
|
+
|
|
2781
|
+
const i18n = moduleManager.getI18nService();
|
|
2782
|
+
```
|
|
2783
|
+
|
|
2784
|
+
#### 3. Use Translations in Components
|
|
2785
|
+
|
|
2786
|
+
```typescript
|
|
2787
|
+
export class MyComponent extends KimuComponentElement {
|
|
2788
|
+
private i18n: any;
|
|
2789
|
+
|
|
2790
|
+
onInit() {
|
|
2791
|
+
this.i18n = KimuModuleManager.getInstance().getI18nService();
|
|
2792
|
+
}
|
|
2793
|
+
|
|
2794
|
+
getData() {
|
|
2795
|
+
return {
|
|
2796
|
+
// Pass translate function to template
|
|
2797
|
+
translate: this.i18n.translate,
|
|
2798
|
+
|
|
2799
|
+
// Or translate in component
|
|
2800
|
+
welcomeMessage: this.i18n.translate('common.welcome'),
|
|
2801
|
+
saveButton: this.i18n.translate('common.save')
|
|
2802
|
+
};
|
|
2803
|
+
}
|
|
2804
|
+
}
|
|
2805
|
+
```
|
|
2806
|
+
|
|
2807
|
+
#### 4. Use in Templates
|
|
2808
|
+
|
|
2809
|
+
```html
|
|
2810
|
+
<div>
|
|
2811
|
+
<h1>${translate('common.welcome')}</h1>
|
|
2812
|
+
<p>${translate('user.profile')}</p>
|
|
2813
|
+
<button>${translate('common.save')}</button>
|
|
2814
|
+
</div>
|
|
2815
|
+
```
|
|
2816
|
+
|
|
2817
|
+
#### 5. String Interpolation
|
|
2818
|
+
|
|
2819
|
+
For dynamic content:
|
|
2820
|
+
|
|
2821
|
+
**Language file:**
|
|
2822
|
+
```json
|
|
2823
|
+
{
|
|
2824
|
+
"greeting": "Hello, {name}!",
|
|
2825
|
+
"itemCount": "You have {count} items"
|
|
2826
|
+
}
|
|
2827
|
+
```
|
|
2828
|
+
|
|
2829
|
+
**In code:**
|
|
2830
|
+
```typescript
|
|
2831
|
+
const greeting = this.i18n.translate('greeting', { name: 'John' });
|
|
2832
|
+
// Result: "Hello, John!"
|
|
2833
|
+
|
|
2834
|
+
const itemCount = this.i18n.translate('itemCount', { count: 5 });
|
|
2835
|
+
// Result: "You have 5 items"
|
|
2836
|
+
```
|
|
2837
|
+
|
|
2838
|
+
#### 6. Language Switching
|
|
2839
|
+
|
|
2840
|
+
```typescript
|
|
2841
|
+
// Get current language
|
|
2842
|
+
const currentLang = i18n.getCurrentLanguage(); // 'en'
|
|
2843
|
+
|
|
2844
|
+
// Set language
|
|
2845
|
+
i18n.setLanguage('it');
|
|
2846
|
+
|
|
2847
|
+
// Listen for language changes
|
|
2848
|
+
i18n.onLanguageChange((newLang) => {
|
|
2849
|
+
console.log('Language changed to:', newLang);
|
|
2850
|
+
// Re-render components
|
|
2851
|
+
});
|
|
2852
|
+
```
|
|
2853
|
+
|
|
2854
|
+
#### 7. Language Switcher UI
|
|
2855
|
+
|
|
2856
|
+
```html
|
|
2857
|
+
<select id="langSelect">
|
|
2858
|
+
<option value="en">English</option>
|
|
2859
|
+
<option value="it">Italiano</option>
|
|
2860
|
+
<option value="fr">Français</option>
|
|
2861
|
+
</select>
|
|
2862
|
+
```
|
|
2863
|
+
|
|
2864
|
+
```typescript
|
|
2865
|
+
onInit() {
|
|
2866
|
+
const langSelect = this.$('#langSelect');
|
|
2867
|
+
langSelect?.addEventListener('change', (e) => {
|
|
2868
|
+
const lang = (e.target as HTMLSelectElement).value;
|
|
2869
|
+
this.i18n.setLanguage(lang);
|
|
2870
|
+
this.onRender(); // Re-render with new language
|
|
2871
|
+
});
|
|
2872
|
+
}
|
|
2873
|
+
```
|
|
2874
|
+
|
|
2875
|
+
### i18n Best Practices
|
|
2876
|
+
|
|
2877
|
+
1. **Always use translation keys** - Never hardcode user-facing text:
|
|
2878
|
+
```typescript
|
|
2879
|
+
// ❌ Bad
|
|
2880
|
+
button.textContent = 'Save';
|
|
2881
|
+
|
|
2882
|
+
// ✅ Good
|
|
2883
|
+
button.textContent = this.i18n.translate('common.save');
|
|
2884
|
+
```
|
|
2885
|
+
|
|
2886
|
+
2. **Organize keys hierarchically**:
|
|
2887
|
+
```json
|
|
2888
|
+
{
|
|
2889
|
+
"common": { "save": "Save", "cancel": "Cancel" },
|
|
2890
|
+
"user": { "profile": "Profile", "settings": "Settings" },
|
|
2891
|
+
"errors": { "network": "Network error" }
|
|
2892
|
+
}
|
|
2893
|
+
```
|
|
2894
|
+
|
|
2895
|
+
3. **Provide fallbacks**:
|
|
2896
|
+
```typescript
|
|
2897
|
+
const text = this.i18n.translate('some.key') || 'Default Text';
|
|
2898
|
+
```
|
|
2899
|
+
|
|
2900
|
+
4. **Keep translations up to date** - When adding new features, update all language files.
|
|
2901
|
+
|
|
2902
|
+
5. **Use descriptive keys** - Keys should indicate context:
|
|
2903
|
+
```json
|
|
2904
|
+
{
|
|
2905
|
+
"button.save": "Save",
|
|
2906
|
+
"button.cancel": "Cancel",
|
|
2907
|
+
"error.network": "Network error",
|
|
2908
|
+
"title.userProfile": "User Profile"
|
|
2909
|
+
}
|
|
2910
|
+
```
|
|
2911
|
+
|
|
2912
|
+
---
|
|
2913
|
+
|
|
2914
|
+
## Practical Examples
|
|
2915
|
+
|
|
2916
|
+
> **Agent Training Note:** Use these examples as templates when generating code.
|
|
2917
|
+
|
|
2918
|
+
### Example 1: Minimal Extension
|
|
2919
|
+
|
|
2920
|
+
```typescript
|
|
2921
|
+
// src/extensions/hello-world/component.ts
|
|
2922
|
+
import { KimuComponent } from '../../core/kimu-component';
|
|
2923
|
+
import { KimuComponentElement } from '../../core/kimu-component-element';
|
|
2924
|
+
|
|
2925
|
+
@KimuComponent({
|
|
2926
|
+
tag: 'hello-world',
|
|
2927
|
+
name: 'Hello World',
|
|
2928
|
+
version: '1.0.0',
|
|
2929
|
+
description: 'A simple hello world component',
|
|
2930
|
+
author: 'KIMU Team',
|
|
2931
|
+
icon: '👋',
|
|
2932
|
+
internal: false,
|
|
2933
|
+
path: 'hello-world',
|
|
2934
|
+
dependencies: []
|
|
2935
|
+
})
|
|
2936
|
+
export class HelloWorldComponent extends KimuComponentElement {
|
|
2937
|
+
onInit() {
|
|
2938
|
+
console.log('Hello World initialized!');
|
|
2939
|
+
}
|
|
2940
|
+
|
|
2941
|
+
getData() {
|
|
2942
|
+
return {
|
|
2943
|
+
message: 'Hello, KIMU Framework!'
|
|
2944
|
+
};
|
|
2945
|
+
}
|
|
2946
|
+
}
|
|
2947
|
+
```
|
|
2948
|
+
|
|
2949
|
+
```html
|
|
2950
|
+
<!-- src/extensions/hello-world/view.html -->
|
|
2951
|
+
<div class="hello-world">
|
|
2952
|
+
<h1>${message}</h1>
|
|
2953
|
+
</div>
|
|
2954
|
+
```
|
|
2955
|
+
|
|
2956
|
+
```css
|
|
2957
|
+
/* src/extensions/hello-world/style.css */
|
|
2958
|
+
hello-world {
|
|
2959
|
+
display: block;
|
|
2960
|
+
padding: 20px;
|
|
2961
|
+
text-align: center;
|
|
2962
|
+
}
|
|
2963
|
+
|
|
2964
|
+
hello-world h1 {
|
|
2965
|
+
color: #007bff;
|
|
2966
|
+
font-size: 32px;
|
|
2967
|
+
}
|
|
2968
|
+
```
|
|
2969
|
+
|
|
2970
|
+
### Example 2: Counter Component with State
|
|
2971
|
+
|
|
2972
|
+
```typescript
|
|
2973
|
+
// src/extensions/counter/component.ts
|
|
2974
|
+
@KimuComponent({
|
|
2975
|
+
tag: 'kimu-counter',
|
|
2976
|
+
name: 'Counter',
|
|
2977
|
+
version: '1.0.0',
|
|
2978
|
+
description: 'A simple counter component',
|
|
2979
|
+
author: 'KIMU Team',
|
|
2980
|
+
icon: '🔢',
|
|
2981
|
+
internal: false,
|
|
2982
|
+
path: 'counter',
|
|
2983
|
+
dependencies: []
|
|
2984
|
+
})
|
|
2985
|
+
export class CounterComponent extends KimuComponentElement {
|
|
2986
|
+
private count: number = 0;
|
|
2987
|
+
|
|
2988
|
+
onInit() {
|
|
2989
|
+
this.count = 0;
|
|
2990
|
+
this.setupEventListeners();
|
|
2991
|
+
}
|
|
2992
|
+
|
|
2993
|
+
onRender() {
|
|
2994
|
+
const display = this.$('#count-display');
|
|
2995
|
+
if (display) {
|
|
2996
|
+
display.textContent = this.count.toString();
|
|
2997
|
+
}
|
|
2998
|
+
}
|
|
2999
|
+
|
|
3000
|
+
private setupEventListeners() {
|
|
3001
|
+
this.$('#increment')?.addEventListener('click', () => this.increment());
|
|
3002
|
+
this.$('#decrement')?.addEventListener('click', () => this.decrement());
|
|
3003
|
+
this.$('#reset')?.addEventListener('click', () => this.reset());
|
|
3004
|
+
}
|
|
3005
|
+
|
|
3006
|
+
private increment() {
|
|
3007
|
+
this.count++;
|
|
3008
|
+
this.onRender();
|
|
3009
|
+
}
|
|
3010
|
+
|
|
3011
|
+
private decrement() {
|
|
3012
|
+
this.count--;
|
|
3013
|
+
this.onRender();
|
|
3014
|
+
}
|
|
3015
|
+
|
|
3016
|
+
private reset() {
|
|
3017
|
+
this.count = 0;
|
|
3018
|
+
this.onRender();
|
|
3019
|
+
}
|
|
3020
|
+
|
|
3021
|
+
getData() {
|
|
3022
|
+
return {
|
|
3023
|
+
count: this.count
|
|
3024
|
+
};
|
|
3025
|
+
}
|
|
3026
|
+
}
|
|
3027
|
+
```
|
|
3028
|
+
|
|
3029
|
+
```html
|
|
3030
|
+
<!-- src/extensions/counter/view.html -->
|
|
3031
|
+
<div class="counter">
|
|
3032
|
+
<h2>Counter</h2>
|
|
3033
|
+
<div class="display">
|
|
3034
|
+
<span id="count-display">${count}</span>
|
|
3035
|
+
</div>
|
|
3036
|
+
<div class="controls">
|
|
3037
|
+
<button id="decrement">-</button>
|
|
3038
|
+
<button id="reset">Reset</button>
|
|
3039
|
+
<button id="increment">+</button>
|
|
3040
|
+
</div>
|
|
3041
|
+
</div>
|
|
3042
|
+
```
|
|
3043
|
+
|
|
3044
|
+
### Example 3: Data Fetching Component
|
|
3045
|
+
|
|
3046
|
+
```typescript
|
|
3047
|
+
// src/extensions/user-list/component.ts
|
|
3048
|
+
interface User {
|
|
3049
|
+
id: number;
|
|
3050
|
+
name: string;
|
|
3051
|
+
email: string;
|
|
3052
|
+
}
|
|
3053
|
+
|
|
3054
|
+
@KimuComponent({
|
|
3055
|
+
tag: 'user-list',
|
|
3056
|
+
name: 'User List',
|
|
3057
|
+
version: '1.0.0',
|
|
3058
|
+
description: 'Displays a list of users',
|
|
3059
|
+
author: 'KIMU Team',
|
|
3060
|
+
icon: '👥',
|
|
3061
|
+
internal: false,
|
|
3062
|
+
path: 'user-list',
|
|
3063
|
+
dependencies: []
|
|
3064
|
+
})
|
|
3065
|
+
export class UserListComponent extends KimuComponentElement {
|
|
3066
|
+
private users: User[] = [];
|
|
3067
|
+
private loading: boolean = false;
|
|
3068
|
+
private error: string | null = null;
|
|
3069
|
+
|
|
3070
|
+
async onInit() {
|
|
3071
|
+
await this.loadUsers();
|
|
3072
|
+
}
|
|
3073
|
+
|
|
3074
|
+
private async loadUsers() {
|
|
3075
|
+
this.loading = true;
|
|
3076
|
+
this.error = null;
|
|
3077
|
+
this.onRender();
|
|
3078
|
+
|
|
3079
|
+
try {
|
|
3080
|
+
const response = await fetch('https://api.example.com/users');
|
|
3081
|
+
if (!response.ok) throw new Error('Failed to fetch users');
|
|
3082
|
+
|
|
3083
|
+
this.users = await response.json();
|
|
3084
|
+
} catch (error) {
|
|
3085
|
+
this.error = error instanceof Error ? error.message : 'Unknown error';
|
|
3086
|
+
} finally {
|
|
3087
|
+
this.loading = false;
|
|
3088
|
+
this.onRender();
|
|
3089
|
+
}
|
|
3090
|
+
}
|
|
3091
|
+
|
|
3092
|
+
onRender() {
|
|
3093
|
+
const container = this.$('#user-container');
|
|
3094
|
+
if (!container) return;
|
|
3095
|
+
|
|
3096
|
+
if (this.loading) {
|
|
3097
|
+
container.innerHTML = '<p>Loading...</p>';
|
|
3098
|
+
return;
|
|
3099
|
+
}
|
|
3100
|
+
|
|
3101
|
+
if (this.error) {
|
|
3102
|
+
container.innerHTML = `<p class="error">${this.error}</p>`;
|
|
3103
|
+
return;
|
|
3104
|
+
}
|
|
3105
|
+
|
|
3106
|
+
container.innerHTML = this.users
|
|
3107
|
+
.map(user => `
|
|
3108
|
+
<div class="user-card">
|
|
3109
|
+
<h3>${user.name}</h3>
|
|
3110
|
+
<p>${user.email}</p>
|
|
3111
|
+
</div>
|
|
3112
|
+
`)
|
|
3113
|
+
.join('');
|
|
3114
|
+
}
|
|
3115
|
+
}
|
|
3116
|
+
```
|
|
3117
|
+
|
|
3118
|
+
### Example 4: Form Component
|
|
3119
|
+
|
|
3120
|
+
```typescript
|
|
3121
|
+
// src/extensions/contact-form/component.ts
|
|
3122
|
+
@KimuComponent({
|
|
3123
|
+
tag: 'contact-form',
|
|
3124
|
+
name: 'Contact Form',
|
|
3125
|
+
version: '1.0.0',
|
|
3126
|
+
description: 'A contact form with validation',
|
|
3127
|
+
author: 'KIMU Team',
|
|
3128
|
+
icon: '📝',
|
|
3129
|
+
internal: false,
|
|
3130
|
+
path: 'contact-form',
|
|
3131
|
+
dependencies: []
|
|
3132
|
+
})
|
|
3133
|
+
export class ContactFormComponent extends KimuComponentElement {
|
|
3134
|
+
private formData = {
|
|
3135
|
+
name: '',
|
|
3136
|
+
email: '',
|
|
3137
|
+
message: ''
|
|
3138
|
+
};
|
|
3139
|
+
|
|
3140
|
+
onInit() {
|
|
3141
|
+
this.setupForm();
|
|
3142
|
+
}
|
|
3143
|
+
|
|
3144
|
+
private setupForm() {
|
|
3145
|
+
const form = this.$('form');
|
|
3146
|
+
form?.addEventListener('submit', (e) => {
|
|
3147
|
+
e.preventDefault();
|
|
3148
|
+
this.handleSubmit();
|
|
3149
|
+
});
|
|
3150
|
+
|
|
3151
|
+
// Real-time validation
|
|
3152
|
+
this.$('#email')?.addEventListener('blur', () => {
|
|
3153
|
+
this.validateEmail();
|
|
3154
|
+
});
|
|
3155
|
+
}
|
|
3156
|
+
|
|
3157
|
+
private handleSubmit() {
|
|
3158
|
+
if (!this.validateForm()) {
|
|
3159
|
+
return;
|
|
3160
|
+
}
|
|
3161
|
+
|
|
3162
|
+
console.log('Form submitted:', this.formData);
|
|
3163
|
+
|
|
3164
|
+
// Send data to server
|
|
3165
|
+
this.submitForm();
|
|
3166
|
+
}
|
|
3167
|
+
|
|
3168
|
+
private validateForm(): boolean {
|
|
3169
|
+
const nameInput = this.$('#name') as HTMLInputElement;
|
|
3170
|
+
const emailInput = this.$('#email') as HTMLInputElement;
|
|
3171
|
+
const messageInput = this.$('#message') as HTMLTextAreaElement;
|
|
3172
|
+
|
|
3173
|
+
this.formData.name = nameInput?.value || '';
|
|
3174
|
+
this.formData.email = emailInput?.value || '';
|
|
3175
|
+
this.formData.message = messageInput?.value || '';
|
|
3176
|
+
|
|
3177
|
+
if (!this.formData.name || !this.formData.email || !this.formData.message) {
|
|
3178
|
+
this.showError('All fields are required');
|
|
3179
|
+
return false;
|
|
3180
|
+
}
|
|
3181
|
+
|
|
3182
|
+
if (!this.isValidEmail(this.formData.email)) {
|
|
3183
|
+
this.showError('Invalid email address');
|
|
3184
|
+
return false;
|
|
3185
|
+
}
|
|
3186
|
+
|
|
3187
|
+
return true;
|
|
3188
|
+
}
|
|
3189
|
+
|
|
3190
|
+
private isValidEmail(email: string): boolean {
|
|
3191
|
+
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
|
3192
|
+
}
|
|
3193
|
+
|
|
3194
|
+
private validateEmail() {
|
|
3195
|
+
const emailInput = this.$('#email') as HTMLInputElement;
|
|
3196
|
+
const email = emailInput?.value || '';
|
|
3197
|
+
|
|
3198
|
+
if (email && !this.isValidEmail(email)) {
|
|
3199
|
+
emailInput?.classList.add('invalid');
|
|
3200
|
+
} else {
|
|
3201
|
+
emailInput?.classList.remove('invalid');
|
|
3202
|
+
}
|
|
3203
|
+
}
|
|
3204
|
+
|
|
3205
|
+
private showError(message: string) {
|
|
3206
|
+
const errorDiv = this.$('#error-message');
|
|
3207
|
+
if (errorDiv) {
|
|
3208
|
+
errorDiv.textContent = message;
|
|
3209
|
+
errorDiv.style.display = 'block';
|
|
3210
|
+
}
|
|
3211
|
+
}
|
|
3212
|
+
|
|
3213
|
+
private async submitForm() {
|
|
3214
|
+
try {
|
|
3215
|
+
const response = await fetch('/api/contact', {
|
|
3216
|
+
method: 'POST',
|
|
3217
|
+
headers: { 'Content-Type': 'application/json' },
|
|
3218
|
+
body: JSON.stringify(this.formData)
|
|
3219
|
+
});
|
|
3220
|
+
|
|
3221
|
+
if (response.ok) {
|
|
3222
|
+
this.showSuccess('Message sent successfully!');
|
|
3223
|
+
this.resetForm();
|
|
3224
|
+
} else {
|
|
3225
|
+
this.showError('Failed to send message');
|
|
3226
|
+
}
|
|
3227
|
+
} catch (error) {
|
|
3228
|
+
this.showError('Network error. Please try again.');
|
|
3229
|
+
}
|
|
3230
|
+
}
|
|
3231
|
+
|
|
3232
|
+
private showSuccess(message: string) {
|
|
3233
|
+
const successDiv = this.$('#success-message');
|
|
3234
|
+
if (successDiv) {
|
|
3235
|
+
successDiv.textContent = message;
|
|
3236
|
+
successDiv.style.display = 'block';
|
|
3237
|
+
}
|
|
3238
|
+
}
|
|
3239
|
+
|
|
3240
|
+
private resetForm() {
|
|
3241
|
+
const form = this.$('form') as HTMLFormElement;
|
|
3242
|
+
form?.reset();
|
|
3243
|
+
this.formData = { name: '', email: '', message: '' };
|
|
3244
|
+
}
|
|
3245
|
+
}
|
|
3246
|
+
```
|
|
3247
|
+
|
|
3248
|
+
---
|
|
3249
|
+
|
|
3250
|
+
## Build & Script Commands
|
|
3251
|
+
|
|
3252
|
+
> **Agent Reminder:** Use these commands for development, testing, and deployment.
|
|
3253
|
+
|
|
3254
|
+
### Common NPM Scripts
|
|
3255
|
+
|
|
3256
|
+
| Command | Description | When to Use |
|
|
3257
|
+
|---------|-------------|-------------|
|
|
3258
|
+
| `npm start` | Start development server with hot reload | During development |
|
|
3259
|
+
| `npm run build` | Build for production (output in `/dist/`) | Before deployment |
|
|
3260
|
+
| `npm test` | Run all tests | Before commit/release |
|
|
3261
|
+
| `npm run lint` | Check code style and errors | Before commit |
|
|
3262
|
+
| `npm run format` | Format code with Prettier | To ensure consistency |
|
|
3263
|
+
| `npm run clean` | Clean build artifacts | Before fresh build |
|
|
3264
|
+
|
|
3265
|
+
### Development Workflow
|
|
3266
|
+
|
|
3267
|
+
1. **Start development**:
|
|
3268
|
+
```bash
|
|
3269
|
+
npm start
|
|
3270
|
+
```
|
|
3271
|
+
Server runs on `http://localhost:3000` with hot reload.
|
|
3272
|
+
|
|
3273
|
+
2. **Make changes**:
|
|
3274
|
+
- Edit files in `src/`
|
|
3275
|
+
- Changes auto-reload in browser
|
|
3276
|
+
- Check console for errors
|
|
3277
|
+
|
|
3278
|
+
3. **Check code quality**:
|
|
3279
|
+
```bash
|
|
3280
|
+
npm run lint
|
|
3281
|
+
npm run format
|
|
3282
|
+
```
|
|
3283
|
+
|
|
3284
|
+
4. **Run tests**:
|
|
3285
|
+
```bash
|
|
3286
|
+
npm test
|
|
3287
|
+
```
|
|
3288
|
+
|
|
3289
|
+
5. **Build for production**:
|
|
3290
|
+
```bash
|
|
3291
|
+
npm run build
|
|
3292
|
+
```
|
|
3293
|
+
Output in `/dist/` directory.
|
|
3294
|
+
|
|
3295
|
+
6. **Preview production build**:
|
|
3296
|
+
```bash
|
|
3297
|
+
npm run preview
|
|
3298
|
+
```
|
|
3299
|
+
|
|
3300
|
+
### Troubleshooting Build Issues
|
|
3301
|
+
|
|
3302
|
+
**If build fails:**
|
|
3303
|
+
1. Clean project: `npm run clean`
|
|
3304
|
+
2. Reinstall dependencies: `rm -rf node_modules package-lock.json && npm install`
|
|
3305
|
+
3. Check Node version: `node --version` (should be >= 18)
|
|
3306
|
+
4. Review error messages carefully
|
|
3307
|
+
5. Check `tsconfig.json` and `vite.config.ts` for misconfigurations
|
|
3308
|
+
|
|
3309
|
+
**If hot reload doesn't work:**
|
|
3310
|
+
1. Restart dev server
|
|
3311
|
+
2. Clear browser cache
|
|
3312
|
+
3. Check browser console for errors
|
|
3313
|
+
4. Verify file paths are correct
|
|
3314
|
+
|
|
3315
|
+
---
|
|
3316
|
+
|
|
3317
|
+
## Security Best Practices
|
|
3318
|
+
|
|
3319
|
+
> **Agent Reminder:** Security is critical. Always follow these guidelines when developing KIMU applications.
|
|
3320
|
+
|
|
3321
|
+
### Input Validation
|
|
3322
|
+
- **Validate all user inputs**: Check type, format, length, and allowed values before processing
|
|
3323
|
+
- **Sanitize strings**: Remove or escape potentially dangerous characters in user-provided text
|
|
3324
|
+
- **Validate file uploads**: Check file type, size, and content before accepting uploads
|
|
3325
|
+
- **Use TypeScript types**: Leverage type system to catch errors at compile time
|
|
3326
|
+
|
|
3327
|
+
```typescript
|
|
3328
|
+
// Good: Input validation
|
|
3329
|
+
function processUserId(userId: string): number {
|
|
3330
|
+
const id = parseInt(userId);
|
|
3331
|
+
if (isNaN(id) || id <= 0) {
|
|
3332
|
+
throw new Error('Invalid user ID');
|
|
3333
|
+
}
|
|
3334
|
+
return id;
|
|
3335
|
+
}
|
|
3336
|
+
|
|
3337
|
+
// Bad: No validation
|
|
3338
|
+
function processUserId(userId: string): number {
|
|
3339
|
+
return parseInt(userId); // Could be NaN or negative
|
|
3340
|
+
}
|
|
3341
|
+
```
|
|
3342
|
+
|
|
3343
|
+
### DOM Manipulation Safety
|
|
3344
|
+
- **Always use framework APIs**: Use `this.$()` instead of direct DOM manipulation
|
|
3345
|
+
- **Avoid `innerHTML` with user content**: Prevents XSS attacks
|
|
3346
|
+
- **Use `textContent` for text**: Safer than `innerHTML` for plain text
|
|
3347
|
+
- **Sanitize HTML if needed**: Use a library like DOMPurify for user-generated HTML
|
|
3348
|
+
|
|
3349
|
+
```typescript
|
|
3350
|
+
// Good: Safe text insertion
|
|
3351
|
+
element.textContent = userInput;
|
|
3352
|
+
|
|
3353
|
+
// Bad: XSS vulnerability
|
|
3354
|
+
element.innerHTML = userInput; // NEVER do this with user input!
|
|
3355
|
+
```
|
|
3356
|
+
|
|
3357
|
+
### Dependency Management
|
|
3358
|
+
- **Keep dependencies updated**: Regularly check for security updates
|
|
3359
|
+
- **Review dependencies**: Check package reputation and maintenance status
|
|
3360
|
+
- **Use lock files**: Commit `package-lock.json` to ensure consistent dependencies
|
|
3361
|
+
- **Audit regularly**: Run `npm audit` to check for known vulnerabilities
|
|
3362
|
+
|
|
3363
|
+
```bash
|
|
3364
|
+
# Check for vulnerabilities
|
|
3365
|
+
npm audit
|
|
3366
|
+
|
|
3367
|
+
# Fix automatically (when possible)
|
|
3368
|
+
npm audit fix
|
|
3369
|
+
|
|
3370
|
+
# Update dependencies
|
|
3371
|
+
npm update
|
|
3372
|
+
```
|
|
3373
|
+
|
|
3374
|
+
### Authentication & Authorization
|
|
3375
|
+
- **Never store credentials in code**: Use environment variables for sensitive data
|
|
3376
|
+
- **Implement proper auth guards**: Check permissions before allowing actions
|
|
3377
|
+
- **Use secure session management**: Implement timeout and secure storage
|
|
3378
|
+
- **Validate on server side**: Never trust client-side validation alone
|
|
3379
|
+
|
|
3380
|
+
```typescript
|
|
3381
|
+
// Good: Route guard with auth check
|
|
3382
|
+
router.addRoute('/admin', () => {
|
|
3383
|
+
if (!isAuthenticated() || !hasAdminRole()) {
|
|
3384
|
+
router.navigate('/login');
|
|
3385
|
+
return;
|
|
3386
|
+
}
|
|
3387
|
+
loadAdminPanel();
|
|
3388
|
+
});
|
|
3389
|
+
```
|
|
3390
|
+
|
|
3391
|
+
### Data Protection
|
|
3392
|
+
- **Don't log sensitive data**: Avoid logging passwords, tokens, personal information
|
|
3393
|
+
- **Use HTTPS**: Always use secure connections in production
|
|
3394
|
+
- **Encrypt sensitive storage**: Use proper encryption for stored sensitive data
|
|
3395
|
+
- **Clear sensitive data**: Remove from memory when no longer needed
|
|
3396
|
+
|
|
3397
|
+
```typescript
|
|
3398
|
+
// Good: No sensitive data in logs
|
|
3399
|
+
console.log('User logged in:', user.id);
|
|
3400
|
+
|
|
3401
|
+
// Bad: Sensitive data exposed
|
|
3402
|
+
console.log('User logged in:', user.password); // NEVER!
|
|
3403
|
+
```
|
|
3404
|
+
|
|
3405
|
+
### Error Handling
|
|
3406
|
+
- **Don't expose internals**: Show generic error messages to users
|
|
3407
|
+
- **Log details server-side**: Keep detailed logs on server, not client
|
|
3408
|
+
- **Handle all errors**: Use try-catch and provide fallbacks
|
|
3409
|
+
- **Validate external data**: Always check data from APIs or external sources
|
|
3410
|
+
|
|
3411
|
+
```typescript
|
|
3412
|
+
// Good: Generic user message
|
|
3413
|
+
try {
|
|
3414
|
+
await fetchUserData();
|
|
3415
|
+
} catch (error) {
|
|
3416
|
+
showToUser('Unable to load data. Please try again.');
|
|
3417
|
+
logToServer(error); // Log full details server-side
|
|
3418
|
+
}
|
|
3419
|
+
|
|
3420
|
+
// Bad: Exposing error details
|
|
3421
|
+
try {
|
|
3422
|
+
await fetchUserData();
|
|
3423
|
+
} catch (error) {
|
|
3424
|
+
alert(error.message); // Could expose stack traces or paths
|
|
3425
|
+
}
|
|
3426
|
+
```
|
|
3427
|
+
|
|
3428
|
+
### Security Checklist
|
|
3429
|
+
Before deploying to production:
|
|
3430
|
+
- [ ] All user inputs are validated and sanitized
|
|
3431
|
+
- [ ] No sensitive data in client-side code
|
|
3432
|
+
- [ ] All dependencies are up to date
|
|
3433
|
+
- [ ] HTTPS is enabled
|
|
3434
|
+
- [ ] Authentication and authorization are properly implemented
|
|
3435
|
+
- [ ] Error messages don't expose sensitive information
|
|
3436
|
+
- [ ] Security headers are configured
|
|
3437
|
+
- [ ] CORS is properly configured
|
|
3438
|
+
- [ ] Content Security Policy (CSP) is implemented
|
|
3439
|
+
- [ ] Regular security audits are scheduled
|
|
3440
|
+
|
|
3441
|
+
### Additional Resources
|
|
3442
|
+
- OWASP Top 10: https://owasp.org/www-project-top-ten/
|
|
3443
|
+
- Security Best Practices: Review `SECURITY.md` in project root
|
|
3444
|
+
- npm audit documentation: https://docs.npmjs.com/cli/v8/commands/npm-audit
|
|
3445
|
+
|
|
3446
|
+
---
|
|
3447
|
+
|
|
3448
|
+
## FAQ & Troubleshooting
|
|
3449
|
+
|
|
3450
|
+
> **Agent Reminder:** Check this section when encountering common issues. Consult this section for common issues, edge cases, and best practices for error handling and project conventions.
|
|
3451
|
+
|
|
3452
|
+
### General Questions
|
|
3453
|
+
|
|
3454
|
+
**Q: How do I create composite extensions with child dependencies?**
|
|
3455
|
+
A: Use the `dependencies` metadata in `@KimuComponent` to specify child extension tags. These will be automatically loaded and available as HTML tags in your template. See the Extension Creation Guide section for detailed examples.
|
|
3456
|
+
|
|
3457
|
+
**Q: What's the difference between dependencies and regular imports?**
|
|
3458
|
+
A: The `dependencies` field is for KIMU child extensions that become available as HTML tags in your template. Regular imports are for utility functions, types, or external libraries.
|
|
3459
|
+
|
|
3460
|
+
**Q: What's the difference between a module and an extension?**
|
|
3461
|
+
A:
|
|
3462
|
+
- **Module**: Provides services/logic (no UI). Examples: router, i18n, storage.
|
|
3463
|
+
- **Extension**: UI component with view, styles, and logic. Examples: dashboard, login page.
|
|
3464
|
+
|
|
3465
|
+
**Q: Where do I put shared utilities?**
|
|
3466
|
+
A: Use `/src/utils/` for reusable functions.
|
|
3467
|
+
|
|
3468
|
+
**Q: Where do I put utility functions?**
|
|
3469
|
+
A: Place reusable utilities in `src/utils/`. Create separate files for different purposes (e.g., `date-utils.ts`, `string-utils.ts`).
|
|
3470
|
+
|
|
3471
|
+
**Q: How do I share code between extensions?**
|
|
3472
|
+
A:
|
|
3473
|
+
1. Create utilities in `src/utils/`
|
|
3474
|
+
2. Create a module if it's a service
|
|
3475
|
+
3. Use child extensions via `dependencies` field
|
|
3476
|
+
|
|
3477
|
+
**Q: Can I use external libraries?**
|
|
3478
|
+
A: Yes! Install via npm and import normally:
|
|
3479
|
+
```bash
|
|
3480
|
+
npm install lodash
|
|
3481
|
+
```
|
|
3482
|
+
```typescript
|
|
3483
|
+
import _ from 'lodash';
|
|
3484
|
+
```
|
|
3485
|
+
|
|
3486
|
+
**Q: How do I add a new test?**
|
|
3487
|
+
A: Place test files in `/tests/` and follow the naming conventions.
|
|
3488
|
+
|
|
3489
|
+
**Q: How do I update documentation?**
|
|
3490
|
+
A: Edit files in `/docs/` and add examples for new features.
|
|
3491
|
+
|
|
3492
|
+
**Q: Lint or build errors?**
|
|
3493
|
+
A: Run `npm run lint` and `npm run build` to check for issues. Fix according to `CODE_GUIDELINES.md`.
|
|
3494
|
+
|
|
3495
|
+
### Component Issues
|
|
3496
|
+
|
|
3497
|
+
**Q: My component doesn't render**
|
|
3498
|
+
A: Check:
|
|
3499
|
+
1. Is the component registered in `extension-manifest.json`?
|
|
3500
|
+
2. Did you call `onRender()` in `onInit()`?
|
|
3501
|
+
3. Are there errors in the browser console?
|
|
3502
|
+
4. Is the component tag correct in HTML?
|
|
3503
|
+
|
|
3504
|
+
**Q: Template variables show as `${variable}` literally**
|
|
3505
|
+
A: Ensure:
|
|
3506
|
+
1. `getData()` returns the variable
|
|
3507
|
+
2. Variable name matches exactly in template
|
|
3508
|
+
3. `onRender()` is called to process template
|
|
3509
|
+
|
|
3510
|
+
**Q: Styles don't apply**
|
|
3511
|
+
A: Check:
|
|
3512
|
+
1. CSS file is imported/loaded
|
|
3513
|
+
2. Selectors are correct (prefix with component tag)
|
|
3514
|
+
3. No conflicting global styles
|
|
3515
|
+
4. Browser DevTools for CSS specificity issues
|
|
3516
|
+
|
|
3517
|
+
**Q: Events don't work**
|
|
3518
|
+
A: Verify:
|
|
3519
|
+
1. Event listeners are added in `onInit()` or after DOM is ready
|
|
3520
|
+
2. Elements exist before adding listeners (use `this.$()`)
|
|
3521
|
+
3. Event names are correct
|
|
3522
|
+
4. Functions are properly bound (`this` context)
|
|
3523
|
+
|
|
3524
|
+
### Routing Issues
|
|
3525
|
+
|
|
3526
|
+
**Q: Routes don't work**
|
|
3527
|
+
A: Check:
|
|
3528
|
+
1. Router module is loaded in `main.ts`
|
|
3529
|
+
2. Routes are defined before navigation
|
|
3530
|
+
3. Route paths match exactly (including leading `/`)
|
|
3531
|
+
4. Hash mode is enabled (`#/path`)
|
|
3532
|
+
|
|
3533
|
+
**Q: Route parameters are undefined**
|
|
3534
|
+
A: Ensure:
|
|
3535
|
+
1. Route is defined with parameter syntax (`:param`)
|
|
3536
|
+
2. Calling `getParams()` inside route handler
|
|
3537
|
+
3. URL matches route pattern
|
|
3538
|
+
|
|
3539
|
+
### i18n Issues
|
|
3540
|
+
|
|
3541
|
+
**Q: Translations don't show**
|
|
3542
|
+
A: Verify:
|
|
3543
|
+
1. i18n module is loaded
|
|
3544
|
+
2. Language files exist in correct location
|
|
3545
|
+
3. Translation keys match exactly
|
|
3546
|
+
4. Current language is set correctly
|
|
3547
|
+
|
|
3548
|
+
**Q: Language switching doesn't work**
|
|
3549
|
+
A: Check:
|
|
3550
|
+
1. `setLanguage()` is called
|
|
3551
|
+
2. Components re-render after language change
|
|
3552
|
+
3. Language file exists for target language
|
|
3553
|
+
|
|
3554
|
+
### Build Issues
|
|
3555
|
+
|
|
3556
|
+
**Q: Build fails with TypeScript errors**
|
|
3557
|
+
A: Run:
|
|
3558
|
+
```bash
|
|
3559
|
+
npm run lint
|
|
3560
|
+
```
|
|
3561
|
+
Fix all TypeScript errors before building.
|
|
3562
|
+
|
|
3563
|
+
**Q: Build output is too large**
|
|
3564
|
+
A: Optimize:
|
|
3565
|
+
1. Enable tree shaking in vite config
|
|
3566
|
+
2. Lazy load large components
|
|
3567
|
+
3. Minify code (should be automatic)
|
|
3568
|
+
4. Check for duplicate dependencies
|
|
3569
|
+
|
|
3570
|
+
**Q: Hot reload is slow**
|
|
3571
|
+
A: Improve:
|
|
3572
|
+
1. Reduce number of files being watched
|
|
3573
|
+
2. Add exclusions to vite config
|
|
3574
|
+
3. Use faster disk (SSD vs HDD)
|
|
3575
|
+
4. Close other resource-intensive apps
|
|
3576
|
+
|
|
3577
|
+
### Performance Issues
|
|
3578
|
+
|
|
3579
|
+
**Q: Component is slow to render**
|
|
3580
|
+
A: Optimize:
|
|
3581
|
+
1. Minimize DOM operations
|
|
3582
|
+
2. Cache DOM queries
|
|
3583
|
+
3. Use debouncing for frequent updates
|
|
3584
|
+
4. Lazy load data
|
|
3585
|
+
5. Avoid unnecessary re-renders
|
|
3586
|
+
|
|
3587
|
+
**Q: App uses too much memory**
|
|
3588
|
+
A: Fix:
|
|
3589
|
+
1. Remove event listeners in `onDestroy()`
|
|
3590
|
+
2. Clear intervals/timeouts
|
|
3591
|
+
3. Release references to large objects
|
|
3592
|
+
4. Check for memory leaks with DevTools
|
|
3593
|
+
|
|
3594
|
+
---
|
|
3595
|
+
|
|
3596
|
+
## Testing & Quality Assurance
|
|
3597
|
+
|
|
3598
|
+
> **Agent Training Note:** Always write tests for new features and run quality checks before committing.
|
|
3599
|
+
|
|
3600
|
+
### Testing Strategy
|
|
3601
|
+
|
|
3602
|
+
1. **Unit Tests**: Test individual functions and methods
|
|
3603
|
+
2. **Component Tests**: Test component behavior and rendering
|
|
3604
|
+
3. **Integration Tests**: Test multiple components working together
|
|
3605
|
+
4. **E2E Tests**: Test complete user flows
|
|
3606
|
+
|
|
3607
|
+
### Writing Tests
|
|
3608
|
+
|
|
3609
|
+
Example using Vitest:
|
|
3610
|
+
|
|
3611
|
+
```typescript
|
|
3612
|
+
// tests/extensions/counter.test.ts
|
|
3613
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
3614
|
+
import { CounterComponent } from '../../src/extensions/counter/component';
|
|
3615
|
+
|
|
3616
|
+
describe('CounterComponent', () => {
|
|
3617
|
+
let counter: CounterComponent;
|
|
3618
|
+
|
|
3619
|
+
beforeEach(() => {
|
|
3620
|
+
counter = new CounterComponent();
|
|
3621
|
+
counter.onInit();
|
|
3622
|
+
});
|
|
3623
|
+
|
|
3624
|
+
it('should initialize with count of 0', () => {
|
|
3625
|
+
expect(counter['count']).toBe(0);
|
|
3626
|
+
});
|
|
3627
|
+
|
|
3628
|
+
it('should increment count', () => {
|
|
3629
|
+
counter['increment']();
|
|
3630
|
+
expect(counter['count']).toBe(1);
|
|
3631
|
+
});
|
|
3632
|
+
|
|
3633
|
+
it('should decrement count', () => {
|
|
3634
|
+
counter['decrement']();
|
|
3635
|
+
expect(counter['count']).toBe(-1);
|
|
3636
|
+
});
|
|
3637
|
+
|
|
3638
|
+
it('should reset count to 0', () => {
|
|
3639
|
+
counter['count'] = 5;
|
|
3640
|
+
counter['reset']();
|
|
3641
|
+
expect(counter['count']).toBe(0);
|
|
3642
|
+
});
|
|
3643
|
+
});
|
|
3644
|
+
```
|
|
3645
|
+
|
|
3646
|
+
### Quality Checklist
|
|
3647
|
+
|
|
3648
|
+
Before committing code, verify:
|
|
3649
|
+
- [ ] Code builds without errors (`npm run build`)
|
|
3650
|
+
- [ ] All tests pass (`npm test`)
|
|
3651
|
+
- [ ] Linter passes (`npm run lint`)
|
|
3652
|
+
- [ ] Code is formatted (`npm run format`)
|
|
3653
|
+
- [ ] No console errors in browser
|
|
3654
|
+
- [ ] Component works as expected
|
|
3655
|
+
- [ ] Documentation is updated
|
|
3656
|
+
- [ ] Types are properly defined (no `any`)
|
|
3657
|
+
|
|
3658
|
+
### Code Review Guidelines
|
|
3659
|
+
|
|
3660
|
+
When reviewing code:
|
|
3661
|
+
1. **Functionality**: Does it work correctly?
|
|
3662
|
+
2. **Tests**: Are there adequate tests?
|
|
3663
|
+
3. **Style**: Does it follow conventions?
|
|
3664
|
+
4. **Performance**: Any obvious bottlenecks?
|
|
3665
|
+
5. **Security**: Any vulnerabilities?
|
|
3666
|
+
6. **Documentation**: Are comments clear?
|
|
3667
|
+
|
|
3668
|
+
---
|
|
3669
|
+
|
|
3670
|
+
## Glossary
|
|
3671
|
+
|
|
3672
|
+
> **Agent Reminder:** Use these definitions for consistent terminology. Refer to the glossary for precise definitions of key concepts and terminology used throughout the project.
|
|
3673
|
+
|
|
3674
|
+
- **KimuComponentElement**: Base class for all UI components in kimu-core.
|
|
3675
|
+
- **KimuComponent**: Decorator for defining components with metadata.
|
|
3676
|
+
- **Component**: A modular UI unit that extends `KimuComponentElement`.
|
|
3677
|
+
- **Extension**: A complete custom feature added in `/src/extensions/`consisting of component.ts, style.css, and view.html.
|
|
3678
|
+
- **Module**: A service or utility that provides reusable functionality without UI.
|
|
3679
|
+
- **Data Binding**: Linking UI elements to logic using reactive properties/methods.
|
|
3680
|
+
- **Lifecycle**: The sequence of events in a component's existence (init, render, destroy).
|
|
3681
|
+
- **Template Engine**: The system that interpolates `${variables}` in HTML templates.
|
|
3682
|
+
- **Decorator**: TypeScript feature used for component metadata (`@KimuComponent`).
|
|
3683
|
+
- **Event Management**: Handling user interactions and system events in components.
|
|
3684
|
+
- **UI Rendering**: Process of displaying components in the browser.
|
|
3685
|
+
- **Service**: A class that provides specific functionality (from a module).
|
|
3686
|
+
- **Router**: Module that manages client-side navigation and URL routing.
|
|
3687
|
+
- **i18n**: Internationalization - supporting multiple languages.
|
|
3688
|
+
- **Manifest**: JSON file listing all registered extensions.
|
|
3689
|
+
- **Hot Reload**: Automatic browser refresh when code changes during development.
|
|
3690
|
+
- **Tree Shaking**: Removing unused code from production build.
|
|
3691
|
+
- **Dependency**: A child extension that a parent extension requires.
|
|
3692
|
+
- **Copilot Agent**: AI assistant that reads this file to generate code and suggestions.
|
|
3693
|
+
- **Semantic Versioning**: Versioning system (MAJOR.MINOR.PATCH) for releases.
|
|
3694
|
+
|
|
3695
|
+
---
|
|
3696
|
+
|
|
3697
|
+
## Agent Training & Workflow
|
|
3698
|
+
|
|
3699
|
+
### Copilot & AI Agent Guide
|
|
3700
|
+
> **Agent Training Note:** This document is your primary source for generating code, following conventions, and applying best practices in KIMU-Core. Read everything, always consult the following sections: Practical Examples, FAQ, Testing, Glossary, Modules, Router, i18n. Propose improvements if you identify missing patterns.
|
|
3701
|
+
|
|
3702
|
+
- **Read the entire document** before generating or modifying code.
|
|
3703
|
+
- **Follow the conventions** in `CODE_GUIDELINES.md` and `CONTRIBUTING.md`.
|
|
3704
|
+
- **Use practical examples** as templates.
|
|
3705
|
+
- **Consult the FAQ** for common issues and edge cases.
|
|
3706
|
+
- **Propose improvements** if you identify missing patterns.
|
|
3707
|
+
- **Use the Glossary** for precise definitions.
|
|
3708
|
+
- **Follow the checklist** for modules and extensions.
|
|
3709
|
+
- **Always document** public APIs and workflows.
|
|
3710
|
+
|
|
3711
|
+
### Recommended Workflow for AI Agents
|
|
3712
|
+
1. Read the creation checklist (module/extension).
|
|
3713
|
+
2. Follow practical examples.
|
|
3714
|
+
3. Consult cross-cutting best practices.
|
|
3715
|
+
4. Use modular patterns and document everything.
|
|
3716
|
+
5. Update the guide if you introduce new patterns.
|
|
3717
|
+
|
|
3718
|
+
### Cross-cutting Best Practices
|
|
3719
|
+
- Modularity and reusability.
|
|
3720
|
+
- Clear documentation in English.
|
|
3721
|
+
- Unit and integration tests.
|
|
3722
|
+
- Consistent and semantic naming.
|
|
3723
|
+
- Secure dependency management.
|
|
3724
|
+
- Input validation and security.
|
|
3725
|
+
- Continuous guide updates.
|
|
3726
|
+
|
|
3727
|
+
### Agent Reminder
|
|
3728
|
+
> Always insert "Agent Reminder" and "Agent Training Note" at the beginning of key sections (modules, extensions, router, i18n, testing, FAQ).
|
|
3729
|
+
|
|
3730
|
+
---
|
|
3731
|
+
|
|
3732
|
+
## Additional Resources
|
|
3733
|
+
|
|
3734
|
+
### Official Documentation
|
|
3735
|
+
- KIMU Core Repository: https://github.com/UnicoVerso/kimu-core
|
|
3736
|
+
- KIMU Documentation: https://github.com/UnicoVerso/kimu-docs
|
|
3737
|
+
- Code Guidelines: `CODE_GUIDELINES.md`
|
|
3738
|
+
- Contributing Guide: `CONTRIBUTING.md`
|
|
3739
|
+
|
|
3740
|
+
### TypeScript Resources
|
|
3741
|
+
- TypeScript Handbook: https://www.typescriptlang.org/docs/
|
|
3742
|
+
- TypeScript Deep Dive: https://basarat.gitbook.io/typescript/
|
|
3743
|
+
|
|
3744
|
+
### Web Components
|
|
3745
|
+
- Web Components Spec: https://developer.mozilla.org/en-US/docs/Web/Web_Components
|
|
3746
|
+
- Custom Elements: https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements
|
|
3747
|
+
|
|
3748
|
+
### Build Tools
|
|
3749
|
+
- Vite Documentation: https://vitejs.dev/
|
|
3750
|
+
- Vite Plugins: https://vitejs.dev/plugins/
|
|
3751
|
+
|
|
3752
|
+
### Testing
|
|
3753
|
+
- Vitest Documentation: https://vitest.dev/
|
|
3754
|
+
- Testing Library: https://testing-library.com/
|
|
3755
|
+
|
|
3756
|
+
---
|
|
3757
|
+
|
|
3758
|
+
## Final Notes for AI Agents
|
|
3759
|
+
|
|
3760
|
+
> **Agent Training Note:** Remember these key principles when working with KIMU:
|
|
3761
|
+
|
|
3762
|
+
1. **Read First, Code Second**: Always review this guide and relevant sections before generating code
|
|
3763
|
+
2. **Follow Patterns**: Use provided examples and established patterns
|
|
3764
|
+
3. **Stay Modular**: Keep components small, focused, and reusable
|
|
3765
|
+
4. **Document Everything**: Clear comments and documentation are essential
|
|
3766
|
+
5. **Test Thoroughly**: Write tests and verify functionality
|
|
3767
|
+
6. **Ask When Uncertain**: Better to ask than generate incorrect code
|
|
3768
|
+
7. **Keep It Simple**: KIMU values simplicity and clarity over complexity
|
|
3769
|
+
8. **Use TypeScript**: Leverage types for safety and developer experience
|
|
3770
|
+
9. **Respect Conventions**: Follow naming, structure, and style guidelines
|
|
3771
|
+
10. **Continuous Learning**: This guide evolves - suggest improvements when you find better patterns
|
|
3772
|
+
|
|
3773
|
+
---
|
|
3774
|
+
|
|
3775
|
+
**Version**: 1.0.0
|
|
3776
|
+
**Last Updated**: December 2025
|
|
3777
|
+
**Maintained By**: KIMU Framework Team
|
|
3778
|
+
|
|
3779
|
+
For questions, issues, or contributions, visit: https://github.com/UnicoVerso/kimu-core
|