* fix(cli): handle interrupts in healthcheck prompt and harden generators
Replace the raw-stdin prompt in the healthcheck generator with the standard
enquirer confirm prompt so Ctrl+C correctly aborts the run instead of leaving
the generator running. Isolate each healthcheck so one throwing does not abort
the rest, and report registry fetch failures instead of throwing.
Make getImportAlias throw on a present-but-invalid config rather than silently
falling back to the default alias, guard against the coerce() NPE in
version-utils, and switch migrate-hlm to readJson. Add unit tests across these
paths and stub network access so the suite runs offline.
Closes#906
* fix(cli): guard version healthcheck fix against missing dependencies section
The fix writeback read packageJson.dependencies[dep] directly, which threw when
a package.json had no dependencies section and the dependency lived only in
devDependencies. Guard both sections with optional chaining so the writeback is
symmetrical and never touches an undefined section.
* 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
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.
Replace the jest-era invocation (npm test ... --updateSnapshot --skip-cache) with the vitest/nx
equivalent so the snapshot can actually be regenerated.
The generate-ui-docs snapshot captures each directive's exportAs, so the avatar exportAs rename
(avatarImage/avatarFallback -> brn*/hlm*) left it stale and failed the unit job. Diff is limited to
those four entries.
The data-slot pass added host/template data-slot to helm navigation-menu and slider, but the brain
directives those wrappers compose (BrnNavigationMenu* via hostDirectives, BrnSlider/brnSliderTrack/
brnSliderRange/brnSliderThumb in the slider template) already emit the identical data-slot on the
same elements. The helm copies were dead duplication and a future drift hazard. Removed them; the
slots remain in the DOM via the brain layer (verified in browser). The genuinely-new slots
(switch, input, progress, popover, calendar root) stay - the brain layer provides none for those.
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.
The data-slot additions inserted the `host` key directly after `selector`, violating the
workspace `@nx/workspace-component-directive-key-order` rule (host must follow hostDirectives).
Reorder the affected calendar/input/navigation-menu/popover/progress/slider metadata; no behavior
change.
Remove the mis-cased `HlmBreadCrumbImports` alias in favour of the canonical
`HlmBreadcrumbImports`, dropping it before 1.0 rather than carrying it on the stable line. The
NgModule migration map is repointed to the canonical name so `nx g @spartan-ng/cli:migrate-module-
imports` still rewrites `HlmBreadCrumbModule` to an export that exists.
_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.
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.
Standardize the `data-slot` styling contract across the helm layer so themes and
consumers have a consistent, public styling hook on every component. Adds the
attribute to switch, switch-thumb, input, slider (track/range/thumb), progress,
progress-indicator, calendar, navigation-menu (root/list/item/trigger/link) and
popover (root/content), matching the shadcn slot 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.
Drawer shipped as a helm lib with docs but was missing from the CLI, so
`nx g @spartan-ng/cli:ui drawer` failed. Register it in the Primitive union and
dependency map, generate its templates + supported-ui-libraries entry, and add a
drift-guard spec asserting the CLI primitive set equals the installable helm
components (with a generator template each) so this cannot recur.
- 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
- 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
- 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
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.
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.
Add RTL preview example with EN/AR/HE translations,
pointer-events:none on body while drawer is open (removed with 300ms
delay on close), and replace div.px-4 with hlm-field-group for proper
spacing.
Chromium renders native select option popups using the select's
translucent dark background, breaking contrast in dark mode. Style
options and optgroups with the Canvas/CanvasText system colors so the
dropdown adapts to the active color-scheme, matching shadcn.
Closes#1426
Emit the spartan-slider-ticks marker so the ticks container padding, which
offsets ticks to the thumb center, is defined per registry style instead of a
fixed px-1.5. The previous fixed padding assumed a 12px thumb, so ticks were
misaligned for styles with larger thumbs (luma, vega, mira, maia). Set the
padding to each style's thumb radius across luma, vega, lyra, nova, mira and
maia, for both horizontal and vertical orientations.
Closes#1455