Skip to content

Commit

Permalink
none working poc, instances are added on each view()
Browse files Browse the repository at this point in the history
  • Loading branch information
sebkolind committed Nov 15, 2023
1 parent d236806 commit db5879d
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 92 deletions.
90 changes: 22 additions & 68 deletions example/app.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { o, mount } from '../dist/one'
import { o, mount, register } from '../dist/one'
import { getItems } from './services/get-items'

const Component = {
Expand All @@ -11,92 +11,46 @@ const Component = {
async onmount ({ data }) {
data.items = await getItems()
},
view ({ data }) {
view () {
return o('div', [
o('h1', 'Items'),
o(List, { items: data.items })
o(List),
o(List, {
items: [
{ id: 1, name: 'Props: Hey!' },
{ id: 2, name: 'Props: Hi!' }
]
})
])
}
}

const List = {
name: 'list',
view ({ props }) {
return o('div', [
o('ul',
props.items.length
? props.items.map(item => o('li', `${item.name}`))
: o('li', 'Loading')
)
])
}
}

const If = {
name: 'if',
data () {
return {
count: 0
items: [
{ id: 1, name: 'Hey!' },
{ id: 2, name: 'Hi!' }
]
}
},
onmount () {
console.log('If mounted')
},
view ({ data }) {
view ({ data, props }) {
return o('div', [
o('h1', 'If'),
o('p', 'Paragraph inside If'),
o('button', data.count ? `Clicked ${data.count} times` : 'Click', {
o('ul', props?.items
? props.items.map(item => o('li', `${item.name}`))
: data.items.map(item => o('li', `${item.name}`))),
o('button', 'Click', {
onclick () {
console.log('clicked')
data.count = data.count + 1
data.items = [...data.items, { id: 3, name: 'Hello!' }]
}
})
])
}
}

const Else = {
name: 'else',
view ({ props }) {
return o('div', [
o('h1', 'Else'),
o('p', `Paragraph inside Else, with prop "name": ${props.name}`),
o('p', 'Another one')
])
}
}

const View = {
name: 'view',
data () {
return {
name: 'Sebastian',
show: true
}
},
view ({ data }) {
return o('div', [
o(Component),
o('p', `Hello ${data.name}`),
o('input', [], {
value: data.name,
name: 'input',
type: 'text',
oninput (e) {
data.name = e.target.value
}
}),
data.show
? o(If, null, { redraw: true })
: o(Else, { name: data.name }, { redraw: true }),
o('button', 'Click to toggle', {
onclick () {
data.show = !data.show
}
})
])
}
}
register(Component)
register(List)

mount(View, document.body)
mount(Component, document.body)
112 changes: 88 additions & 24 deletions lib/one.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
const components = {}

function register (component) {
if (!component.name) {
throw new Error('One.register(): The component must have a name.')
}

if (components[component.name]) {
throw new Error(`One.register(): The component "${component.name}" already exists.`)
}

components[component.name] = {
component,
instances: []
}

return component
}

function o (tag, content, attrs) {
if (Object.prototype.hasOwnProperty.call(tag, 'view')) {
if (content != null && typeof content !== 'object') {
Expand All @@ -8,44 +25,83 @@ function o (tag, content, attrs) {
)
}

if (tag.props) {
const oldProps = tag.props
if (!components[tag.name]) {
throw new Error(`The component "${tag.name}" does not exist. Remember to register it first with the register() function.`)
}

const name = tag.name
const oldProps = content

let component = null

// TODO: This is shit, since each call to `view()` on a component would
// create new instances of nested components..... :(
if (tag?.id) {
// the component is already registered as an instance,
// so we need to grab that instance instead of adding a new one.
console.log('find component', name, tag.id)
// not a big fan of the `find` usage here, but it works for now.
// maybe it's ok for performance, since we don't expect a lot of instances.
component = components[name].instances.find((c) => c.id === tag.id)
} else {
component = { ...components[name].component }

// TODO: Find a better way to generate a unique id.
// Does it have to be a unique random string? Maybe it's find to grab the position in the array?
// But what happens when the array changes? The position will change too.
// component.id = Math.random().toString(36).substring(2, 9)
component.id = `${name}#${components[name].instances.length}`
component.props = content
component.attrs = attrs

components[name].instances.push(component)
}

console.log('render component', component)
// TODO: Find a way to check if the component already exists in the components object
// and if it does, we should add a new instance of the component.
// But how do we know what instance to update?
// Maybe an approach with a register function is a good idea? That gives a bit more control.
// That won't change much, since we still need to know what instance to update. duh.

if (component.props) {
// fix this, it's confusing that `tag` is used here now.
const newProps = content
const keys = Object.keys(oldProps)

const changed = keys.length !== Object.keys(newProps).length ||
keys.some((key) => oldProps[key] !== newProps[key])

if (changed) {
const rendered = tag.view({
data: setupData(tag, attrs),
const rendered = component.view({
data: setupData(component, attrs),
props: content
})
draw(
tag,
component,
rendered
)

tag.props = newProps
tag.attrs = attrs
component.props = newProps

console.log('return rendered with props', component.name)

return rendered
}
}

if (tag.rendered && !attrs?.redraw) {
const cache = tag.rendered.cloneNode(true)
sync(tag.rendered, cache, tag.rendered)
if (component.rendered && !component.attrs?.redraw) {
const cache = component.rendered.cloneNode(true)
sync(component.rendered, cache, component.rendered)
console.log('return cache', component.name)
return cache
}

tag.props = content
tag.attrs = attrs
console.log('render', component.id)
const cmpt = render(component, attrs)
cmpt.onmount()

const component = render(tag, attrs)
component.onmount()

return component.rendered
return cmpt.rendered
}

const el = document.createElement(tag)
Expand All @@ -68,9 +124,9 @@ function render (component, attrs) {
throw new Error('One.render(): The component must have a name.')
}

if (component.rendered && !attrs?.redraw) {
return component
}
// if (component.rendered && !attrs?.redraw) {
// return component
// }

if (typeof component.data === 'function' && !component.dataFn) {
component.dataFn = component.data
Expand All @@ -86,17 +142,16 @@ function render (component, attrs) {
onmount?.({ data: $data, props: component.props })
}

component.rendered = el

el.$one = {
name: component.name,
id: component.id,
isComponent: true,
props: component.props,
attrs
}

component.rendered = el

components[component.name] = component

return component
}

Expand All @@ -114,6 +169,8 @@ function setupData (component, attrs) {
set (target, key, value) {
const s = Reflect.set(target, key, value)

console.log('set', key, value, component)

draw(
component,
component.view({
Expand All @@ -136,6 +193,8 @@ function draw (component, view) {
throw new Error('The component could not be found.')
}

console.log('draw', component.rendered, view)

remove(component.rendered, view.children)
diff(component.rendered, view)
}
Expand All @@ -147,6 +206,8 @@ function diff (dom, view) {
append(dom, view.children)
}

console.log('diff', dom, view)

for (const vn of view.children) {
const dn = dom.children[i]

Expand All @@ -170,6 +231,7 @@ function diff (dom, view) {
}

if (dn.$one?.isComponent && vn.$one?.isComponent) {
console.log('diff component', dn.$one.name, vn.$one.name)
const cmp = components[vn.$one.name]
const rendered = cmp.rendered.cloneNode(true)

Expand Down Expand Up @@ -222,7 +284,9 @@ function sync (from, to, parent) {
})
}

// TODO: This probably doesn't work with the new instances array.
if (components[from.$one?.name]) {
console.log('FIX ME', from.$one.name)
components[from.$one.name].rendered = to
}
}
Expand Down Expand Up @@ -312,4 +376,4 @@ if (process.env.NODE_ENV !== 'production') {
}
}

export { o, render, mount }
export { o, render, mount, register }

0 comments on commit db5879d

Please sign in to comment.