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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@myrmidon/cadmus-thesaurus-store

v1.0.0

Published

Cadmus thesauri store components.

Readme

CadmusThesaurusStore

  • 📦 @myrmidon/cadmus-thesaurus-store

This library contains components for displaying and editing Cadmus thesauri, built on top of @myrmidon/paged-data-browsers.

Thesauri

Thesauri represent taxonomies of any type you might be using in editing your content. For instance, in describing a writing you might have a set of ink colors to pick from. The models for the thesaurus and its entries are defined in an external package (@myrmidon/cadmus-core).

Essentially, a thesaurus is a list of terms, each having an ID and a human-readable value. Such list can be a simple, flat list, or a hierarchical list. In both cases, they are defined as objects having each a list of entries.

Each entry in a thesaurus object has:

  • an arbitrarily assigned id, which must be unique in the context of that object;
  • a text value to be displayed to the end user.

For instance, you might have a list of languages to pick from, like English, French, Italian, etc.: in this case, your thesaurus would have its own ID, e.g. languages, plus entries like eng=English, fre=French, ita=Italian, etc. Here I'm using ISO 639 for language codes, and using standards is always recommended when available; but IDs are totally arbitrary.

You can also have hierarchical thesauri, where entries are arranged in a hierarchy represented with dots in their IDs. For instance, say you want to represent this simple 2-levels hierarchy:

  • language:
    • language: phonology
    • language: morphology
    • language: syntax

You can use a dot in each entry to represent three children entries under the same node:

[
  { "id": "lang.pho", "value": "language: phonology" },
  { "id": "lang.mor", "value": "language: morphology" },
  { "id": "lang.syn", "value": "language: syntax" }
]

By convention, for each dot in the ID there is a colon in the value, so that the full hierarchy is displayed in every entry.

Should you want to have a selectable entry also for the parent language node, you just have to add another one, like this:

[
  { "id": "lang.-", "value": "language" },
  { "id": "lang.pho", "value": "language: phonology" },
  { "id": "lang.mor", "value": "language: morphology" },
  { "id": "lang.syn", "value": "language: syntax" }
]

Services

A couple of services are used by the components in this library:

StaticThesaurusPagedTreeStoreService

Implements PagedTreeStoreService<ThesaurusEntryNodeFilter>. It converts a flat array of ThesaurusEntry objects (all loaded at once — hence "static") into a paged tree, using the dot-separated IDs to infer hierarchy. For example, "animal.mammal.dog" is a child of "animal.mammal", which is a child of "animal".

Nodes are of type ThesaurusEntryPagedTreeNode (extends PagedTreeNode) and the filter is ThesaurusEntryNodeFilter (extends TreeNodeFilter with an optional label field).

An optional renderLabel function can be supplied to the constructor; a built-in helper renderLabelFromLastColon is provided and trims everything up to (and including) the last colon in the label, so "animal: mammal: dog" is rendered as just "dog".

EditableStaticThesaurusPagedTreeStoreService

Extends EditablePagedTreeStoreServiceBase<ThesaurusEntryNodeFilter> and is the editable counterpart of StaticThesaurusPagedTreeStoreService. It still loads all entries at once but tracks in-memory edits (add, update, delete) and can commit them all at once.

Additional method beyond the base interface:

  • getCurrentEntries(): returns the flat ThesaurusEntry[] list with all pending (unsaved) changes applied — the correct data to use when persisting the thesaurus to a server.

Components

ThesaurusBrowserComponent

  • 🔑 cadmus-thesaurus-browser

A readonly paged tree browser for thesaurus entries. This is a lower-level component used directly when you only need to browse and pick a single entry, without the higher-level tree wrapper.

  • ▶️ inputs:
    • service (StaticThesaurusPagedTreeStoreService): the service instance to load nodes from. A default no-op service is used if not provided.
  • 🔥 outputs:
    • nodePick: fired when a leaf node (an entry without children) is clicked.

The component also exposes a label search form (field + find/clear buttons) that calls store.findLabels() and store.removeHilites() on the underlying PagedTreeStore.


ThesaurusTreeComponent

  • 🔑 cadmus-thesaurus-tree

