Skip to content

v1.0.0

Choose a tag to compare

@github-actions github-actions released this 24 Sep 09:43
· 20 commits to main since this release
Immutable release. Only release title and notes can be modified.
6787006

Major Changes

  • #138 c150389 - Stop generating IDs for items without one: their id is now undefined instead of a positional ID like '1-0'. Give an item an id if you look it up by ID. The positional ID moves to the new key property.

  • #311 999feaf - Size label plates to their text instead of a fixed 120 px width. Set --mm-plate-min-width and --mm-plate-max-width to 120px to keep the fixed, truncated width. Plates also default to more padding and rounder corners, with no square corner toward the center.

  • #273 2381311 - createMarkingMenu throws when items in a level are less than 45° apart, such as a level with more than 8 items, because directions that close together can't be told apart. Move extra items into submenus, or space stated angles at least 45° apart.

  • #233 ab83b8b - createMarkingMenu returns a controller instead of an RxJS Observable, so you no longer install rxjs. The menu is active as soon as you create it. Listen with on(type, listener), and stop the menu with dispose() or using.

    // 0.10.1
    const subscription = MarkingMenu(items, parent).subscribe((selection) => {
      console.log(selection.name);
    });
    subscription.unsubscribe();
    
    // 1.0
    const menu = createMarkingMenu({ items, parent });
    menu.on('select', (event) => console.log(event.selection.label));
    menu.dispose();

    The controller emits start, open, move, change, select, and cancel events, exported as classes such as MarkingMenuSelectEvent. Their fields are getters, so spreading an event or JSON.stringify() doesn't copy them. They replace the notifySteps option, with these differences: draw becomes move, move also fires alongside change, cancel has no selection, active is now activeItem and only on move, change, and cancel, and no event has timeStamp.

    menu.state reports what the menu is doing between events: mode is idle, startup, expert, novice, or standalone, and novice and standalone also carry the displayed menu and the activeItem. Inside a listener it already reflects the event being dispatched. The package exports the new MarkingMenuState type.

    menu.open() displays the menu without a gesture. Mouse, touch, pen, and keyboard all operate it, and menu.close() closes it. Pass { position }, in viewport pixels, to center it somewhere other than the parent's center. Events from such a menu have mode: 'standalone', and, like novice mode, fire move on pointer movement. Every event has a source: 'pointer', 'keyboard', 'gesture' (drawing a mark), 'api' (an open() or close() call, or the focus open() gives the first item), or 'focus-loss' (the menu lost focus). position is a viewport point when source is 'pointer', and undefined otherwise. Check source, not mode, to know which. When a stroke was recognized, open, select, and cancel events have a recognition with the stroke and how it was cut into corners and segments. cancel events have a reason: no-selection, interrupted when the browser cancels the pointer, or dismissed when a menu shown with open() is closed. The package exports the new MarkingMenuCancelReason, MarkingMenuEventSource, MarkingMenuOpenOptions, MarkingMenuRecognition, MarkingMenuStrokeAnalysis, and MarkingMenuStrokeSegment types.

  • #144 1580c6e - Ship only an ES module. The UMD build is gone, with its CommonJS, AMD, and window.MarkingMenu global loading. Every supported browser loads ES modules natively: use import or <script type="module">.

  • #260 195d2dd - Spread items evenly around the circle for every item count. Menus with 2, 3, 5, 6, or 7 items change: 3 items sit 120° apart instead of 90°. A learned gesture can now select a different item, without any error. Set each item's angle to keep its old direction.

  • #138 c150389 - Replace the isLeaf() and isRoot() item methods with isLeaf and isRoot properties.

  • #138 c150389 - Items expose their fields through getters instead of own properties, so spreading an item, Object.keys(), or structuredClone() no longer copies them. Read the fields you need explicitly.

  • #126 5a46547 - Rename the item name property to label, and getChildrenByName() to getChildrenByLabel().

  • #277 ca594cd - Raise the default submenuOpeningDelay from 100 ms to 1000 / 3 ms, the same as noviceDwellingTime, so opening a submenu takes the same pause as opening the menu. Set submenuOpeningDelay: 100 to keep the old delay.

  • #118 80d15d6 - Require Chrome and Edge 111, Firefox 115, or Safari and iOS 16.4, or newer. Dark mode colors, which you opt into with color-scheme, need Chrome and Edge 123, Firefox 120, or Safari 17.5. Firefox 115 to 118 don't expose the menu's accessibility roles.

  • #138 c150389 - Replace the default export with the named createMarkingMenu export: import { createMarkingMenu } from 'marking-menu'.

  • #262 3d2d200 - Render labels as plain text instead of HTML, so a label can't inject markup into the page. A label containing HTML now shows the tags as text. Labels are text only.

  • #126 5a46547 - Remove the string shorthand for menu items, so every item has the same shape. Write { label: 'Copy' } instead of 'Copy'.

  • #126 5a46547 - Pass a single configuration object instead of positional arguments: createMarkingMenu({ items, parent, ...options }) instead of MarkingMenu(items, parent, options).

  • #138 c150389 - The root has no id, label, or angle instead of having them set to null.

  • #302 6ca5e42 - Render the menu in an open shadow root on the .marking-menu element, so page styles, such as a box-sizing: border-box reset, can't break its layout. Page CSS can no longer reach the menu's inner elements, and the theme properties are renamed to --mm-*, set on .marking-menu. Check the documentation for the replacements.

  • #277 ca594cd - Replace minSelectionDist (default 40) and minMenuSelectionDist (default 80) with one deadZoneRadius option (default 40). An item becomes active past this radius, and pausing on it opens its submenu. Before, a submenu only opened past minMenuSelectionDist. Rename minSelectionDist to deadZoneRadius and remove minMenuSelectionDist; JavaScript silently ignores the old names.

  • #383 1c836d8 - In novice mode, move focus to the menu and then to the active item, so screen readers announce it. Focus returns where it was when the gesture ends. The focused element gets blur and focusout events during the gesture.

    A menu shown with menu.open() takes focus the same way. Each arrow key moves focus that way around the ring rather than along the item order, so the key you press matches the direction you see. Home and End jump to the ends of the item order, Enter selects a leaf or opens a submenu, Escape goes back up a level or closes the menu from the root, and Tab closes it from any level. It also closes when focus moves elsewhere, leaving focus there. Pass { autoFocus: false } to open it without moving focus; it closes on focus loss only after focus enters it. Entering a submenu always leaves focus in the menu. open events carry willAutoFocus, false only for a menu opened this way.

  • #474 6db62d0 - A menu shown with menu.open() now also answers the mouse, touch, and pen, alongside the keyboard, and shows a pointer cursor over its items. Hovering an item makes it active without moving focus, and moving off the menu clears it. Clicking a leaf selects it and clicking a submenu item opens it, both giving focus to the new level. Clicking outside the menu, or releasing a drag there, dismisses it.

  • #319 f90a2db - Replace the nine stroke options, such as strokeColor and lowerStrokeWidth, with --mm-stroke-* custom properties, so you style strokes in CSS like the rest of the menu. Check the documentation for the replacements.

  • #138 c150389 - Rename children to items, on the items you pass and on the items the menu returns, to match the top-level items option. Items without sub-items return items: [] instead of undefined.

  • #124 de5942f - Rename the subMenuOpeningDelay option to submenuOpeningDelay.

  • #334 3413aa3 - Strokes are no longer clipped to the parent, like the menu itself. Set overflow: hidden on the parent to keep both inside it. The .marking-menu element now stays in the parent until you dispose the menu, so its presence no longer means a menu is open.

  • #150 c7ad8ad - Handle input with Pointer Events. Only the primary mouse button, touch, or pen starts a gesture, so right and middle clicks no longer open the menu, and a second touch no longer ends it. A gesture keeps tracking when the pointer leaves the parent, and always cancels when the browser cancels the pointer. The parent gets touch-action: none until you dispose the menu, except while a menu shown with menu.open() is displayed. Then pointer input goes to the page and no gesture starts.

  • #455 6bae798 - Default item positions now start at the top instead of the right: a menu level where no item states an angle spreads its items 90 degrees counterclockwise from the previous default. Levels with at least one stated angle are unaffected. A learned gesture can now select a different item, without any error. Set each item's angle to keep its old direction.

  • #410 b862390 - Type MarkingMenuLogger's info, warn, and debug as (message: string) => void instead of unknown, so the library can start calling them without a later breaking change. Make error optional too, matching every other method.

  • #138 c150389 - Require item IDs to be unique across the whole menu. createMarkingMenu throws on duplicates, and TypeScript rejects duplicate literal IDs.

