npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

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

NPM Package

UL-Lib Sandbox - StackBlitz

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 @Input trackBy ) 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 the isRowID or trackBy 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

Link to Tailwinds Logic

  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>  

Tailwinds info for Options

UICalendar

| Component | Selector | |