The thesaurus tree component displays a set of hierarchical thesaurus entries in a tree, provided that each entry marks its hierarchy with dots, and allows you to pick any entry.

  • ▶️ inputs:
    • entries (ThesaurusEntry[]): all the entries in the thesaurus. Use this for simple cases where the parent component properly triggers change detection when data changes.
    • entries$ (Observable<ThesaurusEntry[]>): alternative observable of entries. Use this when the parent uses OnPush or zoneless change detection and the regular entries input doesn't update properly.
    • renderLabel ((label: string) => string): optional function for rendering node labels. Defaults to renderLabelFromLastColon. The original label is always emitted via entryChange regardless of this function.
  • 🔥 outputs:
    • entryChange: fired when a leaf node is picked. Only leaf nodes (entries without children) can be selected.

Internally, this component uses a StaticThesaurusPagedTreeStoreService instance and a ThesaurusBrowserComponent.


ThesaurusEntriesPickerComponent

  • 🔑 cadmus-thesaurus-entries-picker

A compact, collapsible picker component for managing multiple entries selected from a hierarchical thesaurus. In its collapsed state it shows the picked entries as a chip list; when expanded it shows the thesaurus tree to pick from.

The component also allows users to enter custom entries beyond the thesaurus entries. Such entries are all marked by an initial $ prefix and do not belong to a thesaurus. This feature must be opted in via allowCustom.

  • ▶️ inputs:
    • availableEntries (ThesaurusEntry[]): all the entries in the thesaurus. Required.
    • hierarchicLabels (boolean): true to show the entries with labels shortened according to their hierarchy.
    • autoSort (boolean): true to automatically sort the picked entries alphabetically (disables drag-and-drop). When false, entries can be manually reordered via drag-and-drop.
    • allowCustom (boolean): true to allow custom values (not in the entries list).
    • minEntries (number): the minimum number of picked entries.
    • maxEntries (number): the maximum number of picked entries (0=unlimited).
    • emptyMessage (string): the message to show when there are no picked entries.
  • 🔁 two-way bindings (Angular signals model):
    • entries (ThesaurusEntry[]): the currently picked entries.
    • expanded (boolean): true when the picker is expanded rather than collapsed.

EditableThesaurusBrowserComponent

  • 🔑 cadmus-editable-thesaurus-browser

An editable paged tree browser for thesaurus entries. Editing happens in memory and when complete the changes can be committed to the underlying data store via EditableStaticThesaurusPagedTreeStoreService.

  • ▶️ inputs:
    • service (EditableStaticThesaurusPagedTreeStoreService): the editable service instance used to load nodes. Required.
    • hasRootFilter (boolean): true to show the tree root nodes filter.
  • 🔥 outputs:
    • nodePick: fired when an entry node is clicked.
    • changesStateChange (boolean): fired when the unsaved-changes state changes. Subscribers can use this to enable/disable save and discard buttons.

Editing operations available via toolbar buttons in the template:

  • Add child: add a new child node under the selected node.
  • Add sibling: add a new sibling node next to the selected node.
  • Edit node: change the label of the selected node.
  • Remove node: delete the selected node and all its descendants (with confirmation).

The component also exposes a label search form and expand/collapse-all buttons, identical to ThesaurusBrowserComponent.


ThesaurusPagedTreeFilterComponent

  • 🔑 cadmus-thesaurus-paged-tree-filter

A filter component for thesaurus paged tree browsers. It can work both as a standalone component (emitting the filter via the filter model) and as a Material dialog (returning the filter when closed).

  • 🔁 two-way binding (Angular signal model):
    • filter (ThesaurusEntryNodeFilter | null | undefined): the current filter value.

When used as a dialog (opened by MatDialog), it closes with the new filter or with null when reset.


ThesEntryEditorComponent

  • 🔑 cadmus-thesaurus-entry-editor

A dialog component for editing a single thesaurus entry (ID and value). Used internally by EditableThesaurusBrowserComponent for add/edit operations.

Input data (EditedThesEntry):

  • id (string): the entry's current ID.
  • value (string): the entry's current value (label).
  • hierarchical (boolean): when true and parentId is set, the ID field is validated to start with the parent ID prefix followed by a dot.
  • parentId (string): the string ID of the parent entry, used to build the hierarchical prefix.
  • idLocked (boolean): when true, the ID field is read-only (used when editing an existing entry).
  • idExists ((id: string) => boolean): a validation callback to prevent duplicate IDs.