Mobile Friendly Process Mapper - edmozley/freeitsm GitHub Wiki
The sixteenth module, and the first where the honest answer is that a phone can read the thing but not build it. Three pages — the mapper itself, the step‑types settings screen and the guide. Shipped in #1415‑#1418, mobile.css v124 / mobile.js v49, LAYER 30.
Read Mobile‑Friendly first for the strategy and the one hard rule, and Techniques & Tricks for the catalogue this round draws on.
§22 exists to split drag into the kind that survives touch and the kind that does not, and this canvas is squarely the second:
process-mapper.js : 11 × mousedown / mousemove / mouseup
0 × touchstart / touchmove / pointerdown
A step cannot be moved with a finger. And every per‑step action — edit label, add a note, link to a URL, create a connected step — lives behind a contextmenu listener, which a touch screen has no way to fire. Between them that is the whole of authoring.
🔑 Say what the round is for, out loud, before building it. A toolbar whose buttons half‑respond is worse than a screen that is honestly read‑only. The round was scoped to making a map readable: reach the list, open a map, pan around it, read the steps, and manage step types in settings.
⭐ And then it grew, because Ed asked a question and the answer was measured rather than assumed — see the selection sheet below. Positioning still needs a mouse; editing what a box says does not.
⭐ And the enabler was already there: .pm-canvas is overflow: auto, so panning is native touch scrolling and needed no JavaScript at all. Measured on a real map: canvas scrollWidth 1546 inside a clientWidth of 358, panned to x=1188, nine steps rendered.
Run before touching anything, and it decided most of the round:
| Grep | Result |
|---|---|
a pre‑existing @media
|
none — no repeat of the LMS trap |
localStorage |
none |
:hover revealing a control |
🔴 one, and it hides the navigation — below |
the page's own style.display writes |
39 — anything positional needed care |
| its own modal class | 🔴 .pm-modal / .pm-modal-overlay, invisible to LAYER 3 |
Process Mapper → Settings → Left panel offers Show on hover: the 260px process list collapses to a 16px strip that expands when the cursor approaches. It is a sensible desktop preference and it is stored per analyst.
On a phone nothing hovers. An analyst who turned it on at their desk arrives to a 16px sliver with no way to open it — every process map in the system behind a control a finger cannot operate.
⭐ This is §26 crossed with the saved‑desktop‑mode trap that the tickets pop‑out (#762) and the knowledge editor (#1000) both sprang. The remedy is the same in all three: leave the stored preference alone and neutralise its effect at phone width. The class stays on the element and comes back untouched above 768px.
The list becomes a slide‑in sheet either way, because 260px of a 360px screen leaves about 100px of canvas.
Ed tested the first build and reported it in one sentence:
"when I tap processes on the hamburger menu it flashes for a split second then vanishes"
The attribute flipped, the scrim appeared, and the panel did not move. The reason is a specificity trap that is easy to walk into and gives no warning at all.
The closed rule was written as a selector list so it could catch the hover mode too:
[data-mobile-module="process-mapper"] .pm-sidebar, /* (0,2,0) */
[data-mobile-module="process-mapper"] .pm-layout.sidebar-hover .pm-sidebar { /* (0,4,0) */
transform: translateX(-100%);
visibility: hidden;
}
body[data-mobile-module="process-mapper"][data-pm-sidebar="open"] .pm-sidebar { /* (0,3,1) */
transform: translateX(0);
}A selector list carries its specificity per selector. (0,3,1) beats the first and loses to the second — so the sheet opened for anyone on the default preference and stayed shut for anyone on hover. Ed was on hover, so for him it never worked once.
🔑 Adding a variant to a CLOSED rule silently raises the bar its OPEN rule has to clear. Mirror the variants on both halves of an open/closed pair, or the pair only half works — and it will be the less common configuration that breaks, which is the hardest kind to notice.
Mirrored, the open rule's second selector is (0,5,1) and wins.
data-pm-sidebar="open" and reported the panel's box. The box was correct — it was still at left: -310. A state assertion has to check the thing the state is for, not that the state was set.
With the sheet finally opening, a screenshot showed the process names cut to a letter or two — "S…", "I…", "A…" — with + New and the search box side by side.
.pm-sidebar is Problem Management's class as well. In LAYER 22 pm- means Problem Management; in LAYER 30 it means Process Mapper. And LAYER 22's block is unscoped:
.pm-sidebar { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; padding: 10px 12px; … }So one module's entire layout mode was arranging another module's panel.
⭐ §15 in its sharpest form so far. It has always warned about a shared component class; this is two modules that independently picked the same three‑letter prefix, which no amount of reading one module's CSS would reveal.
Restated in this layer rather than by scoping LAYER 22, because Problem Management's pages carry no module marker to scope it to — giving them one is a change to a shipped module and belongs in its own round, not as a side effect of opening a new one. Recorded as owed.
left: 0, visible, with six items in it, and every one of those numbers was true.
Ed, part‑way through:
"push back if this is a bad idea but do you think it would be good if we had a little bar at the bottom which shows the currently selected item (box, lane, group etc.) with a little edit button"
The instinct was right and the answer was better than the question, because the module already had most of it — which is only knowable by driving a tap and watching what happens:
tap a step → mousedown fires (browsers synthesise the compatibility mouse
events after a tap), step gains .selected, and
.pm-detail-panel opens with "Step Details" in it
Steps, groups, lanes, connectors and annotations each already have their own detail body and translated title. So the answer was not a new bar with an Edit button — that would have put two taps where one already worked, and needed a new component and new strings to do it. It was to take the module's own 320px right‑hand column and move it to the bottom.
🔑 Before building what somebody asks for, check whether the module already does it badly. A feature request is often a layout complaint wearing a costume.
⭐ The half of the request that shaped the design was the half not about the bar: shows the currently selected item. A sheet that covers the map tells you what you are editing and hides which thing it is. So it takes 58dvh, the canvas is capped to the strip above it, and the selected item is scrolled into that strip. Measured: the step moved from y=411 (behind the sheet) to y=186, fully above it.
The scroll did nothing, and the reason was one line of output:
canvasScroll = 0,0 (max 1186,0)
The canvas scrolls sideways across a wide map, but its content is no taller than its box — so scrollTop has a maximum of zero. There was nowhere to scroll to. padding-bottom on the scroller did not buy the range either (its steps are absolutely positioned). Capping .pm-canvas-wrap to 42dvh does, and it gives the honest layout as well: map above, details below, rather than a sheet floating over a canvas that still believes it is full height.
And then it still read as 0,0 — because MutationObserver callbacks are microtasks, and the probe was reading synchronously in the same task. After a tick: 0,225, exactly the arithmetic. The third time this rollout that check what you actually measured has been the answer rather than a code change.
-
30a — the shell.
.pm-layoutisheight: calc(100vh - 48px), the fourth module in a row (21, 27, 29, this). Handed back to LAYER 2's100dvhflex column, withmin-height: 0so §28 does not bite. - 30c — the toolbar, measured at 749px inside 360. It scrolls sideways in its own box rather than being hidden: some of it (export, the map picker) works by tap perfectly well, and a control you can see and not use is more honest than one that has vanished.
-
30d —
.pm-modalpromoted to a full‑screen sheet. Fourth module to roll its own modal class, and as always nothing in the measurements complains: a 90%‑wide centred box is perfectly contained. - 30e — settings, six columns (Shape · Name · Colour · Order · Active · Actions) as a card feed, with §21 labels on colour, order and active. The shape swatch rides beside the name rather than taking a line.
⭐ Zero new locale keys. The sheet button reads process-mapper.nav.processes — the module's own name for that list, already translated wherever the namespace exists.
-
All three pages contained at 360px, from
docScrollW=837. - Each has a scroller that reaches its end (§28, now part of the routine rather than an afterthought): help 10,952px, settings 344px, and the mapper's canvas panned to x=1188 of 1546.
-
The sheet driven open in BOTH sidebar modes — the default and the hover preference — landing at
left: 0, 310px,visible, withelementFromPointat its centre returning the panel rather than the scrim, six processes listed, and tapping one closing it. -
Desktop control at 1100px: the button is
display: none, the body attribute is absent, the toolbar'soverflow-xis back tovisible, settings is a real<table>withtable-header-group, and zerodata-mobile-labelis stamped anywhere. - 🔑 Problem Management measured as a positive control at 360px and 1100px, because this round writes rules against a class it shares. Unchanged at both:
static grid w=360andstatic block w=250. -
The §25 audit: 83 files, +166/−166, every line a
?v=bump; the module's own diff is three pages × three lines of opt‑in.
- Authoring on a phone. Deliberate, and explained at the top.
-
Problem Management's LAYER 22 block is unscoped. It is wrong in principle even though nothing is broken today — the next module whose classes start
pm-will hit it too. It needs a module marker on Problem Management's pages, which is its own small round.
- Mobile‑Friendly · Techniques & Tricks
- Process Mapper — what the module does