Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@

# Respo Guidebook

使用者注意:本轮将站点 Calcit CLI / `@calcit/procs` 从 **0.31.0** 配对正式 **0.32.1**,采用已发布 Docs Workflow **0.0.40**、Respo **0.17.1**、UI **0.9.0** 和 JS-FFI **0.2.9**。Reel **0.7.0-alpha.5**、Markdown **0.5.0-alpha.5**、Router **0.9.0-alpha.4** 仍为已发布 alpha,不声称完整依赖图均为正式版。升级后重新安装完整精确依赖图并刷新页面,UI 样式可能变化。源码仍仅使用 `calcit.cirru`,依赖以 `deps.cirru` 为准,不恢复 compact/package.cirru。
开发使用配对的 Calcit CLI 和 `@calcit/procs` 0.40.0,并从正式标签解析 Docs Workflow 0.1.0 与 Reel 0.11.0。更新依赖后重新生成前端。

Guide 说明当前 Ref/watch、Option、event handler/app dispatch、名义 Store 和宿主边界。
旧 Beginner Guide、部分 Guide 实现说明和 API 仍有历史片段,尚未全部迁移或独立执行;站点构建通过不代表
所有旧示例都可用于当前版本。新应用以维护中的模板和已发布接口为准。

## 开发与验收

Node 24、Yarn 4.18.0、正式 0.32.1 CLI:
Node 24、Yarn 4.18.0、正式 0.40.0 CLI。
Comment thread
tiye marked this conversation as resolved.
Resolved

