Commit Graph

699 Commits

Author SHA1 Message Date
Leonidas f1cdfcbc9b chore: nightly release 2026-06-18 ⚡ 2026-06-18 04:04:01 +00:00
Patrick bc471546ef fix(radio-group): restore native tab behavior (#1492)
* fix(radio-group): restore native tab behavior

* test(radio-group): cover disabled reset tab target
2026-06-18 00:48:00 +02:00
Ban117 7ada58e03d fix(select): select option with a falsy value on enter keypress (#1493)
selectActiveItem() guarded the commit with a truthiness check (if (value)), so an
option whose value is falsy (false, 0, '') was dropped: pressing Enter just closed
the panel without selecting. Check value !== null && value !== undefined instead, so
a defined falsy value is committed while a missing active item still closes. Applies
to both BrnSelect and BrnSelectMultiple.

Co-authored-by: Benjamin <benjamin@amcbanking.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 15:47:28 +02:00
moosme 01aeb5a231 feat(navigation-menu): add style support #1408 (#1490)
* feat(navigation-menu): add style support #1408

* fix: review

* feat(navigation-menu): add align input to navigation-menu-trigger

* add align example

* feat(navigation-menu): add navOffset

* docs(navigation-menu): update example ids

* feat(navigation-menu): add guard in updateAlign

* feat(navigation-menu): remove group from trigger

* feat(navigation-menu): remove unused data-popup-open classes

* navigation-menu doesn't have data-popup-open attribute

---------

Co-authored-by: Merlin <merlin.moos@oldendorff.com>
Co-authored-by: Marc Stammerjohann <8985933+marcjulian@users.noreply.github.com>
2026-06-17 15:43:07 +02:00
Ashley Hunter d2f40d3014 Merge pull request #1471 from PatrickLarocque/fix/overlay-lifecycle
refactor!: split dialog and overlay portal lifecycles
2026-06-17 10:16:35 +01:00
Leonidas b5e12f4140 chore: nightly release 2026-06-17 ⚡ 2026-06-17 04:12:35 +00:00
Ashley Hunter ecb098bb3d test: cover wait-for-element-animations helper
Active-animation collection (filtering finished, subtree, null-safety) and the
finish/fallback-timer behaviour that replaced the fixed close delay.
2026-06-16 23:56:56 +01:00
Ashley Hunter 35f1a92586 fix: avoid emitting on destroyed overlay/dialog outputs
Destroying a host while its overlay/dialog is open ran the onDestroy
forceClose(), which emits on closed$/stateChanged$. The subscriptions
forwarded those to the component outputs after the directive was destroyed,
logging NG0953 in dev mode. Set a destroyed flag (registered before the
forceClose teardown) and skip the emits once it is set.
2026-06-16 23:41:50 +01:00
Ashley Hunter 23f20bf4dd feat: restore overlay focus-into-content on open via opt-in autoFocus
Moving popover-backed controls off CDK Dialog dropped the dialog's
autoFocus: 'first-tabbable', so popovers no longer moved focus to their
content on open (form fields were left unfocused, comboboxes could not be
typed into immediately).

Add an opt-in autoFocus option to BrnOverlay that focuses the first tabbable
element once the content renders, and enable it in the popover defaults. The
select keeps focus on its trigger because its listbox has no tabbable element,
preserving the aria-activedescendant keyboard model. Re-expose the autoFocus
input on the helm popover wrapper and its CLI template, and refresh the docs
API snapshot.
2026-06-16 23:23:29 +01:00
Ashley Hunter cd932da378 fix(select): keep panel closed after committing a value with the keyboard
Address review feedback on the overlay lifecycle:

- the select trigger re-read its expanded state after selectActiveItem() had
  already closed the panel, so Enter/Tab fell through and re-opened the
  overlay via reopen(); capture the expansion state up-front so a commit no
  longer re-opens on the same keypress
- make the overlay id atomic (++overlaySequence) so the duplicate-id guard and
  the ref share the same counter, matching brn-dialog.service.ts
2026-06-16 23:23:29 +01:00
Ashley Hunter 2e14efcde5 fix(drawer): adapt drawer to the new dialog/overlay lifecycle
The drawer landed on main against the old BrnDialog API. Reconcile it with
this branch's refactor:

- override getPositionStrategy() for the directional position instead of the
  removed mutablePositionStrategy/positionBuilder members (matches BrnSheet)
- constrain BrnDrawerContent<T extends Record<string, unknown>> to satisfy
  BrnDialogContent's tightened generic
- drop the removed closeDelay-era 'delay' input from the drawer close wrapper
  and its CLI template
2026-06-16 23:23:29 +01:00
Ashley Hunter 0c3b653902 Merge origin/main into fix/overlay-lifecycle
Resolve brn-dialog.service.ts conflict: drop the deprecated injectBrnDialogCtx
alias (removed on main during the pre-1.0 audit) and keep the typed
injectBrnDialogContext with the unknown default.
2026-06-16 23:22:47 +01:00
moosme 263648ade1 feat(command): add style and rtl support #1399 (#1488)
* feat(command): add style and rtl support #1399

* fix: comments

* feat(command): remove custom data-hidden is built in

* remove important from rounded

* docs(command): fix typo

* fix(command): check has search input for separator

* otherwise shows multiple separator while searching in the scrollable example

---------

Co-authored-by: Merlin <merlin.moos@oldendorff.com>
Co-authored-by: Marc Stammerjohann <8985933+marcjulian@users.noreply.github.com>
2026-06-16 18:48:35 +02:00
moosme 61a546f24a Merge pull request #1476 from spartan-ng/pre-1.0-audit
chore(repo): pre-1.0 audit - overlay leak fixes, data-slot, CLI drawer, naming
2026-06-16 11:43:11 +02:00
Leonidas bd321c9ab0 chore: nightly release 2026-06-16 ⚡ 2026-06-16 04:12:33 +00:00
Ahmad Mehrabi 715499fe4e feat(date-picker): add Jalali (Persian) calendar support (#1429)
* feat(date-picker): add Jalali (Persian) calendar support

- Add pure Jalali calendar math algorithms (no npm packages)
- Add JalaliDate class with valueOf() for reliable calendar comparison
- Add BrnJalaliDateAdapter implementing BrnDateAdapter<JalaliDate>
- Add comprehensive unit tests for all adapter methods
- Add Persian (Farsi) calendar i18n with RTL layout
- Add Jalali date picker example to docs page
- Add Storybook story with Persian locale
- Extend TranslateService to support 'fa' language

* feat(date-picker): add Jalali (Persian) calendar support

Add pure Jalali calendar math, JalaliDate class, and BrnJalaliDateAdapter with tests.

Move example from component docs to blocks/calendar page per PR review.

* refactor: clean up jalali date-time code

- Deduplicate JALALI_MONTHS array in calendar i18n files
- snake_case to camelCase in PersianDate (gregorianDaysInMonth, jalaliDaysInMonth)
- Expand cryptic param names (j_y to jalaliYear, g_y to gregorianYear, etc.)
- Remove parseInt() no-ops on typed number params
- Remove getMonthName (i18n concern, not calendrical)
- Destructure tuples with descriptive names across adapter/date/persian-date
- Fix month+day add drift: clamp day after month step before day arithmetic

* style: fix long line formatting to pass nx format check

* fix(date-picker): resolve merge conflicts from upstream and stashed changes

Merge descriptive variable names (_constrain, parseInt, getMonthName,
full descriptive names) with upstream descriptive names. All tests pass.

* refactor: remove parseInt unwrapping and getMonthName, add PersianDate tests
2026-06-15 15:05:30 +02:00
copilot-swe-agent[bot] aaf29b4e05 chore(repo): merge main into pre-1.0-audit (resolve drawer brain version conflict) 2026-06-15 11:47:09 +00:00
Ashley Hunter 603d213799 fix(resizable): end drag on touchcancel
A touch drag interrupted by the system fires touchcancel instead of touchend, so the drag teardown
(listeners + cursor) never ran until the next drag or destroy. Listen for touchcancel alongside
touchend and remove it in cleanup. Adds a regression test.
2026-06-15 08:04:00 +01:00
Leonidas 7da9d3e4c3 chore: nightly release 2026-06-15 ⚡ 2026-06-15 04:22:11 +00:00
Ashley Hunter f533fa426c refactor(dialog): remove deprecated injectBrnDialogCtx
Drop the deprecated `injectBrnDialogCtx` in favour of `injectBrnDialogContext`, which the helm
dialog, docs app and storybook already use exclusively. Removing it before 1.0 avoids carrying the
alias on the stable line. The `BrnDialogContext` type it returned stays - it is still used inside
the service.
2026-06-14 23:43:51 +01:00
Ashley Hunter 4ee05f9c50 fix(drawer): release drag listeners and reset timeout on destroy
_cleanup removed only the pointermove listener; the pointerup/pointercancel listeners (registered
with { once: true }) were left attached to document, so a destroy-during-drag - or a normal end
where pointercancel never fired - kept this directive pinned to document until the next global
pointer release. The 500ms _resetDrawer timeout was also fire-and-forget, leaving a stale style
write on detached elements when destroyed within that window.

Remove both listeners in _cleanup, and track the reset timeout so it can be cancelled on destroy.
The timeout is intentionally only cleared on destroy, not in _cleanup, so the normal snap-back
path (which schedules the timeout immediately before _cleanup runs) still clears the transition.
2026-06-14 23:09:41 +01:00
Ashley Hunter a16b251a26 fix(resizable): tear down drag listeners when destroyed mid-drag
startResize attaches mousemove/touchmove/mouseup/touchend listeners to document, removed only
in the drag-end handler. If the group is destroyed mid-drag (navigation, conditional removal),
those listeners stay attached to document - which is never garbage-collected - pinning the
directive and firing against a torn-down view, and the body cursor is left stuck on the resize
cursor.

Hoist the cleanup into a single teardown stored on the instance: it detaches the four document
listeners, cancels any queued animation frame and restores the cursor. It runs on normal
drag-end and from a DestroyRef.onDestroy hook, and also clears a stale in-flight drag before a
new one starts.
2026-06-14 23:02:40 +01:00
Ashley Hunter 935e4c2404 fix(avatar): give image/fallback distinct prefixed exportAs names
BrnAvatarImage/BrnAvatarFallback and their helm wrappers all used the same
unprefixed exportAs ('avatarImage'/'avatarFallback'). Since the helm directive
host-applies the brain one on the same <img>, a template ref was ambiguous, and
the names broke the brn*/hlm* convention every other exportAs follows. Rename to
brnAvatarImage/brnAvatarFallback and hlmAvatarImage/hlmAvatarFallback before the
exportAs surface is locked at 1.0. Regenerated the CLI avatar templates to match.
2026-06-14 22:26:34 +01:00
mehrabix 94a57f4eee Merge remote-tracking branch 'origin/main' into feat/drawer-component 2026-06-14 18:49:54 +03:30
mehrabix 4188133dd8 fix(drawer): remove dead HlmDrawerHandle, fix iOS touch-action, fix _openTime cooldown
- Remove unused HlmDrawerHandle directive
- Add static touch-action: none to .spartan-drawer-content in all
  style files so iOS Safari does not hijack the gesture before the
  pointerdown handler fires
- Set _openTime via effect on dialog state open instead of on first
  pointerdown, so the 500ms cooldown starts when the drawer opens
  rather than eating the user's first drag
2026-06-14 18:40:26 +03:30
mehrabix 112f9d12b2 fix(drawer): prevent pointer capture on tap to fix button clicks on touch
- Replace preventDefault() on pointerdown with conditional touch-action:
  none to avoid suppressing click events per Pointer Events spec
- Defer setPointerCapture to only when drag starts, not on every
  pointerdown — capture redirects synthetic clicks to the captured
  element instead of the button
- Add releasePointerCapture and touch-action restoration in cleanup
  so capture is released before the browser fires click
2026-06-14 15:26:00 +03:30
mehrabix 284c1f04db fix(drawer): correct close animation for left/top and prevent double-close
- Fix _animateAndClose target formula: use ±dimension instead of
  dimension + getTranslate() which produced wrong position for
  left/top drawers (negative transforms), causing drawer to stay
  half-closed
- Add animation: none inline style before close() to prevent
  Tailwind data-closed:slide-out-* keyframe animation from
  overriding inline transform (was visually reopening drawer)
- Add setPointerCapture for reliable pointercancel delivery
- Add DestroyRef.onDestroy cleanup to prevent pointermove listener
  leak if directive is destroyed mid-gesture
- Remove unused _scrollEl field
2026-06-14 14:50:21 +03:30
mehrabix e3271391f8 style(drawer): fix formatting for long line 2026-06-14 13:54:10 +03:30
mehrabix 224c3d268a fix(drawer): handle null event target in shouldDrag call 2026-06-14 13:50:18 +03:30
mehrabix 78399c9aec feat(drawer): rewrite drag handling to match vaul/shadcn implementation
Rewrite BrnDrawerHandle to match vaul v1.1.2 touch/swipe logic:
- Direction detection: 10px touch / 2px mouse swipe threshold, axis
  alignment check prevents horizontal drags on vertical drawers
- shouldDrag with scroll lock: 100ms cooldown after scroll detection,
  DOM walk for scrollable ancestors, 500ms cooldown after open
- Simple velocity: totalDistance / totalTime on release (threshold 0.4)
- Logarithmic rubber-band: dampenValue uses 8 * ln(v+1) - 16
- isAllowedToDrag latch: once drag starts, no re-check on subsequent moves
- Close threshold: 0.25 (25% of drawer dimension, matching vaul)
2026-06-14 13:38:10 +03:30
mehrabix 5d885f3931 feat(drawer): add scrollable content detection to prevent drag on scroll
Detect scrollable ancestors on pointerdown and skip drawer drag when
the scrollable content has remaining scroll in the drag direction.
Only prevent default on pointerdown when no scrollable element is
found, so browser scrolling is not blocked. Move preventDefault in
pointermove after the scroll check.
2026-06-14 13:15:53 +03:30
mehrabix fac0ed879b refactor(drawer): refactor drag handling and component structure
Improve drag smoothness and reliability by implementing position
tracking in BrnDrawerHandle. Simplify the component structure by moving
the handle logic to a host directive on HlmDrawerContent and removing
manual pointer-events management.
2026-06-14 13:14:40 +03:30
Leonidas f377723a53 chore: nightly release 2026-06-14 ⚡ 2026-06-14 04:09:37 +00:00
Patrick 3052af3fd0 fix: restore non-modal popover dismissal 2026-06-13 19:25:04 -04:00
Patrick c7f2e0ce09 fix: address overlay review feedback 2026-06-13 15:36:28 -04:00
Patrick 803614a7bb test: update overlay api snapshots 2026-06-13 14:48:23 -04:00
Patrick c7fb7469d6 fix: restore overlay dismissal semantics 2026-06-13 14:32:40 -04:00
Patrick ba74c53c97 refactor: split dialog and overlay primitives 2026-06-13 14:32:40 -04:00
Patrick 179ec6af8f fix: coordinate overlay lifecycle with animations
Replace fixed close delays with lifecycle-driven disposal so overlays remain responsive.
Wait only for exit animations that actually start and centralize Escape, backdrop, and
outside-pointer dismissal.

BREAKING CHANGE: remove the closeDelay input and configuration option. Remove explicit delay
values; closed-state exit animations are now detected automatically.
2026-06-13 14:32:40 -04:00
mehrabix 2e3059c8a2 feat(drawer): add drawer component with brain primitive and helm styling 2026-06-13 21:31:07 +03:30
Ashley Hunter e0f236ba47 fix: run mcp tests and stop passWithNoTests masking missing test discovery
The mcp vite config lacked `root: __dirname`, so the @nx/vitest executor (which
runs from the workspace root) resolved `src/**/*.spec.ts` against the workspace
root, found nothing, and `passWithNoTests` passed it silently - mcp's 19 tests
never ran.

Pin mcp's root, and drop `passWithNoTests` from every project that has specs
(mcp, cli, tools, brain, helm) so a future test-discovery break fails loudly
instead of going green. registry keeps the flag - it genuinely has no specs.
2026-06-13 17:16:45 +01:00
Ashley Hunter 7182249f21 test: expose brain axe helper via @spartan-ng/brain/testing alias
Replace the cross-entry-point relative import (../../../src/testing/axe) in the
checkbox, collapsible and switch specs with a @spartan-ng/brain/testing path
alias, mirroring the @angular/core/testing convention. The helper stays test
only: no ng-package.json, excluded from the lib build and dependency checks, so
it is never published.
2026-06-13 15:33:21 +01:00
Ashley Hunter 1b743f8019 test: migrate from jest to vitest with browser testing for brain/helm
Replace Jest with Vitest across the workspace. The brain and helm Angular suites
now run in a real browser (Playwright/Chromium via Vitest browser mode) so they
exercise real layout, focus, pointer events and computed styles that jsdom could
not. The cli, tools, mcp, registry and cli-smoke suites run on Vitest's node
environment.

- Add per-project vite configs and switch test targets to @nx/vitest:test
- Convert jest APIs to vi.* and jest module mocks to vi.mock with importOriginal
- Replace jest-axe with a browser-native axe-core helper and toHaveNoViolations
- Regenerate snapshots in vitest format (content unchanged, format-only)
- Remove all jest packages, configs, the preset and the @nx/jest target default
- Install Playwright Chromium in the CI unit job for the browser suites

Also fixes a brain avatar test that asserted inside a fire-and-forget setTimeout,
which passed vacuously under jsdom and only surfaced once a real browser loaded
the image.
2026-06-13 15:16:45 +01:00
Leonidas f29b10bb68 chore: nightly release 2026-06-13 ⚡ 2026-06-13 03:47:26 +00:00
Leonidas 1d4b389e6e chore: nightly release 2026-06-12 ⚡ 2026-06-12 04:02:56 +00:00
Ashley Hunter 859676a41a feat!: drop Tailwind CSS v3 support (#1460)
spartan/ui is now Tailwind CSS v4 only. The v3 compatibility layer added
complexity across the brain preset, the CLI generators and the docs, all of
which is removed here.

Brain:
- Delete the v3 JavaScript preset (hlm-tailwind-preset.js) and its package
  export; the v4 CSS preset (hlm-tailwind-preset.css) is now the only preset.
- Bump the tailwindcss peer dependency to >=4.0.0 and declare tw-animate-css
  as a peer, since it is imported by the CSS preset.

CLI:
- Remove Tailwind version detection and the v3 confirmation prompt; the theme
  generator always emits the v4 stylesheet (preset import plus OKLCH theme).
- Drop the legacy HSL theme table, the v3-only CDK overlay import branch, the
  vestigial addCdkStyles option and the unused registryItemTailwindSchema.

Docs and tooling:
- Remove the Tailwind v3 installation and theming sections and snippets.
- Drop autoprefixer; Tailwind v4 handles vendor prefixing via @tailwindcss/postcss.

BREAKING CHANGE: Tailwind CSS v3 is no longer supported. The
@spartan-ng/brain/hlm-tailwind-preset (JS) package export has been removed; use
the @spartan-ng/brain/hlm-tailwind-preset.css preset with Tailwind CSS v4. The
tailwindcss peer dependency now requires >=4.0.0.
2026-06-12 00:39:14 +02:00
Leonidas a3607e71d7 chore: nightly release 2026-06-11 ⚡ 2026-06-11 04:03:48 +00:00
Ashley Hunter 66f4d9f454 feat(resizable): add style support and rtl example
Closes #1412
2026-06-10 18:09:51 +01:00
Marc Stammerjohann dc2d2c112d feat(collapsible): add rtl and settings panel example (#1453)
* feat(collapsible): add rtl and settings panel example

* docs(collapsible): update feedback
2026-06-10 15:59:40 +02:00
moosme 3dd146e20f Merge pull request #1443 from spartan-ng/wt/popover-1409
feat(popover): add style support and rtl example
2026-06-10 08:57:08 +02:00