Minimally viable DOM Document implementation for NativeScript.

Overview

DOMiNATIVE

NPM

Minimally viable DOM Document implementation for NativeScript

NOTE THIS IS STILL EXPERIMENTAL.


Installation

Via npm:

npm install dominative


Usage

Vanilla

app.js

import { Application } from '@nativescript/core'
import { document } from 'dominative'

const frame = document.createElement('Frame')
const page = document.createElement('Page')
const actionBar = document.createElement('ActionBar')

actionBar.title = 'Hello World!'

page.appendChild(actionBar)
frame.appendChild(page)

Application.run({
	create: () => frame
})

with ef.js

Playground

App.eft

>Frame#root
	>Page
		>ActionBar
			#title = Hello World!
			>ActionBarItem
				#text = Button
		>StackLayout
			>Label
				.Welcome to the wonderland of ef.native!

app.js

import { Application } from '@nativescript/core'
import { domImpl } from 'dominative'
import { setDOMImpl } from 'ef-core'
import App from 'App.eft'

setDOMImpl(domImpl)

const app = new App()

Application.run({
	create: () => app.$refs.root
})

with SingUI

Playground

app.js

import { Application } from '@nativescript/core'
import { document } from 'dominative'
import { browser, prop, setGlobalCtx, useTags, useElement, build } from 'singui'

global.document = document

setGlobalCtx(browser())

const tags = useTags(false)

const app = () =>
	build(() => {
		const { Frame, Page, ActionBar, NavigationButton, ActionItem, StackLayout, Label, Button } = tags

		let frameElement = null

		Frame(() => {
			frameElement = useElement()
			Page(() => {
				ActionBar(() => {
					prop.title = 'Hello World!'
				})
			})
		})

		return frameElement
	})

Application.run({
	create: () => app(),
})

with React + react-dom

Playground - by Ammar Ahmed

Note: This demo might have some issues with Chrome. Use Firefox if necessary.

Register Elements

import { RadSideDrawer } from 'nativescript-ui-sidedrawer'
import { RadListView } from 'nativescript-ui-listview'
import { registerElement, makers } from 'dominative'

// If you cannot determin what the component is based on, you can register it directly.
registerElement('RadSideDrawer', RadSideDrawer)
// Register with a specific type by using a pre-defined maker. Usually we check for inheritance, but with force we can make magic happen
registerElement('RadListView', makers.makeListView(RadListView, {force: true}))

Pseudo Elements

Pseudo elements are not real elements, but they appear as DOM elements to help organize composition.

Prop

Helper to put it's child/children to it's parent node's property by key

Attributes:

key: String: RW The prop name to set on parent.

type: <'array'|'single'>: RW Property type, could be an array prop or a single object prop.

value: any: RW Value to be set to parent. Usually children of this current node. Don't touch unless you know what you're doing.

parent: Element: R Parent node of this node.

class: String: RW Helper to set key and type, could be key:type or multi.level.key:type

Events:

None.

Template

A Template element holds a template to be replicated later, or can create views programmatically.

Attributes:

Share mostly from Prop. Differences are listed below:

key: String: RW Same form Prop, also serves the key name of a KeyedTemplate

type: 'single': R Should not be able to set type on a Template.

value: Function<T extends ViewBase>: R Same as createView.

content: <T extends ViewBase>: RW The single child of this node. Don't touch unless you know what you're doing.

patch: Function<T extends ViewBase>(PatchOptions): R Method to patch an existing clone.

createView: Function<T extends ViewBase>: R Function to create view from this template.

Events:

itemLoading: Triggered when patching. Set event.patched to true to skip default patching method, set event.view to change the view of this item. Additional props on event: view, index, item, data.

createView: Triggered when creating view from the template. Set created view to event.view. If not set, view will be created by cloning the template.

Note:

Template element could only have one element child. If you'd like to have multiple children in a template, just use a different type of view or layout as the only child and insert your other contents inside.

KeyedTemplates

By simpling putting Templates inside an array Prop we could set up a KeyedTemplate.

Example:

<ListView itemTemplateSelector="$item % 2 ? 'odd' : 'even'">
	<Prop key="itemTemplates" type="array">
		<Template key="odd">
			<Label text="odd"/>
		</Template>
		<Template key="even">
			<Label text="even"/>
		</Template>
	</Prop>
</ListView>

Template Handling for Custom Components

There's a special maker caller makeTemplateReceiver, which you can use when the NativeScript component accepts templates.

Example:

import { RadListView } from 'nativescript-ui-listview'
import { registerElement, makers } from 'dominative'

registerElement('RadListView', makers.makeTemplateReceiver(RadListView, {
	templateProps: ['itemTemplate'],
	loadingEvents: ['itemLoading']
}))

templateProps: Array<String>: Props that accepts a template. Do not write keyed template props.

loadingEvents: Array<String>: Events that will fire on the component when items loading.

Helper(s)

import { aliasTagName } from 'dominative'

const tagNameConverter = (CamelCaseName) => {
	// ...whatever your transformation code here
	// This is useful when your framework/renderer doesn't support document.createElement with uppercase letters.
	return transformedName
}

// Convert all built-in tag names
aliasTagName(tagNameConverter)

Caveats

Event Handling

Since NativeScript uses addEventListener and removeEventListener as event handling method names as well as HTML DOM which are causes naming conflicts, we should tell DOMiNATIVE to register event handlers as DOM behavior by explicitly adding a third option:

element.addEventListener('someEvent', callback, {mode: 'DOM'})
element.removeEventListener('someEvent', callback, {mode: 'DOM'})

without the mode: 'DOM' option, DOMiNATIVE will pass the event register operation to the original NativeScript implementation.

