wiki-formant 0.91.0 → 0.91.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/base.css CHANGED
@@ -756,7 +756,8 @@ pre:hover > .code-copy-btn,
756
756
  color: var(--ui-muted);
757
757
  }
758
758
  .block-toolbar__tools, .block-toolbar__actions { display: flex; align-items: center; gap: 0.125rem; }
759
- .block-toolbar__tools { opacity: 0; transition: opacity 150ms; }
759
+ /* Kept right when an editor lets the toolbar wrap, as miow's narrow tab does. */
760
+ .block-toolbar__tools { margin-left: auto; opacity: 0; transition: opacity 150ms; }
760
761
  :is(:hover, :focus-within, [data-selected]) > .block-toolbar > .block-toolbar__tools,
761
762
  .block-toolbar__tools:has([aria-expanded='true']) { opacity: 1; }
762
763
  @media (hover: none) { .block-toolbar__tools { opacity: 1; } }
@@ -779,7 +780,8 @@ pre:hover > .code-copy-btn,
779
780
  :is(.block-toolbar, .block-menu) svg { flex: none; width: 1rem; height: 1rem; }
780
781
 
781
782
  .block-menu { position: relative; display: inline-flex; }
782
- .block-list > .block-menu { align-self: center; }
783
+ /* A list's foot button is centred under it, in a flex list or a plain one. */
784
+ .block-menu:not([data-below]) { display: flex; width: fit-content; margin-inline: auto; }
783
785
  .block-add {
784
786
  display: inline-flex;
785
787
  align-items: center;
@@ -800,15 +802,16 @@ pre:hover > .code-copy-btn,
800
802
  z-index: 50;
801
803
  display: grid;
802
804
  grid-template-columns: repeat(2, minmax(0, 1fr));
803
- width: min(22rem, calc(100vw - 2rem));
805
+ width: min(24rem, calc(100vw - 2rem));
804
806
  padding: 0.25rem;
805
807
  background: var(--ui-surface);
806
808
  border: 1px solid var(--ui-border);
807
809
  border-radius: var(--ui-radius);
808
810
  box-shadow: 0 0.5rem 1.5rem rgb(0 0 0 / 0.25);
809
811
  }
810
- .block-menu:not([data-below]) > .block-menu__panel { left: 50%; translate: -50% 0; }
811
- .block-menu[data-below] > .block-menu__panel { right: 0; }
812
+ .block-menu:not([data-below]) > .block-menu__panel { left: 50%; translate: calc(-50% + var(--nudge, 0px)) 0; }
813
+ /* `--nudge` is what AddBlockMenu moves it by to keep it in the window. */
814
+ .block-menu[data-below] > .block-menu__panel { right: 0; translate: var(--nudge, 0px) 0; }
812
815
  /* A phone has no room to hang it off a button deep in a column: it is a sheet
813
816
  along the foot of the screen. */
814
817
  @media (max-width: 40rem) {
@@ -826,10 +829,12 @@ pre:hover > .code-copy-btn,
826
829
  background: none;
827
830
  font: inherit;
828
831
  font-size: var(--ui-small);
832
+ line-height: 1.25;
829
833
  color: inherit;
830
834
  text-align: left;
831
835
  cursor: pointer;
832
836
  }
833
- .block-menu__item > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
837
+ /* A long name takes a second line rather than losing its end. */
838
+ .block-menu__item > span { min-width: 0; overflow-wrap: anywhere; }
834
839
  .block-menu__item svg { color: var(--ui-muted); }
835
840
  .block-menu__item:is(:hover, :focus-visible) { background: var(--ui-surface-2); outline: none; }
@@ -22,7 +22,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
22
22
  // what lets a column or an infobox hold a list without being handed the whole
23
23
  // configuration. Keep both stable — a module constant or a `useMemo` — or every
24
24
  // card re-renders on every keystroke.
25
- import { createContext, memo, useCallback, useContext, useMemo, useRef, useState, } from 'react';
25
+ import { createContext, memo, useCallback, useContext, useLayoutEffect, useMemo, useRef, useState, } from 'react';
26
26
  import { BlockActions, useBlockOperations, useClickOutside } from './react.js';
27
27
  import { CODE_LANGS, DEFAULT_LANG, EVENT_DATE, eventBegun, eventEnded, eventWhen, LIST_SOURCES, today, } from './blocks.js';
