@naiv/swan 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/SWAN-DSL.md +832 -0
  2. package/dist/SWANServer.d.ts +26 -0
  3. package/dist/SWANServer.d.ts.map +1 -0
  4. package/dist/SWANServer.js +158 -0
  5. package/dist/SWANServer.js.map +1 -0
  6. package/dist/agent-mode/agent-capability.d.ts +28 -0
  7. package/dist/agent-mode/agent-capability.d.ts.map +1 -0
  8. package/dist/agent-mode/agent-capability.js +82 -0
  9. package/dist/agent-mode/agent-capability.js.map +1 -0
  10. package/dist/agent-mode/plan-execution-and-next.d.ts +3 -0
  11. package/dist/agent-mode/plan-execution-and-next.d.ts.map +1 -0
  12. package/dist/agent-mode/plan-execution-and-next.js +33 -0
  13. package/dist/agent-mode/plan-execution-and-next.js.map +1 -0
  14. package/dist/agent-mode/plan-preparation.d.ts +11 -0
  15. package/dist/agent-mode/plan-preparation.d.ts.map +1 -0
  16. package/dist/agent-mode/plan-preparation.js +98 -0
  17. package/dist/agent-mode/plan-preparation.js.map +1 -0
  18. package/dist/command/cmd-chat.d.ts +2 -0
  19. package/dist/command/cmd-chat.d.ts.map +1 -0
  20. package/dist/command/cmd-chat.js +137 -0
  21. package/dist/command/cmd-chat.js.map +1 -0
  22. package/dist/command/cmd-run.d.ts +2 -0
  23. package/dist/command/cmd-run.d.ts.map +1 -0
  24. package/dist/command/cmd-run.js +42 -0
  25. package/dist/command/cmd-run.js.map +1 -0
  26. package/dist/exec.d.ts +3 -0
  27. package/dist/exec.d.ts.map +1 -0
  28. package/dist/exec.js +78 -0
  29. package/dist/exec.js.map +1 -0
  30. package/dist/index.d.ts +2 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +41 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/prompt.d.ts +7 -0
  35. package/dist/prompt.d.ts.map +1 -0
  36. package/dist/prompt.js +90 -0
  37. package/dist/prompt.js.map +1 -0
  38. package/dist/sample-page.d.ts +3 -0
  39. package/dist/sample-page.d.ts.map +1 -0
  40. package/dist/sample-page.js +144 -0
  41. package/dist/sample-page.js.map +1 -0
  42. package/package.json +50 -0