```bash
corepack enable
Expand All @@ -26,9 +26,7 @@ yarn dev
并保存 PR 预览。当前 Guide 计数器与 DOM Events 数据解码示例由官方代码块检查覆盖;原项目没有定义附带测试,零个测试不等于业务覆盖;浏览器导航、
搜索与刷新需另行验收。页面 `hud!` 错误展示保留。

默认 entry 的 dispatch-op 显式绑定原有 renderer 的 Dynamic 宿主入口;
非 Enum 输入仍被拒绝,业务 payload 仍受检后构造 Docs Workflow 的具名 Op。
14 个定义的 schema 与 Store/Op 合同保持;官方 formatter 转换 renderer 的一处类型提示,业务表达式不变,不以关闭证明审计或增加断言绕过 strict。
文档导航直接派发具名 `docs-workflow.schema/Op`。Reel 面板和快捷键通过独立回调接收 `reel.typed/Control`。

## 部署边界

Expand Down
53 changes: 19 additions & 34 deletions calcit.cirru
Original file line number Diff line number Diff line change
Expand Up @@ -34,47 +34,35 @@
'dispatch! $ %{} 'CodeEntry (:doc |)
:code $ quote $ defn dispatch! (op)
when config/dev? $ println |Dispatch: op
match (typed/decode-control op)
(:some control)
reset! *reel $ typed/apply-control updater @*reel control
(:none)
match op
(:states cursor data)
match
try-decode-map-as cursor $ List Tag
(:ok typed-cursor)
reset! *reel $ typed/record-op updater @*reel (docs-schema/Op :states typed-cursor data) (generate-id!)
:timestamp $ shared/date-now-snapshot
(:err message) (eprintln message)
(:hydrate-storage data)
match (try-decode-map-as data 'docs-workflow.schema/Store)
(:ok store)
reset! *reel $ typed/record-op updater @*reel (docs-schema/Op :hydrate-storage store) (generate-id!)
:timestamp $ shared/date-now-snapshot
(:err message) (eprintln message)
_ $ eprintln |Unknown-operation: op
reset! *reel $ typed/record-op updater @*reel op (generate-id!)
:timestamp $ shared/date-now-snapshot
, &unit
:examples $ []
:schema $ quote $ Fn AnyEnum (-> Unit) (:features :js-ffi) (:open :decode)
:schema $ quote $ Fn docs-workflow.schema/Op (-> Unit) (:features :js-ffi)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
'main! $ %{} 'CodeEntry (:doc |)
:code $ quote $ defn main! () (register-languages!)
println "|Running mode:" $ if config/dev? |dev |release
if config/dev? $ load-console-formatter!
render-app!
add-watch! *reel :changes $ fn (reel prev) (render-app!)
listen-devtools! |k dispatch!
listen-devtools-toggle! |k $ fn () $ on-control! (typed/Control :toggle)
browser/set-before-unload! $ fn (event) (persist-storage!)
browser/set-interval! persist-storage! 60000
println "|App started."
:examples $ []
:schema $ quote $ Fn (-> Unit) (:features :js-ffi)
'mount-target $ %{} 'CodeEntry (:doc |)
:code $ quote $ defn mount-target ()
.query-selector (js-cast js/document dom/DomDocument) |.app
.unwrap $ respo-browser/query-selector |.app
:examples $ []
:schema $ quote $ Fn
-> $ JsNullish respo.dom/DomElement
:features :js-ffi
:schema $ quote $ Fn (-> respo.dom/DomElement) (:features :js-ffi)
'on-control! $ %{} 'CodeEntry (:doc |)
:code $ quote $ defn on-control! (control)
when config/dev? $ println |Dispatch: control
reset! *reel $ typed/apply-control updater @*reel control
, &unit
:examples $ []
:schema $ quote $ Fn reel.typed/Control (-> Unit) (:features :js-ffi)
'persist-storage! $ %{} 'CodeEntry (:doc |)
:code $ quote $ defn persist-storage! () (js/console.log |persist)
browser/storage-set! (:storage-key config/site)
Expand All @@ -94,30 +82,27 @@
:schema $ quote $ Fn (-> Unit) (:features :js-ffi)
'render-app! $ %{} 'CodeEntry (:doc |)
:code $ quote $ defn render-app! ()
render! (mount-target) (comp-container @*reel schema/docs)
fn (op)
hint-fn $ Fn Dynamic (-> Unit) (:features :js-ffi)
if (enum? op) (dispatch! op) (raise "|Expected an Enum render action")
, &unit
render-with! (mount-target)
fn () $ comp-container @*reel schema/docs on-control!
, dispatch!
:examples $ []
:schema $ quote $ Fn (-> Unit) (:features :js-ffi)
:ns $ %{} 'NsEntry (:doc |)
:code $ quote $ ns app.main
:require
respo.core :refer $ render! clear-cache!
respo.core :refer $ render-with! clear-cache!
docs-workflow.comp.container :refer $ comp-container
app.updater :refer $ updater
app.schema :as schema
reel.util :refer $ listen-devtools!
reel.util :refer $ listen-devtools-toggle!
app.config :as config
|./calcit.build-errors :default build-errors
|bottom-tip :default hud!
docs-workflow.config :refer $ register-languages!
reel.typed :as typed
js-ffi.browser :as browser
js-ffi.shared :as shared
respo.dom :as dom
docs-workflow.schema :as docs-schema
respo.ffi.browser :as respo-browser
'app.schema $ %{} 'FileEntry
:defs $ {}
'docs $ %{} 'CodeEntry (:doc |)
Expand Down
6 changes: 3 additions & 3 deletions deps.cirru
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{} (:calcit-version |0.38.0)
{} (:calcit-version |0.40.0)
:version |0.0.4
:dependencies $ {} (|Respo/reel.calcit |0.10.0)
:dependencies $ {} (|Respo/reel.calcit |0.11.0)
|Respo/respo-markdown.calcit |0.8.2
|Respo/respo-router.calcit |0.12.2
|Respo/respo-ui.calcit |0.15.2
|Respo/respo.calcit |0.19.5
|calcit-lang/docs-workflow |0.0.42
|calcit-lang/docs-workflow |0.1.0
|calcit-lang/js-ffi |0.2.13
23 changes: 14 additions & 9 deletions docs/guide.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# Guide: Calcit 0.32.1
# Guide: Calcit 0.40.0

This site pairs formal Calcit CLI / `@calcit/procs` **0.32.1** with released Docs Workflow **0.0.40**, Respo **0.17.1** and JS-FFI **0.2.9**. The published UI graph still includes Reel **0.7.0-alpha.5**, Markdown **0.5.0-alpha.5** and Router **0.9.0-alpha.4**; it is not an entirely stable-release graph. Install it using Caps strict and keep runtime and CLI paired. Use `calcit.cirru` for source and `deps.cirru` for module versions; do not restore `compact.cirru` or `package.cirru`.
Use the published Calcit CLI and `@calcit/procs` **0.40.0** together. This site
uses Docs Workflow **0.1.0**, Respo **0.19.5**, Respo UI **0.15.2**, Reel
**0.11.0**, Markdown **0.8.2**, Router **0.12.2**, and JS-FFI **0.2.13**.
Docs Workflow also brings in Alerts **0.14.3**. Install with Caps strict and run
`caps verify --toolchain` to check the version pairing. The source and module
versions live in `calcit.cirru` and `deps.cirru`.

For a new application, start with the maintained
[Respo template](https://github.com/Respo/respo-calcit-workflow). Check its own
Expand Down Expand Up @@ -36,14 +41,14 @@ not prove a JavaScript value has a Calcit schema. Keep JavaScript `bottom-tip`
`respo.core/>>` selects a state branch and carries its cursor. A Respo event
handler receives `(event, dispatch!)`; the dispatch function accepts exactly
one value of the entry's `dispatch-op` type and returns Unit. For state changes,
package the cursor and new state in one application operation, then validate
its fields at the app boundary. A two-argument handler or custom
validate any raw cursor and payload where they enter the app, then construct
and dispatch one application operation. A two-argument handler or custom
`on-select(path, d!)` callback does not make `d!` a two-argument dispatcher.

Define an application Op enum and validate incoming state cursors/payloads
before constructing it. With typed Reel, retain `State<Op, Store>` in a Ref,
handle `typed/decode-control` separately, and use `typed/record-op` for domain
operations. `Date.now` is a host call, not a numeric constant; JS-FFI's
send `reel.typed/Control` to the separate `on-control!` callback, and use
`typed/record-op` for application operations. `Date.now` is a host call, not a numeric constant; JS-FFI's
`date-now-snapshot` exposes a checked `:timestamp` value.

This app uses Docs Workflow's **DocNode, Store and Op**, plus its
Expand All @@ -55,8 +60,8 @@ interchangeable with that module's Store.
Calcit's `get` returns an Option. Match `:some` / `:none`, or use `.unwrap-or`
with a meaningful default; use `.unwrap` only for a real presence invariant.
Do not insert arbitrary empty collections merely to silence checks. State
trees and browser event Maps remain heterogeneous boundaries: validate the
fields consumed rather than asserting every event is an unrelated Struct.
trees can hold heterogeneous values. Browser callbacks use `RespoEvent`, and
widget code validates the host fields it consumes.

## Verification and older chapters

Expand All @@ -68,6 +73,6 @@ fragment or certify browser/WebSocket application behavior.
The Beginner Guide, older implementation discussions under Guide, and several API
chapters retain historical design notes. Their
old macro expansions, direct JavaScript access and operation syntax are not
copy-ready 0.32.1 code. Consult the paired published module's `calcit query def`
copy-ready 0.40.0 code. Consult the paired published module's `calcit query def`
and `query schema` views and the maintained template. Historical examples need
section-by-section migration, not mechanical renaming without contract checks.
54 changes: 32 additions & 22 deletions docs/guide/component-states.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ A component state branch is an open Map with a `:cursor` path and optional
boundary explicit; decode the fields a widget consumes before using them as a
business model. A missing Map key returns `Option :none`, not an implicit nil.

`respo.core/>>` selects a branch and extends its cursor. This small example uses
Tag keys, matching this documentation app's checked `List<Tag>` operation path:
`respo.core/>>` takes one `respo.schema/CoordKey` and appends it to the
parent cursor. The resulting branch stores its path as a
`List<respo.schema/CoordKey>`.

```cirru
let
Expand All @@ -21,22 +22,33 @@ present false, zero or empty string state with an arbitrary default. Match the
Option returned by `get`; decode a present value according to the widget's
actual state shape.

