ul-lib
v0.1.0-alpha.1
Published
```bash npm install ul-lib ``` [NPM Package](https://www.npmjs.com/package/ul-lib)
Downloads
418
Readme
Getting Started
Install
npm install ul-lib
Build
Use the below script to build the CSS file and to build/pack npm package.
npm run buildPack
Configure
Tailwinds v4
Add this to the root css to load tailwind styles Tailwind CSS Installation
@import "tailwindcss";
Tailwindcss-Motion
Add tailwind motion for animations. TailwindCSS-Motion
@plugin "tailwindcss-motion";
DaisyUI v5
Add Daisy UI plug-in DaisyUI Installation
@plugin "daisyui"{
themes: light --default, dark --prefersdark, dracula;
}
UL-Lib CSS Import
Add import of css from ul-lib to css of a new app project.
@import '../node_modules/ul-lib/index.css';
Date Selector Config
In your project that was used to install this package update the angular.json
in the styles property.
Projects > architect > Build > Styles
{
"styles": [
"node_modules/flatpickr/dist/flatpickr.css"
]
}
Modules
| Modules | Components | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | ULAlertsModule | [UIAlertComponent,UIAlertsComponent] | | ULCommonModule | [LocalDatePipe] | | ULInputsModule | [UIBasicInputFieldComponent, UIFormComponent] | | ULMenuModule | [UIMenuComponent, UIMenuDetailComponent, UIMenuDropdownComponent, UIMenuItemComponent] | | ULModalModule | [UIModalPopUpComponent, UIModalViewComponent] | | ULStatsModule | [UIStatComponent, UIStatsComponent] | | ULTableModule | [UIBasicTableComponent, UIBasicTableColumnComponent, UINestedTableRowComponent, UIAdvancedFilterComponent, UIFilterItemComponent ] | | ULTabsModule | [UITabComponent, UITabViewComponent] | | ULViewsModule | [UIAccordionComponent, UICardViewComponent, UIDividerComponent, UIBasicChipComponent, UINavBarComponent, UISidebarComponent, UITooltipComponent, UICalendarViewComponent, UICalendarCellComponent, UICalendarHeaderComponent] |
Pipes
| Pipes | Description | Selector | | ------------- | ----------------------------------------------------------------------- | ----------- | | LocalDatePipe | Uses the native @Angular Date to convert UTC dates into local datetimes | 'localDate' |
UL Components
Overview of the functionality that is available in the UL package. UITable
|Component|Selector|
|---|---|
|UIBasicTableComponent|ul-table
|
Parameters
| Parameters | Data Type | Type | Description | Optional |
| -------------- | ----------------------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------ | -------- |
| dataSource | Function (SearchRequest) => any[] | Observable<any[]> | @Input | Source data for table | |
| searchRequest | SearchRequest | @Input | Object to used when sending request to update source after sort/filtering. | ✅ |
| headerClass | String = 'bg-base-300' | @Input | | ✅ |
| rowClass | String = 'drop-shadow-none shadow-none' | @Input | | ✅ |
| footerClass | String = '' | @Input | | ✅ |
| refreshTrigger | Observable<any>
| @Input | Used to to trigger and return signalR response. This can also be set in the datasource as well. | ✅ |
| triggerHandle | (source: any, tableSource:BehaviorSubject<any[]>) => void
| @Input | Used to update the table before the refresh is fully complete to create seamless row updates. You can also include this in the datasource. | ✅ |
| trackBy | (row:any) => any | @Input | Optionally can be used to indicate a row identity for the table when rendering | ✅ |
Concepts
As mentioned you can include the following the in the Datasource row for the datasource of the table. Also I found the best way to include child or nestedRow data is to include the Observables in the datasource row as well.
|Input Name|Row Property Name| |---|---| |triggerHandle|$trigger| |refreshTrigger|$refresh|
Example
This example will include an Child data and refresh/trigger handling. The example should include filtering and sorting using the searchRequest object.
export class ExampleComponent
{
$exampleSource: (sr: SearchRequest) => Observable<SearchResponse<any>>;
constructor(private exampleService:ServiceExample private updateStores: UpdateStoreMap)
{
//Example Table Source
this.$exampleSource = (sr) => this.exampleService.GetA(sr).ToPageObservable().EditResult(x => {
x.$SubSource1 = this.traceJobService.GetB(x.Id); //Returns on Observable given an individual row
x.$SubSource2 = this.traceJobService.Getc(x.Id); //Returns on Observable given an individual row
x.$refresh = this.updateStores.getStores("ATableUpdate", "BTableUpdate"); //This comes from SignalR
x.$trigger = (updateSource:any, tableSource:BehaviorSubject<any[]>) => {
var ATable = source?.ATableUpdate;
var currentData = tableSource.getValue();
//Use currentData and updateSource to perform your updates
tableSource.next(currentData);
}
return x;
});
}
}
Warning
If you use signalR for the auto-refresh and have a nestedRow then you would need to use the UIColumn @Input Parameter
isRowID
(or use the UITable @InputtrackBy
) because typically the way a row is indicated as open is from the entire Row dataobject matching the row that is being built upon re-rendering. You can set the unique row ID using theisRowID
ortrackBy
delegate and instead of checking the whole row it will compare both the Re-Render row and selected row using the delegate.
{
"RowId": 123,
"Column1": "Value 1",
"Column2": "Value 2",
"Column3": "Value 3"
}
Option A
tableGetId(r:any)
{
return r?.RowId;
}
Option B
<ul-table #tbl class="border-collapse" [dataSource]="$exampleSource" >
<ul-column isRowId dataKey="RowId" display="Row ID" />
<!--...-->
</ul-table>
//This is example of how I decided to store the update observables from SignalR.
export class UpdateStoreMap
{
$stores: Map<string, BehaviorSubject< unknown>> = new Map<string, BehaviorSubject< unknown>>();
updateStore(groupName: string, values: unknown)
{
var isIncluded = this.$stores.has(groupName);
if (!isIncluded) {
this.$stores.set(groupName, new BehaviorSubject(values));
} else {
this.$stores.get(groupName).next(values);
}
}
getStore(groupName:string):BehaviorSubject<unknown> |undefined
{
return this.$stores.get(groupName) ?? undefined;
}
getStores(...groupNames: string[])
{
//Create a selection object of target observables to check if any of the selected changes
//it then converts the output into a object using the groupName as the key and changed rows as the values
/*Example:groupdNames = ['SourceA', 'SourceB']
{
SourceA: [],
SourceB: []
}
*/
var val = groupNames.map(x => this.getStore(x)).filter(x => x != undefined);
return combineLatest(val).pipe(map((m: any[]) => {
var newMap: Map<string, any> = new Map<string, any>();
m.forEach((v, i) => {
newMap.set(groupNames[i], v);
});
return Object.fromEntries(newMap);
}));
}
}
Observable Pipes
Set Refresh/Trigger
//This example uses the SignalR UpdateStoreMap
export class ExampleComponent {
constructor(private sourceService: SourceService, private updateStores: UpdateStoreMap)
{
var source = this.sourceService.get()
.pipe(setRefresh(this.updateStores.getStores('Update1', 'Update2')))
.pipe(setTrigger<{ Update1: any, Update2: any }, any>
((source, table) => source.Update2?.ColumnA == table.ColumnA, 'Update2'));
}
}
Children Components
UIColumn
|Component|Selector|
|---|---|
|UIBasicTableColumnComponent|ul-column
|
Parameters
| Parameters | Data Type | Type | Description | Optional | | ---------- | --------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | | sortable | Boolean | @Input | Is column sortable | ✅ | | display | String | @Input | Sets the column display text | ✅ | | dataKey | String | @Input | Used to get the Property value from the Objects array based on the property key (i.e. dataKey). | | | isFilter | Boolean | @Input | Sets if column is filterable | ✅ | | isRowID | String | @Input | Determines if a dataKey designates this row's rowID. The selected row for the table uses this determine if a row is selected even after a datasource refresh. | ✅ |
UINestedTableRow
|Component|Selector|
|---|---|
|UINestedTableRowComponent|ul-nestedRow
|
Parameters
|Parameters|Data Type|Type|Description|Optional| |---|---|---|---|---| |class|String|@Input()|Set class on NestedRow component.|✅|
Example
<ul-nestedRow>
<ng-template let-row>
<div class="grid grid-cols-2 gap-2">
<span>{{row.display}}</span>
<span>{{row.id}}</span>
</div>
</ng-template>
</ul-nestedRow>
Dependent Entities
ULRow (Optional)
Used to aide in building/customizing the row element when building table. This is a directive and can be applied to the UIBasicTablecomponent by adding the element to the ul-table
tag.
- For now this only applies to the dataRow. (No column row, header row and Nested is handled in its own component)
- No Parameters
| Directive | Selector | Context | Parent |
| ------------------- | -------- | ---------------------- | -------------------------------- |
| UlTableRowDirective | ul-row
| TableCacheContext<T>
| UIBasicTableComponent (ul-table) |
Model
export interface TableCacheContext<T>
{
$implicit: T;
$index: number;
selectedExpandRow?: T;
rowSelected: boolean;
rowTriggered:boolean;
nestedComponent: UINestedTableRowComponent | undefined;
columns: UIColumnHandler[];
cell?:UIColumnHandler ;
isDataRow:boolean;
}
export interface TableRenderCache<T>
{
dataRow: EmbeddedViewRef<TableCacheContext<T>> | undefined;
nestedRow: EmbeddedViewRef<TableCacheContext<T>> | undefined;
context: TableCacheContext<T>;
}
Example
<ul-table #tbl class="border-collapse" [dataSource]="countryData" nestedClickEnabled>
<tr *ul-row="let row;"
class="bg-slate-500"></tr>
<!--...-->
</ul-table>
Information
This should render in real time anytime there is a change and not conflict with changing data as long as you use the trackBy functionality.
ULHeaderCell
Used to aide in building the Header cell for each of the columns. This is optional as well and if not set then the default will be used.
| Directive | Selector | Context | Parent |
| --------------------- | ---------------------------- | ---------------------------------------------------------------------------------------------- | -------------------------------- |
| ULHeaderCellDirective | th[ul-header], [ul-header]
| { "$implicit": "Columns from the TableComponent", "Sort": "Saved Sort object for the table" } | UIBasicTableComponent (ul-table) |
Example
<ul-table #tbl [dataSource]="$source" >
<!--...-->
<th *ul-header="let column;let sort='Sort';"> <!-- Context -->
<div class="flex container group hover:text-red-400">
<button (click)="tbl.SortClicked(column.DataKey)"> <!-- This is how to trigger the table sort from the header definition -->
<span> {{column.Display}} </span> <!-- Output header display name-->
<!--Up Arrow-->
<i class="fa fa-long-arrow-up "
[class.invisible]="!column.Sortable || (sort?.active != column.DataKey) || (sort?.direction ?? '') == 'desc' || (sort?.direction ?? '') == ''"
[class.group-hover:visible]="column.Sortable && ((sort?.direction ?? '') == '' || (sort?.direction == 'desc' && column.DataKey == sort?.active))"
style="padding-right: 1px;" aria-hidden="true"></i>
<!--Down Arrow-->
<i class="fa fa-long-arrow-down"
[class.invisible]="!column.Sortable || (sort?.active != column.DataKey ) || sort?.direction == 'asc' || (sort?.direction ?? '') == '' "
[class.group-hover:visible]="column.Sortable && (sort?.direction == 'asc' && column.DataKey == sort?.active)"
aria-hidden="true"></i>
<!-- The conditional for the classes should be universal so feel free to use your own icons or design for sort client-display -->
</button>
</div>
</th>
</ul-table>
UIFilter
Automatically included in the UITable.
| Component | Selector |
| ---------------------- | ----------------- |
| UIBasicFilterComponent | ul-basic-filter
|
Parameters
| Parameters | Data Type | Type | Description | Optional |
| --------------- | ---------------------------------- | --------- | ----------------------------------------------------------------------------------- | -------- |
| SelectedFilters | EventEmitter<ListItem<string>[]>
| @Output() | Outputs a dataKey and filter pairing determining which data Key should be filtered. | ✅ |
Example
<ul-table [dataSource]="services.magicWand['CompanyLocationsService'].getAllCompanyLocationTypes()">
<ul-column dataKey="id" display="ID">
<!--You can leave the template empty if the result should be just text -->
<!-- The logic uses the dataKey value and applies it like so:
<ng-template #noData let-row let-cell="cell">
<span>{{row[cell.DataKey]}}</span>
</ng-template>
-->
</ul-column>
<ul-column dataKey="display" display="Display">
<ng-template let-row>
<span>{{row.display}}</span>
</ng-template>
</ul-column>
<ul-nestedRow>
<ng-template let-row>
<div class="grid grid-cols-2 gap-2">
<span>{{row.display}}</span>
<span>{{row.id}}</span>
</div>
</ng-template>
</ul-nestedRow>
</ul-table>
UIModal
This component comes with a button and is meant for an inline implementation of the UIModal.
| Component | Selector |
| -------------------- | ---------- |
| UIModalViewComponent | ul-modal
|
Parameters
| Parameters | Data Type | Type | Description | Optional | | ----------- | --------- | ------ | ----------------------------------------- | -------- | | buttonText | String | @Input | Sets the text for the inline button. | | | buttonClass | String | @Input | Sets class for button in the UIModal | ✅ | | modalClass | String | @Input | Set the class on the modal dialog element | ✅ | | contentClass | String | @Input | Set the class on the modal-box element | ✅ | | iconClass | String | @Input | Displays and sets icon for button that opens modal. | ✅ | | Close() | method | Property | Displays and sets icon for button that opens modal. | |
Content Projection
<!-- ... -->
<dialog #Modal1 class="modal overflow-y-auto" [ngClass]="modalClass">
<div class="modal-box max-w-fit" [ngClass]="contentClass">
<ng-content></ng-content> <!-- no tag acts as default -->
<div class="modal-action">
<form method="dialog">
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">✕</button>
<ng-content select="[actions]"></ng-content> <!-- actions tag -->
</form>
</div>
</div>
</dialog>
Example
<ul-modal buttonText="Open Popup">
<div> <!-- no tag acts as default -->
<span>TEST Popup</span>
</div>
<div actions class="grid grid-cols-2 gap-2"> <!-- actions tag --> <button class="btn btn-primary">Test button 1</button>
<button class="btn btn-primary">Test button 2</button>
</div>
</ul-modal>
UITabView
| Component | Selector |
| ------------------ | --------- |
| UITabViewComponent | ul-tabs
|
Parameters
| Parameters | Data Type | Type | Description | Optional | | ---------- | --------- | ------ | ------------------------------------------------------------------ | -------- | | name | String="" | @Input | Sets the tabnameindex inside each tab inside of the tabs component | ✅ |
Content Projection
<div role="tablist" class="tabs tabs-boxed" [ngClass]="class">
<ng-content></ng-content> <!--Nested Content-->
</div>
Child Components
UITab
| Component | Selector |
| -------------- | -------- |
| UITabComponent | ul-tab
|
Parameters
| Parameters | Data Type | Type | Description | Optional | | ------------ | ------------------ | ------ | ---------------------------------------------------------------------------------------------------- | -------- | | tabLabel | String="" | @Input | Sets the text on the button for this tab. | ✅ | | tabSelected | Boolean=False | @Input | Sets whether or not the tab is pre-selected | ✅ | | tabNameIndex | String="my_tabs_1" | @Input | Sets the tab so that only 1 tab that has the same NameIndex can be opened at any given point in time | ✅ | | tabClass | String | @Input | Sets the class for the tab pane | ✅ |
Content Projection
<input #checkbox type="radio" [name]="tabNameIndex" role="tab" class="tab" [attr.aria-label]="tabLabel" /><div role="tabpanel" class="tab-content p-10"><ng-content></ng-content></div>
Example
<ul-tabs class="w-full">
<ul-tab tabLabel="Label 1" tabNameIndex="tab_1" [tabSelected]="true" >
<div class="grid grid-cols-2">
<ul-input contentType="input" label="Input 1" ></ul-input>
<button class="btn btn-accent w-24"> Done </button>
</div>
</ul-tab>
<ul-tab tabLabel="Label 2" tabNameIndex="tab_1" >
<div class="grid grid-cols-2">
<ul-input contentType="input" label="Input 2" defaultValue="Set Default" ></ul-input>
</div>
</ul-tab>
</ul-tabs>
UIMenu
| Component | Selector |
| --------------- | --------- |
| UIMenuComponent | ul-menu
|
Parameters
| Parameters | Data Type | Type | Description | Optional | | ---------- | --------- | ------ | --------------------------- | -------- | | class | String | @Input | Sets the class for the Menu | ✅ |
Example
<ul-menu class="w-48 menu"> <!-- This is set on the component level but angular is kind of stupid -->
<ul-menuItem label="test"></ul-menuItem>
<ul-menuItem label="test 1" >
<ul-menuDetail summary="test">
<ul-menuItem label="inner test"></ul-menuItem>
<ul-menuItem label="inner test 1"></ul-menuItem>
<ul-menuItem label="inner test 1"></ul-menuItem>
</ul-menuDetail>
</ul-menuItem>
<ul-menuItem label="test 2" (action)="print('Hello World')"></ul-menuItem>
</ul-menu>
- You may need to add the class 'menu' to ul-menu. I had 1 project where it was necessary and another where it was not. The class should be preset but even after that issue might persist and is why I left this note. This is due to multiple style sheets and different rendering in different components depending on how its built. Basically there's difference between setting menu on a package level and target project level. 😓
Children Components
UIMenuItem
| Component | Selector |
| ------------------- | ------------- |
| UIMenuItemComponent | ul-menuItem
|
Parameters
| Parameters | Data Type | Type | Description | Required |
| ---------- | ------------------- | ------- | -------------------- | -------- |
| label | String | @Input | Menu option text | |
| click | EventEmitter<any>
| @Output | Handles click action | |
Example
<ul-menuItem label="inner test"></ul-menuItem>
Children Components
UIMenuDetails
Also the UI MenuItem can be inserted into MenuDetails
| Component | Selector |
| --------------------- | --------------- |
| UIMenuDetailComponent | ul-menuDetail
|
Parameters
| Parameters | Data Type | Type | Description | Required | | ---------- | --------- | ------ | --------------------------- | -------- | | summary | String | @Input | Name of folder for dropdown | |
Example
<ul-menuDetail summary="test">
<ul-menuItem label="inner test"></ul-menuItem>
<ul-menuItem label="inner test 1"></ul-menuItem>
<ul-menuItem label="inner test 1"></ul-menuItem>
</ul-menuDetail>
UIMenuDropdown
The main difference between this and UIMenu is that this UI object starts as a button and to open the menu you must click the button. On the other hand UIMenu renders as collapsed but visible.
| Component | Selector |
| ----------------------- | ----------------- |
| UIMenuDropdownComponent | ul-menuDropdown
|
Parameters
| Parameters | Data Type | Type | Description | Required | | ----------- | --------- | ------ | ---------------------------------------------------------------------- | -------- | | class | String | @Input | Class for dropdown | | | buttonText | String | @Input | Sets the text for the inline button that is rendered with the dropdown | | | buttonClass | String | @Input | Sets the class for the button that opens this dropdown. | |
Children Components
Uses the same child components from UIMenu.
-
UIMenuItem
-
UIMenuDetails
Example
<ul-menuDropdown class="w-48" buttonText="test">
<ul-menuItem label="test"></ul-menuItem>
<ul-menuItem label="test 1" >
<ul-menuDetail summary="test">
<ul-menuItem label="inner test"></ul-menuItem>
<ul-menuItem label="inner test 1"></ul-menuItem>
<ul-menuItem label="inner test 1"></ul-menuItem>
</ul-menuDetail>
</ul-menuItem>
<ul-menuItem label="test 2" (click)="print('Hello World')"></ul-menuItem>
</ul-menuDropdown>
UICardView
| Component | Selector |
| ------------------- | --------- |
| UICardViewComponent | ul-card
|
Parameters
| Parameters | Data Type | Type | Description | Required | | ---------- | --------- | ------ | -------------------------------------------- | -------- | | header | String="" | @Input | Sets a title text for the UICard | | | content | String="" | @Input | Sets the span as content to insert text body | | | cardClass | String="" | @Input | Set the class for the UICard | |
Content Projection
<div class="card shadow-xl">
<div class="card-body">
<h2 class="card-title">{{header}}</h2>
<p>{{content}}</p>
<ng-content ></ng-content> <!-- Default content location -->
<div class="card-actions justify-end flex flex-row">
<ng-content select="[actions]"></ng-content> <!-- Must include actions tag -->
</div>
</div>
</div>
Example
<ul-card header="Header Text" content="Lorem Ipsum">
<div>
</div>
<div actions>
<button class="btn btn-accent"> Test </button>
</div>
</ul-card>
UIDetailView
| Component | Selector |
| --------------------- | ----------- |
| UIDetailViewComponent | ul-detail
|
Parameters
| Parameters | Data Type | Type | Description | Required | Options |
| ----------- | -------------------- | ------ | --------------------------------------- | -------- | ------------------------------------------------------------------------------ |
| placement | String | @Input | Sets the placement of the grid class | | "stretch" | "evenly" | "around" | "between" | "end" | "start" | "center" |
| columnCount | Number | @Input | Set the grid class column count | | |
| class | String | @Input | Sets other classes to the Grid element | | |
| gap | Number | @Input | Sets gap for grid class | | |
| details | ListItem<string>[]
| @Input | Sets the data for cells in detail view. | | |
InitLogic
var ConcatedClass:string = ' grid-cols-' + this.columnCount + ' gap-'+ this.gap + ' place-content-' + this.placement;
this.class = this.class + ConcatedClass;
Example
private exDetails: ListItem<string>[] = [
new ListItem("Test1", "Value1"),
new ListItem("Test2", "Value2"),
new ListItem("Test3", "Value3"),
new ListItem("Test4", "Value4")
];
<ul-detail [details]="exDetails" columnCount="2" gap="4" placement="center">
</ul-detail>
UIInputField
| Component | Selector |
| -------------------------- | ---------- |
| UIBasicInputFieldComponent | ul-input
|
Parameters
| Parameters | Data Type | Type | Description | Required | Options |
| ------------- | -------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
| label | String | @Input | Sets the label for the Input form | | |
| contentType | String="input" | @Input | Sets the content type when loading Input box | ✅ | "input" | "select" | "textarea" | "radio" | "toggle" | "checkbox" | "file" | "autocomplete" |
| inputType | String="text" | @Input | Sets the input type for loading the input box. Typically for content type 'input'. | | "color" | "email" | "date" | "month" | "number" | "password" | "search" | "tel" | "text" | "url" | "week" | "autocomplete" |
| dateMode | String="single" | @Input | Sets date input mode | | 'multiple' | 'range' |
| dateOptions | FlatpickrDefaultsInterface=new FlatpickrDefaults() | @Input | Sets other date options | | Options - flatpickr |
| datasource | ListItem<string>[] = []
| @Input | Sets datasource for Select, Autocomplete and Radio | ✅ (If autoComplete is not set) | |
| dataDefault | ListItem<string>
| @Input | Sets the dataDefault for select | ✅ | |
| defaultValue | Any="" | @Input | Sets the default value for any UIInput | | |
| class | String | @Input | Sets class for Input element or actionable element | | |
| formClass | String | @Input | Sets the class for the parent div of the input element and label element | | |
| labelClass | String | @Input | Sets label class | | |
| iconClass | String | @Input | Sets Icon class | | |
| tooltip | String | @Input | When a user hovers over the input it displays a tooltip pop-up | | |
| tipClass | String | @Input | Sets class for tooltip (Direction/Color) | | |
| placeholder | String | @Input | Sets placeholder text for input boxes (Limited to text-based inputs) | | |
| disabled | Boolean | @Input | Disables user input for the input box | | |
| required | Boolean | @Input | This is more to save whether or not an input is required no UI changes occur | | |
| fieldID | String | @Input | Only needed for radio inputs. Sets the name for the radio. Groups with the same name can only have one enabled radio | ✅(Radio) | |
| rowIndex | Number | @Input | Can be used to set an index for duplicate inputs and possibly integrate with UINestedRow | | |
| dataKey | String | @Input | Can be used to locate the target input box in UIFormComponent | | |
| Change | EventEmitter<any>
| @Output | Can extract data from input box from this event for (All Inputs) | | |
| alt | String | @Input | Anything that is not undefined for this attribute will trigger an alternate input design. | | |
| dropdownClass | String | @Input | Specifically for the Autocomplete dropdown class | | |
| autoComplete | (inputValue?:string) => Observable<ListItem<string>[]>
| @Input | Used to dynamically set the autocomplete selection list based on current autocomplete value. Any input value change triggers this function to return a new list. (The observable should auto destroy) | ✅ (If datasource is not set) | |
| validators | ValidatorFn[]? | @Input | Set validators for the input based on output form value. Use method Validate()
to trigger validation check. | | |
| isReactive | string? | @Input | Sets if the input should auto-resize base on screen size | | |
| maxlength | string | @Input | Adds to validation of form. Triggers invalid if value char count is above the maxlength | | |
| minlength | string | @Input | Adds to validation of form. Triggers invalid if value char count is above the minlength | | |
| pattern | string | @Input | Sets regex to verify from the inputs value. | | |
| title | string | @Input | Sets title for input element (Hover hint pops-up) | | |
Logic
GetValue
Can be used to get value from component no matter the type just from one function.
public GetValue(): string | undefined {
if (this.contentType == "select") {
return String(this.SelectElement.nativeElement.value);
} else if (this.contentType == "input") {
return String(this.InputElement.nativeElement.value);
}else if (this.contentType == "radio"){
var selectedItems = this.RadioElement.filter(x => x.nativeElement.checked == 'checked');
return selectedItems.length > 0 ? selectedItems[0].nativeElement.value: undefined;
}else if (this.contentType == "checkbox"){
var selectedItem:string = this.CheckboxElement.nativeElement.checked;
return selectedItem;
}else if(this.contentType == 'multiSelect')
{
return JSON.stringify( this.multiItem.filter(x => (x.nativeElement.firstChild?.lastChild as HTMLInputElement).checked ).map(x => x.nativeElement.ariaValueText));
}
else{
return undefined;
}
}
public SetValue(value:any|undefined){
if (this.contentType == "select") {
this.SelectElement.nativeElement.value = value ?? this.defaultValue;
} else if (this.contentType == "input") {
this.InputElement.nativeElement.value = value ?? this.defaultValue;
}else if (this.contentType == "radio"){
var selectedItems = this.RadioElement.filter(x => x.nativeElement.checked == 'checked');
selectedItems.forEach(x => {
x.nativeElement.checked = value ?? this.defaultValue;
});
}else if (this.contentType == "checkbox"){
this.CheckboxElement.nativeElement.checked = value ?? this.defaultValue;
}else if (this.contentType == "multiSelect"){
this.multiItem.forEach(x => {
var foundDefault = this.multiSelectData?.find(defaults => defaults.nativeElement.value == x.nativeElement.ariaValueText);
var targetCheck = (x.nativeElement.firstChild?.lastChild as HTMLInputElement);
if (foundDefault != undefined)
{
targetCheck.checked = foundDefault?.nativeElement.checked
}
});
}
}
Example
<div class="m-2 grid grid-cols-2 gap-2">
<!-- Dates -->
<ul-input label="Start Date" contentType="input" inputType="date" class="w-64"></ul-input>
<ul-input label="End Date" contentType="input" inputType="date" class="w-64"></ul-input>
<!-- Inputs -->
<ul-input label="Color" contentType="input" inputType="color" class="w-48" iconClass="fa fa-eyedropper mr-1"></ul-input>
<ul-input label="Email" minlength contentType="input" inputType="email" class="w-48" placeholder="Enter Email" iconClass="fa fa-envelope mr-1">
<p hint class="validator-hint hidden">
<!-- This is how the hint is defined. I might change this to a directive instead -->
Test Error Hint
</p>
</ul-input>
<!-- Select -->
<ul-input label="Example Select" contentType="select" [datasource]="exList" class="w-48 text-white" iconClass="fa fa-filter mr-2" labelClass="text-white"></ul-input>
<!-- Radio -->
<ul-input contentType="radio" [datasource]="exDetails" formClass="grid grid-cols-4 gap-2 w-fit"></ul-input>
<!-- Toggle -->
<ul-input contentType="toggle" label="Test switch" iconClass="fa fa-moon mr-1"></ul-input>
<!-- Checkbox -->
<ul-input contentType="checkbox" label="Test checkbox"></ul-input>
<!-- Autocomplete -->
<ul-input contentType="autocomplete" label="Search" [autoComplete]="autocompleteList"
iconClass="fa fa-search mr-1"
tooltip="Test"
tipClass="tooltip-primary tooltip-top" dropdownRelative alt ></ul-input>
<!-- Multi-Select -->
<ul-input contentType="multiSelect" hint="test" (Change)="print($event)" tooltip="Test" label="Test" formClass="m-2">
<input #listItem class="checkbox-error" name="Test 1" value="1" >
<input #listItem class="checkbox-error" name="Test 2" value="2" checked >
<input #listItem class="checkbox-error" name="Test 3" value="3" >
<input #listItem class="checkbox-error" name="Test 4" value="4" >
<input #listItem class="checkbox-error" name="Test 5" value="5" >
<input #listItem class="checkbox-error" name="Test 6" value="6" >
</ul-input>
</div>
UIBasicChip
| Component | Selector |
| -------------------- | --------- |
| UIBasicChipComponent | ul-chip
|
Parameters
| Parameters | Data Type | Type | Description | Required |
| ---------- | ---------------------- | ------- | ------------------------------ | -------- |
| click | EventEmitter<string>
| @Output | Gets the label of clicked chip | |
| class | String | @Input | Chip class | |
| label | String | @Input | Chip text | |
| value | String | @Input | Sets hidden value for chip | |
Example
So far this is only used in filter component
<div class="flex flex-row items-center basis-1/2 mt-2 ml-1">
@if (ChipList.length > 0) {
<span class="text-ghost text-sm "> Delete Filters: </span>
}
@for (item of ChipList; track $index)
{
<ul-chip [label]="item.Key + ': \'' + item.Value! + '\''" [value]="item.Value!" class="badge-sm" (click)="ChipDeleteClick(item.Value!)"></ul-chip>
}
</div>
UIAlerts
I considered making this component something that is built with in a context of a component and therefore can be used in multiple components. The problem is that may cause the pop-ups to overlap. So its better to me to have one HTML Definition that connects to a static source of alerts.
| Component | Selector |
| ----------------- | ----------- |
| UIAlertsComponent | ul-alerts
|
Parameters
| Parameters | Data Type | Type | Description | Required | | ---------- | --------- | ------ | -------------------------------------------------------------------------------------------- | -------- | | allAlerts | Any[] | @Input | Automatically gets the saved alerts from static store but can be overwritten with this input | |
Variables
- static SavedAlerts:any[]
Contains the saved alerts that were created
Logic
Automatically DESTROYS the alert after 10s
public static AddAlert(headerString:string,textString:string, classString:string, timeSecs:number = 7, showAlertBool:boolean=true,buttonList:UIButton[] = [] )
public static ClearAlerts()
Example
<ul-alerts [allAlerts]="getAlerts()"> <!-- Setting the allalerts parameter should no longer be needed -->
</ul-alerts>
AlertEvent(x:any) {
UIAlertsComponent.AddAlert("Test Header", "test text 3", "alert-error", 20, true, [
new UIButton("Button1", "", null)
]);
}
Service
AlertService
Automatically adds the AlertsComponent (NOT Alert) if it hasn't been initialized. Once initialized like below then it can be accessed by any child components from the static instance: UIAlertsComponent
Example
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrl: './app.component.scss',
providers:[AlertsService]
})
export class AppComponent {
title = 'UITools_Test';
constructor(public vcr:ViewContainerRef, public thisAlerts: AlertsService) {
}
}
Dependent Components
UIAlert
Parameters
These are the same parameters used in UIAlerts > allAlerts.
| Parameters | Data Type | Type | Description | Required | | ---------- | --------- | ------ | --------------------------------- | -------- | | header | String | @Input | Sets Header for alert | | | text | String | @Input | Set alert body | | | class | String | @Input | Sets alert class | | | showAlert | Boolean | @Input | Determines if alert should render | | | buttons | UIButton | @Input | Adds buttons to the alert | | | timeSeconds | number | @Input | Seconds that the alert shows on screen for | |
UIAccordion
Ng-Content enabled. Content of inner tags gets passed through to the accordion content.
| Component | Selector |
| -------------------- | -------------- |
| UIAccordionComponent | ul-accordion
|
Parameters
| Parameters | Data Type | Type | Description | Required | Options |
| ---------- | ----------------------- | ------- | --------------------------------------------------------------------- | -------- | --------------------- |
| label | String | @Input | Sets pre-opened accordion text | | |
| isOpened | Boolean | @Input | Sets rather or not the accordion renders pre-opened | | |
| name | String | @Input | Sets accordion name | | |
| type | String | @Input | Sets rather accordion can be multi-select or single-select (By name). | | "radio" | "checkbox" |
| selected | EventEmitter<Boolean>
| @Output | Used to acquire if a accordion is selected upon clicking | | |
Example
<ul-accordion label="Test 1" name="1">
<span>Content 1</span>
</ul-accordion>
<ul-accordion label="Test 2" name="1">
<span>Content 2</span>
</ul-accordion>
UIStats
| Component | Selector |
| ---------------- | ---------- |
| UIStatsComponent | ul-stats
|
Parameters
| Parameters | Data Type | Type | Description | Required | | ---------- | --------- | ------ | --------------------------------- | -------- | | class | String | @Input | Sets class for stats panel holder | |
Dependent Components
UIStat
| Component | Selector |
| --------------- | --------- |
| UIStatComponent | ul-stat
|
Parameters
| Parameters | Data Type | Type | Description | Required | | ---------- | --------- | ------ | ------------------------------------------------ | -------- | | title | String | @Input | Sets the text for the title of the stat | | | value | String | @Input | Sets value text for stat | | | desc | String | @Input | Sets description text for stat | | | titleClass | String | @Input | Sets class of title | | | valueClass | String | @Input | Sets class for value text | | | descClass | String | @Input | Sets description class | | | statClass | String | @Input | Sets class for greater form of this stat | | | iconClass | String | @Input | Sets a fontawesome icon to display with the stat | |
Example
<ul-stat title="Stat 1" value="20%" desc="↖ Lorem Ipsum" iconClass="fa fa-info-circle" valueClass="text-accent" ></ul-stat>
Example
<ul-stats class="">
<ul-stat title="Stat 1" value="20%" desc="↖ Lorem Ipsum" iconClass="fa fa-info-circle" valueClass="text-accent" ></ul-stat>
<ul-stat title="Stat 2" value="40%" desc="↖ Lorem Ipsum" valueClass="text-primary" ></ul-stat>
<ul-stat title="Stat 3" value="10%" desc="↘ Lorem Ipsum" valueClass="text-info"></ul-stat>
</ul-stats>
Use Win + ';' to get some extra characters to use.
Theme Handling
The theme is determined by the below CommonComponentService. DaisyUI Theme Documentation
export abstract class CommonComponentService{
public currentTheme:string = CommonComponentService.themeString;
static themeString :string | 'dark' | 'dracula' | 'light' = localStorage.getItem('theme') ?? 'dark' ;
constructor(){
document.documentElement.setAttribute("data-theme", "dark");
}
static UpdateTheme(theme: string | 'dark' | 'dracula' | 'light'){
localStorage.setItem('theme', theme);
document.documentElement.setAttribute("data-theme", localStorage.getItem('theme')?? theme);
console.log("Updated theme to: " + theme);
}
}
Usage
ThemeEvent(x: any, newTheme:string) {
CommonComponentService.UpdateTheme(newTheme);
}
<div class="m-2 grid grid-cols-3 gap-1">
<button class="btn btn-accent" (click)="ThemeEvent($event, 'dracula')">Dracula</button>
<button class="btn btn-accent" (click)="ThemeEvent($event, 'light')">Light</button>
<button class="btn btn-accent" (click)="ThemeEvent($event, 'dark')">Dark</button>
</div>
UINavBar
| Component | Selector |
| ----------------- | -------- |
| UINavBarComponent | ul-nav
|
Parameters
| Parameters | Data Type | Type | Description | Required | | ---------- | --------- | ------ | ----------------------------------- | -------- | | titleText | String | @Input | Sets the center text for the NavBar | | | titleClass | String | @Input | Sets the class for the center title | | | class | String | @Input | Sets class for NavBar element | |
Content Projection
<div class="navbar bg-base-100" [ngClass]="class">
<div class="navbar-start">
<ng-content select="[start]" ></ng-content>
</div>
<div class="navbar-center">
<button class="btn text-xl" [ngClass]="titleClass">{{titleText}}</button>
</div>
<div class="navbar-end">
<ng-content select="[end]" ></ng-content>
</div>
</div>
Example
<ul-nav titleText="Daisy UI">
<div start>
<ul-menuDropdown class="w-48" buttonText="Menu" buttonClass="btn btn-accent">
<ul-menuItem label="test"></ul-menuItem>
<ul-menuItem label="test 1">
<ul-menuDetail summary="test">
<ul-menuItem label="inner test"></ul-menuItem>
<ul-menuItem label="inner test 1"></ul-menuItem>
<ul-menuItem label="inner test 1"></ul-menuItem>
</ul-menuDetail>
</ul-menuItem>
<ul-menuItem label="test 2" (action)="print('Hello World')"></ul-menuItem>
</ul-menuDropdown>
</div>
<div end> <button class="btn btn-primary"> Activity</button></div>
</ul-nav>
ModalService
This is a service for handling in code Modal Windows to open whilst also maintaining the abillity to extract updated data.
Initialize
- ViewContainerRef must be injected into the parent component
- Inject
ModalService<T>
with target component type<T>
.
Functions
- open(diagComp:
Type<T>
, setInputs:((comp:ComponentRef<T>
) => void) |undefined = undefined)Use to init component
- close()
Use to fully close the dialog
- afterClosed():Observable<T|undefined>
Allows user to subscribe for when dialog is closed
Usage/Example
//...
constructor(public vcr:ViewContainerRef, private mDiag:ModalService<TempComponent>) //Target component
{//...
}
//...
testModal(x:any)
{
this.mDiag.open(TempComponent,(c)=> {
c.setInput('title','Parent Title Example')
});
this.mDiag.afterClosed().subscribe((res) => {
console.log(res?.GetValues());
this.mDiag.close();
});
}
<button class="btn btn-primary" (click)="testModal($event)">Modal</button>
UISidebar
| Component | Selector |
| ------------------ | ------------ |
| UISidebarComponent | ul-sideBar
|
Parameters
| Parameters | Data Type | Type | Description | Required | | ------------- | ----------------------- | ------ | ---------------------------------------------------- | -------- | | actionClass | String='btn btn-accent' | @Input | Sets class for sidebar trigger button | | | actionText | String | @Input | Sets text for button that triggers the button | | | sidebarClass | String | @Input | Sets the class for the menu options in the sidebar | | | sidebarZIndex | String | @Input | Sets the z-axis for the sidebar so no overlaps occur | |
Example
<ul-nav titleText="Daisy UI">
<div start>
<ul-sideBar actionText="Menu">
<li><a href="./testPage">Home</a></li>
<li><a href="./tablePage">Tables</a></li>
<li><a href="./menuExample">Menu</a></li>
<li><a href="./modalExample">Modal</a></li>
<li><a href="./statsExample">Stats</a></li>
<li><a href="./alertsExample">Alerts</a></li>
<li><a href="./inputsExample/">Inputs</a></li>
</ul-sideBar>
</div>
<div end> <button class="btn btn-primary" (click)="NewAlert($event)"> Activity</button></div>
</ul-nav>
UITooltip
This component is meant to be very simple and just wraps content in a tooltip div. If no string is given for a tooltip then the class would not load.
| Component | Selector |
| ------------------ | -------- |
| UITooltipComponent | ul-tip
|
Parameters
| Parameters | Data Type | Type | Description | Required | | ---------- | --------- | ------ | ---------------------- | -------- | | tooltip | String | @Input | Sets the tooltip text | | | tipClass | String | @Input | Sets class for tooltip | |
Content Projection
<div [class.tooltip]="tooltip != undefined" [attr.data-tip]="tooltip" [ngClass]="tipClass">
<ng-content/>
</div>
Example
<ul-input contentType="autocomplete" label="Search" [datasource]="listSource"
iconClass="fa fa-search mr-1" tooltip="Test" tipClass="tooltip-accent tooltip-open" ></ul-input>
UICalendar
| Component | Selector | |