Skip to content

Releases: smm-h/tinymoon

v0.9.1

Choose a tag to compare

@smm-h smm-h released this 18 Jul 12:35

strictcli 0.29 compatibility — fixes tinymoon check crashing at startup

Context

strictcli 0.29.0 requires ctx-first handler signatures. Published tinymoon 0.9.0 crashed at import under current strictcli (handler missing parameter "dir"). This patch migrates all CLI handlers to the ctx-first signature, restoring compatibility.

Fixes

  • Fixed tinymoon check crashing at startup with strictcli 0.29+. The CLI now uses ctx-first handler signatures, restoring compatibility with current strictcli.

v0.9.0

Choose a tag to compare

@smm-h smm-h released this 17 Jul 14:05

Deep-link query parsing and async view factories land in the router; shortcut suppression now covers all light-dismiss overlays; a human visual review pass fixed tooltip cancellation on unrelated scrolls, transcript entry flashing, and demo pacing.

Context

The router features were originally deferred at the frozen core ceiling and became trivial after the ratchet; the shortcuts gap closed by consulting the dismissal registry that postdated it; the polish items came from the first human visual review of the gallery, which also surfaced a real framework tooltip bug.

Features

  • Router deep-link queries and async view factories. Hash links may carry a query (#/route/tail?a=1&b=2) parsed into an object delivered to views via ctx.query/setQuery; a route's view factory may return a Promise, showing a loading placeholder while it resolves and an error block on failure.

Fixes

  • Tooltips survive background scrolling. A hovered tooltip is no longer cancelled when an unrelated region scrolls (e.g. a live feed autoscrolling to its tail); it only closes when the scroll actually moves its anchor.
  • Keyboard shortcuts suppress under transient overlays. While a popover, context menu, select menu, or non-modal drawer is open, ordinary shortcuts no longer fire (only {global: true} do), matching the behavior under modal dialogs.

v0.8.0

Choose a tag to compare

@smm-h smm-h released this 17 Jul 10:41

The size guarantee becomes a standing ratchet (ceilings re-baseline to measured x1.25 when they bind; core re-baselined once to 147,500), with honest comparative positioning — a capability matrix in the README, a dated size survey in the gallery, and small consumer-reported fixes (renderStats instance pass-through, checker-limitation and vendoring documentation).

Context

The frozen core ceiling had reached 17 bytes of headroom and was forcing byte-archaeology on every core-file change; the ratchet keeps walls deliberately close (placement decisions stay forced) while ending the archaeology. Positioning was rewritten against a mid-2026 survey of the minimal-framework landscape — the differentiator stated as surface-per-byte plus enforcement tooling, with measured gzip numbers replacing the absolute "tiny" claim.

Breaking

  • The size guarantee changed: the core JS byte ceiling is no longer frozen. Every tier ceiling (core included) now follows a STANDING RATCHET: it is set to the tier's current measured weight x1.25, and re-baselines to a new measured x1.25 in review whenever a legitimate addition makes it bind. The old "the core ceiling is never raised" promise is retired; the core ceiling re-baselined once, from 118,000 to 147,500 bytes. Walls are kept deliberately close so adding a capability still forces a real placement decision.

Features

  • New README section: Scope and non-goals. Spells out that tinymoon is a fixed-identity, hand-coded, web-only framework and states its explicit non-goals (server-driven UI trees, per-deployment theming, cross-platform native rendering, and app-platform features), so readers can tell at a glance whether it fits their use case.
  • New README positioning: a comparative size story and a capability coverage matrix. The docs now frame tinymoon by surface-per-byte rather than absolute smallness: honest measured numbers (raw ~396 KB, gzip ~128 KB for the whole kit), a metric-discipline note (tinymoon's gzip weight vs competitors' min+gzip), two hedged comparisons (about three Bootstraps; roughly 2x a hand-rolled no-build stack), and a durable capability matrix versus view microframeworks, Mithril, Alpine, htmx, Web Awesome, and Bootstrap.
  • renderStats now accepts already-built createStat instances, or any mix of instances and config objects, not only config objects. Passing an instance no longer throws "label is required" -- an entry carrying an .el is mounted as-is (preserving references, bindings, and a pre-set trend), and the row's destroy still tears it down.

Fixes

  • Documented two conformance-checker details consumers rely on. The external-url rule matches inline URL literals only: a URL passed through a variable (const u = "https://..."; fetch(u)) is neither caught nor allowlistable, so keep external URLs inline at the load site. And vendored framework assets pass by hash-identity in a plain directory with no manifest, but under third_party/ the quarantine's pin requirement applies to them too.

v0.7.0

Choose a tag to compare

@smm-h smm-h released this 16 Jul 20:56

Consumer-driven patch wave: vendored-framework recognition by hash identity, fenced code blocks in doc markdown, put/patch/del net helpers, table row event hooks, 2+1/1+2 grid presets, a WCAG-verified danger button, and a Python-side theme boot snippet — plus checker false-positive fixes and a hard error for a silent route misconfiguration.

Context

every item traces to frictions reported by the four real consumer migrations completed on 0.6.1; the vendored-identity mechanism extends the provenance doctrine so no-backend consumers can vendor the framework without quarantining it; the danger-button ladder exists because the naive red fill fails WCAG in dark theme (measured).

Features

  • createLoadMore now has a load() method. Programmatically trigger the first (or next) page without synthesizing a button click.
  • createGrid gains 2+1 and 1+2 presets. Asymmetric 3-slot layouts — a row of two above one full-width cell, and its mirror — that collapse to a single column on narrow screens.
  • createTable gains onRowClick and onRowHover. Event-delegated row hooks — onRowClick(row, index, event) and onRowHover(row | null, index, event) — that survive setRows() re-renders and never fire for the header or the "more rows" note.
  • net gains put, patch, and del. JSON mutation verbs mirroring post() exactly — ApiError on non-OK, the pre-throw onError hook, the auth-header hook, merged headers, and the abort signal; del sends no body.
  • renderDocMd now supports fenced code blocks. Triple-backtick blocks render verbatim into <pre><code> (an info string like ```js is accepted and ignored; no syntax highlighting). Tables and blockquotes remain out of scope; the inline renderMiniMd dialect is unchanged.
  • createSwitch now has a get() method. Read the switch's current on/off state directly, matching createCheckbox/createRadio.
  • createFileInput now has an open() method. Programmatically open the native file picker, the same as clicking the styled trigger.
  • Vendored tinymoon assets now pass the checker by identity. A file whose bytes sha256-match a packaged framework asset is recognized as framework-own wherever a consumer serves it from (no quarantine needed); editing it breaks the match and it is scanned normally.
  • New .btn.danger button variant. A destructive-action button — solid red fill with a white label — backed by a new red token ladder (--red-solid, --red-solid-hi, --on-red, --red-glow) that clears WCAG AA (4.5:1) contrast in both themes.
  • The PyPI package now exports THEME_BOOT_SNIPPET. from tinymoon import THEME_BOOT_SNIPPET gives Python servers the same pre-paint theme script as the JS export (kept byte-for-byte identical by a sync test), so a server-rendered page can inline it without importing the JS module.
  • New consumption docs. README now covers typed consumption when serving assets yourself (install tinymoon as a devDependency purely for types), the vendored-asset identity story, badges as one-shot elements (mutate or replace, no update API), and the fixed-height virtual-list constraint; index.d.ts annotates each barrel export's real subpath module.

Fixes

  • A route view that is a plain object now hard-errors instead of rendering nothing. Passing a built view object where mountShell expects a factory previously failed silently; it now throws a message naming the fix (wrap it: () => view).
  • Two checker false positives fixed for consumers. HTML numeric character references (&#039;, &#8217;) are no longer flagged as raw #RGB colors; and the plain-object .title false positive is now documented with its bracket-notation workaround (obj["title"] = x). Genuine hex colors and real element.title writes are still detected.

v0.6.1

Choose a tag to compare

@smm-h smm-h released this 16 Jul 16:59

Date/time picker popovers join the centralized light-dismiss engine: toggle buttons close cleanly without reopen races, and pickers nested in other overlays dismiss correctly.

Context

Two prior releases (0.5.0, 0.6.0) were tagged but blocked from registries by load-dependent e2e races, both root-caused (a starved deferred listener registration; a focus no-op on hidden eager routes) and fixed. This release completes the overlay-family migration onto the dismissal engine, hardens the e2e suite against the race classes, and adds a stress preflight gate. It is the first registry-published release of the augmentation line.

Fixes

  • Date/time picker dismissal. Date and time picker popovers now close cleanly when their toggle button is pressed again, and no longer conflict with an enclosing overlay's dismissal (e.g. a picker inside a drawer closes only itself).

v0.6.0

Choose a tag to compare

@smm-h smm-h released this 16 Jul 15:20

Light-dismiss engine and invoker contract: centralized outside-press dismissal with gesture-claim (registerLightDismiss, registerOverlayTrigger), fixing drawer dismissal reliability and toggle close-reopen races across all overlays.

Context

v0.5.0's registry publish was gated on a CI failure that exposed a real race (the drawer's deferred outside-dismiss listener registration could be starved on loaded machines, reproduced deterministically under CPU throttle). Rather than patching the timer, this release ships the already-designed structural replacement: light-dismiss centralized in one synchronous capture-phase listener beside the existing Escape stack, with per-gesture claim so a trigger press closes without re-opening; all five bespoke overlay implementations migrated onto it. Also hardens the e2e suite against a second CI-only flake class (axe scans sampling mid entrance-animation).

Features

  • Overlay-trigger invoker + light-dismiss engine. New registerOverlayTrigger(triggerEl, opener) and registerLightDismiss(opts) (from tinymoon/chrome) give overlays a framework-owned toggle button (aria-expanded, gesture-claim so a close-press cannot immediately reopen) and a centralized outside-pointer dismissal registry.

Fixes

  • Reliable drawer dismissal. A non-modal drawer could intermittently fail to close on an outside click in slow or loaded environments; toggling a drawer via its trigger could close-then-reopen. Both are fixed — outside-pointer dismissal is now registered synchronously and a re-press on the trigger closes it for good.

v0.5.0

Choose a tag to compare

@smm-h smm-h released this 16 Jul 14:02

The augmentation release: forms, data display, state, realtime, and app-chrome primitive families; an isolation-boundary model (tm-embed, vendor quarantine) and expanded conformance enforcement; per-tier size budgets with subpath exports and typed barrels.

Context

A coordinated framework build-out driven by real consumer needs: the widget families (inputs, slider, table, virtual list, tree, filters, feed, charts, drawer, palette, view factory), the L2 state story (store/bind/reconcile), realtime transports, the identity-surface doctrine with loads-vs-navigations re-scoping, the tm-embed boundary and hash-pinned vendor quarantine, the native-control ban expansion now that every replacement factory ships, portable conformance artifacts for non-Python consumers, and the package restructure into budgeted tiers (core frozen, widgets/state/chrome/controls tiers, five stylesheets, tokens.json). Validated end-to-end against a real consumer migration before release.

Breaking

  • Native-control ban expanded. tinymoon check and the runtime auditor now reject native <textarea> and native <input> of every type that has a shipped replacement: text/password/email/url/search/tel (use createInput), range (createSlider), number (createNumber), time (createTimePicker), date (createDatePicker), alongside checkbox/radio/file and <select>/<dialog> as before. A bare typeless <input> also fires (it defaults to text). type="hidden" and type="color" stay legal. Consumer code using these raw natives now fails the checker -- migrate to the named factories.

Features

  • Command palette, shortcuts, lazy mounting, async-state blocks. New tinymoon/chrome modules: a fuzzy command palette (opt-in via installPalette), a keyboard-shortcut binder, IntersectionObserver-gated lazy mounting, and loading/empty/error state blocks with a renderAsync helper.
  • Toast action button. toast(msg, kind, {action: {label, onClick}}) adds one action button that keeps the toast on screen until the action is taken or it is dismissed; acting dismisses.
  • Tri-state theme. Theme now supports "system" (follows the OS light/dark preference and re-resolves live when it changes), alongside explicit light/dark. Adds a cycleTheme(store) helper and a THEME_BOOT_SNIPPET inline no-flash boot script.
  • Documentation. New README and wiki sections cover the tinymoon/chrome barrel (async-state blocks, lazyMount, shortcuts, command palette), the toast action button, and the tri-state theme with its no-flash boot snippet.
  • Shell views. New createView(render) view factory, an eager-route flag to bypass lazy mounting, and shell.announce() for live-region route announcements.
  • Drawer primitive. New openDrawer() overlay primitive plus swipe-to-close on the shell mobile navigation drawer.
  • Tab panels. createTabPanels composes an APG tab bar with lazily-mounted panels.
  • Grid layout. createGrid CSS-first preset layout primitive.
  • Icon button. iconButton — a stateful topbar icon button instance.
  • Data-display widgets, part 2. New primitives: keyboard-navigable tree, filter bar with chips, load-more, breadcrumbs, sparkline, chart container, and activity feed.
  • Data-display widgets. New data-display barrel: badge, createStat/renderStats, sortable createTable, and windowed createVirtualList, with their stylesheet.
  • Status color token. New --gold warn/caution status color with contrast-checked pairs in both themes.
  • Realtime, net, and format helpers. tinymoon/extras gains realtime (SSE/WebSocket with backoff), net ApiError/auth/options, and fmtTime/relativeTime/liveRelativeTime formatters.
  • Settings subscriptions. settings.subscribe(key, cb) (or null for all keys) with store-contract parity.
  • State layer. New tinymoon/state barrel with an L2 state layer: store, bind, and reconcile.
  • Number stepper. createNumber wraps a native input[type=number] with stepper buttons.
  • Time picker. createTimePicker — a 24-hour HH:MM picker with locale-aware display.
  • Combobox and multi-select. New createCombobox and createMultiSelect typeahead primitives.
  • Accordion. createAccordion — grid-rows animated disclosure panels.
  • New icons. plus, minus, and clock icons for steppers and the time picker.
  • Form controls. Styled-native createInput, createTextarea, createField, and createSlider.
  • Embed isolation. createEmbed isolation-boundary primitive with iframe and shadow-DOM modes.
  • Vendor quarantine. Conformance checker gains a hash-pinned vendor quarantine (unpinned-vendor rule) for sanctioned third-party code.
  • Dialog ban. Conformance checker now statically flags consumer <dialog> as a banned native control.
  • External-URL rule. The external-url check now treats <a>/<area> href as navigation rather than a resource load, so hyperlinks are no longer flagged.
  • Conformance artifacts. Committed rules.json, test corpus, and expectations.json plus a generator, enabling cross-language conformance consumption.
  • Token export artifact. Committed assets/tokens.json plus its generator, so consumers can read design tokens as data.
  • Subpath exports. Per-module subpath exports for every shipped JS module.
  • TypeScript types for subpaths. types field and per-export types conditions wired into package.json.
  • TypeScript declarations. Type declarations for the tinymoon/extras barrel.
  • Documentation. README documents the Phase 6A primitives and the chrome-js tier.
  • Documentation. README documents the state and data-display widgets barrels and names all budget tiers.
  • Documentation. README documents the Phase 3B control primitives and the controls-js tier.
  • Documentation. README documents the createInput, createTextarea, createField, and createSlider primitives.
  • Documentation. New README section on running conformance from non-Python CI (portable artifacts, Go worked example, full-scan CLI path).
  • Documentation. README documents subpath imports, the TypeScript types stance, and the per-tier size promise.
  • Documentation. README documents the vendored third-party code quarantine mechanism.
  • Documentation. README documents widgets.css as the optional fifth data-display stylesheet.
  • Documentation. README notes the static <dialog> ban and the framework openModal exemption.
  • Documentation. README documents copyButton and kebabButton as sanctioned one-shot utilities.
  • setPageSub is now exported from the core barrel (import { setPageSub } from "tinymoon"), alongside announce. Views that do not go through createView can set the shell's topbar page-subtitle without reaching into the DOM.
  • Table row and cell class hooks. createTable gains rowClass(row) and per-column cellClass(value, row) — return a class string to tint whole rows or individual cells from your own data. Classes are appended to the framework's own tr/td classes (never replacing them) and re-applied on every setRows().
  • Seek slider variant. createSlider({variant: "seek"}) is an invisible position scrubber for laying over app-drawn visuals (waveform/timeline canvases): the track and thumb go visually transparent while the full-area hit target, focus-visible outline, and slider ARIA stay intact. Your app draws the visuals underneath; the seek slider only scrubs.

Fixes

  • Light theme. The accent highlight color is no longer illegible against the accent -- link and active-state highlights now stay clearly distinguishable in the light theme.
  • Fix. The mobile hamburger now opens the drawer, the drawer closes on Escape, and the icon button has an accessible name.
  • Fix. Small (10px) stat and table labels now use --text-dim to keep 4.5:1 contrast when grain-composited.
  • Fix. The time picker popover is now positioned in viewport coordinates and hidden when closed.
  • Fix. The hidden native input behind createFileInput now has an accessible name.
  • Fix. A focus-shown hovercard now stays glued to its trigger when focus scrolls it into view.

v0.4.0

Choose a tag to compare

@smm-h smm-h released this 15 Jul 11:34

The redesign release: unified primitive API, full accessibility, design token system, object-copy model, responsive mobile support, and a guarantee-grade conformance checker.

Context

A comprehensive external critique identified structural gaps in the framework:
no custom form controls, no ARIA semantics, hardcoded CSS values, no mobile
support, no RTL readiness, and a conformance checker that could be bypassed.

A 12-phase charter addressed every finding. The primitive API was unified
around factory functions returning {el, methods, destroy()}. A kernel module
centralized escape-stack and overlay management. Design tokens replaced all
raw literals. The barrel was split into core and extras for tree-shakeable
imports. Every primitive was rebuilt with APG-compliant keyboard and ARIA
patterns. A runtime auditor and expanded conformance checker close the loop
on charter guarantees.

Breaking

  • Breaking. Unified primitive API: toggleWidget replaced by createSwitch, Select class replaced by createSelect, segmented replaced by createSegmented/createTabs. All primitives now return {el, methods, destroy()}.
  • Breaking. Gallery migrated to createTabs; Select class replaced by createSelect factory with full APG combobox pattern; dead legacy segmented() function removed.
  • Breaking. Barrel split: core (tinymoon) and extras (tinymoon/extras). createSettings, createWikiView, api, post, renderDocMd moved to extras. fmtTime removed. Root index.js re-export shim deleted.
  • Breaking. cssVar moved from settings.js to kernel.js. New kernel module centralizes escape-stack, overlay placement, root-element creation, and CSS variable access.

Features

  • New primitives. createCheckbox, createRadio, createFileInput, createDatePicker (APG grid pattern), createTabs -- all form-participating (except tabs), with full ARIA semantics. Tooltip split into plain-text tooltip and rich hovercard.
  • Accessibility. Modal rebuilt on native <dialog> with focus trap, Escape, aria-labelledby. Toast gets aria-live, dismiss button, pause-on-hover, stack cap. Context menu gets role=menuitem, Shift+F10 keyboard entry, focus restore. Shell gets skip link, route announcer, aria-current.
  • Design tokens. Rem-based type and spacing scales, duration tokens, z-index tokens, line-height and font-weight tokens. Single accent hue via color-mix() derivation. All raw CSS literals replaced with token references.
  • Object-copy system. Focusable data objects with Ctrl+C support, automatic context-menu Copy entries, selection model (.doc-body user-select: text), and print stylesheet.
  • Content-first. All semantic HTML styled by default with identity tokens. Declarative string-view path for the shell. Sidebar drawer JS toggle for mobile hamburger menu.
  • Responsive and i18n. Full mobile support with drawer nav, dvh, 44px touch targets. Logical CSS properties for RTL. Non-Latin font fallback policy. color-scheme declarations for native UI matching.
  • Conformance checker. Template-literal URLs, importmaps, additional attributes, color functions, WebSocket schemes, encoding errors -- 6 bypass classes closed and 3 false-positive classes fixed.
  • Runtime conformance auditor. Dev-mode module checking border-radius, native controls, and network loads at runtime.
  • Selector hygiene. CSS rules scoped, deduplicated, and unified across all stylesheets.
  • TypeScript declarations. index.d.ts for core barrel.
  • Top layer and input styling. Context menu and popover promoted to top layer via popover=manual. Number and range input styling added.
  • Test infrastructure. Playwright + vitest + axe-core test suite. Zero-network, reduced-motion, responsive, RTL, and accessibility CI. Go embed/Handler tests. Characterization baselines and red-green bug tests.

Fixes

  • Fix. Escape multi-close bug: pressing Escape in a Select inside a modal no longer closes both.
  • Fix. copyButton now awaits clipboard write before showing success state.
  • Fix. icon() now throws on unknown name instead of silently returning empty string.
  • Fix. registerCtx throws on duplicate key; renderMiniMd renders non-hash links as plain text; api() checks r.ok and post() no longer silently coerces bad JSON; router catches malformed percent-encoding in hash.
  • Fix. WCAG AA contrast: --text-faint, --on-accent, --border-2 adjusted to pass 4.5:1 / 3:1 in both themes.
  • Fix. prefers-reduced-motion support: blanket suppression of transitions and animations, scroll-behavior override.
  • Fix. RTL layout: switch knob and toast translateX flipped for :dir(rtl).
  • Fix. ensureRoot now applies attributes even if element already exists. Wiki deep-link highlight no longer persists after refreshCurrent().
  • Fix. Axe violations: aria-label on theme button, tabindex=0 on scrollable main.

v0.3.1

Choose a tag to compare

@smm-h smm-h released this 13 Jul 16:52

Toast error hook receives the toast opts for per-call metadata.

Fixes

  • The toast error hook now receives the toast's opts object, so per-call metadata reaches logging hooks.

v0.3.0

Choose a tag to compare

@smm-h smm-h released this 13 Jul 16:33

Shell routing hooks (onRoute, refreshCurrent) and a toast error hook for log mirroring.

Features

  • mountShell gains an onRoute(routeKey, sub) callback and a refreshCurrent() helper; toast errors can be mirrored via setToastErrorHook().