{"_id":"@alga-psa/ui-kit","_rev":"3-ea70d44080f9314378c04eca9d50f0a4","name":"@alga-psa/ui-kit","dist-tags":{"latest":"0.2.0"},"versions":{"0.1.0":{"name":"@alga-psa/ui-kit","version":"0.1.0","_id":"@alga-psa/ui-kit@0.1.0","maintainers":[{"name":"robert-at-nineminds","email":"robert@nineminds.com"}],"dist":{"shasum":"45f3d21d87cdb2468daf187097f6f6bac2e7afb2","tarball":"https://registry.npmjs.org/@alga-psa/ui-kit/-/ui-kit-0.1.0.tgz","fileCount":23,"integrity":"sha512-VtsX7V36C77b5wbeFGDYRb5KHo9pMnhQ8mRCyTvw93b2PW+J0iFjXYpk2rTQJ7yaMtM7RQGCHizuoYGp/koG+g==","signatures":[{"sig":"MEUCIHhxqpvwxAHs2zrRailxR6J8m7sWKBEEy4HGeLBx2B+VAiEAxQKZCsbZ2hypqD5BQNlBO6x7Gv3VNZ1yvredCX3X/BU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":15484},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./theme.css":"./src/theme/tokens.css"},"gitHead":"37249ecb940c3c9465b98daa4d7c16d9ac4fe376","private":false,"scripts":{"build":"tsc -p tsconfig.json","prepublishOnly":"npm run build"},"_npmUser":{"name":"robert-at-nineminds","email":"robert@nineminds.com"},"_npmVersion":"10.9.3","description":"Primitives and tokens for Alga extensions. Zero-dependency React components with CSS variables.","directories":{},"_nodeVersion":"22.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.4.0","@types/react":"^18","@types/react-dom":"^18"},"peerDependencies":{"react":"^18","react-dom":"^18"},"_npmOperationalInternal":{"tmp":"tmp/ui-kit_0.1.0_1756779406045_0.9112358917643832","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@alga-psa/ui-kit","version":"0.2.0","private":false,"type":"module","main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"import":"./dist/index.js","types":"./dist/index.d.ts"},"./theme.css":"./src/theme/tokens.css"},"scripts":{"build":"tsc -p tsconfig.json","prepublishOnly":"npm run build"},"dependencies":{"@radix-ui/react-select":"^2.1.2","@tanstack/react-table":"^8.21.3"},"peerDependencies":{"react":"^18 || ^19","react-dom":"^18 || ^19"},"devDependencies":{"@types/react":"^19","@types/react-dom":"^19","typescript":"^5.4.0"},"publishConfig":{"access":"public"},"_id":"@alga-psa/ui-kit@0.2.0","gitHead":"a5d4ddc61ecb0c349e6b0fd8ef2e4bcf40b8dacd","description":"Zero-dependency React component library for Alga extensions. All components use CSS custom properties for theming and work seamlessly inside extension iframes.","_nodeVersion":"23.10.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-gfE6VB/CGHIft27edYh6i9Szsu6R9jdu+pBRscO5xBJDiNl7jQnJn47Nde2DuDTqcqfWMP+sCFepPATYJk44ng==","shasum":"d6783f2b7796381ab1bbc3f6b13bba76f3f771ba","tarball":"https://registry.npmjs.org/@alga-psa/ui-kit/-/ui-kit-0.2.0.tgz","fileCount":63,"unpackedSize":147629,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCRwPbwXjs9bw2+qs+gFv8Z2CzBGZ88x/83NqE7kbXc0AIhAK6cpXI7UMtGJnRD3oBGEoLcrPFHBR557+ET2+mW8oCV"}]},"_npmUser":{"name":"talya_b","email":"natallia@nineminds.com"},"directories":{},"maintainers":[{"name":"talya_b","email":"natallia@nineminds.com"},{"name":"robert-at-nineminds","email":"robert@nineminds.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ui-kit_0.2.0_1771948877483_0.42531815151468133"},"_hasShrinkwrap":false}},"time":{"created":"2025-09-02T02:16:45.613Z","modified":"2026-02-24T16:01:17.819Z","0.1.0":"2025-09-02T02:16:46.234Z","0.2.0":"2026-02-24T16:01:17.642Z"},"description":"Zero-dependency React component library for Alga extensions. All components use CSS custom properties for theming and work seamlessly inside extension iframes.","maintainers":[{"name":"talya_b","email":"natallia@nineminds.com"},{"name":"robert-at-nineminds","email":"robert@nineminds.com"}],"readme":"# @alga-psa/ui-kit\n\nZero-dependency React component library for Alga extensions. All components use CSS custom properties for theming and work seamlessly inside extension iframes.\n\n> See the **showcase extension** (`ee/extensions/showcase`) for interactive demos of every component.\n\n## Install\n\nImport the theme stylesheet once at the root of your app:\n\n```ts\nimport '@alga-psa/ui-kit/theme.css';\n```\n\n---\n\n## Theme Tokens\n\nTokens are exposed as CSS variables. When running inside an extension iframe the host automatically injects them into `:root`.\n\n| Variable | Light | Dark | Purpose |\n|----------|-------|------|---------|\n| `--alga-bg` | `#ffffff` | `#0b0f14` | Background |\n| `--alga-fg` | `#111111` | `#e5e7eb` | Foreground / text |\n| `--alga-muted` | `#f5f5f7` | `#0f1720` | Muted background |\n| `--alga-muted-fg` | `#4b5563` | `#9ca3af` | Muted text |\n| `--alga-primary` | `#9855ee` | `#8a4dea` | Primary (purple) |\n| `--alga-primary-foreground` | `#ffffff` | `#ffffff` | Text on primary |\n| `--alga-secondary` | `#53d7fa` | `#40cff9` | Secondary (blue) |\n| `--alga-secondary-foreground` | `#111111` | `#0b0f14` | Text on secondary |\n| `--alga-border` | `#e5e7eb` | `#1f2937` | Borders |\n| `--alga-radius` | `8px` | `8px` | Border radius |\n| `--alga-danger` | `#dc2626` | `#ef4444` | Danger / error |\n| `--alga-warning` | `#d97706` | `#f59e0b` | Warning |\n| `--alga-success` | `#16a34a` | `#22c55e` | Success |\n\nYou can also access tokens programmatically:\n\n```ts\nimport { tokens } from '@alga-psa/ui-kit';\n\ntokens.primary   // 'var(--alga-primary)'\ntokens.bg        // 'var(--alga-bg)'\n```\n\n---\n\n## Components\n\n### Core\n\n#### `Button`\n\nThemed button with multiple variants and sizes.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `variant` | `'primary' \\| 'secondary' \\| 'destructive' \\| 'outline' \\| 'ghost' \\| 'link' \\| 'soft' \\| 'dashed'` | `'primary'` | Visual style |\n| `size` | `'xs' \\| 'sm' \\| 'md' \\| 'lg' \\| 'icon'` | `'md'` | Controls padding and font size |\n\n```tsx\n<Button variant=\"secondary\" size=\"sm\">Save</Button>\n```\n\n#### `Text`\n\nTypography component with size, tone, and weight presets.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `as` | `'span' \\| 'p' \\| 'label' \\| 'strong'` | `'span'` | HTML element to render |\n| `size` | `'xs' \\| 'sm' \\| 'md' \\| 'lg'` | `'md'` | Font size preset |\n| `tone` | `'default' \\| 'muted' \\| 'danger' \\| 'warning' \\| 'success'` | `'default'` | Text colour |\n| `weight` | `400 \\| 500 \\| 600 \\| 700` | `400` | Font weight |\n\n```tsx\n<Text as=\"p\" size=\"lg\" tone=\"muted\" weight={600}>Hello</Text>\n```\n\n#### `Card`\n\nBordered container with background, shadow, and rounded corners. Extends standard `<div>` attributes.\n\n```tsx\n<Card style={{ padding: 24 }}>Content here</Card>\n```\n\n#### `Badge`\n\nSmall pill-shaped label for status indicators.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `tone` | `'default' \\| 'info' \\| 'success' \\| 'warning' \\| 'danger'` | `'default'` | Colour scheme |\n\n```tsx\n<Badge tone=\"success\">Active</Badge>\n```\n\n#### `Alert`, `AlertTitle`, `AlertDescription`\n\nContextual alert banner with optional icon.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `tone` | `'info' \\| 'success' \\| 'warning' \\| 'danger'` | `'info'` | Visual tone |\n| `showIcon` | `boolean` | `true` | Show tone-specific icon |\n\n```tsx\n<Alert tone=\"warning\">\n  <AlertTitle>Heads up</AlertTitle>\n  <AlertDescription>This action cannot be undone.</AlertDescription>\n</Alert>\n```\n\n#### `Separator`\n\nThin divider line for separating content.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `orientation` | `'horizontal' \\| 'vertical'` | `'horizontal'` | Direction of the line |\n| `style` | `CSSProperties` | — | Additional inline styles |\n\n---\n\n### Form\n\n#### `Input`\n\nText input with error state support.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `error` | `boolean` | — | Show error styling |\n| `errorMessage` | `string` | — | Error message displayed below input |\n\n```tsx\n<Input placeholder=\"Email\" error={!!err} errorMessage={err} />\n```\n\n#### `TextArea`\n\nMulti-line text input. Extends `<textarea>` attributes.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `error` | `boolean` | — | Show error border |\n| `errorMessage` | `string` | — | Error text below the field |\n| `resize` | `'none' \\| 'vertical' \\| 'horizontal' \\| 'both'` | `'vertical'` | Resize behaviour |\n\n#### `CustomSelect`\n\nDropdown with search filtering.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `options` | `SelectOption[]` | — | Available options |\n| `value` | `string` | — | Selected value |\n| `onChange` | `(value: string) => void` | — | Change callback |\n| `placeholder` | `string` | — | Placeholder text |\n| `searchable` | `boolean` | `true` | Enable search filtering |\n| `disabled` | `boolean` | `false` | Disable the select |\n\n#### `SearchInput`\n\nInput with built-in search icon and optional debounce.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `onSearch` | `(value: string) => void` | — | Debounced search callback |\n| `debounceMs` | `number` | `300` | Debounce delay in ms |\n| `size` | `'sm' \\| 'md'` | `'md'` | Input size |\n\n#### `Checkbox`\n\nThemed checkbox with label.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `label` | `string` | — | Label text |\n| `size` | `'sm' \\| 'md' \\| 'lg'` | `'md'` | Size preset |\n\n#### `RadioGroup`\n\nGroup of mutually exclusive radio buttons.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `options` | `RadioOption[]` | — | Available options |\n| `value` | `string` | — | Selected value |\n| `onChange` | `(value: string) => void` | — | Change callback |\n| `name` | `string` | auto | HTML name attribute |\n| `disabled` | `boolean` | `false` | Disable all options |\n| `orientation` | `'horizontal' \\| 'vertical'` | `'vertical'` | Layout direction |\n| `size` | `'sm' \\| 'md' \\| 'lg'` | `'md'` | Size preset |\n\n`RadioOption`: `{ value: string; label: string; disabled?: boolean }`\n\n```tsx\n<RadioGroup\n  options={[{ value: 'a', label: 'Alpha' }, { value: 'b', label: 'Beta' }]}\n  value={selected}\n  onChange={setSelected}\n/>\n```\n\n#### `Switch`\n\nToggle switch for boolean values.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `checked` | `boolean` | — | Controlled state |\n| `onChange` | `(checked: boolean) => void` | — | Change callback |\n| `size` | `'sm' \\| 'md' \\| 'lg'` | `'md'` | Size preset |\n| `disabled` | `boolean` | `false` | Disable the switch |\n| `label` | `string` | — | Label text |\n\n#### `Label`\n\nStyled `<label>` element.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `required` | `boolean` | — | Show required indicator |\n| `disabled` | `boolean` | — | Apply muted styling |\n\n---\n\n### Data Display\n\n#### `DataTable`\n\nPaginated table with sorting, search, and custom cell rendering.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `data` | `Row[]` | — | Array of row objects |\n| `columns` | `Column<Row>[]` | — | Column definitions |\n| `initialSortKey` | `string` | — | Initial sort column |\n| `searchable` | `boolean` | `false` | Show search input |\n| `pageSize` | `number` | `10` | Rows per page |\n\n`Column<Row>`: `{ key: string; header: string; width?: number; sortable?: boolean; render?: (row) => ReactNode }`\n\n```tsx\n<DataTable\n  data={items}\n  columns={[\n    { key: 'name', header: 'Name', sortable: true },\n    { key: 'status', header: 'Status', render: (row) => <Badge>{row.status}</Badge> },\n  ]}\n/>\n```\n\n---\n\n### Navigation\n\n#### `Tabs`\n\nHorizontal tab bar.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `tabs` | `TabItem[]` | — | Tab definitions |\n| `activeTab` | `string` | — | Currently active tab id |\n| `onChange` | `(id: string) => void` | — | Tab change callback |\n\n`TabItem`: `{ id: string; label: string; icon?: ComponentType; disabled?: boolean }`\n\n```tsx\n<Tabs\n  tabs={[{ id: 'one', label: 'Tab 1' }, { id: 'two', label: 'Tab 2' }]}\n  activeTab={tab}\n  onChange={setTab}\n/>\n```\n\n#### `ViewSwitcher`\n\nSegmented button group for switching between views.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `currentView` | `T` | — | Active view value |\n| `onChange` | `(view: T) => void` | — | View change callback |\n| `options` | `ViewSwitcherOption<T>[]` | — | Available views |\n\n`ViewSwitcherOption<T>`: `{ value: T; label: string; icon?: ComponentType }`\n\n```tsx\n<ViewSwitcher\n  currentView={view}\n  onChange={setView}\n  options={[{ value: 'list', label: 'List' }, { value: 'grid', label: 'Grid' }]}\n/>\n```\n\n#### `Breadcrumbs`\n\nHorizontal breadcrumb navigation trail.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `items` | `BreadcrumbItem[]` | — | Breadcrumb segments |\n| `separator` | `ReactNode` | `'/'` | Custom separator |\n\n`BreadcrumbItem`: `{ label: ReactNode; href?: string; onClick?: () => void }`\n\n```tsx\n<Breadcrumbs items={[\n  { label: 'Home', href: '/' },\n  { label: 'Settings', onClick: goSettings },\n  { label: 'Profile' },\n]} />\n```\n\n#### `DropdownMenu`\n\nPopover menu triggered by a button.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `trigger` | `ReactNode` | — | Trigger element |\n| `items` | `DropdownMenuItem[]` | — | Menu items |\n\n`DropdownMenuItem`: `{ label: string; onClick?: () => void; icon?: ComponentType; danger?: boolean; disabled?: boolean; separator?: boolean }`\n\n---\n\n### Layout\n\n#### `Stack`\n\nFlexbox layout helper for stacking children with consistent spacing.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `direction` | `'row' \\| 'column'` | `'column'` | Flex direction |\n| `gap` | `number \\| string` | `8` | Gap between children (numbers = px) |\n| `align` | `'stretch' \\| 'flex-start' \\| 'center' \\| 'flex-end' \\| 'baseline'` | — | Cross-axis alignment |\n| `justify` | `'flex-start' \\| 'center' \\| 'flex-end' \\| 'space-between' \\| 'space-around' \\| 'space-evenly'` | — | Main-axis alignment |\n\n```tsx\n<Stack direction=\"row\" gap={12} align=\"center\">\n  <Text>Left</Text>\n  <Button>Right</Button>\n</Stack>\n```\n\n#### `Drawer`\n\nSlide-in panel from the right edge with focus trapping and overlay.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `open` | `boolean` | — | Whether the drawer is open |\n| `onClose` | `() => void` | — | Close callback |\n| `width` | `string` | `'fit-content'` | CSS width |\n| `maxWidth` | `string` | `'60vw'` | Max width |\n| `title` | `ReactNode` | — | Drawer title |\n| `overlay` | `boolean` | `true` | Show backdrop overlay |\n| `closeOnOverlayClick` | `boolean` | `true` | Close on overlay click |\n| `closeOnEscape` | `boolean` | `true` | Close on Escape key |\n\n#### `Dialog` / `ConfirmDialog`\n\nModal dialogs.\n\n**Dialog** — base modal with title and children.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `isOpen` | `boolean` | — | Open state |\n| `onClose` | `() => void` | — | Close callback |\n| `title` | `string` | — | Dialog title |\n\n**ConfirmDialog** — confirm / cancel modal.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `isOpen` | `boolean` | — | Open state |\n| `title` | `string` | — | Title |\n| `message` | `string` | — | Body text |\n| `variant` | `'default' \\| 'danger'` | `'default'` | Visual tone |\n| `onConfirm` | `() => void` | — | Confirm callback |\n| `onCancel` | `() => void` | — | Cancel callback |\n\n```tsx\n<ConfirmDialog\n  isOpen={open}\n  title=\"Delete Item\"\n  message=\"Are you sure?\"\n  variant=\"danger\"\n  onConfirm={handleDelete}\n  onCancel={() => setOpen(false)}\n/>\n```\n\n#### `Popover`\n\nPositioned content popover anchored to a trigger element.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `trigger` | `ReactNode` | — | Trigger element |\n| `open` | `boolean` | — | Controlled open state |\n| `onOpenChange` | `(open: boolean) => void` | — | Open state callback |\n| `placement` | `'top' \\| 'bottom' \\| 'left' \\| 'right'` | `'bottom'` | Popover placement |\n\n---\n\n### Feedback\n\n#### `Spinner` / `LoadingIndicator`\n\n**Spinner** — animated circular loading indicator.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `size` | `'button' \\| 'xs' \\| 'sm' \\| 'md' \\| 'lg'` | `'md'` | Diameter preset |\n| `variant` | `'default' \\| 'inverted'` | `'default'` | Use `'inverted'` on coloured backgrounds |\n\n**LoadingIndicator** — spinner with optional text.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `size` | same as Spinner | `'md'` | Spinner size |\n| `text` | `string` | — | Label next to spinner |\n| `layout` | `'inline' \\| 'stacked'` | `'inline'` | Text position |\n\n```tsx\n<Spinner size=\"sm\" />\n<LoadingIndicator text=\"Loading...\" layout=\"stacked\" />\n```\n\n#### `Tooltip`\n\nHover tooltip anchored to its children.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `content` | `ReactNode` | — | Tooltip content |\n| `placement` | `'top' \\| 'bottom' \\| 'left' \\| 'right'` | `'top'` | Position |\n| `delay` | `number` | `200` | Show delay in ms |\n\n```tsx\n<Tooltip content=\"More info\">\n  <Button variant=\"ghost\">?</Button>\n</Tooltip>\n```\n\n#### `Progress`\n\nHorizontal progress bar.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `value` | `number` | — | Current value (0–100) |\n| `max` | `number` | `100` | Maximum value |\n| `size` | `'sm' \\| 'md' \\| 'lg'` | `'md'` | Bar height |\n| `tone` | `'primary' \\| 'success' \\| 'warning' \\| 'danger'` | `'primary'` | Bar colour |\n\n```tsx\n<Progress value={75} tone=\"success\" />\n```\n\n#### `Skeleton` / `SkeletonText` / `SkeletonCircle` / `SkeletonRectangle`\n\nPlaceholder loading shapes.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `width` | `string \\| number` | `'100%'` | Width |\n| `height` | `string \\| number` | `'1em'` | Height |\n| `variant` | `'text' \\| 'circular' \\| 'rectangular'` | `'text'` | Shape |\n| `animation` | `'pulse' \\| 'wave' \\| 'none'` | `'pulse'` | Animation type |\n| `lines` | `number` | `3` | Number of lines (text variant) |\n\n```tsx\n<SkeletonText lines={3} />\n<SkeletonCircle width={40} height={40} />\n```\n\n---\n\n## Hooks\n\n### `useTheme()`\n\nReturns `{ setMode, getMode }` for reading and setting the current theme mode (`'light' | 'dark'`).\n\n```tsx\nimport { useTheme } from '@alga-psa/ui-kit';\n\nconst { setMode, getMode } = useTheme();\nsetMode('dark');\n```\n\n### `applyThemeVars(vars)`\n\nApplies a `Record<string, string>` of CSS custom property values to the document root.\n\n```tsx\nimport { applyThemeVars } from '@alga-psa/ui-kit';\n\napplyThemeVars({ 'alga-primary': '#ff6600' });\n```\n\n---\n\n## Extension Theme Bridge\n\nFor extensions running in iframes, use the built-in theme bridge to receive host theme variables:\n\n```tsx\nimport { applyThemeVars } from '@alga-psa/ui-kit';\n\nwindow.addEventListener('message', (ev) => {\n  const data = ev.data;\n  if (data?.alga === true && data?.version === '1' && data?.type === 'theme') {\n    applyThemeVars(data.payload || {});\n  }\n});\n\n// Signal readiness to the host\nwindow.parent.postMessage({ alga: true, version: '1', type: 'ready' }, '*');\n```\n","readmeFilename":"README.md"}