Skip to content

feat: support providing global custom gutter component#534

Merged
Jefiozie merged 2 commits into
angular-split:mainfrom
Harpush:global-custom-gutter-component
Jun 6, 2026
Merged

feat: support providing global custom gutter component#534
Jefiozie merged 2 commits into
angular-split:mainfrom
Harpush:global-custom-gutter-component

Conversation

@Harpush

@Harpush Harpush commented Apr 2, 2026

Copy link
Copy Markdown
Collaborator

Add support for customizing the gutter using dependency injection by providing a gutter component.
The priority is: GutterTemplate > GutterComponent > Default.
For example:

providers: [provideAngularSplitOptions({ gutterComponent: CustomGutterComponent })],

Due to the inheritance of the split options the above snippet will only override the gutterComponent while keeping the rest of the options from the parent injector.

The second commit adds cursor control. The default resize cursor is applied when no custom gutter is given or when the custom gutter has no handles. If there are handles the default resize cursor is removed.
Each handle adds resize cursor unless suppressDefaultCursor is added.
Each exclude adds default cursor unless suppressDefaultCursor is added.

@Harpush Harpush requested review from Jefiozie and SanderElias April 2, 2026 12:35
@Harpush Harpush force-pushed the global-custom-gutter-component branch from 698fa8e to c0eaf83 Compare April 2, 2026 18:33

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new way to globally customize the split gutter via dependency injection (gutterComponent), while also refining cursor/drag behavior based on whether gutters expose explicit drag handles or excluded regions.

Changes:

  • Add gutterComponent to global AngularSplitDefaultOptions (with hierarchical injector inheritance via provideAngularSplitOptions).
  • Update SplitComponent rendering to prefer GutterTemplate > GutterComponent > Default (using NgComponentOutlet) and adjust default gutter cursor behavior when handles exist.
  • Introduce SplitGuttersManagerService and update gutter handle/exclude directives to register themselves and control drag start + cursor styling.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/app/examples/custom-gutter-style/custom-gutter.component.ts New example custom gutter component used as an injected gutterComponent.
src/app/examples/custom-gutter-style/custom-gutter-style.component.ts Updates example to use provideAngularSplitOptions({ gutterComponent }) and adjusts cursor suppression on excludes.
src/app/examples/custom-gutter-style/custom-gutter-style.component.scss Removes now-inlined example A gutter styling.
projects/angular-split/src/public_api.ts Exposes new gutter-related types publicly.
projects/angular-split/src/lib/split/split.component.ts Adds manager service + uses it to gate drag start; imports NgComponentOutlet.
projects/angular-split/src/lib/split/split.component.html Renders injected gutter component when no gutter template is provided.
projects/angular-split/src/lib/split/split.component.css Removes default resize cursor when gutters have handles; relies on handle/exclude directives for cursor.
projects/angular-split/src/lib/gutter/split-gutters-manager.service.ts New per-split service to track handles/excludes and decide if drag can start.
projects/angular-split/src/lib/gutter/split-gutter.directive.ts Simplifies gutter directive to template-only; context type now aliases the shared context.
projects/angular-split/src/lib/gutter/split-gutter-exclude-from-drag.directive.ts Registers excludes with manager + adds default cursor styling (optionally suppressed).
projects/angular-split/src/lib/gutter/split-gutter-drag-handle.directive.ts Registers handles with manager + adds resize cursor styling (optionally suppressed).
projects/angular-split/src/lib/gutter/split-gutter-context.ts New shared context type for both template and component gutters.
projects/angular-split/src/lib/gutter/split-gutter-component.ts New interface describing the expected gutter component contract.
projects/angular-split/src/lib/angular-split-config.token.ts Adds gutterComponent option to defaults and supports DI-based overrides.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +86 to +87
elements.splice(elements.indexOf(elementRef), 1)

Copilot AI Apr 3, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removeFromMap assumes the gutter entry exists and that elementRef is present in the array. If map.get(gutterNum) returns undefined (e.g. due to mismatched gutterNum / double-destroy) this will throw, and if indexOf(elementRef) returns -1 it will incorrectly remove the last element. Consider guarding for missing entries and a missing index (no-op) before splicing, and only deleting the key when the array is truly empty.

Suggested change
elements.splice(elements.indexOf(elementRef), 1)
if (!elements) {
return
}
const elementIndex = elements.indexOf(elementRef)
if (elementIndex === -1) {
return
}
elements.splice(elementIndex, 1)

Copilot uses AI. Check for mistakes.
import type { SplitGutterContext } from './split-gutter-context'

export interface SplitGutterComponent {
context: InputSignal<SplitGutterContext>

Copilot AI Apr 3, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SplitGutterComponent currently requires context: InputSignal<SplitGutterContext>, which forces consumers to use the signal-based input() API to satisfy gutterComponent: Type<SplitGutterComponent>. Since *ngComponentOutlet will also work with a classic @Input() context: SplitGutterContext, consider widening the contract (e.g., context: SplitGutterContext | InputSignal<SplitGutterContext>) so consumers aren’t artificially constrained by types.

Suggested change
context: InputSignal<SplitGutterContext>
context: SplitGutterContext | InputSignal<SplitGutterContext>

Copilot uses AI. Check for mistakes.
@SanderElias

Copy link
Copy Markdown
Contributor

@Harpush A pulled CP in. Not sure the points are valid, I'll leave that up to you.
Aside from those, it looks good to me. Seems like a good addition!

@Harpush

Harpush commented Apr 3, 2026

Copy link
Copy Markdown
Collaborator Author

@SanderElias
The first comment is a bit of defensive programming... Theoretically it can happen but on creation I add and on destroy I remove.
The second comment allows non signal inputs support - a question whether we want it or not

@SanderElias SanderElias left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@SanderElias

Copy link
Copy Markdown
Contributor

@Harpush works out for me, I approved!

@Harpush

Harpush commented Apr 3, 2026

Copy link
Copy Markdown
Collaborator Author

@SanderElias great! So you can merge and hopefully we can publish a new angular 20 version before migrating to 21

@Harpush

Harpush commented May 16, 2026

Copy link
Copy Markdown
Collaborator Author

@SanderElias @Jefiozie Can we merge and publish it as a minor v20 version?

@Jefiozie

Jefiozie commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Yes we can, we hold the v21 update then rebase that branch and from their start updating

@Jefiozie Jefiozie merged commit c722544 into angular-split:main Jun 6, 2026
11 checks passed
@Harpush Harpush deleted the global-custom-gutter-component branch June 6, 2026 10:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants