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

aspnetzero-workflow-designer

v1.0.2

Published

Framework-neutral workflow designer and form builder custom elements for the ASP.NET Zero workflow & approval builder.

Readme

aspnetzero-workflow-designer

Framework-neutral custom elements for the ASP.NET Zero workflow & approval builder. One implementation, wrapped by Angular, React and ASP.NET Core MVC — so the three UIs cannot drift apart.

Elements

| Tag | Purpose | |---|---| | <workflow-designer> | Graph editor for WorkflowGraphDocument (steps, transitions, layout) | | <workflow-form-builder> | Form editor for WorkflowFormDocument (sections, fields, validation) |

Both are registered automatically on import.

import 'aspnetzero-workflow-designer';

The host contract

The component is pure: documents in, documents out. It never knows the host's auth token, tenant id or API base URL, and it makes no HTTP calls of its own. Everything reaches it through properties, and everything leaves it through events.

Properties (set as JS properties, not attributes)

| Property | Type | Purpose | |---|---|---| | document | WorkflowGraphDocument / WorkflowFormDocument | The canonical document to edit | | localization | Record<string, string> | Host's localization dictionary | | theme | WorkflowThemeTokens | Colour and font tokens; mapped to CSS custom properties | | permissions | { canEdit?, canPublish?, canSimulate? } | canEdit: false puts the editor in read-only mode | | capabilities | { maxSteps?, maxFormFields?, publicFormEnabled?, ... } | Edition limits and feature switches; see Capabilities | | lookups | { users?, roles?, organizationUnits?, ... } | Async callbacks the host provides for pickers | | validationIssues | WorkflowValidationIssue[] | Server validation results; rendered inline on the offending node/field | | form (designer only) | WorkflowFormDocument | The workflow's form, so conditions and mappings can pick its fields | | formBuilder (designer only) | WorkflowFormBuilderElement | The <workflow-form-builder> editing the same form, so focusValidationIssue can hand field issues to it |

Hosts may re-assign any of these as often as they like (React effects, Angular change detection). A value whose content equals the previous one is accepted without a re-render, and document is compared with the document the element last emitted, so handing back the document-change detail is a no-op. When a real change does re-render the element while the user is typing, the focused input keeps its focus, caret and not yet committed text.

Capabilities

Every boolean switch except publicFormEnabled counts as available unless the host sets it to false.

| Capability | Meaning | |---|---| | maxSteps, maxFormFields | Edition limits; the editors refuse to add beyond them | | advancedApprovalsEnabled, externalActionsEnabled, eventWaitEnabled, slackEnabled, teamsEnabled | Hide the steps and inputs that need the feature when false | | attachmentsEnabled | false hides the file attachment field and the attachment inputs | | publicFormEnabled | Opt-in. Files can only be collected on a public form, so the form builder offers the file attachment field only when this is true (and attachmentsEnabled is not false). Leaving it out means "not a public form". A file attachment field already on such a form stays, with an inline warning on its card. |

Assigning a new capabilities object to the live element re-renders the palettes.

Lookups and the assistant

The element never lets a host callback fail loudly: a rejected or throwing lookup yields an empty list, and an identical lookup (same provider, filter and context) that is still in flight is shared rather than sent again, so re-renders and quickly opened dropdowns do not flood the host. The assistant buttons (suggestCondition, summarizeWorkflow) are disabled while their request runs. A result with succeeded: false shows its failureReason inline as a soft warning (hosts should resolve with that shape for "assistant not available" or rate limits rather than reject); a rejected request shows a generic inline warning.

Theming and sizing

The canvas is SVG drawn from JavaScript, so node, port, label, execution and heat-map colours are derived from the resolved theme tokens (--wf-surface, --wf-text, --wf-primary, --wf-success, --wf-warning, --wf-danger, ...; by default the Bootstrap/Metronic --bs-* variables). Status colours are tinted over the surface colour, so a dark theme gets dark nodes. Changing theme or the document's data-bs-theme/data-theme attribute redraws the canvas.

