@semantic-components/mcp-server 0.71.0 → 0.72.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.mjs +4 -386
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -30173,8 +30173,8 @@ var EMPTY_COMPLETION_RESULT = {
|
|
|
30173
30173
|
|
|
30174
30174
|
// libs/mcp-server/src/data/manifest.json
|
|
30175
30175
|
var manifest_default = {
|
|
30176
|
-
version: "0.
|
|
30177
|
-
generatedAt: "2026-03-01T13:
|
|
30176
|
+
version: "0.71.0",
|
|
30177
|
+
generatedAt: "2026-03-01T13:38:54.487Z",
|
|
30178
30178
|
libraries: [
|
|
30179
30179
|
{
|
|
30180
30180
|
name: "@semantic-components/ui",
|
|
@@ -30221,11 +30221,6 @@ var manifest_default = {
|
|
|
30221
30221
|
"ScAvatarImage"
|
|
30222
30222
|
]
|
|
30223
30223
|
},
|
|
30224
|
-
{
|
|
30225
|
-
name: "backdrop",
|
|
30226
|
-
readme: null,
|
|
30227
|
-
exports: []
|
|
30228
|
-
},
|
|
30229
30224
|
{
|
|
30230
30225
|
name: "badge",
|
|
30231
30226
|
readme: '# Badge\n\nDisplays a badge or a component that looks like a badge.\n\n## Components\n\n- `ScBadge` - A small status indicator with variant support\n\n## Usage\n\n```html\n<div scBadge>Badge</div>\n```\n\n## Variants\n\n```html\n<div scBadge>Default</div>\n<div scBadge variant="secondary">Secondary</div>\n<div scBadge variant="destructive">Destructive</div>\n<div scBadge variant="outline">Outline</div>\n```\n\n## With Icons\n\n```html\n<div scBadge class="gap-1">\n <svg class="size-3"><!-- icon --></svg>\n Premium\n</div>\n```\n\n## Notification Count\n\n```html\n<div class="relative">\n <button><!-- button content --></button>\n <span scBadge class="absolute -top-1 -right-1 flex size-5 items-center justify-center p-0">3</span>\n</div>\n```\n\n## Custom Colors\n\nOverride the default colors with custom classes:\n\n```html\n<div scBadge class="bg-green-500 hover:bg-green-500/80">Active</div>\n<div scBadge class="bg-yellow-500 hover:bg-yellow-500/80">Warning</div>\n<div scBadge class="bg-blue-500 hover:bg-blue-500/80">Info</div>\n```\n\n## Inputs\n\n| Input | Type | Default | Description |\n| --------- | -------------------------------------------------------- | ----------- | ---------------------- |\n| `variant` | `\'default\' \\| \'secondary\' \\| \'destructive\' \\| \'outline\'` | `\'default\'` | Badge variant |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n## Variant Styles\n\n| Variant | Description |\n| ------------- | ----------------------------------------------- |\n| `default` | Primary background with primary-foreground text |\n| `secondary` | Secondary background with secondary-foreground |\n| `destructive` | Destructive background for errors/warnings |\n| `outline` | Transparent with border |\n',
|
|
@@ -30514,11 +30509,6 @@ var manifest_default = {
|
|
|
30514
30509
|
readme: '# ScSheet Components\n\nA set of Angular components for creating accessible side panels (drawers) with shadcn/ui styling.\n\n## Architecture\n\nThe components follow a dependency injection (DI) pattern where child components inject the parent `ScSheetProvider` to access shared state. `ScSheetProvider` owns all overlay lifecycle logic (CDK overlay, backdrop, focus trap). The `ScSheetPortal` directive marks the lazy content template that gets portaled into the overlay.\n\n```\nScSheetProvider (root wrapper - manages open state, side + overlay lifecycle)\n\u251C\u2500\u2500 ScSheetTrigger (button that opens sheet)\n\u2514\u2500\u2500 ng-template[scSheetPortal] (lazy content, portaled to CDK overlay)\n \u2514\u2500\u2500 ScSheet (dialog panel with slide animations)\n \u251C\u2500\u2500 ScSheetClose (close button)\n \u251C\u2500\u2500 ScSheetHeader\n \u2502 \u251C\u2500\u2500 ScSheetTitle\n \u2502 \u2514\u2500\u2500 ScSheetDescription\n \u251C\u2500\u2500 (user content)\n \u2514\u2500\u2500 ScSheetFooter\n```\n\n## Components\n\n| Component | Selector | Description |\n| -------------------- | ---------------------------- | ---------------------------------------------- |\n| `ScSheetProvider` | `div[scSheetProvider]` | Root wrapper, manages open state + overlay |\n| `ScSheetTrigger` | `button[scSheetTrigger]` | Button that opens the sheet |\n| `ScSheetPortal` | `ng-template[scSheetPortal]` | Directive marking lazy content for the overlay |\n| `ScSheet` | `div[scSheet]` | Dialog panel with slide animations |\n| `ScSheetHeader` | `div[scSheetHeader]` | Header section container |\n| `ScSheetTitle` | `h2[scSheetTitle]` | Sheet title (aria-labelledby) |\n| `ScSheetDescription` | `p[scSheetDescription]` | Sheet description (aria-describedby) |\n| `ScSheetFooter` | `div[scSheetFooter]` | Footer section for actions |\n| `ScSheetClose` | `button[scSheetClose]` | Button that closes the sheet |\n\n## Usage\n\n### Basic Sheet (Right Side)\n\n```html\n<div scSheetProvider>\n <button scSheetTrigger>Open Sheet</button>\n <ng-template scSheetPortal>\n <div scSheet>\n <button scSheetClose>\n <svg><!-- X icon --></svg>\n <span class="sr-only">Close</span>\n </button>\n <div scSheetHeader>\n <h2 scSheetTitle>Sheet Title</h2>\n <p scSheetDescription>Sheet description goes here.</p>\n </div>\n <!-- Your content -->\n <div scSheetFooter>\n <button>Cancel</button>\n <button>Save</button>\n </div>\n </div>\n </ng-template>\n</div>\n```\n\n### Different Sides\n\n```html\n<!-- Left side -->\n<div scSheetProvider side="left">\n <button scSheetTrigger>Open Left</button>\n <ng-template scSheetPortal>\n <div scSheet>\n <!-- content -->\n </div>\n </ng-template>\n</div>\n\n<!-- Top side -->\n<div scSheetProvider side="top">\n <button scSheetTrigger>Open Top</button>\n <ng-template scSheetPortal>\n <div scSheet>\n <!-- content -->\n </div>\n </ng-template>\n</div>\n\n<!-- Bottom side -->\n<div scSheetProvider side="bottom">\n <button scSheetTrigger>Open Bottom</button>\n <ng-template scSheetPortal>\n <div scSheet>\n <!-- content -->\n </div>\n </ng-template>\n</div>\n```\n\n### Controlled Sheet\n\n```typescript\n@Component({\n template: `\n <div scSheetProvider [(open)]="isOpen" side="right">\n <button scSheetTrigger>Open</button>\n <ng-template scSheetPortal>\n <div scSheet>\n <!-- content -->\n </div>\n </ng-template>\n </div>\n `,\n})\nexport class MyComponent {\n isOpen = signal(false);\n\n openSheet() {\n this.isOpen.set(true);\n }\n\n closeSheet() {\n this.isOpen.set(false);\n }\n}\n```\n\n### Navigation Sheet\n\n```html\n<div scSheetProvider side="left">\n <button scSheetTrigger>Menu</button>\n <ng-template scSheetPortal>\n <div scSheet>\n <button scSheetClose>X</button>\n <div scSheetHeader>\n <h2 scSheetTitle>Navigation</h2>\n </div>\n <nav class="flex flex-col gap-2">\n <a href="#">Home</a>\n <a href="#">Products</a>\n <a href="#">About</a>\n <a href="#">Contact</a>\n </nav>\n </div>\n </ng-template>\n</div>\n```\n\n## Keyboard Navigation\n\n| Key | Action |\n| -------- | --------------------- |\n| `Escape` | Close sheet |\n| `Tab` | Navigate within sheet |\n\n## Side Options\n\n| Side | Description |\n| -------- | ------------------------------ |\n| `right` | Slides in from right (default) |\n| `left` | Slides in from left |\n| `top` | Slides down from top |\n| `bottom` | Slides up from bottom |\n\n## How It Works\n\n### State Management\n\n`ScSheetProvider` uses a `model` signal for the `open` state and an `input` for the `side`:\n\n```typescript\nreadonly side = input<SheetSide>(\'right\');\nreadonly open = model<boolean>(false);\n```\n\nChild components inject `ScSheetProvider` to read or modify this state:\n\n```typescript\n// ScSheetTrigger\nopenSheet(): void {\n this.sheetProvider.open.set(true);\n}\n\n// ScSheetClose\ncloseSheet(): void {\n this.sheetProvider.open.set(false);\n}\n```\n\n### Overlay Management\n\n`ScSheetProvider` creates a CDK overlay and attaches/detaches the `scSheetPortal` template based on state:\n\n```typescript\neffect(() => {\n if (this.overlayOpen()) {\n this.attachSheet();\n } else {\n this.detachSheet();\n }\n});\n```\n\nThe `scSheetPortal` directive marks the `ng-template` whose content is lazily instantiated into the overlay only when the sheet opens.\n\n### Slide Animations\n\n`ScSheet` applies different transform classes based on the side and open state:\n\n```typescript\nconst sideClosedClasses: Record<SheetSide, string> = {\n top: \'-translate-y-full\',\n right: \'translate-x-full\',\n bottom: \'translate-y-full\',\n left: \'-translate-x-full\',\n};\n\nconst sideOpenClasses: Record<SheetSide, string> = {\n top: \'translate-y-0\',\n right: \'translate-x-0\',\n bottom: \'translate-y-0\',\n left: \'translate-x-0\',\n};\n```\n\n## Accessibility\n\n- `role="dialog"` on `ScSheet`\n- `aria-modal="true"` for modal behavior\n- `aria-labelledby` linked to `ScSheetTitle`\n- `aria-describedby` linked to `ScSheetDescription`\n- `aria-haspopup="dialog"` on the trigger\n- `aria-expanded` reflects open state on trigger\n- Focus trapped within the sheet via `cdkTrapFocus`\n- Escape key closes the sheet (via CDK overlay keydown events)\n- Click outside (backdrop) closes the sheet (via CDK overlay backdrop click)\n\n## Customization\n\nAll components accept a `class` input for custom styling:\n\n```html\n<div scSheet class="w-[400px]">\n <!-- custom width -->\n</div>\n\n<div scSheetFooter class="flex-row-reverse">\n <!-- reversed button order -->\n</div>\n```\n',
|
|
30515
30510
|
exports: []
|
|
30516
30511
|
},
|
|
30517
|
-
{
|
|
30518
|
-
name: "sidebar",
|
|
30519
|
-
readme: "# Sidebar\n\nA comprehensive sidebar component system for Angular applications with collapsible states, mobile responsiveness, keyboard shortcuts, and state persistence.\n\n## Components\n\n### Core Components\n\n- `ScSidebarProvider` - Root provider component with state management\n- `ScSidebar` - Main sidebar container\n- `ScSidebarGap` - Invisible spacer that pushes content (used internally by ScSidebar)\n- `ScSidebarContainer` - Fixed-position container for sidebar content (used internally by ScSidebar)\n- `ScSidebarInner` - Inner wrapper with background and variant styles (used internally by ScSidebar)\n- `ScSidebarTrigger` - Toggle button\n- `ScSidebarRail` - Thin invisible button on the sidebar edge that toggles collapse on click. Shows a 2px border on hover and changes cursor direction based on state (w-resize / e-resize)\n- `ScSidebarInset` - Main content wrapper\n\n### Layout Components\n\n- `ScSidebarHeader` - Header section\n- `ScSidebarFooter` - Footer section\n- `ScSidebarBody` - Scrollable content area\n- `ScSidebarSeparator` - Visual separator\n- `ScSidebarInput` - Styled input for search\n\n### Menu Components\n\n- `ScSidebarMenu` - Menu list container (ul)\n- `ScSidebarMenuItem` - Menu list item (li)\n- `ScSidebarMenuButton` - Menu button/link (works with both button and a elements)\n- `ScSidebarMenuAction` - Action button on menu items\n- `ScSidebarMenuBadge` - Badge/counter display\n- `ScSidebarMenuSkeleton` - Loading skeleton\n- `ScSidebarMenuSub` - Submenu container (ul)\n- `ScSidebarMenuSubItem` - Submenu item (li)\n- `ScSidebarMenuSubButton` - Submenu button/link\n\n### Group Components\n\n- `ScSidebarGroup` - Group container\n- `ScSidebarGroupLabel` - Group header/label\n- `ScSidebarGroupAction` - Action button for groups\n- `ScSidebarGroupContent` - Group content wrapper\n\n## Features\n\n- **Reactive State Management** - Built with Angular signals\n- **Keyboard Shortcuts** - Cmd/Ctrl + B to toggle sidebar\n- **LocalStorage Persistence** - State persists across page refreshes\n- **Mobile Responsive** - Sheet drawer on mobile devices\n- **Multiple Variants** - sidebar, floating, inset\n- **Collapsible Modes** - offcanvas, icon, none\n- **Two-way Binding** - Model support for open state\n- **CSS Variables** - Customizable widths\n\n## How It Works\n\nThe sidebar uses a clever layout technique to push content to the side instead of overlaying it:\n\n```\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 ScSidebarProvider (flex container) \u2502\n\u2502 \u2502\n\u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\u2502\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n\u2502 \u2502 ScSidebar \u2502\u2502\u2502 ScSidebarInset (main content) \u2502 \u2502\n\u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502\n\u2502 \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\u2502\u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u2502\n\u2502 \u2502 \u2502 ScSidebarGap \u2502 \u2502\u2502\u2502 \u2502 <header> \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2022 Width: 16rem \u2502 \u2502\u2502\u2502 \u2502 <button scSidebarTrigger> \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2022 No height \u2502 \u2502\u2502\u2502 \u2502 Toggle \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2022 Pushes content in flex \u2502 \u2502\u2502\u2502 \u2502 </button> \u2502 \u2502 \u2502\n\u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\u2502\u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2502\n\u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502\n\u2502 \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\u2502\u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u2502\n\u2502 \u2502 \u2502 ScSidebarContainer \u2502 \u2502\u2502\u2502 \u2502 <main> \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 (position: fixed) \u2502 \u2502\u2502\u2502 \u2502 Your content here \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 ScSidebarInner \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 (bg, rounded, ring) \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 ScSidebarHeader \u2502 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 ScSidebarBody \u2502 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 (scrollable) \u2502 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 \u2502ScSidebarGroup\u2502 \u2502 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u2502 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502GroupLabel\u2502 \u2502 \u2502 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2502 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u2502 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502 Menu \u2502 \u2502 \u2502 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502Button\u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2502 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 ScSidebarFooter \u2502 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2502\u2502\u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502\n\u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\u2502\u2502 \u2502 \u2502\n\u2502 \u2502 \u2502\u2502\u2502 \u2502 \u2502\n\u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\u2502\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n\u2502 \u2502 \u2502\n\u2502 ScSidebarRail \u2502\n\u2502 (thin clickable strip \u2502\n\u2502 on the edge between \u2502\n\u2502 sidebar and content, \u2502\n\u2502 click to toggle) \u2502\n\u2502 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n```\n\n### Key Concepts\n\n1. **ScSidebarGap** - An invisible spacer with width but no height that participates in the flex layout, creating space for the sidebar\n2. **ScSidebarContainer** - The fixed-position wrapper that holds the actual sidebar content, overlaying the gap\n3. **ScSidebarInner** - Applies background color and variant-specific styles (rounded corners, shadow, ring for floating variant)\n4. **ScSidebarRail** - A thin invisible button on the edge between the sidebar and main content; click it to toggle the sidebar. Cursor changes to indicate collapse direction. Shows a subtle 2px border on hover\n5. **Flex Layout** - The provider uses flexbox, making the gap and content area sit side-by-side\n6. **Responsive Collapse** - When collapsed, the gap width transitions to 0, allowing content to use full width\n\nThis architecture ensures smooth transitions and proper content flow without JavaScript layout calculations.\n\n## Basic Usage\n\n```typescript\nimport { ScSidebarProvider, ScSidebar, ScSidebarTrigger, ScSidebarHeader, ScSidebarBody, ScSidebarFooter, ScSidebarMenu, ScSidebarMenuItem, ScSidebarMenuButton, ScSidebarInset } from '@semantic-components/ui';\n\n@Component({\n selector: 'app-layout',\n imports: [\n ScSidebarProvider,\n ScSidebar,\n // ... other imports\n ],\n template: `\n <div scSidebarProvider>\n <div scSidebar>\n <div scSidebarHeader>\n <h2>My App</h2>\n </div>\n\n <div scSidebarBody>\n <ul scSidebarMenu>\n <li scSidebarMenuItem>\n <a scSidebarMenuButton routerLink=\"/dashboard\">Dashboard</a>\n </li>\n </ul>\n </div>\n\n <div scSidebarFooter>User Info</div>\n </div>\n\n <main scSidebarInset>\n <header>\n <button scSidebarTrigger>Toggle</button>\n </header>\n <router-outlet />\n </main>\n </div>\n `,\n})\nexport class AppLayout {}\n```\n\n## Advanced Usage\n\n### With Submenu\n\n```html\n<ul scSidebarMenu>\n <li scSidebarMenuItem>\n <a scSidebarMenuButton>Projects</a>\n <ul scSidebarMenuSub>\n <li scSidebarMenuSubItem>\n <a scSidebarMenuSubButton routerLink=\"/projects/1\">Project 1</a>\n </li>\n </ul>\n </li>\n</ul>\n```\n\n### With Groups\n\n```html\n<div scSidebarGroup>\n <div scSidebarGroupLabel>Navigation</div>\n <div scSidebarGroupContent>\n <ul scSidebarMenu>\n <!-- menu items -->\n </ul>\n </div>\n</div>\n```\n\n### Variants\n\n```html\n<!-- Default sidebar -->\n<div scSidebar variant=\"sidebar\" collapsible=\"icon\">\n <!-- Floating sidebar -->\n <div scSidebar variant=\"floating\" collapsible=\"icon\">\n <!-- Inset sidebar -->\n <div scSidebar variant=\"inset\" collapsible=\"icon\"></div>\n </div>\n</div>\n```\n\n### Two-way Binding\n\n```typescript\n@Component({\n template: `\n <div scSidebarProvider [(open)]=\"sidebarOpen\">\n <!-- sidebar content -->\n </div>\n `,\n})\nexport class MyComponent {\n sidebarOpen = signal(true);\n}\n```\n\n## Configuration\n\n### CSS Variables\n\nThe sidebar uses CSS variables that can be customized:\n\n```css\n:root {\n --sidebar-width: 16rem;\n --sidebar-width-mobile: 18rem; /* Available but not currently used */\n --sidebar-width-icon: 3rem;\n}\n```\n\n**Note:** The mobile sidebar currently uses the default width from the Sheet component. The `--sidebar-width-mobile` variable is available for future customization if needed.\n\n### Props\n\n#### ScSidebar\n\n- `side` - 'left' | 'right' (default: 'left')\n- `variant` - 'sidebar' | 'floating' | 'inset' (default: 'sidebar')\n- `collapsible` - 'offcanvas' | 'icon' | 'none' (default: 'offcanvas')\n\n#### ScSidebarMenuButton\n\n- `size` - 'default' | 'sm' | 'lg' (default: 'default')\n- `isActive` - boolean (default: false)\n- `tooltip` - string (optional)\n\n#### ScSidebarMenuSubButton\n\n- `size` - 'sm' | 'md' (default: 'md')\n- `isActive` - boolean (default: false)\n\n## Keyboard Shortcuts\n\n- `Cmd + B` (Mac) / `Ctrl + B` (Windows) - Toggle sidebar\n\n## State Persistence\n\nThe sidebar state is automatically saved to `localStorage` (key: `sc-sidebar-state`). The state will be restored when the page is refreshed.\n\n## Mobile Behavior\n\nOn screens smaller than 768px (md breakpoint), the sidebar automatically switches to a sheet drawer that slides in from the side using the `ScSheetProvider`, `ScSheetPortal`, and `ScSheet` components. The `ScSidebarTrigger` automatically handles mobile vs desktop toggle logic.\n\n### Mobile Implementation Details\n\nThe mobile view uses the new ScSheet architecture with a provider pattern:\n\n- `ScSheetProvider` manages the open state and side\n- `ScSheetPortal` creates the overlay with backdrop\n- `ScSheet` is the dialog panel with slide animations\n\n**Mobile Width:** The mobile sidebar uses the default width provided by the Sheet component rather than a custom width. This ensures consistency with other sheet-based UI elements and provides a responsive width that adapts to different device sizes.\n\n## Accessibility\n\n- All interactive elements are keyboard accessible\n- Proper ARIA attributes are applied\n- Focus management is handled automatically\n- Screen reader support included\n\n## Demo\n\nSee a comprehensive demo at `/dashboard` in the blocks application.\n",
|
|
30520
|
-
exports: []
|
|
30521
|
-
},
|
|
30522
30512
|
{
|
|
30523
30513
|
name: "skeleton",
|
|
30524
30514
|
readme: '# Skeleton\n\nA placeholder to show while content is loading.\n\n## Components\n\n- `ScSkeleton` - An animated pulse placeholder applied as a directive on a `div`\n\n## Usage\n\n```html\n<div scSkeleton class="h-4 w-48"></div>\n```\n\n## Examples\n\n### Text lines\n\n```html\n<div class="space-y-2">\n <div scSkeleton class="h-4 w-full"></div>\n <div scSkeleton class="h-4 w-3/4"></div>\n <div scSkeleton class="h-4 w-1/2"></div>\n</div>\n```\n\n### Card\n\n```html\n<div class="space-y-4 p-4">\n <div scSkeleton class="h-40 w-full rounded-xl"></div>\n <div class="space-y-2">\n <div scSkeleton class="h-4 w-3/4"></div>\n <div scSkeleton class="h-4 w-1/2"></div>\n </div>\n</div>\n```\n\n### Avatar with text\n\n```html\n<div class="flex items-center gap-3">\n <div scSkeleton class="size-10 rounded-full"></div>\n <div class="space-y-2">\n <div scSkeleton class="h-4 w-32"></div>\n <div scSkeleton class="h-3 w-24"></div>\n </div>\n</div>\n```\n\n## Inputs\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n',
|
|
@@ -30622,96 +30612,11 @@ var manifest_default = {
|
|
|
30622
30612
|
{
|
|
30623
30613
|
name: "@semantic-components/ui-lab",
|
|
30624
30614
|
components: [
|
|
30625
|
-
{
|
|
30626
|
-
name: "animated-counter",
|
|
30627
|
-
readme: '# Animated Counter\n\nA component that animates numbers smoothly between values with customizable easing, formatting, and duration.\n\n## Installation\n\n```typescript\nimport { ScAnimatedCounter } from \'@/ui/animated-counter\';\nimport type { AnimatedCounterEasing, AnimatedCounterOptions } from \'@/ui/animated-counter\';\n```\n\n## Usage\n\n### Basic Usage\n\n```html\n<sc-animated-counter [value]="count" class="text-4xl font-bold" />\n```\n\n```typescript\ncount = signal(0);\n\nincrement(): void {\n this.count.update((v) => v + 100);\n}\n```\n\n### With Prefix and Suffix\n\n```html\n<sc-animated-counter [value]="money" prefix="$" [decimalPlaces]="2" class="text-3xl font-bold text-green-600" />\n\n<sc-animated-counter [value]="percent" suffix="%" [decimalPlaces]="1" class="text-3xl font-bold" />\n```\n\n### Custom Easing\n\n```html\n<sc-animated-counter [value]="value" easing="linear" [duration]="2000" />\n<sc-animated-counter [value]="value" easing="easeIn" [duration]="2000" />\n<sc-animated-counter [value]="value" easing="easeOut" [duration]="2000" />\n<sc-animated-counter [value]="value" easing="easeInOut" [duration]="2000" />\n```\n\n### Large Numbers with Separators\n\n```html\n<sc-animated-counter [value]="largeNumber" separator="," class="text-3xl font-bold" />\n```\n\n## API Reference\n\n### Inputs\n\n| Input | Type | Default | Description |\n| --------------- | -------------------------------------------------- | ----------- | ------------------------ |\n| `value` | `number` | (required) | Target number to display |\n| `duration` | `number` | `1000` | Animation duration in ms |\n| `easing` | `\'linear\' \\| \'easeIn\' \\| \'easeOut\' \\| \'easeInOut\'` | `\'easeOut\'` | Animation easing |\n| `decimalPlaces` | `number` | `0` | Number of decimal places |\n| `separator` | `string` | `\',\'` | Thousands separator |\n| `prefix` | `string` | `\'\'` | Prefix text (e.g., \'$\') |\n| `suffix` | `string` | `\'\'` | Suffix text (e.g., \'%\') |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n### Outputs\n\n| Output | Type | Description |\n| ------------------- | -------- | -------------------------------- |\n| `animationComplete` | `number` | Emitted when animation completes |\n\n### Methods\n\n| Method | Description |\n| --------- | ------------------ |\n| `reset()` | Reset counter to 0 |\n\n## Type Definitions\n\n```typescript\ntype AnimatedCounterEasing = \'linear\' | \'easeIn\' | \'easeOut\' | \'easeInOut\';\n\ninterface AnimatedCounterOptions {\n duration?: number;\n easing?: AnimatedCounterEasing;\n decimalPlaces?: number;\n separator?: string;\n prefix?: string;\n suffix?: string;\n}\n```\n\n## Features\n\n- Smooth number animation with requestAnimationFrame\n- Multiple easing functions\n- Configurable decimal places\n- Thousands separator formatting\n- Prefix and suffix support\n- Accessible with aria-label\n- Automatic animation on value change\n- Tabular numbers for stable width\n',
|
|
30628
|
-
exports: []
|
|
30629
|
-
},
|
|
30630
30615
|
{
|
|
30631
30616
|
name: "audio-player",
|
|
30632
30617
|
readme: '# Audio Player\n\nFeature-rich composable audio player with playlist support, shuffle, repeat, and volume controls.\n\n## Architecture\n\nThe audio player follows the composable architecture pattern, allowing full customization of layout and controls.\n\n```\nScAudioPlayer (Root - State Management)\n \u251C\u2500\u2500 ScAudioPlayerAudio (Hidden audio element)\n \u251C\u2500\u2500 ScAudioPlayerCover (Album artwork)\n \u251C\u2500\u2500 ScAudioPlayerInfo (Track title/artist)\n \u251C\u2500\u2500 ScAudioPlayerProgress (Seekable progress bar)\n \u251C\u2500\u2500 ScAudioPlayerPlayButton (Play/pause)\n \u251C\u2500\u2500 ScAudioPlayerPrevious (Previous track)\n \u251C\u2500\u2500 ScAudioPlayerNext (Next track)\n \u251C\u2500\u2500 ScAudioPlayerShuffle (Shuffle toggle)\n \u251C\u2500\u2500 ScAudioPlayerRepeat (Repeat mode)\n \u2514\u2500\u2500 ScAudioPlayerVolume (Volume slider + mute)\n```\n\n## Components\n\n| Component | Selector | Description |\n| ------------------------- | --------------------------------- | ------------------------------ |\n| `ScAudioPlayer` | `[scAudioPlayer]` | Root directive (state manager) |\n| `ScAudioPlayerAudio` | `audio[scAudioPlayerAudio]` | Hidden audio element |\n| `ScAudioPlayerCover` | `div[scAudioPlayerCover]` | Album artwork display |\n| `ScAudioPlayerInfo` | `div[scAudioPlayerInfo]` | Track title and artist |\n| `ScAudioPlayerProgress` | `div[scAudioPlayerProgress]` | Progress bar with seek |\n| `ScAudioPlayerPlayButton` | `button[scAudioPlayerPlayButton]` | Play/pause button |\n| `ScAudioPlayerPrevious` | `button[scAudioPlayerPrevious]` | Previous track button |\n| `ScAudioPlayerNext` | `button[scAudioPlayerNext]` | Next track button |\n| `ScAudioPlayerShuffle` | `button[scAudioPlayerShuffle]` | Shuffle toggle |\n| `ScAudioPlayerRepeat` | `button[scAudioPlayerRepeat]` | Repeat cycle button |\n| `ScAudioPlayerVolume` | `div[scAudioPlayerVolume]` | Volume slider + mute |\n\n## API\n\n### ScAudioTrack\n\n```typescript\ninterface ScAudioTrack {\n src: string;\n title?: string;\n artist?: string;\n cover?: string;\n duration?: number;\n}\n```\n\n### ScAudioPlayer\n\n| Input | Type | Default | Description |\n| ---------- | ---------------- | ------- | --------------------- |\n| `tracks` | `ScAudioTrack[]` | `[]` | Array of audio tracks |\n| `autoplay` | `boolean` | `false` | Auto-play on load |\n\n| Model | Type | Default | Description |\n| -------------- | -------------------------- | -------- | ------------------- |\n| `currentIndex` | `number` | `0` | Current track index |\n| `volume` | `number` | `1` | Volume level (0-1) |\n| `shuffle` | `boolean` | `false` | Shuffle mode |\n| `repeat` | `\'none\' \\| \'one\' \\| \'all\'` | `\'none\'` | Repeat mode |\n\n| Output | Type | Description |\n| ------------- | -------------- | -------------------------- |\n| `trackChange` | `ScAudioTrack` | Emits when track changes |\n| `play` | `void` | Emits when playback starts |\n| `pause` | `void` | Emits when playback pauses |\n| `ended` | `void` | Emits when track ends |\n\n## Usage\n\n### Basic Usage\n\n```typescript\nreadonly tracks: ScAudioTrack[] = [\n {\n src: \'/audio/song1.mp3\',\n title: \'Song Title\',\n artist: \'Artist Name\',\n cover: \'/images/album.jpg\',\n },\n // ... more tracks\n];\n```\n\n```html\n<div scAudioPlayer [tracks]="tracks" class="bg-card flex flex-col gap-3 rounded-lg border p-4">\n <!-- Cover -->\n <div scAudioPlayerCover class="mx-auto aspect-square w-full max-w-[200px]"></div>\n\n <!-- Track Info -->\n <div scAudioPlayerInfo class="text-center"></div>\n\n <!-- Progress -->\n <div scAudioPlayerProgress></div>\n\n <!-- Controls -->\n <div class="flex items-center justify-center gap-2">\n <button scAudioPlayerShuffle></button>\n <button scAudioPlayerPrevious></button>\n <button scAudioPlayerPlayButton></button>\n <button scAudioPlayerNext></button>\n <button scAudioPlayerRepeat></button>\n </div>\n\n <!-- Volume -->\n <div scAudioPlayerVolume class="justify-center"></div>\n\n <!-- Hidden Audio Element -->\n <audio scAudioPlayerAudio></audio>\n</div>\n```\n\n### Compact Layout\n\nHorizontal layout for sidebars:\n\n```html\n<div scAudioPlayer [tracks]="tracks" class="bg-card flex items-center gap-4 rounded-lg border p-4">\n <div scAudioPlayerCover class="size-16"></div>\n <div scAudioPlayerInfo class="min-w-0 flex-1"></div>\n <div class="flex items-center gap-2">\n <button scAudioPlayerPrevious></button>\n <button scAudioPlayerPlayButton></button>\n <button scAudioPlayerNext></button>\n </div>\n <audio scAudioPlayerAudio></audio>\n</div>\n```\n\n### Minimal Player\n\nSimple player without extra controls:\n\n```html\n<div scAudioPlayer [tracks]="tracks" class="bg-card flex items-center gap-2 rounded-lg border p-2">\n <div scAudioPlayerCover class="size-10"></div>\n <div scAudioPlayerInfo class="min-w-0 flex-1"></div>\n <button scAudioPlayerPrevious></button>\n <button scAudioPlayerPlayButton></button>\n <button scAudioPlayerNext></button>\n <audio scAudioPlayerAudio></audio>\n</div>\n```\n\n### Only Essential Controls\n\n```html\n<div scAudioPlayer [tracks]="tracks" class="bg-card flex flex-col gap-3 rounded-lg border p-4">\n <div scAudioPlayerProgress></div>\n <div class="flex items-center justify-center gap-2">\n <button scAudioPlayerPlayButton></button>\n </div>\n <audio scAudioPlayerAudio></audio>\n</div>\n```\n\n### Custom Layout\n\nCreate any layout you want:\n\n```html\n<div scAudioPlayer [tracks]="tracks" [(volume)]="volume">\n <div class="bg-card grid grid-cols-2 gap-4 rounded-lg border p-6">\n <!-- Left Column -->\n <div class="space-y-4">\n <div scAudioPlayerCover class="aspect-square w-full"></div>\n <div scAudioPlayerInfo></div>\n </div>\n\n <!-- Right Column -->\n <div class="flex flex-col justify-between">\n <div scAudioPlayerVolume></div>\n\n <div class="space-y-4">\n <div scAudioPlayerProgress></div>\n <div class="flex justify-center gap-2">\n <button scAudioPlayerShuffle></button>\n <button scAudioPlayerPrevious></button>\n <button scAudioPlayerPlayButton></button>\n <button scAudioPlayerNext></button>\n <button scAudioPlayerRepeat></button>\n </div>\n </div>\n </div>\n </div>\n\n <audio scAudioPlayerAudio></audio>\n</div>\n```\n\n### Custom Styling\n\nEach component accepts a `class` input:\n\n```html\n<button scAudioPlayerPlayButton class="size-16 bg-blue-500"></button>\n<div scAudioPlayerCover class="size-32 rounded-full"></div>\n<div scAudioPlayerProgress class="gap-4"></div>\n```\n\n### Controlled State\n\n```html\n<div scAudioPlayer [tracks]="tracks" [(currentIndex)]="currentIndex" [(volume)]="volume" [(shuffle)]="shuffle" [(repeat)]="repeat" (trackChange)="onTrackChange($event)" (play)="onPlay()" (pause)="onPause()">\n <!-- ... components ... -->\n</div>\n```\n\n## Features\n\n- \u2705 **Composable**: Mix and match components\n- \u2705 **Flexible Layout**: Full control over structure\n- \u2705 **Custom Styling**: Style each component individually\n- \u2705 **Play/Pause**: Visual feedback\n- \u2705 **Track Navigation**: Previous/next with restart logic\n- \u2705 **Progress Bar**: Click to seek\n- \u2705 **Volume Control**: Slider with mute toggle\n- \u2705 **Shuffle Mode**: Random track order\n- \u2705 **Repeat Modes**: None, one, all\n- \u2705 **Keyboard Navigation**: Seek with arrow keys\n- \u2705 **Touch Friendly**: Works on all devices\n\n## Keyboard Navigation\n\nWhen focused on the progress bar:\n\n| Key | Action |\n| ----------- | ----------------------- |\n| `\u2190` | Seek back 5 seconds |\n| `\u2192` | Seek forward 5 seconds |\n| `Shift + \u2190` | Seek back 10 seconds |\n| `Shift + \u2192` | Seek forward 10 seconds |\n\n## Accessibility\n\n- ARIA labels on all controls\n- Keyboard navigable progress bar\n- Screen reader announcements\n- Focus indicators on buttons\n- Proper button roles and states\n\n## Notes\n\n- The `<audio>` element must be included as a child\n- The `#audio` template reference is handled internally\n- All sub-components require the parent `[scAudioPlayer]` directive\n- Components can be reordered and styled freely\n',
|
|
30633
30618
|
exports: []
|
|
30634
30619
|
},
|
|
30635
|
-
{
|
|
30636
|
-
name: "barcode-scanner",
|
|
30637
|
-
readme: "# Barcode Scanner\n\nScan barcodes and QR codes using your device's camera with the Barcode Detection API.\n\n## Components\n\n- `ScBarcodeScanner` - Full-featured scanner with controls\n- `ScBarcodeScannerSimple` - Simplified scanner wrapper\n\n## Usage\n\n```html\n<sc-barcode-scanner (detected)=\"onDetected($event)\" />\n```\n\n## API\n\n### BarcodeFormat\n\n```typescript\ntype BarcodeFormat = 'aztec' | 'code_128' | 'code_39' | 'code_93' | 'codabar' | 'data_matrix' | 'ean_13' | 'ean_8' | 'itf' | 'pdf417' | 'qr_code' | 'upc_a' | 'upc_e';\n```\n\n### BarcodeResult\n\n```typescript\ninterface BarcodeResult {\n rawValue: string;\n format: BarcodeFormat;\n boundingBox?: DOMRectReadOnly;\n cornerPoints?: { x: number; y: number }[];\n}\n```\n\n### ScBarcodeScanner\n\n| Input | Type | Default | Description |\n| ---------------- | ----------------- | ---------------------------- | ----------------------------- |\n| `formats` | `BarcodeFormat[]` | `['qr_code', 'ean_13', ...]` | Formats to detect |\n| `showLastResult` | `boolean` | `true` | Show last scanned code |\n| `continuous` | `boolean` | `true` | Keep scanning after detection |\n| `scanInterval` | `number` | `100` | Detection interval (ms) |\n| `class` | `string` | - | Additional CSS classes |\n\n| Output | Type | Description |\n| ---------- | --------------- | --------------------------- |\n| `detected` | `BarcodeResult` | Emits when barcode detected |\n| `error$` | `string` | Emits on error |\n\n## Examples\n\n### Basic Usage\n\n```html\n<sc-barcode-scanner (detected)=\"onDetected($event)\" />\n```\n\n```typescript\nonDetected(result: BarcodeResult): void {\n console.log('Scanned:', result.rawValue);\n console.log('Format:', result.format);\n}\n```\n\n### QR Code Only\n\n```html\n<sc-barcode-scanner [formats]=\"['qr_code']\" (detected)=\"onQRDetected($event)\" />\n```\n\n### Product Barcodes\n\n```html\n<sc-barcode-scanner [formats]=\"['ean_13', 'ean_8', 'upc_a', 'upc_e']\" (detected)=\"onProductDetected($event)\" />\n```\n\n### Single Scan Mode\n\nStop scanning after first detection:\n\n```html\n<sc-barcode-scanner [continuous]=\"false\" (detected)=\"onSingleScan($event)\" />\n```\n\n### Without Result Overlay\n\n```html\n<sc-barcode-scanner [showLastResult]=\"false\" (detected)=\"handleResult($event)\" />\n```\n\n## Features\n\n- Real-time barcode detection\n- Multiple barcode format support\n- Front/back camera switching\n- Flashlight/torch control (where supported)\n- Scanning area indicator\n- Last result overlay\n- Start/stop controls\n- Graceful fallback for unsupported browsers\n\n## Browser Support\n\nThe Barcode Detection API is supported in:\n\n| Browser | Support |\n| ---------------- | ----------------- |\n| Chrome 83+ | Desktop & Android |\n| Edge 83+ | Desktop |\n| Opera 69+ | Desktop & Android |\n| Samsung Internet | Android |\n| Firefox | Not supported |\n| Safari | Not supported |\n\nFor unsupported browsers, the component displays a helpful message.\n\n## Permissions\n\nThe scanner requires camera access. Users will be prompted to grant permission when scanning starts.\n\n## Supported Barcode Formats\n\n| Format | Description |\n| ------------- | ----------------------------------- |\n| `qr_code` | QR Code |\n| `ean_13` | European Article Number (13 digits) |\n| `ean_8` | European Article Number (8 digits) |\n| `upc_a` | Universal Product Code A |\n| `upc_e` | Universal Product Code E |\n| `code_128` | Code 128 |\n| `code_39` | Code 39 |\n| `code_93` | Code 93 |\n| `codabar` | Codabar |\n| `itf` | Interleaved 2 of 5 |\n| `pdf417` | PDF417 |\n| `aztec` | Aztec Code |\n| `data_matrix` | Data Matrix |\n\n## Accessibility\n\n- Keyboard accessible controls\n- ARIA labels on buttons\n- Focus indicators\n- Status messages for screen readers\n",
|
|
30638
|
-
exports: []
|
|
30639
|
-
},
|
|
30640
|
-
{
|
|
30641
|
-
name: "button-pattern",
|
|
30642
|
-
readme: null,
|
|
30643
|
-
exports: []
|
|
30644
|
-
},
|
|
30645
|
-
{
|
|
30646
|
-
name: "chart",
|
|
30647
|
-
readme: '# Chart\n\nSVG-based chart components for data visualization.\n\n## Usage\n\n```html\n<div scChartContainer>\n <div scBarChart [data]="data" [height]="300"></div>\n <div scChartLegend [items]="legend"></div>\n</div>\n```\n\n## Components\n\n### ScChartContainer\n\nRoot container that provides chart context and configuration.\n\n**Selector:** `[scChartContainer]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| -------- | ------------- | ------- | ------------------------ |\n| `config` | `ChartConfig` | `{}` | Color and label mappings |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n### ScBarChart\n\nBar chart visualization.\n\n**Selector:** `[scBarChart]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ----------- | ------------------ | ------- | ---------------------- |\n| `data` | `ChartDataPoint[]` | `[]` | Chart data |\n| `height` | `number` | `300` | Chart height in pixels |\n| `barRadius` | `number` | `4` | Bar corner radius |\n| `barGap` | `number` | `8` | Gap between bars |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n### ScLineChart\n\nLine chart visualization with optional area fill.\n\n**Selector:** `[scLineChart]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ------------ | ------------------ | ------- | ---------------------- |\n| `data` | `ChartDataPoint[]` | `[]` | Chart data |\n| `height` | `number` | `300` | Chart height in pixels |\n| `showArea` | `boolean` | `false` | Show area fill |\n| `showPoints` | `boolean` | `true` | Show data points |\n| `color` | `string` | `\'\'` | Line color |\n| `labelStep` | `number` | `1` | X-axis label interval |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n### ScPieChart\n\nPie chart visualization.\n\n**Selector:** `[scPieChart]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ------------- | ------------------ | ------- | ---------------------- |\n| `data` | `ChartDataPoint[]` | `[]` | Chart data |\n| `size` | `number` | `300` | Chart size in pixels |\n| `innerRadius` | `number` | `0` | Inner radius (0 = pie) |\n| `showLabels` | `boolean` | `true` | Show percentage labels |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n### ScDonutChart\n\nDonut chart (pie chart with hole).\n\n**Selector:** `[scDonutChart]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ------------- | ------------------ | ------- | ---------------------- |\n| `data` | `ChartDataPoint[]` | `[]` | Chart data |\n| `size` | `number` | `300` | Chart size in pixels |\n| `innerRadius` | `number` | `60` | Inner radius |\n| `showLabels` | `boolean` | `false` | Show percentage labels |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n### ScChartLegend\n\nChart legend component.\n\n**Selector:** `[scChartLegend]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ------- | ------------------------------------- | ------- | ---------------------- |\n| `items` | `{ label: string; color?: string }[]` | `[]` | Legend items |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n### ScChartTooltip\n\nReusable tooltip component.\n\n**Selector:** `[scChartTooltip]`\n\n**Methods:**\n\n| Method | Description |\n| ------------ | ------------ |\n| `show(x, y)` | Show tooltip |\n| `hide()` | Hide tooltip |\n\n## Types\n\n```typescript\ninterface ChartDataPoint {\n label: string;\n value: number;\n color?: string;\n}\n\ninterface ChartConfig {\n [key: string]: {\n label: string;\n color?: string;\n };\n}\n```\n\n## Examples\n\n### Bar Chart\n\n```html\n<div scChartContainer>\n <div scBarChart [data]="salesData" [height]="250"></div>\n</div>\n```\n\n```typescript\nsalesData = [\n { label: \'Jan\', value: 120 },\n { label: \'Feb\', value: 180 },\n { label: \'Mar\', value: 150 },\n];\n```\n\n### Line Chart\n\n```html\n<div scChartContainer>\n <div scLineChart [data]="data" [height]="250"></div>\n</div>\n```\n\n### Area Chart\n\n```html\n<div scChartContainer>\n <div scLineChart [data]="data" [height]="250" [showArea]="true"></div>\n</div>\n```\n\n### Pie Chart\n\n```html\n<div scChartContainer>\n <div scPieChart [data]="data" [size]="280"></div>\n <div scChartLegend [items]="legend"></div>\n</div>\n```\n\n### Donut Chart\n\n```html\n<div scChartContainer>\n <div scDonutChart [data]="data" [size]="280" [innerRadius]="70"></div>\n</div>\n```\n\n### With Custom Colors\n\n```typescript\ndata = [\n { label: \'Sales\', value: 120, color: \'hsl(var(--chart-1))\' },\n { label: \'Revenue\', value: 180, color: \'hsl(var(--chart-2))\' },\n];\n```\n\n## Chart Colors\n\nThe component uses CSS variables for colors:\n\n- `--chart-1` through `--chart-5`\n\nThese integrate with the shadcn theming system.\n\n## Features\n\n- **SVG-Based**: Pure SVG rendering, no external dependencies\n- **Responsive**: Charts scale to container width\n- **Tooltips**: Built-in hover tooltips\n- **Legends**: Optional legend component\n- **Grid Lines**: Automatic grid lines with labels\n- **Theming**: Uses CSS variables for colors\n- **Interactive**: Hover states on data points\n\n## Accessibility\n\n- SVG elements include appropriate ARIA attributes\n- High contrast colors for readability\n- Interactive elements have hover states\n',
|
|
30648
|
-
exports: []
|
|
30649
|
-
},
|
|
30650
|
-
{
|
|
30651
|
-
name: "color-picker",
|
|
30652
|
-
readme: '# Color Picker\n\nA component for selecting colors with support for various formats and input methods.\n\n## Usage\n\n```html\n<div scColorPicker [(value)]="color" class="space-y-4">\n <div scColorPickerArea></div>\n <div scColorPickerHue></div>\n <div class="flex items-center gap-3">\n <div scColorPickerPreview></div>\n <input scColorPickerInput format="hex" />\n </div>\n</div>\n```\n\n## Components\n\n### ScColorPicker\n\nRoot container that manages color state.\n\n**Selector:** `[scColorPicker]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ---------- | --------- | ------- | ---------------------- |\n| `disabled` | `boolean` | `false` | Disable picker |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n**Two-way Bindings:**\n\n| Binding | Type | Default | Description |\n| ------- | -------- | ----------- | --------------- |\n| `value` | `string` | `\'#000000\'` | Hex color value |\n\n**Computed Properties:**\n\n| Property | Type | Description |\n| -------- | -------- | ------------------ |\n| `hsv` | `HSV` | Current HSV values |\n| `rgb` | `RGB` | Current RGB values |\n| `hsl` | `HSL` | Current HSL values |\n| `hex` | `string` | Current hex value |\n\n**Methods:**\n\n| Method | Description |\n| ------------------ | ---------------------- |\n| `setHsv(hsv)` | Set HSV values |\n| `setRgb(rgb)` | Set RGB values |\n| `setHex(hex)` | Set hex value |\n| `setHue(h)` | Set hue (0-360) |\n| `setSaturation(s)` | Set saturation (0-100) |\n| `setValue(v)` | Set value (0-100) |\n\n### ScColorPickerArea\n\nSaturation/brightness selection area.\n\n**Selector:** `[scColorPickerArea]`\n\nFeatures mouse and touch drag support.\n\n### ScColorPickerHue\n\nHue slider (rainbow gradient).\n\n**Selector:** `[scColorPickerHue]`\n\n### ScColorPickerPreview\n\nColor preview swatch.\n\n**Selector:** `[scColorPickerPreview]`\n\n### ScColorPickerInput\n\nText input for color values.\n\n**Selector:** `input[scColorPickerInput]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| -------- | ------------------------- | ------- | -------------- |\n| `format` | `\'hex\' \\| \'rgb\' \\| \'hsl\'` | `\'hex\'` | Display format |\n| `class` | `string` | `\'\'` | Additional CSS |\n\n### ScColorPickerSwatches\n\nPreset color swatches.\n\n**Selector:** `[scColorPickerSwatches]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| -------- | ---------- | ------------------ | -------------- |\n| `colors` | `string[]` | (12 preset colors) | Swatch colors |\n| `class` | `string` | `\'\'` | Additional CSS |\n\n### ScColorPickerEyeDropper\n\nEye dropper button (Chrome/Edge only).\n\n**Selector:** `button[scColorPickerEyedropper]`\n\nUses the EyeDropper API to pick colors from the screen.\n\n## Types\n\n```typescript\ninterface HSV {\n h: number; // 0-360\n s: number; // 0-100\n v: number; // 0-100\n}\n\ninterface RGB {\n r: number; // 0-255\n g: number; // 0-255\n b: number; // 0-255\n}\n\ninterface HSL {\n h: number; // 0-360\n s: number; // 0-100\n l: number; // 0-100\n}\n```\n\n## Examples\n\n### Full Picker\n\n```html\n<div scColorPicker [(value)]="color" class="space-y-4 rounded-lg border p-4">\n <div scColorPickerArea></div>\n <div scColorPickerHue></div>\n <div class="flex items-center gap-3">\n <div scColorPickerPreview></div>\n <input scColorPickerInput format="hex" class="flex-1" />\n </div>\n</div>\n```\n\n### With Swatches\n\n```html\n<div scColorPicker [(value)]="color" class="space-y-4">\n <div scColorPickerArea></div>\n <div scColorPickerHue></div>\n <div scColorPickerSwatches></div>\n</div>\n```\n\n### With Eye Dropper\n\n```html\n<div scColorPicker [(value)]="color" class="space-y-4">\n <div scColorPickerArea></div>\n <div scColorPickerHue></div>\n <div class="flex gap-2">\n <input scColorPickerInput format="hex" class="flex-1" />\n <button scColorPickerEyedropper></button>\n </div>\n</div>\n```\n\n### Custom Swatches\n\n```html\n<div scColorPicker [(value)]="color">\n <div scColorPickerSwatches [colors]="[\'#ff0000\', \'#00ff00\', \'#0000ff\']"></div>\n</div>\n```\n\n### Simple Swatch Only\n\n```html\n<div scColorPicker [(value)]="color" class="space-y-4">\n <div scColorPickerSwatches></div>\n <div class="flex items-center gap-3">\n <div scColorPickerPreview></div>\n <span>{{ color() }}</span>\n </div>\n</div>\n```\n\n### Compact\n\n```html\n<div scColorPicker [(value)]="color" class="w-[200px] space-y-3">\n <div scColorPickerArea class="h-32"></div>\n <div scColorPickerHue></div>\n <input scColorPickerInput format="hex" />\n</div>\n```\n\n## Features\n\n- **Saturation/Brightness Area**: 2D picker for saturation and brightness\n- **Hue Slider**: Full spectrum hue selection\n- **Multiple Formats**: Hex, RGB, HSL display\n- **Preset Swatches**: Quick color selection\n- **Eye Dropper**: Pick colors from screen (Chrome/Edge)\n- **Touch Support**: Works on mobile devices\n- **Two-way Binding**: Sync color state with `[(value)]`\n\n## Accessibility\n\n- Keyboard accessible input field\n- ARIA labels on swatch buttons\n- Screen reader text for eye dropper\n- Focus indicators on interactive elements\n',
|
|
30653
|
-
exports: []
|
|
30654
|
-
},
|
|
30655
|
-
{
|
|
30656
|
-
name: "combobox",
|
|
30657
|
-
readme: '# Combobox\n\nAutocomplete input and command palette with a list of suggestions. Built on `@angular/aria` primitives using a composable, nested combobox pattern.\n\n## Architecture\n\nUses a **nested combobox** pattern:\n\n1. **Outer combobox** (`ScCombobox`, readonly) \u2014 acts as trigger, opens/closes dialog\n2. **ComboboxDialog** (inside `ScComboboxPortal`) \u2014 native `<dialog>` popup\n3. **Inner combobox** (inside `ScComboboxPortal`, `filterMode="manual"`, `alwaysExpanded`) \u2014 handles search + keyboard navigation\n4. **Listbox + Option** (`ScComboboxList` + `ScComboboxItem`) \u2014 the actual options list\n\nThe search input is **built into** `ScComboboxPortal`\'s template (not projected). This is required because the search `ComboboxInput` must be in the inner `Combobox`\'s DI context.\n\n## Components\n\n| Component | Selector | Aria Primitive | Purpose |\n| ------------------------- | ------------------------------ | -------------------------------------------------------------------------------- | --------------------------------------- |\n| `ScCombobox` | `div[scCombobox]` | `Combobox` (hostDirective, readonly) | Root container |\n| `ScComboboxTrigger` | `div[scComboboxTrigger]` | \u2014 | Styling wrapper for trigger |\n| `ScComboboxInput` | `input[scComboboxInput]` | `ComboboxInput` (hostDirective) | Invisible input (opens dropdown) |\n| `ScComboboxIcon` | `svg[scComboboxIcon]` | \u2014 | Chevron icon with rotation on expand |\n| `ScComboboxPortal` | `div[scComboboxPortal]` | `ComboboxPopupContainer` + `ComboboxDialog` + inner `Combobox` + `ComboboxInput` | Dialog popup with built-in search input |\n| `ScComboboxList` | `div[scComboboxList]` | `Listbox` (hostDirective) | Scrollable options list |\n| `ScComboboxItem` | `div[scComboboxItem]` | `Option` (hostDirective) | Individual option |\n| `ScComboboxItemIndicator` | `svg[scComboboxItemIndicator]` | \u2014 | Checkmark (visible when selected) |\n| `ScComboboxEmpty` | `div[scComboboxEmpty]` | \u2014 | Empty state message |\n\n### ScComboboxPortal\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ------------------- | -------- | ------------- | ------------------------ |\n| `searchPlaceholder` | `string` | `\'Search...\'` | Search input placeholder |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n**Two-way Bindings:**\n\n| Binding | Type | Description |\n| ------------- | -------- | -------------------------- |\n| `searchValue` | `string` | Current search/filter text |\n\n### ScComboboxList\n\nExposes from `Listbox` hostDirective:\n\n| Input/Output | Type | Description |\n| ------------ | ---------- | ------------------------- |\n| `[(values)]` | `string[]` | Selected values |\n| `[multi]` | `boolean` | Enable multiple selection |\n\n### ScComboboxItem\n\nExposes from `Option` hostDirective:\n\n| Input | Type | Description |\n| ------------ | --------- | -------------------------- |\n| `[value]` | `string` | Option value (required) |\n| `[label]` | `string` | Option label for typeahead |\n| `[disabled]` | `boolean` | Disable this option |\n\n## Usage\n\n### Single Select\n\n```html\n<div scCombobox class="w-[200px]">\n <div scComboboxTrigger>\n <span class="pointer-events-none absolute left-3 truncate">{{ displayValue() }}</span>\n <input scComboboxInput />\n <svg scComboboxIcon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">\n <path d="m7 15 5 5 5-5" />\n <path d="m7 9 5-5 5 5" />\n </svg>\n </div>\n <div scComboboxPortal searchPlaceholder="Search..." [(searchValue)]="search">\n @if (filteredOptions().length === 0) {\n <div scComboboxEmpty>No results found.</div>\n }\n <div scComboboxList [(values)]="selectedValues">\n @for (option of filteredOptions(); track option.value) {\n <div scComboboxItem [value]="option.value" [label]="option.label">\n <span>{{ option.label }}</span>\n <svg scComboboxItemIndicator xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">\n <path d="M20 6 9 17l-5-5" />\n </svg>\n </div>\n }\n </div>\n </div>\n</div>\n```\n\n```typescript\nreadonly search = signal(\'\');\nreadonly selectedValues = signal<string[]>([]);\n\nreadonly options = [\n { value: \'next\', label: \'Next.js\' },\n { value: \'angular\', label: \'Angular\' },\n];\n\nreadonly filteredOptions = computed(() => {\n const query = this.search().toLowerCase();\n if (!query) return this.options;\n return this.options.filter((o) => o.label.toLowerCase().includes(query));\n});\n\nreadonly displayValue = computed(() => {\n const vals = this.selectedValues();\n if (vals.length === 0) return \'Select...\';\n const option = this.options.find((o) => o.value === vals[0]);\n return option?.label ?? \'Select...\';\n});\n\nconstructor() {\n // Auto-close on single select + clear search\n afterRenderEffect(() => {\n if (this.selectedValues().length > 0) this.search.set(\'\');\n });\n}\n```\n\n### Multiple Selection\n\n```html\n<div scComboboxList [multi]="true" [(values)]="selectedValues">\n <!-- same item template -->\n</div>\n```\n\n### Disabled Options\n\n```html\n<div scComboboxItem [value]="option.value" [label]="option.label" [disabled]="true">\n <!-- content -->\n</div>\n```\n\n## Consumer Responsibilities\n\nThe composable API puts the consumer in control of:\n\n- **Display text** \u2014 compute from `selectedValues()` and your options array\n- **Filtering** \u2014 filter your options array using `searchValue` model\n- **Selected values** \u2014 manage via `[(values)]` on `ScComboboxList` (always `string[]`)\n- **Auto-close** \u2014 for single-select, use `afterRenderEffect` to close after selection\n\n## Features\n\n- Search/filter with built-in search input inside the dialog\n- Single and multiple selection via Listbox `multi` input\n- Disabled options via Option `disabled` input\n- Checkmark indicator for selected options\n- Full keyboard navigation via `@angular/aria` primitives\n- Dialog positioning anchored below the trigger\n\n## Accessibility\n\n- `@angular/aria` `Combobox`, `ComboboxInput`, `ComboboxDialog`, `Listbox`, and `Option` directives handle all ARIA attributes\n- Keyboard navigation (arrow keys, enter, escape) managed by aria primitives\n- Focus management between trigger and dialog\n- `aria-selected` on options, `aria-expanded` on trigger\n- Native `<dialog>` element for proper focus trapping\n',
|
|
30658
|
-
exports: []
|
|
30659
|
-
},
|
|
30660
|
-
{
|
|
30661
|
-
name: "command",
|
|
30662
|
-
readme: '# Command Components\n\nA command palette for fast, keyboard-driven navigation and actions.\n\n## Architecture\n\n```\nScCommand (Root)\n \u251C\u2500\u2500 value: model<string> (search query)\n \u2502\n \u251C\u2500\u2500 ScCommandInput (search input with icon)\n \u2502\n \u2514\u2500\u2500 ScCommandList (scrollable results)\n \u2502\n \u251C\u2500\u2500 ScCommandEmpty (shown when no results)\n \u2502\n \u251C\u2500\u2500 ScCommandGroup\n \u2502 \u251C\u2500\u2500 ScCommandGroupHeading\n \u2502 \u251C\u2500\u2500 ScCommandItem\n \u2502 \u2502 \u2514\u2500\u2500 ScCommandShortcut\n \u2502 \u2514\u2500\u2500 ScCommandItem\n \u2502\n \u251C\u2500\u2500 ScCommandSeparator\n \u2502\n \u2514\u2500\u2500 ScCommandGroup\n \u2514\u2500\u2500 ...\n```\n\n## Components\n\n| Component | Selector | Description |\n| ----------------------- | ------------------------- | ------------------------------ |\n| `ScCommand` | `div[scCommand]` | Root wrapper with search state |\n| `ScCommandInput` | `div[scCommandInput]` | Search input with icon |\n| `ScCommandList` | `div[scCommandList]` | Scrollable results container |\n| `ScCommandEmpty` | `div[scCommandEmpty]` | Shown when no results match |\n| `ScCommandGroup` | `div[scCommandGroup]` | Group of related items |\n| `ScCommandGroupHeading` | `[scCommandGroupHeading]` | Group heading text |\n| `ScCommandItem` | `div[scCommandItem]` | Individual command item |\n| `ScCommandSeparator` | `[scCommandSeparator]` | Visual separator |\n| `ScCommandShortcut` | `[scCommandShortcut]` | Keyboard shortcut display |\n\n## Inputs\n\n### ScCommandInput\n\n| Input | Type | Default | Description |\n| ------------- | -------- | ------------- | ---------------------- |\n| `placeholder` | `string` | `\'Search...\'` | Input placeholder text |\n\n### ScCommandItem\n\n| Input | Type | Default | Description |\n| ---------- | ---------- | ------- | ------------------------------ |\n| `value` | `string` | `\'\'` | Searchable value for filtering |\n| `keywords` | `string[]` | `[]` | Additional search keywords |\n| `disabled` | `boolean` | `false` | Whether item is disabled |\n| `selected` | `boolean` | `false` | Whether item is selected |\n\n## Outputs\n\n### ScCommandItem\n\n| Output | Type | Description |\n| -------- | ------ | ---------------------------- |\n| `select` | `void` | Emitted when item is clicked |\n\n## Usage\n\n### Basic Command\n\n```html\n<div scCommand class="rounded-lg border shadow-md">\n <div scCommandInput placeholder="Type a command..." />\n <div scCommandList>\n <div scCommandEmpty>No results found.</div>\n <div scCommandGroup>\n <span scCommandGroupHeading>Actions</span>\n <div scCommandItem value="new file" (select)="newFile()">\n <svg>...</svg>\n <span>New File</span>\n <span scCommandShortcut>\u2318N</span>\n </div>\n <div scCommandItem value="open file" (select)="openFile()">\n <svg>...</svg>\n <span>Open File</span>\n <span scCommandShortcut>\u2318O</span>\n </div>\n </div>\n </div>\n</div>\n```\n\n### With Multiple Groups\n\n```html\n<div scCommandList>\n <div scCommandGroup>\n <span scCommandGroupHeading>Suggestions</span>\n <div scCommandItem value="calendar">Calendar</div>\n <div scCommandItem value="calculator">Calculator</div>\n </div>\n <div scCommandSeparator></div>\n <div scCommandGroup>\n <span scCommandGroupHeading>Settings</span>\n <div scCommandItem value="profile">Profile</div>\n <div scCommandItem value="billing">Billing</div>\n </div>\n</div>\n```\n\n### With Keywords for Better Search\n\n```html\n<div scCommandItem value="profile" [keywords]="[\'account\', \'user\', \'settings\']" (select)="goToProfile()">Profile</div>\n```\n\nItems will match if the search query matches either the `value` or any of the `keywords`.\n\n### In a Dialog\n\n```html\n<div scDialogProvider [(open)]="open">\n <ng-template scDialogPortal>\n <div scDialog class="p-0">\n <div scCommand>\n <div scCommandInput />\n <div scCommandList>\n <!-- items -->\n </div>\n </div>\n </div>\n </ng-template>\n</div>\n```\n\n## Features\n\n- **Real-time filtering**: Items filter as you type\n- **Keyword search**: Match by value or additional keywords\n- **Groups**: Organize items into logical groups\n- **Keyboard shortcuts**: Display shortcuts with `sc-command-shortcut`\n- **Empty state**: Show message when no results\n- **Scrollable list**: Fixed height with overflow scroll\n\n## Accessibility\n\n- Uses `role="listbox"` on the list\n- Uses `role="option"` on items\n- Uses `role="group"` on groups\n- Uses `role="separator"` on separators\n- `data-disabled` and `data-selected` attributes\n\n## Styling\n\nThe components use Tailwind CSS with shadcn/ui design tokens:\n\n- Container: `bg-popover text-popover-foreground rounded-md`\n- Input: `border-b` separator with search icon\n- Items: `hover:bg-accent` on hover, icons sized to `size-4`\n- Shortcuts: `text-muted-foreground text-xs`\n',
|
|
30663
|
-
exports: []
|
|
30664
|
-
},
|
|
30665
|
-
{
|
|
30666
|
-
name: "confetti",
|
|
30667
|
-
readme: "# Confetti\n\nA celebration animation effect with customizable particles for showing success or celebration moments.\n\n## Installation\n\n```typescript\nimport { ScConfetti } from '@/ui/confetti';\nimport type { ConfettiOptions, ConfettiParticle, ConfettiShape } from '@/ui/confetti';\n```\n\n## Usage\n\n### Basic Usage\n\n```html\n<sc-confetti #confetti (complete)=\"onComplete()\" />\n\n<button (click)=\"confetti.fire()\">Fire Confetti!</button>\n```\n\n### With Custom Options\n\n```typescript\nconfetti.fire({\n particleCount: 100,\n spread: 70,\n colors: ['#ff0000', '#00ff00', '#0000ff'],\n origin: { x: 0.5, y: 0.5 },\n});\n```\n\n### Fire from Element\n\n```typescript\n@ViewChild('celebrateBtn') celebrateBtn!: ElementRef;\n\nfireFromButton(): void {\n this.confetti.fireFromElement(this.celebrateBtn.nativeElement, {\n particleCount: 50,\n spread: 60,\n });\n}\n```\n\n### Multiple Bursts\n\n```typescript\n// Fire from multiple origins\nconfetti.fire({ origin: { x: 0.3, y: 0.6 }, particleCount: 50 });\nconfetti.fire({ origin: { x: 0.7, y: 0.6 }, particleCount: 50 });\n```\n\n## API Reference\n\n### Inputs\n\n| Input | Type | Default | Description |\n| --------- | ----------------- | ------- | ------------------------ |\n| `options` | `ConfettiOptions` | `{}` | Default confetti options |\n\n### Outputs\n\n| Output | Type | Description |\n| ---------- | ------ | -------------------------------- |\n| `complete` | `void` | Emitted when animation completes |\n\n### Methods\n\n| Method | Description |\n| ------------------------------------ | ------------------------------- |\n| `fire(options?)` | Fire confetti with options |\n| `fireFromElement(element, options?)` | Fire from specific element |\n| `stop()` | Stop animation and clear canvas |\n\n## Type Definitions\n\n```typescript\ninterface ConfettiOptions {\n particleCount?: number; // Number of particles (default: 100)\n spread?: number; // Spread angle in degrees (default: 70)\n startVelocity?: number; // Initial velocity (default: 30)\n decay?: number; // Velocity decay rate (default: 0.94)\n gravity?: number; // Gravity effect (default: 1)\n drift?: number; // Horizontal drift (default: 0)\n colors?: string[]; // Particle colors\n shapes?: ConfettiShape[]; // Particle shapes\n origin?: { x: number; y: number }; // Origin point (0-1)\n duration?: number; // Animation duration in ms (default: 3000)\n}\n\ntype ConfettiShape = 'square' | 'circle' | 'triangle' | 'ribbon';\n```\n\n## Features\n\n- Canvas-based particle animation\n- Customizable particle count, colors, and shapes\n- Adjustable spread, velocity, and gravity\n- Fire from specific elements or custom origins\n- Multiple simultaneous bursts support\n- Automatic cleanup on completion\n- Responsive canvas sizing\n",
|
|
30668
|
-
exports: []
|
|
30669
|
-
},
|
|
30670
|
-
{
|
|
30671
|
-
name: "context-menu",
|
|
30672
|
-
readme: '# Context Menu Components\n\nDisplays a menu at the pointer position when triggered by a right-click.\n\n## Architecture\n\n```\nScContextMenu (Root)\n \u251C\u2500\u2500 open: signal<boolean>\n \u251C\u2500\u2500 position: signal<{x, y}>\n \u2502\n \u251C\u2500\u2500 ScContextMenuTrigger (wraps any element)\n \u2502 \u2514\u2500\u2500 Listens to contextmenu event\n \u2502\n \u2514\u2500\u2500 ScContextMenuContent (ng-template)\n \u251C\u2500\u2500 Uses CDK Overlay at mouse position\n \u2502\n \u251C\u2500\u2500 ScContextMenuLabel\n \u251C\u2500\u2500 ScContextMenuItem\n \u2502 \u2514\u2500\u2500 ScContextMenuShortcut\n \u251C\u2500\u2500 ScContextMenuSeparator\n \u2502\n \u2514\u2500\u2500 ScContextMenuSub\n \u251C\u2500\u2500 ScContextMenuSubTrigger\n \u2514\u2500\u2500 ScContextMenuSubContent\n```\n\n## Components\n\n| Component | Selector | Description |\n| ------------------------- | ------------------------------ | ------------------------------------ |\n| `ScContextMenu` | `div[scContextMenu]` | Root wrapper with overlay management |\n| `ScContextMenuTrigger` | `[scContextMenuTrigger]` | Element that triggers on right-click |\n| `ScContextMenuContent` | `<sc-context-menu-content>` | Menu content container |\n| `ScContextMenuItem` | `[scContextMenuItem]` | Individual menu item |\n| `ScContextMenuLabel` | `[scContextMenuLabel]` | Label for grouping items |\n| `ScContextMenuSeparator` | `[scContextMenuSeparator]` | Visual separator |\n| `ScContextMenuShortcut` | `[scContextMenuShortcut]` | Keyboard shortcut display |\n| `ScContextMenuSub` | `div[scContextMenuSub]` | Submenu wrapper |\n| `ScContextMenuSubTrigger` | `div[scContextMenuSubTrigger]` | Submenu trigger |\n| `ScContextMenuSubContent` | `div[scContextMenuSubContent]` | Submenu content |\n\n## Usage\n\n### Basic Context Menu\n\n```html\n<div scContextMenu>\n <div scContextMenuTrigger class="h-32 w-64 border border-dashed">Right click here</div>\n\n <sc-context-menu-content>\n <div scContextMenuItem (select)="onCut()">\n Cut\n <span scContextMenuShortcut>\u2318X</span>\n </div>\n <div scContextMenuItem (select)="onCopy()">\n Copy\n <span scContextMenuShortcut>\u2318C</span>\n </div>\n <div scContextMenuItem (select)="onPaste()">\n Paste\n <span scContextMenuShortcut>\u2318V</span>\n </div>\n </sc-context-menu-content>\n</div>\n```\n\n### With Labels and Separators\n\n```html\n<sc-context-menu-content>\n <span scContextMenuLabel>Edit</span>\n <div scContextMenuSeparator></div>\n <div scContextMenuItem>Cut</div>\n <div scContextMenuItem>Copy</div>\n <div scContextMenuItem>Paste</div>\n</sc-context-menu-content>\n```\n\n### With Submenu\n\n```html\n<sc-context-menu-content>\n <div scContextMenuItem>Back</div>\n <div scContextMenuItem>Forward</div>\n\n <div scContextMenuSub>\n <div scContextMenuSubTrigger>More Tools</div>\n <div scContextMenuSubContent>\n <div scContextMenuItem>Save Page As...</div>\n <div scContextMenuItem>Create Shortcut...</div>\n <div scContextMenuItem>Developer Tools</div>\n </div>\n </div>\n</sc-context-menu-content>\n```\n\n### With Disabled Items\n\n```html\n<div scContextMenuItem [disabled]="true">Disabled Item</div>\n```\n\n## Inputs\n\n### ScContextMenuItem\n\n| Input | Type | Default | Description |\n| --------------- | --------- | ------- | ------------------------------- |\n| `disabled` | `boolean` | `false` | Whether the item is disabled |\n| `closeOnSelect` | `boolean` | `true` | Whether to close menu on select |\n\n### ScContextMenuLabel\n\n| Input | Type | Default | Description |\n| ------- | --------- | ------- | ------------------------------------ |\n| `inset` | `boolean` | `false` | Add left padding to align with items |\n\n## Outputs\n\n### ScContextMenuItem\n\n| Output | Type | Description |\n| -------- | ------ | ----------------------------- |\n| `select` | `void` | Emitted when item is selected |\n\n## Features\n\n- **Right-click triggered**: Opens at mouse cursor position\n- **Backdrop dismiss**: Clicking outside closes the menu\n- **Escape key**: Closes the menu\n- **Submenu support**: Nested menus with hover trigger\n- **Keyboard shortcuts**: Display keyboard shortcuts with `sc-context-menu-shortcut`\n- **Disabled items**: Support for disabled menu items\n\n## Accessibility\n\n- Uses `role="menu"` and `role="menuitem"`\n- `aria-haspopup` and `aria-expanded` on submenu triggers\n- `tabindex="-1"` on menu items for focus management\n- Escape key closes the menu\n\n## Differences from Regular Menu\n\n| Feature | Context Menu | Menu |\n| -------- | ------------------ | ------------------- |\n| Trigger | Right-click | Click on button |\n| Position | At mouse cursor | Attached to trigger |\n| Use case | Contextual actions | Dropdown menus |\n',
|
|
30673
|
-
exports: []
|
|
30674
|
-
},
|
|
30675
|
-
{
|
|
30676
|
-
name: "copy-button",
|
|
30677
|
-
readme: '# Copy Button\n\nA button component that copies text to clipboard with visual feedback.\n\n## Usage\n\n```html\n<button scCopyButton [value]="textToCopy"></button>\n```\n\n## Components\n\n### ScCopyButton\n\nCore copy button with icon and feedback animation.\n\n**Selector:** `button[scCopyButton]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ---------- | ------------------------------------- | --------- | ---------------------- |\n| `value` | `string` | Required | Text to copy |\n| `disabled` | `boolean` | `false` | Disabled state |\n| `timeout` | `number` | `2000` | Feedback duration (ms) |\n| `variant` | `\'default\' \\| \'ghost\' \\| \'outline\'` | `\'ghost\'` | Visual style |\n| `size` | `\'sm\' \\| \'default\' \\| \'lg\' \\| \'icon\'` | `\'icon\'` | Button size |\n| `class` | `string` | `\'\'` | Additional CSS |\n\n**Outputs:**\n\n| Output | Type | Description |\n| ------------- | -------- | --------------------- |\n| `copySuccess` | `string` | Emits copied value |\n| `copyError` | `Error` | Emits on copy failure |\n\n**Methods:**\n\n| Method | Description |\n| --------- | --------------------- |\n| `copy()` | Trigger copy manually |\n| `reset()` | Reset copied state |\n\n### ScCopyButtonWithText\n\nCopy button with text label.\n\n**Selector:** `[scCopyButtonWithText]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ------------ | ----------------------------------- | ----------- | ----------------- |\n| `value` | `string` | Required | Text to copy |\n| `disabled` | `boolean` | `false` | Disabled state |\n| `timeout` | `number` | `2000` | Feedback duration |\n| `variant` | `\'default\' \\| \'ghost\' \\| \'outline\'` | `\'default\'` | Visual style |\n| `size` | `\'sm\' \\| \'default\' \\| \'lg\'` | `\'default\'` | Button size |\n| `copyText` | `string` | `\'Copy\'` | Text before copy |\n| `copiedText` | `string` | `\'Copied!\'` | Text after copy |\n\n### ScCopyInput\n\nInput field with integrated copy button.\n\n**Selector:** `[scCopyInput]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ---------- | --------- | -------- | --------------------- |\n| `value` | `string` | Required | Value to display/copy |\n| `readonly` | `boolean` | `true` | Input readonly state |\n| `class` | `string` | `\'\'` | Additional CSS |\n\n### ScCopyCode\n\nCode block with copy button.\n\n**Selector:** `[scCopyCode]`\n\n**Inputs:**\n\n| Input | Type | Required | Description |\n| ------- | -------- | -------- | -------------- |\n| `value` | `string` | Yes | Code to copy |\n| `class` | `string` | No | Additional CSS |\n\n## Examples\n\n### Basic\n\n```html\n<button scCopyButton [value]="\'Hello, World!\'"></button>\n```\n\n### With Event Handler\n\n```html\n<button scCopyButton [value]="text" (copySuccess)="onCopied($event)" (copyError)="onError($event)"></button>\n```\n\n### Variants\n\n```html\n<button scCopyButton [value]="text" variant="ghost"></button>\n<button scCopyButton [value]="text" variant="outline"></button>\n<button scCopyButton [value]="text" variant="default"></button>\n```\n\n### Sizes\n\n```html\n<button scCopyButton [value]="text" size="sm"></button>\n<button scCopyButton [value]="text" size="default"></button>\n<button scCopyButton [value]="text" size="lg"></button>\n<button scCopyButton [value]="text" size="icon"></button>\n```\n\n### With Text Label\n\n```html\n<div scCopyButtonWithText [value]="\'Copy this text\'"></div>\n\n<div scCopyButtonWithText [value]="shareLink" copyText="Copy Link" copiedText="Link Copied!"></div>\n```\n\n### Copy Input\n\n```html\n<div scCopyInput [value]="\'https://example.com/share/abc123\'"></div>\n\n<div>\n <label>API Key</label>\n <div scCopyInput [value]="apiKey"></div>\n</div>\n```\n\n### Copy Code Block\n\n```html\n<div scCopyCode [value]="codeSnippet">{{ codeSnippet }}</div>\n```\n\n### Inline with Text\n\n```html\n<div class="flex items-center gap-2 rounded-md border px-3 py-2">\n <code class="flex-1">npm install package</code>\n <button scCopyButton [value]="\'npm install package\'" size="sm"></button>\n</div>\n```\n\n### Custom Timeout\n\n```html\n<button scCopyButton [value]="text" [timeout]="5000">Copy (5s feedback)</button>\n```\n\n### Disabled\n\n```html\n<button scCopyButton [value]="text" [disabled]="true"></button>\n```\n\n### Share URL Pattern\n\n```html\n<div class="flex items-center gap-2">\n <input [value]="shareUrl" readonly class="flex-1 rounded border px-3 py-2" />\n <button scCopyButton [value]="shareUrl" variant="outline"></button>\n</div>\n```\n\n### Color Code Pattern\n\n```html\n<div class="flex items-center gap-3">\n <div class="size-10 rounded-md" [style.background]="color"></div>\n <span class="flex-1">{{ color }}</span>\n <button scCopyButton [value]="color" variant="ghost"></button>\n</div>\n```\n\n### Promo Code Pattern\n\n```html\n<div class="flex items-center justify-between">\n <code class="text-2xl font-bold">SAVE20</code>\n <button scCopyButton [value]="\'SAVE20\'" variant="outline">Copy Code</button>\n</div>\n```\n\n## Features\n\n- **Clipboard API**: Uses modern `navigator.clipboard.writeText()`\n- **Visual Feedback**: Icon changes to checkmark on success\n- **Configurable Timeout**: Control how long feedback shows\n- **Multiple Variants**: Ghost, outline, and default styles\n- **Multiple Sizes**: Small, default, large, and icon-only\n- **Convenience Components**: Input, code block, and text label wrappers\n- **Events**: Success and error callbacks\n- **Programmatic Control**: `copy()` and `reset()` methods\n\n## Accessibility\n\n- `aria-label` updates based on state\n- `data-copied` attribute for styling\n- Focus visible indicators\n- Disabled state support\n- Proper button semantics\n',
|
|
30678
|
-
exports: []
|
|
30679
|
-
},
|
|
30680
|
-
{
|
|
30681
|
-
name: "countdown",
|
|
30682
|
-
readme: '# Countdown\n\nCountdown timer with multiple variants, customizable labels, and completion events.\n\n## Components\n\n- `ScCountdown` - Full countdown display with days, hours, minutes, seconds\n- `ScCountdownSimple` - Inline countdown text\n\n## Usage\n\n### Basic Countdown\n\n```html\n<sc-countdown [targetDate]="futureDate" (complete)="onComplete()" />\n```\n\n### Simple Countdown\n\n```html\n<sc-countdown-simple [targetDate]="futureDate" format="hh:mm:ss" />\n```\n\n### Cards Variant\n\n```html\n<sc-countdown [targetDate]="futureDate" variant="cards" />\n```\n\n## API\n\n### ScCountdown\n\n| Input | Type | Default | Description |\n| ---------------- | ----------------------------------- | ----------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n| `targetDate` | `Date` | - | **Required.** End date |\n| `autoStart` | `boolean` | `true` | Start automatically |\n| `showDays` | `boolean` | `true` | Show days unit |\n| `showHours` | `boolean` | `true` | Show hours unit |\n| `showMinutes` | `boolean` | `true` | Show minutes unit |\n| `showSeconds` | `boolean` | `true` | Show seconds unit |\n| `alwaysShowDays` | `boolean` | `false` | Show days even if 0 |\n| `showSeparator` | `boolean` | `true` | Show separators |\n| `separator` | `string` | `\':\'` | Separator character |\n| `daysLabel` | `string` | `\'Days\'` | Days label text |\n| `hoursLabel` | `string` | `\'Hours\'` | Hours label text |\n| `minutesLabel` | `string` | `\'Minutes\'` | Minutes label text |\n| `secondsLabel` | `string` | `\'Seconds\'` | Seconds label text |\n| `variant` | `\'default\' \\| \'compact\' \\| \'cards\'` | `\'default\'` | Visual variant |\n\n| Output | Type | Description |\n| ---------- | --------------- | ------------------------- |\n| `tick` | `CountdownTime` | Emits every second |\n| `complete` | `void` | Emits when countdown ends |\n\n| Method | Returns | Description |\n| ------------- | --------------- | ----------------------- |\n| `start()` | `void` | Start the countdown |\n| `stop()` | `void` | Stop the countdown |\n| `reset()` | `void` | Reset to initial time |\n| `getTime()` | `CountdownTime` | Get current time values |\n| `isRunning()` | `boolean` | Check if running |\n\n### ScCountdownSimple\n\n| Input | Type | Default | Description |\n| ------------ | --------------------------------- | ------------ | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n| `targetDate` | `Date` | - | **Required.** End date |\n| `format` | `\'hh:mm:ss\' \\| \'mm:ss\' \\| \'full\'` | `\'hh:mm:ss\'` | Display format |\n| `autoStart` | `boolean` | `true` | Start automatically |\n\n| Output | Type | Description |\n| ---------- | -------- | ------------------------- |\n| `tick` | `number` | Emits remaining ms |\n| `complete` | `void` | Emits when countdown ends |\n\n| Method | Returns | Description |\n| ---------------- | -------- | ------------------- |\n| `start()` | `void` | Start the countdown |\n| `stop()` | `void` | Stop the countdown |\n| `getRemaining()` | `number` | Get remaining ms |\n\n## CountdownTime Interface\n\n```typescript\ninterface CountdownTime {\n days: number;\n hours: number;\n minutes: number;\n seconds: number;\n total: number; // Total milliseconds remaining\n}\n```\n\n## Variants\n\n| Variant | Description |\n| --------- | ----------------------------- |\n| `default` | Large numbers with labels |\n| `compact` | Smaller, space-efficient |\n| `cards` | Each unit in a card container |\n\n## Format Options (Simple)\n\n| Format | Example Output | Description |\n| ---------- | -------------- | ------------------------- |\n| `hh:mm:ss` | `02:30:45` | Hours, minutes, seconds |\n| `mm:ss` | `150:45` | Total minutes and seconds |\n| `full` | `2d 02:30:45` | Days prefix when > 0 |\n\n## Examples\n\n### Product Launch\n\n```html\n<div class="text-center">\n <h2>Coming Soon</h2>\n <sc-countdown [targetDate]="launchDate" variant="cards" daysLabel="DAYS" hoursLabel="HRS" minutesLabel="MIN" secondsLabel="SEC" (complete)="showLaunch()" />\n</div>\n```\n\n### Flash Sale\n\n```html\n<div class="sale-banner">\n <span>Sale ends in:</span>\n <sc-countdown-simple [targetDate]="saleEndDate" format="hh:mm:ss" class="font-bold" />\n</div>\n```\n\n### Event Timer\n\n```typescript\n@Component({\n template: `\n <sc-countdown #timer [targetDate]="eventDate" [autoStart]="false" (complete)="onEventStart()" />\n <button (click)="timer.start()">Start</button>\n <button (click)="timer.stop()">Pause</button>\n `,\n})\nexport class EventTimer {\n eventDate = new Date(\'2024-12-31T23:59:59\');\n\n onEventStart() {\n console.log(\'Happy New Year!\');\n }\n}\n```\n\n### Quiz Timer\n\n```html\n<sc-countdown-simple [targetDate]="quizEndTime" format="mm:ss" class="text-xl" (complete)="submitQuiz()" />\n```\n\n### Custom Labels\n\n```html\n<sc-countdown [targetDate]="date" daysLabel="D" hoursLabel="H" minutesLabel="M" secondsLabel="S" />\n```\n\n## Accessibility\n\n- Container has `role="timer"` for screen readers\n- Dynamic `aria-label` with human-readable time remaining\n- Updates announce remaining time contextually\n',
|
|
30683
|
-
exports: []
|
|
30684
|
-
},
|
|
30685
|
-
{
|
|
30686
|
-
name: "data-table",
|
|
30687
|
-
readme: '# Data Table\n\nAdvanced table component with sorting, filtering, column visibility, row selection, and pagination.\n\n## Usage\n\n```html\n<div scDataTable [data]="data" [columns]="columns">\n <input scDataTableFilter placeholder="Search..." />\n <div scDataTableColumnToggle></div>\n\n <table>\n <thead scDataTableHeader>\n <tr>\n <th scDataTableHead columnId="name" [sortable]="true">Name</th>\n <th scDataTableHead columnId="email" [sortable]="true">Email</th>\n </tr>\n </thead>\n <tbody scDataTableBody>\n @for (row of data; track row.id) {\n <tr scDataTableRow>\n <td scDataTableCell>{{ row.name }}</td>\n <td scDataTableCell>{{ row.email }}</td>\n </tr>\n }\n </tbody>\n </table>\n\n <div scDataTablePagination></div>\n</div>\n```\n\n## Components\n\n### ScDataTable\n\nRoot container that manages table state and provides context.\n\n**Selector:** `[scDataTable]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| --------- | ---------------- | ------- | ------------------ |\n| `data` | `T[]` | `[]` | Data array |\n| `columns` | `ColumnDef<T>[]` | `[]` | Column definitions |\n| `class` | `string` | `\'\'` | Additional CSS |\n\n**Two-way Bindings:**\n\n| Binding | Type | Default | Description |\n| ------------------ | ----------------------- | ----------- | --------------------- |\n| `sorting` | `SortingState \\| null` | `null` | Current sort state |\n| `columnVisibility` | `ColumnVisibilityState` | `{}` | Column visibility map |\n| `globalFilter` | `string` | `\'\'` | Global filter value |\n| `rowSelection` | `Set<number>` | `new Set()` | Selected row indices |\n\n**Outputs:**\n\n| Output | Type | Description |\n| -------------- | ---------------------- | ---------------------- |\n| `sortChange` | `SortingState \\| null` | Emits on sort change |\n| `filterChange` | `string` | Emits on filter change |\n\n**Computed Properties:**\n\n- `visibleColumns` - Columns filtered by visibility\n- `filteredData` - Data filtered by global filter\n- `sortedData` - Data sorted by current sort state\n\n### ScDataTableHeader\n\nTable header container.\n\n**Selector:** `[scDataTableHeader]`\n\n### ScDataTableBody\n\nTable body container.\n\n**Selector:** `[scDataTableBody]`\n\n### ScDataTableRow\n\nTable row with selection state.\n\n**Selector:** `[scDataTableRow]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ---------- | --------- | ------- | --------------- |\n| `selected` | `boolean` | `false` | Selection state |\n| `class` | `string` | `\'\'` | Additional CSS |\n\n### ScDataTableHead\n\nTable header cell with optional sorting.\n\n**Selector:** `[scDataTableHead]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ---------- | --------- | ------- | --------------------- |\n| `columnId` | `string` | `\'\'` | Column ID for sorting |\n| `sortable` | `boolean` | `false` | Enable sorting |\n| `class` | `string` | `\'\'` | Additional CSS |\n\n### ScDataTableCell\n\nTable data cell.\n\n**Selector:** `[scDataTableCell]`\n\n### ScDataTableFilter\n\nGlobal filter input.\n\n**Selector:** `input[scDataTableFilter]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ------------- | -------- | ------------- | ----------------- |\n| `placeholder` | `string` | `\'Filter...\'` | Input placeholder |\n| `class` | `string` | `\'\'` | Additional CSS |\n\n### ScDataTableColumnToggle\n\nDropdown to toggle column visibility.\n\n**Selector:** `[scDataTableColumnToggle]`\n\n### ScDataTablePagination\n\nPagination controls with page size selector.\n\n**Selector:** `[scDataTablePagination]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| --------------- | ---------- | ---------------------- | -------------------- |\n| `pageSizes` | `number[]` | `[10, 20, 30, 40, 50]` | Page size options |\n| `showSelection` | `boolean` | `true` | Show selection count |\n| `class` | `string` | `\'\'` | Additional CSS |\n\n**Two-way Bindings:**\n\n| Binding | Type | Default | Description |\n| ------------- | -------- | ------- | -------------- |\n| `pageSize` | `number` | `10` | Items per page |\n| `currentPage` | `number` | `1` | Current page |\n\n## Types\n\n### ColumnDef<T>\n\n```typescript\ninterface ColumnDef<T> {\n id: string;\n header: string;\n accessorKey?: keyof T;\n accessorFn?: (row: T) => unknown;\n cell?: (row: T) => string;\n enableSorting?: boolean;\n enableHiding?: boolean;\n sortingFn?: (a: T, b: T, direction: SortDirection) => number;\n}\n```\n\n### SortingState\n\n```typescript\ninterface SortingState {\n id: string;\n desc: boolean;\n}\n```\n\n### ColumnVisibilityState\n\n```typescript\ninterface ColumnVisibilityState {\n [columnId: string]: boolean;\n}\n```\n\n## Examples\n\n### Basic Table\n\n```html\n<div scDataTable [data]="users" [columns]="columns">\n <table>\n <thead scDataTableHeader>\n <tr>\n <th scDataTableHead>Name</th>\n <th scDataTableHead>Email</th>\n </tr>\n </thead>\n <tbody scDataTableBody>\n @for (user of users; track user.id) {\n <tr scDataTableRow>\n <td scDataTableCell>{{ user.name }}</td>\n <td scDataTableCell>{{ user.email }}</td>\n </tr>\n }\n </tbody>\n </table>\n</div>\n```\n\n### With Sorting\n\n```html\n<div #table scDataTable [data]="users" [columns]="columns">\n <table>\n <thead scDataTableHeader>\n <tr>\n <th scDataTableHead columnId="name" [sortable]="true">Name</th>\n <th scDataTableHead columnId="email" [sortable]="true">Email</th>\n </tr>\n </thead>\n <tbody scDataTableBody>\n @for (user of table.sortedData(); track user.id) {\n <tr scDataTableRow>\n <td scDataTableCell>{{ user.name }}</td>\n <td scDataTableCell>{{ user.email }}</td>\n </tr>\n }\n </tbody>\n </table>\n</div>\n```\n\n### With Filtering\n\n```html\n<div #table scDataTable [data]="users" [columns]="columns">\n <input scDataTableFilter placeholder="Search users..." />\n\n <table>\n <thead scDataTableHeader>\n <tr>\n <th scDataTableHead>Name</th>\n <th scDataTableHead>Email</th>\n </tr>\n </thead>\n <tbody scDataTableBody>\n @for (user of table.filteredData(); track user.id) {\n <tr scDataTableRow>\n <td scDataTableCell>{{ user.name }}</td>\n <td scDataTableCell>{{ user.email }}</td>\n </tr>\n } @empty {\n <tr>\n <td colspan="2" class="text-center">No results found.</td>\n </tr>\n }\n </tbody>\n </table>\n</div>\n```\n\n### With Row Selection\n\n```html\n<div #table scDataTable [data]="users" [columns]="columns">\n <table>\n <thead scDataTableHeader>\n <tr>\n <th scDataTableHead>\n <input type="checkbox" [checked]="table.isAllRowsSelected()" [indeterminate]="table.isSomeRowsSelected()" (change)="table.toggleAllRowSelection()" />\n </th>\n <th scDataTableHead>Name</th>\n </tr>\n </thead>\n <tbody scDataTableBody>\n @for (user of table.sortedData(); track user.id; let i = $index) {\n <tr scDataTableRow [selected]="table.isRowSelected(i)">\n <td scDataTableCell>\n <input type="checkbox" [checked]="table.isRowSelected(i)" (change)="table.toggleRowSelection(i)" />\n </td>\n <td scDataTableCell>{{ user.name }}</td>\n </tr>\n }\n </tbody>\n </table>\n</div>\n```\n\n### With Column Visibility\n\n```html\n<div scDataTable [data]="users" [columns]="columns">\n <div scDataTableColumnToggle></div>\n <!-- ... -->\n</div>\n```\n\n### With Pagination\n\n```html\n<div scDataTable [data]="users" [columns]="columns">\n <!-- ... table ... -->\n\n <div scDataTablePagination [(pageSize)]="pageSize" [(currentPage)]="currentPage" [pageSizes]="[5, 10, 25, 50]"></div>\n</div>\n```\n\n## Features\n\n- **Sorting**: Click column headers to sort ascending/descending\n- **Filtering**: Global text search across all columns\n- **Column Visibility**: Show/hide columns dynamically\n- **Row Selection**: Single and bulk selection with indeterminate state\n- **Pagination**: Configurable page sizes with navigation controls\n- **Custom Rendering**: Use accessorFn for computed values, cell for custom display\n- **Custom Sorting**: Provide sortingFn for custom sort logic\n- **Generic Types**: Full TypeScript support with generic data types\n\n## Accessibility\n\n- Proper table semantics with `<table>`, `<thead>`, `<tbody>`\n- Sortable columns indicate direction with icons\n- Checkboxes have proper focus states\n- Keyboard navigation supported for interactive elements\n- Selected rows indicated with `data-selected` attribute\n',
|
|
30688
|
-
exports: []
|
|
30689
|
-
},
|
|
30690
|
-
{
|
|
30691
|
-
name: "date-range-picker",
|
|
30692
|
-
readme: '# Date Range Picker\n\nSelect a range of dates with presets, min/max constraints, and various display formats.\n\n## Components\n\n- `ScDateRangePicker` - Date range picker with calendar dropdown\n\n## Usage\n\n### Basic Usage\n\n```html\n<sc-date-range-picker [(value)]="dateRange" placeholder="Select date range" />\n```\n\n### With Presets\n\n```html\n<sc-date-range-picker [(value)]="dateRange" [presets]="presets" placeholder="Select date range" />\n```\n\n```typescript\nimport { createDateRangePresets } from \'./date-range-picker\';\n\npresets = createDateRangePresets();\n```\n\n### With Min/Max Dates\n\n```html\n<sc-date-range-picker [minDate]="minDate" [maxDate]="maxDate" placeholder="Select date range" />\n```\n\n## API\n\n### ScDateRangePicker\n\n| Input | Type | Default | Description |\n| --------------- | ------------------- | --------------------- | ----------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n| `placeholder` | `string` | `\'Select date range\'` | Placeholder text |\n| `disabled` | `boolean` | `false` | Disable the picker |\n| `minDate` | `Date \\| undefined` | `undefined` | Minimum selectable date |\n| `maxDate` | `Date \\| undefined` | `undefined` | Maximum selectable date |\n| `disabledDates` | `Date[]` | `[]` | Specific disabled dates |\n| `presets` | `DateRangePreset[]` | `[]` | Quick selection presets |\n| `showTwoMonths` | `boolean` | `false` | Show two calendars |\n| `showClear` | `boolean` | `true` | Show clear button |\n| `dateFormat` | `string` | `\'short\'` | Date display format |\n\n| Output | Type | Description |\n| ------------- | ----------- | --------------------------- |\n| `value` | `DateRange` | Two-way binding for range |\n| `valueChange` | `DateRange` | Emits when range changes |\n| `apply` | `DateRange` | Emits when Apply is clicked |\n\n| Method | Returns | Description |\n| ------------ | ----------- | ----------------- |\n| `focus()` | `void` | Focus the trigger |\n| `getRange()` | `DateRange` | Get current range |\n\n## DateRange Interface\n\n```typescript\ninterface DateRange {\n from: Date | undefined;\n to: Date | undefined;\n}\n```\n\n## DateRangePreset Interface\n\n```typescript\ninterface DateRangePreset {\n label: string;\n value: DateRange;\n}\n```\n\n## Date Formats\n\n| Format | Example Output | Description |\n| ------- | ------------------ | ----------------- |\n| `short` | `Jan 15, 2024` | Abbreviated month |\n| `long` | `January 15, 2024` | Full month name |\n| `iso` | `2024-01-15` | ISO 8601 format |\n\n## Helper Function\n\n```typescript\nimport { createDateRangePresets } from \'./date-range-picker\';\n\n// Creates common presets:\n// - Today\n// - Yesterday\n// - Last 7 days\n// - Last 14 days\n// - Last 30 days\n// - This month\n// - Last month\nconst presets = createDateRangePresets();\n```\n\n## Examples\n\n### Analytics Dashboard\n\n```html\n<div class="flex justify-between">\n <h2>Analytics</h2>\n <sc-date-range-picker [(value)]="dateRange" [presets]="presets" (apply)="fetchData()" />\n</div>\n```\n\n### Custom Presets\n\n```typescript\nconst customPresets: DateRangePreset[] = [\n {\n label: \'This Week\',\n value: {\n from: getStartOfWeek(),\n to: new Date(),\n },\n },\n {\n label: \'This Quarter\',\n value: {\n from: getStartOfQuarter(),\n to: new Date(),\n },\n },\n];\n```\n\n### Booking System\n\n```html\n<sc-date-range-picker [(value)]="bookingDates" [minDate]="today" [disabledDates]="bookedDates" placeholder="Select check-in and check-out" />\n```\n\n## Accessibility\n\n- Trigger has `aria-expanded` and `aria-haspopup="dialog"`\n- Dropdown has `role="dialog"` and `aria-modal="true"`\n- Calendar is keyboard navigable\n- Clear button has descriptive `aria-label`\n',
|
|
30693
|
-
exports: []
|
|
30694
|
-
},
|
|
30695
|
-
{
|
|
30696
|
-
name: "diff-viewer",
|
|
30697
|
-
readme: "# Diff Viewer\n\nSide-by-side or unified view for comparing text and code changes.\n\n## Usage\n\n```html\n<sc-diff-viewer [oldText]=\"originalCode\" [newText]=\"modifiedCode\" [oldTitle]=\"'file.ts (original)'\" [newTitle]=\"'file.ts (modified)'\" />\n```\n\n## API\n\n### ScDiffViewer\n\n| Input | Type | Default | Description |\n| -------------------- | ---------------------- | --------- | ---------------------------- |\n| `oldText` | `string` | `''` | Original text content |\n| `newText` | `string` | `''` | Modified text content |\n| `oldTitle` | `string` | `''` | Title for original version |\n| `newTitle` | `string` | `''` | Title for modified version |\n| `defaultViewMode` | `'split' \\| 'unified'` | `'split'` | Initial view mode |\n| `showHeader` | `boolean` | `true` | Show header with stats |\n| `showFooter` | `boolean` | `true` | Show footer with counts |\n| `showViewModeToggle` | `boolean` | `true` | Show view mode toggle |\n| `showSideHeaders` | `boolean` | `true` | Show side-by-side headers |\n| `showWordDiff` | `boolean` | `true` | Highlight word-level changes |\n| `ignoreWhitespace` | `boolean` | `false` | Ignore whitespace diffs |\n| `ignoreCase` | `boolean` | `false` | Ignore case diffs |\n| `maxHeight` | `string` | `'600px'` | Maximum viewer height |\n\n### DiffResult\n\n```typescript\ninterface DiffResult {\n lines: DiffLine[];\n additions: number;\n deletions: number;\n unchanged: number;\n}\n\ninterface DiffLine {\n type: 'added' | 'removed' | 'unchanged' | 'modified';\n oldLineNumber?: number;\n newLineNumber?: number;\n oldContent?: string;\n newContent?: string;\n content?: string;\n}\n```\n\n## Examples\n\n### Basic Comparison\n\n```html\n<sc-diff-viewer [oldText]=\"oldCode\" [newText]=\"newCode\" />\n```\n\n### With Titles\n\n```html\n<sc-diff-viewer [oldText]=\"oldCode\" [newText]=\"newCode\" [oldTitle]=\"'config.json (before)'\" [newTitle]=\"'config.json (after)'\" />\n```\n\n### Unified View\n\n```html\n<sc-diff-viewer [oldText]=\"oldText\" [newText]=\"newText\" [defaultViewMode]=\"'unified'\" />\n```\n\n### Ignore Whitespace\n\n```html\n<sc-diff-viewer [oldText]=\"oldText\" [newText]=\"newText\" [ignoreWhitespace]=\"true\" />\n```\n\n### Minimal View\n\n```html\n<sc-diff-viewer [oldText]=\"oldText\" [newText]=\"newText\" [showHeader]=\"false\" [showFooter]=\"false\" [showViewModeToggle]=\"false\" />\n```\n\n## Utility Functions\n\n### computeDiff\n\nCompute the diff between two strings:\n\n```typescript\nimport { computeDiff } from './ui/diff-viewer';\n\nconst result = computeDiff(oldText, newText, {\n ignoreWhitespace: true,\n ignoreCase: false,\n});\n\nconsole.log(result.additions); // Number of added lines\nconsole.log(result.deletions); // Number of removed lines\nconsole.log(result.lines); // Array of DiffLine objects\n```\n\n### createUnifiedDiff\n\nCreate unified diff format (like git diff):\n\n```typescript\nimport { createUnifiedDiff } from './ui/diff-viewer';\n\nconst unifiedDiff = createUnifiedDiff(oldText, newText, {\n oldHeader: 'a/file.ts',\n newHeader: 'b/file.ts',\n contextLines: 3,\n});\n\n// Output:\n// --- a/file.ts\n// +++ b/file.ts\n// @@ -1,4 +1,5 @@\n// unchanged line\n// -removed line\n// +added line\n// unchanged line\n```\n\n### computeWordDiff\n\nCompute word-level diff for inline highlighting:\n\n```typescript\nimport { computeWordDiff } from './ui/diff-viewer';\n\nconst { oldParts, newParts } = computeWordDiff('the quick brown fox', 'the fast brown dog');\n\n// oldParts: [{ text: 'the', changed: false }, { text: 'quick', changed: true }, ...]\n// newParts: [{ text: 'the', changed: false }, { text: 'fast', changed: true }, ...]\n```\n\n## View Modes\n\n### Split View\n\n- Shows old and new versions side-by-side\n- Empty rows for alignment\n- Best for detailed line-by-line comparison\n\n### Unified View\n\n- Single column with + and - markers\n- Similar to `git diff` output\n- More compact for large files\n\n## Features\n\n- LCS-based diff algorithm\n- Line-by-line comparison\n- Word-level diff highlighting\n- Split (side-by-side) view\n- Unified (single column) view\n- Line numbers for both versions\n- Change statistics\n- View mode toggle\n- Ignore whitespace option\n- Ignore case option\n- Scrollable with max height\n- Responsive design\n\n## Color Coding\n\n- Green background: Added lines\n- Red background: Removed lines\n- No highlight: Unchanged lines\n- Word-level highlighting within changed lines\n",
|
|
30698
|
-
exports: []
|
|
30699
|
-
},
|
|
30700
|
-
{
|
|
30701
|
-
name: "dock",
|
|
30702
|
-
readme: "# Dock\n\nA macOS-style icon dock with magnification effect on hover, perfect for application launchers or navigation.\n\n## Composable Architecture\n\nThe dock component follows a composable architecture pattern, where functionality is split across multiple components that work together through dependency injection.\n\n### Components\n\n- **ScDock**: Root directive that manages dock state (hover effects, magnification)\n- **ScDockItems**: Wrapper component for dock items\n- **ScDockItem**: Individual dock item button\n- **ScDockBadge**: Optional badge indicator for items\n\n### State Management\n\nThe `ScDock` directive provides state through an `InjectionToken`:\n\n- Manages hover state for magnification effects\n- Handles item registration and indexing\n- Computes transformations for magnification\n- Emits click events\n\nChild components inject `SC_DOCK` to access parent state and methods.\n\n## Installation\n\n```typescript\nimport { ScDock, ScDockItems, ScDockItem, ScDockBadge } from '@/ui/dock';\nimport type { DockItem, DockPosition, DockSize } from '@/ui/dock';\n```\n\n## Usage\n\n### Basic Usage\n\n```html\n<nav scDock (itemClick)=\"onItemClick($event)\">\n <div scDockItems>\n @for (item of items; track item.id) {\n <button scDockItem [item]=\"item\"></button>\n }\n </div>\n</nav>\n```\n\n```typescript\nitems: DockItem[] = [\n { id: 'home', label: 'Home', icon: '<svg>...</svg>' },\n { id: 'mail', label: 'Mail', icon: '<svg>...</svg>' },\n { id: 'settings', label: 'Settings', icon: '<svg>...</svg>' },\n];\n\nonItemClick(item: DockItem): void {\n console.log('Clicked:', item.label);\n}\n```\n\n### With Badges\n\n```html\n<nav scDock>\n <div scDockItems>\n @for (item of items; track item.id) {\n <button scDockItem [item]=\"item\">\n @if (item.badge !== undefined) {\n <span scDockBadge>{{ item.badge }}</span>\n }\n </button>\n }\n </div>\n</nav>\n```\n\n```typescript\nitems: DockItem[] = [\n { id: 'mail', label: 'Mail', icon: '...', badge: 5 },\n { id: 'notifications', label: 'Notifications', icon: '...', badge: '!' },\n];\n```\n\n### Without Magnification\n\n```html\n<nav scDock [magnification]=\"false\">\n <div scDockItems>\n @for (item of items; track item.id) {\n <button scDockItem [item]=\"item\"></button>\n }\n </div>\n</nav>\n```\n\n### Custom Magnification Scale\n\n```html\n<nav scDock [magnificationScale]=\"2\">\n <div scDockItems>\n @for (item of items; track item.id) {\n <button scDockItem [item]=\"item\"></button>\n }\n </div>\n</nav>\n```\n\n### Size Variants\n\n```html\n<nav scDock size=\"sm\">\n <div scDockItems>\n @for (item of items; track item.id) {\n <button scDockItem [item]=\"item\"></button>\n }\n </div>\n</nav>\n```\n\n## API Reference\n\n### ScDock (Directive)\n\n**Selector**: `[scDock]`\n\n#### Inputs\n\n| Input | Type | Default | Description |\n| -------------------- | ------------------------------- | -------------------- | ----------------------- |\n| `position` | `'bottom' \\| 'left' \\| 'right'` | `'bottom'` | Dock position |\n| `size` | `'sm' \\| 'md' \\| 'lg'` | `'md'` | Icon size |\n| `magnification` | `boolean` | `true` | Enable magnification |\n| `magnificationScale` | `number` | `1.5` | Max magnification scale |\n| `ariaLabel` | `string` | `'Application dock'` | Accessible label |\n\n#### Outputs\n\n| Output | Type | Description |\n| ----------- | ---------- | ---------------------------- |\n| `itemClick` | `DockItem` | Emitted when item is clicked |\n\n### ScDockItems (Component)\n\n**Selector**: `div[scDockItems]`\n\nContainer for dock items. Automatically styled based on parent dock configuration.\n\n#### Inputs\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `''` | Additional CSS classes |\n\n### ScDockItem (Component)\n\n**Selector**: `button[scDockItem]`\n\nIndividual dock item button.\n\n#### Inputs\n\n| Input | Type | Default | Description |\n| ------- | ---------- | ------- | ---------------------- |\n| `item` | `DockItem` | - | Required. Item data |\n| `class` | `string` | `''` | Additional CSS classes |\n\n### ScDockBadge (Component)\n\n**Selector**: `span[scDockBadge]`\n\nBadge indicator for dock items.\n\n#### Inputs\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `''` | Additional CSS classes |\n\n## Type Definitions\n\n```typescript\ninterface DockItem {\n id: string;\n label: string;\n icon: string;\n href?: string;\n badge?: number | string;\n disabled?: boolean;\n}\n\ntype DockPosition = 'bottom' | 'left' | 'right';\ntype DockSize = 'sm' | 'md' | 'lg';\n```\n\n## Features\n\n- macOS-style magnification effect on hover\n- Smooth scale transitions\n- Badge support for notifications\n- Multiple size variants\n- Disabled state support\n- Glassmorphism styling\n- Keyboard accessible\n- Touch-friendly\n- Customizable magnification scale\n",
|
|
30703
|
-
exports: []
|
|
30704
|
-
},
|
|
30705
|
-
{
|
|
30706
|
-
name: "emoji-picker",
|
|
30707
|
-
readme: "# Emoji Picker\n\nA searchable emoji picker with categories, search functionality, and recently used emojis.\n\n## Components\n\n- `ScEmojiPicker` - Main emoji picker panel\n- `ScEmojiPickerTrigger` - Button trigger for use with popover\n\n## Usage\n\n```html\n<!-- Basic usage -->\n<sc-emoji-picker (emojiSelect)=\"onEmojiSelect($event)\" />\n\n<!-- Without search -->\n<sc-emoji-picker [showSearch]=\"false\" />\n\n<!-- Without category tabs -->\n<sc-emoji-picker [showCategories]=\"false\" />\n\n<!-- Without recently used -->\n<sc-emoji-picker [showRecent]=\"false\" />\n\n<!-- Custom columns -->\n<sc-emoji-picker [columns]=\"6\" class=\"w-56\" />\n\n<!-- Two-way binding -->\n<sc-emoji-picker [(value)]=\"selectedEmoji\" />\n```\n\n## API\n\n### ScEmojiPicker\n\n| Input | Type | Default | Description |\n| ---------------- | ----------------- | ------------------ | -------------------------------- |\n| `class` | `string` | `''` | Additional CSS classes |\n| `categories` | `EmojiCategory[]` | Default categories | Custom emoji categories |\n| `showSearch` | `boolean` | `true` | Show search input |\n| `showCategories` | `boolean` | `true` | Show category tabs |\n| `showRecent` | `boolean` | `true` | Show recently used section |\n| `maxRecent` | `number` | `8` | Max recently used emojis to show |\n| `columns` | `number` | `8` | Number of columns in grid |\n| `value` | `string` | `''` | Selected emoji (two-way) |\n\n| Output | Type | Description |\n| ------------- | ------- | ------------------------------ |\n| `emojiSelect` | `Emoji` | Emitted when emoji is selected |\n\n### ScEmojiPickerTrigger\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `''` | Additional CSS classes |\n\n## Types\n\n```typescript\ninterface Emoji {\n emoji: string;\n name: string;\n keywords?: string[];\n}\n\ninterface EmojiCategory {\n id: string;\n name: string;\n icon: string;\n emojis: Emoji[];\n}\n```\n\n## Default Categories\n\nThe picker includes these default categories:\n\n- Smileys & Emotion (\u{1F600})\n- People & Body (\u{1F44B})\n- Animals & Nature (\u{1F436})\n- Food & Drink (\u{1F354})\n- Activities (\u26BD)\n- Objects (\u{1F4A1})\n- Symbols (\u2764\uFE0F)\n- Flags (\u{1F3C1})\n\n## Examples\n\n### With Popover\n\n```html\n<div scPopoverProvider>\n <button scPopoverTrigger scEmojiPickerTrigger></button>\n <div scPopoverPortal>\n <div scPopover>\n <sc-emoji-picker (emojiSelect)=\"insertEmoji($event)\" />\n </div>\n </div>\n</div>\n```\n\n### In Chat Input\n\n```html\n<div class=\"relative\">\n <input type=\"text\" [(ngModel)]=\"message\" />\n <button (click)=\"showPicker = !showPicker\">\u{1F600}</button>\n</div>\n@if (showPicker) {\n<sc-emoji-picker (emojiSelect)=\"message = message + $event.emoji; showPicker = false\" />\n}\n```\n\n### Quick Reactions\n\n```html\n<div class=\"flex gap-1\">\n @for (emoji of ['\u{1F44D}', '\u2764\uFE0F', '\u{1F602}', '\u{1F62E}', '\u{1F622}']; track emoji) {\n <button (click)=\"addReaction(emoji)\">{{ emoji }}</button>\n }\n</div>\n```\n\n### Custom Categories\n\n```typescript\nconst customCategories: EmojiCategory[] = [\n {\n id: 'favorites',\n name: 'Favorites',\n icon: '\u2B50',\n emojis: [\n { emoji: '\u{1F44D}', name: 'thumbs up' },\n { emoji: '\u2764\uFE0F', name: 'red heart' },\n { emoji: '\u{1F389}', name: 'party popper' },\n ],\n },\n];\n```\n\n```html\n<sc-emoji-picker [categories]=\"customCategories\" />\n```\n\n## Features\n\n- **Search**: Type to filter emojis by name or keywords\n- **Categories**: Navigate between emoji categories with tabs\n- **Recently Used**: Automatically tracks recently selected emojis\n- **Keyboard Navigation**: Navigate with arrow keys\n- **Accessible**: Proper ARIA labels for screen readers\n",
|
|
30708
|
-
exports: []
|
|
30709
|
-
},
|
|
30710
|
-
{
|
|
30711
|
-
name: "image-annotator",
|
|
30712
|
-
readme: "# Image Annotator\n\nA canvas-based image annotation component with drawing tools for adding annotations on top of images.\n\n## Installation\n\n```typescript\nimport { ScImageAnnotator } from '@/ui/image-annotator';\nimport type { Annotation, AnnotationPoint, AnnotationTool } from '@/ui/image-annotator';\n```\n\n## Usage\n\n### Basic Usage\n\n```html\n<sc-image-annotator src=\"https://example.com/image.jpg\" [width]=\"800\" [height]=\"600\" (annotationsChange)=\"onAnnotationsChange($event)\" (save)=\"onSave($event)\" />\n```\n\n```typescript\nonAnnotationsChange(annotations: Annotation[]) {\n console.log('Annotations updated:', annotations);\n}\n\nonSave(dataUrl: string) {\n console.log('Image saved as data URL');\n}\n```\n\n### With Custom Dimensions\n\n```html\n<sc-image-annotator src=\"/assets/photo.png\" [width]=\"1200\" [height]=\"800\" />\n```\n\n### Programmatic Control\n\n```html\n<sc-image-annotator #annotator [src]=\"imageSrc\" />\n\n<button (click)=\"loadAnnotations()\">Load</button>\n<button (click)=\"clearAnnotations()\">Clear</button>\n```\n\n```typescript\n@ViewChild('annotator') annotator!: ScImageAnnotator;\n\nloadAnnotations() {\n this.annotator.setAnnotations(savedAnnotations);\n}\n\nclearAnnotations() {\n this.annotator.clearAll();\n}\n\ngetAnnotations() {\n return this.annotator.getAnnotations();\n}\n```\n\n## API Reference\n\n### Inputs\n\n| Input | Type | Default | Description |\n| -------- | -------- | ---------- | ----------------------- |\n| `src` | `string` | (required) | Image source URL |\n| `width` | `number` | `600` | Canvas width in pixels |\n| `height` | `number` | `400` | Canvas height in pixels |\n| `class` | `string` | `''` | Additional CSS classes |\n\n### Outputs\n\n| Output | Type | Description |\n| ------------------- | -------------- | ----------------------------------------- |\n| `annotationsChange` | `Annotation[]` | Emitted when annotations are modified |\n| `save` | `string` | Emitted with data URL when image is saved |\n\n### Methods\n\n| Method | Description |\n| -------------------------------- | -------------------------------- |\n| `getAnnotations(): Annotation[]` | Get current annotations |\n| `setAnnotations(annotations)` | Set annotations programmatically |\n| `undo()` | Remove last annotation |\n| `clearAll()` | Clear all annotations |\n| `download()` | Download annotated image as PNG |\n\n## Type Definitions\n\n```typescript\ntype AnnotationTool = 'pen' | 'line' | 'rectangle' | 'circle' | 'arrow' | 'text' | 'eraser';\n\ninterface AnnotationPoint {\n x: number;\n y: number;\n}\n\ninterface Annotation {\n id: string;\n tool: AnnotationTool;\n points: AnnotationPoint[];\n color: string;\n lineWidth: number;\n text?: string;\n}\n```\n\n## Available Tools\n\n| Tool | Description |\n| --------- | -------------------------------- |\n| Pen | Freehand drawing |\n| Line | Straight line between two points |\n| Rectangle | Rectangle shape |\n| Circle | Circle/ellipse from center point |\n| Arrow | Line with arrowhead |\n| Eraser | Remove annotations by proximity |\n\n## Features\n\n- Multiple drawing tools (pen, line, rectangle, circle, arrow)\n- Eraser tool for removing annotations\n- Color picker with preset colors\n- Adjustable line width\n- Undo functionality\n- Clear all annotations\n- Download annotated image as PNG\n- Cross-origin image support\n- Real-time annotation preview\n- Toolbar with tool selection\n- Programmatic annotation control\n",
|
|
30713
|
-
exports: []
|
|
30714
|
-
},
|
|
30715
30620
|
{
|
|
30716
30621
|
name: "image-compare",
|
|
30717
30622
|
readme: '# Image Compare\n\nBefore/after image comparison slider with keyboard and touch support. Built using the composable architecture pattern for maximum flexibility.\n\n## Components\n\n- `ScImageCompare` (directive) - Root state management\n- `ScImageCompareContainer` - Interactive container with event handling\n- `ScImageCompareBefore` - Before image positioning\n- `ScImageCompareAfter` - After image with clip-path reveal\n- `ScImageCompareSlider` - Draggable slider line and handle\n- `ScImageCompareLabel` - Customizable labels\n\n## Basic Usage\n\n```html\n<div scImageCompare class="aspect-2/1 w-full max-w-2xl">\n <div scImageCompareContainer>\n <img scImageCompareBefore src="before.jpg" alt="Before" />\n <img scImageCompareAfter src="after.jpg" alt="After" />\n <div scImageCompareSlider></div>\n <div scImageCompareLabel class="top-2 left-2">Before</div>\n <div scImageCompareLabel class="top-2 right-2">After</div>\n </div>\n</div>\n```\n\n## API\n\n### ScImageCompare (Directive)\n\nThe root directive that manages state.\n\n| Input | Type | Default | Description |\n| ------------- | ---------------------------- | -------------- | ------------------ |\n| `orientation` | `\'horizontal\' \\| \'vertical\'` | `\'horizontal\'` | Slider orientation |\n\n| Model | Type | Default | Description |\n| ---------- | -------- | ------- | ----------------------- |\n| `position` | `number` | `50` | Slider position (0-100) |\n\n### ScImageCompareContainer\n\nThe interactive container that handles user input.\n\n| Input | Type | Default | Description |\n| ----------- | -------- | --------------------------- | -------------------- |\n| `ariaLabel` | `string` | `\'Image comparison slider\'` | Accessibility label |\n| `class` | `string` | - | Additional CSS class |\n\n### ScImageCompareBefore / ScImageCompareAfter\n\nImage components for before/after images. Use as attribute directives on `<img>` tags.\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | -------------------- |\n| `class` | `string` | - | Additional CSS class |\n\n### ScImageCompareSlider\n\nThe draggable slider line and handle.\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | -------------------- |\n| `class` | `string` | - | Additional CSS class |\n\n**Content Projection:** Place custom handle icons inside the slider component.\n\n### ScImageCompareLabel\n\nLabel component with full positioning control.\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | -------------------- |\n| `class` | `string` | - | Additional CSS class |\n\n## Examples\n\n### Basic Usage\n\n```html\n<div scImageCompare class="aspect-2/1 w-full max-w-2xl">\n <div scImageCompareContainer>\n <img scImageCompareBefore src="/images/before.jpg" alt="Before" />\n <img scImageCompareAfter src="/images/after.jpg" alt="After" />\n <div scImageCompareSlider></div>\n <div scImageCompareLabel class="top-2 left-2">Before</div>\n <div scImageCompareLabel class="top-2 right-2">After</div>\n </div>\n</div>\n```\n\n### Without Labels\n\nSimply omit the label components:\n\n```html\n<div scImageCompare class="aspect-2/1 w-full max-w-2xl">\n <div scImageCompareContainer>\n <img scImageCompareBefore src="before.jpg" alt="Before" />\n <img scImageCompareAfter src="after.jpg" alt="After" />\n <div scImageCompareSlider></div>\n </div>\n</div>\n```\n\n### Vertical Orientation\n\n```html\n<div scImageCompare [orientation]="\'vertical\'" class="aspect-2/3 w-full max-w-sm">\n <div scImageCompareContainer>\n <img scImageCompareBefore src="before.jpg" alt="Top" />\n <img scImageCompareAfter src="after.jpg" alt="Bottom" />\n <div scImageCompareSlider></div>\n <div scImageCompareLabel class="top-2 left-2">Top</div>\n <div scImageCompareLabel class="bottom-2 left-2">Bottom</div>\n </div>\n</div>\n```\n\n### Custom Labels\n\nLabels have full positioning control:\n\n```html\n<div scImageCompare class="aspect-2/1 w-full max-w-2xl">\n <div scImageCompareContainer>\n <img scImageCompareBefore src="before.jpg" alt="Before" />\n <img scImageCompareAfter src="after.jpg" alt="After" />\n <div scImageCompareSlider></div>\n <div scImageCompareLabel class="bottom-4 left-4 rounded-full bg-blue-500 px-3 py-1 text-white">Original</div>\n <div scImageCompareLabel class="right-4 bottom-4 rounded-full bg-green-500 px-3 py-1 text-white">Enhanced</div>\n </div>\n</div>\n```\n\n### Custom Slider Handle\n\nUse content projection to customize the slider handle:\n\n```html\n<div scImageCompare>\n <div scImageCompareContainer>\n <img scImageCompareBefore src="before.jpg" alt="Before" />\n <img scImageCompareAfter src="after.jpg" alt="After" />\n <div scImageCompareSlider>\n <!-- Custom handle content -->\n <svg><!-- Your custom icon --></svg>\n </div>\n </div>\n</div>\n```\n\n### Controlled Position\n\n```typescript\n@Component({\n template: `\n <div scImageCompare [(position)]="position" class="aspect-2/1 w-full max-w-2xl">\n <div scImageCompareContainer>\n <img scImageCompareBefore src="before.jpg" alt="Before" />\n <img scImageCompareAfter src="after.jpg" alt="After" />\n <div scImageCompareSlider></div>\n </div>\n </div>\n\n <input type="range" min="0" max="100" [value]="position()" (input)="position.set(+$any($event.target).value)" />\n `,\n})\nexport class MyComponent {\n readonly position = signal(50);\n}\n```\n\n### Custom Initial Position\n\n```typescript\nreadonly position = signal(25); // Start at 25%\n```\n\n```html\n<div scImageCompare [(position)]="position">\n <div scImageCompareContainer>\n <img scImageCompareBefore src="before.jpg" alt="Before" />\n <img scImageCompareAfter src="after.jpg" alt="After" />\n <div scImageCompareSlider></div>\n </div>\n</div>\n```\n\n## Keyboard Navigation\n\n| Key | Action |\n| --------------- | ------------------------ |\n| `\u2190` / `\u2192` | Move slider (horizontal) |\n| `\u2191` / `\u2193` | Move slider (vertical) |\n| `Shift` + Arrow | Move by 10% |\n| `Home` | Go to 0% |\n| `End` | Go to 100% |\n\n## Styling\n\nThe component uses CSS `clip-path` for the reveal effect. Set dimensions on the root:\n\n```html\n<!-- Fixed aspect ratio -->\n<div scImageCompare class="aspect-video w-full max-w-2xl">...</div>\n\n<!-- Square -->\n<div scImageCompare class="aspect-square w-full max-w-md">...</div>\n\n<!-- Custom dimensions -->\n<div scImageCompare class="h-[400px] w-[600px]">...</div>\n```\n\n## Composable Architecture\n\nThis component follows the composable architecture pattern:\n\n- **Root Directive** (`sc-image-compare`): Manages state (position, orientation)\n- **Container** (`sc-image-compare-container`): Handles user interactions (mouse, touch, keyboard)\n- **Image Components**: Positioned with appropriate clip-path\n- **Slider**: Customizable via content projection\n- **Labels**: Optional, fully customizable positioning and styling\n\nBenefits:\n\n- Full control over structure and layout\n- Easy customization of all visual elements\n- Content projection for icons and labels\n- Can add additional elements between components\n\n## Accessibility\n\n- Full keyboard support with arrow keys\n- ARIA slider role with value announcements\n- Screen reader accessible labels\n- Focus ring for keyboard navigation\n- Touch support for mobile devices\n',
|
|
@@ -30722,140 +30627,6 @@ var manifest_default = {
|
|
|
30722
30627
|
readme: null,
|
|
30723
30628
|
exports: []
|
|
30724
30629
|
},
|
|
30725
|
-
{
|
|
30726
|
-
name: "infinite-scroll",
|
|
30727
|
-
readme: '# Infinite Scroll\n\nAutomatically load more content as the user scrolls to the bottom of a container.\n\n## Components\n\n- `ScInfiniteScroll` - Main container with scroll detection\n- `ScInfiniteScrollLoader` - Custom loading indicator slot\n- `ScInfiniteScrollEnd` - Custom end message slot\n\n## Usage\n\n```html\n<sc-infinite-scroll class="h-[400px] rounded-lg border" [loading]="loading()" [hasReachedEnd]="reachedEnd()" (loadMore)="loadMore()">\n <div class="space-y-2 p-4">\n @for (item of items(); track item.id) {\n <div class="rounded border p-4">{{ item.title }}</div>\n }\n </div>\n</sc-infinite-scroll>\n```\n\n## API\n\n### ScInfiniteScroll\n\n| Input | Type | Default | Description |\n| --------------- | --------- | ------------------------- | ----------------------------------------- |\n| `threshold` | `number` | `100` | Distance from bottom (px) to trigger load |\n| `loading` | `boolean` | `false` | Whether currently loading |\n| `hasReachedEnd` | `boolean` | `false` | Whether all content is loaded |\n| `endMessage` | `string` | `"No more items to load"` | Message shown at end |\n| `class` | `string` | - | Additional CSS classes |\n\n| Output | Type | Description |\n| ---------- | ------ | ------------------------------------- |\n| `loadMore` | `void` | Emitted when more content should load |\n\n### ScInfiniteScrollLoader\n\nCustom loading indicator. Place inside `ScInfiniteScroll`.\n\n```html\n<sc-infinite-scroll [loading]="loading()" (loadMore)="load()">\n <!-- content -->\n\n <div scInfiniteScrollLoader class="flex items-center gap-2 py-4">\n <div class="bg-primary size-2 animate-bounce rounded-full"></div>\n <div class="bg-primary size-2 animate-bounce rounded-full"></div>\n <div class="bg-primary size-2 animate-bounce rounded-full"></div>\n </div>\n</sc-infinite-scroll>\n```\n\n### ScInfiniteScrollEnd\n\nCustom end message. Place inside `ScInfiniteScroll`.\n\n```html\n<sc-infinite-scroll [hasReachedEnd]="reachedEnd()" (loadMore)="load()">\n <!-- content -->\n\n <div scInfiniteScrollEnd class="py-4 text-center">You\'ve reached the end!</div>\n</sc-infinite-scroll>\n```\n\n## Examples\n\n### Basic Usage\n\n```typescript\n@Component({\n template: `\n <sc-infinite-scroll class="h-[400px] rounded-lg border" [loading]="loading()" [hasReachedEnd]="reachedEnd()" (loadMore)="loadMore()">\n <div class="space-y-2 p-4">\n @for (item of items(); track item.id) {\n <div class="rounded border p-4">{{ item.title }}</div>\n }\n </div>\n </sc-infinite-scroll>\n `,\n})\nexport class MyComponent {\n readonly items = signal<Item[]>([]);\n readonly loading = signal(false);\n readonly reachedEnd = signal(false);\n\n loadMore(): void {\n if (this.loading() || this.reachedEnd()) return;\n this.loading.set(true);\n\n // Simulate API call\n setTimeout(() => {\n const newItems = this.fetchItems();\n this.items.update((items) => [...items, ...newItems]);\n\n if (this.items().length >= 100) {\n this.reachedEnd.set(true);\n }\n this.loading.set(false);\n }, 1000);\n }\n}\n```\n\n### Custom Threshold\n\nLoad content earlier by increasing the threshold:\n\n```html\n<sc-infinite-scroll [threshold]="200" [loading]="loading()" (loadMore)="loadMore()">\n <!-- content -->\n</sc-infinite-scroll>\n```\n\n### Grid Layout\n\nWorks with any content layout:\n\n```html\n<sc-infinite-scroll [loading]="loading()" (loadMore)="loadMore()">\n <div class="grid grid-cols-3 gap-4 p-4">\n @for (item of items(); track item.id) {\n <div class="bg-muted/50 rounded border p-4">{{ item.title }}</div>\n }\n </div>\n</sc-infinite-scroll>\n```\n\n## Accessibility\n\n- Announces loading state to screen readers\n- Uses semantic HTML structure\n- Keyboard accessible content\n',
|
|
30728
|
-
exports: []
|
|
30729
|
-
},
|
|
30730
|
-
{
|
|
30731
|
-
name: "kanban-board",
|
|
30732
|
-
readme: "# Kanban Board\n\nA drag-and-drop task board component for project management and workflow visualization.\n\n## Installation\n\nImport the components from the kanban-board module:\n\n```typescript\nimport { ScKanbanBoard, ScKanbanColumn, ScKanbanCard } from '@/ui/kanban-board';\n```\n\n## Usage\n\n### Basic Usage\n\n```html\n<sc-kanban-board [(columns)]=\"columns\" [(cards)]=\"cards\" (cardMoved)=\"onCardMoved($event)\" (cardAdded)=\"onCardAdded($event)\" />\n```\n\n```typescript\nimport { signal } from '@angular/core';\nimport type { KanbanColumn, KanbanCard } from '@/ui/kanban-board';\n\ncolumns = signal<KanbanColumn[]>([\n { id: 'todo', title: 'To Do', order: 0 },\n { id: 'in-progress', title: 'In Progress', order: 1 },\n { id: 'done', title: 'Done', order: 2 },\n]);\n\ncards = signal<KanbanCard[]>([\n { id: '1', title: 'Task 1', columnId: 'todo', order: 0 },\n { id: '2', title: 'Task 2', columnId: 'in-progress', order: 0 },\n]);\n```\n\n### With Column Colors and WIP Limits\n\n```typescript\ncolumns = signal<KanbanColumn[]>([\n { id: 'backlog', title: 'Backlog', order: 0, color: '#6b7280' },\n { id: 'todo', title: 'To Do', order: 1, color: '#3b82f6' },\n { id: 'in-progress', title: 'In Progress', order: 2, color: '#f59e0b', limit: 3 },\n { id: 'done', title: 'Done', order: 3, color: '#22c55e' },\n]);\n```\n\n### Cards with Full Details\n\n```typescript\ncards = signal<KanbanCard[]>([\n {\n id: '1',\n title: 'Implement authentication',\n description: 'Add login, registration, and password reset',\n columnId: 'in-progress',\n order: 0,\n labels: [\n { id: 'l1', text: 'Feature', color: '#8b5cf6' },\n { id: 'l2', text: 'Security', color: '#ef4444' },\n ],\n assignee: {\n id: 'u1',\n name: 'Alice Johnson',\n initials: 'AJ',\n },\n priority: 'high',\n dueDate: new Date('2024-12-31'),\n },\n]);\n```\n\n### Read-Only Board\n\n```html\n<sc-kanban-board [(columns)]=\"columns\" [(cards)]=\"cards\" [showAddCard]=\"false\" [showDeleteCard]=\"false\" [showAddColumn]=\"false\" />\n```\n\n### Disabled Board\n\n```html\n<sc-kanban-board [(columns)]=\"columns\" [(cards)]=\"cards\" [disabled]=\"true\" />\n```\n\n## API Reference\n\n### ScKanbanBoard\n\nThe main container component that manages columns and cards.\n\n#### Inputs\n\n| Input | Type | Default | Description |\n| ---------------- | ---------------- | ------- | ------------------------------------------------- |\n| `columns` | `KanbanColumn[]` | `[]` | Array of columns (two-way binding with `model()`) |\n| `cards` | `KanbanCard[]` | `[]` | Array of cards (two-way binding with `model()`) |\n| `disabled` | `boolean` | `false` | Disable all drag and drop interactions |\n| `showAddCard` | `boolean` | `true` | Show add card buttons in columns |\n| `showDeleteCard` | `boolean` | `true` | Show delete button on cards |\n| `showAddColumn` | `boolean` | `true` | Show add column button |\n| `class` | `string` | `''` | Additional CSS classes |\n\n#### Outputs\n\n| Output | Type | Description |\n| ----------------- | ------------------------------------------ | ------------------------------------------- |\n| `cardMoved` | `KanbanDragEvent` | Emitted when a card is moved |\n| `cardAdded` | `KanbanCardAddEvent` | Emitted when a card is added |\n| `cardDeleted` | `KanbanCardDeleteEvent` | Emitted when a card is deleted |\n| `cardClick` | `KanbanCard` | Emitted when a card is clicked |\n| `columnAdded` | `string` | Emitted when a column is added (title) |\n| `columnCollapsed` | `{ columnId: string; collapsed: boolean }` | Emitted when a column is collapsed/expanded |\n\n### ScKanbanColumn\n\nIndividual column component (used internally by ScKanbanBoard).\n\n### ScKanbanCard\n\nIndividual card component (used internally by ScKanbanColumn).\n\n## Type Definitions\n\n### KanbanColumn\n\n```typescript\ninterface KanbanColumn {\n id: string;\n title: string;\n order: number;\n color?: string; // Header accent color (hex)\n limit?: number; // WIP limit - shows warning when exceeded\n collapsed?: boolean; // Collapsed state\n}\n```\n\n### KanbanCard\n\n```typescript\ninterface KanbanCard {\n id: string;\n title: string;\n description?: string;\n columnId: string;\n order: number;\n labels?: KanbanLabel[];\n assignee?: KanbanAssignee;\n dueDate?: Date;\n priority?: 'low' | 'medium' | 'high' | 'urgent';\n metadata?: Record<string, unknown>;\n}\n```\n\n### KanbanLabel\n\n```typescript\ninterface KanbanLabel {\n id: string;\n text: string;\n color: string; // Hex color for label\n}\n```\n\n### KanbanAssignee\n\n```typescript\ninterface KanbanAssignee {\n id: string;\n name: string;\n avatar?: string; // URL to avatar image\n initials?: string; // Fallback if no avatar\n}\n```\n\n### KanbanDragEvent\n\n```typescript\ninterface KanbanDragEvent {\n card: KanbanCard;\n sourceColumnId: string;\n targetColumnId: string;\n sourceIndex: number;\n targetIndex: number;\n}\n```\n\n### KanbanCardAddEvent\n\n```typescript\ninterface KanbanCardAddEvent {\n columnId: string;\n title: string;\n}\n```\n\n### KanbanCardDeleteEvent\n\n```typescript\ninterface KanbanCardDeleteEvent {\n card: KanbanCard;\n columnId: string;\n}\n```\n\n## Features\n\n- **Drag and Drop**: Move cards between columns and reorder within columns using native HTML5 drag and drop\n- **Visual Feedback**: Drop zones highlight during drag, cards show insertion indicators\n- **Column Management**: Add new columns, collapse/expand columns\n- **Card Management**: Add and delete cards with inline forms\n- **Labels**: Color-coded labels for categorization\n- **Priority Indicators**: Visual priority markers (low, medium, high, urgent)\n- **Due Dates**: Date display with overdue highlighting (red for past, orange for soon)\n- **Assignees**: Avatar or initials display with tooltip\n- **WIP Limits**: Column card limits with warning when exceeded\n- **Keyboard Accessible**: Cards are focusable and can be activated with Enter/Space\n- **Two-Way Binding**: Use `[(columns)]` and `[(cards)]` for automatic state sync\n\n## Accessibility\n\n- Cards have `role=\"listitem\"` and are keyboard focusable\n- Columns have `role=\"list\"` with descriptive labels\n- Collapse/expand buttons have proper ARIA attributes\n- Delete and add buttons have descriptive `aria-label` attributes\n- Focus indicators are visible for keyboard navigation\n\n## Styling\n\nThe component uses Tailwind CSS classes and supports theming through CSS variables:\n\n- `--background` / `--foreground`: Base colors\n- `--card`: Card background\n- `--muted` / `--muted-foreground`: Secondary colors\n- `--primary` / `--primary-foreground`: Accent colors\n- `--destructive`: Delete action color\n- `--ring`: Focus ring color\n\nCustom styling can be applied via the `class` input on the board component.\n",
|
|
30733
|
-
exports: []
|
|
30734
|
-
},
|
|
30735
|
-
{
|
|
30736
|
-
name: "language-switcher",
|
|
30737
|
-
readme: null,
|
|
30738
|
-
exports: [
|
|
30739
|
-
"ScLanguageService",
|
|
30740
|
-
"SC_LANGUAGE_CONFIG",
|
|
30741
|
-
"ScLanguageToggle"
|
|
30742
|
-
]
|
|
30743
|
-
},
|
|
30744
|
-
{
|
|
30745
|
-
name: "lightbox",
|
|
30746
|
-
readme: '# Lightbox\n\nFull-screen image viewer with zoom, navigation, and keyboard support. Built using the composable architecture pattern for maximum flexibility.\n\n## Components\n\n- `ScLightbox` (directive) - Root state management\n- `ScLightboxContainer` - Full-screen overlay UI with all controls\n- `ScLightboxTrigger` - Trigger directive to open lightbox at specific index\n- `ScLightboxGallery` - Pre-built gallery grid with integrated lightbox\n\n## Basic Usage\n\n```html\n<div scLightbox [images]="images">\n <div class="flex gap-4">\n @for (image of images; track image.src; let i = $index) {\n <button scLightboxTrigger [index]="i" class="h-32 w-32 overflow-hidden rounded">\n <img [src]="image.src" [alt]="image.alt" class="size-full object-cover" />\n </button>\n }\n </div>\n <div scLightboxContainer></div>\n</div>\n```\n\n## API\n\n### LightboxImage\n\n```typescript\ninterface LightboxImage {\n src: string; // Full-size image URL\n alt?: string; // Alt text\n title?: string; // Title shown in bottom bar\n description?: string; // Description shown in bottom bar\n thumbnail?: string; // Thumbnail URL (uses src if not provided)\n}\n```\n\n### ScLightbox (Directive)\n\nThe root directive that manages state.\n\n**Selector:** `[scLightbox]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| --------------------- | ----------------- | ------- | ---------------------------- |\n| `images` | `LightboxImage[]` | `[]` | Array of images to display |\n| `showThumbnails` | `boolean` | `true` | Show thumbnail strip |\n| `showZoom` | `boolean` | `true` | Show zoom controls |\n| `showCounter` | `boolean` | `true` | Show image counter |\n| `showInfo` | `boolean` | `true` | Show image title/description |\n| `loop` | `boolean` | `true` | Loop navigation at ends |\n| `closeOnOverlayClick` | `boolean` | `true` | Close when clicking overlay |\n| `closeOnEscape` | `boolean` | `true` | Close on Escape key |\n\n**Two-way Bindings:**\n\n| Model | Type | Default | Description |\n| -------------- | --------- | ------- | ------------------------------- |\n| `isOpen` | `boolean` | `false` | Whether lightbox is open |\n| `currentIndex` | `number` | `0` | Current image index (0-indexed) |\n\n**Outputs:**\n\n| Output | Type | Description |\n| ------------- | -------- | -------------------------- |\n| `opened` | `number` | Emitted when opened |\n| `closed` | `void` | Emitted when closed |\n| `indexChange` | `number` | Emitted when image changes |\n\n**Methods (via template reference):**\n\n| Method | Returns | Description |\n| ------------------- | ------- | ---------------------- |\n| `open(index?)` | `void` | Open at specific index |\n| `close()` | `void` | Close lightbox |\n| `next()` | `void` | Go to next image |\n| `previous()` | `void` | Go to previous image |\n| `goTo(index)` | `void` | Go to specific image |\n| `zoomIn()` | `void` | Increase zoom |\n| `zoomOut()` | `void` | Decrease zoom |\n| `resetZoom()` | `void` | Reset zoom to 100% |\n| `getCurrentImage()` | `Image` | Get current image data |\n\n### ScLightboxContainer\n\nThe full-screen overlay component that renders all UI.\n\n**Selector:** `[scLightboxContainer]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | -------------------- |\n| `class` | `string` | `\'\'` | Additional CSS class |\n\n**Content Projection Slots:**\n\n- `[scLightboxCloseIcon]` - Custom close button icon\n- `[scLightboxPrevIcon]` - Custom previous button icon\n- `[scLightboxNextIcon]` - Custom next button icon\n- `[scLightboxLoading]` - Custom loading indicator\n\n### ScLightboxTrigger\n\nDirective that opens the lightbox when clicked.\n\n**Selector:** `[scLightboxTrigger]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ------------------------------- |\n| `index` | `number` | `0` | Image index to open (0-indexed) |\n\n### ScLightboxGallery\n\nPre-built gallery grid with integrated lightbox.\n\n**Selector:** `sc-lightbox-gallery`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ---------------- | ----------------- | ------- | ------------------------- |\n| `images` | `LightboxImage[]` | `[]` | Array of images |\n| `columns` | `number` | `3` | Number of grid columns |\n| `gap` | `number` | `4` | Gap size (Tailwind scale) |\n| `loop` | `boolean` | `true` | Loop navigation |\n| `showCounter` | `boolean` | `true` | Show counter |\n| `showInfo` | `boolean` | `true` | Show image info |\n| `showZoom` | `boolean` | `true` | Show zoom controls |\n| `showThumbnails` | `boolean` | `true` | Show thumbnails |\n| `class` | `string` | `\'\'` | Additional CSS class |\n\n## Examples\n\n### Basic Lightbox\n\n```html\n<div scLightbox [images]="images">\n <div class="flex gap-4">\n @for (image of images; track image.src; let i = $index) {\n <button scLightboxTrigger [index]="i" class="h-32 w-32 overflow-hidden rounded-lg">\n <img [src]="image.src" [alt]="image.alt" class="size-full object-cover" />\n </button>\n }\n </div>\n <div scLightboxContainer></div>\n</div>\n```\n\n```typescript\nreadonly images: LightboxImage[] = [\n { src: \'/images/photo1.jpg\', alt: \'Photo 1\' },\n { src: \'/images/photo2.jpg\', alt: \'Photo 2\' },\n { src: \'/images/photo3.jpg\', alt: \'Photo 3\' },\n];\n```\n\n### With Image Info\n\n```html\n<div scLightbox [images]="images">\n <div class="flex gap-4">\n @for (image of images; track image.src; let i = $index) {\n <button scLightboxTrigger [index]="i">\n <img [src]="image.thumbnail || image.src" [alt]="image.alt" />\n </button>\n }\n </div>\n <div scLightboxContainer></div>\n</div>\n```\n\n```typescript\nreadonly images: LightboxImage[] = [\n {\n src: \'/images/photo1.jpg\',\n alt: \'Sunset\',\n title: \'Beautiful Sunset\',\n description: \'Taken at the beach during golden hour\',\n thumbnail: \'/images/photo1-thumb.jpg\',\n },\n // ...\n];\n```\n\n### Pre-built Gallery\n\n```html\n<sc-lightbox-gallery [images]="images" class="max-w-4xl grid-cols-4 gap-2" />\n```\n\n### Controlled Lightbox\n\n```typescript\n@Component({\n template: `\n <div scLightbox [images]="images" [(isOpen)]="isOpen" [(currentIndex)]="currentIndex">\n <button (click)="isOpen.set(true)">Open Lightbox</button>\n <div scLightboxContainer></div>\n </div>\n\n <p>Currently showing image {{ currentIndex() + 1 }}</p>\n `,\n})\nexport class MyComponent {\n readonly isOpen = signal(false);\n readonly currentIndex = signal(0);\n readonly images: LightboxImage[] = [...];\n}\n```\n\n### Open Programmatically\n\n```typescript\n@Component({\n template: `\n <div scLightbox #lightbox="scLightbox" [images]="images">\n <button (click)="lightbox.open(2)">Open at Image 3</button>\n <div scLightboxContainer></div>\n </div>\n `,\n})\nexport class MyComponent {\n readonly images: LightboxImage[] = [...];\n}\n```\n\n### Without Thumbnails or Zoom\n\n```html\n<div scLightbox [images]="images" [showThumbnails]="false" [showZoom]="false">\n <div class="flex gap-4">\n @for (image of images; track image.src; let i = $index) {\n <button scLightboxTrigger [index]="i">\n <img [src]="image.src" [alt]="image.alt" />\n </button>\n }\n </div>\n <div scLightboxContainer></div>\n</div>\n```\n\n### Custom Icons\n\nUse content projection to customize icons:\n\n```html\n<div scLightbox [images]="images">\n <div class="flex gap-4">\n @for (image of images; track image.src; let i = $index) {\n <button scLightboxTrigger [index]="i">\n <img [src]="image.src" [alt]="image.alt" />\n </button>\n }\n </div>\n\n <div scLightboxContainer>\n <!-- Custom close icon -->\n <svg scLightboxCloseIcon>\n <!-- Your custom close icon -->\n </svg>\n\n <!-- Custom navigation icons -->\n <svg scLightboxPrevIcon>\n <!-- Your custom prev icon -->\n </svg>\n <svg scLightboxNextIcon>\n <!-- Your custom next icon -->\n </svg>\n\n <!-- Custom loading indicator -->\n <div scLightboxLoading>\n <span>Loading...</span>\n </div>\n </div>\n</div>\n```\n\n### Listen to Events\n\n```typescript\n@Component({\n template: `\n <div\n scLightbox\n [images]="images"\n (opened)="onOpened($event)"\n (closed)="onClosed()"\n (indexChange)="onIndexChange($event)"\n >\n <div class="flex gap-4">\n @for (image of images; track image.src; let i = $index) {\n <button scLightboxTrigger [index]="i">\n <img [src]="image.src" [alt]="image.alt" />\n </button>\n }\n </div>\n <div scLightboxContainer></div>\n </div>\n `,\n})\nexport class MyComponent {\n readonly images: LightboxImage[] = [...];\n\n onOpened(index: number) {\n console.log(\'Lightbox opened at index:\', index);\n }\n\n onClosed() {\n console.log(\'Lightbox closed\');\n }\n\n onIndexChange(index: number) {\n console.log(\'Image changed to index:\', index);\n }\n}\n```\n\n### No Loop\n\n```html\n<div scLightbox [images]="images" [loop]="false">\n <!-- Previous/Next buttons will be disabled at start/end -->\n <div class="flex gap-4">\n @for (image of images; track image.src; let i = $index) {\n <button scLightboxTrigger [index]="i">\n <img [src]="image.src" [alt]="image.alt" />\n </button>\n }\n </div>\n <div scLightboxContainer></div>\n</div>\n```\n\n## Keyboard Navigation\n\nWhen lightbox is open:\n\n| Key | Action |\n| ------------------ | ------------------ |\n| `\u2190` / `ArrowLeft` | Previous image |\n| `\u2192` / `ArrowRight` | Next image |\n| `Escape` | Close lightbox |\n| `+` / `=` | Zoom in |\n| `-` | Zoom out |\n| `0` | Reset zoom to 100% |\n\n## Composable Architecture\n\nThis component follows the composable architecture pattern:\n\n- **Root Directive** (`sc-lightbox`): Manages all state (isOpen, currentIndex, zoom, images)\n- **Container** (`sc-lightbox-container`): Renders full-screen overlay with complete UI (close button, navigation, image display, loading, zoom controls, thumbnails)\n- **Trigger**: Directive to open lightbox at specific index\n- **Gallery**: Pre-built component that combines everything\n\nBenefits:\n\n- Separation of concerns: state vs UI\n- Container handles all rendering and user interactions\n- Content projection for customizing icons and loading indicator\n- Can use triggers anywhere in your template\n- Gallery component provides quick setup for common use case\n\n## Accessibility\n\n- Full keyboard navigation support\n- ARIA dialog role with proper labeling\n- Screen reader announcements for image changes\n- Focus management when opening/closing\n- Escape key to close\n- Touch-friendly controls for mobile\n\n## Notes\n\n- Images are preloaded for smooth transitions\n- Zoom level persists during navigation\n- Thumbnails show current image with visual indicator\n- Body scroll is locked when lightbox is open\n- Overlay click and Escape key can be disabled if needed\n',
|
|
30747
|
-
exports: [
|
|
30748
|
-
"ScLightboxTrigger",
|
|
30749
|
-
"ScLightboxGallery"
|
|
30750
|
-
]
|
|
30751
|
-
},
|
|
30752
|
-
{
|
|
30753
|
-
name: "marquee",
|
|
30754
|
-
readme: '# Marquee\n\nScrolling content with smooth infinite animations, multiple directions, and customizable speed.\n\n## Components\n\n- `ScMarquee` - Main marquee container with duplicate content support\n- `ScMarqueeItem` - Individual item in the marquee\n- `ScMarqueeClone` - Clone container for seamless looping\n- `ScMarqueeFade` - Wrapper that adds gradient fade effects\n- `ScAutoMarquee` - Self-contained auto-looping marquee\n- `ScMarqueeText` - Simple text-only marquee\n\n## Usage\n\n### Text Marquee\n\n```html\n<sc-marquee-text text="Breaking news: This is scrolling text!" [duration]="15" />\n```\n\n### Content Marquee\n\n```html\n<sc-marquee [duration]="30" [gap]="24">\n @for (item of items; track item) {\n <div scMarqueeItem>{{ item }}</div>\n }\n <ng-container scMarqueeClone>\n @for (item of items; track item) {\n <div scMarqueeItem>{{ item }}</div>\n }\n </ng-container>\n</sc-marquee>\n```\n\n### Vertical Marquee\n\n```html\n<sc-marquee direction="vertical" [duration]="20">\n <!-- items -->\n</sc-marquee>\n```\n\n### Reversed Direction\n\n```html\n<sc-marquee [reverse]="true">\n <!-- items -->\n</sc-marquee>\n```\n\n## API\n\n### ScMarquee\n\n| Input | Type | Default | Description |\n| -------------- | ---------------------------- | -------------- | ------------------------ |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n| `direction` | `\'horizontal\' \\| \'vertical\'` | `\'horizontal\'` | Scroll direction |\n| `duration` | `number` | `40` | Animation duration (sec) |\n| `gap` | `number` | `16` | Gap between items (px) |\n| `pauseOnHover` | `boolean` | `true` | Pause animation on hover |\n| `reverse` | `boolean` | `false` | Reverse scroll direction |\n\n### ScMarqueeText\n\n| Input | Type | Default | Description |\n| -------------- | --------- | ------- | ----------------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n| `text` | `string` | - | **Required.** Text to display |\n| `separator` | `string` | `\'\u2022\'` | Separator between repetitions |\n| `duration` | `number` | `20` | Animation duration (sec) |\n| `pauseOnHover` | `boolean` | `true` | Pause animation on hover |\n| `reverse` | `boolean` | `false` | Reverse scroll direction |\n\n### ScMarqueeItem\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n### ScMarqueeClone\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n### ScMarqueeFade\n\n| Input | Type | Default | Description |\n| ----------- | ---------------------------- | -------------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n| `direction` | `\'horizontal\' \\| \'vertical\'` | `\'horizontal\'` | Fade direction |\n| `fadeSize` | `string` | `\'5rem\'` | Size of fade gradient |\n\n## Examples\n\n### Logo Carousel\n\n```html\n<sc-marquee [duration]="30" [gap]="48">\n @for (logo of logos; track logo) {\n <div scMarqueeItem class="flex h-16 w-32 items-center justify-center rounded border">{{ logo }}</div>\n }\n <ng-container scMarqueeClone>\n @for (logo of logos; track logo) {\n <div scMarqueeItem class="flex h-16 w-32 items-center justify-center rounded border">{{ logo }}</div>\n }\n </ng-container>\n</sc-marquee>\n```\n\n### Testimonials\n\n```html\n<sc-marquee [duration]="40" [gap]="24">\n @for (testimonial of testimonials; track testimonial.name) {\n <div scMarqueeItem class="w-80 rounded border p-4">\n <p>"{{ testimonial.quote }}"</p>\n <p class="font-medium">{{ testimonial.name }}</p>\n </div>\n }\n <ng-container scMarqueeClone>\n <!-- duplicate content -->\n </ng-container>\n</sc-marquee>\n```\n\n### Vertical Notifications\n\n```html\n<div class="h-48 overflow-hidden">\n <sc-marquee direction="vertical" [duration]="20">\n @for (notification of notifications; track notification.id) {\n <div scMarqueeItem class="rounded border p-3">{{ notification.icon }} {{ notification.title }}</div>\n }\n <ng-container scMarqueeClone>\n <!-- duplicate content -->\n </ng-container>\n </sc-marquee>\n</div>\n```\n\n### Stacked Marquees\n\n```html\n<div class="space-y-2">\n <sc-marquee [duration]="30"><!-- row 1 --></sc-marquee>\n <sc-marquee [duration]="25" [reverse]="true"><!-- row 2 --></sc-marquee>\n <sc-marquee [duration]="35"><!-- row 3 --></sc-marquee>\n</div>\n```\n\n### Speed Variations\n\n```html\n<!-- Fast -->\n<sc-marquee-text text="Fast" [duration]="10" />\n\n<!-- Normal -->\n<sc-marquee-text text="Normal" [duration]="20" />\n\n<!-- Slow -->\n<sc-marquee-text text="Slow" [duration]="40" />\n```\n\n## How It Works\n\nThe marquee creates seamless infinite scrolling by:\n\n1. Displaying the original content\n2. Displaying a clone of the content (via `sc-marquee-clone`)\n3. Animating both together with CSS animations\n4. When the first set scrolls out, the second set takes its place seamlessly\n\nFor `sc-marquee-text`, the text is automatically duplicated multiple times internally.\n\n## Accessibility\n\n- Clone content is marked with `aria-hidden="true"` to prevent duplicate screen reader announcements\n- Pause on hover allows users to read content\n- Animations respect `prefers-reduced-motion` media query (can be added via CSS)\n',
|
|
30755
|
-
exports: []
|
|
30756
|
-
},
|
|
30757
|
-
{
|
|
30758
|
-
name: "masonry-grid",
|
|
30759
|
-
readme: '# Masonry Grid\n\nA Pinterest-style layout component that arranges items in columns with varying heights.\n\n## Installation\n\nImport the components from the masonry-grid module:\n\n```typescript\nimport { ScMasonryGrid, ScMasonryItem } from \'@/ui/masonry-grid\';\n```\n\n## Usage\n\n### Basic Usage\n\n```html\n<sc-masonry-grid [columns]="4" [gap]="16">\n @for (item of items; track item.id) {\n <sc-masonry-item>\n <div class="card">\n <!-- Your content -->\n </div>\n </sc-masonry-item>\n }\n</sc-masonry-grid>\n```\n\n### Image Gallery\n\n```html\n<sc-masonry-grid [columns]="3" [gap]="12">\n @for (image of images; track image.id) {\n <sc-masonry-item>\n <img [src]="image.url" [alt]="image.title" class="w-full rounded-lg" />\n </sc-masonry-item>\n }\n</sc-masonry-grid>\n```\n\n### Custom Breakpoints\n\n```html\n<sc-masonry-grid\n [columns]="4"\n [gap]="16"\n [breakpoints]="[\n { minWidth: 0, columns: 1 },\n { minWidth: 640, columns: 2 },\n { minWidth: 1024, columns: 4 }\n ]"\n>\n <!-- items -->\n</sc-masonry-grid>\n```\n\n### Absolute Positioning Mode\n\n```html\n<sc-masonry-grid [columns]="3" [gap]="16" layoutMode="absolute">\n <!-- items -->\n</sc-masonry-grid>\n```\n\n### Programmatic Relayout\n\n```typescript\nimport { viewChild } from \'@angular/core\';\nimport { ScMasonryGrid } from \'@/ui/masonry-grid\';\n\nreadonly masonryGrid = viewChild(ScMasonryGrid);\n\nonContentChange(): void {\n // Trigger manual relayout after content changes\n this.masonryGrid()?.relayout();\n}\n```\n\n## API Reference\n\n### ScMasonryGrid\n\nThe main container component for the masonry layout.\n\n#### Inputs\n\n| Input | Type | Default | Description |\n| ------------- | ------------------------- | --------------------- | --------------------------- |\n| `columns` | `number` | `4` | Default number of columns |\n| `gap` | `number` | `16` | Gap between items in pixels |\n| `breakpoints` | `MasonryBreakpoint[]` | `DEFAULT_BREAKPOINTS` | Responsive breakpoints |\n| `layoutMode` | `\'columns\' \\| \'absolute\'` | `\'columns\'` | Layout algorithm to use |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n#### Public Methods\n\n| Method | Description |\n| ------------ | --------------------------------------- |\n| `relayout()` | Manually trigger a layout recalculation |\n\n### ScMasonryItem\n\nWrapper component for each item in the grid.\n\n#### Outputs\n\n| Output | Type | Description |\n| ------------ | ------------------- | ------------------------------ |\n| `sizeChange` | `{ width, height }` | Emitted when item size changes |\n\n#### Public Methods\n\n| Method | Returns | Description |\n| -------------- | ------------- | -------------------------- |\n| `getElement()` | `HTMLElement` | Get the native DOM element |\n| `getHeight()` | `number` | Get the element\'s height |\n\n## Type Definitions\n\n### MasonryBreakpoint\n\n```typescript\ninterface MasonryBreakpoint {\n minWidth: number; // Minimum viewport width\n columns: number; // Number of columns at this breakpoint\n}\n```\n\n### MasonryConfig\n\n```typescript\ninterface MasonryConfig {\n columns?: number;\n gap?: number;\n breakpoints?: MasonryBreakpoint[];\n}\n```\n\n### MasonryLayoutMode\n\n```typescript\ntype MasonryLayoutMode = \'columns\' | \'absolute\';\n```\n\n## Default Breakpoints\n\n```typescript\nconst DEFAULT_BREAKPOINTS: MasonryBreakpoint[] = [\n { minWidth: 0, columns: 1 }, // Mobile\n { minWidth: 640, columns: 2 }, // sm\n { minWidth: 768, columns: 3 }, // md\n { minWidth: 1024, columns: 4 }, // lg\n { minWidth: 1280, columns: 5 }, // xl\n];\n```\n\n## Layout Modes\n\n### columns (default)\n\nUses CSS `column-count` for layout. This is the most performant option:\n\n- **Pros**: Native browser layout, no JavaScript calculations, smooth animations\n- **Cons**: Items flow top-to-bottom then left-to-right (not shortest-column-first)\n- **Best for**: Most use cases, image galleries, card layouts\n\n### absolute\n\nUses JavaScript-calculated absolute positioning:\n\n- **Pros**: Items placed in shortest column first, better space utilization\n- **Cons**: Requires JavaScript calculations, may need manual relayout\n- **Best for**: When precise shortest-column placement is required\n\n## Features\n\n- **CSS Columns Layout**: Uses native CSS columns for optimal performance\n- **Responsive**: Configurable breakpoints for different screen sizes\n- **Flexible Gap**: Customizable spacing between items\n- **Dynamic Content**: Handles varying item heights automatically\n- **Two Layout Modes**: CSS columns or absolute positioning\n- **Manual Relayout**: Trigger recalculation when content changes\n- **ResizeObserver**: Automatically responds to container size changes\n\n## Styling\n\nThe component uses CSS columns for layout. Each item automatically:\n\n- Breaks inside avoid (prevents items from splitting across columns)\n- Has margin-bottom equal to the gap\n\nCustom styling can be applied via the `class` input or by styling the content within `sc-masonry-item`.\n\n## Performance Tips\n\n1. **Use `columns` mode** (default) for best performance\n2. **Add `loading="lazy"`** to images for better initial load\n3. **Use `track` in `@for`** loops for efficient DOM updates\n4. **Call `relayout()`** sparingly, only when necessary\n\n## Browser Support\n\n- CSS Columns: Supported in all modern browsers\n- ResizeObserver: Supported in all modern browsers (polyfill available for older browsers)\n',
|
|
30760
|
-
exports: []
|
|
30761
|
-
},
|
|
30762
|
-
{
|
|
30763
|
-
name: "mention-input",
|
|
30764
|
-
readme: "# Mention Input\n\nText input with @mention support for users, channels, or custom entities.\n\n## Components\n\n- `ScMentionInput` - Textarea with mention autocomplete\n\n## Usage\n\n### Basic Usage\n\n```html\n<sc-mention-input [(value)]=\"message\" [(mentions)]=\"mentionedUsers\" [users]=\"availableUsers\" placeholder=\"Type @ to mention someone...\" />\n```\n\n### Custom Trigger Character\n\n```html\n<sc-mention-input [users]=\"channels\" trigger=\"#\" placeholder=\"Type # to mention a channel...\" />\n```\n\n## API\n\n### ScMentionInput\n\n| Input | Type | Default | Description |\n| ------------- | --------------- | -------------------------------- | ------------------------ |\n| `class` | `string` | `''` | Additional CSS classes |\n| `placeholder` | `string` | `'Type @ to mention someone...'` | Placeholder text |\n| `disabled` | `boolean` | `false` | Disable the input |\n| `rows` | `number` | `3` | Number of visible rows |\n| `users` | `MentionUser[]` | `[]` | Available users/entities |\n| `trigger` | `string` | `'@'` | Trigger character |\n\n| Output | Type | Description |\n| --------------- | --------------- | -------------------------------- |\n| `value` | `string` | Two-way binding for text value |\n| `mentions` | `MentionUser[]` | Two-way binding for mentions |\n| `mentionSelect` | `MentionUser` | Emits when a mention is selected |\n\n| Method | Returns | Description |\n| ----------------- | --------------- | ------------------ |\n| `focus()` | `void` | Focus the textarea |\n| `getMentions()` | `MentionUser[]` | Get all mentions |\n| `clearMentions()` | `void` | Clear all mentions |\n\n## MentionUser Interface\n\n```typescript\ninterface MentionUser {\n id: string;\n name: string;\n username: string;\n avatar?: string;\n}\n```\n\n## Features\n\n- **Trigger Detection**: Activates when typing the trigger character (default: @)\n- **Search Filtering**: Filters users by name or username as you type\n- **Keyboard Navigation**: Use Arrow keys to navigate, Enter/Tab to select, Escape to close\n- **Avatar Support**: Display user avatars in the suggestion list\n- **Duplicate Prevention**: Already mentioned users are filtered from suggestions\n- **Custom Triggers**: Use any character as a trigger (e.g., # for channels)\n\n## Examples\n\n### Chat Application\n\n```typescript\n@Component({\n template: `\n <sc-mention-input [(value)]=\"message\" [(mentions)]=\"mentions\" [users]=\"teamMembers\" placeholder=\"Type a message...\" [rows]=\"2\" />\n <button (click)=\"sendMessage()\">Send</button>\n `,\n})\nexport class ChatInput {\n message = signal('');\n mentions = signal<MentionUser[]>([]);\n teamMembers: MentionUser[] = [\n { id: '1', name: 'John Doe', username: 'johndoe' },\n { id: '2', name: 'Jane Smith', username: 'janesmith' },\n ];\n\n sendMessage() {\n console.log('Message:', this.message());\n console.log('Mentioned:', this.mentions());\n }\n}\n```\n\n### With Avatars\n\n```typescript\nconst users: MentionUser[] = [\n { id: '1', name: 'Sarah', username: 'sarah', avatar: 'https://example.com/sarah.jpg' },\n { id: '2', name: 'Mike', username: 'mike', avatar: 'https://example.com/mike.jpg' },\n];\n```\n\n### Channel Mentions\n\n```html\n<sc-mention-input [users]=\"channels\" trigger=\"#\" placeholder=\"Mention a channel with #...\" />\n```\n\n```typescript\nconst channels: MentionUser[] = [\n { id: '1', name: 'General', username: 'general' },\n { id: '2', name: 'Engineering', username: 'engineering' },\n { id: '3', name: 'Design', username: 'design' },\n];\n```\n\n## Accessibility\n\n- Dropdown has `role=\"listbox\"` for screen readers\n- Options have `role=\"option\"` and `aria-selected`\n- Keyboard navigation support (Arrow keys, Enter, Tab, Escape)\n- Focus management when selecting mentions\n",
|
|
30765
|
-
exports: []
|
|
30766
|
-
},
|
|
30767
|
-
{
|
|
30768
|
-
name: "multi-select",
|
|
30769
|
-
readme: '# Multi-Select\n\nSelect multiple options from a dropdown with chips, search, and select-all functionality.\n\n## Components\n\n- `ScMultiSelect` - Multi-selection dropdown with chips\n\n## Usage\n\n### Basic Usage\n\n```html\n<sc-multi-select [(value)]="selectedValues" [options]="options" placeholder="Select options..." />\n```\n\n### With Select All\n\n```html\n<sc-multi-select [options]="options" [showSelectAll]="true" placeholder="Select..." />\n```\n\n### Count Display (No Chips)\n\n```html\n<sc-multi-select [options]="options" [showChips]="false" placeholder="Select..." />\n```\n\n## API\n\n### ScMultiSelect\n\n| Input | Type | Default | Description |\n| ------------------- | --------------------- | --------------------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n| `placeholder` | `string` | `\'Select options...\'` | Placeholder text |\n| `disabled` | `boolean` | `false` | Disable the select |\n| `options` | `MultiSelectOption[]` | `[]` | Available options |\n| `searchable` | `boolean` | `true` | Enable search input |\n| `showChips` | `boolean` | `true` | Show chips vs count |\n| `showSelectAll` | `boolean` | `false` | Show select all option |\n| `showClearAll` | `boolean` | `true` | Show clear all button |\n| `maxDisplayedChips` | `number` | `3` | Max chips before "+N" |\n\n| Output | Type | Description |\n| -------------- | ------------------- | ---------------------------- |\n| `value` | `string[]` | Two-way binding for values |\n| `valueChange` | `string[]` | Emits when selection changes |\n| `optionSelect` | `MultiSelectOption` | Emits when option selected |\n| `optionRemove` | `MultiSelectOption` | Emits when option removed |\n\n| Method | Returns | Description |\n| ---------------------- | --------------------- | -------------------- |\n| `focus()` | `void` | Focus the trigger |\n| `getSelectedOptions()` | `MultiSelectOption[]` | Get selected options |\n\n## MultiSelectOption Interface\n\n```typescript\ninterface MultiSelectOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n```\n\n## Features\n\n- **Chip Display**: Selected items shown as removable chips\n- **Count Display**: Alternative compact display showing "N selected"\n- **Searchable**: Filter options by typing\n- **Select All**: Quickly select/deselect all visible options\n- **Clear All**: Remove all selections at once\n- **Disabled Options**: Individual options can be disabled\n- **Keyboard Navigation**: Escape to close dropdown\n\n## Examples\n\n### Basic Multi-Select\n\n```typescript\n@Component({\n template: `\n <sc-multi-select [(value)]="selectedFruits" [options]="fruits" placeholder="Select fruits..." />\n `,\n})\nexport class FruitPicker {\n selectedFruits = signal<string[]>([]);\n fruits: MultiSelectOption[] = [\n { value: \'apple\', label: \'Apple\' },\n { value: \'banana\', label: \'Banana\' },\n { value: \'cherry\', label: \'Cherry\' },\n ];\n}\n```\n\n### With Disabled Options\n\n```typescript\nconst frameworks: MultiSelectOption[] = [\n { value: \'react\', label: \'React\' },\n { value: \'angular\', label: \'Angular\' },\n { value: \'vue\', label: \'Vue\' },\n { value: \'svelte\', label: \'Svelte\', disabled: true },\n];\n```\n\n### Form Integration\n\n```html\n<form class="space-y-4">\n <div>\n <label>Select your interests</label>\n <sc-multi-select [(value)]="interests" [options]="interestOptions" [showSelectAll]="true" placeholder="Choose interests..." />\n </div>\n <button type="submit">Save</button>\n</form>\n```\n\n### Without Search\n\n```html\n<sc-multi-select [options]="sizes" [searchable]="false" placeholder="Select sizes..." />\n```\n\n### Handling Selection Changes\n\n```typescript\n@Component({\n template: `\n <sc-multi-select [options]="options" (valueChange)="onSelectionChange($event)" (optionSelect)="onOptionSelected($event)" (optionRemove)="onOptionRemoved($event)" />\n `,\n})\nexport class SelectHandler {\n onSelectionChange(values: string[]) {\n console.log(\'Selected values:\', values);\n }\n\n onOptionSelected(option: MultiSelectOption) {\n console.log(\'Added:\', option.label);\n }\n\n onOptionRemoved(option: MultiSelectOption) {\n console.log(\'Removed:\', option.label);\n }\n}\n```\n\n## Accessibility\n\n- Trigger has `aria-expanded` and `aria-haspopup="listbox"`\n- Dropdown has `role="listbox"` and `aria-multiselectable="true"`\n- Options have `role="option"` and `aria-selected`\n- Chip remove buttons have descriptive `aria-label`\n- Keyboard support (Escape to close)\n',
|
|
30770
|
-
exports: []
|
|
30771
|
-
},
|
|
30772
|
-
{
|
|
30773
|
-
name: "native-checkbox",
|
|
30774
|
-
readme: '# Native Checkbox\n\nA directive that styles native `<input type="checkbox">` elements while preserving native form behavior.\n\n## Why Native Checkbox?\n\nUnlike `ScCheckbox` (which is a custom component), `ScNativeCheckbox` is a directive for native HTML checkbox inputs. This provides:\n\n- **Native form integration** - Works with `ngModel`, Reactive Forms, and Signal Forms\n- **No ControlValueAccessor needed** - The native input handles all form state\n- **Browser accessibility** - Leverages built-in browser accessibility features\n- **Smaller bundle** - No custom form control logic\n\n## Components\n\n- `ScNativeCheckbox` - Directive for `<input type="checkbox">`\n\n## Usage\n\n### Basic\n\n```html\n<input scNativeCheckbox id="terms" (change)="onCheck($event)" />\n<label for="terms">Accept terms</label>\n```\n\n### With ngModel\n\n```html\n<input scNativeCheckbox [(ngModel)]="accepted" id="terms" />\n<label for="terms">Accept terms</label>\n```\n\n### With Signal Forms\n\n```typescript\nimport { signal } from \'@angular/core\';\nimport { form, FormField } from \'@angular/forms/signals\';\n\nreadonly formModel = signal({ newsletter: false });\nreadonly checkboxForm = form(this.formModel);\n```\n\n```html\n<input scNativeCheckbox type="checkbox" id="newsletter" [formField]="checkboxForm.newsletter" />\n<label for="newsletter">Subscribe</label>\n```\n\nNote: Add `FormField` to your component\'s `imports` array to use the `[formField]` directive. When using `[formField]`, you cannot use other property bindings like `[checked]` on the same element.\n\n### Indeterminate State\n\n```html\n<input scNativeCheckbox [indeterminate]="someSelected" id="select-all" />\n<label for="select-all">Select all</label>\n```\n\n### Disabled\n\n```html\n<input scNativeCheckbox disabled id="disabled" />\n<label for="disabled">Disabled checkbox</label>\n```\n\n## Inputs\n\n| Input | Type | Default | Description |\n| --------------- | --------- | ------- | ---------------------------------------- |\n| `checked` | `boolean` | - | Checked state (for programmatic control) |\n| `indeterminate` | `boolean` | `false` | Whether checkbox is indeterminate |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n## Architecture\n\n### Styling Approach\n\nThe directive uses `appearance: none` to hide the native checkbox appearance and applies custom styles via Tailwind CSS classes. The checkmark icon is rendered as a background-image using inline SVG data URIs.\n\n```\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Native <input type="checkbox"> \u2502\n\u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n\u2502 \u2502 appearance: none \u2502 \u2502\n\u2502 \u2502 + Tailwind border/bg \u2502 \u2502\n\u2502 \u2502 + SVG background-image \u2502 \u2502\n\u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n```\n\n### State Tracking\n\nThe directive listens to `change` and `input` events to track the native checked state, then conditionally shows the checkmark SVG via `background-image`.\n\nCSS pseudo-classes (`:checked`, `:disabled`, `:focus-visible`) handle visual state changes natively.\n\n### Comparison with ScCheckbox\n\n| Feature | ScCheckbox | ScNativeCheckbox |\n| -------------------- | ------------------- | ---------------------- |\n| Type | Component | Directive |\n| Form Integration | Two-way via model() | Native form controls |\n| ARIA | Manual attributes | Native browser support |\n| Checkmark | SVG in template | SVG background-image |\n| Signal Forms | FormCheckboxControl | FormCheckboxControl |\n| ControlValueAccessor | Not implemented | Not needed |\n\n## Accessibility\n\n- Native `<input type="checkbox">` provides built-in accessibility\n- Works with `<label for="id">` associations\n- Keyboard accessible (Space to toggle, Tab to navigate)\n- Focus ring styling via `:focus-visible`\n- Disabled state via native `disabled` attribute\n',
|
|
30775
|
-
exports: [
|
|
30776
|
-
"ScNativeCheckbox"
|
|
30777
|
-
]
|
|
30778
|
-
},
|
|
30779
|
-
{
|
|
30780
|
-
name: "navbar",
|
|
30781
|
-
readme: '# Navbar\n\nA responsive navigation bar block with mobile menu support. Automatically adapts between desktop horizontal navigation and a mobile hamburger menu with slide-in drawer.\n\n## Components\n\n- `ScNavbarProvider` - Root provider that manages state and links navbar with mobile menu\n- `ScNavbar` - Root nav element for the main navigation bar\n- `ScNavbarBrand` - Brand/logo section with focus styles\n- `ScNavbarGroup` - Groups navbar elements together (e.g., brand + navigation)\n- `ScNavbarActions` - Right-aligned action buttons container\n- `ScNavbarMobileTrigger` - Mobile menu toggle button (uses content projection for icons)\n- `ScNavbarMobilePortal` - Mobile menu portal using CDK overlay (handles rendering)\n- `ScNavbarMobileMenu` - Mobile menu container with styling (customizable)\n- `ScNavbarMobileLink` - Mobile menu link with auto-close on navigation\n\n## Architecture\n\nThe navbar uses a provider pattern similar to the sheet component:\n\n- **Provider**: `ScNavbarProvider` wraps everything and manages state\n- **Navbar**: The actual navigation bar sits inside the provider\n- **Mobile Menu**: The mobile menu portal is a sibling to the navbar (not nested inside)\n- **Components communicate**: All components inject the provider to access shared state\n\nThis architecture allows the mobile menu to be positioned independently while maintaining a clean connection to the navbar state.\n\n## Usage\n\n### Basic Navbar\n\nThe recommended approach is to use `ScNavigationMenu` for navigation. See the example below.\n\n**Note:** The navbar uses `justify-between` to space its direct children. Use `sc-navbar-group` to keep related elements (like brand and navigation) together on the left side.\n\n### With Navigation Menu\n\nYou can integrate `ScNavigationMenu` components for dropdown navigation:\n\n```typescript\nimport { SiMenuIcon, SiXIcon } from \'@semantic-icons/lucide-icons\';\n\n@Component({\n imports: [\n ScNavbar,\n ScNavbarProvider,\n ScNavbarMobileTrigger,\n // ... other imports\n SiMenuIcon,\n SiXIcon,\n ],\n template: `\n <div scNavbarProvider>\n <nav scNavbar>\n <div scNavbarGroup>\n <a scNavbarBrand routerLink="/">\n <span>Brand</span>\n </a>\n\n <!-- Navigation Menu with Dropdowns -->\n <nav scNavigationMenu class="hidden md:flex">\n <ul scNavigationMenuList>\n <li scNavigationMenuItem>\n <button scNavigationMenuTrigger>Products</button>\n <div scNavigationMenuContent>\n <ul class="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2">\n <li>\n <a scNavigationMenuLink routerLink="/products/web">\n <div class="text-sm font-medium leading-none">Web Apps</div>\n <p class="line-clamp-2 text-sm leading-snug text-muted-foreground">\n Build modern web applications\n </p>\n </a>\n </li>\n <!-- More items -->\n </ul>\n </div>\n </li>\n\n <li scNavigationMenuItem>\n <a scNavigationMenuLink routerLink="/docs">Docs</a>\n </li>\n </ul>\n </nav>\n </div>\n\n <div scNavbarActions>\n <button scButton>Get Started</button>\n <button scNavbarMobileTrigger #trigger="scNavbarMobileTrigger">\n @if (trigger.isMobileMenuOpen()) {\n <svg si-x-icon></svg>\n } @else {\n <svg si-menu-icon></svg>\n }\n <span class="sr-only">\n {{ trigger.isMobileMenuOpen() ? \'Close menu\' : \'Open menu\' }}\n </span>\n </button>\n </div>\n </nav>\n\n <!-- Mobile Menu -->\n <div scNavbarMobilePortal>\n <div scNavbarMobileMenu>\n <a scNavbarMobileLink routerLink="/products">Products</a>\n <a scNavbarMobileLink routerLink="/docs">Docs</a>\n </div>\n </div>\n </div>\n `,\n})\n```\n\n**Note:** The navigation menu automatically closes when navigation occurs (via router events).\n\n## Controlling Mobile Menu State\n\nYou can control the mobile menu state using two-way binding on the provider:\n\n```html\n<div scNavbarProvider [(open)]="mobileMenuOpen">\n <!-- navbar content -->\n</div>\n```\n\n```typescript\nexport class MyComponent {\n readonly mobileMenuOpen = model(false);\n}\n```\n\n## Active State\n\nUse the `active` input to indicate the current page for mobile links:\n\n```html\n<a scNavbarMobileLink routerLink="/about" [active]="isAboutPage">About</a>\n```\n\n## With RouterLinkActive\n\nFor automatic active state based on the current route:\n\n```html\n<a scNavbarMobileLink routerLink="/about" routerLinkActive="active" #rla="routerLinkActive" [active]="rla.isActive">About</a>\n```\n\n## Mobile Menu Behavior\n\nThe mobile menu automatically:\n\n- Closes when clicking a mobile link (auto-navigation)\n- Closes when pressing the Escape key\n- Uses CDK overlay for proper z-index stacking and portal rendering\n- Slides in from the top below the navbar\n- Animates smoothly with CSS transitions\n- State is managed by the provider and shared across all components\n\n**Icons**: The mobile trigger uses content projection for icons, allowing consumers to provide their own icons (e.g., hamburger menu when closed, X when open) via the `isMobileMenuOpen()` signal accessible through template references.\n\n## Custom Styling\n\nAll components accept a `class` input for custom styles:\n\n```html\n<nav scNavbar class="sticky top-0 z-50">\n <a scNavbarBrand class="text-primary">Brand</a>\n <nav scNavigationMenu>\n <!-- navigation menu items -->\n </nav>\n</nav>\n```\n\n### Customizing Mobile Menu\n\nThe mobile menu container can be styled directly using the `class` input:\n\n```html\n<div scNavbarMobilePortal>\n <div scNavbarMobileMenu class="bg-red-500 p-8">\n <!-- Custom background and padding -->\n </div>\n</div>\n```\n\n## Inputs\n\n### ScNavbarProvider\n\n| Input | Type | Default | Description |\n| ------- | --------- | ------- | ------------------------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n| `open` | `boolean` | `false` | Two-way binding for mobile menu state |\n\n### ScNavbar\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n### ScNavbarMobileMenu\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n### ScNavbarMobileTrigger\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n**Export As:** `scNavbarMobileTrigger`\n\n**Public Properties (via template reference):**\n\n| Property | Type | Description |\n| ------------------ | ----------------- | --------------------------- |\n| `isMobileMenuOpen` | `Signal<boolean>` | Whether mobile menu is open |\n\n**Usage:** Use a template reference variable with `#trigger="scNavbarMobileTrigger"` to access the `isMobileMenuOpen()` signal for conditional icon rendering.\n\n### ScNavbarMobileLink\n\n| Input | Type | Default | Description |\n| -------- | --------- | ------- | ------------------------------------ |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n| `active` | `boolean` | `false` | Whether the link is currently active |\n\n## CSS Variables\n\nThe navbar uses the following CSS variable for positioning:\n\n| Variable | Default | Description |\n| ----------------- | ------- | ----------------------------------------------------- |\n| `--navbar-height` | `57px` | Height of the navbar, used to position mobile content |\n\n## Accessibility\n\n- Uses semantic `<nav>` element\n- Mobile trigger includes `aria-expanded` and `aria-controls` attributes\n- Mobile menu has `role="navigation"` and `aria-label="Mobile navigation"`\n- Screen reader text for hamburger icon state changes\n- Uses `inert` attribute to prevent focus on hidden mobile content\n- Overlay is marked with `aria-hidden="true"`\n- All interactive elements have visible focus indicators\n',
|
|
30782
|
-
exports: []
|
|
30783
|
-
},
|
|
30784
|
-
{
|
|
30785
|
-
name: "notification-center",
|
|
30786
|
-
readme: "# Notification Center\n\nA grouped notification management component with filtering, read states, and action buttons.\n\n## Installation\n\nImport the components from the notification-center module:\n\n```typescript\nimport { ScNotificationCenter, ScNotificationCenterContainer, type Notification, type NotificationGroup } from '@/ui/notification-center';\n```\n\n## Components\n\n- **ScNotificationCenter (Directive)**: State management and business logic\n- **ScNotificationCenterContainer**: UI rendering with header, filters, and notification list\n- **ScNotificationGroup**: Grouped notification section (used internally)\n- **ScNotificationItem**: Individual notification item (used internally)\n\n## Usage\n\n### Basic Usage\n\n```html\n<div scNotificationCenter [(notifications)]=\"notifications\" (markRead)=\"onMarkRead($event)\" (dismiss)=\"onDismiss($event)\">\n <div scNotificationCenterContainer></div>\n</div>\n```\n\n```typescript\nimport { signal } from '@angular/core';\nimport type { Notification } from '@/ui/notification-center';\n\nnotifications = signal<Notification[]>([\n {\n id: '1',\n title: 'New message',\n description: 'You have a new message from Alice',\n type: 'message',\n timestamp: new Date(),\n read: false,\n },\n {\n id: '2',\n title: 'Build completed',\n type: 'success',\n timestamp: new Date(Date.now() - 3600000),\n read: true,\n },\n]);\n```\n\n### With Groups\n\n```html\n<div scNotificationCenter [(notifications)]=\"notifications\" [groups]=\"groups()\">\n <div scNotificationCenterContainer></div>\n</div>\n```\n\n```typescript\nimport type { Notification, NotificationGroup } from '@/ui/notification-center';\n\ngroups = signal<NotificationGroup[]>([\n { id: 'messages', title: 'Messages' },\n { id: 'alerts', title: 'Alerts' },\n { id: 'updates', title: 'Updates' },\n]);\n\nnotifications = signal<Notification[]>([\n {\n id: '1',\n title: 'New message from Alice',\n type: 'message',\n timestamp: new Date(),\n read: false,\n groupId: 'messages', // Links to group\n },\n {\n id: '2',\n title: 'Security alert',\n type: 'warning',\n timestamp: new Date(),\n read: false,\n groupId: 'alerts',\n },\n]);\n```\n\n### With Actions\n\n```typescript\nnotifications = signal<Notification[]>([\n {\n id: '1',\n title: 'Payment failed',\n description: 'Your payment method was declined.',\n type: 'error',\n timestamp: new Date(),\n read: false,\n action: {\n label: 'Update payment',\n handler: () => console.log('Navigate to payment settings'),\n },\n },\n]);\n```\n\n### With Avatars\n\n```typescript\nnotifications = signal<Notification[]>([\n {\n id: '1',\n title: 'New message from Alice',\n description: 'Hey! Are you available for a call?',\n type: 'message',\n timestamp: new Date(),\n read: false,\n avatar: 'https://example.com/alice.jpg',\n },\n]);\n```\n\n### Custom Empty State\n\n```html\n<div scNotificationCenter [(notifications)]=\"notifications\" emptyTitle=\"All caught up!\" emptyDescription=\"No new notifications to show.\">\n <div scNotificationCenterContainer></div>\n</div>\n```\n\n### Without Filters\n\n```html\n<div scNotificationCenter [(notifications)]=\"notifications\" [showFilters]=\"false\">\n <div scNotificationCenterContainer></div>\n</div>\n```\n\n### Custom Container Styling\n\n```html\n<div scNotificationCenter [(notifications)]=\"notifications\" class=\"h-[500px] max-w-md\">\n <div scNotificationCenterContainer class=\"h-full\"></div>\n</div>\n```\n\n## API Reference\n\n### ScNotificationCenter (Directive)\n\nThe root directive that manages notification state and business logic.\n\n#### Selector\n\n`[scNotificationCenter]`\n\n#### Inputs\n\n| Input | Type | Default | Description |\n| ------------------ | --------------------- | ------------------------- | -------------------------------- |\n| `notifications` | `Notification[]` | `[]` | Array of notifications (two-way) |\n| `groups` | `NotificationGroup[]` | `[]` | Groups for categorizing |\n| `title` | `string` | `'Notifications'` | Header title |\n| `showFilters` | `boolean` | `true` | Show all/unread/read filter tabs |\n| `showClearAll` | `boolean` | `true` | Show clear all button |\n| `showDismiss` | `boolean` | `true` | Show dismiss button on items |\n| `emptyTitle` | `string` | `'No notifications'` | Empty state title |\n| `emptyDescription` | `string` | `\"You're all caught up!\"` | Empty state description |\n\n#### Outputs\n\n| Output | Type | Description |\n| -------------- | -------------------------- | ------------------------- |\n| `markRead` | `{ notification, read }` | Read state changed |\n| `markAllRead` | `void` | All marked as read |\n| `dismiss` | `Notification` | Notification dismissed |\n| `clearAll` | `void` | All notifications cleared |\n| `actionClick` | `{ notification, action }` | Action button clicked |\n| `itemClick` | `Notification` | Notification clicked |\n| `filterChange` | `NotificationFilter` | Filter changed |\n\n#### Exported As\n\n`scNotificationCenter` - Access directive instance via template reference variable\n\n```html\n<div scNotificationCenter #center=\"scNotificationCenter\">\n <!-- Access center.totalUnread(), center.filteredNotifications(), etc. -->\n</div>\n```\n\n### ScNotificationCenterContainer\n\nThe container component that renders the notification center UI.\n\n#### Selector\n\n`[scNotificationCenterContainer]`\n\n#### Inputs\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `''` | Additional CSS classes |\n\n### ScNotificationGroup\n\nIndividual group component (used internally by container).\n\n### ScNotificationItem\n\nIndividual notification item component (used internally by container).\n\n## Composable Architecture\n\nThe notification center follows a composable architecture pattern that separates state management from UI rendering:\n\n### Pattern Overview\n\n1. **Root Directive** (`sc-notification-center`): Manages all state, computed values, and business logic\n2. **Container Component** (`sc-notification-center-container`): Renders the UI and delegates actions to the directive\n3. **Dependency Injection**: The container accesses the directive's state via the `SC_NOTIFICATION_CENTER` injection token\n\n### Benefits\n\n- **Separation of Concerns**: State management is isolated from UI rendering\n- **Flexibility**: You can access directive state via template references for custom implementations\n- **Reusability**: The directive can be used with custom containers or UI implementations\n- **Testability**: Business logic in the directive is easier to test in isolation\n\n### Example with Template Reference\n\n```html\n<div scNotificationCenter #center=\"scNotificationCenter\" [(notifications)]=\"notifications\">\n <!-- Access state -->\n <p>Total unread: {{ center.totalUnread() }}</p>\n <p>Filtered: {{ center.filteredNotifications().length }}</p>\n\n <!-- Use the standard container -->\n <div scNotificationCenterContainer></div>\n</div>\n```\n\n### Custom Implementation\n\nYou can build custom UIs by accessing the directive's state:\n\n```html\n<div scNotificationCenter #center=\"scNotificationCenter\" [(notifications)]=\"notifications\">\n <!-- Custom UI using directive state -->\n <div class=\"custom-header\">\n <h2>{{ center.title() }}</h2>\n <span class=\"badge\">{{ center.totalUnread() }}</span>\n </div>\n\n <!-- Custom notification list -->\n @for (notification of center.filteredNotifications(); track notification.id) {\n <div class=\"custom-notification\">\n {{ notification.title }}\n <button (click)=\"center.onDismiss(notification)\">Dismiss</button>\n </div>\n }\n</div>\n```\n\n## Type Definitions\n\n### Notification\n\n```typescript\ninterface Notification {\n id: string;\n title: string;\n description?: string;\n type: NotificationType;\n timestamp: Date;\n read: boolean;\n groupId?: string; // Links to NotificationGroup.id\n avatar?: string; // URL for avatar image\n icon?: string; // Custom SVG icon\n action?: NotificationAction;\n metadata?: Record<string, unknown>;\n}\n```\n\n### NotificationType\n\n```typescript\ntype NotificationType = 'info' | 'success' | 'warning' | 'error' | 'message';\n```\n\nEach type has a distinct icon and color:\n\n- `info`: Gray info circle\n- `success`: Green checkmark\n- `warning`: Yellow/orange triangle\n- `error`: Red X circle\n- `message`: Blue chat bubble\n\n### NotificationAction\n\n```typescript\ninterface NotificationAction {\n label: string; // Button text\n url?: string; // Optional URL to navigate\n handler?: () => void; // Optional click handler\n}\n```\n\n### NotificationGroup\n\n```typescript\ninterface NotificationGroup {\n id: string;\n title: string;\n icon?: string; // Custom SVG icon\n collapsed?: boolean; // Initial collapsed state\n}\n```\n\n### NotificationFilter\n\n```typescript\ntype NotificationFilter = 'all' | 'unread' | 'read';\n```\n\n## Features\n\n- **Grouped Notifications**: Organize notifications by category\n- **Filtering**: Filter by all, unread, or read status\n- **Batch Actions**: Mark all as read, clear all, clear group\n- **Individual Actions**: Mark read, dismiss, custom action buttons\n- **Notification Types**: Visual indicators for info, success, warning, error, message\n- **Avatars**: Display user avatars for message-type notifications\n- **Timestamps**: Relative time display (5m ago, 2h ago, etc.)\n- **Collapsible Groups**: Expand/collapse notification groups\n- **Empty State**: Customizable empty state display\n- **Two-Way Binding**: Use `[(notifications)]` for automatic state sync\n\n## Accessibility\n\n- Notifications use `role=\"article\"` and are keyboard focusable\n- Groups use proper ARIA expanded states\n- All interactive elements have descriptive `aria-label` attributes\n- Focus indicators are visible for keyboard navigation\n- Notifications are contained in `role=\"feed\"` regions\n\n## Styling\n\nThe component uses Tailwind CSS classes and supports theming through CSS variables:\n\n- `--background` / `--foreground`: Base colors\n- `--muted` / `--muted-foreground`: Secondary colors\n- `--primary` / `--primary-foreground`: Accent/unread colors\n- `--ring`: Focus ring color\n\nNotification types use semantic colors:\n\n- Success: Green (`green-500`, `green-600`)\n- Warning: Yellow/Orange (`yellow-500`, `yellow-600`)\n- Error: Red (`red-500`, `red-600`)\n- Message: Blue (`blue-500`, `blue-600`)\n- Info: Muted gray\n",
|
|
30787
|
-
exports: []
|
|
30788
|
-
},
|
|
30789
|
-
{
|
|
30790
|
-
name: "number-field",
|
|
30791
|
-
readme: '# Number Field\n\nA composable numeric input component with scrubbing support, increment/decrement buttons, and label integration.\n\n## Architecture\n\nThe Number Field component follows a composable pattern with multiple sub-components:\n\n- **ScNumberField**: Root container that manages state and provides context\n- **ScNumberFieldScrubArea**: Interactive label area with mouse scrubbing to adjust values\n- **ScNumberFieldInputGroup**: Container for input and stepper buttons\n- **ScNumberFieldInput**: The numeric input field\n- **ScNumberFieldIncrement**: Button to increase value\n- **ScNumberFieldDecrement**: Button to decrease value\n\n## Basic Usage\n\n```html\n<div scNumberField [(value)]="quantity" [min]="1" [max]="10">\n <div scNumberFieldScrubArea>\n <label scLabel>Quantity</label>\n </div>\n\n <div scNumberFieldGroup>\n <button scNumberFieldDecrement></button>\n <input scNumberFieldInput />\n <button scNumberFieldIncrement></button>\n </div>\n</div>\n```\n\n## Components\n\n### ScNumberField\n\nRoot container directive that manages the numeric state and provides context to child components.\n\n**Selector:** `[scNumberField]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| --------------- | -------------------------- | ------- | -------------------------------- |\n| `min` | `number \\| null` | `null` | Minimum allowed value |\n| `max` | `number \\| null` | `null` | Maximum allowed value |\n| `step` | `number` | `1` | Increment/decrement step size |\n| `disabled` | `boolean` | `false` | Disabled state |\n| `allowEmpty` | `boolean` | `true` | Allow null/empty value |\n| `scrubSpeed` | `number` | `1` | Mouse scrubbing speed multiplier |\n| `formatOptions` | `Intl.NumberFormatOptions` | `{}` | Number formatting options |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n**Two-way Bindings:**\n\n| Binding | Type | Default | Description |\n| ------- | ---------------- | ------- | ------------- |\n| `value` | `number \\| null` | `null` | Current value |\n\n**Outputs:**\n\n| Output | Type | Description |\n| ------------- | ---------------- | -------------------------- |\n| `valueChange` | `number \\| null` | Emitted when value changes |\n\n### ScNumberFieldScrubArea\n\nAn interactive area (typically wrapping a label) that allows users to scrub (drag) to change the value.\n\n**Selector:** `[scNumberFieldScrubArea]`\n\n**Features:**\n\n- Click and drag horizontally to adjust value\n- Visual feedback with cursor change\n- Respects min/max boundaries\n- Configurable scrub speed\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n### ScNumberFieldInputGroup\n\nContainer for grouping the input field with increment/decrement buttons.\n\n**Selector:** `[scNumberFieldGroup]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n### ScNumberFieldInput\n\nThe input field for displaying and editing the numeric value.\n\n**Selector:** `input[scNumberFieldInput]`\n\n**Features:**\n\n- Automatic number formatting\n- Keyboard support (Arrow Up/Down)\n- Input validation\n- Respects disabled state\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n### ScNumberFieldIncrement\n\nButton to increase the value by the step amount.\n\n**Selector:** `button[scNumberFieldIncrement]`\n\n**Features:**\n\n- Auto-disables when max value reached\n- Custom icon support via content projection\n- Keyboard accessible\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n### ScNumberFieldDecrement\n\nButton to decrease the value by the step amount.\n\n**Selector:** `button[scNumberFieldDecrement]`\n\n**Features:**\n\n- Auto-disables when min value reached\n- Custom icon support via content projection\n- Keyboard accessible\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n## Examples\n\n### Basic with Label\n\n```html\n<div scNumberField [(value)]="count" [min]="0" [max]="100">\n <div scNumberFieldScrubArea>\n <label scLabel>Count</label>\n </div>\n\n <div scNumberFieldGroup>\n <button scNumberFieldDecrement></button>\n <input scNumberFieldInput />\n <button scNumberFieldIncrement></button>\n </div>\n</div>\n```\n\n### With Custom Step\n\n```html\n<div scNumberField [(value)]="price" [step]="0.5" [min]="0">\n <div scNumberFieldScrubArea>\n <label scLabel>Price</label>\n </div>\n\n <div scNumberFieldGroup>\n <button scNumberFieldDecrement></button>\n <input scNumberFieldInput />\n <button scNumberFieldIncrement></button>\n </div>\n</div>\n```\n\n### Decimal Values with Formatting\n\n```html\n<div scNumberField [(value)]="amount" [step]="0.01" [min]="0" [formatOptions]="{ minimumFractionDigits: 2, maximumFractionDigits: 2 }">\n <div scNumberFieldScrubArea>\n <label scLabel>Amount ($)</label>\n </div>\n\n <div scNumberFieldGroup>\n <button scNumberFieldDecrement></button>\n <input scNumberFieldInput />\n <button scNumberFieldIncrement></button>\n </div>\n</div>\n```\n\n### Custom Scrub Speed\n\n```html\n<div scNumberField [(value)]="opacity" [min]="0" [max]="100" [scrubSpeed]="0.5">\n <div scNumberFieldScrubArea>\n <label scLabel>Opacity (%)</label>\n </div>\n\n <div scNumberFieldGroup>\n <button scNumberFieldDecrement></button>\n <input scNumberFieldInput />\n <button scNumberFieldIncrement></button>\n </div>\n</div>\n```\n\n### Disabled State\n\n```html\n<div scNumberField [value]="10" [disabled]="true">\n <div scNumberFieldScrubArea>\n <label scLabel>Locked Value</label>\n </div>\n\n <div scNumberFieldGroup>\n <button scNumberFieldDecrement></button>\n <input scNumberFieldInput />\n <button scNumberFieldIncrement></button>\n </div>\n</div>\n```\n\n### Without Label (Input Group Only)\n\n```html\n<div scNumberField [(value)]="quantity" [min]="1" [max]="10">\n <div scNumberFieldGroup>\n <button scNumberFieldDecrement></button>\n <input scNumberFieldInput />\n <button scNumberFieldIncrement></button>\n </div>\n</div>\n```\n\n### Custom Icons\n\n```html\n<div scNumberField [(value)]="volume">\n <div scNumberFieldScrubArea>\n <label scLabel>Volume</label>\n </div>\n\n <div scNumberFieldGroup>\n <button scNumberFieldDecrement>\n <svg><!-- Custom minus icon --></svg>\n </button>\n <input scNumberFieldInput />\n <button scNumberFieldIncrement>\n <svg><!-- Custom plus icon --></svg>\n </button>\n </div>\n</div>\n```\n\n### With Description\n\n```html\n<div class="space-y-2">\n <div scNumberField [(value)]="age" [min]="0" [max]="120">\n <div scNumberFieldScrubArea>\n <label scLabel>Age</label>\n </div>\n\n <div scNumberFieldGroup>\n <button scNumberFieldDecrement></button>\n <input scNumberFieldInput />\n <button scNumberFieldIncrement></button>\n </div>\n </div>\n <p class="text-muted-foreground text-sm">Your age in years</p>\n</div>\n```\n\n## Scrubbing Behavior\n\nThe scrub area allows users to adjust values by clicking and dragging:\n\n1. **Click** on the scrub area (label)\n2. **Drag left** to decrease value\n3. **Drag right** to increase value\n4. The cursor changes to indicate scrubbing mode\n5. Value updates in real-time as you drag\n\n**Scrub Speed Formula:**\n\n```\nnewValue = currentValue + (mouseDeltaX * step * scrubSpeed)\n```\n\n## Keyboard Navigation\n\nWhen focused on the input field:\n\n| Key | Action |\n| ----------- | ---------------------- |\n| `ArrowUp` | Increment by step |\n| `ArrowDown` | Decrement by step |\n| `Tab` | Move to next focusable |\n| `Shift+Tab` | Move to prev focusable |\n| `Enter` | Confirm and blur |\n\n## Features\n\n- **Mouse Scrubbing**: Drag on label to adjust value\n- **Min/Max Constraints**: Enforce value boundaries\n- **Custom Step**: Support any step value including decimals\n- **Decimal Precision**: Handles floating-point precision correctly\n- **Number Formatting**: Optional Intl.NumberFormat support\n- **Empty Values**: Optional null value support\n- **Disabled State**: Full disabled support across all sub-components\n- **Keyboard Support**: Arrow keys for increment/decrement\n- **Two-way Binding**: Sync with `[(value)]`\n- **Composable**: Mix and match sub-components as needed\n\n## Accessibility\n\n- Proper ARIA attributes on input (`aria-valuemin`, `aria-valuemax`, `aria-valuenow`)\n- Labels properly associated with inputs\n- `aria-label` on increment/decrement buttons\n- Disabled states properly communicated\n- Keyboard navigation support\n- Focus management within component\n- Screen reader friendly value announcements\n\n## Styling\n\nAll components accept a `class` input for custom styling. Default styles provide:\n\n- Consistent border and spacing\n- Focus states with ring\n- Hover states on buttons\n- Disabled state opacity\n- Scrub area cursor feedback\n\n## Component Communication\n\nComponents communicate through the `SC_NUMBER_FIELD` injection token:\n\n```typescript\nexport const SC_NUMBER_FIELD = new InjectionToken<ScNumberField>(\'SC_NUMBER_FIELD\');\n```\n\nChild components inject the parent context to access:\n\n- Current value\n- Min/Max constraints\n- Step size\n- Disabled state\n- Increment/Decrement methods\n- Can increment/decrement computed values\n\n## Best Practices\n\n1. **Always provide a label** for accessibility, even if visually hidden\n2. **Set min/max** when there are logical boundaries\n3. **Use appropriate step values** for the data type (e.g., 0.01 for currency)\n4. **Adjust scrubSpeed** for different value ranges (smaller for large ranges)\n5. **Consider formatOptions** for displaying formatted numbers\n6. **Test keyboard navigation** to ensure accessibility\n',
|
|
30792
|
-
exports: [
|
|
30793
|
-
"ScNumberField",
|
|
30794
|
-
"SC_NUMBER_FIELD",
|
|
30795
|
-
"ScNumberFieldScrubArea",
|
|
30796
|
-
"ScNumberFieldInputGroup",
|
|
30797
|
-
"ScNumberFieldInput",
|
|
30798
|
-
"ScNumberFieldIncrement",
|
|
30799
|
-
"ScNumberFieldDecrement"
|
|
30800
|
-
]
|
|
30801
|
-
},
|
|
30802
|
-
{
|
|
30803
|
-
name: "opt-field",
|
|
30804
|
-
readme: null,
|
|
30805
|
-
exports: [
|
|
30806
|
-
"ScOptField",
|
|
30807
|
-
"ScOptFieldSlotGroup",
|
|
30808
|
-
"ScOptFieldSlot",
|
|
30809
|
-
"ScOptFieldSlotInput",
|
|
30810
|
-
"ScOptFieldSlotCaret",
|
|
30811
|
-
"ScOptFieldSlotChar",
|
|
30812
|
-
"ScOptFieldSeparator"
|
|
30813
|
-
]
|
|
30814
|
-
},
|
|
30815
|
-
{
|
|
30816
|
-
name: "org-chart",
|
|
30817
|
-
readme: "# Org Chart\n\nA hierarchical organization chart component for visualizing company structures and reporting relationships.\n\n## Installation\n\nImport the components from the org-chart module:\n\n```typescript\nimport { ScOrgChart } from '@/ui/org-chart';\nimport type { OrgChartNode, OrgChartNodeClickEvent } from '@/ui/org-chart';\n```\n\n## Usage\n\n### Basic Usage\n\n```html\n<sc-org-chart [data]=\"orgData\" (nodeClick)=\"onNodeClick($event)\" />\n```\n\n```typescript\norgData: OrgChartNode = {\n id: '1',\n name: 'John Smith',\n title: 'CEO',\n children: [\n {\n id: '2',\n name: 'Jane Doe',\n title: 'CTO',\n children: [\n { id: '3', name: 'Bob Wilson', title: 'Developer' },\n { id: '4', name: 'Alice Brown', title: 'Designer' },\n ],\n },\n {\n id: '5',\n name: 'Mike Johnson',\n title: 'CFO',\n },\n ],\n};\n\nonNodeClick(event: OrgChartNodeClickEvent): void {\n console.log('Clicked:', event.node.name);\n}\n```\n\n### Horizontal Layout\n\n```html\n<sc-org-chart [data]=\"orgData\" direction=\"horizontal\" />\n```\n\n### With Avatars\n\n```typescript\norgData: OrgChartNode = {\n id: '1',\n name: 'Sarah Johnson',\n title: 'CEO',\n avatar: 'https://example.com/sarah.jpg',\n children: [\n {\n id: '2',\n name: 'Michael Chen',\n title: 'CTO',\n avatar: 'https://example.com/michael.jpg',\n },\n ],\n};\n```\n\n### With Departments\n\n```typescript\norgData: OrgChartNode = {\n id: '1',\n name: 'John Smith',\n title: 'CEO',\n department: 'Executive',\n children: [\n {\n id: '2',\n name: 'Jane Doe',\n title: 'Engineering Manager',\n department: 'Engineering',\n },\n ],\n};\n```\n\n### Compact Mode\n\n```html\n<sc-org-chart [data]=\"orgData\" [compact]=\"true\" />\n```\n\n### Non-collapsible\n\n```html\n<sc-org-chart [data]=\"orgData\" [collapsible]=\"false\" />\n```\n\n### Initial Expanded State\n\n```typescript\norgData: OrgChartNode = {\n id: '1',\n name: 'John Smith',\n title: 'CEO',\n expanded: false, // Start collapsed\n children: [...],\n};\n```\n\n## API Reference\n\n### ScOrgChart\n\nThe main organization chart component.\n\n#### Inputs\n\n| Input | Type | Default | Description |\n| ------------- | ---------------------------- | ---------------------- | ----------------------------- |\n| `data` | `OrgChartNode \\| null` | `null` | Root node of the organization |\n| `direction` | `'vertical' \\| 'horizontal'` | `'vertical'` | Layout direction |\n| `collapsible` | `boolean` | `true` | Allow nodes to be collapsed |\n| `compact` | `boolean` | `false` | Use smaller node cards |\n| `ariaLabel` | `string` | `'Organization chart'` | Accessible label |\n| `class` | `string` | `''` | Additional CSS classes |\n\n#### Outputs\n\n| Output | Type | Description |\n| ------------ | ------------------------- | ----------------------------------------- |\n| `nodeClick` | `OrgChartNodeClickEvent` | Emitted when a node is clicked |\n| `nodeExpand` | `OrgChartNodeExpandEvent` | Emitted when a node is expanded/collapsed |\n\n### ScOrgChartNode\n\nIndividual node component (used internally, can also be used directly for custom layouts).\n\n#### Inputs\n\n| Input | Type | Default | Description |\n| ------------- | ------------------- | ------------ | --------------------- |\n| `node` | `OrgChartNode` | (required) | Node data to display |\n| `direction` | `OrgChartDirection` | `'vertical'` | Layout direction |\n| `collapsible` | `boolean` | `true` | Allow collapse |\n| `compact` | `boolean` | `false` | Use compact card size |\n\n## Type Definitions\n\n### OrgChartNode\n\n```typescript\ninterface OrgChartNode {\n id: string;\n name: string;\n title?: string;\n avatar?: string;\n department?: string;\n children?: OrgChartNode[];\n expanded?: boolean;\n data?: Record<string, unknown>;\n}\n```\n\n### OrgChartNodeClickEvent\n\n```typescript\ninterface OrgChartNodeClickEvent {\n node: OrgChartNode;\n event: MouseEvent;\n}\n```\n\n### OrgChartNodeExpandEvent\n\n```typescript\ninterface OrgChartNodeExpandEvent {\n node: OrgChartNode;\n expanded: boolean;\n}\n```\n\n### OrgChartDirection\n\n```typescript\ntype OrgChartDirection = 'vertical' | 'horizontal';\n```\n\n## Node Properties\n\n| Property | Type | Required | Description |\n| ------------ | ------------------------- | -------- | -------------------------------- |\n| `id` | `string` | Yes | Unique identifier for the node |\n| `name` | `string` | Yes | Person's full name |\n| `title` | `string` | No | Job title or position |\n| `avatar` | `string` | No | URL to profile image |\n| `department` | `string` | No | Department or team name |\n| `children` | `OrgChartNode[]` | No | Direct reports (child nodes) |\n| `expanded` | `boolean` | No | Initial expanded state |\n| `data` | `Record<string, unknown>` | No | Custom data attached to the node |\n\n## Accessibility\n\nThe Org Chart component follows accessibility best practices:\n\n- Container has `role=\"tree\"` for screen readers\n- Nodes have `aria-expanded` attribute when collapsible\n- Each node has accessible label combining name and title\n- Focus indicators for keyboard navigation\n- Avatar images include proper alt text\n- Initials fallback for nodes without avatars\n\n## Keyboard Navigation\n\n| Key | Action |\n| ----- | ------------------------------------- |\n| Tab | Move focus between nodes |\n| Enter | Toggle expand/collapse, trigger click |\n| Space | Toggle expand/collapse, trigger click |\n\n## Styling\n\nThe component uses Tailwind CSS classes and supports theming:\n\n- Node cards use `bg-card` and `border` colors\n- Connectors use `bg-border` color\n- Avatar fallback uses `bg-primary/10` with `text-primary`\n- Hover states include shadow transitions\n\n### Custom Styling\n\n```html\n<sc-org-chart [data]=\"orgData\" class=\"[&_button]:shadow-lg\" />\n```\n\n## Features\n\n- Hierarchical tree structure visualization\n- Vertical and horizontal layout options\n- Collapsible nodes with smooth expand/collapse\n- Avatar support with initials fallback\n- Department and title display\n- Compact mode for dense hierarchies\n- Connector lines between nodes\n- Click and expand event handlers\n- Custom data attachment\n- Recursive rendering\n- Full keyboard and screen reader support\n\n## Use Cases\n\n- Company organization charts\n- Team hierarchy visualization\n- Management reporting structures\n- Department org charts\n- Project team structures\n- Family trees\n- Any hierarchical relationship visualization\n",
|
|
30818
|
-
exports: []
|
|
30819
|
-
},
|
|
30820
|
-
{
|
|
30821
|
-
name: "password-field",
|
|
30822
|
-
readme: '# Password Field\n\nA composable password input component with visibility toggle and optional strength indicator.\n\n## Architecture\n\nThe Password Field component follows a composable pattern with multiple sub-components:\n\n- **ScPasswordField**: Root container that manages state and provides context\n- **ScPasswordFieldInputGroup**: Container for input and toggle button\n- **ScPasswordFieldInput**: The password input field\n- **ScPasswordFieldToggle**: Button to toggle password visibility\n\n## Basic Usage\n\n```html\n<div scPasswordField [(value)]="password">\n <div scPasswordFieldInputGroup>\n <input scPasswordFieldInput placeholder="Enter password" />\n <button scPasswordFieldToggle></button>\n </div>\n</div>\n```\n\n## Components\n\n### ScPasswordField\n\nRoot container directive that manages the password state and visibility.\n\n**Selector:** `[scPasswordField]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| --------------- | --------- | ------- | ------------------------ |\n| `disabled` | `boolean` | `false` | Disabled state |\n| `showByDefault` | `boolean` | `false` | Show password by default |\n\n**Two-way Bindings:**\n\n| Binding | Type | Default | Description |\n| ------- | -------- | ------- | ------------- |\n| `value` | `string` | `\'\'` | Current value |\n\n**Outputs:**\n\n| Output | Type | Description |\n| ------------------ | --------- | ------------------------------- |\n| `valueChange` | `string` | Emitted when value changes |\n| `visibilityChange` | `boolean` | Emitted when visibility toggles |\n\n### ScPasswordFieldInputGroup\n\nContainer for grouping the input field with the toggle button.\n\n**Selector:** `[scPasswordFieldInputGroup]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n### ScPasswordFieldInput\n\nThe password input field.\n\n**Selector:** `input[scPasswordFieldInput]`\n\n**Features:**\n\n- Auto-switches between password/text type\n- Supports placeholder, autocomplete\n- Respects disabled/readonly states\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| -------------- | --------- | -------------------- | ---------------------- |\n| `placeholder` | `string` | `\'\'` | Placeholder text |\n| `readonly` | `boolean` | `false` | Readonly state |\n| `autocomplete` | `string` | `\'current-password\'` | Autocomplete attribute |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n### ScPasswordFieldToggle\n\nButton to toggle password visibility.\n\n**Selector:** `button[scPasswordFieldToggle]`\n\n**Features:**\n\n- Auto-disables when field is disabled\n- Shows eye/eye-off icons\n- Custom icon support via content projection\n- Keyboard accessible\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n## Examples\n\n### Basic\n\n```html\n<div scPasswordField [(value)]="password">\n <div scPasswordFieldInputGroup>\n <input scPasswordFieldInput placeholder="Enter password" />\n <button scPasswordFieldToggle></button>\n </div>\n</div>\n```\n\n### With Label\n\n```html\n<div class="space-y-2">\n <label scLabel for="password">Password</label>\n <div scPasswordField [(value)]="password">\n <div scPasswordFieldInputGroup>\n <input scPasswordFieldInput id="password" placeholder="Enter password" />\n <button scPasswordFieldToggle></button>\n </div>\n </div>\n</div>\n```\n\n### Show by Default\n\n```html\n<div scPasswordField [(value)]="password" [showByDefault]="true">\n <div scPasswordFieldInputGroup>\n <input scPasswordFieldInput placeholder="API Key" />\n <button scPasswordFieldToggle></button>\n </div>\n</div>\n```\n\n### Disabled\n\n```html\n<div scPasswordField [value]="\'********\'" [disabled]="true">\n <div scPasswordFieldInputGroup>\n <input scPasswordFieldInput />\n <button scPasswordFieldToggle></button>\n </div>\n</div>\n```\n\n### New Password\n\n```html\n<div scPasswordField [(value)]="newPassword">\n <div scPasswordFieldInputGroup>\n <input scPasswordFieldInput placeholder="New password" autocomplete="new-password" />\n <button scPasswordFieldToggle></button>\n </div>\n</div>\n```\n\n### Custom Icons\n\n```html\n<div scPasswordField [(value)]="password">\n <div scPasswordFieldInputGroup>\n <input scPasswordFieldInput />\n <button scPasswordFieldToggle>\n <!-- Custom icon content -->\n @if (visible()) {\n <span>Hide</span>\n } @else {\n <span>Show</span>\n }\n </button>\n </div>\n</div>\n```\n\n### With Description\n\n```html\n<div class="space-y-2">\n <label scLabel>Password</label>\n <div scPasswordField [(value)]="password">\n <div scPasswordFieldInputGroup>\n <input scPasswordFieldInput />\n <button scPasswordFieldToggle></button>\n </div>\n </div>\n <p class="text-muted-foreground text-sm">Must be at least 8 characters</p>\n</div>\n```\n\n## Features\n\n- **Visibility Toggle**: Show/hide password text\n- **Disabled State**: Full disabled support across all sub-components\n- **Autocomplete Support**: Proper autocomplete attributes\n- **Two-way Binding**: Sync with `[(value)]`\n- **Composable**: Mix and match sub-components as needed\n- **Accessible**: Proper ARIA labels and keyboard support\n\n## Accessibility\n\n- Proper `aria-label` on toggle button\n- `aria-pressed` state on toggle button\n- Labels properly associated with inputs\n- Disabled states properly communicated\n- Focus management within component\n- Screen reader friendly announcements\n\n## Styling\n\nAll components accept a `class` input for custom styling. Default styles provide:\n\n- Consistent border and spacing\n- Focus states with ring\n- Hover states on toggle button\n- Disabled state opacity\n- Proper positioning for toggle button\n\n## Component Communication\n\nComponents communicate through the `SC_PASSWORD_FIELD` injection token:\n\n```typescript\nexport const SC_PASSWORD_FIELD = new InjectionToken<ScPasswordField>(\'SC_PASSWORD_FIELD\');\n```\n\nChild components inject the parent context to access:\n\n- Current value\n- Visibility state\n- Disabled state\n- Toggle methods\n\n## Best Practices\n\n1. **Always provide a label** for accessibility\n2. **Use appropriate autocomplete** values (current-password, new-password)\n3. **Add password requirements** in description text\n4. **Consider password strength** indicators for new passwords\n5. **Test keyboard navigation** to ensure accessibility\n',
|
|
30823
|
-
exports: [
|
|
30824
|
-
"ScPasswordField",
|
|
30825
|
-
"SC_PASSWORD_FIELD",
|
|
30826
|
-
"ScPasswordFieldInputGroup",
|
|
30827
|
-
"ScPasswordFieldInput",
|
|
30828
|
-
"ScPasswordFieldToggle",
|
|
30829
|
-
"ScPasswordFieldStrengthBar",
|
|
30830
|
-
"ScPasswordFieldStrength",
|
|
30831
|
-
"ScPasswordFieldRequirements"
|
|
30832
|
-
]
|
|
30833
|
-
},
|
|
30834
|
-
{
|
|
30835
|
-
name: "pdf-viewer",
|
|
30836
|
-
readme: "# PDF Viewer\n\nA document viewer component for displaying PDF files with navigation, zoom, and toolbar controls.\n\n## Installation\n\nImport the components from the pdf-viewer module:\n\n```typescript\nimport { ScPdfViewer, ScPdfViewerToolbar } from '@/ui/pdf-viewer';\n```\n\n## Usage\n\n### Basic Usage\n\n```html\n<sc-pdf-viewer [src]=\"pdfUrl\" [title]=\"'My Document'\" class=\"h-[600px]\" />\n```\n\n### With Event Handlers\n\n```html\n<sc-pdf-viewer [src]=\"pdfUrl\" (loaded)=\"onLoaded($event)\" (pageChange)=\"onPageChange($event)\" (zoomChange)=\"onZoomChange($event)\" (errorEvent)=\"onError($event)\" />\n```\n\n```typescript\nimport type {\n PdfLoadEvent,\n PdfPageChangeEvent,\n PdfZoomChangeEvent,\n PdfErrorEvent,\n} from '@/ui/pdf-viewer';\n\nonLoaded(event: PdfLoadEvent): void {\n console.log('PDF loaded, total pages:', event.totalPages);\n}\n\nonPageChange(event: PdfPageChangeEvent): void {\n console.log('Page:', event.currentPage, '/', event.totalPages);\n}\n\nonZoomChange(event: PdfZoomChangeEvent): void {\n console.log('Zoom level:', event.zoom, 'Scale:', event.scale);\n}\n\nonError(event: PdfErrorEvent): void {\n console.error('Error loading PDF:', event.message);\n}\n```\n\n### Without Toolbar\n\n```html\n<sc-pdf-viewer [src]=\"pdfUrl\" [showToolbar]=\"false\" />\n```\n\n### Custom Toolbar Configuration\n\n```html\n<sc-pdf-viewer\n [src]=\"pdfUrl\"\n [toolbarConfig]=\"{\n showNavigation: true,\n showPageInfo: true,\n showZoom: true,\n showRotate: false,\n showDownload: true,\n showPrint: false,\n showFullscreen: true\n }\"\n/>\n```\n\n### Initial Page and Zoom\n\n```html\n<sc-pdf-viewer [src]=\"pdfUrl\" [initialPage]=\"3\" [initialZoom]=\"1.5\" />\n```\n\n### Programmatic Control\n\n```typescript\nimport { viewChild } from '@angular/core';\nimport { ScPdfViewer } from '@/ui/pdf-viewer';\n\nreadonly pdfViewer = viewChild(ScPdfViewer);\n\ngoToPage(page: number): void {\n this.pdfViewer()?.setPage(page);\n}\n\nsetZoom(level: PdfZoomLevel): void {\n this.pdfViewer()?.setZoom(level);\n}\n```\n\n## API Reference\n\n### ScPdfViewer\n\nThe main PDF viewer component.\n\n#### Inputs\n\n| Input | Type | Default | Description |\n| --------------- | ------------------ | ------------------------ | ---------------------------------- |\n| `src` | `string` | `''` | URL of the PDF document |\n| `title` | `string` | `''` | Document title for a11y & download |\n| `showToolbar` | `boolean` | `true` | Show or hide the toolbar |\n| `toolbarConfig` | `PdfToolbarConfig` | `DEFAULT_TOOLBAR_CONFIG` | Configure toolbar controls |\n| `initialPage` | `number` | `1` | Initial page to display |\n| `initialZoom` | `PdfZoomLevel` | `'auto'` | Initial zoom level |\n| `class` | `string` | `''` | Additional CSS classes |\n\n#### Outputs\n\n| Output | Type | Description |\n| ------------ | -------------------- | -------------------------- |\n| `loaded` | `PdfLoadEvent` | Emitted when PDF is loaded |\n| `pageChange` | `PdfPageChangeEvent` | Emitted when page changes |\n| `zoomChange` | `PdfZoomChangeEvent` | Emitted when zoom changes |\n| `errorEvent` | `PdfErrorEvent` | Emitted on load error |\n\n#### Public Methods\n\n| Method | Parameters | Description |\n| ----------------- | --------------------- | --------------------------- |\n| `setPage()` | `page: number` | Navigate to a specific page |\n| `setZoom()` | `level: PdfZoomLevel` | Set the zoom level |\n| `setTotalPages()` | `total: number` | Set total page count |\n\n### ScPdfViewerToolbar\n\nStandalone toolbar component (used internally or separately).\n\n## Type Definitions\n\n### PdfToolbarConfig\n\n```typescript\ninterface PdfToolbarConfig {\n showNavigation?: boolean; // Page navigation buttons\n showZoom?: boolean; // Zoom controls\n showDownload?: boolean; // Download button\n showPrint?: boolean; // Print button\n showFullscreen?: boolean; // Fullscreen toggle\n showPageInfo?: boolean; // Page number display\n showRotate?: boolean; // Rotate buttons\n}\n```\n\n### PdfZoomLevel\n\n```typescript\ntype PdfZoomLevel = 'auto' | 'page-fit' | 'page-width' | number;\n```\n\nAvailable zoom presets:\n\n- `'auto'` - Automatic fit\n- `'page-fit'` - Fit entire page\n- `'page-width'` - Fit to page width\n- `number` - Specific scale (e.g., `1.5` for 150%)\n\n### Event Types\n\n```typescript\ninterface PdfLoadEvent {\n totalPages: number;\n}\n\ninterface PdfPageChangeEvent {\n currentPage: number;\n totalPages: number;\n}\n\ninterface PdfZoomChangeEvent {\n zoom: PdfZoomLevel;\n scale: number;\n}\n\ninterface PdfErrorEvent {\n error: Error;\n message: string;\n}\n```\n\n## Features\n\n- **Native PDF Rendering**: Uses browser's built-in PDF viewer for maximum compatibility\n- **Page Navigation**: Previous/next buttons and direct page input\n- **Zoom Controls**: Zoom in/out, preset levels, and custom percentages\n- **Rotation**: Rotate document left or right\n- **Download**: Download the PDF file\n- **Print**: Print the document\n- **Fullscreen**: Toggle fullscreen viewing mode\n- **Loading State**: Shows spinner while PDF is loading\n- **Error Handling**: Displays error message with retry option\n- **Empty State**: Placeholder when no PDF is loaded\n- **Customizable Toolbar**: Show/hide individual controls\n- **Keyboard Accessible**: All controls are keyboard navigable\n\n## Styling\n\nThe component uses Tailwind CSS classes and supports theming through CSS variables:\n\n- `--background` / `--foreground`: Base colors\n- `--muted` / `--muted-foreground`: Secondary colors\n- `--primary` / `--primary-foreground`: Accent colors\n- `--destructive`: Error colors\n- `--ring`: Focus ring color\n- `--border`: Border colors\n\n## Notes\n\n- **CORS**: PDF URLs must be served with appropriate CORS headers for cross-origin access\n- **Browser Support**: Uses native browser PDF rendering via `<object>` and `<iframe>` elements\n- **Page Count**: For accurate page count tracking, consider integrating PDF.js\n- **Print/Download**: Depends on browser permissions and PDF URL accessibility\n- **Security**: Be cautious with user-provided PDF URLs to prevent security issues\n",
|
|
30837
|
-
exports: []
|
|
30838
|
-
},
|
|
30839
|
-
{
|
|
30840
|
-
name: "phone-input",
|
|
30841
|
-
readme: "# Phone Input\n\nPhone number input with country code selector and formatting options.\n\n## Components\n\n- `ScPhoneInput` - Full phone input with searchable country dropdown\n- `ScPhoneInputSimple` - Simple phone input with automatic formatting\n\n## Usage\n\n### With Country Selector\n\n```html\n<sc-phone-input [(value)]=\"phone\" [(countryCode)]=\"country\" defaultCountry=\"US\" (countryChange)=\"onCountryChange($event)\" />\n```\n\n### Simple Input (US Format)\n\n```html\n<sc-phone-input-simple [(value)]=\"phone\" format=\"us\" placeholder=\"(555) 555-5555\" />\n```\n\n### Simple Input (International Format)\n\n```html\n<sc-phone-input-simple [(value)]=\"phone\" format=\"international\" placeholder=\"+1 555 555 5555\" />\n```\n\n## API\n\n### ScPhoneInput\n\n| Input | Type | Default | Description |\n| ---------------- | ----------- | ---------------- | ---------------------- |\n| `class` | `string` | `''` | Additional CSS classes |\n| `placeholder` | `string` | `'Phone number'` | Placeholder text |\n| `disabled` | `boolean` | `false` | Disable the input |\n| `defaultCountry` | `string` | `'US'` | Default country code |\n| `countries` | `Country[]` | `COUNTRIES` | Custom country list |\n\n| Output | Type | Description |\n| --------------- | --------- | ------------------------------------ |\n| `value` | `string` | Two-way binding for full number |\n| `countryCode` | `string` | Two-way binding for country code |\n| `valueChange` | `string` | Emits full number with dial code |\n| `countryChange` | `Country` | Emits when country selection changes |\n\n| Method | Returns | Description |\n| ------------------ | ---------------------- | ------------------------------ |\n| `focus()` | `void` | Focus the phone input |\n| `getFullNumber()` | `string` | Get full number with dial code |\n| `getPhoneNumber()` | `string` | Get phone number only |\n| `getCountry()` | `Country \\| undefined` | Get selected country |\n\n### ScPhoneInputSimple\n\n| Input | Type | Default | Description |\n| ------------- | ----------------------------------- | ------------------ | ---------------------- |\n| `class` | `string` | `''` | Additional CSS classes |\n| `placeholder` | `string` | `'(555) 555-5555'` | Placeholder text |\n| `disabled` | `boolean` | `false` | Disable the input |\n| `showIcon` | `boolean` | `true` | Show phone icon |\n| `format` | `'us' \\| 'international' \\| 'none'` | `'us'` | Number format |\n\n| Output | Type | Description |\n| ------- | -------- | ------------------------------- |\n| `value` | `string` | Two-way binding for phone value |\n\n| Method | Returns | Description |\n| --------------- | -------- | --------------------------- |\n| `focus()` | `void` | Focus the input |\n| `getRawValue()` | `string` | Get digits only (no format) |\n\n## Country Interface\n\n```typescript\ninterface Country {\n code: string; // ISO 3166-1 alpha-2 (e.g., 'US')\n name: string; // Full country name\n dialCode: string; // Dial code with + (e.g., '+1')\n flag: string; // Flag emoji\n}\n```\n\n## Format Options\n\n| Format | Example Output | Description |\n| --------------- | ----------------- | -------------------------- |\n| `us` | `(555) 555-5555` | US phone number format |\n| `international` | `+1 555 555 5555` | International format |\n| `none` | `5555555555` | Digits only, no formatting |\n\n## Utility Functions\n\n```typescript\nimport { COUNTRIES, getCountryByCode, getCountryByDialCode } from './countries';\n\n// Get all countries\nconst allCountries = COUNTRIES;\n\n// Find country by ISO code\nconst usa = getCountryByCode('US');\n\n// Find country by dial code\nconst uk = getCountryByDialCode('+44');\n```\n\n## Examples\n\n### Contact Form\n\n```html\n<form class=\"space-y-4\">\n <div>\n <label>Name</label>\n <input type=\"text\" />\n </div>\n <div>\n <label>Phone</label>\n <sc-phone-input defaultCountry=\"US\" />\n </div>\n <button type=\"submit\">Submit</button>\n</form>\n```\n\n### With Validation\n\n```typescript\n@Component({\n template: `\n <sc-phone-input #phone [(value)]=\"phoneNumber\" />\n @if (phoneNumber() && phoneNumber().length < 10) {\n <p class=\"text-destructive text-sm\">Please enter a valid phone number</p>\n }\n `,\n})\nexport class PhoneForm {\n phoneNumber = signal('');\n}\n```\n\n### Custom Country List\n\n```typescript\nconst europeanCountries: Country[] = [\n { code: 'GB', name: 'United Kingdom', dialCode: '+44', flag: '\u{1F1EC}\u{1F1E7}' },\n { code: 'DE', name: 'Germany', dialCode: '+49', flag: '\u{1F1E9}\u{1F1EA}' },\n { code: 'FR', name: 'France', dialCode: '+33', flag: '\u{1F1EB}\u{1F1F7}' },\n];\n\n// In template\n<sc-phone-input [countries]=\"europeanCountries\" defaultCountry=\"GB\" />\n```\n\n## Accessibility\n\n- Country selector button has `aria-expanded` and `aria-haspopup`\n- Country options have `role=\"option\"` and `aria-selected`\n- Search input in dropdown for easy filtering\n- Keyboard navigation support (Enter to select, Escape to close)\n- Phone icon is decorative (no aria-label needed)\n\n## Included Countries\n\nThe default `COUNTRIES` array includes 50+ countries covering:\n\n- North America (US, CA, MX)\n- Europe (UK, DE, FR, IT, ES, etc.)\n- Asia Pacific (JP, KR, CN, AU, SG, etc.)\n- Middle East (AE, SA, IL)\n- South America (BR, AR, CL, etc.)\n- Africa (ZA, NG, KE, EG)\n",
|
|
30842
|
-
exports: []
|
|
30843
|
-
},
|
|
30844
|
-
{
|
|
30845
|
-
name: "qr-code",
|
|
30846
|
-
readme: "# QR Code\n\nGenerate QR codes from text or URLs with customizable colors and optional logo support.\n\n## Components\n\n- `ScQrCode` - Basic QR code generator\n- `ScQrCodeDownload` - QR code with download button\n\n## Usage\n\n```html\n<sc-qr-code [value]=\"'https://example.com'\" [size]=\"200\" />\n```\n\n## API\n\n### ScQrCode\n\n| Input | Type | Default | Description |\n| ---------------------- | -------------------------- | ----------- | ---------------------- |\n| `value` | `string` | _required_ | Text or URL to encode |\n| `size` | `number` | `200` | Size in pixels |\n| `errorCorrectionLevel` | `'L' \\| 'M' \\| 'Q' \\| 'H'` | `'M'` | Error correction level |\n| `foregroundColor` | `string` | `'#000000'` | Module color |\n| `backgroundColor` | `string` | `'#ffffff'` | Background color |\n| `quietZone` | `number` | `2` | Quiet zone modules |\n| `logo` | `string` | `''` | Logo image URL |\n| `logoSize` | `number` | `0.2` | Logo size (0-1) |\n| `ariaLabel` | `string` | `'QR Code'` | Accessibility label |\n| `class` | `string` | - | Additional CSS classes |\n\n### ScQrCodeDownload\n\nExtends `ScQrCode` with:\n\n| Input | Type | Default | Description |\n| --------------- | --------- | ------------ | -------------------- |\n| `showDownload` | `boolean` | `true` | Show download button |\n| `downloadLabel` | `string` | `'Download'` | Button label |\n| `filename` | `string` | `'qrcode'` | Download filename |\n\n### Error Correction Levels\n\n| Level | Recovery | Use Case |\n| ----- | -------- | --------------------- |\n| `L` | ~7% | Clean environments |\n| `M` | ~15% | General use (default) |\n| `Q` | ~25% | Industrial use |\n| `H` | ~30% | With logo overlay |\n\n## Examples\n\n### Basic QR Code\n\n```html\n<sc-qr-code [value]=\"'https://example.com'\" />\n```\n\n### Custom Colors\n\n```html\n<sc-qr-code [value]=\"'Hello World'\" [foregroundColor]=\"'#1d4ed8'\" [backgroundColor]=\"'#dbeafe'\" />\n```\n\n### With Logo\n\nUse high error correction when adding a logo:\n\n```html\n<sc-qr-code [value]=\"'https://example.com'\" [errorCorrectionLevel]=\"'H'\" [logo]=\"'/assets/logo.svg'\" [logoSize]=\"0.25\" />\n```\n\n### Different Sizes\n\n```html\n<sc-qr-code [value]=\"'Small'\" [size]=\"100\" />\n<sc-qr-code [value]=\"'Medium'\" [size]=\"150\" />\n<sc-qr-code [value]=\"'Large'\" [size]=\"200\" />\n```\n\n### With Download\n\n```html\n<sc-qr-code-download [value]=\"'https://example.com'\" [filename]=\"'my-qr-code'\" [downloadLabel]=\"'Save QR Code'\" />\n```\n\n### Common Use Cases\n\n```html\n<!-- Website URL -->\n<sc-qr-code [value]=\"'https://example.com'\" />\n\n<!-- Phone number -->\n<sc-qr-code [value]=\"'tel:+1234567890'\" />\n\n<!-- Email -->\n<sc-qr-code [value]=\"'mailto:hello@example.com'\" />\n\n<!-- WiFi -->\n<sc-qr-code [value]=\"'WIFI:T:WPA;S:NetworkName;P:password;;'\" />\n\n<!-- SMS -->\n<sc-qr-code [value]=\"'sms:+1234567890?body=Hello'\" />\n\n<!-- vCard -->\n<sc-qr-code [value]=\"'BEGIN:VCARD\\nVERSION:3.0\\nN:Doe;John\\nEND:VCARD'\" />\n```\n\n## Features\n\n- Pure TypeScript QR code generation (no external dependencies)\n- SVG-based rendering for sharp display at any size\n- Customizable colors\n- Logo overlay support\n- Multiple error correction levels\n- Adjustable quiet zone\n- Download as PNG\n\n## Accessibility\n\n- ARIA role=\"img\" with customizable label\n- High contrast between modules and background\n- Works with screen readers\n",
|
|
30847
|
-
exports: []
|
|
30848
|
-
},
|
|
30849
|
-
{
|
|
30850
|
-
name: "rating-field",
|
|
30851
|
-
readme: '# Rating Field Component\n\nA composable rating field component for Angular applications, built with a three-tier directive architecture for maximum flexibility and accessibility.\n\n## Architecture\n\nThe component consists of three directives:\n\n1. **ScRatingField** - Parent directive managing value state and configuration\n2. **ScRatingItemGroup** - Container directive managing hover state and keyboard navigation\n3. **ScRatingItem** - Individual rating item directive\n\n## Basic Usage\n\n```html\n<div scRatingField [(value)]="rating">\n <div scRatingItemGroup>\n @for (i of [1, 2, 3, 4, 5]; track i) {\n <span scRatingItem [value]="i">\n <svg si-star-icon class="size-5"></svg>\n </span>\n }\n </div>\n</div>\n```\n\n## Features\n\n- **Two-way binding** - Use `[(value)]` for reactive value updates\n- **Hover preview** - Visual feedback shows rating before selection\n- **Half-star support** - Enable `[allowHalf]="true"` for 0.5 increments\n- **Custom icons** - Use any icon (stars, hearts, etc.)\n- **Keyboard navigation** - Full arrow key, Home, End support\n- **Accessibility** - WCAG AA compliant with proper ARIA attributes\n- **Readonly/Disabled states** - Control interactivity\n- **Clear capability** - Click same value to reset (configurable)\n\n## API\n\n### ScRatingField\n\n| Input | Type | Default | Description |\n| ---------------- | --------- | ------- | ------------------------------------------- |\n| `value` | `number` | `0` | Current rating value (use with `[(value)]`) |\n| `allowHalf` | `boolean` | `false` | Enable half-star ratings |\n| `allowClear` | `boolean` | `true` | Allow clearing by clicking same value |\n| `readonly` | `boolean` | `false` | Make the rating read-only |\n| `disabled` | `boolean` | `false` | Disable the rating |\n| `label` | `string` | `\'\'` | Accessible label for the rating |\n| `ariaLabelledby` | `string` | `\'\'` | ID of element labeling the rating |\n\n**Note:** The `max` value is automatically calculated from the highest `value` among all rating items.\n\n### ScRatingItemGroup\n\nContainer directive that manages hover state and keyboard navigation. No inputs required.\n\n### ScRatingItem\n\n| Input | Type | Required | Description |\n| ------- | -------- | -------- | ------------------------------------- |\n| `value` | `number` | Yes | The rating value this item represents |\n\n## Examples\n\n### Half-Star Rating\n\n```html\n<div scRatingField [(value)]="rating" [allowHalf]="true">\n <div scRatingItemGroup>\n @for (i of [1, 2, 3, 4, 5]; track i) {\n <span scRatingItem [value]="i">\n <svg si-star-icon class="size-6"></svg>\n </span>\n }\n </div>\n</div>\n```\n\n### Custom Icons (Hearts)\n\n```html\n<div scRatingField [(value)]="rating">\n <div scRatingItemGroup>\n @for (i of [1, 2, 3, 4, 5]; track i) {\n <span scRatingItem [value]="i">\n <svg si-heart-icon class="size-5"></svg>\n </span>\n }\n </div>\n</div>\n```\n\n### Readonly Display\n\n```html\n<div scRatingField [value]="4.5" [readonly]="true">\n <div scRatingItemGroup>\n @for (i of [1, 2, 3, 4, 5]; track i) {\n <span scRatingItem [value]="i">\n <svg si-star-icon class="size-5"></svg>\n </span>\n }\n </div>\n</div>\n```\n\n## Accessibility\n\nThe component implements WCAG AA accessibility standards:\n\n- **ARIA roles**: `group` for container, `radiogroup` for items container, `radio` for items\n- **ARIA attributes**: `aria-label`, `aria-labelledby`, `aria-checked`, `aria-valuenow/min/max`\n- **Keyboard navigation**: Arrow keys, Home, End, Space, Enter\n- **Focus management**: Roving tabindex pattern for optimal keyboard navigation\n- **Screen reader support**: Announces current value and changes\n\n## Keyboard Shortcuts\n\n- **Arrow Right/Up**: Increase rating by step (1 or 0.5)\n- **Arrow Left/Down**: Decrease rating by step\n- **Home**: Set to minimum (0)\n- **End**: Set to maximum\n- **Space/Enter**: Select focused item\n\n## Styling\n\nItems expose a `data-state` attribute with values:\n\n- `full` - Item is fully selected\n- `half` - Item is half selected (when `allowHalf` is enabled)\n- `empty` - Item is not selected\n\nUse CSS to style based on state:\n\n```css\n[scRatingItem][data-state=\'full\'] svg {\n fill: gold;\n color: gold;\n}\n\n[scRatingItem][data-state=\'half\'] svg {\n fill: url(#half-gradient);\n}\n\n[scRatingItem][data-state=\'empty\'] svg {\n fill: none;\n color: gray;\n}\n```\n',
|
|
30852
|
-
exports: []
|
|
30853
|
-
},
|
|
30854
|
-
{
|
|
30855
|
-
name: "search-input",
|
|
30856
|
-
readme: "# Search Input\n\nA search input with autocomplete suggestions, debounced search, and keyboard navigation.\n\n## Installation\n\n```typescript\nimport { ScSearchInput } from '@/ui/search-input';\nimport type { SearchSuggestion, SearchInputOptions } from '@/ui/search-input';\n```\n\n## Usage\n\n### Basic Usage\n\n```html\n<sc-search-input [suggestions]=\"suggestions\" (search)=\"onSearch($event)\" (suggestionSelect)=\"onSelect($event)\" />\n```\n\n```typescript\nsuggestions: SearchSuggestion[] = [\n { id: '1', label: 'Apple', description: 'A fruit' },\n { id: '2', label: 'Banana', description: 'A yellow fruit' },\n];\n\nonSearch(query: string): void {\n console.log('Search:', query);\n}\n\nonSelect(suggestion: SearchSuggestion): void {\n console.log('Selected:', suggestion);\n}\n```\n\n### With Loading State\n\n```html\n<sc-search-input [suggestions]=\"results\" [loading]=\"isLoading\" (search)=\"onAsyncSearch($event)\" />\n```\n\n### With Categories\n\n```typescript\nsuggestions: SearchSuggestion[] = [\n { id: '1', label: 'MacBook Pro', description: 'Laptop', category: 'Electronics' },\n { id: '2', label: 'Nike Air Max', description: 'Shoes', category: 'Footwear' },\n];\n```\n\n## API Reference\n\n### Inputs\n\n| Input | Type | Default | Description |\n| ---------------- | -------------------- | ------------- | ------------------------ |\n| `suggestions` | `SearchSuggestion[]` | `[]` | Autocomplete suggestions |\n| `placeholder` | `string` | `'Search...'` | Input placeholder |\n| `debounceMs` | `number` | `300` | Debounce delay in ms |\n| `minChars` | `number` | `1` | Min chars to trigger |\n| `maxSuggestions` | `number` | `10` | Max suggestions to show |\n| `loading` | `boolean` | `false` | Show loading spinner |\n| `class` | `string` | `''` | Additional CSS classes |\n\n### Outputs\n\n| Output | Type | Description |\n| ------------------ | ------------------ | ----------------------------- |\n| `search` | `string` | Emitted on debounced search |\n| `suggestionSelect` | `SearchSuggestion` | Emitted when item is selected |\n| `queryChange` | `string` | Emitted on every input change |\n\n### Methods\n\n| Method | Description |\n| --------- | ------------------ |\n| `clear()` | Clear search input |\n| `focus()` | Focus the input |\n\n## Type Definitions\n\n```typescript\ninterface SearchSuggestion {\n id: string;\n label: string;\n description?: string;\n icon?: string;\n category?: string;\n}\n```\n\n## Features\n\n- Debounced search to reduce API calls\n- Keyboard navigation (Arrow keys, Enter, Escape)\n- Loading state with spinner\n- Clear button\n- Category support for grouped suggestions\n- Click outside to close\n- Accessible with ARIA attributes\n",
|
|
30857
|
-
exports: []
|
|
30858
|
-
},
|
|
30859
30630
|
{
|
|
30860
30631
|
name: "signature-pad",
|
|
30861
30632
|
readme: '# Signature Pad\n\nCanvas-based signature capture component with touch and mouse support.\n\n## Composable Architecture\n\nThe signature pad uses a **composable architecture** that gives you full control over layout and functionality.\n\n### Basic Usage\n\n```typescript\nimport { ScSignaturePad, ScSignaturePadCanvas, ScSignaturePadControls, ScSignaturePadUndoButton, ScSignaturePadClearButton } from \'@semantic-components/ui-lab\';\nimport { SiUndoIcon, SiTrash2Icon } from \'@semantic-icons/lucide-icons\';\n\n@Component({\n imports: [ScSignaturePad, ScSignaturePadCanvas, ScSignaturePadControls, ScSignaturePadUndoButton, ScSignaturePadClearButton, SiUndoIcon, SiTrash2Icon],\n template: `\n <div scSignaturePad class="relative inline-block">\n <canvas scSignaturePadCanvas [(value)]="signature" [width]="400" [height]="200"></canvas>\n\n <div scSignaturePadControls>\n <button scSignaturePadUndo>\n <svg si-undo-icon class="size-4"></svg>\n </button>\n <button scSignaturePadClear>\n <svg si-trash-2-icon class="size-4"></svg>\n </button>\n </div>\n </div>\n `,\n})\nexport class MyComponent {\n readonly signature = signal(\'\');\n}\n```\n\n### Composable Components\n\n**`ScSignaturePad` (Directive)**\n\n- Root directive that provides context\n- Manages signature state and drawing logic\n- **Selector**: `[scSignaturePad]`\n- **Inputs**: `disabled`, `penColor`, `penWidth`, `backgroundColor`\n\n**`ScSignaturePadCanvas` (Component)**\n\n- Canvas element for drawing\n- **Selector**: `canvas[scSignaturePadCanvas]`\n- **Inputs**: `width`, `height`, `ariaLabel`, `class`\n- **Model**: `value` (two-way bindable data URL)\n- **Outputs**: `signatureChange`, `strokeEnd`\n\n**`ScSignaturePadControls` (Component)**\n\n- Container for control buttons (uses `<ng-content>`)\n- **Selector**: `div[scSignaturePadControls]`\n- **Default position**: `absolute top-2 right-2`\n\n**`ScSignaturePadUndoButton` (Component)**\n\n- Undo last stroke\n- **Selector**: `button[scSignaturePadUndo]`\n- **Auto-disabled**: When no strokes to undo\n\n**`ScSignaturePadClearButton` (Component)**\n\n- Clear entire signature\n- **Selector**: `button[scSignaturePadClear]`\n- **Auto-disabled**: When signature is empty\n\n**`ScSignaturePadToolbar` (Component)**\n\n- Optional container for toolbar items (uses `<ng-content>`)\n- **Selector**: `div[scSignaturePadToolbar]`\n- **Default styling**: Flex row with gap\n\n**`ScSignaturePadColorButton` (Component)**\n\n- Button to select pen color\n- **Selector**: `button[scSignaturePadPenColor]`\n- **Inputs**: `color` (required, hex color string)\n- **Auto-active**: When color matches current pen color\n\n**`ScSignaturePadWidthButton` (Component)**\n\n- Button to select pen width\n- **Selector**: `button[scSignaturePadPenWidth]`\n- **Inputs**: `width` (required, number in pixels)\n- **Auto-active**: When width matches current pen width\n\n### Flexible Examples\n\n#### Custom Button Layout\n\n```html\n<div scSignaturePad>\n <canvas scSignaturePadCanvas [width]="500" [height]="250"></canvas>\n\n <!-- Controls at bottom instead of top-right -->\n <div scSignaturePadControls class="static mt-2 justify-center">\n <button scSignaturePadUndo class="px-4 py-2">Undo</button>\n <button scSignaturePadClear class="px-4 py-2">Clear</button>\n </div>\n</div>\n```\n\n#### With Custom Buttons\n\n```html\n<div scSignaturePad #pad>\n <canvas scSignaturePadCanvas [(value)]="signature"></canvas>\n\n <div scSignaturePadControls>\n <button scSignaturePadUndo>\n <svg si-undo-icon></svg>\n </button>\n <button scSignaturePadClear>\n <svg si-trash-icon></svg>\n </button>\n <!-- Add your own buttons -->\n <button (click)="downloadSignature(pad)">\n <svg si-download-icon></svg>\n </button>\n </div>\n</div>\n```\n\n#### Without Controls Container\n\n```html\n<div scSignaturePad>\n <canvas scSignaturePadCanvas></canvas>\n</div>\n\n<!-- External controls -->\n<div class="mt-2 flex gap-2">\n <button scSignaturePadUndo>Undo</button>\n <button scSignaturePadClear>Clear</button>\n <button (click)="save()">Save</button>\n</div>\n```\n\n#### With Color Selection\n\n```html\n<div scSignaturePad class="space-y-3">\n <!-- Color toolbar -->\n <div scSignaturePadToolbar>\n <button scSignaturePadPenColor [color]="\'#000000\'">\n <span class="size-4 rounded-full border" style="background: #000000"></span>\n </button>\n <button scSignaturePadPenColor [color]="\'#1d4ed8\'">\n <span class="size-4 rounded-full border" style="background: #1d4ed8"></span>\n </button>\n <button scSignaturePadPenColor [color]="\'#dc2626\'">\n <span class="size-4 rounded-full border" style="background: #dc2626"></span>\n </button>\n </div>\n\n <!-- Canvas -->\n <div class="relative inline-block">\n <canvas scSignaturePadCanvas></canvas>\n <div scSignaturePadControls>\n <button scSignaturePadUndo>Undo</button>\n <button scSignaturePadClear>Clear</button>\n </div>\n </div>\n</div>\n```\n\n#### With Width Selection\n\n```html\n<div scSignaturePad class="space-y-3">\n <div scSignaturePadToolbar>\n <button scSignaturePadPenWidth [width]="2">\n <span class="bg-foreground w-4 rounded-full" style="height: 2px"></span>\n </button>\n <button scSignaturePadPenWidth [width]="4">\n <span class="bg-foreground w-4 rounded-full" style="height: 4px"></span>\n </button>\n <button scSignaturePadPenWidth [width]="6">\n <span class="bg-foreground w-4 rounded-full" style="height: 6px"></span>\n </button>\n </div>\n\n <div class="relative inline-block">\n <canvas scSignaturePadCanvas></canvas>\n </div>\n</div>\n```\n\n#### Combined Toolbar\n\n```html\n<div scSignaturePadToolbar>\n <!-- Colors -->\n <button scSignaturePadPenColor [color]="\'#000000\'">\n <span class="size-4 rounded-full border" style="background: #000000"></span>\n </button>\n <button scSignaturePadPenColor [color]="\'#1d4ed8\'">\n <span class="size-4 rounded-full border" style="background: #1d4ed8"></span>\n </button>\n\n <!-- Separator (optional) -->\n <div class="bg-border h-6 w-px"></div>\n\n <!-- Widths -->\n <button scSignaturePadPenWidth [width]="2">\n <span class="bg-foreground w-4 rounded-full" style="height: 2px"></span>\n </button>\n <button scSignaturePadPenWidth [width]="4">\n <span class="bg-foreground w-4 rounded-full" style="height: 4px"></span>\n </button>\n</div>\n```\n\n## Features\n\n- \u2705 Touch and mouse support\n- \u2705 Smooth drawing with line interpolation\n- \u2705 Undo functionality (stroke by stroke)\n- \u2705 Export to PNG, JPEG, or Blob\n- \u2705 Customizable pen color and width\n- \u2705 Responsive canvas sizing\n- \u2705 **Composable architecture** for maximum flexibility\n- \u2705 Use with `@semantic-icons` for consistent icons\n\n## Accessibility\n\n- Keyboard accessible controls\n- ARIA labels for screen readers\n- Focus indicators on buttons\n- Disabled state support\n- Touch-friendly button sizes\n',
|
|
@@ -30871,119 +30642,15 @@ var manifest_default = {
|
|
|
30871
30642
|
"ScSignaturePadWidthButton"
|
|
30872
30643
|
]
|
|
30873
30644
|
},
|
|
30874
|
-
{
|
|
30875
|
-
name: "sortable-list",
|
|
30876
|
-
readme: '# Sortable List\n\nA drag and drop list component for reordering items.\n\n## Usage\n\n```html\n<div scSortableList [(items)]="items" class="gap-2">\n @for (item of items(); track item; let i = $index) {\n <div scSortableItem [index]="i" [item]="item" class="rounded-md border p-3">{{ item }}</div>\n }\n</div>\n```\n\n## Components\n\n### ScSortableList\n\nRoot container that manages sortable state.\n\n**Selector:** `[scSortableList]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ------------- | ---------------------------- | ------------ | -------------------- |\n| `orientation` | `\'vertical\' \\| \'horizontal\'` | `\'vertical\'` | List direction |\n| `disabled` | `boolean` | `false` | Disable reordering |\n| `handleOnly` | `boolean` | `false` | Only drag via handle |\n| `class` | `string` | `\'\'` | Additional CSS |\n\n**Two-way Bindings:**\n\n| Binding | Type | Default | Description |\n| ------- | ----- | ------- | -------------- |\n| `items` | `T[]` | `[]` | Array of items |\n\n**Outputs:**\n\n| Output | Type | Description |\n| ------------ | ------------------ | ------------------ |\n| `sortChange` | `SortableEvent<T>` | Item was reordered |\n| `sortStart` | `{ item, index }` | Drag started |\n| `sortEnd` | `SortableEvent<T>` | Drag ended |\n\n**Methods:**\n\n| Method | Description |\n| -------------------- | --------------------------- |\n| `moveItem(from, to)` | Move item programmatically |\n| `moveUp(index)` | Move item up one position |\n| `moveDown(index)` | Move item down one position |\n\n### ScSortableItem\n\nIndividual draggable item.\n\n**Selector:** `[scSortableItem]`\n\n**Inputs:**\n\n| Input | Type | Required | Description |\n| ------- | -------- | -------- | -------------- |\n| `index` | `number` | Yes | Item index |\n| `item` | `T` | Yes | Item data |\n| `class` | `string` | No | Additional CSS |\n\n**Data Attributes:**\n\n| Attribute | Description |\n| ---------------- | -------------------------- |\n| `data-dragging` | Present when being dragged |\n| `data-drag-over` | Present when drag target |\n\n### ScSortableHandle\n\nOptional drag handle (use with `handleOnly`).\n\n**Selector:** `[scSortableHandle]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | -------------- |\n| `class` | `string` | `\'\'` | Additional CSS |\n\n### ScSortableOverlay\n\nOptional overlay during drag (prevents interaction with other elements).\n\n**Selector:** `[scSortableOverlay]`\n\n## Types\n\n### SortableEvent<T>\n\n```typescript\ninterface SortableEvent<T> {\n item: T;\n previousIndex: number;\n currentIndex: number;\n}\n```\n\n## Examples\n\n### Basic\n\n```html\n<div scSortableList [(items)]="items" class="gap-2">\n @for (item of items(); track item; let i = $index) {\n <div scSortableItem [index]="i" [item]="item" class="rounded-md border p-3">{{ item }}</div>\n }\n</div>\n```\n\n### With Drag Handle\n\n```html\n<div scSortableList [(items)]="items" [handleOnly]="true" class="gap-2">\n @for (item of items(); track item; let i = $index) {\n <div scSortableItem [index]="i" [item]="item" class="flex items-center gap-3 border p-3">\n <span scSortableHandle></span>\n <span>{{ item }}</span>\n </div>\n }\n</div>\n```\n\n### Horizontal Layout\n\n```html\n<div scSortableList [(items)]="items" orientation="horizontal" class="gap-3">\n @for (item of items(); track item; let i = $index) {\n <div scSortableItem [index]="i" [item]="item" class="rounded-md border p-4">{{ item }}</div>\n }\n</div>\n```\n\n### Task List\n\n```html\n<div scSortableList [(items)]="tasks" [handleOnly]="true" class="gap-1">\n <div scSortableOverlay></div>\n @for (task of tasks(); track task.id; let i = $index) {\n <div scSortableItem [index]="i" [item]="task" class="flex items-center gap-3 border p-3">\n <span scSortableHandle></span>\n <input type="checkbox" [checked]="task.completed" />\n <span>{{ task.title }}</span>\n </div>\n }\n</div>\n```\n\n### With Sort Events\n\n```html\n<div scSortableList [(items)]="items" (sortStart)="onSortStart($event)" (sortChange)="onSortChange($event)" (sortEnd)="onSortEnd($event)">...</div>\n```\n\n```typescript\nonSortChange(event: SortableEvent<Item>) {\n console.log(`Moved "${event.item}" from ${event.previousIndex} to ${event.currentIndex}`);\n}\n```\n\n### Disabled\n\n```html\n<div scSortableList [items]="items" [disabled]="true">\n @for (item of items; track item; let i = $index) {\n <div scSortableItem [index]="i" [item]="item" class="border p-3 opacity-60">{{ item }}</div>\n }\n</div>\n```\n\n### Custom Handle Icon\n\n```html\n<span scSortableHandle>\n <svg class="size-5"><!-- custom icon --></svg>\n</span>\n```\n\n### Playlist Example\n\n```html\n<div scSortableList [(items)]="songs" [handleOnly]="true" class="divide-y">\n @for (song of songs(); track song.id; let i = $index) {\n <div scSortableItem [index]="i" [item]="song" class="flex items-center gap-4 p-3">\n <span scSortableHandle></span>\n <span class="text-muted-foreground">{{ i + 1 }}</span>\n <div class="flex-1">\n <p class="font-medium">{{ song.title }}</p>\n <p class="text-muted-foreground text-sm">{{ song.artist }}</p>\n </div>\n <span>{{ song.duration }}</span>\n </div>\n }\n</div>\n```\n\n## Keyboard Navigation\n\n| Key | Action |\n| -------------------------- | ------------------------------------- |\n| `ArrowUp` / `ArrowLeft` | Move item up (based on orientation) |\n| `ArrowDown` / `ArrowRight` | Move item down (based on orientation) |\n| `Tab` | Move focus between items |\n\n## Features\n\n- **Drag and Drop**: Native HTML5 drag and drop\n- **Keyboard Support**: Arrow keys to reorder when focused\n- **Handle Mode**: Restrict dragging to handle element\n- **Orientations**: Vertical or horizontal layouts\n- **Visual Feedback**: Opacity and ring indicators during drag\n- **Events**: Callbacks for sort start, change, and end\n- **Overlay**: Optional overlay to prevent interaction during drag\n- **Two-way Binding**: Sync with `[(items)]`\n- **Generic Types**: Full TypeScript support\n\n## Accessibility\n\n- Focusable items with `tabindex`\n- Keyboard reordering with arrow keys\n- ARIA label on drag handle\n- Visual focus indicators\n- Disabled state support\n',
|
|
30877
|
-
exports: [
|
|
30878
|
-
"ScSortableList",
|
|
30879
|
-
"SC_SORTABLE_LIST",
|
|
30880
|
-
"ScSortableItem",
|
|
30881
|
-
"SC_SORTABLE_ITEM",
|
|
30882
|
-
"ScSortableHandle",
|
|
30883
|
-
"ScSortableOverlay"
|
|
30884
|
-
]
|
|
30885
|
-
},
|
|
30886
|
-
{
|
|
30887
|
-
name: "speed-dial",
|
|
30888
|
-
readme: '# Speed Dial\n\nA floating action button (FAB) that expands to reveal a set of related actions.\n\n## Installation\n\nImport the components from the speed-dial module:\n\n```typescript\nimport { ScSpeedDial, ScSpeedDialAction } from \'@/ui/speed-dial\';\nimport type { SpeedDialAction, SpeedDialDirection } from \'@/ui/speed-dial\';\n```\n\n## Usage\n\n### Basic Usage\n\n```html\n<sc-speed-dial [actions]="actions" (actionClick)="onActionClick($event)" />\n```\n\n```typescript\nactions: SpeedDialAction[] = [\n {\n id: \'edit\',\n icon: \'<svg>...</svg>\',\n label: \'Edit\',\n },\n {\n id: \'delete\',\n icon: \'<svg>...</svg>\',\n label: \'Delete\',\n },\n];\n\nonActionClick(event: SpeedDialActionClickEvent): void {\n console.log(\'Action clicked:\', event.action.label);\n}\n```\n\n### Direction Options\n\n```html\n<!-- Expand upward (default) -->\n<sc-speed-dial [actions]="actions" direction="up" />\n\n<!-- Expand downward -->\n<sc-speed-dial [actions]="actions" direction="down" />\n\n<!-- Expand to the left -->\n<sc-speed-dial [actions]="actions" direction="left" />\n\n<!-- Expand to the right -->\n<sc-speed-dial [actions]="actions" direction="right" />\n```\n\n### Custom Icons\n\n```html\n<sc-speed-dial [actions]="actions" [icon]="customIcon" [closeIcon]="customCloseIcon" />\n```\n\n### Size Variants\n\n```html\n<!-- Small -->\n<sc-speed-dial [actions]="actions" size="sm" actionSize="sm" />\n\n<!-- Medium (default) -->\n<sc-speed-dial [actions]="actions" size="md" actionSize="md" />\n\n<!-- Large -->\n<sc-speed-dial [actions]="actions" size="lg" actionSize="lg" />\n```\n\n### Without Labels\n\n```html\n<sc-speed-dial [actions]="actions" [showLabels]="false" />\n```\n\n### Controlled Open State\n\n```html\n<sc-speed-dial [actions]="actions" [(open)]="isOpen" (openChange)="onOpenChange($event)" />\n```\n\n### Positioning\n\nThe Speed Dial component uses inline positioning by default. For fixed or floating positioning, wrap it in a positioned container:\n\n```html\n<!-- Fixed bottom-right position -->\n<div class="fixed right-6 bottom-6 z-50">\n <sc-speed-dial [actions]="actions" />\n</div>\n\n<!-- Absolute within container -->\n<div class="relative h-96">\n <div class="absolute right-4 bottom-4">\n <sc-speed-dial [actions]="actions" />\n </div>\n</div>\n```\n\n## API Reference\n\n### ScSpeedDial\n\nThe main speed dial component with floating action button.\n\n#### Inputs\n\n| Input | Type | Default | Description |\n| --------------------- | ------------------------------------- | ---------------- | ----------------------------- |\n| `actions` | `SpeedDialAction[]` | `[]` | Array of action items |\n| `direction` | `\'up\' \\| \'down\' \\| \'left\' \\| \'right\'` | `\'up\'` | Direction to expand actions |\n| `icon` | `string` | Plus icon | SVG icon for closed state |\n| `closeIcon` | `string` | X icon | SVG icon for open state |\n| `label` | `string` | `\'Open actions\'` | Label for the main button |\n| `ariaLabel` | `string` | `\'Speed dial\'` | Accessible label |\n| `showLabels` | `boolean` | `true` | Show action labels |\n| `closeOnActionClick` | `boolean` | `true` | Close menu after action click |\n| `closeOnOutsideClick` | `boolean` | `true` | Close menu on outside click |\n| `size` | `\'sm\' \\| \'md\' \\| \'lg\'` | `\'md\'` | Size of main FAB button |\n| `actionSize` | `\'sm\' \\| \'md\' \\| \'lg\'` | `\'md\'` | Size of action buttons |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n#### Two-way Bindings\n\n| Binding | Type | Description |\n| ------- | --------- | ------------------------- |\n| `open` | `boolean` | Open/closed state of menu |\n\n#### Outputs\n\n| Output | Type | Description |\n| ------------- | --------------------------- | ------------------------------- |\n| `actionClick` | `SpeedDialActionClickEvent` | Emitted when action is clicked |\n| `openChange` | `boolean` | Emitted when open state changes |\n\n#### Public Methods\n\n| Method | Description |\n| ---------- | ----------------- |\n| `toggle()` | Toggle open state |\n| `close()` | Close the menu |\n\n### ScSpeedDialAction\n\nIndividual action button component (used internally).\n\n#### Inputs\n\n| Input | Type | Default | Description |\n| -------------- | ---------------------- | ------- | ------------------------- |\n| `icon` | `string` (required) | - | SVG icon string |\n| `label` | `string` (required) | - | Action label |\n| `disabled` | `boolean` | `false` | Disable the action |\n| `ariaLabel` | `string` | - | Custom accessible label |\n| `showLabel` | `boolean` | `true` | Show label next to action |\n| `labelVisible` | `boolean` | `true` | Label visibility state |\n| `size` | `\'sm\' \\| \'md\' \\| \'lg\'` | `\'md\'` | Button size |\n\n## Type Definitions\n\n### SpeedDialAction\n\n```typescript\ninterface SpeedDialAction {\n id: string;\n icon: string;\n label: string;\n disabled?: boolean;\n ariaLabel?: string;\n}\n```\n\n### SpeedDialActionClickEvent\n\n```typescript\ninterface SpeedDialActionClickEvent {\n action: SpeedDialAction;\n index: number;\n}\n```\n\n### SpeedDialDirection\n\n```typescript\ntype SpeedDialDirection = \'up\' | \'down\' | \'left\' | \'right\';\n```\n\n## Accessibility\n\nThe Speed Dial component follows accessibility best practices:\n\n- Main button has `aria-expanded` indicating open/closed state\n- Main button has `aria-haspopup="true"` indicating a menu\n- Actions menu has `role="menu"` for screen readers\n- Each action has `aria-label` for clear identification\n- Pressing Escape closes the menu\n- Labels provide visual context and appear as tooltips\n- Disabled actions are properly indicated\n\n## Keyboard Navigation\n\n| Key | Action |\n| ------ | -------------------------- |\n| Enter | Toggle menu / Click action |\n| Space | Toggle menu / Click action |\n| Escape | Close menu |\n\n## Styling\n\nThe component uses Tailwind CSS classes and supports theming through CSS variables:\n\n- `--primary` / `--primary-foreground`: Main FAB colors\n- `--secondary` / `--secondary-foreground`: Action button colors\n- `--popover` / `--popover-foreground`: Label colors\n- `--ring`: Focus ring color\n\n### Custom Styling\n\n```html\n<sc-speed-dial [actions]="actions" class="[&_button]:bg-blue-500" />\n```\n\n## Animation\n\nThe Speed Dial features smooth animations:\n\n- Main FAB has shadow transition on hover\n- Actions animate with opacity, scale, and position\n- Staggered reveal based on action index\n- Configurable transition timing\n\n## Features\n\n- Floating action button with expandable menu\n- Four expansion directions (up, down, left, right)\n- Customizable main button and close icons\n- Three size variants for flexibility\n- Optional action labels with tooltips\n- Support for disabled actions\n- Auto-close on action click or outside click\n- Escape key to close\n- Smooth staggered animations\n- Full keyboard and screen reader support\n- Responsive and mobile-friendly\n\n## Use Cases\n\n- Quick actions toolbar\n- Social sharing buttons\n- Add/create menus\n- Navigation shortcuts\n- Contact options\n- Settings quick access\n',
|
|
30889
|
-
exports: []
|
|
30890
|
-
},
|
|
30891
|
-
{
|
|
30892
|
-
name: "split-button",
|
|
30893
|
-
readme: '# Split Button\n\nA button with a dropdown menu for additional actions. The main button performs the primary action, while the dropdown provides secondary options.\n\n## Installation\n\n```typescript\nimport { ScSplitButton } from \'@/ui/split-button\';\nimport type { SplitButtonAction, SplitButtonSize, SplitButtonVariant } from \'@/ui/split-button\';\n```\n\n## Usage\n\n### Basic Usage\n\n```html\n<sc-split-button label="Save" [actions]="actions" (mainClick)="onSave()" (actionClick)="onActionClick($event)" />\n```\n\n```typescript\nactions: SplitButtonAction[] = [\n { id: \'save-draft\', label: \'Save as Draft\' },\n { id: \'save-template\', label: \'Save as Template\' },\n { id: \'discard\', label: \'Discard\', destructive: true },\n];\n```\n\n### With Icon\n\n```html\n<sc-split-button label="Download" [icon]="downloadIcon" [actions]="downloadActions" />\n```\n\n### Variant Options\n\n```html\n<sc-split-button label="Default" variant="default" [actions]="actions" />\n<sc-split-button label="Secondary" variant="secondary" [actions]="actions" />\n<sc-split-button label="Outline" variant="outline" [actions]="actions" />\n<sc-split-button label="Destructive" variant="destructive" [actions]="actions" />\n```\n\n### Size Variants\n\n```html\n<sc-split-button label="Small" size="sm" [actions]="actions" />\n<sc-split-button label="Medium" size="md" [actions]="actions" />\n<sc-split-button label="Large" size="lg" [actions]="actions" />\n```\n\n## API Reference\n\n### Inputs\n\n| Input | Type | Default | Description |\n| ---------- | -------------------------------------------------------- | ----------- | ------------------------- |\n| `label` | `string` | (required) | Main button label |\n| `actions` | `SplitButtonAction[]` | `[]` | Dropdown menu actions |\n| `icon` | `string` | `undefined` | HTML icon for main button |\n| `variant` | `\'default\' \\| \'secondary\' \\| \'outline\' \\| \'destructive\'` | `\'default\'` | Button style variant |\n| `size` | `\'sm\' \\| \'md\' \\| \'lg\'` | `\'md\'` | Button size |\n| `disabled` | `boolean` | `false` | Disable the entire button |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n### Outputs\n\n| Output | Type | Description |\n| ------------- | ------------------- | ------------------------------------- |\n| `mainClick` | `void` | Emitted when main button is clicked |\n| `actionClick` | `SplitButtonAction` | Emitted when dropdown item is clicked |\n\n## Type Definitions\n\n```typescript\ninterface SplitButtonAction {\n id: string;\n label: string;\n icon?: string;\n disabled?: boolean;\n destructive?: boolean;\n}\n\ntype SplitButtonVariant = \'default\' | \'secondary\' | \'outline\' | \'destructive\';\ntype SplitButtonSize = \'sm\' | \'md\' | \'lg\';\n```\n\n## Features\n\n- Split button with dropdown menu\n- Multiple style variants\n- Multiple size options\n- Main button with optional icon\n- Dropdown actions with optional icons\n- Destructive action styling\n- Disabled state for button and individual actions\n- Click outside to close dropdown\n- Escape key to close dropdown\n- Keyboard accessible\n- Animated chevron indicator\n',
|
|
30894
|
-
exports: []
|
|
30895
|
-
},
|
|
30896
|
-
{
|
|
30897
|
-
name: "spotlight",
|
|
30898
|
-
readme: '# Spotlight\n\nHighlight specific UI elements with a spotlight overlay effect for feature discovery and user guidance.\n\n## Usage\n\n```html\n<button (click)="spotlight.show(\'#my-element\')">Show Spotlight</button>\n\n<sc-spotlight #spotlight [padding]="12">\n <sc-spotlight-title>Feature Title</sc-spotlight-title>\n <sc-spotlight-description>Description of the highlighted feature.</sc-spotlight-description>\n <sc-spotlight-actions>\n <button (click)="spotlight.close()">Got it</button>\n </sc-spotlight-actions>\n</sc-spotlight>\n```\n\n## API\n\n### ScSpotlight\n\n| Input | Type | Default | Description |\n| --------------------- | ------------------- | ---------- | ------------------------------- |\n| `target` | `string \\| Element` | `null` | CSS selector or Element |\n| `padding` | `number` | `8` | Padding around highlighted area |\n| `borderRadius` | `number` | `8` | Border radius of spotlight |\n| `overlayOpacity` | `number` | `0.75` | Overlay darkness (0-1) |\n| `animationDuration` | `number` | `300` | Animation duration in ms |\n| `showClose` | `boolean` | `true` | Show close button |\n| `closeOnOverlayClick` | `boolean` | `true` | Close when clicking overlay |\n| `closeOnEscape` | `boolean` | `true` | Close on Escape key |\n| `scrollIntoView` | `boolean` | `true` | Scroll target into view |\n| `scrollBehavior` | `ScrollBehavior` | `\'smooth\'` | Scroll animation type |\n| `contentPlacement` | `string` | `\'auto\'` | Position of content panel |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n| Output | Type | Description |\n| -------- | ------ | --------------------------- |\n| `opened` | `void` | Emits when spotlight opens |\n| `closed` | `void` | Emits when spotlight closes |\n\n| Method | Type | Description |\n| -------- | ----------------------------- | ------------------------- |\n| `show` | `(target: string \\| Element)` | Show spotlight on element |\n| `hide` | `() => void` | Hide the spotlight |\n| `toggle` | `(target: string \\| Element)` | Toggle visibility |\n| `close` | `() => void` | Close the spotlight |\n\n### ScSpotlightTitle\n\nStyled title for the spotlight content.\n\n### ScSpotlightDescription\n\nStyled description text for the spotlight content.\n\n### ScSpotlightActions\n\nContainer for action buttons with proper spacing.\n\n## Examples\n\n### Basic Spotlight\n\n```html\n<button (click)="spotlight.show(\'#feature-card\')">Highlight Feature</button>\n\n<sc-spotlight #spotlight>\n <sc-spotlight-title>New Feature!</sc-spotlight-title>\n <sc-spotlight-description>Check out this exciting new capability.</sc-spotlight-description>\n</sc-spotlight>\n```\n\n### With Custom Styling\n\n```html\n<sc-spotlight #spotlight [padding]="16" [borderRadius]="12" [overlayOpacity]="0.85">\n <sc-spotlight-title>Premium Feature</sc-spotlight-title>\n <sc-spotlight-description>Upgrade to access this feature.</sc-spotlight-description>\n <sc-spotlight-actions>\n <button (click)="spotlight.close()">Maybe Later</button>\n <button (click)="upgrade()">Upgrade Now</button>\n </sc-spotlight-actions>\n</sc-spotlight>\n```\n\n### Programmatic Target\n\n```typescript\n// Using CSS selector\nspotlight.show(\'#my-element\');\n\n// Using Element reference\nconst element = document.querySelector(\'.my-class\');\nspotlight.show(element);\n```\n\n### Input-Driven\n\n```html\n<sc-spotlight [target]="activeTarget()">\n <!-- Content automatically updates when target changes -->\n</sc-spotlight>\n```\n\n```typescript\nactiveTarget = signal<string | null>(null);\n\nhighlightElement(selector: string) {\n this.activeTarget.set(selector);\n}\n\nclearHighlight() {\n this.activeTarget.set(null);\n}\n```\n\n## Features\n\n- SVG mask-based overlay with spotlight cutout\n- Animated pulse effect on highlighted element\n- Auto-positioning content panel\n- Customizable padding, border radius, and opacity\n- Close on overlay click or Escape key\n- Scroll target into view automatically\n- ResizeObserver for dynamic element tracking\n- Content slot for custom tooltips and actions\n- Smooth enter/exit animations\n\n## Accessibility\n\n- ARIA dialog role with modal attribute\n- Keyboard navigable (Escape to close)\n- Focus trap within spotlight\n- Screen reader friendly\n',
|
|
30899
|
-
exports: []
|
|
30900
|
-
},
|
|
30901
|
-
{
|
|
30902
|
-
name: "stat-card",
|
|
30903
|
-
readme: '# Stat Card\n\nA composable set of directives for displaying statistics and metrics with optional trends, icons, and descriptions.\n\n## Components\n\n- `ScStatCard` - Main container with border, background, and padding\n- `ScStatCardLabel` - Label/title text styling\n- `ScStatCardValue` - Large value/metric display styling\n- `ScStatCardIcon` - Icon container styling\n- `ScStatCardChange` - Trend/change indicator styling with color variants\n- `ScStatCardDescription` - Additional description text styling\n\n## Installation\n\n```typescript\nimport { ScStatCard, ScStatCardLabel, ScStatCardValue, ScStatCardIcon, ScStatCardChange, ScStatCardDescription } from \'@semantic-components/ui-lab\';\n```\n\n## Usage\n\n### Basic Stat Card\n\n```html\n<div scStatCard>\n <div class="space-y-1">\n <p scStatCardLabel>Total Revenue</p>\n <p scStatCardValue>$45,231.89</p>\n </div>\n <p scStatCardDescription>Revenue for the current period</p>\n</div>\n```\n\n### With Icon\n\n```html\n<div scStatCard>\n <div class="flex items-start justify-between">\n <div class="space-y-1">\n <p scStatCardLabel>Active Users</p>\n <p scStatCardValue>2,350</p>\n </div>\n <div scStatCardIcon>\n <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\n <path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" />\n <circle cx="9" cy="7" r="4" />\n <path d="M22 21v-2a4 4 0 0 0-3-3.87" />\n <path d="M16 3.13a4 4 0 0 1 0 7.75" />\n </svg>\n </div>\n </div>\n</div>\n```\n\n### With Trend Indicator\n\n```html\n<div scStatCard>\n <div class="space-y-1">\n <p scStatCardLabel>Sales</p>\n <p scStatCardValue>12,234</p>\n </div>\n\n <div class="mt-3 flex items-center gap-2">\n <span scStatCardChange trend="up">\n <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\n <path d="m18 15-6-6-6 6" />\n </svg>\n <span>+20.1%</span>\n </span>\n <span class="text-muted-foreground text-xs">from last month</span>\n </div>\n</div>\n```\n\n### Complete Example\n\n```html\n<div scStatCard variant="default" size="md">\n <div class="flex items-start justify-between">\n <div class="space-y-1">\n <p scStatCardLabel size="md">Total Revenue</p>\n <p scStatCardValue size="md">$45,231.89</p>\n </div>\n <div scStatCardIcon size="md">\n <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\n <path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6" />\n </svg>\n </div>\n </div>\n\n <div class="mt-3 flex items-center gap-2">\n <span scStatCardChange trend="up">\n <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\n <path d="m18 15-6-6-6 6" />\n </svg>\n <span>+20.1%</span>\n </span>\n <span class="text-muted-foreground text-xs">from last month</span>\n </div>\n\n <p scStatCardDescription class="mt-2">Your revenue increased significantly this month</p>\n</div>\n```\n\n## Variants\n\n### Default (with border)\n\n```html\n<div scStatCard variant="default">\n <!-- content -->\n</div>\n```\n\n### Outline (thick border)\n\n```html\n<div scStatCard variant="outline">\n <!-- content -->\n</div>\n```\n\n### Filled (colored background)\n\n```html\n<div scStatCard variant="filled">\n <!-- content -->\n</div>\n```\n\n## Sizes\n\n### Small\n\n```html\n<div scStatCard size="sm">\n <p scStatCardLabel size="sm">Label</p>\n <p scStatCardValue size="sm">1,234</p>\n</div>\n```\n\n### Medium (default)\n\n```html\n<div scStatCard size="md">\n <p scStatCardLabel size="md">Label</p>\n <p scStatCardValue size="md">5,678</p>\n</div>\n```\n\n### Large\n\n```html\n<div scStatCard size="lg">\n <p scStatCardLabel size="lg">Label</p>\n <p scStatCardValue size="lg">9,012</p>\n</div>\n```\n\n## Trend Colors\n\nThe `sc-stat-card-change` directive automatically applies colors based on the `trend` input:\n\n- `trend="up"` - Green text (positive)\n- `trend="down"` - Red text (negative)\n- `trend="neutral"` - Muted text (neutral)\n\n```html\n<span scStatCardChange trend="up">\n <svg><!-- up arrow --></svg>\n <span>+12.5%</span>\n</span>\n\n<span scStatCardChange trend="down">\n <svg><!-- down arrow --></svg>\n <span>-5.2%</span>\n</span>\n\n<span scStatCardChange trend="neutral">\n <span>No change</span>\n</span>\n```\n\n## API Reference\n\n### ScStatCard Inputs\n\n| Input | Type | Default | Description |\n| --------- | ------------------------------------ | ----------- | ---------------------- |\n| `variant` | `\'default\' \\| \'outline\' \\| \'filled\'` | `\'default\'` | Card style variant |\n| `size` | `\'sm\' \\| \'md\' \\| \'lg\'` | `\'md\'` | Card padding size |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n### ScStatCardLabel Inputs\n\n| Input | Type | Default | Description |\n| ------- | ---------------------- | ------- | ---------------------- |\n| `size` | `\'sm\' \\| \'md\' \\| \'lg\'` | `\'md\'` | Label text size |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n### ScStatCardValue Inputs\n\n| Input | Type | Default | Description |\n| ------- | ---------------------- | ------- | ---------------------- |\n| `size` | `\'sm\' \\| \'md\' \\| \'lg\'` | `\'md\'` | Value text size |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n### ScStatCardIcon Inputs\n\n| Input | Type | Default | Description |\n| ------- | ---------------------- | ------- | ---------------------- |\n| `size` | `\'sm\' \\| \'md\' \\| \'lg\'` | `\'md\'` | Icon container size |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n### ScStatCardChange Inputs\n\n| Input | Type | Default | Description |\n| ------- | ----------------------------- | ----------- | ---------------------- |\n| `trend` | `\'up\' \\| \'down\' \\| \'neutral\'` | `\'neutral\'` | Trend direction/color |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n### ScStatCardDescription Inputs\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n## Type Definitions\n\n```typescript\ntype StatCardTrend = \'up\' | \'down\' | \'neutral\';\ntype StatCardVariant = \'default\' | \'outline\' | \'filled\';\ntype StatCardSize = \'sm\' | \'md\' | \'lg\';\n```\n\n## Styling Reference\n\n| Component | Default Styling |\n| ----------------------- | ---------------------------------------------------------------------------- |\n| `ScStatCard` | `rounded-lg transition-colors` + variant/size classes |\n| `ScStatCardLabel` | `font-medium text-muted-foreground` + size-specific font size |\n| `ScStatCardValue` | `font-bold tracking-tight` + size-specific font size |\n| `ScStatCardIcon` | `rounded-md bg-muted p-2 inline-flex items-center justify-center` + SVG size |\n| `ScStatCardChange` | `inline-flex items-center gap-1 text-xs font-medium` + trend color |\n| `ScStatCardDescription` | `text-xs text-muted-foreground` |\n\n## Features\n\n- Fully composable - use only what you need\n- Content projection for maximum flexibility\n- Multiple style variants (default, outline, filled)\n- Multiple size options (sm, md, lg)\n- Automatic trend-based coloring\n- Support for custom icons from any library\n- Responsive design\n- Custom class support on all directives\n\n## Accessibility\n\n- Uses semantic HTML structure\n- All directives accept standard HTML attributes\n- Ensure proper heading hierarchy for labels\n- Use appropriate ARIA labels for trend indicators\n- Icons should have descriptive text for screen readers\n\n## Example Layouts\n\n### Grid of Stats\n\n```html\n<div class="grid gap-4 md:grid-cols-2 lg:grid-cols-4">\n <div scStatCard>\n <p scStatCardLabel>Total Revenue</p>\n <p scStatCardValue>$45,231.89</p>\n </div>\n\n <div scStatCard>\n <p scStatCardLabel>Active Users</p>\n <p scStatCardValue>2,350</p>\n </div>\n\n <div scStatCard>\n <p scStatCardLabel>Sales</p>\n <p scStatCardValue>12,234</p>\n </div>\n\n <div scStatCard>\n <p scStatCardLabel>Conversions</p>\n <p scStatCardValue>573</p>\n </div>\n</div>\n```\n\n### Custom Layout\n\nSince all components use content projection, you can create any layout you need:\n\n```html\n<div scStatCard>\n <!-- Custom header with icon on left -->\n <div class="mb-4 flex items-center gap-3">\n <div scStatCardIcon>\n <svg><!-- icon --></svg>\n </div>\n <p scStatCardLabel>Revenue</p>\n </div>\n\n <!-- Centered value -->\n <p scStatCardValue class="text-center">$45,231.89</p>\n\n <!-- Bottom trend -->\n <div class="mt-4 flex justify-center">\n <span scStatCardChange trend="up">\n <span>\u2191 20.1%</span>\n </span>\n </div>\n</div>\n```\n',
|
|
30904
|
-
exports: []
|
|
30905
|
-
},
|
|
30906
|
-
{
|
|
30907
|
-
name: "stepper",
|
|
30908
|
-
readme: '# Stepper\n\nA multi-step wizard component for guiding users through a process.\n\n## Usage\n\n```html\n<div scStepper [(activeStep)]="currentStep">\n <div scStepperList>\n <div scStepperItem [step]="0">\n <button scStepperTrigger></button>\n <span scStepperTitle>Step 1</span>\n </div>\n <div scStepperSeparator></div>\n <div scStepperItem [step]="1">\n <button scStepperTrigger></button>\n <span scStepperTitle>Step 2</span>\n </div>\n </div>\n\n <div scStepperContent [step]="0">Step 1 content</div>\n <div scStepperContent [step]="1">Step 2 content</div>\n\n <button scStepperPrevious>Previous</button>\n <button scStepperNext>Next</button>\n</div>\n```\n\n## Components\n\n### ScStepper\n\nRoot container that manages step state.\n\n**Selector:** `[scStepper]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ------------- | ---------------------------- | -------------- | ---------------------- |\n| `orientation` | `\'horizontal\' \\| \'vertical\'` | `\'horizontal\'` | Layout orientation |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n**Two-way Bindings:**\n\n| Binding | Type | Default | Description |\n| ------------ | -------- | ------- | ------------------- |\n| `activeStep` | `number` | `0` | Current active step |\n\n**Methods:**\n\n| Method | Description |\n| ------------------------ | --------------------------- |\n| `goToStep(step: number)` | Navigate to a specific step |\n| `nextStep()` | Go to next step |\n| `prevStep()` | Go to previous step |\n| `isStepComplete(step)` | Check if step is complete |\n| `isStepActive(step)` | Check if step is active |\n\n### ScStepperList\n\nContainer for step indicators.\n\n**Selector:** `[scStepperList]`\n\n### ScStepperItem\n\nIndividual step indicator.\n\n**Selector:** `[scStepperItem]`\n\n**Inputs:**\n\n| Input | Type | Required | Description |\n| ------- | -------- | -------- | -------------------- |\n| `step` | `number` | Yes | Step index (0-based) |\n| `class` | `string` | No | Additional CSS |\n\n**Data Attributes:**\n\n| Attribute | Values |\n| ------------ | -------------------------------------- |\n| `data-state` | `\'complete\' \\| \'active\' \\| \'inactive\'` |\n\n### ScStepperTrigger\n\nClickable step button with number or check icon.\n\n**Selector:** `button[scStepperTrigger]`\n\n### ScStepperSeparator\n\nVisual line between steps.\n\n**Selector:** `[scStepperSeparator]`\n\n**Data Attributes:**\n\n| Attribute | Values |\n| ------------ | -------------------------- |\n| `data-state` | `\'complete\' \\| \'inactive\'` |\n\n### ScStepperContent\n\nContent panel for a step.\n\n**Selector:** `[scStepperContent]`\n\n**Inputs:**\n\n| Input | Type | Required | Description |\n| ------- | -------- | -------- | -------------------- |\n| `step` | `number` | Yes | Step index (0-based) |\n| `class` | `string` | No | Additional CSS |\n\n### ScStepperTitle\n\nTitle text for a step.\n\n**Selector:** `[scStepperTitle]`\n\n### ScStepperDescription\n\nDescription text for a step.\n\n**Selector:** `[scStepperDescription]`\n\n### ScStepperPrevious\n\nButton to go to previous step.\n\n**Selector:** `button[scStepperPrevious]`\n\nAuto-disables on first step.\n\n### ScStepperNext\n\nButton to go to next step.\n\n**Selector:** `button[scStepperNext]`\n\n## Examples\n\n### Horizontal Stepper\n\n```html\n<div scStepper [(activeStep)]="step">\n <div scStepperList>\n <div scStepperItem [step]="0">\n <button scStepperTrigger></button>\n <div class="flex flex-col">\n <span scStepperTitle>Account</span>\n <span scStepperDescription>Create your account</span>\n </div>\n </div>\n <div scStepperSeparator></div>\n <div scStepperItem [step]="1">\n <button scStepperTrigger></button>\n <div class="flex flex-col">\n <span scStepperTitle>Profile</span>\n <span scStepperDescription>Set up your profile</span>\n </div>\n </div>\n <div scStepperSeparator></div>\n <div scStepperItem [step]="2">\n <button scStepperTrigger></button>\n <div class="flex flex-col">\n <span scStepperTitle>Complete</span>\n <span scStepperDescription>Review and submit</span>\n </div>\n </div>\n </div>\n\n <div scStepperContent [step]="0">Account form...</div>\n <div scStepperContent [step]="1">Profile form...</div>\n <div scStepperContent [step]="2">Review...</div>\n\n <div class="flex justify-between">\n <button scStepperPrevious>Previous</button>\n <button scStepperNext>Next</button>\n </div>\n</div>\n```\n\n### Vertical Stepper\n\n```html\n<div scStepper orientation="vertical" [(activeStep)]="step">\n <div scStepperList>\n <div scStepperItem [step]="0">\n <button scStepperTrigger></button>\n <div class="flex flex-col">\n <span scStepperTitle>Step 1</span>\n <span scStepperDescription>First step</span>\n @if (step === 0) {\n <div class="mt-4">Step 1 content here</div>\n }\n </div>\n <div scStepperSeparator></div>\n </div>\n <div scStepperItem [step]="1">\n <button scStepperTrigger></button>\n <div class="flex flex-col">\n <span scStepperTitle>Step 2</span>\n <span scStepperDescription>Second step</span>\n </div>\n </div>\n </div>\n</div>\n```\n\n### Simple Number Steps\n\n```html\n<div scStepper [(activeStep)]="step">\n <div scStepperList>\n <div scStepperItem [step]="0">\n <button scStepperTrigger></button>\n </div>\n <div scStepperSeparator></div>\n <div scStepperItem [step]="1">\n <button scStepperTrigger></button>\n </div>\n <div scStepperSeparator></div>\n <div scStepperItem [step]="2">\n <button scStepperTrigger></button>\n </div>\n </div>\n\n <button scStepperPrevious>Back</button>\n <button scStepperNext>Continue</button>\n</div>\n```\n\n## Features\n\n- **Horizontal/Vertical**: Supports both orientations\n- **Click Navigation**: Click any step to navigate directly\n- **Step States**: Complete, active, and inactive visual states\n- **Auto-disable**: Previous button disabled on first step\n- **Check Icons**: Completed steps show a checkmark\n- **Two-way Binding**: Sync step state with `[(activeStep)]`\n\n## Accessibility\n\n- Uses `role="tablist"` for step list\n- Uses `role="tab"` for step triggers\n- Uses `role="tabpanel"` for step content\n- `aria-selected` indicates active step\n- Keyboard navigation via Tab key\n',
|
|
30909
|
-
exports: []
|
|
30910
|
-
},
|
|
30911
|
-
{
|
|
30912
|
-
name: "tag-input",
|
|
30913
|
-
readme: '# Tag Input\n\nA multi-tag input component with chips for adding and removing tags.\n\n## Usage\n\n```html\n<div scTagInput [(tags)]="tags">\n @for (tag of tags(); track tag) {\n <span scTagInputTag [tag]="tag"></span>\n }\n <input scTagInputField />\n</div>\n```\n\n## Components\n\n### ScTagInput\n\nRoot container that manages tag state.\n\n**Selector:** `[scTagInput]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ----------------- | ---------------- | ---------------- | ---------------------- |\n| `placeholder` | `string` | `\'Add tag...\'` | Input placeholder |\n| `disabled` | `boolean` | `false` | Disabled state |\n| `maxTags` | `number \\| null` | `null` | Maximum number of tags |\n| `allowDuplicates` | `boolean` | `false` | Allow duplicate tags |\n| `delimiters` | `string[]` | `[\'Enter\', \',\']` | Keys that add tags |\n| `minLength` | `number` | `1` | Minimum tag length |\n| `maxLength` | `number \\| null` | `null` | Maximum tag length |\n| `class` | `string` | `\'\'` | Additional CSS |\n\n**Two-way Bindings:**\n\n| Binding | Type | Default | Description |\n| ------- | ---------- | ------- | ------------- |\n| `tags` | `string[]` | `[]` | Array of tags |\n\n**Outputs:**\n\n| Output | Type | Description |\n| ----------- | -------- | --------------- |\n| `tagAdd` | `string` | Tag was added |\n| `tagRemove` | `string` | Tag was removed |\n\n**Methods:**\n\n| Method | Description |\n| ------------------------- | -------------------------- |\n| `addTag(value)` | Add a tag programmatically |\n| `removeTag(tag)` | Remove a specific tag |\n| `removeTagAtIndex(index)` | Remove tag by index |\n| `removeLastTag()` | Remove the last tag |\n| `clearAll()` | Remove all tags |\n| `focusInput()` | Focus the input field |\n\n### ScTagInputField\n\nThe input field for typing new tags.\n\n**Selector:** `input[scTagInputField]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ----------- | --------- | ------- | ------------------------- |\n| `addOnBlur` | `boolean` | `false` | Add tag when losing focus |\n| `class` | `string` | `\'\'` | Additional CSS |\n\n### ScTagInputTag\n\nIndividual tag chip.\n\n**Selector:** `[scTagInputTag]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| --------- | --------------------------------------- | ----------- | -------------- |\n| `tag` | `string` | Required | Tag text |\n| `variant` | `\'default\' \\| \'secondary\' \\| \'outline\'` | `\'default\'` | Visual style |\n| `class` | `string` | `\'\'` | Additional CSS |\n\n### ScTagInputClear\n\nButton to clear all tags.\n\n**Selector:** `button[scTagInputClear]`\n\n### ScTagInputCount\n\nDisplay tag count with optional max.\n\n**Selector:** `[scTagInputCount]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| --------- | --------- | ------- | ------------------- |\n| `showMax` | `boolean` | `true` | Show max in "x / y" |\n| `class` | `string` | `\'\'` | Additional CSS |\n\n## Examples\n\n### Basic\n\n```html\n<div scTagInput [(tags)]="tags">\n @for (tag of tags(); track tag) {\n <span scTagInputTag [tag]="tag"></span>\n }\n <input scTagInputField />\n</div>\n```\n\n### With Clear Button\n\n```html\n<div scTagInput [(tags)]="tags">\n @for (tag of tags(); track tag) {\n <span scTagInputTag [tag]="tag"></span>\n }\n <input scTagInputField />\n <button scTagInputClear></button>\n</div>\n```\n\n### With Max Tags\n\n```html\n<div scTagInput [(tags)]="tags" [maxTags]="5">\n @for (tag of tags(); track tag) {\n <span scTagInputTag [tag]="tag"></span>\n }\n <input scTagInputField />\n</div>\n<span scTagInputCount></span>\n```\n\n### Different Variants\n\n```html\n<!-- Default (Primary) -->\n<span scTagInputTag [tag]="tag" variant="default"></span>\n\n<!-- Secondary -->\n<span scTagInputTag [tag]="tag" variant="secondary"></span>\n\n<!-- Outline -->\n<span scTagInputTag [tag]="tag" variant="outline"></span>\n```\n\n### Custom Delimiters\n\n```html\n<!-- Add tags with Space or Tab -->\n<div scTagInput [(tags)]="tags" [delimiters]="[\'Enter\', \' \', \'Tab\']">\n @for (tag of tags(); track tag) {\n <span scTagInputTag [tag]="tag"></span>\n }\n <input scTagInputField />\n</div>\n```\n\n### Allow Duplicates\n\n```html\n<div scTagInput [(tags)]="tags" [allowDuplicates]="true">\n @for (tag of tags(); track $index) {\n <span scTagInputTag [tag]="tag"></span>\n }\n <input scTagInputField />\n</div>\n```\n\n### Add on Blur\n\n```html\n<div scTagInput [(tags)]="tags">\n @for (tag of tags(); track tag) {\n <span scTagInputTag [tag]="tag"></span>\n }\n <input scTagInputField [addOnBlur]="true" />\n</div>\n```\n\n### With Validation\n\n```html\n<div scTagInput [(tags)]="tags" [minLength]="2" [maxLength]="20">\n @for (tag of tags(); track tag) {\n <span scTagInputTag [tag]="tag"></span>\n }\n <input scTagInputField />\n</div>\n```\n\n### Disabled\n\n```html\n<div scTagInput [tags]="[\'Fixed\', \'Tags\']" [disabled]="true">\n @for (tag of [\'Fixed\', \'Tags\']; track tag) {\n <span scTagInputTag [tag]="tag"></span>\n }\n <input scTagInputField />\n</div>\n```\n\n### Form Field\n\n```html\n<div class="space-y-2">\n <label class="text-sm font-medium">Skills</label>\n <div scTagInput [(tags)]="skills" [maxTags]="10" placeholder="Add a skill...">\n @for (tag of skills(); track tag) {\n <span scTagInputTag [tag]="tag" variant="secondary"></span>\n }\n <input scTagInputField />\n </div>\n <div class="text-muted-foreground flex justify-between text-xs">\n <span>Add up to 10 skills</span>\n <span scTagInputCount></span>\n </div>\n</div>\n```\n\n### Email Recipients\n\n```html\n<div scTagInput [(tags)]="emails" placeholder="Add recipient...">\n @for (email of emails(); track email) {\n <span scTagInputTag [tag]="email" variant="outline" class="rounded-full"></span>\n }\n <input scTagInputField [addOnBlur]="true" />\n</div>\n```\n\n## Keyboard Navigation\n\n| Key | Action |\n| ----------- | ------------------------------------ |\n| `Enter` | Add tag (default delimiter) |\n| `,` | Add tag (default delimiter) |\n| `Backspace` | Remove last tag (when input empty) |\n| `Tab` | Move focus / add tag (if configured) |\n\n## Features\n\n- **Flexible Delimiters**: Configure any keys to trigger tag addition\n- **Duplicate Prevention**: Optional duplicate checking\n- **Max Tags Limit**: Enforce maximum number of tags\n- **Validation**: Min/max length constraints\n- **Add on Blur**: Optionally add tag when input loses focus\n- **Paste Support**: Paste comma-separated values\n- **Keyboard Support**: Full keyboard navigation\n- **Clear All**: Remove all tags at once\n- **Count Display**: Show current/max tag count\n- **Multiple Variants**: Default, secondary, outline styles\n- **Two-way Binding**: Sync with `[(tags)]`\n\n## Accessibility\n\n- Click container to focus input\n- ARIA labels on remove buttons\n- Keyboard navigation support\n- Focus indicators\n- Disabled state support\n',
|
|
30914
|
-
exports: []
|
|
30915
|
-
},
|
|
30916
|
-
{
|
|
30917
|
-
name: "theme-toggle",
|
|
30918
|
-
readme: '# Theme Toggle\n\nA component for switching between light and dark themes with system preference support.\n\n## Usage\n\n### Basic Toggle Button\n\nThe theme toggle uses content projection for icons, following the declarative architecture pattern.\n\n```typescript\nimport { ScThemeToggle } from \'@semantic-components/ui-lab\';\nimport { SiMoonIcon, SiSunIcon } from \'@semantic-icons/lucide-icons\';\n\n@Component({\n imports: [ScThemeToggle, SiSunIcon, SiMoonIcon],\n template: `\n <button scThemeToggle #toggle="scThemeToggle">\n @if (toggle.isDark()) {\n <svg si-sun-icon></svg>\n } @else {\n <svg si-moon-icon></svg>\n }\n </button>\n `,\n})\nexport class MyComponent {}\n```\n\n### With Variants\n\n```html\n<!-- Default variant -->\n<button scThemeToggle variant="default" #toggle="scThemeToggle">\n @if (toggle.isDark()) {\n <svg si-sun-icon></svg>\n } @else {\n <svg si-moon-icon></svg>\n }\n</button>\n\n<!-- Outline variant -->\n<button scThemeToggle variant="outline" #toggle="scThemeToggle">\n @if (toggle.isDark()) {\n <svg si-sun-icon></svg>\n } @else {\n <svg si-moon-icon></svg>\n }\n</button>\n\n<!-- Ghost variant -->\n<button scThemeToggle variant="ghost" #toggle="scThemeToggle">\n @if (toggle.isDark()) {\n <svg si-sun-icon></svg>\n } @else {\n <svg si-moon-icon></svg>\n }\n</button>\n```\n\n### With Sizes\n\n```html\n<button scThemeToggle size="sm" #toggle="scThemeToggle">\n @if (toggle.isDark()) {\n <svg si-sun-icon></svg>\n } @else {\n <svg si-moon-icon></svg>\n }\n</button>\n```\n\n### Theme Select Dropdown\n\nThe theme select follows the composable pattern - consumers provide the label and connect it with IDs.\n\n```typescript\nimport { ScThemeField, ScThemeSelect } from \'@semantic-components/ui-lab\';\n\n@Component({\n imports: [ScThemeField, ScThemeSelect],\n template: `\n <div scThemeField>\n <label class="text-sm font-medium">Theme</label>\n <select scThemeSelect>\n <option value="light">Light</option>\n <option value="dark">Dark</option>\n <option value="system">System</option>\n </select>\n </div>\n `,\n})\nexport class MyComponent {}\n```\n\nWith translations:\n\n```html\n<div scThemeField>\n <label>Th\xE8me</label>\n <select scThemeSelect>\n <option value="light">Lumi\xE8re</option>\n <option value="dark">Sombre</option>\n <option value="system">Syst\xE8me</option>\n </select>\n</div>\n```\n\nWithout ScThemeField (custom layout, manual IDs):\n\n```html\n<div class="custom-layout">\n <label for="my-theme">Choose theme</label>\n <select scThemeSelect id="my-theme">\n <option value="light">Light</option>\n <option value="dark">Dark</option>\n <option value="system">System</option>\n </select>\n</div>\n```\n\n### Using ScTheme Directly\n\n```typescript\nimport { ScTheme } from \'@semantic-components/ui-lab\';\n\nexport class MyComponent {\n private theme = inject(ScTheme);\n\n // Read the current theme\n currentTheme = this.theme.theme;\n\n // Check if dark mode is active\n isDark = this.theme.isDark;\n\n // Set a specific theme\n setDark() {\n this.theme.setTheme(\'dark\');\n }\n\n // Toggle between light and dark\n toggle() {\n this.theme.toggleTheme();\n }\n}\n```\n\n## Components\n\n### ScThemeToggle\n\nA button that toggles between light and dark themes. Uses content projection for icons following the declarative architecture pattern.\n\n**Selector:** `button[scThemeToggle]`\n\n**Export As:** `scThemeToggle`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| --------- | -------------------- | --------- | ---------------------- |\n| `variant` | `ThemeToggleVariant` | `\'ghost\'` | Visual style variant |\n| `size` | `ThemeToggleSize` | `\'icon\'` | Button size |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n**Variants:** `\'default\'` | `\'outline\'` | `\'ghost\'`\n\n**Sizes:** `\'default\'` | `\'sm\'` | `\'lg\'` | `\'icon\'`\n\n**Public Properties (via template reference):**\n\n| Property | Type | Description |\n| -------- | ----------------- | ---------------------------- |\n| `isDark` | `Signal<boolean>` | Whether dark theme is active |\n\n**Usage:**\n\nUse a template reference variable with `#toggle="scThemeToggle"` to access the `isDark()` signal for conditional icon rendering.\n\n### ScThemeSelect\n\nA dropdown select for choosing between light, dark, and system themes. Follows the composable pattern - consumers provide the label, options, and IDs for full control and i18n support.\n\n**Selector:** `select[scThemeSelect]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n**Options:**\n\nConsumers must provide the option elements via content projection. The values must be `\'light\'`, `\'dark\'`, or `\'system\'`.\n\n```html\n<option value="light">Light</option>\n<option value="dark">Dark</option>\n<option value="system">System</option>\n```\n\n### ScThemeField\n\nA container component for theme select with consistent spacing and automatic ID management.\n\n**Selector:** `div[scThemeField]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n**Behavior:**\n\nAutomatically generates a unique ID and applies it to the label\'s `for` attribute and the select\'s `id` attribute, ensuring proper accessibility without manual ID management.\n\n## ScTheme\n\nA singleton service for managing theme state.\n\n**Properties:**\n\n| Property | Type | Description |\n| --------------- | --------------------------- | ------------------------------------------------- |\n| `theme` | `Signal<Theme>` | Current theme setting (\'light\', \'dark\', \'system\') |\n| `resolvedTheme` | `Signal<\'light\' \\| \'dark\'>` | Actual applied theme (resolves \'system\') |\n| `isDark` | `Signal<boolean>` | Whether dark theme is currently active |\n\n**Methods:**\n\n| Method | Parameters | Description |\n| ------------- | -------------- | ----------------------------- |\n| `setTheme` | `theme: Theme` | Set the theme explicitly |\n| `toggleTheme` | none | Toggle between light and dark |\n\n## Architecture\n\nThis component follows the **declarative architecture** pattern:\n\n- **Content Projection**: Icons are provided by consumers via `<ng-content />`, not embedded in the component\n- **Template References**: Use `#toggle="scThemeToggle"` to access component state in templates\n- **Signal-based State**: The `isDark()` signal drives conditional rendering\n- **No Imperative Methods**: All state changes happen through user interactions, not programmatic calls\n\nThis design gives consumers full control over icon presentation while maintaining clean separation of concerns.\n\n## Accessibility\n\n- The toggle button uses `aria-label` to describe the action\n- The toggle button uses `aria-pressed` to indicate the current state\n- The select dropdown includes a screen-reader-only label\n- Icons are marked with `aria-hidden="true"`\n- Full keyboard navigation support\n\n## Persistence\n\nThe theme preference is automatically persisted to `localStorage` under the key `sc-theme` and restored on page load.\n',
|
|
30919
|
-
exports: [
|
|
30920
|
-
"ScThemeToggle",
|
|
30921
|
-
"ThemeToggleVariant",
|
|
30922
|
-
"ThemeToggleSize",
|
|
30923
|
-
"ScThemeSelect",
|
|
30924
|
-
"ScThemeField",
|
|
30925
|
-
"ScTheme",
|
|
30926
|
-
"Theme"
|
|
30927
|
-
]
|
|
30928
|
-
},
|
|
30929
30645
|
{
|
|
30930
30646
|
name: "time-picker-clock",
|
|
30931
30647
|
readme: null,
|
|
30932
30648
|
exports: []
|
|
30933
30649
|
},
|
|
30934
|
-
{
|
|
30935
|
-
name: "timeline",
|
|
30936
|
-
readme: "# Timeline\n\nDisplay a sequence of events or activities in chronological order.\n\n## Components\n\n- `ScTimeline` - Container for timeline items\n- `ScTimelineItem` - Individual timeline entry\n- `ScTimelineConnector` - Vertical line connecting items\n- `ScTimelineDot` - Circle indicator with optional icon\n- `ScTimelineContent` - Content container\n- `ScTimelineTitle` - Title text\n- `ScTimelineDescription` - Description text\n- `ScTimelineTime` - Timestamp text\n\n## Usage\n\n```html\n<div scTimeline>\n <div scTimelineItem>\n <div scTimelineConnector></div>\n <div scTimelineDot></div>\n <div scTimelineContent>\n <h4 scTimelineTitle>Event Title</h4>\n <p scTimelineDescription>Event description goes here.</p>\n <span scTimelineTime>January 2024</span>\n </div>\n </div>\n\n <div scTimelineItem>\n <div scTimelineDot></div>\n <div scTimelineContent>\n <h4 scTimelineTitle>Last Event</h4>\n <p scTimelineDescription>No connector for the last item.</p>\n </div>\n </div>\n</div>\n```\n\n## API\n\n### ScTimeline\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `''` | Additional CSS classes |\n\n### ScTimelineItem\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `''` | Additional CSS classes |\n\n### ScTimelineDot\n\n| Input | Type | Default | Description |\n| --------- | ------------------------------------------------------------- | ----------- | ---------------------- |\n| `class` | `string` | `''` | Additional CSS classes |\n| `variant` | `'default' \\| 'outline' \\| 'success' \\| 'warning' \\| 'error'` | `'default'` | Visual variant |\n| `size` | `'sm' \\| 'default' \\| 'lg'` | `'default'` | Size of the dot |\n\n### ScTimelineConnector\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `''` | Additional CSS classes |\n\n### ScTimelineContent\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `''` | Additional CSS classes |\n\n### ScTimelineTitle\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `''` | Additional CSS classes |\n\n### ScTimelineDescription\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `''` | Additional CSS classes |\n\n### ScTimelineTime\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `''` | Additional CSS classes |\n\n## Dot Variants\n\n| Variant | Description |\n| --------- | ------------------------------------ |\n| `default` | Primary background color |\n| `outline` | Border only, transparent background |\n| `success` | Green background for completed items |\n| `warning` | Yellow background for in-progress |\n| `error` | Red background for failed items |\n\n## Dot Sizes\n\n| Size | Dimensions |\n| --------- | ---------- |\n| `sm` | 16px |\n| `default` | 24px |\n| `lg` | 32px |\n\n## Examples\n\n### With Status Icons\n\n```html\n<div scTimelineItem>\n <div scTimelineConnector></div>\n <div scTimelineDot variant=\"success\">\n <svg class=\"size-3\"><!-- check icon --></svg>\n </div>\n <div scTimelineContent>\n <h4 scTimelineTitle>Completed</h4>\n </div>\n</div>\n```\n\n### Activity Feed\n\n```html\n<div scTimeline>\n <div scTimelineItem class=\"pb-4\">\n <div scTimelineConnector></div>\n <div scTimelineDot size=\"sm\"></div>\n <div scTimelineContent class=\"space-y-0\">\n <p class=\"text-sm\">\n <span class=\"font-medium\">John Doe</span>\n created a new project\n </p>\n <span scTimelineTime>2 hours ago</span>\n </div>\n </div>\n</div>\n```\n\n### Order Tracking\n\n```html\n<div scTimeline>\n <div scTimelineItem>\n <div scTimelineConnector></div>\n <div scTimelineDot variant=\"success\" size=\"lg\">\n <svg class=\"size-4\"><!-- package icon --></svg>\n </div>\n <div scTimelineContent>\n <h4 scTimelineTitle>Shipped</h4>\n <p scTimelineDescription>Your package is on its way.</p>\n <span scTimelineTime>Jan 16, 2024</span>\n </div>\n </div>\n</div>\n```\n\n## Structure\n\nThe timeline uses absolute positioning for the dot and connector elements:\n\n```\nTimeline\n\u251C\u2500\u2500 TimelineItem (relative, left padding)\n\u2502 \u251C\u2500\u2500 TimelineConnector (absolute, vertical line)\n\u2502 \u251C\u2500\u2500 TimelineDot (absolute, circle)\n\u2502 \u2514\u2500\u2500 TimelineContent\n\u2502 \u251C\u2500\u2500 TimelineTitle\n\u2502 \u251C\u2500\u2500 TimelineDescription\n\u2502 \u2514\u2500\u2500 TimelineTime\n```\n\nThe connector should be omitted from the last timeline item to avoid an orphaned line.\n",
|
|
30937
|
-
exports: []
|
|
30938
|
-
},
|
|
30939
|
-
{
|
|
30940
|
-
name: "timezone",
|
|
30941
|
-
readme: null,
|
|
30942
|
-
exports: [
|
|
30943
|
-
"ScTimezoneService",
|
|
30944
|
-
"SC_TIMEZONE_CONFIG",
|
|
30945
|
-
"ScTimezoneDisplay",
|
|
30946
|
-
"variantStyles",
|
|
30947
|
-
"sizeStyles",
|
|
30948
|
-
"TimezoneVariant",
|
|
30949
|
-
"TimezoneSize",
|
|
30950
|
-
"ScTimezoneSelect",
|
|
30951
|
-
"ScTimezoneButton",
|
|
30952
|
-
"ScTimezoneBadge"
|
|
30953
|
-
]
|
|
30954
|
-
},
|
|
30955
|
-
{
|
|
30956
|
-
name: "tour-guide",
|
|
30957
|
-
readme: "# Tour Guide\n\nStep-by-step UI tour component for user onboarding and feature discovery.\n\n## Usage\n\n```typescript\nimport { TourService, TourOptions, ScTourGuide } from './ui/tour-guide';\n\n// Inject the service\nconst tourService = inject(TourService);\n\n// Start a tour\nconst options: TourOptions = {\n steps: [\n {\n target: '#element-1',\n title: 'Welcome',\n content: 'This is the first step of the tour.',\n placement: 'bottom',\n },\n {\n target: '#element-2',\n title: 'Settings',\n content: 'Configure your preferences here.',\n },\n ],\n showProgress: true,\n showStepNumbers: true,\n};\n\ntourService.start(options);\n```\n\n```html\n<!-- Add the component to your template -->\n<sc-tour-guide (stepChange)=\"onStepChange($event)\" (tourComplete)=\"onTourComplete()\" (tourClosed)=\"onTourClosed()\" />\n```\n\n## API\n\n### TourStep\n\n```typescript\ninterface TourStep {\n target: string; // CSS selector for the target element\n title: string;\n content: string;\n placement?: 'top' | 'bottom' | 'left' | 'right' | 'auto';\n highlightPadding?: number;\n disableInteraction?: boolean;\n beforeShow?: () => void | Promise<void>;\n afterHide?: () => void | Promise<void>;\n}\n```\n\n### TourOptions\n\n```typescript\ninterface TourOptions {\n steps: TourStep[];\n overlayOpacity?: number; // Default: 0.5\n animationDuration?: number; // Default: 300\n showProgress?: boolean; // Default: true\n showStepNumbers?: boolean; // Default: true\n allowClose?: boolean; // Default: true\n allowKeyboardNavigation?: boolean; // Default: true\n scrollBehavior?: ScrollBehavior; // Default: 'smooth'\n scrollPadding?: number; // Default: 100\n}\n```\n\n### TourService\n\n| Method | Type | Description |\n| ------------- | ------------------------- | ---------------------- |\n| `start` | `(options: TourOptions)` | Start a new tour |\n| `stop` | `() => void` | Stop the current tour |\n| `next` | `() => void` | Go to next step |\n| `previous` | `() => void` | Go to previous step |\n| `goTo` | `(index: number) => void` | Jump to specific step |\n| `isActive` | `Signal<boolean>` | Whether tour is active |\n| `currentStep` | `Signal<number>` | Current step index |\n| `steps` | `Signal<TourStep[]>` | All tour steps |\n| `progress` | `Signal<number>` | Progress percentage |\n\n### ScTourGuide\n\n| Output | Type | Description |\n| -------------- | -------- | ------------------------------- |\n| `stepChange` | `number` | Emits when step changes |\n| `tourComplete` | `void` | Emits when tour finishes |\n| `tourClosed` | `void` | Emits when tour is closed early |\n\n## Examples\n\n### Basic Tour\n\n```typescript\ntourService.start({\n steps: [\n { target: '#dashboard', title: 'Dashboard', content: 'Your main overview.' },\n { target: '#settings', title: 'Settings', content: 'Configure options.' },\n { target: '#help', title: 'Help', content: 'Get support.' },\n ],\n});\n```\n\n### Minimal Tour (No Progress/Numbers)\n\n```typescript\ntourService.start({\n steps: [...],\n showProgress: false,\n showStepNumbers: false,\n overlayOpacity: 0.7\n});\n```\n\n### Custom Placement\n\n```typescript\n{\n target: '#sidebar',\n title: 'Navigation',\n content: 'Access all sections here.',\n placement: 'right',\n highlightPadding: 16\n}\n```\n\n## Keyboard Shortcuts\n\n| Key | Action |\n| ------- | ------------------ |\n| `\u2192` | Next step |\n| `\u2190` | Previous step |\n| `Enter` | Next step / Finish |\n| `Esc` | Close tour |\n\n## Features\n\n- SVG mask-based overlay with spotlight cutout\n- Auto-positioning tooltips with smart placement\n- Progress bar and step number indicators\n- Keyboard navigation support\n- Scroll target elements into view\n- Customizable highlight padding\n- Lifecycle hooks for before/after step actions\n- Injectable service for programmatic control\n- Responsive overlay that tracks window resize/scroll\n\n## Accessibility\n\n- ARIA dialog role with modal attribute\n- Keyboard navigable\n- Focus management\n- Screen reader friendly labels\n",
|
|
30958
|
-
exports: []
|
|
30959
|
-
},
|
|
30960
|
-
{
|
|
30961
|
-
name: "transfer-list",
|
|
30962
|
-
readme: "# Transfer List\n\nA dual-list component for moving items between source and target lists with selection and search support.\n\n## Installation\n\n```typescript\nimport { ScTransferList } from '@/ui/transfer-list';\nimport type { TransferListItem, TransferListState } from '@/ui/transfer-list';\n```\n\n## Usage\n\n### Basic Usage\n\n```html\n<sc-transfer-list [(sourceItems)]=\"sourceItems\" [(targetItems)]=\"targetItems\" (change)=\"onChange($event)\" />\n```\n\n```typescript\nsourceItems = signal<TransferListItem[]>([\n { id: '1', label: 'Item 1', description: 'Description' },\n { id: '2', label: 'Item 2' },\n { id: '3', label: 'Item 3' },\n]);\n\ntargetItems = signal<TransferListItem[]>([]);\n```\n\n### With Custom Titles\n\n```html\n<sc-transfer-list [(sourceItems)]=\"available\" [(targetItems)]=\"selected\" sourceTitle=\"Available Options\" targetTitle=\"Selected Options\" />\n```\n\n### Without Search\n\n```html\n<sc-transfer-list [(sourceItems)]=\"source\" [(targetItems)]=\"target\" [searchable]=\"false\" />\n```\n\n### With Disabled Items\n\n```typescript\nsourceItems = signal<TransferListItem[]>([\n { id: '1', label: 'Movable Item' },\n { id: '2', label: 'Locked Item', disabled: true },\n]);\n```\n\n## API Reference\n\n### Inputs\n\n| Input | Type | Default | Description |\n| ------------- | -------------------- | ------------- | --------------------------- |\n| `sourceItems` | `TransferListItem[]` | `[]` | Source list items (two-way) |\n| `targetItems` | `TransferListItem[]` | `[]` | Target list items (two-way) |\n| `sourceTitle` | `string` | `'Available'` | Source list title |\n| `targetTitle` | `string` | `'Selected'` | Target list title |\n| `searchable` | `boolean` | `true` | Enable search in lists |\n| `height` | `string` | `'300px'` | List max height |\n| `class` | `string` | `''` | Additional CSS classes |\n\n### Outputs\n\n| Output | Type | Description |\n| -------- | ------------------------------------------------------------ | ------------------------- |\n| `change` | `{ source: TransferListItem[]; target: TransferListItem[] }` | Emitted when lists change |\n\n## Type Definitions\n\n```typescript\ninterface TransferListItem {\n id: string;\n label: string;\n description?: string;\n disabled?: boolean;\n}\n\ninterface TransferListState {\n source: TransferListItem[];\n target: TransferListItem[];\n}\n```\n\n## Features\n\n- Two-way binding for both lists\n- Move selected items between lists\n- Move all items at once\n- Select/deselect all in each list\n- Search filtering in both lists\n- Disabled items support\n- Item descriptions\n- Checkbox selection\n- Indeterminate checkbox state\n- Keyboard accessible\n",
|
|
30963
|
-
exports: []
|
|
30964
|
-
},
|
|
30965
|
-
{
|
|
30966
|
-
name: "tree",
|
|
30967
|
-
readme: '# Tree\n\nA hierarchical collapsible tree for displaying nested data. Built with Angular ARIA for full accessibility.\n\n## Features\n\n- \u2728 **Simple API** - Minimal boilerplate with automatic parent-child management\n- \u267F **Fully Accessible** - Built on Angular ARIA with complete keyboard navigation\n- \u{1F3A8} **Customizable** - Style items, icons, and indentation\n- \u{1F4C1} **Unlimited Nesting** - Support for deeply nested structures\n- \u{1F3AC} **Animated** - Smooth expand/collapse transitions\n- \u{1F3AF} **Type-Safe** - Full TypeScript support\n\n## Quick Start\n\n```html\n<ul scTree #tree="scTree">\n <li scTreeItem [parent]="tree.tree" value="folder">\n <button scTreeItemTrigger>\n <svg scTreeItemIcon><!-- folder icon --></svg>\n <span>Folder</span>\n </button>\n <ul scTreeItemGroup>\n <li scTreeItem [parent]="tree.tree" value="file">\n <button scTreeItemTrigger>\n <svg scTreeItemIcon><!-- file icon --></svg>\n <span>File.ts</span>\n </button>\n </li>\n </ul>\n </li>\n</ul>\n```\n\n## Getting Started\n\nTo create a tree:\n\n1. **Add the root tree** with a template reference:\n\n ```html\n <ul scTree #tree="scTree"></ul>\n ```\n\n2. **Add tree items** with parent binding and unique value:\n\n ```html\n <li scTreeItem [parent]="tree.tree" value="unique-id"></li>\n ```\n\n3. **Add a clickable trigger** to expand/collapse:\n\n ```html\n <button scTreeItemTrigger>Item Label</button>\n ```\n\n4. **Wrap nested children** (no additional bindings needed):\n ```html\n <ul scTreeItemGroup>\n <!-- Child items here -->\n </ul>\n ```\n\n**Key Points:**\n\n- All items use `[parent]="tree.tree"` regardless of nesting depth\n- Each item needs a unique `value` attribute\n- `sc-tree-item-group` automatically connects to its parent item\n- The component handles all ARIA attributes and accessibility\n\n## Components\n\n### ScTree\n\nRoot container with tree role. Uses Angular ARIA\'s `Tree` directive.\n\n**Selector:** `ul[scTree]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n### ScTreeItem\n\nIndividual tree item that can have children. Uses Angular ARIA\'s `TreeItem` directive.\n\n**Selector:** `li[scTreeItem]`\n\n**Required Inputs:**\n\n| Input | Type | Description |\n| -------- | ----------------------- | -------------------------------------------------------------- |\n| `parent` | `Tree \\| TreeItemGroup` | Reference to the root tree (use `tree.tree` from template ref) |\n| `value` | `string` | Unique identifier for this item |\n\n**Optional Inputs:**\n\n| Input | Type | Default | Description |\n| ---------- | --------- | ------- | ---------------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n| `label` | `string` | - | Accessible label (optional) |\n| `disabled` | `boolean` | `false` | Whether the item is disabled |\n| `expanded` | `boolean` | `false` | Initial expanded state |\n\n**Properties:**\n\n- `level`: Computed nesting level (0 for root items)\n- `hasChildren`: Computed based on presence of `sc-tree-item-group`\n- `treeItem`: Access to Angular ARIA\'s TreeItem instance\n - `treeItem.expanded()`: Signal for expanded state\n - `treeItem.selected()`: Signal for selected state\n - `treeItem.disabled()`: Signal for disabled state\n\n### ScTreeItemTrigger\n\nClickable button to expand/collapse the item.\n\n**Selector:** `button[scTreeItemTrigger]`\n\nAutomatically includes:\n\n- Chevron icon that rotates when expanded\n- Proper indentation based on nesting level\n- Full keyboard navigation support via Angular ARIA\n\n### ScTreeItemGroup\n\nContainer for nested child items. Uses Angular ARIA\'s `TreeItemGroup` directive internally.\n\n**Selector:** `ul[scTreeItemGroup]`\n\n**Inputs:**\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\nAutomatically connects to its parent tree item - no manual bindings required. Hidden when parent item is collapsed.\n\n### ScTreeItemIcon\n\nOptional icon slot for tree items.\n\n**Selector:** `[scTreeItemIcon]`\n\n## Examples\n\n### File Explorer with Icons\n\n```html\n<ul scTree #tree="scTree">\n <li scTreeItem [parent]="tree.tree" value="src" [expanded]="true">\n <button scTreeItemTrigger>\n <svg scTreeItemIcon class="text-blue-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor">\n <path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z" />\n </svg>\n <span>src</span>\n </button>\n <ul scTreeItemGroup>\n <li scTreeItem [parent]="tree.tree" value="app" [expanded]="true">\n <button scTreeItemTrigger>\n <svg scTreeItemIcon class="text-blue-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor">\n <path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z" />\n </svg>\n <span>app</span>\n </button>\n <ul scTreeItemGroup>\n <li scTreeItem [parent]="tree.tree" value="main">\n <button scTreeItemTrigger>\n <svg scTreeItemIcon class="text-green-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor">\n <path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" />\n <path d="M14 2v4a2 2 0 0 0 2 2h4" />\n </svg>\n <span>main.ts</span>\n </button>\n </li>\n <li scTreeItem [parent]="tree.tree" value="app-component">\n <button scTreeItemTrigger>\n <svg scTreeItemIcon class="text-green-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor">\n <path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" />\n <path d="M14 2v4a2 2 0 0 0 2 2h4" />\n </svg>\n <span>app.component.ts</span>\n </button>\n </li>\n </ul>\n </li>\n </ul>\n </li>\n</ul>\n```\n\n### Navigation Tree\n\n```html\n<ul scTree #tree="scTree">\n <li scTreeItem [parent]="tree.tree" value="getting-started" [expanded]="true">\n <button scTreeItemTrigger>Getting Started</button>\n <ul scTreeItemGroup>\n <li scTreeItem [parent]="tree.tree" value="intro">\n <button scTreeItemTrigger>Introduction</button>\n </li>\n <li scTreeItem [parent]="tree.tree" value="install">\n <button scTreeItemTrigger>Installation</button>\n </li>\n <li scTreeItem [parent]="tree.tree" value="config">\n <button scTreeItemTrigger>Configuration</button>\n </li>\n </ul>\n </li>\n <li scTreeItem [parent]="tree.tree" value="components">\n <button scTreeItemTrigger>Components</button>\n <ul scTreeItemGroup>\n <li scTreeItem [parent]="tree.tree" value="button">\n <button scTreeItemTrigger>Button</button>\n </li>\n <li scTreeItem [parent]="tree.tree" value="input">\n <button scTreeItemTrigger>Input</button>\n </li>\n </ul>\n </li>\n</ul>\n```\n\n### Simple Tree (No Icons)\n\n```html\n<ul scTree #tree="scTree">\n <li scTreeItem [parent]="tree.tree" value="fruits">\n <button scTreeItemTrigger>Fruits</button>\n <ul scTreeItemGroup>\n <li scTreeItem [parent]="tree.tree" value="apple">\n <button scTreeItemTrigger>Apple</button>\n </li>\n <li scTreeItem [parent]="tree.tree" value="banana">\n <button scTreeItemTrigger>Banana</button>\n </li>\n </ul>\n </li>\n <li scTreeItem [parent]="tree.tree" value="vegetables">\n <button scTreeItemTrigger>Vegetables</button>\n <ul scTreeItemGroup>\n <li scTreeItem [parent]="tree.tree" value="carrot">\n <button scTreeItemTrigger>Carrot</button>\n </li>\n </ul>\n </li>\n</ul>\n```\n\n### Controlled Expansion\n\nAccess the Angular ARIA `TreeItem` instance to programmatically control expansion:\n\n```typescript\n@Component({\n imports: [ScTree, ScTreeItem, ScTreeItemTrigger, ScTreeItemGroup],\n template: `\n <ul scTree #tree="scTree">\n <li scTreeItem [parent]="tree.tree" value="item" #item="scTreeItem">\n <button scTreeItemTrigger>Item (Expanded: {{ item.treeItem.expanded() }})</button>\n <ul scTreeItemGroup>\n <li scTreeItem [parent]="tree.tree" value="child">\n <button scTreeItemTrigger>Child</button>\n </li>\n </ul>\n </li>\n </ul>\n <button (click)="item.treeItem.expanded.update(v => !v)">Toggle Item</button>\n `,\n})\nexport class MyComponent {}\n```\n\nOr access from a child component:\n\n```typescript\nexport class MyTreeItemComponent {\n readonly treeItem = inject(ScTreeItem);\n\n toggleExpansion() {\n this.treeItem.treeItem.expanded.update((v) => !v);\n }\n}\n```\n\n## API Design\n\nThis tree component uses a **simplified API** compared to traditional hierarchical implementations:\n\n- **Single parent reference**: All items use `[parent]="tree.tree"`, not nested group references\n- **Automatic relationships**: `sc-tree-item-group` automatically connects to its parent item internally\n- **No manual wiring**: No need for `[ownedBy]` bindings or complex template reference chains\n\nThis design prioritizes developer experience while maintaining full Angular ARIA accessibility features.\n\n## Styling & Customization\n\nAll components accept a `class` input for custom styling:\n\n```html\n<ul scTree #tree="scTree" class="rounded-lg border p-4">\n <li scTreeItem [parent]="tree.tree" value="item" class="my-custom-item">\n <button scTreeItemTrigger class="font-bold hover:bg-blue-100">Custom Styled Item</button>\n </li>\n</ul>\n```\n\n**Built-in Features:**\n\n- Automatic indentation based on nesting level (12px per level)\n- Animated chevron icon rotation on expand/collapse\n- Hover and focus states for accessibility\n- Selected item highlighting (via `aria-selected`)\n\n**Customizing Icons:**\n\nUse the `sc-tree-item-icon` attribute on any SVG or icon element:\n\n```html\n<button scTreeItemTrigger>\n <svg scTreeItemIcon class="text-blue-500">\n <!-- Your custom icon -->\n </svg>\n <span>Item Label</span>\n</button>\n```\n\n## Keyboard Navigation\n\nAngular ARIA provides comprehensive keyboard navigation:\n\n| Key | Action |\n| --------------- | ----------------------------------------- |\n| `Enter`/`Space` | Activate/select item |\n| `ArrowDown` | Move to next visible item |\n| `ArrowUp` | Move to previous visible item |\n| `ArrowRight` | Expand collapsed item/move to first child |\n| `ArrowLeft` | Collapse expanded item/move to parent |\n| `Home` | Move to first item |\n| `End` | Move to last visible item |\n| `a-z` | Type-ahead to find items |\n\n## Accessibility\n\nBuilt with Angular ARIA for full accessibility:\n\n- `role="tree"` on root container (via Angular ARIA)\n- `role="treeitem"` on each item (via Angular ARIA)\n- `role="group"` on nested content (via Angular ARIA)\n- `aria-expanded` reflects expand state\n- `aria-selected` reflects selection state\n- `aria-disabled` for disabled items\n- Full keyboard navigation support\n- Focus management and roving tabindex\n- Screen reader announcements\n',
|
|
30968
|
-
exports: [
|
|
30969
|
-
"ScTree",
|
|
30970
|
-
"ScTreeItemTrigger",
|
|
30971
|
-
"ScTreeItemTriggerIcon",
|
|
30972
|
-
"ScTreeItem",
|
|
30973
|
-
"SC_TREE_ITEM",
|
|
30974
|
-
"ScTreeItemIcon",
|
|
30975
|
-
"ScTreeItemGroup"
|
|
30976
|
-
]
|
|
30977
|
-
},
|
|
30978
30650
|
{
|
|
30979
30651
|
name: "video-player",
|
|
30980
30652
|
readme: '# Video Player\n\nFull-featured HTML5 video player with composable controls, keyboard shortcuts, and fullscreen support.\n\n## Composable Architecture\n\nThe video player uses a **composable architecture** that gives you full control over layout and functionality.\n\n### Basic Usage\n\n```typescript\nimport {\n ScVideoPlayer,\n ScVideoPlayerControls,\n ScVideoPlayerPlayPause,\n ScVideoPlayerProgress,\n ScVideoPlayerTime,\n ScVideoPlayerFullscreen,\n} from \'@semantic-components/ui-lab\';\n\n@Component({\n imports: [\n ScVideoPlayer,\n ScVideoPlayerControls,\n ScVideoPlayerPlayPause,\n ScVideoPlayerProgress,\n ScVideoPlayerTime,\n ScVideoPlayerFullscreen,\n ],\n template: `\n <div scVideoPlayer [src]="\'video.mp4\'" [poster]="\'poster.jpg\'">\n <div scVideoPlayerControls>\n <div scVideoPlayerProgress></div>\n <div scVideoPlayerToolbar>\n <button scVideoPlayerPlayPause>\n <!-- Play/pause icon -->\n </button>\n <span scVideoPlayerTime></span>\n <button scVideoPlayerFullscreen>\n <!-- Fullscreen icon -->\n </button>\n </div>\n </div>\n </div>\n `,\n})\n```\n\n### Composable Components\n\n**`ScVideoPlayer`**\n\n- Root component that renders the video and provides context\n- **Selector**: `[scVideoPlayer]`\n- **Inputs**: `src`, `poster`\n- Manages playback state, volume, fullscreen, etc.\n\n**`ScVideoPlayerControls`**\n\n- Container for control elements (uses `<ng-content>`)\n- **Selector**: `div[scVideoPlayerControls]`\n- **Default position**: Absolute bottom with gradient overlay\n\n**`ScVideoPlayerToolbar`**\n\n- Flex container for control buttons\n- **Selector**: `div[scVideoPlayerToolbar]`\n\n**`ScVideoPlayerPlayPause`**\n\n- Play/pause toggle button\n- **Selector**: `button[scVideoPlayerPlayPause]`\n- **Auto state**: Reflects playing/paused state\n\n**`ScVideoPlayerProgress`**\n\n- Seek bar with buffering indicator\n- **Selector**: `div[scVideoPlayerProgress]`\n- Shows buffered ranges and current progress\n\n**`ScVideoPlayerVolume`**\n\n- Volume control with mute button and slider\n- **Selector**: `div[scVideoPlayerVolume]`\n- Requires `[volume-icon]` selector for icon content\n\n**`ScVideoPlayerTime`**\n\n- Current time / duration display\n- **Selector**: `span[scVideoPlayerTime]`\n- Automatically formats time\n\n**`ScVideoPlayerSkip`**\n\n- Skip forward/back button\n- **Selector**: `button[scVideoPlayerSkip]`\n- **Inputs**: `seconds` (required), `ariaLabel`\n\n**`ScVideoPlayerSpeed`**\n\n- Playback speed menu\n- **Selector**: `div[scVideoPlayerSpeed]`\n- **Inputs**: `speeds` (default: `[0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2]`)\n\n**`ScVideoPlayerFullscreen`**\n\n- Fullscreen toggle\n- **Selector**: `button[scVideoPlayerFullscreen]`\n\n**`ScVideoPlayerPip`**\n\n- Picture-in-picture toggle\n- **Selector**: `button[scVideoPlayerPip]`\n\n**`ScVideoPlayerBigPlay`**\n\n- Large centered play button overlay\n- **Selector**: `button[scVideoPlayerBigPlay]`\n- Auto-hides when playing or buffering\n\n**`ScVideoPlayerBufferingIndicator`**\n\n- Buffering indicator directive\n- **Selector**: `svg[scVideoPlayerBufferingIndicator]`\n- Auto-hides when not buffering\n\n**`ScVideoPlayerSpacer`**\n\n- Flexible spacer for toolbar layout\n- **Selector**: `div[scVideoPlayerSpacer]`\n\n### Flexible Examples\n\n#### Minimal Player\n\n```html\n<div scVideoPlayer [src]="video">\n <div scVideoPlayerControls>\n <button scVideoPlayerPlayPause>Play</button>\n </div>\n</div>\n```\n\n#### With Progress and Time\n\n```html\n<div scVideoPlayer [src]="video">\n <div scVideoPlayerControls>\n <div scVideoPlayerProgress></div>\n <div scVideoPlayerToolbar>\n <button scVideoPlayerPlayPause>\u23EF</button>\n <span scVideoPlayerTime></span>\n </div>\n </div>\n</div>\n```\n\n#### Full-Featured Player\n\n```html\n<div scVideoPlayer #player="scVideoPlayer" [src]="video" [poster]="poster">\n <svg scVideoPlayerBufferingIndicator siLoaderIcon></svg>\n\n <button scVideoPlayerBigPlay>\n <!-- Play icon -->\n </button>\n\n <div scVideoPlayerControls>\n <div scVideoPlayerProgress></div>\n\n <div scVideoPlayerToolbar>\n <button scVideoPlayerPlayPause>\u23EF</button>\n <button scVideoPlayerSkip [seconds]="-10">\u23EA</button>\n <button scVideoPlayerSkip [seconds]="10">\u23E9</button>\n\n <div scVideoPlayerVolume>\n <svg volume-icon><!-- Volume icon --></svg>\n </div>\n\n <span scVideoPlayerTime class="ml-2"></span>\n\n <div scVideoPlayerSpacer></div>\n\n <div scVideoPlayerSpeed></div>\n <button scVideoPlayerPip>PiP</button>\n <button scVideoPlayerFullscreen>\u26F6</button>\n </div>\n </div>\n</div>\n```\n\n## Types\n\n```typescript\ninterface ScVideoSource {\n src: string;\n type?: string;\n label?: string;\n}\n\ninterface ScVideoTrack {\n src: string;\n kind: \'subtitles\' | \'captions\' | \'descriptions\' | \'chapters\' | \'metadata\';\n srclang: string;\n label: string;\n default?: boolean;\n}\n```\n\n## Features\n\n- Composable architecture for maximum flexibility\n- Progress bar with buffering indicator\n- Volume slider with mute toggle\n- Playback speed selection\n- Skip forward/back buttons\n- Picture-in-picture support\n- Fullscreen mode\n- Keyboard navigation\n- Multiple video sources\n- Subtitle/caption support\n- Buffering indicator\n- Customizable controls layout\n\n## Accessibility\n\n- ARIA labels on all controls\n- Keyboard navigable\n- Screen reader friendly\n- Focus indicators\n- Semantic HTML structure\n',
|
|
30981
30653
|
exports: []
|
|
30982
|
-
},
|
|
30983
|
-
{
|
|
30984
|
-
name: "virtual-list",
|
|
30985
|
-
readme: '# Virtual List\n\nA high-performance virtualized list component that efficiently renders large datasets by only rendering visible items.\n\n## Installation\n\n```typescript\nimport { ScVirtualList } from \'@/ui/virtual-list\';\nimport type { VirtualListItem, VirtualListRange } from \'@/ui/virtual-list\';\n```\n\n## Usage\n\n### Basic Usage\n\n```html\n<sc-virtual-list [items]="items" [itemHeight]="48" [height]="400">\n <ng-template let-item let-index="index">\n <div class="border-b p-3">{{ index }}: {{ item }}</div>\n </ng-template>\n</sc-virtual-list>\n```\n\n```typescript\nitems = Array.from({ length: 10000 }, (_, i) => `Item ${i + 1}`);\n```\n\n### Custom Item Template\n\n```html\n<sc-virtual-list [items]="users" [itemHeight]="64">\n <ng-template let-user let-index="index">\n <div class="flex items-center gap-3 border-b p-3">\n <img [src]="user.avatar" class="h-10 w-10 rounded-full" />\n <div>\n <div class="font-medium">{{ user.name }}</div>\n <div class="text-muted-foreground text-sm">{{ user.email }}</div>\n </div>\n </div>\n </ng-template>\n</sc-virtual-list>\n```\n\n### With Custom Track Function\n\n```html\n<sc-virtual-list [items]="items" [trackByFn]="trackById">\n <ng-template let-item>{{ item.name }}</ng-template>\n</sc-virtual-list>\n```\n\n```typescript\ntrackById = (index: number, item: User) => item.id;\n```\n\n### Listening to Range Changes\n\n```html\n<sc-virtual-list [items]="items" (rangeChange)="onRangeChange($event)">\n <ng-template let-item>{{ item }}</ng-template>\n</sc-virtual-list>\n```\n\n```typescript\nonRangeChange(range: VirtualListRange) {\n console.log(\'Visible range:\', range.start, \'-\', range.end);\n}\n```\n\n## API Reference\n\n### Inputs\n\n| Input | Type | Default | Description |\n| ------------ | ------------------------------------- | ---------- | --------------------------------- |\n| `items` | `T[]` | `[]` | Array of items to render |\n| `itemHeight` | `number` | `48` | Fixed height of each item in px |\n| `overscan` | `number` | `3` | Extra items to render above/below |\n| `height` | `string \\| number` | `\'400px\'` | Container height |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n| `trackByFn` | `(index: number, item: T) => unknown` | `(i) => i` | Track function for items |\n\n### Outputs\n\n| Output | Type | Description |\n| ------------- | ------------------ | ---------------------------------- |\n| `rangeChange` | `VirtualListRange` | Emitted when visible range changes |\n\n### Methods\n\n| Method | Description |\n| ----------------------------------------- | ----------------------------- |\n| `scrollToIndex(index: number, behavior?)` | Scroll to specific item index |\n| `scrollToTop(behavior?)` | Scroll to top of list |\n| `scrollToBottom(behavior?)` | Scroll to bottom of list |\n\n## Type Definitions\n\n```typescript\ninterface VirtualListRange {\n start: number;\n end: number;\n}\n\ninterface VirtualListItem<T = unknown> {\n index: number;\n data: T;\n}\n```\n\n## Features\n\n- Efficient virtualization for large datasets\n- Fixed-height item rendering\n- Configurable overscan for smoother scrolling\n- Custom item templates via ng-template\n- Custom track function support\n- Programmatic scroll methods\n- Range change events for infinite loading\n- Smooth scroll behavior support\n',
|
|
30986
|
-
exports: []
|
|
30987
30654
|
}
|
|
30988
30655
|
]
|
|
30989
30656
|
},
|
|
@@ -30999,60 +30666,11 @@ var manifest_default = {
|
|
|
30999
30666
|
},
|
|
31000
30667
|
{
|
|
31001
30668
|
name: "@semantic-components/code",
|
|
31002
|
-
components: [
|
|
31003
|
-
{
|
|
31004
|
-
name: "code-editor",
|
|
31005
|
-
readme: '# Code Editor Components\n\nAn interactive code editor component with syntax highlighting powered by [Shiki](https://shiki.style/) and shadcn/ui styling. Features line numbers, auto-indent, tab handling, and cursor position tracking. Automatically follows the app\'s light/dark theme.\n\n## Import\n\n```typescript\nimport { ScCodeEditor, ScCodeEditorHeader, ScCodeEditorLabel, ScCodeEditorFooter, ScCodeEditorContent, ScCodeEditorCopyButton, ScCodeEditorLanguage, detectLanguage } from \'@semantic-components/ui-lab\';\n```\n\n## Architecture\n\nThe component uses Shiki\'s dual-theme feature (`github-light` + `github-dark`) with `defaultColor: false` to generate CSS variable-based output. The CSS switches between `--shiki-light` and `--shiki-dark` variables based on the `.dark` class on the document root.\n\n```\nScCodeEditor (Root - div[scCodeEditor])\n\u251C\u2500\u2500 ScCodeEditorHeader (Header - div[scCodeEditorHeader])\n\u2502 \u251C\u2500\u2500 ScCodeEditorLabel (Label - span[scCodeEditorLabel])\n\u2502 \u2514\u2500\u2500 ScCodeEditorCopyButton (Copy button)\n\u251C\u2500\u2500 ScCodeEditorContent (Content - div[scCodeEditorContent])\n\u2502 \u251C\u2500\u2500 Line numbers (optional)\n\u2502 \u2514\u2500\u2500 Editable textarea with syntax highlighting\n\u2514\u2500\u2500 ScCodeEditorFooter (Footer - div[scCodeEditorFooter])\n \u2514\u2500\u2500 Cursor position and stats\n```\n\n## Components\n\n| Component | Selector | Description |\n| ------------------------ | -------------------------------- | ------------------------------------- |\n| `ScCodeEditor` | `div[scCodeEditor]` | Root container with border and focus |\n| `ScCodeEditorHeader` | `div[scCodeEditorHeader]` | Header bar with border |\n| `ScCodeEditorLabel` | `span[scCodeEditorLabel]` | Label for filename or language |\n| `ScCodeEditorContent` | `div[scCodeEditorContent]` | Editable code area with highlighting |\n| `ScCodeEditorCopyButton` | `button[scCodeEditorCopyButton]` | Copy button with visual feedback |\n| `ScCodeEditorFooter` | `div[scCodeEditorFooter]` | Footer with cursor position and stats |\n\n## Inputs\n\n### ScCodeEditor (Root)\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\nThe root container with border, rounded corners, and focus-within ring.\n\n### ScCodeEditorHeader\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\nHeader bar with bottom border for filename/language label and copy button.\n\n### ScCodeEditorLabel\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\nLabel for displaying filename or language with muted foreground styling.\n\n### ScCodeEditorFooter\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\nFooter bar with top border for displaying cursor position and file statistics.\n\n### ScCodeEditorCopyButton\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------------ | ---------------------- |\n| `code` | `string` | **required** | The code to copy |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\nCopy button that shows a checkmark on successful copy for 2 seconds.\n\n### ScCodeEditorContent\n\n| Input | Type | Default | Description |\n| -------------------- | ---------------------- | ------------- | --------------------------------- |\n| `value` | `string` | `\'\'` | Two-way bound editor value |\n| `language` | `ScCodeEditorLanguage` | `\'plaintext\'` | Language for syntax highlighting |\n| `filename` | `string` | `\'\'` | Filename for language detection |\n| `placeholder` | `string` | `\'\'` | Placeholder text when empty |\n| `disabled` | `boolean` | `false` | Whether the editor is disabled |\n| `readonly` | `boolean` | `false` | Whether the editor is read-only |\n| `showLineNumbers` | `boolean` | `true` | Whether to show line numbers |\n| `tabSize` | `number` | `2` | Number of spaces per tab |\n| `insertSpaces` | `boolean` | `true` | Insert spaces instead of tabs |\n| `wordWrap` | `boolean` | `false` | Enable word wrapping |\n| `autoDetectLanguage` | `boolean` | `false` | Auto-detect language from content |\n| `ariaLabel` | `string` | `\'\'` | Accessibility label |\n| `ariaDescribedby` | `string` | `\'\'` | Accessibility description ID |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\n## Outputs\n\n### ScCodeEditorContent\n\n| Output | Type | Description |\n| ------------------ | ---------------------------------- | --------------------------------- |\n| `valueChange` | `string` | Emitted when editor value changes |\n| `languageDetected` | `ScCodeEditorLanguage` | Emitted when language is detected |\n| `cursorChange` | `{ line: number; column: number }` | Emitted when cursor moves |\n\n## Supported Languages\n\n`angular-ts` | `typescript` | `javascript` | `html` | `css` | `json` | `python` | `bash` | `shell` | `markdown` | `yaml` | `sql` | `go` | `rust` | `java` | `plaintext`\n\n## Usage\n\n### Basic Usage\n\n```html\n<div scCodeEditor>\n <div scCodeEditorContent [(value)]="code" language="typescript"></div>\n</div>\n```\n\n### Full Featured Editor\n\n```html\n<div scCodeEditor>\n <div scCodeEditorHeader>\n <div class="flex items-center gap-2">\n <span class="text-muted-foreground text-sm">{{ filename }}</span>\n <span scCodeEditorLabel>{{ language }}</span>\n </div>\n <button scCodeEditorCopyButton [code]="code"></button>\n </div>\n\n <div scCodeEditorContent [(value)]="code" [language]="language" [filename]="filename" [showLineNumbers]="true" (cursorChange)="onCursorChange($event)"></div>\n\n <div scCodeEditorFooter>\n <div class="flex items-center gap-3">\n <span>Ln {{ line }}, Col {{ column }}</span>\n </div>\n <div class="flex items-center gap-3">\n <span>{{ lineCount }} lines</span>\n <span>{{ charCount }} chars</span>\n </div>\n </div>\n</div>\n```\n\n### Minimal Editor (No Header/Footer)\n\n```html\n<div scCodeEditor>\n <div scCodeEditorContent [(value)]="code" language="json" [showLineNumbers]="false"></div>\n</div>\n```\n\n### With Auto-Detect Language\n\n```html\n<div scCodeEditor>\n <div scCodeEditorHeader>\n <span scCodeEditorLabel>{{ detectedLanguage }}</span>\n <button scCodeEditorCopyButton [code]="code"></button>\n </div>\n\n <div scCodeEditorContent [(value)]="code" [autoDetectLanguage]="true" (languageDetected)="detectedLanguage = $event"></div>\n</div>\n```\n\n### Read-Only Mode\n\n```html\n<div scCodeEditor>\n <div scCodeEditorContent [(value)]="code" language="typescript" [readonly]="true"></div>\n</div>\n```\n\n### With Word Wrap\n\n```html\n<div scCodeEditor>\n <div scCodeEditorContent [(value)]="longCode" language="markdown" [wordWrap]="true" class="max-h-[400px]"></div>\n</div>\n```\n\n### Custom Tab Size\n\n```html\n<div scCodeEditor>\n <div scCodeEditorContent [(value)]="code" language="python" [tabSize]="4" [insertSpaces]="true"></div>\n</div>\n```\n\n### Tracking Cursor Position\n\n```typescript\nexport class MyComponent {\n code = signal(\'\');\n cursorPosition = signal({ line: 1, column: 1 });\n\n onCursorChange(position: { line: number; column: number }) {\n this.cursorPosition.set(position);\n }\n}\n```\n\n```html\n<div scCodeEditor>\n <div scCodeEditorContent [(value)]="code" language="typescript" (cursorChange)="onCursorChange($event)"></div>\n\n <div scCodeEditorFooter>\n <span>Ln {{ cursorPosition().line }}, Col {{ cursorPosition().column }}</span>\n </div>\n</div>\n```\n\n## Features\n\n### Composable Architecture\n\nBuild custom layouts with separate header, content, and footer components.\n\n### Syntax Highlighting\n\nPowered by Shiki with 30+ languages supported. Real-time highlighting as you type.\n\n### Smart Indentation\n\n- **Tab key**: Insert spaces or tabs (configurable)\n- **Shift+Tab**: Outdent current line\n- **Enter**: Auto-indent based on previous line\n- **Auto-indent**: Extra indent after `{`, `[`, or `:`\n- **Smart brackets**: Auto-outdent when typing `}`, `]`, or `)`\n\n### Line Numbers\n\nOptional line numbers with active line highlighting.\n\n### Language Detection\n\nAutomatic language detection from file extension or content patterns using the `detectLanguage()` function.\n\n### Cursor Tracking\n\nReal-time cursor position (line and column) tracking with change events.\n\n### Copy Button\n\nBuilt-in copy-to-clipboard functionality with visual feedback.\n\n### Accessibility\n\n- Proper ARIA labels and descriptions\n- Keyboard navigation support\n- Screen reader friendly\n- Focus management\n\n### Customizable\n\nAll components accept custom classes for styling flexibility.\n\n## Theming\n\nThe component automatically follows the app\'s theme:\n\n- **Light mode**: Uses `github-light` Shiki theme\n- **Dark mode**: Uses `github-dark` Shiki theme (activated by `.dark` class on `<html>`)\n\nNo manual theme configuration is needed. The component renders both theme colors as CSS variables and switches between them with CSS.\n\n## Keyboard Shortcuts\n\n| Key | Action |\n| ------------- | ----------------------------------------- |\n| `Tab` | Insert indent (spaces or tab) |\n| `Shift+Tab` | Remove indent |\n| `Enter` | New line with auto-indent |\n| `{`, `[`, `:` | Extra indent on next line after Enter |\n| `}`, `]`, `)` | Auto-outdent when line is only whitespace |\n\n## Utility Functions\n\n### detectLanguage(code, filename?)\n\nAutomatically detects the programming language from code content or filename.\n\n```typescript\nimport { detectLanguage } from \'@semantic-components/ui-lab\';\n\nconst language = detectLanguage(code, \'app.component.ts\');\n// Returns: \'typescript\'\n\nconst detectedFromContent = detectLanguage(\'function hello() {}\');\n// Returns: \'javascript\'\n```\n\n**Detection logic:**\n\n1. If filename provided, detect from extension\n2. If no filename, analyze code patterns:\n - HTML tags \u2192 `html`\n - JSON structure \u2192 `json`\n - TypeScript types \u2192 `typescript`\n - JavaScript keywords \u2192 `javascript`\n - Python syntax \u2192 `python`\n - SQL keywords \u2192 `sql`\n - Markdown headers \u2192 `markdown`\n - Shebang \u2192 `bash`\n\n## Styling\n\nThe components use Tailwind CSS with shadcn/ui design tokens:\n\n- **Container** (`ScCodeEditor`): Focus-within ring, rounded border\n- **Header** (`ScCodeEditorHeader`): Flex layout with bottom border\n- **Label** (`ScCodeEditorLabel`): Small muted text\n- **Footer** (`ScCodeEditorFooter`): Flex layout with top border\n- **Content** (`ScCodeEditorContent`): Relative positioning with overlay layers\n- **Line numbers**: Muted at 50% opacity, active line at 100%\n- **Code font**: System monospace stack (`ui-monospace, SFMono-Regular, ...`)\n- **Textarea**: Transparent with colored caret for overlay effect\n\n## Advanced Example\n\n```typescript\nexport class CodeEditorExample {\n code = signal(`function greet(name: string) {\n console.log(\\`Hello, \\${name}!\\`);\n}\n\ngreet(\'World\');`);\n\n filename = signal(\'example.ts\');\n language = signal<ScCodeEditorLanguage>(\'typescript\');\n stats = computed(() => {\n const value = this.code();\n return {\n lines: value.split(\'\\n\').length,\n chars: value.length,\n };\n });\n}\n```\n\n```html\n<div scCodeEditor>\n <div scCodeEditorHeader>\n <div class="flex items-center gap-2">\n <span class="text-muted-foreground text-sm">{{ filename() }}</span>\n <span scCodeEditorLabel>{{ language() }}</span>\n </div>\n <button scCodeEditorCopyButton [code]="code()"></button>\n </div>\n\n <div scCodeEditorContent [(value)]="code" [language]="language()" [filename]="filename()" [showLineNumbers]="true" [tabSize]="2" [insertSpaces]="true" class="max-h-[600px] min-h-[300px]"></div>\n\n <div scCodeEditorFooter>\n <div class="flex items-center gap-3">\n <span>Ln {{ stats().line }}, Col {{ stats().column }}</span>\n </div>\n <div class="flex items-center gap-3">\n <span>{{ stats().lines }} lines</span>\n <span>{{ stats().chars }} chars</span>\n </div>\n </div>\n</div>\n```\n',
|
|
31006
|
-
exports: []
|
|
31007
|
-
},
|
|
31008
|
-
{
|
|
31009
|
-
name: "code-viewer",
|
|
31010
|
-
readme: '# Code Viewer Components\n\nA read-only code display component with syntax highlighting powered by [Shiki](https://shiki.style/) and shadcn/ui styling. Automatically follows the app\'s light/dark theme.\n\n## Import\n\n```typescript\nimport { ScCodeViewer, ScCodeViewerHeader, ScCodeViewerLabel, ScCodeViewerContent, ScCodeViewerLanguage } from \'@semantic-components/ui-lab\';\n```\n\n## Architecture\n\nThe component uses Shiki\'s dual-theme feature (`github-light` + `github-dark`) with `defaultColor: false` to generate CSS variable-based output. The CSS switches between `--shiki-light` and `--shiki-dark` variables based on the `.dark` class on the document root.\n\n```\nScCodeViewer (Root - div[scCodeViewer])\n\u251C\u2500\u2500 ScCodeViewerHeader (Header - div[scCodeViewerHeader])\n\u2502 \u251C\u2500\u2500 ScCodeViewerLabel (Label - span[scCodeViewerLabel])\n\u2502 \u2514\u2500\u2500 ScCopyButton (Copy button)\n\u2514\u2500\u2500 ScCodeViewerContent (Content - div[scCodeViewerContent])\n```\n\n## Components\n\n| Component | Selector | Description |\n| --------------------- | -------------------------- | -------------------------------- |\n| `ScCodeViewer` | `div[scCodeViewer]` | Root container with border |\n| `ScCodeViewerHeader` | `div[scCodeViewerHeader]` | Header bar with border |\n| `ScCodeViewerLabel` | `span[scCodeViewerLabel]` | Label for filename or language |\n| `ScCodeViewerContent` | `div[scCodeViewerContent]` | Content with syntax highlighting |\n\n## Inputs\n\n### ScCodeViewer (Root)\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\nThe root container with border and rounded corners.\n\n### ScCodeViewerHeader\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\nHeader bar with bottom border for filename/language label and copy button.\n\n### ScCodeViewerLabel\n\n| Input | Type | Default | Description |\n| ------- | -------- | ------- | ---------------------- |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\nLabel for displaying filename or language with muted foreground styling.\n\n### ScCodeViewerContent\n\n| Input | Type | Default | Description |\n| ----------------- | ---------------------- | ------------- | -------------------------------- |\n| `code` | `string` | **required** | The source code to display |\n| `language` | `ScCodeViewerLanguage` | `\'plaintext\'` | Language for syntax highlighting |\n| `showLineNumbers` | `boolean` | `false` | Whether to show line numbers |\n| `class` | `string` | `\'\'` | Additional CSS classes |\n\nThe content component with Shiki syntax highlighting.\n\n## Supported Languages\n\n`angular-ts` | `typescript` | `javascript` | `html` | `css` | `json` | `python` | `bash` | `shell` | `markdown` | `yaml` | `sql` | `go` | `rust` | `java` | `plaintext`\n\n## Usage\n\n### Basic Usage\n\n```html\n<div scCodeViewer>\n <div scCodeViewerHeader>\n <span scCodeViewerLabel>TypeScript</span>\n <button scCopyButton [value]="code"></button>\n </div>\n <div scCodeViewerContent [code]="code" language="typescript"></div>\n</div>\n```\n\n### With Filename\n\n```html\n<div scCodeViewer>\n <div scCodeViewerHeader>\n <span scCodeViewerLabel>app.component.ts</span>\n <button scCopyButton [value]="code"></button>\n </div>\n <div scCodeViewerContent [code]="code" language="angular-ts"></div>\n</div>\n```\n\n### With Line Numbers\n\n```html\n<div scCodeViewer>\n <div scCodeViewerHeader>\n <span scCodeViewerLabel>{{ filename }}</span>\n <button scCopyButton [value]="code"></button>\n </div>\n <div scCodeViewerContent [code]="code" language="typescript" [showLineNumbers]="true"></div>\n</div>\n```\n\n### Without Header\n\n```html\n<div scCodeViewer>\n <div scCodeViewerContent [code]="code" language="json"></div>\n</div>\n```\n\n### With Max Height\n\n```html\n<div scCodeViewer>\n <div scCodeViewerHeader>\n <span scCodeViewerLabel>{{ language }}</span>\n <button scCopyButton [value]="code"></button>\n </div>\n <div scCodeViewerContent [code]="longCode" language="typescript" maxHeight="300px"></div>\n</div>\n```\n\n### Custom Header Content\n\n```html\n<div scCodeViewer>\n <div scCodeViewerHeader>\n <div class="flex items-center gap-2">\n <svg class="size-4"><!-- icon --></svg>\n <span scCodeViewerLabel>{{ filename }}</span>\n <span class="text-muted-foreground text-xs">({{ lines }} lines)</span>\n </div>\n <div class="flex gap-2">\n <button>Download</button>\n <button scCopyButton [value]="code"></button>\n </div>\n </div>\n <div scCodeViewerContent [code]="code" [language]="language"></div>\n</div>\n```\n\n## Theming\n\nThe component automatically follows the app\'s theme:\n\n- **Light mode**: Uses `github-light` Shiki theme\n- **Dark mode**: Uses `github-dark` Shiki theme (activated by `.dark` class on `<html>`)\n\nNo manual theme configuration is needed. The component renders both theme colors as CSS variables and switches between them with CSS.\n\n## Features\n\n- **Composable Architecture**: Build custom layouts with separate header and content components\n- **Syntax Highlighting**: Powered by Shiki with 30+ languages supported\n- **Automatic Theming**: Follows app\'s light/dark mode automatically\n- **Line Numbers**: Optional line number display\n- **Copy Button**: Built-in copy-to-clipboard functionality with ScCopyButton\n- **Customizable**: All components accept custom classes\n- **Accessible**: Proper semantic HTML and ARIA attributes\n\n## Styling\n\nThe components use Tailwind CSS with shadcn/ui design tokens:\n\n- **Container** (`ScCodeViewer`): `rounded-lg border border-border overflow-hidden`\n- **Header** (`ScCodeViewerHeader`): `flex items-center justify-between border-b border-border px-4 py-2`\n- **Label** (`ScCodeViewerLabel`): `text-xs font-medium text-muted-foreground`\n- **Content** (`ScCodeViewerContent`): `overflow-auto` with configurable max-height\n- **Code font**: System monospace stack (`ui-monospace, SFMono-Regular, ...`)\n- **Line numbers**: Muted foreground at 50% opacity, non-selectable\n',
|
|
31011
|
-
exports: []
|
|
31012
|
-
}
|
|
31013
|
-
]
|
|
30669
|
+
components: []
|
|
31014
30670
|
},
|
|
31015
30671
|
{
|
|
31016
30672
|
name: "@semantic-components/editor",
|
|
31017
|
-
components: [
|
|
31018
|
-
{
|
|
31019
|
-
name: "editor",
|
|
31020
|
-
readme: '# Editor Component\n\nComposable WYSIWYG editor built with [Tiptap](https://tiptap.dev/), a headless rich-text editor framework powered by ProseMirror.\n\n## Installation\n\nThe editor component requires Tiptap packages as peer dependencies. Install them alongside `@semantic-components/ui`:\n\n```bash\nnpm install @semantic-components/ui \\\n @tiptap/core \\\n @tiptap/starter-kit \\\n @tiptap/extension-text-align \\\n @tiptap/extension-placeholder\n```\n\nOr if you already have `@semantic-components/ui` installed:\n\n```bash\nnpm install @tiptap/core @tiptap/starter-kit @tiptap/extension-text-align @tiptap/extension-placeholder\n```\n\n**Note**: Link and Underline extensions are included in `@tiptap/starter-kit` v3, so no need to install them separately.\n\n## Features\n\n- **Rich Text Editing**: Bold, italic, underline, strikethrough, headings, lists, blockquotes, code, links, and more\n- **Keyboard Shortcuts**: Built-in shortcuts for all formatting commands (Ctrl+B, Ctrl+I, Ctrl+U, Ctrl+Z, Ctrl+Y, etc.)\n- **Customizable Toolbar**: Composable architecture allows full control over toolbar layout\n- **Two-Way Binding**: Seamless synchronization with Angular signals\n- **Accessibility**: Full keyboard navigation and ARIA support\n- **Extensible**: Built on Tiptap, allowing custom extensions and commands\n\n## Implementation\n\nThe editor is powered by [Tiptap](https://tiptap.dev/), a headless rich-text editor framework built on ProseMirror. This provides:\n\n- **Robust editing**: Industry-standard editing engine\n- **Extensibility**: Add custom extensions and commands\n- **Keyboard shortcuts**: Built-in shortcuts for all formatting\n- **Better browser support**: Works consistently across modern browsers\n- **Future-ready**: Foundation for collaboration, mentions, slash commands, etc.\n\n### Extensions Included\n\nThe editor comes pre-configured with these Tiptap extensions:\n\n- **StarterKit**: Bold, Italic, Strike, Underline, Code, Heading, Lists, Blockquote, History, HardBreak, Paragraph, Text, Link\n - Link configured with: `openOnClick: false`, `target="_blank"`, `rel="noopener noreferrer"`\n- **TextAlign**: Text alignment (left, center, right, justify)\n- **Placeholder**: Customizable placeholder text\n\n### Bundle Size\n\n- **Total**: ~30 KB (minified)\n- **Gzipped**: ~10 KB\n\nThis is an acceptable trade-off for the significant improvements in reliability, extensibility, and developer experience.\n\n## Basic Usage\n\n```typescript\nimport { Component, signal } from \'@angular/core\';\nimport { ScEditor, ScEditorContent, ScEditorToolbar, ScEditorToolbarGroup, ScEditorBoldButton, ScEditorItalicButton, ScEditorUnderlineButton, ScEditorFooter, ScEditorCount, ScEditorWordCount, ScEditorCharCount } from \'@semantic-components/ui-lab\';\n\n@Component({\n selector: \'app-example\',\n imports: [ScEditor, ScEditorContent, ScEditorToolbar, ScEditorToolbarGroup, ScEditorBoldButton, ScEditorItalicButton, ScEditorUnderlineButton, ScEditorFooter, ScEditorCount, ScEditorWordCount, ScEditorCharCount],\n template: `\n <div scEditor class="overflow-hidden rounded-lg border">\n <div scEditorToolbar>\n <div scEditorToolbarGroup>\n <button scEditorBold>Bold</button>\n <button scEditorItalic>Italic</button>\n <button scEditorUnderline>Underline</button>\n </div>\n </div>\n\n <div scEditorContent [(value)]="content" placeholder="Start typing..."></div>\n\n <div scEditorFooter>\n <div scEditorCount>\n <span scEditorWordCount></span>\n <span scEditorCharCount></span>\n </div>\n </div>\n </div>\n `,\n})\nexport class ExampleComponent {\n readonly content = signal(\'\');\n}\n```\n\n## API\n\n### ScEditor (Directive)\n\nRoot directive that manages editor state and provides context to child components.\n\n**Selector**: `[scEditor]`\n\n**Inputs**:\n\n- `disabled: boolean` - Disables the editor\n- `readonly: boolean` - Makes the editor read-only\n\n**Signals** (accessed via `inject(SC_EDITOR)`):\n\n- `isBold()` - Whether bold is active\n- `isItalic()` - Whether italic is active\n- `isUnderline()` - Whether underline is active\n- `isStrikethrough()` - Whether strikethrough is active\n- `isOrderedList()` - Whether ordered list is active\n- `isUnorderedList()` - Whether unordered list is active\n- `isBlockquote()` - Whether blockquote is active\n- `alignment()` - Current text alignment (\'left\' | \'center\' | \'right\' | \'justify\')\n- `currentHeading()` - Current heading level (\'p\' | \'h1\' | \'h2\' | \'h3\' | \'h4\' | \'h5\' | \'h6\')\n- `canUndo()` - Whether undo is available\n- `canRedo()` - Whether redo is available\n- `editorInstance()` - The Tiptap Editor instance (for advanced usage)\n\n**Methods**:\n\n- `execCommand(command: string, value?: string)` - Execute a formatting command\n- `updateToolbarState()` - Update toolbar button states (called automatically)\n- `initializeEditor(element: HTMLElement, content: string, placeholder: string)` - Initialize Tiptap (called automatically)\n- `destroyEditor()` - Cleanup Tiptap instance (called automatically)\n\n### ScEditorContent (Component)\n\nContent area where text editing happens.\n\n**Selector**: `div[scEditorContent]`\n\n**Inputs**:\n\n- `value: string` - Two-way bindable HTML content (use with `[(value)]`)\n- `placeholder: string` - Placeholder text (default: "Start typing...")\n- `ariaLabel: string` - ARIA label (default: "Rich text editor")\n- `class: string` - Additional CSS classes (use Tailwind utilities for sizing, e.g., `min-h-[300px] max-h-[500px]`)\n\n**Outputs**:\n\n- `focus` - Emitted when editor gains focus\n- `blur` - Emitted when editor loses focus\n\n### Toolbar Components\n\nAll toolbar buttons inject `SC_EDITOR` and call the appropriate commands.\n\n**Available Buttons**:\n\n- `ScEditorBoldButton` - Toggle bold\n- `ScEditorItalicButton` - Toggle italic\n- `ScEditorUnderlineButton` - Toggle underline\n- `ScEditorStrikethroughButton` - Toggle strikethrough\n- `ScEditorCodeButton` - Toggle inline code\n- `ScEditorLinkButton` - Insert/edit link (prompts for URL)\n- `ScEditorBulletListButton` - Toggle bullet list\n- `ScEditorNumberedListButton` - Toggle numbered list\n- `ScEditorBlockquoteButton` - Toggle blockquote\n- `ScEditorAlignLeftButton` - Align left\n- `ScEditorAlignCenterButton` - Align center\n- `ScEditorAlignRightButton` - Align right\n- `ScEditorAlignJustifyButton` - Align justify\n- `ScEditorUndoButton` - Undo last action\n- `ScEditorRedoButton` - Redo last action\n- `ScEditorClearFormattingButton` - Remove all formatting\n\n**Containers**:\n\n- `ScEditorToolbar` - Toolbar container\n- `ScEditorToolbarGroup` - Group related buttons\n- `ScEditorSeparator` - Visual separator between groups\n- `ScEditorFooter` - Footer container\n- `ScEditorHeader` - Header container\n\n**Utilities**:\n\n- `ScEditorCount` - Container for count components (uses `<ng-content>`, allows custom layout)\n- `ScEditorWordCount` - Display word count (e.g., "42 words")\n- `ScEditorCharCount` - Display character count (e.g., "256 characters")\n- `ScEditorHeadingSelect` - Dropdown to select heading level\n\n## Keyboard Shortcuts\n\nAll standard keyboard shortcuts are handled by Tiptap:\n\n- **Ctrl+B** / **Cmd+B** - Bold\n- **Ctrl+I** / **Cmd+I** - Italic\n- **Ctrl+U** / **Cmd+U** - Underline\n- **Ctrl+Z** / **Cmd+Z** - Undo\n- **Ctrl+Shift+Z** / **Cmd+Shift+Z** - Redo\n- **Ctrl+Y** / **Cmd+Y** - Redo\n- **Ctrl+E** / **Cmd+E** - Inline code\n\n## Advanced Usage\n\n### Accessing the Tiptap Editor Instance\n\nFor advanced use cases, you can access the underlying Tiptap editor:\n\n```typescript\nimport { inject, effect } from \'@angular/core\';\nimport { SC_EDITOR } from \'@semantic-components/ui-lab\';\n\nexport class MyComponent {\n readonly editor = inject(SC_EDITOR);\n\n constructor() {\n effect(() => {\n const instance = this.editor.editorInstance();\n if (instance) {\n // Access Tiptap API\n console.log(instance.getJSON()); // Get content as JSON\n console.log(instance.getHTML()); // Get content as HTML\n console.log(instance.getText()); // Get plain text\n\n // Execute custom commands\n instance.chain().focus().toggleBold().run();\n }\n });\n }\n}\n```\n\n### Custom Commands\n\nYou can execute any Tiptap command via the editor instance:\n\n```typescript\nthis.editor.editorInstance()?.chain().focus().setHeading({ level: 2 }).insertContent(\'Hello world!\').run();\n```\n\n## Migration from execCommand\n\nPrevious versions used the deprecated `document.execCommand()` API. The current version uses Tiptap internally while maintaining the same external API for backwards compatibility.\n\n**Breaking Changes**: None! The external API remains identical.\n\n**Advanced Users**: If you directly accessed `contentElement()` for DOM manipulation, you should now use `editorInstance()` to interact with the editor via Tiptap\'s API.\n\n## Future Enhancements\n\nBuilt on Tiptap, these features can be easily added in the future:\n\n1. **Collaboration** - Real-time co-editing with `@tiptap/extension-collaboration`\n2. **Mentions** - @-mentions with autocomplete\n3. **Slash Commands** - `/` for quick formatting\n4. **Tables** - Rich table support\n5. **Images** - Drag-and-drop image upload\n6. **Custom Extensions** - Domain-specific formatting\n7. **Markdown Support** - Input/output markdown\n8. **Character Limits** - Built-in extension for content limits\n\n## Styling\n\nThe editor uses Tailwind CSS with CSS variables for theming. All styles respect the current theme (light/dark mode) and use OKLCH color format.\n\n**CSS Variables Used**:\n\n- `--border` - Border color (blockquote, hr)\n- `--muted` - Muted background (code, pre)\n- `--muted-foreground` - Muted text (placeholder, blockquote)\n- `--primary` - Primary color (links)\n\nColors are defined in OKLCH format and automatically adapt to light/dark themes.\n\n**Customization**:\n\n```html\n<!-- Custom font and text size -->\n<div scEditorContent class="font-serif text-lg"></div>\n\n<!-- Custom height constraints -->\n<div scEditorContent class="max-h-[600px] min-h-[300px]"></div>\n\n<!-- Remove default padding -->\n<div scEditorContent class="p-0"></div>\n\n<!-- Default: Both counts with standard layout -->\n<div scEditorFooter>\n <div scEditorCount>\n <span scEditorWordCount></span>\n <span scEditorCharCount></span>\n </div>\n</div>\n\n<!-- Only word count -->\n<div scEditorFooter>\n <div scEditorCount>\n <span scEditorWordCount></span>\n </div>\n</div>\n\n<!-- Only character count -->\n<div scEditorFooter>\n <div scEditorCount>\n <span scEditorCharCount></span>\n </div>\n</div>\n\n<!-- Custom separator and styling -->\n<div scEditorFooter>\n <div scEditorCount>\n <span scEditorWordCount class="text-blue-600"></span>\n <span class="text-muted-foreground">\u2022</span>\n <span scEditorCharCount class="text-green-600"></span>\n </div>\n</div>\n\n<!-- Footer with additional content -->\n<div scEditorFooter>\n <button class="text-primary text-sm hover:underline">Save draft</button>\n <div scEditorCount>\n <span scEditorWordCount></span>\n <span scEditorCharCount></span>\n </div>\n</div>\n\n<!-- Without using ScEditorCount container -->\n<div scEditorFooter class="justify-between">\n <div class="flex gap-2">\n <span scEditorWordCount class="text-xs"></span>\n <span scEditorCharCount class="text-xs"></span>\n </div>\n <button>Submit</button>\n</div>\n```\n\nDefault classes applied: `block outline-none overflow-y-auto min-h-[150px] max-h-[400px] p-4 prose prose-sm max-w-none dark:prose-invert`\n\n## Accessibility\n\nThe editor follows WCAG AA standards:\n\n- Full keyboard navigation\n- ARIA labels on all buttons\n- Focus management\n- Screen reader support\n- High contrast mode support\n\n## Browser Support\n\nWorks in all modern browsers that support ES2015+ and ProseMirror:\n\n- Chrome/Edge 90+\n- Firefox 88+\n- Safari 14+\n\n## License\n\nMIT\n',
|
|
31021
|
-
exports: [
|
|
31022
|
-
"ScEditor",
|
|
31023
|
-
"SC_EDITOR",
|
|
31024
|
-
"ScEditorAlignment",
|
|
31025
|
-
"ScEditorHeading",
|
|
31026
|
-
"ScEditorContent",
|
|
31027
|
-
"ScEditorToolbar",
|
|
31028
|
-
"ScEditorToolbarGroup",
|
|
31029
|
-
"ScEditorHeader",
|
|
31030
|
-
"ScEditorFooter",
|
|
31031
|
-
"ScEditorSeparator",
|
|
31032
|
-
"ScEditorBoldButton",
|
|
31033
|
-
"ScEditorItalicButton",
|
|
31034
|
-
"ScEditorUnderlineButton",
|
|
31035
|
-
"ScEditorStrikethroughButton",
|
|
31036
|
-
"ScEditorUndoButton",
|
|
31037
|
-
"ScEditorRedoButton",
|
|
31038
|
-
"ScEditorAlignLeftButton",
|
|
31039
|
-
"ScEditorAlignCenterButton",
|
|
31040
|
-
"ScEditorAlignRightButton",
|
|
31041
|
-
"ScEditorAlignJustifyButton",
|
|
31042
|
-
"ScEditorBulletListButton",
|
|
31043
|
-
"ScEditorNumberedListButton",
|
|
31044
|
-
"ScEditorLinkButton",
|
|
31045
|
-
"ScEditorBlockquoteButton",
|
|
31046
|
-
"ScEditorCodeButton",
|
|
31047
|
-
"ScEditorHorizontalRuleButton",
|
|
31048
|
-
"ScEditorClearFormattingButton",
|
|
31049
|
-
"ScEditorHeadingSelect",
|
|
31050
|
-
"ScEditorCount",
|
|
31051
|
-
"ScEditorWordCount",
|
|
31052
|
-
"ScEditorCharCount"
|
|
31053
|
-
]
|
|
31054
|
-
}
|
|
31055
|
-
]
|
|
30673
|
+
components: []
|
|
31056
30674
|
}
|
|
31057
30675
|
],
|
|
31058
30676
|
guides: [
|