Skip to content

Releases: pinpointzero73/domma

Domma v1.0.1

Choose a tag to compare

@github-actions github-actions released this 27 Oct 10:47

v1.0.1 - Context menus stay open while scrolling (2026-10-27)

Fixed

  • Scrolling a long context menu or one of its submenus keeps it open. Scrolling the surrounding page still closes the menu.
  • Context menus contain scroll gestures and remain within the viewport on smaller screens.

Domma v1.0.0

Choose a tag to compare

@github-actions github-actions released this 26 Oct 07:41

v1.0.0 - Domma 1.0 (2026-10-26)

Changed

  • The API is stable. From 1.0, a change that breaks working code needs a new major version: patch releases fix bugs, minor releases add features. 1.0.0 contains no code changes from 0.60.0. It marks the end of the road-to-1.0 work, done in 0.54 to 0.60:
    • 0.54: globals and noConflict, imports that are safe in Node, packaging.
    • 0.55: one set of conventions (open/close, destroy(), E.get, dm: events, one instance per call with all()), and each web component is a thin wrapper over its E.* component.
    • 0.56: dropzone, range slider, command palette, split pane, virtual list, i18n and focus trap.
    • 0.57: focus trapping in modals, slideovers, dialogs and popovers, and type declarations generated from the source.
    • 0.58: the deprecated forms removed.
    • 0.59 / 0.60: the type catalogue.
  • The docs describe the current API. The README and Components guide still described the timeline alias and the array-shaped factory results as working; both were removed in 0.58.

Domma v0.60.0

Choose a tag to compare

@github-actions github-actions released this 25 Oct 21:20

v0.60.0 - Added: every component's options in the type catalogue (2026-10-25)

Added

  • The type catalogue lists every E.* component's options. elements in domma-js/types/catalogue.json maps each factory that takes an options object to its options type - progression, rangeSlider, datePicker and the rest, not only the components $.setup() can create. Domma CMS uses it to describe its shortcodes' settings.

Domma v0.59.0

Choose a tag to compare

@github-actions github-actions released this 25 Oct 20:01

v0.59.0 - Added: a type catalogue for editors and tools (2026-10-25)

Added

  • A type catalogue for tools that cannot run TypeScript. assets/types/catalogue.json (domma-js/types/catalogue.json) lists every component $.setup() can create, its factory and its options: each option's kind (boolean, number, string, the values of an enum, ...) and its doc line, read from the generated declarations. npm run build:types writes it and npm run check:types fails when it is stale. Domma CMS's page editor uses it to check a page's config.

Fixed

  • $.setup() gives cookieConsent, notification and alarm their options. They were called with the selector in place of the options, so a config's options for them were dropped.
  • Setup config types say what works. initial and event text / html / attr values take numbers and booleans (they are converted to text), and a form component's options are typed as FormSetupOptions - its own options plus schema and data.

Domma v0.58.2

Choose a tag to compare

@github-actions github-actions released this 25 Oct 15:30

v0.58.2 - Fixes: command palette recents survive a reload (2026-10-25)

Fixed

  • Command palette recents from async pages and sources. A command that came from an async children page or a source search was remembered only by id, so after a reload nothing could find it and it vanished from Recent. A link command (an href, no action) now keeps a copy of what it needs to be shown and followed again, under <recentKey>:saved; clearRecent() removes both keys.

Added

  • resolveRecent(id) option on E.commandPalette: returns the command for a remembered id the list does not hold (one that runs code, which cannot be saved). A command it returns under a different id is ignored.

Domma v0.58.1

Choose a tag to compare

@github-actions github-actions released this 25 Oct 09:03

v0.58.1 - Fixes: range slider reset and tooltip attribute, wizard Previous, table rows in .html(), focus trap layers (2026-10-25)

