44 </a >
55</p >
66
7- # @softwarity/loading-indicator
7+ # @softwarity/split-button
88
99<p align =" center " >
10- <a href =" https://www.npmjs.com/package/@softwarity/loading-indicator " >
11- <img src="https://img.shields.io/npm/v/@softwarity/loading-indicator ?color=blue&label=npm" alt="npm version">
10+ <a href =" https://www.npmjs.com/package/@softwarity/split-button " >
11+ <img src="https://img.shields.io/npm/v/@softwarity/split-button ?color=blue&label=npm" alt="npm version">
1212 </a >
13- <a href =" https://github.com/softwarity/loading-indicator /blob/main/LICENSE " >
13+ <a href =" https://github.com/softwarity/split-button /blob/main/LICENSE " >
1414 <img src="https://img.shields.io/badge/license-MIT-blue" alt="license">
1515 </a >
16- <a href =" https://github.com/softwarity/loading-indicator /actions/workflows/main.yml " >
17- <img src="https://github.com/softwarity/loading-indicator /actions/workflows/main.yml/badge.svg" alt="build status">
16+ <a href =" https://github.com/softwarity/split-button /actions/workflows/main.yml " >
17+ <img src="https://github.com/softwarity/split-button /actions/workflows/main.yml/badge.svg" alt="build status">
1818 </a >
1919</p >
2020
21- An Angular component that displays an expressive [ Material 3 loading indicator ] ( https://m3.material.io/components/loading-indicator /overview ) with smooth morphing animation between organic shapes .
21+ An Angular directive that creates a [ Material Design 3 split button ] ( https://m3.material.io/components/buttons /overview ) with a dropdown menu for secondary actions .
2222
23- ** [ Live Demo] ( https://softwarity.github.io/loading-indicator / ) ** | ** [ Release Notes] ( RELEASE_NOTES.md ) **
23+ ** [ Live Demo] ( https://softwarity.github.io/split-button / ) ** | ** [ Release Notes] ( RELEASE_NOTES.md ) **
2424
2525<p align =" center " >
26- <a href =" https://softwarity.github.io/loading-indicator / " >
27- <img src="projects/demo/src/assets/preview.png" alt="Loading Indicator Preview" width="400">
26+ <a href =" https://softwarity.github.io/split-button / " >
27+ <img src="projects/demo/src/assets/preview.png" alt="Split Button Preview" width="400">
2828 </a >
2929</p >
3030
3131## Features
3232
33- - ** Material 3 Expressive Design ** - Smooth morphing animation between 7 organic shapes
34- - ** 60fps Animation ** - Uses requestAnimationFrame for butter-smooth performance
33+ - ** Material Design 3 Compliant ** - Follows M3 button specifications
34+ - ** 5 Button Variants ** - Text, Filled, Tonal, Outlined, Elevated
3535- ** Responsive to Theme** - Automatically adapts to light/dark color schemes
36- - ** Customizable Size** - Adjustable diameter from small to large
37- - ** Optional Container** - Circular background for better visibility
36+ - ** MatMenu Integration** - Works seamlessly with Angular Material's menu component
3837- ** Material 3 Ready** - Uses M3 design tokens for theming (` --mat-sys-* ` )
39- - ** Standalone Component ** - Easy to import in any Angular 21+ application
40- - ** Lightweight ** - Pure SVG animation, no external dependencies
38+ - ** Standalone Directive ** - Easy to import in any Angular 21+ application
39+ - ** Accessible ** - Keyboard navigation and ARIA support
4140
4241## Installation
4342
4443``` bash
45- npm install @softwarity/loading-indicator
44+ npm install @softwarity/split-button
4645```
4746
4847### Peer Dependencies
4948
5049| Package | Version |
5150| ---------| ---------|
5251| @angular/core | >= 21.0.0 |
52+ | @angular/material | >= 21.0.0 |
5353
5454## Usage
5555
56- Import the component in your standalone component:
56+ ### 1. Include styles in your global stylesheet
57+
58+ In your ` styles.scss ` , import and include the split-button styles:
59+
60+ ``` scss
61+ @use ' @softwarity/split-button/split-button-theme' as split-button ;
62+
63+ // Include split-button base styles (required)
64+ @include split-button .styles ();
65+ ```
66+
67+ ### 2. Import the directive in your component
5768
5869``` typescript
59- import { LoadingIndicatorComponent } from ' @softwarity/loading-indicator' ;
70+ import { SplitButtonDirective } from ' @softwarity/split-button' ;
71+ import { MatMenuModule } from ' @angular/material/menu' ;
6072
6173@Component ({
6274 selector: ' app-my-component' ,
63- imports: [LoadingIndicatorComponent ],
75+ imports: [SplitButtonDirective , MatMenuModule ],
6476 template: ` ... `
6577})
6678export class MyComponent {}
6779```
6880
69- Add the ` loading-indicator ` component in your template:
81+ ### 3. Add the ` appSplitButton ` directive to your button
7082
7183``` html
72- <!-- Basic usage -->
73- <loading-indicator />
84+ <!-- Text button (default) -->
85+ <button appSplitButton [appSplitButtonTrigger] =" trigger" (click) =" onSave()" >
86+ Save
87+ </button >
88+ <span [matMenuTriggerFor] =" menu" #trigger =" matMenuTrigger" ></span >
89+ <mat-menu #menu =" matMenu" >
90+ <button mat-menu-item (click) =" onSaveAs()" >Save As...</button >
91+ <button mat-menu-item (click) =" onSaveDraft()" >Save Draft</button >
92+ </mat-menu >
93+
94+ <!-- Filled variant -->
95+ <button appSplitButton =" filled" [appSplitButtonTrigger] =" trigger" (click) =" onSubmit()" >
96+ Submit
97+ </button >
7498
75- <!-- With custom diameter -->
76- <loading-indicator [diameter] =" 96" />
99+ <!-- Outlined variant -->
100+ <button appSplitButton =" outlined" [appSplitButtonTrigger] =" trigger" (click) =" onAction()" >
101+ Action
102+ </button >
77103
78- <!-- With container background -->
79- <loading-indicator withContainer />
104+ <!-- Tonal variant -->
105+ <button appSplitButton =" tonal" [appSplitButtonTrigger] =" trigger" (click) =" onProcess()" >
106+ Process
107+ </button >
80108
81- <!-- Combined -->
82- <loading-indicator [diameter] =" 64" withContainer />
109+ <!-- Elevated variant -->
110+ <button appSplitButton =" elevated" [appSplitButtonTrigger] =" trigger" (click) =" onExport()" >
111+ Export
112+ </button >
83113```
84114
85115## API
@@ -88,20 +118,31 @@ Add the `loading-indicator` component in your template:
88118
89119| Input | Type | Default | Description |
90120| -------| ------| ---------| -------------|
91- | ` diameter ` | ` number ` | ` 48 ` | Size of the loading indicator in pixels |
92- | ` withContainer ` | ` boolean ` | ` false ` | When true, displays a circular background container behind the shape |
121+ | ` appSplitButton ` | ` '' \| 'filled' \| 'tonal' \| 'outlined' \| 'elevated' ` | ` '' ` | Button variant following Material Design 3 guidelines |
122+ | ` appSplitButtonTrigger ` | ` MatMenuTrigger ` | ` undefined ` | Reference to the MatMenuTrigger for the dropdown menu |
123+ | ` disabled ` | ` boolean ` | ` false ` | Whether the button is disabled |
124+
125+ ### Button Variants
126+
127+ | Variant | Description |
128+ | ---------| -------------|
129+ | Text (default) | Lowest emphasis, for less important actions |
130+ | Filled | High emphasis, for primary actions |
131+ | Tonal | Medium emphasis with a container color from the secondary palette |
132+ | Outlined | Medium emphasis with a border outline |
133+ | Elevated | Medium emphasis with a shadow elevation |
93134
94135## Theming (Material 3)
95136
96- The component provides a SCSS mixin to customize the colors. This approach follows Angular Material's theming pattern.
137+ The directive provides a SCSS mixin to customize the colors. This approach follows Angular Material's theming pattern.
97138
98139### Setup
99140
100141In your application's ` styles.scss ` , import the theme file and call the ` overrides ` mixin:
101142
102143``` scss
103144@use ' @angular/material' as mat ;
104- @use ' @softwarity/loading-indicator/loading-indicator -theme' as loading-indicator ;
145+ @use ' @softwarity/split-button/split-button -theme' as split-button ;
105146
106147// Your Material 3 theme
107148html {
@@ -112,8 +153,8 @@ html {
112153 )
113154 ));
114155
115- // Optional: customize loading indicator colors
116- // @include loading-indicator .overrides();
156+ // Optional: customize split-button colors
157+ // @include split-button .overrides();
117158}
118159```
119160
@@ -123,70 +164,74 @@ The `overrides` mixin accepts a map of tokens to customize the appearance:
123164
124165| Token | Default | Description |
125166| -------| ---------| -------------|
126- | ` background-color ` | ` var(--mat-sys-primary-container) ` | Background color when withContainer is true |
127- | ` shape-color ` | ` var(--mat-sys-on-secondary-container) ` | Color of the animated shape |
167+ | ` text-label-color ` | ` var(--mat-sys-primary) ` | Label color for text variant |
168+ | ` filled-container-color ` | ` var(--mat-sys-primary) ` | Container color for filled variant |
169+ | ` filled-label-color ` | ` var(--mat-sys-on-primary) ` | Label color for filled variant |
170+ | ` outlined-outline-color ` | ` var(--mat-sys-outline) ` | Border color for outlined variant |
171+ | ` outlined-label-color ` | ` var(--mat-sys-primary) ` | Label color for outlined variant |
172+ | ` tonal-container-color ` | ` var(--mat-sys-secondary-container) ` | Container color for tonal variant |
173+ | ` tonal-label-color ` | ` var(--mat-sys-on-secondary-container) ` | Label color for tonal variant |
174+ | ` elevated-container-color ` | ` var(--mat-sys-surface-container-low) ` | Container color for elevated variant |
175+ | ` elevated-label-color ` | ` var(--mat-sys-primary) ` | Label color for elevated variant |
128176
129177### Examples
130178
131179``` scss
132- // Customize colors with light/dark support
133- @include loading-indicator .overrides ((
134- background- color : light-dark (#e8def8 , #4a4458 ),
135- shape - color: light-dark (#6750a4 , #ccc2dc )
180+ // Customize filled button colors
181+ @include split-button .overrides ((
182+ filled - container - color: light-dark (#6750a4 , #d0bcff ),
183+ filled - label - color: light-dark (#ffffff , #381e72 )
136184));
137185
138- // Use Material 3 system colors
139- @include loading-indicator .overrides ((
140- background -color : var (--mat-sys-tertiary-container ),
141- shape - color: var (--mat-sys-on-tertiary-container )
186+ // Use Material 3 system colors for tonal variant
187+ @include split-button .overrides ((
188+ tonal - container - color: var (--mat-sys-tertiary-container ),
189+ tonal - label - color: var (--mat-sys-on-tertiary-container )
142190));
143191
144192// Custom brand colors
145- @include loading-indicator .overrides ((
146- shape- color: #ff5722
193+ @include split-button .overrides ((
194+ filled- container- color: #ff5722 ,
195+ filled- label- color: #ffffff
147196));
148197```
149198
150199## Examples
151200
152- ### Centered Overlay
153-
154- ``` html
155- <div class =" loading-overlay" >
156- <loading-indicator [diameter] =" 64" withContainer />
157- </div >
158- ```
159-
160- ### Inline Button Loading
201+ ### Save Action with Alternatives
161202
162203``` html
163- <button [disabled] =" isLoading" >
164- @if (isLoading) {
165- <loading-indicator [diameter] =" 24" />
166- } @else {
167- Submit
168- }
204+ <button appSplitButton =" filled" [appSplitButtonTrigger] =" saveTrigger" (click) =" onSave()" >
205+ Save
169206</button >
207+ <span [matMenuTriggerFor] =" saveMenu" #saveTrigger =" matMenuTrigger" ></span >
208+ <mat-menu #saveMenu =" matMenu" >
209+ <button mat-menu-item (click) =" onSaveAs()" >Save As...</button >
210+ <button mat-menu-item (click) =" onSaveDraft()" >Save Draft</button >
211+ <button mat-menu-item (click) =" onSaveAndClose()" >Save & Close</button >
212+ </mat-menu >
170213```
171214
172- ### Content Placeholder
215+ ### Export with Format Options
173216
174217``` html
175- @if (isLoading) {
176- <loading-indicator [diameter] =" 48" />
177- } @else {
178- <app-content />
179- }
218+ <button appSplitButton =" outlined" [appSplitButtonTrigger] =" exportTrigger" (click) =" onExportPDF()" >
219+ Export PDF
220+ </button >
221+ <span [matMenuTriggerFor] =" exportMenu" #exportTrigger =" matMenuTrigger" ></span >
222+ <mat-menu #exportMenu =" matMenu" >
223+ <button mat-menu-item (click) =" onExportCSV()" >Export CSV</button >
224+ <button mat-menu-item (click) =" onExportXLSX()" >Export Excel</button >
225+ <button mat-menu-item (click) =" onExportJSON()" >Export JSON</button >
226+ </mat-menu >
180227```
181228
182- ### With Deferred Loading
229+ ### Disabled State
183230
184231``` html
185- @defer (on idle) {
186- <app-heavy-component />
187- } @placeholder (minimum 500ms) {
188- <loading-indicator [diameter] =" 64" withContainer />
189- }
232+ <button appSplitButton =" filled" [appSplitButtonTrigger] =" trigger" [disabled] =" true" >
233+ Disabled
234+ </button >
190235```
191236
192237## License
0 commit comments