A Respo event handler receives two arguments: the event Map and the application
dispatch function. That dispatch function accepts **one** entry `dispatch-op`
value and returns Unit. Two handler arguments do not imply a two-argument
state dispatcher. Wrap the cursor and new state in the app's single operation:
A Respo event handler receives a `respo.schema/RespoEvent` and a dispatcher.
The dispatcher accepts one operation of the entry's `dispatch-op` type and
returns Unit. In this site, that operation is `docs-workflow.schema/Op`.
A custom callback such as `on-select(path, d!)` has two parameters, while each
call to `d!` still passes a single operation.

Validate external data where it enters the app. A widget that imports a
draft can check it as a String and use the cursor of its own state branch
when constructing the operation.

```cirru
fn (event d!)
d! $ :: :states cursor new-state
, &unit
let
states $ {} (:cursor $ [])
branch $ respo.core/>> states :task
raw-draft $ parse-cirru-edn "|do |Edited"
cursor $ decode-map-as
.unwrap $ get branch :cursor
List respo.schema/CoordKey
draft $ decode-map-as raw-draft 'String
operation $ docs-workflow.schema/Op :states cursor draft
assert= (docs-workflow.schema/Op :states ([] :task) |Edited) operation
```

This is a callback fragment in a context that already provides `cursor` and
`new-state`, not a standalone program. This site's application boundary checks
the raw Enum and payload before constructing the published nominal Op.
A custom callback such as `on-select(path, d!)` can also have two arguments;
that does not change the arity of the `d!` value passed to it.
Pass the validated operation to `d!` from the event handler. Use the
widget's own schema for its payload, such as a named Struct when it stores
several fields. To restore a saved store, decode the raw data against
`docs-workflow.schema/Store` before constructing `Op :hydrate-storage`.