The editor needs at least --wf-designer-min-height (default 560px); read-only views (instance timeline, template preview, heat map) need only --wf-designer-readonly-min-height (default 320px), so they fit a shorter host box. The minimap stays inside the canvas and is hidden when the canvas is too small to hold it.

Events

| Event | Detail | Meaning | |---|---|---| | document-change | { document, isDirty } | The user edited the document | | selection-change | { nodeId? , fieldId? } | Selection moved | | command | { command: 'save' \| 'validate' \| 'simulate' \| 'publish' } | The user asked the host to run a host-owned action |

| issue-focus | WorkflowIssueFocusDetail = { tab: 'flow' \| 'form' \| 'trigger', issue, nodeId?, edgeId?, branchId?, fieldId?, inputName? } | focusValidationIssue resolved an issue; show this host tab |

The host owns save/validate/simulate/publish. The component only asks.

Methods

| Method | Element | Purpose | |---|---|---| | focusValidationIssue(issue: WorkflowValidationIssue): boolean | both | Shows what a validation issue is about (see below) |

focusValidationIssue takes one of the objects the host passes through validationIssues (code, nodeId, edgeId, fieldId, branchId) and returns true when something was focused:

  • On <workflow-designer>, a step, transition or branch issue selects it on the canvas, opens the inspector tab holding the setting the issue's code names (an SlaDurationInvalid issue opens Service level, an ApprovalNodeTargetMissing issue Assignment, and so on) and pans the canvas until the step is visible. A field issue is handed to the element in formBuilder when the host set one; a start-trigger issue (ResponsibleUser..., StartTrigger..., public form slug and embed origin codes) is left to the host's trigger tab. In every case the element dispatches issue-focus whose tab says which of the host's tabs (flow, form, trigger) holds the issue — the element has no tabs of its own, so the host switches.
  • On <workflow-form-builder>, a field issue selects the field, scrolls its row into view and dispatches issue-focus with tab: 'form'.
  • Ids neither document knows return false and dispatch nothing, so a stale issue list is harmless.
  • Calling it before the element has rendered (not yet connected, or the document not yet set) is fine: the focus is applied by the first render. Ids are still checked against the documents the element holds at call time, so set document (and form) first.

The inline issue list in the designer's inspector uses the same method: every issue is a button (keyboard reachable) that opens the tab holding the setting it is about.

A typical host wiring:

designer.formBuilder = formBuilder;
designer.addEventListener('issue-focus', (event) => showTab(event.detail.tab));

issueRow.addEventListener('click', () => designer.focusValidationIssue(issue));

Canonical schema

src/schema/workflow-schema.ts mirrors the product-owned C# contract (WorkflowGraphDocument, WorkflowFormDocument and friends) — not any graph library's internal model. Swapping the rendering library must never change the persisted JSON.

Example

<workflow-designer id="designer"></workflow-designer>
<script type="module">
    import 'aspnetzero-workflow-designer';

    const designer = document.getElementById('designer');

    designer.localization = { WorkflowNodeType_Approval: 'Onay' };
    designer.permissions = { canEdit: true };
    designer.capabilities = { maxSteps: 40 };
    designer.document = serverGraphDocument;

    designer.addEventListener('document-change', (event) => {
        draft.graph = event.detail.document;
    });
</script>

Development

npm install
npm run dev        # demo page at demo/index.html
npm run typecheck
npm test           # vitest suite under test/
npm run build      # ESM + UMD + rolled-up .d.ts into dist/

Rendering uses AntV X6 — a vanilla-JS graph library, chosen precisely because it carries no framework dependency and therefore works identically inside all three host UIs.

How the hosts get the designer

ASP.NET Zero lives in its own repository and never reads this one. All three of its UIs install the published aspnetzero-workflow-designer package from npm, so they run the same build:

