@damarkuncoro/meta-architecture-style-engine 0.1.0 β 0.1.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/README.md +985 -14
- package/lib/cjs/cli/index.js +160 -112
- package/lib/cjs/cli/index.js.map +1 -1
- package/lib/cjs/index.d.ts +202 -111
- package/lib/cjs/index.js +720 -642
- package/lib/cjs/index.js.map +1 -1
- package/lib/esm/cli/index.js +160 -112
- package/lib/esm/cli/index.js.map +1 -1
- package/lib/esm/index.d.mts +202 -111
- package/lib/esm/index.js +716 -643
- package/lib/esm/index.js.map +1 -1
- package/package.json +6 -4
package/README.md
CHANGED
|
@@ -1,26 +1,332 @@
|
|
|
1
1
|
# Meta Architecture Style Engine (MASE)
|
|
2
2
|
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
3
5
|
**Official Style Governance & Runtime for Meta Architecture**
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
[](https://www.npmjs.com/package/@damarkuncoro/meta-architecture-style-engine)
|
|
8
|
+
[](https://www.npmjs.com/package/@damarkuncoro/meta-architecture-style-engine)
|
|
9
|
+
[](LICENSE)
|
|
10
|
+
[](https://www.typescriptlang.org/)
|
|
11
|
+
[]()
|
|
12
|
+
[]()
|
|
13
|
+
[]()
|
|
14
|
+
[]()
|
|
15
|
+
[]()
|
|
16
|
+
[]()
|
|
17
|
+
[](https://github.com/damarkuncoro/meta-architecture-style-engine/pulls)
|
|
18
|
+
[](https://github.com/damarkuncoro/meta-architecture-style-engine/blob/main/CODE_OF_CONDUCT.md)
|
|
19
|
+
|
|
20
|
+
*A Constitutional Styling System - Where Style is Law, Not Just Visuals*
|
|
21
|
+
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## π Table of Contents
|
|
27
|
+
|
|
28
|
+
- [Overview](#-overview)
|
|
29
|
+
- [Philosophy](#-philosophy)
|
|
30
|
+
- [Key Features](#-key-features)
|
|
31
|
+
- [Architecture](#-architecture)
|
|
32
|
+
- [Installation](#-installation)
|
|
33
|
+
- [Quick Start](#-quick-start)
|
|
34
|
+
- [Usage](#-usage)
|
|
35
|
+
- [Runtime Usage](#runtime-usage)
|
|
36
|
+
- [CLI Usage](#cli-usage)
|
|
37
|
+
- [DSL Syntax](#dsl-syntax)
|
|
38
|
+
- [API Reference](#-api-reference)
|
|
39
|
+
- [Examples](#-examples)
|
|
40
|
+
- [Development](#-development)
|
|
41
|
+
- [Contributing](#-contributing)
|
|
42
|
+
- [License](#-license)
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## π― Overview
|
|
47
|
+
|
|
48
|
+
**MASE (Meta Architecture Style Engine)** is a powerful style governance and runtime engine designed for Meta Architecture. Unlike traditional styling frameworks, MASE treats styling as a constitutional system where every style decision is validated against a set of rules and constraints.
|
|
49
|
+
|
|
50
|
+
MASE enforces design system rules, manages tokens, and compiles style contracts into various output formats (CSS, React Native, PDF) through a sophisticated governance system inspired by the Trias Politica principle.
|
|
51
|
+
|
|
52
|
+
### What Makes MASE Different?
|
|
53
|
+
|
|
54
|
+
| Traditional Approach | MASE Approach |
|
|
55
|
+
| :--- | :--- |
|
|
56
|
+
| **Utility Classes** | **Style Contracts** (Legal Articles) |
|
|
57
|
+
| **Config Files** | **Constitutions** (Laws) |
|
|
58
|
+
| **Prefix Variants** (`hover:`) | **Contextual Laws** |
|
|
59
|
+
| **Compilers** | **Style Resolution Engine** (Judiciary) |
|
|
60
|
+
| **CSS Output** | **Canonical Style Graph** + **Materializer** |
|
|
61
|
+
| **Best Practices** | **Enforced Governance** |
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## π‘ Philosophy
|
|
66
|
+
|
|
67
|
+
MASE is not just another "Tailwind Killer" or styling framework. It's a **Constitutional Styling System** β a governance system for styling where:
|
|
68
|
+
|
|
69
|
+
> **"Style is not just visual, but a legal decision that must be validated."**
|
|
70
|
+
|
|
71
|
+
### Core Principles
|
|
72
|
+
|
|
73
|
+
1. **Separation of Concerns**: Complete separation between specification, validation, and materialization
|
|
74
|
+
2. **Type Safety**: Every style decision is validated at compile-time and runtime
|
|
75
|
+
3. **Platform Agnostic**: The core engine doesn't know about CSS, React Native, or any specific platform
|
|
76
|
+
4. **Immutable Truth**: Style contracts and token registries are immutable sources of truth
|
|
77
|
+
5. **Audit Trail**: Every style resolution can be traced back to its constitutional origin
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## β¨ Key Features
|
|
82
|
+
|
|
83
|
+
### ποΈ Style Governance
|
|
84
|
+
- **Constitution-based Rules**: Define what's legal in your design system
|
|
85
|
+
- **Domain Taxonomy**: Organize rules by semantic domains (Layout, Typography, Interaction)
|
|
86
|
+
- **Token Registry**: Centralized management of design tokens
|
|
87
|
+
- **Violation Detection**: Automatic detection of style violations with educational error messages
|
|
88
|
+
|
|
89
|
+
### βοΈ Runtime Style Resolution
|
|
90
|
+
- **StyleProvider**: React context provider for theme and device context
|
|
91
|
+
- **StyleContract**: Type-safe style contracts with validation
|
|
92
|
+
- **Dynamic Resolution**: Context-aware style resolution based on theme, device, and platform
|
|
93
|
+
- **Performance Optimized**: Sub-5ms resolution per component
|
|
94
|
+
|
|
95
|
+
### π¨ Multi-Platform Support
|
|
96
|
+
- **CSS Materializer**: Generate optimized CSS for web applications
|
|
97
|
+
- **React Native Materializer**: Generate StyleSheet for native applications
|
|
98
|
+
- **PDF Materializer**: Generate render instructions for PDF generation
|
|
99
|
+
- **Extensible**: Easy to add custom materializers for any platform
|
|
100
|
+
|
|
101
|
+
### π Contract DSL
|
|
102
|
+
- **Declarative Syntax**: Define style contracts using a specialized DSL
|
|
103
|
+
- **Type-Safe**: Compile-time validation of contract definitions
|
|
104
|
+
- **Context-Aware**: Define responsive and state-based styling rules
|
|
105
|
+
- **Theme Support**: Built-in support for light/dark themes
|
|
106
|
+
|
|
107
|
+
### π§ Developer Experience
|
|
108
|
+
- **CLI Tools**: Command-line interface for validation, compilation, and generation
|
|
109
|
+
- **TypeScript Support**: Full TypeScript support with type definitions
|
|
110
|
+
- **Dual Build**: Supports both ESM and CJS modules
|
|
111
|
+
- **Zero-Dependency Testing**: Uses Node.js native test runner for lightweight and fast testing
|
|
112
|
+
- **Hot Reload**: Watch mode for development
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## ποΈ Architecture
|
|
117
|
+
|
|
118
|
+
MASE implements the **Trias Politica** principle, separating styling into three independent bodies:
|
|
119
|
+
|
|
120
|
+
### 1. The Constitution (Spec Layer)
|
|
121
|
+
The **Written Law** that defines what's legal in the design system universe.
|
|
122
|
+
|
|
123
|
+
- **Semantic Namespace**: Universal language (e.g., `background.intent.primary`)
|
|
124
|
+
- **Domain Taxonomy**: Legal area groupings (Layout, Typography, Interaction)
|
|
125
|
+
- **Token Registry**: The "currency" of the nation (atomic values)
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
// Example Constitution
|
|
129
|
+
const buttonConstitution = {
|
|
130
|
+
domain: 'interaction',
|
|
131
|
+
rules: {
|
|
132
|
+
intent: {
|
|
133
|
+
allows: ['color.primary', 'color.secondary'],
|
|
134
|
+
default: 'color.primary'
|
|
135
|
+
},
|
|
136
|
+
padding: {
|
|
137
|
+
allows: ['space.sm', 'space.md', 'space.lg'],
|
|
138
|
+
default: 'space.md'
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### 2. The Judiciary (Style Resolution Engine - SRE)
|
|
145
|
+
The **Judicial Body (Judge)** that validates style contracts.
|
|
146
|
+
|
|
147
|
+
- **Responsibility**: Accepts `StyleContract` and `Context`, decides if valid or violates constitution
|
|
148
|
+
- **Characteristics**:
|
|
149
|
+
- β Doesn't know CSS
|
|
150
|
+
- β Doesn't know Platform (Web/Native)
|
|
151
|
+
- β
Only knows **Legal vs Illegal**
|
|
152
|
+
- **Output**: `StyleResolutionResult` (Resolved Node or Violation Verdict)
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
// Example Resolution
|
|
156
|
+
const result = engine.resolve(contract, constitution, context);
|
|
157
|
+
// Returns: { valid: true, className: 'bg-primary p-md' }
|
|
158
|
+
// Or: { valid: false, violations: [...] }
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### 3. The Executive (Style Materialization Engine - SME)
|
|
162
|
+
The **Executive Body (Executor)** that executes judicial decisions into physical reality.
|
|
163
|
+
|
|
164
|
+
- **Responsibility**: Execute judicial decisions into actual styles
|
|
165
|
+
- **Plugin System**:
|
|
166
|
+
- **CSS Materializer**: Converts decisions to CSS (Web)
|
|
167
|
+
- **Native Materializer**: Converts decisions to StyleSheet (React Native)
|
|
168
|
+
- **PDF/Canvas**: Converts decisions to render instructions
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
// Example Materialization
|
|
172
|
+
const cssMaterializer = new CSSMaterializer();
|
|
173
|
+
const css = cssMaterializer.materialize(resolvedStyle, context);
|
|
174
|
+
// Returns: ".button { background: #007bff; padding: 1rem; }"
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Architecture Diagram
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
181
|
+
β MASE Architecture β
|
|
182
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
|
|
183
|
+
β β
|
|
184
|
+
β ββββββββββββββββββββ ββββββββββββββββββββ β
|
|
185
|
+
β β Constitution βββββββΆβ Judiciary β β
|
|
186
|
+
β β (Spec Layer) β β (SRE) β β
|
|
187
|
+
β β β β β β
|
|
188
|
+
β β β’ Semantic NS β β β’ Validation β β
|
|
189
|
+
β β β’ Domain Tax β β β’ Resolution β β
|
|
190
|
+
β β β’ Token Reg β β β’ Violation β β
|
|
191
|
+
β ββββββββββββββββββββ ββββββββββ¬ββββββββββ β
|
|
192
|
+
β β β
|
|
193
|
+
β βΌ β
|
|
194
|
+
β ββββββββββββββββββββ β
|
|
195
|
+
β β Executive β β
|
|
196
|
+
β β (SME) β β
|
|
197
|
+
β β β β
|
|
198
|
+
β β β’ CSS Mat β β
|
|
199
|
+
β β β’ RN Mat β β
|
|
200
|
+
β β β’ PDF Mat β β
|
|
201
|
+
β ββββββββββββββββββββ β
|
|
202
|
+
β β
|
|
203
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
204
|
+
```
|
|
6
205
|
|
|
7
|
-
|
|
206
|
+
---
|
|
8
207
|
|
|
9
|
-
|
|
10
|
-
- **Runtime Style Resolution**: Dynamic style resolution with `StyleProvider` and `StyleContract`.
|
|
11
|
-
- **Multi-Platform Support**: Materializers for CSS, React Native, and PDF.
|
|
12
|
-
- **Contract DSL**: Define style contracts using a specialized DSL.
|
|
13
|
-
- **Dual Build**: Supports both ESM and CJS.
|
|
208
|
+
## π¦ Installation
|
|
14
209
|
|
|
15
|
-
|
|
210
|
+
### Install the Package
|
|
16
211
|
|
|
17
212
|
```bash
|
|
18
213
|
npm install @damarkuncoro/meta-architecture-style-engine
|
|
19
214
|
```
|
|
20
215
|
|
|
21
|
-
|
|
216
|
+
### Install CLI Globally (Optional)
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
npm install -g @damarkuncoro/meta-architecture-style-engine
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Peer Dependencies
|
|
223
|
+
|
|
224
|
+
MASE requires the following peer dependencies:
|
|
225
|
+
|
|
226
|
+
```json
|
|
227
|
+
{
|
|
228
|
+
"peerDependencies": {
|
|
229
|
+
"@damarkuncoro/meta-architecture": "^2.0.4",
|
|
230
|
+
"react": ">=18.0.0"
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## π Quick Start
|
|
22
238
|
|
|
23
|
-
|
|
239
|
+
Get started with MASE in 5 minutes.
|
|
240
|
+
|
|
241
|
+
### Step 1: Create a Contract File
|
|
242
|
+
|
|
243
|
+
Create a file named `Button.contract.dsl`:
|
|
244
|
+
|
|
245
|
+
```dsl
|
|
246
|
+
contract Button {
|
|
247
|
+
domain: interaction
|
|
248
|
+
|
|
249
|
+
intent {
|
|
250
|
+
allows: [color.primary, color.secondary]
|
|
251
|
+
default: color.primary
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
padding {
|
|
255
|
+
allows: [space.sm, space.md, space.lg]
|
|
256
|
+
default: space.md
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Step 2: Validate Your Contract
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
mase validate Button.contract.dsl
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Output:
|
|
268
|
+
```
|
|
269
|
+
β
Contract is valid!
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Step 3: Compile to TypeScript
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
mase compile Button.contract.dsl -o Button.ts
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
This generates a TypeScript file with your contract.
|
|
279
|
+
|
|
280
|
+
### Step 4: Generate CSS
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
mase generate-css Button.contract.dsl -o button.css
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
This generates CSS classes based on your contract.
|
|
287
|
+
|
|
288
|
+
### Step 5: Use in Your Application
|
|
289
|
+
|
|
290
|
+
```tsx
|
|
291
|
+
import { StyleProvider, useStyleContext } from '@damarkuncoro/meta-architecture-style-engine';
|
|
292
|
+
import { ButtonContract } from './Button';
|
|
293
|
+
|
|
294
|
+
function App() {
|
|
295
|
+
return (
|
|
296
|
+
<StyleProvider initialTheme="light">
|
|
297
|
+
<MyComponent />
|
|
298
|
+
</StyleProvider>
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function MyComponent() {
|
|
303
|
+
const { theme, device } = useStyleContext();
|
|
304
|
+
|
|
305
|
+
const buttonStyles = ButtonContract.resolve({
|
|
306
|
+
device,
|
|
307
|
+
theme,
|
|
308
|
+
platform: 'web'
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
return (
|
|
312
|
+
<button className={buttonStyles.className}>
|
|
313
|
+
Click me
|
|
314
|
+
</button>
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## π Usage
|
|
322
|
+
|
|
323
|
+
### Runtime Usage
|
|
324
|
+
|
|
325
|
+
#### StyleProvider
|
|
326
|
+
|
|
327
|
+
Wrap your application with the `StyleProvider` to enable style resolution.
|
|
328
|
+
|
|
329
|
+
**Web Usage (Default):**
|
|
24
330
|
|
|
25
331
|
```tsx
|
|
26
332
|
import { StyleProvider } from '@damarkuncoro/meta-architecture-style-engine';
|
|
@@ -34,12 +340,677 @@ function App() {
|
|
|
34
340
|
}
|
|
35
341
|
```
|
|
36
342
|
|
|
37
|
-
|
|
343
|
+
**Native Usage (with Adapter):**
|
|
344
|
+
|
|
345
|
+
MASE is platform-agnostic. For non-web platforms, inject the appropriate adapter.
|
|
346
|
+
|
|
347
|
+
```tsx
|
|
348
|
+
import { StyleProvider, NativePlatformAdapter } from '@damarkuncoro/meta-architecture-style-engine';
|
|
349
|
+
|
|
350
|
+
const nativeAdapter = new NativePlatformAdapter();
|
|
351
|
+
|
|
352
|
+
function App() {
|
|
353
|
+
return (
|
|
354
|
+
<StyleProvider
|
|
355
|
+
initialTheme="light"
|
|
356
|
+
adapter={nativeAdapter}
|
|
357
|
+
>
|
|
358
|
+
<YourApp />
|
|
359
|
+
</StyleProvider>
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
#### useStyleContext
|
|
365
|
+
|
|
366
|
+
Access theme and device context in your components:
|
|
367
|
+
|
|
368
|
+
```tsx
|
|
369
|
+
import { useStyleContext } from '@damarkuncoro/meta-architecture-style-engine';
|
|
370
|
+
|
|
371
|
+
function MyComponent() {
|
|
372
|
+
const { theme, device, platform } = useStyleContext();
|
|
373
|
+
|
|
374
|
+
return (
|
|
375
|
+
<div>
|
|
376
|
+
Current theme: {theme}
|
|
377
|
+
Current device: {device}
|
|
378
|
+
</div>
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
#### StyleContract
|
|
384
|
+
|
|
385
|
+
Create type-safe style contracts:
|
|
386
|
+
|
|
387
|
+
```typescript
|
|
388
|
+
import { StyleContract } from '@damarkuncoro/meta-architecture-style-engine';
|
|
389
|
+
|
|
390
|
+
const buttonContract = new StyleContract({
|
|
391
|
+
intent: 'color.primary',
|
|
392
|
+
padding: 'space.md',
|
|
393
|
+
borderRadius: 'radius.md'
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
const resolved = buttonContract.resolve({
|
|
397
|
+
theme: 'light',
|
|
398
|
+
device: 'desktop',
|
|
399
|
+
platform: 'web'
|
|
400
|
+
});
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
#### StyleResolutionEngine
|
|
404
|
+
|
|
405
|
+
Use the core engine for advanced scenarios:
|
|
406
|
+
|
|
407
|
+
```typescript
|
|
408
|
+
import {
|
|
409
|
+
StyleResolutionEngine,
|
|
410
|
+
TokenRegistry,
|
|
411
|
+
ThemeResolver
|
|
412
|
+
} from '@damarkuncoro/meta-architecture-style-engine';
|
|
413
|
+
|
|
414
|
+
// Create engine
|
|
415
|
+
const tokenRegistry = new TokenRegistry();
|
|
416
|
+
const themeResolver = new ThemeResolver();
|
|
417
|
+
const engine = new StyleResolutionEngine(tokenRegistry, themeResolver);
|
|
418
|
+
|
|
419
|
+
// Define contract
|
|
420
|
+
const contract = {
|
|
421
|
+
intent: 'color.primary',
|
|
422
|
+
padding: 'space.md'
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
// Define constitution
|
|
426
|
+
const constitution = {
|
|
427
|
+
componentName: 'Button',
|
|
428
|
+
rules: [
|
|
429
|
+
{
|
|
430
|
+
property: 'intent',
|
|
431
|
+
domain: 'interaction',
|
|
432
|
+
allowedTokens: ['color.primary', 'color.secondary']
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
property: 'padding',
|
|
436
|
+
domain: 'layout',
|
|
437
|
+
allowedTokens: ['space.sm', 'space.md', 'space.lg']
|
|
438
|
+
}
|
|
439
|
+
]
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
// Resolve
|
|
443
|
+
const result = engine.resolve(contract, constitution);
|
|
444
|
+
|
|
445
|
+
console.log(result.className); // "bg-primary p-md"
|
|
446
|
+
console.log(result.valid); // true
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### CLI Usage
|
|
450
|
+
|
|
451
|
+
#### Initialize a New Project
|
|
452
|
+
|
|
453
|
+
```bash
|
|
454
|
+
mase init my-app
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
#### Compile Contract
|
|
458
|
+
|
|
459
|
+
```bash
|
|
460
|
+
mase compile Button.contract.dsl -o Button.ts
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
Options:
|
|
464
|
+
- `-o, --output <file>` - Output file
|
|
465
|
+
- `--format <format>` - Output format (ts, json, ast)
|
|
466
|
+
- `--watch` - Watch for changes
|
|
467
|
+
|
|
468
|
+
#### Validate Contract
|
|
469
|
+
|
|
470
|
+
```bash
|
|
471
|
+
mase validate Button.contract.dsl
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
Options:
|
|
475
|
+
- `--strict` - Enable strict validation
|
|
476
|
+
- `--fix` - Auto-fix issues
|
|
477
|
+
- `--watch` - Watch for changes
|
|
478
|
+
|
|
479
|
+
#### Generate CSS
|
|
480
|
+
|
|
481
|
+
```bash
|
|
482
|
+
mase generate-css Button.contract.dsl -o button.css
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
Options:
|
|
486
|
+
- `-o, --output <file>` - Output file
|
|
487
|
+
- `--format <format>` - Output format (class, variable, inline)
|
|
488
|
+
- `--theme <theme>` - Theme (light, dark)
|
|
489
|
+
- `--device <device>` - Device (mobile, tablet, desktop)
|
|
490
|
+
|
|
491
|
+
#### Watch for Changes
|
|
492
|
+
|
|
493
|
+
```bash
|
|
494
|
+
mase watch Button.contract.dsl
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
Options:
|
|
498
|
+
- `--command <command>` - Command to run on change
|
|
499
|
+
- `--debounce <ms>` - Debounce time in ms
|
|
500
|
+
|
|
501
|
+
### DSL Syntax
|
|
502
|
+
|
|
503
|
+
The MASE DSL provides a declarative way to define style contracts.
|
|
504
|
+
|
|
505
|
+
#### Basic Contract
|
|
506
|
+
|
|
507
|
+
```dsl
|
|
508
|
+
contract Button {
|
|
509
|
+
domain: interaction
|
|
510
|
+
|
|
511
|
+
intent {
|
|
512
|
+
allows: [color.primary, color.secondary]
|
|
513
|
+
default: color.primary
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
padding {
|
|
517
|
+
allows: [space.sm, space.md, space.lg]
|
|
518
|
+
default: space.md
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
#### Responsive Styling
|
|
524
|
+
|
|
525
|
+
```dsl
|
|
526
|
+
contract Container {
|
|
527
|
+
domain: layout
|
|
528
|
+
|
|
529
|
+
padding {
|
|
530
|
+
allows: [space.sm, space.md, space.lg]
|
|
531
|
+
default: space.md
|
|
532
|
+
|
|
533
|
+
constraints {
|
|
534
|
+
mobile: [space.sm, space.md]
|
|
535
|
+
desktop: [space.md, space.lg]
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
#### State-Based Styling
|
|
542
|
+
|
|
543
|
+
```dsl
|
|
544
|
+
contract Button {
|
|
545
|
+
domain: interaction
|
|
546
|
+
|
|
547
|
+
intent {
|
|
548
|
+
allows: [color.primary, color.secondary]
|
|
549
|
+
default: color.primary
|
|
550
|
+
|
|
551
|
+
constraints {
|
|
552
|
+
hover: [color.primary.hover, color.secondary.hover]
|
|
553
|
+
active: [color.primary.active, color.secondary.active]
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
#### Theme Support
|
|
560
|
+
|
|
561
|
+
```dsl
|
|
562
|
+
contract Card {
|
|
563
|
+
domain: layout
|
|
564
|
+
|
|
565
|
+
background {
|
|
566
|
+
allows: [surface.card, surface.ground]
|
|
567
|
+
default: surface.card
|
|
568
|
+
|
|
569
|
+
constraints {
|
|
570
|
+
dark: [surface.card.dark, surface.ground.dark]
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
---
|
|
577
|
+
|
|
578
|
+
## π§ API Reference
|
|
579
|
+
|
|
580
|
+
### Core Exports
|
|
581
|
+
|
|
582
|
+
#### Domain Layer
|
|
583
|
+
|
|
584
|
+
```typescript
|
|
585
|
+
// Types
|
|
586
|
+
export * from './domain/types';
|
|
587
|
+
|
|
588
|
+
// Core Engine
|
|
589
|
+
export { StyleResolutionEngine } from './domain/StyleResolutionEngine';
|
|
590
|
+
export { CanonicalStyleGraph } from './domain/CanonicalStyleGraph';
|
|
591
|
+
export { ContextBinder } from './domain/ContextBinder';
|
|
592
|
+
export { ViolationEngine } from './domain/ViolationEngine';
|
|
593
|
+
|
|
594
|
+
// Registries
|
|
595
|
+
export { TokenRegistry } from './domain/TokenRegistry';
|
|
596
|
+
export { ThemeResolver } from './domain/ThemeResolver';
|
|
597
|
+
export { ContextFactory } from './domain/ContextFactory';
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
#### Runtime Layer
|
|
601
|
+
|
|
602
|
+
```typescript
|
|
603
|
+
export { StyleContract } from './runtime/StyleContract';
|
|
604
|
+
export { StyleProvider } from './runtime/StyleProvider';
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
#### Adapter Layer
|
|
608
|
+
|
|
609
|
+
```typescript
|
|
610
|
+
export { MasePlugin } from './adapter/MasePlugin';
|
|
611
|
+
export { createPipeline } from './adapter/pipeline-factory';
|
|
612
|
+
export * from './adapter/rules';
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
#### Data Layer
|
|
616
|
+
|
|
617
|
+
```typescript
|
|
618
|
+
export * from './data/tokens';
|
|
619
|
+
export * from './data/constitutions';
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
#### DSL Layer
|
|
623
|
+
|
|
624
|
+
```typescript
|
|
625
|
+
export {
|
|
626
|
+
ContractDSLTokenizer,
|
|
627
|
+
ContractDSLParser,
|
|
628
|
+
ContractDSLValidator,
|
|
629
|
+
ContractDSLCompiler
|
|
630
|
+
} from './dsl';
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
#### Materializer Layer
|
|
634
|
+
|
|
635
|
+
```typescript
|
|
636
|
+
export type {
|
|
637
|
+
Materializer,
|
|
638
|
+
MaterializationContext,
|
|
639
|
+
MaterializationResult
|
|
640
|
+
} from './materializer';
|
|
641
|
+
|
|
642
|
+
export {
|
|
643
|
+
MaterializationError,
|
|
644
|
+
CSSMaterializer,
|
|
645
|
+
RNMaterializer,
|
|
646
|
+
PDFMaterializer
|
|
647
|
+
} from './materializer';
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
### Key Interfaces
|
|
651
|
+
|
|
652
|
+
#### StyleContract
|
|
653
|
+
|
|
654
|
+
```typescript
|
|
655
|
+
interface StyleContract {
|
|
656
|
+
resolve(context: ResolutionContext): StyleResolutionResult;
|
|
657
|
+
validate(): ValidationResult;
|
|
658
|
+
}
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
#### StyleResolutionResult
|
|
662
|
+
|
|
663
|
+
```typescript
|
|
664
|
+
interface StyleResolutionResult {
|
|
665
|
+
valid: boolean;
|
|
666
|
+
className?: string;
|
|
667
|
+
styles?: Record<string, any>;
|
|
668
|
+
violations?: Violation[];
|
|
669
|
+
}
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
#### ResolutionContext
|
|
673
|
+
|
|
674
|
+
```typescript
|
|
675
|
+
interface ResolutionContext {
|
|
676
|
+
theme: 'light' | 'dark';
|
|
677
|
+
device: 'mobile' | 'tablet' | 'desktop';
|
|
678
|
+
platform: 'web' | 'native' | 'pdf';
|
|
679
|
+
state?: Record<string, any>;
|
|
680
|
+
}
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
---
|
|
684
|
+
|
|
685
|
+
## π Examples
|
|
686
|
+
|
|
687
|
+
### Phase 2 Examples
|
|
688
|
+
|
|
689
|
+
Explore advanced Phase 2 features:
|
|
690
|
+
|
|
691
|
+
- **[Interactive DSL Playground](./examples/advanced/dsl-playground/README.md)** - Live DSL editor with real-time validation
|
|
692
|
+
- **[Advanced ContractEntity](./examples/advanced/contract-entity/README.md)** - Lifecycle hooks, middleware, composition
|
|
693
|
+
|
|
694
|
+
### Complete Button Component
|
|
695
|
+
|
|
696
|
+
```tsx
|
|
697
|
+
import React from 'react';
|
|
698
|
+
import { StyleProvider, useStyleContext, StyleContract } from '@damarkuncoro/meta-architecture-style-engine';
|
|
699
|
+
|
|
700
|
+
// Define button contract
|
|
701
|
+
const buttonContract = new StyleContract({
|
|
702
|
+
intent: 'color.primary',
|
|
703
|
+
padding: 'space.md',
|
|
704
|
+
borderRadius: 'radius.md',
|
|
705
|
+
fontSize: 'text.base',
|
|
706
|
+
fontWeight: 'font.semibold'
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
function Button({ children, variant = 'primary' }: ButtonProps) {
|
|
710
|
+
const { theme, device } = useStyleContext();
|
|
711
|
+
|
|
712
|
+
const styles = buttonContract.resolve({
|
|
713
|
+
theme,
|
|
714
|
+
device,
|
|
715
|
+
platform: 'web',
|
|
716
|
+
state: { variant }
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
return (
|
|
720
|
+
<button className={styles.className}>
|
|
721
|
+
{children}
|
|
722
|
+
</button>
|
|
723
|
+
);
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
function App() {
|
|
727
|
+
return (
|
|
728
|
+
<StyleProvider initialTheme="light">
|
|
729
|
+
<Button>Click me</Button>
|
|
730
|
+
</StyleProvider>
|
|
731
|
+
);
|
|
732
|
+
}
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
### Card Component with Responsive Design
|
|
736
|
+
|
|
737
|
+
```tsx
|
|
738
|
+
import React from 'react';
|
|
739
|
+
import { StyleProvider, useStyleContext, StyleContract } from '@damarkuncoro/meta-architecture-style-engine';
|
|
740
|
+
|
|
741
|
+
const cardContract = new StyleContract({
|
|
742
|
+
background: 'surface.card',
|
|
743
|
+
padding: 'space.lg',
|
|
744
|
+
borderRadius: 'radius.lg',
|
|
745
|
+
shadow: 'shadow.md'
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
function Card({ children }: CardProps) {
|
|
749
|
+
const { theme, device } = useStyleContext();
|
|
750
|
+
|
|
751
|
+
const styles = cardContract.resolve({
|
|
752
|
+
theme,
|
|
753
|
+
device,
|
|
754
|
+
platform: 'web'
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
return (
|
|
758
|
+
<div className={styles.className}>
|
|
759
|
+
{children}
|
|
760
|
+
</div>
|
|
761
|
+
);
|
|
762
|
+
}
|
|
763
|
+
```
|
|
764
|
+
|
|
765
|
+
### TypeScript-Only Usage
|
|
766
|
+
|
|
767
|
+
```typescript
|
|
768
|
+
import {
|
|
769
|
+
StyleResolutionEngine,
|
|
770
|
+
TokenRegistry,
|
|
771
|
+
ThemeResolver,
|
|
772
|
+
CSSMaterializer
|
|
773
|
+
} from '@damarkuncoro/meta-architecture-style-engine';
|
|
774
|
+
|
|
775
|
+
// Setup
|
|
776
|
+
const tokenRegistry = new TokenRegistry();
|
|
777
|
+
const themeResolver = new ThemeResolver();
|
|
778
|
+
const engine = new StyleResolutionEngine(tokenRegistry, themeResolver);
|
|
779
|
+
const cssMaterializer = new CSSMaterializer();
|
|
780
|
+
|
|
781
|
+
// Define contract
|
|
782
|
+
const contract = {
|
|
783
|
+
background: 'surface.card',
|
|
784
|
+
padding: 'space.lg',
|
|
785
|
+
borderRadius: 'radius.lg'
|
|
786
|
+
};
|
|
787
|
+
|
|
788
|
+
// Define constitution
|
|
789
|
+
const constitution = {
|
|
790
|
+
componentName: 'Card',
|
|
791
|
+
domain: 'layout',
|
|
792
|
+
rules: [
|
|
793
|
+
{
|
|
794
|
+
property: 'background',
|
|
795
|
+
allowedTokens: ['surface.card', 'surface.ground']
|
|
796
|
+
},
|
|
797
|
+
{
|
|
798
|
+
property: 'padding',
|
|
799
|
+
allowedTokens: ['space.sm', 'space.md', 'space.lg']
|
|
800
|
+
},
|
|
801
|
+
{
|
|
802
|
+
property: 'borderRadius',
|
|
803
|
+
allowedTokens: ['radius.sm', 'radius.md', 'radius.lg']
|
|
804
|
+
}
|
|
805
|
+
]
|
|
806
|
+
};
|
|
807
|
+
|
|
808
|
+
// Resolve
|
|
809
|
+
const context = {
|
|
810
|
+
theme: 'light',
|
|
811
|
+
device: 'desktop',
|
|
812
|
+
platform: 'web'
|
|
813
|
+
};
|
|
814
|
+
|
|
815
|
+
const result = engine.resolve(contract, constitution, context);
|
|
816
|
+
|
|
817
|
+
// Materialize
|
|
818
|
+
if (result.valid) {
|
|
819
|
+
const css = cssMaterializer.materialize(result, context);
|
|
820
|
+
console.log(css);
|
|
821
|
+
}
|
|
822
|
+
```
|
|
823
|
+
|
|
824
|
+
---
|
|
825
|
+
|
|
826
|
+
## π οΈ Development
|
|
827
|
+
|
|
828
|
+
### Setup
|
|
38
829
|
|
|
39
830
|
```bash
|
|
40
|
-
|
|
831
|
+
# Clone the repository
|
|
832
|
+
git clone https://github.com/damarkuncoro/meta-architecture-style-engine.git
|
|
833
|
+
cd meta-architecture-style-engine
|
|
834
|
+
|
|
835
|
+
# Install dependencies
|
|
836
|
+
npm install
|
|
837
|
+
|
|
838
|
+
# Build the project
|
|
839
|
+
npm run build
|
|
840
|
+
|
|
841
|
+
# Run tests
|
|
842
|
+
npm test
|
|
843
|
+
```
|
|
844
|
+
|
|
845
|
+
### Project Structure
|
|
846
|
+
|
|
847
|
+
```
|
|
848
|
+
meta-architecture-style-engine/
|
|
849
|
+
βββ src/
|
|
850
|
+
β βββ adapter/ # Plugin system and pipeline factory
|
|
851
|
+
β βββ cli/ # Command-line interface
|
|
852
|
+
β βββ data/ # Tokens and constitutions
|
|
853
|
+
β βββ domain/ # Core engine (SRE)
|
|
854
|
+
β βββ dsl/ # Contract DSL compiler
|
|
855
|
+
β βββ materializer/ # Platform materializers (SME)
|
|
856
|
+
β βββ runtime/ # React runtime components
|
|
857
|
+
βββ docs/ # Documentation
|
|
858
|
+
βββ __tests__/ # Test files
|
|
859
|
+
βββ package.json
|
|
860
|
+
βββ tsconfig.json
|
|
861
|
+
βββ tsup.config.ts # Build configuration
|
|
41
862
|
```
|
|
42
863
|
|
|
43
|
-
|
|
864
|
+
### Scripts
|
|
865
|
+
|
|
866
|
+
```bash
|
|
867
|
+
# Build
|
|
868
|
+
npm run build
|
|
869
|
+
|
|
870
|
+
# Test
|
|
871
|
+
npm test
|
|
872
|
+
|
|
873
|
+
# Clean build artifacts
|
|
874
|
+
npm run clean
|
|
875
|
+
|
|
876
|
+
# Run CLI
|
|
877
|
+
npm run cli
|
|
878
|
+
```
|
|
879
|
+
|
|
880
|
+
### Testing
|
|
881
|
+
|
|
882
|
+
MASE uses Vitest for testing. Tests are organized by component and follow the test matrix specification:
|
|
883
|
+
|
|
884
|
+
- **Valid Contract**: Happy path scenarios
|
|
885
|
+
- **Invalid Token**: Token not in registry
|
|
886
|
+
- **Invalid Semantic**: Wrong semantic key
|
|
887
|
+
- **Domain Violation**: Cross-domain properties
|
|
888
|
+
- **Context Fallback**: Graceful degradation
|
|
889
|
+
- **Hard Rejection**: Fatal violations
|
|
890
|
+
- **Performance**: < 5ms resolution per component
|
|
891
|
+
|
|
892
|
+
### Quality Metrics
|
|
893
|
+
|
|
894
|
+
| Metric | Target | Description |
|
|
895
|
+
| :--- | :--- | :--- |
|
|
896
|
+
| **Type Safety** | 100% | No `any`, fully typed contracts |
|
|
897
|
+
| **Platform Agnostic** | 100% | SRE code has no CSS/Web terminology |
|
|
898
|
+
| **Immutability** | Enforced | CSG and Token Registry are `readonly` |
|
|
899
|
+
| **Audit Trail** | 100% | Every resolution decision is traceable |
|
|
900
|
+
|
|
901
|
+
---
|
|
902
|
+
|
|
903
|
+
## π€ Contributing
|
|
904
|
+
|
|
905
|
+
We welcome contributions! Please follow these guidelines:
|
|
906
|
+
|
|
907
|
+
### Contribution Guidelines
|
|
908
|
+
|
|
909
|
+
1. **Strict Separation**: Don't mix CSS logic in the SRE
|
|
910
|
+
2. **Spec-First**: Discuss constitution changes before coding
|
|
911
|
+
3. **Violation as Feature**: Errors are governance features, not bugs
|
|
912
|
+
4. **Type Safety**: Maintain 100% type safety
|
|
913
|
+
5. **Testing**: Ensure all tests pass before submitting PR
|
|
914
|
+
|
|
915
|
+
### Development Workflow
|
|
916
|
+
|
|
917
|
+
1. Fork the repository
|
|
918
|
+
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
919
|
+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
920
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
921
|
+
5. Open a Pull Request
|
|
922
|
+
|
|
923
|
+
### Code of Conduct
|
|
924
|
+
|
|
925
|
+
- Be respectful and inclusive
|
|
926
|
+
- Provide constructive feedback
|
|
927
|
+
- Focus on what is best for the community
|
|
928
|
+
- Show empathy towards other community members
|
|
929
|
+
|
|
930
|
+
---
|
|
931
|
+
|
|
932
|
+
## π License
|
|
933
|
+
|
|
934
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
935
|
+
|
|
936
|
+
---
|
|
937
|
+
|
|
938
|
+
## π Acknowledgments
|
|
939
|
+
|
|
940
|
+
- Inspired by the principles of constitutional governance
|
|
941
|
+
- Built with TypeScript for type safety
|
|
942
|
+
- Powered by the Meta Architecture ecosystem
|
|
943
|
+
|
|
944
|
+
---
|
|
945
|
+
|
|
946
|
+
## π Support & Community
|
|
947
|
+
|
|
948
|
+
### Documentation
|
|
949
|
+
|
|
950
|
+
- **[Full Documentation](./docs/README.md)** - Complete documentation
|
|
951
|
+
- **[Quick Start Guide](./docs/quick-start.md)** - Get started in 5 minutes
|
|
952
|
+
- **[Development Guide](./docs/development.md)** - Comprehensive development guide
|
|
953
|
+
- **[Phase 2: Integration Design & DSL](./docs/phase2-integration-design.md)** - Context-awareness, ContractEntity, and DSL features
|
|
954
|
+
- **[Architecture Diagrams](./docs/architecture-diagram.md)** - Visual architecture documentation
|
|
955
|
+
- **[Performance Benchmarks](./docs/benchmarks.md)** - Performance metrics and comparisons
|
|
956
|
+
- **[Migration Guide](./docs/migration-guide.md)** - Migrate from Tailwind/CSS-in-JS
|
|
957
|
+
- **[DSL Reference](./docs/dsl-reference.md)** - Quick reference card for DSL syntax
|
|
958
|
+
- **[Interactive Demo](./docs/interactive-demo.md)** - Interactive examples and live demos
|
|
959
|
+
- **[Troubleshooting](./docs/troubleshooting.md)** - Common issues and solutions
|
|
960
|
+
|
|
961
|
+
### Framework Integrations
|
|
962
|
+
|
|
963
|
+
- **[Next.js Integration](./docs/integrations/nextjs.md)** - Integrate MASE with Next.js
|
|
964
|
+
- **[React Native Integration](./docs/integrations/react-native.md)** - Integrate MASE with React Native
|
|
965
|
+
- **[Storybook Integration](./docs/integrations/storybook.md)** - Integrate MASE with Storybook
|
|
966
|
+
|
|
967
|
+
### Examples
|
|
968
|
+
|
|
969
|
+
- **[Examples Directory](./examples/README.md)** - Comprehensive examples collection
|
|
970
|
+
- **[Basic Examples](./examples/basic/)** - Button, Card, Input components
|
|
971
|
+
- **[Advanced Examples](./examples/advanced/)** - Responsive, theming, animations
|
|
972
|
+
- **[Real-World Apps](./examples/real-world/)** - E-commerce, Dashboard, Social apps
|
|
973
|
+
|
|
974
|
+
### Community
|
|
975
|
+
|
|
976
|
+
- **[GitHub Issues](https://github.com/damarkuncoro/meta-architecture-style-engine/issues)** - Report bugs
|
|
977
|
+
- **[GitHub Discussions](https://github.com/damarkuncoro/meta-architecture-style-engine/discussions)** - Ask questions
|
|
978
|
+
- **[Pull Requests](https://github.com/damarkuncoro/meta-architecture-style-engine/pulls)** - Contribute code
|
|
979
|
+
|
|
980
|
+
---
|
|
981
|
+
|
|
982
|
+
## πΊοΈ Roadmap
|
|
983
|
+
|
|
984
|
+
### β
Phase 0: Prototype (v0.1)
|
|
985
|
+
- Basic `TokenRegistry` & `StyleRule`
|
|
986
|
+
- Simple `StyleValidator` (Runtime)
|
|
987
|
+
- `StrictButton` component demo
|
|
988
|
+
|
|
989
|
+
### β
Phase 1: Review & Ratify (Materialization)
|
|
990
|
+
- Card Governance implementation
|
|
991
|
+
- Testing strategy with Vitest
|
|
992
|
+
- Domain expansion (Shadow, Surface)
|
|
993
|
+
|
|
994
|
+
### π Phase 2: Integration Design & DSL
|
|
995
|
+
- Context-Awareness for responsive design
|
|
996
|
+
- ContractEntity abstract class
|
|
997
|
+
- DSL Design for declarative contracts
|
|
998
|
+
|
|
999
|
+
### π Phase 3: SRE Implementation
|
|
1000
|
+
- Style resolution algorithms
|
|
1001
|
+
- Context Binder for variants/conditions
|
|
1002
|
+
|
|
1003
|
+
### π Phase 4: SME (Materializers)
|
|
1004
|
+
- Semantic node to CSS Properties mapping
|
|
1005
|
+
- Atomic CSS generation optimization
|
|
1006
|
+
|
|
1007
|
+
---
|
|
1008
|
+
|
|
1009
|
+
<div align="center">
|
|
1010
|
+
|
|
1011
|
+
**Built with β€οΈ by Damar Kuncoro**
|
|
1012
|
+
|
|
1013
|
+
[](https://github.com/damarkuncoro)
|
|
1014
|
+
[](https://twitter.com/damarkuncoro)
|
|
44
1015
|
|
|
45
|
-
|
|
1016
|
+
</div>
|