Docs/API mismatches and gaps found while migrating Pulse onto the design system #1

Open
opened 2026-09-08 22:17:20 -04:00 by jared · 0 comments
Owner

Found while migrating Pulse (LotusGuild/pulse, issue #2) onto web_template@bbec859
(base.css/base.js v1.2). Each item below cost debugging time or forced a downstream workaround.
Happy to send PRs for any of them.

1. node/layout.ejs — en-dash comment delimiters make the file unrenderable

Lines 1 and 29 open/close the header comment with <%– / –%> (U+2013 EN DASH) instead of
<%# / %>. EJS does not recognise those, so ejs.renderFile('node/layout.ejs', …) throws
immediately — the layout cannot be used as shipped. Pulse had to vendor a fixed copy.

$ sed -n '1p;29p' node/layout.ejs | cat -A | head
<%M-bM-^@M-^S$          <- <%–
M-bM-^@M-^S%>$          <- –%>

Fix: <%#%>.

2. README documents .lt-modal-backdrop; the CSS ships .lt-modal-overlay

README's modal example uses <div class="lt-modal-backdrop" …>. base.css defines only
.lt-modal-overlay (and .lt-modal-overlay.is-open), and lt.modal.open/close toggle
is-open on that class. Copying the README example produces a modal that never displays.

3. README documents .lt-alert-warning; the CSS ships .lt-alert--warning

README ("Types: lt-alert-info, lt-alert-success, lt-alert-warning, lt-alert-danger")
does not match base.css, which defines the double-dash BEM modifiers
.lt-alert--warning, .lt-alert--error, .lt-alert--success, .lt-alert--purple.
There is no --info and no --danger at all; the single-dash names are all no-ops.
Suggest either aliasing the single-dash names in CSS or fixing the README, and adding
an --info variant (or documenting that --purple plays that role).

4. README documents .lt-field-hint / .lt-field-error; the CSS has .lt-form-hint and no error style

  • .lt-field-hint (README line ~311) does not exist; the real class is .lt-form-hint.
  • .lt-field-error is not defined in base.css at all, and there is no
    invalid-input state (e.g. .lt-input.is-invalid) either — yet inline validation is
    a basic need for every form in the system. Pulse ships its own:
.lt-field-error { color: var(--accent-red); font-size: 0.72rem; letter-spacing: 0.02em; margin-top: 4px; }
.lt-input.is-invalid, .lt-textarea.is-invalid, .lt-select.is-invalid { border-color: var(--accent-red); }

Please consider adopting these upstream so apps stop re-inventing them.

5. No .lt-modal-lg

base.css ships .lt-modal-xs (280px) and .lt-modal-sm (360px) plus the .lt-modal
default (width: min(520px, 92vw), capped at max-width: 640px). There is no large
variant, but wide modals are common (JSON editors, log viewers, side-by-side compare).
Pulse defines one locally:

.lt-modal.lt-modal-lg { width: min(900px, 95vw); max-width: 900px; }
@media (max-width: 767px) { .lt-modal.lt-modal-lg { max-width: 96vw; } }
@media (max-width: 479px) { .lt-modal.lt-modal-lg { max-width: 100vw; } }

Note the two media queries are required because the section-78 caps
(.lt-modal { max-width: 96vw / 100vw }) lose on specificity to any .lt-modal.lt-modal-*
selector — worth keeping in mind if -lg is added upstream.

6. lt.pagination — README option names do not match the implementation

README:

lt.pagination.init(el, { total: 100, pageSize: 10, current: 1, onChange(page) {} });

Implementation (module 55): { total, perPage = 10, page = 1, onChange, maxBtns = 7 }.
pageSize and current are silently ignored, so the documented call always renders
page 1 with the default 10-per-page. Either rename the options or fix the README
(and document maxBtns).

7. lt.init ignores the documented csrf and skipBoot options

README documents:

lt.init({ skipBoot: false, csrf: 'token',  });

ltInit only reads { boot, bootName, tooltip, accordion, alerts, clipboard, sidebar, submenus }.
skipBoot: true does nothing (the real switch is boot: false), and csrf: 'token' is
dropped, contradicting "CSRF token is read from <meta name="csrf-token"> or set via
lt.init({ csrf: 'token' })".

8. lt.ws.connect gives up permanently after maxRetries (default 10)

With reconnect: true, maxRetries defaults to 10 and the backoff is
min(reconnectDelay * 1.5^(n-1), 30000), so a page loses live updates for good after
roughly 5 minutes of server downtime — with no further attempts and no way to resume
short of a reload. For a dashboard left open overnight this is the wrong default.

Suggestions: default to unlimited retries (keep the 30 s backoff cap), and/or expose a
reconnectNow() on the handle plus an onGiveUp callback so the app can surface a
"reconnect" affordance. Pulse currently passes maxRetries: Number.MAX_SAFE_INTEGER.

Found while migrating **Pulse** (`LotusGuild/pulse`, issue #2) onto `web_template@bbec859` (base.css/base.js v1.2). Each item below cost debugging time or forced a downstream workaround. Happy to send PRs for any of them. ## 1. `node/layout.ejs` — en-dash comment delimiters make the file unrenderable Lines 1 and 29 open/close the header comment with `<%–` / `–%>` (U+2013 EN DASH) instead of `<%#` / `%>`. EJS does not recognise those, so `ejs.renderFile('node/layout.ejs', …)` throws immediately — the layout cannot be used as shipped. Pulse had to vendor a fixed copy. ``` $ sed -n '1p;29p' node/layout.ejs | cat -A | head <%M-bM-^@M-^S$ <- <%– M-bM-^@M-^S%>$ <- –%> ``` **Fix:** `<%#` … `%>`. ## 2. README documents `.lt-modal-backdrop`; the CSS ships `.lt-modal-overlay` README's modal example uses `<div class="lt-modal-backdrop" …>`. `base.css` defines only `.lt-modal-overlay` (and `.lt-modal-overlay.is-open`), and `lt.modal.open/close` toggle `is-open` on that class. Copying the README example produces a modal that never displays. ## 3. README documents `.lt-alert-warning`; the CSS ships `.lt-alert--warning` README ("Types: `lt-alert-info`, `lt-alert-success`, `lt-alert-warning`, `lt-alert-danger`") does not match `base.css`, which defines the double-dash BEM modifiers `.lt-alert--warning`, `.lt-alert--error`, `.lt-alert--success`, `.lt-alert--purple`. There is no `--info` and no `--danger` at all; the single-dash names are all no-ops. Suggest either aliasing the single-dash names in CSS or fixing the README, and adding an `--info` variant (or documenting that `--purple` plays that role). ## 4. README documents `.lt-field-hint` / `.lt-field-error`; the CSS has `.lt-form-hint` and no error style - `.lt-field-hint` (README line ~311) does not exist; the real class is `.lt-form-hint`. - `.lt-field-error` is not defined in `base.css` at all, and there is no invalid-input state (e.g. `.lt-input.is-invalid`) either — yet inline validation is a basic need for every form in the system. Pulse ships its own: ```css .lt-field-error { color: var(--accent-red); font-size: 0.72rem; letter-spacing: 0.02em; margin-top: 4px; } .lt-input.is-invalid, .lt-textarea.is-invalid, .lt-select.is-invalid { border-color: var(--accent-red); } ``` Please consider adopting these upstream so apps stop re-inventing them. ## 5. No `.lt-modal-lg` `base.css` ships `.lt-modal-xs` (280px) and `.lt-modal-sm` (360px) plus the `.lt-modal` default (`width: min(520px, 92vw)`, capped at `max-width: 640px`). There is no large variant, but wide modals are common (JSON editors, log viewers, side-by-side compare). Pulse defines one locally: ```css .lt-modal.lt-modal-lg { width: min(900px, 95vw); max-width: 900px; } @media (max-width: 767px) { .lt-modal.lt-modal-lg { max-width: 96vw; } } @media (max-width: 479px) { .lt-modal.lt-modal-lg { max-width: 100vw; } } ``` Note the two media queries are required because the section-78 caps (`.lt-modal { max-width: 96vw / 100vw }`) lose on specificity to any `.lt-modal.lt-modal-*` selector — worth keeping in mind if `-lg` is added upstream. ## 6. `lt.pagination` — README option names do not match the implementation README: ```js lt.pagination.init(el, { total: 100, pageSize: 10, current: 1, onChange(page) {} }); ``` Implementation (module 55): `{ total, perPage = 10, page = 1, onChange, maxBtns = 7 }`. `pageSize` and `current` are silently ignored, so the documented call always renders page 1 with the default 10-per-page. Either rename the options or fix the README (and document `maxBtns`). ## 7. `lt.init` ignores the documented `csrf` and `skipBoot` options README documents: ```js lt.init({ skipBoot: false, csrf: 'token', … }); ``` `ltInit` only reads `{ boot, bootName, tooltip, accordion, alerts, clipboard, sidebar, submenus }`. `skipBoot: true` does nothing (the real switch is `boot: false`), and `csrf: 'token'` is dropped, contradicting "CSRF token is read from `<meta name="csrf-token">` or set via `lt.init({ csrf: 'token' })`". ## 8. `lt.ws.connect` gives up permanently after `maxRetries` (default 10) With `reconnect: true`, `maxRetries` defaults to `10` and the backoff is `min(reconnectDelay * 1.5^(n-1), 30000)`, so a page loses live updates for good after roughly 5 minutes of server downtime — with no further attempts and no way to resume short of a reload. For a dashboard left open overnight this is the wrong default. Suggestions: default to unlimited retries (keep the 30 s backoff cap), and/or expose a `reconnectNow()` on the handle plus an `onGiveUp` callback so the app can surface a "reconnect" affordance. Pulse currently passes `maxRetries: Number.MAX_SAFE_INTEGER`.
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: LotusGuild/web_template#1