@softwarity/split-button 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -33,6 +33,7 @@ An Angular directive that creates a [Material Design 3 split button](https://m3.
33
33
  - **Material Design 3 Compliant** - Follows M3 button specifications
34
34
  - **5 Button Variants** - Text, Filled, Tonal, Outlined, Elevated
35
35
  - **Responsive to Theme** - Automatically adapts to light/dark color schemes
36
+ - **Toolbar-aware** - Text & outlined variants auto-adapt their label color inside a `mat-toolbar`
36
37
  - **MatMenu Integration** - Works seamlessly with Angular Material's menu component
37
38
  - **Material 3 Ready** - Uses M3 design tokens for theming (`--mat-sys-*`)
38
39
  - **Standalone Directive** - Easy to import in any Angular 21+ application
@@ -151,6 +152,10 @@ The `overrides` mixin accepts a map of tokens to customize the appearance:
151
152
  | `elevated-container-color` | `var(--mat-sys-surface-container-low)` | Container color for elevated variant |
152
153
  | `elevated-label-color` | `var(--mat-sys-primary)` | Label color for elevated variant |
153
154
 
155
+ ### Adapting to the surrounding container
156
+
157
+ The transparent variants (`text` and `outlined`) inherit `--mat-toolbar-container-text-color`, so their label and chevron automatically match the text color of a surrounding `mat-toolbar` — just like a real `matButton`. Outside a toolbar they fall back to `var(--mat-sys-primary)`. The container variants (`filled`, `tonal`, `elevated`) keep their own label color over their own background. You can override any of this with the tokens above.
158
+
154
159
  ### Examples
155
160
 
156
161
  ```scss
@@ -4,7 +4,21 @@ import { DOCUMENT } from '@angular/common';
4
4
 
5
5
  const VARIANT_CLASSES = ['split-button--filled', 'split-button--tonal', 'split-button--outlined', 'split-button--elevated'];
6
6
  const STYLE_ID = 'split-button-styles';
7
- /** Injects styles into the document head (only once) */
7
+ /**
8
+ * Injects styles into the document head (only once).
9
+ *
10
+ * Color strategy (mirrors how a real `matButton` behaves):
11
+ * - Tokens use the Angular Material v17+ `--mat-button-*` names. The legacy
12
+ * `--mdc-*` names are no longer emitted by Material, so reading them always
13
+ * fell through to the `--mat-sys-*` fallback and never picked up the theme.
14
+ * - The "transparent" variants (text, outlined) add `--mat-toolbar-container-text-color`
15
+ * to their fallback chain so their label/chevron auto-adapt to a `mat-toolbar`'s
16
+ * text color — Material remaps the same token for its own buttons, but only on
17
+ * `.mat-mdc-button-base.mat-unthemed` elements (which this directive's wrapper
18
+ * is not), so we inherit the toolbar token directly instead.
19
+ * - The "container" variants (filled, tonal, elevated) keep their own label color;
20
+ * they sit on their own background and must not follow the container's text color.
21
+ */
8
22
  function injectStyles(doc) {
9
23
  if (doc.getElementById(STYLE_ID))
10
24
  return;
@@ -14,7 +28,7 @@ function injectStyles(doc) {
14
28
  .split-button {
15
29
  display: inline-flex;
16
30
  align-items: stretch;
17
- border-radius: var(--split-button-container-shape, var(--mdc-outlined-button-container-shape, 20px));
31
+ border-radius: var(--split-button-container-shape, var(--mat-button-outlined-container-shape, 20px));
18
32
  overflow: hidden;
19
33
  vertical-align: middle;
20
34
  height: 40px;
@@ -23,8 +37,8 @@ function injectStyles(doc) {
23
37
  border: none;
24
38
  background: transparent;
25
39
  border-radius: 0;
26
- border-top-left-radius: var(--split-button-container-shape, var(--mdc-outlined-button-container-shape, 20px));
27
- border-bottom-left-radius: var(--split-button-container-shape, var(--mdc-outlined-button-container-shape, 20px));
40
+ border-top-left-radius: var(--split-button-container-shape, var(--mat-button-outlined-container-shape, 20px));
41
+ border-bottom-left-radius: var(--split-button-container-shape, var(--mat-button-outlined-container-shape, 20px));
28
42
  min-width: unset;
29
43
  padding: 0 16px 0 24px;
30
44
  height: 40px;
@@ -36,7 +50,7 @@ function injectStyles(doc) {
36
50
  display: inline-flex;
37
51
  align-items: center;
38
52
  justify-content: center;
39
- color: var(--split-button-text-label-color, var(--mdc-text-button-label-text-color, var(--mat-sys-primary)));
53
+ color: var(--split-button-text-label-color, var(--mat-button-text-label-text-color, var(--mat-toolbar-container-text-color, var(--mat-sys-primary))));
40
54
  }
41
55
  .split-button .split-button-main:hover {
42
56
  background: color-mix(in srgb, var(--mat-sys-primary) 8%, transparent);
@@ -47,8 +61,8 @@ function injectStyles(doc) {
47
61
  border: none;
48
62
  background: transparent;
49
63
  border-radius: 0;
50
- border-top-right-radius: var(--split-button-container-shape, var(--mdc-outlined-button-container-shape, 20px));
51
- border-bottom-right-radius: var(--split-button-container-shape, var(--mdc-outlined-button-container-shape, 20px));
64
+ border-top-right-radius: var(--split-button-container-shape, var(--mat-button-outlined-container-shape, 20px));
65
+ border-bottom-right-radius: var(--split-button-container-shape, var(--mat-button-outlined-container-shape, 20px));
52
66
  width: 40px;
53
67
  min-width: 40px;
54
68
  max-width: 40px;
@@ -60,7 +74,7 @@ function injectStyles(doc) {
60
74
  justify-content: center;
61
75
  height: 40px;
62
76
  flex-shrink: 0;
63
- color: var(--split-button-text-label-color, var(--mdc-text-button-label-text-color, var(--mat-sys-primary)));
77
+ color: var(--split-button-text-label-color, var(--mat-button-text-label-text-color, var(--mat-toolbar-container-text-color, var(--mat-sys-primary))));
64
78
  }
65
79
  .split-button .split-button-chevron:hover {
66
80
  background: color-mix(in srgb, currentColor 8%, transparent);
@@ -76,22 +90,22 @@ function injectStyles(doc) {
76
90
  }
77
91
  /* Outlined variant */
78
92
  .split-button.split-button--outlined {
79
- border: 1px solid var(--split-button-outlined-outline-color, var(--mdc-outlined-button-outline-color, var(--mat-sys-outline)));
93
+ border: 1px solid var(--split-button-outlined-outline-color, var(--mat-button-outlined-outline-color, var(--mat-sys-outline)));
80
94
  }
81
95
  .split-button.split-button--outlined .split-button-main {
82
- color: var(--split-button-outlined-label-color, var(--mdc-outlined-button-label-text-color, var(--mat-sys-primary)));
96
+ color: var(--split-button-outlined-label-color, var(--mat-button-outlined-label-text-color, var(--mat-toolbar-container-text-color, var(--mat-sys-primary))));
83
97
  }
84
98
  .split-button.split-button--outlined .split-button-chevron {
85
- border-left: 1px solid var(--split-button-outlined-outline-color, var(--mdc-outlined-button-outline-color, var(--mat-sys-outline)));
86
- color: var(--split-button-outlined-label-color, var(--mdc-outlined-button-label-text-color, var(--mat-sys-primary)));
99
+ border-left: 1px solid var(--split-button-outlined-outline-color, var(--mat-button-outlined-outline-color, var(--mat-sys-outline)));
100
+ color: var(--split-button-outlined-label-color, var(--mat-button-outlined-label-text-color, var(--mat-toolbar-container-text-color, var(--mat-sys-primary))));
87
101
  }
88
102
  /* Elevated variant */
89
103
  .split-button.split-button--elevated {
90
- box-shadow: var(--split-button-elevated-shadow, var(--mdc-protected-button-container-elevation-shadow, 0 1px 2px 0 rgba(0,0,0,0.3), 0 1px 3px 1px rgba(0,0,0,0.15)));
91
- background: var(--split-button-elevated-container-color, var(--mdc-protected-button-container-color, var(--mat-sys-surface-container-low)));
104
+ box-shadow: var(--split-button-elevated-shadow, var(--mat-button-protected-container-elevation-shadow, 0 1px 2px 0 rgba(0,0,0,0.3), 0 1px 3px 1px rgba(0,0,0,0.15)));
105
+ background: var(--split-button-elevated-container-color, var(--mat-button-protected-container-color, var(--mat-sys-surface-container-low)));
92
106
  }
93
107
  .split-button.split-button--elevated .split-button-main {
94
- color: var(--split-button-elevated-label-color, var(--mdc-protected-button-label-text-color, var(--mat-sys-primary)));
108
+ color: var(--split-button-elevated-label-color, var(--mat-button-protected-label-text-color, var(--mat-sys-primary)));
95
109
  position: relative;
96
110
  }
97
111
  .split-button.split-button--elevated .split-button-main::after {
@@ -105,14 +119,14 @@ function injectStyles(doc) {
105
119
  opacity: 0.2;
106
120
  }
107
121
  .split-button.split-button--elevated .split-button-chevron {
108
- color: var(--split-button-elevated-label-color, var(--mdc-protected-button-label-text-color, var(--mat-sys-primary)));
122
+ color: var(--split-button-elevated-label-color, var(--mat-button-protected-label-text-color, var(--mat-sys-primary)));
109
123
  }
110
124
  /* Filled variant */
111
125
  .split-button.split-button--filled {
112
- background: var(--split-button-filled-container-color, var(--mdc-filled-button-container-color, var(--mat-sys-primary)));
126
+ background: var(--split-button-filled-container-color, var(--mat-button-filled-container-color, var(--mat-sys-primary)));
113
127
  }
114
128
  .split-button.split-button--filled .split-button-main {
115
- color: var(--split-button-filled-label-color, var(--mdc-filled-button-label-text-color, var(--mat-sys-on-primary)));
129
+ color: var(--split-button-filled-label-color, var(--mat-button-filled-label-text-color, var(--mat-sys-on-primary)));
116
130
  position: relative;
117
131
  }
118
132
  .split-button.split-button--filled .split-button-main::after {
@@ -129,7 +143,7 @@ function injectStyles(doc) {
129
143
  background: color-mix(in srgb, var(--mat-sys-on-primary) 8%, transparent);
130
144
  }
131
145
  .split-button.split-button--filled .split-button-chevron {
132
- color: var(--split-button-filled-label-color, var(--mdc-filled-button-label-text-color, var(--mat-sys-on-primary)));
146
+ color: var(--split-button-filled-label-color, var(--mat-button-filled-label-text-color, var(--mat-sys-on-primary)));
133
147
  }
134
148
  /* Tonal variant */
135
149
  .split-button.split-button--tonal {
@@ -319,10 +333,10 @@ class SplitButtonDirective {
319
333
  }
320
334
  });
321
335
  }
322
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: SplitButtonDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
323
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "21.1.1", type: SplitButtonDirective, isStandalone: true, selector: "[appSplitButton]", inputs: { appSplitButton: "appSplitButton", appSplitButtonTrigger: "appSplitButtonTrigger", disabled: ["disabled", "disabled", booleanAttribute] }, host: { properties: { "class.split-button-main": "this.mainClass" } }, usesOnChanges: true, ngImport: i0 }); }
336
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SplitButtonDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
337
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "21.2.17", type: SplitButtonDirective, isStandalone: true, selector: "[appSplitButton]", inputs: { appSplitButton: "appSplitButton", appSplitButtonTrigger: "appSplitButtonTrigger", disabled: ["disabled", "disabled", booleanAttribute] }, host: { properties: { "class.split-button-main": "this.mainClass" } }, usesOnChanges: true, ngImport: i0 }); }
324
338
  }
325
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: SplitButtonDirective, decorators: [{
339
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SplitButtonDirective, decorators: [{
326
340
  type: Directive,
327
341
  args: [{
328
342
  selector: '[appSplitButton]',
@@ -1 +1 @@
1
- {"version":3,"file":"softwarity-split-button.mjs","sources":["../../src/lib/split-button.directive.ts","../../src/public-api.ts","../../src/softwarity-split-button.ts"],"sourcesContent":["import {\n Directive,\n ElementRef,\n Input,\n Renderer2,\n AfterViewInit,\n OnDestroy,\n OnChanges,\n SimpleChanges,\n inject,\n HostBinding,\n booleanAttribute\n} from '@angular/core';\nimport { DOCUMENT } from '@angular/common';\nimport { MatMenuTrigger } from '@angular/material/menu';\n\n/** M3 Button variant type */\nexport type SplitButtonVariant = '' | 'filled' | 'tonal' | 'outlined' | 'elevated';\n\nconst VARIANT_CLASSES = ['split-button--filled', 'split-button--tonal', 'split-button--outlined', 'split-button--elevated'];\n\nconst STYLE_ID = 'split-button-styles';\n\n/** Injects styles into the document head (only once) */\nfunction injectStyles(doc: Document): void {\n if (doc.getElementById(STYLE_ID)) return;\n\n const style = doc.createElement('style');\n style.id = STYLE_ID;\n style.textContent = `\n .split-button {\n display: inline-flex;\n align-items: stretch;\n border-radius: var(--split-button-container-shape, var(--mdc-outlined-button-container-shape, 20px));\n overflow: hidden;\n vertical-align: middle;\n height: 40px;\n }\n .split-button .split-button-main {\n border: none;\n background: transparent;\n border-radius: 0;\n border-top-left-radius: var(--split-button-container-shape, var(--mdc-outlined-button-container-shape, 20px));\n border-bottom-left-radius: var(--split-button-container-shape, var(--mdc-outlined-button-container-shape, 20px));\n min-width: unset;\n padding: 0 16px 0 24px;\n height: 40px;\n font-family: var(--mat-sys-label-large-font);\n font-size: var(--mat-sys-label-large-size, 14px);\n font-weight: var(--mat-sys-label-large-weight, 500);\n letter-spacing: var(--mat-sys-label-large-tracking, 0.1px);\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: var(--split-button-text-label-color, var(--mdc-text-button-label-text-color, var(--mat-sys-primary)));\n }\n .split-button .split-button-main:hover {\n background: color-mix(in srgb, var(--mat-sys-primary) 8%, transparent);\n }\n .split-button .split-button-chevron {\n all: unset;\n box-sizing: border-box;\n border: none;\n background: transparent;\n border-radius: 0;\n border-top-right-radius: var(--split-button-container-shape, var(--mdc-outlined-button-container-shape, 20px));\n border-bottom-right-radius: var(--split-button-container-shape, var(--mdc-outlined-button-container-shape, 20px));\n width: 40px;\n min-width: 40px;\n max-width: 40px;\n padding: 0;\n margin: 0;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 40px;\n flex-shrink: 0;\n color: var(--split-button-text-label-color, var(--mdc-text-button-label-text-color, var(--mat-sys-primary)));\n }\n .split-button .split-button-chevron:hover {\n background: color-mix(in srgb, currentColor 8%, transparent);\n }\n .split-button .split-button-chevron:focus-visible {\n outline: 2px solid var(--mat-sys-primary);\n outline-offset: -2px;\n }\n .split-button .split-button-icon {\n width: 24px;\n height: 24px;\n display: block;\n }\n /* Outlined variant */\n .split-button.split-button--outlined {\n border: 1px solid var(--split-button-outlined-outline-color, var(--mdc-outlined-button-outline-color, var(--mat-sys-outline)));\n }\n .split-button.split-button--outlined .split-button-main {\n color: var(--split-button-outlined-label-color, var(--mdc-outlined-button-label-text-color, var(--mat-sys-primary)));\n }\n .split-button.split-button--outlined .split-button-chevron {\n border-left: 1px solid var(--split-button-outlined-outline-color, var(--mdc-outlined-button-outline-color, var(--mat-sys-outline)));\n color: var(--split-button-outlined-label-color, var(--mdc-outlined-button-label-text-color, var(--mat-sys-primary)));\n }\n /* Elevated variant */\n .split-button.split-button--elevated {\n box-shadow: var(--split-button-elevated-shadow, var(--mdc-protected-button-container-elevation-shadow, 0 1px 2px 0 rgba(0,0,0,0.3), 0 1px 3px 1px rgba(0,0,0,0.15)));\n background: var(--split-button-elevated-container-color, var(--mdc-protected-button-container-color, var(--mat-sys-surface-container-low)));\n }\n .split-button.split-button--elevated .split-button-main {\n color: var(--split-button-elevated-label-color, var(--mdc-protected-button-label-text-color, var(--mat-sys-primary)));\n position: relative;\n }\n .split-button.split-button--elevated .split-button-main::after {\n content: '';\n position: absolute;\n right: 0;\n top: 20%;\n height: 60%;\n width: 1px;\n background: currentColor;\n opacity: 0.2;\n }\n .split-button.split-button--elevated .split-button-chevron {\n color: var(--split-button-elevated-label-color, var(--mdc-protected-button-label-text-color, var(--mat-sys-primary)));\n }\n /* Filled variant */\n .split-button.split-button--filled {\n background: var(--split-button-filled-container-color, var(--mdc-filled-button-container-color, var(--mat-sys-primary)));\n }\n .split-button.split-button--filled .split-button-main {\n color: var(--split-button-filled-label-color, var(--mdc-filled-button-label-text-color, var(--mat-sys-on-primary)));\n position: relative;\n }\n .split-button.split-button--filled .split-button-main::after {\n content: '';\n position: absolute;\n right: 0;\n top: 20%;\n height: 60%;\n width: 1px;\n background: currentColor;\n opacity: 0.2;\n }\n .split-button.split-button--filled .split-button-main:hover {\n background: color-mix(in srgb, var(--mat-sys-on-primary) 8%, transparent);\n }\n .split-button.split-button--filled .split-button-chevron {\n color: var(--split-button-filled-label-color, var(--mdc-filled-button-label-text-color, var(--mat-sys-on-primary)));\n }\n /* Tonal variant */\n .split-button.split-button--tonal {\n background: var(--split-button-tonal-container-color, var(--mat-sys-secondary-container));\n }\n .split-button.split-button--tonal .split-button-main {\n color: var(--split-button-tonal-label-color, var(--mat-sys-on-secondary-container));\n position: relative;\n }\n .split-button.split-button--tonal .split-button-main::after {\n content: '';\n position: absolute;\n right: 0;\n top: 20%;\n height: 60%;\n width: 1px;\n background: currentColor;\n opacity: 0.2;\n }\n .split-button.split-button--tonal .split-button-main:hover {\n background: color-mix(in srgb, var(--mat-sys-on-secondary-container) 8%, transparent);\n }\n .split-button.split-button--tonal .split-button-chevron {\n color: var(--split-button-tonal-label-color, var(--mat-sys-on-secondary-container));\n }\n /* Disabled state */\n .split-button.split-button--disabled {\n pointer-events: none;\n opacity: var(--split-button-disabled-opacity, 0.38);\n }\n /* Hidden trigger utility - covers full height at right edge for proper menu alignment in both directions */\n .split-button > .hidden-trigger {\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n width: 1px;\n height: 100%;\n visibility: hidden;\n pointer-events: none;\n }\n `;\n doc.head.appendChild(style);\n}\n\n/**\n * Split button directive that transforms a button into a split button with dropdown.\n * Follows Material Design 3 guidelines.\n *\n * Usage:\n * ```html\n * <button appSplitButton [appSplitButtonTrigger]=\"trigger\" (click)=\"doAction()\">\n * Text button (default)\n * </button>\n * <button appSplitButton=\"filled\" [appSplitButtonTrigger]=\"trigger\" (click)=\"doAction()\">\n * Filled button\n * </button>\n * <span [matMenuTriggerFor]=\"menu\" #trigger=\"matMenuTrigger\"></span>\n * <mat-menu #menu=\"matMenu\">\n * <button mat-menu-item>Option 1</button>\n * </mat-menu>\n * ```\n *\n * M3 Button Variants:\n * - (no value): Text button - lowest emphasis\n * - filled: High emphasis\n * - tonal: Medium emphasis with container color\n * - outlined: Medium emphasis with border\n * - elevated: Medium emphasis with shadow\n */\n@Directive({\n selector: '[appSplitButton]',\n standalone: true\n})\nexport class SplitButtonDirective implements AfterViewInit, OnDestroy, OnChanges {\n private readonly el = inject(ElementRef);\n private readonly renderer = inject(Renderer2);\n private readonly document = inject(DOCUMENT);\n\n /** M3 button variant - empty string or no value means text button (lowest emphasis) */\n @Input() appSplitButton: SplitButtonVariant = '';\n\n /** MatMenuTrigger reference for the dropdown */\n @Input() appSplitButtonTrigger?: MatMenuTrigger;\n\n /** Whether the button is disabled */\n @Input({ transform: booleanAttribute }) disabled = false;\n\n @HostBinding('class.split-button-main') mainClass = true;\n\n private wrapper: HTMLElement | null = null;\n private chevronButton: HTMLButtonElement | null = null;\n private clickListener: (() => void) | null = null;\n private initialized = false;\n\n ngAfterViewInit(): void {\n injectStyles(this.document);\n setTimeout(() => {\n this.createSplitButton();\n this.initialized = true;\n }, 0);\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (!this.initialized || !this.wrapper) return;\n\n // Handle variant changes\n if (changes['appSplitButton']) {\n this.updateVariantClass();\n }\n\n // Handle disabled changes\n if (changes['disabled']) {\n this.updateDisabledState();\n }\n }\n\n ngOnDestroy(): void {\n this.clickListener?.();\n if (this.wrapper && this.wrapper.parentNode) {\n const host = this.el.nativeElement;\n this.wrapper.parentNode.insertBefore(host, this.wrapper);\n this.wrapper.parentNode.removeChild(this.wrapper);\n }\n }\n\n private updateVariantClass(): void {\n if (!this.wrapper) return;\n\n // Remove all variant classes\n VARIANT_CLASSES.forEach(cls => {\n this.renderer.removeClass(this.wrapper, cls);\n });\n\n // Add new variant class if specified\n if (this.appSplitButton) {\n this.renderer.addClass(this.wrapper, `split-button--${this.appSplitButton}`);\n }\n }\n\n private updateDisabledState(): void {\n if (!this.wrapper || !this.chevronButton) return;\n\n if (this.disabled) {\n this.renderer.addClass(this.wrapper, 'split-button--disabled');\n this.renderer.setAttribute(this.chevronButton, 'disabled', 'true');\n } else {\n this.renderer.removeClass(this.wrapper, 'split-button--disabled');\n this.renderer.removeAttribute(this.chevronButton, 'disabled');\n }\n }\n\n private createSplitButton(): void {\n const host = this.el.nativeElement as HTMLElement;\n const parent = host.parentNode;\n if (!parent) return;\n\n // Create wrapper\n this.wrapper = this.renderer.createElement('div');\n this.renderer.addClass(this.wrapper, 'split-button');\n\n // Only add variant class if a variant is specified (otherwise it's text/default)\n if (this.appSplitButton) {\n this.renderer.addClass(this.wrapper, `split-button--${this.appSplitButton}`);\n }\n\n if (this.disabled) {\n this.renderer.addClass(this.wrapper, 'split-button--disabled');\n }\n\n // Create chevron button\n this.chevronButton = this.renderer.createElement('button');\n this.renderer.setAttribute(this.chevronButton, 'type', 'button');\n this.renderer.addClass(this.chevronButton, 'split-button-chevron');\n\n if (this.disabled) {\n this.renderer.setAttribute(this.chevronButton, 'disabled', 'true');\n }\n\n // Add chevron SVG icon using innerHTML for proper namespace handling\n this.chevronButton!.innerHTML = `\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24\" width=\"24\" viewBox=\"0 -960 960 960\" fill=\"currentColor\" class=\"split-button-icon\">\n <path d=\"M480-360 280-560h400L480-360Z\"/>\n </svg>\n `;\n\n // Wrap the host element\n this.renderer.insertBefore(parent, this.wrapper, host);\n this.renderer.appendChild(this.wrapper, host);\n this.renderer.appendChild(this.wrapper, this.chevronButton);\n\n // Move the trigger element inside the wrapper for proper menu alignment (below the full button)\n if (this.appSplitButtonTrigger) {\n const triggerEl = (this.appSplitButtonTrigger as any)._element?.nativeElement;\n if (triggerEl) {\n this.renderer.setStyle(this.wrapper, 'position', 'relative');\n this.renderer.appendChild(this.wrapper, triggerEl);\n }\n // Configure menu position so it aligns with the left edge of the split button\n const menu = this.appSplitButtonTrigger.menu;\n if (menu) {\n menu.xPosition = 'before';\n }\n }\n\n // Setup click handler for chevron - opens the menu via the trigger\n this.clickListener = this.renderer.listen(this.chevronButton, 'click', (event: Event) => {\n event.preventDefault();\n event.stopPropagation();\n if (this.appSplitButtonTrigger && !this.disabled) {\n this.appSplitButtonTrigger.openMenu();\n }\n });\n }\n}\n","/*\n * Public API Surface of split-button\n */\n\nexport { SplitButtonDirective } from './lib/split-button.directive';\n\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"softwarity-split-button.mjs","sources":["../../src/lib/split-button.directive.ts","../../src/public-api.ts","../../src/softwarity-split-button.ts"],"sourcesContent":["import {\n Directive,\n ElementRef,\n Input,\n Renderer2,\n AfterViewInit,\n OnDestroy,\n OnChanges,\n SimpleChanges,\n inject,\n HostBinding,\n booleanAttribute\n} from '@angular/core';\nimport { DOCUMENT } from '@angular/common';\nimport { MatMenuTrigger } from '@angular/material/menu';\n\n/** M3 Button variant type */\nexport type SplitButtonVariant = '' | 'filled' | 'tonal' | 'outlined' | 'elevated';\n\nconst VARIANT_CLASSES = ['split-button--filled', 'split-button--tonal', 'split-button--outlined', 'split-button--elevated'];\n\nconst STYLE_ID = 'split-button-styles';\n\n/**\n * Injects styles into the document head (only once).\n *\n * Color strategy (mirrors how a real `matButton` behaves):\n * - Tokens use the Angular Material v17+ `--mat-button-*` names. The legacy\n * `--mdc-*` names are no longer emitted by Material, so reading them always\n * fell through to the `--mat-sys-*` fallback and never picked up the theme.\n * - The \"transparent\" variants (text, outlined) add `--mat-toolbar-container-text-color`\n * to their fallback chain so their label/chevron auto-adapt to a `mat-toolbar`'s\n * text color — Material remaps the same token for its own buttons, but only on\n * `.mat-mdc-button-base.mat-unthemed` elements (which this directive's wrapper\n * is not), so we inherit the toolbar token directly instead.\n * - The \"container\" variants (filled, tonal, elevated) keep their own label color;\n * they sit on their own background and must not follow the container's text color.\n */\nfunction injectStyles(doc: Document): void {\n if (doc.getElementById(STYLE_ID)) return;\n\n const style = doc.createElement('style');\n style.id = STYLE_ID;\n style.textContent = `\n .split-button {\n display: inline-flex;\n align-items: stretch;\n border-radius: var(--split-button-container-shape, var(--mat-button-outlined-container-shape, 20px));\n overflow: hidden;\n vertical-align: middle;\n height: 40px;\n }\n .split-button .split-button-main {\n border: none;\n background: transparent;\n border-radius: 0;\n border-top-left-radius: var(--split-button-container-shape, var(--mat-button-outlined-container-shape, 20px));\n border-bottom-left-radius: var(--split-button-container-shape, var(--mat-button-outlined-container-shape, 20px));\n min-width: unset;\n padding: 0 16px 0 24px;\n height: 40px;\n font-family: var(--mat-sys-label-large-font);\n font-size: var(--mat-sys-label-large-size, 14px);\n font-weight: var(--mat-sys-label-large-weight, 500);\n letter-spacing: var(--mat-sys-label-large-tracking, 0.1px);\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: var(--split-button-text-label-color, var(--mat-button-text-label-text-color, var(--mat-toolbar-container-text-color, var(--mat-sys-primary))));\n }\n .split-button .split-button-main:hover {\n background: color-mix(in srgb, var(--mat-sys-primary) 8%, transparent);\n }\n .split-button .split-button-chevron {\n all: unset;\n box-sizing: border-box;\n border: none;\n background: transparent;\n border-radius: 0;\n border-top-right-radius: var(--split-button-container-shape, var(--mat-button-outlined-container-shape, 20px));\n border-bottom-right-radius: var(--split-button-container-shape, var(--mat-button-outlined-container-shape, 20px));\n width: 40px;\n min-width: 40px;\n max-width: 40px;\n padding: 0;\n margin: 0;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 40px;\n flex-shrink: 0;\n color: var(--split-button-text-label-color, var(--mat-button-text-label-text-color, var(--mat-toolbar-container-text-color, var(--mat-sys-primary))));\n }\n .split-button .split-button-chevron:hover {\n background: color-mix(in srgb, currentColor 8%, transparent);\n }\n .split-button .split-button-chevron:focus-visible {\n outline: 2px solid var(--mat-sys-primary);\n outline-offset: -2px;\n }\n .split-button .split-button-icon {\n width: 24px;\n height: 24px;\n display: block;\n }\n /* Outlined variant */\n .split-button.split-button--outlined {\n border: 1px solid var(--split-button-outlined-outline-color, var(--mat-button-outlined-outline-color, var(--mat-sys-outline)));\n }\n .split-button.split-button--outlined .split-button-main {\n color: var(--split-button-outlined-label-color, var(--mat-button-outlined-label-text-color, var(--mat-toolbar-container-text-color, var(--mat-sys-primary))));\n }\n .split-button.split-button--outlined .split-button-chevron {\n border-left: 1px solid var(--split-button-outlined-outline-color, var(--mat-button-outlined-outline-color, var(--mat-sys-outline)));\n color: var(--split-button-outlined-label-color, var(--mat-button-outlined-label-text-color, var(--mat-toolbar-container-text-color, var(--mat-sys-primary))));\n }\n /* Elevated variant */\n .split-button.split-button--elevated {\n box-shadow: var(--split-button-elevated-shadow, var(--mat-button-protected-container-elevation-shadow, 0 1px 2px 0 rgba(0,0,0,0.3), 0 1px 3px 1px rgba(0,0,0,0.15)));\n background: var(--split-button-elevated-container-color, var(--mat-button-protected-container-color, var(--mat-sys-surface-container-low)));\n }\n .split-button.split-button--elevated .split-button-main {\n color: var(--split-button-elevated-label-color, var(--mat-button-protected-label-text-color, var(--mat-sys-primary)));\n position: relative;\n }\n .split-button.split-button--elevated .split-button-main::after {\n content: '';\n position: absolute;\n right: 0;\n top: 20%;\n height: 60%;\n width: 1px;\n background: currentColor;\n opacity: 0.2;\n }\n .split-button.split-button--elevated .split-button-chevron {\n color: var(--split-button-elevated-label-color, var(--mat-button-protected-label-text-color, var(--mat-sys-primary)));\n }\n /* Filled variant */\n .split-button.split-button--filled {\n background: var(--split-button-filled-container-color, var(--mat-button-filled-container-color, var(--mat-sys-primary)));\n }\n .split-button.split-button--filled .split-button-main {\n color: var(--split-button-filled-label-color, var(--mat-button-filled-label-text-color, var(--mat-sys-on-primary)));\n position: relative;\n }\n .split-button.split-button--filled .split-button-main::after {\n content: '';\n position: absolute;\n right: 0;\n top: 20%;\n height: 60%;\n width: 1px;\n background: currentColor;\n opacity: 0.2;\n }\n .split-button.split-button--filled .split-button-main:hover {\n background: color-mix(in srgb, var(--mat-sys-on-primary) 8%, transparent);\n }\n .split-button.split-button--filled .split-button-chevron {\n color: var(--split-button-filled-label-color, var(--mat-button-filled-label-text-color, var(--mat-sys-on-primary)));\n }\n /* Tonal variant */\n .split-button.split-button--tonal {\n background: var(--split-button-tonal-container-color, var(--mat-sys-secondary-container));\n }\n .split-button.split-button--tonal .split-button-main {\n color: var(--split-button-tonal-label-color, var(--mat-sys-on-secondary-container));\n position: relative;\n }\n .split-button.split-button--tonal .split-button-main::after {\n content: '';\n position: absolute;\n right: 0;\n top: 20%;\n height: 60%;\n width: 1px;\n background: currentColor;\n opacity: 0.2;\n }\n .split-button.split-button--tonal .split-button-main:hover {\n background: color-mix(in srgb, var(--mat-sys-on-secondary-container) 8%, transparent);\n }\n .split-button.split-button--tonal .split-button-chevron {\n color: var(--split-button-tonal-label-color, var(--mat-sys-on-secondary-container));\n }\n /* Disabled state */\n .split-button.split-button--disabled {\n pointer-events: none;\n opacity: var(--split-button-disabled-opacity, 0.38);\n }\n /* Hidden trigger utility - covers full height at right edge for proper menu alignment in both directions */\n .split-button > .hidden-trigger {\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n width: 1px;\n height: 100%;\n visibility: hidden;\n pointer-events: none;\n }\n `;\n doc.head.appendChild(style);\n}\n\n/**\n * Split button directive that transforms a button into a split button with dropdown.\n * Follows Material Design 3 guidelines.\n *\n * Usage:\n * ```html\n * <button appSplitButton [appSplitButtonTrigger]=\"trigger\" (click)=\"doAction()\">\n * Text button (default)\n * </button>\n * <button appSplitButton=\"filled\" [appSplitButtonTrigger]=\"trigger\" (click)=\"doAction()\">\n * Filled button\n * </button>\n * <span [matMenuTriggerFor]=\"menu\" #trigger=\"matMenuTrigger\"></span>\n * <mat-menu #menu=\"matMenu\">\n * <button mat-menu-item>Option 1</button>\n * </mat-menu>\n * ```\n *\n * M3 Button Variants:\n * - (no value): Text button - lowest emphasis\n * - filled: High emphasis\n * - tonal: Medium emphasis with container color\n * - outlined: Medium emphasis with border\n * - elevated: Medium emphasis with shadow\n */\n@Directive({\n selector: '[appSplitButton]',\n standalone: true\n})\nexport class SplitButtonDirective implements AfterViewInit, OnDestroy, OnChanges {\n private readonly el = inject(ElementRef);\n private readonly renderer = inject(Renderer2);\n private readonly document = inject(DOCUMENT);\n\n /** M3 button variant - empty string or no value means text button (lowest emphasis) */\n @Input() appSplitButton: SplitButtonVariant = '';\n\n /** MatMenuTrigger reference for the dropdown */\n @Input() appSplitButtonTrigger?: MatMenuTrigger;\n\n /** Whether the button is disabled */\n @Input({ transform: booleanAttribute }) disabled = false;\n\n @HostBinding('class.split-button-main') mainClass = true;\n\n private wrapper: HTMLElement | null = null;\n private chevronButton: HTMLButtonElement | null = null;\n private clickListener: (() => void) | null = null;\n private initialized = false;\n\n ngAfterViewInit(): void {\n injectStyles(this.document);\n setTimeout(() => {\n this.createSplitButton();\n this.initialized = true;\n }, 0);\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (!this.initialized || !this.wrapper) return;\n\n // Handle variant changes\n if (changes['appSplitButton']) {\n this.updateVariantClass();\n }\n\n // Handle disabled changes\n if (changes['disabled']) {\n this.updateDisabledState();\n }\n }\n\n ngOnDestroy(): void {\n this.clickListener?.();\n if (this.wrapper && this.wrapper.parentNode) {\n const host = this.el.nativeElement;\n this.wrapper.parentNode.insertBefore(host, this.wrapper);\n this.wrapper.parentNode.removeChild(this.wrapper);\n }\n }\n\n private updateVariantClass(): void {\n if (!this.wrapper) return;\n\n // Remove all variant classes\n VARIANT_CLASSES.forEach(cls => {\n this.renderer.removeClass(this.wrapper, cls);\n });\n\n // Add new variant class if specified\n if (this.appSplitButton) {\n this.renderer.addClass(this.wrapper, `split-button--${this.appSplitButton}`);\n }\n }\n\n private updateDisabledState(): void {\n if (!this.wrapper || !this.chevronButton) return;\n\n if (this.disabled) {\n this.renderer.addClass(this.wrapper, 'split-button--disabled');\n this.renderer.setAttribute(this.chevronButton, 'disabled', 'true');\n } else {\n this.renderer.removeClass(this.wrapper, 'split-button--disabled');\n this.renderer.removeAttribute(this.chevronButton, 'disabled');\n }\n }\n\n private createSplitButton(): void {\n const host = this.el.nativeElement as HTMLElement;\n const parent = host.parentNode;\n if (!parent) return;\n\n // Create wrapper\n this.wrapper = this.renderer.createElement('div');\n this.renderer.addClass(this.wrapper, 'split-button');\n\n // Only add variant class if a variant is specified (otherwise it's text/default)\n if (this.appSplitButton) {\n this.renderer.addClass(this.wrapper, `split-button--${this.appSplitButton}`);\n }\n\n if (this.disabled) {\n this.renderer.addClass(this.wrapper, 'split-button--disabled');\n }\n\n // Create chevron button\n this.chevronButton = this.renderer.createElement('button');\n this.renderer.setAttribute(this.chevronButton, 'type', 'button');\n this.renderer.addClass(this.chevronButton, 'split-button-chevron');\n\n if (this.disabled) {\n this.renderer.setAttribute(this.chevronButton, 'disabled', 'true');\n }\n\n // Add chevron SVG icon using innerHTML for proper namespace handling\n this.chevronButton!.innerHTML = `\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24\" width=\"24\" viewBox=\"0 -960 960 960\" fill=\"currentColor\" class=\"split-button-icon\">\n <path d=\"M480-360 280-560h400L480-360Z\"/>\n </svg>\n `;\n\n // Wrap the host element\n this.renderer.insertBefore(parent, this.wrapper, host);\n this.renderer.appendChild(this.wrapper, host);\n this.renderer.appendChild(this.wrapper, this.chevronButton);\n\n // Move the trigger element inside the wrapper for proper menu alignment (below the full button)\n if (this.appSplitButtonTrigger) {\n const triggerEl = (this.appSplitButtonTrigger as any)._element?.nativeElement;\n if (triggerEl) {\n this.renderer.setStyle(this.wrapper, 'position', 'relative');\n this.renderer.appendChild(this.wrapper, triggerEl);\n }\n // Configure menu position so it aligns with the left edge of the split button\n const menu = this.appSplitButtonTrigger.menu;\n if (menu) {\n menu.xPosition = 'before';\n }\n }\n\n // Setup click handler for chevron - opens the menu via the trigger\n this.clickListener = this.renderer.listen(this.chevronButton, 'click', (event: Event) => {\n event.preventDefault();\n event.stopPropagation();\n if (this.appSplitButtonTrigger && !this.disabled) {\n this.appSplitButtonTrigger.openMenu();\n }\n });\n }\n}\n","/*\n * Public API Surface of split-button\n */\n\nexport { SplitButtonDirective } from './lib/split-button.directive';\n\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softwarity/split-button",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "author": "Softwarity",
5
5
  "license": "MIT",
6
6
  "description": "Angular Material 3 split button directive with dropdown menu support",
@@ -24,6 +24,10 @@
24
24
  "dependencies": {
25
25
  "tslib": "^2.6.2"
26
26
  },
27
+ "overrides": {
28
+ "undici": "^7.27.3",
29
+ "@babel/core": "^7.29.6"
30
+ },
27
31
  "sideEffects": false,
28
32
  "module": "fesm2022/softwarity-split-button.mjs",
29
33
  "typings": "types/softwarity-split-button.d.ts",
@@ -35,5 +39,6 @@
35
39
  "types": "./types/softwarity-split-button.d.ts",
36
40
  "default": "./fesm2022/softwarity-split-button.mjs"
37
41
  }
38
- }
42
+ },
43
+ "type": "module"
39
44
  }