Skip to main content

Zero-dependency vanilla JS/CSS UI framework with a conformance checker CLI

Project description

tinymoon

A content-first web framework: you bring plain, semantic content and small view objects; tinymoon brings the app -- shell, typography, widgets, motion. Everything ships as native ES modules and plain CSS with zero dependencies, zero build steps, and zero network loads.

tinymoon's palette is its identity. Consumer CSS must not redefine framework tokens.

Install

npm (core + extras):

npm install tinymoon

The npm package exports two barrels: "tinymoon" (core primitives) and "tinymoon/extras" (wiki, networking, settings). Assets are available at "tinymoon/assets/*".

PyPI (assets + conformance checker CLI):

pip install tinymoon

tinymoon.assets_path() returns the directory containing css/, js/, and fonts/.

Go (embedded filesystem):

import "github.com/smm-h/tinymoon"

// tinymoon.Assets  — embed.FS rooted at the repo root
// tinymoon.FS()    — fs.FS rooted at the assets directory
// tinymoon.Handler() — http.Handler serving the assets

Quick start

Link the four CSS layers (tokens first) and import the ES modules -- no build step, no bundler:

<link rel="stylesheet" href="assets/css/tokens.css">
<link rel="stylesheet" href="assets/css/base.css">
<link rel="stylesheet" href="assets/css/shell.css">
<link rel="stylesheet" href="assets/css/primitives.css">

<script type="module">
import { mountShell, toast } from "./assets/js/index.js";
import { createSettings } from "./assets/js/extras.js";

const settings = createSettings({
  storageKey: "my-app",
  defaults: { theme: "dark" },
});
settings.load();
settings.applyTheme();

const shell = mountShell({
  root: document.body,
  brand: {
    name: "myapp",
    logoHTML: '<div class="wordmark">my<b>app</b></div>',
  },
  routes: {
    home: {
      title: "Home",
      icon: "library",
      view: () => HomeView,
    },
  },
  defaultRoute: "home",
});
</script>

With npm, use bare specifiers by adding an import map:

<script type="importmap">
{ "imports": { "tinymoon": "./node_modules/tinymoon/assets/js/index.js",
               "tinymoon/extras": "./node_modules/tinymoon/assets/js/extras.js" } }
</script>

Primitives

Core (tinymoon)

Shell and DOM:

  • mountShell(opts) -- mount the app shell with sidebar, topbar, router, and footer slot
  • el(tag, cls?, text?) -- element factory
  • $(sel, root?) -- querySelector shorthand
  • $$(sel, root?) -- querySelectorAll (returns array)

Controls:

  • createSwitch(opts) -- role="switch" toggle button (not form-participating)
  • createCheckbox(opts) -- hidden-native checkbox facade (form-participating)
  • createRadio(opts) -- hidden-native radio facade (form-participating)
  • createFileInput(opts) -- hidden-native file input facade (form-participating)
  • createSegmented(opts) -- segmented control with hidden radios (form-participating)
  • createTabs(opts) -- tab bar (not form-participating)
  • createSelect(opts) -- custom dropdown select
  • createDatePicker(opts) -- calendar date picker
  • copyButton(getText, tip?) -- one-click clipboard copy button
  • kebabButton(itemsFn, tip?) -- three-dot menu button

Overlays:

  • toast(msg, level?, opts?) -- toast notification ("ok", "err", or plain)
  • setToastErrorHook(fn) -- mirror error toasts into a custom hook
  • openModal(opts) -- modal dialog (returns close function)
  • openPopover(anchor, builder) / closePopover() -- positioned popover
  • registerCtx(key, provider) / registerCtxFooter(fn) -- context menu regions
  • showCtxMenu(x, y, items, anchor?) / hideCtxMenu() -- programmatic context menu
  • ensureTooltip(el, text) / hideTip() -- tooltip lifecycle
  • ensureHovercard(el, md) / hideHovercard() -- rich hovercard with markdown

Data and utilities:

  • ICONS -- built-in icon set (26 icons)
  • icon(name) -- render an icon as an SVG string
  • registerIcons(map) -- merge consumer icons (collisions are hard errors)
  • renderMiniMd(text) -- inline markdown to DOM fragment (bold, code, links)
  • cssVar(name) -- read a computed CSS custom property value
  • ensureRoot() -- ensure the root element exists
  • placeBelow(anchor, el) -- position an element below an anchor
  • registerCopyable(el, fn) / unregisterCopyable(el) -- register elements for the copy system
  • getCopyData(el) -- retrieve copy data from a registered element

