rip-lang 3.10.6 → 3.10.7
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 +1 -1
- package/docs/RIP-LANG.md +109 -0
- package/docs/dist/rip-ui.min.js +169 -159
- package/docs/dist/rip-ui.min.js.br +0 -0
- package/docs/dist/rip.browser.min.js +170 -160
- package/docs/dist/rip.browser.min.js.br +0 -0
- package/docs/results/images/cover_bg.jpg +0 -0
- package/docs/results/images/crossover.svg +20 -0
- package/docs/results/images/heart.png +0 -0
- package/docs/results/images/human_body.png +0 -0
- package/docs/results/images/pancreas.png +0 -0
- package/docs/results/images/yoga_lady.jpg +0 -0
- package/docs/results/index.html +1117 -0
- package/package.json +1 -1
- package/src/compiler.js +10 -0
- package/src/components.js +151 -53
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
|
-
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-3.10.
|
|
12
|
+
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-3.10.7-blue.svg" alt="Version"></a>
|
|
13
13
|
<a href="#zero-dependencies"><img src="https://img.shields.io/badge/dependencies-ZERO-brightgreen.svg" alt="Dependencies"></a>
|
|
14
14
|
<a href="#"><img src="https://img.shields.io/badge/tests-1%2C243%2F1%2C243-brightgreen.svg" alt="Tests"></a>
|
|
15
15
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License"></a>
|
package/docs/RIP-LANG.md
CHANGED
|
@@ -322,6 +322,7 @@ Multiple lines
|
|
|
322
322
|
| `*` | Merge assign | `*obj = {a: 1}` | `Object.assign(obj, {a: 1})` |
|
|
323
323
|
| `not in` | Not in | `x not in arr` | Negated membership test |
|
|
324
324
|
| `not of` | Not of | `k not of obj` | Negated key existence |
|
|
325
|
+
| `<=>` | Two-way bind | `value <=> name` | Bidirectional reactive binding (render blocks) |
|
|
325
326
|
|
|
326
327
|
## Assignment Operators
|
|
327
328
|
|
|
@@ -915,6 +916,110 @@ declare const count: Signal<number>;
|
|
|
915
916
|
declare const doubled: Computed<number>;
|
|
916
917
|
```
|
|
917
918
|
|
|
919
|
+
## Two-Way Binding (`<=>`)
|
|
920
|
+
|
|
921
|
+
The `<=>` operator creates bidirectional reactive bindings inside render blocks.
|
|
922
|
+
It connects a parent's reactive state to a child element or component — changes
|
|
923
|
+
flow in both directions automatically. This is a Rip original.
|
|
924
|
+
|
|
925
|
+
### With HTML Elements
|
|
926
|
+
|
|
927
|
+
```coffee
|
|
928
|
+
export Form = component
|
|
929
|
+
@name := ''
|
|
930
|
+
@age := 25
|
|
931
|
+
@agree := false
|
|
932
|
+
|
|
933
|
+
render
|
|
934
|
+
input value <=> @name # text input
|
|
935
|
+
input type: "number", value <=> @age # number input
|
|
936
|
+
input type: "checkbox", checked <=> @agree # checkbox
|
|
937
|
+
p "#{@name}, age #{@age}, agreed: #{@agree}"
|
|
938
|
+
```
|
|
939
|
+
|
|
940
|
+
`value <=> @name` compiles to two things:
|
|
941
|
+
1. **State → DOM**: an effect that sets `el.value = name` whenever `name` changes
|
|
942
|
+
2. **DOM → State**: an event listener that sets `name = e.target.value` on input
|
|
943
|
+
|
|
944
|
+
The compiler auto-detects types:
|
|
945
|
+
- Text inputs use the `input` event and `e.target.value`
|
|
946
|
+
- Number/range inputs use `e.target.valueAsNumber`
|
|
947
|
+
- Checkboxes use the `change` event and `e.target.checked`
|
|
948
|
+
|
|
949
|
+
### With Components
|
|
950
|
+
|
|
951
|
+
`<=>` works with custom components using the same syntax:
|
|
952
|
+
|
|
953
|
+
```coffee
|
|
954
|
+
export App = component
|
|
955
|
+
@selected := 'viewer'
|
|
956
|
+
@showDialog := false
|
|
957
|
+
@darkMode := false
|
|
958
|
+
|
|
959
|
+
render
|
|
960
|
+
Select value <=> @selected
|
|
961
|
+
Option value: "viewer", "Viewer"
|
|
962
|
+
Option value: "editor", "Editor"
|
|
963
|
+
Option value: "admin", "Admin"
|
|
964
|
+
Switch checked <=> @darkMode, "Dark mode"
|
|
965
|
+
Dialog open <=> @showDialog
|
|
966
|
+
p "Are you sure?"
|
|
967
|
+
p "Role: #{@selected}"
|
|
968
|
+
```
|
|
969
|
+
|
|
970
|
+
The parent owns the state. The child reads it and writes back to it. No
|
|
971
|
+
callback props, no `onChange` handlers, no `onOpenChange`, no `setValue`.
|
|
972
|
+
|
|
973
|
+
### Why This Matters
|
|
974
|
+
|
|
975
|
+
React requires explicit `value` + `onChange` pairs for every bindable property.
|
|
976
|
+
This is the "controlled component" pattern — the single most tedious aspect of
|
|
977
|
+
React development:
|
|
978
|
+
|
|
979
|
+
```jsx
|
|
980
|
+
// React: 8 lines of wiring for 4 controls
|
|
981
|
+
const [name, setName] = useState('');
|
|
982
|
+
const [role, setRole] = useState('viewer');
|
|
983
|
+
const [notify, setNotify] = useState(true);
|
|
984
|
+
const [show, setShow] = useState(false);
|
|
985
|
+
|
|
986
|
+
<input value={name} onChange={e => setName(e.target.value)} />
|
|
987
|
+
<Select value={role} onValueChange={setRole} />
|
|
988
|
+
<Switch checked={notify} onCheckedChange={setNotify} />
|
|
989
|
+
<Dialog open={show} onOpenChange={setShow} />
|
|
990
|
+
```
|
|
991
|
+
|
|
992
|
+
Rip eliminates all of it:
|
|
993
|
+
|
|
994
|
+
```coffee
|
|
995
|
+
# Rip: 4 state declarations, 4 bindings, zero callbacks
|
|
996
|
+
@name := ''
|
|
997
|
+
@role := 'viewer'
|
|
998
|
+
@notify := true
|
|
999
|
+
@show := false
|
|
1000
|
+
|
|
1001
|
+
input value <=> @name
|
|
1002
|
+
Select value <=> @role
|
|
1003
|
+
Switch checked <=> @notify
|
|
1004
|
+
Dialog open <=> @show
|
|
1005
|
+
```
|
|
1006
|
+
|
|
1007
|
+
Vue has `v-model`. Svelte has `bind:`. But Rip's `<=>` is cleaner — it works
|
|
1008
|
+
uniformly across HTML elements and custom components with the same syntax, the
|
|
1009
|
+
same operator, and the same mental model. No framework-specific directives, no
|
|
1010
|
+
special component protocol. Just a reactive binding that flows both ways.
|
|
1011
|
+
|
|
1012
|
+
### Auto-Detection
|
|
1013
|
+
|
|
1014
|
+
Even without `<=>`, the compiler auto-detects when `value:` or `checked:` is
|
|
1015
|
+
bound to a reactive expression and generates two-way binding automatically:
|
|
1016
|
+
|
|
1017
|
+
```coffee
|
|
1018
|
+
# These are equivalent:
|
|
1019
|
+
input value <=> @name # explicit
|
|
1020
|
+
input value: @name # auto-detected (name is reactive)
|
|
1021
|
+
```
|
|
1022
|
+
|
|
918
1023
|
---
|
|
919
1024
|
|
|
920
1025
|
# 7. Async Patterns
|
|
@@ -1545,6 +1650,10 @@ a =~ /pat/ # regex match, captures in _
|
|
|
1545
1650
|
a[/pat/, 1] # regex extract
|
|
1546
1651
|
a? # existence check (a != null)
|
|
1547
1652
|
a ?? b # nullish coalescing
|
|
1653
|
+
|
|
1654
|
+
# Two-way binding (render blocks)
|
|
1655
|
+
input value <=> @name # bidirectional reactive binding
|
|
1656
|
+
Dialog open <=> @show # works with components too
|
|
1548
1657
|
```
|
|
1549
1658
|
|
|
1550
1659
|
## File Templates
|