# @letsprogram/ng-oat : Full API Reference > Signal-first Angular UI component library built on Oat CSS. 40+ standalone components, directive wrappers, Signal Forms integration, CVA adapters, 87 design tokens, and 12 ready-made recipe layouts. Requires Angular 21 and above. Package: `@letsprogram/ng-oat` v0.1.8 Install: `npm i @letsprogram/ng-oat` Peer deps: `@angular/core@^21`, `@angular/common@^21`, `@angular/forms@^21` ## Setup ```typescript // app.config.ts import { provideNgOat } from '@letsprogram/ng-oat'; export const appConfig = { providers: [provideNgOat()] }; ``` Include the Oat CSS stylesheet and tokens CSS in your angular.json styles array or import them globally. Optional theming: ```typescript import { provideNgOatTheme } from '@letsprogram/ng-oat'; providers: [ provideNgOat(), provideNgOatTheme({ tokens: { '--oat-primary': '#3b82f6', '--oat-radius-medium': '0.5rem', } }) ] ``` --- ## Components ### NgOatButton Selector: `ng-oat-button` Import: `import { NgOatButton } from '@letsprogram/ng-oat';` | Input | Type | Default | |-------|------|---------| | variant | `'default' \| 'secondary' \| 'danger'` | `'default'` | | btnStyle | `'filled' \| 'outline' \| 'ghost'` | `'filled'` | | size | `'default' \| 'small' \| 'large'` | `'default'` | | icon | `boolean` | `false` | | type | `'button' \| 'submit' \| 'reset'` | `'button'` | | disabled | `boolean` | `false` | | ariaLabel | `string` | `''` | Output: `clicked: MouseEvent` Content: projects button label text/icons. ```html Save Delete ... ``` --- ### NgOatSplitButton Selector: `ng-oat-split-button` Import: `import { NgOatSplitButton } from '@letsprogram/ng-oat';` | Input | Type | Default | |-------|------|---------| | label | `string` | **required** | | variant | `'default' \| 'secondary' \| 'danger'` | `'default'` | | btnStyle | `'filled' \| 'outline' \| 'ghost'` | `'filled'` | | size | `'default' \| 'small' \| 'large'` | `'default'` | | disabled | `boolean` | `false` | Output: `clicked: MouseEvent` Content: project `[role="menuitem"]` elements for the dropdown menu. ```html ``` --- ### NgOatBadge Selector: `ng-oat-badge` Import: `import { NgOatBadge } from '@letsprogram/ng-oat';` | Input | Type | Default | |-------|------|---------| | variant | `'default' \| 'secondary' \| 'outline' \| 'danger' \| 'success'` | `'default'` | Content: projects badge text. ```html Active Error ``` --- ### NgOatAlert Selector: `ng-oat-alert` Import: `import { NgOatAlert } from '@letsprogram/ng-oat';` | Input | Type | Default | |-------|------|---------| | variant | `'default' \| 'success' \| 'danger' \| 'warning'` | `'default'` | | size | `'compact' \| 'default' \| 'comfortable'` | `'default'` | | dismissible | `boolean` | `false` | Output: `dismissed: void` Content: projects alert body. Host has `role="alert"`. ```html Your changes have been saved. ``` --- ### NgOatCard / NgOatCardHeader / NgOatCardFooter Selectors: `ng-oat-card`, `ng-oat-card-header`, `ng-oat-card-footer` Import: `import { NgOatCard, NgOatCardHeader, NgOatCardFooter } from '@letsprogram/ng-oat';` No inputs/outputs : pure content projection. ```html

Card Title

Card body content