Minor Changes

  • #474 6db62d0 - Add --mm-inner-connector-thickness (default 0) and --mm-outer-connector-thickness (default 4px) to size each connector on its own, and --mm-connector-color/--mm-connector-color-active, a shared fallback color for both connectors.

  • #261 b93d497 - Let items set an optional angle, in degrees clockwise from the right. Items without one fill the gaps between stated angles.

  • #290 1b2b563 - Place labels so they don't overlap, instead of at one fixed distance from the center. Tune the spacing with the --mm-plate-gap-* properties.

  • #370 aa25858 - Expose the menu to assistive technologies with the menu and menuitem roles. Items take their label as their name, and items with a submenu have aria-haspopup="menu".

  • #386 06f9ae4 - Add --mm-muted-color, the default color of earlier gesture segments. Earlier segments are lighter than 0.10.1's [#777](https://github.com/QuentinRoy/Marking-Menu/issues/777).

  • #345 55d8361 - Show a dot growing inside a circle during the pause before a menu or submenu opens. It fades in instead when the user prefers reduced motion. Style it with --mm-indicator-fill and --mm-indicator-background.

  • #382 fc6b7c5 - Draw a 1px gray inset outline on wedges, blue on the active one. Change it with --mm-outline-width and --mm-outline-color, their -active variants, and per-part variants, which can also outline plates.

  • #384 76e13b1 - Use system colors in forced colors mode.

  • #147 9c46198 - Ship TypeScript declarations. Items in events are typed from the items you pass, so their id and label narrow to the values you wrote.

  • #382 fc6b7c5 - Change the default colors: wedges and plates have a pale fill with black labels, and the active item turns blue. Set --mm-fill and --mm-fill-active to recolor wedges, plates, and connectors together. Colors follow dark mode when the page declares color-scheme: light dark.

  • #304 f8594c1 - Draw a ring of wedges around the menu center, one per item. Style it with the --mm-wedge-* properties. Connectors now start at the ring; set --mm-inner-connector-color and --mm-inner-connector-thickness to draw them from the center.

Patch Changes

  • #147 9c46198 - Drop the raf-schd dependency.

  • #188 fe933d7 - A log option without an error method falls back to console.error, and error always receives an Error.

  • #233 ab83b8b - After a gesture switches from expert to novice mode, events report mode: 'novice' instead of undefined.

  • #344 7e7b3fb - Support a parent owned by another document, such as an iframe's.

  • #193 a872408 - Hide the cursor during gestures instead of showing a crosshair, and restore the parent's own inline cursor afterward instead of clearing it.

  • #253 7d6704b - Fix strokes drawn away from the pointer when the parent is not at the top-left corner of the viewport.

  • #409 b7cbb41 - Fix the submenu-opening dwell never rearming once it fires on a leaf item, so a submenu right next to that leaf could no longer open by dwelling.

All notable changes to this project will be documented in this file. Entries are generated from Changesets — see .changeset/README.md for how to add one.