Fixed

  • Range slider and form reset. Inputs the slider creates (a container target, or the second thumb), and a caller's input without a value attribute, now get the starting value as their value attribute, so a form reset puts the slider back where it started instead of the midpoint. destroy() gives the caller's input back its own attribute.
  • Range slider no longer wears data-tooltip. Its tooltip setting moved to data-tooltip-mode on .dm-range-slider, because [data-tooltip] is what pages scan to attach E.tooltip() - a slider picked up a tooltip reading "hover". Restyled CSS that targeted .dm-range-slider[data-tooltip=…] should use [data-tooltip-mode=…].
  • F.wizard Previous keeps what was typed. Leaving a step by Previous, prevStep(), nextStep() or goToStep() saves that step's values first (without validating), so coming back shows them and getStepData() includes them.
  • .html() into a table part. Rows written into a <tbody>, <thead>, <tfoot> or <table>, and cells into a <tr>, are no longer dropped by DOMPurify, which parses as if into <body>. They are sanitised in their table context, with the same rules as before.
  • Focus trap allowOutsideFocus: 'layers'. A position: fixed element that was already on the page and stacks below the trap (a fixed site header under a modal) is now page, not a floating layer, so focus can no longer leave an overlay for it. Toasts, popovers and anything opened after the trap still count as layers. New helper: stackLevel(el).