Action
``` --- ### NgOatAccordion Selector: `ng-oat-accordion` Import: `import { NgOatAccordion } from '@letsprogram/ng-oat';` | Input | Type | Default | |-------|------|---------| | items | `NgOatAccordionItem[]` | **required** | | group | `string \| undefined` | `undefined` | NgOatAccordionItem: `{ title: string; content: string; open?: boolean }` Output: `toggled: { item: NgOatAccordionItem; open: boolean }` ```typescript items: NgOatAccordionItem[] = [ { title: 'Section 1', content: 'Content for section 1' }, { title: 'Section 2', content: 'Content for section 2', open: true }, ]; ``` ```html ``` --- ### NgOatTable Selector: `ng-oat-table` Import: `import { NgOatTable } from '@letsprogram/ng-oat';` | Input | Type | Default | |-------|------|---------| | columns | `NgOatTableColumn[]` | **required** | | data | `Record[]` | **required** | | striped | `boolean` | `false` | | clickable | `boolean` | `false` | | emptyText | `string` | `'No data available.'` | | scrollX | `boolean` | `false` | | scrollY | `string` | `''` | NgOatTableColumn: `{ key: string; label: string; width?: string; align?: 'left'|'center'|'right'; render?: (val, row) => string }` Output: `rowClick: Record` ```html ``` --- ### NgOatBreadcrumb Selector: `ng-oat-breadcrumb` Import: `import { NgOatBreadcrumb, NgOatBreadcrumbIcon } from '@letsprogram/ng-oat';` | Input | Type | Default | |-------|------|---------| | items | `OatBreadcrumbItem[]` | **required** | OatBreadcrumbItem: `{ label: string; url?: string; icon?: string }` Output: `navigate: OatBreadcrumbItem` Content: optional `ng-template[ngOatBreadcrumbIcon]` for custom icon rendering. ```html ``` --- ### NgOatPagination Selector: `ng-oat-pagination` Import: `import { NgOatPagination } from '@letsprogram/ng-oat';` | Input | Type | Default | |-------|------|---------| | totalPages | `number` | **required** | | currentPage | `number` | `1` | | maxVisible | `number` | `5` | Output: `pageChange: number` ```html ``` --- ### NgOatProgress Selector: `ng-oat-progress` Import: `import { NgOatProgress } from '@letsprogram/ng-oat';` | Input | Type | Default | |-------|------|---------| | value | `number` | **required** | | max | `number` | `100` | ```html ``` --- ### NgOatMeter Selector: `ng-oat-meter` Import: `import { NgOatMeter } from '@letsprogram/ng-oat';` | Input | Type | Default | |-------|------|---------| | value | `number` | **required** | | min | `number` | `0` | | max | `number` | `1` | | low | `number \| undefined` | `undefined` | | high | `number \| undefined` | `undefined` | | optimum | `number \| undefined` | `undefined` | ```html ``` --- ### NgOatSpinner Selector: `ng-oat-spinner` Import: `import { NgOatSpinner } from '@letsprogram/ng-oat';` | Input | Type | Default | |-------|------|---------| | size | `'small' \| 'default' \| 'large'` | `'default'` | | overlay | `boolean` | `false` | Host: `aria-busy="true"`. Content projection supported. ```html Loading data... ``` --- ### NgOatSwitch Selector: `ng-oat-switch` Import: `import { NgOatSwitch } from '@letsprogram/ng-oat';` | Input/Model | Type | Default | Kind | |-------------|------|---------|------| | label | `string` | `''` | input | | checked | `boolean` | `false` | model (two-way) | | disabled | `boolean` | `false` | model (two-way) | Output: `changed: boolean` Implements `FormCheckboxControl` for Signal Forms. ```html ``` --- ### NgOatSkeleton Selector: `ng-oat-skeleton` Import: `import { NgOatSkeleton } from '@letsprogram/ng-oat';` | Input | Type | Default | |-------|------|---------| | type | `'line' \| 'box'` | `'line'` | | width | `string \| undefined` | `undefined` | ```html ``` --- ### NgOatAvatar Selector: `ng-oat-avatar` Import: `import { NgOatAvatar } from '@letsprogram/ng-oat';` | Input | Type | Default | |-------|------|---------| | src | `string` | `''` | | alt | `string` | `''` | | initials | `string` | `''` | | fallback | `string` | `''` | | size | `'sm' \| 'default' \| 'lg' \| 'xl'` | `'default'` | Auto-generates initials from `alt` if `src` fails and `initials` not set. ```html ``` --- ### NgOatSeparator Selector: `ng-oat-separator` Import: `import { NgOatSeparator } from '@letsprogram/ng-oat';` | Input | Type | Default | |-------|------|---------| | orientation | `'horizontal' \| 'vertical'` | `'horizontal'` | | label | `string` | `''` | ```html ``` --- ### NgOatFileUpload Selector: `ng-oat-file-upload` Import: `import { NgOatFileUpload } from '@letsprogram/ng-oat';` | Input | Type | Default | |-------|------|---------| | accept | `string` | `''` | | multiple | `boolean` | `false` | | maxSize | `number` | `0` | | disabled | `boolean` | `false` | | label | `string` | `''` | Output: `filesSelected: File[]` Methods: `openFilePicker()`, `removeFile(index)` Public signal: `files` ```html ``` --- ### NgOatInputOtp Selector: `ng-oat-input-otp` Import: `import { NgOatInputOtp } from '@letsprogram/ng-oat';` | Input/Model | Type | Default | Kind | |-------------|------|---------|------| | length | `number` | `6` | input | | separator | `number` | `0` | input | | mask | `boolean` | `false` | input | | value | `string` | `''` | model (two-way) | | disabled | `boolean` | `false` | model (two-way) | Implements `FormValueControl` for Signal Forms. ```html ``` --- ### NgOatSearchInput Selector: `ng-oat-search-input` Import: `import { NgOatSearchInput } from '@letsprogram/ng-oat';` | Input/Model | Type | Default | Kind | |-------------|------|---------|------| | placeholder | `string` | `'Search...'` | input | | shortcut | `string` | `''` | input | | debounceMs | `number` | `300` | input | | value | `string` | `''` | model (two-way) | | disabled | `boolean` | `false` | model (two-way) | Output: `search: string` Implements `FormValueControl`. Methods: `clear()`, `focus()`. ```html ``` --- ### NgOatCarousel Selector: `ng-oat-carousel` Import: `import { NgOatCarousel } from '@letsprogram/ng-oat';` | Input/Model | Type | Default | Kind | |-------------|------|---------|------| | slides | `NgOatCarouselSlide[]` | `[]` | input | | autoplay | `boolean` | `false` | input | | interval | `number` | `5000` | input | | loop | `boolean` | `true` | input | | showArrows | `boolean` | `true` | input | | showDots | `boolean` | `true` | input | | aspectRatio | `'auto' \| '16:9' \| '4:3' \| '1:1'` | `'auto'` | input | | activeIndex | `number` | `0` | model (two-way) | NgOatCarouselSlide: `{ src: string; alt?: string; caption?: string }` Output: `slideChange: number` Methods: `next()`, `prev()`, `goTo(index)` ```html ``` --- ### NgOatCardCarousel Selector: `ng-oat-card-carousel` Import: `import { NgOatCardCarousel } from '@letsprogram/ng-oat';` | Input | Type | Default | |-------|------|---------| | heading | `string` | `''` | | ariaLabel | `string` | `'Product carousel'` | | items | `NgOatProductCard[]` | `[]` | | showSeeAll | `boolean` | `false` | NgOatProductCard: `{ title: string; image: string; price?: string; description?: string }` Outputs: `seeAllClick: void`, `cardClick: NgOatProductCard` ```html ``` --- ### NgOatToolbar / NgOatToolbarRow Selectors: `ng-oat-toolbar`, `ng-oat-toolbar-row` Import: `import { NgOatToolbar, NgOatToolbarRow } from '@letsprogram/ng-oat';` | Input | Type | Default | |-------|------|---------| | color | `'default' \| 'primary' \| 'accent'` | `'default'` | | dense | `boolean` | `false` | | fixed | `boolean` | `true` | Content slots: `[toolbarStart]`, default, `[toolbarEnd]`. ```html App Name Nav links here ``` --- ### NgOatThemeSelector Selector: `ng-oat-theme-selector` Import: `import { NgOatThemeSelector } from '@letsprogram/ng-oat';` | Input | Type | Default | |-------|------|---------| | mode | `'dropdown' \| 'toggle'` | `'dropdown'` | | initialTheme | `NgOatTheme \| undefined` | `undefined` | | themes | `NgOatThemeOption[]` | `[light, dark, system]` | NgOatTheme: `'light' | 'dark' | 'system'` Output: `themeChange: NgOatTheme` Persists to localStorage. ```html ``` --- ### NgOatToggle Selector: `ng-oat-toggle` Import: `import { NgOatToggle } from '@letsprogram/ng-oat';` | Input/Model | Type | Default | Kind | |-------------|------|---------|------| | variant | `'default' \| 'outline'` | `'default'` | input | | size | `'sm' \| 'default' \| 'lg'` | `'default'` | input | | disabled | `boolean` | `false` | input | | toggleValue | `string` | `''` | input | | pressed | `boolean` | `false` | model (two-way) | Output: `pressedChange: boolean` ```html Bold ``` --- ### NgOatToggleGroup Selector: `ng-oat-toggle-group` Import: `import { NgOatToggleGroup } from '@letsprogram/ng-oat';` | Input/Model | Type | Default | Kind | |-------------|------|---------|------| | multiple | `boolean` | `false` | input | | disabled | `boolean` | `false` | input | | variant | `'default' \| 'outline'` | `'default'` | input | | size | `'sm' \| 'default' \| 'lg'` | `'default'` | input | | value | `string` | `''` | model (two-way) | ```html Left Center Right ``` --- ### NgOatChip / NgOatChipGroup / NgOatChipInput Selectors: `ng-oat-chip`, `ng-oat-chip-group`, `ng-oat-chip-input` Import: `import { NgOatChip, NgOatChipGroup, NgOatChipInput } from '@letsprogram/ng-oat';` **NgOatChip:** | Input/Model | Type | Default | Kind | |-------------|------|---------|------| | variant | `'default' \| 'secondary' \| 'outline' \| 'success' \| 'warning' \| 'danger'` | `'default'` | input | | size | `'sm' \| 'default' \| 'lg'` | `'default'` | input | | removable | `boolean` | `false` | input | | selectable | `boolean` | `false` | input | | chipValue | `string` | `''` | input | | label | `string` | `''` | input | | selected | `boolean` | `false` | model (two-way) | Outputs: `removed: void`, `selectedChange: boolean` **NgOatChipGroup:** | Input/Model | Type | Default | Kind | |-------------|------|---------|------| | multiple | `boolean` | `false` | input | | value | `string` | `''` | model (two-way) | Output: `chipRemoved: string` **NgOatChipInput:** | Input/Model | Type | Default | Kind | |-------------|------|---------|------| | placeholder | `string` | `'Add item...'` | input | | maxChips | `number` | `Infinity` | input | | chips | `string[]` | `[]` | model (two-way) | Outputs: `chipAdded: string`, `chipRemovedEvent: string` ```html Angular React ``` --- ## Directive Wrappers (Component Versions) ### NgOatDropdownComponent Selector: `ng-oat-dropdown` Import: `import { NgOatDropdownComponent } from '@letsprogram/ng-oat';` Output: `openChange: boolean` Methods: `open()`, `close()`, `toggle()` Content: `[trigger]` attribute for trigger button, `[role="menuitem"]` for items. ```html ``` --- ### NgOatTooltipComponent Selector: `ng-oat-tooltip` Import: `import { NgOatTooltipComponent } from '@letsprogram/ng-oat';` | Input | Type | Default | |-------|------|---------| | text | `string` | `''` | | template | `TemplateRef \| undefined` | `undefined` | | position | `'top' \| 'bottom' \| 'left' \| 'right'` | `'top'` | | delay | `number` | `700` | | disabled | `boolean` | `false` | Methods: `show()`, `hide()`. Signal: `isVisible`. ```html ``` --- ### NgOatSidebarComponent Selector: `ng-oat-sidebar` Import: `import { NgOatSidebarComponent } from '@letsprogram/ng-oat';` | Input | Type | Default | |-------|------|---------| | mode | `'fixed' \| 'overlay'` | `'fixed'` | | scrollLock | `boolean` | `true` | | initialOpen | `boolean` | `false` | Output: `openChange: boolean` Methods: `open()`, `close()`, `toggle()`. Signal: `isOpen`. ```html
Main content
``` --- ### NgOatTabsComponent Selector: `ng-oat-tabs` Import: `import { NgOatTabsComponent } from '@letsprogram/ng-oat';` | Input | Type | Default | |-------|------|---------| | tabs | `(string \| NgOatTabItem)[]` | **required** | NgOatTabItem: `{ label: string; disabled?: boolean }` Output: `tabChange: { index: number; tab: HTMLElement }` Method: `selectTab(index)`. Signal: `activeIndex`. ```html
Overview content
Details content
Reviews content
``` --- ### NgOatDialogComponent Selector: `ng-oat-dialog` Import: `import { NgOatDialogComponent } from '@letsprogram/ng-oat';` Output: `closed: string` Methods: `showModal()`, `show()`, `close(returnValue?)` Content slots: `[header]`, default body, `[footer]`. ```html

