Skip to content

V0.4.0 #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 56 commits into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
4d70d90
wip - store revisions
kennyfrc Jun 21, 2024
cd59845
wip - more revisions
kennyfrc Jun 21, 2024
f8ce896
wip - invariant update
kennyfrc Jun 21, 2024
a802c2b
fix - query key
kennyfrc Jun 21, 2024
0bfe9d8
wip - fixes query key bug
kennyfrc Jun 21, 2024
c4dd4b9
wip - new slice mechanism - some tests fixed
kennyfrc Jun 22, 2024
7f58288
wip - store state
kennyfrc Jun 22, 2024
eaf277c
wip - slice improvements
kennyfrc Jun 23, 2024
49778b9
wip - call it model
kennyfrc Jun 24, 2024
6e8ec45
wip - fix fsm
kennyfrc Jul 1, 2024
baa7582
wip - comments
kennyfrc Jul 1, 2024
5d92a88
wip - better validation
kennyfrc Jul 1, 2024
23a0ace
wip - improve api
kennyfrc Jul 2, 2024
cbb6ed1
wip - update api
kennyfrc Jul 2, 2024
3e975c9
wip - add trigger, memo to store
kennyfrc Jul 14, 2024
102072f
wip - keep it simple - just a store instead of adding slices or models
kennyfrc Jul 15, 2024
292f8af
wip - async actions or thunks
kennyfrc Jul 15, 2024
09a9ec0
wip - improve our thunk
kennyfrc Jul 15, 2024
c98204e
wip - better thunk example (sequential dependencies)
kennyfrc Jul 16, 2024
505966c
wip - defineThunk and dispatchAsync
kennyfrc Jul 16, 2024
9db9f23
wip - cleaner defineMachine, add dispatchAsync to all contexts
kennyfrc Jul 16, 2024
a369838
wip - add examples for thunks
kennyfrc Jul 16, 2024
1e3feb0
wip - make query and mutate thenable
kennyfrc Jul 16, 2024
45ae85a
wip - dispatch tweaks
kennyfrc Jul 16, 2024
8c89e60
wip - cyclic dependency detection
kennyfrc Jul 16, 2024
ac8c231
wip - rename `thunk` to `asyncAction` to make it more newbie friendly…
kennyfrc Jul 17, 2024
9767c80
wip - rollback returning values in actions (not allowed w/ immer)
kennyfrc Jul 17, 2024
a9267ce
wip - better error messages
kennyfrc Jul 22, 2024
af12594
wip - catch undefined actions in dispatch (common in handrolled state…
kennyfrc Jul 23, 2024
101f6e0
wip - hooks and schema
kennyfrc Jul 27, 2024
211610f
wip - types for schema
kennyfrc Jul 28, 2024
30f1e36
wip - gitignore
kennyfrc Jul 28, 2024
66fa849
revert - remove wip code
kennyfrc Jul 28, 2024
554defb
wip - action specs
kennyfrc Jul 28, 2024
4da0b53
wip - tweak postcondition
kennyfrc Jul 28, 2024
de26255
wip - tweak dependent types
kennyfrc Jul 29, 2024
dea54c0
wip - fix dependent sum type
kennyfrc Jul 29, 2024
15588e0
wip - feat(model) - added model, fixed tests
kennyfrc Aug 1, 2024
0eefda8
wip - feat(model) - revise model implementation
kennyfrc Aug 10, 2024
f89a2be
wip - feat(idb) - first cut of idb
kennyfrc Aug 11, 2024
dea729f
wip - refactor(idb), feat(localStorage) - improve code readability of…
kennyfrc Aug 12, 2024
cec544a
wip - tests - add tests for idb and localstorage
kennyfrc Aug 12, 2024
91f5c17
wip - fix(tests) - localStorage
kennyfrc Aug 12, 2024
54974fe
wip - refactor(localStorage) - improve ls api
kennyfrc Aug 12, 2024
a456ef3
wip - fix(hooks) - type revisions work in prod but tests need to be u…
kennyfrc Aug 12, 2024
5371172
wip - style - just use default prettier moving forward
kennyfrc Aug 13, 2024
98577b6
wip - refactor(tests) - use our own test suite instead of jasmine
kennyfrc Aug 14, 2024
cf74a8c
wip - style - prettier
kennyfrc Aug 14, 2024
ce7f2df
wip - fix(types) - allow partial validation
kennyfrc Aug 14, 2024
47156da
wip - refactor(tests) - just change state to getState()
kennyfrc Aug 14, 2024
c93e61b
wip - fix(state-machine) - address various state machine bugs and add…
kennyfrc Aug 14, 2024
90ef7bc
wip - feat(url-store) - our client-side router alternative: reactive …
kennyfrc Aug 14, 2024
bab63cc
wip - refactor(url-store) - same interface as observable store. can n…
kennyfrc Aug 20, 2024
f2699d4
wip - refactor(url-store) - improve title defaults
kennyfrc Aug 25, 2024
79b888c
wip - feat(reactive-element) - new interaction context in elementf
kennyfrc Sep 2, 2024
c3e72d7
wip - chore - doc updates
kennyfrc Sep 2, 2024
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
7 changes: 5 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -181,6 +181,9 @@ out
/examples/build

package-lib.json
src/scratch.js
src/scratch*.js
src/spike.js
src/test.js
src/test*.js
src/assert.js
src/runner.js
.aider*
60 changes: 29 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -2,9 +2,9 @@

⚠️ Expect API changes until v1.0.0 ⚠️

Current version: 0.3.23.
Current version: 0.4.0

Bundle Size: 14kb minified & gzipped.
Bundle Size: 15kb minified & gzipped.

A simple yet powerful toolkit for interactive islands in web applications. No build step required.

@@ -20,7 +20,7 @@ Note that Cami specializes in bringing rich interactivity to your web applicatio
const { html, ReactiveElement } = cami;

class CounterElement extends ReactiveElement {
count = 0
count = 0;

template() {
return html`
@@ -31,21 +31,21 @@ Note that Cami specializes in bringing rich interactivity to your web applicatio
}
}

customElements.define('cami-counter', CounterElement);
customElements.define("cami-counter", CounterElement);
</script>
```

[Documentation](https://camijs.com/) | [API Reference](https://camijs.com/api/) | [CDN Link](https://unpkg.com/cami@latest/build/cami.cdn.js) | [Introduction](https://camijs.com/)

## Learn By Example

* [Counter](https://camijs.com/learn_by_example/counter/)
* [Interactive Registration Form](https://camijs.com/learn_by_example/form_validation/)
* [Todo List with Server State Management](https://camijs.com/learn_by_example/todo_list_server/)
* [Cart with Client & Server State Management](https://camijs.com/learn_by_example/cart/)
* [Blog with Optimistic UI](https://camijs.com/learn_by_example/blog/)
* [Nested Key Updates](https://camijs.com/learn_by_example/nested_updates/)
* [WAI-ARIA Compliant Modal](https://camijs.com/learn_by_example/modal/)
- [Counter](https://camijs.com/learn_by_example/counter/)
- [Interactive Registration Form](https://camijs.com/learn_by_example/form_validation/)
- [Todo List with Server State Management](https://camijs.com/learn_by_example/todo_list_server/)
- [Cart with Client & Server State Management](https://camijs.com/learn_by_example/cart/)
- [Blog with Optimistic UI](https://camijs.com/learn_by_example/blog/)
- [Nested Key Updates](https://camijs.com/learn_by_example/nested_updates/)
- [WAI-ARIA Compliant Modal](https://camijs.com/learn_by_example/modal/)

## Key Concepts:

@@ -65,34 +65,34 @@ To use it, you'll need to create a custom element and register it with `customEl
<script src="https://unpkg.com/cami@latest/build/cami.cdn.js"></script>
<article>
<h1>Counter</h1>
<counter-component
></counter-component>
<counter-component></counter-component>
</article>
<script type="module">
const { html, ReactiveElement } = cami;

class CounterElement extends ReactiveElement {
count = 0

template() {
return html`
<button @click=${() => this.count--}>-</button>
<button @click=${() => this.count++}>+</button>
<div>Count: ${this.count}</div>
`;
customElements.define(
"counter-component",
class extends ReactiveElement {
count = 0;

template() {
return html`
<button @click=${() => this.count--}>-</button>
<button @click=${() => this.count++}>+</button>
<div>Count: ${this.count}</div>
`;
}
}
}

customElements.define('counter-component', CounterElement);
);
</script>
```

## Features include:

* **Reactive Web Components**: Simplifies front-end web development with `ReactiveElement`. This is done through [Observable Properties](https://camijs.com/features/observable_property). They are properties of a `ReactiveElement` instance that are automatically observed for changes. When a change occurs, the `ReactiveElement` instance is notified and can react accordingly by re-rendering the component. Observable properties support deep updates, array changes, and reactive attributes, making it easier to manage dynamic content. Lastly, this removes the boilerplate of `signal()`, `setState()`, or `reactive()` that you might find in other libraries.
* **Async State Management**: Easily manage server data. Our library provides a simple API for fetching and updating data with [`query` and `mutation`](https://camijs.com/features/async_state_management). Use the `query` method to fetch and cache data, with options to control how often it refreshes. The `mutation` method lets you update data and immediately reflect those changes in the UI, providing a smooth experience without waiting for server responses.
* **Cross-component State Management with Stores**: Share state across different components with ease using a single store using [`cami.store`](https://camijs.com/features/client_state_management). By default, this uses `localStorage` to persist state across page refreshes. This is useful for storing user preferences, authentication tokens, and other data that needs to be shared across components. This is also useful for storing data that needs to be shared across tabs.
* **Streams & Functional Reactive Programming (FRP)**: Handle asynchronous events gracefully with [Observable Streams](https://camijs.com/features/streams/). They offer powerful functions like `map`, `filter`, `flatMap`, and `debounce` to process events in a sophisticated yet manageable way, for clean & declarative code.
- **Reactive Web Components**: Simplifies front-end web development with `ReactiveElement`. This is done through [Observable Properties](https://camijs.com/features/observable_property). They are properties of a `ReactiveElement` instance that are automatically observed for changes. When a change occurs, the `ReactiveElement` instance is notified and can react accordingly by re-rendering the component. Observable properties support deep updates, array changes, and reactive attributes, making it easier to manage dynamic content. Lastly, this removes the boilerplate of `signal()`, `setState()`, or `reactive()` that you might find in other libraries.
- **Async State Management**: Easily manage server data. Our library provides a simple API for fetching and updating data with [`query` and `mutation`](https://camijs.com/features/async_state_management). Use the `query` method to fetch and cache data, with options to control how often it refreshes. The `mutation` method lets you update data and immediately reflect those changes in the UI, providing a smooth experience without waiting for server responses.
- **Cross-component State Management with Stores**: Share state across different components with ease using a single store using [`cami.store`](https://camijs.com/features/client_state_management). By default, this uses `localStorage` to persist state across page refreshes. This is useful for storing user preferences, authentication tokens, and other data that needs to be shared across components. This is also useful for storing data that needs to be shared across tabs.
- **Streams & Functional Reactive Programming (FRP)**: Handle asynchronous events gracefully with [Observable Streams](https://camijs.com/features/streams/). They offer powerful functions like `map`, `filter`, `flatMap`, and `debounce` to process events in a sophisticated yet manageable way, for clean & declarative code.

Please visit our [Documentation](https://camijs.com/), [API Reference](https://camijs.com/api/), [Examples](https://camijs.com/learn_by_example/counter/), or [Core Concepts](https://camijs.com/features/observable_property/) to learn more.

@@ -109,7 +109,6 @@ That said, I like the idea of declarative templates, uni-directional data flow,
- **Lean Teams or Solo Devs**: If you're building a small to medium-sized application, I built Cami with that in mind. You can start with `ReactiveElement`, and once you need to share state between components, you can add our store. It's a great choice for rich data tables, dashboards, calculators, and other interactive islands. If you're working with large applications with large teams, you may want to consider other frameworks.
- **Developers of Multi-Page Applications**: For folks who have an existing server-rendered application, you can use Cami to add interactivity to your application.


## Examples

To learn Cami by example, see our [examples](https://camijs.com/learn_by_example/counter/).
@@ -135,7 +134,6 @@ JSDoc is used to build the API reference. We use Material for MkDocs for the doc

To make JSDoc be compatible with MkDocs, we use jsdoc2md to generate markdown files from JSDoc comments. We use then use MkDocs to build the documentation site.


### Testing

We use Jasmine for testing. To run the tests, run:
5,876 changes: 5,861 additions & 15 deletions build/cami.cdn.js

Large diffs are not rendered by default.

Binary file modified build/cami.cdn.js.gz
Binary file not shown.
8 changes: 4 additions & 4 deletions build/cami.cdn.js.map

Large diffs are not rendered by default.

5,855 changes: 5,840 additions & 15 deletions build/cami.module.js

Large diffs are not rendered by default.

Binary file modified build/cami.module.js.gz
Binary file not shown.
8 changes: 4 additions & 4 deletions build/cami.module.js.map

Large diffs are not rendered by default.

43 changes: 4 additions & 39 deletions build_examples.sh
Original file line number Diff line number Diff line change
@@ -1,38 +1,18 @@
#!/bin/bash
# A ridiculous script to build the example pages
# A script to build the example pages

set -e
set -u

# Directory containing the partials
partials_dir="examples/partials"

# Directory containing the layout
layout_dir="examples/layouts"

# Placeholder for newline characters
newline_placeholder="NEWLINE_PLACEHOLDER"

# Remove all old example files
rm -f examples/*.html

count=0
# Iterate over each file in the partials directory
for file in "$partials_dir"/_*.html; do
# Check if file exists and is readable
if [[ -r "$file" ]]; then
# Read the content of the file, replacing newline characters with the placeholder
content=$(cat "$file" | tr '\n' '\r' | sed "s/\r/$newline_placeholder/g")

# Escape special characters in the content
content=$(echo "$content" | sed -e 's/[\/&]/\\&/g')

# Check if content was read successfully
if [[ $? -ne 0 ]]; then
echo "Error reading file $file"
continue
fi

# Get the base name of the file, without the directory or extension
base_name=$(basename "$file" .html)

@@ -42,27 +22,12 @@ for file in "$partials_dir"/_*.html; do
# Copy the layout file to a new file with the new name
cp "$layout_dir/layout.html" "examples/$new_name.html"

# Check if copy was successful
if [[ $? -ne 0 ]]; then
echo "Error copying layout to examples/$new_name.html"
continue
fi

# Replace the placeholder with the content, then replace the newline placeholder with actual newline characters
escaped_content=$(printf '%q' "$content")
sed -i '' "s#<!-- YIELD -->#$content#g" "examples/$new_name.html"
sed -i '' "s/$newline_placeholder/\\
/g" "examples/$new_name.html"

# Check if sed command was successful
if [[ $? -ne 0 ]]; then
echo "Error replacing placeholder in $new_name.html"
continue
fi
# Use sed to replace the placeholder with the content
sed -i '' -e '/<!-- YIELD -->/r '"$file" -e '/<!-- YIELD -->/d' "examples/$new_name.html"

# If it's the first iteration, show "Building Documentation..."
if [[ $count -eq 0 ]]; then
echo "\n📚 Built Examples:"
echo -e "\n📚 Built Examples:"
fi
echo " ./examples/$new_name.html"

Binary file modified bun.lockb
Binary file not shown.
6 changes: 3 additions & 3 deletions docs/api/console_functions.md
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ The following functions can be invoked in the developer tools console. When you
<dd><p>This function disables logging. This is the default setting.</p></dd>

<dt><a href="#events.enable">cami.events.enable()</a> ⇒ <code>void</code></dt>
<dd><p>This function enables event emissions. This emits the `cami:state:change` event. One can then attach an eventListener to the window to capture this event. This is the default setting.</p></dd>
<dd><p>This function enables event emissions. This emits the `cami:elem:state:change` event. One can then attach an eventListener to the window to capture this event. This is the default setting.</p></dd>

<dt><a href="#events.disable">cami.events.disable()</a> ⇒ <code>void</code></dt>
<dd><p>This function disables event emissions.</p></dd>
@@ -42,12 +42,12 @@ cami.debug.disable();
<a name="events.enable"></a>

### cami.events.enable()
This function enables event emissions. This emits the `cami:state:change` event. One can then attach an eventListener to the window to capture this event. This is the default setting.
This function enables event emissions. This emits the `cami:elem:state:change` event. One can then attach an eventListener to the window to capture this event. This is the default setting.

**Example**
```javascript
cami.events.enable();
window.addEventListener('cami:state:change', function(e) {
window.addEventListener('cami:elem:state:change', function(e) {
console.log('State changed:', e.detail);
});
```
Loading