For the tree update itself, use the current three-argument helper:

Expand All @@ -48,11 +60,9 @@ let

`update-state-tree` and `respo.cursor/update-states` expose open boundaries;
`update-states` also takes three arguments: store, cursor, new state. Their
results are not automatically proof of a nominal Store. This app's published
Docs Workflow updater checks the updated state Map before assigning it into
Store. Its app dispatcher validates cursors and hydrated stores before building
`docs-workflow.schema/Op`, then typed Reel records that operation.

Use the actual checked `app.main/dispatch!` and `docs-workflow.updater/updater`
definitions as integration references. The removed `case-default` example and
the old two-argument `update-states` call are not current alternatives.
results require a check before assignment to a nominal Store. This site's
`app.main/dispatch!` takes an already constructed `Op` and records it in typed
Reel. The published `docs-workflow.updater/updater` checks the resulting state
Map before assigning it into Store. That Map check allows heterogeneous
payloads, so widget-specific validation belongs at the input boundary.
Reel controls enter through the separate `on-control!` callback.
2 changes: 1 addition & 1 deletion docs/home.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

Inspired by React and Reagent.

This site targets formal Calcit/procs **0.32.1**. Choose **Guide** in the sidebar
This site targets formal Calcit/procs **0.40.0**. Choose **Guide** in the sidebar
for current migration notes. Beginner Guide and older API chapters retain
historical material; not every snippet is ported or independently type-checked.

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"packageManager": "yarn@4.18.0",
"dependencies": {
"@calcit/procs": "0.38.0"
"@calcit/procs": "0.40.0"
},
"devDependencies": {
"bottom-tip": "^0.1.5",
Expand Down
10 changes: 5 additions & 5 deletions yarn.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.