kriszyp / alkali Goto Github PK
View Code? Open in Web Editor NEWAlkali is library for functional reactive data flows that drive native-based UI elements
Home Page: https://kriszyp.github.io/alkali/
License: MIT License
Alkali is library for functional reactive data flows that drive native-based UI elements
Home Page: https://kriszyp.github.io/alkali/
License: MIT License
class Foo extends Div('.foo') {
// @param { Variable.<Boolean>} active
created({active}) {
new ElementRenderer({
element: this,
variable: active,
renderUpdate: (isActive) => {
this.classList.toggle('active', isActive)
this.classList.toggle('inactive', !isActive)
this.classList.toggle('hidden', !isActive)
}
})
}
}
new Foo({ active: new Variable(false) })
Results in
<div class="foo"></div>
Expected
<div class="foo hidden inactive"></div>
let selection = new Variable(new Map())
selection.subscribe((event) => {
console.log('Selection changed:', event.value())
})
selection.set('foo', true)
selection.property('foo').subscribe((event) => {
console.log('Foo changed:', event.value())
})
selection.set('foo', false)
selection.set('foo', 'foo')
selection.property('foo').put(true)
// Logs the following
// Selection changed: Map {}
// Selection changed: Map {"foo" => true}
// Foo changed: true
// Selection changed: Map {"foo" => false}
// Selection changed: Map {"foo" => 'foo'}
// Selection changed: Map {"foo" => true}
selection.property('foo').updated()
// Selection changed: Map {"foo" => true}
// Foo changed: true
Line 108
here outputs a warning:
Unreachable code after return statement
Lines 105 to 110 in 1c29e5e
Is it possible/desirable for maps generated by keyBy to return original variable instances?
class Foo extends Variable<{ Name: string, Id: number }> {}
const Collection = VArray.of(Foo)
const collection = new Collection([{
Name: 'Kerry',
Id: 123
}])
const index = collection.keyBy(model => model.get('Id'))
// fails
assert.strictEqual(index.property(123), collection.property(0))
// fails
assert(index.property(123) instanceof Foo)
let newProps = {
Name: 'Jerry',
Id: 123,
}
index.set(123, newProps)
// fails
assert.strictEqual(collection.get(0), newProps)
let foo = new Variable({'': 'foo'})
foo.get('')
// -> 'foo'
foo.property('').subscribe((event) => {
console.log(event.value())
})
foo.set('', 'wat')
foo.property('').put('does it blend?')
// nothing happens, the subscribed event handler never fires.
This issue came up when using variables to represent selection state hashes, and some (selectable) values come up as empty string.
This works but it also triggers updaters for the entire object, rather than just that 1 property:
foo.set('', 'wat') && foo.property('').updated()
At times I'd like to be able to quickly set up a sandbox for toying around with variables. Being able to import as a Node CommonJS module would be helpful.
Hello, first thank you for all your work on this, hopping this isn't a dumb question.
I'd like to know if a variable has any listeners, or dependent variable using its value, but can't find anything about it or in the variable object. Is there any relatively fast way to do this ?
The fact that promise values are implicitly resolved in transforms largely solves the issue of dealing with them, however there still arises from time to time the case of some downstream consumer eagerly, non-reactively, forcing the resolution of a variable chain, and assuming the value it receives is not a wrapping promise. When the value is not a promise, this works fine and is unremarkable, but if a Promise sneaks into the chain at any point, it can become very difficult to track down and currently requires breaking/bridging the reactivity.
This can be done explicitly with a simple utility, like:
export default (variableYieldingPromise, initialValue) => {
const outputVar = new Variable(initialValue)
variableYieldingPromise.subscribe((e) => {
Promise.resolve(e.value()).then((value) => outputVar.put(value))
})
return outputVar
}
However this is pretty clunky, and non-idiomatic. It would be preferable if there were some idiomatic way to "consume"/coalesce Promises such that we have a guarantee to never see them (at least, never see an initial level of Promises - Promises are self-composable, so I would not expect to see a Promise yielding underlying value that is itself a Promise).
e.g.:
var s = new Variable('z')
var v = s.as(VPromised)
assert.equal(v.valueOf(), 'z')
s.put(new Promise(function (r) {
setTimeout(function() { r('a') }, 100)
}))
assert.equal(v.valueOf(), 'z')
return new Promise(setTimeout).then(function () {
// still initial value
assert.equal(v.valueOf(), 'z')
return new Promise(function (r) { setTimeout(r, 110) }).then(function() {
// should contain resolved value now
assert.equal(v.valueOf(), 'a')
})
})
See #41 for tests illustrating usage, and several unsuccessful stabs at an implementation
This will correctly render as "0" in the element:
Span({ textContent: 0 })
These will create an empty element:
Span({ content: 0 })
Span(0)
Span('.some-class', 0)
In the process of trying to exploit the behavior of "non-proxying" variable assignment for derived/dynamic defaults, as documented here, I noticed that this may not be working.
let sourceVariable = new Variable({foo: 1})
let containingVariable = new Variable(sourceVariable)
sourceVariable.set('foo', 2) // this will propagate down to containingVariable
containingVariable.set('foo', 3) // this will not affect the sourceVariable
containingVariable.get('foo') -> 3
sourceVariable.get('foo') -> 2
Test cases at PR #39
Hey Kris, are you open to a PR augmenting the way alkali is packaged to include native ES6 module support?
import { equal } from 'alkali'
let foo = new Variable('foo')
// Fails
let isFoo: VBoolean = equal(foo, 'foo')
Equivalent to lodash's isEmpty
: https://lodash.com/docs/4.17.4#isEmpty
To simplify code like...
el1 = createThing1()
new PropertyUpdater({variable: variable, element: el1...
el2 = createThing2()
new PropertyUpdater({variable: variable, element: el2...
elN = createThingN()
new PropertyUpdater({variable: variable, element: elN...
It might be nice to support multiple (statically) configured elements in Updaters. There is somewhat related support for specifying a selector, but not an explicit list of elements.
E.g.
new PropertyUpdater({
name: 'disabled',
elements: [e1, e2, e3],
variable: disabledVar
})
I started on a tentative patch, which was mostly a straightforward conversion from operating on this.element
to iterating on this.elements
, but ran into this line that I'm not sure what to do with:
if (!context || context == this.element || context.contains(this.element)) {
I think in this case the intent is to determine whether the passed context "matches" the element configuration of the updater; i'm not sure if that makes sense in the case of multiple elements, or perhaps warrants a more sophisticated check for array inclusion.
ListUpdater would get a bit more complicated since it has state, I suspect that would only require keeping a map of builtList
on element.
Not a high priority, I just wanted to see if it was something that could be done simply and fit with the intent of Updaters (maybe there is a better way to aggregate similar Updaters).
Hello, I'm creating a MyButton class as:
class MyButton extends Div('.my-morphing-button', {
caption: Variable,
close_caption: Variable,
body: Variable,
modal_num: Variable,
}){
created(properties)....
And I want to use modal_num for child Div's class name like:
MyButton.children = [
Div('.morph-button-modal-`${MorphButton.modal_num}`', [ /*doesn't work for class name*/
MorphButton.modal_num /*but works for content*/
])
]
But I can't set desired number to the class name. How to fix it?.. (Is it possible?)
Thanks in advance
For example, to show play icon (we can use spans though)
<i class="icon-play"></i>
Can the property
, get
, and set
methods for object variables be extended to work for Map
data structures?
let selection = new Variable(new Map())
// User selects the `false` value
selection.set(false, true)
selection.get(false)
// -> true
Text inputs are notoriously finicky for detecting changes reliably. I had to supplement the default bindChanges
functionality, as below, to respond to changes without waiting for a blur to occur:
const ADDTL_TEXT_INPUT_CHANGE_EVENTS = [ 'propertychange', 'click', 'keyup', 'input', 'paste']
const textInput = new Variable()
const textInputCtrl = TextInput('.form-control', {
type: 'text',
name: 'name',
created: function() {
// try harder to detect changes eagerly
const updateVar = () => { this.content.put(this['typedValue' in this ? 'typedValue' : 'value'], this) }
for (const type of ADDTL_TEXT_INPUT_CHANGE_EVENTS) {
this.addEventListener(type, updateVar)
}
}
}, this.textInput)
I'm wondering if this could be made configurable, or bindChanges
added to the element prototype?
This not work for me, cannot set src to image.
import {Div, Span, Image, Variable} from 'alkali';
let PromoComp = new Div('.outer', [
Image({src: '/img/wikipedia/wP.png'})
]);
Also, to the document appends <image></image>
, but must <img />
Alkali version - 0.11.7
It seems that it doesn't correctly toggle the HTMLSelectElement.disabled
property.
let strings = new VArray(['foo', 'bar', 'baz'])
let startsWithB = source.filter(v => v[0] === 'b')
strings.splice(1, 1)
strings.valueOf()
// -> ['foo', 'baz']
startsWithB.valueOf()
// -> ['bar, 'baz']
// expected ['baz']
To support fewer transforms/renderers when mutating multiple classes:
let selected = new Variable({
'1': true
})
function buildButton(id) {
Button({
classes: selected.to((selected) => ({
active: !!selected[id],
inactive: !selected[id],
}))
}
this not works:
import { Div, Span } from 'alkali';
// define
class MyComponent extends Div {
}
MyComponent.children = [
Span(MyComponent.property('title')),
];
// init
var el = new MyComponent({
title: 'text for the span',
link: 'a link for a[href]'
});
// console.log(el)
document.body.appendChild( el )
Requesting Fieldset to be added to standard elements.
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.