Confirm

Are you sure?

Cancel OK
Open Dialog ``` --- ## Signal Forms Fields All form field components implement Angular Signal Forms control interfaces, enabling model-based reactive forms without RxJS. ### NgOatInput Selector: `ng-oat-input` Import: `import { NgOatInput } from '@letsprogram/ng-oat';` | Input/Model | Type | Default | Kind | |-------------|------|---------|------| | label | `string` | `''` | input | | type | `'text' \| 'email' \| 'password' \| 'number' \| 'tel' \| 'url' \| 'search' \| 'date' \| 'datetime-local' \| 'time' \| 'month' \| 'week' \| 'color'` | `'text'` | input | | placeholder | `string` | `''` | input | | readonly | `boolean` | `false` | input | | required | `boolean` | `false` | input | | invalid | `boolean` | `false` | input | | showErrors | `boolean` | `true` | input | | min | `number \| undefined` | `undefined` | input | | max | `number \| undefined` | `undefined` | input | | minLength | `number \| undefined` | `undefined` | input | | maxLength | `number \| undefined` | `undefined` | input | | autocomplete | `string \| undefined` | `undefined` | input | | errors | `ValidationError[]` | `[]` | input | | value | `string` | `''` | model (two-way) | | disabled | `boolean` | `false` | model (two-way) | | touched | `boolean` | `false` | model (two-way) | Implements `FormValueControl`. ```html ``` --- ### NgOatTextarea Selector: `ng-oat-textarea` Import: `import { NgOatTextarea } from '@letsprogram/ng-oat';` | Input/Model | Type | Default | Kind | |-------------|------|---------|------| | label | `string` | `''` | input | | placeholder | `string` | `''` | input | | rows | `number` | `4` | input | | readonly | `boolean` | `false` | input | | required | `boolean` | `false` | input | | value | `string` | `''` | model (two-way) | | disabled | `boolean` | `false` | model (two-way) | ```html ``` --- ### NgOatSelect Selector: `ng-oat-select` Import: `import { NgOatSelect } from '@letsprogram/ng-oat';` | Input/Model | Type | Default | Kind | |-------------|------|---------|------| | label | `string` | `''` | input | | placeholder | `string` | `''` | input | | options | `NgOatSelectOption[]` | **required** | input | | required | `boolean` | `false` | input | | value | `string` | `''` | model (two-way) | | disabled | `boolean` | `false` | model (two-way) | NgOatSelectOption: `{ label: string; value: string; disabled?: boolean }` ```html ``` --- ### NgOatCheckbox Selector: `ng-oat-checkbox` Import: `import { NgOatCheckbox } from '@letsprogram/ng-oat';` | Input/Model | Type | Default | Kind | |-------------|------|---------|------| | label | `string` | `''` | input | | checked | `boolean` | `false` | model (two-way) | | disabled | `boolean` | `false` | model (two-way) | Implements `FormCheckboxControl`. ```html ``` --- ### NgOatRadioGroup Selector: `ng-oat-radio-group` Import: `import { NgOatRadioGroup } from '@letsprogram/ng-oat';` | Input/Model | Type | Default | Kind | |-------------|------|---------|------| | label | `string` | `''` | input | | options | `NgOatRadioOption[]` | **required** | input | | required | `boolean` | `false` | input | | value | `string` | `''` | model (two-way) | | disabled | `boolean` | `false` | model (two-way) | NgOatRadioOption: `{ label: string; value: string; disabled?: boolean }` ```html ``` --- ### NgOatFormError Selector: `ng-oat-form-error` Import: `import { NgOatFormError } from '@letsprogram/ng-oat';` | Input | Type | Default | |-------|------|---------| | control | `FieldState \| undefined` | `undefined` | | errors | `string[]` | `[]` | | show | `boolean` | `false` | Use `control` for Signal Forms, or `errors` + `show` for Reactive/Template forms. ```html ``` --- ## Directives ### NgOatDropdown Selector: `[ngOatDropdown]` Import: `import { NgOatDropdown } from '@letsprogram/ng-oat';` Attribute directive that initializes Oat dropdown behavior on a container element. ### NgOatTooltip Selector: `[ngOatTooltip]` Import: `import { NgOatTooltip } from '@letsprogram/ng-oat';` Attribute directive for native Oat tooltips via `data-tooltip`. ### NgOatSidebar Selector: `[ngOatSidebar]` Import: `import { NgOatSidebar } from '@letsprogram/ng-oat';` Attribute directive for Oat sidebar initialization. ### NgOatTabs Selector: `[ngOatTabs]` Import: `import { NgOatTabs } from '@letsprogram/ng-oat';` Attribute directive for Oat tabs initialization. ### NgOatDialog Selector: `[ngOatDialog]` Import: `import { NgOatDialog } from '@letsprogram/ng-oat';` Attribute directive for native `` Oat enhancement. --- ## CVA Adapters For use with Angular Reactive Forms or Template-driven Forms. ### NgOatValueCva Selector: `[ngOatValueCva]` Import: `import { NgOatValueCva } from '@letsprogram/ng-oat';` Bridges `ControlValueAccessor` to any component implementing `NgOatValueHost`. ### NgOatCheckboxCva Selector: `[ngOatCheckboxCva]` Import: `import { NgOatCheckboxCva } from '@letsprogram/ng-oat';` Bridges `ControlValueAccessor` to any component implementing `NgOatCheckboxHost`. ### NgOatFormsCva Import: `import { NgOatFormsCva } from '@letsprogram/ng-oat';` Convenience array containing all CVA directives for spread into imports. ```typescript // Using with Reactive Forms @Component({ imports: [ReactiveFormsModule, NgOatInput, NgOatValueCva], template: `` }) ``` --- ## Providers ### provideNgOat() Import: `import { provideNgOat } from '@letsprogram/ng-oat';` Required provider for ng-oat. Call in your app config providers array. Options: `NgOatOptions` (currently no required options). ### provideNgOatTheme(config) Import: `import { provideNgOatTheme } from '@letsprogram/ng-oat';` Optional provider for custom token overrides. ```typescript provideNgOatTheme({ tokens: { '--oat-primary': '#6366f1', '--oat-radius-medium': '0.75rem', '--oat-font-sans': '"Inter", system-ui, sans-serif', } }) ``` --- ## Design Tokens (87 total) All tokens use the `--oat-*` prefix and map to upstream `--*` Oat CSS custom properties. ### Colors (22) `--oat-background`, `--oat-foreground`, `--oat-card`, `--oat-card-foreground`, `--oat-primary`, `--oat-primary-foreground`, `--oat-secondary`, `--oat-secondary-foreground`, `--oat-muted`, `--oat-muted-foreground`, `--oat-faint`, `--oat-faint-foreground`, `--oat-accent`, `--oat-danger`, `--oat-danger-foreground`, `--oat-success`, `--oat-success-foreground`, `--oat-warning`, `--oat-warning-foreground`, `--oat-border`, `--oat-input`, `--oat-ring` ### Spacing (12) `--oat-space-1` through `--oat-space-6`, `--oat-space-8`, `--oat-space-10`, `--oat-space-12`, `--oat-space-14`, `--oat-space-16`, `--oat-space-18` ### Border Radius (4) `--oat-radius-small`, `--oat-radius-medium`, `--oat-radius-large`, `--oat-radius-full` ### Typography (14) `--oat-font-sans`, `--oat-font-mono`, `--oat-text-1` through `--oat-text-8`, `--oat-text-regular`, `--oat-leading-normal`, `--oat-font-normal`, `--oat-font-medium`, `--oat-font-semibold`, `--oat-font-bold` ### Shadows (3) `--oat-shadow-small`, `--oat-shadow-medium`, `--oat-shadow-large` ### Transitions (2) `--oat-transition-fast`, `--oat-transition` ### Z-Index (8) `--oat-z-base`, `--oat-z-sticky`, `--oat-z-fixed`, `--oat-z-dropdown`, `--oat-z-toast`, `--oat-z-modal`, `--oat-z-popover`, `--oat-z-tooltip` ### Dimensions (1) `--oat-bar-height` ### Component-level (5) `--oat-grid-cols`, `--oat-grid-gap`, `--oat-container-max`, `--oat-container-pad`, `--oat-topnav-offset` --- ## Utilities ### Version ```typescript import { OAT_VERSION } from '@letsprogram/ng-oat'; console.log(OAT_VERSION); // '0.1.8' ``` ### Tooltip Positioner ```typescript import { TOOLTIP_POSITIONER } from '@letsprogram/ng-oat'; // Injection token for custom tooltip positioning logic ``` --- ## Recipes Full-page layout patterns using ng-oat components: - **Login** : Username/password form with validation, forgot password link - **Registration** : Multi-field signup form with terms acceptance - **Dashboard** : Admin layout with sidebar navigation, stats cards, tables - **Blog** : Article listing with cards, pagination - **Comments** : Threaded comment section with avatars, reply form - **Contact** : Contact form with map placeholder - **Pricing** : Pricing tier cards with feature comparison - **Profile** : User profile page with avatar, info sections - **File Manager** : File browser with breadcrumbs, table, actions - **Settings** : Settings panel with form sections, toggles - **Notifications** : Notification feed with badges, actions - **Search Results** : Search page with filters, result cards, pagination