package/SWAN-DSL.md ADDED
@@ -0,0 +1,832 @@
1
+ # SWAN DSL — a UI Interaction DSL Full Specification
2
+
3
+ ---
4
+
5
+ # 1. Purpose
6
+
7
+ This DSL describes:
8
+
9
+ > **User interfaces as hierarchical interaction graphs with explicit navigation states.**
10
+
11
+ It is designed to:
12
+
13
+ * Model pages, components, and flows
14
+ * Separate navigation from interaction
15
+ * Enable compilation to web/mobile frameworks
16
+ * Support visualization and verification
17
+
18
+ It is **declarative**, **state-oriented**, and **framework-agnostic**.
19
+
20
+ ---
21
+
22
+ # 2. Core Concepts
23
+
24
+ ## 2.1 Application
25
+
26
+ An application is the top-level container.
27
+
28
+ It defines:
29
+
30
+ * identity
31
+ * entry point
32
+ * owned pages and components
33
+
34
+ ```dsl
35
+ app MyApp {
36
+ entry Home
37
+ }
38
+ ```
39
+
40
+ ---
41
+
42
+ ## 2.2 Pages (Navigation States)
43
+
44
+ A `page` represents a **reachable navigation state**.
45
+
46
+ Properties:
47
+
48
+ | Property | Value |
49
+ | ----------- | ----- |
50
+ | Addressable | Yes |
51
+ | Routable | Yes |
52
+ | Reusable | No |
53
+ | Stateful | Yes |
54
+
55
+ Pages:
56
+
57
+ * may contain UI
58
+ * may contain components
59
+ * may emit navigation
60
+ * may be navigation targets
61
+
62
+ ---
63
+
64
+ ## 2.3 Components (Interaction Units)
65
+
66
+ A `component` represents a **reusable interaction unit**.
67
+
68
+ Properties:
69
+
70
+ | Property | Value |
71
+ | ----------- | ------------------- |
72
+ | Addressable | No |
73
+ | Routable | No |
74
+ | Reusable | Yes |
75
+ | Stateful | No (locally scoped) |
76
+
77
+ Components:
78
+
79
+ * may contain components
80
+ * may contain logic
81
+ * may emit navigation
82
+ * may not be targets
83
+
84
+ ---
85
+
86
+ ## 2.4 Navigation
87
+
88
+ Navigation is the transition between pages.
89
+
90
+ Only pages may be navigation destinations.
91
+
92
+ ```dsl
93
+ -> Dashboard // valid
94
+ -> LoginForm // invalid
95
+ ```
96
+
97
+ Navigation events bubble upward.
98
+
99
+ ---
100
+
101
+ # 3. Structural Model
102
+
103
+ ```
104
+ Application
105
+ ├── Pages (graph nodes)
106
+ └── Components (hierarchical tree)
107
+ ```
108
+
109
+ * Pages form a directed graph
110
+ * Components form a tree
111
+ * Navigation edges connect pages
112
+
113
+ No cycles restriction is imposed.
114
+
115
+ ---
116
+
117
+ # 4. Lexical Elements
118
+
119
+ ## 4.1 Identifiers
120
+
121
+ ```
122
+ Identifier ::= Letter (Letter | Digit | "_")*
123
+ ```
124
+
125
+ Case-sensitive.
126
+
127
+ ---
128
+
129
+ ## 4.2 Literals
130
+
131
+ ### String
132
+
133
+ ```
134
+ "Any UTF-8 text"
135
+ ```
136
+
137
+ ### Number
138
+
139
+ ```
140
+ 123 | 45.67
141
+ ```
142
+
143
+ ### Boolean
144
+
145
+ ```
146
+ true | false
147
+ ```
148
+
149
+ ---
150
+
151
+ # 5. Top-Level Grammar (EBNF)
152
+
153
+ ```ebnf
154
+ Program ::= AppDecl { PageDecl | ComponentDecl }
155
+
156
+ AppDecl ::= "app" Identifier "{" "entry" Identifier "}"
157
+
158
+ PageDecl ::= "page" Identifier Block
159
+
160
+ ComponentDecl ::= "component" Identifier Block
161
+
162
+ Block ::= "{" { Statement } "}"
163
+
164
+ QueryDecl ::= "query" Identifier [ ":" Type ] [ "=" Literal ]
165
+
166
+ Type ::= "string" | "number" | "boolean"
167
+ ```
168
+
169
+ ---
170
+
171
+ # 6. Statements
172
+
173
+ ```ebnf
174
+ Statement ::=
175
+ UIStatement
176
+ | UseStatement
177
+ | ActionStatement
178
+ | HandlerStatement
179
+ | ConditionalStatement
180
+ | QueryStatement
181
+ ```
182
+
183
+ ---
184
+
185
+ ## 6.1 UI Statements
186
+
187
+ ```ebnf
188
+ UIStatement ::=
189
+ "header" String
190
+ | "text" String
191
+ | "button" String NavTarget
192
+ | "link" String NavTarget
193
+ | "field" Identifier
194
+ | "input" Identifier
195
+ | TableStatement
196
+ | ChartStatement
197
+ ```
198
+
199
+ Example:
200
+
201
+ ```dsl
202
+ header "Login"
203
+ text "Welcome back"
204
+ ```
205
+
206
+ ---
207
+
208
+ ## 6.7 Table Statement
209
+
210
+ A `table` statement renders **tabular data** with named columns.
211
+
212
+ Each row is a fixed-width list of values that must match the declared columns.
213
+
214
+ ```ebnf
215
+ TableStatement ::= "table" Identifier "{" TableColumns TableRows "}"
216
+
217
+ TableColumns ::= "columns" "[" ColumnName { "," ColumnName } "]"
218
+
219
+ ColumnName ::= String
220
+
221
+ TableRows ::= { TableRow }
222
+
223
+ TableRow ::= "row" "[" CellValue { "," CellValue } "]"
224
+
225
+ CellValue ::= Literal | Expression
226
+ ```
227
+
228
+ Example:
229
+
230
+ ```dsl
231
+ table UserList {
232
+ columns ["Name", "Role", "Status"]
233
+ row ["Alice", "Admin", "Active"]
234
+ row ["Bob", "Viewer", "Inactive"]
235
+ }
236
+ ```
237
+
238
+ The table identifier (`UserList`) names the table for semantic checking. It does **not** introduce a navigable scope.
239
+
240
+ ---
241
+
242
+ ## 6.8 Chart Statement
243
+
244
+ A `chart` statement renders **visual data** using a specified chart type.
245
+
246
+ Each `series` is a named data sequence. Each `point` is a single `x, y` data pair.
247
+
248
+ ```ebnf
249
+ ChartStatement ::= "chart" Identifier ChartType "{" { SeriesDecl } "}"
250
+
251
+ ChartType ::= "bar" | "line" | "pie" | "area" | "scatter"
252
+
253
+ SeriesDecl ::= "series" String "{" { DataPoint } "}"
254
+
255
+ DataPoint ::= "point" CellValue "," CellValue
256
+
257
+ CellValue ::= Literal | Expression
258
+ ```
259
+
260
+ | Part | Required | Description |
261
+ | -------------- | -------- | ---------------------------------------- |
262
+ | Identifier | Yes | Chart name (unique within scope) |
263
+ | ChartType | Yes | Visual style: bar, line, pie, area, scatter |
264
+ | `series` block | Yes (≥1) | Named sequence of data points |
265
+ | `point` x, y | Yes (≥1) | Single (x, y) coordinate or category |
266
+
267
+ Example:
268
+
269
+ ```dsl
270
+ chart MonthlySales line {
271
+ series "Revenue" {
272
+ point "Jan", 4200
273
+ point "Feb", 5800
274
+ point "Mar", 7100
275
+ }
276
+ series "Cost" {
277
+ point "Jan", 2100
278
+ point "Feb", 3000
279
+ point "Mar", 3500
280
+ }
281
+ }
282
+ ```
283
+
284
+ Pie charts use label/value pairs:
285
+
286
+ ```dsl
287
+ chart TrafficSource pie {
288
+ series "Sources" {
289
+ point "Organic", 65
290
+ point "Paid", 20
291
+ point "Direct", 15
292
+ }
293
+ }
294
+ ```
295
+
296
+ ---
297
+
298
+ ## 6.2 Component Composition
299
+
300
+ ```ebnf
301
+ UseStatement ::= "use" Identifier
302
+ ```
303
+
304
+ Example:
305
+
306
+ ```dsl
307
+ use LoginForm
308
+ ```
309
+
310
+ ---
311
+
312
+ ## 6.3 Actions
313
+
314
+ Actions represent named interaction events.
315
+
316
+ ```ebnf
317
+ ActionStatement ::=
318
+ "submit" String "->" Identifier
319
+ | "click" String "->" Identifier
320
+ ```
321
+
322
+ Example:
323
+
324
+ ```dsl
325
+ submit "Continue" -> authenticate
326
+ ```
327
+
328
+ Here `authenticate` is an action identifier.
329
+
330
+ ---
331
+
332
+ ## 6.4 Event Handlers
333
+
334
+ Handlers define control flow.
335
+
336
+ ```ebnf
337
+ HandlerStatement ::=
338
+ "on" Identifier "{" { OutcomeClause } "}"
339
+
340
+ OutcomeClause ::=
341
+ Identifier "->" Identifier
342
+ ```
343
+
344
+ Example:
345
+
346
+ ```dsl
347
+ on authenticate {
348
+ success -> Dashboard
349
+ error -> LoginError
350
+ }
351
+ ```
352
+
353
+ ---
354
+
355
+ ## 6.5 Conditionals
356
+
357
+ ```ebnf
358
+ ConditionalStatement ::=
359
+ "if" Expression Block
360
+ ```
361
+
362
+ Example:
363
+
364
+ ```dsl
365
+ if user.role == "admin" {
366
+ button "Admin" -> AdminPanel
367
+ }
368
+ ```
369
+
370
+ ---
371
+
372
+ ## 6.6 Page Query Statement
373
+
374
+ A `query` statement declares a **URL query parameter** accepted by a page.
375
+ It maps directly to the query string portion of the URL (e.g. `/search?q=hello&page=2`).
376
+
377
+ Only valid inside a `page` block — **not** inside components.
378
+
379
+ ```ebnf
380
+ QueryStatement ::=
381
+ "query" Identifier [ ":" Type ] [ "=" Literal ]
382
+
383
+ Type ::= "string" | "number" | "boolean"
384
+ ```
385
+
386
+ | Part | Required | Description |
387
+ | ----------- | -------- | ---------------------------------------- |
388
+ | Identifier | Yes | Query parameter key (maps to URL `?key`) |
389
+ | `:` Type | No | Expected value type (default: `string`) |
390
+ | `=` Literal | No | Default value when parameter is absent |
391
+
392
+ Example:
393
+
394
+ ```dsl
395
+ page Search {
396
+ query q // ?q=<any string>
397
+ query page : number = 1 // ?page=2 (default: 1)
398
+ query active : boolean // ?active=true
399
+
400
+ header "Search Results"
401
+ text "Showing results for query"
402
+ }
403
+ ```
404
+
405
+ Runtime behaviour:
406
+
407
+ * Query values are read from the URL on page entry.
408
+ * If a parameter is absent and a default is declared, the default is used.
409
+ * If a parameter is absent and no default is declared, the value is `null`.
410
+ * Query values are available in expressions via the `query` scope:
411
+
412
+ ```dsl
413
+ if query.active == true {
414
+ text "Showing active items only"
415
+ }
416
+ ```
417
+
418
+ ---
419
+
420
+ # 7. Expressions
421
+
422
+ ```ebnf
423
+ Expression ::=
424
+ Identifier
425
+ | Literal
426
+ | Expression Operator Expression
427
+ ```
428
+
429
+ Operators:
430
+
431
+ ```
432
+ == != < > <= >= && || !
433
+ ```
434
+
435
+ Scope:
436
+
437
+ * `user`
438
+ * `session`
439
+ * `env`
440
+
441
+ ---
442
+
443
+ # 8. Navigation Targets
444
+
445
+ ```ebnf
446
+ NavTarget ::= "->" Identifier [ QueryArgs ]
447
+
448
+ QueryArgs ::= "?" QueryArg { "&" QueryArg }
449
+
450
+ QueryArg ::= Identifier "=" Expression
451
+ ```
452
+
453
+ Semantics:
454
+
455
+ * Identifier must resolve to a `page`
456
+ * Resolution is static
457
+ * `QueryArgs` are optional; they set query parameter values on the target page
458
+ * Each key in `QueryArgs` must match a `query` declaration on the target page
459
+
460
+ Example:
461
+
462
+ ```dsl
463
+ button "Next Page" -> Search?q="hello"&page=2
464
+ ```
465
+
466
+ ---
467
+
468
+ # 9. Semantic Rules (Static)
469
+
470
+ ### SR-1: Single Entry Point
471
+
472
+ ```
473
+ app must define exactly one entry page
474
+ ```
475
+
476
+ ### SR-2: Valid Entry
477
+
478
+ ```
479
+ entry must reference a page
480
+ ```
481
+
482
+ ### SR-3: Valid Targets
483
+
484
+ ```
485
+ All navigation targets must be pages
486
+ ```
487
+
488
+ ### SR-4: No Orphan Pages
489
+
490
+ ```
491
+ All pages must be reachable from entry
492
+ ```
493
+
494
+ (optional strict mode)
495
+
496
+ ### SR-5: No Cyclic Components
497
+
498
+ ```
499
+ Component composition graph must be acyclic
500
+ ```
501
+
502
+ ### SR-6: Unique Names
503
+
504
+ ```
505
+ Identifiers are unique per namespace
506
+ ```
507
+
508
+ Namespaces:
509
+
510
+ * pages
511
+ * components
512
+ * actions
513
+ * tables (within a page or component block)
514
+ * charts (within a page or component block)
515
+
516
+ ### SR-7: Query in Pages Only
517
+
518
+ ```
519
+ query statements are only valid inside page blocks
520
+ ```
521
+
522
+ ### SR-8: Unique Query Keys
523
+
524
+ ```
525
+ Query parameter identifiers must be unique within a page
526
+ ```
527
+
528
+ ### SR-9: Valid Query Args in Navigation
529
+
530
+ ```
531
+ Each key in a navigation QueryArgs list must match
532
+ a query declaration on the target page
533
+ ```
534
+
535
+ ### SR-10: Table Column Count Consistency
536
+
537
+ ```
538
+ Every row in a table must have exactly as many cells
539
+ as there are declared columns
540
+ ```
541
+
542
+ Example of a violation:
543
+
544
+ ```dsl
545
+ table Bad {
546
+ columns ["A", "B", "C"]
547
+ row ["x", "y"] // error: 2 cells, 3 columns expected
548
+ }
549
+ ```
550
+
551
+ ### SR-11: Table Must Have Columns
552
+
553
+ ```
554
+ A table block must declare at least one column
555
+ and at least one row
556
+ ```
557
+
558
+ ### SR-12: Chart Must Have at Least One Series
559
+
560
+ ```
561
+ A chart block must contain at least one series declaration
562
+ ```
563
+
564
+ ### SR-13: Series Must Have at Least One Point
565
+
566
+ ```
567
+ Each series block must contain at least one data point
568
+ ```
569
+
570
+ ### SR-14: Pie Chart Single Series
571
+
572
+ ```
573
+ A pie chart may only contain a single series
574
+ ```
575
+
576
+ Pie charts represent a whole divided into parts. Multiple series on a pie chart are undefined and rejected.
577
+
578
+ ---
579
+
580
+ # 10. Runtime Semantics
581
+
582
+ ## 10.1 Rendering
583
+
584
+ Rendering is recursive:
585
+
586
+ ```
587
+ Render(Page):
588
+ render local UI
589
+ render used components
590
+
591
+ Render(Component):
592
+ render UI
593
+ render children
594
+ ```
595
+
596
+ ---
597
+
598
+ ## 10.2 Event Propagation
599
+
600
+ 1. User triggers event
601
+ 2. Component handles if defined
602
+ 3. Otherwise bubbles up
603
+ 4. Page resolves navigation
604
+
605
+ ---
606
+
607
+ ## 10.3 Navigation Resolution
608
+
609
+ When a navigation intent occurs:
610
+
611
+ ```
612
+ -> TargetPage
613
+ ```
614
+
615
+ Runtime:
616
+
617
+ ```
618
+ currentPage := TargetPage
619
+ re-render
620
+ ```
621
+
622
+ State is reset unless persisted.
623
+
624
+ ---
625
+
626
+ ## 10.4 Table Rendering
627
+
628
+ A table is rendered as a **two-dimensional grid**:
629
+
630
+ ```
631
+ Render(Table):
632
+ render header row from columns[]
633
+ for each row:
634
+ render cells left-to-right
635
+ ```
636
+
637
+ Cell values are evaluated lazily at render time. If a cell contains an expression, it is resolved against the current scope (`user`, `session`, `env`, `query`).
638
+
639
+ ---
640
+
641
+ ## 10.5 Chart Rendering
642
+
643
+ A chart is rendered as a **visual data graphic** delegated to the compilation target:
644
+
645
+ ```
646
+ Render(Chart):
647
+ resolve all point values
648
+ emit chart type + series data to target backend
649
+ ```
650
+
651
+ The DSL does not prescribe pixel layout — that is the responsibility of the compilation target (e.g., React renders a `<Chart>` component; HTML emits a `<canvas>` block).
652
+
653
+ Point values:
654
+
655
+ * `x` axis — category label (String) or numeric position (Number)
656
+ * `y` axis — numeric value (Number)
657
+
658
+ For pie charts the `x` value is the **slice label** and `y` is the **slice size**.
659
+
660
+ ---
661
+
662
+ # 11. Flow Semantics
663
+
664
+ Each action defines a mini-state machine.
665
+
666
+ Example:
667
+
668
+ ```dsl
669
+ submit -> auth
670
+
671
+ on auth {
672
+ success -> Dashboard
673
+ error -> LoginError
674
+ }
675
+ ```
676
+
677
+ Equivalent to:
678
+
679
+ ```
680
+ Idle → Submitting → {Success, Error}
681
+ ```
682
+
683
+ ---
684
+
685
+ # 12. Validation Phases
686
+
687
+ ## Phase 1: Parsing
688
+
689
+ * Grammar conformance
690
+
691
+ ## Phase 2: Name Resolution
692
+
693
+ * Link identifiers
694
+ * Build symbol tables
695
+
696
+ ## Phase 3: Flow Analysis
697
+
698
+ * Build navigation graph
699
+ * Check reachability
700
+
701
+ ## Phase 4: Type Checking (optional)
702
+
703
+ * Validate expressions
704
+ * Validate fields
705
+
706
+ ---
707
+
708
+ # 13. Compilation Targets
709
+
710
+ The DSL is target-independent.
711
+
712
+ Possible backends:
713
+
714
+ | Target | Page / Component Mapping | Table Mapping | Chart Mapping |
715
+ | ------- | ------------------------ | ------------------- | -------------------------- |
716
+ | HTML | Routes + templates | `<table>` element | `<canvas>` + Chart.js |
717
+ | React | Router + components | `<Table>` component | `<Chart>` component |
718
+ | Flutter | Navigator + Widgets | `DataTable` widget | `fl_chart` widget |
719
+ | SwiftUI | NavigationStack | `Table` view | `Swift Charts` view |
720
+
721
+ ---
722
+
723
+ # 14. Example (Complete Program)
724
+
725
+ ```dsl
726
+ app MyApp {
727
+ entry Home
728
+ }
729
+
730
+ page Home {
731
+ header "Welcome"
732
+ button "Log in" -> Login
733
+ button "Search" -> Search?q=""&page=1
734
+ button "Dashboard" -> Dashboard
735
+ }
736
+
737
+ component LoginForm {
738
+ field email
739
+ field password
740
+
741
+ submit "Continue" -> auth
742
+
743
+ on auth {
744
+ success -> Dashboard
745
+ error -> LoginError
746
+ }
747
+ }
748
+
749
+ page Login {
750
+ header "Login"
751
+ use LoginForm
752
+ }
753
+
754
+ page LoginError {
755
+ text "Invalid credentials"
756
+ button "Retry" -> Login
757
+ }
758
+
759
+ page Dashboard {
760
+ header "Dashboard"
761
+ text "Hello!"
762
+ button "Logout" -> Home
763
+ button "Search Items" -> Search?q=""&page=1
764
+
765
+ // Recent users table
766
+ table RecentUsers {
767
+ columns ["Name", "Role", "Last Seen"]
768
+ row ["Alice", "Admin", "2 mins ago"]
769
+ row ["Bob", "Viewer", "1 hour ago"]
770
+ row ["Carol", "Editor", "Yesterday"]
771
+ }
772
+
773
+ // Monthly activity chart
774
+ chart MonthlyLogins line {
775
+ series "Logins" {
776
+ point "Jan", 320
777
+ point "Feb", 410
778
+ point "Mar", 390
779
+ point "Apr", 520
780
+ }
781
+ }
782
+
783
+ // Traffic breakdown (pie)
784
+ chart TrafficSource pie {
785
+ series "Sources" {
786
+ point "Organic", 58
787
+ point "Paid", 27
788
+ point "Direct", 15
789
+ }
790
+ }
791
+ }
792
+
793
+ page Search {
794
+ query q : string = ""
795
+ query page : number = 1
796
+ query active : boolean
797
+
798
+ header "Search"
799
+ text "Showing results"
800
+
801
+ if query.active == true {
802
+ text "(active items only)"
803
+ }
804
+
805
+ button "Next" -> Search?q=query.q&page=query.page+1
806
+ button "Home" -> Home
807
+ }
808
+ ```
809
+
810
+ ---
811
+
812
+ # 15. Design Guarantees
813
+
814
+ This DSL guarantees:
815
+
816
+ ✅ Explicit navigation graph
817
+ ✅ No hidden routes
818
+ ✅ Predictable composition
819
+ ✅ Static analyzability
820
+ ✅ Framework independence
821
+ ✅ AI-safe generation
822
+ ✅ Schema-checked tabular data
823
+ ✅ Declarative, backend-agnostic charts
824
+
825
+ ---
826
+
827
+ # 16. Design Philosophy
828
+
829
+ > Pages are states.
830
+ > Components are behavior.
831
+ > Flows are explicit.
832
+ > Navigation is centralized.