├── site
└── demos
│ ├── components
│ └── ajax-get
│ │ ├── data.json
│ │ ├── styles.css
│ │ └── ajax-get.js.html
│ ├── ajax-get.js
│ └── index.html
├── captain-definition
├── babel.config.js
├── docs
├── source
│ ├── img
│ │ └── debug-error.png
│ ├── installation.md
│ ├── components
│ │ ├── binding.md
│ │ ├── template.md
│ │ ├── store.md
│ │ ├── events.md
│ │ ├── directives.md
│ │ ├── index.md
│ │ └── configuration.md
│ ├── conf.py
│ ├── faq.md
│ ├── index.md
│ └── examples.md
├── requirements.txt
├── Makefile
└── make.bat
├── test
├── helpers.js
├── component.test.js
├── emerj.test.js
├── onchange.test.js
├── events.test.js
├── component-helpers.test.js
├── directives.test.js
└── utils.test.js
├── tsconfig.json
├── .gitignore
├── .github
├── workflows
│ └── js.yml
├── ISSUE_TEMPLATE
│ └── config.yml
└── FUNDING.yml
├── Dockerfile
├── .readthedocs.yaml
├── pyproject.toml
├── rollup.config.js
├── DEVELOPING.md
├── LICENSE
├── logo.svg
├── package.json
├── README.md
├── CHANGELOG.md
├── src
├── events.js
├── directives.js
├── component-helpers.js
├── index.js
├── emerj.js
├── component.js
└── utils.js
├── dist
└── dlite.es.js
└── poetry.lock
/site/demos/components/ajax-get/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "neat": "cool"
3 | }
--------------------------------------------------------------------------------
/site/demos/components/ajax-get/styles.css:
--------------------------------------------------------------------------------
1 | h2 {
2 | color: aquamarine;
3 | }
--------------------------------------------------------------------------------
/captain-definition:
--------------------------------------------------------------------------------
1 | {
2 | "schemaVersion": 2,
3 | "dockerfilePath": "./Dockerfile"
4 | }
5 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ["@babel/preset-env"],
3 | plugins: [],
4 | };
5 |
--------------------------------------------------------------------------------
/docs/source/img/debug-error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adamghill/dlite/main/docs/source/img/debug-error.png
--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | Sphinx
2 | linkify-it-py
3 | myst-parser
4 | furo
5 | sphinx-copybutton
6 | sphinx-autobuild
7 | toml
--------------------------------------------------------------------------------
/test/helpers.js:
--------------------------------------------------------------------------------
1 | export class Fixture {
2 | constructor(data, expected, name = null) {
3 | this.data = data;
4 | this.expected = expected;
5 |
6 | self.name = name || data;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowJs": true,
4 | "checkJs": true,
5 | "noEmit": true,
6 | "target": "es6",
7 | "moduleResolution": "node"
8 | },
9 | "include": ["src/**/*"],
10 | "exclude": ["node_modules/"]
11 | }
12 |
--------------------------------------------------------------------------------
/site/demos/components/ajax-get/ajax-get.js.html:
--------------------------------------------------------------------------------
1 |
2 |
{this.activity.activity}
3 |
4 | - Type: {this.activity.type}
5 | - Price: {this.getPrice()}
6 | - Accessibility: {this.activity.accessibility}
7 | - Participants: {this.activity.participants}
8 |
9 |
--------------------------------------------------------------------------------
/test/component.test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @vitest-environment jsdom
3 | */
4 |
5 | import { test, expect } from "vitest";
6 |
7 | import Component from "../src/component.js";
8 |
9 | test("initialize", () => {
10 | const template = `Hello World
`;
11 |
12 | const actual = Component({
13 | template: template,
14 | tagName: "my-tag",
15 | });
16 |
17 | expect(actual).toBe(null);
18 | });
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # JS Projects
2 | *.py[co]
3 | __pycache__*
4 |
5 | # Packages
6 | *.egg
7 | *.egg-info
8 | .cache
9 | eggs
10 | parts
11 | bin
12 | var
13 | sdist
14 | develop-eggs
15 | .installed.cfg
16 | MANIFEST
17 | .idea/*
18 | .idea
19 | .idea/libraries/sass_stdlib.xml
20 | .sass-cache
21 | .vscode
22 | .DS_Store
23 | node_modules/
24 | package-lock.json
25 |
26 | dev/
27 | perf/
28 | docs/build/
29 | deploykey
30 | deploykey.pub
31 |
--------------------------------------------------------------------------------
/.github/workflows/js.yml:
--------------------------------------------------------------------------------
1 | name: JavaScript
2 | on: [push]
3 |
4 | jobs:
5 | test:
6 | runs-on: ubuntu-latest
7 |
8 | steps:
9 | - uses: actions/checkout@v2.3.4
10 | with:
11 | fetch-depth: 1
12 |
13 | - name: Set up node
14 | uses: actions/setup-node@v2.1.2
15 |
16 | - name: Install node packages
17 | run: npm install
18 |
19 | - name: Test
20 | run: npm run t
21 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.10.8-slim as python-base
2 |
3 | # Copy files and directories to docker
4 | COPY poetry.lock pyproject.toml package.json ./
5 | COPY docs ./docs
6 | COPY site ./site
7 |
8 | # Install dependencies
9 | RUN pip install poetry
10 | RUN poetry install --only main
11 |
12 | # Copy changelog to docs
13 | RUN cp CHANGELOG.md docs/source/changelog.md
14 |
15 | # Build docs in the site directory
16 | RUN poetry run sphinx-build -W -b dirhtml docs/source site
17 |
18 | FROM nginx
19 | COPY --from=python-base ./site /usr/share/nginx/html
20 |
--------------------------------------------------------------------------------
/test/emerj.test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @vitest-environment jsdom
3 | */
4 |
5 | import { describe, test, expect } from "vitest";
6 |
7 | import { nodesByKey } from "../src/emerj.js";
8 |
9 | test("nodesByKey", () => {
10 | const el = document.createElement("div");
11 | const child = document.createElement("p");
12 | child.id = "asdf";
13 | el.prepend(child);
14 |
15 | const makeKey = (node) => node.id;
16 |
17 | const actual = nodesByKey(el, makeKey);
18 |
19 | const expected = '';
20 |
21 | expect(actual.asdf.outerHTML).toEqual(expected);
22 | });
23 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: Bug Report
4 | url: https://github.com/adamghill/dlite/discussions/new
5 | about: Submit a bug or an issue
6 | - name: Feature request
7 | url: https://github.com/adamghill/dlite/discussions/new
8 | about: For ideas or feature requests
9 | - name: Support questions & other
10 | url: https://github.com/adamghill/dlite/discussions/new
11 | about: If you have a question or need help using the library
12 | - name: Documentation issue
13 | url: https://github.com/adamghill/dlite/discussions/new
14 | about: For documentation improvements
15 |
--------------------------------------------------------------------------------
/.readthedocs.yaml:
--------------------------------------------------------------------------------
1 | # Read the Docs configuration file
2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
3 |
4 | # Required
5 | version: 2
6 |
7 | # Set the OS, Python version, and other tools you might need
8 | build:
9 | os: ubuntu-24.04
10 | tools:
11 | python: "3.13"
12 |
13 | # Build documentation in the "docs/" directory with Sphinx
14 | sphinx:
15 | configuration: docs/source/conf.py
16 |
17 | # Optionally, but recommended,
18 | # declare the Python requirements required to build your documentation
19 | # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
20 | python:
21 | install:
22 | - requirements: docs/requirements.txt
23 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line, and also
5 | # from the environment for the first two.
6 | SPHINXOPTS ?=
7 | SPHINXBUILD ?= sphinx-build
8 | SOURCEDIR = source
9 | BUILDDIR = build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.poetry]
2 | name = "dlite-docs"
3 | version = "0.0.0"
4 | description = "Documentation for dlite"
5 | authors = ["adamghill "]
6 | license = "MIT"
7 | repository = "https://github.com/adamghill/dlite/"
8 | homepage = "https://dlitejs.com"
9 | documentation = "https://dlitejs.com"
10 |
11 | [tool.poetry.urls]
12 | "Funding" = "https://github.com/sponsors/adamghill"
13 |
14 | [tool.poetry.dependencies]
15 | python = ">=3.7,<4.0"
16 | Sphinx = "*"
17 | linkify-it-py = "*"
18 | myst-parser = "*"
19 | furo = "*"
20 | sphinx-copybutton = "*"
21 | sphinx-autobuild = "*"
22 | toml = "*"
23 | attrs = "*"
24 |
25 | [build-system]
26 | requires = ["poetry-core>=1.0.0"]
27 | build-backend = "poetry.core.masonry.api"
28 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Rollup config
3 | *
4 | * This script config allows us to create a bundle of the library
5 | * the library is meant to be used at ES module, or
15 | ```
16 |
17 | You can also specify a version using the `unpkg` CDN to minimize the effect of breaking changes.
18 |
19 | ```html
20 |
23 | ```
24 |
25 | ## NPM
26 |
27 | You can also install via NPM.
28 |
29 | ```shell
30 | npm install dlite
31 | ```
32 |
33 | Then, import `dlite` in your JavaScript.
34 |
35 | ```js
36 | import Dlite from 'dlite';
37 | ```
38 |
--------------------------------------------------------------------------------
/docs/source/components/binding.md:
--------------------------------------------------------------------------------
1 | # Data Binding
2 |
3 | The `@bind` attribute creates two-way data bindings on `input`, `textarea`, and `select` elements. Bound elements will update the appropriate `data` on input events.
4 |
5 | :::{code} html
6 | :force: true
7 |
18 |
19 |
20 |
21 | Hello {this.salutation} {this.name}
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | :::
33 |
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=source
11 | set BUILDDIR=build
12 |
13 | if "%1" == "" goto help
14 |
15 | %SPHINXBUILD% >NUL 2>NUL
16 | if errorlevel 9009 (
17 | echo.
18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19 | echo.installed, then set the SPHINXBUILD environment variable to point
20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
21 | echo.may add the Sphinx directory to PATH.
22 | echo.
23 | echo.If you don't have Sphinx installed, grab it from
24 | echo.http://sphinx-doc.org/
25 | exit /b 1
26 | )
27 |
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29 | goto end
30 |
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33 |
34 | :end
35 | popd
36 |
--------------------------------------------------------------------------------
/DEVELOPING.md:
--------------------------------------------------------------------------------
1 | # Developing `dlite`
2 |
3 | ## Installation for documentation
4 |
5 | 1. `poetry install`
6 |
7 | ## Run documentation site
8 |
9 | 1. `npm run sa`
10 | 1. Go to http://localhost:8000 in your browser
11 |
12 | ## Run documentation site via Docker
13 |
14 | 1. docker build -t dlite . && docker container run -p 8557:80 dlite:latest
15 | 1. Go to http://localhost:8557 in your browser
16 |
17 | ## Build documentation site
18 |
19 | 1. `npm run sb`
20 |
21 | ## Installation for demos
22 |
23 | 1. `brew install --cask growlnotify`
24 | 1. `npm install dev-server -g`
25 |
26 | ## Run demo site
27 |
28 | 1. `npm run r`
29 | 1. Go to http://localhost:4000/site/demos/ in your browser
30 |
31 | ## Publish new version
32 |
33 | 1. Update `CHANGELOG.md`
34 | 1. Update version in `package.json`
35 | 1. `npm run t && npm run b`
36 | 1. Commit/tag/push changes
37 | 1. `npm publish`
38 | 1. [Create a new release](https://github.com/adamghill/dlite/releases/new)
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2023 Adam Hill
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/docs/source/conf.py:
--------------------------------------------------------------------------------
1 | # Configuration file for the Sphinx documentation builder.
2 |
3 | import json
4 |
5 |
6 | # -- Project information
7 |
8 | project = "dlite"
9 | copyright = "2023, Adam Hill"
10 | author = "Adam Hill"
11 |
12 | with open("../../package.json") as f:
13 | package = json.load(f)
14 |
15 | version = package["version"]
16 | release = version
17 |
18 |
19 | # -- General configuration
20 |
21 | extensions = [
22 | "sphinx.ext.duration",
23 | "sphinx.ext.doctest",
24 | "sphinx.ext.autodoc",
25 | "sphinx.ext.autosummary",
26 | "sphinx.ext.intersphinx",
27 | "myst_parser",
28 | "sphinx_copybutton",
29 | "sphinx.ext.napoleon",
30 | "sphinx.ext.autosectionlabel",
31 | ]
32 |
33 | intersphinx_mapping = {
34 | "python": ("https://docs.python.org/3/", None),
35 | "sphinx": ("https://www.sphinx-doc.org/en/master/", None),
36 | }
37 | intersphinx_disabled_domains = ["std"]
38 |
39 | templates_path = ["_templates"]
40 |
41 | # -- Options for HTML output
42 |
43 | html_theme = "furo"
44 |
45 | # -- Options for EPUB output
46 | epub_show_urls = "footnote"
47 |
48 | autosectionlabel_prefix_document = True
49 | autosectionlabel_maxdepth = 3
50 |
51 | myst_heading_anchors = 3
52 | myst_enable_extensions = ["linkify", "colon_fence"]
53 |
--------------------------------------------------------------------------------
/test/onchange.test.js:
--------------------------------------------------------------------------------
1 | import { test, expect } from "vitest";
2 | import { objectOnChange } from "../src/utils.js";
3 |
4 | test("set new property", () => {
5 | const initialData = {};
6 | const data = objectOnChange(initialData, () => {});
7 | data.name = "Litedom";
8 | expect(data.name).toBe("Litedom");
9 | });
10 |
11 | test("set new property affecting initial source", () => {
12 | const initialData = {};
13 | const data = objectOnChange(initialData, () => {});
14 | data.name = "Litedom";
15 | expect(initialData.name).toBe("Litedom");
16 | });
17 |
18 | test("get ___target___ #", () => {
19 | const initialData = {};
20 | const data = objectOnChange(initialData, () => {});
21 | data.name = "Litedom";
22 | expect(data["#"]).toEqual({ name: "Litedom" });
23 | });
24 |
25 | test("objectOnChange callback function", () =>
26 | new Promise((done) => {
27 | const initialData = {};
28 | const data = objectOnChange(initialData, () => {
29 | expect(data.name).toBe("Litedom");
30 | done();
31 | });
32 |
33 | data.name = "Litedom";
34 | }));
35 |
36 | test("with array", () => {
37 | const initialData = {
38 | myObj: {},
39 | };
40 | const data = objectOnChange(initialData, () => {});
41 | data.myObj.myArray = [1, 2, 3];
42 | expect(data.myObj.myArray.length).toEqual(3);
43 | });
44 |
--------------------------------------------------------------------------------
/site/demos/ajax-get.js:
--------------------------------------------------------------------------------
1 | import Dlite, { fetcher } from "//unpkg.com/dlite";
2 | // import Dlite, { fetcher } from "../../src/index.js";
3 |
4 | const template = await fetcher("components/ajax-get/ajax-get.js.html");
5 |
6 | const formatter = new Intl.NumberFormat("en-US", {
7 | style: "currency",
8 | currency: "USD",
9 | });
10 |
11 | const componentConfigurations = [
12 | {
13 | tagName: "ajax-get",
14 | template: template,
15 | },
16 | {
17 | el: "#template-shadow",
18 | template: template,
19 | },
20 | {
21 | el: "#template-no-shadow",
22 | template: template,
23 | shadowDOM: false,
24 | },
25 | {
26 | el: "#in-place-template",
27 | },
28 | ];
29 |
30 | const components = Dlite(componentConfigurations, {
31 | getPrice() {
32 | if (this.data.activity.price == 0) {
33 | return "Free!";
34 | } else if (!this.data.activity.price) {
35 | return "";
36 | }
37 |
38 | return formatter.format(this.data.activity.price);
39 | },
40 | debug: true,
41 | shadowDOM: true,
42 | data: { activity: {} },
43 | async created() {
44 | const activity = await fetcher("https://www.boredapi.com/api/activity");
45 |
46 | // Simulate network latency
47 | setTimeout(() => {
48 | this.data.activity = activity;
49 | }, 500);
50 | },
51 | });
52 |
53 | console.log("components", components);
54 |
--------------------------------------------------------------------------------
/site/demos/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | I am the shadow
21 |
22 |
23 |
24 | I am not the shadow
25 |
26 |
27 |
32 |
33 |
34 |
39 |
48 |
49 |
50 |
51 |
52 |
53 |
{this.activity.activity}
54 |
55 | - Type: {this.activity.type}
56 | - Price: {this.activity.price}
57 | - Accessibility: {this.activity.accessibility}
58 | - Participants: {this.activity.participants}
59 |
60 |
61 |
62 |
63 |
64 | Not a template
65 |
66 |
67 |
68 |