| Host | How it gets the designer | |---|---| | Angular (angular/) | aspnetzero-workflow-designer dependency, imports the ESM build | | React (react/) | aspnetzero-workflow-designer dependency, imports the ESM build | | ASP.NET Core MVC (Web.Mvc) | aspnetzero-workflow-designer dependency; bundles.json turns dist/workflow-designer.umd.cjs into _Bundles/workflow-designer.min.js |

The contract with the server

npm run build also writes dist/workflow-contract.json: the step kinds, input names, default keys, vocabularies, schema versions and localization keys this version uses, taken from the same constants the bundle is built from (see src/contract/workflow-contract.ts). ASP.NET Zero keeps a copy in its test project. WorkflowDesignerContract_Tests and the other contract tests there compare the server with that copy, and fail when the copy is not the version a host locks.

Releasing a change

  1. Change the package, then run npm test and npm run build.
  2. Raise version in package.json (a new step kind or input is a minor version, a fix a patch).
  3. Run npm publish. prepublishOnly runs the tests and the build again, so a broken package is not published.
  4. In the ASP.NET Zero repository, in angular/, react/ and aspnet-core/src/MyCompanyName.AbpZeroTemplate.Web.Mvc/, run pnpm add aspnetzero-workflow-designer@~<version>.
  5. At the root of that repository, run npm run refresh-workflow-designer-contract, then commit the result and the lockfiles with the server change that needed the new version.

Trying a change in a host before publishing

With the two repositories checked out side by side, point a host at this folder for the time being:

cd angular            # or react
pnpm link ../../workflow-designer

cd aspnet-core/src/MyCompanyName.AbpZeroTemplate.Web.Mvc
pnpm link ../../../../workflow-designer

The host now reads this folder's dist/, so run npm run build here after each change (MVC also needs npm run create-bundles). pnpm link adds a link: override to the host's pnpm-workspace.yaml and changes its pnpm-lock.yaml; do not commit those. To go back to the published package, revert both files and run pnpm install.

Status

What the package implements today:

Workflow designer

  • Node palette (click or drag onto the canvas), canvas with pan/zoom/grid, zoom to fit, minimap, snaplines, auto layout and an outline panel.
  • Node add/move/select/delete, multi-select, edge drawing with automatic edge-kind assignment per source node type, parallel fan-out nodes paired with their join node.
  • Undo/redo and copy/paste (toolbar and keyboard shortcuts).
  • A descriptor-driven properties inspector, grouped into tabs by input category (for example Assignment, Behaviour, Service level, Delivery), with editors resolved by uiHint through the input editor registry.
  • Condition branches: add, remove and reorder branches, and a condition builder over form fields, variables and step outputs; optional assistant suggestions through lookups.suggestCondition.
  • Assignee pickers (requester's manager, user, role, organization unit, fallback role) wired to the host lookups (lookups.optionsProvider, or the older users/roles/organizationUnits callbacks).
  • SLA editing (the "Service level" tab; "Escalate after" and "Escalate to" appear once escalation is switched on), notification recipients, chat channels (Slack / Teams) with adaptive card editing, secret pickers, action parameter and event payload mapping tables.
  • Workflow variables panel, inline validation issues, and an optional assistant workflow summary (lookups.summarizeWorkflow).

Form builder

  • Field palette, field add/reorder/remove, sections (add, rename, remove; removing a section moves its fields to the section above it), repeater fields with row fields and calculated fields.
  • The file attachment field only on public forms (capabilities.publicFormEnabled: true).
  • A descriptor-driven properties panel for label/key/required/validation, and a row-per-option editor for single and multi select options.
  • A new field's key is derived from its label (Total amount becomes totalAmount; accented and Turkish letters are folded to ASCII, a key starts with a letter and is made unique with 2, 3, ...) and keeps following the label until the user edits the key by hand. Keys that arrived with the document are never changed.
  • A palette note that signed-in requesters attach files from the request page, since the file attachment field exists only for public forms.