In DOM mode, your event callback function will receive a DOM-like Event object instead of the NativeScript data object. The original data object will be placed at event.data in most cases.

License

MIT

You might also like...

Using Htmx, ASP.NET Core, and Marten (postgres document db) to sort list

Using Htmx, ASP.NET Core, and Marten (postgres document db) to sort list

Feb 16, 2022

Lightweight (zero dependencies) library for enabling cross document web messaging on top of the MessageChannel API.

Lightweight (zero dependencies) library for enabling cross document web messaging on top of the MessageChannel API.

Jul 15, 2022

A tool to document your package.json scripts

A tool to document your package.json scripts

why A tool to document your package.json scripts Why why? As your project grows you add more scripts to package.json. When a new member joins the proj

Sep 22, 2022

Apinto document project, which includes the use tutorials, development documents and other related contents of apinto.

apinto-docs Apinto document project, which includes the use tutorials, development documents and other related contents of apinto. README 本文档由 VuePres

Dec 1, 2022

This template is for generating a .NET C# wrapper for the RabbitMQ client based on your AsyncAPI document.

This template is for generating a .NET C# wrapper for the RabbitMQ client based on your AsyncAPI document.

.NET C# RabbitMQ template This is a .NET C# RabbitMQ template for the AsyncAPI generator This template is for generating a .NET C# wrapper for the Rab

Dec 21, 2022

Harassment Manager is a web application that aims to empower users to document and take action on abuse targeted at them on online platforms.

Harassment Manager Online abuse and harassment silence important voices in conversation, forcing already marginalized people offline. Harassment Manag

Dec 6, 2022

WordPress Gutenberg plugin to display the attributes for the currently selected block in the Document sidebar.

WordPress Gutenberg plugin to display the attributes for the currently selected block in the Document sidebar.

Block X-ray Attributes Stable Tag: 1.2.0 Requires at least: 5.5 Tested up to: 5.9 Requires PHP: 7.2 License: GPL v2 or later Tags: block attributes, g

Mar 18, 2022

A tool to document your package.json scripts

A tool to document your package.json scripts

why A tool to document your package.json scripts Why why? As your project grows you add more scripts to package.json. When a new member joins the proj

Sep 22, 2022

Syncronize a YJS document to/from a plain old javascript object

y-pojo Syncronize a YJS document to/from a plain old javascript object This library enables multiple users to share state in the form of a Plain ol' J

Nov 12, 2022
Comments
  • Some questions about DOMINATIVE

    Some questions about DOMINATIVE

    Hi @ClassicOldSong I love what you people are working on. I have some questions though about this implementation.

    1. What is the scope of this implementation, I know you have shown some examples with ui frameworks but can it be used to fully replace the DOM & use it with any framework such as SolidJS?

    2. I would love to know what you are planning to finally do with this, I can help out with the implementation where possible. NativeScript with a good but minimal dom implementation could really help focus on just one DOM that could run any framework.

    3. The performance can be a big challenge as this adds some extra overhead obviously, however it's possible to minimize it as much as possible by keeping the DOM layer as if it was a proxy between Native Views and the UI Framework which I think you are already doing.

    Anyways this is awesome work.

    opened by ammarahm-ed 43
  • register custom components

    register custom components

    Now you can register any custom component with just:

    import { ListView } from "@nativescript/core";
    
    declare module "dominative" {
      interface NSCustomComponentsMap {
        NSList: ExtendWithCustomEventHandlers<typeof ListView, ListView>;
      }
    }
    
    opened by ammarahm-ed 0
Owner
SudoMaker
Make it so.
SudoMaker
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
NativeScript + Tailwind CSS + Angular Mobile Starter

NativeScript + Tailwind CSS + Angular Mobile Starter This repo is a small starting point for building a native iOS and Android app with Tailwind CSS,

Johan Ljungdahl 6 Nov 4, 2022
Custom Vitest matchers to test the state of the DOM, forked from jest-dom.

vitest-dom Custom Vitest matchers to test the state of the DOM This library is a fork of @testing-library/jest-dom. It shares that library's implement

Chance Strickland 14 Dec 16, 2022
An extension of DOM-testing-library to provide hooks into the shadow dom

Why? Currently, DOM-testing-library does not support checking shadow roots for elements. This can be troublesome when you're looking for something wit

Konnor Rogers 28 Dec 13, 2022
ParkyDB - block based, linkable and verifiable document database -- javascript reference implementation

Ancon ParkyDB A data mesh database using Web 3.0 technology Note: Requires Node v17.7.2 and up for development More about data mesh architecture Block

Ancon Protocol 6 Aug 16, 2022
This document introduces an early implementation of the Node-RED runtime that runs on resource-constrained microcontrollers (MCUs).

Node-RED MCU Edition Copyright 2022, Moddable Tech, Inc. All rights reserved. Peter Hoddie Updated June 25, 2022 Introduction This document introduces

Peter Hoddie 53 Jan 3, 2023
A personal semantic search engine capable of surfacing relevant bookmarks, journal entries, notes, blogs, contacts, and more, built on an efficient document embedding algorithm and Monocle's personal search index.

Revery ?? Revery is a semantic search engine that operates on my Monocle search index. While Revery lets me search through the same database of tens o

Linus Lee 215 Dec 30, 2022
A thin wrapper around arweave-js for versioned permaweb document management.

?? ar-wrapper A thin wrapper around arweave-js for versioned permaweb document management. Helps to abstract away complexity for document storage for

verses 8 May 12, 2022
Preview document wrtting in YOUR markdown.

Glance Vim Do you know the number of Markdown flavours in the world? Everyone has an own flavour. It's hard to find the suitable Markdown previewer fo

TANIGUCHI Masaya 31 Dec 6, 2022