Which side the message takes
Targets at each edge of the screen, between two fixed rails, and a step with nothing to point at, so the message takes whichever side has room or docks at the foot.
const story = { id: 'message-sides', steps: [ { id: 'below', target: '[data-intro]', message: 'Below is tried first: under the thing it describes is the least ' + 'surprising place for a message. There is room under this card on ' + 'a screen tall enough, and the box sits there. On a shorter one it ' + 'does not fit, and the box takes the next side tried, above.', }, { id: 'above', target: '[data-milestone]', message: 'This card was below the fold when the step was drawn, so there ' + 'was no screen under it and the box went above — picked once, ' + 'from where the card was. Scroll down to meet it: the box rides ' + 'with the card the whole way, and no script runs while it does.', }, { id: 'beside-right', target: '[data-tools]', message: 'Above and below this rail there is almost no viewport, so the ' + 'box takes the first side with room — the right, on a screen wide ' + 'enough to hold it there. On a narrower one no side has room, and ' + 'the box falls back to below.', }, { id: 'beside-left', target: '[data-inspector]', message: 'The same choice from the other edge. The right side is off the ' + 'screen this time, so the box takes the left, the last side tried ' + '— on a screen wide enough to hold it there. On a narrower one no ' + 'side has room, and the box falls back to below.', }, { // A step that points at nothing cuts nothing, so there is no hole // for the box to sit beside and no anchor to hang it on. Docking at // the foot of the viewport is that case — and DESIGN.md, **Browser // support**, is where the same place is reached the other way. id: 'docked', message: 'Rendering the PDF… Nothing is pointed at, so nothing is cut, ' + 'and a box with no hole to sit beside docks at the foot of the ' + 'viewport instead. It stays there rather than pretending to have ' + 'an anchor it would drift away from.', awaits: 'export-finished', onEnter: () => { void renderExport() }, }, { id: 'exported', target: '[data-status]', message: 'And back where it started: the export landed near the top of ' + 'the inspector, there is room under it again, and the first side ' + 'tried is the one that wins.', }, ],} satisfies LekoStory// The application's own export, in the place an application would put it —// DESIGN.md, **Signals and steps**.renderExport = async () => { await new Promise((resolve) => setTimeout(resolve, 2800)) at('[data-status]').textContent = 'PDF ready.' leko.reached('export-finished')}