@integritymarketing/ic-ui-core
v0.7.0
Published
The Ic* component library — every component shared by all Integrity product environments. `.` is the reviewed API; `./experimental` is Backlog-parity work awaiting design review and carries no stability guarantee.
Readme
@integritymarketing/ic-ui-core
The Ic* component library — everything shared by every Integrity product
environment. 129 public components (several files export more than one),
plus 32 hooks, constants and helpers.
pnpm add @integritymarketing/ic-ui-core @mui/material @emotion/react @emotion/styled// Deep import — one component, and you don't pull AG Grid to render a Button.
import { IcButton } from '@integritymarketing/ic-ui-core/IcButton';
// Or the barrel, for the reviewed public API.
import { IcButton, IcAlert } from '@integritymarketing/ic-ui-core';Named exports only. There are no default exports.
Most applications should install their environment package
(@integritymarketing/ic-ui-connect / ui-pro) instead — those re-export this in
full and are where an approved product difference would live.
Two entry points
| Import | Contents | Guarantee |
| --------------------------------------------- | ----------------------- | ---------------------------------------------------------- |
| @integritymarketing/ic-ui-core | 108 reviewed components | Stable. Semver applies. |
| @integritymarketing/ic-ui-core/experimental | 21 more, unreviewed | None. Awaiting design review; may change or disappear. |
experimental is Backlog-parity work — components built to match the legacy
Storybook but not yet signed off by design. The Figma Make kit marks them
unavailable and tells Make not to use them. A component leaves experimental by
passing design review, not by being useful.
Icons must be registered before they render
This package contains no glyph data. IcSvgIcon draws from a registry the
consumer fills in:
import { registerIcons } from '@integritymarketing/ic-ui-core';
import {
fontAwesomePaths,
fontAwesomeViewBoxes,
} from '@integritymarketing/ic-icons';
registerIcons(fontAwesomePaths, fontAwesomeViewBoxes); // once, at startupSkip it and every icon renders a correctly sized empty box — a gap in the layout, never a crash — and the registry warns once per name in development so the gap is traceable.
Two reasons it works this way, and the first is not negotiable:
- Licensing.
@integritymarketing/ic-iconsis Font Awesome Pro artwork. Ific-ui-coreimported it, the tarball would carry licensed path data and could not be published anywhere a sandbox reads anonymously — public npm, a Figma Make preview. Now the same tarball is safe on any registry andic-iconsstays private. - Size.
fontAwesomePathsis one object literal, so nothing tree-shakes: rendering a single icon used to pull all 1010 glyphs, ~793 KB. Consumers now ship what they register.
IcSvgIconName still types every valid name, so a typo is still a compile
error. It is generated into src/iconNames.ts from the registry — names are
not licensed, path data is — and pnpm check:icon-names fails the build if
the two drift.
For a project that consumes the public packages and cannot install ic-icons,
pnpm icons:subset emits a small registration module for just the glyphs a
screen uses. See packages/icons/README.md.
Registration is explicit rather than a side-effect import on purpose: every
package here sets sideEffects: false, so a bundler would be entitled to drop
an auto-registering module and leave you with blank icons and nothing to debug.
Peer dependencies
React, react-dom, MUI and Emotion are peers, so the design system uses the copy your application already has. One React, one theme context.
Three groups are real dependencies rather than peers, because they are implementation details of one component each and not things a consumer should have to know about:
| Dependency | Exists for |
| ------------------------------------ | ------------------------------------- |
| ag-grid-community, ag-grid-react | IcDataGrid |
| framer-motion | IcAskIntegrityAnimation and friends |
| @tiptap/* (six packages) | IcTextEditor |
IcTextEditor is worth calling out: it is ProseMirror-backed via tiptap, so
pnpm add @integritymarketing/ic-ui-core now installs a rich-text editing engine
whether or not you render one.
It should not reach your bundle unless you use it — the package is ESM-only,
declares sideEffects: false, and tsup emits one entry per component — so a
bundler can drop it. The deep import (ui-core/IcTextEditor) is the form that
does not depend on that working.
Rules that apply to every file here
Enforced by pnpm lint, not by review:
- No colour literals, in any notation. Not hex, and not
rgb(),rgba(),hsl()or a named CSS colour either. Usevar(--token)or an MUI palette path. Grey borders arevar(--divider). - No
style={}on a component. Usesx,styled()or a theme override. A raw CSS object bypasses the palette paths, the spacing scale and the breakpoints. Lowercase DOM and SVG elements are exempt — they have nosx. - No inline
<svg>or<i>. UseIcSvgIconwith a name from the registry. - No raw
<div>inside a component — compose with MUIBox/Stack. Layout wrappers may use a div. - No hand-rolled
<table>. Tables are AG Grid viaIcDataGrid. - Never Tailwind, never Lucide, never Radix or shadcn.
One more rule applies but is not enforced by lint: never !important. See
docs/Guidelines.md.
Three kinds of file are exempted from the SVG and colour rules, each for a reason
recorded in tooling/eslint-config/index.js: the brand artwork (IcLogo,
IcCircleLogo, IcConnectLogo and src/logo/), IcSsoButton (third-party
provider marks that must be reproduced exactly), and IcAskIntegrityAnimation
(a framer-motion path-morph illustration).
Trademarks
This package is MIT licensed, and that grant covers the source code only — not the marks in it.
Google and the Google logo are trademarks of Google LLC. Microsoft and the
Microsoft logo are trademarks of the Microsoft group of companies. They appear
in IcSsoButton solely to identify the corresponding sign-in provider, imply no
endorsement or affiliation, and are governed by each owner's brand guidelines —
validate against the current version before production use, or supply a
vendor-issued asset through the icon prop.
Integrity's own brand artwork remains Integrity's property and is likewise not
licensed by the MIT grant. See LICENSE.
Adding a component
All five artifacts, or it is not done:
src/Ic<Name>.tsx—forwardRef,export interface Ic<Name>Props extends …src/Ic<Name>.test.tsx— seepackages/ui-core/src/IcButton.test.tsxfor the patternapps/storybook/stories/<section>/<Name>.stories.tsx— every variant and stateapps/storybook/stories/<section>/<Name>.mdx— Purpose, Anatomy, Accessibility, Props, Do / Don't- Export it from
index.ts(reviewed) orexperimental.ts(not yet)
The Do / Don't section is load-bearing, not decoration: it is the source the
Figma Make kit is generated from. pnpm check:make-kit fails when a public
component lacks one, because Make would then be handed a component with no
rules.
Also add a written spec in docs/components/ covering why it is built this
way — the decisions and the rejected alternatives.
Testing
pnpm testVitest + Testing Library in jsdom. expect(...).toHaveNoA11yViolations() runs
axe over document.body — deliberately the body, not the render container,
because MUI portals Modal, Drawer, Menu, Tooltip and Snackbar outside it and
scanning the container reports a clean result for a drawer full of failures.
Contrast is not asserted in these tests. axe's color-contrast rule cannot
evaluate under jsdom — it needs canvas.getContext for ligature detection — and
when it bails it reports zero violations and zero passes, which reads as
green. Contrast is enforced by Storybook's addon-a11y in a real browser, on
every story. See vitest.setup.ts.