Changed

  • Kickstart types. The MPA kickstart (CLI init and add-ai, and the browser builder's AI files) now ships frontend/types/ copied from the declarations generated from the source (assets/types), replacing a hand-kept copy that had drifted. build:types runs before build:kickstart-files.

Domma v0.58.0

Choose a tag to compare

@github-actions github-actions released this 24 Oct 22:17

v0.58.0 - Deprecated APIs removed (2026-10-24)

Removed (breaking)

Everything 0.55 marked as deprecated is gone. Domma CMS 1.10.14 (with Docs 2.14.1) and Docs Pro 0.11.2 no longer use them; update those before this release.

Removed Use instead
Modal's unprefixed open / close DOM events on modal.element modal.on('close', fn) / modal.once('close', fn), or the bubbling dm:modal:close (detail {instance, args})
Popover's popover:show / shown / hide / hidden DOM events pop.on('shown', fn), or bubbling, cancelable dm:popover:<name>; e.detail.instance replaces e.detail.popover
Sortable's sortable:start / move / sort / drop / cancel / end DOM events .on('sort', fn), or dm:sortable:<name>; the old detail is e.detail.args[0]
Using E.tooltip(), E.buttonGroup() or E.listGroup() as an array ([i], length, forEach, map, iteration) .all() on the result, or E.tooltip.all(sel) / E.buttonGroup.all(sel) / E.listGroup.all(sel)
E.buttonGroup() / E.listGroup() returning [] when nothing matches They return null, like E.tooltip(); .all(sel) still returns []
E.timeline(selector, options) E.progression(selector, {mode: 'timeline', ...options})
Domma.theme.setVariant(), toggle(), listVariants() Domma.theme.set('ocean-dark'), listThemes() / listBases()
ThemeRoller loadPreset() Domma.theme.set(name)

show() / hide() / isVisible() stay as permanent aliases of open() / close() / isOpen(). window.DommaOptions.deprecationWarnings is still read, for future deprecations.

Domma v0.57.0

Choose a tag to compare

@github-actions github-actions released this 24 Oct 20:04

v0.57.0 - Focus trapping in overlays (2026-10-24)

Focus stays in modals, slideovers, dialogs and popovers

  • E.modal, E.slideover and E.alert / E.confirm / E.prompt now keep Tab and Shift+Tab inside while they
    are open, and put focus back where it was when they close. The modal's cycle runs through its X, the content
    you put in it and the footer buttons in the order they show. A slideover focuses its panel on open, so the
    first Tab reaches its first control; a field you focus after open() keeps focus.
  • New options trapFocus (default true) and returnFocus (default true) on all three. A modal or slideover
    without a backdrop is not trapped unless you pass trapFocus: true, since the page beside it stays usable.
  • Overlays stack: a modal from a slideover, a confirm from a modal, a slideover from a slideover. The newest
    holds Tab; closing it hands focus back to where it was in the one beneath, which holds Tab again. An overlay
    closed underneath a newer one leaves focus alone and passes its own return target up.
  • Toasts and their buttons, popovers, context menus, date pickers and other floating panels opened from an
    overlay keep focus and clicks; Tab moves through them and back into the overlay. The page behind, and an
    overlay beneath, stay out of reach. Mark anything else that should take focus with data-focus-trap-allow.
  • Tab is left alone when something used it first: a textarea that indents on Tab, a grid that moves between
    cells, an editor's own Tab handling (anything that calls preventDefault()).
  • Popovers keep their non-modal Tab behaviour. Inside an overlay, Tab off the end of one goes to the next
    control in that overlay, not the page behind. trapFocus: true on a popover now uses the focus trap.
  • Escape and the close buttons still call close(), so a guard you put on close still runs. destroy()
    removes the trap. Nothing is made inert.
  • Focus trap: Tab is decided as the key reaches window, so handlers on the way can claim it; new options
    allowOutsideFocus (false | true | 'layers' | function) and register; a trap whose containers left the
    page lets go of focus.

Types generated from the source

  • The TypeScript declarations (assets/types/, the package's types) are now generated from the JSDoc in src/
    by npm run build:types (part of npm run build) instead of being written by hand. They cover what they did
    before and more: the router (R), auth (A), forms (F), effects, blueprint helpers (B), web components,
    every E.* factory and its instance, and the Schema Builder. H.get<T>() and the other HTTP methods are
    generic, $() events are typed by name ('click' gives a MouseEvent), and isDomma() is a type guard.
  • Every alias Domma puts on window is now declared as a global (E, H, I, T, R, A, F, B joined
    $, _, M, D, S), plus FL from domma-flags.
  • Types now follow the code where the old hand-written ones did not: names and members that never existed are
    gone (HttpResponse, ThemeChangeEvent, BackToTopScrollEvent, BackToTopShowEvent, H.setDefaults,
    S.setPrefix, several DataTable methods), and signatures that were wrong are fixed (T filter / filterBy,
    PageInfo.page, theme.preview(theme)). Module values such as utils or elements are type-only exports, since
    the ES module never exported them at runtime.
  • The separate hand-kept copy in public/assets/ide/phpstorm/ is retired; point an IDE at assets/types/index.d.ts.
  • npm run check:types (in make check and CI) fails when the committed declarations differ from a fresh
    generation, and type-checks a small consumer under tsc --strict. See docs/Types.md.

Fixes

  • A click, key or input handler inside a modal, slideover or dialog may move focus outside it on purpose - an "Insert" button that focuses the page editor behind its slideover, inserts, then closes keeps working (allowScriptFocus, on for the overlays). Focus that escapes any other way is still brought back.

  • A date picker or dropdown opened from inside a slideover or modal draws above it instead of behind it.

  • A.createUserInfo() renders the signed-in user and wires its logout button; it had no constructor, so it never did. The button keeps working after a login or logout re-renders it, and destroy() stops listening for auth changes.

Domma v0.56.0

Choose a tag to compare

@github-actions github-actions released this 24 Oct 16:12

v0.56.0 - New components: dropzone, range slider, command palette, focus trap, split pane, virtual list and translations (2026-10-24)

i18n

  • New Domma.i18n module, with Domma.t(key, params) as the shortcut: messages as nested JSON
    (flattened to dot keys, merged on add()), load() from a URL via H.get or a loader (cached,
    concurrent loads shared), a fallback chain (fr-CA -> fr -> fallbacks).
  • Plurals and select as objects of forms ({one, few, many, other, '=0'}, {select: 'gender', ...})
    chosen by Intl.PluralRules, ordinals included. No ICU parser to ship.
  • t() returns plain text; html() keeps the message's markup and escapes every param. Messages
    are never evaluated.
  • number(), currency(), date() (Date, timestamp, string or D()), relative() and list()
    over cached Intl formatters in the current locale.
  • translate(root) fills data-i18n, data-i18n-html (sanitised) and data-i18n-attr, with
    data-i18n-params; changing locale sets <html lang dir> (rtl for Arabic, Hebrew, Persian,
    Urdu...) and re-translates the page. detect() picks a locale from storage, the browser or
    <html lang> and can remember it with S.
  • Missing keys return the key (or default), fire missing and an onMissing hook, and warn once;
    window.DommaOptions = {i18nWarnings: false} silences them. Events change, missing, loaded
    via i18n.on() and as dm:i18n:* on document.
  • data-i18n-attr never writes event handlers (on*), style, srcdoc or formaction, and URL
    attributes (href, src, action, ...) only take http(s), mailto:, tel: or relative values -
    so neither a message nor a param can add script. Refusals warn once.
  • Types in assets/types/i18n.d.ts; guide in docs/I18n.md; showcase page showcase/i18n/.

Focus trap

E.focusTrap(container, options) keeps Tab, Shift+Tab and stray focus inside one or more containers while it is
active. Tabbables are found live (shadow roots included), a container with nothing tabbable takes focus itself, and
traps stack - opening a second pauses the first, closing it hands focus back. Options for initial and returned focus,
Escape, outside clicks and inert on the rest of the page. Also importable on its own from
src/components/focus-trap.js for other components.

Command palette

E.commandPalette(options) is a Cmd/Ctrl+K launcher: fuzzy search with highlighted matches, groups, recent commands
(remembered with S), shortcut hints, nested pages (arrays or async), and an async source that is debounced and
abortable with loading, empty and error states. Full keyboard support, the ARIA combobox + listbox pattern, a focus
trap, theme tokens, reduced motion and a full-width panel on phones.

Split Pane

E.splitPane(container, options) makes resizable panes out of a container's children, with draggable,
focusable role="separator" gutters between them. Side by side or stacked, 2 or more panes, nests.
Min/max sizes in px or %, snapOffset, collapsible panes (double-click, a gutter button, Enter, or
collapse(i) / expand(i)), sizes remembered with persistKey, RTL, and iframes in panes cannot swallow a
drag. Events: beforedrag (cancelable), dragstart, drag, dragend, resize, collapse, expand.
Showcase: showcase/elements/split-pane/.

Virtual List

E.virtualList(container, options) renders only the visible rows of a long list in a scrolling container -
100,000 fixed-height rows keep about fifteen rows in the page. Fixed itemHeight or 'auto' with measured,
cached heights and a stable scroll position; keyField re-uses rows; prepend() keeps your place;
scrollToIndex(i, {align}). Infinite loading with loadMore() (one load at a time, loading / end / error rows,
retry). Roving-tabindex keyboard navigation (arrows, Page Up/Down, Home/End, Enter) that never loses the
focused row. Strings from render() are sanitised unless safe: false. Events: render, scroll,
loadmore, loaded, end, error, itemclick. Showcase: showcase/elements/virtual-list/.

Dropzone

E.dropzone(target, options) turns an element into a place to drop, browse for or paste files. A real
<input type="file"> (yours, or one it adds) carries them, so inside a <form> the files submit with it - the
input's file list is kept in step with what the area shows. Rules: accept, maxSize, minSize, maxFiles and
a cancelable onBeforeAdd; refusals fire reject(entry, 'type' | 'size' | 'count') and are announced to screen
readers. Images get thumbnails. With upload: {url, field, headers, data, concurrency} each file is sent on its own
with a progress bar, automatic retry, a Retry button and cancel(). A file dropped just outside the area no
longer navigates away from the page while a drag is under way. F.create takes type: 'dropzone'.

E.dropzone('#attachments', {accept: 'image/*,.pdf', maxSize: 5 * 1024 * 1024, maxFiles: 4});

Range slider

E.rangeSlider(target, options) (alias E.slider) - one value or a [low, high] range between two thumbs, with
ticks, labelled marks, a tooltip, vertical orientation and right-to-left support. Full keyboard (arrows, Page Up /
Page Down, Home / End), ARIA sliders with aria-valuetext from the labels formatter, and pointer dragging with a
touch-sized hit area. Real <input type="range"> elements carry the value and fire native input / change, so
forms, FormData and model bindings see it. F.create takes type: 'slider'.

E.rangeSlider('#price', {range: true, min: 0, max: 1000, step: 10, value: [100, 600], labels: v => '£' + v});

Domma v0.55.0

Choose a tag to compare

@github-actions github-actions released this 24 Oct 15:07

v0.55.0 - API conventions, one implementation per component (2026-10-24)

API conventions (non-breaking)

  • Every onX option on the UI components now has a matching .on('x', fn) event and a bubbling dm:<component>:x DOM event with detail = {instance, args}. Options run exactly as before.
  • Overlays (dropdown, sidebar, autocomplete, pillbox, slideover, date picker, context menu, cookie consent) all answer open(), close(), toggle() and isOpen(); show(), hide() and isVisible() stay as permanent aliases. Popover gains open(), close() and isVisible().
  • The aliases, close buttons, backdrops and Escape all call close() by name, so a "discard changes?" guard patched onto instance.close covers every way out.
  • Slideover, dropdown, sidebar, date picker, autocomplete, pillbox and context menu fire a cancelable beforeclose (and beforeopen): return false from onBeforeClose or a listener, or call preventDefault(), to keep it open. destroy() always closes.
  • E.buttonGroup() and E.listGroup() return the first instance when the selector matches several elements, with .all() (and E.buttonGroup.all() / E.listGroup.all()) for the list. Using the result as an array still works, with a one-time warning, until 1.0.
  • E.get(el) finds skeletons, avatars, avatar groups and choosers as well as every component; E.popover.getInstance, E.skeleton.get, E.avatar.get and E.avatarGroup.get give the same answer.
  • E.chooser() with a missing host returns an inert chooser instead of null, and choosers have an element property.
  • E.notify({title, body, ...}) works as well as E.notify(title, options).
  • Alarms: removeAlarm(id) is the name; remove(id) keeps working.
  • Fixes: a sidebar's floating toggle is removed on destroy(); a destroyed cookie consent is no longer handed back by E.cookieConsent(); destroying a slideover in the frame it opened no longer throws.

See "Conventions" in docs/Components.md.

One implementation per component

E.card, E.modal, E.tooltip, E.badge, E.numberBadge, E.toast, E.loader (with showLoader, hideLoader, fullscreenLoader), E.backToTop, E.createModal and E.showModal now each have one implementation, a component like the rest (src/components/). The <domma-*> tags are thin shells that build that same component on themselves.

  • The element you pass is the component's element. Nothing replaces it any more, so references you hold, listeners bound to it, #id lookups and E.get(el) all keep working. Every instance has a real options object.
  • Theme colours reach every one of them. Inside the old shadow roots, --dm-primary, --dm-success, the greys and the shadows were declared in terms of themselves, which made them invalid, so each component drew its hard-coded fallback whatever the theme. In Chrome under ocean-dark, the page's primary was #48cae4 and a badge's was rgb(79, 70, 229). Card, badge, number badge, tooltip, toast, loader and back-to-top are now plain page markup styled by elements.css. The modal keeps a shadow root (on your element) and now uses the theme.
  • Events follow the shared conventions: every onX option has a matching .on('x') and dm:<component>:x DOM event. The old unprefixed close, show, click and remove events no longer leak out of nested components, and a badge click fires once.
  • Modal: onClosed fires, and factory modals honour onOpened, onClosed, headerClass, bodyClass and className. New cancelable onBeforeOpen / onBeforeClose (also .on('beforeclose') and dm:modal:beforeclose). The X, backdrop and Escape call close() by name, so a replaced close() is honoured, and Escape closes only the top modal. The unprefixed open and close DOM events are still dispatched on the element, once per open or close, until 1.0. show() / hide() stay as aliases of open() / close(). showModal() resolves with null when the modal is closed without a button.
  • Modal content (content, setContent()) is sanitised as $().html() does, which removes inputs and buttons. Pass {safe: false} for trusted markup. Selector mode keeps your .modal-header / .modal-body markup and wires its .modal-close, [data-close] and [data-dismiss="modal"] buttons.
  • Toast: the message is always text unless you pass html: true, which is now sanitised (safe: false for trusted markup). E.toast('123') shows "123". action is a shorthand for a single actions entry, and an action's onClick is called.
  • Tooltip: E.tooltip(selector) sets up every match, not just the first. It returns the first instance, and all() (or E.tooltip.all()) gives every one; using the result as an array still works, with a one-time warning, until 1.0. A tooltip whose target is removed from the page hides with it. The tooltip appears beside the target without wrapping it. A title is used as the content when there is no content (the browser's own tooltip is held back), and keyboard focus shows hover tooltips.
  • Badge keeps child markup such as icons, and card keeps loose text. Card's hoverable gives the .card-hover border highlight, and color: 'primary' adds .card-primary.
  • fullscreenLoader() reuses one overlay, and hideLoader('#dm-loader-fullscreen') hides it. Loader options given as strings (centered: 'false') are read correctly.
  • E.backToTop('#my-button') now uses that button, and inside the container it watches, it sticks to that container's corner. Any other selector still adds a button to the body.
  • The <domma-*> tags are registered on first use or when the page contains one. Their methods (badge.setVariant(), nb.increment()) are on the tag, and a changed attribute updates the component. <domma-toast> is gone (use E.toast). So is the legacy-wrappers module with its createXWrapper exports, which nothing in Domma used.