socketsupply / components Goto Github PK
View Code? Open in Web Editor NEWExample Components (Built with Tonic)
Home Page: https://tonicframework.dev
License: MIT License
Example Components (Built with Tonic)
Home Page: https://tonicframework.dev
License: MIT License
calling reRender breaks the button, adding some internal css to the value of the button
Currently windowed
reads & renders from this.rows
which is an array.
By changing that to an interface it can be swapped to by anything that's a synchronous API like C++ or lmdb
I am using the TonicChart component. It renders well.
I am trying to make a change programmatically, e.g. changing the width via
document.getElementsByTagName('tonic-chart')[0].reRender({'width': '400px', 'height': '600px', 'src': '{"labels":["Foo","Bar","Bazz"],"datasets":[{"label":"Quxx (millions)","backgroundColor":["#c3c3c3","#f06653","#8f8f8f"],"data":[278,467,34]}]}'})
The component does not render anymore.
Here is a self-contained HTML page that contains the TonicChart code (mostly unchanged).
I have just hardcoded the chart.js and forced the data to be read from the src
attribute.
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script type="module">
import Tonic from './@socketsupply/tonic/index.js'
export class TonicChart extends Tonic {
static stylesheet () {
return `
tonic-chart {
display: inline-block;
position: relative;
}
tonic-chart canvas {
display: inline-block;
position: relative;
}
`
}
draw (data = {}, options = {}) {
const root = this.querySelector('canvas')
const type = this.props.type || options.type
if (!this.Chart) {
console.error('No chart constructor found')
return
}
return new this.Chart(root, {
type,
options,
data
})
}
async redraw () {
return this.connected()
}
async fetch (url, opts = {}) {
if (!url) return {}
try {
const res = await window.fetch(url, opts)
return { data: await res.json() }
} catch (err) {
return { err }
}
}
async connected () {
let data = null
this.Chart = Chart // hard-coded
if (!this.Chart) return
const options = {
...this.props,
...this.props.options
}
const src = this.props.src
console.log(src)
/*
if (typeof src === 'string') {
const response = await this.fetch(src)
if (response.err) {
console.error(response.err)
data = {}
} else {
data = response.data
}
}
if (src === Object(src)) {
console.log('object')
data = src
}
*/
data = JSON.parse(src)
console.log(data)
if (data && data.chartData) {
throw new Error('chartData propery deprecated')
}
if (data) {
this.draw(data, options)
}
}
render () {
const {
width,
height
} = this.props
this.style.width = width
this.style.height = height
return this.html`
<canvas ...${{ width, height }}>
</canvas>
`
}
}
Tonic.add(TonicChart, 'tonic-chart');
</script>
</head>
<body>
This is a test.
<tonic-chart
width="500px"
height="250px"
src='{"labels":["Foo","Bar","Bazz"],"datasets":[{"label":"Quxx (millions)","backgroundColor":["#c3c3c3","#f06653","#8f8f8f"],"data":[278,467,34]}]}'
type="line">
</tonic-chart>
</body>
</html>
<tonic-chart
type="line"
width="600"
height="150px"
options="${opts}"
src="./chartdata.json">
</tonic-chart>
The value of options
when passed to the component is {0: '$', 1: '{', 2: 'o', 3: 'p', 4: 't', 5: 's', 6: '}'
instead of the value of opts
.
I have tried with backsticks and I am getting the same result.
Am I missing something?
Thanks for the tonic and components libraries! I really like them!
I have a problem on desktop Chrome (Version 75.0.3770.142 (Official Build) (64-bit) on Mac) where clicking on a tonic-input sometimes doesn't register. I have to 'search' around the input area with my mouse before the cursor will turn into a type cursor, and I am able to click into the input and start typing.
After some digging around, it turns out that an inline-toaster component, which is disabled, that I placed right before the input in the document, is somehow getting in the way and making it difficult to click into the input. Perhaps best shown with a screenshot:
In the above screenshot, trying to click into the input in the upper-half of the input won't work, i.e., clicking into the green area of the screenshot no workie. Turns out the div.tonic--main
component highlighted in the screenshot is part of the inline-toaster component.
Here's the relevant markup:
return `
<h3>Create a new note:</h3>
<tonic-toaster-inline id=error-toast type=danger dismiss=true
display=${error ? 'true' : 'false'}>
${error}
</tonic-toaster-inline>
<form name="new_note" action=${ROOT}api/notes method=post>
<tonic-input
label="Note"
type=text
id=note_body
name=note
placeholder="Enter your note"
spellcheck=false>
</tonic-input>
<tonic-button async=true id=note_submit>
Submit
</tonic-button>
</form>
I'm using tonic v9.0.5 of tonic and v5.2.4 of components.
Thanks in advance for any help!
To prevent any collisions with user css, all classes used internally should be prefixed in the following format...
.library--component--classname
For example...
.tonic--windowed--outer
Actual reference here
We should allow a build option where instead of the styles being inlined with the component and attached to a style element at runtime, they can be compiled to a single build artifact. This way the user can include the css any way they want and we can take better advantage of caching.
When using the windowed component to create a table, it can be useful to allow text selection to copy content from the scrollview.
This would only be useful for some tables / windowed sub classes.
A way to reproduce this is for example:
<form name="new_note" action=/api/notes method=post>
<tonic-input
label="Note"
type=text
id=note_body
name=note
placeholder="Enter your note"
spellcheck=false>
</tonic-input>
<tonic-button async=true id=note_submit>
Submit
</tonic-button>
</form>
And then have this code in the click handler:
click (evt) {
// TODO: a problem here when you enter double quotes - upon submitting the
// input text gets cut off at the double quote. weird.
if (Tonic.match(evt.target, 'tonic-button#note_submit')) {
const note_body = this.root.querySelector('#note_body');
const submit = this.root.querySelector('#note_submit');
if (note_body.value.length === 0) {
note_body.setInvalid('Note cannot be empty!');
evt.preventDefault();
submit.loading(false);
return;
}
note_body.setValid();
}
}
If you enter a value into the input that contains a double quote, say my"note
, and click the button, you'll notice that before the form POST
s to the server, the note content will cut off at the double quote. I dug around a bit and it turns out that it's caused by the call to setValid()
. That eventually routes to code inside the tonic repo, and in particular, here: https://github.com/heapwolf/tonic/blob/master/index.js#L129
The content
variable returned by the above line contains the HTML for the input and the double quote is not being escaped inside the <input>
tag value
attribute. So upon calling setValid()
, the input inside tonic-input looks something like <input type="text" value="my"note />
- and so the rest of the note gets cut off.
When there is no icon there should be no padding to accommodate it on the right hand side of the input.
I was trying to get tonic-dialog to work in a declarative way instead of in a sub class way
For example
class InlineDialog extends Dialog {
render () {
return this.html`
${this.childNodes}
`
}
}
Tonic.add(InlineDialog)
For the dialog really all I wanted was to just to <tonic-dialog><div>...</div></tonic-dialog>
However the implementation of tonic-dialog is completely different to the implementation of every other component because it uses the DOM api to build nodes instead of HTML and thus doesn't get to benefit from any of the _prop or _placehold logic in tonic.
Adding render="false"
as a prop should allow the user to decide if they want the dialog to render before show is called.
Tonic is ESM already. We want components to be ESM as well
I noticed this when adding a checkbox inside of an inline-toaster.
I couldn't find any way to close a split run, calling toggle()
sometimes opens it
I ended up doing
const splitRun = document.querySelector('#split-run')
if (splitRun) {
const isOpen = splitRun.right.style.width && splitRun.right.style.width !== '0px'
if (isOpen) {
splitRun.toggle('right')
}
}
First check if its open and only if its open call toggle
to close it. cc @heapwolf
Today I noticed that calling reRender()
synchronously from an event handler has suprising behavior.
I have a change
handler on a tonic-input
to do validation when the input value changes.
By calling reRender()
on my component to update the errorMessage
on tonic-input
I actually mess with the focus / blur state of the tonic-input
component.
The order of events is :
change
; => reRenderreRender
=> TonicInput#setEvents()
=> focus()
blur
event but input.focus()
is already called so i am still focused on the input even though i clicked awayblur
fires; working as expected.Basically the DOM is firing a series of events in an order that makes sense to the browser ['change', 'blur']
and by mutating innerHTML
or re-rendering components synchronously in one of those event handlers can cause all kinds of weird side effects that break the flow of events.
Change the behavior of reRender()
to schedule the re-render in the request animation frame. Add a new method called reRenderSync()
to force reRender right now if that's the desired behavior.
We could use some "magic" to only schedule a reRender()
in request animation frame if we are currently inside an event handler by setting a global boolean in handleEvent()
; this means that reRender()
becomes reRenderSync()
if called outside of an event handler.
I want to host my Tonic app using static file hosting, so I can't have users request paths that don't really exist (actually I am experimenting with web extensions, so it's not really hosted at all). That's why I keep my application paths inside the hash fragment of the URL. I can't get TonicRouter to match these, though.
Initially I only got a blank page (so not even the none
router matched), but I managed to resolve that using the pushState
-hack. but still, I am not able to get it to match the itworks-router.
Is this intended?
import Tonic from '@socketsupply/tonic';
import {TonicRouter} from '@socketsupply/components/router';
class MWE extends Tonic {
connected () {
window.history.pushState({},"", window.location); // HACK
this.addEventListener('match', this.reRender);
}
render () {
return this.html`
<tonic-router id="itworks-router" path="/#/itworks">
it works
</tonic-router>
<tonic-router id="notfound-router" none>
it at least sort of works
</tonic-router>
`;
}
}
Tonic.add(TonicRouter);
Tonic.add(MWE);
document.body.innerHTML = '<m-w-e id="container"></m-w-e>';
If checked
attribute isn't specified, the client event does not appear to fire when the label is clicked.
Make height of dialog automatically adjust to content if height="auto"
.
would be nice to have docs around that in the readme so that I can send PRs more easily ๐
and i could even try to set up CI for it
I use multiple tonic-button
s as part of a larger component, and for this parent component's click handler, I want to figure out which button got clicked. Since the id
attribute doesn't seem to get passed along to the final button
element created, I can't use e.target.matches
, as per tonic event docs to determine which button got clicked.
Also the tonic-button
properties lists out id
as a property.
If I'm doing it wrong, please let me know :D if not, I can try my hand at a PR! lemme know
If a tonic-input
does not have an id
attribute then when you type in it and re-render the component the text that was typed is lost.
You need to add an id
attribute to tonic-input
a pattern we've noticed is that we have a <section class="scrollable">...</section>
tag in some places with the appropriate overflow set on it. The scrollTop
position often needs to be remembered, a component that had this in its state would be useful.
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.