curvenote / runtime Goto Github PK
View Code? Open in Web Editor NEWCreate variables and components that react to changes in state through user-defined functions. Based on Redux.
Home Page: https://curvenote.dev/runtime
License: MIT License
Create variables and components that react to changes in state through user-defined functions. Based on Redux.
Home Page: https://curvenote.dev/runtime
License: MIT License
PropTypes needs arrays.
const slider = store.dispatch(actions.createComponent(
'slider', 'scope',
{ value: { func: 'x' }, min: { value: 1 } },
{ change: { func: '{"x": value}' } },
));
This should follow the same pattern as #3 for taking an object.
This should simplify the scope/name issue. However, the default behavior should not name the component. Only set the scope.
This is getting overridden in the ink-basic
packages. And components should not have names by default.
transform
, for example, takes an argument scoped within the component.
export const InkRangeSpec = {
name: 'range',
description: 'Range input',
properties: {
value: { type: types.PropTypes.number, default: 0 },
min: { type: types.PropTypes.number, default: 0 },
max: { type: types.PropTypes.number, default: 100 },
step: { type: types.PropTypes.number, default: 1 },
transform: {type: types.PropTypes.string, default: '', args: ['value'], has:{func: true, value: false}}
},
events: {
change: { args: ['value'] },
},
};
This doesn't actually work:
store.dispatch(actions.createComponentSpec(SliderSpec));
It requires you to break it out. The first arg should take a string or an object.
also:
createComponentSpec
--> createSpec
to match #2
This allows for how I wrote the docs. :)
The flatter state is a bit more sensible, will require a few changes in the folder structure, but I think clearer overall.
This would be helpful for the charting functions.
I am not really sure how to get the mapped function.
I want to return this:
() => Math.sin(x)
So that I can:
array.map((x) => [x, func(x)])
Problem is that that requires a function type? And the array doesn't exist on the object, so it can't really be a property remap. :(
Needs more thought.
I'm not sure if this is the correct repo to post this feature request, I'm sorry if it's not, I can repost elsewhere if necessary.
First off, I am very impressed at the concise expressivity iooxa
offers in terms of reactive components, it's very easy and reliable once you understand how it's meant to be used! Awesome work, it's even better than the already great ink-components
predecessor package :-D
I would like to suggest an extension on how variables are handled to make some of them reactive, just like r-display
for example. This would be especially useful for variables that are defined as an aggregate of other variables, in other words are dependent on other variables, which is often useful for complex calculations to store and reuse intermediate results.
Currently, the only way to propagate changes is "top-down": the parent variables must update the children's variables values using the :change
attribute. But this leads to an unnatural writing style in complex applications. This could be improved with a "bottom-up" approach where we directly define inside the children's variables definition what are the parent/dependent variables, similarly to what is done with r-display
.
Let me show an example to clarify: let's say we make an app with 5 r-vars
: a, b, c, the sum of a+b+c and the sum squared.
Here is what we currently need to write:
<script src="https://unpkg.com/@iooxa/article"></script>
<link rel="stylesheet" href="https://unpkg.com/@iooxa/article/dist/iooxa.css">
<div style="display: flex; flex-direction: column">
<r-var name="a" value="1" type="Number"></r-var>
<r-var name="b" value="10" type="Number"></r-var>
<r-var name="c" value="100" type="Number"></r-var>
<r-var name="sum" value="111" type="Number"></r-var>
<r-var name="sum_squared" value="12321" type="Number"></r-var>
<r-input label="a" :value="a" :change="{a: parseFloat(value), sum: parseFloat(value)+b+c, sum_squared: (parseFloat(value)+b+c)**2}"></r-input>
<r-input label="b" :value="b" :change="{b: parseFloat(value), sum: a+parseFloat(value)+c, sum_squared: (a+parseFloat(value)+c)**2}"></r-input>
<r-input label="c" :value="c" :change="{c: parseFloat(value), sum: a+b+parseFloat(value), sum_squared: (a+b+parseFloat(value))**2}"></r-input>
<r-input label="Sum" :value="sum" :change="{sum: value, a: value-b-c, sum_squared: value**2}"></r-input> <!-- Simply change one variable so that the input sum is correct -->
<r-input label="Sum squared" bind="sum_squared"></r-input>
</div>
Beside the issues with parseFloat
which I mentioned in another issue elsewhere, the current approach leads to a lot of redundancy. Basically, the children r-var
sum
needs to be redefined inside each parent r-var
's :change
attribute, with pretty much the same code copy/pasted except that the current parent variable becomes value
. Not only that, but all children of sum
itself, such as sum_squared
here, also need to be redefined at the level of each parents at all levels, hence here in both a, b, c and sum. We have only a 3 level depth tree here, the more depth the more redundancy.
Here is my "bottom-up" suggestion:
<script src="https://unpkg.com/@iooxa/article"></script>
<link rel="stylesheet" href="https://unpkg.com/@iooxa/article/dist/iooxa.css">
<div style="display: flex; flex-direction: column">
<r-var name="a" value="1" type="Number"></r-var>
<r-var name="b" value="10" type="Number"></r-var>
<r-var name="c" value="100" type="Number"></r-var>
<r-var name="sum" value="a+b+c" type="Number"></r-var>
<r-var name="sum_squared" value="sum**2" type="Number"></r-var>
<r-input label="a" :value="a" :change="{a: parseFloat(value)}"></r-input>
<r-input label="b" :value="b" :change="{b: parseFloat(value)}"></r-input>
<r-input label="c" :value="c" :change="{c: parseFloat(value)}"></r-input>
<r-input label="Sum" :value="sum" :change="{a: value-b-c}"></r-input> <!-- Simply change one variable so that the input sum is correct -->
<r-input label="Sum squared" bind="sum_squared"></r-input>
</div>
As you can see now the aggregate variables, sum
and sum_squared
, are now defined directly in r-var
. The idea is that the value of sum should always reflect a+b+c
. Hence in the :change
attribute of the r-input
of sum
, we do not need to update the value of sum
as it is always defined by the sum of a+b+c
, we only need to change one of these parent variables (here I chose a
for the sake of this example). Also I guess that in the runtime, if we make something reactive, it's then tied to these variables, so I guess that trying to set {sum: value}
wouldn't work anyway.
So to summarize, sum
and sum_squared
are in this case a bit different variables than the standard r-var
: whereas the r-var
are meant to be directly set by user inputs, sum
and sum_squared
are only indirectly set, and are directly tied to other r-vars
. That's why I call them "aggregate variables". In the above example I used :value="a+b+c"
to define the dependency to the parents, but if it's simpler from an implementation standpoint to use a differently named attribute I see no issue.
About potential issues: it seems infinite recursion may be possible when updating reactive aggregate variables. In the example above, updating r-var
a
should update sum
but then in cascade it should also update sum_squared
. We could imagine two aggregates variables like: <r-var name="b1" value="a*b2"></r-var>
and <r-var name="b2" value="a*b1"></r-var>
with r-var a
being a standard r-var
that can be set with a r-input
for example. Updating a
would trigger an infinite loop between b1
and b2
in theory. I'm honestly not very experienced with javascript so I don't know how reactivity works technically, so I'm not sure how this could be handled, maybe with a list of variables to update to ensure the cascading only updates each children variable once when a
is updated? Or just throw an error, that would work too.
Maybe this is not possible to implement, so in that case please disregard this ticket :-) It just spawned from my experiments to see how far iooxa
could go, and as I found it can be used to make not just explorable explorations but even calculators and probably more when combined with custom javascript (or Brython) :-) The root of my thought started as very simple question, I was just wondering why I could not store a r-var
for an intermediate result just like values of r-display
while keeping the reactivity. In the end, as you can see in the concrete case that is the calculator I linked above, I used a mix of the first approach of duplicating code in all parent r-vars
' inputs, and of avoiding the declaration of unnecessary intermediate resultst r-vars
to minimize the depth of the dependency tree.
In ink-chart it is nice to have nextColor()
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.