Extras (tinymoon/extras)

  • api(path) -- GET JSON from a same-origin path
  • post(path, body, onError?) -- POST JSON to a same-origin path
  • createSettings(opts) -- localStorage-backed settings store with schema validation
  • createWikiView(opts) -- wiki view factory with table of contents and deep-linkable sections
  • renderDocMd(md) -- block-level markdown to DOM (paragraphs, subheadings, lists)

Identity

The visual identity is enforced by constraint, not offered as options:

  • Sharp corners everywhere -- border-radius is 0; no exceptions.
  • Three-font system -- brand headings (Space Grotesk), UI body (IBM Plex Sans), monospace for data (IBM Plex Mono). All vendored, no network loads.
  • Glow language -- accent glows on active cards, focused inputs, and modals. Restrained and consistent.
  • Grain -- a subtle SVG noise overlay on the background.
  • Motion timing -- all transitions are 100--180ms one-shot eases. The spinner is the only continuous animation.
  • No native browser controls -- checkbox, radio, select, file input, and date picker are all custom-drawn with hidden native elements for form participation and accessibility.
  • AA contrast -- every text-on-background token pair passes WCAG AA 4.5:1. Enforced by CI.
  • Reduced motion -- prefers-reduced-motion: reduce suppresses all animation and transition durations to near-zero. Enforced by E2E tests.

Design tokens let you re-theme and re-accent; they do not let you opt out of the identity.

Conformance checker

tinymoon check scans .html, .css, and .js files and enforces the framework's non-negotiables as hard errors:

  • external-url -- no network loads (no http://, https://, or //host URLs in HTML, CSS, or JS)
  • native-control -- no native <select>, <dialog>, or <input type=checkbox|radio|file>
  • title-attr -- no title= attributes (use the tooltip primitive)
  • border-radius -- no border-radius other than 0/0px
  • raw-color -- no color literals outside :root/html[data-theme] token definitions
uvx tinymoon check --dir ./web

One line per violation, exit non-zero on any finding. No --skip, --ignore, or warning mode. Exempt specific URLs by adding them to tinymoon-allowlist.txt at the scanned directory root.

App model

Copy system. registerCopyable(el, fn) marks any element as copyable -- clicking it copies the value returned by fn() to the clipboard, with a toast confirmation. The copyButton helper wires a standalone copy button. getCopyData(el) retrieves registered copy data programmatically.

Selection model. Elements declare tooltips via data-tooltip (plain text) and hovercards via data-hovercard (markdown with bold, code, links). The framework manages hover intent, positioning, and the hover bridge automatically.

View contract. Routes map to view objects {root, built, build(), refresh(), setSub?}. The shell's router owns the lifecycle: build() constructs the DOM once (idempotent), refresh() runs on every visit, setSub(sub) receives deep-link tails. A string value instead of a view factory activates the content-first path -- plain HTML styled automatically with zero framework classes.

Gallery

The gallery is a complete tinymoon app that documents every design token and primitive. Serve the repo root with a static server and open /gallery/:

python3 -m http.server
# open http://localhost:8000/gallery/

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tinymoon-0.4.0.tar.gz (204.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tinymoon-0.4.0-py3-none-any.whl (171.1 kB view details)

Uploaded Python 3

File details

Details for the file tinymoon-0.4.0.tar.gz.

File metadata

  • Download URL: tinymoon-0.4.0.tar.gz
  • Upload date:
  • Size: 204.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for tinymoon-0.4.0.tar.gz
Algorithm Hash digest
SHA256 d700649c858ed0a3bdb7a5ae60efa0f0271da90e9ac79a0b7bf242ade460d883
MD5 20853b0aca55f08cf06f7c2dd8deaf2d
BLAKE2b-256 4098d95809dbc989d0777f7e70266855de55376f545e205d715bdb237e3c83f3

See more details on using hashes here.

Provenance

The following attestation bundles were made for tinymoon-0.4.0.tar.gz:

Publisher: publish.yml on smm-h/tinymoon

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file tinymoon-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: tinymoon-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 171.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for tinymoon-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d5ad023631e5bdb2cac0f1ce3de2c68dd7337eea6f26d01514e524d81f0bfcf5
MD5 3c537552d794297e0eceaadcf0487ace
BLAKE2b-256 241f68b9503d7c9b9bc069ffceb1ed8e322ad2357d9dbb222ba5091570fd068d

See more details on using hashes here.

Provenance

The following attestation bundles were made for tinymoon-0.4.0-py3-none-any.whl:

Publisher: publish.yml on smm-h/tinymoon

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page