Repository navigation
merge/probar history - #1
Merged
Merged
Conversation
imanimanyara
commented
Oct 1, 2026
Member
- Initial release
- Add CLI/terminal renderer, segments, multi-progress, error UX, i18n
- Document v0.6.0, add multi-progress/CLI examples and demos
- Redesign the demo as an Apple-style site (landing + playground + build)
- Trim leading blank from extracted changelog release body
- Fix gradient rendering bugs; broaden Web Component/React; update docs
- Harden headless/terminal paths and fix audit findings
- Fix headless toJSON crash; latch group done; tidy bind interval cleanup
- Redesign the leading peg as a clean shine; add inline status messages
- Remove peg; add configurator, multicolor, data-attrs; fix glow/tooltip/segments
- Harden mountTo resolution; fix attribute drift; doc cleanups
- Make height fill the container; fix demo grey strip; redesign configurator
- Default height 6px; document height units (px/rem/em/%/all)
- Docs: document the full current option/method surface
- Group: keep completed children visible instead of leaving empty rows
- Design-system + architecture consistency sweep
- Round glow + add border; success completes to 100%; one visual fixture
- Rebuild the demo site on Webpixels CSS; keep the library framework-free
- Fix radius-attribute coercion, trackXHR leak, and degenerate geometry
- Fix data-tabar-colors parsing for functional colors; tailwind example reset
- Playground: fixed-position overlay clears itself (autoHide on done)
- Stop publishing the internal types/api-check.ts fixture to npm
- Route vulnerability disclosure to security@simtabi.com
Tabar — a dependency-free, framework-agnostic progress bar. Linear bars (top/bottom/left/right/inline) and circular SVG rings, all sharing the same configuration, themes, gradients, glow, stripes, tooltips, persistence and API. Upload/download tracking with smoothed speed and ETA; an error state; reactivity via bind() and a reactive React hook; JSON + API config with two-way reporting; events (instance, global bus, DOM); localization (i18n); a Web Component; full TypeScript types; and SCSS-sourced, responsive styles.
Terminal (ANSI) renderer + `tabar` CLI bin drive the same Tabar API headlessly in Node (TTY redraw / non-TTY lines, spinner, color, width). Multi-progress: segments on one bar (stacked + overlay with mode-aware aggregation) and a TabarGroup container of child bars with an auto-aggregated overall. Error UX: warning/success states, retry()/retryWith, stall detection, aria-live announcements, errorTimeout. i18n: ten built-in locales incl. Arabic with RTL-aware linear fill and circular sweep. complete/attempts getters. New entries: ./node, ./terminal, ./group. Headless goto() bug fixed.
Bump to 0.6.0 with a CHANGELOG entry covering the terminal/CLI renderer, segments, TabarGroup, error UX and full i18n/RTL. Add a multi-progress/CLI docs page and README coverage (web+CLI, segments, feedback). New examples (cli.js, multi-progress.html) and demo sections for segments, groups and state feedback.
Replace the single demo page with a marketing site under site/: a hero + features + live shapes showcase landing page and a dedicated, grouped playground covering every capability (shapes, themes, transfers, segments, groups, states, events). A small esbuild+Sass step builds site/ to the git-ignored site/dist/; serve.js serves it with a repo-root fallback for examples/ and dist/. Adds cli.js + multi-progress.html examples and removes the old demo/.
The release workflow already passes the tagged version's CHANGELOG section as the GitHub release body (body_path) alongside generate_release_notes; skip leading blank lines so the body starts at the first content, and echo a preview in the log.
Gradients: - The 'gradient' theme is now a real computed fill, so setGradientType/Shape/ Position/Angle apply to it (previously a no-op: the SCSS fell back to a hardcoded linear-gradient). - A circular 'gradient' ring now paints an SVG <linearGradient> stroke instead of rendering solid. - Anchor any gradient fill to the full track via --tabar-fill-scale so its colors stay put as the bar grows instead of compressing/shifting. Removed the redundant gradient-theme rule whose `background` shorthand reset the anchor; rainbow keeps its scroll (background-repeat). Web Component: accept `segments` as a JSON attribute plus the v0.6.0 options (segment-mode, aggregate, announce, stall-timeout, gradient-shape/position, direction, locale). React hook: re-render on error/warning/success and expose `complete`. Docs: refresh CONTRIBUTING (new layout/scripts), installation (entry points, Node/CLI, SSR), configuration (segments/feedback options, new vars + data attrs), theming (gradient theme controls + anchoring + circular), events (new events + ten built-in locales).
Fix a real crash: indeterminate() touched the DOM with no headless guard, so it threw under the terminal renderer. Remove the shared aria-live region with the last bar (was orphaned); guard debounced persistence against post-destroy writes; mint monotonic segment ids (no collision after remove+add); restore a 100% persisted bar as done. Terminal: don't flood non-TTY output when active or indeterminate, gate the spinner to TTY and unref its timer so the process can exit. CLI: a bare number without --total is a percentage. <tabar-bar>: empty numeric attrs are unset and persist accepts a JSON object; useTabar re-renders on error/warning/success and exposes complete. Group children accept a weight.
Validation surfaced another headless crash: toJSON() referenced the browser-only
`Element` global unguarded, throwing in Node (breaking config export and
fromJSON round-trips there). Guard it with `typeof Element !== 'undefined'`.
TabarGroup now emits `done` exactly once per completion (re-arming when a new
incomplete child is added) instead of on every child completion while already
done. bind({interval}) is no longer tracked in the timeout set — destroy() runs
the unbind, which clears it with clearInterval. Adds Node-env regression tests.
The peg was a fixed 100px box-shadow rectangle colored with --tabar-color and tilted rotate(2deg) translateY(-2px) — on tall or gradient bars it rendered as a clashing, offset rectangle (the reported artifact). Replace it with a soft, color-agnostic leading-edge shine clipped to the fill (RTL + vertical aware, --tabar-peg to recolor). Add inline status messages: `messages` maps each state (plus a `default`) to a string or (percent, bar) => string shown on the bar, with setMessages/ setMessage, a `message` getter, messageAlign/messageColor and --tabar-message-* CSS vars. Content is rendered via textContent (no HTML injection). Wired into the site's upload/states showcase and the playground. Types, docs and tests.
…p/segments
Two rounds of styling/config work consolidated on this branch:
Bug fixes
- Tooltip never showed: the wrapper only opened overflow for glow, clipping the
tip rendered above the bar; setTooltip() also attached the tip to the SVG arc
for circular rings. Open overflow on [data-tooltip-tabar-on] and attach to the
wrapper for circular.
- Glow was a faint, clipped shadow: replace it with a layered, --tabar-glow-size
driven halo that bleeds onto surroundings; demo stages no longer clip it.
- Segments could not advance past three chunks (a playground bug): advance the
bar's live segments on the 0-100 scale instead of three hardcoded ones.
Features
- Remove the leading-edge "peg" entirely (option, element, CSS, --tabar-peg).
- Full live configurator in the playground driving the whole option surface,
with a generated code snippet and a dynamic multi-color stop editor.
- Centered edge positions (top/bottom/left/right-center) and a configurable
fixed-bar length/offset (--tabar-length/--tabar-offset).
- Multiple colors: a `colors` multi-stop alias, colorMode gradient|bands (hard
blocks) and colorAnimate (scrolling), with matching setters.
- Circular options: trackColor, lineCap, startAngle, clockwise, glowSize.
- Declarative config: expand the <tabar-bar> attribute surface and read
data-tabar-* off the mount element for plain instances (JS options win);
coercion shared via src/attrs.js so the paths can't drift.
- Group the demo-site assets under assets/{css,js,img} in site/ and site/dist/.
Tests/CI
- Add Playwright: a deterministic visual gallery + fixed-position fixture and a
functional click-through of every control, run on light/dark in the official
Playwright Linux container with committed baselines; new CI job.
- Expand unit coverage (tooltip, positions/length, multicolor, circular, data
attributes, >3-segment advance) and a web-component test.
Follow-up audit fixes: - An invalid `mountTo` selector string threw a DOMException from the constructor (both the new data-attribute resolver and `_resolveHost`). Guard `document.querySelector` and fall back to the default mount; `_resolveHost` now reuses the shared resolver. - attribute drift: `max` and `debug` were real options but missing from the shared attribute list, so they couldn't be set via `<tabar-bar>` or `data-tabar-*`; add them. Remove the dead `min` coercion key (no such option). - Make `setClockwise`'s `--tabar-flip` formula match `_applyTheme`'s verbatim. - Fix a stale `site/visual.js` path in CONTRIBUTING after the asset move. - Tests for invalid-selector fallback and data-tabar-max/-debug.
…rator - height: a linear bar's `height` now accepts any CSS length (e.g. '100%') so it can fill its host; numbers stay px, circular keeps a numeric stroke. Settable via setHeight() and the `height`/`data-tabar-height` attribute (number or string). - Demos: every inline demo bar now fills its track (height:'100%') and the track surface is the bar's only track, so the grey "bottom border" strip below a shorter bar is gone. - Configurator: redesigned the section — a preview card and a grouped action toolbar (Progress / States / View) instead of one long button row; refined the mini-button styling. The preview host sizes to the configured thickness (and drops the track box for circular rings). - Tests for string/percentage height (incl. data-tabar-height) and circular staying numeric.
- Bump the default `height` from 3px to 6px for a more visible bar out of the box (SCSS $height, DEFAULTS, and the fallbacks in _applyTheme/setHeight). - Document that a linear bar's `height` already accepts any CSS length — number → px, string passes through (rem/em/%/vh/calc) — with guidance on which to pick: px for predictable chrome (the default), rem to scale with type, % to fill a sized host. Circular height stays numeric px. - Tests: default is 6px; rem/em/% all honored.
- README: feature bullets now cover center positions + length, multi-color modes (bands/animated), the bleeding glow and flexible height; integration bullet notes data-tabar-* attributes; the API-at-a-glance table gains the new setters (setLength/setOffset/setTrackColor/setLineCap/setStartAngle/setClockwise, setColors/addColorStop/removeColorStop/setColorMode/setColorAnimate, setGlowSize). - integration.md: rewrote the declarative-config section — the full <tabar-bar> attribute surface plus the plain-mount data-tabar-* fallback and the JS-only function-option caveat. - architecture.md: a Declarative configuration note covering the shared src/attrs.js coercion and the data-attr-under-JS merge order. - theming.md: height defaults to 6px and accepts px/rem/em/% (cross-links to the new configuration.md "Height units" guidance).
A TabarGroup child inherited the default autoHide, so on done() it hid its bar (and reset to 0) while its row kept the reserved min-height — producing a growing stack of empty white rows after downloads finished, and dropping the overall aggregate. Default group children to autoHide:false so they persist at their final value (filled rows, accurate aggregate); opt back in per-child with autoHide:true. Regression test added.
Library
- Circular setHeight/setSize are live now: recompute the ring radius/
circumference and repaint, so changing stroke/diameter no longer mis-scales
the arc (_recomputeRing). setShape rebuilds linear↔circular preserving state.
- Broader, consistent API: setSize/setShape/setPosition/setDirection/setMax/
setMinimum/setSegmentMode/setZIndex, read-only getters for every option, and
TabarGroup setChildDefaults/setOverallDefaults. Document colors>gradient>theme
precedence and the glow/striped-as-modifier model.
- Fix: data-tabar-length="240" now reads as 240px (length joined the DIMENSION
set); React useTabar syncs on start/resume/show/hide/stall/retry; the CLI
guards against a trailing value flag.
Tooling
- Types for every export (added terminal/element .d.ts, wired into exports);
license banner on minified bundles; serve.js MIME map + PORT parse; lint the
demo JS; opt-in coverage (@vitest/coverage-v8 + test:coverage).
Site design system (Apple-rigorous, tokenized, accessible)
- Token layer: 4/8px spacing grid, type/radius/leading/tracking scales,
breakpoint vars; replaced scattered magic numbers; unified card/demo/panel
padding and button/input treatments.
- Accessibility: :focus-visible rings on all controls, dark-mode muted-text
contrast fix, full prefers-reduced-motion coverage, de-duplicated dark theme
(shared mixin), aria-pressed theme toggle + aria-live event log.
- Favicon + Open Graph/Twitter cards (assets/img/{favicon,og}.svg).
Tests: new coverage for the setters/getters, circular geometry recompute,
setShape rebuild, and numeric data-tabar-length.
- Glow now follows the bar's rounded shape (rounds the fill to --tabar-radius) instead of rendering a hard rectangle, and sits outside any border. - Add a configurable linear-track border: borderWidth/borderStyle/borderColor + setBorder()/setBorderColor, --tabar-border-* vars, data-tabar-border-* attrs, types, and a configurator group. Reset for circular (a box round a ring is wrong). - succeed() completes the bar to 100% (green) without auto-hiding; error()/warn() keep their current value. set()/reset() still clear transient states. - Configurator color editor seeds 3 colors and keeps a 3-color minimum for bands. - Consolidate the two visual fixtures into one visual.html: fixed/center positions render inside contained "viewport-frame" tiles (a transform ancestor scopes position:fixed); delete visual-fixed.html/.js; regenerate baselines. - Docs (README/configuration/theming/integration/events), a data-tabar-* bands+border example, and tests for the new border/success and the previously-untested setters.
Migrate the demo's presentation to Webpixels CSS (a Bootstrap-based utility + component framework) instead of a hand-rolled design system, and polish the landing/playground for consistent, Apple-style rhythm. The library is untouched and still ships zero CSS-framework dependency. - Vendor @webpixels/css locally: build-site.js copies dist/all.css -> site/dist/assets/css/webpixels.css (offline/CI-deterministic, no runtime CDN). - index.html + playground.html rebuilt with Bootstrap/Webpixels classes (navbar, card, btn, form-control/select/range/check, grid, utilities); every id / data-act / data-testid / data-sc hook preserved. - playground.js control generator emits Bootstrap form classes; landing.js + playground.js theme toggle drives Bootstrap's data-bs-theme (persisted). - styles.scss slimmed to a thin demo-glue layer over --x-* tokens; brand the primary token + button blue for contrast; adaptive CTA band; frosted sticky navbar; restrained example-card hover. - visual.html is self-contained (loads no site/framework CSS) so screenshot baselines stay stable; examples/webpixels.html added. - Fix landing inconsistencies: balanced 3x3 features grid (added Persistence), py-lg-12 spacing, and a pre-paint inline script to avoid the dark-mode FOUC. - Docs (README/CONTRIBUTING/CHANGELOG) note the demo=Webpixels vs library=BEM, framework-free split.
- cornersToCss now parses string corner values, so radius/innerRadius set via <tabar-bar>/data-tabar-*/JSON apply instead of silently falling back to 0 (bare number -> px, comma/space list -> per-corner, other CSS length passes through). - trackXHR removes its progress/load/error/abort listeners on completion and on destroy() (registered in _unbinds) — no more leaked XHR/instance mid-transfer. - normalizeValue guards max <= 0 (no divide-by-zero corruption); circular radius clamps to >= 0 when size <= stroke (no invalid SVG arc). - Consolidate the CHANGELOG [Unreleased] into single Added/Changed/Removed/Fixed sections (was three Added blocks); ignore local scratch-*.mjs harnesses. - Tests for each fix.
… reset
- coerceAttr splits the colors/gradient attribute on top-level commas only, so
rgb()/hsl()/color-mix() values keep their inner commas
("rgb(1,2,3),#fff" -> ['rgb(1,2,3)', '#fff']).
- examples/tailwind.html: Reset chained .show() onto set()'s Promise return,
which threw — split into two statements.
- Tests for the colors attribute.
opensource@simtabi.com is the community address; security@simtabi.com is the dedicated disclosure inbox per the org convention, kept separate so a report is never buried in a feature-request thread.
probar (2020) is tabar's predecessor and lives on GitHub as simtabi/probar, which becomes simtabi/tabar. Merging its history in as an ancestor keeps all 30 of its commits reachable and gives the two histories a common base, so tabar can land on that repository through a normal pull request. probar's three files move unchanged to legacy/probar/; tabar's own files are untouched, and package.json's files whitelist keeps legacy/ out of the npm package.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Unresolved packaging, Web Component, group lifecycle, terminal reuse, and documentation defects affect advertised public behavior.
Review effort: Balanced
Findings: 9
Open (10)
Mark distributed element entry as side-effectful · New Guard Web Storage access during initialization · New Restrict initial attribute parsing to recognized options · New Use live setters for structural and positional attributes · New Handle invalid selectors safely in TabarGroup · New Emit group completion when removing the final unfinished child · New Initialize snapshot.complete to a boolean · New Clear TTY lines even when colors are disabled · New Re-arm finished state when reusing completed bars · New Clarify opt-in network behavior in security policy · New
What changed in this PR
This PR establishes Tabar’s modern v0.6 codebase, combining browser, terminal, framework integration, documentation, demos, testing, packaging, and project governance.
Changes:
- Adds terminal, group, React, Web Component, and declarative-attribute integrations.
- Introduces comprehensive unit/E2E testing, build tooling, package exports, and CI/release automation.
- Adds a redesigned demo site, examples, API documentation, and legacy ProBar history.
| File | Description |
|---|---|
vitest.config.js |
Configures unit tests and coverage. |
types/terminal.d.ts |
Declares terminal exports. |
types/react.d.ts |
Declares the React hook. |
types/node.d.ts |
Declares Node and terminal APIs. |
types/group.d.ts |
Declares group APIs. |
types/element.d.ts |
Declares the Web Component. |
types/api-check.ts |
Exercises public declarations. |
tsconfig.json |
Configures declaration type-checking. |
test/terminal.test.js |
Tests terminal and headless behavior. |
test/react.test.js |
Tests React integration. |
test/group.test.js |
Tests group aggregation and lifecycle. |
test/element.test.js |
Tests declarative attributes. |
src/terminal.js |
Implements ANSI terminal rendering. |
src/react.js |
Implements the React hook. |
src/node.js |
Defines the Node entry point. |
src/group.js |
Implements grouped progress bars. |
src/element.js |
Implements <tabar-bar>. |
src/attrs.js |
Centralizes attribute coercion. |
site/visual.html |
Provides the visual fixture page. |
site/index.html |
Adds the marketing landing page. |
site/assets/scss/styles.scss |
Styles the demo site. |
site/assets/js/visual.js |
Builds visual test scenarios. |
site/assets/js/landing.js |
Drives landing-page interactions. |
site/assets/img/og.svg |
Adds social-preview artwork. |
site/assets/img/favicon.svg |
Adds the site favicon. |
site/assets/img/.gitkeep |
Documents the image directory. |
SECURITY.md |
Defines vulnerability reporting. |
scripts/serve.js |
Serves demos locally. |
scripts/build.js |
Bundles package entry points. |
scripts/build-site.js |
Builds the marketing site. |
scripts/build-css.js |
Compiles library styles. |
README.md |
Documents features and usage. |
playwright.config.js |
Configures browser testing. |
package.json |
Defines packaging, exports, and scripts. |
LICENSE |
Adds the MIT license. |
legacy/probar/readme.md |
Preserves legacy documentation. |
legacy/probar/ProBar.js |
Preserves the legacy implementation. |
examples/webpixels.html |
Adds a Webpixels example. |
examples/tailwind.html |
Adds a Tailwind example. |
examples/no-framework.html |
Adds a vanilla example. |
examples/multi-progress.html |
Demonstrates segments and groups. |
examples/cli.js |
Demonstrates terminal usage. |
examples/bootstrap.html |
Adds a Bootstrap example. |
eslint.config.js |
Configures JavaScript linting. |
e2e/visual.spec.js |
Adds visual regression coverage. |
e2e/playground.spec.js |
Tests playground interactions. |
docs/tools/theming.md |
Documents visual customization. |
docs/tools/progress.md |
Documents transfers and reactivity. |
docs/tools/persistence.md |
Documents persisted state. |
docs/tools/multi-and-cli.md |
Documents groups and terminal usage. |
docs/tools/integration.md |
Documents API and framework integration. |
docs/tools/events.md |
Documents events and localization. |
docs/tools/concurrency.md |
Documents concurrent instances. |
docs/release.md |
Defines the release process. |
docs/installation.md |
Documents installation paths. |
docs/configuration.md |
Documents the option surface. |
docs/architecture.md |
Explains internal architecture. |
CONTRIBUTING.md |
Defines contributor workflows. |
CODE_OF_CONDUCT.md |
Adds community standards. |
CHANGELOG.md |
Records releases and current changes. |
bin/tabar.js |
Implements the command-line interface. |
.gitignore |
Excludes generated artifacts. |
.github/workflows/release.yml |
Automates releases and publishing. |
.github/workflows/ci.yml |
Adds test and visual CI. |
.github/PULL_REQUEST_TEMPLATE.md |
Adds the PR checklist. |
.github/ISSUE_TEMPLATE/feature_request.yml |
Adds feature-request intake. |
.github/ISSUE_TEMPLATE/config.yml |
Configures issue routing. |
.github/ISSUE_TEMPLATE/bug_report.yml |
Adds bug-report intake. |
.github/dependabot.yml |
Configures dependency updates. |
.editorconfig |
Defines editor formatting defaults. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+81
to
+84
| "sideEffects": [ | ||
| "*.css", | ||
| "./src/element.js" | ||
| ], |
Comment on lines
+8
to
+17
| const prefersDark = () => window.matchMedia?.('(prefers-color-scheme: dark)').matches; | ||
| const saved = localStorage.getItem('tabar-theme'); | ||
| root.setAttribute('data-bs-theme', saved || (prefersDark() ? 'dark' : 'light')); | ||
| const reflectTheme = () => themeBtn?.setAttribute('aria-pressed', String(root.getAttribute('data-bs-theme') === 'dark')); | ||
| reflectTheme(); | ||
| themeBtn?.addEventListener('click', () => { | ||
| const next = root.getAttribute('data-bs-theme') === 'dark' ? 'light' : 'dark'; | ||
| root.setAttribute('data-bs-theme', next); | ||
| localStorage.setItem('tabar-theme', next); | ||
| reflectTheme(); |
Comment on lines
+21
to
+25
| for (const name of this.getAttributeNames()) { | ||
| const key = toCamel(name); | ||
| const v = coerceAttr(key, this.getAttribute(name)); | ||
| if (v !== undefined) cfg[key] = v; | ||
| } |
| const coerced = coerceAttr(key, newValue); | ||
| if (key === 'value') this._bar.set(coerced); | ||
| else if (key === 'segments') this._bar.setSegments(coerced || []); | ||
| else this._bar.configure({ [key]: coerced }); |
Comment on lines
+34
to
+37
| const host = | ||
| options.mountTo instanceof Element | ||
| ? options.mountTo | ||
| : (typeof options.mountTo === 'string' && document.querySelector(options.mountTo)) || document.body; |
Comment on lines
+120
to
+121
| this._children.delete(id); | ||
| this._sync(); |
| export function useTabar(options = {}) { | ||
| const ref = useRef(null); | ||
| const barRef = useRef(null); | ||
| const [snapshot, setSnapshot] = useState({ value: 0, state: 'idle', stats: null }); |
| if (stopped) return; | ||
| const line = buildLine(); | ||
| if (isTTY) { | ||
| stream.write(`\r${color ? ANSI.clearLine : ''}${line}`); |
Comment on lines
+113
to
+120
| const onUpdate = () => { | ||
| paint(); | ||
| if (bar.state === 'indeterminate' && isTTY && !spinTimer) spin(); | ||
| else if (bar.state !== 'indeterminate') stopSpinner(); | ||
| }; | ||
| const onDone = () => { | ||
| if (finished) return; | ||
| finished = true; |
Comment on lines
+24
to
+25
| Tabar runs in the browser and has no runtime dependencies. It does not make network | ||
| requests. It does read and write to `localStorage`/`sessionStorage` when persistence is |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