28
28
  import { BANNER_VARIANTS } from './text.js';
@@ -91,12 +91,32 @@ const BlockCard = memo(function BlockCard({ block, index, total, selected, neste
91
91
  const body = meta ? schema.renderBody(block, onUpdate) : null;
92
92
  return (_jsxs("section", { className: "block-card", "data-selected": selected || undefined, "data-nested": nested || undefined, onFocusCapture: onSelect, onClick: onSelect, children: [_jsx(BlockToolbar, { label: label, icon: meta?.icon, index: index, total: total, ops: { move, duplicate, remove }, icons: kit.icons, options: offered, onAdd: onAdd }), body ?? _jsx("p", { className: kit.classNames.muted, children: "Kept as it is \u2013 this editor has no fields for it." })] }));
93
93
  });
94
+ /** The least gap, in px, between an open menu and the window's side. */
95
+ const MENU_MARGIN = 8;
94
96
  /** An add button and its menu, which closes on a pick, a click outside it or Escape. Nothing to offer, no button. */
95
97
  export function AddBlockMenu({ options, onPick, icon, below = false, label = 'Add block' }) {
96
98
  const [open, setOpen] = useState(false);
97
99
  const close = useCallback(() => setOpen(false), []);
98
100
  const ref = useClickOutside(close);
99
101
  const trigger = useRef(null);
102
+ const panel = useRef(null);
103
+ // Hung off a button deep in a column, the panel can run past the window's
104
+ // edge: it moves back in by what it overhangs. A phone's sheet is fixed and
105
+ // already fits.
106
+ useLayoutEffect(() => {
107
+ const el = panel.current;
108
+ const view = el?.ownerDocument.defaultView;
109
+ if (!el || !view)
110
+ return;
111
+ el.style.removeProperty('--nudge');
112
+ if (view.getComputedStyle(el).position === 'fixed')
113
+ return;
114
+ const { left, right } = el.getBoundingClientRect();
115
+ const edge = el.ownerDocument.documentElement.clientWidth - MENU_MARGIN;
116
+ const nudge = left < MENU_MARGIN ? MENU_MARGIN - left : right > edge ? edge - right : 0;
117
+ if (nudge)
118
+ el.style.setProperty('--nudge', `${nudge}px`);
119
+ }, [open]);
100
120
  if (options.length === 0)
101
121
  return null;
102
122
  return (_jsxs("span", { ref: ref, className: "block-menu", "data-below": below || undefined, onKeyDown: e => {
@@ -105,7 +125,7 @@ export function AddBlockMenu({ options, onPick, icon, below = false, label = 'Ad
105
125
  e.stopPropagation();
106
126
  close();
107
127
  trigger.current?.focus();
108
- }, children: [_jsxs("button", { ref: trigger, type: "button", className: below ? 'block-toolbar__button' : 'block-add', title: below ? 'Add a block below' : undefined, "aria-label": below ? 'Add a block below' : undefined, "aria-haspopup": "menu", "aria-expanded": open, onClick: () => setOpen(o => !o), children: [icon, !below && label] }), open && (_jsx("span", { className: "block-menu__panel", role: "menu", children: options.map(o => (_jsxs("button", { type: "button", role: "menuitem", className: "block-menu__item", title: o.hint, onClick: e => {
128
+ }, children: [_jsxs("button", { ref: trigger, type: "button", className: below ? 'block-toolbar__button' : 'block-add', title: below ? 'Add a block below' : undefined, "aria-label": below ? 'Add a block below' : undefined, "aria-haspopup": "menu", "aria-expanded": open, onClick: () => setOpen(o => !o), children: [icon, !below && label] }), open && (_jsx("span", { ref: panel, className: "block-menu__panel", role: "menu", children: options.map(o => (_jsxs("button", { type: "button", role: "menuitem", className: "block-menu__item", title: o.hint, onClick: e => {
109
129
  // Inside a card, a pick is not also a click on the card.
110
130
  e.stopPropagation();
111
131
  close();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wiki-formant",
3
- "version": "0.91.0",
3
+ "version": "0.91.1",
4
4
  "description": "The portable half of a wiki: derived taxonomy and facet controls, a version-negotiating MCP transport, markdown twins, block rendering, a rich-text editor engine, conditional-GET plumbing, and the headers and CSP every origin sends.",
5
5
  "type": "module",
6
6
  "license": "MIT",