@super-ic/sbr-icon-contracts
v0.1.3
Published
SBR tenant semantic icon contract: 57 tenant icon IDs composed with the SuperIC core set behind a decorative/label accessibility discriminator that is enforced at render.
Readme
@super-ic/sbr-icon-contracts
The SBR tenant semantic icon contract. It adds 57 tenant-specific semantic icon IDs on top of the
36 core IDs in @super-ic/icon-contracts, giving a composite surface of 93 unique semantic IDs, and
it exposes two React components that will not render an icon unless the caller has made an explicit
accessibility decision.
Semantic IDs are the API. Vendor glyph component names are an implementation detail that this package owns and may re-map; consumers must never import a glyph component directly.
Install
npm i @super-ic/sbr-icon-contractsPeers you provide:
| Peer | Range | Why |
| --- | --- | --- |
| react | >=19.0.0 | The exported components are React components. |
There is no react-dom peer: nothing in dist/ touches the DOM renderer, and no @super-ic/foundation
peer either, because this package emits no CSS and reads no design token. Icons inherit currentColor
and size from the props below, so a consumer that never installs the token layer still renders correct
icons. If you are also consuming @super-ic/web-patterns or @super-ic/app-patterns, the foundation
token import is required by those packages, not by this one.
nucleo-ui-outline-18 is an optional peer. This package installs without
a licence. Rendering requires importing @super-ic/sbr-icon-contracts/nucleo
once at the application root, which requires the licensed vendor package. See
"Vendor licence gate" below.
Usage
import "@super-ic/sbr-icon-contracts/nucleo";
import "@super-ic/icon-contracts/nucleo";
import { SbrIcon, SupericIcon } from "@super-ic/sbr-icon-contracts";
// Decorative: the icon repeats adjacent text, so it is hidden from assistive tech.
<SbrIcon name="navigation.home" decorative size={20} />
// Meaningful: the icon is the only carrier of the meaning, so it needs a label.
<SbrIcon name="trust.residency-verified" decorative={false} label="Residency verified" size={18} />
// SupericIcon accepts core IDs and SBR IDs from the same union.
<SupericIcon name="action.search" decorative={false} label="Search" />The decorative discriminator
decorative is a required discriminated-union tag, not an optional hint. There is no default, and the
component throws at render rather than emitting an inaccessible icon. Two shapes are legal and
nothing else is:
| Shape | Meaning | What renders |
| --- | --- | --- |
| { decorative: true }, label absent | The icon adds no information a screen reader needs | aria-hidden="true", no aria-label, no role |
| { decorative: false, label: "…" } | The icon carries meaning on its own | aria-label="<label>" plus role="img" |
Three render-time throws enforce it:
| Call | Error message |
| --- | --- |
| decorative missing, or any value other than true/false ("yes", 0, null) | icon decorative discriminator must be true or false |
| decorative: true with a label | decorative icons cannot carry a label |
| decorative: false with a missing, non-string, or whitespace-only label | meaningful icon label must be a non-empty string |
TypeScript rejects all three at compile time; the runtime checks exist because the boundary between a
typed design system and an untyped caller (JS consumers, JSON-driven renderers, as any) is exactly
where accessibility regressions enter. Treat a throw as a bug in the call site, never as something to
catch and swallow.
An unknown semantic ID throws too, from the lookup rather than the render: getSbrNucleoIcon and
getSupericNucleoIcon raise UnknownIconNameError ("unknown semantic icon name") for any ID outside
the contract, and SbrIcon / SupericIcon inherit that behaviour because they resolve the glyph before
rendering.
Both components also emit data-semantic-icon="<id>" and data-icon-size="<size>", which is what
contract tests and visual gates assert against. Do not strip them.
Props
Both components take the shared shape below plus the decorative discriminator above. aria-hidden,
aria-label, role and name are removed from the passthrough SVG props, because the discriminator
owns them.
| Prop | Type | Default | Notes |
| --- | --- | --- | --- |
| name | SbrIconName (SbrIcon) or SupericIconName (SupericIcon) | required | Semantic ID from the contract |
| size | IconSize (12 \| 14 \| 16 \| 18 \| 20 \| 24 \| 32) | 16 | Also written to data-icon-size |
| strokeWidth | number | 1.5 | Only override for a deliberate optical fix |
| ...rest | SVGProps<SVGSVGElement> | none | className, style, data-* and so on |
Exports
| Export | Kind | What it is |
| --- | --- | --- |
| SbrIcon, SupericIcon | components | The two renderers described above |
| SBR_ICON_NAMES | readonly string[] | The 57 tenant semantic IDs, frozen order |
| SBR_ICON_VENDOR_EXPORTS | Record<SbrIconName, string> | ID to glyph export name, for contract tests |
| SBR_NUCLEO_ICON_EXPORTS | alias | Same map as SBR_ICON_VENDOR_EXPORTS |
| bindSbrGlyphs | function | Synchronous glyph injection; /nucleo calls this |
| getSbrNucleoIcon, getSupericNucleoIcon | functions | Throwing lookups |
| CORE_ICON_NAMES, ICON_SIZES, UnknownIconNameError, IconGlyphsNotBoundError, IconGlyphsIncompleteError | re-exports | Re-exported from @super-ic/icon-contracts |
| SbrIconName, SupericIconName, CoreIconName, IconSize | types | Semantic ID and size unions |
| SbrIconProps, SupericIconProps, IconProps | types | The discriminated prop unions |
The tenant ID namespaces are communication.*, marketplace.*, navigation.*, operations.* and
trust.*. SBR_ICON_NAMES is the authoritative list; enumerate it rather than hardcoding IDs.
Vendor licence gate
The package installs without a licence. Rendering requires importing
@super-ic/sbr-icon-contracts/nucleo once, which requires
[email protected] and the environment variable NUCLEO_LICENSE_KEY
for the vendor's own install check. This README names the variable only.
Without that import, SbrIcon throws IconGlyphsNotBoundError and never
degrades to a placeholder glyph. The /nucleo adapter binds the SBR set
only. Import @super-ic/icon-contracts/nucleo as well before rendering
SupericIcon with a core name.
Nothing in dist/ contains vendor glyph path data; only the mapping from
semantic IDs to vendor export names. The vendor package supplies the glyphs.
Package shape
type: "module", ESM only. Entries: . resolving to dist/index.js and
./nucleo resolving to dist/nucleo.js. sideEffects lists ./dist/nucleo.js
so bundlers keep the binding call. The published tarball is dist/ plus the
manifest and this README: no source, no tests, no build state.
