Skip to content

@presencelearning/ui

Angular component library for Presence Learning. Provides reusable UI components built on Angular Material and @presencelearning/styles.

Current version: 1.2.2. Ships as a root entry point plus per-group secondary entry points (@presencelearning/ui/topbar, /theme, /rich-text-editor, etc.) — most components are still importable from the bare @presencelearning/ui root, but command-palette and rich-text-editor are secondary-entry-only. See the “Adding a new secondary entry point” section below for how entries are wired up.

Terminal window
npm install @presencelearning/ui

Declared in package.json:

  • @angular/core >=18.0.0 <22.0.0
  • @angular/common >=18.0.0 <22.0.0
  • @angular/cdk >=18.0.0 <22.0.0
  • @angular/material >=18.0.0 <22.0.0
  • @presencelearning/styles ^1.0.0

Also imported by the library but not currently declared as peers — your app needs them installed: @angular/forms (rich text editor), @angular/router (NavigationLinkComponent), @angular/animations (NavigationComponent), and rxjs.

The rich text editor bundles its own runtime dependencies (17 @tiptap/* packages, dompurify, unicode-emoji-json), so they install transitively rather than as peers.

Note that the exported class names have no Pl prefix — the pl- prefix appears only on the selectors.

ComponentSelectorDescription
NavigationComponentpl-navigationMain navigation with expandable/collapsible sidebar
NavigationLinkComponentpl-navigation-linkNavigation link with icon and label
HelpMenuComponentpl-help-menuHelp menu dropdown
BannerComponentpl-bannerInline info/success banner with optional link and action buttons
RichTextEditorComponentpl-rich-text-editorTiptap-based rich text editor with mentions, emoji, tables, and images
PlaceholderComponentpl-placeholderDashed-border box for verifying that the library is wired up correctly

NavigationTriggerDirective ([plNavigationTrigger], exportAs: 'plNavigationTrigger') is also exported, for toggling the sidebar from outside it.

InputTypeDefaultDescription
pagesNavLink[][]Primary navigation links
resourcesNavLink[][]Secondary/resource links
hiddenRoutesstring[][]Routes on which the nav hides itself
currentUrlstring''Drives active-link highlighting

Outputs: linkClicked: NavLink, navigationToggled: boolean. Public methods: toggle(skipSave = false), open(), close(), toggleHelpMenu(). Project help menu content via a #helpMenuContent template.

NavLink resolution priority is routerLink → href → plain button. Collapsed state persists through the PL_NAVIGATION_STORAGE injection token, which defaults to defaultNavigationStorage (localStorage under the key pl-navigation). Override the token to change or disable persistence.

InputTypeDefaultDescription
typeBannerType ('info' | 'success')'info'Visual treatment
titlestring—Banner heading
bodystring—Banner body text
bodyLinkLabelstring—Label for an inline link in the body
bodyLinkHrefstring—Href for the inline body link
primaryButtonLabelstring—Renders the primary action when set
secondaryButtonLabelstring—Renders the secondary action when set
showCloseButtonbooleanfalseRenders a close affordance

Outputs: primaryClicked, secondaryClicked, bodyLinkClicked, closeClicked (all void).

Implements ControlValueAccessor, so it works with formControl/ngModel as well as with the value/valueChange pair.

InputTypeDefaultDescription
valuestring''Editor HTML
readonlybooleanfalseRenders read-only
placeholderstring''Empty-state placeholder
mentionsFetchMentionsFetch | nullnullSupplies @-mention candidates

Output: valueChange: string. Public method: print(): void.

Register the editor engine once at app level:

app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideRichTextEditor } from '@presencelearning/ui/rich-text-editor';
export const appConfig: ApplicationConfig = {
providers: [provideRichTextEditor()],
};
ExportKindDescription
BannerTypetype'info' | 'success'
NavLinktypeNavigation entry — label, optional icon, href, routerLink, external, active, children, enabled
HelpMenuLinktypeHelp menu entry — title, subtitle, optional icon, href, external, local
HelpMenuEmailtypeHelp menu email entry — address, label
PL_NAVIGATION_STORAGEInjectionToken<NavigationStorage>Persistence for the sidebar collapsed state
defaultNavigationStorageconstlocalStorage adapter used by default
NavigationStorageinterfaceContract for a custom storage adapter
provideRichTextEditorfunction() => EnvironmentProviders — registers the Tiptap engine
ActiveStateinterfaceCurrent editor formatting state
MentionIteminterfaceA single mention candidate
MentionsFetchtypeMention lookup callback
HeadingLeveltypeHeading levels the editor supports

Stories exist for BannerComponent, NavigationComponent, PlaceholderComponent, and RichTextEditorComponent. Run locally:

Terminal window
npm run storybook --workspace=@presencelearning/ui

The hand-written exports map in packages/ui/package.json doesn’t get generated — it has to be kept in sync by hand whenever a new secondary entry point is added. To add one:

  1. Create packages/ui/<name>/ng-package.json pointing at a barrel in src/lib/<name>/index.ts.
  2. Add an entry for ./<name> to the exports map in packages/ui/package.json, prefixed with dist/ (matching the pattern of the existing entries).
  3. If the group should also remain public from the root, add export * from './lib/<name>'; to packages/ui/src/index.ts.

Skipping any of these steps leaves the hand-written exports map silently out of sync with the actual build output.


Source: packages/ui