{"components":[{"name":"Accordion","dir":"accordion","entry":"omaris","importPath":"import { Accordion } from 'omaris'","summary":"MD3 expansion panels.","details":["`type=\"single\"` is the classic accordion — opening one closes the rest. `type=\"multiple\"` lets several stay open. Either way the open set is one bindable `value`, so it can be driven from a URL or restored from storage without the component owning the state."],"examples":[],"classesType":null,"parts":[],"variants":[{"name":"variant","doc":"","default":"plain","values":[{"name":"plain","doc":"Rows separated by hairlines, flush with the page."},{"name":"separated","doc":"Each panel its own raised card."},{"name":"outlined","doc":"One outlined block, rows divided inside it."}]}],"story":{"title":"Containment/Accordion","category":"Containment","own":true,"stories":["Playground","Single","Multiple","Variants","With icons and badges"]},"props":[{"name":"value","optional":true,"type":"string[]","default":"[]","bindable":true,"doc":"Open item values. Bindable.","details":[],"examples":[]},{"name":"type","optional":true,"type":"'single' | 'multiple'","default":"'single'","bindable":false,"doc":"`single` closes the others on open; `multiple` doesn't.","details":[],"examples":[]},{"name":"variant","optional":true,"type":"AccordionVariant","default":"'plain'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"collapsible","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Stop the last open item from being closed.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"AccordionItem","dir":"accordion","entry":"omaris","importPath":"import { AccordionItem } from 'omaris'","summary":"One panel of an `Accordion`: a header you press and the content it reveals.","details":["`value` is how the parent tracks it, so it has to be unique within the set."],"examples":[],"classesType":"AccordionItemClasses","parts":[{"name":"root","doc":""},{"name":"trigger","doc":""},{"name":"headline","doc":""},{"name":"supporting","doc":""},{"name":"wrapper","doc":"The animated wrapper. A grid row going 0fr → 1fr is the one way to transition to a content-derived height without measuring it."},{"name":"content","doc":""},{"name":"inner","doc":""},{"name":"chevron","doc":""}],"variants":[{"name":"variant","doc":"","values":[{"name":"plain","doc":""},{"name":"separated","doc":""},{"name":"outlined","doc":""}]},{"name":"open","doc":"","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Containment/Accordion","category":"Containment","own":false,"stories":["Playground","Single","Multiple","Variants","With icons and badges"]},"props":[{"name":"value","optional":false,"type":"string","bindable":false,"doc":"Identifies the panel in the accordion's `value`.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"Trigger text.","details":[],"examples":[]},{"name":"supportingText","optional":true,"type":"string","bindable":false,"doc":"Second line in the trigger.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"AccordionItemClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"icon","optional":true,"type":"Snippet","bindable":false,"doc":"Leading icon in the trigger.","details":[],"examples":[]},{"name":"heading","optional":true,"type":"Snippet","bindable":false,"doc":"Rich trigger content, in place of `title`.","details":[],"examples":[]},{"name":"end","optional":true,"type":"Snippet","bindable":false,"doc":"Trailing content before the chevron — a badge, a count.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"The panel body.","details":[],"examples":[]}]},{"name":"AiChat","dir":"ai-chat","entry":"omaris","importPath":"import { AiChat } from 'omaris'","summary":"A conversation with a model — the thread, the streaming reply, the composer, the stop button — wired to whichever model you have.","details":["The smallest call is one prop:","The person's messages sit in a compact bubble on the end side; the model's reply runs as plain text the width of the column, markdown and code blocks rendered. The thread follows the reply as it streams until the person scrolls up, and a button brings them back. Replies can be stopped, retried, regenerated and copied, and the person's own messages edited. `send` is any `(messages, ctx) => reply`, and a reply can be a string, an async iterable, a `ReadableStream` or the raw `Response` from a `fetch` — the component reads all of them.","The column is 48rem at most, centred; set `--chat-measure` on the root for another width."],"examples":[{"lang":"svelte","code":"<AiChat send={chatEndpoint('/api/chat')} />"}],"classesType":"AiChatClasses","parts":[{"name":"root","doc":""},{"name":"header","doc":"Above the thread — a title, a model picker. Only rendered with a `header` snippet."},{"name":"thread","doc":"The scrolling area, full width so its scrollbar sits at the edge."},{"name":"content","doc":"The centred column inside the thread."},{"name":"user","doc":"One of the person's messages, on the end side: the bubble, and its tools — beside it on hover with a mouse, under it on touch."},{"name":"bubble","doc":"The bubble around the person's message."},{"name":"assistant","doc":"One reply: the optional avatar and the text column."},{"name":"avatar","doc":"The circle beside a reply, with `avatar`."},{"name":"reply","doc":"The reply's column: reasoning, text, error, tools."},{"name":"prose","doc":"Rendered markdown."},{"name":"cursor","doc":"The dot at the end of a reply still arriving."},{"name":"typing","doc":"The three dots before the first word."},{"name":"tools","doc":"The copy / regenerate / edit row under a message."},{"name":"reasoning","doc":"The model's reasoning, folded above its answer when it sent any."},{"name":"alert","doc":"A failed reply's message and retry."},{"name":"empty","doc":"Before the first message."},{"name":"mark","doc":"The circle above the headline."},{"name":"title","doc":""},{"name":"description","doc":""},{"name":"suggestions","doc":""},{"name":"footer","doc":"The composer, the jump button over it and the disclaimer under it."},{"name":"jump","doc":"The \"jump to latest\" button, floating over the composer."},{"name":"composer","doc":"The single rounded surface: text field and send button."},{"name":"input","doc":""},{"name":"disclaimer","doc":"The line under the composer: \"Can make mistakes\"."}],"variants":[{"name":"tone","doc":"","default":"primary","values":[{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""}]},{"name":"disabled","doc":"","values":[{"name":"true","doc":""}]}],"story":{"title":"Communication/AI Chat","category":"Communication","own":true,"stories":["Playground","Empty","History","Avatar","Streaming","Error","Reasoning","Long thread","Headless","Overridden"]},"props":[{"name":"send","optional":true,"type":"SendFn","bindable":false,"doc":"Answers the conversation. `chatEndpoint('/api/chat')`, `mockChat()`, or any `(messages, ctx) => reply` of your own — a `fetch` whose `Response` you return as is will do.","details":[],"examples":[]},{"name":"messages","optional":true,"type":"AiChatMessage[]","default":"[]","bindable":true,"doc":"The conversation. Bindable; give it a history to resume one.","details":[],"examples":[]},{"name":"prompt","optional":true,"type":"string","default":"''","bindable":true,"doc":"The text in the composer. Bindable.","details":[],"examples":[]},{"name":"system","optional":true,"type":"string","bindable":false,"doc":"A system prompt, carried in the request by `chatEndpoint()`.","details":[],"examples":[]},{"name":"status","optional":true,"type":"AiChatStatus","default":"'idle'","bindable":true,"doc":"Where it is. Bindable, read-only in practice.","details":[],"examples":[]},{"name":"tone","optional":true,"type":"AiChatTone","default":"'primary'","bindable":false,"doc":"Colours the send button, the focus ring, links and the assistant's mark.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"'32rem'","bindable":false,"doc":"Height of the whole thing, in px or any CSS length. `class=\"h-full\"` also works.","details":[],"examples":[]},{"name":"avatar","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"A small mark beside each reply. The `icon` snippet replaces what is in it.","details":[],"examples":[]},{"name":"suggestions","optional":true,"type":"string[]","default":"[]","bindable":false,"doc":"Prompts offered as chips before the first message.","details":[],"examples":[]},{"name":"assistantName","optional":true,"type":"string","default":"'Assistant'","bindable":false,"doc":"The name the assistant goes by, for screen readers.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","default":"'How can I help?'","bindable":false,"doc":"The headline before the first message.","details":[],"examples":[]},{"name":"hint","optional":true,"type":"string","bindable":false,"doc":"The line under it.","details":[],"examples":[]},{"name":"placeholder","optional":true,"type":"string","default":"'Message…'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"disclaimer","optional":true,"type":"string","bindable":false,"doc":"The line under the composer.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onsend","optional":true,"type":"(message: AiChatMessage) => void","bindable":false,"doc":"Called with the message the person sent.","details":[],"examples":[]},{"name":"onfinish","optional":true,"type":"(message: AiChatMessage) => void","bindable":false,"doc":"Called with the finished reply.","details":[],"examples":[]},{"name":"onerror","optional":true,"type":"(error: Error) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(messages: AiChatMessage[]) => void","bindable":false,"doc":"Called after any change to the conversation.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"AiChatClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"header","optional":true,"type":"Snippet","bindable":false,"doc":"Above the thread.","details":[],"examples":[]},{"name":"icon","optional":true,"type":"Snippet","bindable":false,"doc":"The assistant's mark, in the empty state and the `avatar`. Defaults to sparkles.","details":[],"examples":[]},{"name":"empty","optional":true,"type":"Snippet<[AiChatEmptyContext]>","bindable":false,"doc":"Replaces the empty thread.","details":[],"examples":[]},{"name":"message","optional":true,"type":"Snippet<[AiChatMessageContext]>","bindable":false,"doc":"Replaces what a message shows — the bubble's text, or the reply's.","details":[],"examples":[]},{"name":"actions","optional":true,"type":"Snippet<[AiChatMessageContext]>","bindable":false,"doc":"Extra buttons under a message, after copy, regenerate and edit.","details":[],"examples":[]},{"name":"composer","optional":true,"type":"Snippet<[AiChatComposerContext]>","bindable":false,"doc":"Replaces the composer. An empty snippet takes it away.","details":[],"examples":[]}]},{"name":"AiImage","dir":"ai-image","entry":"omaris","importPath":"import { AiImage } from 'omaris'","summary":"A picture made from a sentence — the frame, the prompt bar, the wait and the picture, wired to whichever model you have.","details":["The smallest call is one prop:","That already has a prompt bar, suggestion chips, a spinner on the frame's surface while the model works, a picture that fades in once it has loaded, and download / regenerate / edit on it. `generate` is any function of `(request, ctx) => results`; three ship: `gemini()` and `openaiImages()` for those APIs, `endpoint()` for a route of yours, and `mockGenerate()` for a screen with no backend yet. Swapping models is swapping that one prop.","Everything after that is opt-in. `prompt` + `auto` makes a picture with nothing to press — a hero image, a product placeholder. `count` asks for a grid. `composer=\"none\"` takes the prompt bar away so your own UI calls `generate()` through `bind:this`. `history` keeps every result on a strip. `attach` lets a person drop a picture in to edit, and the edit tool feeds a result back in as the reference for the next one. Every part is a slot in `classes`, and every state is a snippet."],"examples":[{"lang":"svelte","code":"<AiImage generate={endpoint('/api/image')} />"}],"classesType":"AiImageClasses","parts":[{"name":"root","doc":""},{"name":"frame","doc":"The picture area. `--ai-aspect` is its shape; `aspect-auto` plus a height overrides it."},{"name":"canvas","doc":"Holds the finished picture, or the grid of them."},{"name":"grid","doc":"`count` above one lays the results out here."},{"name":"cell","doc":"One result's cell. Also the button that selects it from the grid."},{"name":"image","doc":"The picture. Fades in when a new one lands."},{"name":"loader","doc":"The wait: the frame's surface, covering it while the model works."},{"name":"spinner","doc":"The spinner in the middle of the wait."},{"name":"empty","doc":"Nothing made yet."},{"name":"emptyIcon","doc":""},{"name":"title","doc":""},{"name":"description","doc":""},{"name":"suggestions","doc":""},{"name":"alert","doc":"What went wrong, with a retry."},{"name":"tools","doc":"The corner toolbar over a finished picture."},{"name":"caption","doc":"The model's words about the picture, under it."},{"name":"composer","doc":"The prompt bar."},{"name":"attachment","doc":"The attached reference, as a small tile at the start of the bar."},{"name":"input","doc":""},{"name":"controls","doc":"The attach and the send/stop buttons."},{"name":"history","doc":"The strip of past results."},{"name":"thumb","doc":""}],"variants":[{"name":"tone","doc":"","default":"primary","values":[{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""}]},{"name":"variant","doc":"","default":"filled","values":[{"name":"filled","doc":"A tinted surface — the default, reads as a card."},{"name":"outlined","doc":"A hairline, for a frame inside a form."},{"name":"ghost","doc":"Nothing but the picture."}]},{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]},{"name":"composer","doc":"Where the prompt bar sits.","default":"below","values":[{"name":"below","doc":""},{"name":"overlay","doc":""},{"name":"none","doc":""}]},{"name":"fresh","doc":"A picture just made, rather than one handed in: it fades in.","values":[{"name":"true","doc":""}]},{"name":"sized","doc":"A height was given, so the aspect steps aside.","values":[{"name":"true","doc":""}]},{"name":"disabled","doc":"","values":[{"name":"true","doc":""}]}],"story":{"title":"Inputs/AI Image","category":"Inputs","own":true,"stories":["Playground","Idle","Generating","Regenerating","Done","Grid and history","Error","Overlay composer","Editing a reference","Headless","Auto, no controls","Sizes","Variants and tones","Overridden","Overridden loader"]},"props":[{"name":"generate","optional":true,"type":"GenerateFn","bindable":false,"doc":"Makes the pictures. `gemini({ apiKey })`, `openaiImages({ apiKey })`, `endpoint('/api/image')`, `mockGenerate()`, or any `(request, ctx) => results` of your own.","details":[],"examples":[]},{"name":"prompt","optional":true,"type":"string","default":"''","bindable":true,"doc":"The prompt in the bar. Bindable.","details":[],"examples":[]},{"name":"auto","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Generate as soon as there is a prompt — on mount, and again when it changes.","details":[],"examples":[]},{"name":"aspect","optional":true,"type":"AiImageAspect","default":"'1:1'","bindable":false,"doc":"The shape of the picture. Also the shape of the frame.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","bindable":false,"doc":"Frame height, in px or any CSS length. Replaces the aspect.","details":[],"examples":[]},{"name":"count","optional":true,"type":"number","default":"1","bindable":false,"doc":"How many pictures per prompt. Above one they tile in the frame.","details":[],"examples":[]},{"name":"reference","optional":true,"type":"string | Blob","default":"undefined","bindable":true,"doc":"A picture to edit or draw from — a URL, data URL or `Blob`. Bindable: the attach button and the edit tool set it.","details":[],"examples":[]},{"name":"params","optional":true,"type":"Record<string","bindable":false,"doc":"Model-specific knobs, passed through untouched in the request.","details":[],"examples":[]},{"name":"src","optional":true,"type":"string","default":"undefined","bindable":true,"doc":"The picture on show. Bindable; set it to start with one.","details":[],"examples":[]},{"name":"images","optional":true,"type":"AiImageItem[]","default":"[]","bindable":true,"doc":"Every picture made so far, newest first. Bindable.","details":[],"examples":[]},{"name":"keep","optional":true,"type":"number","default":"24","bindable":false,"doc":"How many past pictures to keep in `images`.","details":[],"examples":[]},{"name":"status","optional":true,"type":"AiImageStatus","default":"'idle'","bindable":true,"doc":"Where it is. Bindable, read-only in practice.","details":[],"examples":[]},{"name":"alt","optional":true,"type":"string","bindable":false,"doc":"Alt text for the results. Defaults to the prompt.","details":[],"examples":[]},{"name":"tone","optional":true,"type":"AiImageTone","default":"'primary'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"variant","optional":true,"type":"AiImageVariant","default":"'filled'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"AiImageSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"composer","optional":true,"type":"AiImageComposer","default":"'below'","bindable":false,"doc":"`below` the frame, `overlay` on it, or `none` for a prompt UI of your own.","details":[],"examples":[]},{"name":"tools","optional":true,"type":"AiImageTool[]","default":"DEFAULT_TOOLS","bindable":false,"doc":"The buttons over a finished picture. `[]` for none.","details":[],"examples":[]},{"name":"history","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Keep a strip of past results under the frame.","details":[],"examples":[]},{"name":"viewer","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Tap a finished picture to open it full-screen.","details":[],"examples":[]},{"name":"caption","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Show the model's words about the picture, under it, when there are any.","details":[],"examples":[]},{"name":"attach","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Offer an attach button in the bar, so a person can drop a picture in to edit.","details":[],"examples":[]},{"name":"suggestions","optional":true,"type":"string[]","default":"[]","bindable":false,"doc":"Prompts offered as chips before anything is made.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"The headline of the empty frame.","details":[],"examples":[]},{"name":"hint","optional":true,"type":"string","bindable":false,"doc":"The line under it.","details":[],"examples":[]},{"name":"placeholder","optional":true,"type":"string","default":"'Describe the picture you want…'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"generateLabel","optional":true,"type":"string","default":"'Generate'","bindable":false,"doc":"Accessible name of the send button.","details":[],"examples":[]},{"name":"submitOnEnter","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"A submit with nothing typed. Defaults to Enter; `false` needs the button.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onstart","optional":true,"type":"(request: AiImageRequest) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onresult","optional":true,"type":"(images: AiImageItem[]) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onerror","optional":true,"type":"(error: Error) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"oncancel","optional":true,"type":"() => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(image: AiImageItem | undefined) => void","bindable":false,"doc":"Called when the picture on show changes — a new result, a history pick, a clear.","details":[],"examples":[]},{"name":"ondownload","optional":true,"type":"(image: AiImageItem) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"AiImageClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"empty","optional":true,"type":"Snippet<[AiImageEmptyContext]>","bindable":false,"doc":"Replaces the empty frame.","details":[],"examples":[]},{"name":"loading","optional":true,"type":"Snippet<[AiImageLoadingContext]>","bindable":false,"doc":"Replaces the spinner. Drawn on the loader's surface.","details":[],"examples":[]},{"name":"image","optional":true,"type":"Snippet<[AiImageResultContext]>","bindable":false,"doc":"Replaces one finished picture.","details":[],"examples":[]},{"name":"error","optional":true,"type":"Snippet<[AiImageErrorContext]>","bindable":false,"doc":"Replaces the error.","details":[],"examples":[]},{"name":"bar","optional":true,"type":"Snippet<[AiImageComposerContext]>","bindable":false,"doc":"Replaces the prompt bar.","details":[],"examples":[]},{"name":"actions","optional":true,"type":"Snippet<[AiImageResultContext]>","bindable":false,"doc":"Extra buttons in the corner toolbar.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Content under the frame, before the bar — a caption, a legend.","details":[],"examples":[]}]},{"name":"Alert","dir":"alert","entry":"omaris","importPath":"import { Alert } from 'omaris'","summary":"Alert — MD3's banner, for a message that belongs to the page rather than floating over it.","details":["A default icon comes with each tone, so the common case is one line of markup; pass the `icon` snippet to override it, or `icon={false}`-style by setting `showIcon={false}` to drop it entirely.","`role` follows the tone: a destructive alert announces itself immediately, everything else waits its turn."],"examples":[],"classesType":"AlertClasses","parts":[{"name":"root","doc":""},{"name":"icon","doc":""},{"name":"body","doc":""},{"name":"title","doc":""},{"name":"description","doc":""},{"name":"actions","doc":""},{"name":"close","doc":""}],"variants":[{"name":"tone","doc":"","default":"info","values":[{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""}]},{"name":"variant","doc":"","default":"tonal","values":[{"name":"tonal","doc":"Tinted block — the default banner."},{"name":"outlined","doc":"Hairline frame, for a quieter note inside a form."},{"name":"bar","doc":"A rule down the leading edge — the log-entry look."},{"name":"plain","doc":"No container at all — an inline form error."}]},{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]}],"story":{"title":"Communication/Alert","category":"Communication","own":true,"stories":["Playground","Tones","Variants","Sizes","With actions","Without icon"]},"props":[{"name":"tone","optional":true,"type":"AlertTone","default":"'info'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"variant","optional":true,"type":"AlertVariant","default":"'tonal'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"AlertSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"Heading line.","details":[],"examples":[]},{"name":"description","optional":true,"type":"string","bindable":false,"doc":"Body text. Use children for rich content.","details":[],"examples":[]},{"name":"showIcon","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Draw the tone's default icon.","details":[],"examples":[]},{"name":"dismissible","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Adds the trailing ×.","details":[],"examples":[]},{"name":"ondismiss","optional":true,"type":"() => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"AlertClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"icon","optional":true,"type":"Snippet","bindable":false,"doc":"Replaces the tone's default icon.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Body content, in place of `description`.","details":[],"examples":[]},{"name":"actions","optional":true,"type":"Snippet","bindable":false,"doc":"Buttons under the body.","details":[],"examples":[]}]},{"name":"AppShell","dir":"app-shell","entry":"omaris","importPath":"import { AppShell } from 'omaris'","summary":"The frame a dashboard is built in.","details":["The thing that goes wrong in a hand-rolled dashboard is always the same: the whole document scrolls, so the sidebar — which is only as tall as the viewport — slides up out of the window with everything else. The fix is to decide *once* which element scrolls, and this is where that decision lives:","- `scroll=\"main\"` (the default) pins the shell to the viewport and lets only the content column scroll. The sidebar and the app bar stay exactly where they are, forever, with no `sticky` anywhere. - `scroll=\"page\"` lets the document scroll instead, and sticks the sidebar to the top of it. Better for long reading pages, and the only one where a phone's address bar still collapses on the way down.","Either way the shell hands the scrolling element to its children through context, so a `TopAppBar` inside it lifts and collapses against the right thing without being told which — `scrollContainer` becomes a thing you only reach for when the layout isn't a shell."],"examples":[{"lang":"svelte","code":"<AppShell>\n  <AppShellSidebar>\n    <NavigationDrawer bordered>…</NavigationDrawer>\n  </AppShellSidebar>\n\n  <AppShellMain>\n    <TopAppBar title=\"Overview\" />\n    <AppShellContent>…</AppShellContent>\n  </AppShellMain>\n</AppShell>"}],"classesType":null,"parts":[],"variants":[{"name":"scroll","doc":"","default":"main","values":[]}],"story":{"title":"Layout/App Shell","category":"Layout","own":true,"stories":["Dashboard","Scroll modes","Sticky footer","Inspector","Plain panel"]},"props":[{"name":"scroll","optional":true,"type":"NonNullable<Variants['scroll']>","default":"'main'","bindable":false,"doc":"Which element scrolls: the content column, or the document.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"AppShellContent","dir":"app-shell","entry":"omaris","importPath":"import { AppShellContent } from 'omaris'","summary":"The padded well a page's content sits in.","details":["A dashboard reads badly at 2000px wide and badly again at 320px with no gutter, so this is the one place that owns both: a measure that caps the line length and a gutter that grows with the viewport."],"examples":[],"classesType":null,"parts":[],"variants":[{"name":"width","doc":"The measure. `full` fills the column — right for a wide table.","default":"full","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""},{"name":"xl","doc":""},{"name":"full","doc":""}]},{"name":"padded","doc":"","default":"true","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Layout/App Shell","category":"Layout","own":false,"stories":["Dashboard","Scroll modes","Sticky footer","Inspector","Plain panel"]},"props":[{"name":"width","optional":true,"type":"NonNullable<Variants['width']>","default":"'full'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"padded","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Gutter and the rhythm between sections. Off when the page brings its own.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"AppShellFooter","dir":"app-shell","entry":"omaris","importPath":"import { AppShellFooter } from 'omaris'","summary":"The bottom band of the content column.","details":["`sticky` keeps it against the bottom of the viewport — the bar a table with a selection or a form with unsaved changes needs."],"examples":[],"classesType":null,"parts":[],"variants":[],"story":{"title":"Layout/App Shell","category":"Layout","own":false,"stories":["Dashboard","Scroll modes","Sticky footer","Inspector","Plain panel"]},"props":[{"name":"sticky","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Hold it at the bottom of the column rather than after the content.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"AppShellHeader","dir":"app-shell","entry":"omaris","importPath":"import { AppShellHeader } from 'omaris'","summary":"A band that stays at the top of the content column while it scrolls.","details":["A `TopAppBar` can stick on its own, so this is for the cases it can't cover alone: a bar plus a filter row, a banner above the bar, anything that has to stay up there as one piece."],"examples":[],"classesType":null,"parts":[],"variants":[],"story":{"title":"Layout/App Shell","category":"Layout","own":false,"stories":["Dashboard","Scroll modes","Sticky footer","Inspector","Plain panel"]},"props":[{"name":"sticky","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Ride up with the content instead of staying put.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"AppShellMain","dir":"app-shell","entry":"omaris","importPath":"import { AppShellMain } from 'omaris'","summary":"The content column of an `AppShell` — and, in the default scroll mode, the element that scrolls.","details":["It registers itself with the shell, so everything inside that cares about scrolling (a `TopAppBar`, mostly) finds it on its own."],"examples":[],"classesType":null,"parts":[],"variants":[],"story":{"title":"Layout/App Shell","category":"Layout","own":false,"stories":["Dashboard","Scroll modes","Sticky footer","Inspector","Plain panel"]},"props":[{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"AppShellSidebar","dir":"app-shell","entry":"omaris","importPath":"import { AppShellSidebar } from 'omaris'","summary":"The column an `AppShell` puts beside its main area — a navigation drawer, usually.","details":["It stays put while the content scrolls, and drops out below `breakpoint`, where the drawer should be modal instead."],"examples":[],"classesType":null,"parts":[],"variants":[],"story":{"title":"Layout/App Shell","category":"Layout","own":false,"stories":["Dashboard","Scroll modes","Sticky footer","Inspector","Plain panel"]},"props":[{"name":"side","optional":true,"type":"'start' | 'end'","default":"'start'","bindable":false,"doc":"Which edge it sits on. `end` gives you an inspector panel instead.","details":[],"examples":[]},{"name":"breakpoint","optional":true,"type":"AppShellSidebarBreakpoint","default":"'md'","bindable":false,"doc":"Viewport width at which the column appears. `false` keeps it at every size — what you want when the thing inside is already responsive.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible name, when the column isn't a single labelled drawer.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"AreaChart","dir":"chart","entry":"omaris/chart","importPath":"import { AreaChart } from 'omaris/chart'","summary":"Area chart.","details":["Several values per row become several bands: pass `series` and each one takes the next colour in the palette, gets a legend entry, and appears in the tooltip. `stacked` piles them instead of overlapping them."],"examples":[{"lang":"svelte","code":"<AreaChart data={rows} x=\"date\" y=\"revenue\" />"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Charts","category":"Data Display","own":false,"stories":["Area","Line","Bar","Pie and donut","Scatter","Sparkline","Empty","References and annotations","Brush and zoom","Legend isolate and CSV","Error","Combo","Radar","Radial bar and gauge","Funnel","Treemap","Candlestick"]},"props":[{"name":"stacked","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Pile the series on top of each other rather than overlapping them.","details":[],"examples":[]},{"name":"curve","optional":true,"type":"ChartCurve","default":"'smooth'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"fillOpacity","optional":true,"type":"number","default":"0.18","bindable":false,"doc":"Opacity of the fill under each line.","details":[],"examples":[]},{"name":"points","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Mark each data point.","details":[],"examples":[]},{"name":"data","optional":false,"type":"T[]","bindable":false,"doc":"","details":[],"examples":[]},{"name":"x","optional":true,"type":"Field<T>","bindable":false,"doc":"The category or time field.","details":[],"examples":[]},{"name":"y","optional":true,"type":"Field<T>","bindable":false,"doc":"The value field. Ignored once `series` names its own.","details":[],"examples":[]},{"name":"series","optional":true,"type":"ChartSeries<T>[]","bindable":false,"doc":"Several values per row. Each gets a colour and a legend entry.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"260","bindable":false,"doc":"Plot height. A number is px; a string is any CSS length.","details":[],"examples":[]},{"name":"axis","optional":true,"type":"boolean | 'x' | 'y'","default":"true","bindable":false,"doc":"`true` for both, or just the one you want.","details":[],"examples":[]},{"name":"grid","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"legend","optional":true,"type":"ChartLegend","default":"false","bindable":false,"doc":"`true` shows the legend and lets a click toggle a series off. `'isolate'` makes a click show that series alone, and a second one bring the rest back — which is the move you actually want on a chart with six lines on it.","details":[],"examples":[]},{"name":"tooltip","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"formatX","optional":true,"type":"(value: never) => string","bindable":false,"doc":"Tick labels along the x axis.","details":[],"examples":[]},{"name":"formatY","optional":true,"type":"(value: never) => string","bindable":false,"doc":"Tick labels along the y axis, and the tooltip's values.","details":[],"examples":[]},{"name":"colors","optional":true,"type":"readonly string[]","default":"CHART_COLORS","bindable":false,"doc":"Palette override, cycled across the series.","details":[],"examples":[]},{"name":"padding","optional":true,"type":"number | { top?: number; right?: number; bottom?: number; left?: number }","bindable":false,"doc":"Space around the plot, in px — room for long axis labels.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible description of what the chart shows.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"empty","optional":true,"type":"Snippet","bindable":false,"doc":"Shown in place of the plot when `data` is empty.","details":[],"examples":[]},{"name":"emptyText","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"error","optional":true,"type":"boolean | string | Error","bindable":false,"doc":"Something went wrong. Truthy puts the chart into its error state; a string or an `Error` supplies the message.","details":[],"examples":[]},{"name":"errorText","optional":true,"type":"string","bindable":false,"doc":"The message, when `error` is just `true`.","details":[],"examples":[]},{"name":"errorState","optional":true,"type":"Snippet<[{ message: string }]>","bindable":false,"doc":"Replaces the whole error state.","details":[],"examples":[]},{"name":"onRetry","optional":true,"type":"() => void","bindable":false,"doc":"Offers a \"Try again\" button in the error state.","details":[],"examples":[]},{"name":"csv","optional":true,"type":"boolean | string","default":"false","bindable":false,"doc":"Offer the plotted rows as a CSV download, from a button in the corner. A string names the file.","details":[],"examples":[]},{"name":"csvColumns","optional":true,"type":"(string | { key: string; label?: string; value?: (row: T) => unknown })[]","bindable":false,"doc":"Which fields the download writes, in order. Defaults to every field.","details":[],"examples":[]},{"name":"references","optional":true,"type":"ChartReference[]","bindable":false,"doc":"Lines and bands at fixed values — targets, thresholds, windows.","details":[],"examples":[]},{"name":"annotations","optional":true,"type":"ChartAnnotation[]","bindable":false,"doc":"Notes pinned to a point.","details":[],"examples":[]},{"name":"brush","optional":true,"type":"ChartBrush","bindable":false,"doc":"Drag across the plot to select a range, and zoom the chart to it.","details":[],"examples":[]},{"name":"zoom","optional":true,"type":"ChartZoom","bindable":false,"doc":"Wheel or pinch to zoom, drag to pan.","details":[],"examples":[]}]},{"name":"Avatar","dir":"avatar","entry":"omaris","importPath":"import { Avatar } from 'omaris'","summary":"Avatar — image, initials, or icon, in that order of preference.","details":["The image is only shown once it has actually decoded, so a broken or slow URL falls back to the initials instead of flashing a blank hole. Initials get a deterministic tint derived from the name, so the same person is the same color everywhere in the app."],"examples":[],"classesType":"AvatarClasses","parts":[{"name":"root","doc":"Sizing, shape and the fallback colours live here — and nothing clips. The presence dot is a child of this box and is meant to sit proud of a circle's edge; `overflow-hidden` here is what used to shave a slice off it."},{"name":"media","doc":"The clipping layer. Only the picture and the initials are cut to the shape, so the dot outside it survives."},{"name":"image","doc":""},{"name":"status","doc":"The ring that marks a live/away state, MD3 presence style."}],"variants":[{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""},{"name":"xl","doc":""}]},{"name":"shape","doc":"","default":"circle","values":[{"name":"circle","doc":""},{"name":"square","doc":"MD3's rounded square, for org and product avatars."}]},{"name":"status","doc":"","default":"none","values":[{"name":"none","doc":""},{"name":"online","doc":""},{"name":"away","doc":""},{"name":"busy","doc":""},{"name":"offline","doc":""}]}],"story":{"title":"Data Display/Avatar","category":"Data Display","own":true,"stories":["Playground","Fallbacks","Sizes","Shapes","Presence","Presence, overridden","Derived colours","Groups"]},"props":[{"name":"size","optional":true,"type":"AvatarSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"shape","optional":true,"type":"AvatarShape","default":"'circle'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"status","optional":true,"type":"AvatarStatus","default":"'none'","bindable":false,"doc":"Presence dot in the bottom corner.","details":[],"examples":[]},{"name":"src","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"alt","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"name","optional":true,"type":"string","bindable":false,"doc":"Full name. Initials and the fallback tint are derived from it.","details":[],"examples":[]},{"name":"initials","optional":true,"type":"string","bindable":false,"doc":"Override the derived initials.","details":[],"examples":[]},{"name":"colorize","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Paint the initials fallback with the name-derived tint.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"AvatarClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Shown when there's no image and no name — an icon, usually.","details":[],"examples":[]}]},{"name":"AvatarGroup","dir":"avatar","entry":"omaris","importPath":"import { AvatarGroup } from 'omaris'","summary":"A stack of overlapping avatars — the people on a thread, the members of a team.","details":["Give it the same `size` as the avatars inside it, or the overlap will not match. `overflow` adds the trailing \"+n\" for the ones that did not fit."],"examples":[],"classesType":null,"parts":[],"variants":[{"name":"size","doc":"","default":"md","values":[{"name":"xs","doc":""},{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""},{"name":"xl","doc":""}]}],"story":{"title":"Data Display/Avatar","category":"Data Display","own":false,"stories":["Playground","Fallbacks","Sizes","Shapes","Presence","Presence, overridden","Derived colours","Groups"]},"props":[{"name":"size","optional":true,"type":"AvatarSize","default":"'md'","bindable":false,"doc":"Overlap amount. Must match the avatars' own `size` to look right.","details":[],"examples":[]},{"name":"overflow","optional":true,"type":"number","bindable":false,"doc":"Renders a \"+n\" chip after the children.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"ClassesOf<typeof avatarGroupVariants>","bindable":false,"doc":"Tailwind per part.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"Badge","dir":"badge","entry":"omaris","importPath":"import { Badge } from 'omaris'","summary":"Badge — a status pill, or the count that rides on an icon.","details":["Same two axes as the button: `variant` is the fill style and `tone` the color role, resolved through the shared `--btn-*` properties. `dot` and `count` are MD3's small and large notification badges; both take `anchor` to pin themselves to the corner of a `relative` parent."],"examples":[],"classesType":null,"parts":[],"variants":[{"name":"tone","doc":"","default":"primary","values":[{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""}]},{"name":"variant","doc":"","default":"filled","values":[{"name":"filled","doc":""},{"name":"tonal","doc":""},{"name":"outlined","doc":""},{"name":"text","doc":"Ghosted — the label carries the color, nothing else."}]},{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]},{"name":"dot","doc":"MD3 small badge: a 6dp dot with no label.","values":[{"name":"true","doc":""}]},{"name":"count","doc":"MD3 large badge: a count that stays circular until it needs room.","values":[{"name":"true","doc":""}]},{"name":"anchor","doc":"Pins the badge to the corner of a `relative` parent — a sibling of what it counts, not a wrapper around it. Without a positioned ancestor the badge's containing block is the page, and it lands in the top corner of the screen rather than of the bell.","default":"none","values":[{"name":"none","doc":""},{"name":"top-end","doc":""},{"name":"top-start","doc":""}]}],"story":{"title":"Communication/Badge","category":"Communication","own":true,"stories":["Playground","Variants","Tones","Sizes","Counts and dots","Anchored","As status"]},"props":[{"name":"variant","optional":true,"type":"BadgeVariant","default":"'filled'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"tone","optional":true,"type":"BadgeTone","default":"'primary'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"BadgeSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"dot","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Renders the 6dp dot instead of a label.","details":[],"examples":[]},{"name":"value","optional":true,"type":"number","bindable":false,"doc":"A number badge. Values above `max` render as \"99+\", and the pill stays a circle until two digits force it wider.","details":["The number *is* the content: a badge given a `value` draws it and nothing else, so anything passed as children is dropped. Put the thing being counted beside the badge, inside a `relative` box."],"examples":[]},{"name":"max","optional":true,"type":"number","default":"99","bindable":false,"doc":"Cap for `value`.","details":[],"examples":[]},{"name":"anchor","optional":true,"type":"BadgeAnchor","default":"'none'","bindable":false,"doc":"Corner of the `relative` parent to pin to.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Screen-reader text — \"3 unread\", not \"3\".","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"BarChart","dir":"chart","entry":"omaris/chart","importPath":"import { BarChart } from 'omaris/chart'","summary":"Bar chart.","details":["`horizontal` turns it on its side, which is what long category names actually want; `stacked` and `grouped` decide what several series do with the same band."],"examples":[{"lang":"svelte","code":"<BarChart data={rows} x=\"channel\" y=\"signups\" />"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Charts","category":"Data Display","own":false,"stories":["Area","Line","Bar","Pie and donut","Scatter","Sparkline","Empty","References and annotations","Brush and zoom","Legend isolate and CSV","Error","Combo","Radar","Radial bar and gauge","Funnel","Treemap","Candlestick"]},"props":[{"name":"horizontal","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Bars run along the x axis, categories down the y one.","details":[],"examples":[]},{"name":"stacked","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Pile several series into one bar.","details":[],"examples":[]},{"name":"grouped","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Sit several series side by side within the band.","details":[],"examples":[]},{"name":"radius","optional":true,"type":"number","default":"4","bindable":false,"doc":"Corner radius on the bars, in px.","details":[],"examples":[]},{"name":"labels","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Print the value on each bar.","details":[],"examples":[]},{"name":"data","optional":false,"type":"T[]","bindable":false,"doc":"","details":[],"examples":[]},{"name":"x","optional":true,"type":"Field<T>","bindable":false,"doc":"The category or time field.","details":[],"examples":[]},{"name":"y","optional":true,"type":"Field<T>","bindable":false,"doc":"The value field. Ignored once `series` names its own.","details":[],"examples":[]},{"name":"series","optional":true,"type":"ChartSeries<T>[]","bindable":false,"doc":"Several values per row. Each gets a colour and a legend entry.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"260","bindable":false,"doc":"Plot height. A number is px; a string is any CSS length.","details":[],"examples":[]},{"name":"axis","optional":true,"type":"boolean | 'x' | 'y'","default":"true","bindable":false,"doc":"`true` for both, or just the one you want.","details":[],"examples":[]},{"name":"grid","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"legend","optional":true,"type":"ChartLegend","default":"false","bindable":false,"doc":"`true` shows the legend and lets a click toggle a series off. `'isolate'` makes a click show that series alone, and a second one bring the rest back — which is the move you actually want on a chart with six lines on it.","details":[],"examples":[]},{"name":"tooltip","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"formatX","optional":true,"type":"(value: never) => string","bindable":false,"doc":"Tick labels along the x axis.","details":[],"examples":[]},{"name":"formatY","optional":true,"type":"(value: never) => string","bindable":false,"doc":"Tick labels along the y axis, and the tooltip's values.","details":[],"examples":[]},{"name":"colors","optional":true,"type":"readonly string[]","default":"CHART_COLORS","bindable":false,"doc":"Palette override, cycled across the series.","details":[],"examples":[]},{"name":"padding","optional":true,"type":"number | { top?: number; right?: number; bottom?: number; left?: number }","bindable":false,"doc":"Space around the plot, in px — room for long axis labels.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible description of what the chart shows.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"empty","optional":true,"type":"Snippet","bindable":false,"doc":"Shown in place of the plot when `data` is empty.","details":[],"examples":[]},{"name":"emptyText","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"error","optional":true,"type":"boolean | string | Error","bindable":false,"doc":"Something went wrong. Truthy puts the chart into its error state; a string or an `Error` supplies the message.","details":[],"examples":[]},{"name":"errorText","optional":true,"type":"string","bindable":false,"doc":"The message, when `error` is just `true`.","details":[],"examples":[]},{"name":"errorState","optional":true,"type":"Snippet<[{ message: string }]>","bindable":false,"doc":"Replaces the whole error state.","details":[],"examples":[]},{"name":"onRetry","optional":true,"type":"() => void","bindable":false,"doc":"Offers a \"Try again\" button in the error state.","details":[],"examples":[]},{"name":"csv","optional":true,"type":"boolean | string","default":"false","bindable":false,"doc":"Offer the plotted rows as a CSV download, from a button in the corner. A string names the file.","details":[],"examples":[]},{"name":"csvColumns","optional":true,"type":"(string | { key: string; label?: string; value?: (row: T) => unknown })[]","bindable":false,"doc":"Which fields the download writes, in order. Defaults to every field.","details":[],"examples":[]},{"name":"references","optional":true,"type":"ChartReference[]","bindable":false,"doc":"Lines and bands at fixed values — targets, thresholds, windows.","details":[],"examples":[]},{"name":"annotations","optional":true,"type":"ChartAnnotation[]","bindable":false,"doc":"Notes pinned to a point.","details":[],"examples":[]},{"name":"brush","optional":true,"type":"ChartBrush","bindable":false,"doc":"Drag across the plot to select a range, and zoom the chart to it.","details":[],"examples":[]},{"name":"zoom","optional":true,"type":"ChartZoom","bindable":false,"doc":"Wheel or pinch to zoom, drag to pan.","details":[],"examples":[]}]},{"name":"Breadcrumb","dir":"breadcrumb","entry":"omaris","importPath":"import { Breadcrumb } from 'omaris'","summary":"Breadcrumbs.","details":["Long trails collapse in the middle rather than wrapping or truncating the labels — the first and last few crumbs are the ones that carry meaning, and the \"…\" expands the rest in place."],"examples":[],"classesType":"BreadcrumbClasses","parts":[{"name":"root","doc":""},{"name":"list","doc":""},{"name":"item","doc":""},{"name":"link","doc":""},{"name":"current","doc":""},{"name":"separator","doc":""},{"name":"expand","doc":"The button that expands a collapsed middle."}],"variants":[{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""}]}],"story":{"title":"Navigation/Breadcrumb","category":"Navigation","own":true,"stories":["Playground","Collapsing","Sizes","Custom separator","Buttons instead of links"]},"props":[{"name":"items","optional":false,"type":"BreadcrumbItem[]","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"BreadcrumbSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"maxItems","optional":true,"type":"number","default":"5","bindable":false,"doc":"Collapse the middle once the trail is longer than this. `0` never collapses.","details":[],"examples":[]},{"name":"itemsBeforeCollapse","optional":true,"type":"number","default":"1","bindable":false,"doc":"Crumbs kept at the start of a collapsed trail.","details":[],"examples":[]},{"name":"itemsAfterCollapse","optional":true,"type":"number","default":"2","bindable":false,"doc":"Crumbs kept at the end of a collapsed trail.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","default":"'Breadcrumb'","bindable":false,"doc":"Accessible name.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"BreadcrumbClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"separator","optional":true,"type":"Snippet","bindable":false,"doc":"Custom separator, in place of the chevron.","details":[],"examples":[]}]},{"name":"Button","dir":"button","entry":"omaris","importPath":"import { Button } from 'omaris'","summary":"MD3 buttons, the Expressive way.","details":["Two axes instead of one long variant list: `variant` is the *fill style* (elevated / filled / tonal / outlined / text) and `tone` is the *color role* (primary / secondary / … / destructive), which resolves to the `--btn-*` custom properties in `tones.ts`. Every fill style works with every tone, with no combinatorial explosion of classes."],"examples":[],"classesType":null,"parts":[],"variants":[{"name":"tone","doc":"","default":"primary","values":[{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""}]},{"name":"variant","doc":"","default":"filled","values":[{"name":"filled","doc":""},{"name":"tonal","doc":""},{"name":"elevated","doc":""},{"name":"outlined","doc":""},{"name":"text","doc":""},{"name":"link","doc":""}]},{"name":"size","doc":"MD3 Expressive's five heights: 32 / 40 / 56 / 96 / 136dp. `sm` is the classic Material button and stays the default.","default":"sm","values":[{"name":"xs","doc":""},{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""},{"name":"xl","doc":""}]},{"name":"shape","doc":"A pill, or MD3's rounded-rectangle. Fixed — it never morphs.","default":"round","values":[{"name":"round","doc":""},{"name":"square","doc":""}]},{"name":"icon","doc":"Square, label-less button. Requires an `aria-label`.","values":[{"name":"true","doc":""}]},{"name":"toggle","doc":"An unselected toggle reads as a neutral surface whatever its tone; selecting it brings the tone's real colors back.","values":[{"name":"true","doc":""}]}],"story":{"title":"Actions/Button","category":"Actions","own":true,"stories":["Playground","Variants","Tones","Sizes","Shapes","With icons","Loading","Toggle","Button group","Disabled","As link"]},"props":[{"name":"variant","optional":true,"type":"ButtonVariant","default":"'filled'","bindable":false,"doc":"Fill style. MD3's five, plus `link` for inline navigation.","details":[],"examples":[]},{"name":"tone","optional":true,"type":"ButtonTone","default":"'primary'","bindable":false,"doc":"Color role the fill style paints with.","details":[],"examples":[]},{"name":"size","optional":true,"type":"ButtonSize","default":"'sm'","bindable":false,"doc":"MD3 Expressive heights: 32 / 40 / 56 / 96 / 136dp.","details":[],"examples":[]},{"name":"shape","optional":true,"type":"ButtonShape","default":"'round'","bindable":false,"doc":"Pill (`round`) or MD3 rounded rectangle (`square`).","details":[],"examples":[]},{"name":"icon","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Square, label-less button. Requires an `aria-label`.","details":[],"examples":[]},{"name":"ripple","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Material ripple on press. Set false for a flat, instant button.","details":[],"examples":[]},{"name":"confetti","optional":true,"type":"boolean | ConfettiOptions","default":"false","bindable":false,"doc":"Confetti on press. `true` for the default burst, or any `ConfettiOptions` — `confetti={{ preset: 'fireworks' }}`.","details":[],"examples":[]},{"name":"loading","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Grows a spinner in at the start of the button and blocks interaction. The label stays put; only an `icon` button swaps its icon out.","details":[],"examples":[]},{"name":"toggle","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Turns the button into a two-state toggle driven by `pressed`. Ignored when `href` is set — a link has no pressed state.","details":[],"examples":[]},{"name":"pressed","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Selected state of a toggle button. Bindable.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"ButtonGroup","dir":"button-group","entry":"omaris","importPath":"import { ButtonGroup } from 'omaris'","summary":"MD3 button group — a row of buttons that reads as one control.","details":["`connected` is the segmented look: a hairline gap between children, pill ends on the outside, squared corners on the inside. `spaced` just lays buttons out on the MD3 8dp rhythm and leaves their shapes alone.","The group restyles whatever buttons you put in it, so children can stay plain `<Button>`s; set their `variant` to pick the group's fill."],"examples":[],"classesType":null,"parts":[],"variants":[{"name":"variant","doc":"","default":"connected","values":[{"name":"connected","doc":""},{"name":"spaced","doc":""}]},{"name":"orientation","doc":"","default":"horizontal","values":[{"name":"horizontal","doc":""},{"name":"vertical","doc":""}]},{"name":"full","doc":"Stretches the children to share the width evenly.","values":[{"name":"true","doc":""}]}],"story":{"title":"Actions/Button Group","category":"Actions","own":true,"stories":["Playground","Connected","Segmented","Spaced","Vertical","Full width"]},"props":[{"name":"variant","optional":true,"type":"ButtonGroupVariant","default":"'connected'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"orientation","optional":true,"type":"ButtonGroupOrientation","default":"'horizontal'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"full","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible name for the group.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"Calendar","dir":"calendar","entry":"omaris","importPath":"import { Calendar } from 'omaris'","summary":"Month grid — one date, a range, or a handful of dates.","details":["Values are plain `Date`s at local midnight: `new Date(2026, 2, 3)` is March 3rd, and so is every date the calendar gives back. What `value` holds follows `mode` — a `Date` (or `null`) for `single`, a `{ start, end }` (or `null`) for `range`, a `Date[]` for `multiple`.","It is the full WAI-ARIA date grid: arrows move a day or a week, Home and End go to the ends of the week, PageUp/PageDown a month, with Shift a year, and only one day is ever a tab stop. The caption opens a month and year grid for jumping further than a few presses. A range previews itself from its first day to wherever the pointer or the focus is, and its band is drawn with logical sides, so it reads right in Arabic.","Names come from `Intl` in the page's language, with Western digits always; the week starts on the day that language starts it on."],"examples":[{"lang":"svelte","code":"<Calendar bind:value={day} min={today} />\n<Calendar mode=\"range\" months={2} bind:value={range} />"}],"classesType":"CalendarClasses","parts":[{"name":"root","doc":"The whole calendar. `--cal-cell` here sizes every day."},{"name":"months","doc":"The row of months — side by side from `sm` up, stacked below it."},{"name":"month","doc":"One month: its header and its grid. Hidden under the month/year grid."},{"name":"header","doc":"Caption and the previous/next buttons."},{"name":"caption","doc":"The month and year — a button that opens the month/year grid."},{"name":"nav","doc":"The previous and next buttons."},{"name":"grid","doc":"One month's `role=\"grid\"`."},{"name":"weeks","doc":"The weeks, which slide when the month changes."},{"name":"row","doc":"A week, or the weekday headings — seven columns, eight with week numbers."},{"name":"weekday","doc":"A weekday column heading."},{"name":"weekNumber","doc":"The ISO week number at the start of a row."},{"name":"cell","doc":"The `gridcell` around a day."},{"name":"day","doc":"The day's button — the full cell, so the hit area is the cell."},{"name":"track","doc":"Holds the band and the face, and is exactly as tall as the face."},{"name":"band","doc":"The range band behind the faces, rounded where a row or the range ends."},{"name":"face","doc":"The round face with the day number on it."},{"name":"picker","doc":"The month or year grid the caption opens, laid over the days."},{"name":"pickerHeader","doc":"The year (or the span of years) and its arrows."},{"name":"pickerGrid","doc":"Three columns of months or years."},{"name":"pickerItem","doc":"A month or a year in that grid."}],"variants":[],"story":{"title":"Inputs/Calendar","category":"Inputs","own":true,"stories":["Playground","Today selected","Range","Two months","Multiple","Bounds and disabled days","Week numbers","Right to left","Overridden"]},"props":[{"name":"mode","optional":true,"type":"M","bindable":false,"doc":"`'single'` (the default), `'range'` or `'multiple'`. Decides what `value` holds.","details":[],"examples":[]},{"name":"value","optional":true,"type":"CalendarValue<M>","bindable":true,"doc":"The selection, at local midnight. A `Date` or `null` in `single`, `{ start, end }` or `null` in `range` — set on the second press, never half-filled — and a sorted `Date[]` in `multiple`.","details":[],"examples":[]},{"name":"month","optional":true,"type":"Date","bindable":true,"doc":"The first month on screen. Defaults to the selection's month, or today's.","details":[],"examples":[]},{"name":"min","optional":true,"type":"Date","bindable":false,"doc":"Earliest selectable day. The previous button stops at its month.","details":[],"examples":[]},{"name":"max","optional":true,"type":"Date","bindable":false,"doc":"Latest selectable day. The next button stops at its month.","details":[],"examples":[]},{"name":"isDateDisabled","optional":true,"type":"(date: Date) => boolean","bindable":false,"doc":"Days that cannot be picked — weekends, holidays, sold-out dates.","details":[],"examples":[]},{"name":"locale","optional":true,"type":"string","bindable":false,"doc":"BCP-47 tag for names and the first weekday. Defaults to `<html lang>`, then the browser.","details":[],"examples":[]},{"name":"weekStartsOn","optional":true,"type":"Weekday","bindable":false,"doc":"0 is Sunday. Defaults to the locale's own first day.","details":[],"examples":[]},{"name":"months","optional":true,"type":"1 | 2","default":"1","bindable":false,"doc":"Months side by side. They stack below the `sm` breakpoint.","details":[],"examples":[]},{"name":"showOutsideDays","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Fill the first and last rows with the neighbouring months' days. Ignored with two months, where the neighbour is already on screen.","details":[],"examples":[]},{"name":"showWeekNumbers","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"ISO week numbers at the start of each row.","details":[],"examples":[]},{"name":"weekdayFormat","optional":true,"type":"'narrow' | 'short'","default":"'narrow'","bindable":false,"doc":"Weekday headings: `narrow` (\"M\") or `short` (\"Mon\").","details":[],"examples":[]},{"name":"autofocus","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Focus the active day as soon as the calendar mounts — for one that opens in a popup.","details":[],"examples":[]},{"name":"swipe","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Swipe sideways on a touch screen to change month.","details":[],"examples":[]},{"name":"haptics","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Vibrate on a pick, where the haptics store is on.","details":[],"examples":[]},{"name":"labels","optional":true,"type":"CalendarLabels","bindable":false,"doc":"Accessible names for the arrows, the caption and the week column — for translation.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(value: CalendarValue<M>) => void","bindable":false,"doc":"Fires with the new value after every pick — for `range`, once the range is whole.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"Merged onto the root, so `class=\"p-0\"` removes the padding.","details":[],"examples":[]},{"name":"classes","optional":true,"type":"CalendarClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"CandlestickChart","dir":"chart","entry":"omaris/chart","importPath":"import { CandlestickChart } from 'omaris/chart'","summary":"Candlestick chart — open, high, low and close in one mark per period.","details":["The periods sit on a band scale rather than a time one, so a weekend or a market holiday closes the gap instead of drawing empty space — which is what every trading chart does and why they can't just be a `BarChart`.","`hollow` draws rising candles as outlines, the convention that survives a red/green colour-vision problem: filled means down whatever the hue."],"examples":[{"lang":"svelte","code":"<CandlestickChart data={days} />"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Charts","category":"Data Display","own":false,"stories":["Area","Line","Bar","Pie and donut","Scatter","Sparkline","Empty","References and annotations","Brush and zoom","Legend isolate and CSV","Error","Combo","Radar","Radial bar and gauge","Funnel","Treemap","Candlestick"]},"props":[{"name":"data","optional":false,"type":"T[]","bindable":false,"doc":"","details":[],"examples":[]},{"name":"x","optional":true,"type":"Field<T>","default":"'date'","bindable":false,"doc":"The period field. Defaults to `row.date`.","details":[],"examples":[]},{"name":"open","optional":true,"type":"Field<T>","default":"'open'","bindable":false,"doc":"Defaults to `row.open`.","details":[],"examples":[]},{"name":"high","optional":true,"type":"Field<T>","default":"'high'","bindable":false,"doc":"Defaults to `row.high`.","details":[],"examples":[]},{"name":"low","optional":true,"type":"Field<T>","default":"'low'","bindable":false,"doc":"Defaults to `row.low`.","details":[],"examples":[]},{"name":"close","optional":true,"type":"Field<T>","default":"'close'","bindable":false,"doc":"Defaults to `row.close`.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"300","bindable":false,"doc":"Plot height. A number is px; a string is any CSS length.","details":[],"examples":[]},{"name":"axis","optional":true,"type":"boolean | 'x' | 'y'","default":"true","bindable":false,"doc":"`true` for both, or just the one you want.","details":[],"examples":[]},{"name":"grid","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"tooltip","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"up","optional":true,"type":"string","default":"'var(--success)'","bindable":false,"doc":"Any CSS colour for a period that closed up.","details":[],"examples":[]},{"name":"down","optional":true,"type":"string","default":"'var(--destructive)'","bindable":false,"doc":"Any CSS colour for a period that closed down.","details":[],"examples":[]},{"name":"hollow","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Draw rising candles as outlines rather than fills.","details":[],"examples":[]},{"name":"width","optional":true,"type":"number","default":"0.62","bindable":false,"doc":"Share of the band each candle body takes.","details":[],"examples":[]},{"name":"formatX","optional":true,"type":"(value: never) => string","bindable":false,"doc":"Tick labels along the x axis.","details":[],"examples":[]},{"name":"formatY","optional":true,"type":"(value: never) => string","bindable":false,"doc":"Tick labels along the y axis, and the tooltip's values.","details":[],"examples":[]},{"name":"padding","optional":true,"type":"number | { top?: number; right?: number; bottom?: number; left?: number }","bindable":false,"doc":"Space around the plot, in px.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible description of what the chart shows.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"empty","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]},{"name":"emptyText","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"error","optional":true,"type":"boolean | string | Error","bindable":false,"doc":"Something went wrong. Truthy puts the chart into its error state; a string or an `Error` supplies the message.","details":[],"examples":[]},{"name":"errorText","optional":true,"type":"string","bindable":false,"doc":"The message, when `error` is just `true`.","details":[],"examples":[]},{"name":"errorState","optional":true,"type":"Snippet<[{ message: string }]>","bindable":false,"doc":"Replaces the whole error state.","details":[],"examples":[]},{"name":"onRetry","optional":true,"type":"() => void","bindable":false,"doc":"Offers a \"Try again\" button in the error state.","details":[],"examples":[]},{"name":"csv","optional":true,"type":"boolean | string","default":"false","bindable":false,"doc":"Offer the plotted rows as a CSV download, from a button in the corner. A string names the file.","details":[],"examples":[]},{"name":"csvColumns","optional":true,"type":"(string | { key: string; label?: string; value?: (row: T) => unknown })[]","bindable":false,"doc":"Which fields the download writes, in order. Defaults to every field.","details":[],"examples":[]},{"name":"references","optional":true,"type":"ChartReference[]","bindable":false,"doc":"Lines and bands at fixed values — targets, thresholds, windows.","details":[],"examples":[]},{"name":"annotations","optional":true,"type":"ChartAnnotation[]","bindable":false,"doc":"Notes pinned to a point.","details":[],"examples":[]},{"name":"brush","optional":true,"type":"ChartBrush","bindable":false,"doc":"Drag across the plot to select a range, and zoom the chart to it.","details":[],"examples":[]},{"name":"zoom","optional":true,"type":"ChartZoom","bindable":false,"doc":"Wheel or pinch to zoom, drag to pan.","details":[],"examples":[]}]},{"name":"Card","dir":"card","entry":"omaris","importPath":"import { Card } from 'omaris'","summary":"MD3 card — elevated, filled, or outlined.","details":["A plain card is a passive container. Give it `href` or `onclick` and it becomes a real target: it picks up the state layer, a ripple, a focus ring, and lifts a step on hover. That's the whole difference, so a grid of clickable cards doesn't need a wrapper `<a>` around each one."],"examples":[],"classesType":null,"parts":[],"variants":[{"name":"variant","doc":"","default":"outlined","values":[{"name":"elevated","doc":""},{"name":"filled","doc":""},{"name":"outlined","doc":""}]},{"name":"size","doc":"","default":"md","values":[{"name":"md","doc":""},{"name":"lg","doc":""}]},{"name":"interactive","doc":"Wired up automatically when the card is a link or has `onclick`.","values":[{"name":"true","doc":""}]},{"name":"selected","doc":"Marks the card as chosen — a plan picker, a selectable tile.","values":[{"name":"true","doc":""}]}],"story":{"title":"Containment/Card","category":"Containment","own":true,"stories":["Playground","Variants","Interactive","Selectable","With media","Sizes"]},"props":[{"name":"variant","optional":true,"type":"CardVariant","default":"'outlined'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"CardSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"interactive","optional":true,"type":"boolean","bindable":false,"doc":"Force the interactive treatment on a card that handles its own press.","details":[],"examples":[]},{"name":"selected","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Chosen state — border and ring in the primary color.","details":[],"examples":[]},{"name":"ripple","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Ripple on press. Interactive cards only.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]},{"name":"tone","optional":true,"type":"ButtonTone","bindable":false,"doc":"Color role the fill style paints with.","details":[],"examples":[]},{"name":"shape","optional":true,"type":"ButtonShape","bindable":false,"doc":"Pill (`round`) or MD3 rounded rectangle (`square`).","details":[],"examples":[]},{"name":"icon","optional":true,"type":"boolean","bindable":false,"doc":"Square, label-less button. Requires an `aria-label`.","details":[],"examples":[]},{"name":"confetti","optional":true,"type":"boolean | ConfettiOptions","bindable":false,"doc":"Confetti on press. `true` for the default burst, or any `ConfettiOptions` — `confetti={{ preset: 'fireworks' }}`.","details":[],"examples":[]},{"name":"loading","optional":true,"type":"boolean","bindable":false,"doc":"Grows a spinner in at the start of the button and blocks interaction. The label stays put; only an `icon` button swaps its icon out.","details":[],"examples":[]},{"name":"toggle","optional":true,"type":"boolean","bindable":false,"doc":"Turns the button into a two-state toggle driven by `pressed`. Ignored when `href` is set — a link has no pressed state.","details":[],"examples":[]},{"name":"pressed","optional":true,"type":"boolean","bindable":true,"doc":"Selected state of a toggle button. Bindable.","details":[],"examples":[]}]},{"name":"CardContent","dir":"card","entry":"omaris","importPath":"import { CardContent } from 'omaris'","summary":"A card's body — the text and controls between its header and its footer.","details":["It is the part that grows, so a row of cards with different amounts to say still line their footers up."],"examples":[],"classesType":null,"parts":[],"variants":[],"story":{"title":"Containment/Card","category":"Containment","own":false,"stories":["Playground","Variants","Interactive","Selectable","With media","Sizes"]},"props":[{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"CardFooter","dir":"card","entry":"omaris","importPath":"import { CardFooter } from 'omaris'","summary":"A card's actions, laid out in a row that wraps.","details":["MD3 puts card actions at the end, which is the default here; `align` moves them for the cases where that reads wrong."],"examples":[],"classesType":null,"parts":[],"variants":[],"story":{"title":"Containment/Card","category":"Containment","own":false,"stories":["Playground","Variants","Interactive","Selectable","With media","Sizes"]},"props":[{"name":"align","optional":true,"type":"'start' | 'end' | 'between'","default":"'end'","bindable":false,"doc":"Where the actions sit. MD3 puts card actions at the end.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"CardHeader","dir":"card","entry":"omaris","importPath":"import { CardHeader } from 'omaris'","summary":"The heading row of a card: a leading slot, a title block, a trailing slot.","details":["The row wraps rather than crushes. An `end` slot holding a couple of buttons is wider than a phone leaves over once the icon and the title have had their share, and a `shrink-0` trailing slot in a row that cannot wrap takes that width from the title instead — which is how a heading ends up reading one word per line down a 60px column. `basis` on the body is the threshold: while the title can keep 12rem the row stays on one line and nothing moves, and below that the trailing slot drops to a line of its own."],"examples":[],"classesType":"CardHeaderClasses","parts":[{"name":"root","doc":""},{"name":"start","doc":"An avatar or icon before the title."},{"name":"body","doc":"Title and supporting line, stacked."},{"name":"title","doc":""},{"name":"description","doc":""},{"name":"end","doc":"An overflow menu or badge after the title."}],"variants":[],"story":{"title":"Containment/Card","category":"Containment","own":false,"stories":["Playground","Variants","Interactive","Selectable","With media","Sizes"]},"props":[{"name":"heading","optional":true,"type":"string","bindable":false,"doc":"Heading text. Use the `title` snippet instead for rich markup.","details":[],"examples":[]},{"name":"description","optional":true,"type":"string","bindable":false,"doc":"Supporting line under the heading.","details":[],"examples":[]},{"name":"level","optional":true,"type":"2 | 3 | 4 | 5 | 6","default":"3","bindable":false,"doc":"Heading level, so cards nest correctly in a page outline.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"CardHeaderClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"start","optional":true,"type":"Snippet","bindable":false,"doc":"Leading slot — an avatar or icon.","details":[],"examples":[]},{"name":"end","optional":true,"type":"Snippet","bindable":false,"doc":"Trailing slot — an overflow menu, a badge.","details":[],"examples":[]},{"name":"title","optional":true,"type":"Snippet","bindable":false,"doc":"Rich heading, in place of `heading`.","details":[],"examples":[]},{"name":"supporting","optional":true,"type":"Snippet","bindable":false,"doc":"Rich supporting line, in place of `description`.","details":[],"examples":[]}]},{"name":"CardMedia","dir":"card","entry":"omaris","importPath":"import { CardMedia } from 'omaris'","summary":"The image at the top of a card.","details":["`bleed` is the one worth knowing: it cancels the card's padding so the picture reaches the edges, and rounds only the corners it actually touches."],"examples":[],"classesType":null,"parts":[],"variants":[],"story":{"title":"Containment/Card","category":"Containment","own":false,"stories":["Playground","Variants","Interactive","Selectable","With media","Sizes"]},"props":[{"name":"src","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"alt","optional":true,"type":"string","default":"''","bindable":false,"doc":"","details":[],"examples":[]},{"name":"ratio","optional":true,"type":"'16/9' | '4/3' | '1/1' | '3/2' | 'auto'","default":"'16/9'","bindable":false,"doc":"Common MD3 media ratios.","details":[],"examples":[]},{"name":"bleed","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Cancels the card's padding so the media reaches the edges, and keeps only the corners it actually touches rounded.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Overlaid content — a play button, a gradient caption.","details":[],"examples":[]}]},{"name":"Carousel","dir":"carousel","entry":"omaris","importPath":"import { Carousel } from 'omaris'","summary":"MD3 carousel.","details":["The layouts are Material's own: `hero` (one large item with the next peeking as a strip), `centered` (strips either side of the big one), `multi-browse` (large, medium, small in a row), `full` (one item edge to edge) and `uncontained` (a plain scroller of equal items).","**One clock, one owner.** The strip does not scroll natively. A finger, a mouse, a trackpad, an arrow and the autoplay timer all write the same number — the fractional index the row is resting at — and one animation frame reads it back and places every card with a `transform`. Nothing is ever a frame behind anything else: the old build let the browser scroll and then chased it with JavaScript, so every card trailed the finger by a frame, froze on iOS while momentum ran, and jolted whenever snapping was switched back on under a moving gesture.","**It lands like a thrown thing.** Letting go hands the release velocity to a critically damped spring, so the row keeps the speed it had under the finger and decelerates into the nearest item with no kink and no bounce. A press mid-flight stops it dead under the thumb. Arrows, dots and a caller setting `index` glide on MD3's emphasized-decelerate, the same curve as everything the library animates in CSS. The ends give with a rubber band rather than a wall, and `loop` really loops — the last item folds straight into the first in either direction.","The keyline morph is continuous: every item's width and offset are a function of that one number, so strips grow into cards and cards fold into strips while you drag, tracking your finger frame for frame. Only the cards on screen are in layout at all, each on its own compositor layer, and geometry is written straight to their styles — the reactive graph only hears about the things the template needs (which item is in front, which are strips).","**Captions ride along.** An item's box narrows continuously as it folds into a strip, and text inside a narrowing box re-wraps on every frame. So the snippet is told two more things: `fullWidth`, the front card's resting width, to pin a caption to (`w-(--carousel-card)`) so it is clipped rather than reflowed; and `reveal`, 0 for a strip to 1 for the card in front, to fade it by (`opacity-(--carousel-reveal)`). Both are also set as custom properties.","**`morph` melts one slide into the next.** For `full` and `story` the slides need not slide at all: with `morph` on, the front slide stays put and the next one dissolves in over it while both are warped by a noise displacement that peaks halfway and settles to nothing — dragged, the warp tracks the finger; released, it lands with the spring. `melt` drips the picture downward, `ripple` breaks it into water, `shear` slices it sideways. It is an SVG filter on the two cards involved and nothing else, so it costs the same whether there are two slides or two hundred.","**A story is the same primitive, told by a clock.** `variant=\"story\"` is one full-bleed slide with a segmented timer across the top, tap zones either side, and press-and-hold to freeze it. The bar and the turn are the same clock, so they cannot drift apart, and a hold resumes where it stopped rather than restarting the slide."],"examples":[{"lang":"svelte","code":"<Carousel items={photos} bind:index indicators controls>\n  {#snippet item(photo)}\n    <img src={photo.src} alt={photo.alt} class=\"size-full object-cover\" />\n    <span class=\"absolute start-0 bottom-0 w-(--carousel-card) p-4 opacity-(--carousel-reveal)\">\n      {photo.title}\n    </span>\n  {/snippet}\n</Carousel>"}],"classesType":"CarouselClasses","parts":[{"name":"root","doc":""},{"name":"frame","doc":"Holds the track and the controls floated over it."},{"name":"viewport","doc":"The window onto the row. Horizontal touches are ours, vertical ones stay with the page, and a pinch still zooms."},{"name":"track","doc":"The row the cards are placed on. Fills the viewport; never moves itself."},{"name":"item","doc":"One card, placed by `transform` at its morphed width. Its own compositor layer, and its layout contained, so a card narrowing costs the browser that card and nothing around it."},{"name":"strip","doc":"A strip is a preview — pressing it brings it forward."},{"name":"control","doc":"Prev/next, floated over the viewport's edges."},{"name":"indicators","doc":""},{"name":"dot","doc":""},{"name":"segments","doc":"Story: the timer, one segment per slide, floated over the top."},{"name":"segment","doc":"One slide's share of the timer."},{"name":"segmentFill","doc":"How much of that share has run. Its width is the clock."},{"name":"header","doc":"A scrim across the top for a name, a time, an overflow menu. The scrim itself takes no pointer events and the controls inside it do, so a tap between them still reaches the story. Anything interactive that isn't a link, button or field needs its own `pointer-events-auto`."},{"name":"footer","doc":"The same, across the bottom, for actions."}],"variants":[{"name":"variant","doc":"","default":"hero","values":[{"name":"hero","doc":""},{"name":"centered","doc":""},{"name":"multi-browse","doc":""},{"name":"full","doc":""},{"name":"story","doc":"One slide, edge to edge, on a clock. See the notes above."},{"name":"uncontained","doc":""}]},{"name":"dragging","doc":"A drag in progress: the cursor says so, and nothing gets selected on the way.","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Containment/Carousel","category":"Containment","own":true,"stories":["Playground","Centered hero","Multi-browse","Uncontained","Full with autoplay","Story","Story, restyled","Right to left","Morph","Overridden height"]},"props":[{"name":"items","optional":false,"type":"T[]","bindable":false,"doc":"","details":[],"examples":[]},{"name":"item","optional":false,"type":"Snippet<[T, CarouselItemContext]>","bindable":false,"doc":"How to draw one item. It fills the card; images should `object-cover`.","details":[],"examples":[]},{"name":"variant","optional":true,"type":"CarouselVariant","default":"'hero'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"index","optional":true,"type":"number","default":"0","bindable":true,"doc":"The item in front. Bindable.","details":[],"examples":[]},{"name":"gap","optional":true,"type":"number","bindable":false,"doc":"Gap between items, in px. Defaults to 8, and to 0 for a story.","details":[],"examples":[]},{"name":"stripWidth","optional":true,"type":"number","default":"56","bindable":false,"doc":"Width of a peeking strip, in px.","details":[],"examples":[]},{"name":"itemWidth","optional":true,"type":"number","default":"240","bindable":false,"doc":"Item width for `uncontained`, in px.","details":[],"examples":[]},{"name":"loop","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Wrap around at the ends. With enough items to fill the row it is a true loop — the last folds into the first in either direction; with fewer, the ends still join but by a cut.","details":[],"examples":[]},{"name":"autoplay","optional":true,"type":"number","default":"0","bindable":false,"doc":"Advance every this many ms. Pauses under the pointer, on focus, and offscreen — a story instead pauses while held, while a key has focused it, and whenever `paused` is set.","details":[],"examples":[]},{"name":"controls","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Draw prev/next buttons.","details":[],"examples":[]},{"name":"indicators","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Draw the dots.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible name — \"Product photos\".","details":[],"examples":[]},{"name":"itemLabel","optional":true,"type":"(item: T, index: number) => string","bindable":false,"doc":"Names each item for assistive tech. Defaults to \"n of total\".","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(index: number) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"oncomplete","optional":true,"type":"() => void","bindable":false,"doc":"The last slide's timer ran out with `loop` off — the story is over.","details":[],"examples":[]},{"name":"header","optional":true,"type":"Snippet<[T, CarouselItemContext]>","bindable":false,"doc":"Drawn across the top of the frame, over the slide: a name, a time, a close button. Direct children of it are clickable; everything around them still taps through to the story.","details":[],"examples":[]},{"name":"footer","optional":true,"type":"Snippet<[T, CarouselItemContext]>","bindable":false,"doc":"The same, across the bottom: actions, a reply box.","details":[],"examples":[]},{"name":"paused","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Held open by the caller — a menu is up, a video is buffering. Bindable. A press-and-hold is not written back here — it is its own state, read from the root's `data-held` attribute.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","bindable":false,"doc":"How tall the viewport is. A number is px, a string is any CSS length. Defaults to `14rem`, and to `30rem` for a story — `100dvh` for one that fills the screen.","details":["The default lives in a custom property rather than a utility class, so a height in `classes.viewport` genuinely replaces it. To size by ratio instead, clear the height and let the aspect class govern: `height=\"auto\"` with `classes={{ viewport: 'aspect-4/5' }}`."],"examples":[]},{"name":"morph","optional":true,"type":"boolean | CarouselMorph","default":"false","bindable":false,"doc":"Dissolve between slides with a warp instead of sliding them, for `full` and `story`. `true` is `melt`; see `CarouselMorph` for the others. Ignored by the morphing layouts, which have their own motion.","details":[],"examples":[]},{"name":"morphStrength","optional":true,"type":"number","default":"48","bindable":false,"doc":"How far the warp displaces at its peak, in px.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"CarouselClasses","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"ChartFrame","dir":"chart","entry":"omaris/chart","importPath":"import { ChartFrame } from 'omaris/chart'","summary":"The box every chart draws into.","details":["LayerChart measures its container, so a chart needs a height from somewhere; this is that somewhere. It also owns the three states that aren't a plot — nothing to draw, a request that failed, and the download button that hands the numbers back — because \"no data\" should be a sentence rather than an empty pair of axes, and a chart that renders clean axes while the metrics service is down has told you a lie."],"examples":[],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Charts","category":"Data Display","own":false,"stories":["Area","Line","Bar","Pie and donut","Scatter","Sparkline","Empty","References and annotations","Brush and zoom","Legend isolate and CSV","Error","Combo","Radar","Radial bar and gauge","Funnel","Treemap","Candlestick"]},"props":[{"name":"height","optional":false,"type":"number | string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible description of what the chart shows.","details":[],"examples":[]},{"name":"role","optional":true,"type":"'img' | 'group'","default":"'group'","bindable":false,"doc":"`'group'` — the default — for a plot with anything in it a person can reach: a legend that filters, a tooltip, the CSV button, the \"Try again\" of the error state. `'img'` for a plot that really is just a picture, which hides the SVG's innards from a screen reader — and which promises there is nothing inside to tab to, so it is wrong the moment there is.","details":["Either way the role is only applied when there is a `label` to go with it: an unnamed `img` is a picture a screen reader announces and cannot describe."],"examples":[]},{"name":"blank","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"True when there's nothing to draw.","details":[],"examples":[]},{"name":"emptyText","optional":true,"type":"string","default":"'No data'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"empty","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]},{"name":"error","optional":true,"type":"boolean | string | Error","bindable":false,"doc":"Something went wrong. Truthy replaces the plot with the error state; a string or an `Error` supplies the message.","details":[],"examples":[]},{"name":"errorText","optional":true,"type":"string","default":"'Could not load this chart'","bindable":false,"doc":"The message, when `error` is just `true`.","details":[],"examples":[]},{"name":"errorState","optional":true,"type":"Snippet<[{ message: string }]>","bindable":false,"doc":"Replaces the whole error state.","details":[],"examples":[]},{"name":"onRetry","optional":true,"type":"() => void","bindable":false,"doc":"Offers a \"Try again\" button in the error state.","details":[],"examples":[]},{"name":"csv","optional":true,"type":"boolean | string","default":"false","bindable":false,"doc":"Offer `rows` as a CSV download. A string names the file.","details":[],"examples":[]},{"name":"rows","optional":true,"type":"readonly T[]","bindable":false,"doc":"The rows the download writes.","details":[],"examples":[]},{"name":"csvColumns","optional":true,"type":"(string | CsvColumn<T>)[]","bindable":false,"doc":"Which fields the download writes, in order. Defaults to every field.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"Checkbox","dir":"checkbox","entry":"omaris","importPath":"import { Checkbox } from 'omaris'","summary":"MD3 checkbox.","details":["A real `<input type=\"checkbox\">` does the work — keyboard, form submission, `indeterminate` — and is drawn over with a box that fills from the center when checked. The 40dp state layer around the 18dp box is the MD3 touch target; it only shows on hover, focus and press."],"examples":[],"classesType":"CheckboxClasses","parts":[{"name":"root","doc":""},{"name":"control","doc":"Wrapper that holds the state layer and the box."},{"name":"box","doc":"The visible square: the outline, and nothing else."},{"name":"fill","doc":"The colour, on a layer of its own so it can grow from the middle rather than snap on. Scaling a solid square is one compositor property — it stays at 60fps in a list of a hundred rows, which animating `background-color` would not."},{"name":"input","doc":"The `<input>` itself: invisible, but still the thing you click."},{"name":"mark","doc":"The tick / dash. Both paths are always in the DOM and are drawn on by walking `stroke-dashoffset` down to zero, so the tick writes itself in the direction a hand would and the dash slides out from the centre — a mounted `{#if}` could only fade."},{"name":"label","doc":""},{"name":"description","doc":""}],"variants":[{"name":"tone","doc":"","default":"primary","values":[{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""}]},{"name":"size","doc":"","default":"md","values":[{"name":"md","doc":""},{"name":"lg","doc":""}]},{"name":"invalid","doc":"","values":[{"name":"true","doc":""}]},{"name":"disabled","doc":"","values":[{"name":"true","doc":""}]}],"story":{"title":"Selection/Checkbox","category":"Selection","own":true,"stories":["Playground","States","Sizes","Tones","With description","Parent and children","Motion","Motion, overridden","Paint","Paint, scoped"]},"props":[{"name":"tone","optional":true,"type":"CheckboxTone","default":"'primary'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"CheckboxSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"checked","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Bindable.","details":[],"examples":[]},{"name":"indeterminate","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"The dash state — some but not all children are checked.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Text beside the box.","details":[],"examples":[]},{"name":"description","optional":true,"type":"string","bindable":false,"doc":"Second line under the label.","details":[],"examples":[]},{"name":"invalid","optional":true,"type":"boolean","bindable":false,"doc":"Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"haptics","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"A haptic tap when it's ticked or cleared. Follows the shared `haptics` store; `false` opts this checkbox out.","details":[],"examples":[]},{"name":"sound","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"A sound cue when it's ticked. Follows the shared `sound` store; `false` opts this checkbox out.","details":[],"examples":[]},{"name":"paint","optional":true,"type":"boolean | string","default":"true","bindable":false,"doc":"Drag across a run of checkboxes to set them all, the way a phone's photo grid selects. The box you press decides the direction — start on an empty one and the stroke ticks, start on a ticked one and it clears. On by default.","details":["A stroke stays inside its container (the nearest list, form, table or `fieldset`); pass a name to paint across one you don't control, and the same name has to be on every box in the run. `false` opts a checkbox out of being painted and of starting a stroke."],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"CheckboxClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Rich label, in place of `label`.","details":[],"examples":[]},{"name":"ref","optional":true,"type":"HTMLInputElement | null","default":"null","bindable":true,"doc":"","details":[],"examples":[]}]},{"name":"Chip","dir":"chip","entry":"omaris","importPath":"import { Chip } from 'omaris'","summary":"MD3 chip — assist, filter, input and suggestion, in one component.","details":["The four MD3 chip types differ only in behaviour, so they're expressed as props rather than four components: `selectable` gives you a filter chip (with the tick that slides in), `onremove` gives you an input chip (with the trailing ×), and neither gives you assist/suggestion.","A removable chip nests a real button inside, so the × is reachable by keyboard on its own rather than being a click target painted on top."],"examples":[],"classesType":"ChipClasses","parts":[{"name":"root","doc":""},{"name":"label","doc":""},{"name":"check","doc":"The leading tick on a filter chip: zero-width until selected."},{"name":"remove","doc":"The trailing × on an input chip."}],"variants":[{"name":"tone","doc":"","default":"primary","values":[{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""}]},{"name":"variant","doc":"","default":"outlined","values":[{"name":"outlined","doc":"MD3's default chip: a hairline outline on the surface."},{"name":"tonal","doc":"Filled, for chips that need to read as a solid object."},{"name":"elevated","doc":"Elevated — a chip floating over content."}]},{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]},{"name":"shape","doc":"Pill instead of MD3's rounded rectangle.","default":"round","values":[{"name":"round","doc":""},{"name":"square","doc":""}]},{"name":"pressable","doc":"","values":[{"name":"true","doc":""}]},{"name":"selected","doc":"","values":[{"name":"true","doc":""}]},{"name":"disabled","doc":"","values":[{"name":"true","doc":""}]}],"story":{"title":"Selection/Chip","category":"Selection","own":true,"stories":["Playground","Variants","Sizes","The four kinds","Filter set","Input chips","With avatars","Tones","Disabled"]},"props":[{"name":"variant","optional":true,"type":"ChipVariant","default":"'outlined'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"tone","optional":true,"type":"ChipTone","default":"'primary'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"ChipSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"shape","optional":true,"type":"ChipShape","default":"'round'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"selectable","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Turns the chip into a filter chip: clicking toggles `selected`.","details":[],"examples":[]},{"name":"selected","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Selected state of a filter chip. Bindable.","details":[],"examples":[]},{"name":"check","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Hide the leading tick on a selected filter chip.","details":[],"examples":[]},{"name":"onremove","optional":true,"type":"() => void","bindable":false,"doc":"Adds the trailing ×. Called when it's pressed.","details":[],"examples":[]},{"name":"removeLabel","optional":true,"type":"string","bindable":false,"doc":"Accessible name for the × — \"Remove React\".","details":[],"examples":[]},{"name":"ripple","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"ChipClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"start","optional":true,"type":"Snippet","bindable":false,"doc":"Leading icon or avatar.","details":[],"examples":[]},{"name":"end","optional":true,"type":"Snippet","bindable":false,"doc":"Trailing icon, before the × if there is one.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]},{"name":"icon","optional":true,"type":"boolean","bindable":false,"doc":"Square, label-less button. Requires an `aria-label`.","details":[],"examples":[]},{"name":"confetti","optional":true,"type":"boolean | ConfettiOptions","bindable":false,"doc":"Confetti on press. `true` for the default burst, or any `ConfettiOptions` — `confetti={{ preset: 'fireworks' }}`.","details":[],"examples":[]},{"name":"loading","optional":true,"type":"boolean","bindable":false,"doc":"Grows a spinner in at the start of the button and blocks interaction. The label stays put; only an `icon` button swaps its icon out.","details":[],"examples":[]},{"name":"toggle","optional":true,"type":"boolean","bindable":false,"doc":"Turns the button into a two-state toggle driven by `pressed`. Ignored when `href` is set — a link has no pressed state.","details":[],"examples":[]},{"name":"pressed","optional":true,"type":"boolean","bindable":true,"doc":"Selected state of a toggle button. Bindable.","details":[],"examples":[]}]},{"name":"ChipGroup","dir":"chip","entry":"omaris","importPath":"import { ChipGroup } from 'omaris'","summary":"A set of chips that belong together, with the accessible name that implies.","details":["`overflow` is the real decision: `wrap` flows onto more lines and is right in a form, `scroll` keeps one line that swipes sideways and is what MD3 does for a filter bar above a list."],"examples":[],"classesType":null,"parts":[],"variants":[],"story":{"title":"Selection/Chip","category":"Selection","own":false,"stories":["Playground","Variants","Sizes","The four kinds","Filter set","Input chips","With avatars","Tones","Disabled"]},"props":[{"name":"overflow","optional":true,"type":"'wrap' | 'scroll'","default":"'wrap'","bindable":false,"doc":"`wrap` lets the set flow onto more lines — the right choice in a form. `scroll` keeps it to one line that swipes sideways, which is what MD3 does for a filter bar above a list.","details":["`scroll` bleeds 16px past its container on each side and restores the inset inside itself, so the strip runs to the screen edge while the first chip still lines up with the text above it. It therefore wants a container with at least `px-4`; in one with none, those 16px are 16px of horizontal page scroll."],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible name for the set.","details":[],"examples":[]},{"name":"multiple","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"A set where chips are chosen, rather than one where they act.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"CircularProgress","dir":"progress","entry":"omaris","importPath":"import { CircularProgress } from 'omaris'","summary":"MD3 circular progress — the spinner, and the ring that counts up.","details":["Drawn as an SVG so the stroke stays crisp at any size and the sweep can be animated with `stroke-dashoffset` instead of a clip. Determinate when `value` is a number."],"examples":[],"classesType":"CircularProgressClasses","parts":[{"name":"root","doc":""},{"name":"svg","doc":""},{"name":"track","doc":""},{"name":"indicator","doc":""},{"name":"content","doc":"Centered slot — a percentage, or an icon."}],"variants":[{"name":"tone","doc":"","default":"primary","values":[{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""}]},{"name":"size","doc":"","default":"md","values":[{"name":"xs","doc":""},{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""},{"name":"xl","doc":""}]}],"story":{"title":"Communication/Progress","category":"Communication","own":false,"stories":["Playground","Determinate","Buffered","Indeterminate","Sizes","Tones","Circular","Live"]},"props":[{"name":"value","optional":true,"type":"number","bindable":false,"doc":"0…`max`. Leave undefined to spin.","details":[],"examples":[]},{"name":"max","optional":true,"type":"number","default":"100","bindable":false,"doc":"","details":[],"examples":[]},{"name":"tone","optional":true,"type":"CircularProgressTone","default":"'primary'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"CircularProgressSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"thickness","optional":true,"type":"number","default":"4","bindable":false,"doc":"Stroke width, as a fraction of the radius.","details":[],"examples":[]},{"name":"track","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Draw the unfilled remainder of the ring.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"CircularProgressClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Centered content — omit for a bare ring.","details":[],"examples":[]}]},{"name":"CodeBlock","dir":"code-block","entry":"omaris","importPath":"import { CodeBlock } from 'omaris'","summary":"A code block: highlighted, copyable, and themed like everything else.","details":["The colours are tokens (`--code-keyword`, `--code-string`, …) defined in both themes and driven by the same chroma knob as the rest of the palette, so a muted theme gets muted code and a re-hued one gets re-hued code. The highlighter is `highlight.ts` — no Prism, no Shiki, no `innerHTML`; every token is a real element."],"examples":[{"lang":"svelte","code":"<CodeBlock lang=\"svelte\" title=\"button.svelte\" lineNumbers highlight=\"2-4\" {code} />"}],"classesType":"CodeBlockClasses","parts":[{"name":"root","doc":""},{"name":"header","doc":"Filename bar: title, language chip, actions."},{"name":"title","doc":""},{"name":"badge","doc":""},{"name":"viewport","doc":"The scroll container — focusable, so a keyboard can scroll it."},{"name":"code","doc":""},{"name":"line","doc":"One line — a row so the gutter can stay put while the code scrolls."},{"name":"gutter","doc":"Line number, pinned against horizontal scroll."},{"name":"sign","doc":"`+` / `-` column, in diff mode."},{"name":"content","doc":""},{"name":"float","doc":"The floating copy button when there's no header to hold it."},{"name":"expand","doc":"\"Show all\" strip under a collapsed block."},{"name":"fade","doc":"The fade that says \"there's more below\"."}],"variants":[{"name":"variant","doc":"","default":"outlined","values":[{"name":"outlined","doc":"The default — a bordered surface, like a card."},{"name":"filled","doc":"Fills without a border, for use inside an already-bordered surface."},{"name":"ghost","doc":"No container at all — code on the page."}]},{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""}]},{"name":"wrap","doc":"","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]},{"name":"focus","doc":"Dims everything that isn't called out, until you hover the block.","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Data display/CodeBlock","category":"Data Display","own":true,"stories":["Playground","Bare","Highlighted lines","Focus","Diff","Collapsed","Languages","Variants","Wrapped"]},"props":[{"name":"code","optional":false,"type":"string","bindable":false,"doc":"The source. Leading and trailing blank lines are trimmed.","details":[],"examples":[]},{"name":"lang","optional":true,"type":"string","default":"'plain'","bindable":false,"doc":"`ts`, `svelte`, `css`, `json`, `bash`, `python`, `sql`, `yaml`, `md`, …","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"Filename, shown in the header bar.","details":[],"examples":[]},{"name":"variant","optional":true,"type":"CodeBlockVariant","default":"'outlined'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"CodeBlockSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"badge","optional":true,"type":"boolean","bindable":false,"doc":"Show the language chip. Defaults to on whenever there's a header.","details":[],"examples":[]},{"name":"lineNumbers","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"startLine","optional":true,"type":"number","default":"1","bindable":false,"doc":"Number the first line is given.","details":[],"examples":[]},{"name":"highlight","optional":true,"type":"string | number[]","bindable":false,"doc":"Lines to call out — `[2, 5]` or `'2,5-8'`.","details":[],"examples":[]},{"name":"focus","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Dim every line that isn't called out until the block is hovered.","details":[],"examples":[]},{"name":"diff","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Read `+`/`-` prefixes as a diff and tint the lines.","details":[],"examples":[]},{"name":"copy","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Offer the copy button.","details":[],"examples":[]},{"name":"wrap","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Wrap long lines instead of scrolling sideways.","details":[],"examples":[]},{"name":"collapse","optional":true,"type":"number","bindable":false,"doc":"Collapse to this many lines, with a control to open it up.","details":[],"examples":[]},{"name":"actions","optional":true,"type":"Snippet","bindable":false,"doc":"Extra header controls, before the copy button.","details":[],"examples":[]},{"name":"oncopy","optional":true,"type":"(code: string) => void","bindable":false,"doc":"Fires after the source lands on the clipboard.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"CodeBlockClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"CodeEditor","dir":"code-editor","entry":"omaris","importPath":"import { CodeEditor } from 'omaris'","summary":"A code editor with no editor in it.","details":["It is a real `<textarea>` with a highlighted copy of the same text painted exactly behind it — which sounds like a trick and is actually the reason to do it. Native text editing is *hard*: IME composition, mobile autocorrect, spellcheck, undo that survives a page's own edits, screen readers, drag-and-drop of selected text, the Home key doing what your OS says it does. A contenteditable rewrites all of it, badly. A textarea gets all of it for free, and the only thing it lacks is colour — so colour is the only thing added.","On top of that sit the things a plain textarea genuinely lacks: `Tab` indents a selection, `Enter` keeps your indentation, brackets close themselves, `⌘/` comments, `⌥↑`/`⌥↓` move a line and `⌥⇧↑`/`⌥⇧↓` duplicate it, `⌘F` finds and replaces, `⌘D` walks the occurrences of a word, `⌃Space` completes it, and every edit goes through the browser's own insert command so `⌘Z` still walks back one change at a time.","And one prop turns it into vim — modes, operators, text objects, registers, marks, `/` search, `.`, and an ex line with `:s///` and `:set`:"],"examples":[{"lang":"svelte","code":"<CodeEditor bind:value lang=\"ts\" lineNumbers height={320} />"},{"lang":"svelte","code":"<CodeEditor bind:value lang=\"ts\" vim />"}],"classesType":"CodeEditorClasses","parts":[{"name":"root","doc":""},{"name":"header","doc":"Filename bar."},{"name":"title","doc":""},{"name":"badge","doc":""},{"name":"tools","doc":"The header's trailing group — your `actions`, then the copy button."},{"name":"float","doc":"The copy button when there is no header to hold it. Quiet until the pointer is over the editor, and always there on a touch screen, where there is no hover to reveal it with."},{"name":"frame","doc":"Gutter and text, side by side."},{"name":"gutter","doc":"The line-number column. Scrolls with the text, never sideways."},{"name":"gutterInner","doc":""},{"name":"gutterLine","doc":"One number. Its height must match a text line exactly."},{"name":"gutterMarked","doc":"A gutter number on a line that has a diagnostic."},{"name":"editor","doc":"Holds the painted copy and the real textarea, exactly on top of each other."},{"name":"paint","doc":"The highlighted copy. Never interactive — it is a picture of the text. In flow, so `height=\"auto\"` has a content height to grow to."},{"name":"code","doc":""},{"name":"line","doc":"One painted line."},{"name":"active","doc":"The line the caret is on."},{"name":"overlay","doc":"Search hits, the bracket pair, diagnostics, the vim caret."},{"name":"overlayInner","doc":""},{"name":"match","doc":"One search hit."},{"name":"matchCurrent","doc":"The hit `Enter` would jump to."},{"name":"bracket","doc":"The bracket under the caret and its partner."},{"name":"caret","doc":"Vim's block caret."},{"name":"marker","doc":"The rule under a diagnostic."},{"name":"guide","doc":"One indent-guide rule."},{"name":"input","doc":"The textarea. Transparent text, visible caret — the paint shows through."},{"name":"placeholder","doc":"Shown over an empty editor."},{"name":"find","doc":"Find and replace, floating over the top-right of the text."},{"name":"findRow","doc":""},{"name":"findField","doc":""},{"name":"findButton","doc":""},{"name":"findCount","doc":""},{"name":"menu","doc":"The completion list."},{"name":"option","doc":""},{"name":"optionActive","doc":""},{"name":"status","doc":"Line, column and length."},{"name":"mode","doc":"`NORMAL`, `INSERT`, …"},{"name":"command","doc":"The `:` line, and anything vim has to say."},{"name":"pending","doc":"The keys of a half-typed vim command."}],"variants":[{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""}]},{"name":"wrap","doc":"","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]},{"name":"readOnly","doc":"","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]},{"name":"blockCaret","doc":"Vim's normal and visual modes draw their own caret.","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Inputs/Code Editor","category":"Inputs","own":true,"stories":["Playground","Editing","Languages","Placeholder","Read only","Grows with content","Vim","Relative numbers","Find and replace","Diagnostics","Completions","Restyled vim"]},"props":[{"name":"value","optional":true,"type":"string","default":"''","bindable":true,"doc":"The source. Bindable.","details":[],"examples":[]},{"name":"lang","optional":true,"type":"string","default":"'plain'","bindable":false,"doc":"`ts`, `svelte`, `css`, `json`, `bash`, … — the names `CodeBlock` takes.","details":[],"examples":[]},{"name":"size","optional":true,"type":"CodeEditorSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"Filename, shown in the header bar.","details":[],"examples":[]},{"name":"badge","optional":true,"type":"boolean","bindable":false,"doc":"Show the language chip. Defaults to on whenever there is a header.","details":[],"examples":[]},{"name":"copy","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Offer a copy button. It goes in the header when there is one, and floats over the top corner when there is not — where it fades in on hover, and stays put on a touch screen.","details":["It copies the selection when there is one and the whole file when there is not, and it never takes the caret out of the editor."],"examples":[]},{"name":"actions","optional":true,"type":"Snippet","bindable":false,"doc":"Extra header controls, before the copy button.","details":[],"examples":[]},{"name":"oncopy","optional":true,"type":"(text: string) => void","bindable":false,"doc":"Fires after the source lands on the clipboard, with what was copied.","details":[],"examples":[]},{"name":"lineNumbers","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"relativeLineNumbers","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Number every line by its distance from the caret, as `:set rnu` does.","details":[],"examples":[]},{"name":"startLine","optional":true,"type":"number","default":"1","bindable":false,"doc":"Number the first line is given.","details":[],"examples":[]},{"name":"wrap","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Wrap long lines instead of scrolling sideways.","details":[],"examples":[]},{"name":"highlightActiveLine","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Tint the line the caret is on.","details":[],"examples":[]},{"name":"readOnly","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"tabSize","optional":true,"type":"number","default":"2","bindable":false,"doc":"Indent width, in spaces.","details":[],"examples":[]},{"name":"insertSpaces","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Indent with spaces rather than a tab character.","details":[],"examples":[]},{"name":"autoClose","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Close brackets and quotes as you type, and wrap a selection in them.","details":[],"examples":[]},{"name":"status","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Line, column and character count along the bottom. On by default with `vim`.","details":[],"examples":[]},{"name":"vim","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Modal editing: normal, insert, visual and visual-line, operators and motions (`d2w`, `ci\"`, `>ip`, `gUiw`), registers, marks, `/` search, `.`, `<C-a>`, and `:w :q :s/// :set`. `u` and `<C-r>` undo a whole command — `ciwfoo<Esc>` included — and still leave `⌘Z` working.","details":[],"examples":[]},{"name":"vimMode","optional":true,"type":"VimMode","default":"'normal'","bindable":true,"doc":"The mode vim is in. Bindable, for a status bar of your own.","details":[],"examples":[]},{"name":"find","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"`⌘F` / `⌘H`.","details":[],"examples":[]},{"name":"bracketMatch","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Ring the bracket under the caret and its partner.","details":[],"examples":[]},{"name":"indentGuides","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"A rule down each level of indentation.","details":[],"examples":[]},{"name":"markers","optional":true,"type":"CodeEditorMarker[]","default":"[]","bindable":false,"doc":"Errors and warnings to draw under the text.","details":[],"examples":[]},{"name":"completions","optional":true,"type":"string[] | ((context: CodeEditorCompletionContext) => string[])","bindable":false,"doc":"What `⌃Space` offers. A list, or a function called with the word being typed. Given a list, the menu also opens as you type. Left out, `⌃Space` still completes from the words already in the document.","details":[],"examples":[]},{"name":"comment","optional":true,"type":"string | [string, string]","bindable":false,"doc":"What `⌘/` and vim's `gc` comment with. A line token like `'#'`, or an open/close pair. Defaults to the one `lang` uses.","details":[],"examples":[]},{"name":"onsave","optional":true,"type":"(value: string) => void","bindable":false,"doc":"`⌘S`, and vim's `:w`.","details":[],"examples":[]},{"name":"onquit","optional":true,"type":"() => void","bindable":false,"doc":"Vim's `:q`. Nothing happens without it.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(value: string) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"'18rem'","bindable":false,"doc":"Height of the editing area. A number is px, a string any CSS length. It lives in a property rather than a class, so a height in `classes.frame` genuinely replaces it — `height=\"auto\"` with a `min-h-*` class lets it grow with the content instead.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"CodeEditorClasses","bindable":false,"doc":"","details":[],"examples":[]},{"name":"ref","optional":true,"type":"HTMLTextAreaElement | null","default":"null","bindable":true,"doc":"","details":[],"examples":[]}]},{"name":"Collapsible","dir":"collapsible","entry":"omaris","importPath":"import { Collapsible } from 'omaris'","summary":"A single disclosure: a header you press and the block it shows or hides.","details":["The one-panel sibling of `Accordion`, with the same motion — the body rides a grid row going `0fr → 1fr`, which is the one way to transition to a content-derived height without measuring it, so nothing jumps when the content changes while it is open. The chevron turns with it on the same curve, and the body fades in a beat behind so text never appears half clipped.","The header is either the built-in one — `title`, `supportingText`, an `icon` and an `end` slot, with the chevron — or your own element through `trigger`, which is handed the ARIA and the handler to spread on it:","A closed body is `inert`, so nothing inside it can take focus or be read out while it is out of sight."],"examples":[{"lang":"svelte","code":"<Collapsible bind:open>\n  {#snippet trigger(props)}\n    <Button variant=\"text\" {...props}>{open ? 'Show less' : 'Show all 12'}</Button>\n  {/snippet}\n  …\n</Collapsible>"}],"classesType":"CollapsibleClasses","parts":[{"name":"root","doc":""},{"name":"trigger","doc":""},{"name":"icon","doc":"Leading icon in the built-in trigger."},{"name":"headline","doc":""},{"name":"title","doc":""},{"name":"supporting","doc":""},{"name":"chevron","doc":""},{"name":"wrapper","doc":"The animated wrapper; its single grid row is what opens."},{"name":"content","doc":"Clips the body while the row is shorter than it."},{"name":"inner","doc":""}],"variants":[{"name":"variant","doc":"","default":"plain","values":[{"name":"plain","doc":"Flush on the page — no surface of its own."},{"name":"outlined","doc":"A hairline card, for a disclosure that sits among other things."},{"name":"filled","doc":"A tonal card, for a disclosure that is a thing of its own."}]},{"name":"open","doc":"","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Containment/Collapsible","category":"Containment","own":true,"stories":["Playground","Open","Variants","With icon and count","Disabled","Custom trigger","Overridden"]},"props":[{"name":"open","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Whether the body is showing. Bindable.","details":[],"examples":[]},{"name":"onOpenChange","optional":true,"type":"(open: boolean) => void","bindable":false,"doc":"Called whenever it opens or closes from the trigger.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"Header text for the built-in trigger.","details":[],"examples":[]},{"name":"supportingText","optional":true,"type":"string","bindable":false,"doc":"A second line under `title` — \"3 filters applied\".","details":[],"examples":[]},{"name":"variant","optional":true,"type":"CollapsibleVariant","default":"'plain'","bindable":false,"doc":"`plain` flush on the page, `outlined` a hairline card, `filled` a tonal one.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"The trigger does nothing and reads as unavailable. The body keeps its state.","details":[],"examples":[]},{"name":"headingLevel","optional":true,"type":"2 | 3 | 4 | 5 | 6","bindable":false,"doc":"Wraps the built-in trigger in a heading of this level, for a disclosure that titles a section of the page. Leave unset for one that doesn't.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"CollapsibleClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"icon","optional":true,"type":"Snippet","bindable":false,"doc":"Leading icon in the built-in trigger.","details":[],"examples":[]},{"name":"end","optional":true,"type":"Snippet","bindable":false,"doc":"Trailing content before the chevron — a count, a badge.","details":[],"examples":[]},{"name":"trigger","optional":true,"type":"Snippet<[CollapsibleTriggerProps]>","bindable":false,"doc":"Your own trigger in place of the built-in one. Spread the props onto a button — they carry `aria-expanded`, `aria-controls` and the toggle.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"The body.","details":[],"examples":[]},{"name":"id","optional":false,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"aria-expanded","optional":false,"type":"boolean","bindable":false,"doc":"","details":[],"examples":[]},{"name":"aria-controls","optional":false,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onclick","optional":false,"type":"(event: MouseEvent) => void","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"ColorPicker","dir":"color-picker","entry":"omaris","importPath":"import { ColorPicker } from 'omaris'","summary":"A colour picker that thinks in OKLCH, because this library does.","details":["Lightness runs up the y-axis and chroma across the x-axis. How far across is `plane`:","- `relative` (the default) scales the row to the most colour *that lightness* can hold, so the rectangle is full of colour, the right edge is the most saturated this hue gets here, and every point you can drag to is a colour sRGB can show. Moving lightness or hue takes the chroma with it, which is why the puck never falls out of the gamut on its own. - `absolute` scales every row to the same chroma and leaves the rest transparent, drawing the gamut's real silhouette — the lopsided leaf that grows and shrinks as you turn the hue. True to the geometry, and mostly empty: at any one lightness sRGB holds a fraction of the widest chroma it holds anywhere, so most of the box is checkerboard you cannot pick from.","Either way nothing is clipped behind your back: a colour outside sRGB — typed in, or bound from elsewhere — says so, and asking for hex maps it back by lowering chroma only, so your hue and lightness survive.","`value` is a plain CSS string in whatever `format` you asked for, so it drops straight into a token, a form field or a style attribute."],"examples":[{"lang":"svelte","code":"<ColorPicker bind:value format=\"oklch\" swatches={brand} />"}],"classesType":"ColorPickerClasses","parts":[{"name":"root","doc":""},{"name":"area","doc":"The lightness × chroma plane."},{"name":"canvas","doc":""},{"name":"areaThumb","doc":"The puck on the plane."},{"name":"controls","doc":"Preview + sliders."},{"name":"preview","doc":"The current colour, over a checkerboard."},{"name":"previewFill","doc":""},{"name":"sliders","doc":""},{"name":"slider","doc":"One slider row."},{"name":"alphaTrack","doc":"The alpha track's checkerboard sits under its gradient."},{"name":"track","doc":""},{"name":"thumb","doc":""},{"name":"fields","doc":"Numeric and text inputs."},{"name":"field","doc":""},{"name":"label","doc":""},{"name":"input","doc":""},{"name":"eyedropper","doc":"The \"sample a pixel\" button, where the browser has one."},{"name":"swatches","doc":""},{"name":"swatch","doc":""},{"name":"hint","doc":"Says when the colour has been mapped back into sRGB."}],"variants":[{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]},{"name":"compact","doc":"Trims it to the plane and the hue strip.","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Inputs/Color Picker","category":"Inputs","own":true,"stories":["Playground","Relative chroma","Hex output","With alpha","Sizes","Out of gamut","Relative against absolute","The leaf at every hue","Compact in a panel"]},"props":[{"name":"value","optional":true,"type":"string","default":"'oklch(0.6 0.18 260)'","bindable":true,"doc":"The colour, as CSS text in `format`. Bindable.","details":[],"examples":[]},{"name":"format","optional":true,"type":"ColorFormat","default":"'oklch'","bindable":false,"doc":"How `value` is written. Parsing accepts hex, `rgb()`, `oklch()` and `oklab()` whatever this says.","details":[],"examples":[]},{"name":"size","optional":true,"type":"ColorPickerSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"alpha","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Show the alpha slider and carry alpha in `value`.","details":[],"examples":[]},{"name":"swatches","optional":true,"type":"string[]","bindable":false,"doc":"Preset colours under the picker. Any CSS colour string.","details":[],"examples":[]},{"name":"plane","optional":true,"type":"PlaneScale","default":"'relative'","bindable":false,"doc":"How the plane's x-axis is scaled — `relative` fills it with the colour this lightness can hold, `absolute` draws the gamut's own silhouette against transparency.","details":[],"examples":[]},{"name":"channels","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Show the L / C / H number boxes beside the text field.","details":[],"examples":[]},{"name":"eyedropper","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Offer the browser's screen sampler, where there is one.","details":[],"examples":[]},{"name":"compact","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","default":"'Colour'","bindable":false,"doc":"Accessible name for the plane.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(value: string, color: Oklch) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"ColorPickerClasses","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"Combobox","dir":"combobox","entry":"omaris","importPath":"import { Combobox } from 'omaris'","summary":"Combobox — type to search, arrow to the one you want, Enter to take it.","details":["Give it `options` and it filters them as you type (accent-insensitive, matches anywhere in the label or the option's `keywords`). Give it `load` instead and it asks you for results, debounced, with an `AbortSignal` so a slow reply for \"ir\" never overwrites the answer for \"iraq\":","Focus never leaves the input — the list is driven with `aria-activedescendant` — so it works with a screen reader, a phone keyboard and a form's Tab order exactly like a plain text field."],"examples":[{"lang":"svelte","code":"<Combobox bind:value options={countries} label=\"Country\" />\n<Combobox bind:value load={(q, signal) => api.users(q, { signal })} />"}],"classesType":"ComboboxClasses","parts":[{"name":"root","doc":"Wrapper: label, field, supporting text."},{"name":"field","doc":"The frame: border, background, height, adornment layout."},{"name":"control","doc":"The bare <input>; the frame owns every decoration."},{"name":"label","doc":""},{"name":"adornment","doc":"Icon slots at either end of the frame."},{"name":"affix","doc":"Flat text glued to the value — \"https://\", \"kg\"."},{"name":"action","doc":"An interactive trailing control: reveal, clear."},{"name":"support","doc":"Helper line under the field, and the counter beside it."},{"name":"counter","doc":""},{"name":"surface","doc":""},{"name":"option","doc":""},{"name":"group","doc":"A non-interactive heading above a run of options."},{"name":"body","doc":""},{"name":"description","doc":""},{"name":"check","doc":""},{"name":"empty","doc":"\"No results\", \"Searching…\"."},{"name":"highlight","doc":"The part of a label that matched what was typed."}],"variants":[],"story":{"title":"Inputs/Combobox","category":"Inputs","own":true,"stories":["Playground","Async","Creatable","Right to left","Sizes","Filled and ghost"]},"props":[{"name":"variant","optional":true,"type":"InputVariant","default":"'outline'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"InputSize","default":"'default'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"value","optional":true,"type":"string","default":"''","bindable":true,"doc":"The chosen option's value. Bindable.","details":[],"examples":[]},{"name":"selected","optional":true,"type":"ComboboxOption | null","default":"null","bindable":true,"doc":"The chosen option itself. Bindable, for when `value` alone isn't enough.","details":[],"examples":[]},{"name":"query","optional":true,"type":"string","default":"''","bindable":true,"doc":"What's in the box. Bindable.","details":[],"examples":[]},{"name":"options","optional":true,"type":"ComboboxOption[]","bindable":false,"doc":"A fixed list, filtered locally.","details":[],"examples":[]},{"name":"load","optional":true,"type":"ComboboxLoad","bindable":false,"doc":"Fetch results for a query instead.","details":[],"examples":[]},{"name":"debounce","optional":true,"type":"number","default":"200","bindable":false,"doc":"ms to wait after the last keystroke before calling `load`.","details":[],"examples":[]},{"name":"minChars","optional":true,"type":"number","default":"0","bindable":false,"doc":"Don't call `load` until this many characters are typed.","details":[],"examples":[]},{"name":"maxResults","optional":true,"type":"number","default":"50","bindable":false,"doc":"Cap on rows shown from a local filter.","details":[],"examples":[]},{"name":"filter","optional":true,"type":"(option: ComboboxOption, query: string) => boolean","bindable":false,"doc":"Your own local matcher.","details":[],"examples":[]},{"name":"allowCustom","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Take whatever's typed as the value when nothing matches.","details":[],"examples":[]},{"name":"openOnFocus","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Open the list as soon as the field is focused.","details":[],"examples":[]},{"name":"clearable","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Show an × that empties the field.","details":[],"examples":[]},{"name":"highlight","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Bolden the matched part of each label.","details":[],"examples":[]},{"name":"emptyText","optional":true,"type":"string","default":"'No results'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"loadingText","optional":true,"type":"string","default":"'Searching…'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"supportingText","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"invalid","optional":true,"type":"boolean","bindable":false,"doc":"Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"required","optional":true,"type":"boolean","bindable":false,"doc":"Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"start","optional":true,"type":"Snippet","bindable":false,"doc":"Leading icon inside the frame.","details":[],"examples":[]},{"name":"option","optional":true,"type":"Snippet<[ComboboxOption, { selected: boolean; active: boolean; query: string }]>","bindable":false,"doc":"Custom row rendering.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(value: string, option: ComboboxOption | null) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"ComboboxClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"ref","optional":true,"type":"HTMLInputElement | null","default":"null","bindable":true,"doc":"","details":[],"examples":[]}]},{"name":"ComboChart","dir":"chart","entry":"omaris/chart","importPath":"import { ComboChart } from 'omaris/chart'","summary":"Combo chart — bars and lines on one plot.","details":["The pairing worth having is a magnitude and a rate: bars for the amount, a line for the percentage it works out to. Those two don't share a scale, so `axis: 'right'` gives the line its own, drawn down the right-hand edge and labelled in its own units.","Bar series stack; a line never joins the stack, whatever else is on the chart. Grouped bars beside a line are a `BarChart` and a second series away from being unreadable, so they aren't offered here."],"examples":[{"lang":"svelte","code":"<ComboChart\n  data={months}\n  x=\"month\"\n  series={[\n    { key: 'revenue', type: 'bar' },\n    { key: 'margin', type: 'line', axis: 'right' }\n  ]}\n/>"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Charts","category":"Data Display","own":false,"stories":["Area","Line","Bar","Pie and donut","Scatter","Sparkline","Empty","References and annotations","Brush and zoom","Legend isolate and CSV","Error","Combo","Radar","Radial bar and gauge","Funnel","Treemap","Candlestick"]},"props":[{"name":"data","optional":false,"type":"T[]","bindable":false,"doc":"","details":[],"examples":[]},{"name":"x","optional":true,"type":"Field<T>","bindable":false,"doc":"The category or time field.","details":[],"examples":[]},{"name":"series","optional":true,"type":"ComboSeries<T>[]","default":"[]","bindable":false,"doc":"What to draw, in the order it draws.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"280","bindable":false,"doc":"Plot height. A number is px; a string is any CSS length.","details":[],"examples":[]},{"name":"axis","optional":true,"type":"boolean | 'x' | 'y'","default":"true","bindable":false,"doc":"`true` for both, or just the one you want.","details":[],"examples":[]},{"name":"grid","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"legend","optional":true,"type":"ChartLegend","default":"false","bindable":false,"doc":"`true` toggles a series off on click; `'isolate'` shows it alone.","details":[],"examples":[]},{"name":"tooltip","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"stacked","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Pile the bar series rather than overlapping them.","details":[],"examples":[]},{"name":"radius","optional":true,"type":"number","default":"4","bindable":false,"doc":"Corner radius on the bars, in px.","details":[],"examples":[]},{"name":"formatX","optional":true,"type":"(value: never) => string","bindable":false,"doc":"Tick labels along the x axis.","details":[],"examples":[]},{"name":"formatY","optional":true,"type":"(value: never) => string","bindable":false,"doc":"Tick labels down the left axis.","details":[],"examples":[]},{"name":"formatY2","optional":true,"type":"(value: never) => string","bindable":false,"doc":"Tick labels down the right axis.","details":[],"examples":[]},{"name":"colors","optional":true,"type":"readonly string[]","default":"CHART_COLORS","bindable":false,"doc":"Palette override, cycled across the series.","details":[],"examples":[]},{"name":"padding","optional":true,"type":"number | { top?: number; right?: number; bottom?: number; left?: number }","bindable":false,"doc":"Space around the plot, in px.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible description of what the chart shows.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"empty","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]},{"name":"emptyText","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"error","optional":true,"type":"boolean | string | Error","bindable":false,"doc":"Something went wrong. Truthy puts the chart into its error state; a string or an `Error` supplies the message.","details":[],"examples":[]},{"name":"errorText","optional":true,"type":"string","bindable":false,"doc":"The message, when `error` is just `true`.","details":[],"examples":[]},{"name":"errorState","optional":true,"type":"Snippet<[{ message: string }]>","bindable":false,"doc":"Replaces the whole error state.","details":[],"examples":[]},{"name":"onRetry","optional":true,"type":"() => void","bindable":false,"doc":"Offers a \"Try again\" button in the error state.","details":[],"examples":[]},{"name":"csv","optional":true,"type":"boolean | string","default":"false","bindable":false,"doc":"Offer the plotted rows as a CSV download, from a button in the corner. A string names the file.","details":[],"examples":[]},{"name":"csvColumns","optional":true,"type":"(string | { key: string; label?: string; value?: (row: T) => unknown })[]","bindable":false,"doc":"Which fields the download writes, in order. Defaults to every field.","details":[],"examples":[]},{"name":"references","optional":true,"type":"ChartReference[]","bindable":false,"doc":"Lines and bands at fixed values — targets, thresholds, windows.","details":[],"examples":[]},{"name":"annotations","optional":true,"type":"ChartAnnotation[]","bindable":false,"doc":"Notes pinned to a point.","details":[],"examples":[]},{"name":"brush","optional":true,"type":"ChartBrush","bindable":false,"doc":"Drag across the plot to select a range, and zoom the chart to it.","details":[],"examples":[]},{"name":"zoom","optional":true,"type":"ChartZoom","bindable":false,"doc":"Wheel or pinch to zoom, drag to pan.","details":[],"examples":[]}]},{"name":"CommandPalette","dir":"command-palette","entry":"omaris","importPath":"import { CommandPalette } from 'omaris'","summary":"⌘K — a search field over every action in the app, opened from anywhere.","details":["Built on `Dialog`, so it gets the focus trap, the inert page behind and Escape for free, and on a phone it is the same bottom sheet every dialog becomes there — stretched to full height, with the field at the top where the thumb and the keyboard both expect it.","Matching is fuzzy, and ranked the way people type: `gs` finds \"Go to settings\", `nwis` finds \"New issue\", and the characters that matched are drawn in the accent colour. Results keep their groups, best group first.","An item with `children` is a page: selecting it opens those as a new list with its name as a chip in the field, Backspace on an empty field goes back, and a search from the top level reaches into every page at once.","The field is a real combobox over a real listbox: ↑ and ↓ move (and wrap), Enter runs, `aria-activedescendant` keeps a screen reader on the active row, and the active row scrolls itself into view. The global hotkey (`mod+k` by default) is listened for only while the palette is mounted."],"examples":[{"lang":"svelte","code":"<CommandPalette\n  bind:open\n  items={[\n    { heading: 'Go to', items: [{ id: 'inbox', label: 'Inbox', href: '/inbox', shortcut: 'mod+i' }] },\n    { heading: 'Actions', items: [{ id: 'new', label: 'New issue', shortcut: 'c', onselect: create }] }\n  ]}\n/>"}],"classesType":"CommandPaletteClasses","parts":[{"name":"root","doc":"The `Dialog` itself."},{"name":"body","doc":"The dialog's body — what the palette's height is measured from."},{"name":"header","doc":"The search row: icon or back button, page chips, field."},{"name":"searchIcon","doc":"The magnifier at the start of the field."},{"name":"back","doc":"The back button, in the magnifier's place on a nested page."},{"name":"crumbs","doc":"The chips naming each page opened on the way here."},{"name":"crumb","doc":"One page chip — a `Chip`, so this lands on its root."},{"name":"input","doc":""},{"name":"clear","doc":"The × that empties the field."},{"name":"progress","doc":"The line under the field while `loading`."},{"name":"list","doc":"The scrolling listbox."},{"name":"page","doc":"The results of one page, faded in as the page changes."},{"name":"group","doc":"One group of results."},{"name":"heading","doc":""},{"name":"option","doc":""},{"name":"icon","doc":"The icon well at the start of a row."},{"name":"text","doc":"Label and description, stacked."},{"name":"label","doc":""},{"name":"path","doc":"\"Theme ›\" before a result found inside a page."},{"name":"description","doc":""},{"name":"highlight","doc":"The characters that matched the query."},{"name":"shortcut","doc":"The row's shortcut — hidden on touch, where there is no keyboard."},{"name":"chevron","doc":"The › on a row that opens a page."},{"name":"empty","doc":""},{"name":"footer","doc":"The key hints along the bottom. Hidden on touch."},{"name":"hint","doc":""}],"variants":[],"story":{"title":"Navigation/Command Palette","category":"Navigation","own":true,"stories":["Playground","Nested pages","Recent","Server search","Custom empty","Right to left","Overridden"]},"props":[{"name":"open","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Bindable.","details":[],"examples":[]},{"name":"items","optional":false,"type":"CommandGroup[]","bindable":false,"doc":"The rows, in groups.","details":[],"examples":[]},{"name":"query","optional":true,"type":"string","default":"''","bindable":true,"doc":"What is typed in the field. Bindable, for searching a server as it changes.","details":[],"examples":[]},{"name":"placeholder","optional":true,"type":"string","default":"'Type a command or search…'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"hotkey","optional":true,"type":"string | string[] | false","default":"'mod+k'","bindable":false,"doc":"The shortcut that toggles it from anywhere on the page — `'mod+k'` is ⌘K on a Mac and Ctrl+K elsewhere. `false` for none. Listened for only while the palette is mounted.","details":[],"examples":[]},{"name":"recent","optional":true,"type":"number","default":"5","bindable":false,"doc":"How many recently chosen rows to remember and show first. Needs `recentKey`.","details":[],"examples":[]},{"name":"recentKey","optional":true,"type":"string","bindable":false,"doc":"localStorage key the recent rows are kept under. Without one, nothing is remembered.","details":[],"examples":[]},{"name":"recentHeading","optional":true,"type":"string","default":"'Recent'","bindable":false,"doc":"Heading over the recent rows.","details":[],"examples":[]},{"name":"loading","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Draw a progress line under the field — for results that are on their way.","details":[],"examples":[]},{"name":"empty","optional":true,"type":"Snippet<[string]>","bindable":false,"doc":"Drawn when nothing matches. Handed the query.","details":[],"examples":[]},{"name":"filter","optional":true,"type":"CommandFilter | false","bindable":false,"doc":"Replace the fuzzy ranking. `false` shows `items` exactly as given, for a list a server has already filtered.","details":[],"examples":[]},{"name":"limit","optional":true,"type":"number","default":"100","bindable":false,"doc":"Most results shown for a query. The best ones, by score.","details":[],"examples":[]},{"name":"onselect","optional":true,"type":"(item: CommandItem) => void","bindable":false,"doc":"Called with every row chosen, after the row's own `onselect`.","details":[],"examples":[]},{"name":"closeOnSelect","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Close once a row has been chosen. On by default.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","default":"'Command palette'","bindable":false,"doc":"Accessible name of the dialog.","details":[],"examples":[]},{"name":"backLabel","optional":true,"type":"string","default":"'Back'","bindable":false,"doc":"Accessible name of the back button on a nested page.","details":[],"examples":[]},{"name":"clearLabel","optional":true,"type":"string","default":"'Clear'","bindable":false,"doc":"Accessible name of the button that empties the field.","details":[],"examples":[]},{"name":"hints","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"The key hints along the bottom. Hidden on touch either way.","details":[],"examples":[]},{"name":"footer","optional":true,"type":"Snippet","bindable":false,"doc":"Replaces the key hints — in another language, say. Hidden on touch too.","details":[],"examples":[]},{"name":"mobileQuery","optional":true,"type":"string","default":"'(max-width: 639px)'","bindable":false,"doc":"What counts as a phone — below it the palette is a full-height sheet.","details":[],"examples":[]},{"name":"onclose","optional":true,"type":"() => void","bindable":false,"doc":"Called after it has finished closing.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"CommandPaletteClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the dialog.","details":[],"examples":[]}]},{"name":"ContextMenu","dir":"context-menu","entry":"omaris","importPath":"import { ContextMenu } from 'omaris'","summary":"The right-click menu.","details":["Wraps a region and opens a `Menu` at the pointer when it is right-clicked — or long-pressed, which is the same gesture on a touch screen and the reason a context menu is not a desktop-only idea. The rows are the same `MenuItem`, `MenuLabel` and `Divider` a `Menu` takes, and choosing one closes the menu.","It is always a shortcut, never the only way to do something: every action in here must also be reachable from a button, a menu or the keyboard."],"examples":[{"lang":"svelte","code":"<ContextMenu>\n  {#snippet trigger()}\n    <Card>Right-click me</Card>\n  {/snippet}\n  <MenuItem onclick={rename}>Rename</MenuItem>\n  <MenuItem tone=\"destructive\" onclick={remove}>Delete</MenuItem>\n</ContextMenu>"}],"classesType":"MenuClasses","parts":[{"name":"surface","doc":""},{"name":"trigger","doc":"The wrapper around whatever opens the menu — `w-full`, usually."}],"variants":[],"story":{"title":"Containment/Context Menu","category":"Containment","own":true,"stories":["Playground","A full menu","Per row","Sizes","Disabled","Overridden"]},"props":[{"name":"open","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Bindable.","details":[],"examples":[]},{"name":"size","optional":true,"type":"MenuSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Never opens, and the browser's own menu comes back.","details":[],"examples":[]},{"name":"longPress","optional":true,"type":"number","default":"500","bindable":false,"doc":"How long a touch has to be held before the menu opens, in ms. `0` turns the gesture off and leaves right-click as the only way in.","details":[],"examples":[]},{"name":"closeOnSelect","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Leave the menu open after a row is chosen — for a set of toggles.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible name for the menu.","details":[],"examples":[]},{"name":"mobileSheet","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"On a phone, rise from the bottom edge as a sheet — dragged down to dismiss, rows a thumb can hit — rather than opening under a finger that is covering it. `false` keeps it at the press point.","details":[],"examples":[]},{"name":"trigger","optional":true,"type":"Snippet","bindable":false,"doc":"The region that answers the right-click.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"The rows — `MenuItem`, `MenuLabel`, `Divider`.","details":[],"examples":[]},{"name":"onopen","optional":true,"type":"(position: { x: number; y: number }) => void","bindable":false,"doc":"Fires with the coordinates the menu opened at.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"MenuClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` covers the wrapper.","details":[],"examples":[]}]},{"name":"ContributionGraph","dir":"contribution-graph","entry":"omaris","importPath":"import { ContributionGraph } from 'omaris'","summary":"The activity calendar: one square per day, a year across.","details":["It is the clearest way to show *when* something happened over a long stretch — commits, workouts, shifts, deliveries, sales. A chart shows the shape of a trend; this shows the habit, the gaps and the streaks, and it does it in a block small enough to sit at the top of a page.","On a narrow screen there are two honest answers and it takes both: `fit=\"trim\"` drops the oldest weeks until the rest fit the container exactly, and `fit=\"scroll\"` keeps the year and scrolls it, opening at the most recent week."],"examples":[{"lang":"svelte","code":"<ContributionGraph data={days} tone=\"success\" fit=\"trim\" stats />"}],"classesType":"ContributionGraphClasses","parts":[{"name":"root","doc":"The tooltip hangs off this, so it is the positioned ancestor."},{"name":"header","doc":"The title row above the grid."},{"name":"title","doc":"\"1,248 contributions in the last year\"."},{"name":"stats","doc":"The three figures under `stats`."},{"name":"board","doc":"The weekday column and the scroller, side by side."},{"name":"scroller","doc":"The scroller the grid lives in — the weekday names stay outside it, so they are still there once it has been scrolled. The padding is room for a focus ring on an edge square; the negative margins hand that room back to the layout."},{"name":"frame","doc":"The month names and the grid, stacked."},{"name":"weekdays","doc":"The column of weekday names, aligned with the grid's rows."},{"name":"months","doc":"The row of month names."},{"name":"grid","doc":"The squares."},{"name":"cell","doc":"One square — the shape and the colour, with no interaction in it."},{"name":"legend","doc":"\"Less ▢▢▢▢▢ More\"."},{"name":"tooltip","doc":"The floating label. Positioned against the root, so nothing clips it."}],"variants":[{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]}],"story":{"title":"Data Display/Contribution Graph","category":"Data Display","own":true,"stories":["Playground","A year","Narrow","Tones","Sizes","Selectable","Bare","Overridden"]},"props":[{"name":"data","optional":true,"type":"ActivityDay[]","default":"[]","bindable":false,"doc":"One entry per day that has anything. Missing days are empty ones.","details":[],"examples":[]},{"name":"to","optional":true,"type":"Date","bindable":false,"doc":"Last day on the grid. Defaults to today.","details":[],"examples":[]},{"name":"from","optional":true,"type":"Date","bindable":false,"doc":"First day. Defaults to `weeks` back from `to`.","details":[],"examples":[]},{"name":"weeks","optional":true,"type":"number","default":"53","bindable":false,"doc":"How far back to go when there is no `from`.","details":[],"examples":[]},{"name":"fit","optional":true,"type":"ContributionFit","default":"'scroll'","bindable":false,"doc":"What happens when the grid is wider than its container.","details":[],"examples":[]},{"name":"size","optional":true,"type":"ContributionGraphSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"tone","optional":true,"type":"Tone","default":"'primary'","bindable":false,"doc":"The colour the levels are mixed from.","details":[],"examples":[]},{"name":"weekStart","optional":true,"type":"0 | 1 | 2 | 3 | 4 | 5 | 6","default":"0","bindable":false,"doc":"Day the week starts on — 0 Sunday, 1 Monday.","details":[],"examples":[]},{"name":"thresholds","optional":true,"type":"[number, number, number, number]","bindable":false,"doc":"Counts at which each level starts, ascending, four of them. Left out, they are the quartiles of the data — so a graph of a busy year and one of a quiet year are both readable.","details":[],"examples":[]},{"name":"months","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Draw the month names above the grid.","details":[],"examples":[]},{"name":"weekdays","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Draw the weekday names beside it.","details":[],"examples":[]},{"name":"legend","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Draw the Less–More key under it.","details":[],"examples":[]},{"name":"stats","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Show the total, the longest run and the current one.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"Replaces the built-in \"N contributions in …\" title.","details":[],"examples":[]},{"name":"unit","optional":true,"type":"string","default":"'contribution'","bindable":false,"doc":"The noun in the title and every tooltip — \"commit\", \"workout\".","details":[],"examples":[]},{"name":"locale","optional":true,"type":"string","bindable":false,"doc":"BCP-47 tag for the month, weekday and date names.","details":[],"examples":[]},{"name":"onselect","optional":true,"type":"(day: ActivityCell) => void","bindable":false,"doc":"Fires when a day is clicked or activated from the keyboard.","details":[],"examples":[]},{"name":"day","optional":true,"type":"Snippet<[ActivityCell]>","bindable":false,"doc":"Replaces a square. Gets the day and its level.","details":[],"examples":[]},{"name":"header","optional":true,"type":"Snippet<[{ total: number; days: number }]>","bindable":false,"doc":"Replaces the header row.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"ContributionGraphClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"DataList","dir":"data-list","entry":"omaris","importPath":"import { DataList } from 'omaris'","summary":"Key/value details — an order's number, status and total; a profile's email, role and join date — as a real `<dl>`, so a screen reader reads each label with its value rather than as two unrelated runs of text.","details":["`horizontal` puts the labels in a column beside their values, and stacks them on its own once the list itself is narrower than 24rem. That is a container query, not a screen one, so the same list reads right in a wide page, a side panel and a phone without being told which it is in."],"examples":[{"lang":"svelte","code":"<DataList dividers>\n  <DataListItem label=\"Order\" value=\"#4021\" copyable />\n  <DataListItem label=\"Status\"><Badge tone=\"success\">Paid</Badge></DataListItem>\n</DataList>"}],"classesType":null,"parts":[],"variants":[{"name":"dividers","doc":"","values":[{"name":"true","doc":""}]}],"story":{"title":"Data Display/Data List","category":"Data Display","own":true,"stories":["Playground","Stacks when narrow","Vertical","Receipt","Sizes","Overridden"]},"props":[{"name":"orientation","optional":true,"type":"DataListOrientation","default":"'horizontal'","bindable":false,"doc":"`horizontal` puts each label in a column beside its value, and stacks them once the list is narrower than 24rem. `vertical` always stacks.","details":[],"examples":[]},{"name":"size","optional":true,"type":"DataListSize","default":"'md'","bindable":false,"doc":"Text size and row padding together.","details":[],"examples":[]},{"name":"dividers","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"A hairline between rows.","details":[],"examples":[]},{"name":"align","optional":true,"type":"DataListAlign","default":"'start'","bindable":false,"doc":"Where values sit in a horizontal list. `end` is the receipt layout — a total at the far edge, lined up with the numbers above it.","details":[],"examples":[]},{"name":"labelWidth","optional":true,"type":"number | string","bindable":false,"doc":"Width of the label column in a horizontal list: pixels, or any CSS length. Defaults to 40% of the list, up to 12rem.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"DataListItem","dir":"data-list","entry":"omaris","importPath":"import { DataListItem } from 'omaris'","summary":"One row of a `DataList`: a `<dt>` and its `<dd>`, grouped in a `<div>` the way the HTML spec allows, so each row can be styled as one.","details":["`copyable` adds a copy button after the value — an order number, an API key, an IBAN. The confirmation is the button itself turning into a tick, right where the finger is; there is no toast to say what the tick said."],"examples":[],"classesType":"DataListItemClasses","parts":[{"name":"root","doc":""},{"name":"label","doc":"The `<dt>`."},{"name":"value","doc":"The `<dd>`: the value and, if there is one, the copy button."},{"name":"content","doc":"The value itself, which wraps rather than pushing the row wider."},{"name":"copy","doc":"The copy button."}],"variants":[{"name":"orientation","doc":"","default":"horizontal","values":[{"name":"horizontal","doc":""},{"name":"vertical","doc":""}]},{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]},{"name":"align","doc":"","default":"start","values":[{"name":"start","doc":""},{"name":"end","doc":""}]}],"story":{"title":"Data Display/Data List","category":"Data Display","own":false,"stories":["Playground","Stacks when narrow","Vertical","Receipt","Sizes","Overridden"]},"props":[{"name":"label","optional":false,"type":"string","bindable":false,"doc":"The term — \"Order\", \"Email\", \"Joined\".","details":[],"examples":[]},{"name":"value","optional":true,"type":"string | number | null","bindable":false,"doc":"The value, as text. Use children for anything richer — a badge, a link, an avatar. With neither, the row shows a dash and tells a screen reader the value is not set.","details":[],"examples":[]},{"name":"copyable","optional":true,"type":"boolean | string","default":"false","bindable":false,"doc":"Add a copy button after the value. `true` copies what is shown — the `value`, or the text of the children; a string copies that instead, for a value displayed differently from how it is pasted (a masked key, a formatted IBAN).","details":[],"examples":[]},{"name":"copyLabel","optional":true,"type":"string","bindable":false,"doc":"Accessible name of the copy button. Defaults to \"Copy {label}\".","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"DataListItemClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"icon","optional":true,"type":"Snippet","bindable":false,"doc":"An icon before the label.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Rich value, in place of `value`.","details":[],"examples":[]}]},{"name":"DateField","dir":"date-field","entry":"omaris","importPath":"import { DateField } from 'omaris'","summary":"A date input: a field that shows the date in the page's language and opens a `Calendar` to change it — anchored under the field on a desktop, in a bottom sheet on a phone, where a popover would be a thumb's width from the edge.","details":["It looks and behaves like `Input` — the same variants, sizes, label, supporting text and invalid state — so a form reads as one thing. The value is a `Date` at local midnight, or `null`; with a `name` it is also posted as `YYYY-MM-DD`.","Keyboard: Enter, Space or ↓ opens the calendar with focus on the date, the arrows walk it, Enter picks and closes, Escape closes without picking. Backspace on the field clears it."],"examples":[{"lang":"svelte","code":"<DateField label=\"Due\" bind:value={due} min={new Date()} />"}],"classesType":"DateFieldClasses","parts":[{"name":"root","doc":"Wrapper: label, field, supporting text."},{"name":"field","doc":"The frame: border, background, height."},{"name":"control","doc":"The button that opens the calendar: the whole frame, minus the clear button."},{"name":"value","doc":"The formatted date, or the placeholder."},{"name":"placeholder","doc":"Added to `value` while there is no date."},{"name":"icon","doc":"The calendar glyph at the end."},{"name":"action","doc":"The clear button."},{"name":"label","doc":"The label above the frame."},{"name":"support","doc":"The helper or error line under the frame."},{"name":"panel","doc":"The popover the calendar opens in, on a desktop."},{"name":"sheet","doc":"The bottom sheet it opens in, on a phone."}],"variants":[{"name":"variant","doc":"","default":"outline","values":[{"name":"outline","doc":"The default: a hairline frame on the page background."},{"name":"filled","doc":"Softer — a tinted well with no border until you touch it."},{"name":"ghost","doc":"No frame at all, for fields nested in another surface."}]},{"name":"size","doc":"","default":"default","values":[{"name":"sm","doc":""},{"name":"default","doc":""},{"name":"lg","doc":""}]},{"name":"invalid","doc":"","default":"false","values":[{"name":"true","doc":""}]}],"story":{"title":"Inputs/Date Field","category":"Inputs","own":true,"stories":["Playground","Variants","Sizes","States","Right to left","Overridden"]},"props":[{"name":"value","optional":true,"type":"Date | null","default":"null","bindable":true,"doc":"The date, at local midnight, or `null`. Bindable.","details":[],"examples":[]},{"name":"variant","optional":true,"type":"DateFieldVariant","default":"'outline'","bindable":false,"doc":"`outline`, `filled` or `ghost` — the same frames as `Input`.","details":[],"examples":[]},{"name":"size","optional":true,"type":"DateFieldSize","default":"'default'","bindable":false,"doc":"`sm`, `default` or `lg` — the same heights as `Input`.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Label above the field.","details":[],"examples":[]},{"name":"required","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Marks the label required.","details":[],"examples":[]},{"name":"supportingText","optional":true,"type":"string","bindable":false,"doc":"Helper line under the field. Turns into the error text when invalid.","details":[],"examples":[]},{"name":"invalid","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Marks the field invalid and wires up aria-invalid.","details":[],"examples":[]},{"name":"placeholder","optional":true,"type":"string","default":"'Select a date'","bindable":false,"doc":"Shown, greyed, while there is no date.","details":[],"examples":[]},{"name":"format","optional":true,"type":"Intl.DateTimeFormatOptions","default":"{ dateStyle: 'medium' }","bindable":false,"doc":"How the date reads in the field. `Intl.DateTimeFormat` options, with Western digits added — `{ dateStyle: 'long' }`, or `{ weekday: 'short', day: 'numeric', month: 'short' }`.","details":[],"examples":[]},{"name":"min","optional":true,"type":"Date","bindable":false,"doc":"Earliest selectable day.","details":[],"examples":[]},{"name":"max","optional":true,"type":"Date","bindable":false,"doc":"Latest selectable day.","details":[],"examples":[]},{"name":"isDateDisabled","optional":true,"type":"(date: Date) => boolean","bindable":false,"doc":"Days that cannot be picked.","details":[],"examples":[]},{"name":"locale","optional":true,"type":"string","bindable":false,"doc":"BCP-47 tag for the field and the calendar. Defaults to `<html lang>`.","details":[],"examples":[]},{"name":"weekStartsOn","optional":true,"type":"Weekday","bindable":false,"doc":"0 is Sunday. Defaults to the locale's first day.","details":[],"examples":[]},{"name":"clearable","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Show an × that empties the field once it has a date.","details":[],"examples":[]},{"name":"open","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Whether the calendar is open. Bindable.","details":[],"examples":[]},{"name":"mobileQuery","optional":true,"type":"string","default":"'(max-width: 639px)'","bindable":false,"doc":"What counts as a phone, where the calendar opens in a bottom sheet.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(value: Date | null) => void","bindable":false,"doc":"Fires after a pick or a clear.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"Merged onto the root wrapper.","details":[],"examples":[]},{"name":"classes","optional":true,"type":"DateFieldClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"calendarClasses","optional":true,"type":"CalendarClasses","bindable":false,"doc":"Per-part overrides for the calendar inside the popup.","details":[],"examples":[]},{"name":"ref","optional":true,"type":"HTMLButtonElement | null","default":"null","bindable":true,"doc":"The trigger button.","details":[],"examples":[]}]},{"name":"DatePicker","dir":"picker","entry":"omaris","importPath":"import { DatePicker } from 'omaris'","summary":"Three wheels — day, month, year — in the order this locale writes them.","details":["The day wheel is rebuilt from the month and the year, so February never offers a 30th and a leap year does offer the 29th. `min` and `max` grey out the rows outside the range rather than removing them, so the wheel does not change length under the finger."],"examples":[{"lang":"svelte","code":"<DatePicker bind:value={birthday} max={new Date()} monthFormat=\"short\" />"}],"classesType":"PickerClasses","parts":[{"name":"root","doc":""},{"name":"header","doc":"The title line above the wheels."},{"name":"stage","doc":"Everything the band is drawn behind: the wheels and both fades."},{"name":"band","doc":"The strip marking the centre row."},{"name":"wheels","doc":"The row of wheels. Masked so rows dissolve towards the edges."},{"name":"actions","doc":"The cancel/confirm row. Only rendered when `onconfirm` is given."},{"name":"action","doc":"One of those buttons."}],"variants":[],"story":{"title":"Inputs/Picker","category":"Inputs","own":false,"stories":["Playground","Date","Time","Date and time","Number","Custom columns","Text options","With actions","Sizes and depth","Disabled","Overridden"]},"props":[{"name":"value","optional":true,"type":"Date | null","default":"null","bindable":true,"doc":"The date. Bindable. `null` until a wheel is touched.","details":[],"examples":[]},{"name":"min","optional":true,"type":"Date","bindable":false,"doc":"Earliest selectable date. Also the first year on the wheel.","details":[],"examples":[]},{"name":"max","optional":true,"type":"Date","bindable":false,"doc":"Latest selectable date. Also the last year on the wheel.","details":[],"examples":[]},{"name":"locale","optional":true,"type":"string","bindable":false,"doc":"BCP-47 tag for the month names and the column order.","details":[],"examples":[]},{"name":"monthFormat","optional":true,"type":"'long' | 'short' | 'numeric'","default":"'long'","bindable":false,"doc":"How the months read. `numeric` for a wheel with no room for names.","details":[],"examples":[]},{"name":"weekday","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Prefix the day with its weekday — \"Wed 17\".","details":[],"examples":[]},{"name":"labels","optional":true,"type":"{ day?: string; month?: string; year?: string }","bindable":false,"doc":"Accessible names for the three wheels.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(value: Date) => void","bindable":false,"doc":"Fires once a wheel settles.","details":[],"examples":[]},{"name":"columnClasses","optional":true,"type":"PickerColumnClasses","bindable":false,"doc":"Per-part overrides for the wheels themselves.","details":[],"examples":[]},{"name":"classes","optional":true,"type":"PickerClasses","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"PickerSize","bindable":false,"doc":"Row height and type scale.","details":[],"examples":[]},{"name":"surface","optional":true,"type":"PickerSurface","bindable":false,"doc":"How the frame is drawn.","details":[],"examples":[]},{"name":"visible","optional":true,"type":"number","bindable":false,"doc":"Rows on screen at once. Rounded up to the next odd number.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"A title above the wheels.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","bindable":false,"doc":"Disables every wheel inside.","details":[],"examples":[]},{"name":"haptics","optional":true,"type":"boolean","bindable":false,"doc":"Play a tick as each row passes the centre, once haptics are on.","details":[],"examples":[]},{"name":"onconfirm","optional":true,"type":"() => void","bindable":false,"doc":"Renders the action row. Called with the value already committed.","details":[],"examples":[]},{"name":"oncancel","optional":true,"type":"() => void","bindable":false,"doc":"Renders a cancel button beside it.","details":[],"examples":[]},{"name":"confirmLabel","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"cancelLabel","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"footer","optional":true,"type":"Snippet","bindable":false,"doc":"Replaces the built-in action row.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"DateRangeField","dir":"date-range-field","entry":"omaris","importPath":"import { DateRangeField } from 'omaris'","summary":"A date-range input for a dashboard's filter bar: a field that reads \"Mar 3 – 9, 2026\" and opens two months side by side with a rail of shortcuts — Today, Last 7 days, This month — beside them.","details":["On a desktop the second press on the calendar commits the range and closes, and a shortcut commits at once. On a phone it is a bottom sheet with one month and a row of shortcut chips, and nothing changes until Apply — a thumb that lands on the wrong day costs nothing.","The value is `{ start, end }` at local midnight, both ends inclusive, or `null`. With a `name` it posts as an ISO interval, `2026-03-03/2026-03-09`."],"examples":[{"lang":"svelte","code":"<DateRangeField label=\"Period\" bind:value={period} max={new Date()} />"}],"classesType":"DateRangeFieldClasses","parts":[{"name":"body","doc":"Presets and calendar together, inside the popup."},{"name":"presets","doc":"The shortcut rail: a column at the start on a wide screen, a scrolling row otherwise."},{"name":"preset","doc":"One shortcut."},{"name":"footer","doc":"Cancel and Apply, pinned under the sheet on a phone."},{"name":"root","doc":"Wrapper: label, field, supporting text."},{"name":"field","doc":"The frame: border, background, height."},{"name":"control","doc":"The button that opens the calendar: the whole frame, minus the clear button."},{"name":"value","doc":"The formatted date, or the placeholder."},{"name":"placeholder","doc":"Added to `value` while there is no date."},{"name":"icon","doc":"The calendar glyph at the end."},{"name":"action","doc":"The clear button."},{"name":"label","doc":"The label above the frame."},{"name":"support","doc":"The helper or error line under the frame."},{"name":"panel","doc":"The popover the calendar opens in, on a desktop."},{"name":"sheet","doc":"The bottom sheet it opens in, on a phone."}],"variants":[{"name":"compact","doc":"The phone's sheet: presets become an edge-to-edge row of chips.","values":[{"name":"true","doc":""}]}],"story":{"title":"Inputs/Date Range Field","category":"Inputs","own":true,"stories":["Playground","Bounds and presets","States","Right to left","Overridden"]},"props":[{"name":"value","optional":true,"type":"DateRange | null","default":"null","bindable":true,"doc":"The range, or `null`. Bindable.","details":[],"examples":[]},{"name":"variant","optional":true,"type":"DateFieldVariant","default":"'outline'","bindable":false,"doc":"`outline`, `filled` or `ghost` — the same frames as `Input`.","details":[],"examples":[]},{"name":"size","optional":true,"type":"DateFieldSize","default":"'default'","bindable":false,"doc":"`sm`, `default` or `lg` — the same heights as `Input`.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Label above the field.","details":[],"examples":[]},{"name":"required","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Marks the label required.","details":[],"examples":[]},{"name":"supportingText","optional":true,"type":"string","bindable":false,"doc":"Helper line under the field. Turns into the error text when invalid.","details":[],"examples":[]},{"name":"invalid","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Marks the field invalid and wires up aria-invalid.","details":[],"examples":[]},{"name":"placeholder","optional":true,"type":"string","default":"'Select a range'","bindable":false,"doc":"Shown, greyed, while there is no range.","details":[],"examples":[]},{"name":"format","optional":true,"type":"Intl.DateTimeFormatOptions","default":"{ dateStyle: 'medium' }","bindable":false,"doc":"`Intl.DateTimeFormat` options for the two ends, joined by `formatRange`.","details":[],"examples":[]},{"name":"presets","optional":true,"type":"DatePreset[]","default":"defaultDatePresets","bindable":false,"doc":"Shortcuts beside the calendar — Today through This year unless you pass your own, or `[]` for none. Each is clamped to `min` and `max` when chosen, and one that falls wholly outside them is disabled.","details":[],"examples":[]},{"name":"months","optional":true,"type":"1 | 2","default":"2","bindable":false,"doc":"Months side by side on a desktop. A phone always gets one.","details":[],"examples":[]},{"name":"min","optional":true,"type":"Date","bindable":false,"doc":"Earliest selectable day.","details":[],"examples":[]},{"name":"max","optional":true,"type":"Date","bindable":false,"doc":"Latest selectable day — `today` for a filter over data that ends now.","details":[],"examples":[]},{"name":"isDateDisabled","optional":true,"type":"(date: Date) => boolean","bindable":false,"doc":"Days that cannot be picked.","details":[],"examples":[]},{"name":"locale","optional":true,"type":"string","bindable":false,"doc":"BCP-47 tag for the field and the calendar. Defaults to `<html lang>`.","details":[],"examples":[]},{"name":"weekStartsOn","optional":true,"type":"Weekday","bindable":false,"doc":"0 is Sunday. Defaults to the locale's first day.","details":[],"examples":[]},{"name":"clearable","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Show an × that empties the field once it has a range.","details":[],"examples":[]},{"name":"open","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Whether the calendar is open. Bindable.","details":[],"examples":[]},{"name":"mobileQuery","optional":true,"type":"string","default":"'(max-width: 639px)'","bindable":false,"doc":"What counts as a phone, where the calendar opens in a bottom sheet.","details":[],"examples":[]},{"name":"labels","optional":true,"type":"DateRangeFieldLabels","bindable":false,"doc":"The words the field says itself — the presets group's name, Apply, Cancel.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(value: DateRange | null) => void","bindable":false,"doc":"Fires when a range is committed or cleared.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"Merged onto the root wrapper.","details":[],"examples":[]},{"name":"classes","optional":true,"type":"DateRangeFieldClasses","bindable":false,"doc":"Per-part Tailwind overrides — the frame's parts and the presets'.","details":[],"examples":[]},{"name":"calendarClasses","optional":true,"type":"CalendarClasses","bindable":false,"doc":"Per-part overrides for the calendar inside the popup.","details":[],"examples":[]},{"name":"ref","optional":true,"type":"HTMLButtonElement | null","default":"null","bindable":true,"doc":"The trigger button.","details":[],"examples":[]}]},{"name":"DateTimePicker","dir":"picker","entry":"omaris","importPath":"import { DateTimePicker } from 'omaris'","summary":"A day, an hour and a minute in one row of wheels.","details":["The day is one wheel of whole dates — \"Today\", \"Tomorrow\", \"Wed 17 Sep\" — rather than three of day, month and year. It is the shape a datetime actually gets picked in: a booking is next Tuesday at half four, not the 17th and September and 2026.","The range is a year forward from today unless you say otherwise, so a picker for something in the past needs a `min`."],"examples":[{"lang":"svelte","code":"<DateTimePicker bind:value={startsAt} minuteStep={15} />"}],"classesType":"PickerClasses","parts":[{"name":"root","doc":""},{"name":"header","doc":"The title line above the wheels."},{"name":"stage","doc":"Everything the band is drawn behind: the wheels and both fades."},{"name":"band","doc":"The strip marking the centre row."},{"name":"wheels","doc":"The row of wheels. Masked so rows dissolve towards the edges."},{"name":"actions","doc":"The cancel/confirm row. Only rendered when `onconfirm` is given."},{"name":"action","doc":"One of those buttons."}],"variants":[],"story":{"title":"Inputs/Picker","category":"Inputs","own":false,"stories":["Playground","Date","Time","Date and time","Number","Custom columns","Text options","With actions","Sizes and depth","Disabled","Overridden"]},"props":[{"name":"value","optional":true,"type":"Date | null","default":"null","bindable":true,"doc":"The moment. Bindable.","details":[],"examples":[]},{"name":"min","optional":true,"type":"Date","bindable":false,"doc":"First selectable day. Defaults to today.","details":[],"examples":[]},{"name":"max","optional":true,"type":"Date","bindable":false,"doc":"Last selectable day. Defaults to a year from today.","details":[],"examples":[]},{"name":"minuteStep","optional":true,"type":"number","default":"5","bindable":false,"doc":"Minutes between rows.","details":[],"examples":[]},{"name":"locale","optional":true,"type":"string","bindable":false,"doc":"BCP-47 tag for the day labels.","details":[],"examples":[]},{"name":"relative","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Say \"Today\" and \"Tomorrow\" instead of their dates.","details":[],"examples":[]},{"name":"labels","optional":true,"type":"{ day?: string; hour?: string; minute?: string; meridiem?: string; am?: string; pm?: string; }","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(value: Date) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"columnClasses","optional":true,"type":"PickerColumnClasses","bindable":false,"doc":"Per-part overrides for the wheels themselves.","details":[],"examples":[]},{"name":"classes","optional":true,"type":"PickerClasses","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"PickerSize","bindable":false,"doc":"Row height and type scale.","details":[],"examples":[]},{"name":"surface","optional":true,"type":"PickerSurface","bindable":false,"doc":"How the frame is drawn.","details":[],"examples":[]},{"name":"visible","optional":true,"type":"number","bindable":false,"doc":"Rows on screen at once. Rounded up to the next odd number.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"A title above the wheels.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","bindable":false,"doc":"Disables every wheel inside.","details":[],"examples":[]},{"name":"haptics","optional":true,"type":"boolean","bindable":false,"doc":"Play a tick as each row passes the centre, once haptics are on.","details":[],"examples":[]},{"name":"onconfirm","optional":true,"type":"() => void","bindable":false,"doc":"Renders the action row. Called with the value already committed.","details":[],"examples":[]},{"name":"oncancel","optional":true,"type":"() => void","bindable":false,"doc":"Renders a cancel button beside it.","details":[],"examples":[]},{"name":"confirmLabel","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"cancelLabel","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"footer","optional":true,"type":"Snippet","bindable":false,"doc":"Replaces the built-in action row.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"DeviceMockup","dir":"device-mockup","entry":"omaris","importPath":"import { DeviceMockup } from 'omaris'","summary":"A device drawn around whatever you put on its screen.","details":["Six frames — `phone`, `android`, `tablet`, `laptop`, `browser` and `watch` — in five finishes, the handhelds in either orientation. The screen holds your own markup, a screenshot (`image`) or a live site (`src`).","**The screen is the device's real viewport.** The phone's glass is 390 CSS px wide, the tablet's 834, the laptop's 1440 — content is laid out at that size and the whole drawing is then scaled as one picture. A snippet wraps as it would on the hardware and a site in the iframe gets its mobile layout, however small the mockup is drawn.","**It sizes itself.** Each device has a width it looks right at, and it never grows wider than its container. `width` changes the first; a `max-w-*` or `w-*` class works too.","**Content stays clear of the hardware.** The status bar, the island and the home indicator are drawn over the glass, and the content box sits between them, scrolling when it is taller. Give the glass a colour with `classes={{ screen: '…' }}` and it runs edge to edge behind them."],"examples":[{"lang":"svelte","code":"<DeviceMockup device=\"phone\">\n  <MyScreen />\n</DeviceMockup>\n\n<DeviceMockup device=\"browser\" src=\"https://example.com\" label=\"Example\" />"}],"classesType":"DeviceMockupClasses","parts":[{"name":"root","doc":"The box the drawing takes up on the page."},{"name":"frame","doc":"The body: the metal rail and the bezel inside it, or a window."},{"name":"screen","doc":"The glass. Everything on it is clipped to its corners."},{"name":"content","doc":"The box your content is laid out in — clear of the hardware, scrolling."},{"name":"status","doc":"The clock and the signal, wi-fi and battery glyphs across the top."},{"name":"cutout","doc":"The island or the punch-hole."},{"name":"button","doc":"A physical key, standing proud of the rail."},{"name":"stand","doc":"The laptop's base, the watch's straps."},{"name":"chrome","doc":"The browser window's title bar."}],"variants":[{"name":"finish","doc":"The material the body is made of.","default":"graphite","values":[{"name":"graphite","doc":""},{"name":"silver","doc":""},{"name":"gold","doc":""},{"name":"sky","doc":""},{"name":"porcelain","doc":""}]},{"name":"window","doc":"A window is drawn in the theme's surfaces rather than in metal.","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Containment/Device Mockup","category":"Containment","own":true,"stories":["Playground","Every device","Finishes","Landscape","Screenshot","A website in a browser window","Overridden"]},"props":[{"name":"device","optional":true,"type":"DeviceId","default":"'phone'","bindable":false,"doc":"Which frame to draw.","details":[],"examples":[]},{"name":"orientation","optional":true,"type":"DeviceOrientation","default":"'portrait'","bindable":false,"doc":"Turned sideways. The laptop, the browser and the watch ignore it.","details":[],"examples":[]},{"name":"finish","optional":true,"type":"DeviceFinish","default":"'graphite'","bindable":false,"doc":"The body's colour. The browser window follows the theme instead.","details":[],"examples":[]},{"name":"width","optional":true,"type":"number | string","bindable":false,"doc":"How wide to draw it — px, or any CSS length. It still never grows past its container. Defaults to a width that suits the device.","details":[],"examples":[]},{"name":"image","optional":true,"type":"string","bindable":false,"doc":"A screenshot to fill the screen with, edge to edge.","details":[],"examples":[]},{"name":"src","optional":true,"type":"string","bindable":false,"doc":"A site to load on the screen, at the device's own viewport.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible name: the iframe's title, the image's alt text.","details":[],"examples":[]},{"name":"sandbox","optional":true,"type":"string","bindable":false,"doc":"`sandbox` for the iframe. Set it for a site you do not control.","details":[],"examples":[]},{"name":"allow","optional":true,"type":"string","bindable":false,"doc":"`allow` for the iframe — clipboard, camera, fullscreen.","details":[],"examples":[]},{"name":"url","optional":true,"type":"string","bindable":false,"doc":"What the browser window's address bar reads. Defaults to `src`'s host.","details":[],"examples":[]},{"name":"statusBar","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"The clock and battery across the top of a phone, tablet or watch.","details":[],"examples":[]},{"name":"safeArea","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Keep content clear of the status bar, the island and the home indicator. Off, it runs under them — for a wallpaper or a full-bleed picture. An `image` is always full bleed.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"DeviceMockupClasses","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet<[DeviceScreenContext]>","bindable":false,"doc":"What goes on the screen. Takes the screen's size, if it wants it.","details":[],"examples":[]}]},{"name":"Dialog","dir":"dialog","entry":"omaris","importPath":"import { Dialog } from 'omaris'","summary":"MD3 dialog, on the native `<dialog>` element.","details":["`showModal()` brings the focus trap, the inert background, the top layer and Escape-to-close for free — all the parts a hand-rolled modal gets subtly wrong. What's added on top is the MD3 look, an exit animation (native `close()` is instant, so the close is deferred until the animation has run), and the icon/headline/supporting-text layout.","Three things make it feel finished rather than merely correct:","- **It resizes smoothly.** The panel's height is driven from the measured body, so swapping a step, revealing an error or loading a list grows the dialog with an emphasized curve instead of jumping. Width follows `size` the same way. - **It closes itself.** A close button sits at the top end corner — out of the headline's way, and mirrored under `dir=\"rtl\"` — unless the dialog is explicitly undismissable. - **It is a bottom sheet on a phone.** Below `mobileQuery` the same dialog anchors to the bottom edge, grows a drag handle and can be thrown away with a flick — the shape a modal is supposed to take on a touch screen."],"examples":[],"classesType":"DialogClasses","parts":[{"name":"root","doc":""},{"name":"panel","doc":"The morphing box. Its height is written from the measured body, so it is the one element that knows how tall the dialog should be — and `overflow-hidden` is what lets it lag behind the content during the transition instead of clipping nothing at all."},{"name":"body","doc":"Scroll container, and the box whose height the panel follows."},{"name":"close","doc":"Pinned to the panel, so it stays put while the body scrolls."},{"name":"handle","doc":"MD3's drag handle, and the mouse's grab point on a bottom sheet."},{"name":"grip","doc":""},{"name":"icon","doc":""},{"name":"header","doc":"Headline and supporting text, kept together as one block."},{"name":"title","doc":""},{"name":"description","doc":""},{"name":"content","doc":""},{"name":"actions","doc":""}],"variants":[{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""},{"name":"xl","doc":""},{"name":"full","doc":"Edge to edge — the MD3 full-screen dialog."}]},{"name":"centered","doc":"Centers the icon, headline and text — MD3's alert layout.","values":[{"name":"true","doc":""}]},{"name":"closable","doc":"Room for the close button at the top end corner.","values":[{"name":"true","doc":""}]},{"name":"mode","doc":"`sheet` is the same dialog re-anchored to the bottom edge for a phone: full width, one pair of rounded corners, and the sheet keyframes instead of the centered ones.","default":"dialog","values":[{"name":"dialog","doc":""},{"name":"sheet","doc":""}]}],"story":{"title":"Containment/Dialog","category":"Containment","own":true,"stories":["Playground","Alert","Form","Scrolling content","Full screen","Morphing height","Morphing width","Responsive","Right to left"]},"props":[{"name":"open","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Bindable.","details":[],"examples":[]},{"name":"size","optional":true,"type":"DialogSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"Headline.","details":[],"examples":[]},{"name":"description","optional":true,"type":"string","bindable":false,"doc":"Supporting text under the headline.","details":[],"examples":[]},{"name":"centered","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Center the icon, headline and supporting text.","details":[],"examples":[]},{"name":"dismissible","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Allow Escape and a backdrop press to close it.","details":[],"examples":[]},{"name":"closable","optional":true,"type":"boolean","bindable":false,"doc":"Close button at the top end corner. Defaults to `dismissible`.","details":[],"examples":[]},{"name":"closeLabel","optional":true,"type":"string","default":"'Close'","bindable":false,"doc":"Accessible name for that button.","details":[],"examples":[]},{"name":"responsive","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Become a bottom sheet on a phone. On by default.","details":[],"examples":[]},{"name":"mobileQuery","optional":true,"type":"string","default":"'(max-width: 639px)'","bindable":false,"doc":"What counts as a phone.","details":[],"examples":[]},{"name":"morph","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Animate height and width changes. On by default.","details":[],"examples":[]},{"name":"drag","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Drag the bottom sheet away with a finger. On by default.","details":[],"examples":[]},{"name":"onclose","optional":true,"type":"() => void","bindable":false,"doc":"Called after the dialog has finished closing.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"DialogClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"icon","optional":true,"type":"Snippet","bindable":false,"doc":"Icon above the headline.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"The body.","details":[],"examples":[]},{"name":"actions","optional":true,"type":"Snippet","bindable":false,"doc":"Buttons along the bottom.","details":[],"examples":[]}]},{"name":"DiffViewer","dir":"diff-viewer","entry":"omaris","importPath":"import { DiffViewer } from 'omaris'","summary":"A diff, unified or side by side, with the syntax colouring the rest of the library uses.","details":["Two things separate this from a red-and-green list of lines. It runs a second diff *inside* a changed pair of lines, so a renamed variable shows as one word moving rather than two whole lines replaced; and long runs of untouched code collapse to a strip you can click, because the point of a diff is what changed and 400 unchanged lines are not it.","Feed it `before` and `after` and it does the work, or hand it the `patch` that `git diff` printed and it will render that instead — identically, since both end up in the same shape."],"examples":[{"lang":"svelte","code":"<DiffViewer lang=\"ts\" {before} {after} view=\"split\" context={3} />"}],"classesType":"DiffViewerClasses","parts":[{"name":"root","doc":""},{"name":"header","doc":"Filename, stats, and the view switch."},{"name":"title","doc":""},{"name":"stats","doc":"`+12 −4`."},{"name":"added","doc":""},{"name":"removed","doc":""},{"name":"action","doc":""},{"name":"viewport","doc":"The scroll container."},{"name":"table","doc":"Everything inside the scroller, sized to the widest line."},{"name":"row","doc":"One line, or one pair of lines in split view."},{"name":"side","doc":"Half a split row."},{"name":"gutter","doc":"A line number, pinned against horizontal scroll."},{"name":"sign","doc":"The `+` / `−` column."},{"name":"code","doc":"The code itself."},{"name":"word","doc":"A run of characters added or removed inside a changed line."},{"name":"gap","doc":"The \"N unchanged lines\" strip."},{"name":"empty","doc":"Shown when the two sides are the same."}],"variants":[{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""}]},{"name":"wrap","doc":"","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Data display/DiffViewer","category":"Data Display","own":true,"stories":["Playground","Word-level detail","Side by side","Collapsed context","From a patch","No changes","Narrow and wrapped"]},"props":[{"name":"before","optional":true,"type":"string","default":"''","bindable":false,"doc":"The old text. Ignored when `patch` is given.","details":[],"examples":[]},{"name":"after","optional":true,"type":"string","default":"''","bindable":false,"doc":"The new text.","details":[],"examples":[]},{"name":"patch","optional":true,"type":"string","bindable":false,"doc":"A unified patch, as `git diff` prints it. Wins over `before`/`after`.","details":[],"examples":[]},{"name":"lang","optional":true,"type":"string","default":"'plain'","bindable":false,"doc":"`ts`, `svelte`, `css`, … — the same names `CodeBlock` takes.","details":[],"examples":[]},{"name":"view","optional":true,"type":"DiffView","default":"'unified'","bindable":true,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"DiffViewerSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"context","optional":true,"type":"number","default":"3","bindable":false,"doc":"Unchanged lines kept either side of a change. `Infinity` keeps them all.","details":[],"examples":[]},{"name":"lineNumbers","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"wrap","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"Filename in the header.","details":[],"examples":[]},{"name":"titles","optional":true,"type":"[string, string]","bindable":false,"doc":"Per-side filenames, for a rename. Falls back to `title`.","details":[],"examples":[]},{"name":"stats","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Show the `+n −n` counts.","details":[],"examples":[]},{"name":"switchable","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Offer the unified / split switch.","details":[],"examples":[]},{"name":"emptyText","optional":true,"type":"string","default":"'No changes.'","bindable":false,"doc":"Shown when nothing changed.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"'32rem'","bindable":false,"doc":"Tallest the scroller gets. A number is px, a string any CSS length.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"DiffViewerClasses","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"Divider","dir":"divider","entry":"omaris","importPath":"import { Divider } from 'omaris'","summary":"MD3 divider — a hairline that separates content without dividing the layout. `inset` indents it past a leading icon or avatar so the rule lines up with the text column of a list.","details":["With children it becomes a labelled rule, with the line drawn on both sides of the label. The two rules are `flex-1`, so they share whatever the label leaves and the divider survives a narrow container instead of pushing the label out of it."],"examples":[],"classesType":null,"parts":[],"variants":[{"name":"orientation","doc":"","default":"horizontal","values":[{"name":"horizontal","doc":""},{"name":"vertical","doc":""}]},{"name":"inset","doc":"Indents the rule to line up with a list's text column.","default":"none","values":[{"name":"none","doc":""},{"name":"start","doc":""},{"name":"both","doc":""}]},{"name":"emphasis","doc":"","default":"subtle","values":[{"name":"subtle","doc":""},{"name":"strong","doc":""}]}],"story":{"title":"Containment/Divider","category":"Containment","own":true,"stories":["Playground","Insets","Vertical","With a label","Emphasis","Constrained"]},"props":[{"name":"orientation","optional":true,"type":"DividerOrientation","default":"'horizontal'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"inset","optional":true,"type":"DividerInset","default":"'none'","bindable":false,"doc":"Indent so the rule aligns with a list's text column.","details":[],"examples":[]},{"name":"emphasis","optional":true,"type":"DividerEmphasis","default":"'subtle'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"A label sat in the middle of the rule. Horizontal only.","details":[],"examples":[]}]},{"name":"Dock","dir":"dock","entry":"omaris","importPath":"import { Dock } from 'omaris'","summary":"The macOS dock, in Material.","details":["A row of tiles that swell under the pointer — the one nearest it most, its neighbours less, the rest not at all — and shrink back the moment it leaves. Every tile is a real button or link, so it is a launcher, a toolbar, a quick-actions strip: anything a handful of icons can name.","**The motion.** Every tile's scale is a spring chasing a target set by its distance from the pointer — a cosine bump, `distance` px wide, up to `magnification` times the base `size`. The swell is drawn with transforms, never layout: the neighbours slide aside by exactly what the tiles grew, around the pointer, so the tile under it stays under it and the bar widens out of both ends. Distances are measured on the row at rest, which does not move, so there is nothing for the motion to feed back on — no flicker on a fast sweep, no drift at the ends. The bar's own height never changes; the tiles rise out of it. One frame loop writes it all, and only while something is still moving.","**A finger gets no magnification.** There is no pointer to be near on a touch screen, and a tile that grows under a thumb moves the thing the thumb is about to press. The tiles stay at `size`, which is 48px by default — a comfortable target — and the press itself is answered by the state layer and the ripple.","**A keyboard gets it.** Tab into the dock, the arrow keys move between tiles, and the tile with focus is the one that swells, label showing, so the keyboard sees exactly what the pointer sees.","**It fits.** A row of eight tiles at 48px is wider than a small phone. Rather than scroll — a dock that scrolls is a list — the tiles shrink, evenly, until the bar fits the width it has, and grow back when it has more. A row that had to shrink has no room to swell either, so it holds still. `size` is the most a tile gets, not a promise."],"examples":[{"lang":"svelte","code":"<Dock label=\"Apps\">\n  <DockItem label=\"Mail\" active onclick={openMail}>{@render mailIcon()}</DockItem>\n  <DockItem label=\"Calendar\" badge=\"3\">{@render calendarIcon()}</DockItem>\n  <DockDivider />\n  <DockItem label=\"Trash\">{@render trashIcon()}</DockItem>\n</Dock>"}],"classesType":"DockClasses","parts":[{"name":"bar","doc":"The row the tiles sit in. Its size is the dock at rest, always."},{"name":"surface","doc":"What the bar looks like: a layer behind the tiles that stretches with them as they swell, so style this, not `bar`."}],"variants":[{"name":"orientation","doc":"","default":"horizontal","values":[{"name":"horizontal","doc":""},{"name":"vertical","doc":""}]},{"name":"variant","doc":"","default":"elevated","values":[{"name":"elevated","doc":"A tonal MD3 surface with a soft edge."},{"name":"filled","doc":"The same, flatter, for a dock that sits inside a card."},{"name":"glass","doc":"Frosted glass: whatever is behind the bar blurs through it."},{"name":"plain","doc":"No bar at all: tiles on whatever is behind them."}]}],"story":{"title":"Navigation/Dock","category":"Navigation","own":true,"stories":["Playground","Vertical","Glass","Labels always","Links, no magnification","Overridden"]},"props":[{"name":"orientation","optional":true,"type":"DockOrientation","default":"'horizontal'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"variant","optional":true,"type":"DockVariant","default":"'elevated'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"number","default":"48","bindable":false,"doc":"Base tile size, in px.","details":[],"examples":[]},{"name":"magnification","optional":true,"type":"number","default":"1.7","bindable":false,"doc":"How big the tile under the pointer gets, as a multiple of `size`. `1` turns the effect off.","details":[],"examples":[]},{"name":"distance","optional":true,"type":"number","default":"130","bindable":false,"doc":"How far from the pointer a tile is still affected, in px.","details":[],"examples":[]},{"name":"labels","optional":true,"type":"DockLabels","default":"'hover'","bindable":false,"doc":"When labels show. `hover` (the default) is the tooltip above the tile under the pointer or with focus; `always` prints them under every tile; `never` keeps them for assistive tech only.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible name — \"Apps\".","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"DockClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"DockDivider","dir":"dock","entry":"omaris","importPath":"import { DockDivider } from 'omaris'","summary":"A hairline between two groups of tiles — apps on one side, the trash on the other.","details":[],"examples":[],"classesType":null,"parts":[],"variants":[{"name":"orientation","doc":"","default":"horizontal","values":[{"name":"horizontal","doc":""},{"name":"vertical","doc":""}]}],"story":{"title":"Navigation/Dock","category":"Navigation","own":false,"stories":["Playground","Vertical","Glass","Labels always","Links, no magnification","Overridden"]},"props":[{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"DockItem","dir":"dock","entry":"omaris","importPath":"import { DockItem } from 'omaris'","summary":"One tile in a `Dock`: an icon, a name, and the press.","details":["A button, or a link when it has an `href`. The name is the tooltip that rises over the tile as it swells, and the accessible name whether or not it is ever drawn. `active` puts the running-app dot under it; `badge` the count in its corner.","The tile's size and place belong to the dock: it sets the rest size as `--dock-base` and, frame by frame, the swell as `--dock-scale` and the slide aside as the root's `translate` — so style the control, not its box, and size the icon relative to it (`[&_svg]:size-1/2` is already set)."],"examples":[],"classesType":"DockItemClasses","parts":[{"name":"root","doc":"The tile's place in the row, at rest. The label hangs off it."},{"name":"tile","doc":"The tile, at the dock's base size, swollen by a transform so the row's layout never moves. Holds the control and the badge."},{"name":"control","doc":"The pressable tile itself."},{"name":"label","doc":"The name, as a tooltip or a caption."},{"name":"dot","doc":"The dot that says \"running\" — or \"current\"."},{"name":"badge","doc":"The count in the corner."}],"variants":[{"name":"orientation","doc":"","default":"horizontal","values":[{"name":"horizontal","doc":""},{"name":"vertical","doc":""}]},{"name":"labels","doc":"How the label is shown.","default":"hover","values":[{"name":"hover","doc":""},{"name":"always","doc":""},{"name":"never","doc":""}]},{"name":"active","doc":"","default":"false","values":[{"name":"true","doc":""}]}],"story":{"title":"Navigation/Dock","category":"Navigation","own":false,"stories":["Playground","Vertical","Glass","Labels always","Links, no magnification","Overridden"]},"props":[{"name":"label","optional":false,"type":"string","bindable":false,"doc":"The tile's name. Drawn as the tooltip, and read to assistive tech always.","details":[],"examples":[]},{"name":"href","optional":true,"type":"string","bindable":false,"doc":"Makes it a link.","details":[],"examples":[]},{"name":"target","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"active","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"The running dot under the tile — or \"you are here\".","details":[],"examples":[]},{"name":"badge","optional":true,"type":"string | number | boolean","bindable":false,"doc":"A count in the corner. `true` for a plain dot.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onclick","optional":true,"type":"(event: MouseEvent) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"DockItemClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"The icon. An `<svg>` is sized to half the tile, an `<img>` fills it.","details":[],"examples":[]}]},{"name":"DrawingBoard","dir":"drawing-board","entry":"omaris","importPath":"import { DrawingBoard } from 'omaris'","summary":"An infinite canvas you can actually draw on: pen, shapes, arrows, text and sticky notes, with pan, zoom, selection, undo and export.","details":["The board is a *document*, not a picture. Everything on it is a plain object in `elements` — position, paint and content — so it can be bound, stored, diffed, generated from data, and handed back to another board exactly as it was. Nothing is baked into pixels until you ask for a PNG.","Every part of the chrome is optional and every part is replaceable: `tools` picks the strip, `toolbar`, `stylePanel`, `zoomControls` and `historyControls` turn the panels off, and `children` puts your own over the canvas. With all of them off it is a viewer — `readonly` makes that official, and the pan and zoom still work.","It works on a phone without being told. Below about 30rem of board the chrome folds into one bar that scrolls sideways — palette, undo, redo, the tools, zoom, clear — and the paint panel becomes a sheet that button opens, so the drawing keeps the board instead of three floating panels. Targets grow under a coarse pointer, two fingers pan as well as zoom, and a double-tap opens text the way a double-click does.","`bind:this` gives you the rest: `undo`, `redo`, `addElement`, `insertImage`, `zoomToFit`, `toSVG`, `toBlob`, `toJSON` and `load`."],"examples":[{"lang":"svelte","code":"<DrawingBoard bind:elements onchange={save} height={520} />"}],"classesType":"DrawingBoardClasses","parts":[{"name":"root","doc":""},{"name":"canvas","doc":"The stage the drawing lives on. Everything else floats over it."},{"name":"surface","doc":"The drawing itself, in scene coordinates."},{"name":"overlay","doc":"Selection, handles and the marquee — screen coordinates, never exported."},{"name":"panel","doc":"A floating panel: the tool strip, the style bar, the clusters."},{"name":"toolbar","doc":"The tool strip. Centred by auto margins between both edges rather than from `left-1/2`, which hands an absolute box only half the board to fit in and wraps the strip long before it has to."},{"name":"style","doc":"The paint panel — colours, weight, opacity, and what to do with a selection. It is capped to the board and scrolls inside itself, so a short board gets a short panel rather than one hanging out of it."},{"name":"section","doc":"A labelled row inside the style panel."},{"name":"caption","doc":"The caption over a row of swatches."},{"name":"row","doc":"The row a set of choices sits in."},{"name":"button","doc":"One button: a tool, a swatch holder, a step, an action."},{"name":"swatch","doc":"A colour chip."},{"name":"choice","doc":"A choice that is not a colour — stroke weight, dash, fill."},{"name":"slider","doc":"The opacity slider."},{"name":"zoom","doc":"The zoom cluster, bottom start."},{"name":"history","doc":"Undo, redo and the rest, bottom end — above the zoom cluster on a board too narrow for both."},{"name":"status","doc":"The zoom readout between the two steppers."},{"name":"separator","doc":"A hairline between groups in a panel."},{"name":"editor","doc":"The text box that opens over a text element while it is edited."}],"variants":[{"name":"toolbarPosition","doc":"Which end of the board the tool strip sits at.","default":"top","values":[{"name":"top","doc":""},{"name":"bottom","doc":""}]},{"name":"panelSide","doc":"Which side the paint panel sits on.","default":"start","values":[{"name":"start","doc":""},{"name":"end","doc":""}]},{"name":"compact","doc":"A board too narrow to float panels over — a phone. The chrome folds into the one scrolling bar and the paint panel becomes a sheet across it, so the drawing keeps the rest of the board instead of three sides of chrome sitting on top of it. Set from the board's measured width, not the viewport's: a narrow board on a desktop has the same problem.","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Inputs/Drawing Board","category":"Inputs","own":true,"stories":["Playground","Drawing","From data","Read only","Cut down","Exporting","On a phone","Overridden","With AI"]},"props":[{"name":"elements","optional":true,"type":"DrawingElement[]","default":"[]","bindable":true,"doc":"The document. Bindable, and the whole state of the drawing.","details":[],"examples":[]},{"name":"tool","optional":true,"type":"DrawingTool","default":"'pen'","bindable":true,"doc":"The tool in hand. Bindable, so a toolbar of your own can set it.","details":[],"examples":[]},{"name":"selection","optional":true,"type":"string[]","default":"[]","bindable":true,"doc":"Ids of the selected elements. Bindable.","details":[],"examples":[]},{"name":"camera","optional":true,"type":"Camera","default":"{ x: 0, y: 0, zoom: 1 }","bindable":true,"doc":"Where the camera is and how far in. Bindable.","details":[],"examples":[]},{"name":"ink","optional":true,"type":"DrawingStyle","default":"{ ...defaultDrawingStyle }","bindable":true,"doc":"The paint new elements are made with — and what a selection is repainted to. Bindable.","details":[],"examples":[]},{"name":"tools","optional":true,"type":"DrawingTool[]","default":"drawingBoardTools.map((spec) => spec.tool)","bindable":false,"doc":"Which tools the strip offers, in order.","details":[],"examples":[]},{"name":"palette","optional":true,"type":"DrawingSwatch[]","default":"drawingInk","bindable":false,"doc":"The colours in the stroke row.","details":[],"examples":[]},{"name":"fills","optional":true,"type":"DrawingSwatch[]","default":"drawingFills","bindable":false,"doc":"The colours in the fill row.","details":[],"examples":[]},{"name":"toolbar","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"toolbarPosition","optional":true,"type":"DrawingBoardToolbarPosition","default":"'top'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"stylePanel","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"panelSide","optional":true,"type":"DrawingBoardPanelSide","default":"'start'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"zoomControls","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"historyControls","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"grid","optional":true,"type":"DrawingGrid","default":"'dots'","bindable":false,"doc":"The backdrop: `'dots'`, `'lines'`, or `'none'` for a blank page.","details":[],"examples":[]},{"name":"gridSize","optional":true,"type":"number","default":"20","bindable":false,"doc":"Grid spacing in scene units — and the step everything snaps to.","details":[],"examples":[]},{"name":"snap","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Snap new and moved elements to the grid. Bindable.","details":[],"examples":[]},{"name":"keepTool","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Keep the tool in hand after a shape is drawn, instead of dropping back to select. For drawing ten of something in a row.","details":[],"examples":[]},{"name":"readonly","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Look, don't touch. Pan and zoom still work.","details":[],"examples":[]},{"name":"minZoom","optional":true,"type":"number","default":"0.1","bindable":false,"doc":"How far out and in the camera may go.","details":[],"examples":[]},{"name":"maxZoom","optional":true,"type":"number","default":"8","bindable":false,"doc":"","details":[],"examples":[]},{"name":"maxHistory","optional":true,"type":"number","default":"100","bindable":false,"doc":"How many steps of undo to keep.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"'32rem'","bindable":false,"doc":"Height of the board. A number is px, a string any CSS length.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(elements: DrawingElement[]) => void","bindable":false,"doc":"Fires after any change to the document, with the new elements.","details":[],"examples":[]},{"name":"onselect","optional":true,"type":"(selected: DrawingElement[]) => void","bindable":false,"doc":"Fires when the selection changes, with the selected elements.","details":[],"examples":[]},{"name":"ontool","optional":true,"type":"(tool: DrawingTool) => void","bindable":false,"doc":"Fires when the tool changes — including from a keyboard shortcut.","details":[],"examples":[]},{"name":"oncamera","optional":true,"type":"(camera: Camera) => void","bindable":false,"doc":"Fires while panning and zooming.","details":[],"examples":[]},{"name":"ai","optional":true,"type":"DrawingBoardAi","bindable":false,"doc":"The optional AI: a sparkle in the strip that draws from the sketch.","details":[],"examples":[]},{"name":"toolbarExtra","optional":true,"type":"Snippet","bindable":false,"doc":"Extra buttons at the end of the tool strip.","details":[],"examples":[]},{"name":"panelExtra","optional":true,"type":"Snippet","bindable":false,"doc":"Extra controls at the foot of the style panel.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Your own chrome, over the canvas.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"DrawingBoardClasses","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"Emoji","dir":"emoji-picker","entry":"omaris","importPath":"import { Emoji } from 'omaris'","summary":"One emoji, drawn by the emoji font at a size you can name.","details":["A bare emoji in a `<span>` is drawn by whichever family in the text stack happens to cover the character, sits on the text baseline (so it hangs below a line of copy) and is read out by a screen reader as its Unicode name whether that helps or not. This fixes all three: the emoji font first, optical alignment, and a label that is *yours* — or nothing at all when the emoji is decoration next to text that already says it."],"examples":[{"lang":"svelte","code":"<Emoji emoji=\"🎉\" size=\"xl\" label=\"Celebrating\" />\n<Emoji emoji=\"👋\" tone={3} />"}],"classesType":null,"parts":[],"variants":[{"name":"size","doc":"","default":"md","values":[{"name":"xs","doc":""},{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""},{"name":"xl","doc":""},{"name":"2xl","doc":""},{"name":"inherit","doc":"Takes `--emoji-size` from whatever it sits in."}]}],"story":{"title":"Inputs/Emoji Picker","category":"Inputs","own":false,"stories":["Playground","Default","Behind a button","Custom trigger","Skin tone","Overridden","Sizes","Empty","Emoji"]},"props":[{"name":"emoji","optional":false,"type":"string","bindable":false,"doc":"The character.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"What it means, for a screen reader — \"Celebrating\", not \"party popper\". Leave it out and the emoji is hidden from assistive tech, which is right whenever the text beside it already says the same thing.","details":[],"examples":[]},{"name":"tone","optional":true,"type":"EmojiSkinTone","default":"0","bindable":false,"doc":"Tint it. `0` is the default yellow.","details":[],"examples":[]},{"name":"size","optional":true,"type":"EmojiSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"EmojiButton","dir":"emoji-picker","entry":"omaris","importPath":"import { EmojiButton } from 'omaris'","summary":"The emoji keyboard behind a button — the shape it takes in a composer, a reaction bar or a form field.","details":["It presents itself two ways from one set of props, because a popover and a phone do not mix: on a pointer it is a panel anchored to the trigger, flipping to whichever side has room; below `mobileQuery` it is a bottom sheet you can throw away with a flick, with the grid sized for a thumb. Neither is a second component to keep in step — the same `EmojiPicker` is inside both.","The trigger is a snippet, so it can be anything — the default is a round button showing the emoji you last chose."],"examples":[{"lang":"svelte","code":"<EmojiButton bind:value />\n<EmojiButton onselect={(emoji) => react(emoji)} placeholder=\"🙂\" />"}],"classesType":"EmojiButtonClasses","parts":[{"name":"trigger","doc":"The default trigger."},{"name":"popover","doc":"The positioned box, on a pointer. Nothing but position: the anchor measures this element, and a transform on it would be measured too — which is how a panel ends up half off the screen mid-entrance."},{"name":"surface","doc":"The panel inside it, which is what actually animates in."},{"name":"sheetPicker","doc":"The picker inside the bottom sheet."}],"variants":[{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]}],"story":{"title":"Inputs/Emoji Picker","category":"Inputs","own":false,"stories":["Playground","Default","Behind a button","Custom trigger","Skin tone","Overridden","Sizes","Empty","Emoji"]},"props":[{"name":"value","optional":true,"type":"string","default":"''","bindable":true,"doc":"The emoji last chosen, tone applied. Bindable.","details":[],"examples":[]},{"name":"open","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Whether the panel is showing. Bindable.","details":[],"examples":[]},{"name":"onselect","optional":true,"type":"(emoji: string, entry: EmojiEntry) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"EmojiButtonSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"placeholder","optional":true,"type":"string","default":"'\\u{1F642}'","bindable":false,"doc":"Shown on the default trigger before anything is chosen.","details":[],"examples":[]},{"name":"reflect","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Put the chosen emoji on the trigger. On by default.","details":[],"examples":[]},{"name":"closeOnSelect","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Close as soon as one is picked. On by default.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","default":"'Pick an emoji'","bindable":false,"doc":"Accessible name for the default trigger.","details":[],"examples":[]},{"name":"side","optional":true,"type":"AnchorSide","default":"'bottom'","bindable":false,"doc":"Preferred side of the trigger. Flips when there isn't room.","details":[],"examples":[]},{"name":"align","optional":true,"type":"AnchorAlign","default":"'start'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"offset","optional":true,"type":"number","default":"8","bindable":false,"doc":"Gap between trigger and panel, in px.","details":[],"examples":[]},{"name":"responsive","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Become a bottom sheet on a narrow screen. On by default.","details":[],"examples":[]},{"name":"mobileQuery","optional":true,"type":"string","default":"'(max-width: 639px)'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"skinTone","optional":true,"type":"EmojiSkinTone","default":"0","bindable":true,"doc":"The chosen skin tone. Bindable, and remembered with the recents.","details":[],"examples":[]},{"name":"recent","optional":true,"type":"string[]","default":"[]","bindable":true,"doc":"Recently used emoji, most recent first. Bindable.","details":[],"examples":[]},{"name":"storageKey","optional":true,"type":"string | null","default":"'omaris:emoji'","bindable":false,"doc":"localStorage key for the recents and the tone. `null` to not persist.","details":[],"examples":[]},{"name":"picker","optional":true,"type":"EmojiPickerOptions","bindable":false,"doc":"Everything else the panel takes.","details":[],"examples":[]},{"name":"trigger","optional":true,"type":"Snippet<[{ open: boolean; emoji: string }]>","bindable":false,"doc":"Your own trigger, in place of the round button. Draw the shape only — it is rendered inside the button that opens the panel, so it must not contain an interactive element of its own.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"EmojiButtonClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the trigger.","details":[],"examples":[]}]},{"name":"EmojiPicker","dir":"emoji-picker","entry":"omaris","importPath":"import { EmojiPicker } from 'omaris'","summary":"The emoji keyboard: search, categories, skin tone and a memory of what you picked last.","details":["It is a *panel*, not a popup — drop it into a sheet, a dialog, a card or the side of a composer, and it fills whatever it is given. The grid columns come from the container's width rather than a breakpoint, so the same picker is nine across in a desktop popover and six across on a phone without being told which one it is in. `EmojiButton` is this panel plus a trigger, anchored on a pointer and a bottom sheet on a touch screen.","The whole surface is reachable from the keyboard: type to search, arrow around the grid (the arrows wrap across rows and carry on into the next category), Enter to take one, Escape to clear the search. Focus moves by a roving tabindex, so Tab passes over the grid in one step rather than walking five hundred buttons."],"examples":[{"lang":"svelte","code":"<EmojiPicker onselect={(emoji) => (message += emoji)} />\n<EmojiPicker bind:value bind:skinTone height={280} />"}],"classesType":"EmojiPickerClasses","parts":[{"name":"root","doc":"The panel."},{"name":"header","doc":"The search row."},{"name":"search","doc":"The field itself — a self-contained pill, not the Input frame."},{"name":"searchIcon","doc":"The magnifier in the search field."},{"name":"input","doc":"The search field's own `<input>`."},{"name":"clear","doc":"The × that empties the field. Present only while there is one."},{"name":"tabs","doc":"The category rail."},{"name":"indicator","doc":"The pill that slides between tabs. One element that moves, rather than a background that fades in and out on nine of them."},{"name":"tab","doc":"One category, drawn as its own representative emoji."},{"name":"scroller","doc":"The scrolling body."},{"name":"section","doc":"One category's heading and grid."},{"name":"heading","doc":"The category name, which sticks to the top as you scroll past it."},{"name":"grid","doc":"One category's cells — as many across as the width holds."},{"name":"cell","doc":"One emoji."},{"name":"empty","doc":"\"No emoji found\"."},{"name":"emptyIcon","doc":"The face over \"no emoji found\"."},{"name":"emptyText","doc":"`emptyText` itself."},{"name":"footer","doc":"The preview row along the bottom."},{"name":"previewEmoji","doc":"The emoji under the cursor, shown large."},{"name":"previewName","doc":"Its name."},{"name":"tones","doc":"The skin tone control: one swatch that unfurls into six."},{"name":"toneToggle","doc":"The swatch that opens the tone row, showing the current tone."},{"name":"toneList","doc":"The row of six, which grows out of the toggle rather than appearing."},{"name":"tone","doc":"One tone in that row."}],"variants":[{"name":"size","doc":"Cell size, and with it the emoji, the panel width and the rhythm.","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]},{"name":"fixedColumns","doc":"Fixed columns instead of as many as fit. Off by default, because \"as many as fit\" is what makes one picker work on both a phone and a wide popover.","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]},{"name":"bare","doc":"Square off the panel — for a picker that fills a sheet.","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Inputs/Emoji Picker","category":"Inputs","own":true,"stories":["Playground","Default","Behind a button","Custom trigger","Skin tone","Overridden","Sizes","Empty","Emoji"]},"props":[{"name":"value","optional":true,"type":"string","default":"''","bindable":true,"doc":"The emoji last chosen, tone applied. Bindable.","details":[],"examples":[]},{"name":"onselect","optional":true,"type":"(emoji: string, entry: EmojiEntry) => void","bindable":false,"doc":"Called with the chosen emoji and the entry behind it.","details":[],"examples":[]},{"name":"onclose","optional":true,"type":"() => void","bindable":false,"doc":"Escape on an empty search field.","details":[],"examples":[]},{"name":"size","optional":true,"type":"EmojiPickerSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"groups","optional":true,"type":"EmojiGroup[]","bindable":false,"doc":"Your own set, in place of the built-in one.","details":[],"examples":[]},{"name":"search","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Show the search field.","details":[],"examples":[]},{"name":"query","optional":true,"type":"string","default":"''","bindable":true,"doc":"What the search field is bound to. Bindable.","details":[],"examples":[]},{"name":"searchPlaceholder","optional":true,"type":"string","default":"'Search emoji'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"categories","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Show the category rail.","details":[],"examples":[]},{"name":"preview","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Show the preview row along the bottom.","details":[],"examples":[]},{"name":"tones","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Offer the skin tone control. Needs `preview`.","details":[],"examples":[]},{"name":"skinTone","optional":true,"type":"EmojiSkinTone","default":"0","bindable":true,"doc":"The chosen skin tone. Bindable.","details":[],"examples":[]},{"name":"recent","optional":true,"type":"string[]","default":"[]","bindable":true,"doc":"Recently used emoji, most recent first. Bindable.","details":[],"examples":[]},{"name":"storageKey","optional":true,"type":"string | null","default":"'omaris:emoji'","bindable":false,"doc":"localStorage key the recents and the tone are remembered under. `null` keeps them for the life of the component only.","details":[],"examples":[]},{"name":"maxRecent","optional":true,"type":"number","default":"24","bindable":false,"doc":"How many recents to keep.","details":[],"examples":[]},{"name":"columns","optional":true,"type":"number","bindable":false,"doc":"Force a column count instead of fitting as many as the width allows.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"260","bindable":false,"doc":"Height of the scrolling area — a number of px or any CSS length.","details":[],"examples":[]},{"name":"autofocus","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Put the cursor in the search field on mount.","details":[],"examples":[]},{"name":"bare","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Drop the panel's own border, radius and background.","details":[],"examples":[]},{"name":"emptyText","optional":true,"type":"string","default":"'No emoji found'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"footer","optional":true,"type":"Snippet<[{ emoji: string; name: string }]>","bindable":false,"doc":"Replaces the preview row's contents, keeping the row.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"EmojiPickerClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"Empty","dir":"empty","entry":"omaris","importPath":"import { Empty } from 'omaris'","summary":"Empty state.","details":["The screen a dashboard spends more time showing than anyone plans for — no results, nothing created yet, a failed load. Giving it a component means those three read as one family instead of three improvisations."],"examples":[],"classesType":"EmptyClasses","parts":[{"name":"root","doc":""},{"name":"icon","doc":"The icon sits in a tinted circle so it reads as deliberate."},{"name":"title","doc":""},{"name":"description","doc":""},{"name":"actions","doc":""}],"variants":[{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]},{"name":"tone","doc":"","default":"neutral","values":[{"name":"neutral","doc":""},{"name":"destructive","doc":"For a failed load rather than an empty one."}]},{"name":"bordered","doc":"A dashed frame, for a drop zone or an unfilled slot.","values":[{"name":"true","doc":""}]}],"story":{"title":"Data Display/Empty","category":"Data Display","own":true,"stories":["Playground","The three cases","Sizes","As a drop zone"]},"props":[{"name":"title","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"description","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"EmptySize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"tone","optional":true,"type":"EmptyTone","default":"'neutral'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"bordered","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"EmptyClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"icon","optional":true,"type":"Snippet","bindable":false,"doc":"Icon or illustration. A default inbox icon is used without one.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Extra content between the text and the actions.","details":[],"examples":[]},{"name":"actions","optional":true,"type":"Snippet","bindable":false,"doc":"Buttons under the text.","details":[],"examples":[]}]},{"name":"Fab","dir":"fab","entry":"omaris","importPath":"import { Fab } from 'omaris'","summary":"MD3 floating action button. Three sizes (40 / 56 / 96dp), plus `extended` for the pill that carries a label next to the icon.","details":["A FAB sits above the content, so it keeps a resting elevation and only lifts further on hover — it never drops to flat."],"examples":[],"classesType":null,"parts":[],"variants":[{"name":"tone","doc":"","default":"primary","values":[{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""}]},{"name":"variant","doc":"","default":"tonal","values":[{"name":"tonal","doc":"MD3's default: the tone's container color."},{"name":"filled","doc":"Higher-emphasis FAB, for the one action on the screen."},{"name":"surface","doc":"Neutral FAB that lets the icon carry the color."}]},{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]},{"name":"extended","doc":"Grows the FAB into a labelled pill.","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Actions/FAB","category":"Actions","own":true,"stories":["Playground","Sizes","Variants","Tones","Extended"]},"props":[{"name":"variant","optional":true,"type":"FabVariant","default":"'tonal'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"tone","optional":true,"type":"FabTone","default":"'primary'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"FabSize","default":"'md'","bindable":false,"doc":"40 / 56 / 96dp.","details":[],"examples":[]},{"name":"extended","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Show the label beside the icon instead of an icon-only circle.","details":[],"examples":[]},{"name":"ripple","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"confetti","optional":true,"type":"boolean | ConfettiOptions","default":"false","bindable":false,"doc":"Confetti on press. `true` for the default burst, or any `ConfettiOptions` — `confetti={{ preset: 'fireworks' }}`.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"The icon. Always rendered.","details":[],"examples":[]},{"name":"label","optional":true,"type":"Snippet","bindable":false,"doc":"The label, shown only when `extended`.","details":[],"examples":[]},{"name":"shape","optional":true,"type":"ButtonShape","bindable":false,"doc":"Pill (`round`) or MD3 rounded rectangle (`square`).","details":[],"examples":[]},{"name":"icon","optional":true,"type":"boolean","bindable":false,"doc":"Square, label-less button. Requires an `aria-label`.","details":[],"examples":[]},{"name":"loading","optional":true,"type":"boolean","bindable":false,"doc":"Grows a spinner in at the start of the button and blocks interaction. The label stays put; only an `icon` button swaps its icon out.","details":[],"examples":[]},{"name":"toggle","optional":true,"type":"boolean","bindable":false,"doc":"Turns the button into a two-state toggle driven by `pressed`. Ignored when `href` is set — a link has no pressed state.","details":[],"examples":[]},{"name":"pressed","optional":true,"type":"boolean","bindable":true,"doc":"Selected state of a toggle button. Bindable.","details":[],"examples":[]}]},{"name":"Field","dir":"field","entry":"omaris","importPath":"import { Field } from 'omaris'","summary":"Field — the label, the help line and the error, around any control.","details":["The control inside stays bare: `<Field label=\"Email\" error={err}><Input /></Field>`. The field shares its ids and its state through context, so the control picks up the right `id`, `aria-describedby`, `aria-invalid`, `required` and `disabled` on its own — and anything the control is given directly still wins.","One DOM order, two layouts. Vertical stacks label, control, description, error. Horizontal puts the label and description at the start and the control at the end, the settings-row shape a switch or a checkbox wants.","The error opens rather than appears: its row grows from nothing and fades in, so the form below slides down instead of jumping. It closes the same way, still showing the old text while it goes."],"examples":[],"classesType":"FieldClasses","parts":[{"name":"root","doc":""},{"name":"label","doc":""},{"name":"control","doc":"Wraps whatever control you pass as children."},{"name":"description","doc":""},{"name":"error","doc":"The live region the error is announced from. Always present."},{"name":"collapse","doc":"The row that opens: grid rows from 0fr to 1fr, and a fade."},{"name":"message","doc":"The error line itself, with its glyph."}],"variants":[{"name":"orientation","doc":"","default":"vertical","values":[{"name":"vertical","doc":""},{"name":"horizontal","doc":""}]},{"name":"disabled","doc":"","values":[{"name":"true","doc":""}]}],"story":{"title":"Inputs/Field","category":"Inputs","own":true,"stories":["Playground","Error opens and closes","Around any control","Horizontal","Disabled and required","Overridden"]},"props":[{"name":"label","optional":true,"type":"string","bindable":false,"doc":"The label. Its `for` points at the control, so pressing it focuses it.","details":[],"examples":[]},{"name":"description","optional":true,"type":"string","bindable":false,"doc":"Help under the control — what the value is for, or what shape it takes.","details":[],"examples":[]},{"name":"error","optional":true,"type":"string","bindable":false,"doc":"The error text. Setting it marks the field invalid; clearing it closes the error again. Announced politely, never read out over what the person is typing.","details":[],"examples":[]},{"name":"invalid","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Invalid with no message — for when the reason is shown somewhere else. Set automatically by `error`.","details":[],"examples":[]},{"name":"required","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Stars the label and marks the control required.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Dims the label and description and disables the control.","details":[],"examples":[]},{"name":"orientation","optional":true,"type":"FieldOrientation","default":"'vertical'","bindable":false,"doc":"`vertical` stacks the parts. `horizontal` puts the label at the start and the control at the end — a switch, a checkbox, a compact number.","details":[],"examples":[]},{"name":"controlId","optional":true,"type":"string","bindable":false,"doc":"The control's id. Set it here rather than on the control, so the label's `for` and the control agree. Generated when omitted.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"One control. A group — radios, a slider — is labelled by the field too.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"FieldClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"FileUpload","dir":"file-upload","entry":"omaris","importPath":"import { FileUpload } from 'omaris'","summary":"A dropzone that takes files from all three places people have them: dropped, browsed, and — the one usually missing — pasted.","details":["The smallest useful call is one attribute:","That already drags, drops, browses, pastes screenshots, walks dropped folders, previews images, shows sizes and lets each file be removed. Everything past it is opt-in: `accept` and `maxSize` to filter, `max` to cap, `preview=\"grid\"` for a gallery, and an `upload` function to make it send the files itself, with per-file progress, cancel and retry.","With no `upload`, the component is a picker: `files` is the state and the surrounding form does the sending."],"examples":[{"lang":"svelte","code":"<FileUpload bind:files />"},{"lang":"svelte","code":"<FileUpload\n  accept=\"image/*,.pdf\"\n  maxSize={5 * 1000 * 1000}\n  upload={async (item, { progress, signal }) => {\n    const body = new FormData();\n    body.set('file', item.file);\n    const res = await fetch('/api/upload', { method: 'POST', body, signal });\n    progress(100);\n    return await res.json();\n  }}\n/>"}],"classesType":"FileUploadClasses","parts":[{"name":"root","doc":""},{"name":"zone","doc":"The drop target. `group/zone` so the artwork inside can react to the drag without any of it being wired up in JavaScript."},{"name":"spotlight","doc":"The pointer-following glow. Pure decoration, hidden from a11y."},{"name":"trigger","doc":"The label that makes the whole zone one big file picker. It sits above the artwork and the copy — those are positioned too, and a later sibling paints over an earlier one, so without the `z-10` the picker only opens where the zone happens to be empty."},{"name":"media","doc":"The stack of sheets that fans open when a drag comes over."},{"name":"sheet","doc":"One sheet of that stack. The two behind take the surface rather than the tone, or the three of them read as one lumpy shape instead of as paper stacked on paper."},{"name":"face","doc":"The front sheet — the one with the arrow on it."},{"name":"glyph","doc":"The arrow drawn on it."},{"name":"copy","doc":""},{"name":"title","doc":""},{"name":"description","doc":""},{"name":"controls","doc":"The row holding the browse button and any `actions`."},{"name":"alert","doc":"The rule that just got broken, under the zone."},{"name":"summary","doc":"\"3 files · 8.2 MB\" and the clear-all button."},{"name":"list","doc":""},{"name":"item","doc":"One file."},{"name":"thumb","doc":"The thumbnail, or the extension when there is nothing to show."},{"name":"info","doc":""},{"name":"name","doc":""},{"name":"meta","doc":""},{"name":"bar","doc":"The per-file progress bar; present only while it means something."},{"name":"actions","doc":"The remove / cancel / retry cluster."},{"name":"overlay","doc":"The full-window veil `dropAnywhere` raises."},{"name":"overlayCard","doc":"The card inside that veil."}],"variants":[{"name":"tone","doc":"","default":"primary","values":[{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""}]},{"name":"variant","doc":"","default":"dashed","values":[{"name":"dashed","doc":"The default: a dashed outline that firms up under a drag."},{"name":"outlined","doc":"A hairline card, for a dropzone that sits inside a form."},{"name":"tonal","doc":"Filled with the tone's container — the loudest of the three."},{"name":"ghost","doc":"No container at all until a drag arrives."}]},{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]},{"name":"preview","doc":"How accepted files are shown under the zone.","default":"list","values":[{"name":"list","doc":""},{"name":"grid","doc":""},{"name":"none","doc":""}]},{"name":"dragging","doc":"A drag is over the zone.","values":[{"name":"true","doc":""}]},{"name":"disabled","doc":"","values":[{"name":"true","doc":""}]}],"story":{"title":"Inputs/File Upload","category":"Inputs","own":true,"stories":["Playground","Variants","Sizes","Constrained","Single file","Uploading","Failure and retry","Manual start","Drop anywhere","Custom rows","Overridden","Disabled"]},"props":[{"name":"files","optional":true,"type":"UploadFile[]","default":"[]","bindable":true,"doc":"The accepted files. Bindable, and the only state you need — every other prop is a rule about what may enter it.","details":[],"examples":[]},{"name":"accept","optional":true,"type":"string","bindable":false,"doc":"`<input accept>` grammar: `image/*`, `.csv`, `application/pdf`.","details":[],"examples":[]},{"name":"multiple","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"max","optional":true,"type":"number","bindable":false,"doc":"Cap on how many files may be held at once.","details":[],"examples":[]},{"name":"maxSize","optional":true,"type":"number","bindable":false,"doc":"Largest file, in bytes. `5 * 1000 * 1000` is 5 MB.","details":[],"examples":[]},{"name":"minSize","optional":true,"type":"number","bindable":false,"doc":"Smallest file, in bytes — catches empty and truncated files.","details":[],"examples":[]},{"name":"directory","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Let the picker take a whole folder. Dropped folders always walk.","details":[],"examples":[]},{"name":"paste","optional":true,"type":"boolean | 'focus'","default":"true","bindable":false,"doc":"Take files from a paste. `true` listens on the window and skips pastes aimed at a text field elsewhere; `'focus'` only listens while the dropzone itself has focus. `false` turns it off.","details":[],"examples":[]},{"name":"dropAnywhere","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Accept a drop anywhere on the page, with a full-window veil.","details":[],"examples":[]},{"name":"capture","optional":true,"type":"'user' | 'environment'","bindable":false,"doc":"On a phone, open the camera instead of the file browser.","details":[],"examples":[]},{"name":"name","optional":true,"type":"string","bindable":false,"doc":"Submitted with the surrounding form, like any `<input name>`.","details":[],"examples":[]},{"name":"required","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"upload","optional":true,"type":"UploadFn","bindable":false,"doc":"Sends a file. Give it one and the component becomes an uploader.","details":[],"examples":[]},{"name":"autoUpload","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Start uploading the moment a file is accepted.","details":[],"examples":[]},{"name":"concurrency","optional":true,"type":"number","default":"3","bindable":false,"doc":"How many uploads run at once.","details":[],"examples":[]},{"name":"variant","optional":true,"type":"FileUploadVariant","default":"'dashed'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"tone","optional":true,"type":"FileUploadTone","default":"'primary'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"FileUploadSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"preview","optional":true,"type":"FileUploadPreview","default":"'list'","bindable":false,"doc":"`list` rows, `grid` tiles, or `none` to render the files yourself.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"The headline in the zone.","details":[],"examples":[]},{"name":"hint","optional":true,"type":"string","bindable":false,"doc":"The line under it. Defaults to a sentence built from the rules.","details":[],"examples":[]},{"name":"browseLabel","optional":true,"type":"string | null","default":"'Browse files'","bindable":false,"doc":"Text of the browse button. `null` removes it.","details":[],"examples":[]},{"name":"onadd","optional":true,"type":"(files: UploadFile[]) => void","bindable":false,"doc":"Called with the files that were just accepted.","details":[],"examples":[]},{"name":"onreject","optional":true,"type":"(rejections: UploadRejection[]) => void","bindable":false,"doc":"Called with the files that were turned away, and why.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(files: UploadFile[]) => void","bindable":false,"doc":"Called with the whole list after any change to it.","details":[],"examples":[]},{"name":"oncomplete","optional":true,"type":"(files: UploadFile[]) => void","bindable":false,"doc":"Called once nothing is left to upload.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"FileUploadClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"icon","optional":true,"type":"Snippet","bindable":false,"doc":"Replaces the fanning sheets.","details":[],"examples":[]},{"name":"title","optional":true,"type":"Snippet","bindable":false,"doc":"Replaces the headline.","details":[],"examples":[]},{"name":"description","optional":true,"type":"Snippet","bindable":false,"doc":"Replaces the line under it.","details":[],"examples":[]},{"name":"actions","optional":true,"type":"Snippet","bindable":false,"doc":"Extra controls beside the browse button.","details":[],"examples":[]},{"name":"file","optional":true,"type":"Snippet<[FileUploadRowContext]>","bindable":false,"doc":"Replaces the whole row or tile for one file.","details":[],"examples":[]}]},{"name":"FunnelChart","dir":"chart","entry":"omaris/chart","importPath":"import { FunnelChart } from 'omaris/chart'","summary":"Funnel chart — how many made it through each stage.","details":["Each stage is a band that tapers into the next, with the count and the share above it. The numbers sit outside the band rather than on it, because a label printed over a saturated fill is a contrast bug waiting for the one palette that breaks it.","`drop` swaps the share of the first stage for the share of the previous one, which is the number a growth team actually argues about."],"examples":[{"lang":"svelte","code":"<FunnelChart data={steps} />"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Charts","category":"Data Display","own":false,"stories":["Area","Line","Bar","Pie and donut","Scatter","Sparkline","Empty","References and annotations","Brush and zoom","Legend isolate and CSV","Error","Combo","Radar","Radial bar and gauge","Funnel","Treemap","Candlestick"]},"props":[{"name":"data","optional":false,"type":"T[]","bindable":false,"doc":"","details":[],"examples":[]},{"name":"label","optional":true,"type":"Field<T>","default":"'label'","bindable":false,"doc":"Field naming each stage. Defaults to `row.label`.","details":[],"examples":[]},{"name":"value","optional":true,"type":"Field<T>","default":"'value'","bindable":false,"doc":"Field holding each stage's count. Defaults to `row.value`.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"300","bindable":false,"doc":"Plot height. A number is px; a string is any CSS length.","details":[],"examples":[]},{"name":"gap","optional":true,"type":"number","default":"4","bindable":false,"doc":"Gap between stages, in px.","details":[],"examples":[]},{"name":"share","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Show each stage's share — of the first stage, or of the previous.","details":[],"examples":[]},{"name":"drop","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Measure the share against the previous stage rather than the first.","details":[],"examples":[]},{"name":"format","optional":true,"type":"(value: number) => string","bindable":false,"doc":"How each count reads.","details":[],"examples":[]},{"name":"colors","optional":true,"type":"readonly string[]","default":"CHART_COLORS","bindable":false,"doc":"Palette override, cycled across the stages.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"Accessible description of what the chart shows.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"empty","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]},{"name":"emptyText","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"error","optional":true,"type":"boolean | string | Error","bindable":false,"doc":"Something went wrong. Truthy puts the chart into its error state; a string or an `Error` supplies the message.","details":[],"examples":[]},{"name":"errorText","optional":true,"type":"string","bindable":false,"doc":"The message, when `error` is just `true`.","details":[],"examples":[]},{"name":"errorState","optional":true,"type":"Snippet<[{ message: string }]>","bindable":false,"doc":"Replaces the whole error state.","details":[],"examples":[]},{"name":"onRetry","optional":true,"type":"() => void","bindable":false,"doc":"Offers a \"Try again\" button in the error state.","details":[],"examples":[]},{"name":"csv","optional":true,"type":"boolean | string","default":"false","bindable":false,"doc":"Offer the plotted rows as a CSV download, from a button in the corner. A string names the file.","details":[],"examples":[]},{"name":"csvColumns","optional":true,"type":"(string | { key: string; label?: string; value?: (row: T) => unknown })[]","bindable":false,"doc":"Which fields the download writes, in order. Defaults to every field.","details":[],"examples":[]}]},{"name":"Gauge","dir":"chart","entry":"omaris/chart","importPath":"import { Gauge } from 'omaris/chart'","summary":"Gauge — one number against the range it lives in.","details":["A dial rather than a bar because the sweep carries \"how far through the range\" at a glance, which is the only question a single number on a dashboard is ever asked. The value is printed in the middle, so the reading never depends on eyeballing an arc.","`thresholds` colours the dial by where the value landed — the first entry the value is at or under wins — which turns it into a status light without a second component."],"examples":[{"lang":"svelte","code":"<Gauge value={72} max={100} caption=\"of quota\" />"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Charts","category":"Data Display","own":false,"stories":["Area","Line","Bar","Pie and donut","Scatter","Sparkline","Empty","References and annotations","Brush and zoom","Legend isolate and CSV","Error","Combo","Radar","Radial bar and gauge","Funnel","Treemap","Candlestick"]},"props":[{"name":"value","optional":false,"type":"number","bindable":false,"doc":"","details":[],"examples":[]},{"name":"min","optional":true,"type":"number","default":"0","bindable":false,"doc":"Bottom of the range.","details":[],"examples":[]},{"name":"max","optional":true,"type":"number","default":"100","bindable":false,"doc":"Top of the range.","details":[],"examples":[]},{"name":"sweep","optional":true,"type":"number","default":"270","bindable":false,"doc":"Degrees the dial sweeps, centred on the top.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"200","bindable":false,"doc":"Plot height. A number is px; a string is any CSS length.","details":[],"examples":[]},{"name":"thickness","optional":true,"type":"number","default":"14","bindable":false,"doc":"Thickness of the dial, in px.","details":[],"examples":[]},{"name":"color","optional":true,"type":"string","default":"'var(--primary)'","bindable":false,"doc":"Any CSS colour. Ignored where a `thresholds` entry matches.","details":[],"examples":[]},{"name":"thresholds","optional":true,"type":"{ at: number; color: string }[]","bindable":false,"doc":"Colour by value: the first entry whose `at` the value is at or under wins, and anything above them all falls back to `color`.","details":[],"examples":[]},{"name":"format","optional":true,"type":"(value: number) => string","bindable":false,"doc":"How the printed value reads. Defaults to the number itself.","details":[],"examples":[]},{"name":"caption","optional":true,"type":"string","bindable":false,"doc":"A word under the number — \"of quota\", \"requests/s\".","details":[],"examples":[]},{"name":"centre","optional":true,"type":"Snippet<[{ value: number }]>","bindable":false,"doc":"Replaces the number and caption in the middle.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"Accessible description of what the gauge shows.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"error","optional":true,"type":"boolean | string | Error","bindable":false,"doc":"Something went wrong. Truthy puts the chart into its error state; a string or an `Error` supplies the message.","details":[],"examples":[]},{"name":"errorText","optional":true,"type":"string","bindable":false,"doc":"The message, when `error` is just `true`.","details":[],"examples":[]},{"name":"errorState","optional":true,"type":"Snippet<[{ message: string }]>","bindable":false,"doc":"Replaces the whole error state.","details":[],"examples":[]},{"name":"onRetry","optional":true,"type":"() => void","bindable":false,"doc":"Offers a \"Try again\" button in the error state.","details":[],"examples":[]},{"name":"csv","optional":true,"type":"boolean | string","default":"false","bindable":false,"doc":"Offer the plotted rows as a CSV download, from a button in the corner. A string names the file.","details":[],"examples":[]},{"name":"csvColumns","optional":true,"type":"(string | { key: string; label?: string; value?: (row: T) => unknown })[]","bindable":false,"doc":"Which fields the download writes, in order. Defaults to every field.","details":[],"examples":[]}]},{"name":"Gauge","dir":"gauge","entry":"omaris","importPath":"import { Gauge } from 'omaris'","summary":"A radial gauge — one number against the range it lives in.","details":["The arc is a real SVG stroke with a dash offset, and it stays crisp at any size. The sweep and the number in the middle are driven by one tweened value on the emphasized curve, so a new reading glides in and counts up together, stopping at the same instant — and the dial rises from empty when it first appears. `animate={false}` makes it jump, a number sets the duration in ms. `segments` paint zones on the track (a red band past 80%, say) without touching the indicator, so the reading and the scale stay separate things."],"examples":[{"lang":"svelte","code":"<Gauge value={72} label=\"CPU\" tone=\"warning\" segments={[{ from: 80, tone: 'destructive' }]} />"}],"classesType":"GaugeClasses","parts":[{"name":"root","doc":""},{"name":"svg","doc":"The square the arc is drawn in."},{"name":"track","doc":"The unfilled remainder of the sweep."},{"name":"segment","doc":"A coloured band on the track, behind the indicator."},{"name":"indicator","doc":"The filled arc. Its sweep is tweened in script; only the colour transitions here."},{"name":"content","doc":"Centred stack: value over label."},{"name":"value","doc":""},{"name":"label","doc":""},{"name":"tick","doc":"Tick marks around the scale."}],"variants":[{"name":"tone","doc":"","default":"primary","values":[{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""}]},{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]}],"story":{"title":"Data display/Gauge","category":"Data Display","own":true,"stories":["Playground","Tones","Sizes","Sweeps","Segments","Live","Animation","Custom content"]},"props":[{"name":"value","optional":false,"type":"number","bindable":false,"doc":"","details":[],"examples":[]},{"name":"min","optional":true,"type":"number","default":"0","bindable":false,"doc":"","details":[],"examples":[]},{"name":"max","optional":true,"type":"number","default":"100","bindable":false,"doc":"","details":[],"examples":[]},{"name":"tone","optional":true,"type":"GaugeTone","default":"'primary'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"GaugeSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"sweep","optional":true,"type":"number","default":"270","bindable":false,"doc":"Degrees of arc. 270 is the classic dial; 360 closes it into a ring.","details":[],"examples":[]},{"name":"thickness","optional":true,"type":"number","default":"0.22","bindable":false,"doc":"Stroke width as a share of the radius.","details":[],"examples":[]},{"name":"rounded","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Round the ends of both arcs.","details":[],"examples":[]},{"name":"segments","optional":true,"type":"GaugeSegment[]","bindable":false,"doc":"Zones on the track — thresholds, safe ranges, a red line.","details":[],"examples":[]},{"name":"ticks","optional":true,"type":"number","default":"0","bindable":false,"doc":"Evenly spaced ticks around the scale. `0` draws none.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Under the number — \"CPU\", \"of 2,000\".","details":[],"examples":[]},{"name":"format","optional":true,"type":"(value: number) => string","bindable":false,"doc":"Formats the number in the middle. Defaults to a rounded integer.","details":[],"examples":[]},{"name":"showValue","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Hide the centred readout — for a gauge in a dense table cell.","details":[],"examples":[]},{"name":"animate","optional":true,"type":"boolean | number","default":"true","bindable":false,"doc":"Glide to a new value rather than jump. `true` takes 700 ms on the emphasized curve, a number sets the duration in ms, `false` is instant. Reduced motion is always instant.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Replaces the whole centre stack.","details":[],"examples":[]},{"name":"name","optional":true,"type":"string","bindable":false,"doc":"Accessible name. Falls back to `label`, and one of the two is required: a meter with a value and no name reaches a screen reader as \"64 percent\" of nothing. Give it one whenever the centre stack is replaced by `children`, which is the case where `label` is gone.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"GaugeClasses","bindable":false,"doc":"","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","bindable":false,"doc":"Plot height. A number is px; a string is any CSS length.","details":[],"examples":[]},{"name":"color","optional":true,"type":"string","bindable":false,"doc":"Any CSS colour. Ignored where a `thresholds` entry matches.","details":[],"examples":[]},{"name":"thresholds","optional":true,"type":"{ at: number; color: string }[]","bindable":false,"doc":"Colour by value: the first entry whose `at` the value is at or under wins, and anything above them all falls back to `color`.","details":[],"examples":[]},{"name":"caption","optional":true,"type":"string","bindable":false,"doc":"A word under the number — \"of quota\", \"requests/s\".","details":[],"examples":[]},{"name":"centre","optional":true,"type":"Snippet<[{ value: number }]>","bindable":false,"doc":"Replaces the number and caption in the middle.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"Accessible description of what the gauge shows.","details":[],"examples":[]},{"name":"error","optional":true,"type":"boolean | string | Error","bindable":false,"doc":"Something went wrong. Truthy puts the chart into its error state; a string or an `Error` supplies the message.","details":[],"examples":[]},{"name":"errorText","optional":true,"type":"string","bindable":false,"doc":"The message, when `error` is just `true`.","details":[],"examples":[]},{"name":"errorState","optional":true,"type":"Snippet<[{ message: string }]>","bindable":false,"doc":"Replaces the whole error state.","details":[],"examples":[]},{"name":"onRetry","optional":true,"type":"() => void","bindable":false,"doc":"Offers a \"Try again\" button in the error state.","details":[],"examples":[]},{"name":"csv","optional":true,"type":"boolean | string","bindable":false,"doc":"Offer the plotted rows as a CSV download, from a button in the corner. A string names the file.","details":[],"examples":[]},{"name":"csvColumns","optional":true,"type":"(string | { key: string; label?: string; value?: (row: T) => unknown })[]","bindable":false,"doc":"Which fields the download writes, in order. Defaults to every field.","details":[],"examples":[]}]},{"name":"IconButton","dir":"icon-button","entry":"omaris","importPath":"import { IconButton } from 'omaris'","summary":"MD3 icon button. Same tone system as `Button`, but its own geometry: height comes from `size`, width from `width` as a ratio of that height (MD3's narrow / default / wide, which are ~0.8× / 1× / 1.3×).","details":[],"examples":[],"classesType":null,"parts":[],"variants":[{"name":"tone","doc":"","default":"primary","values":[{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""}]},{"name":"variant","doc":"","default":"standard","values":[{"name":"filled","doc":""},{"name":"tonal","doc":""},{"name":"elevated","doc":""},{"name":"outlined","doc":""},{"name":"standard","doc":"The default: no container until you touch it."}]},{"name":"size","doc":"","default":"sm","values":[{"name":"xs","doc":""},{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""},{"name":"xl","doc":""}]},{"name":"width","doc":"","default":"default","values":[{"name":"narrow","doc":""},{"name":"default","doc":""},{"name":"wide","doc":""}]},{"name":"shape","doc":"","default":"round","values":[{"name":"round","doc":""},{"name":"square","doc":""}]},{"name":"toggle","doc":"","values":[{"name":"true","doc":""}]}],"story":{"title":"Actions/Icon Button","category":"Actions","own":true,"stories":["Playground","Variants","Sizes","Widths","Shapes","Toggle","Disabled","Overridden attributes"]},"props":[{"name":"variant","optional":true,"type":"IconButtonVariant","default":"'standard'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"tone","optional":true,"type":"IconButtonTone","default":"'primary'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"IconButtonSize","default":"'sm'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"width","optional":true,"type":"IconButtonWidth","default":"'default'","bindable":false,"doc":"Horizontal weight relative to the height — MD3's three densities.","details":[],"examples":[]},{"name":"shape","optional":true,"type":"IconButtonShape","default":"'round'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"ripple","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"confetti","optional":true,"type":"boolean | ConfettiOptions","default":"false","bindable":false,"doc":"Confetti on press. `true` for the default burst, or any `ConfettiOptions` — `confetti={{ preset: 'fireworks' }}`.","details":[],"examples":[]},{"name":"toggle","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Turns the button into a two-state toggle driven by `pressed`. Ignored when `href` is set — a link has no pressed state.","details":[],"examples":[]},{"name":"pressed","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Selected state of a toggle button. Bindable.","details":[],"examples":[]},{"name":"selectedIcon","optional":true,"type":"Snippet","bindable":false,"doc":"Icon shown while `pressed`. Lets a toggle swap outline for solid, the way Material's own icons do.","details":[],"examples":[]},{"name":"aria-label","optional":false,"type":"string","bindable":false,"doc":"Required — an icon alone carries no accessible name.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]},{"name":"icon","optional":true,"type":"boolean","bindable":false,"doc":"Square, label-less button. Requires an `aria-label`.","details":[],"examples":[]},{"name":"loading","optional":true,"type":"boolean","bindable":false,"doc":"Grows a spinner in at the start of the button and blocks interaction. The label stays put; only an `icon` button swaps its icon out.","details":[],"examples":[]}]},{"name":"ImageCropper","dir":"image-cropper","entry":"omaris","importPath":"import { ImageCropper } from 'omaris'","summary":"Crop an image by moving the image, not the box.","details":["The crop window sits still in the middle at the aspect ratio you asked for, and the picture pans and zooms underneath it — the gesture every phone camera has trained everyone to expect. Zooming happens *under the pointer*: the pixel beneath the cursor, or between two fingers, is the one that stays put.","The picture is *constrained*: it can never be moved or zoomed far enough to leave a gap inside the window, so an empty corner is not a thing that can happen — at any angle, not only at quarter turns. The export replays exactly the transform you see, at whatever output size you name, so what lands in the blob is what was in the frame.","The window itself can be sized — `ratios` puts a row of aspect presets under the stage, `resizable` puts handles on the window, and `aspect=\"free\"` lets the two of them shape it freely."],"examples":[{"lang":"svelte","code":"<ImageCropper bind:this={cropper} src={file} aspect={1} shape=\"circle\" />\n<Button onclick={async () => upload(await cropper.toBlob())}>Save</Button>"}],"classesType":"ImageCropperClasses","parts":[{"name":"root","doc":""},{"name":"stage","doc":"The dark stage the picture moves around in."},{"name":"image","doc":"The picture. Only ever moved with a compositor transform."},{"name":"window","doc":"The crop window. Everything outside it is dimmed by one enormous spread shadow, so the scrim is a single element that can never fall out of register with the hole in it."},{"name":"grid","doc":"Rule-of-thirds lines inside the window."},{"name":"gridLine","doc":""},{"name":"handle","doc":"A corner or edge grip on the window. Only rendered when the cropper is `resizable`; each one is a real button, so the window can be sized from the keyboard too."},{"name":"ratios","doc":"The row of aspect-ratio presets."},{"name":"ratio","doc":""},{"name":"controls","doc":"Zoom slider and the buttons beside it."},{"name":"slider","doc":""},{"name":"angle","doc":"The straighten row: a fine-angle slider and its readout."},{"name":"angleValue","doc":""},{"name":"button","doc":""},{"name":"loading","doc":"Shown until the picture has loaded."}],"variants":[{"name":"shape","doc":"","default":"rect","values":[{"name":"rect","doc":""},{"name":"circle","doc":""}]}],"story":{"title":"Inputs/Image Cropper","category":"Inputs","own":true,"stories":["Playground","Cropping","Avatar","Ratios","Filling a panel","Ratios and resizing","Straighten and flip","Free crop"]},"props":[{"name":"src","optional":false,"type":"string","bindable":false,"doc":"Image URL, object URL or data URL.","details":[],"examples":[]},{"name":"alt","optional":true,"type":"string","default":"''","bindable":false,"doc":"Describes the picture, for anyone who cannot see it.","details":[],"examples":[]},{"name":"aspect","optional":true,"type":"ImageCropperAspect","default":"1","bindable":true,"doc":"Width ÷ height of the crop window. `1` is a square, `'free'` is any. Bindable.","details":[],"examples":[]},{"name":"shape","optional":true,"type":"ImageCropperShape","default":"'rect'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"zoom","optional":true,"type":"number","default":"1","bindable":true,"doc":"Zoom, where `1` is \"just covers the window\". Bindable.","details":[],"examples":[]},{"name":"rotation","optional":true,"type":"number","default":"0","bindable":true,"doc":"Rotation in degrees — any angle, not only quarter turns. Bindable.","details":[],"examples":[]},{"name":"flipX","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Mirror the picture left to right. Bindable.","details":[],"examples":[]},{"name":"flipY","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Mirror the picture top to bottom. Bindable.","details":[],"examples":[]},{"name":"maxZoom","optional":true,"type":"number","default":"5","bindable":false,"doc":"","details":[],"examples":[]},{"name":"grid","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Draw the rule-of-thirds grid while the crop is being changed.","details":[],"examples":[]},{"name":"controls","optional":true,"type":"boolean | ImageCropperControl[]","default":"true","bindable":false,"doc":"The controls under the stage: `true` for the usual set, `false` for none, or the list you want — `['zoom', 'straighten', 'reset']`.","details":[],"examples":[]},{"name":"ratios","optional":true,"type":"boolean | ImageCropperRatio[]","default":"false","bindable":false,"doc":"A row of aspect presets over the controls. `true` for the built-in set, or your own — `[{ label: 'Cover', value: 3 }]`.","details":[],"examples":[]},{"name":"resizable","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Put handles on the window so its size can be dragged.","details":[],"examples":[]},{"name":"inset","optional":true,"type":"number","default":"0.86","bindable":false,"doc":"Widest the crop window may be drawn, as a share of the stage. Leaves room around it so there is somewhere to drag from, and caps how far the handles can be pulled.","details":[],"examples":[]},{"name":"crossorigin","optional":true,"type":"'anonymous' | 'use-credentials'","bindable":false,"doc":"Set for a cross-origin image that has to be exported. Without it the canvas is tainted and `toBlob` throws.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"'20rem'","bindable":false,"doc":"Height of the stage. A number is px, a string any CSS length — a property rather than a class, so `classes.stage` can replace it.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(crop: CropRect) => void","bindable":false,"doc":"Fires whenever the crop settles, with the rectangle in source pixels.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Extra content over the stage — a \"choose a different photo\" button.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"ImageCropperClasses","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"ImageViewer","dir":"image-viewer","entry":"omaris","importPath":"import { ImageViewer } from 'omaris'","summary":"Image viewer — tap a picture and it lifts off the page into a full-screen, zoomable, swipeable lightbox, then settles back where it came from. The feel of react-photo-view, for Svelte.","details":["Wrap the thumbnails and mark each one:","Or drive it yourself, with no thumbnails on the page:","Gestures: pinch and wheel to zoom, double-tap (or click) to toggle it, drag to pan, swipe sideways for the next one — a zoomed picture pans to its edge first — and pull down or pinch in to close. Tap the picture to hide the controls. Keys: arrows, Home/End, +/-/0 for zoom, R to rotate, Escape to close."],"examples":[{"lang":"svelte","code":"<ImageViewer>\n  {#each photos as p}\n    <ImageViewerItem src={p.full} alt={p.alt}>\n      <img src={p.thumb} alt={p.alt} class=\"rounded-lg\" />\n    </ImageViewerItem>\n  {/each}\n</ImageViewer>"},{"lang":"svelte","code":"<ImageViewer images={photos} bind:open bind:index />"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Containment/Image Viewer","category":"Containment","own":true,"stories":["Gallery","Programmatic","Mixed shapes","Overridden","Single with actions"]},"props":[{"name":"images","optional":true,"type":"ImageViewerImage[]","bindable":false,"doc":"Images to show, when not using `ImageViewerItem`s.","details":[],"examples":[]},{"name":"open","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Bindable.","details":[],"examples":[]},{"name":"index","optional":true,"type":"number","default":"0","bindable":true,"doc":"Which image is showing. Bindable.","details":[],"examples":[]},{"name":"loop","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"The arrow keys and buttons wrap from the last picture to the first. Swiping never does — it stops at either end with a rubber band, the way a phone's gallery does.","details":[],"examples":[]},{"name":"maxScale","optional":true,"type":"number","default":"5","bindable":false,"doc":"Furthest you can zoom in.","details":[],"examples":[]},{"name":"toolbar","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Show the top bar: counter, zoom, rotate, close.","details":[],"examples":[]},{"name":"arrows","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Show the prev/next arrows on wide screens.","details":[],"examples":[]},{"name":"dismissible","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Allow the pull-down and the scrim tap to close it.","details":[],"examples":[]},{"name":"actions","optional":true,"type":"Snippet<[{ image: ImageViewerImage; index: number }]>","bindable":false,"doc":"Extra toolbar actions, rendered before the close button.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(index: number) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onclose","optional":true,"type":"() => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"ImageViewerItem","dir":"image-viewer","entry":"omaris","importPath":"import { ImageViewerItem } from 'omaris'","summary":"Marks a thumbnail as openable in the surrounding `ImageViewer`.","details":["Wraps whatever you put inside — an `<img>`, a card, an avatar — in a button, and remembers where it is so the viewer can open from, and close back to, that exact spot."],"examples":[],"classesType":null,"parts":[],"variants":[],"story":{"title":"Containment/Image Viewer","category":"Containment","own":false,"stories":["Gallery","Programmatic","Mixed shapes","Overridden","Single with actions"]},"props":[{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"IndexScrubber","dir":"index-scrubber","entry":"omaris","importPath":"import { IndexScrubber } from 'omaris'","summary":"The A-Z rail down the side of a long list — the one every phone's contacts app has, and almost nothing on the web does.","details":["Drag it and the list follows your thumb immediately; let go and it stops where you left it. Tap a letter and it scrolls there smoothly instead — a drag is aiming, a tap is a destination, and they should not feel the same.","**The letters magnify under the finger.** Each one is scaled and pushed toward the content by a Gaussian falloff around the pointer, so the rail swells into a lens rather than highlighting one row: the letter you are on is legible at a glance without a callout, and the ones either side of it tell you which way to move. The callout is there anyway, as a morphing MD3 shape, because a thumb covers the rail it is dragging.","**It condenses instead of overflowing.** A rail that cannot fit every letter in the height it has drops to every second or third and puts a dot between them, exactly as iOS does — and the drag still addresses all of them, so a letter that isn't drawn is still reachable.","Given sections whose `id`s are on the page it finds the scroller itself, scrolls to them, and tracks which one you are in as you scroll normally. Give it `onselect` instead and it will only report.","The keyboard gets a real path through it: one tab stop, then the arrows walk the letters and Home/End jump to the ends."],"examples":[{"lang":"svelte","code":"const groups = groupByInitial(contacts, (c) => c.name, { fill: true });\n\n<div class=\"relative\">\n  <List>…sections with `id={group.id}`…</List>\n  <IndexScrubber sections={groups} class=\"absolute inset-y-0 end-1\" />\n</div>"}],"classesType":"IndexScrubberClasses","parts":[{"name":"root","doc":"The frame. Position it — `absolute inset-y-0 end-1`, usually."},{"name":"rail","doc":"The rail itself. It grows a surface under it while it is being dragged, which is what stops the letters from sitting on top of the list they are scrolling."},{"name":"track","doc":"The letters' box. Every row is an equal share of its height."},{"name":"row","doc":"One letter."},{"name":"dot","doc":"A row standing in for the letters this rail had no room for."},{"name":"bubble","doc":"The callout beside the finger."}],"variants":[{"name":"side","doc":"","default":"end","values":[{"name":"end","doc":"The usual: the rail on the trailing edge, letters bulging inward."},{"name":"start","doc":""}]},{"name":"scrubbing","doc":"","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Navigation/IndexScrubber","category":"Navigation","own":true,"stories":["Playground","Against a list","Not enough room","Leading edge","Overridden"]},"props":[{"name":"sections","optional":false,"type":"IndexSection[]","bindable":false,"doc":"The stops, in the order the list has them. `groupByInitial` builds these.","details":[],"examples":[]},{"name":"active","optional":true,"type":"string","bindable":true,"doc":"The section currently in view. Bindable.","details":[],"examples":[]},{"name":"onselect","optional":true,"type":"(key: string, section: IndexSection) => void","bindable":false,"doc":"Called on every change, dragging included.","details":[],"examples":[]},{"name":"container","optional":true,"type":"HTMLElement | string | null","default":"null","bindable":false,"doc":"The scroller. A selector, an element, or left out — in which case the nearest scrollable ancestor of the target section is used, falling back to the page.","details":[],"examples":[]},{"name":"offset","optional":true,"type":"number","default":"0","bindable":false,"doc":"Distance from the top of the scroller that counts as \"at\" a section, in px.","details":[],"examples":[]},{"name":"scroll","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Scroll to the section. Off leaves the scrolling entirely to `onselect`.","details":[],"examples":[]},{"name":"observe","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Follow the scroller and keep `active` current as the user scrolls normally.","details":[],"examples":[]},{"name":"side","optional":true,"type":"'end' | 'start'","default":"'end'","bindable":false,"doc":"Which edge the rail is pinned to. It only decides which way the letters bulge.","details":[],"examples":[]},{"name":"magnify","optional":true,"type":"number","default":"0.85","bindable":false,"doc":"The magnification under the finger. `0` turns it off and leaves a plain rail.","details":[],"examples":[]},{"name":"spread","optional":true,"type":"number","default":"46","bindable":false,"doc":"How far the magnification reaches, in px. Wider is softer.","details":[],"examples":[]},{"name":"bulge","optional":true,"type":"number","default":"14","bindable":false,"doc":"How far the swollen letters lean toward the content, in px.","details":[],"examples":[]},{"name":"bubble","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"The callout beside the finger.","details":[],"examples":[]},{"name":"bubbleShape","optional":true,"type":"ShapeName","default":"'cookie-9'","bindable":false,"doc":"Its outline. Any of the 36 in the shape library.","details":[],"examples":[]},{"name":"bubbleSize","optional":true,"type":"number","default":"60","bindable":false,"doc":"Its size, in px.","details":[],"examples":[]},{"name":"haptics","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"A tick as each new letter comes under the finger. Follows the shared store.","details":[],"examples":[]},{"name":"rowHeight","optional":true,"type":"number","default":"13","bindable":false,"doc":"Height one letter needs, in px — what decides when the rail condenses.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","default":"'Section index'","bindable":false,"doc":"Accessible name for the rail.","details":[],"examples":[]},{"name":"callout","optional":true,"type":"Snippet<[IndexSection]>","bindable":false,"doc":"Replace the callout. It is handed the section under the finger.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"IndexScrubberClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"InlineEdit","dir":"inline-edit","entry":"omaris","importPath":"import { InlineEdit } from 'omaris'","summary":"Click the text, it becomes a field. Nothing on the page moves.","details":["That last part is the whole component. The usual way to build this — swap a `<span>` for an `<input>` — changes the box's height, its padding and its font all at once, so the line jumps, the row below it jumps, and on a card the whole layout reflows twice per edit. Here the reading view, the input and an invisible copy of the text share one grid cell: the copy sizes the cell, the other two stretch to fill it, and all three carry identical type and padding. The box is the same size before, during and after — and it grows with what is typed, in one place, as you type."],"examples":[{"lang":"svelte","code":"<InlineEdit bind:value={name} onsave={rename} />\n<InlineEdit bind:value={note} multiline variant=\"body-sm\" />"}],"classesType":"InlineEditClasses","parts":[{"name":"root","doc":"The stack. Its size comes from the invisible copy inside it."},{"name":"sizer","doc":"The invisible copy of the text. Nothing else sizes this component."},{"name":"view","doc":"What you see when it is not being edited."},{"name":"control","doc":"The control. Same font, same padding, same border box as the view."},{"name":"pencil","doc":"The pencil. Sits in space that is reserved whether it shows or not."},{"name":"placeholder","doc":"The text when there is none — \"Add a description\"."},{"name":"error","doc":"The error line. Floats under the box, so it never pushes anything."},{"name":"actions","doc":"The confirm/cancel pair, when `actions` is on. Also floating."},{"name":"action","doc":"One of those buttons."},{"name":"busy","doc":"The spinner shown while an async `onsave` is in flight."}],"variants":[{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]},{"name":"pencil","doc":"Reserve room at the end for the pencil, shown or not.","default":"true","values":[{"name":"true","doc":""},{"name":"false","doc":""}]},{"name":"block","doc":"Fill the container instead of hugging the text.","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]},{"name":"align","doc":"","default":"start","values":[{"name":"start","doc":""},{"name":"center","doc":""},{"name":"end","doc":""}]}],"story":{"title":"Inputs/Inline Edit","category":"Inputs","own":true,"stories":["Playground","No layout shift","Sizes","Multiline","Empty","Saving","Validated","Confirm buttons","Opened from outside","Read only and disabled","Overridden"]},"props":[{"name":"value","optional":true,"type":"string","default":"''","bindable":true,"doc":"The text. Bindable, and only written once a save succeeds.","details":[],"examples":[]},{"name":"editing","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Whether the field is open. Bindable — the way to open it from a button.","details":[],"examples":[]},{"name":"size","optional":true,"type":"InlineEditSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"align","optional":true,"type":"InlineEditAlign","default":"'start'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"multiline","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"A `textarea` that grows by the line instead of an input.","details":[],"examples":[]},{"name":"block","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Fill the container rather than hugging the text.","details":[],"examples":[]},{"name":"trigger","optional":true,"type":"InlineEditTrigger","default":"'click'","bindable":false,"doc":"What opens the field. `manual` leaves it to `bind:editing`.","details":[],"examples":[]},{"name":"submitOn","optional":true,"type":"InlineEditSubmit","default":"'both'","bindable":false,"doc":"When the change is kept. Escape always cancels.","details":[],"examples":[]},{"name":"pencil","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Show the pencil on hover. Its space is reserved either way.","details":[],"examples":[]},{"name":"actions","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Float a confirm/cancel pair under the field — worth it on touch.","details":[],"examples":[]},{"name":"selectOnEdit","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Select the whole value when the field opens.","details":[],"examples":[]},{"name":"placeholder","optional":true,"type":"string","default":"'Empty'","bindable":false,"doc":"Shown, greyed, when the value is empty.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible name — what this text *is*. Required in practice.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"readonly","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Reads, never edits. The hover hint and the pencil go away.","details":[],"examples":[]},{"name":"maxlength","optional":true,"type":"number","bindable":false,"doc":"","details":[],"examples":[]},{"name":"validate","optional":true,"type":"(value: string) => string | null","bindable":false,"doc":"Checked before saving. Return a message to refuse the change and keep the field open; return `null` to let it through.","details":[],"examples":[]},{"name":"onsave","optional":true,"type":"(value: string) => void | Promise<unknown>","bindable":false,"doc":"Called with the new text. Return a promise and the field waits on it, showing a spinner — a rejection keeps the field open with the message.","details":[],"examples":[]},{"name":"oncancel","optional":true,"type":"() => void","bindable":false,"doc":"Called when the edit is abandoned.","details":[],"examples":[]},{"name":"view","optional":true,"type":"Snippet<[string]>","bindable":false,"doc":"Replaces the reading view — a badge, an avatar beside the name.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"InlineEditClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"ref","optional":true,"type":"HTMLInputElement | HTMLTextAreaElement | null","default":"null","bindable":true,"doc":"","details":[],"examples":[]}]},{"name":"Input","dir":"input","entry":"omaris","importPath":"import { Input } from 'omaris'","summary":"Text field.","details":["A quiet frame that wakes up on focus: the border takes the accent and a soft ring blooms around it. The label sits above the field and the supporting text below, so nothing moves when the field is filled in.","Everything a field usually needs is built in — a password eye, a clear button, affixes, a counter, a loading state — so a form is one line per field instead of a nest of wrappers."],"examples":[],"classesType":"InputClasses","parts":[{"name":"root","doc":"Wrapper: label, field, supporting text."},{"name":"field","doc":"The frame: border, background, height, adornment layout."},{"name":"control","doc":"The bare <input>; the frame owns every decoration."},{"name":"label","doc":""},{"name":"adornment","doc":"Icon slots at either end of the frame."},{"name":"affix","doc":"Flat text glued to the value — \"https://\", \"kg\"."},{"name":"action","doc":"An interactive trailing control: reveal, clear."},{"name":"support","doc":"Helper line under the field, and the counter beside it."},{"name":"counter","doc":""}],"variants":[{"name":"variant","doc":"","default":"outline","values":[{"name":"outline","doc":"The default: a hairline frame on the page background."},{"name":"filled","doc":"Softer — a tinted well with no border until you touch it."},{"name":"ghost","doc":"No frame at all, for fields nested in another surface."}]},{"name":"size","doc":"","default":"default","values":[{"name":"sm","doc":""},{"name":"default","doc":""},{"name":"lg","doc":""}]},{"name":"invalid","doc":"","default":"false","values":[{"name":"true","doc":""}]},{"name":"trailing","doc":"Tightens the trailing padding when a round action sits at the end.","values":[{"name":"true","doc":""}]}],"story":{"title":"Inputs/Text Field","category":"Inputs","own":true,"stories":["Playground","Variants","With icons","Sizes","Password","Clearable, counter and loading","Prefix and suffix","States","Formats","Dashboard form"]},"props":[{"name":"variant","optional":true,"type":"InputVariant","default":"'outline'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"InputSize","default":"'default'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"type","optional":true,"type":"HTMLInputTypeAttribute","default":"'text'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"format","optional":true,"type":"InputFormatName | InputFormat","bindable":false,"doc":"What the field accepts. A built-in name (`decimal`, `slug`, `phone`, …) or your own `InputFormat`. Rejected characters never make it in, and the format's keyboard hints come along with it.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Label above the field. Wired to the control, so clicking focuses it.","details":[],"examples":[]},{"name":"required","optional":true,"type":"boolean","bindable":false,"doc":"Marks the label required and sets `required` on the control. Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"supportingText","optional":true,"type":"string","bindable":false,"doc":"Helper line under the field. Turns into the error text when invalid.","details":[],"examples":[]},{"name":"invalid","optional":true,"type":"boolean","bindable":false,"doc":"Marks the field invalid and wires up aria-invalid. Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"value","optional":true,"type":"string | number | null","bindable":true,"doc":"","details":[],"examples":[]},{"name":"revealable","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Show the eye toggle on a password field. On by default — that's the behaviour every password field wants and nobody wants to rebuild.","details":[],"examples":[]},{"name":"revealed","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Starts a password field revealed. Bindable.","details":[],"examples":[]},{"name":"clearable","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Adds a clear (×) button once the field has a value.","details":[],"examples":[]},{"name":"loading","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Swaps the trailing controls for a spinner and blocks interaction.","details":[],"examples":[]},{"name":"counter","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Live `n/maxlength` count beside the supporting text.","details":[],"examples":[]},{"name":"prefix","optional":true,"type":"string","bindable":false,"doc":"Flat text glued to the start of the value — \"https://\", \"@\".","details":[],"examples":[]},{"name":"suffix","optional":true,"type":"string","bindable":false,"doc":"Flat text glued to the end of the value — \"kg\", \".com\".","details":[],"examples":[]},{"name":"start","optional":true,"type":"Snippet","bindable":false,"doc":"Leading icon.","details":[],"examples":[]},{"name":"end","optional":true,"type":"Snippet","bindable":false,"doc":"Trailing icon or control, after the built-in actions.","details":[],"examples":[]},{"name":"supporting","optional":true,"type":"Snippet","bindable":false,"doc":"Richer supporting text — a link, a strength meter.","details":[],"examples":[]},{"name":"onclear","optional":true,"type":"() => void","bindable":false,"doc":"Fires after the clear button empties the field.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"InputClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"ref","optional":true,"type":"HTMLInputElement | null","default":"null","bindable":true,"doc":"","details":[],"examples":[]}]},{"name":"JsonViewer","dir":"json-viewer","entry":"omaris","importPath":"import { JsonViewer } from 'omaris'","summary":"A JSON tree you can actually read: collapsible, searchable, and coloured with the same `--code-*` tokens as `CodeBlock`, so a payload in a docs page and a payload in a debug panel look like the same language.","details":["A collapsed node still tells you what is inside it — `{ id, name, +3 }`, `[ 12 items ]` — because the usual alternative, an opaque `{…}`, means expanding every node just to find the one you wanted.","Filtering keeps matches *and their ancestors*, so a hit five levels down arrives with the path that leads to it rather than as an orphan row."],"examples":[{"lang":"svelte","code":"<JsonViewer value={response} depth={2} search copy />"}],"classesType":"JsonViewerClasses","parts":[{"name":"root","doc":""},{"name":"header","doc":"Filter box and the toolbar buttons."},{"name":"search","doc":""},{"name":"action","doc":""},{"name":"viewport","doc":"The scrolling tree."},{"name":"row","doc":"One row: the toggle, the key, and either a value or a brace."},{"name":"toggle","doc":"The disclosure triangle. A leaf gets an empty one, to keep the column."},{"name":"spacer","doc":""},{"name":"key","doc":""},{"name":"punctuation","doc":""},{"name":"value","doc":"A scalar. The colour says which type it is."},{"name":"preview","doc":"The summary drawn inside a collapsed brace."},{"name":"count","doc":"`12 items`, at the end of a container row."},{"name":"copy","doc":"Copy-this-node, revealed on hover."},{"name":"empty","doc":"Nothing matched the filter."}],"variants":[{"name":"variant","doc":"","default":"outlined","values":[{"name":"outlined","doc":""},{"name":"filled","doc":""},{"name":"ghost","doc":""}]},{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""}]}],"story":{"title":"Data display/JsonViewer","category":"Data Display","own":true,"stories":["Playground","Collapsed previews","Filtering","From a string","Variants","Height replaced"]},"props":[{"name":"value","optional":false,"type":"unknown","bindable":false,"doc":"Any value. A string that parses as JSON is parsed; one that doesn't is shown as a string.","details":[],"examples":[]},{"name":"name","optional":true,"type":"string","default":"'$'","bindable":false,"doc":"Name for the root node.","details":[],"examples":[]},{"name":"variant","optional":true,"type":"JsonViewerVariant","default":"'outlined'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"JsonViewerSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"depth","optional":true,"type":"number","default":"1","bindable":false,"doc":"How many levels start open. `Infinity` opens everything.","details":[],"examples":[]},{"name":"search","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Show the filter box.","details":[],"examples":[]},{"name":"copy","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Per-node copy buttons, and a copy-all in the header.","details":[],"examples":[]},{"name":"maxStringLength","optional":true,"type":"number","default":"120","bindable":false,"doc":"Longest string shown before it is elided.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"'20rem'","bindable":false,"doc":"Height of the scroll area. A number is px, a string any CSS length — a property rather than a class, so `classes.viewport` can replace it.","details":[],"examples":[]},{"name":"indent","optional":true,"type":"number","default":"14","bindable":false,"doc":"Indent per level, in px.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"JsonViewerClasses","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"Kanban","dir":"kanban","entry":"omaris","importPath":"import { Kanban } from 'omaris'","summary":"A board of columns you drag cards between.","details":["Three decisions shape this one.","**Pointer events, not HTML drag-and-drop.** The native API cannot be styled, does not fire on touch at all, and hands you a drag image the browser drew. This tracks the pointer directly, so the same code works with a mouse, a finger and a pen. The gesture's listeners live on the window, never on the card — a card the render can remove is no place to keep a pointer — so a release anywhere, on or off the board, always ends the drag.","**The list is never mutated mid-drag.** What you see while dragging is a *preview* — the card dimmed in place, or a gap put where it would land — and `columns` only changes when you let go. So a drag that is cancelled costs nothing, and the data never passes through a state that was not asked for.","**It works from the keyboard.** `Space` picks a card up, the arrows move it between positions and columns, `Space` drops it and `Escape` puts it back. A board that can only be used with a mouse is not finished.","Cards slide rather than jump: the preview is keyed by the item's identity and animated with FLIP, so every card that has to move to make room is seen moving, and the ghost flies into the gap on release."],"examples":[{"lang":"svelte","code":"<Kanban bind:columns key={(task) => task.id} onmove={save}>\n  {#snippet card(task)}<Text>{task.title}</Text>{/snippet}\n</Kanban>"}],"classesType":"KanbanClasses","parts":[{"name":"root","doc":"The horizontally scrolling board."},{"name":"column","doc":"One column."},{"name":"header","doc":""},{"name":"dot","doc":"The tone dot before the title."},{"name":"title","doc":""},{"name":"count","doc":"`4` or `4 / 5` when the column has a limit."},{"name":"over","doc":"The count, when the column is over its limit."},{"name":"lock","doc":"The padlock on a locked column."},{"name":"list","doc":"The scrolling stack of cards."},{"name":"cell","doc":"The keyed wrapper FLIP measures — one per card, or the gap."},{"name":"card","doc":"One card."},{"name":"placeholder","doc":"The gap showing where the card would land."},{"name":"ghost","doc":"The card under the pointer. Fixed to the viewport, never in the flow."},{"name":"empty","doc":"Shown in a column with nothing in it."},{"name":"add","doc":"\"Add a card\", under the stack."},{"name":"status","doc":"Live region announcing what a keyboard drag is doing."}],"variants":[{"name":"density","doc":"","default":"comfortable","values":[{"name":"comfortable","doc":""},{"name":"compact","doc":""}]}],"story":{"title":"Data display/Kanban","category":"Data Display","own":true,"stories":["Playground","Dragging","Limits and locks","Rich cards","Keyboard","Compact, with adding","Overridden"]},"props":[{"name":"columns","optional":false,"type":"KanbanColumn<T>[]","bindable":true,"doc":"The board. Bindable — a drop rewrites it.","details":[],"examples":[]},{"name":"card","optional":false,"type":"Snippet<[T, KanbanCardContext<T>]>","bindable":false,"doc":"How to draw one card.","details":[],"examples":[]},{"name":"header","optional":true,"type":"Snippet<[KanbanColumn<T>]>","bindable":false,"doc":"Replaces a column's whole header row — dot, title, count and `columnActions`.","details":[],"examples":[]},{"name":"columnActions","optional":true,"type":"Snippet<[KanbanColumn<T>]>","bindable":false,"doc":"Rendered at the end of the default header — a menu, usually.","details":[],"examples":[]},{"name":"key","optional":true,"type":"(item: T, index: number) => string | number","bindable":false,"doc":"Identity, which is what keeps a card the same element while it slides. Defaults to the item's `id`, then its index.","details":[],"examples":[]},{"name":"label","optional":true,"type":"(item: T) => string","bindable":false,"doc":"Names a card for assistive tech during a keyboard drag.","details":[],"examples":[]},{"name":"density","optional":true,"type":"KanbanDensity","default":"'comfortable'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"columnWidth","optional":true,"type":"number | string","default":"272","bindable":false,"doc":"Column width. A number is px, a string any CSS length.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"'28rem'","bindable":false,"doc":"Board height. A number is px, a string any CSS length — a property rather than a class, so `classes.root` can replace it.","details":[],"examples":[]},{"name":"emptyText","optional":true,"type":"string","default":"'Nothing here'","bindable":false,"doc":"Shown in an empty column.","details":[],"examples":[]},{"name":"addable","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Show the \"add a card\" row under each column.","details":[],"examples":[]},{"name":"addLabel","optional":true,"type":"string","default":"'Add a card'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onmove","optional":true,"type":"(move: KanbanMove<T>) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onadd","optional":true,"type":"(columnId: string) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"KanbanClasses","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"Kbd","dir":"kbd","entry":"omaris","importPath":"import { Kbd } from 'omaris'","summary":"A key cap — the `<kbd>` a shortcut is drawn with.","details":["Give it `keys` and it draws the whole combo, one cap per key, in the platform's own spelling: `keys=\"mod+k\"` is ⌘ K on a Mac and Ctrl + K everywhere else, with the modifiers in the order that keyboard writes them. Each symbol carries its name for a screen reader, so ⌘ is read as \"Command\" rather than skipped.","Give it children instead and it is one cap around whatever you wrote.","The server does not know the keyboard, so it renders Ctrl; the cap swaps to ⌘ on hydration. Pass `platform` to pin it."],"examples":[{"lang":"svelte","code":"<Kbd keys=\"mod+k\" />\n<Kbd keys={['shift', 'enter']} size=\"sm\" />\n<Kbd>Esc</Kbd>"}],"classesType":"KbdClasses","parts":[{"name":"root","doc":"The combo. Not a cap itself — the row the caps sit in."},{"name":"key","doc":"One key cap."},{"name":"separator","doc":"The `+` between caps on a non-Apple keyboard."}],"variants":[{"name":"variant","doc":"","default":"raised","values":[{"name":"raised","doc":"A cap with depth: a heavier bottom edge, like the real key."},{"name":"flat","doc":"Flat, for inside a menu row or a chip where depth is noise."}]},{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]}],"story":{"title":"Data Display/Kbd","category":"Data Display","own":true,"stories":["Playground","Platforms","Sizes","Variants","Single keys","As a string","Right to left","Overridden"]},"props":[{"name":"keys","optional":true,"type":"string | readonly string[]","bindable":false,"doc":"The combo to draw: `'mod+k'`, `'shift+enter'`, or the same as an array. `mod` is ⌘ on Apple devices and Ctrl elsewhere. Without it, the children are drawn as one cap.","details":[],"examples":[]},{"name":"variant","optional":true,"type":"KbdVariant","default":"'raised'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"KbdSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"platform","optional":true,"type":"ShortcutPlatform","default":"'auto'","bindable":false,"doc":"Which keyboard to draw for. `auto` asks the browser once it has hydrated, and draws Ctrl until then.","details":[],"examples":[]},{"name":"separator","optional":true,"type":"string | false","bindable":false,"doc":"Drawn between caps. Defaults to nothing on a Mac, where combos are written ⌘K, and `+` elsewhere, where they are written Ctrl+K. `false` for none anywhere.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"KbdClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"One cap's content, when `keys` is not set.","details":[],"examples":[]}]},{"name":"Label","dir":"label","entry":"omaris","importPath":"import { Label } from 'omaris'","summary":"A form label. `for` wires it to its control, so clicking it focuses.","details":["Most omaris fields take a `label` prop and render this themselves; reach for it directly when you are labelling something that doesn't."],"examples":[],"classesType":null,"parts":[],"variants":[],"story":{"title":"Inputs/Label","category":"Inputs","own":true,"stories":["Playground","Required","Disabled","Labelling a control","Overridden"]},"props":[{"name":"required","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Appends a `*`, announced as \"required\" by screen readers.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"LineChart","dir":"chart","entry":"omaris/chart","importPath":"import { LineChart } from 'omaris/chart'","summary":"Line chart.","details":["The same `series` shape as the other charts, so swapping a line for an area or a bar is a one-word change. `references`, `annotations`, `brush`, `zoom`, `csv` and `error` are shared with them too."],"examples":[{"lang":"svelte","code":"<LineChart data={rows} x=\"date\" y=\"latency\" />"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Charts","category":"Data Display","own":false,"stories":["Area","Line","Bar","Pie and donut","Scatter","Sparkline","Empty","References and annotations","Brush and zoom","Legend isolate and CSV","Error","Combo","Radar","Radial bar and gauge","Funnel","Treemap","Candlestick"]},"props":[{"name":"curve","optional":true,"type":"ChartCurve","default":"'smooth'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"points","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Mark each data point.","details":[],"examples":[]},{"name":"dashed","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Dash the line — for a forecast or a target.","details":[],"examples":[]},{"name":"data","optional":false,"type":"T[]","bindable":false,"doc":"","details":[],"examples":[]},{"name":"x","optional":true,"type":"Field<T>","bindable":false,"doc":"The category or time field.","details":[],"examples":[]},{"name":"y","optional":true,"type":"Field<T>","bindable":false,"doc":"The value field. Ignored once `series` names its own.","details":[],"examples":[]},{"name":"series","optional":true,"type":"ChartSeries<T>[]","bindable":false,"doc":"Several values per row. Each gets a colour and a legend entry.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"260","bindable":false,"doc":"Plot height. A number is px; a string is any CSS length.","details":[],"examples":[]},{"name":"axis","optional":true,"type":"boolean | 'x' | 'y'","default":"true","bindable":false,"doc":"`true` for both, or just the one you want.","details":[],"examples":[]},{"name":"grid","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"legend","optional":true,"type":"ChartLegend","default":"false","bindable":false,"doc":"`true` shows the legend and lets a click toggle a series off. `'isolate'` makes a click show that series alone, and a second one bring the rest back — which is the move you actually want on a chart with six lines on it.","details":[],"examples":[]},{"name":"tooltip","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"formatX","optional":true,"type":"(value: never) => string","bindable":false,"doc":"Tick labels along the x axis.","details":[],"examples":[]},{"name":"formatY","optional":true,"type":"(value: never) => string","bindable":false,"doc":"Tick labels along the y axis, and the tooltip's values.","details":[],"examples":[]},{"name":"colors","optional":true,"type":"readonly string[]","default":"CHART_COLORS","bindable":false,"doc":"Palette override, cycled across the series.","details":[],"examples":[]},{"name":"padding","optional":true,"type":"number | { top?: number; right?: number; bottom?: number; left?: number }","bindable":false,"doc":"Space around the plot, in px — room for long axis labels.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible description of what the chart shows.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"empty","optional":true,"type":"Snippet","bindable":false,"doc":"Shown in place of the plot when `data` is empty.","details":[],"examples":[]},{"name":"emptyText","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"error","optional":true,"type":"boolean | string | Error","bindable":false,"doc":"Something went wrong. Truthy puts the chart into its error state; a string or an `Error` supplies the message.","details":[],"examples":[]},{"name":"errorText","optional":true,"type":"string","bindable":false,"doc":"The message, when `error` is just `true`.","details":[],"examples":[]},{"name":"errorState","optional":true,"type":"Snippet<[{ message: string }]>","bindable":false,"doc":"Replaces the whole error state.","details":[],"examples":[]},{"name":"onRetry","optional":true,"type":"() => void","bindable":false,"doc":"Offers a \"Try again\" button in the error state.","details":[],"examples":[]},{"name":"csv","optional":true,"type":"boolean | string","default":"false","bindable":false,"doc":"Offer the plotted rows as a CSV download, from a button in the corner. A string names the file.","details":[],"examples":[]},{"name":"csvColumns","optional":true,"type":"(string | { key: string; label?: string; value?: (row: T) => unknown })[]","bindable":false,"doc":"Which fields the download writes, in order. Defaults to every field.","details":[],"examples":[]},{"name":"references","optional":true,"type":"ChartReference[]","bindable":false,"doc":"Lines and bands at fixed values — targets, thresholds, windows.","details":[],"examples":[]},{"name":"annotations","optional":true,"type":"ChartAnnotation[]","bindable":false,"doc":"Notes pinned to a point.","details":[],"examples":[]},{"name":"brush","optional":true,"type":"ChartBrush","bindable":false,"doc":"Drag across the plot to select a range, and zoom the chart to it.","details":[],"examples":[]},{"name":"zoom","optional":true,"type":"ChartZoom","bindable":false,"doc":"Wheel or pinch to zoom, drag to pan.","details":[],"examples":[]}]},{"name":"List","dir":"list","entry":"omaris","importPath":"import { List } from 'omaris'","summary":"MD3 list.","details":["A plain container: the rows carry the styling. `dividers` draws the hairline between rows without every row needing to know whether it's the last one."],"examples":[],"classesType":null,"parts":[],"variants":[{"name":"variant","doc":"","default":"plain","values":[{"name":"plain","doc":"Rows straight on the page."},{"name":"surface","doc":"Rows on a raised surface with rounded ends."},{"name":"outlined","doc":"Same, with a hairline frame."}]},{"name":"dividers","doc":"","values":[{"name":"true","doc":""}]},{"name":"spaced","doc":"Rounds each row and spaces them out — the \"cards in a list\" look.","values":[{"name":"true","doc":""}]},{"name":"padding","doc":"","default":"none","values":[{"name":"none","doc":""},{"name":"sm","doc":""},{"name":"md","doc":""}]}],"story":{"title":"Containment/List","category":"Containment","own":true,"stories":["Playground","Line counts","With slots","With controls","Variants","Spaced","Compact"]},"props":[{"name":"variant","optional":true,"type":"ListVariant","default":"'plain'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"dividers","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Hairline between rows.","details":[],"examples":[]},{"name":"spaced","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Round each row and space them apart.","details":[],"examples":[]},{"name":"padding","optional":true,"type":"'none' | 'sm' | 'md'","default":"'none'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible name for the list.","details":[],"examples":[]},{"name":"as","optional":true,"type":"'div' | 'nav'","default":"'div'","bindable":false,"doc":"The element to render. The default `div` carries `role=\"list\"`, which lets a row be a `<button>` or `<a>` directly — a `<ul>` would need every row wrapped in an `<li>`, and a wrapper can't take the divider. Use `nav` for a navigation list.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"ListItem","dir":"list","entry":"omaris","importPath":"import { ListItem } from 'omaris'","summary":"MD3 list item — one, two or three lines.","details":["The line count is inferred: a row with supporting text is two lines, and one with `lines={3}` clamps the supporting text at three. Heights follow MD3's 56 / 72 / 88dp.","Give it `href` or `onclick` and it becomes a real target — button or link, with the state layer, ripple and focus ring — rather than a div with a cursor."],"examples":[],"classesType":"ListItemClasses","parts":[{"name":"root","doc":""},{"name":"leading","doc":""},{"name":"body","doc":""},{"name":"headline","doc":""},{"name":"supporting","doc":"The second (and third) line."},{"name":"trailing","doc":"Right-hand meta — a time, a count, a switch."}],"variants":[{"name":"lines","doc":"","values":[{"name":"1","doc":""},{"name":"2","doc":""},{"name":"3","doc":""}]},{"name":"interactive","doc":"","values":[{"name":"true","doc":""}]},{"name":"selected","doc":"","values":[{"name":"true","doc":""}]},{"name":"inset","doc":"Aligns a row with no leading slot to those that have one.","values":[{"name":"true","doc":""}]},{"name":"density","doc":"","default":"comfortable","values":[{"name":"comfortable","doc":""},{"name":"compact","doc":""}]}],"story":{"title":"Containment/List","category":"Containment","own":false,"stories":["Playground","Line counts","With slots","With controls","Variants","Spaced","Compact"]},"props":[{"name":"headline","optional":true,"type":"string","bindable":false,"doc":"Main line.","details":[],"examples":[]},{"name":"supportingText","optional":true,"type":"string","bindable":false,"doc":"Second line. Its presence makes the row two lines tall.","details":[],"examples":[]},{"name":"lines","optional":true,"type":"ListItemLines","bindable":false,"doc":"Force the line count rather than inferring it.","details":[],"examples":[]},{"name":"density","optional":true,"type":"ListItemDensity","default":"'comfortable'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"interactive","optional":true,"type":"boolean","bindable":false,"doc":"Force the interactive treatment.","details":[],"examples":[]},{"name":"selected","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Chosen state — the current page in a nav list, say.","details":[],"examples":[]},{"name":"inset","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Indent to line up with rows that have a leading slot.","details":[],"examples":[]},{"name":"ripple","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"ListItemClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"leading","optional":true,"type":"Snippet","bindable":false,"doc":"Leading slot — icon, avatar, checkbox.","details":[],"examples":[]},{"name":"trailing","optional":true,"type":"Snippet","bindable":false,"doc":"Trailing slot — meta text, a switch, an overflow menu.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Rich body, in place of `headline` / `supportingText`.","details":[],"examples":[]},{"name":"variant","optional":true,"type":"ButtonVariant","bindable":false,"doc":"Fill style. MD3's five, plus `link` for inline navigation.","details":[],"examples":[]},{"name":"tone","optional":true,"type":"ButtonTone","bindable":false,"doc":"Color role the fill style paints with.","details":[],"examples":[]},{"name":"size","optional":true,"type":"ButtonSize","bindable":false,"doc":"MD3 Expressive heights: 32 / 40 / 56 / 96 / 136dp.","details":[],"examples":[]},{"name":"shape","optional":true,"type":"ButtonShape","bindable":false,"doc":"Pill (`round`) or MD3 rounded rectangle (`square`).","details":[],"examples":[]},{"name":"icon","optional":true,"type":"boolean","bindable":false,"doc":"Square, label-less button. Requires an `aria-label`.","details":[],"examples":[]},{"name":"confetti","optional":true,"type":"boolean | ConfettiOptions","bindable":false,"doc":"Confetti on press. `true` for the default burst, or any `ConfettiOptions` — `confetti={{ preset: 'fireworks' }}`.","details":[],"examples":[]},{"name":"loading","optional":true,"type":"boolean","bindable":false,"doc":"Grows a spinner in at the start of the button and blocks interaction. The label stays put; only an `icon` button swaps its icon out.","details":[],"examples":[]},{"name":"toggle","optional":true,"type":"boolean","bindable":false,"doc":"Turns the button into a two-state toggle driven by `pressed`. Ignored when `href` is set — a link has no pressed state.","details":[],"examples":[]},{"name":"pressed","optional":true,"type":"boolean","bindable":true,"doc":"Selected state of a toggle button. Bindable.","details":[],"examples":[]}]},{"name":"LogViewer","dir":"log-viewer","entry":"omaris","importPath":"import { LogViewer } from 'omaris'","summary":"A log console: levels, filtering, search, ANSI colour, expandable rows and a tail that follows.","details":["The hard part of a log view is not the styling, it is that logs are *long*. Rows are virtualised — only the slice on screen exists in the DOM — so a hundred thousand lines scroll as smoothly as ten, and the scrollbar still tells the truth about how much there is. An expanded row's panel is the one thing whose height is measured rather than known, and there are never more than a few of those open, so the arithmetic stays a short walk over a sorted list. Wrapping turns virtualisation off deliberately: a wrapped line has no knowable height until it is laid out, and a guessed height is a jumping scrollbar.","Following the tail sticks to the bottom while output arrives and lets go the moment you scroll up, which is the behaviour every terminal has and most web log views forget."],"examples":[{"lang":"svelte","code":"<LogViewer {lines} follow search levels={['error', 'warn']} />"}],"classesType":"LogViewerClasses","parts":[{"name":"root","doc":""},{"name":"header","doc":""},{"name":"search","doc":"The search field — an `Input`, so this lands on its root."},{"name":"searchNav","doc":"Match position and the previous / next buttons, beside the field."},{"name":"matchCount","doc":"`3 / 12`."},{"name":"filters","doc":"The level chips."},{"name":"filter","doc":"One level chip — a `Chip`, so this lands on its root."},{"name":"action","doc":"The wrap / follow / clear toggles."},{"name":"tools","doc":"Copy-all and download, at the end of the header."},{"name":"tool","doc":"A header icon button."},{"name":"viewport","doc":"The scroll container."},{"name":"canvas","doc":"Sized to the whole log, so the scrollbar is honest while rows are virtual."},{"name":"window","doc":"The visible slice, pushed down to where it belongs."},{"name":"row","doc":"One line."},{"name":"toggle","doc":"The chevron in the gutter of a row that has details."},{"name":"gutter","doc":""},{"name":"time","doc":""},{"name":"level","doc":"The level tag: fixed width, so messages line up."},{"name":"source","doc":"`api`, `worker-3` — where the line came from."},{"name":"message","doc":""},{"name":"mark","doc":"A search hit inside a line."},{"name":"markActive","doc":"The hit on the row search is currently parked on."},{"name":"rowAction","doc":"Copy-this-line, revealed on hover at the end of the row."},{"name":"details","doc":"The panel under an expanded row."},{"name":"detailsCard","doc":"Its card: sticky, so it stays in view while the log scrolls sideways."},{"name":"detailsText","doc":"A string detail — a stack trace, a payload dump."},{"name":"jump","doc":"\"Jump to the newest line\", while the tail is not being followed. A sibling of the viewport rather than a child: an absolute box inside a scroll container scrolls away with the log it is meant to float over."},{"name":"empty","doc":""},{"name":"count","doc":"The count, at the end of the header."},{"name":"live","doc":"The screen-reader announcement of the newest line while following."}],"variants":[{"name":"size","doc":"","default":"md","values":[{"name":"md","doc":""}]},{"name":"wrap","doc":"Wrapping turns virtualisation off — a wrapped row has no height until it is laid out, and guessing one makes the scrollbar jump.","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Data display/LogViewer","category":"Data Display","own":true,"stories":["Playground","Parsed from strings","Twenty thousand lines","ANSI output","Structured with details","Following a tail","Search","Wrapped and restyled"]},"props":[{"name":"lines","optional":false,"type":"(string | LogEntry)[]","bindable":false,"doc":"Raw lines, one string each, or entries with their parts already split out.","details":[],"examples":[]},{"name":"size","optional":true,"type":"LogViewerSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"levels","optional":true,"type":"LogLevel[]","bindable":true,"doc":"Which levels to show. Left off, all of them. Lines with no level are always shown, unless this is an empty array. Bindable.","details":[],"examples":[]},{"name":"filters","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Show the level filter chips.","details":[],"examples":[]},{"name":"search","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Show the search box.","details":[],"examples":[]},{"name":"follow","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Stick to the newest line as output arrives. Bindable.","details":[],"examples":[]},{"name":"wrappable","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Offer the wrap toggle in the header.","details":[],"examples":[]},{"name":"wrap","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Wrap long lines instead of scrolling sideways. Bindable.","details":[],"examples":[]},{"name":"lineNumbers","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Line numbers down the left.","details":[],"examples":[]},{"name":"timestamps","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Draw the timestamp column.","details":[],"examples":[]},{"name":"tools","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Copy-all and download buttons in the header.","details":[],"examples":[]},{"name":"filename","optional":true,"type":"string","default":"'output.log'","bindable":false,"doc":"Name of the file the download button saves.","details":[],"examples":[]},{"name":"expandable","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Rows with `details` open on click, `Enter` or `Space`.","details":[],"examples":[]},{"name":"expanded","optional":true,"type":"number[]","default":"[]","bindable":true,"doc":"Indices (into `lines`) of the rows whose details are open. Bindable.","details":[],"examples":[]},{"name":"onrowclick","optional":true,"type":"(row: LogRow, index: number) => void","bindable":false,"doc":"Called when a row is clicked or activated from the keyboard.","details":[],"examples":[]},{"name":"formatTime","optional":true,"type":"(time: Date) => string","bindable":false,"doc":"How a timestamp is written. Defaults to a 12-hour clock with seconds, `02:05:09 PM`, in the page's language and Western digits. A bare `14:05:09` at the start of a raw line is read as today at that time.","details":[],"examples":[]},{"name":"emptyText","optional":true,"type":"string","default":"'Nothing to show.'","bindable":false,"doc":"Shown when nothing is left after filtering.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"'24rem'","bindable":false,"doc":"Height of the console. A number is px, a string any CSS length — a property rather than a class, so `classes.viewport` can replace it.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"LogViewerClasses","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"Magnifier","dir":"magnifier","entry":"omaris","importPath":"import { Magnifier } from 'omaris'","summary":"A loupe that really magnifies — text included.","details":["Wrap anything. A pointer over it (or a press and hold on a touch screen) raises a lens that follows the finger and shows what is under it, larger.","**It is not a zoomed screenshot.** The lens holds a live copy of the content, scaled with a CSS transform, so the browser lays the text out and rasterises it *at the magnified size*: glyphs are as crisp at 4× as they are at 1×, and vector art, borders and shadows come with them. A background-image trick can only ever enlarge pixels, which is why the usual \"product zoom\" turns type to mush.","The copy is taken when the lens opens and is inert — no ids collide, no handler fires twice, nothing inside it is focusable. Content that changes while the lens is up wants `live`, which re-takes it as the DOM changes.","On a touch screen it behaves like the system loupe: press and hold for `hold` ms to summon it, then drag. The glass rides *above* the finger and — the part that is usually got wrong — it looks where it sits, not at what the finger is covering. Aiming a loupe at the one spot you cannot see is guesswork; here the thing under the glass is the thing you are inspecting, and the finger stays out of the picture. A finger that travels before the hold is up was scrolling, and is left alone — so the page still scrolls normally over a magnified region. On a mouse the lens sits on the pointer and the system cursor gets out of its way.","Keyboard users get it too — a control that appears on focus opens the lens, the arrow keys walk it around, and Escape puts it away.","**`fluid` makes it a drop of glass.** The lens eases after the pointer instead of sitting on it, stretches a little along its own motion and rounds out again as it slows, and the picture bends at the rim — a radial displacement, with the red and blue bent by slightly different amounts so a fine colour fringe rides the edge, the way it does on a real loupe. The refraction is an SVG filter on the glass alone, not on the copy, so it costs a lens-sized area per frame whatever is under it."],"examples":[{"lang":"svelte","code":"<Magnifier zoom={2.5}>\n  <p class=\"text-body-sm\">Terms nobody can read at this size…</p>\n</Magnifier>\n\n<Magnifier src=\"/map.png\" alt=\"Site plan\" shape=\"circle\" zoom={3} />"}],"classesType":"MagnifierClasses","parts":[{"name":"root","doc":"The frame around the content. Position lives here, and so does the long press: `touch-pan-y` leaves the page scrolling until the lens is actually up, and the callout suppression stops the OS offering to select the text under a finger that is trying to magnify it."},{"name":"source","doc":"The content, exactly as it would have rendered without the lens."},{"name":"image","doc":"A picture passed as `src`, for the common case."},{"name":"lens","doc":"The glass. Round by default, clipped, elevated, with a rim that reads as a bevel rather than a border."},{"name":"glass","doc":"The pane between the picture and the rim. The refraction filter goes here, clipped to the glass, so the sheen and the bevel above it stay sharp and the shadow outside it is not bent."},{"name":"stage","doc":"The scaled copy. Everything that makes the magnification happen."},{"name":"sheen","doc":"The body of the glass. A curved piece of glass is darker at its rim than at its middle — that vignette, more than any highlight, is what stops a lens reading as a circular crop. On top of it a soft glare falls from the top-left and a fainter one bounces back off the bottom edge, both blurred, because a hard-edged highlight reads as a sticker stuck to the screen."},{"name":"rim","doc":"The bevel, over the glare so the edge stays crisp: a bright hairline just inside the rim, a darker one a few pixels further in, and a hairline on the rim itself."},{"name":"control","doc":"The keyboard affordance — invisible until it is focused."}],"variants":[{"name":"shape","doc":"","default":"circle","values":[{"name":"circle","doc":""},{"name":"rounded","doc":""},{"name":"square","doc":""}]},{"name":"holding","doc":"A held lens must not also scroll the page under it.","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]},{"name":"blind","doc":"With the lens up, the lens *is* the cursor. Leaving the arrow on top of it puts a black wedge over the middle of the thing you came to look at.","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]},{"name":"pixelated","doc":"Enlarged pixels, on purpose — a sprite sheet, a QR code.","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Foundations/Magnifier","category":"Foundations","own":true,"stories":["Playground","Over a picture","Shapes","Text loupe","Fluid glass","Controlled","Overridden"]},"props":[{"name":"zoom","optional":true,"type":"number","default":"2","bindable":false,"doc":"How much bigger. `2` is a reading aid, `4` inspects a detail.","details":[],"examples":[]},{"name":"shape","optional":true,"type":"MagnifierShape","default":"'circle'","bindable":false,"doc":"The glass's outline.","details":[],"examples":[]},{"name":"width","optional":true,"type":"number | string","default":"132","bindable":false,"doc":"Lens width — a number is px, a string is any CSS length.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","bindable":false,"doc":"Lens height. Defaults to `width`, which is what makes a circle round.","details":[],"examples":[]},{"name":"trigger","optional":true,"type":"MagnifierTrigger","default":"'auto'","bindable":false,"doc":"What summons it. `auto` — the default — reads the pointer: a mouse opens it on hover, a finger on a press and hold.","details":[],"examples":[]},{"name":"hold","optional":true,"type":"number","default":"320","bindable":false,"doc":"How long a touch has to hold still before the lens appears, in ms.","details":[],"examples":[]},{"name":"lift","optional":true,"type":"number | 'auto'","default":"'auto'","bindable":false,"doc":"How far above the pointer the lens both sits *and looks*, in px, so a finger never covers what it is magnifying. `'auto'` lifts it for touch only, by enough to clear the glass.","details":[],"examples":[]},{"name":"hideCursor","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Hide the system cursor while the lens is up, so nothing is drawn over the magnified content. `false` keeps the arrow.","details":[],"examples":[]},{"name":"open","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Whether the lens is up. Bindable, so it can be driven from outside.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Turn it off without unwrapping the content.","details":[],"examples":[]},{"name":"live","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Re-copy the content as it changes, for something that moves under the glass.","details":[],"examples":[]},{"name":"pixelated","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Enlarge the pixels rather than smoothing them.","details":[],"examples":[]},{"name":"fluid","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"A drop of glass rather than a disc: the lens eases after the pointer, stretches along its motion, and refracts at the rim.","details":[],"examples":[]},{"name":"refraction","optional":true,"type":"number","default":"26","bindable":false,"doc":"How hard the rim bends the picture with `fluid`, in px.","details":[],"examples":[]},{"name":"keyboard","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Offer the lens to the keyboard as well.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","default":"'Magnify'","bindable":false,"doc":"The name of the keyboard control, and the lens's accessible label.","details":[],"examples":[]},{"name":"src","optional":true,"type":"string","bindable":false,"doc":"A picture to magnify, for the common case. Children work too.","details":[],"examples":[]},{"name":"alt","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"MagnifierClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"Map","dir":"map","entry":"omaris/map","importPath":"import { Map } from 'omaris/map'","summary":"Interactive map.","details":["That's a working map — the base style is keyless, so there's no account to make and no token to leak. It follows the theme by default, swapping to the dark base map when the app does.","Everything else in the map family is a child of this one and finds the map through context, so a marker is `<Marker lngLat={…} />` and a layer is `<MapLayer …/>` — no imperative `map.addLayer` in your page, and nothing to tear down by hand.","## Gestures","The wheel zooms and one finger pans, the way every map anyone has used behaves. There is no modifier to hold and no \"use two fingers\" scrim: MapLibre's cooperative-gesture mode buys back the page's scroll at the cost of making the map feel broken, and a map that ignores the first gesture aimed at it is worse than a page that needs one flick around it.","If a map really must not eat the page's scroll, give it `scrollZoom={false}` — the buttons in `<MapControls>` still zoom — or `interactive={false}` for a picture of a place."],"examples":[{"lang":"svelte","code":"<Map center={[44.0, 36.19]} zoom={11} />"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Map","category":"Data Display","own":true,"stories":["Playground","Markers and popups","Drag a pin","Clusters","Heatmap","Routes","GeoJSON","Draw a territory","Geofencing","Location picker","Vehicles"]},"props":[{"name":"center","optional":true,"type":"LngLat","default":"[0, 0]","bindable":true,"doc":"`[longitude, latitude]`. Bindable.","details":[],"examples":[]},{"name":"zoom","optional":true,"type":"number","default":"2","bindable":true,"doc":"Bindable.","details":[],"examples":[]},{"name":"bearing","optional":true,"type":"number","default":"0","bindable":true,"doc":"Rotation in degrees. Bindable.","details":[],"examples":[]},{"name":"pitch","optional":true,"type":"number","default":"0","bindable":true,"doc":"Tilt in degrees. Bindable.","details":[],"examples":[]},{"name":"bounds","optional":true,"type":"MapBounds","bindable":false,"doc":"Frame these bounds instead of using `center`/`zoom`.","details":[],"examples":[]},{"name":"fitPadding","optional":true,"type":"number | Partial<MapPadding>","default":"40","bindable":false,"doc":"Padding, in px, kept around `bounds` — one number for all four sides, or a side or two of their own: `{ bottom: 320 }` frames the trip in the strip of map a sheet leaves visible. A side not named keeps the default 40.","details":[],"examples":[]},{"name":"style","optional":true,"type":"MapStyleName | 'blank' | string | StyleSpecification","bindable":false,"doc":"A name from `MAP_STYLES`, `'blank'`, a URL, or a full style object.","details":[],"examples":[]},{"name":"theme","optional":true,"type":"'light' | 'dark' | 'auto'","default":"'auto'","bindable":false,"doc":"`auto` follows the app's light/dark setting.","details":[],"examples":[]},{"name":"minZoom","optional":true,"type":"number","bindable":false,"doc":"","details":[],"examples":[]},{"name":"maxZoom","optional":true,"type":"number","bindable":false,"doc":"","details":[],"examples":[]},{"name":"maxBounds","optional":true,"type":"MapBounds","bindable":false,"doc":"Keep the viewport inside these bounds.","details":[],"examples":[]},{"name":"interactive","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Turn off every interaction — a static picture of a place.","details":[],"examples":[]},{"name":"rotatable","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Let a drag rotate and tilt the map.","details":[],"examples":[]},{"name":"scrollZoom","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"The wheel zooms.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"400","bindable":false,"doc":"Height of the map. A number is px; a string is any CSS length.","details":[],"examples":[]},{"name":"attribution","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Show the attribution the base maps require. Leave it on.","details":[],"examples":[]},{"name":"cursor","optional":true,"type":"string","bindable":false,"doc":"Cursor over the map.","details":[],"examples":[]},{"name":"onload","optional":true,"type":"(map: MapLibreMap) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onmove","optional":true,"type":"(viewport: MapViewport) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onmoveend","optional":true,"type":"(viewport: MapViewport) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onclick","optional":true,"type":"(lngLat: LngLat, event: MapMouseEvent) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"oncontextmenu","optional":true,"type":"(lngLat: LngLat, event: MapMouseEvent) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Markers, layers, controls — anything that needs the map.","details":[],"examples":[]},{"name":"overlay","optional":true,"type":"Snippet","bindable":false,"doc":"Drawn over the map, outside its own event handling.","details":[],"examples":[]}]},{"name":"MapCluster","dir":"map","entry":"omaris/map","importPath":"import { MapCluster } from 'omaris/map'","summary":"Thousands of points, grouped.","details":["Ten thousand markers is ten thousand DOM nodes and a map that stutters; the same points as a clustered source stay on the GPU and don't. A press on a cluster zooms to the extent it covers, which is what makes the pile navigable rather than merely tidy.","Clusters grow with their count in steps rather than continuously, so a glance tells you the order of magnitude."],"examples":[{"lang":"svelte","code":"<MapCluster id=\"stops\" data={stops} />"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Map","category":"Data Display","own":false,"stories":["Playground","Markers and popups","Drag a pin","Clusters","Heatmap","Routes","GeoJSON","Draw a territory","Geofencing","Location picker","Vehicles"]},"props":[{"name":"id","optional":false,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"data","optional":false,"type":"GeoJsonInput","bindable":false,"doc":"","details":[],"examples":[]},{"name":"radius","optional":true,"type":"number","default":"50","bindable":false,"doc":"How near two points have to be to group, in px.","details":[],"examples":[]},{"name":"maxZoom","optional":true,"type":"number","default":"14","bindable":false,"doc":"Above this zoom every point stands alone.","details":[],"examples":[]},{"name":"color","optional":true,"type":"string","default":"'var(--chart-1)'","bindable":false,"doc":"Any CSS colour, for the clusters and the lone points.","details":[],"examples":[]},{"name":"steps","optional":true,"type":"[number, number]","default":"[10, 50]","bindable":false,"doc":"Counts at which a cluster steps up a size.","details":[],"examples":[]},{"name":"pointRadius","optional":true,"type":"number","default":"6","bindable":false,"doc":"Radius of a point that isn't in a cluster, in px.","details":[],"examples":[]},{"name":"onclick","optional":true,"type":"(event: MapLayerMouseEvent) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onpointclick","optional":true,"type":"(lngLat: LngLat, event: MapLayerMouseEvent) => void","bindable":false,"doc":"A press on a single point, with its coordinates.","details":[],"examples":[]}]},{"name":"MapControls","dir":"map","entry":"omaris/map","importPath":"import { MapControls } from 'omaris/map'","summary":"Zoom, compass, locate and fullscreen — as omaris buttons rather than MapLibre's, so they carry the app's radii, shadows and focus rings and sit at a real touch target size.","details":["The compass only appears once the map is rotated, because a control that does nothing is a control in the way."],"examples":[{"lang":"svelte","code":"<Map>\n  <MapControls locate fullscreen />\n</Map>"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Map","category":"Data Display","own":false,"stories":["Playground","Markers and popups","Drag a pin","Clusters","Heatmap","Routes","GeoJSON","Draw a territory","Geofencing","Location picker","Vehicles"]},"props":[{"name":"position","optional":true,"type":"'top-start' | 'top-end' | 'bottom-start' | 'bottom-end'","default":"'top-end'","bindable":false,"doc":"Corner it sits in.","details":[],"examples":[]},{"name":"zoom","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"compass","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Reset north. Hidden while the map is already facing north.","details":[],"examples":[]},{"name":"locate","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Jump to the visitor's position.","details":[],"examples":[]},{"name":"fullscreen","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"scale","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"A bar showing what the current scale means on the ground.","details":[],"examples":[]},{"name":"onlocate","optional":true,"type":"(lngLat: LngLat) => void","bindable":false,"doc":"Called with the located position, so a caller can drop a marker.","details":[],"examples":[]},{"name":"onlocateerror","optional":true,"type":"(error: GeolocationPositionError) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Extra buttons, below the built-in ones.","details":[],"examples":[]}]},{"name":"MapDraw","dir":"map","entry":"omaris/map","importPath":"import { MapDraw } from 'omaris/map'","summary":"Draw a territory on the map.","details":["Tap to drop a corner, tap the first one again — or press Finish — to close the shape. Drag a corner to move it, drag the midpoint between two to add one, and press a corner's × to take it out.","Built for a finger first: the handles are real touch targets rather than 6px canvas dots, and everything is a tap rather than a click-and-hold, because a long press on a map means something else.","The shape is a plain GeoJSON polygon, which is what `<MapGeofence>` and `pointInPolygon` take, so drawing a delivery zone and watching for couriers leaving it are the same two lines apart."],"examples":[{"lang":"svelte","code":"<MapDraw bind:polygon onfinish={save} />"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Map","category":"Data Display","own":false,"stories":["Playground","Markers and popups","Drag a pin","Clusters","Heatmap","Routes","GeoJSON","Draw a territory","Geofencing","Location picker","Vehicles"]},"props":[{"name":"polygon","optional":true,"type":"Feature<Polygon>","default":"undefined","bindable":true,"doc":"The shape. Bindable — `undefined` until it's closed.","details":[],"examples":[]},{"name":"drawing","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Start in drawing mode. Bindable.","details":[],"examples":[]},{"name":"editable","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Let existing corners be moved, added and removed.","details":[],"examples":[]},{"name":"color","optional":true,"type":"string","default":"'var(--chart-1)'","bindable":false,"doc":"Any CSS colour.","details":[],"examples":[]},{"name":"id","optional":true,"type":"string","default":"'omaris-draw'","bindable":false,"doc":"Prefix for the layers this adds.","details":[],"examples":[]},{"name":"onfinish","optional":true,"type":"(polygon: Feature<Polygon>) => void","bindable":false,"doc":"Fires when the shape closes.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(points: LngLat[]) => void","bindable":false,"doc":"Fires on every change, including while drawing.","details":[],"examples":[]},{"name":"onclear","optional":true,"type":"() => void","bindable":false,"doc":"Fires when the shape is cleared.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"MapGeofence","dir":"map","entry":"omaris/map","importPath":"import { MapGeofence } from 'omaris/map'","summary":"Watch points against zones and say when one crosses.","details":["The zones draw themselves, each in its own colour, and every time `points` changes the component works out which of them moved in or out of which zone since the last update — so a live feed of positions becomes a stream of enter and leave events without any bookkeeping in the page.","Membership is settled by ray casting on plain coordinates, which is exact for any zone drawn on a screen. Nothing is polled and nothing is timed: an event fires when a position changes, and only then."],"examples":[{"lang":"svelte","code":"<MapGeofence\n  zones={territories}\n  points={couriers}\n  onleave={(event) => toast.warning(`${event.point.name} left ${event.zone.name}`)}\n/>"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Map","category":"Data Display","own":false,"stories":["Playground","Markers and popups","Drag a pin","Clusters","Heatmap","Routes","GeoJSON","Draw a territory","Geofencing","Location picker","Vehicles"]},"props":[{"name":"zones","optional":false,"type":"Zone[]","bindable":false,"doc":"","details":[],"examples":[]},{"name":"points","optional":true,"type":"TrackedPoint[]","default":"[]","bindable":false,"doc":"The points being watched. Update it and the crossings are reported.","details":[],"examples":[]},{"name":"id","optional":true,"type":"string","default":"'omaris-geofence'","bindable":false,"doc":"Prefix for the layers this adds.","details":[],"examples":[]},{"name":"show","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Draw the zones. Off when something else already draws them.","details":[],"examples":[]},{"name":"showPoints","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Draw the points too.","details":[],"examples":[]},{"name":"fillOpacity","optional":true,"type":"number","default":"0.14","bindable":false,"doc":"Fill opacity of each zone.","details":[],"examples":[]},{"name":"onenter","optional":true,"type":"(event: GeofenceEvent) => void","bindable":false,"doc":"A point crossed into a zone.","details":[],"examples":[]},{"name":"onleave","optional":true,"type":"(event: GeofenceEvent) => void","bindable":false,"doc":"A point crossed out of one.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(inside: Map<string, string[]>) => void","bindable":false,"doc":"Which zones hold each point, on every change.","details":[],"examples":[]},{"name":"marker","optional":true,"type":"Snippet<[TrackedPoint, string[]]>","bindable":false,"doc":"Rendered for each point, in place of the default dot.","details":[],"examples":[]}]},{"name":"MapGeoJson","dir":"map","entry":"omaris/map","importPath":"import { MapGeoJson } from 'omaris/map'","summary":"Draw GeoJSON, whatever's in it.","details":["One component covers the case that otherwise needs a source and three layers: polygons get a fill and an outline, lines get a stroke, points get dots — each filtered to the geometry it belongs to, so a mixed collection draws correctly without being split up first.","Colour follows the theme by default. Give it a `color` for one shade throughout, or a `colorBy` property name to colour by a field."],"examples":[{"lang":"svelte","code":"<MapGeoJson id=\"districts\" data={districts} />"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Map","category":"Data Display","own":false,"stories":["Playground","Markers and popups","Drag a pin","Clusters","Heatmap","Routes","GeoJSON","Draw a territory","Geofencing","Location picker","Vehicles"]},"props":[{"name":"id","optional":false,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"data","optional":false,"type":"GeoJsonInput","bindable":false,"doc":"","details":[],"examples":[]},{"name":"color","optional":true,"type":"string | unknown[]","default":"'var(--chart-1)'","bindable":false,"doc":"Any CSS colour, or a MapLibre expression.","details":[],"examples":[]},{"name":"colorBy","optional":true,"type":"string","bindable":false,"doc":"Colour each feature by this property, which must hold a colour.","details":[],"examples":[]},{"name":"fillOpacity","optional":true,"type":"number","default":"0.18","bindable":false,"doc":"Fill opacity for polygons.","details":[],"examples":[]},{"name":"lineWidth","optional":true,"type":"number","default":"2","bindable":false,"doc":"Stroke width for lines and polygon outlines.","details":[],"examples":[]},{"name":"pointRadius","optional":true,"type":"number","default":"5","bindable":false,"doc":"Radius of point features, in px.","details":[],"examples":[]},{"name":"dash","optional":true,"type":"number[]","bindable":false,"doc":"Dash the lines — `[2, 2]` and so on.","details":[],"examples":[]},{"name":"interactive","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Show a pointer and respond to presses.","details":[],"examples":[]},{"name":"before","optional":true,"type":"string","bindable":false,"doc":"Insert below this layer id, to sit under the base map's labels.","details":[],"examples":[]},{"name":"visible","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onclick","optional":true,"type":"(event: MapLayerMouseEvent) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onhover","optional":true,"type":"(event: MapLayerMouseEvent | null) => void","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"MapHeatmap","dir":"map","entry":"omaris/map","importPath":"import { MapHeatmap } from 'omaris/map'","summary":"Density, as heat.","details":["For the question clustering can't answer: not \"how many points are here\" but \"where is this concentrated\". The ramp runs from transparent through the chart roles, so it reads on both base maps, and it fades out as you zoom in — past a certain point the individual features are the better answer, and `<MapCluster>` or a circle layer takes over."],"examples":[{"lang":"svelte","code":"<MapHeatmap id=\"orders\" data={orders} weight=\"total\" />"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Map","category":"Data Display","own":false,"stories":["Playground","Markers and popups","Drag a pin","Clusters","Heatmap","Routes","GeoJSON","Draw a territory","Geofencing","Location picker","Vehicles"]},"props":[{"name":"id","optional":false,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"data","optional":false,"type":"GeoJsonInput","bindable":false,"doc":"","details":[],"examples":[]},{"name":"weight","optional":true,"type":"string","bindable":false,"doc":"Property whose value weights each point. Defaults to one each.","details":[],"examples":[]},{"name":"maxWeight","optional":true,"type":"number","default":"1","bindable":false,"doc":"Largest expected value of `weight`, for scaling.","details":[],"examples":[]},{"name":"radius","optional":true,"type":"number","default":"24","bindable":false,"doc":"Blur radius, in px.","details":[],"examples":[]},{"name":"intensity","optional":true,"type":"number","default":"1","bindable":false,"doc":"","details":[],"examples":[]},{"name":"opacity","optional":true,"type":"number","default":"0.8","bindable":false,"doc":"","details":[],"examples":[]},{"name":"maxZoom","optional":true,"type":"number","default":"16","bindable":false,"doc":"Stop drawing above this zoom, where points are better.","details":[],"examples":[]},{"name":"before","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"visible","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"MapLayer","dir":"map","entry":"omaris/map","importPath":"import { MapLayer } from 'omaris/map'","summary":"A style layer over a source.","details":["It finds its source from the `<MapSource>` around it, re-adds itself after a restyle, and turns MapLibre's per-layer event API into ordinary props — including the pointer cursor, which is the bit everyone forgets and which is the difference between a layer that looks clickable and one that doesn't."],"examples":[{"lang":"svelte","code":"<MapLayer id=\"zones\" type=\"fill\" paint={{ 'fill-color': '#2563eb' }} />"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Map","category":"Data Display","own":false,"stories":["Playground","Markers and popups","Drag a pin","Clusters","Heatmap","Routes","GeoJSON","Draw a territory","Geofencing","Location picker","Vehicles"]},"props":[{"name":"id","optional":false,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"type","optional":false,"type":"LayerSpecification['type']","bindable":false,"doc":"","details":[],"examples":[]},{"name":"source","optional":true,"type":"string","bindable":false,"doc":"Defaults to the enclosing `<MapSource>`.","details":[],"examples":[]},{"name":"sourceLayer","optional":true,"type":"string","bindable":false,"doc":"Layer within a vector source.","details":[],"examples":[]},{"name":"paint","optional":true,"type":"Record<string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"layout","optional":true,"type":"Record<string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"filter","optional":true,"type":"FilterSpecification","bindable":false,"doc":"","details":[],"examples":[]},{"name":"minZoom","optional":true,"type":"number","bindable":false,"doc":"","details":[],"examples":[]},{"name":"maxZoom","optional":true,"type":"number","bindable":false,"doc":"","details":[],"examples":[]},{"name":"before","optional":true,"type":"string","bindable":false,"doc":"Insert below this layer, to sit under the labels.","details":[],"examples":[]},{"name":"visible","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Hide without removing.","details":[],"examples":[]},{"name":"interactive","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Show a pointer over the layer's features.","details":[],"examples":[]},{"name":"onclick","optional":true,"type":"(event: MapLayerMouseEvent) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onhover","optional":true,"type":"(event: MapLayerMouseEvent | null) => void","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"MapPicker","dir":"map","entry":"omaris/map","importPath":"import { MapPicker } from 'omaris/map'","summary":"\"Put the pin where you are.\"","details":["Two ways to choose a point, and the picker knows which one fits:","- On a touchscreen the pin stays fixed in the middle and the map moves under it. A finger that drags a pin covers it, and a map that pans is the gesture everyone already knows; the pin lifts while the map is moving and settles when it stops. - With a mouse the pin sits on the map and is dragged — or moved with a click on the spot. A mouse is precise and covers nothing.","`mode` forces either. Either way `lngLat` is bindable, `onchange` fires as it moves and `onsettle` once it has stopped — which is when to ask a geocoder for the address. Hand that in as `describe` and the picker shows it in a caption over the pin.","Arrow keys nudge the pin with the keyboard, in both modes."],"examples":[{"lang":"svelte","code":"<Map center={here} zoom={15}>\n  <MapPicker bind:lngLat={pickup} />\n</Map>"}],"classesType":"MapPickerClasses","parts":[{"name":"root","doc":""},{"name":"pin","doc":"The pin, tip on the point."},{"name":"caption","doc":"The address over the pin."},{"name":"control","doc":"The focusable control the pin lives in."}],"variants":[{"name":"tone","doc":"","default":"primary","values":[{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""}]},{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]},{"name":"lifted","doc":"Mid-move: the pin rises off the ground.","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]},{"name":"disabled","doc":"","values":[{"name":"true","doc":""}]}],"story":{"title":"Data Display/Map","category":"Data Display","own":false,"stories":["Playground","Markers and popups","Drag a pin","Clusters","Heatmap","Routes","GeoJSON","Draw a territory","Geofencing","Location picker","Vehicles"]},"props":[{"name":"lngLat","optional":true,"type":"LngLat","bindable":true,"doc":"The chosen point. Bindable; starts at the map's centre when omitted.","details":[],"examples":[]},{"name":"mode","optional":true,"type":"MapPickerMode","default":"'auto'","bindable":false,"doc":"`center` fixes the pin in the middle and moves the map; `drag` moves the pin. `auto` is `center` on a coarse pointer and `drag` on a fine one.","details":[],"examples":[]},{"name":"tone","optional":true,"type":"MapPickerTone","default":"'primary'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"MapPickerSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"describe","optional":true,"type":"string | ((lngLat: LngLat) => string | Promise<string>)","bindable":false,"doc":"Text for the caption — a string, or a function of the point that may return a promise. Called once the pin settles.","details":[],"examples":[]},{"name":"clickToMove","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"In `drag` mode, a click on the map moves the pin there. On by default.","details":[],"examples":[]},{"name":"nudge","optional":true,"type":"number","default":"8","bindable":false,"doc":"Pixels an arrow key moves the pin.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Show the pin but take no input.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","default":"'Location'","bindable":false,"doc":"Accessible name of the pin.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(lngLat: LngLat) => void","bindable":false,"doc":"Fires with every movement, mid-gesture included.","details":[],"examples":[]},{"name":"onsettle","optional":true,"type":"(lngLat: LngLat) => void","bindable":false,"doc":"Fires once the pin has come to rest.","details":[],"examples":[]},{"name":"z","optional":true,"type":"number","bindable":false,"doc":"Stacking order against markers, in `drag` mode.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"MapPickerClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Replaces the pin. Its bottom edge is the point.","details":[],"examples":[]}]},{"name":"MapPopup","dir":"map","entry":"omaris/map","importPath":"import { MapPopup } from 'omaris/map'","summary":"A card anchored to a place on the map.","details":["MapLibre positions it — including keeping it on screen near the edges — and everything inside is ordinary markup, so it takes the app's own type and spacing rather than a map library's."],"examples":[{"lang":"svelte","code":"<MapPopup bind:open lngLat={selected}>\n  <p class=\"font-medium\">Warehouse 4</p>\n</MapPopup>"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Map","category":"Data Display","own":false,"stories":["Playground","Markers and popups","Drag a pin","Clusters","Heatmap","Routes","GeoJSON","Draw a territory","Geofencing","Location picker","Vehicles"]},"props":[{"name":"lngLat","optional":false,"type":"LngLat","bindable":false,"doc":"`[longitude, latitude]` it points at.","details":[],"examples":[]},{"name":"open","optional":true,"type":"boolean","default":"true","bindable":true,"doc":"Bindable.","details":[],"examples":[]},{"name":"anchor","optional":true,"type":"| 'center'","bindable":false,"doc":"Which side of the coordinate it sits on. Auto-placed when unset.","details":[],"examples":[]},{"name":"offset","optional":true,"type":"number","default":"14","bindable":false,"doc":"Distance from the coordinate, in px. The default clears a dot; a `pin` marker stands about 44px above its point, so a popup on one wants `offset={44}` or it sits on the pin's head.","details":[],"examples":[]},{"name":"closeButton","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Show the ×.","details":[],"examples":[]},{"name":"closeOnClick","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"A press on the map closes it.","details":[],"examples":[]},{"name":"focus","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Pan the map so the popup fits.","details":[],"examples":[]},{"name":"maxWidth","optional":true,"type":"string","default":"'18rem'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onclose","optional":true,"type":"() => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"MapRoute","dir":"map","entry":"omaris/map","importPath":"import { MapRoute } from 'omaris/map'","summary":"A path between places.","details":["`arc` bends each leg into a curve, which is what makes a point-to-point map (a flight, a shipment) legible: two straight lines between the same three cities overlap, two arcs don't.","`animate` marches the dashes along the line, so direction is visible without an arrowhead."],"examples":[{"lang":"svelte","code":"<MapRoute id=\"delivery\" coordinates={stops} arc />"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Map","category":"Data Display","own":false,"stories":["Playground","Markers and popups","Drag a pin","Clusters","Heatmap","Routes","GeoJSON","Draw a territory","Geofencing","Location picker","Vehicles"]},"props":[{"name":"id","optional":false,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"coordinates","optional":false,"type":"LngLat[]","bindable":false,"doc":"The path, in order.","details":[],"examples":[]},{"name":"color","optional":true,"type":"string","default":"'var(--chart-1)'","bindable":false,"doc":"Any CSS colour.","details":[],"examples":[]},{"name":"width","optional":true,"type":"number","default":"3","bindable":false,"doc":"","details":[],"examples":[]},{"name":"arc","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Bend each leg instead of drawing it straight.","details":[],"examples":[]},{"name":"bend","optional":true,"type":"number","default":"0.2","bindable":false,"doc":"How far each arc bows out, as a fraction of the leg's length.","details":[],"examples":[]},{"name":"dash","optional":true,"type":"number[]","bindable":false,"doc":"Dash pattern, e.g. `[2, 2]`.","details":[],"examples":[]},{"name":"animate","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"March the dashes along the line. Implies `dash`.","details":[],"examples":[]},{"name":"halo","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"A soft wider line under the main one, so it reads over any base map.","details":[],"examples":[]},{"name":"opacity","optional":true,"type":"number","default":"1","bindable":false,"doc":"","details":[],"examples":[]},{"name":"before","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"visible","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"MapSource","dir":"map","entry":"omaris/map","importPath":"import { MapSource } from 'omaris/map'","summary":"A GeoJSON source, declared rather than added.","details":["It survives a restyle — changing the base map throws away every source and layer, and this puts them back — and it updates in place when the data changes, which is what keeps a live feed from flickering and what lets a drawing tool redraw on every corner."],"examples":[{"lang":"svelte","code":"<MapSource id=\"stops\" data={stops}>\n  <MapLayer id=\"stops-dots\" type=\"circle\" paint={{ 'circle-radius': 5 }} />\n</MapSource>"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Map","category":"Data Display","own":false,"stories":["Playground","Markers and popups","Drag a pin","Clusters","Heatmap","Routes","GeoJSON","Draw a territory","Geofencing","Location picker","Vehicles"]},"props":[{"name":"id","optional":false,"type":"string","bindable":false,"doc":"Unique within the map. Layers refer to it by this.","details":[],"examples":[]},{"name":"data","optional":false,"type":"GeoJsonInput","bindable":false,"doc":"","details":[],"examples":[]},{"name":"cluster","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Group nearby points. See `<MapCluster>` for the ready-made version.","details":[],"examples":[]},{"name":"clusterRadius","optional":true,"type":"number","default":"50","bindable":false,"doc":"","details":[],"examples":[]},{"name":"clusterMaxZoom","optional":true,"type":"number","default":"14","bindable":false,"doc":"","details":[],"examples":[]},{"name":"clusterProperties","optional":true,"type":"Record<string","bindable":false,"doc":"Sums and counts to compute per cluster.","details":[],"examples":[]},{"name":"tolerance","optional":true,"type":"number","bindable":false,"doc":"Simplification tolerance. Lower is more faithful and heavier.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Layers reading from this source.","details":[],"examples":[]}]},{"name":"MapVehicle","dir":"map","entry":"omaris/map","importPath":"import { MapVehicle } from 'omaris/map'","summary":"Something that moves: a car, a courier, a bus, a boat.","details":["Give it a new `lngLat` and it drives there rather than teleporting — easing across over `duration`, and turning to face the way it is going. Set `duration` to the interval positions arrive at (a ping every two seconds → `duration={2000}`) and the vehicle never stops between them.","With a `path`, `progress` says how far along it is, by distance, and the heading comes from the leg it is on. `follow` keeps the map centred on it until the person drags the map away; bind it, and a \"recentre\" button is one line.","A `plain` vehicle sits straight on the map with its shadow under it, the way a ride app draws the cars around you; a `badge` puts the same car in a tinted circle, which reads better in a crowd or over a busy basemap."],"examples":[{"lang":"svelte","code":"<MapVehicle model=\"taxi\" lngLat={driver} />"},{"lang":"svelte","code":"<MapVehicle model=\"car\" path={route} progress={0.4} />"}],"classesType":"MapVehicleClasses","parts":[{"name":"root","doc":""},{"name":"body","doc":"The clickable, tinted part — everything but the label."},{"name":"glyph","doc":"The rotating glyph."},{"name":"pulse","doc":"The ring that breathes under a live vehicle."},{"name":"label","doc":"Text under the vehicle. Stays upright whatever the heading."}],"variants":[{"name":"variant","doc":"","default":"plain","values":[{"name":"plain","doc":""},{"name":"badge","doc":""}]},{"name":"tone","doc":"","default":"foreground","values":[{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""},{"name":"foreground","doc":"The page's own foreground — the black car on the map."}]},{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]},{"name":"active","doc":"","values":[{"name":"true","doc":""}]},{"name":"pressable","doc":"","values":[{"name":"true","doc":""}]}],"story":{"title":"Data Display/Map","category":"Data Display","own":false,"stories":["Playground","Markers and popups","Drag a pin","Clusters","Heatmap","Routes","GeoJSON","Draw a territory","Geofencing","Location picker","Vehicles"]},"props":[{"name":"model","optional":true,"type":"VehicleModel","default":"'car'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"lngLat","optional":true,"type":"LngLat","bindable":false,"doc":"Where it is. Each change is driven to, not jumped to.","details":[],"examples":[]},{"name":"path","optional":true,"type":"LngLat[]","bindable":false,"doc":"Follow this path instead of `lngLat`; `progress` says how far.","details":[],"examples":[]},{"name":"progress","optional":true,"type":"number","default":"0","bindable":false,"doc":"0 → 1 along `path`, by distance.","details":[],"examples":[]},{"name":"heading","optional":true,"type":"number","bindable":false,"doc":"Degrees clockwise from north. Worked out from the movement when omitted.","details":[],"examples":[]},{"name":"duration","optional":true,"type":"number","default":"600","bindable":false,"doc":"How long a move takes, in ms — the interval positions arrive at.","details":[],"examples":[]},{"name":"variant","optional":true,"type":"MapVehicleVariant","default":"'plain'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"tone","optional":true,"type":"MapVehicleTone","default":"'foreground'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"MapVehicleSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"active","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Highlight it — the one that is yours.","details":[],"examples":[]},{"name":"pulse","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"A ring breathing under it: live, and being tracked.","details":[],"examples":[]},{"name":"follow","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Keep the map centred on it. Bindable: a drag on the map turns it off, so a \"recentre\" button is `onclick={() => (follow = true)}`.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Short text under it.","details":[],"examples":[]},{"name":"z","optional":true,"type":"number","bindable":false,"doc":"Stacking order against the other markers.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"Accessible name. Falls back to `label`, then to the model.","details":[],"examples":[]},{"name":"onclick","optional":true,"type":"(lngLat: LngLat) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onarrive","optional":true,"type":"(lngLat: LngLat, heading: number) => void","bindable":false,"doc":"Fires when a move finishes — with where it is and which way it faces.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"MapVehicleClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Replaces the glyph. Still rotated to the heading.","details":[],"examples":[]}]},{"name":"MapVehicleIcon","dir":"map","entry":"omaris/map","importPath":"import { MapVehicleIcon } from 'omaris/map'","summary":"One of the vehicles on its own — for a list of ride tiers, a legend, a chip — drawn exactly as `<MapVehicle>` draws it on the map.","details":["The body takes `currentColor`, so `text-primary` paints the car and the shading follows. Facing north by default; `heading` turns it."],"examples":[{"lang":"svelte","code":"<MapVehicleIcon model=\"taxi\" class=\"size-8\" />"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Map","category":"Data Display","own":false,"stories":["Playground","Markers and popups","Drag a pin","Clusters","Heatmap","Routes","GeoJSON","Draw a territory","Geofencing","Location picker","Vehicles"]},"props":[{"name":"model","optional":true,"type":"VehicleModel","default":"'car'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"heading","optional":true,"type":"number","default":"0","bindable":false,"doc":"Degrees clockwise from north.","details":[],"examples":[]},{"name":"shadow","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Draw the soft shadow on the ground. Off for an icon in a list.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"Marker","dir":"map","entry":"omaris/map","importPath":"import { Marker } from 'omaris/map'","summary":"A point on the map.","details":["The default pin is a real element rather than a canvas sprite, so it takes tones, sizes and a `class` like everything else — and its content can be anything: a snippet turns it into a photo, a price, an avatar.","`draggable` makes `lngLat` bindable, which is how you let someone place a delivery address by dragging it."],"examples":[{"lang":"svelte","code":"<Marker lngLat={[44.0, 36.19]} label=\"Warehouse\" />"}],"classesType":"MarkerClasses","parts":[{"name":"root","doc":""},{"name":"label","doc":"Text riding beside the pin."}],"variants":[{"name":"tone","doc":"","default":"primary","values":[{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""}]},{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]},{"name":"pin","doc":"A pin with a point, rather than a dot.","values":[{"name":"true","doc":""}]},{"name":"active","doc":"","values":[{"name":"true","doc":""}]}],"story":{"title":"Data Display/Map","category":"Data Display","own":false,"stories":["Playground","Markers and popups","Drag a pin","Clusters","Heatmap","Routes","GeoJSON","Draw a territory","Geofencing","Location picker","Vehicles"]},"props":[{"name":"lngLat","optional":false,"type":"LngLat","bindable":true,"doc":"`[longitude, latitude]`. Bindable when `draggable`.","details":[],"examples":[]},{"name":"tone","optional":true,"type":"MarkerTone","default":"'primary'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"MarkerSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"pin","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Draw a teardrop pin instead of a dot.","details":[],"examples":[]},{"name":"active","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Highlight it — the selected one in a list, say.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Short text under the pin.","details":[],"examples":[]},{"name":"anchor","optional":true,"type":"| 'center'","default":"pin ? 'bottom' : 'center'","bindable":false,"doc":"Which part of the element sits on the coordinate.","details":[],"examples":[]},{"name":"draggable","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Let it be dragged. `lngLat` follows.","details":[],"examples":[]},{"name":"z","optional":true,"type":"number","bindable":false,"doc":"Stacking order against the other markers.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"Accessible name. Falls back to `label`.","details":[],"examples":[]},{"name":"onclick","optional":true,"type":"(lngLat: LngLat) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"ondragend","optional":true,"type":"(lngLat: LngLat) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"MarkerClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Replaces the pin entirely.","details":[],"examples":[]}]},{"name":"Masonry","dir":"masonry","entry":"omaris","importPath":"import { Masonry } from 'omaris'","summary":"A masonry grid — the photo wall. Cards of unequal height, packed so the bottom edge comes out level, in reading order.","details":["CSS `columns` is the cheap version of this and it has two problems: it lays items out top-to-bottom-then-across, so reading order runs down the first column, and a card can be sliced in half across a column break. This measures instead. Every card's height is watched by one `ResizeObserver`, and each one goes to whichever column is currently shortest — the greedy packing that actually levels the bottom — while the DOM stays one flat list in source order, so tabbing through it goes left to right and top to bottom like the eye does.","**Nothing is ever re-created.** Every card is absolutely positioned and moved with `translate`, so a card that lands in a different column after a resize slides there — it is not torn down and rebuilt. Focus, scroll, a playing video and a decoded image all survive the reflow, and the reflow itself is a transition rather than a jump.","The column count is derived from the container, not the viewport, so a grid in a sidebar collapses to one column while the same component in the main region shows four, with no breakpoints to keep in sync.","Before the first measurement — on the server, and in the instant before hydration — the cards sit in a plain CSS grid with the same column count, so a prerendered page is never empty."],"examples":[{"lang":"svelte","code":"<Masonry items={photos} minColumnWidth={200} gap={16} onend={loadMore}>\n  {#snippet item(photo)}\n    <img src={photo.src} alt={photo.alt} width={photo.w} height={photo.h} class=\"w-full rounded-shape-xl\" />\n  {/snippet}\n</Masonry>"}],"classesType":"MasonryClasses","parts":[{"name":"item","doc":"Wrapper around one entry — what gets measured and moved. Until the entry has been measured it is drawn transparent at a guessed position, so a grid is never blank while it settles."},{"name":"sentinel","doc":"The hairline at the bottom that `onend` watches."}],"variants":[{"name":"ready","doc":"Absolute packing once measured; a CSS grid of the same shape before.","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]},{"name":"animate","doc":"A re-pack slides each card to its new place, and a card added later fades and rises into the wall. Off, everything snaps.","default":"true","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Layout/Masonry","category":"Layout","own":true,"stories":["Playground","Photo wall","Load more","Balance","Container-driven","Overridden","RTL"]},"props":[{"name":"items","optional":false,"type":"T[]","bindable":false,"doc":"","details":[],"examples":[]},{"name":"item","optional":false,"type":"Snippet<[T, MasonryItemContext]>","bindable":false,"doc":"How to draw one entry. It is given the full width of its column.","details":[],"examples":[]},{"name":"columns","optional":true,"type":"number","bindable":false,"doc":"Fix the column count. Left off, it is derived from the container's width and `minColumnWidth`.","details":[],"examples":[]},{"name":"minColumnWidth","optional":true,"type":"number","default":"240","bindable":false,"doc":"Narrowest a column may get before one is dropped.","details":[],"examples":[]},{"name":"maxColumns","optional":true,"type":"number","default":"8","bindable":false,"doc":"Ceiling for the derived count.","details":[],"examples":[]},{"name":"gap","optional":true,"type":"number | string","default":"16","bindable":false,"doc":"Gap between columns and between cards.","details":[],"examples":[]},{"name":"balance","optional":true,"type":"MasonryBalance","default":"'height'","bindable":false,"doc":"`height` packs each card into the shortest column — a level bottom edge. `order` deals them out in turn, which keeps a strict left-to-right rhythm at the cost of a ragged bottom.","details":[],"examples":[]},{"name":"animate","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Slide cards on a re-pack and fade new ones in. Reduced motion turns it off.","details":[],"examples":[]},{"name":"key","optional":true,"type":"(item: T, index: number) => string | number","bindable":false,"doc":"Stable key per entry. Defaults to the index.","details":[],"examples":[]},{"name":"onend","optional":true,"type":"() => void","bindable":false,"doc":"Called once when the bottom of the wall scrolls within `endOffset` of the viewport — the hook for infinite scroll. It re-arms when `items` change, so appending a page makes it fire again for the next one.","details":[],"examples":[]},{"name":"endOffset","optional":true,"type":"number","default":"400","bindable":false,"doc":"How far above the bottom `onend` fires, in px.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"MasonryClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"Menu","dir":"menu","entry":"omaris","importPath":"import { Menu } from 'omaris'","summary":"MD3 menu — a list of actions hanging off a trigger.","details":["The trigger snippet is handed the ARIA and the click handler to spread onto whatever opens the menu, so the attributes land on the real button rather than a wrapper. The surface is portalled and anchored, so it escapes scroll containers and flips when it runs out of room.","Keyboard: Enter/Space/↓ open it, ↑↓ move, Home/End jump, typing jumps to a matching item, Escape closes and hands focus back to the trigger."],"examples":[],"classesType":"MenuClasses","parts":[{"name":"surface","doc":""},{"name":"trigger","doc":"The wrapper around whatever opens the menu — `w-full`, usually."}],"variants":[{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]}],"story":{"title":"Navigation/Menu","category":"Navigation","own":true,"stories":["Playground","From an icon button","Grouped","Single choice","Multiple choice","Submenus","Matching the trigger width","A long list"]},"props":[{"name":"open","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Bindable.","details":[],"examples":[]},{"name":"side","optional":true,"type":"AnchorSide","default":"'bottom'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"align","optional":true,"type":"AnchorAlign","default":"'start'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"offset","optional":true,"type":"number","default":"6","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"MenuSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"matchWidth","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Make the menu at least as wide as its trigger.","details":[],"examples":[]},{"name":"closeOnSelect","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Leave the menu open after an item is chosen — for a set of toggles.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible name for the menu.","details":[],"examples":[]},{"name":"mobileSheet","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"On a phone, rise from the bottom edge as a sheet — full width, a scrim behind, dragged down to dismiss, rows a thumb can hit — instead of hanging off the trigger. `false` keeps it anchored.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"MenuClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"trigger","optional":true,"type":"Snippet<[MenuTriggerProps]>","bindable":false,"doc":"Receives the props to spread onto the opening control.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"The items — `MenuItem`, `MenuLabel`, `Divider`. Arrow-key navigation finds rows by their `data-menu-item` attribute, which `MenuItem` sets for you; an item you build yourself needs that attribute or the keyboard will skip it.","details":[],"examples":[]},{"name":"aria-haspopup","optional":false,"type":"'menu'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"aria-expanded","optional":false,"type":"boolean","bindable":false,"doc":"","details":[],"examples":[]},{"name":"aria-controls","optional":false,"type":"string | undefined","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onclick","optional":false,"type":"(event: MouseEvent) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onkeydown","optional":false,"type":"(event: KeyboardEvent) => void","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"MenuItem","dir":"menu","entry":"omaris","importPath":"import { MenuItem } from 'omaris'","summary":"A row in a `Menu`.","details":["Renders as a link when given `href`, otherwise a button. `selected` gives you the checkable variant (MD3's menu with a leading tick); `tone=\"destructive\"` is the delete row."],"examples":[],"classesType":"MenuItemClasses","parts":[{"name":"root","doc":""},{"name":"label","doc":"The label. Truncates by default; override to let it wrap."},{"name":"shortcut","doc":"The right-aligned `shortcut` hint."},{"name":"check","doc":"The tick drawn while `selected`."}],"variants":[{"name":"tone","doc":"","default":"default","values":[{"name":"default","doc":""},{"name":"destructive","doc":""}]},{"name":"selected","doc":"","values":[{"name":"true","doc":""}]},{"name":"inset","doc":"","values":[{"name":"true","doc":"Aligns with rows that have a leading icon, when this one doesn't."}]}],"story":{"title":"Navigation/Menu","category":"Navigation","own":false,"stories":["Playground","From an icon button","Grouped","Single choice","Multiple choice","Submenus","Matching the trigger width","A long list"]},"props":[{"name":"tone","optional":true,"type":"MenuItemTone","default":"'default'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"selected","optional":true,"type":"boolean","bindable":false,"doc":"Checkable row: shows a trailing tick when true. Leaving it undefined keeps the row a plain `menuitem` rather than a checkbox.","details":[],"examples":[]},{"name":"radio","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"One of a set, rather than a toggle of its own: the checkable row becomes a `menuitemradio`, which is what a screen reader needs to say \"Sort by: Name, selected, 1 of 3\".","details":[],"examples":[]},{"name":"inset","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Indent to line up with rows that have a leading icon.","details":[],"examples":[]},{"name":"shortcut","optional":true,"type":"string","bindable":false,"doc":"Right-aligned hint — a keyboard shortcut, a count.","details":[],"examples":[]},{"name":"ripple","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"MenuItemClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"icon","optional":true,"type":"Snippet","bindable":false,"doc":"Leading icon.","details":[],"examples":[]},{"name":"end","optional":true,"type":"Snippet","bindable":false,"doc":"Trailing content, before the tick.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]},{"name":"variant","optional":true,"type":"ButtonVariant","bindable":false,"doc":"Fill style. MD3's five, plus `link` for inline navigation.","details":[],"examples":[]},{"name":"size","optional":true,"type":"ButtonSize","bindable":false,"doc":"MD3 Expressive heights: 32 / 40 / 56 / 96 / 136dp.","details":[],"examples":[]},{"name":"shape","optional":true,"type":"ButtonShape","bindable":false,"doc":"Pill (`round`) or MD3 rounded rectangle (`square`).","details":[],"examples":[]},{"name":"confetti","optional":true,"type":"boolean | ConfettiOptions","bindable":false,"doc":"Confetti on press. `true` for the default burst, or any `ConfettiOptions` — `confetti={{ preset: 'fireworks' }}`.","details":[],"examples":[]},{"name":"loading","optional":true,"type":"boolean","bindable":false,"doc":"Grows a spinner in at the start of the button and blocks interaction. The label stays put; only an `icon` button swaps its icon out.","details":[],"examples":[]},{"name":"toggle","optional":true,"type":"boolean","bindable":false,"doc":"Turns the button into a two-state toggle driven by `pressed`. Ignored when `href` is set — a link has no pressed state.","details":[],"examples":[]},{"name":"pressed","optional":true,"type":"boolean","bindable":true,"doc":"Selected state of a toggle button. Bindable.","details":[],"examples":[]}]},{"name":"MenuLabel","dir":"menu","entry":"omaris","importPath":"import { MenuLabel } from 'omaris'","summary":"A heading over a run of menu items.","details":["Presentational only — it is never in the focus order and screen readers skip past it to the items themselves."],"examples":[],"classesType":null,"parts":[],"variants":[],"story":{"title":"Navigation/Menu","category":"Navigation","own":false,"stories":["Playground","From an icon button","Grouped","Single choice","Multiple choice","Submenus","Matching the trigger width","A long list"]},"props":[{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"MenuSub","dir":"menu","entry":"omaris","importPath":"import { MenuSub } from 'omaris'","summary":"A row that opens a menu of its own — \"Move to ▸\", \"Sort by ▸\".","details":["On a desktop the submenu hangs off the row's far edge: it opens on hover after a short intent delay, on a press, or on → (← in a right-to-left document), and ← or Escape comes back out to the row.","On a phone the parent menu is a bottom sheet, and a second sheet on top of it — or a panel hanging off the side of a full-width one — would be worse than no submenu at all. There the row expands in place instead, its items indented under it, the way a native settings list does."],"examples":[],"classesType":"MenuSubClasses","parts":[{"name":"trigger","doc":"The row that opens it. Styled by `MenuItem`; this adds the chevron's room."},{"name":"chevron","doc":""},{"name":"surface","doc":"The submenu's panel, when it hangs off the side."},{"name":"inline","doc":"The in-place list, when the menu is a sheet."}],"variants":[],"story":{"title":"Navigation/Menu","category":"Navigation","own":false,"stories":["Playground","From an icon button","Grouped","Single choice","Multiple choice","Submenus","Matching the trigger width","A long list"]},"props":[{"name":"label","optional":false,"type":"string","bindable":false,"doc":"The row's text.","details":[],"examples":[]},{"name":"open","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Bindable.","details":[],"examples":[]},{"name":"delay","optional":true,"type":"number","default":"120","bindable":false,"doc":"Delay before a hover opens it, in ms — long enough to cross it on the way down.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"MenuSubClasses","bindable":false,"doc":"","details":[],"examples":[]},{"name":"icon","optional":true,"type":"Snippet","bindable":false,"doc":"Leading icon on the row.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"The submenu's rows — `MenuItem`, `MenuLabel`, `Divider`, another `MenuSub`.","details":[],"examples":[]}]},{"name":"MultiSelect","dir":"multi-select","entry":"omaris","importPath":"import { MultiSelect } from 'omaris'","summary":"Several values from a list, in one field.","details":["The field is a text input with the chosen options sitting in front of it, so typing filters and Backspace on an empty query takes the last one back off — the two things that make a tag field feel finished. The list stays open while you pick, because picking several and reopening a menu five times are different jobs."],"examples":[{"lang":"svelte","code":"<MultiSelect bind:values={tags} {options} label=\"Labels\" max={5} />\n<MultiSelect bind:values display=\"count\" collapse={2} creatable />"}],"classesType":"MultiSelectClasses","parts":[{"name":"root","doc":"Wrapper: label, field, supporting text."},{"name":"field","doc":"The frame: border, background, height, adornment layout."},{"name":"control","doc":"The bare <input>; the frame owns every decoration."},{"name":"label","doc":""},{"name":"adornment","doc":"Icon slots at either end of the frame."},{"name":"affix","doc":"Flat text glued to the value — \"https://\", \"kg\"."},{"name":"action","doc":"An interactive trailing control: reveal, clear."},{"name":"support","doc":"Helper line under the field, and the counter beside it."},{"name":"counter","doc":""},{"name":"surface","doc":""},{"name":"option","doc":""},{"name":"group","doc":"A non-interactive heading above a run of options."},{"name":"body","doc":""},{"name":"description","doc":""},{"name":"check","doc":""},{"name":"empty","doc":"\"No results\", \"Searching…\"."},{"name":"highlight","doc":"The part of a label that matched what was typed."},{"name":"chips","doc":"The chips and the text input, wrapped inside the frame."},{"name":"chip","doc":"One chosen option — a `Chip`, so it is the library's chip and not a lookalike. A quiet tonal tag a little shorter than the frame's line: the field is the thing to read, and the chips are in it."},{"name":"row","doc":"A row of the list. The box is the selected state, so the container tint the single-value lists give a chosen row is dropped — three chosen rows in a row read as one grey block, and the box already said it."},{"name":"box","doc":"The tick beside an option in the list — a `Checkbox`, for the same reason."},{"name":"all","doc":"The \"Select all\" row above the options."},{"name":"divider","doc":"The hairline between \"Select all\" and the options."},{"name":"count","doc":"\"3 selected\", and the \"+2\" chip that stands for the collapsed ones."},{"name":"search","doc":"The bare text input the chips sit in front of."},{"name":"chevron","doc":"The ▾ at the end of the frame — a button, so it closes the list as well as opening it."}],"variants":[{"name":"size","doc":"","default":"default","values":[{"name":"sm","doc":""},{"name":"default","doc":""},{"name":"lg","doc":""}]}],"story":{"title":"Selection/Multi Select","category":"Selection","own":true,"stories":["Playground","Chips","Grouped, with select all","Count and collapse","Creatable","Capped","Sizes and variants","Not searchable","Disabled and invalid","Overridden"]},"props":[{"name":"values","optional":true,"type":"string[]","default":"[]","bindable":true,"doc":"The chosen values, in the order they were picked. Bindable.","details":[],"examples":[]},{"name":"options","optional":true,"type":"MultiSelectOption[]","default":"[]","bindable":false,"doc":"The options. Rows with a `group` are filed under that heading.","details":[],"examples":[]},{"name":"query","optional":true,"type":"string","default":"''","bindable":true,"doc":"What's in the search box. Bindable.","details":[],"examples":[]},{"name":"variant","optional":true,"type":"InputVariant","default":"'outline'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"InputSize","default":"'default'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"display","optional":true,"type":"MultiSelectDisplay","default":"'chips'","bindable":false,"doc":"How the chosen options read in the closed field.","details":[],"examples":[]},{"name":"collapse","optional":true,"type":"number","bindable":false,"doc":"Show only this many chips, and a \"+n\" for the rest.","details":[],"examples":[]},{"name":"max","optional":true,"type":"number","bindable":false,"doc":"Most that can be chosen. The remaining rows go disabled at the cap.","details":[],"examples":[]},{"name":"searchable","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Let the field filter as you type. On by default.","details":[],"examples":[]},{"name":"mobileSheet","optional":true,"type":"boolean","bindable":false,"doc":"On a phone, the list rises from the bottom edge as a sheet — full width, a scrim behind, dragged down to dismiss, rows a thumb can hit — instead of hanging under the field. `false` keeps it anchored.","details":[],"examples":[]},{"name":"creatable","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Offer the typed text as a new value when nothing matches it.","details":[],"examples":[]},{"name":"filter","optional":true,"type":"(option: MultiSelectOption, query: string) => boolean","bindable":false,"doc":"Your own matcher, when label and `keywords` aren't enough.","details":[],"examples":[]},{"name":"highlight","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Bolden the matched part of each label.","details":[],"examples":[]},{"name":"clearable","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Show an × that empties the field.","details":[],"examples":[]},{"name":"closeOnSelect","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Close the list after each pick. Off by default — this is a multi-select.","details":[],"examples":[]},{"name":"selectAll","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"A \"Select all\" / \"Clear\" row above the options.","details":[],"examples":[]},{"name":"emptyText","optional":true,"type":"string","default":"'No results'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"supportingText","optional":true,"type":"string","bindable":false,"doc":"Helper line under the field. Becomes the error text when `invalid`.","details":[],"examples":[]},{"name":"invalid","optional":true,"type":"boolean","bindable":false,"doc":"Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"required","optional":true,"type":"boolean","bindable":false,"doc":"Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(values: string[], options: MultiSelectOption[]) => void","bindable":false,"doc":"Fires with the new list on every change.","details":[],"examples":[]},{"name":"oncreate","optional":true,"type":"(label: string) => MultiSelectOption | void","bindable":false,"doc":"Called when a `creatable` field takes text that matched nothing.","details":[],"examples":[]},{"name":"start","optional":true,"type":"Snippet","bindable":false,"doc":"Leading icon inside the frame.","details":[],"examples":[]},{"name":"option","optional":true,"type":"Snippet<[MultiSelectOption, { selected: boolean; active: boolean; query: string }]>","bindable":false,"doc":"Replaces a row of the list.","details":[],"examples":[]},{"name":"chip","optional":true,"type":"Snippet<[MultiSelectOption, { remove: () => void }]>","bindable":false,"doc":"Replaces a chip in the field.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"MultiSelectClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"ref","optional":true,"type":"HTMLInputElement | null","default":"null","bindable":true,"doc":"","details":[],"examples":[]}]},{"name":"Navigation","dir":"navigation-bar","entry":"omaris","importPath":"import { Navigation } from 'omaris'","summary":"A bottom bar and the screens it moves between, holding the one piece of state they share.","details":["On its own a `NavigationBar` is a row of buttons and the app decides what they do. Wrapped in a `Navigation` the destination becomes one bindable value: items take a `value` instead of `selected` and an `onclick`, and `NavigationViews` lays the screens out beside each other so a finger can drag between them — the way a phone's own apps behave, with the active indicator sliding under the drag rather than jumping when it ends."],"examples":[{"lang":"svelte","code":"<Navigation swipeable bind:value class=\"h-dvh\">\n  <NavigationViews>\n    <NavigationView value=\"home\">…</NavigationView>\n    <NavigationView value=\"profile\">…</NavigationView>\n  </NavigationViews>\n\n  <NavigationBar label=\"Main\">\n    <NavigationBarItem value=\"home\" label=\"Home\" icon={home} />\n    <NavigationBarItem value=\"profile\" label=\"Profile\" icon={person} />\n  </NavigationBar>\n</Navigation>"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Navigation/Navigation Bar","category":"Navigation","own":false,"stories":["Playground","Label modes","With badges","Filled selected icon","Swipeable screens","Overridden"]},"props":[{"name":"value","optional":true,"type":"string","default":"undefined","bindable":true,"doc":"The current destination. Bindable.","details":[],"examples":[]},{"name":"swipeable","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Let the views be dragged sideways. Needs them wrapped in `NavigationViews`, and mounts them all at once so there is something to drag to — pair it with `lazy` when a screen is expensive.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"NavigationBar","dir":"navigation-bar","entry":"omaris","importPath":"import { NavigationBar } from 'omaris'","summary":"MD3 navigation bar — the bottom bar on a phone, 3–5 destinations.","details":["Holds `NavigationBarItem`s and shares the label policy with them, so \"labels only on the active item\" is one prop here rather than a decision repeated on every destination.","Inside a `Navigation` the bar stops being a row of independent buttons: items take a `value`, the container says which one is current, and the active indicator becomes a single pill that slides between them — under the finger, at the same fraction, when the screens are swiped."],"examples":[],"classesType":null,"parts":[],"variants":[{"name":"elevated","doc":"","values":[{"name":"true","doc":""}]},{"name":"fixed","doc":"Pin it to the bottom of the viewport.","values":[{"name":"true","doc":""}]}],"story":{"title":"Navigation/Navigation Bar","category":"Navigation","own":true,"stories":["Playground","Label modes","With badges","Filled selected icon","Swipeable screens","Overridden"]},"props":[{"name":"size","optional":true,"type":"NavigationBarSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"elevated","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"fixed","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"labels","optional":true,"type":"NavigationLabelMode","default":"'always'","bindable":false,"doc":"Applies to every item that doesn't override it.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible name — \"Main\".","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"NavigationBarItem","dir":"navigation-bar","entry":"omaris","importPath":"import { NavigationBarItem } from 'omaris'","summary":"A destination in a `NavigationBar`.","details":["The MD3 signature is the *active indicator*: a pill that sits behind the icon only, not the label, and grows into place when the destination is selected. The icon and the pill are separate elements for exactly that reason — the ripple and state layer belong to the pill, while the label underneath stays untouched.","In an expanded rail the same destination becomes a row — icon beside label — and the pill stretches to cover the whole row, the way MD3's expanded rail and drawer draw it."],"examples":[],"classesType":"NavigationBarItemClasses","parts":[{"name":"root","doc":""},{"name":"indicator","doc":"The pill behind the icon — MD3's active indicator."},{"name":"label","doc":""}],"variants":[{"name":"layout","doc":"","default":"bar","values":[{"name":"bar","doc":"Stacked: icon over label, in a bar."},{"name":"rail","doc":"Stacked: icon over label."},{"name":"row","doc":"A row: icon beside label."}]},{"name":"selected","doc":"","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]},{"name":"showLabel","doc":"Whether the label is drawn at all.","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Navigation/Navigation Bar","category":"Navigation","own":false,"stories":["Playground","Label modes","With badges","Filled selected icon","Swipeable screens","Overridden"]},"props":[{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Label under the icon.","details":[],"examples":[]},{"name":"value","optional":true,"type":"string","bindable":false,"doc":"Names the destination, and the `NavigationView` it opens. Inside a `Navigation` this replaces `selected` and the `onclick` that went with it — the container owns which one is current.","details":[],"examples":[]},{"name":"selected","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"labels","optional":true,"type":"NavigationLabelMode","bindable":false,"doc":"Override the container's label policy for this destination.","details":[],"examples":[]},{"name":"badge","optional":true,"type":"number | boolean","bindable":false,"doc":"A count on the icon — rendered as an anchored badge.","details":[],"examples":[]},{"name":"badgeMax","optional":true,"type":"number","default":"99","bindable":false,"doc":"Cap for a numeric badge.","details":[],"examples":[]},{"name":"ripple","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"NavigationBarItemClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"icon","optional":true,"type":"Snippet","bindable":false,"doc":"The icon. Swap it for a filled version when selected if you like.","details":[],"examples":[]},{"name":"selectedIcon","optional":true,"type":"Snippet","bindable":false,"doc":"Icon shown only while selected — MD3's filled/outlined pair.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]},{"name":"variant","optional":true,"type":"ButtonVariant","bindable":false,"doc":"Fill style. MD3's five, plus `link` for inline navigation.","details":[],"examples":[]},{"name":"tone","optional":true,"type":"ButtonTone","bindable":false,"doc":"Color role the fill style paints with.","details":[],"examples":[]},{"name":"size","optional":true,"type":"ButtonSize","bindable":false,"doc":"MD3 Expressive heights: 32 / 40 / 56 / 96 / 136dp.","details":[],"examples":[]},{"name":"shape","optional":true,"type":"ButtonShape","bindable":false,"doc":"Pill (`round`) or MD3 rounded rectangle (`square`).","details":[],"examples":[]},{"name":"confetti","optional":true,"type":"boolean | ConfettiOptions","bindable":false,"doc":"Confetti on press. `true` for the default burst, or any `ConfettiOptions` — `confetti={{ preset: 'fireworks' }}`.","details":[],"examples":[]},{"name":"loading","optional":true,"type":"boolean","bindable":false,"doc":"Grows a spinner in at the start of the button and blocks interaction. The label stays put; only an `icon` button swaps its icon out.","details":[],"examples":[]},{"name":"toggle","optional":true,"type":"boolean","bindable":false,"doc":"Turns the button into a two-state toggle driven by `pressed`. Ignored when `href` is set — a link has no pressed state.","details":[],"examples":[]},{"name":"pressed","optional":true,"type":"boolean","bindable":true,"doc":"Selected state of a toggle button. Bindable.","details":[],"examples":[]}]},{"name":"NavigationDrawer","dir":"navigation-drawer","entry":"omaris","importPath":"import { NavigationDrawer } from 'omaris'","summary":"MD3 navigation drawer — the sidebar of a dashboard, in all three of the shapes a dashboard needs it in.","details":["- `standard` is the always-there sidebar of a desktop layout. - `collapsed` narrows it to its icons, which is what most dashboards actually want on a laptop. Every row keeps its label as a tooltip, so nothing is lost by narrowing it. - `modal` is the temporary drawer of a phone or a tablet: it slides over the page on a scrim, closes on Escape, on a press outside, on choosing a destination — and follows a finger dragged toward the edge, springing back if the drag was half-hearted.","`responsive` picks between the last two on the viewport, so one drawer is right on every screen without the layout knowing which it got.","`resizable` lets the sidebar be dragged to a width that suits the content — the edge is a real separator, so the arrow keys move it too."],"examples":[],"classesType":"NavigationDrawerClasses","parts":[{"name":"root","doc":""},{"name":"body","doc":"Scrolls; the header and footer don't."},{"name":"header","doc":""},{"name":"footer","doc":""},{"name":"dialog","doc":"The modal shell: a dialog on a scrim, sliding in from the edge."},{"name":"grip","doc":"The drag target on the trailing edge of a resizable drawer."}],"variants":[{"name":"collapsed","doc":"","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]},{"name":"bordered","doc":"","values":[{"name":"true","doc":""}]},{"name":"modal","doc":"Over the page rather than beside it — the width is the dialog's.","values":[{"name":"true","doc":""}]}],"story":{"title":"Navigation/Navigation Drawer","category":"Navigation","own":true,"stories":["Playground","Collapsible","Sections","Modal","Responsive","Nested groups","Collapsing with a group open","Resizable"]},"props":[{"name":"collapsed","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Narrow the drawer to its icons. Bindable.","details":[],"examples":[]},{"name":"bordered","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible name.","details":[],"examples":[]},{"name":"mode","optional":true,"type":"NavigationDrawerMode","default":"'standard'","bindable":false,"doc":"Beside the content, or over it. `responsive` overrides this.","details":[],"examples":[]},{"name":"open","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Whether a modal drawer is showing. Bindable.","details":[],"examples":[]},{"name":"responsive","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Be a modal drawer on a narrow viewport and a standard one on a wide one. `true` switches at `breakpoint`.","details":[],"examples":[]},{"name":"breakpoint","optional":true,"type":"number","default":"900","bindable":false,"doc":"Viewport width, in px, at or above which the drawer stays standard.","details":[],"examples":[]},{"name":"closeOnNavigate","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Close a modal drawer when a destination inside it is chosen.","details":[],"examples":[]},{"name":"resizable","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Let the trailing edge be dragged to set the width.","details":[],"examples":[]},{"name":"width","optional":true,"type":"number","default":"280","bindable":true,"doc":"Width in px while expanded. Bindable; only used when `resizable`.","details":[],"examples":[]},{"name":"minWidth","optional":true,"type":"number","default":"220","bindable":false,"doc":"","details":[],"examples":[]},{"name":"maxWidth","optional":true,"type":"number","default":"420","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onclose","optional":true,"type":"() => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"NavigationDrawerClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"header","optional":true,"type":"Snippet","bindable":false,"doc":"Pinned to the top — a logo, a compose button.","details":[],"examples":[]},{"name":"footer","optional":true,"type":"Snippet","bindable":false,"doc":"Pinned to the bottom — the account row, usually.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"NavigationDrawerItem","dir":"navigation-drawer","entry":"omaris","importPath":"import { NavigationDrawerItem } from 'omaris'","summary":"A destination in a `NavigationDrawer`.","details":["MD3's drawer item is a 56dp pill: the whole row is the active indicator, unlike the bar item where only the icon gets one. When the drawer collapses, the row becomes a centred icon — the label survives both as its accessible name and as a tooltip, so a narrowed sidebar is still readable rather than a column of guesses.","Give it a `submenu` and it becomes a group: the row grows a chevron and the nested destinations open under it against a guide line, which is how a dashboard's navigation actually nests.","**The row collapses; it is not rebuilt.** Every element here is in the DOM in both states — the label and the trailing content included — and the narrowing is a transition on the properties that differ. Nothing is added, removed or reparented on the way, which is what lets the row travel with the sidebar's own width instead of snapping to the new shape on the first frame and leaving the panel to catch up."],"examples":[],"classesType":"NavigationDrawerItemClasses","parts":[{"name":"root","doc":""},{"name":"tail","doc":"Everything after the icon, collapsed as one piece."},{"name":"label","doc":""},{"name":"trailing","doc":"Trailing count or badge."},{"name":"chevron","doc":"The chevron on a group row."},{"name":"submenu","doc":"Animates the nested rows open without anyone measuring them."},{"name":"nest","doc":"The guide line the nested rows hang off."}],"variants":[{"name":"selected","doc":"","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]},{"name":"collapsed","doc":"","default":"false","values":[{"name":"false","doc":""}]}],"story":{"title":"Navigation/Navigation Drawer","category":"Navigation","own":false,"stories":["Playground","Collapsible","Sections","Modal","Responsive","Nested groups","Collapsing with a group open","Resizable"]},"props":[{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Row text — and the accessible name once the drawer collapses.","details":[],"examples":[]},{"name":"selected","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"badge","optional":true,"type":"number | string","bindable":false,"doc":"Trailing count.","details":[],"examples":[]},{"name":"ripple","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"expanded","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Whether the nested rows are showing. Bindable.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"NavigationDrawerItemClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"icon","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]},{"name":"selectedIcon","optional":true,"type":"Snippet","bindable":false,"doc":"Icon shown only while selected.","details":[],"examples":[]},{"name":"trailing","optional":true,"type":"Snippet","bindable":false,"doc":"Trailing slot, in place of `badge`.","details":[],"examples":[]},{"name":"submenu","optional":true,"type":"Snippet","bindable":false,"doc":"Nested destinations. Their presence turns the row into a group.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]},{"name":"variant","optional":true,"type":"ButtonVariant","bindable":false,"doc":"Fill style. MD3's five, plus `link` for inline navigation.","details":[],"examples":[]},{"name":"tone","optional":true,"type":"ButtonTone","bindable":false,"doc":"Color role the fill style paints with.","details":[],"examples":[]},{"name":"size","optional":true,"type":"ButtonSize","bindable":false,"doc":"MD3 Expressive heights: 32 / 40 / 56 / 96 / 136dp.","details":[],"examples":[]},{"name":"shape","optional":true,"type":"ButtonShape","bindable":false,"doc":"Pill (`round`) or MD3 rounded rectangle (`square`).","details":[],"examples":[]},{"name":"confetti","optional":true,"type":"boolean | ConfettiOptions","bindable":false,"doc":"Confetti on press. `true` for the default burst, or any `ConfettiOptions` — `confetti={{ preset: 'fireworks' }}`.","details":[],"examples":[]},{"name":"loading","optional":true,"type":"boolean","bindable":false,"doc":"Grows a spinner in at the start of the button and blocks interaction. The label stays put; only an `icon` button swaps its icon out.","details":[],"examples":[]},{"name":"toggle","optional":true,"type":"boolean","bindable":false,"doc":"Turns the button into a two-state toggle driven by `pressed`. Ignored when `href` is set — a link has no pressed state.","details":[],"examples":[]},{"name":"pressed","optional":true,"type":"boolean","bindable":true,"doc":"Selected state of a toggle button. Bindable.","details":[],"examples":[]}]},{"name":"NavigationDrawerSection","dir":"navigation-drawer","entry":"omaris","importPath":"import { NavigationDrawerSection } from 'omaris'","summary":"A labelled group of items inside a `NavigationDrawer`.","details":["The label folds away when the drawer is collapsed to a rail, so a rail does not show headings with nothing under them — folds rather than disappears, on the drawer's own curve and duration, and it stays in the accessibility tree the whole time so the group keeps its name."],"examples":[],"classesType":null,"parts":[],"variants":[],"story":{"title":"Navigation/Navigation Drawer","category":"Navigation","own":false,"stories":["Playground","Collapsible","Sections","Modal","Responsive","Nested groups","Collapsing with a group open","Resizable"]},"props":[{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Group heading. Hidden (but still announced) when collapsed.","details":[],"examples":[]},{"name":"divider","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Hairline above the group.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"NavigationView","dir":"navigation-bar","entry":"omaris","importPath":"import { NavigationView } from 'omaris'","summary":"One screen behind one destination. Its `value` must match the item's.","details":["Views scroll on their own — a phone remembers where you were on the other tab, and a shared scroller cannot. Inside a swipeable `NavigationViews` every view stays mounted regardless of `keepMounted`; there has to be something beside the current one to drag towards. `lazy` on the viewport is the way out of paying for all of them at once: a view is then built the first time it comes within a swipe of the screen, and kept afterwards."],"examples":[],"classesType":null,"parts":[],"variants":[],"story":{"title":"Navigation/Navigation Bar","category":"Navigation","own":false,"stories":["Playground","Label modes","With badges","Filled selected icon","Swipeable screens","Overridden"]},"props":[{"name":"value","optional":false,"type":"string","bindable":false,"doc":"Must match the `value` of the destination that opens it.","details":[],"examples":[]},{"name":"keepMounted","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Keep the view mounted while hidden, in a set that isn't swipeable. Costs memory but preserves scroll position, form state and any in-flight work.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"NavigationViews","dir":"navigation-bar","entry":"omaris","importPath":"import { NavigationViews } from 'omaris'","summary":"The viewport the screens live in, and the thing a swipe moves.","details":["Without `swipeable` on the `Navigation` it shows one view at a time and costs nothing. With it, the views are laid out in a row and this drags them: the track follows the finger one-to-one, resists past the first and last destination, and settles on the next one from either the distance travelled or the speed it was thrown at — a flick moves a screen even when it barely moved at all.","`touch-action: pan-y` hands the browser the vertical axis and keeps the horizontal one, so a swipe never fights a scroll. It is not enough on its own: Chromium hands a touch to its own scrolling anyway and fires `pointercancel` a frame later, which is why the horizontal `touchmove` is also cancelled once the drag has been claimed. Without that the finger gets one frame of movement and the gesture dies."],"examples":[],"classesType":null,"parts":[],"variants":[],"story":{"title":"Navigation/Navigation Bar","category":"Navigation","own":false,"stories":["Playground","Label modes","With badges","Filled selected icon","Swipeable screens","Overridden"]},"props":[{"name":"threshold","optional":true,"type":"number","default":"0.25","bindable":false,"doc":"Fraction of the width a drag has to cover before it counts as a move. A fast flick moves regardless.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Turns the gesture off for this viewport, leaving the layout alone.","details":[],"examples":[]},{"name":"mouse","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Drag with a mouse too. Off by default — a swipe is a touch gesture.","details":[],"examples":[]},{"name":"lazy","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Build a screen the first time it is reached, then keep it mounted.","details":[],"examples":[]},{"name":"fill","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Grow to fill the `Navigation` column. Off sizes it by its content.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"NotificationCenter","dir":"notification-center","entry":"omaris","importPath":"import { NotificationCenter } from 'omaris'","summary":"The bell in the top bar, and everything behind it.","details":["A bell with the unread count on it opens a panel: a title and \"Mark all read\", All and Unread tabs, and the notifications themselves — an unread dot, an avatar or an icon, the title and a line or two of body, and a time that keeps itself current (\"3m\", then \"4m\"). On a desktop the panel hangs off the bell; on a phone it is a screen of its own — a top app bar with a back arrow, sliding in from the edge the way a page does — because a popover a thumb has to reach across for is the wrong shape there, and an inbox wants the whole height and nothing else pulling on the rows.","The bell rings once when the unread count goes up, and not at all under reduced motion.","Rows are dismissed the way each device expects. A finger swipes one away — or swipes the other way to mark it read — and a mouse gets an × that appears where the time was. Either way the row folds shut before `ondismiss` runs, so the list closes over the gap rather than jumping.","The component never changes `notifications` itself: every callback is a request, and the list you pass back is the answer. Past `virtualize` rows the list is windowed, so a backlog of a thousand opens as fast as one of ten."],"examples":[{"lang":"svelte","code":"<NotificationCenter\n  {notifications}\n  onread={(id) => markRead(id)}\n  onreadall={markAllRead}\n  ondismiss={(id) => remove(id)}\n/>"}],"classesType":"NotificationCenterClasses","parts":[{"name":"root","doc":"The box around the bell and its count — `relative`, so the badge can pin to it."},{"name":"bell","doc":"The bell — an `IconButton`, so this lands on its root. It swings from the top."},{"name":"badge","doc":"The unread count on the bell — a `Badge`."},{"name":"panel","doc":"The popover's surface, on a desktop."},{"name":"screen","doc":"The full-screen view on a phone — a native modal `<dialog>`."},{"name":"header","doc":"Title and \"Mark all read\" — the top app bar on a phone."},{"name":"back","doc":"The back arrow in the phone's top app bar — an `IconButton`."},{"name":"heading","doc":""},{"name":"markAll","doc":"\"Mark all read\" — a `Button`."},{"name":"tabs","doc":"The tab set."},{"name":"tabPanel","doc":"One tab's panel — the box the list scrolls inside."},{"name":"list","doc":"The scrolling list."},{"name":"item","doc":"One notification's wrapper — it folds shut when the row is dismissed."},{"name":"row","doc":"The pressable row — a link with `href`, a button without."},{"name":"dot","doc":"The unread dot, at the start of an unread row."},{"name":"media","doc":"The avatar, or the icon well."},{"name":"icon","doc":"The icon well, when a row has an `icon` rather than an `avatar`."},{"name":"text","doc":""},{"name":"title","doc":""},{"name":"body","doc":""},{"name":"time","doc":"The relative time. Gives way to the × under a hovering mouse."},{"name":"dismiss","doc":"The ×. A mouse gets it on hover; a finger swipes instead."},{"name":"empty","doc":""},{"name":"footer","doc":""}],"variants":[],"story":{"title":"Communication/Notification Center","category":"Communication","own":true,"stories":["Playground","A long backlog","Empty","Full screen","Overridden"]},"props":[{"name":"notifications","optional":false,"type":"NotificationItem[]","bindable":false,"doc":"","details":[],"examples":[]},{"name":"open","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Whether the panel is open. Bindable.","details":[],"examples":[]},{"name":"tab","optional":true,"type":"NotificationTab","default":"'all'","bindable":true,"doc":"The tab showing. Bindable.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","default":"'Notifications'","bindable":false,"doc":"The panel's heading, and its accessible name.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","default":"'Notifications'","bindable":false,"doc":"The bell's accessible name. The unread count is added to it.","details":[],"examples":[]},{"name":"onread","optional":true,"type":"(id: string) => void","bindable":false,"doc":"A notification was opened, or swiped the other way: mark it read.","details":[],"examples":[]},{"name":"onreadall","optional":true,"type":"() => void","bindable":false,"doc":"\"Mark all read\" was pressed. Without it the button is not drawn.","details":[],"examples":[]},{"name":"ondismiss","optional":true,"type":"(id: string) => void","bindable":false,"doc":"A notification was dismissed — swiped away, or its × pressed. Called once the row has folded shut. Without it rows cannot be dismissed.","details":[],"examples":[]},{"name":"onselect","optional":true,"type":"(notification: NotificationItem) => void","bindable":false,"doc":"A notification was pressed, after `onread`.","details":[],"examples":[]},{"name":"empty","optional":true,"type":"Snippet<[NotificationTab]>","bindable":false,"doc":"Drawn when the tab has nothing in it. Handed the tab.","details":[],"examples":[]},{"name":"footer","optional":true,"type":"Snippet<[{ close: () => void }]>","bindable":false,"doc":"Along the bottom of the panel — a \"See all\" link, say.","details":[],"examples":[]},{"name":"icon","optional":true,"type":"Snippet","bindable":false,"doc":"Replaces the bell glyph.","details":[],"examples":[]},{"name":"locale","optional":true,"type":"string","bindable":false,"doc":"Language for the relative times. Defaults to `<html lang>`.","details":[],"examples":[]},{"name":"max","optional":true,"type":"number","default":"99","bindable":false,"doc":"The count stops at this and adds a `+`.","details":[],"examples":[]},{"name":"virtualize","optional":true,"type":"number","default":"50","bindable":false,"doc":"Past this many rows the list is windowed.","details":[],"examples":[]},{"name":"align","optional":true,"type":"AnchorAlign","default":"'end'","bindable":false,"doc":"Which edge of the bell the popover lines up with.","details":[],"examples":[]},{"name":"mobileQuery","optional":true,"type":"string","default":"'(max-width: 639px)'","bindable":false,"doc":"What counts as a phone — there the panel is a full-screen view.","details":[],"examples":[]},{"name":"markAllLabel","optional":true,"type":"string","default":"'Mark all read'","bindable":false,"doc":"Labels, for another language.","details":[],"examples":[]},{"name":"allLabel","optional":true,"type":"string","default":"'All'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"unreadLabel","optional":true,"type":"string","default":"'Unread'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"dismissLabel","optional":true,"type":"string","default":"'Dismiss'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"readLabel","optional":true,"type":"string","default":"'Read'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"closeLabel","optional":true,"type":"string","default":"'Back'","bindable":false,"doc":"The back arrow that closes the full-screen view on a phone.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"NotificationCenterClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"NumberInput","dir":"number-input","entry":"omaris","importPath":"import { NumberInput } from 'omaris'","summary":"A number field that is a text field underneath.","details":["`<input type=\"number\">` is the wrong control for almost every number a dashboard collects: it cannot be emptied without a fight, it accepts `1e5` and `+-`, its own spinners are unstyleable, and a scroll over a focused one silently changes the value. This is a plain text input with a format that rejects anything that is not a number, so an empty field means `null` rather than a `0` that will not delete.","The steppers hold to repeat, accelerate the longer they are held, stop at `min`/`max`, and never take focus off the field."],"examples":[{"lang":"svelte","code":"<NumberInput label=\"Quantity\" bind:value min={1} max={99} />\n<NumberInput layout=\"split\" bind:value suffix=\"kg\" precision={1} />"}],"classesType":"NumberInputClasses","parts":[{"name":"root","doc":"Wrapper: label, field, supporting text."},{"name":"field","doc":"The frame: border, background, height, adornment layout."},{"name":"control","doc":"The bare <input>; the frame owns every decoration."},{"name":"label","doc":""},{"name":"adornment","doc":"Icon slots at either end of the frame."},{"name":"affix","doc":"Flat text glued to the value — \"https://\", \"kg\"."},{"name":"action","doc":"An interactive trailing control: reveal, clear."},{"name":"support","doc":"Helper line under the field, and the counter beside it."},{"name":"counter","doc":""},{"name":"step","doc":"A stepper button. Sized from the field's own `--field-action`."},{"name":"steppers","doc":"The pair of steppers, and the gap between them."}],"variants":[{"name":"emphasis","doc":"Filled steppers read as buttons in a dense row; the default is quiet.","default":"plain","values":[{"name":"plain","doc":""},{"name":"tonal","doc":""}]}],"story":{"title":"Inputs/Number Input","category":"Inputs","own":true,"stories":["Playground","Layouts","Empty is null","Sizes","Variants and emphasis","Units and precision","At the bounds","Disabled, readonly, invalid","Overridden"]},"props":[{"name":"value","optional":true,"type":"number | null","default":"null","bindable":true,"doc":"The number. `null` when the field is empty — not `0`. Bindable.","details":[],"examples":[]},{"name":"layout","optional":true,"type":"NumberInputLayout","default":"'trailing'","bindable":false,"doc":"Where the steppers sit, or `none` for a bare field.","details":[],"examples":[]},{"name":"emphasis","optional":true,"type":"NumberInputEmphasis","default":"'plain'","bindable":false,"doc":"How loud the steppers are.","details":[],"examples":[]},{"name":"variant","optional":true,"type":"InputVariant","default":"'outline'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"InputSize","default":"'default'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"min","optional":true,"type":"number","bindable":false,"doc":"Lower bound. The − stepper stops here, and `clamp` snaps to it.","details":[],"examples":[]},{"name":"max","optional":true,"type":"number","bindable":false,"doc":"Upper bound.","details":[],"examples":[]},{"name":"step","optional":true,"type":"number","default":"1","bindable":false,"doc":"One press of a stepper, or one arrow key. Shift multiplies it by 10.","details":[],"examples":[]},{"name":"precision","optional":true,"type":"number","default":"0","bindable":false,"doc":"Decimal places. `0` — the default — makes it an integer field.","details":[],"examples":[]},{"name":"group","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Group the thousands while the field is idle — `12,500`.","details":[],"examples":[]},{"name":"clamp","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Snap into `[min, max]` when the field is left.","details":[],"examples":[]},{"name":"wrap","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Wrap past the bounds instead of stopping — 12 → 1 on an hour field. Needs both `min` and `max`.","details":[],"examples":[]},{"name":"wheel","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Change the value on a wheel over the focused field. Off by default: a page that scrolls under the pointer must not edit the form.","details":[],"examples":[]},{"name":"picker","optional":true,"type":"boolean | 'always'","default":"false","bindable":false,"doc":"Collect the number on a wheel instead of a keyboard when the pointer is a finger.","details":["A typed number is fastest with a keyboard in front of you and slowest with a thumb, where the numeric keypad covers half the screen to change a quantity by one. `picker` leaves the desktop field exactly as it is and turns the touch one into a tap that opens a [Picker](/docs/components/picker) in a bottom sheet — the steppers and `bind:value` are unchanged either way.","`'always'` uses the wheel on a mouse too, for a field whose value is the point of the screen.","It needs `min` and `max` — a wheel has to have ends — and a range of at most {@link PICKER_MAX_ROWS} steps, since every row is a real element and a wheel that long is slower than typing. The field stays a plain field when either is missing, rather than opening something unusable."],"examples":[{"lang":"svelte","code":"<NumberInput label=\"Weight\" bind:value min={30} max={200} suffix=\"kg\" picker />"}]},{"name":"pickerTitle","optional":true,"type":"string","bindable":false,"doc":"Title on the picker sheet. Defaults to the field's own label.","details":[],"examples":[]},{"name":"pickerConfirmLabel","optional":true,"type":"string","default":"'Done'","bindable":false,"doc":"Confirm button on the picker sheet.","details":[],"examples":[]},{"name":"pickerCancelLabel","optional":true,"type":"string","default":"'Cancel'","bindable":false,"doc":"Cancel button on the picker sheet.","details":[],"examples":[]},{"name":"formatValue","optional":true,"type":"(value: number) => string","bindable":false,"doc":"Renders the settled value. Replaces the built-in grouping.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"supportingText","optional":true,"type":"string","bindable":false,"doc":"Helper line under the field. Becomes the error text when `invalid`.","details":[],"examples":[]},{"name":"invalid","optional":true,"type":"boolean","bindable":false,"doc":"Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","bindable":false,"doc":"Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"readonly","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"required","optional":true,"type":"boolean","bindable":false,"doc":"Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"placeholder","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"prefix","optional":true,"type":"string","bindable":false,"doc":"Flat text glued to the start of the value — \"$\", \"#\".","details":[],"examples":[]},{"name":"suffix","optional":true,"type":"string","bindable":false,"doc":"Flat text glued to the end — \"kg\", \"%\".","details":[],"examples":[]},{"name":"name","optional":true,"type":"string","bindable":false,"doc":"Posts the raw number, not the formatted text, under this name.","details":[],"examples":[]},{"name":"id","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"aria-label","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"aria-describedby","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"decrementLabel","optional":true,"type":"string","default":"'Decrease'","bindable":false,"doc":"Accessible label for the − stepper.","details":[],"examples":[]},{"name":"incrementLabel","optional":true,"type":"string","default":"'Increase'","bindable":false,"doc":"Accessible label for the + stepper.","details":[],"examples":[]},{"name":"haptics","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Play a tick on each step once `haptics.enabled` is on.","details":[],"examples":[]},{"name":"supporting","optional":true,"type":"Snippet","bindable":false,"doc":"Richer supporting text — a link, a hint.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(value: number | null) => void","bindable":false,"doc":"Fires once per settled value, after clamping.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"NumberInputClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"ref","optional":true,"type":"HTMLInputElement | null","default":"null","bindable":true,"doc":"","details":[],"examples":[]}]},{"name":"NumberPicker","dir":"picker","entry":"omaris","importPath":"import { NumberPicker } from 'omaris'","summary":"One wheel over a run of numbers.","details":["A hundred values in one flick, which is what a wheel is for. On a desktop, where a typed number is faster, [Number Input](/docs/components/number-input) is the better control."],"examples":[{"lang":"svelte","code":"<NumberPicker bind:value={weight} min={30} max={200} unit=\"kg\" />"}],"classesType":"PickerClasses","parts":[{"name":"root","doc":""},{"name":"header","doc":"The title line above the wheels."},{"name":"stage","doc":"Everything the band is drawn behind: the wheels and both fades."},{"name":"band","doc":"The strip marking the centre row."},{"name":"wheels","doc":"The row of wheels. Masked so rows dissolve towards the edges."},{"name":"actions","doc":"The cancel/confirm row. Only rendered when `onconfirm` is given."},{"name":"action","doc":"One of those buttons."}],"variants":[],"story":{"title":"Inputs/Picker","category":"Inputs","own":false,"stories":["Playground","Date","Time","Date and time","Number","Custom columns","Text options","With actions","Sizes and depth","Disabled","Overridden"]},"props":[{"name":"value","optional":true,"type":"number","default":"0","bindable":true,"doc":"The number. Bindable.","details":[],"examples":[]},{"name":"min","optional":true,"type":"number","default":"0","bindable":false,"doc":"","details":[],"examples":[]},{"name":"max","optional":true,"type":"number","default":"100","bindable":false,"doc":"","details":[],"examples":[]},{"name":"step","optional":true,"type":"number","default":"1","bindable":false,"doc":"The gap between rows.","details":[],"examples":[]},{"name":"precision","optional":true,"type":"number","default":"0","bindable":false,"doc":"Decimal places on each row's label.","details":[],"examples":[]},{"name":"unit","optional":true,"type":"string","bindable":false,"doc":"Drawn small beside every row — \"kg\", \"%\".","details":[],"examples":[]},{"name":"loop","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Spin past the ends and come back round.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","default":"'Value'","bindable":false,"doc":"Accessible name for the wheel.","details":[],"examples":[]},{"name":"format","optional":true,"type":"(value: number) => string","bindable":false,"doc":"Replaces the row's text.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(value: number) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"columnClasses","optional":true,"type":"PickerColumnClasses","bindable":false,"doc":"Per-part overrides for the wheel itself.","details":[],"examples":[]},{"name":"classes","optional":true,"type":"PickerClasses","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"PickerSize","bindable":false,"doc":"Row height and type scale.","details":[],"examples":[]},{"name":"surface","optional":true,"type":"PickerSurface","bindable":false,"doc":"How the frame is drawn.","details":[],"examples":[]},{"name":"visible","optional":true,"type":"number","bindable":false,"doc":"Rows on screen at once. Rounded up to the next odd number.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"A title above the wheels.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","bindable":false,"doc":"Disables every wheel inside.","details":[],"examples":[]},{"name":"haptics","optional":true,"type":"boolean","bindable":false,"doc":"Play a tick as each row passes the centre, once haptics are on.","details":[],"examples":[]},{"name":"onconfirm","optional":true,"type":"() => void","bindable":false,"doc":"Renders the action row. Called with the value already committed.","details":[],"examples":[]},{"name":"oncancel","optional":true,"type":"() => void","bindable":false,"doc":"Renders a cancel button beside it.","details":[],"examples":[]},{"name":"confirmLabel","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"cancelLabel","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"footer","optional":true,"type":"Snippet","bindable":false,"doc":"Replaces the built-in action row.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"OtpInput","dir":"otp-input","entry":"omaris","importPath":"import { OtpInput } from 'omaris'","summary":"The one-time code field.","details":["One real `<input>` lies invisibly across the whole row and the boxes are drawn under it. That is the part worth knowing: a code field built from one box per digit has to reimplement paste, autofill, select-all, backspace across a boundary and every mobile keyboard's idea of what a character is — and gets at least one of them wrong. Here the browser does all of it, so pasting `123 456` from a message fills the row, iOS's one-time-code suggestion lands, ⌘A selects the code and ⌫ clears it."],"examples":[{"lang":"svelte","code":"<OtpInput bind:value={code} oncomplete={verify} />\n<OtpInput length={8} pattern=\"alphanumeric\" groups={[4, 4]} />"}],"classesType":"OtpInputClasses","parts":[{"name":"slot","doc":"One box. `data-active` while the caret is in it."},{"name":"char","doc":"The character in the box."},{"name":"caret","doc":"The blinking bar shown in the empty box the caret is in."},{"name":"separator","doc":"The gap drawn between two groups. Inert, for the same reason a box is."},{"name":"control","doc":"The control itself — transparent, and exactly over the row."}],"variants":[{"name":"variant","doc":"","default":"outline","values":[{"name":"outline","doc":"A box per digit — the default, and the one people expect."},{"name":"filled","doc":"A tinted well, no border until the caret arrives."},{"name":"underline","doc":"A rule under each digit, for a lighter form."}]},{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]},{"name":"invalid","doc":"","default":"false","values":[{"name":"true","doc":""}]},{"name":"disabled","doc":"","values":[{"name":"true","doc":""}]}],"story":{"title":"Inputs/OTP Input","category":"Inputs","own":true,"stories":["Playground","Complete","Variants","Sizes","Grouped","Masked","Invalid","Disabled and readonly","Overridden"]},"props":[{"name":"value","optional":true,"type":"string","default":"''","bindable":true,"doc":"The code so far. Bindable, and never longer than `length`.","details":[],"examples":[]},{"name":"length","optional":true,"type":"number","default":"6","bindable":false,"doc":"How many characters the code has.","details":[],"examples":[]},{"name":"variant","optional":true,"type":"OtpInputVariant","default":"'outline'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"OtpInputSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"pattern","optional":true,"type":"OtpPattern","default":"'digits'","bindable":false,"doc":"What the field accepts. Anything else is dropped, typed or pasted.","details":[],"examples":[]},{"name":"uppercase","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Upper-case every letter as it lands — codes are usually read aloud.","details":[],"examples":[]},{"name":"groups","optional":true,"type":"number[]","bindable":false,"doc":"Split the row — `[3, 3]` for `123-456`. Must add up to `length`.","details":[],"examples":[]},{"name":"separator","optional":true,"type":"string","default":"'–'","bindable":false,"doc":"What sits between two groups.","details":[],"examples":[]},{"name":"mask","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Show dots instead of the characters.","details":[],"examples":[]},{"name":"invalid","optional":true,"type":"boolean","bindable":false,"doc":"Marks the row invalid and shakes it once. Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","bindable":false,"doc":"Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"readonly","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"autofocus","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Take focus on mount — right on a screen whose only job is the code.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible name for the whole row. \"Verification code\" when omitted — or, inside a `Field`, the field's own label.","details":[],"examples":[]},{"name":"oncomplete","optional":true,"type":"(value: string) => void","bindable":false,"doc":"Fires the moment the last character lands, typed or pasted.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(value: string) => void","bindable":false,"doc":"Fires on every change, complete or not.","details":[],"examples":[]},{"name":"slot","optional":true,"type":"Snippet<[{ char: string; index: number; active: boolean; filled: boolean }]>","bindable":false,"doc":"Replaces a box's contents. Gets the character and the box's state.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"OtpInputClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"ref","optional":true,"type":"HTMLInputElement | null","default":"null","bindable":true,"doc":"","details":[],"examples":[]}]},{"name":"PageTransition","dir":"page-transition","entry":"omaris","importPath":"import { PageTransition } from 'omaris'","summary":"Page transitions — off unless you ask for one.","details":["`transition` defaults to `false`, and a `false` transition renders the children with no wrapper, no keyed block and no cost: navigation behaves exactly as it did before this component existed. Name a pattern and the page starts moving, on the same MD3 curves the components use.","— where `page` is SvelteKit's `$app/state`, so every navigation is a new key and every key change is a transition.","**`direction=\"auto\"` works out which way you went.** It keeps the keys it has seen as a stack: a key it has never seen is forward and goes on the stack, and a key already on it is a Back — the stack unwinds to it and the pattern plays in reverse. That is a browser Back button, a swipe back and a breadcrumb, all without the layout being told which.","Seventeen patterns, each with the duration it actually wants, so `duration` is only there for when you disagree. Patterns that travel along the inline axis follow the writing direction, so forward is leftward in Arabic without a second preset.","The two pages are stacked in one grid cell while they cross, so nothing jumps and the scroll position doesn't lurch. The leaving page is made inert on its way out, so a click can't land on a page that's gone.","Neither page may move the document while they cross. Two things would, and both are handled here rather than left to the consumer:","- **The pair's height.** Stacked in one grid cell, the row is as tall as the taller of the two, so a tall page leaving a short one holds the document at the old height and then drops it — a scrollbar that appears for a few frames and goes. The leaving page is taken out of flow at its own size the moment it starts to leave, so the container is only ever the height of the page arriving. - **The travel.** A page translated 32px or a full width is still part of the scrollable overflow, so the axis it moves along grows a scrollbar mid-flight. The container clips while a transition is running and stops clipping the moment it ends, so a menu or a sticky header that overflows on purpose is unaffected the rest of the time."],"examples":[{"lang":"svelte","code":"<PageTransition key={page.url.pathname} transition=\"push\" direction=\"auto\">\n  {@render children()}\n</PageTransition>"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"System/PageTransition","category":"System","own":true,"stories":["Off by default","Playground","Every preset","Like a native stack","Between heights","Overridden"]},"props":[{"name":"key","optional":true,"type":"unknown","bindable":false,"doc":"Change this to run a transition — `page.url.pathname`, usually.","details":[],"examples":[]},{"name":"transition","optional":true,"type":"PageTransitionName | false","default":"false","bindable":false,"doc":"The pattern, or `false` (the default) for none at all.","details":[],"examples":[]},{"name":"direction","optional":true,"type":"PageTransitionDirection | 'auto'","default":"'forward'","bindable":false,"doc":"Which way the axis patterns travel. `auto` reads it off the keys it has seen: a new one is forward, one it has been to before is a Back.","details":[],"examples":[]},{"name":"duration","optional":true,"type":"number","bindable":false,"doc":"Total time for the pair, in ms. Defaults to what the pattern wants.","details":[],"examples":[]},{"name":"clip","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Clip the travel while a transition runs. On unless a page has something that has to escape the container mid-flight.","details":[],"examples":[]},{"name":"scroll","optional":true,"type":"'keep' | 'top'","default":"'keep'","bindable":false,"doc":"Put the scroll back to the top as the new page arrives. `'top'` scrolls the nearest scrollable ancestor, which is the app frame in a dashboard and the window on an ordinary page.","details":[],"examples":[]},{"name":"focus","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Move focus to the arriving page, the way a native screen change does, so a keyboard lands on the new page rather than back at the top of the document.","details":[],"examples":[]},{"name":"onstart","optional":true,"type":"(direction: PageTransitionDirection) => void","bindable":false,"doc":"Called as a pair starts, with the direction it is playing.","details":[],"examples":[]},{"name":"onend","optional":true,"type":"() => void","bindable":false,"doc":"Called once the pair has landed.","details":[],"examples":[]},{"name":"children","optional":false,"type":"Snippet","bindable":false,"doc":"The page.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"Pagination","dir":"pagination","entry":"omaris","importPath":"import { Pagination } from 'omaris'","summary":"Pagination.","details":["The page list keeps a fixed width whatever page you're on — the window of numbers slides, and ellipses stand in for the gaps — so the control doesn't reflow under the pointer as you click through it.","The selected page isn't drawn on the button. It's a single pill living behind the row that slides to whichever number is current, so paging reads as one object moving rather than one square blinking off and another blinking on. It lands without sliding on first paint, and on a `motion-reduce` display it only ever lands."],"examples":[],"classesType":"PaginationClasses","parts":[{"name":"root","doc":""},{"name":"indicator","doc":"The selected pill. Sized and placed from the current button's own box, so it tracks whatever the size variant made that button."},{"name":"page","doc":""},{"name":"current","doc":"The pill behind it carries the fill, so this is only the ink."},{"name":"ellipsis","doc":""},{"name":"summary","doc":"The \"1–10 of 240\" line."},{"name":"meta","doc":"Holds the rows-per-page choice and the summary, side by side."},{"name":"perPage","doc":"The rows-per-page `Select`."}],"variants":[{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""}]}],"story":{"title":"Navigation/Pagination","category":"Navigation","own":true,"stories":["Playground","Sizes","Positions","Few pages","With summary","Rows per page","Compact","Wider window"]},"props":[{"name":"page","optional":true,"type":"number","default":"1","bindable":true,"doc":"Current page, 1-based. Bindable.","details":[],"examples":[]},{"name":"count","optional":false,"type":"number","bindable":false,"doc":"Total number of pages.","details":[],"examples":[]},{"name":"size","optional":true,"type":"PaginationSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"siblings","optional":true,"type":"number","default":"1","bindable":false,"doc":"How many numbers to show around the current page.","details":[],"examples":[]},{"name":"boundaries","optional":true,"type":"number","default":"1","bindable":false,"doc":"How many to always show at each end.","details":[],"examples":[]},{"name":"compact","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Hide the number list, leaving just previous/next.","details":[],"examples":[]},{"name":"total","optional":true,"type":"number","bindable":false,"doc":"Total rows, for the \"1–10 of 240\" summary.","details":[],"examples":[]},{"name":"perPage","optional":true,"type":"number","bindable":true,"doc":"Rows per page, for the summary. Bindable, when `perPageOptions` lets it change.","details":[],"examples":[]},{"name":"perPageOptions","optional":true,"type":"number[]","bindable":false,"doc":"Offer these as a \"Rows per page\" choice beside the summary — `[10, 25, 50, 100]`. Changing it keeps the first visible row on screen by moving `page` to wherever that row now lands.","details":[],"examples":[]},{"name":"perPageLabel","optional":true,"type":"string","default":"'Rows per page'","bindable":false,"doc":"Label for the rows-per-page choice.","details":[],"examples":[]},{"name":"onpagechange","optional":true,"type":"(page: number) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onperpagechange","optional":true,"type":"(perPage: number) => void","bindable":false,"doc":"Called when the rows-per-page choice changes.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","default":"'Pagination'","bindable":false,"doc":"Accessible name.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"PaginationClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"PhoneInput","dir":"phone-input","entry":"omaris","importPath":"import { PhoneInput } from 'omaris'","summary":"A phone field that stores E.164 and lets people type a national number.","details":["The dial code lives in the country picker rather than the field, so nobody types `+964` and nobody can mistype it. Pasting a full international number works too: `+90 …`, `0090 …` and `00964 …` all switch the country."],"examples":[],"classesType":"InputClasses","parts":[{"name":"root","doc":"Wrapper: label, field, supporting text."},{"name":"field","doc":"The frame: border, background, height, adornment layout."},{"name":"control","doc":"The bare <input>; the frame owns every decoration."},{"name":"label","doc":""},{"name":"adornment","doc":"Icon slots at either end of the frame."},{"name":"affix","doc":"Flat text glued to the value — \"https://\", \"kg\"."},{"name":"action","doc":"An interactive trailing control: reveal, clear."},{"name":"support","doc":"Helper line under the field, and the counter beside it."},{"name":"counter","doc":""}],"variants":[],"story":{"title":"Inputs/Phone Input","category":"Inputs","own":true,"stories":["Playground","Bound value","States","Other countries","Sizes"]},"props":[{"name":"value","optional":true,"type":"string","default":"''","bindable":true,"doc":"The number in E.164 — `+9647701234567`. Bindable, `''` when empty.","details":[],"examples":[]},{"name":"country","optional":true,"type":"string","default":"'IQ'","bindable":true,"doc":"Selected country, as an ISO code. Bindable.","details":[],"examples":[]},{"name":"countries","optional":true,"type":"Country[]","default":"COUNTRIES","bindable":false,"doc":"Countries offered in the picker.","details":[],"examples":[]},{"name":"variant","optional":true,"type":"InputVariant","default":"'outline'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"InputSize","default":"'default'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"supportingText","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"invalid","optional":true,"type":"boolean","bindable":false,"doc":"Forces the error state. Otherwise the field checks itself on blur — and, inside a `Field`, is invalid while the field is.","details":[],"examples":[]},{"name":"incompleteMessage","optional":true,"type":"string","default":"'That number looks incomplete.'","bindable":false,"doc":"Shown when a half-typed number is left behind.","details":[],"examples":[]},{"name":"validate","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Turn off the on-blur completeness check.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","bindable":false,"doc":"Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"readonly","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"required","optional":true,"type":"boolean","bindable":false,"doc":"Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"placeholder","optional":true,"type":"string","bindable":false,"doc":"Overrides the country's own example number.","details":[],"examples":[]},{"name":"id","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"name","optional":true,"type":"string","bindable":false,"doc":"Posts the E.164 value under this name.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"InputClasses","bindable":false,"doc":"Per-part Tailwind overrides, forwarded to the `Input` underneath.","details":[],"examples":[]},{"name":"ref","optional":true,"type":"HTMLInputElement | null","default":"null","bindable":true,"doc":"","details":[],"examples":[]}]},{"name":"Picker","dir":"picker","entry":"omaris","importPath":"import { Picker } from 'omaris'","summary":"The frame a set of wheels sits in: the selection band across the middle, the fade at the top and bottom edges, and — when you give it `onconfirm` — the cancel/confirm row under them.","details":["It is a surface, not an overlay. Put it in a [Sheet](/docs/components/sheet) on a phone or a [Dialog](/docs/components/dialog) on a desktop; drop it straight into a form when the value is the point of the screen.","Built for a thumb first. A wheel is the fastest way through a hundred values on a touch screen and the slowest on a desktop, where a [Select](/docs/components/select) or a typed field wins."],"examples":[{"lang":"svelte","code":"<Picker title=\"Duration\">\n  <PickerColumn label=\"Hours\" options={hours} bind:value={h} unit=\"h\" />\n  <PickerColumn label=\"Minutes\" options={minutes} bind:value={m} unit=\"m\" />\n</Picker>"}],"classesType":"PickerClasses","parts":[{"name":"root","doc":""},{"name":"header","doc":"The title line above the wheels."},{"name":"stage","doc":"Everything the band is drawn behind: the wheels and both fades."},{"name":"band","doc":"The strip marking the centre row."},{"name":"wheels","doc":"The row of wheels. Masked so rows dissolve towards the edges."},{"name":"actions","doc":"The cancel/confirm row. Only rendered when `onconfirm` is given."},{"name":"action","doc":"One of those buttons."}],"variants":[{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]},{"name":"surface","doc":"How the frame itself is drawn.","default":"plain","values":[{"name":"plain","doc":"No frame — the wheels sit on whatever is behind them."},{"name":"card","doc":"A card: a border, the popover background and a soft shadow."},{"name":"filled","doc":"A tinted well, for a picker inside a form."}]}],"story":{"title":"Inputs/Picker","category":"Inputs","own":true,"stories":["Playground","Date","Time","Date and time","Number","Custom columns","Text options","With actions","Sizes and depth","Disabled","Overridden"]},"props":[{"name":"size","optional":true,"type":"PickerSize","default":"'md'","bindable":false,"doc":"Row height and type scale.","details":[],"examples":[]},{"name":"surface","optional":true,"type":"PickerSurface","default":"'plain'","bindable":false,"doc":"How the frame is drawn.","details":[],"examples":[]},{"name":"visible","optional":true,"type":"number","bindable":false,"doc":"Rows on screen at once. Rounded up to the next odd number.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"A title above the wheels.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Disables every wheel inside.","details":[],"examples":[]},{"name":"haptics","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Play a tick as each row passes the centre, once haptics are on.","details":[],"examples":[]},{"name":"onconfirm","optional":true,"type":"() => void","bindable":false,"doc":"Renders the action row. Called with the value already committed.","details":[],"examples":[]},{"name":"oncancel","optional":true,"type":"() => void","bindable":false,"doc":"Renders a cancel button beside it.","details":[],"examples":[]},{"name":"confirmLabel","optional":true,"type":"string","default":"'OK'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"cancelLabel","optional":true,"type":"string","default":"'Cancel'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"footer","optional":true,"type":"Snippet","bindable":false,"doc":"Replaces the built-in action row.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"The wheels — one `PickerColumn` each.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"PickerClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"PickerColumn","dir":"picker","entry":"omaris","importPath":"import { PickerColumn } from 'omaris'","summary":"One wheel.","details":["The scrolling is the browser's own — `overflow-y: scroll` with `scroll-snap-type: y mandatory` — because nothing written in JavaScript matches the momentum a phone gives a native scroller for free. What is scripted is only the part CSS cannot do: the cylinder, where each row is tilted and faded by its distance from the centre, and settling on the row that ends up there."],"examples":[{"lang":"svelte","code":"<PickerColumn label=\"Hour\" options={hours} bind:value={hour} loop />"}],"classesType":"PickerColumnClasses","parts":[{"name":"root","doc":"The scroller. Holds the snap points and the perspective."},{"name":"item","doc":"One snap target. Never transformed — a scaled row moves its own snap point."},{"name":"face","doc":"The row's face. This is what tilts, fades and scales."},{"name":"unit","doc":"The unit glued to every row — \"kg\", \"min\"."}],"variants":[{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]}],"story":{"title":"Inputs/Picker","category":"Inputs","own":false,"stories":["Playground","Date","Time","Date and time","Number","Custom columns","Text options","With actions","Sizes and depth","Disabled","Overridden"]},"props":[{"name":"options","optional":false,"type":"readonly (PickerOption<T> | string)[]","bindable":false,"doc":"The rows. Strings are shorthand for `{ value: s, label: s }`.","details":[],"examples":[]},{"name":"value","optional":true,"type":"T","default":"undefined as T","bindable":true,"doc":"The selected row's value. Bindable.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible name for the wheel — \"Hour\", \"Month\". Required in practice.","details":[],"examples":[]},{"name":"caption","optional":true,"type":"string","bindable":false,"doc":"A caption above the wheel. Rarely needed; the value usually says it.","details":[],"examples":[]},{"name":"loop","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Spin past the ends and come back round. For a cycle — hours, minutes, months — and wrong for a bounded range like a year.","details":[],"examples":[]},{"name":"unit","optional":true,"type":"string","bindable":false,"doc":"A unit drawn small beside every row — \"kg\", \"min\".","details":[],"examples":[]},{"name":"size","optional":true,"type":"PickerSize","bindable":false,"doc":"Overrides the size inherited from the `Picker`.","details":[],"examples":[]},{"name":"visible","optional":true,"type":"number","bindable":false,"doc":"Overrides the visible row count inherited from the `Picker`.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"hug","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Let the wheel size itself to its widest row instead of sharing the width.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(value: T) => void","bindable":false,"doc":"Fires once the wheel settles, not on every row it passes.","details":[],"examples":[]},{"name":"row","optional":true,"type":"Snippet<[PickerOption<T>, boolean]>","bindable":false,"doc":"Replaces the row's text. Gets the option and whether it is centred.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"PickerColumnClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"PieChart","dir":"chart","entry":"omaris/chart","importPath":"import { PieChart } from 'omaris/chart'","summary":"Pie and donut chart.","details":["Unlike the axis charts this one takes a row per slice rather than a series per column, so `label` and `value` name the two fields it needs. `centre` fills the hole in a donut, which is where the total belongs."],"examples":[{"lang":"svelte","code":"<PieChart data={rows} label=\"channel\" value=\"signups\" donut />"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Charts","category":"Data Display","own":false,"stories":["Area","Line","Bar","Pie and donut","Scatter","Sparkline","Empty","References and annotations","Brush and zoom","Legend isolate and CSV","Error","Combo","Radar","Radial bar and gauge","Funnel","Treemap","Candlestick"]},"props":[{"name":"data","optional":false,"type":"T[]","bindable":false,"doc":"","details":[],"examples":[]},{"name":"label","optional":true,"type":"Field<T>","default":"'label'","bindable":false,"doc":"Field naming each slice. Defaults to `row.label`.","details":["This is the name of a *column*, not the chart's own name — that is `title`. Passing a sentence here silently labels every slice `undefined`, which shows up as a legend of blanks."],"examples":[]},{"name":"value","optional":true,"type":"Field<T>","default":"'value'","bindable":false,"doc":"Field holding each slice's size. Defaults to `row.value`.","details":[],"examples":[]},{"name":"donut","optional":true,"type":"boolean | number","default":"false","bindable":false,"doc":"Cut the middle out. A number is the hole's radius in px.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"260","bindable":false,"doc":"Plot height. A number is px; a string is any CSS length.","details":[],"examples":[]},{"name":"legend","optional":true,"type":"ChartLegend","default":"false","bindable":false,"doc":"`true` toggles a slice off on click; `'isolate'` shows it alone.","details":[],"examples":[]},{"name":"tooltip","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"labels","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Print each slice's value on it.","details":[],"examples":[]},{"name":"colors","optional":true,"type":"readonly string[]","default":"CHART_COLORS","bindable":false,"doc":"Palette override, cycled across the slices.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"Accessible description of what the chart shows.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"centre","optional":true,"type":"Snippet","bindable":false,"doc":"Content for the middle of a donut — a total, usually.","details":[],"examples":[]},{"name":"empty","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]},{"name":"emptyText","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"error","optional":true,"type":"boolean | string | Error","bindable":false,"doc":"Something went wrong. Truthy puts the chart into its error state; a string or an `Error` supplies the message.","details":[],"examples":[]},{"name":"errorText","optional":true,"type":"string","bindable":false,"doc":"The message, when `error` is just `true`.","details":[],"examples":[]},{"name":"errorState","optional":true,"type":"Snippet<[{ message: string }]>","bindable":false,"doc":"Replaces the whole error state.","details":[],"examples":[]},{"name":"onRetry","optional":true,"type":"() => void","bindable":false,"doc":"Offers a \"Try again\" button in the error state.","details":[],"examples":[]},{"name":"csv","optional":true,"type":"boolean | string","default":"false","bindable":false,"doc":"Offer the plotted rows as a CSV download, from a button in the corner. A string names the file.","details":[],"examples":[]},{"name":"csvColumns","optional":true,"type":"(string | { key: string; label?: string; value?: (row: T) => unknown })[]","bindable":false,"doc":"Which fields the download writes, in order. Defaults to every field.","details":[],"examples":[]}]},{"name":"Popover","dir":"popover","entry":"omaris","importPath":"import { Popover } from 'omaris'","summary":"A panel that hangs off a trigger and holds whatever you put in it — a filter form, a colour picker, a profile card, a confirmation.","details":["The `trigger` snippet is handed the ARIA and the handlers to spread onto whatever opens it, so they land on the real button rather than a wrapper. The panel is portalled and anchored, so it escapes scroll containers, flips when it runs out of room and shrinks rather than hanging off the bottom of the screen.","`openOn` decides the gesture: `click` is the default and takes focus into the panel, `hover` is a preview card that survives the trip from the trigger, `focus` opens on tab, `manual` leaves it to `bind:open`.","Keyboard: Enter/Space/↓ open it, Tab cycles inside it, Escape closes it and puts focus back on the trigger."],"examples":[{"lang":"svelte","code":"<Popover title=\"Filters\">\n  {#snippet trigger(props)}\n    <Button variant=\"outlined\" {...props}>Filters</Button>\n  {/snippet}\n  {#snippet children({ close })}\n    <Checkbox label=\"Archived\" />\n    <Button onclick={close}>Apply</Button>\n  {/snippet}\n</Popover>"}],"classesType":"PopoverClasses","parts":[{"name":"trigger","doc":"The wrapper around whatever opens it — `w-full` for a full-width trigger."},{"name":"surface","doc":""},{"name":"content","doc":"The scrolling part. The arrow sits outside it, so it is never clipped."},{"name":"header","doc":"Title and description, when either is set."},{"name":"title","doc":""},{"name":"description","doc":""},{"name":"footer","doc":"Actions along the bottom."},{"name":"arrow","doc":"The pointer. A rotated square straddling the edge, with the two inner borders dropped so nothing crosses the surface."}],"variants":[{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""},{"name":"auto","doc":"No width and no padding — for a panel that brings its own."}]}],"story":{"title":"Containment/Popover","category":"Containment","own":true,"stories":["Playground","Form","Sides","Hover card","Overridden"]},"props":[{"name":"open","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Bindable.","details":[],"examples":[]},{"name":"onOpenChange","optional":true,"type":"(open: boolean) => void","bindable":false,"doc":"Called whenever it opens or closes, however that happened.","details":[],"examples":[]},{"name":"openOn","optional":true,"type":"PopoverTrigger","default":"'click'","bindable":false,"doc":"The gesture that opens it.","details":[],"examples":[]},{"name":"side","optional":true,"type":"AnchorSide","default":"'bottom'","bindable":false,"doc":"Which side to prefer. Flips when there isn't room.","details":[],"examples":[]},{"name":"align","optional":true,"type":"AnchorAlign","default":"'center'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"offset","optional":true,"type":"number","default":"8","bindable":false,"doc":"Gap between the trigger and the panel, in px.","details":[],"examples":[]},{"name":"size","optional":true,"type":"PopoverSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"matchWidth","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Make the panel at least as wide as its trigger.","details":[],"examples":[]},{"name":"arrow","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Show the pointer. It tracks the trigger, not the panel's middle.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"Heading, and the panel's accessible name.","details":[],"examples":[]},{"name":"description","optional":true,"type":"string","bindable":false,"doc":"A line under the title.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Opening is a no-op, and an open one closes.","details":[],"examples":[]},{"name":"delay","optional":true,"type":"number","default":"120","bindable":false,"doc":"Delay before a hover opens it, in ms.","details":[],"examples":[]},{"name":"closeDelay","optional":true,"type":"number","default":"140","bindable":false,"doc":"Grace period before a hover closes it — the trip to the panel.","details":[],"examples":[]},{"name":"closeOnEscape","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Escape closes it.","details":[],"examples":[]},{"name":"closeOnOutsideClick","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"A press outside closes it.","details":[],"examples":[]},{"name":"trapFocus","optional":true,"type":"boolean","bindable":false,"doc":"Keep Tab inside the panel while it is open. Defaults to on for `click` and `manual`, off for the pointer-driven modes.","details":[],"examples":[]},{"name":"autofocus","optional":true,"type":"boolean | string","bindable":false,"doc":"What to focus on open: the first focusable thing (`true`), the panel itself (`false`), or a CSS selector for one element inside it. Defaults to `true` for `click` and `manual`, `false` otherwise.","details":[],"examples":[]},{"name":"portalTo","optional":true,"type":"PortalTarget","bindable":false,"doc":"Where the panel is portalled. The body, by default.","details":[],"examples":[]},{"name":"mobileSheet","optional":true,"type":"boolean","bindable":false,"doc":"On a phone, rise from the bottom edge as a sheet — full width, a scrim behind, dragged down to dismiss — instead of hanging off the trigger. On by default for a popover opened by a press; `false` keeps it anchored on every screen.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"Merged onto the panel, so `class=\"w-80\"` resizes it.","details":[],"examples":[]},{"name":"classes","optional":true,"type":"PopoverClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the panel.","details":[],"examples":[]},{"name":"trigger","optional":true,"type":"Snippet<[PopoverTriggerProps]>","bindable":false,"doc":"Receives the props to spread onto the opening control.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet<[PopoverBody]>","bindable":false,"doc":"The panel's contents.","details":[],"examples":[]},{"name":"footer","optional":true,"type":"Snippet<[PopoverBody]>","bindable":false,"doc":"Buttons along the bottom, separated from the content.","details":[],"examples":[]},{"name":"aria-haspopup","optional":false,"type":"'dialog'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"aria-expanded","optional":false,"type":"boolean","bindable":false,"doc":"","details":[],"examples":[]},{"name":"aria-controls","optional":false,"type":"string | undefined","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onclick","optional":false,"type":"(event: MouseEvent) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onkeydown","optional":false,"type":"(event: KeyboardEvent) => void","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"PriceInput","dir":"price-input","entry":"omaris","importPath":"import { PriceInput } from 'omaris'","summary":"A money field: the currency decides the symbol, which side it sits on, how many decimals are allowed and how much one step is worth.","details":["The value stays a number, so nothing downstream has to parse a formatted string back."],"examples":[],"classesType":"InputClasses","parts":[{"name":"root","doc":"Wrapper: label, field, supporting text."},{"name":"field","doc":"The frame: border, background, height, adornment layout."},{"name":"control","doc":"The bare <input>; the frame owns every decoration."},{"name":"label","doc":""},{"name":"adornment","doc":"Icon slots at either end of the frame."},{"name":"affix","doc":"Flat text glued to the value — \"https://\", \"kg\"."},{"name":"action","doc":"An interactive trailing control: reveal, clear."},{"name":"support","doc":"Helper line under the field, and the counter beside it."},{"name":"counter","doc":""}],"variants":[],"story":{"title":"Inputs/Price Input","category":"Inputs","own":true,"stories":["Playground","Currency picker","Single currency","Presets","Shorthand and Arabic digits","Junk input","Bounds","Sizes"]},"props":[{"name":"value","optional":true,"type":"number | null","default":"null","bindable":true,"doc":"The amount, as a number. Bindable, and null when the field is empty.","details":[],"examples":[]},{"name":"currency","optional":true,"type":"string","default":"'IQD'","bindable":true,"doc":"Selected currency code. Bindable.","details":[],"examples":[]},{"name":"currencies","optional":true,"type":"Currency[]","default":"DEFAULT_CURRENCIES","bindable":false,"doc":"Currencies offered. More than one renders the picker.","details":[],"examples":[]},{"name":"variant","optional":true,"type":"InputVariant","default":"'outline'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"InputSize","default":"'default'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Label above the field.","details":[],"examples":[]},{"name":"supportingText","optional":true,"type":"string","bindable":false,"doc":"Helper line. Replaced by the error text when `invalid`.","details":[],"examples":[]},{"name":"min","optional":true,"type":"number","bindable":false,"doc":"","details":[],"examples":[]},{"name":"max","optional":true,"type":"number","bindable":false,"doc":"","details":[],"examples":[]},{"name":"step","optional":true,"type":"number","bindable":false,"doc":"Arrow-key increment. Defaults to the currency's own step.","details":[],"examples":[]},{"name":"clamp","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Snap the value into [min, max] when the field is left.","details":[],"examples":[]},{"name":"presets","optional":true,"type":"number[]","bindable":false,"doc":"One-tap amounts under the field, in the current currency.","details":[],"examples":[]},{"name":"rates","optional":true,"type":"Record<string","bindable":false,"doc":"Value of one unit of each currency in a shared base, keyed by code — `{ IQD: 1, USD: 1310 }`. Drives the approximate second amount.","details":[],"examples":[]},{"name":"secondary","optional":true,"type":"string","bindable":false,"doc":"Code the approximation is shown in. Hidden when it's the active one.","details":[],"examples":[]},{"name":"invalid","optional":true,"type":"boolean","bindable":false,"doc":"Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","bindable":false,"doc":"Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"readonly","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"required","optional":true,"type":"boolean","bindable":false,"doc":"Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"placeholder","optional":true,"type":"string","default":"'0'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"id","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"name","optional":true,"type":"string","bindable":false,"doc":"Posts the raw number (not the formatted text) under this name.","details":[],"examples":[]},{"name":"aria-describedby","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"hint","optional":true,"type":"Snippet","bindable":false,"doc":"Replaces the built-in approximation line.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"InputClasses","bindable":false,"doc":"Per-part Tailwind overrides, forwarded to the `Input` underneath.","details":[],"examples":[]},{"name":"ref","optional":true,"type":"HTMLInputElement | null","default":"null","bindable":true,"doc":"","details":[],"examples":[]}]},{"name":"Progress","dir":"progress","entry":"omaris","importPath":"import { Progress } from 'omaris'","summary":"MD3 linear progress indicator.","details":["Determinate when `value` is a number, indeterminate when it isn't. The MD3 Expressive detail is the gap between the filled bar and the track, plus the little stop dot at the end of the track — both are drawn here rather than faked with a solid bar."],"examples":[],"classesType":"ProgressClasses","parts":[{"name":"root","doc":""},{"name":"track","doc":"The unfilled remainder."},{"name":"indicator","doc":"The filled portion."},{"name":"buffer","doc":"What has loaded ahead of the playhead — `buffer`. Under the fill, over the track."},{"name":"stop","doc":"MD3's stop indicator: a dot pinned to the far end of the track."}],"variants":[{"name":"tone","doc":"","default":"primary","values":[{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""}]},{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]}],"story":{"title":"Communication/Progress","category":"Communication","own":true,"stories":["Playground","Determinate","Buffered","Indeterminate","Sizes","Tones","Circular","Live"]},"props":[{"name":"value","optional":true,"type":"number","bindable":false,"doc":"0…`max`. Leave undefined for the indeterminate animation.","details":[],"examples":[]},{"name":"max","optional":true,"type":"number","default":"100","bindable":false,"doc":"","details":[],"examples":[]},{"name":"tone","optional":true,"type":"ProgressTone","default":"'primary'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"ProgressSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible name — \"Uploading\", not \"progress bar\".","details":[],"examples":[]},{"name":"stop","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Draw MD3's stop dot at the end of the track. Determinate only.","details":[],"examples":[]},{"name":"buffer","optional":true,"type":"number","bindable":false,"doc":"How far ahead is ready, on the same 0…`max` scale — a video's buffered range, a stream that downloads faster than it plays. Drawn as a paler run from the fill to this point. Determinate only.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"ProgressClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"PullToRefresh","dir":"pull-to-refresh","entry":"omaris","importPath":"import { PullToRefresh } from 'omaris'","summary":"Pull down to refetch — the gesture every phone app has, on the web.","details":["Wrap the thing that scrolls. A finger that starts at the top and travels down drags the content with it against a rubber band; past `threshold` the indicator arms, and letting go runs `onrefresh` and holds the indicator until the promise settles.","**The indicator is a ring around a morphing MD3 shape.** The ring is the read-out — it closes as the pull reaches the threshold, then becomes a turning segment while the refetch runs, so one element says both \"this far to go\" and \"something is happening\". The outline inside travels through `shapes` as you pull and cycles through them while it refreshes, which is what makes the pull itself the animation rather than a bar that fills. `shapes` picks a different set, and the `indicator` snippet replaces the whole thing; it is handed the live distance, progress and state, so a custom one can be just as physical.","The gesture is only taken from a scroll origin and only when it is clearly downward, so a horizontal swipe, a carousel or a list already scrolled down keeps it. Travel is damped asymptotically toward `max`, and a flick past half the threshold refreshes without reaching it.","With `onrefresh`, `refreshing` is managed for you and held for at least `minimum` ms so a fast refetch doesn't flash. Without it the component is controlled: `bind:refreshing` and clear it yourself.","Reduced motion keeps the gesture and drops the flourish — nothing spins, and the settle is a cut rather than a spring."],"examples":[{"lang":"svelte","code":"<PullToRefresh onrefresh={() => orders.reload()} height=\"26rem\">\n  <List>…</List>\n</PullToRefresh>"}],"classesType":"PullToRefreshClasses","parts":[{"name":"root","doc":"The frame. Not the scroller — it clips the travel while a pull is on, and stops clipping the moment it is over, so a sticky header inside is only ever clipped mid-gesture."},{"name":"indicator","doc":"The indicator's rail: centred, above the content, never hit-tested."},{"name":"disc","doc":"The default indicator's disc — the thing the shape sits in."},{"name":"arc","doc":"The arc around the disc, tracing how much of the pull is done."},{"name":"glyph","doc":"The shape inside the disc."},{"name":"viewport","doc":"What actually scrolls, and what the pull moves."}],"variants":[{"name":"dragging","doc":"No transition while a finger is on it — the pull *is* the clock. A mouse can pull too, and one that is dragging the list must not also be selecting the text in it.","default":"false","values":[{"name":"true","doc":""}]},{"name":"scroller","doc":"","default":"true","values":[{"name":"true","doc":""},{"name":"false","doc":""}]},{"name":"overlay","doc":"The indicator floats over the content instead of pushing it down.","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"System/PullToRefresh","category":"System","own":true,"stories":["Playground","Overlay","Controlled","A different indicator","Overridden"]},"props":[{"name":"onrefresh","optional":true,"type":"() => unknown","bindable":false,"doc":"Run the refetch. Return a promise and the indicator is held until it settles; return nothing and it is held for `minimum`. Leave it out to drive the component yourself with `bind:refreshing`.","details":[],"examples":[]},{"name":"refreshing","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Whether the refresh is running. Bindable, and the whole API without `onrefresh`.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Turn the gesture off — while a dialog is up, or the list is empty.","details":[],"examples":[]},{"name":"threshold","optional":true,"type":"number","default":"72","bindable":false,"doc":"Travel at which a release refreshes, in px.","details":[],"examples":[]},{"name":"max","optional":true,"type":"number","default":"140","bindable":false,"doc":"Furthest the content can be pulled, in px. The rubber band's asymptote.","details":[],"examples":[]},{"name":"minimum","optional":true,"type":"number","default":"450","bindable":false,"doc":"Shortest time the indicator stays up, in ms, so a fast refetch doesn't flash.","details":[],"examples":[]},{"name":"overlay","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Let the indicator float over the content rather than pushing it down.","details":[],"examples":[]},{"name":"scroller","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Whether this component owns the scrolling. The default gives the viewport its own `overflow-y-auto` and `height`; `false` leaves the scrolling to the page (or to an ancestor) and only reads the gesture.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"'24rem'","bindable":false,"doc":"How tall the scrolling viewport is — a number is px, a string is any CSS length. Ignored when `scroller` is `false`.","details":["It lives in a custom property rather than a utility class so a height in `classes.viewport` genuinely replaces it."],"examples":[]},{"name":"shapes","optional":true,"type":"ShapeName[]","default":"['circle', 'cookie-4', 'cookie-9', 'clover-4', 'burst']","bindable":false,"doc":"The outlines the indicator travels through as you pull, and spins through.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","default":"'Refreshing'","bindable":false,"doc":"What a screen reader is told while the refresh runs.","details":[],"examples":[]},{"name":"armedLabel","optional":true,"type":"string","default":"'Release to refresh'","bindable":false,"doc":"What it is told once the pull would refresh on release.","details":[],"examples":[]},{"name":"indicator","optional":true,"type":"Snippet<[PullState]>","bindable":false,"doc":"Replace the indicator entirely. It is handed the live state.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"PullToRefreshClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"children","optional":false,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"QrCode","dir":"qr-code","entry":"omaris","importPath":"import { QrCode } from 'omaris'","summary":"A QR code, drawn as vector, encoded here.","details":["**It is SVG, not a picture of one.** One `<path>` for the data, one for the eyes, one for their pupils — so it is sharp at any size, prints at the printer's resolution rather than the screen's, takes a gradient or a theme colour like anything else on the page, and weighs a few kilobytes at version 40. A canvas QR is a blurry QR the moment anyone zooms, and a `<rect>`-per-module QR is thirty thousand elements.","**The encoder is here too**, so there is no dependency and no network call: numeric, alphanumeric and byte modes, versions 1 to 40, all four error-correction levels, and the smallest of the three modes chosen for whatever you pass. Text is UTF-8.","Styling is the point of the rest: `shape` and `eyes` change how the modules and the corners are drawn, `gradient` paints them, and `logo` puts a mark in the middle — which raises the correction level to `H` on its own, because a logo is damage and the code has to survive it.","`bind:this` gives you `download()`, `toDataURL()` and `toBlob()`, with the theme's colours resolved, so what is saved is what was on screen."],"examples":[{"lang":"svelte","code":"<QrCode value=\"https://omaris.dev\" />\n<QrCode value={qrWifi({ ssid: 'Cafe', password: 'hunter2' })} caption=\"Guest Wi-Fi\" />"}],"classesType":"QrCodeClasses","parts":[{"name":"root","doc":""},{"name":"frame","doc":"The box the code sits in."},{"name":"svg","doc":""},{"name":"logo","doc":"The mark in the middle, when there is one."},{"name":"caption","doc":""},{"name":"error","doc":"Shown in place of the code when the text will not fit one."}],"variants":[{"name":"variant","doc":"","default":"plain","values":[{"name":"plain","doc":"The code and nothing else."},{"name":"card","doc":"On a surface, with a quiet border — a code meant to be shown."},{"name":"padded","doc":"Same, without the frame drawn: padding only, for printing."}]}],"story":{"title":"Data Display/QR Code","category":"Data Display","own":true,"stories":["Playground","Correction levels","Module shapes","Eye shapes","Coloured and gradient","With a logo","Payloads","Download","Too long to encode","Overridden"]},"props":[{"name":"value","optional":false,"type":"string","bindable":false,"doc":"What the code says. A URL, a phone number, a Wi-Fi payload, anything.","details":[],"examples":[]},{"name":"level","optional":true,"type":"QrLevel","bindable":false,"doc":"How much damage the code survives: `L` ~7%, `M` ~15%, `Q` ~25%, `H` ~30%. Defaults to `M`, or `H` when there is a `logo` — more correction means a denser code, so it is not free.","details":[],"examples":[]},{"name":"size","optional":true,"type":"number | string","default":"176","bindable":false,"doc":"Rendered size. A number is px, a string any CSS length.","details":[],"examples":[]},{"name":"margin","optional":true,"type":"number","default":"4","bindable":false,"doc":"The quiet zone, in modules. Four is the standard's minimum and what scanners are built for; less than that and some will not see the code at all.","details":[],"examples":[]},{"name":"shape","optional":true,"type":"QrShape","default":"'square'","bindable":false,"doc":"How each module is drawn.","details":[],"examples":[]},{"name":"radius","optional":true,"type":"number","default":"0.35","bindable":false,"doc":"Corner radius for `shape=\"rounded\"`, in modules — `0` to `0.5`.","details":[],"examples":[]},{"name":"eyes","optional":true,"type":"QrEyes","default":"'square'","bindable":false,"doc":"How the three corner markers are drawn.","details":[],"examples":[]},{"name":"color","optional":true,"type":"string","default":"'var(--color-foreground)'","bindable":false,"doc":"The code's colour. Defaults to the theme's foreground.","details":[],"examples":[]},{"name":"background","optional":true,"type":"string","default":"'var(--color-background)'","bindable":false,"doc":"Behind it. `transparent` leaves whatever is underneath.","details":[],"examples":[]},{"name":"eyeColor","optional":true,"type":"string","bindable":false,"doc":"The corner frames, if they should differ from the modules.","details":[],"examples":[]},{"name":"pupilColor","optional":true,"type":"string","bindable":false,"doc":"The pupils, if they should differ from the frames.","details":[],"examples":[]},{"name":"gradient","optional":true,"type":"QrGradient","bindable":false,"doc":"A gradient over the modules, in place of `color`.","details":[],"examples":[]},{"name":"logo","optional":true,"type":"string","bindable":false,"doc":"A mark in the middle. Any image URL, a data URI included.","details":[],"examples":[]},{"name":"logoSize","optional":true,"type":"number","default":"0.22","bindable":false,"doc":"How much of the code's width the logo covers. Keep it under `0.3`.","details":[],"examples":[]},{"name":"logoMargin","optional":true,"type":"number","default":"1","bindable":false,"doc":"Clear space punched around the logo, in modules.","details":[],"examples":[]},{"name":"logoRadius","optional":true,"type":"number | string","default":"6","bindable":false,"doc":"Rounding on the logo's backing plate — a number is px.","details":[],"examples":[]},{"name":"caption","optional":true,"type":"string","bindable":false,"doc":"Below the code.","details":[],"examples":[]},{"name":"variant","optional":true,"type":"QrCodeVariant","default":"'plain'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"The code's accessible name. Falls back to `caption`, then `value`.","details":[],"examples":[]},{"name":"minVersion","optional":true,"type":"number","bindable":false,"doc":"Force a version, 1–40, when a code has to keep its module count — printed on a template, say. Too small for the data is still refused.","details":[],"examples":[]},{"name":"mask","optional":true,"type":"number","bindable":false,"doc":"Force one of the eight mask patterns. By default the best is chosen.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Replaces the caption line.","details":[],"examples":[]},{"name":"onerror","optional":true,"type":"(error: Error) => void","bindable":false,"doc":"Told when the value cannot be encoded — too long for a version 40 code.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"QrCodeClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"RadarChart","dir":"chart","entry":"omaris/chart","importPath":"import { RadarChart } from 'omaris/chart'","summary":"Radar chart — several measures on one shape, so two things can be compared across all of them at once.","details":["The same `series` shape as the cartesian charts, so a comparison is one prop:","Every spoke shares one scale, which is the only way the shape means anything — spokes with different ranges draw a picture of nothing. Normalise the measures before they get here, or set `max`."],"examples":[{"lang":"svelte","code":"<RadarChart data={scores} x=\"skill\" y=\"you\" />"},{"lang":"svelte","code":"<RadarChart data={scores} x=\"skill\" series={[{ key: 'you' }, { key: 'team' }]} legend />"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Charts","category":"Data Display","own":false,"stories":["Area","Line","Bar","Pie and donut","Scatter","Sparkline","Empty","References and annotations","Brush and zoom","Legend isolate and CSV","Error","Combo","Radar","Radial bar and gauge","Funnel","Treemap","Candlestick"]},"props":[{"name":"data","optional":false,"type":"T[]","bindable":false,"doc":"","details":[],"examples":[]},{"name":"x","optional":true,"type":"Field<T>","bindable":false,"doc":"The field naming each spoke.","details":[],"examples":[]},{"name":"y","optional":true,"type":"Field<T>","bindable":false,"doc":"The value field. Ignored once `series` names its own.","details":[],"examples":[]},{"name":"series","optional":true,"type":"ChartSeries<T>[]","bindable":false,"doc":"Several values per row. Each gets a colour and a legend entry.","details":[],"examples":[]},{"name":"max","optional":true,"type":"number","bindable":false,"doc":"Top of the shared scale. Defaults to the largest value in the data.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"300","bindable":false,"doc":"Plot height. A number is px; a string is any CSS length.","details":[],"examples":[]},{"name":"grid","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Rings and spokes behind the shapes.","details":[],"examples":[]},{"name":"axis","optional":true,"type":"boolean | 'x' | 'y'","default":"'x'","bindable":false,"doc":"`'x'` — the default — names the spokes. `true` also labels the rings, which is worth having when the scale isn't obvious and a collision with whichever spoke points down when it is.","details":[],"examples":[]},{"name":"ticks","optional":true,"type":"number","default":"4","bindable":false,"doc":"How many rings.","details":[],"examples":[]},{"name":"legend","optional":true,"type":"ChartLegend","default":"false","bindable":false,"doc":"`true` toggles a series off on click; `'isolate'` shows it alone.","details":[],"examples":[]},{"name":"tooltip","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"points","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Mark each spoke's value.","details":[],"examples":[]},{"name":"fillOpacity","optional":true,"type":"number","default":"0.16","bindable":false,"doc":"Opacity of the fill inside each shape.","details":[],"examples":[]},{"name":"formatY","optional":true,"type":"(value: never) => string","bindable":false,"doc":"Tick labels on the rings.","details":[],"examples":[]},{"name":"colors","optional":true,"type":"readonly string[]","default":"CHART_COLORS","bindable":false,"doc":"Palette override, cycled across the series.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible description of what the chart shows.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"empty","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]},{"name":"emptyText","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"error","optional":true,"type":"boolean | string | Error","bindable":false,"doc":"Something went wrong. Truthy puts the chart into its error state; a string or an `Error` supplies the message.","details":[],"examples":[]},{"name":"errorText","optional":true,"type":"string","bindable":false,"doc":"The message, when `error` is just `true`.","details":[],"examples":[]},{"name":"errorState","optional":true,"type":"Snippet<[{ message: string }]>","bindable":false,"doc":"Replaces the whole error state.","details":[],"examples":[]},{"name":"onRetry","optional":true,"type":"() => void","bindable":false,"doc":"Offers a \"Try again\" button in the error state.","details":[],"examples":[]},{"name":"csv","optional":true,"type":"boolean | string","default":"false","bindable":false,"doc":"Offer the plotted rows as a CSV download, from a button in the corner. A string names the file.","details":[],"examples":[]},{"name":"csvColumns","optional":true,"type":"(string | { key: string; label?: string; value?: (row: T) => unknown })[]","bindable":false,"doc":"Which fields the download writes, in order. Defaults to every field.","details":[],"examples":[]}]},{"name":"RadialBarChart","dir":"chart","entry":"omaris/chart","importPath":"import { RadialBarChart } from 'omaris/chart'","summary":"Radial bar chart — one ring per row, each filled to its share of the whole.","details":["A bar chart bent into a circle. It reads well for a handful of progress-shaped values — quota attainment, storage used, tickets closed — and badly for more than about six, because the inner rings get shorter for the same value and the comparison stops being honest. Past that, `BarChart` is the right answer.","Each ring is drawn on an unfilled track, so \"how far along\" reads without an axis. `centre` fills the hole, which is where the total goes."],"examples":[{"lang":"svelte","code":"<RadialBarChart data={teams} max={100} />"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Charts","category":"Data Display","own":false,"stories":["Area","Line","Bar","Pie and donut","Scatter","Sparkline","Empty","References and annotations","Brush and zoom","Legend isolate and CSV","Error","Combo","Radar","Radial bar and gauge","Funnel","Treemap","Candlestick"]},"props":[{"name":"data","optional":false,"type":"T[]","bindable":false,"doc":"","details":[],"examples":[]},{"name":"label","optional":true,"type":"Field<T>","default":"'label'","bindable":false,"doc":"Field naming each ring. Defaults to `row.label`.","details":[],"examples":[]},{"name":"value","optional":true,"type":"Field<T>","default":"'value'","bindable":false,"doc":"Field holding each ring's value. Defaults to `row.value`.","details":[],"examples":[]},{"name":"max","optional":true,"type":"number","bindable":false,"doc":"The value a complete ring means. Defaults to the largest one.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"260","bindable":false,"doc":"Plot height. A number is px; a string is any CSS length.","details":[],"examples":[]},{"name":"thickness","optional":true,"type":"number","default":"14","bindable":false,"doc":"Thickness of each ring, in px.","details":[],"examples":[]},{"name":"gap","optional":true,"type":"number","default":"6","bindable":false,"doc":"Gap between rings, in px.","details":[],"examples":[]},{"name":"sweep","optional":true,"type":"number","default":"360","bindable":false,"doc":"Degrees each ring sweeps when full. 360 is a closed circle.","details":[],"examples":[]},{"name":"legend","optional":true,"type":"ChartLegend","default":"false","bindable":false,"doc":"`true` toggles a ring off on click; `'isolate'` shows it alone.","details":[],"examples":[]},{"name":"tooltip","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"colors","optional":true,"type":"readonly string[]","default":"CHART_COLORS","bindable":false,"doc":"Palette override, cycled across the rings.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"Accessible description of what the chart shows.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"centre","optional":true,"type":"Snippet","bindable":false,"doc":"Content for the middle — a total, usually.","details":[],"examples":[]},{"name":"empty","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]},{"name":"emptyText","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"error","optional":true,"type":"boolean | string | Error","bindable":false,"doc":"Something went wrong. Truthy puts the chart into its error state; a string or an `Error` supplies the message.","details":[],"examples":[]},{"name":"errorText","optional":true,"type":"string","bindable":false,"doc":"The message, when `error` is just `true`.","details":[],"examples":[]},{"name":"errorState","optional":true,"type":"Snippet<[{ message: string }]>","bindable":false,"doc":"Replaces the whole error state.","details":[],"examples":[]},{"name":"onRetry","optional":true,"type":"() => void","bindable":false,"doc":"Offers a \"Try again\" button in the error state.","details":[],"examples":[]},{"name":"csv","optional":true,"type":"boolean | string","default":"false","bindable":false,"doc":"Offer the plotted rows as a CSV download, from a button in the corner. A string names the file.","details":[],"examples":[]},{"name":"csvColumns","optional":true,"type":"(string | { key: string; label?: string; value?: (row: T) => unknown })[]","bindable":false,"doc":"Which fields the download writes, in order. Defaults to every field.","details":[],"examples":[]}]},{"name":"Radio","dir":"radio","entry":"omaris","importPath":"import { Radio } from 'omaris'","summary":"MD3 radio button.","details":["Inside a `<RadioGroup>` it takes its name, value binding, tone and size from the group. On its own it works as a plain controlled radio — bind `group` the way you would with Svelte's own `bind:group`.","The dot scales in from nothing rather than appearing, which is the detail that makes a radio feel like MD3 rather than a browser default."],"examples":[],"classesType":"RadioClasses","parts":[{"name":"root","doc":""},{"name":"control","doc":""},{"name":"circle","doc":"The ring."},{"name":"dot","doc":"The filled center, scaled from 0 when unselected."},{"name":"input","doc":""},{"name":"label","doc":""},{"name":"description","doc":""}],"variants":[{"name":"tone","doc":"","default":"primary","values":[{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""}]},{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]},{"name":"checked","doc":"","values":[{"name":"true","doc":""},{"name":"false","doc":""}]},{"name":"invalid","doc":"","values":[{"name":"true","doc":""}]},{"name":"disabled","doc":"","values":[{"name":"true","doc":""}]}],"story":{"title":"Selection/Radio","category":"Selection","own":true,"stories":["Playground","States","Sizes","With descriptions","Horizontal","Invalid"]},"props":[{"name":"value","optional":false,"type":"string","bindable":false,"doc":"This radio's value. Required — it's what the group selects.","details":[],"examples":[]},{"name":"group","optional":true,"type":"string | undefined","default":"undefined","bindable":true,"doc":"The selected value, when the radio is used outside a group. Bindable.","details":[],"examples":[]},{"name":"tone","optional":true,"type":"RadioTone","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"RadioSizeToken","bindable":false,"doc":"","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"description","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"invalid","optional":true,"type":"boolean","bindable":false,"doc":"","details":[],"examples":[]},{"name":"haptics","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"A haptic tap when it's picked. Follows the shared `haptics` store; `false` opts this radio out.","details":[],"examples":[]},{"name":"sound","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"A sound cue when it's picked. Follows the shared `sound` store; `false` opts this radio out.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"RadioClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]},{"name":"ref","optional":true,"type":"HTMLInputElement | null","default":"null","bindable":true,"doc":"","details":[],"examples":[]}]},{"name":"RadioGroup","dir":"radio","entry":"omaris","importPath":"import { RadioGroup } from 'omaris'","summary":"The fieldset around a run of radios: legend, the options, a helper line.","details":[],"examples":[],"classesType":"RadioGroupClasses","parts":[{"name":"root","doc":""},{"name":"label","doc":"The group heading, rendered as the fieldset's legend."},{"name":"options","doc":"Where the radios sit."},{"name":"support","doc":""}],"variants":[{"name":"orientation","doc":"","default":"vertical","values":[{"name":"vertical","doc":""},{"name":"horizontal","doc":""}]},{"name":"invalid","doc":"","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Selection/Radio","category":"Selection","own":false,"stories":["Playground","States","Sizes","With descriptions","Horizontal","Invalid"]},"props":[{"name":"value","optional":true,"type":"string","default":"undefined","bindable":true,"doc":"Selected value. Bindable.","details":[],"examples":[]},{"name":"name","optional":true,"type":"string","bindable":false,"doc":"Shared `name` for the radios. Generated when omitted.","details":[],"examples":[]},{"name":"orientation","optional":true,"type":"'vertical' | 'horizontal'","default":"'vertical'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"tone","optional":true,"type":"Tone","default":"'primary'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"RadioSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","bindable":false,"doc":"Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"required","optional":true,"type":"boolean","bindable":false,"doc":"Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"invalid","optional":true,"type":"boolean","bindable":false,"doc":"Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Group heading, rendered as the fieldset's legend.","details":[],"examples":[]},{"name":"supportingText","optional":true,"type":"string","bindable":false,"doc":"Helper line under the group. Turns red when `invalid`.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"RadioGroupClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"RangeSlider","dir":"slider","entry":"omaris","importPath":"import { RangeSlider } from 'omaris'","summary":"Two handles, one track — a price range, a time window.","details":["The handles can't cross; `minDistance` keeps them apart."],"examples":[{"lang":"svelte","code":"<RangeSlider bind:value={[20, 80]} label=\"Price\" format={(v) => `$${v}`} showValue />"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Selection/Slider","category":"Selection","own":false,"stories":["Playground","Wave","Media player","Range","Vertical","Sizes","Stepped","Tones","Disabled","Elastic","In a form"]},"props":[{"name":"value","optional":true,"type":"[number, number]","default":"[0, 100]","bindable":true,"doc":"`[low, high]`. Bindable.","details":[],"examples":[]},{"name":"oninput","optional":true,"type":"(value: [number, number]) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(value: [number, number]) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"min","optional":true,"type":"number","bindable":false,"doc":"","details":[],"examples":[]},{"name":"max","optional":true,"type":"number","bindable":false,"doc":"","details":[],"examples":[]},{"name":"step","optional":true,"type":"number","bindable":false,"doc":"","details":[],"examples":[]},{"name":"minDistance","optional":true,"type":"number","bindable":false,"doc":"Smallest allowed gap between the two handles of a range.","details":[],"examples":[]},{"name":"tone","optional":true,"type":"SliderTone","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"SliderSize","bindable":false,"doc":"","details":[],"examples":[]},{"name":"orientation","optional":true,"type":"SliderOrientation","bindable":false,"doc":"","details":[],"examples":[]},{"name":"wave","optional":true,"type":"boolean | 'always'","bindable":false,"doc":"Ripple a wave through the filled part while it's being dragged. `'always'` keeps it moving — for a media player that's playing.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Label above the track.","details":[],"examples":[]},{"name":"supportingText","optional":true,"type":"string","bindable":false,"doc":"Helper line below the track.","details":[],"examples":[]},{"name":"showValue","optional":true,"type":"boolean","bindable":false,"doc":"Show the current value beside the label.","details":[],"examples":[]},{"name":"bubble","optional":true,"type":"boolean | 'always'","bindable":false,"doc":"Float the value over the handle while dragging; `'always'` keeps it up.","details":[],"examples":[]},{"name":"ticks","optional":true,"type":"boolean","bindable":false,"doc":"Draw a stop dot at every step. Ignored above 30 steps.","details":[],"examples":[]},{"name":"format","optional":true,"type":"(value: number) => string","bindable":false,"doc":"Turns a number into display text — \"40%\", \"$12\".","details":[],"examples":[]},{"name":"name","optional":true,"type":"string","bindable":false,"doc":"Submit the value(s) with the surrounding form.","details":[],"examples":[]},{"name":"elastic","optional":true,"type":"boolean","bindable":false,"doc":"Let the track stretch when dragged past either end, and spring back on release.","details":[],"examples":[]},{"name":"haptics","optional":true,"type":"boolean","bindable":false,"doc":"A haptic tick on every step, and a firmer bump at either end. Follows the shared `haptics` store; `false` opts this slider out.","details":[],"examples":[]},{"name":"sound","optional":true,"type":"boolean","bindable":false,"doc":"A sound cue as the handle passes each step, and a duller one at the ends. Follows the shared `sound` store; `false` opts this slider out.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","bindable":false,"doc":"Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"ariaLabel","optional":true,"type":"string | string[]","bindable":false,"doc":"Accessible name for each handle, when there's no visible label.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"SliderClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"ref","optional":true,"type":"HTMLDivElement | null","default":"null","bindable":true,"doc":"","details":[],"examples":[]}]},{"name":"Rating","dir":"rating","entry":"omaris","importPath":"import { Rating } from 'omaris'","summary":"Rating — a row of stars, or of any icon you give it.","details":["It is one control, not five buttons: a `slider` from 0 to `max`, with a spoken value (\"3.5 of 5\") and one Tab stop. The arrows step it — mirrored under RTL — Home and End go to the ends, and a digit key jumps straight to that many.","Under the pointer it previews before it commits: hover and the stars fill up to where you are, drag a finger along and they follow it, let go and the chosen star pops. `allowHalf` splits every star down the middle, the starting half giving the half-point.","`readonly` turns it into a display — an image with the value for its name — and it fills fractionally, so an average of 4.3 shows a third of a star."],"examples":[{"lang":"svelte","code":"<Rating bind:value label=\"Your rating\" />\n<Rating value={4.3} readonly size=\"sm\" />"}],"classesType":"RatingClasses","parts":[{"name":"root","doc":""},{"name":"item","doc":"One star's box: the empty icon, with the filled one laid over it."},{"name":"icon","doc":"The icon at rest, unfilled."},{"name":"fill","doc":"The filled icon, clipped from the start to the star's share of the value."}],"variants":[{"name":"tone","doc":"","default":"warning","values":[{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""}]},{"name":"size","doc":"20 / 24 / 32px icons; under a finger every star grows to a 44px target.","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]},{"name":"interactive","doc":"","values":[{"name":"true","doc":""}]},{"name":"disabled","doc":"","values":[{"name":"true","doc":""}]}],"story":{"title":"Selection/Rating","category":"Selection","own":true,"stories":["Playground","Half stars","Read-only","Sizes and tones","Custom icon","Disabled and in a Field","Overridden"]},"props":[{"name":"value","optional":true,"type":"number","default":"0","bindable":true,"doc":"The rating, from 0 to `max`. 0 is \"not rated\". Bindable.","details":[],"examples":[]},{"name":"max","optional":true,"type":"number","default":"5","bindable":false,"doc":"How many stars.","details":[],"examples":[]},{"name":"allowHalf","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Half-star steps — the starting half of a star gives the half-point.","details":[],"examples":[]},{"name":"readonly","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"A display, not a control: no focus, no pointer, fractional fill.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","bindable":false,"doc":"Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"clearable","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Pressing the current value again clears it back to 0.","details":[],"examples":[]},{"name":"size","optional":true,"type":"RatingSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"tone","optional":true,"type":"RatingTone","default":"'warning'","bindable":false,"doc":"Colour of a filled star. Amber by default — the colour a rating is read in.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible name. \"Rating\" when omitted — or, inside a `Field`, the field's own label.","details":[],"examples":[]},{"name":"valueText","optional":true,"type":"(value: number, max: number) => string","default":"(v: number, m: number) => `${Math.round(v * 10) / 10} of ${m}`","bindable":false,"doc":"The spoken value. Defaults to \"3.5 of 5\".","details":[],"examples":[]},{"name":"name","optional":true,"type":"string","bindable":false,"doc":"Posts the value in a form under this name.","details":[],"examples":[]},{"name":"icon","optional":true,"type":"Snippet","bindable":false,"doc":"The icon, drawn twice — once unfilled, once filled and clipped. Paint it with `currentColor` and it takes both colours.","details":[],"examples":[]},{"name":"haptics","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"A buzz when a value is chosen, once `haptics.enabled` is on.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(value: number) => void","bindable":false,"doc":"Fires when a value is committed — a press, a lifted finger, a key.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"RatingClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"ref","optional":true,"type":"HTMLDivElement | null","default":"null","bindable":true,"doc":"","details":[],"examples":[]}]},{"name":"Reorder","dir":"list","entry":"omaris","importPath":"import { Reorder } from 'omaris'","summary":"A list whose rows you can drag into a different order.","details":["It takes the container props `List` takes, so an existing list becomes reorderable by swapping the tag and binding the array:","Four things decide how this feels.","**Nothing moves in the DOM while you drag.** The rows are measured once, on lift, and everything after that is a `translate` on rows that never change place or identity — the lifted one follows the pointer, the ones it passes slide by exactly the space it left behind. No re-render, no re-keying, no list that reshuffles under a finger. `items` is rewritten once, on release, so a cancelled drag costs nothing and the array never passes through an order nobody asked for.","**The gap is exact.** Taking a row out closes precisely its own height plus the list's gap, so rows of different heights land where they look like they will — the usual \"shift everything by one row height\" only looks right when every row is the same size.","**The drop has nothing to see.** On release the row glides into its slot and sheds its lift on the way; only once it has arrived is `items` rewritten, with every transition held off for that one frame, so rows that swap elements under the new order are already standing where the old order left them. Dividers are drawn by position, not by DOM order, so the hairline is where the row *is*, and every row is the same height whether it is last or not.","**It works from the keyboard.** Every row is a tab stop: `Space` picks it up, the arrows move it, `Space` drops it, `Escape` puts it back, and each step is announced. A list that can only be reordered with a mouse is not reorderable.","By default a drag starts anywhere on the row that is not a control. `handle` narrows that to `<ReorderHandle />`, which is what a row full of text or a row that is itself a link wants."],"examples":[{"lang":"svelte","code":"<Reorder bind:items variant=\"outlined\" dividers>\n  {#snippet children(item)}\n    <ListItem role=\"presentation\" headline={item.name}>\n      {#snippet leading()}<ReorderHandle />{/snippet}\n    </ListItem>\n  {/snippet}\n</Reorder>"}],"classesType":"ReorderClasses","parts":[{"name":"root","doc":"The list. It takes `List`'s own look; what it adds is the behaviour a drag needs — no text selection, no page panning, and `isolate` so a lifted row's z-index is scoped to this list."},{"name":"row","doc":"One row's wrapper — the thing that actually moves. `translate` is transitioned so a row that has to make way is *seen* making way; `data-live` takes that transition off the row under the pointer, which must not lag behind the finger holding it. `data-dropping` is the glide into its slot after release: still above its neighbours, but already shedding the lift. `data-snap` is the one frame in which the new order is written and nothing may animate."},{"name":"handle","doc":"The grip. A target in its own right, not just an icon."},{"name":"status","doc":"What a keyboard drag is doing, for anyone who cannot see it."}],"variants":[{"name":"dividers","doc":"The hairline between rows. `List` draws it on every row but the last *in the DOM*, which is wrong the moment a row is carried somewhere else and makes the last row a pixel shorter than the rest — so here every row has it, and the one that is last on screen (or in hand) turns it transparent.","values":[{"name":"true","doc":""}]}],"story":{"title":"Containment/Reorder","category":"Containment","own":true,"stories":["Playground","Handle only","Spaced cards","Rows of different heights","With controls in the row","Disabled","Overridden"]},"props":[{"name":"items","optional":false,"type":"T[]","bindable":true,"doc":"The rows, in order. Bindable — a drop rewrites it.","details":[],"examples":[]},{"name":"children","optional":false,"type":"Snippet<[T, ReorderContext]>","bindable":false,"doc":"How to draw one row.","details":[],"examples":[]},{"name":"key","optional":true,"type":"(item: T, index: number) => string | number","bindable":false,"doc":"Identity, which is what keeps a row the same element across a reorder. Defaults to the item's `id`, then its index.","details":[],"examples":[]},{"name":"label","optional":true,"type":"(item: T) => string","bindable":false,"doc":"Names a row for assistive tech during a keyboard drag.","details":[],"examples":[]},{"name":"handle","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Only `<ReorderHandle />` may start a drag. Leave it off and the whole row is the grip — anything but a control inside it.","details":[],"examples":[]},{"name":"listLabel","optional":true,"type":"string","bindable":false,"doc":"Accessible name for the list.","details":[],"examples":[]},{"name":"variant","optional":true,"type":"ListVariant","default":"'plain'","bindable":false,"doc":"Container look — the same three `List` has.","details":[],"examples":[]},{"name":"dividers","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"spaced","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"padding","optional":true,"type":"'none' | 'sm' | 'md'","default":"'none'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onreorder","optional":true,"type":"(move: ReorderMove<T>) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"ReorderClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"ReorderHandle","dir":"list","entry":"omaris","importPath":"import { ReorderHandle } from 'omaris'","summary":"The grip on a reorderable row.","details":["Drop it in a row's `leading` or `trailing` slot. It marks where a pointer drag may begin when `<Reorder handle />` is on, and it tells anyone looking that the row moves at all — a list that can be reordered and doesn't say so is a list nobody reorders.","It is deliberately not focusable. The row itself is the tab stop, and carries the whole keyboard gesture, so a handle in the tab order would only be a second stop that does nothing."],"examples":[],"classesType":null,"parts":[],"variants":[],"story":{"title":"Containment/List","category":"Containment","own":false,"stories":["Playground","Line counts","With slots","With controls","Variants","Spaced","Compact"]},"props":[{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Replaces the six-dot glyph.","details":[],"examples":[]}]},{"name":"ResizableHandle","dir":"resizable","entry":"omaris","importPath":"import { ResizableHandle } from 'omaris'","summary":"The divider between two panels — and the thing you drag.","details":["The hit area is deliberately wider than the line it draws: a 1px divider is impossible to grab, so the target is `hitArea` px of transparent padding with the hairline centred inside it — and at least 24px of it under a coarse pointer, because 8px is a mouse's margin of error, not a finger's. That line thickens and takes the primary colour while it is hovered, focused or dragged, under an MD3 state layer, so the affordance shows up before you press rather than after — and it pulses for a moment each time a drag lands on a snap point, so the magnet is felt as well as seen.","It is a real `separator` for assistive tech: arrows move it, Home and End throw it to either extreme, and Enter — or a double-click — collapses or restores a collapsible neighbour, or puts both neighbours back at their defaults when neither collapses."],"examples":[],"classesType":"ResizableHandleClasses","parts":[{"name":"root","doc":""},{"name":"grip","doc":"A raised pill centred on the divider; primary while the handle is live."}],"variants":[{"name":"direction","doc":"","default":"horizontal","values":[{"name":"horizontal","doc":""},{"name":"vertical","doc":""}]},{"name":"disabled","doc":"","values":[{"name":"true","doc":""}]}],"story":{"title":"Containment/Resizable","category":"Containment","own":false,"stories":["Playground","Snapping","Pixel limits","Collapsible sidebar","Nested","Vertical","Bound sizes","Three panes","Overridden","RTL"]},"props":[{"name":"withHandle","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Draw the grip, so the divider is obviously draggable.","details":[],"examples":[]},{"name":"keyboardStep","optional":true,"type":"number","bindable":false,"doc":"Percentage points one arrow press moves it. Falls back to the group's `step`.","details":[],"examples":[]},{"name":"hitArea","optional":true,"type":"number","default":"8","bindable":false,"doc":"Width of the pointer target in px. The line it draws stays 1px, and a coarse pointer gets at least 24px however small this is.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","default":"'Resize'","bindable":false,"doc":"Accessible name — \"Resize sidebar\".","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"ResizableHandleClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"ResizablePanel","dir":"resizable","entry":"omaris","importPath":"import { ResizablePanel } from 'omaris'","summary":"One pane of a `ResizablePanelGroup`.","details":["It grows in proportion to its share of the layout, so no width or height is ever written onto it — which is what lets a drag stay at 60fps and a collapsed panel disappear cleanly at zero.","Its limits take a percentage or a pixel string: `min=\"240px\"` is a floor in pixels whatever the group's size, `snapPoints={[25, 50, 75]}` are the shares a drag magnetises to, and `bind:collapsed` opens and shuts a collapsible panel from a toolbar button."],"examples":[],"classesType":null,"parts":[],"variants":[{"name":"animated","doc":"Collapsing is animated; a drag is not — that has to track the pointer.","values":[{"name":"true","doc":""}]}],"story":{"title":"Containment/Resizable","category":"Containment","own":false,"stories":["Playground","Snapping","Pixel limits","Collapsible sidebar","Nested","Vertical","Bound sizes","Three panes","Overridden","RTL"]},"props":[{"name":"defaultSize","optional":true,"type":"ResizableSize","bindable":false,"doc":"Share of the group to open at — a percentage, or pixels as `'320px'`.","details":[],"examples":[]},{"name":"min","optional":true,"type":"ResizableSize","default":"10","bindable":false,"doc":"Smallest share it may take — a percentage, or pixels as `'240px'`.","details":[],"examples":[]},{"name":"max","optional":true,"type":"ResizableSize","default":"100","bindable":false,"doc":"Largest share it may take — a percentage, or pixels as `'600px'`.","details":[],"examples":[]},{"name":"collapsible","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Let it be squashed shut past `min`, snapping to `collapsedSize`.","details":[],"examples":[]},{"name":"collapsedSize","optional":true,"type":"number","default":"0","bindable":false,"doc":"Size a collapsed panel rests at, as a percentage.","details":[],"examples":[]},{"name":"collapsed","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Whether it is shut. Bindable — set it to collapse or expand from outside.","details":[],"examples":[]},{"name":"snapPoints","optional":true,"type":"number[]","bindable":false,"doc":"Percentages a drag pulls onto as the handle comes near.","details":[],"examples":[]},{"name":"snapThreshold","optional":true,"type":"number","default":"3","bindable":false,"doc":"How close, in percentage points, before a snap point pulls.","details":[],"examples":[]},{"name":"onResize","optional":true,"type":"(size: number) => void","bindable":false,"doc":"Fires with the new size whenever this panel is resized.","details":[],"examples":[]},{"name":"onCollapse","optional":true,"type":"(collapsed: boolean) => void","bindable":false,"doc":"Fires when it collapses or opens back up.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"ResizablePanelGroup","dir":"resizable","entry":"omaris","importPath":"import { ResizablePanelGroup } from 'omaris'","summary":"Resizable panels — the dashboard split view.","details":["The group owns the layout, in percentages; the panels and handles inside it register themselves and read their share back out, so nothing has to be wired up by hand:","Space taken from one side is given to the other nearest-first, so a drag past a neighbour's minimum keeps going into the one after it instead of stopping dead. `collapsible` panels snap shut — and back open — as the handle crosses the midpoint between their collapsed and minimum sizes, and a panel with `snapPoints` pulls the handle onto them as it comes near, which is what makes a sidebar feel magnetic rather than fiddly.","Limits can be pixels as well as percentages: `min=\"240px\"` is resolved against the group's own extent and re-resolved whenever that changes, so a sidebar keeps its floor when the window shrinks.","Panels and handles are paired by where they are in the DOM, not by the order they mounted in, so a panel behind an `{#if}` can come and go and every handle still knows which two panels it splits. Sizes are plain numbers, so `autoSaveId` can put them in `localStorage` and hand them back on the next visit."],"examples":[{"lang":"svelte","code":"<ResizablePanelGroup autoSaveId=\"inbox\" bind:this={group}>\n  <ResizablePanel defaultSize={28} min=\"220px\" collapsible bind:collapsed>…</ResizablePanel>\n  <ResizableHandle withHandle />\n  <ResizablePanel snapPoints={[50]}>…</ResizablePanel>\n</ResizablePanelGroup>"}],"classesType":null,"parts":[],"variants":[{"name":"direction","doc":"","default":"horizontal","values":[{"name":"horizontal","doc":""},{"name":"vertical","doc":""}]},{"name":"dragging","doc":"Nothing selects while a handle is being dragged.","values":[{"name":"true","doc":""}]}],"story":{"title":"Containment/Resizable","category":"Containment","own":false,"stories":["Playground","Snapping","Pixel limits","Collapsible sidebar","Nested","Vertical","Bound sizes","Three panes","Overridden","RTL"]},"props":[{"name":"direction","optional":true,"type":"ResizableDirection","default":"'horizontal'","bindable":false,"doc":"Axis the panels are laid out along.","details":[],"examples":[]},{"name":"sizes","optional":true,"type":"number[]","default":"[]","bindable":true,"doc":"Panel sizes as percentages, in order. Bindable.","details":[],"examples":[]},{"name":"autoSaveId","optional":true,"type":"string","bindable":false,"doc":"Persist the layout under this key in `localStorage`.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Freeze the layout: no handle can be dragged, keyed or double-clicked.","details":[],"examples":[]},{"name":"step","optional":true,"type":"number","default":"5","bindable":false,"doc":"Percentage points one arrow press moves a handle. A handle's own `keyboardStep` wins.","details":[],"examples":[]},{"name":"onLayout","optional":true,"type":"(sizes: number[]) => void","bindable":false,"doc":"Fires whenever the layout settles on new sizes.","details":[],"examples":[]},{"name":"onDragStart","optional":true,"type":"() => void","bindable":false,"doc":"A handle has been grabbed.","details":[],"examples":[]},{"name":"onDragEnd","optional":true,"type":"(sizes: number[]) => void","bindable":false,"doc":"The handle has been let go, with the sizes it left behind.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"RichTextEditor","dir":"rich-text-editor","entry":"omaris","importPath":"import { RichTextEditor } from 'omaris'","summary":"A rich text editor that is a `contenteditable` and a toolbar, and nothing else.","details":["There is no document model here, and that is the design. A model-backed editor (ProseMirror, Lexical, TipTap) is the right answer for collaborative editing, custom node types or a schema you must enforce — and it is 100–300 kB, which is more than this entire library. For the job most apps actually have — a description, a note, a comment, with bold and a list in it — the browser already ships an editor, and this puts a proper toolbar and a themed surface on it.","The parts that are usually got wrong are handled:","- **Paste is cleaned.** Pasted HTML goes through an allowlist, so a paragraph from a word processor arrives as a paragraph and not as forty spans carrying somebody else's fonts and colours. - **`value` is sanitised the same way** before it is put on screen, so round-tripping content through a database cannot smuggle a script in. - **The caret survives.** The DOM is only rewritten when `value` really differs from what is in the box, so typing never resets the cursor. - **The output is styled by tokens.** Headings, lists and quotes are themed with the same scale as the rest of the library, in both themes."],"examples":[{"lang":"svelte","code":"<RichTextEditor bind:value placeholder=\"Describe the issue…\" />"}],"classesType":"RichTextEditorClasses","parts":[{"name":"root","doc":""},{"name":"toolbar","doc":"The button strip."},{"name":"separator","doc":"A hairline between groups of buttons."},{"name":"tool","doc":"One toolbar button."},{"name":"select","doc":"The block-style select."},{"name":"linkBar","doc":"The row that slides in when a link is being added."},{"name":"linkInput","doc":""},{"name":"content","doc":"The editable surface. The rendered HTML is styled here rather than in a stylesheet, so a consumer can replace any of it through `classes.content`."},{"name":"placeholder","doc":"Sits over an empty document."},{"name":"status","doc":"Word and character counts."}],"variants":[{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""}]},{"name":"readOnly","doc":"","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Inputs/Rich Text Editor","category":"Inputs","own":true,"stories":["Playground","Editing","A comment box","Sanitised input","Read only","Restyled"]},"props":[{"name":"value","optional":true,"type":"string","default":"''","bindable":true,"doc":"The document, as HTML. Bindable.","details":[],"examples":[]},{"name":"size","optional":true,"type":"RichTextEditorSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"tools","optional":true,"type":"RichTextTool[]","default":"DEFAULT_TOOLS","bindable":false,"doc":"Which buttons, and in what order. `'separator'` draws a divider.","details":[],"examples":[]},{"name":"placeholder","optional":true,"type":"string","default":"'Write something…'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"readOnly","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"status","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Word and character counts along the bottom.","details":[],"examples":[]},{"name":"sanitize","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Run pasted and incoming HTML through the tag allowlist. Leave it on unless the content is already trusted *and* already clean.","details":[],"examples":[]},{"name":"allowedTags","optional":true,"type":"string[]","default":"[]","bindable":false,"doc":"Tags kept by the sanitiser, on top of the defaults.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"'9rem'","bindable":false,"doc":"Minimum height of the editing area. A number is px, a string any CSS length — a property rather than a class, so `classes.content` can replace it.","details":[],"examples":[]},{"name":"toolbar","optional":true,"type":"Snippet","bindable":false,"doc":"Extra buttons, rendered at the end of the toolbar.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(value: string) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"RichTextEditorClasses","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"SafeArea","dir":"safe-area","entry":"omaris","importPath":"import { SafeArea } from 'omaris'","summary":"The padding that keeps an interface out from under the hardware.","details":["A phone does not hand a web view a rectangle. It hands it a screen with a notch or a camera hole across the top, a home indicator along the bottom, rounded corners at every one of them, and — in landscape — a bar down whichever side is currently the bottom. Anything pinned to an edge is under one of those until something pads it away, which is the single most common way a web app that looked fine in a browser looks broken once it is wrapped in Capacitor.","Wrap the app once and the whole thing is inside the usable area:","More often you want one edge, because a header or a bottom bar is supposed to reach the screen edge — it is only its *contents* that must not:","`min` is the part people forget. An inset is `0` on a phone with no home indicator, so padding that is only the inset collapses to nothing on half the devices; `min` is the padding you wanted anyway, and the inset takes over when it is larger.","The insets only report once the document has asked for the whole screen (`viewport-fit=cover` in the viewport meta — `omaris native` writes it). Without it every edge is `0` and this component is `min` and nothing else.","It is plain CSS, so it is right on the first paint and costs no JavaScript. The `safeArea` rune is the same numbers when you need them as numbers, and `pt-safe-top` / `pb-safe-bottom` / `ps-safe-start` / `pe-safe-end` are the same padding when a wrapper element is one element too many."],"examples":[{"lang":"svelte","code":"<SafeArea class=\"min-h-dvh\">\n  {@render children()}\n</SafeArea>"},{"lang":"svelte","code":"<footer class=\"bg-surface-container\">\n  <SafeArea edges={['bottom']} min={12}>…</SafeArea>\n</footer>"}],"classesType":null,"parts":[],"variants":[{"name":"top","doc":"","default":"true","values":[{"name":"true","doc":""},{"name":"false","doc":""}]},{"name":"bottom","doc":"","default":"true","values":[{"name":"true","doc":""},{"name":"false","doc":""}]},{"name":"start","doc":"","default":"true","values":[{"name":"true","doc":""},{"name":"false","doc":""}]},{"name":"end","doc":"","default":"true","values":[{"name":"true","doc":""},{"name":"false","doc":""}]},{"name":"keyboard","doc":"Grow the bottom inset by however much the keyboard is covering.","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]},{"name":"mode","doc":"Pad with margin instead. For something that has a background of its own and should be *moved* off the edge rather than padded away from it.","default":"padding","values":[{"name":"padding","doc":""},{"name":"margin","doc":""}]}],"story":{"title":"Layout/Safe Area","category":"Layout","own":true,"stories":["Playground","With and without","Edges","Landscape","Minimum","Margin","Measured","Overridden"]},"props":[{"name":"edges","optional":true,"type":"SafeAreaEdge[]","default":"[...SAFE_AREA_EDGES]","bindable":false,"doc":"Which edges to hold clear. Defaults to all four — name the ones you mean as soon as a parent is already handling another.","details":[],"examples":[]},{"name":"min","optional":true,"type":"number | string","default":"0","bindable":false,"doc":"The padding you wanted anyway, as a floor under every inset. A number is px, a string any CSS length. Without it an edge with no hardware in the way gets no padding at all.","details":[],"examples":[]},{"name":"keyboard","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Add the on-screen keyboard's height to the bottom edge.","details":[],"examples":[]},{"name":"mode","optional":true,"type":"SafeAreaMode","default":"'padding'","bindable":false,"doc":"Move it off the edge with margin rather than padding into it.","details":[],"examples":[]},{"name":"as","optional":true,"type":"keyof HTMLElementTagNameMap","default":"'div'","bindable":false,"doc":"The element to render. `div` unless the region has a better name.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"ref","optional":true,"type":"HTMLElement | null","default":"null","bindable":true,"doc":"","details":[],"examples":[]}]},{"name":"ScatterChart","dir":"chart","entry":"omaris/chart","importPath":"import { ScatterChart } from 'omaris/chart'","summary":"Scatter chart.","details":["Give it `size` and the points scale with a third value, which is the bubble chart without a second component."],"examples":[{"lang":"svelte","code":"<ScatterChart data={rows} x=\"spend\" y=\"revenue\" />"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Charts","category":"Data Display","own":false,"stories":["Area","Line","Bar","Pie and donut","Scatter","Sparkline","Empty","References and annotations","Brush and zoom","Legend isolate and CSV","Error","Combo","Radar","Radial bar and gauge","Funnel","Treemap","Candlestick"]},"props":[{"name":"radius","optional":true,"type":"number","default":"4","bindable":false,"doc":"Radius of each point, in px.","details":[],"examples":[]},{"name":"size","optional":true,"type":"BaseChartProps<T>['x']","bindable":false,"doc":"Field driving the point size, for a bubble chart.","details":[],"examples":[]},{"name":"sizeRange","optional":true,"type":"[number, number]","default":"[3, 18]","bindable":false,"doc":"Smallest and largest radius when `size` is set.","details":[],"examples":[]},{"name":"data","optional":false,"type":"T[]","bindable":false,"doc":"","details":[],"examples":[]},{"name":"x","optional":true,"type":"Field<T>","bindable":false,"doc":"The category or time field.","details":[],"examples":[]},{"name":"y","optional":true,"type":"Field<T>","bindable":false,"doc":"The value field. Ignored once `series` names its own.","details":[],"examples":[]},{"name":"series","optional":true,"type":"ChartSeries<T>[]","bindable":false,"doc":"Several values per row. Each gets a colour and a legend entry.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"260","bindable":false,"doc":"Plot height. A number is px; a string is any CSS length.","details":[],"examples":[]},{"name":"axis","optional":true,"type":"boolean | 'x' | 'y'","default":"true","bindable":false,"doc":"`true` for both, or just the one you want.","details":[],"examples":[]},{"name":"grid","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"legend","optional":true,"type":"ChartLegend","default":"false","bindable":false,"doc":"`true` shows the legend and lets a click toggle a series off. `'isolate'` makes a click show that series alone, and a second one bring the rest back — which is the move you actually want on a chart with six lines on it.","details":[],"examples":[]},{"name":"tooltip","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"formatX","optional":true,"type":"(value: never) => string","bindable":false,"doc":"Tick labels along the x axis.","details":[],"examples":[]},{"name":"formatY","optional":true,"type":"(value: never) => string","bindable":false,"doc":"Tick labels along the y axis, and the tooltip's values.","details":[],"examples":[]},{"name":"colors","optional":true,"type":"readonly string[]","default":"CHART_COLORS","bindable":false,"doc":"Palette override, cycled across the series.","details":[],"examples":[]},{"name":"padding","optional":true,"type":"number | { top?: number; right?: number; bottom?: number; left?: number }","bindable":false,"doc":"Space around the plot, in px — room for long axis labels.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible description of what the chart shows.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"empty","optional":true,"type":"Snippet","bindable":false,"doc":"Shown in place of the plot when `data` is empty.","details":[],"examples":[]},{"name":"emptyText","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"error","optional":true,"type":"boolean | string | Error","bindable":false,"doc":"Something went wrong. Truthy puts the chart into its error state; a string or an `Error` supplies the message.","details":[],"examples":[]},{"name":"errorText","optional":true,"type":"string","bindable":false,"doc":"The message, when `error` is just `true`.","details":[],"examples":[]},{"name":"errorState","optional":true,"type":"Snippet<[{ message: string }]>","bindable":false,"doc":"Replaces the whole error state.","details":[],"examples":[]},{"name":"onRetry","optional":true,"type":"() => void","bindable":false,"doc":"Offers a \"Try again\" button in the error state.","details":[],"examples":[]},{"name":"csv","optional":true,"type":"boolean | string","default":"false","bindable":false,"doc":"Offer the plotted rows as a CSV download, from a button in the corner. A string names the file.","details":[],"examples":[]},{"name":"csvColumns","optional":true,"type":"(string | { key: string; label?: string; value?: (row: T) => unknown })[]","bindable":false,"doc":"Which fields the download writes, in order. Defaults to every field.","details":[],"examples":[]},{"name":"references","optional":true,"type":"ChartReference[]","bindable":false,"doc":"Lines and bands at fixed values — targets, thresholds, windows.","details":[],"examples":[]},{"name":"annotations","optional":true,"type":"ChartAnnotation[]","bindable":false,"doc":"Notes pinned to a point.","details":[],"examples":[]},{"name":"brush","optional":true,"type":"ChartBrush","bindable":false,"doc":"Drag across the plot to select a range, and zoom the chart to it.","details":[],"examples":[]},{"name":"zoom","optional":true,"type":"ChartZoom","bindable":false,"doc":"Wheel or pinch to zoom, drag to pan.","details":[],"examples":[]}]},{"name":"ScrollArea","dir":"scroll-area","entry":"omaris","importPath":"import { ScrollArea } from 'omaris'","summary":"A scroll container that looks like it belongs: thin, token-coloured bars that thicken under the pointer, and optional edge fades that say there is more beyond an edge — and only when there is.","details":["**It is native scroll, nothing else.** The browser moves the content, so a trackpad, a wheel, a flick with iOS momentum, the keyboard and `scrollIntoView` all behave exactly as they do everywhere else. No JavaScript scrolls anything. What the component adds is read-only: a passive scroll listener, throttled to one read per animation frame, that notes which edges the content has moved away from.","**The fades are a mask**, not a gradient painted over the content, so they work on any background — a card, an image, a tinted surface — without being told its colour. Each edge fades in as the content leaves it and out as it comes back, and the scrollbar lanes are kept out of the mask so the bar itself is never faded.","**It is reachable.** A scroll area whose content overflows takes focus (`tabindex=\"0\"`), so a keyboard can scroll it with the arrows and Page keys; with a `label` it is a named `region` as well. An area that fits its content takes nothing and says nothing.","Size it from the outside — `maxHeight`, or a height class on the root. It ships no height of its own, so `class=\"h-64\"` or `max-h-[50dvh]` replaces nothing and needs no `!`.","The edges it has left are on the root as `data-overflow-top`, `-bottom`, `-start` and `-end`, for a shadow or a divider of your own: `data-overflow-top:shadow-1`."],"examples":[{"lang":"svelte","code":"<ScrollArea maxHeight=\"20rem\" fade label=\"Activity\">\n  {#each events as e (e.id)}<ActivityRow {e} />{/each}\n</ScrollArea>"}],"classesType":"ScrollAreaClasses","parts":[{"name":"root","doc":"The frame. It does not scroll: it carries the size, the shape and the focus ring, so the ring is never faded by the viewport's mask."},{"name":"viewport","doc":"The element that scrolls. Rounded like its frame, so content clips at the corners."},{"name":"content","doc":"Wraps the children; its size is what the area measures against."}],"variants":[{"name":"orientation","doc":"","default":"vertical","values":[{"name":"vertical","doc":""},{"name":"horizontal","doc":"A row that runs off the side. The content is as wide as it wants to be."},{"name":"both","doc":""}]},{"name":"fade","doc":"","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Layout/Scroll Area","category":"Layout","own":true,"stories":["Playground","Vertical","Edge fades","Horizontal","Both","Fits its content","Overridden"]},"props":[{"name":"orientation","optional":true,"type":"ScrollAreaOrientation","default":"'vertical'","bindable":false,"doc":"Which way it scrolls. The other axis is clipped.","details":[],"examples":[]},{"name":"maxHeight","optional":true,"type":"number | string","bindable":false,"doc":"The tallest it grows before it scrolls. A number is px, a string any CSS length — `320`, `\"20rem\"`, `\"50dvh\"`. Unset, it grows with its content unless something outside gives it a height.","details":["Set as a custom property rather than a class, so a `max-h-*` or `h-*` in `class` replaces it outright."],"examples":[]},{"name":"fade","optional":true,"type":"boolean | number | string","default":"false","bindable":false,"doc":"Fade the content out at each edge it has been scrolled away from. `true` is a 1.5rem fade; a number (px) or a CSS length sets the depth.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Names the area for a screen reader — \"Activity\", \"Order items\". When the content overflows the area takes focus, and with a label it is a `region` too. `aria-label` works the same.","details":[],"examples":[]},{"name":"ref","optional":true,"type":"HTMLDivElement | null","default":"null","bindable":true,"doc":"The scrolling element, for `scrollTo` and friends. Bindable.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"ScrollAreaClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"SearchBar","dir":"search-bar","entry":"omaris","importPath":"import { SearchBar } from 'omaris'","summary":"MD3 search — the bar and the view it opens into.","details":["The bar is the pill that sits in a top app bar: a leading icon (or a menu button), the query, and whatever belongs at the end — an avatar, a mic, a filter. Focus it and it becomes the *search view*, which is the part most implementations skip and the part that makes search feel native:","- On a phone the bar *is* the button that opens the search screen: one tap and the screen fades up over the page, with the field focused and the keyboard already up. It never sits there half-open with a caret in a pill and no results — the tap that focuses it is the tap that opens the screen. - On a wide screen it stays put and drops a docked panel underneath, which is what a dashboard wants — the page stays visible behind it. - `view=\"auto\"` picks between the two on the viewport, so one bar is right on both.","Results can be handed over as `suggestions` — filtered locally as you type, or left alone with `filter={false}` when they come from a server — or drawn from scratch with the `results` snippet. Either way the arrow keys walk them, Enter takes the highlighted one, Escape backs out, and the field carries the `combobox` semantics a screen reader needs.","The first result is highlighted the moment there is a query, so Enter opens the obvious answer without arrowing down to it first — the way the address bar behaves. `autoHighlight={false}` restores the plain behaviour, where Enter searches for what was typed."],"examples":[],"classesType":"SearchBarClasses","parts":[{"name":"root","doc":""},{"name":"input","doc":""},{"name":"icon","doc":"A static icon slot — the magnifier, usually."},{"name":"action","doc":"A pressable one — back, clear, mic."},{"name":"view","doc":""},{"name":"viewHeader","doc":"The field row inside the view."},{"name":"results","doc":"Everything under the field, in either view."},{"name":"docked","doc":"The docked panel a wide screen gets instead. It starts at the bar's own width and may grow with its content, but only so far — a dropdown three times the width of the field it hangs off no longer reads as belonging to it."},{"name":"body","doc":"The column inside the view: field, results, footer."},{"name":"surface","doc":""},{"name":"option","doc":""},{"name":"group","doc":"A non-interactive heading above a run of options."},{"name":"description","doc":""},{"name":"check","doc":""},{"name":"empty","doc":"\"No results\", \"Searching…\"."},{"name":"highlight","doc":"The part of a label that matched what was typed."}],"variants":[{"name":"variant","doc":"","default":"filled","values":[{"name":"filled","doc":"MD3's default: a tinted pill with no border."},{"name":"outlined","doc":""},{"name":"elevated","doc":"Floating over content — a map, a hero image."}]},{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]},{"name":"expanded","doc":"Set while the view is open — the bar holds its space but steps aside.","values":[{"name":"true","doc":""}]},{"name":"asButton","doc":"On a phone the bar is a button, not a field: it opens the search screen rather than taking a caret of its own.","values":[{"name":"true","doc":""}]}],"story":{"title":"Navigation/Search Bar","category":"Navigation","own":true,"stories":["Playground","In an app bar","Full-screen view","Enter searches, not selects","Over content"]},"props":[{"name":"value","optional":true,"type":"string","default":"''","bindable":true,"doc":"The query. Bindable.","details":[],"examples":[]},{"name":"open","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Whether the search view is showing. Bindable.","details":[],"examples":[]},{"name":"placeholder","optional":true,"type":"string","default":"'Search'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"variant","optional":true,"type":"SearchBarVariant","default":"'filled'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"SearchBarSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"view","optional":true,"type":"SearchBarView","default":"'auto'","bindable":false,"doc":"Which view focusing the bar opens.","details":[],"examples":[]},{"name":"breakpoint","optional":true,"type":"number","default":"768","bindable":false,"doc":"Viewport width, in px, under which `auto` goes full screen.","details":[],"examples":[]},{"name":"suggestions","optional":true,"type":"SearchSuggestion[]","default":"[]","bindable":false,"doc":"Rows to show under the field.","details":[],"examples":[]},{"name":"filter","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Filter `suggestions` against the query here. Off when they arrive already filtered.","details":[],"examples":[]},{"name":"autoHighlight","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Highlight the first result as soon as there is a query, so Enter takes it without a trip through the arrow keys. Turn it off where Enter should search for what was typed rather than open the best guess.","details":[],"examples":[]},{"name":"loading","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Spinner in the field.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"emptyText","optional":true,"type":"string","default":"'No results'","bindable":false,"doc":"Text when a query matches nothing.","details":[],"examples":[]},{"name":"onsearch","optional":true,"type":"(value: string) => void","bindable":false,"doc":"Fires on Enter, with the query.","details":[],"examples":[]},{"name":"onselect","optional":true,"type":"(suggestion: SearchSuggestion) => void","bindable":false,"doc":"Fires when a suggestion is taken.","details":[],"examples":[]},{"name":"onclear","optional":true,"type":"() => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onopen","optional":true,"type":"(open: boolean) => void","bindable":false,"doc":"Fires as the view opens and closes.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"SearchBarClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"leading","optional":true,"type":"Snippet","bindable":false,"doc":"Leading slot. Defaults to a magnifier — pass a menu button instead.","details":[],"examples":[]},{"name":"trailing","optional":true,"type":"Snippet","bindable":false,"doc":"Trailing slot — an avatar, a mic, a filter button.","details":[],"examples":[]},{"name":"results","optional":true,"type":"Snippet","bindable":false,"doc":"The whole result area, in place of `suggestions`.","details":[],"examples":[]},{"name":"footer","optional":true,"type":"Snippet","bindable":false,"doc":"Pinned under the results — \"see all\", a keyboard hint.","details":[],"examples":[]}]},{"name":"SegmentedButton","dir":"segmented-button","entry":"omaris","importPath":"import { SegmentedButton } from 'omaris'","summary":"MD3 segmented button.","details":["A set of two to five related choices that reads as one control. Unlike `ButtonGroup`, which only lays buttons out, this owns the selection: it takes a value (or an array of them), reports changes, and renders MD3's leading tick on the chosen segments.","The tick slides in from zero width, so selecting a segment grows it rather than swapping its content."],"examples":[],"classesType":"SegmentedButtonClasses","parts":[{"name":"root","doc":"`w-fit max-w-full`, because `inline-flex` is not enough on its own and neither half of this is either."},{"name":"segment","doc":""},{"name":"check","doc":"The tick: zero-width until the segment is selected."},{"name":"label","doc":""}],"variants":[{"name":"tone","doc":"","default":"primary","values":[{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""}]},{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]},{"name":"full","doc":"Segments share the width evenly.","values":[{"name":"true","doc":""}]},{"name":"shape","doc":"MD3's rounded rectangle instead of the pill.","default":"round","values":[{"name":"round","doc":""},{"name":"square","doc":""}]}],"story":{"title":"Actions/Segmented Button","category":"Actions","own":true,"stories":["Playground","Sizes","Multiple","Icons","Shapes","Full width","Tones and disabled segments"]},"props":[{"name":"items","optional":false,"type":"SegmentedItem[]","bindable":false,"doc":"","details":[],"examples":[]},{"name":"value","optional":true,"type":"string","default":"undefined","bindable":true,"doc":"Selected value, in single mode. Bindable.","details":[],"examples":[]},{"name":"values","optional":true,"type":"string[]","default":"[]","bindable":true,"doc":"Selected values, in multiple mode. Bindable.","details":[],"examples":[]},{"name":"multiple","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Allow more than one segment at a time.","details":[],"examples":[]},{"name":"tone","optional":true,"type":"SegmentedTone","default":"'primary'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"SegmentedSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"shape","optional":true,"type":"SegmentedShape","default":"'round'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"full","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"check","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Draw the leading tick on selected segments.","details":[],"examples":[]},{"name":"keepIcon","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Keep a segment's own icon instead of swapping it for the tick.","details":[],"examples":[]},{"name":"mandatory","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Refuse to clear the last selection.","details":[],"examples":[]},{"name":"ripple","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible name for the set.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(value: string | string[]) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"SegmentedButtonClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"Select","dir":"select","entry":"omaris","importPath":"import { Select } from 'omaris'","summary":"Select — the Input's frame around a styled list of values.","details":["The list is drawn by the library, so it matches the rest of the UI in both themes, shows icons and descriptions, and can be navigated with arrows, Home/End and type-ahead while focus stays on the field. Pass `native` to get the OS picker instead — the one dropdown that always works on a phone.","For a list you *search*, use `Combobox`. For a menu of actions, `Menu`."],"examples":[],"classesType":"SelectClasses","parts":[{"name":"root","doc":""},{"name":"field","doc":""},{"name":"control","doc":"The trigger, or the native `<select>`: keeps its hit area, loses its chrome."},{"name":"value","doc":""},{"name":"chevron","doc":""},{"name":"adornment","doc":""},{"name":"action","doc":""},{"name":"label","doc":""},{"name":"support","doc":""},{"name":"placeholder","doc":""},{"name":"surface","doc":""},{"name":"option","doc":""},{"name":"group","doc":"A non-interactive heading above a run of options."},{"name":"body","doc":""},{"name":"description","doc":""},{"name":"check","doc":""},{"name":"empty","doc":"\"No results\", \"Searching…\"."},{"name":"highlight","doc":"The part of a label that matched what was typed."}],"variants":[{"name":"variant","doc":"","default":"outline","values":[{"name":"outline","doc":""},{"name":"filled","doc":""},{"name":"ghost","doc":""}]},{"name":"size","doc":"","default":"default","values":[{"name":"sm","doc":""},{"name":"default","doc":""},{"name":"lg","doc":""}]},{"name":"invalid","doc":"","default":"false","values":[{"name":"true","doc":""}]}],"story":{"title":"Inputs/Select","category":"Inputs","own":true,"stories":["Playground","Grouped","Rich options","Right to left","Variants","Sizes","States","Native"]},"props":[{"name":"variant","optional":true,"type":"SelectVariant","default":"'outline'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"SelectSize","default":"'default'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"value","optional":true,"type":"string","default":"''","bindable":true,"doc":"Selected value. Bindable.","details":[],"examples":[]},{"name":"options","optional":true,"type":"SelectOption[]","bindable":false,"doc":"Options to render. Omit and pass `<option>` children for a native select.","details":[],"examples":[]},{"name":"placeholder","optional":true,"type":"string","bindable":false,"doc":"Shown, greyed, while nothing is chosen.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"required","optional":true,"type":"boolean","bindable":false,"doc":"Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"supportingText","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"invalid","optional":true,"type":"boolean","bindable":false,"doc":"Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"native","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Use the OS picker instead of the styled list.","details":[],"examples":[]},{"name":"mobileSheet","optional":true,"type":"boolean","bindable":false,"doc":"On a phone, the list rises from the bottom edge as a sheet — full width, a scrim behind, dragged down to dismiss, rows a thumb can hit — instead of hanging under the field. `false` keeps it anchored.","details":[],"examples":[]},{"name":"clearable","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Show an × that empties the field.","details":[],"examples":[]},{"name":"emptyText","optional":true,"type":"string","default":"'No options'","bindable":false,"doc":"Text for an empty `options` array.","details":[],"examples":[]},{"name":"start","optional":true,"type":"Snippet","bindable":false,"doc":"Leading icon inside the frame.","details":[],"examples":[]},{"name":"option","optional":true,"type":"Snippet<[SelectOption, { selected: boolean; active: boolean }]>","bindable":false,"doc":"Custom row rendering for the styled list.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(value: string, option: SelectOption | undefined) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"SelectClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]},{"name":"ref","optional":true,"type":"HTMLSelectElement | HTMLButtonElement | null","default":"null","bindable":true,"doc":"","details":[],"examples":[]}]},{"name":"Shape","dir":"shape","entry":"omaris","importPath":"import { Shape } from 'omaris'","summary":"The Material 3 shape library, as a box you can put things in.","details":["Thirty-six outlines — cookies, clovers, bursts, an arch, a heart — that clip whatever is inside them: a photo, an avatar, an icon, a flat block of colour. They are the decorative end of MD3, and the point of them is that they move.","**It morphs, and it morphs between any two of them.** Change `shape` and the outline travels; give it `hover` or `press` and it answers the pointer. There is no list of legal pairs, because the morph does not interpolate path data — every outline is walked into the same ring of 72 points, wound the same way and started at the same place, so a heart can become a pixel triangle as easily as a circle becomes a square. The content underneath never moves; only the hole it is seen through does.","**Spin does not tilt the picture.** `spin` turns the outline while the contents counter-rotate on the same clock, so a face inside a spinning cookie stays upright — the MD3 loading indicator's trick, and the reason `spin` with `cycle` reads as one moving object rather than a rotating image.","Everything respects `prefers-reduced-motion`: morphs land immediately, spinning and cycling stop. Shapes are clipped in `objectBoundingBox` space, so a square box keeps them true and a rectangle stretches them on purpose."],"examples":[{"lang":"svelte","code":"<Shape shape=\"cookie-9\" hover=\"clover-4\" src={user.photo} alt={user.name} size=\"5rem\" />\n<Shape cycle={['cookie-9', 'clover-4', 'pill']} spin class=\"size-10 bg-primary\" />"}],"classesType":"ShapeClasses","parts":[{"name":"root","doc":"The clipped box. Sizing, colour and elevation live here, and so does the spin — the outline is a `clip-path` on this element, so turning it turns the shape."},{"name":"content","doc":"Everything inside, on its own layer so it can be turned back the other way while the shape spins. Also the reason a child can be `absolute` without escaping the clip."},{"name":"image","doc":""}],"variants":[{"name":"spin","doc":"","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Foundations/Shape","category":"Foundations","own":true,"stories":["Playground","Every shape","Morphing","Loading","Media","Overridden"]},"props":[{"name":"shape","optional":true,"type":"ShapeName","default":"'circle'","bindable":false,"doc":"The outline. Changing it morphs, rather than cutting.","details":[],"examples":[]},{"name":"hover","optional":true,"type":"ShapeName","bindable":false,"doc":"Morph to this while the pointer is over it, or focus is inside.","details":[],"examples":[]},{"name":"press","optional":true,"type":"ShapeName","bindable":false,"doc":"Morph to this while it is being pressed.","details":[],"examples":[]},{"name":"cycle","optional":true,"type":"ShapeName[]","bindable":false,"doc":"Morph through these forever — a loader, or an idle flourish.","details":[],"examples":[]},{"name":"interval","optional":true,"type":"number","default":"1400","bindable":false,"doc":"How long each shape in `cycle` is held, in ms.","details":[],"examples":[]},{"name":"duration","optional":true,"type":"number","default":"500","bindable":false,"doc":"How long one morph takes, in ms. `0` cuts instead.","details":[],"examples":[]},{"name":"spin","optional":true,"type":"boolean | number","default":"false","bindable":false,"doc":"Turn the outline while the contents stay upright. Seconds per turn, or `true` for 12.","details":[],"examples":[]},{"name":"size","optional":true,"type":"string | number","default":"'6rem'","bindable":false,"doc":"Width and height, as a CSS length. Numbers are pixels.","details":[],"examples":[]},{"name":"src","optional":true,"type":"string","bindable":false,"doc":"A picture to clip, for the common case. Children work too.","details":[],"examples":[]},{"name":"alt","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"ShapeClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"Share","dir":"share","entry":"omaris","importPath":"import { Share } from 'omaris'","summary":"The share sheet — a bottom sheet on a phone, a centred dialog on a desktop, built on `Dialog` so the focus trap, the drag-to-dismiss and the morphing height all come for free.","details":["Sharing is three fields — a link, a headline, a sentence — so that is the whole required API, and it is `navigator.share()`'s own shape:","That alone gives a preview of what is being shared, a link bar that copies and says so in place, seven working destinations with their intent URLs already written, a QR code for handing the link to a phone across the table, and the platform's own sheet where the browser has one. Nothing to wire.","Everything is then replaceable a piece at a time. `targets` takes names and objects in the same array, so keeping the defaults and adding one of your own is `targets={['whatsapp', 'email', mattermost]}`. `people` puts a row of faces above the apps — recent recipients, teammates, devices — each with the channel it would send over badged on the avatar. `actions` are the rows underneath: save, print, revoke the link.","It reports what it did where the result would otherwise be invisible and nowhere else: copying says \"Copied\" on the row that was pressed, and opening WhatsApp says nothing, because WhatsApp opened.","Keyboard: Tab reaches every row, the arrow keys walk each rail (and follow the writing direction), Home and End jump to its ends, Escape closes."],"examples":[{"lang":"svelte","code":"<Share bind:open url={link} title=\"Q3 report\" text=\"Revenue is up 14%.\" />"}],"classesType":"ShareClasses","parts":[{"name":"root","doc":"The dialog itself — the box the whole sheet is drawn in."},{"name":"surface","doc":"Everything inside it, as one column."},{"name":"header","doc":"Preview row: what is being shared, and the way out."},{"name":"thumb","doc":"The square at its start — a thumbnail, or a glyph."},{"name":"heading","doc":"What is being shared."},{"name":"subheading","doc":"The line under it — your own text, or the link, tidied."},{"name":"close","doc":"The close button."},{"name":"link","doc":"The copyable link bar."},{"name":"linkText","doc":"The link inside it, shortened to host and path."},{"name":"copy","doc":"The press that copies it."},{"name":"section","doc":"A labelled block — the people rail, the apps rail."},{"name":"label","doc":"Its caption, and the rail's accessible name."},{"name":"rail","doc":"The horizontal scroller. It fades at whichever edge still has something past it, so a rail that scrolls says so without a scrollbar."},{"name":"target","doc":"One destination."},{"name":"tile","doc":"The coloured square. `--share-tint` is the brand colour and `--share-ink` what sits on it, both written per tile — which is how one component paints a WhatsApp green and a theme role with the same class."},{"name":"targetLabel","doc":"Under the tile. Two lines at most, then it clips."},{"name":"targetDetail","doc":"The quieter second line — a device, a last-shared time."},{"name":"person","doc":"A person's circular tile, in place of `tile`."},{"name":"badge","doc":"The channel badge on it — the app the message would go through."},{"name":"actions","doc":"The list of rows under the rails."},{"name":"action","doc":"One row."},{"name":"actionLabel","doc":"Its label."},{"name":"actionDetail","doc":"Right-hand meta, before the glyph."},{"name":"actionIcon","doc":"The trailing glyph."},{"name":"qr","doc":"The QR panel, once the code has been asked for."},{"name":"qrPlate","doc":"The plate the code is drawn on. White in both themes on purpose: a scanner wants dark modules on a light field, and an inverted code is one half the phones in a room cannot read."},{"name":"footer","doc":"Pinned under everything the sheet offers."}],"variants":[{"name":"density","doc":"Roomier tiles and rows for a sheet that is mostly thumbed.","default":"comfortable","values":[{"name":"comfortable","doc":""},{"name":"compact","doc":""}]}],"story":{"title":"Containment/Share","category":"Containment","own":true,"stories":["Playground","Basic","People","Custom targets and actions","Overridden"]},"props":[{"name":"open","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Bindable.","details":[],"examples":[]},{"name":"url","optional":true,"type":"string","bindable":false,"doc":"The link being shared. Everything else has a sensible default from it.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"Headline — the page, product or file. Also the preview's first line.","details":[],"examples":[]},{"name":"text","optional":true,"type":"string","bindable":false,"doc":"The sentence that goes with it, and the preview's second line.","details":[],"examples":[]},{"name":"files","optional":true,"type":"File[]","bindable":false,"doc":"Attachments for the platform sheet. Web intents get the link instead.","details":[],"examples":[]},{"name":"image","optional":true,"type":"string","bindable":false,"doc":"A thumbnail of what is being shared.","details":[],"examples":[]},{"name":"heading","optional":true,"type":"string","default":"'Share'","bindable":false,"doc":"The sheet's own headline, above the preview. Defaults to \"Share\".","details":[],"examples":[]},{"name":"targets","optional":true,"type":"readonly (ShareTargetId | ShareTarget)[] | false","default":"DEFAULT_TARGETS","bindable":false,"doc":"Destinations, by name or as objects, in one array. Defaults to the seven built-ins; `false` drops the rail entirely.","details":[],"examples":[]},{"name":"people","optional":true,"type":"readonly ShareTarget[]","bindable":false,"doc":"Faces above the apps — recent recipients, teammates, devices.","details":[],"examples":[]},{"name":"actions","optional":true,"type":"readonly ShareAction[]","bindable":false,"doc":"Rows under the rails. The QR row is added to them, not instead of them.","details":[],"examples":[]},{"name":"peopleLabel","optional":true,"type":"string","default":"'Send to'","bindable":false,"doc":"Caption over the people rail, and its accessible name.","details":[],"examples":[]},{"name":"targetsLabel","optional":true,"type":"string","default":"'Share via'","bindable":false,"doc":"Caption over the apps rail, and its accessible name.","details":[],"examples":[]},{"name":"link","optional":true,"type":"boolean","bindable":false,"doc":"Show the copyable link bar. On whenever there is a `url`.","details":[],"examples":[]},{"name":"qr","optional":true,"type":"boolean","bindable":false,"doc":"Offer the QR code row. On whenever there is a `url`.","details":[],"examples":[]},{"name":"native","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Offer the platform's own sheet where the browser has one. On by default.","details":[],"examples":[]},{"name":"nativeLabel","optional":true,"type":"string","default":"'More'","bindable":false,"doc":"What that tile is called.","details":[],"examples":[]},{"name":"closeOnShare","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Close the sheet once a destination has been handed the payload. On by default.","details":[],"examples":[]},{"name":"size","optional":true,"type":"ShareSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"density","optional":true,"type":"ShareDensity","default":"'comfortable'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"responsive","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Become a bottom sheet on a phone. On by default.","details":[],"examples":[]},{"name":"mobileQuery","optional":true,"type":"string","bindable":false,"doc":"What counts as a phone.","details":[],"examples":[]},{"name":"dismissible","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Escape, a press outside and a downward drag close it.","details":[],"examples":[]},{"name":"closeLabel","optional":true,"type":"string","default":"'Close'","bindable":false,"doc":"Accessible name for the close button.","details":[],"examples":[]},{"name":"onshare","optional":true,"type":"(id: string, data: ShareData) => void","bindable":false,"doc":"Fires with the id of whatever was pressed, once it has been acted on.","details":[],"examples":[]},{"name":"onclose","optional":true,"type":"() => void","bindable":false,"doc":"Fires after the sheet has finished closing.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"ShareClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"thumb","optional":true,"type":"Snippet","bindable":false,"doc":"Replaces the preview square — a file icon, a colour swatch, a chart.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Extra content between the link bar and the rails.","details":[],"examples":[]},{"name":"footer","optional":true,"type":"Snippet","bindable":false,"doc":"Pinned under everything — a visibility switch, an expiry note.","details":[],"examples":[]}]},{"name":"Sheet","dir":"sheet","entry":"omaris","importPath":"import { Sheet } from 'omaris'","summary":"MD3 side and bottom sheets.","details":["Same native `<dialog>` foundation as `Dialog` — focus trap, top layer, Escape — but anchored to an edge and sliding in from it.","It is also draggable, the way a drawer on a phone is: the sheet follows your finger, stops dead at its own edge rather than lifting off it, dims the backdrop as it goes, and either springs back or leaves depending on how far and how fast you threw it. A half-hearted drag always comes back — you have to mean it. The rules for reading a gesture live in `drag.ts`.","Opening, closing, snapping and dragging are all the same one movement: a distance from the edge, transitioned. There is no entrance keyframe to collide with a gesture, so grabbing the sheet mid-open picks it up from wherever it is, and nothing can re-play an animation it has finished.","A finger drags it from anywhere; a mouse drags it by the handle or the header, so selecting text in the body still works on a desktop.","Every bit of it is keyboard-reachable without dragging: the handle is a real close button, Escape works, and the backdrop is clickable.","`modal={false}` makes it a panel rather than an interruption: no backdrop, no focus trap, and the page behind stays live — the sheet a map app keeps over the map, resting on a snap point while the map is still dragged and tapped. `inline` keeps that panel inside its own container instead of the viewport, so it can sit over one region of a screen and leave a navigation bar below it alone. Give that container `relative overflow-hidden`: a sheet resting on a snap point hangs past the container's edge by the part that is not showing."],"examples":[],"classesType":"SheetClasses","parts":[{"name":"root","doc":""},{"name":"header","doc":""},{"name":"title","doc":""},{"name":"description","doc":""},{"name":"footer","doc":""},{"name":"handle","doc":"MD3's drag handle on a bottom sheet — and the grab point."},{"name":"grip","doc":"The visible bar inside that target."}],"variants":[{"name":"side","doc":"","default":"end","values":[{"name":"start","doc":""},{"name":"end","doc":""},{"name":"top","doc":""},{"name":"bottom","doc":""}]},{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""},{"name":"full","doc":""}]},{"name":"drag","doc":"Dragging by the chrome must never be mistaken for a scroll — or for a text selection. The callout suppression is the touch half of that: without it, a finger resting on the sheet long enough to start pulling it gets iOS's \"Copy / Look Up\" bubble and a highlighted word instead of a sheet that moves.","values":[{"name":"true","doc":""}]},{"name":"modal","doc":"A panel over a live page has no top layer to sit in, so it stacks with a z-index and casts a lighter shadow than a modal does.","values":[{"name":"false","doc":""}]},{"name":"inline","doc":"Positioned against its own container rather than the viewport.","values":[{"name":"true","doc":""}]}],"story":{"title":"Containment/Sheet","category":"Containment","own":true,"stories":["Playground","Sides","Bottom sheet","Drag to dismiss","After a drag","Snap points","As a navigation drawer","Persistent, inline"]},"props":[{"name":"open","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Bindable.","details":[],"examples":[]},{"name":"side","optional":true,"type":"SheetSide","default":"'end'","bindable":false,"doc":"Edge it hangs off. `start`/`end` follow the writing direction.","details":[],"examples":[]},{"name":"size","optional":true,"type":"SheetSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"description","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"dismissible","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Escape, a backdrop press and a full drag close it.","details":[],"examples":[]},{"name":"modal","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"A modal sheet dims and blocks the page. `false` leaves the page live behind a panel with no backdrop — for a sheet that rests over a map, not one that asks a question.","details":[],"examples":[]},{"name":"inline","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Keep it inside the nearest positioned ancestor instead of the viewport. Sizes and snap points then read against that box.","details":[],"examples":[]},{"name":"handle","optional":true,"type":"boolean","bindable":false,"doc":"Show MD3's drag handle. On by default for a bottom sheet.","details":[],"examples":[]},{"name":"drag","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Follow the pointer. On by default.","details":[],"examples":[]},{"name":"dragThreshold","optional":true,"type":"number","default":"0.5","bindable":false,"doc":"Fraction of the sheet that has to be dragged away before a release dismisses it. A flick dismisses from anywhere regardless.","details":[],"examples":[]},{"name":"snapPoints","optional":true,"type":"number[]","bindable":false,"doc":"Resting fractions of the sheet, ascending — `[0.4, 1]` gives a peek and a full height. Dragging below the smallest one dismisses.","details":[],"examples":[]},{"name":"snap","optional":true,"type":"number","default":"1","bindable":true,"doc":"Fraction currently rested at. Bindable.","details":[],"examples":[]},{"name":"onclose","optional":true,"type":"() => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onsnap","optional":true,"type":"(snap: number) => void","bindable":false,"doc":"Fires each time the sheet settles on a different snap point.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"SheetClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"headerEnd","optional":true,"type":"Snippet","bindable":false,"doc":"Trailing slot in the header — a close button, usually.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]},{"name":"footer","optional":true,"type":"Snippet","bindable":false,"doc":"Pinned action row along the bottom.","details":[],"examples":[]}]},{"name":"Skeleton","dir":"skeleton","entry":"omaris","importPath":"import { Skeleton } from 'omaris'","summary":"Skeleton placeholder.","details":["`shimmer` sweeps a highlight across the block; `pulse` just breathes. The sweep rides on `translate` only — a compositor property — so a screenful of skeletons stays at 60fps and costs no layout. Both stop dead under `prefers-reduced-motion`, leaving a plain grey block: a loading state should never be the thing that makes someone sick.","Skeletons are decorative by default (`aria-hidden`), because a screen reader announcing \"Loading\" once per grey box is noise. Put one `label` on the skeleton that stands for the whole region — or better, mark the region itself `aria-busy` — and leave the rest silent."],"examples":[],"classesType":null,"parts":[],"variants":[{"name":"animation","doc":"","default":"shimmer","values":[{"name":"shimmer","doc":""},{"name":"pulse","doc":""},{"name":"none","doc":""}]},{"name":"shape","doc":"","default":"block","values":[{"name":"text","doc":""},{"name":"block","doc":""},{"name":"circle","doc":""}]}],"story":{"title":"Data Display/Skeleton","category":"Data Display","own":true,"stories":["Playground","Shapes","Paragraphs","Animations","Matching the real layout"]},"props":[{"name":"animation","optional":true,"type":"SkeletonAnimation","default":"'shimmer'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"shape","optional":true,"type":"SkeletonShape","default":"'block'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"lines","optional":true,"type":"number","default":"1","bindable":false,"doc":"Number of lines. Above one, the block repeats with a short last line so it reads as a paragraph.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Announce this skeleton as a live loading region under this name. Use it once per region — not once per block.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"Slider","dir":"slider","entry":"omaris","importPath":"import { Slider } from 'omaris'","summary":"MD3 Expressive slider.","details":["For two handles, see `RangeSlider`."],"examples":[{"lang":"svelte","code":"<Slider bind:value label=\"Volume\" showValue />\n<Slider bind:value wave />                 <!-- ripples while dragging -->\n<Slider bind:value wave=\"always\" />        <!-- a playing media track -->\n<Slider bind:value orientation=\"vertical\" size=\"lg\" />"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Selection/Slider","category":"Selection","own":true,"stories":["Playground","Wave","Media player","Range","Vertical","Sizes","Stepped","Tones","Disabled","Elastic","In a form"]},"props":[{"name":"value","optional":true,"type":"number","default":"0","bindable":true,"doc":"Bindable.","details":[],"examples":[]},{"name":"oninput","optional":true,"type":"(value: number) => void","bindable":false,"doc":"Fires on every change.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(value: number) => void","bindable":false,"doc":"Fires when a drag ends or a key is pressed — the commit moment.","details":[],"examples":[]},{"name":"min","optional":true,"type":"number","bindable":false,"doc":"","details":[],"examples":[]},{"name":"max","optional":true,"type":"number","bindable":false,"doc":"","details":[],"examples":[]},{"name":"step","optional":true,"type":"number","bindable":false,"doc":"","details":[],"examples":[]},{"name":"minDistance","optional":true,"type":"number","bindable":false,"doc":"Smallest allowed gap between the two handles of a range.","details":[],"examples":[]},{"name":"tone","optional":true,"type":"SliderTone","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"SliderSize","bindable":false,"doc":"","details":[],"examples":[]},{"name":"orientation","optional":true,"type":"SliderOrientation","bindable":false,"doc":"","details":[],"examples":[]},{"name":"wave","optional":true,"type":"boolean | 'always'","bindable":false,"doc":"Ripple a wave through the filled part while it's being dragged. `'always'` keeps it moving — for a media player that's playing.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Label above the track.","details":[],"examples":[]},{"name":"supportingText","optional":true,"type":"string","bindable":false,"doc":"Helper line below the track.","details":[],"examples":[]},{"name":"showValue","optional":true,"type":"boolean","bindable":false,"doc":"Show the current value beside the label.","details":[],"examples":[]},{"name":"bubble","optional":true,"type":"boolean | 'always'","bindable":false,"doc":"Float the value over the handle while dragging; `'always'` keeps it up.","details":[],"examples":[]},{"name":"ticks","optional":true,"type":"boolean","bindable":false,"doc":"Draw a stop dot at every step. Ignored above 30 steps.","details":[],"examples":[]},{"name":"format","optional":true,"type":"(value: number) => string","bindable":false,"doc":"Turns a number into display text — \"40%\", \"$12\".","details":[],"examples":[]},{"name":"name","optional":true,"type":"string","bindable":false,"doc":"Submit the value(s) with the surrounding form.","details":[],"examples":[]},{"name":"elastic","optional":true,"type":"boolean","bindable":false,"doc":"Let the track stretch when dragged past either end, and spring back on release.","details":[],"examples":[]},{"name":"haptics","optional":true,"type":"boolean","bindable":false,"doc":"A haptic tick on every step, and a firmer bump at either end. Follows the shared `haptics` store; `false` opts this slider out.","details":[],"examples":[]},{"name":"sound","optional":true,"type":"boolean","bindable":false,"doc":"A sound cue as the handle passes each step, and a duller one at the ends. Follows the shared `sound` store; `false` opts this slider out.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","bindable":false,"doc":"Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"ariaLabel","optional":true,"type":"string | string[]","bindable":false,"doc":"Accessible name for each handle, when there's no visible label.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"SliderClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"ref","optional":true,"type":"HTMLDivElement | null","default":"null","bindable":true,"doc":"","details":[],"examples":[]}]},{"name":"Sparkline","dir":"chart","entry":"omaris/chart","importPath":"import { Sparkline } from 'omaris/chart'","summary":"Sparkline — a trend with no axes, sized to sit inline in a table cell or a stat tile.","details":["It takes a bare array of numbers as happily as a list of rows, because at this size the shape is the whole message and anything else is ceremony. Nothing here is interactive: a sparkline that swallows a tap inside a row is worse than one you can't hover."],"examples":[{"lang":"svelte","code":"<Sparkline data={points} />"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Charts","category":"Data Display","own":false,"stories":["Area","Line","Bar","Pie and donut","Scatter","Sparkline","Empty","References and annotations","Brush and zoom","Legend isolate and CSV","Error","Combo","Radar","Radial bar and gauge","Funnel","Treemap","Candlestick"]},"props":[{"name":"data","optional":false,"type":"T[] | number[]","bindable":false,"doc":"","details":[],"examples":[]},{"name":"y","optional":true,"type":"Field<T>","bindable":false,"doc":"Field holding the value. Ignored when `data` is numbers.","details":[],"examples":[]},{"name":"width","optional":true,"type":"number | string","default":"'100%'","bindable":false,"doc":"Any CSS length, or a number of px.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"32","bindable":false,"doc":"","details":[],"examples":[]},{"name":"color","optional":true,"type":"string","default":"CHART_COLORS[0]","bindable":false,"doc":"Any CSS colour. Defaults to the first chart role.","details":[],"examples":[]},{"name":"area","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Fill under the line.","details":[],"examples":[]},{"name":"curve","optional":true,"type":"ChartCurve","default":"'smooth'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"marker","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Dot on the last point, so \"where it ended\" reads at a glance.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"Spinner","dir":"spinner","entry":"omaris","importPath":"import { Spinner } from 'omaris'","summary":"A small busy indicator for inline use — at the end of a row, on a chip, beside a line of text, in the corner of a card that is refetching.","details":["It is the indeterminate `CircularProgress` drawn lighter: the same arc turning over the same ring, on a thinner stroke with a faint track in the arc's own colour rather than a tonal container, so it sits in a line of text without outweighing it. Reach for `CircularProgress` when the wait deserves a place of its own on the screen, or when it has a value.","It announces itself politely — `role=\"status\"` with an `sr-only` label, \"Loading\" unless you say otherwise — so a screen reader hears that something is happening without the visual being read out.","`tone=\"current\"` takes the colour of the text around it, which is what a spinner on a chip or a coloured surface wants. A button that is working already has one: `loading` on `Button`."],"examples":[{"lang":"svelte","code":"<div class=\"flex items-center gap-3\">\n  <Text class=\"flex-1\">orders-2026-09.csv</Text>\n  {#if syncing}<Spinner size=\"sm\" label=\"Syncing orders\" />{/if}\n</div>"}],"classesType":"SpinnerClasses","parts":[{"name":"root","doc":""},{"name":"svg","doc":"The turning part. Reduced motion slows it rather than stopping it: a spinner that stands still says nothing is happening, which is a lie."},{"name":"track","doc":""},{"name":"indicator","doc":""},{"name":"label","doc":"The `sr-only` text a screen reader announces."}],"variants":[{"name":"tone","doc":"","default":"primary","values":[{"name":"current","doc":"The colour of the text around it."},{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""}]},{"name":"size","doc":"","default":"md","values":[{"name":"xs","doc":"12px — inside a chip, beside a caption."},{"name":"sm","doc":"16px — beside body text, at the end of a dense row."},{"name":"md","doc":"20px — at the end of a list row, in a toolbar."},{"name":"lg","doc":"32px — in the middle of a card that is loading."}]}],"story":{"title":"Communication/Spinner","category":"Communication","own":true,"stories":["Playground","Sizes","Tones","Inline","On a colored surface","Overridden"]},"props":[{"name":"tone","optional":true,"type":"SpinnerTone","default":"'primary'","bindable":false,"doc":"`current` inherits the surrounding text colour — the choice on a coloured surface.","details":[],"examples":[]},{"name":"size","optional":true,"type":"SpinnerSize","default":"'md'","bindable":false,"doc":"`xs` 12px, `sm` 16px, `md` 20px, `lg` 32px.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","default":"'Loading'","bindable":false,"doc":"What a screen reader hears — \"Saving\", \"Loading orders\". Defaults to \"Loading\". It is `sr-only`; nothing is drawn.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"SpinnerClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"SplashScreen","dir":"splash-screen","entry":"omaris","importPath":"import { SplashScreen } from 'omaris'","summary":"The screen an app shows before it has anything else to show.","details":["That is the whole of the common case. With no props it renders on the server — so it is in the HTML, not painted after hydration — waits for the page to finish loading, holds for `minDuration` so a fast boot doesn't blink, and leaves. Nothing to wire up, nothing to remember to turn off.","Everything past that is a decision you can take back:","- **`bind:open`** when you know what \"ready\" means. Auto-hide switches itself off the moment the splash is controlled, so it can never take the screen away from under you. - **`splash`** — a {@link SplashController} — when booting is a sequence: it carries `open`, `progress` and `message` together, and `splash.run([…])` walks the steps and puts each one on screen. - **`variant` and `pattern`** are the look: a colour scheme and a decorative layer, chosen separately, so a branded splash and a plain one differ by one word rather than by a rewrite. - **`exit`** is how it leaves, which is the part anyone remembers. `iris` opens a hole in the middle and the app is behind it. - **`inline`** puts the whole thing inside its container instead of over the viewport — the same screen for a pane, a dashboard tab or a preview that is still loading.","Two flashes are designed out rather than left to the caller. `minDuration` keeps a splash that only had 40ms of work to cover on screen long enough to be read instead of blinking, and `appearAfter` stops it appearing at all when the app was ready before the delay ran out — the two together mean a splash is either absent or deliberate."],"examples":[{"lang":"svelte","code":"<!-- +layout.svelte -->\n<SplashScreen title=\"Acme\" />"}],"classesType":"SplashScreenClasses","parts":[{"name":"root","doc":"The full-bleed surface. Everything else sits on it."},{"name":"scrim","doc":"The tint over a photograph, so text stays legible on any image."},{"name":"backdrop","doc":"The decorative layer — the pattern, when there is one."},{"name":"content","doc":"Logo, words and indicator, stacked and centred. Full width on purpose: a bar that is wider than the screen it is on has to be clamped by something, and this is the something."},{"name":"logo","doc":"The mark, at the size `size` asks for."},{"name":"halo","doc":"The ring that leaves the logo when `halo` is set."},{"name":"title","doc":""},{"name":"description","doc":""},{"name":"indicator","doc":"Wrapper for whichever indicator is running; sets its colour."},{"name":"track","doc":"The bar's groove. Never wider than the screen it is on."},{"name":"fill","doc":"The filled part of the bar."},{"name":"message","doc":"The line under the indicator — \"Loading your workspace\"."},{"name":"percent","doc":""},{"name":"actions","doc":""},{"name":"footer","doc":"Pinned to the bottom edge: a version, a byline, a legal line."}],"variants":[{"name":"variant","doc":"The colour the screen is. `primary` and `inverse` are the branded ones; `glass` is for a splash that goes over an app that is already on screen.","default":"background","values":[{"name":"background","doc":""},{"name":"surface","doc":""},{"name":"primary","doc":""},{"name":"inverse","doc":""},{"name":"glass","doc":""},{"name":"image","doc":""}]},{"name":"pattern","doc":"The decorative layer over the colour.","default":"none","values":[{"name":"none","doc":""},{"name":"gradient","doc":""},{"name":"aurora","doc":""},{"name":"mesh","doc":""},{"name":"spotlight","doc":""},{"name":"grid","doc":""},{"name":"dots","doc":""}]},{"name":"size","doc":"How big the mark and the type are.","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]},{"name":"align","doc":"Where the block sits. `top` leaves room for a wordmark below it.","default":"center","values":[{"name":"center","doc":""},{"name":"top","doc":""},{"name":"bottom","doc":""}]},{"name":"inline","doc":"Inside its container rather than over the viewport. The container needs a position of its own — `relative` — for it to hold.","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"System/Splash Screen","category":"System","own":true,"stories":["Playground","Variants","Patterns","Indicators","Exits","Progress","Controller","Overridden"]},"props":[{"name":"open","optional":true,"type":"boolean","bindable":true,"doc":"Whether the splash is up.","details":["Leave it out and the component runs itself: it starts up and comes down when the page has loaded. Bind it — or pass a `splash` — and it is yours, auto-hide included."],"examples":[]},{"name":"splash","optional":true,"type":"SplashController","bindable":false,"doc":"A {@link SplashController}, for a boot sequence. It supplies `open`, `progress` and `message`; any of the three passed as a prop wins.","details":[],"examples":[]},{"name":"variant","optional":true,"type":"SplashScreenVariant","default":"'background'","bindable":false,"doc":"The colour scheme.","details":[],"examples":[]},{"name":"pattern","optional":true,"type":"SplashScreenPattern","default":"'none'","bindable":false,"doc":"The decorative layer over it.","details":[],"examples":[]},{"name":"size","optional":true,"type":"SplashScreenSize","default":"'md'","bindable":false,"doc":"Mark and type size.","details":[],"examples":[]},{"name":"align","optional":true,"type":"SplashScreenAlign","default":"'center'","bindable":false,"doc":"Where the block sits.","details":[],"examples":[]},{"name":"indicator","optional":true,"type":"SplashScreenIndicator","default":"'spinner'","bindable":false,"doc":"What loops while it is up.","details":[],"examples":[]},{"name":"exit","optional":true,"type":"SplashScreenExit","default":"'fade'","bindable":false,"doc":"How it leaves.","details":[],"examples":[]},{"name":"enter","optional":true,"type":"SplashScreenEnter","default":"'rise'","bindable":false,"doc":"How the content arrives.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"The app's name, under the mark.","details":[],"examples":[]},{"name":"description","optional":true,"type":"string","bindable":false,"doc":"One line under the title. Say what is happening, not \"Loading…\".","details":[],"examples":[]},{"name":"message","optional":true,"type":"string","bindable":false,"doc":"The line under the indicator. Changing it fades the new one in.","details":[],"examples":[]},{"name":"progress","optional":true,"type":"number","bindable":false,"doc":"How far along, 0–100. Left out, the indicator is indeterminate — which is the honest answer unless you really are counting something.","details":[],"examples":[]},{"name":"percent","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Show the percentage beside the bar. Only with a real `progress`.","details":[],"examples":[]},{"name":"simulate","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Move an indeterminate bar along on its own, up to about 90%.","details":["A lie, and a useful one: it says the app is working. It stops short of the end and only lands on 100 when the splash is actually done."],"examples":[]},{"name":"halo","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"A ring that pulses out of the logo. Costs nothing, reads as alive.","details":[],"examples":[]},{"name":"image","optional":true,"type":"string","bindable":false,"doc":"Background photograph, for `variant=\"image\"`.","details":[],"examples":[]},{"name":"minDuration","optional":true,"type":"number","default":"600","bindable":false,"doc":"The shortest time it may be on screen once shown, in ms. What stops a 40ms boot from flashing a splash at somebody.","details":[],"examples":[]},{"name":"appearAfter","optional":true,"type":"number","default":"0","bindable":false,"doc":"Wait this long before showing it at all, in ms. An app that becomes ready inside the delay never shows a splash — the best splash screen is the one nobody had to see.","details":[],"examples":[]},{"name":"duration","optional":true,"type":"number","default":"520","bindable":false,"doc":"How long the exit takes, in ms.","details":[],"examples":[]},{"name":"autoHide","optional":true,"type":"boolean | number","default":"true","bindable":false,"doc":"When an uncontrolled splash takes itself off: `true` waits for the page to finish loading, a number is a plain timeout in ms, `false` leaves it up until something sets `open`.","details":[],"examples":[]},{"name":"lockScroll","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Stop the page behind it scrolling while it is up.","details":[],"examples":[]},{"name":"portalTo","optional":true,"type":"PortalTarget","bindable":false,"doc":"Where the overlay is moved to. `null` keeps it where it is.","details":[],"examples":[]},{"name":"inline","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Inside its container instead of over the viewport.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"What a screen reader calls it.","details":[],"examples":[]},{"name":"onhide","optional":true,"type":"() => void","bindable":false,"doc":"The exit has started.","details":[],"examples":[]},{"name":"onhidden","optional":true,"type":"() => void","bindable":false,"doc":"The splash is off screen and out of the DOM.","details":[],"examples":[]},{"name":"logo","optional":true,"type":"Snippet","bindable":false,"doc":"The mark. An `<img>`, an inline `<svg>`, anything.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Extra content between the words and the indicator.","details":[],"examples":[]},{"name":"actions","optional":true,"type":"Snippet","bindable":false,"doc":"Buttons — a \"Retry\" for a boot that failed, usually.","details":[],"examples":[]},{"name":"footer","optional":true,"type":"Snippet","bindable":false,"doc":"Pinned to the bottom edge: version, byline, legal line.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"SplashScreenClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"SplitButton","dir":"split-button","entry":"omaris","importPath":"import { SplitButton } from 'omaris'","summary":"MD3 Expressive split button.","details":["One button doing two jobs: the wide half runs the default action, the narrow half opens the rest. Both halves share a fill and tone, and the chevron rotates while the menu is open — the MD3 Expressive detail that tells you which half you just pressed."],"examples":[],"classesType":"SplitButtonClasses","parts":[{"name":"action","doc":"The wide half that runs the default action."},{"name":"trigger","doc":"The narrow half that opens the menu."},{"name":"chevron","doc":""}],"variants":[{"name":"open","doc":"","default":"false","values":[{"name":"true","doc":""}]}],"story":{"title":"Actions/Split Button","category":"Actions","own":true,"stories":["Playground","Variants","Sizes","With an icon","States"]},"props":[{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Label of the main action.","details":[],"examples":[]},{"name":"variant","optional":true,"type":"ButtonVariant","default":"'filled'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"tone","optional":true,"type":"ButtonTone","default":"'primary'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"ButtonSize","default":"'sm'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"loading","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"open","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Menu open state. Bindable.","details":[],"examples":[]},{"name":"side","optional":true,"type":"AnchorSide","default":"'bottom'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"align","optional":true,"type":"AnchorAlign","default":"'end'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"menuLabel","optional":true,"type":"string","default":"'More actions'","bindable":false,"doc":"Accessible name for the half that opens the menu.","details":[],"examples":[]},{"name":"onclick","optional":true,"type":"(event: MouseEvent) => void","bindable":false,"doc":"The default action.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"SplitButtonClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"icon","optional":true,"type":"Snippet","bindable":false,"doc":"Leading icon on the main half.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Rich label, in place of `label`.","details":[],"examples":[]},{"name":"menu","optional":true,"type":"Snippet","bindable":false,"doc":"The menu's items.","details":[],"examples":[]}]},{"name":"StatCard","dir":"stat-card","entry":"omaris","importPath":"import { StatCard } from 'omaris'","summary":"The KPI tile every dashboard opens with: a label, one number, and how that number moved.","details":["It is a `Card` underneath — the same three surfaces, the same sizes, and the same rule for becoming pressable: give it `href` or `onclick` and the whole tile is one target, with the state layer, the ripple and a press that gives a little under the finger.","`delta` is a **fraction**, the way a ratio comes out of arithmetic: `0.124` is +12.4%, `-0.03` is −3%. The arrow and the colour come from its sign, and `invert` is for the metrics where down is the good news — churn, refunds, response time.","Charts are not imported here, so the main entry stays light. Put a `Sparkline` from `omaris/chart` in the `chart` snippet and it spans the bottom of the tile."],"examples":[{"lang":"svelte","code":"<StatCard label=\"Revenue\" value={48210} format={{ style: 'currency', currency: 'USD' }}\n  delta={0.124} deltaLabel=\"vs last week\" />"}],"classesType":"StatCardClasses","parts":[{"name":"root","doc":""},{"name":"header","doc":"Label and value on the start side, the icon on the end."},{"name":"body","doc":""},{"name":"label","doc":""},{"name":"icon","doc":"The icon's tonal container."},{"name":"value","doc":""},{"name":"trend","doc":"Delta chip and its label."},{"name":"delta","doc":"The arrow and the percentage, on a tinted pill."},{"name":"deltaLabel","doc":""},{"name":"chart","doc":"Wraps the `chart` snippet; bleeds a little so a sparkline reaches the edges."},{"name":"footer","doc":""}],"variants":[{"name":"tone","doc":"","default":"primary","values":[{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""}]},{"name":"good","doc":"The movement is good news — up, or down with `invert`.","values":[{"name":"true","doc":""}]},{"name":"bad","doc":"The movement is bad news.","values":[{"name":"true","doc":""}]},{"name":"pressable","doc":"Wired up when the tile is a link or has `onclick`.","values":[]}],"story":{"title":"Data Display/Stat Card","category":"Data Display","own":true,"stories":["Playground","Trends","With chart","Loading","Interactive","Animated","Sizes","Overridden"]},"props":[{"name":"label","optional":true,"type":"string","bindable":false,"doc":"What is being measured — \"Revenue\", \"Active users\".","details":[],"examples":[]},{"name":"value","optional":true,"type":"string | number","bindable":false,"doc":"The figure. A number is formatted with `format` and `locale`, in Western digits whatever the locale; a string is shown as given, for a value you have already formatted (\"4m 12s\", \"—\").","details":[],"examples":[]},{"name":"format","optional":true,"type":"Intl.NumberFormatOptions","bindable":false,"doc":"`Intl.NumberFormat` options for a numeric `value` — currency, `notation: 'compact'`, fraction digits. The numbering system is pinned to Western digits on top of whatever you pass.","details":[],"examples":[]},{"name":"locale","optional":true,"type":"string","bindable":false,"doc":"BCP-47 tag for the value and the delta. Defaults to the runtime's.","details":[],"examples":[]},{"name":"delta","optional":true,"type":"number","bindable":false,"doc":"The change, as a fraction: `0.124` is +12.4%, `-0.03` is −3%. The arrow and the colour come from its sign; the chip shows its size.","details":[],"examples":[]},{"name":"deltaFormat","optional":true,"type":"Intl.NumberFormatOptions","bindable":false,"doc":"How `delta` is written. Defaults to a percentage with at most one fraction digit. Pass `{ style: 'decimal' }` for a delta that is a count rather than a ratio (\"+3 orders\").","details":[],"examples":[]},{"name":"deltaLabel","optional":true,"type":"string","bindable":false,"doc":"What the delta is measured against — \"vs last week\".","details":[],"examples":[]},{"name":"trend","optional":true,"type":"StatCardTrend","bindable":false,"doc":"Which way it moved. Derived from the sign of `delta`; set it for a trend you know without a delta to show.","details":[],"examples":[]},{"name":"invert","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Down is the good direction — churn, refunds, latency. Swaps which trend is coloured as success and which as destructive; the arrow still points the way the number went.","details":[],"examples":[]},{"name":"variant","optional":true,"type":"CardVariant","default":"'outlined'","bindable":false,"doc":"Card surface, as on `Card`.","details":[],"examples":[]},{"name":"size","optional":true,"type":"CardSize","default":"'md'","bindable":false,"doc":"Padding, gap and radius, as on `Card`; the value's type role steps with it.","details":[],"examples":[]},{"name":"tone","optional":true,"type":"Tone","default":"'primary'","bindable":false,"doc":"The icon container's colour role.","details":[],"examples":[]},{"name":"loading","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Swap the value, the delta and the chart for skeletons. The label stays, since you know it already, and the tile keeps its height.","details":[],"examples":[]},{"name":"animate","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Count up to a numeric `value` on mount, and tween between values as it changes. Off by default, and skipped entirely under reduced motion.","details":[],"examples":[]},{"name":"ripple","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Ripple on press. Pressable tiles only.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"StatCardClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"icon","optional":true,"type":"Snippet","bindable":false,"doc":"An icon, drawn in a tonal square at the top end of the tile.","details":[],"examples":[]},{"name":"chart","optional":true,"type":"Snippet","bindable":false,"doc":"A chart along the bottom — a `Sparkline` from `omaris/chart`.","details":[],"examples":[]},{"name":"footer","optional":true,"type":"Snippet","bindable":false,"doc":"A last line — a link to the report, when the figure was updated.","details":[],"examples":[]},{"name":"shape","optional":true,"type":"ButtonShape","bindable":false,"doc":"Pill (`round`) or MD3 rounded rectangle (`square`).","details":[],"examples":[]},{"name":"confetti","optional":true,"type":"boolean | ConfettiOptions","bindable":false,"doc":"Confetti on press. `true` for the default burst, or any `ConfettiOptions` — `confetti={{ preset: 'fireworks' }}`.","details":[],"examples":[]},{"name":"toggle","optional":true,"type":"boolean","bindable":false,"doc":"Turns the button into a two-state toggle driven by `pressed`. Ignored when `href` is set — a link has no pressed state.","details":[],"examples":[]},{"name":"pressed","optional":true,"type":"boolean","bindable":true,"doc":"Selected state of a toggle button. Bindable.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"StatusIncident","dir":"status-page","entry":"omaris","importPath":"import { StatusIncident } from 'omaris'","summary":"One incident, and the thread of updates under it.","details":["Newest first, because the question is always \"what is happening now\" and the answer to it should not be at the bottom of a scroll. The older updates stay, in order, because the second question is \"how long has this been going on\" — and a status page that overwrites its own history every twenty minutes cannot answer either one afterwards."],"examples":[],"classesType":"StatusIncidentClasses","parts":[{"name":"root","doc":""},{"name":"header","doc":""},{"name":"title","doc":"`basis` so the row actually wraps. `flex-1` alone is a basis of zero, so on a phone the badge and the timestamp keep their width and the headline takes what is left — which was 130px, and an incident title read three words down a column. Below 12rem the two of them drop to a line of their own instead."},{"name":"stage","doc":"The badge saying how far along it is."},{"name":"when","doc":""},{"name":"scope","doc":"The affected services, listed under the title."},{"name":"chip","doc":""},{"name":"updates","doc":"The thread. The rule down the left is drawn by the items."},{"name":"update","doc":"One update. The line and the node are `before`/`after` on the item itself, so the thread is one element per update rather than an element per update plus an element per connector."},{"name":"updateHead","doc":""},{"name":"updateStage","doc":""},{"name":"updateWhen","doc":""},{"name":"body","doc":""}],"variants":[{"name":"muted","doc":"A resolved incident is history; it should not shout from the page.","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Data Display/Status Page","category":"Data Display","own":false,"stories":["Playground","A whole page","Every level","Emphasis","Indicators","A service on its own","An incident in progress","Overridden"]},"props":[{"name":"title","optional":false,"type":"string","bindable":false,"doc":"What happened, in a line.","details":[],"examples":[]},{"name":"level","optional":true,"type":"StatusLevel","default":"'major'","bindable":false,"doc":"How bad it was. Colours the title's marker.","details":[],"examples":[]},{"name":"startedAt","optional":true,"type":"Date | string","bindable":false,"doc":"When it started.","details":[],"examples":[]},{"name":"services","optional":true,"type":"string[]","default":"[]","bindable":false,"doc":"What it affected.","details":[],"examples":[]},{"name":"updates","optional":true,"type":"IncidentUpdate[]","default":"[]","bindable":false,"doc":"The thread. Given oldest first or newest first; it is sorted.","details":[],"examples":[]},{"name":"muted","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Dim it — for a resolved incident in a history list.","details":[],"examples":[]},{"name":"locale","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Replaces the update thread.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"StatusIncidentClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"StatusIndicator","dir":"status-page","entry":"omaris","importPath":"import { StatusIndicator } from 'omaris'","summary":"A dot, and what it means.","details":["The dot alone is the thing everybody draws and nobody can read: green and amber are the same dot to a good share of people looking at it, and a page whose entire message is a colour has no message for them. So the label ships by default and `label={false}` is the deliberate choice, with the state still readable to a screen reader either way.","A live state pulses. Not for decoration — a page left open on a wall is the normal way this is read, and the pulse is what says the page is still watching rather than frozen on an old render."],"examples":[],"classesType":"StatusIndicatorClasses","parts":[{"name":"root","doc":""},{"name":"dot","doc":"The dot itself, with a halo that beats out when `pulse` is on."},{"name":"label","doc":""}],"variants":[{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""}]},{"name":"pulse","doc":"","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Data Display/Status Page","category":"Data Display","own":false,"stories":["Playground","A whole page","Every level","Emphasis","Indicators","A service on its own","An incident in progress","Overridden"]},"props":[{"name":"level","optional":false,"type":"StatusLevel","bindable":false,"doc":"","details":[],"examples":[]},{"name":"label","optional":true,"type":"string | false","bindable":false,"doc":"The words beside the dot. `false` hides them, a string replaces them.","details":[],"examples":[]},{"name":"size","optional":true,"type":"StatusIndicatorSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"pulse","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Beat the halo — for a page that is watching a live feed.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"StatusIndicatorClasses","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"StatusPage","dir":"status-page","entry":"omaris","importPath":"import { StatusPage } from 'omaris'","summary":"The page itself: one sentence at the top, and everything else under it.","details":["The banner is the whole design. Someone opening a status page has one question and about two seconds of patience for it, so the answer is the largest thing on the screen, in a colour, with an icon that says the same thing for anyone the colour doesn't reach — and `worstStatus()` computes it, because the overall state of a system is its worst part, never its average.","The time it was last checked sits under that. A status page with no timestamp is a status page nobody can tell from a broken one."],"examples":[{"lang":"svelte","code":"<StatusPage level={worstStatus(services.map((s) => s.level))} updatedAt={new Date()}>\n  {#each services as service}\n    <StatusService {...service} />\n  {/each}\n</StatusPage>"}],"classesType":"StatusPageClasses","parts":[{"name":"root","doc":""},{"name":"banner","doc":"The headline panel."},{"name":"mark","doc":"The icon disc."},{"name":"headline","doc":""},{"name":"title","doc":""},{"name":"updated","doc":"\"Checked 2 minutes ago\"."},{"name":"actions","doc":"Buttons on the right of the banner."},{"name":"section","doc":"A section — the services, the incident history."},{"name":"sectionHeader","doc":""},{"name":"sectionTitle","doc":""},{"name":"group","doc":"The stack of services, with a hairline between rows."},{"name":"timeline","doc":"The stack of incidents."},{"name":"empty","doc":"Shown where a section has nothing in it — the good outcome, usually."}],"variants":[{"name":"emphasis","doc":"How loudly the banner is drawn.","default":"tonal","values":[{"name":"tonal","doc":"Tinted panel. The default: readable across a room."},{"name":"solid","doc":"The accent at full strength — for a wallboard."},{"name":"quiet","doc":"A hairline and a dot. For a status strip inside an app."}]}],"story":{"title":"Data Display/Status Page","category":"Data Display","own":true,"stories":["Playground","A whole page","Every level","Emphasis","Indicators","A service on its own","An incident in progress","Overridden"]},"props":[{"name":"level","optional":false,"type":"StatusLevel","bindable":false,"doc":"The one thing the page says. `worstStatus()` computes it from the parts.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"Replaces the sentence the level would otherwise write.","details":[],"examples":[]},{"name":"updatedAt","optional":true,"type":"Date | string","bindable":false,"doc":"When the numbers were last true.","details":[],"examples":[]},{"name":"updatedLabel","optional":true,"type":"string","bindable":false,"doc":"Replaces \"Checked <time>\".","details":[],"examples":[]},{"name":"emphasis","optional":true,"type":"StatusPageEmphasis","default":"'tonal'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"locale","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"actions","optional":true,"type":"Snippet","bindable":false,"doc":"Buttons on the right of the banner — subscribe, refresh, history.","details":[],"examples":[]},{"name":"banner","optional":true,"type":"Snippet","bindable":false,"doc":"Replaces the whole banner.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Everything under it: services, incidents, whatever else.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"StatusPageClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"StatusService","dir":"status-page","entry":"omaris","importPath":"import { StatusService } from 'omaris'","summary":"One service, and the last however many days of it.","details":["The bar is the part that matters. A status page that shows only today answers \"is it working now\" and nothing else; the history is what answers \"is it usually working\", which is the question anyone reading a status page actually has.","How many days fit is measured, not guessed: the track counts how many bars it can draw at a readable width and shows that many of the most recent, so the same component is ninety days on a dashboard and three weeks on a phone without a breakpoint anywhere."],"examples":[{"lang":"svelte","code":"<StatusService name=\"API\" level=\"operational\" history={days} />"}],"classesType":"StatusServiceClasses","parts":[{"name":"root","doc":""},{"name":"header","doc":"Name on the left, current state on the right."},{"name":"name","doc":""},{"name":"description","doc":""},{"name":"state","doc":""},{"name":"track","doc":"The row of bars."},{"name":"bar","doc":"One day."},{"name":"readout","doc":"The hovered day's detail, floating over the track."},{"name":"legend","doc":"\"90 days ago — 99.98% uptime — Today\"."},{"name":"legendRule","doc":""},{"name":"uptime","doc":""}],"variants":[{"name":"density","doc":"","default":"comfortable","values":[{"name":"comfortable","doc":""},{"name":"compact","doc":""}]}],"story":{"title":"Data Display/Status Page","category":"Data Display","own":false,"stories":["Playground","A whole page","Every level","Emphasis","Indicators","A service on its own","An incident in progress","Overridden"]},"props":[{"name":"name","optional":false,"type":"string","bindable":false,"doc":"What the service is called.","details":[],"examples":[]},{"name":"description","optional":true,"type":"string","bindable":false,"doc":"A line under it — what it covers, or which region.","details":[],"examples":[]},{"name":"level","optional":true,"type":"StatusLevel","bindable":false,"doc":"How it is right now. Defaults to the most recent point's level.","details":[],"examples":[]},{"name":"history","optional":true,"type":"StatusPoint[]","default":"[]","bindable":false,"doc":"Oldest first. Anything that does not fit is dropped from the front.","details":[],"examples":[]},{"name":"uptime","optional":true,"type":"number","bindable":false,"doc":"Uptime to print, `0`–`100`. Computed from `history` when left out — pass it when the real number comes from somewhere with more data than the bars are showing.","details":[],"examples":[]},{"name":"legend","optional":true,"type":"string | false","bindable":false,"doc":"The words under the bar. `false` drops the whole legend row.","details":[],"examples":[]},{"name":"labels","optional":true,"type":"{ state?: string | false; uptime?: string; today?: string }","bindable":false,"doc":"The words the row writes for itself, for a page that is not in English: the state beside the dot, and the two fixed words in the legend. One prop rather than three, because they are always replaced together — a row that says \"جاهزية\" and \"Today\" is worse than either. `state: false` leaves the dot alone, with the state still read out to a screen reader.","details":[],"examples":[]},{"name":"minBarWidth","optional":true,"type":"number","default":"4","bindable":false,"doc":"How thin the bars may get before older days are dropped, in px.","details":[],"examples":[]},{"name":"density","optional":true,"type":"StatusServiceDensity","default":"'comfortable'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"locale","optional":true,"type":"string","bindable":false,"doc":"Locale for the dates and the percentage.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Extra content under the legend — a link to the region's own page.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"StatusServiceClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"Stepper","dir":"stepper","entry":"omaris","importPath":"import { Stepper } from 'omaris'","summary":"Wizard progress — where you are in a checkout, an onboarding, a form too long for one screen.","details":["Shaped like `Tabs`: the parent holds the position, each `StepperItem` is one step, and the order they are written in is the order they go in. `bind:step` is the index; the content under the stepper is yours to switch on it, so a step's form can live wherever the page wants it.","`linear` (the default) is the checkout rule: steps behind you can be revisited, steps ahead cannot be skipped to. Turn it off for a set of sections that can be filled in any order.","A horizontal stepper narrower than 36rem does not squeeze its titles until they truncate — it collapses to \"Step 2 of 4 · Payment\" over a progress bar. That is a container query, so a stepper in a narrow dialog on a wide screen collapses too."],"examples":[{"lang":"svelte","code":"<Stepper bind:step label=\"Checkout\">\n  <StepperItem title=\"Shipping\" />\n  <StepperItem title=\"Payment\" />\n  <StepperItem title=\"Review\" />\n</Stepper>"}],"classesType":"StepperClasses","parts":[{"name":"root","doc":""},{"name":"list","doc":"The `<ol>` of steps."},{"name":"compact","doc":"The collapsed \"Step 2 of 4\" view of a narrow horizontal stepper."},{"name":"summary","doc":"\"Step 2 of 4 · Payment\"."},{"name":"next","doc":"\"Next: Review\", at the end of the summary line."},{"name":"progress","doc":""}],"variants":[{"name":"orientation","doc":"","default":"horizontal","values":[{"name":"horizontal","doc":""},{"name":"vertical","doc":""}]},{"name":"collapse","doc":"","default":"true","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Navigation/Stepper","category":"Navigation","own":true,"stories":["Playground","States","Vertical","Non-linear","Collapsed","Overridden"]},"props":[{"name":"step","optional":true,"type":"number","default":"0","bindable":true,"doc":"The current step's index, from 0. Bindable. Set it to the number of steps to mark every one complete — the wizard is finished.","details":[],"examples":[]},{"name":"orientation","optional":true,"type":"'horizontal' | 'vertical'","default":"'horizontal'","bindable":false,"doc":"A row across the top, or a column with each step's content under it.","details":[],"examples":[]},{"name":"linear","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Steps behind the current one can be revisited; steps ahead cannot be skipped to. Off, any step can be picked at any time.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","default":"'Progress'","bindable":false,"doc":"Accessible name for the list of steps — \"Checkout\".","details":[],"examples":[]},{"name":"collapse","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Let a horizontal stepper narrower than 36rem collapse to \"Step 2 of 4 · Title\" over a progress bar. Off, it stays a row and its titles truncate.","details":[],"examples":[]},{"name":"counter","optional":true,"type":"(step: number, total: number) => string","default":"(current, total) => `Step ${current} of ${total}`","bindable":false,"doc":"How the collapsed view counts: `(2, 4) => 'Step 2 of 4'`.","details":[],"examples":[]},{"name":"upNext","optional":true,"type":"(title: string) => string","default":"(title) => `Next: ${title}`","bindable":false,"doc":"How the collapsed view names what comes next: `'Review' => 'Next: Review'`.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"StepperClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"The `StepperItem`s.","details":[],"examples":[]}]},{"name":"StepperItem","dir":"stepper","entry":"omaris","importPath":"import { StepperItem } from 'omaris'","summary":"One step of a `Stepper`: a numbered indicator, a title, and the line to the next step, which fills in as the step is completed.","details":["Its state is worked out from where it sits: before the current step it is complete, at it current, after it upcoming. `error` overrides all three, and `complete` marks a step done out of order in a non-linear stepper.","In a vertical stepper, `children` is the step's content, opened under the current step and closed under the others — mounted throughout, so a half-filled form survives being stepped away from."],"examples":[],"classesType":"StepperItemClasses","parts":[{"name":"root","doc":""},{"name":"step","doc":"The pressable part: indicator, title and description."},{"name":"indicator","doc":"The numbered circle. Its look follows the step's `data-state`, so the same selectors are there for a consumer's own styling."},{"name":"body","doc":""},{"name":"title","doc":""},{"name":"description","doc":""},{"name":"connector","doc":"The line to the next step."},{"name":"fill","doc":"The part of the line that fills in as the step completes."},{"name":"content","doc":"Vertical only: the step's content, opened while it is current."}],"variants":[{"name":"vertical","doc":"Set from the `Stepper`'s orientation.","default":"false","values":[{"name":"false","doc":""},{"name":"true","doc":""}]},{"name":"clickable","doc":"Whether pressing the step goes to it.","values":[{"name":"true","doc":""}]},{"name":"filled","doc":"The line after this step is filled.","values":[{"name":"true","doc":""}]},{"name":"open","doc":"","values":[{"name":"true","doc":""}]}],"story":{"title":"Navigation/Stepper","category":"Navigation","own":false,"stories":["Playground","States","Vertical","Non-linear","Collapsed","Overridden"]},"props":[{"name":"title","optional":false,"type":"string","bindable":false,"doc":"The step's name — \"Shipping\". Also what the collapsed view shows.","details":[],"examples":[]},{"name":"description","optional":true,"type":"string","bindable":false,"doc":"A line under the title — \"Where it's going\".","details":[],"examples":[]},{"name":"error","optional":true,"type":"boolean | string","default":"false","bindable":false,"doc":"Something is wrong with this step: the indicator turns destructive and says so. A string is shown in place of the description.","details":[],"examples":[]},{"name":"complete","optional":true,"type":"boolean","bindable":false,"doc":"Mark the step done regardless of where the stepper is — a section of a non-linear form filled in out of order. Leave it unset and the position decides.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"The step cannot be picked, even when the stepper would allow it.","details":[],"examples":[]},{"name":"completeLabel","optional":true,"type":"string","default":"'completed'","bindable":false,"doc":"Spoken after a completed step's title.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"StepperItemClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"icon","optional":true,"type":"Snippet","bindable":false,"doc":"An icon in place of the step's number. A completed step still shows its tick.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Vertical only: the step's content, opened while it is the current step.","details":[],"examples":[]}]},{"name":"SwipeItem","dir":"list","entry":"omaris","importPath":"import { SwipeItem } from 'omaris'","summary":"A row you can swipe aside to get at its actions.","details":["Wrap anything — a `ListItem`, a `Card`, a table row — and it gains the gesture every mail app has: drag it away from either edge and the actions underneath are revealed, let go halfway and it snaps open, throw it and it opens or closes on its own. With `fullSwipe`, carrying the row clear across fires the first action without a second press.","Only one row is open at a time, anywhere on the page — opening this one closes the last, which is what keeps a long list from turning into a column of half-open drawers.","An action marked `dismiss` plays the row out: it slides clear, the height collapses, and only then does the callback run, so the list can drop the record while the space is already closing.","It lands like a thrown thing: letting go hands the release velocity to a critically damped spring, so the row keeps the speed it had under the finger and settles with no kink and no bounce. A trackpad's two-finger swipe is the same gesture, and a tap on an open row closes it, the way every mail app does.","An action fires on the press coming up rather than on the click the browser makes of it, so a tap that lands straight after the swipe works the first time instead of the second.","It works without a pointer: the row answers the arrow keys (the leading pane on <kbd>ArrowRight</kbd> in a left-to-right document, the trailing one on <kbd>ArrowLeft</kbd>, <kbd>Escape</kbd> to close), focus moves into the pane as it opens, and while the row is closed its actions are `inert` so they stay out of the tab order."],"examples":[],"classesType":"SwipeItemClasses","parts":[{"name":"clip","doc":""},{"name":"actions","doc":"The actions as one block — what the row opens far enough to show."},{"name":"action","doc":""},{"name":"row","doc":"The part that actually moves."}],"variants":[{"name":"side","doc":"","values":[{"name":"start","doc":""},{"name":"end","doc":""}]},{"name":"labels","doc":"Icon only, for a row too short to carry a label under one.","default":"true","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Containment/Swipe Item","category":"Containment","own":true,"stories":["Playground","Icons only","Cards","Custom pane"]},"props":[{"name":"startActions","optional":true,"type":"SwipeAction[]","default":"[]","bindable":false,"doc":"Actions behind the leading edge — swiping toward the end reveals them.","details":[],"examples":[]},{"name":"endActions","optional":true,"type":"SwipeAction[]","default":"[]","bindable":false,"doc":"Actions behind the trailing edge.","details":[],"examples":[]},{"name":"fullSwipe","optional":true,"type":"boolean | SwipeSide","default":"false","bindable":false,"doc":"Let a swipe clear across the row fire that side's first action with no second press. `true` arms both edges.","details":[],"examples":[]},{"name":"fullSwipeThreshold","optional":true,"type":"number","default":"0.55","bindable":false,"doc":"Fraction of the row a full swipe has to cross.","details":[],"examples":[]},{"name":"labels","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Draw the labels under the icons.","details":[],"examples":[]},{"name":"open","optional":true,"type":"SwipeSide | null","default":"null","bindable":true,"doc":"Which side is showing. Bindable — set it to open or close the row.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onopen","optional":true,"type":"(side: SwipeSide | null) => void","bindable":false,"doc":"Fires when the row settles open or closed.","details":[],"examples":[]},{"name":"ondismiss","optional":true,"type":"() => void","bindable":false,"doc":"Fires once a dismissing action has played out and the row has collapsed.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"SwipeItemClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":["`classes.row` is the one people reach for: the moving row needs an opaque background or the actions behind it show through, so a list on a tinted surface has to restate it."],"examples":[]},{"name":"start","optional":true,"type":"Snippet","bindable":false,"doc":"Custom leading pane, in place of `startActions`.","details":[],"examples":[]},{"name":"end","optional":true,"type":"Snippet","bindable":false,"doc":"Custom trailing pane, in place of `endActions`.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"Switch","dir":"switch","entry":"omaris","importPath":"import { Switch } from 'omaris'","summary":"MD3 switch.","details":["The MD3 details that make it feel alive: the handle is small when off and grows when on, it swells while pressed, an MD3 state layer haloes it on hover/press, and the optional check/cross icon rides inside it.","Everything that moves animates `translate` and `scale` only — never `justify-content` (which doesn't interpolate, so the handle used to jump) and never `width`/`height` (which relayout mid-gesture and stutter on touch). Both are compositor properties, so the whole thing stays smooth on a phone. It's still pure CSS off a checkbox input, so keyboard and form behaviour come free."],"examples":[],"classesType":"SwitchClasses","parts":[{"name":"root","doc":""},{"name":"track","doc":"The track."},{"name":"handle","doc":"The slot the knob travels in. Always the full \"on\" handle size, so the only thing that changes is `translate` — no layout, no jump."},{"name":"state","doc":"The MD3 state layer, haloing the knob on hover and press."},{"name":"knob","doc":"The knob itself — the only thing that scales."},{"name":"input","doc":""},{"name":"icon","doc":""},{"name":"label","doc":""},{"name":"description","doc":""}],"variants":[{"name":"tone","doc":"","default":"primary","values":[{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""}]},{"name":"size","doc":"","default":"md","values":[{"name":"md","doc":""},{"name":"lg","doc":""}]},{"name":"checked","doc":"","values":[{"name":"true","doc":""},{"name":"false","doc":""}]},{"name":"disabled","doc":"","values":[{"name":"true","doc":""},{"name":"false","doc":""}]},{"name":"icons","doc":"","values":[{"name":"true","doc":""}]}],"story":{"title":"Selection/Switch","category":"Selection","own":true,"stories":["Playground","States","Sizes","With icons","Tones","Settings rows"]},"props":[{"name":"tone","optional":true,"type":"SwitchTone","default":"'primary'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"SwitchSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"checked","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Bindable.","details":[],"examples":[]},{"name":"icons","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Draw a tick (on) and a cross (off) inside the handle.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"description","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"labelPosition","optional":true,"type":"'start' | 'end'","default":"'end'","bindable":false,"doc":"Put the label before the switch — the settings-row layout.","details":[],"examples":[]},{"name":"haptics","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"A haptic tap when it flips. Follows the shared `haptics` store; `false` opts this switch out.","details":[],"examples":[]},{"name":"sound","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"A sound cue when it flips. Follows the shared `sound` store; `false` opts this switch out.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"SwitchClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]},{"name":"ref","optional":true,"type":"HTMLInputElement | null","default":"null","bindable":true,"doc":"","details":[],"examples":[]}]},{"name":"Tab","dir":"tabs","entry":"omaris","importPath":"import { Tab } from 'omaris'","summary":"One tab in a `TabList`. Its `value` names the `TabPanel` it opens.","details":[],"examples":[],"classesType":null,"parts":[],"variants":[{"name":"variant","doc":"","default":"primary","values":[{"name":"primary","doc":"Icon over label, MD3's top-level tab."},{"name":"secondary","doc":"Icon beside label, for a tab set nested in a page."}]},{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""}]},{"name":"stacked","doc":"Icon above the label rather than beside it.","values":[{"name":"true","doc":""}]}],"story":{"title":"Navigation/Tabs","category":"Navigation","own":false,"stories":["Playground","Primary and secondary","With icons","With badges","Fitted","Vertical","Scrollable","Disabled tab","Swipeable"]},"props":[{"name":"value","optional":false,"type":"string","bindable":false,"doc":"Identifies the tab, and the panel it controls.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Label text. Use children for rich content.","details":[],"examples":[]},{"name":"stacked","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Stack the icon above the label — MD3's two-line primary tab.","details":[],"examples":[]},{"name":"badge","optional":true,"type":"Snippet","bindable":false,"doc":"A count or dot rendered after the label.","details":[],"examples":[]},{"name":"icon","optional":true,"type":"Snippet","bindable":false,"doc":"Leading icon.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"Table","dir":"table","entry":"omaris","importPath":"import { Table } from 'omaris'","summary":"Data table.","details":["Driven by a `columns` array rather than markup, because that's what a dashboard table actually is — the same header/cell/alignment decisions repeated per column. Each column can still take over its own cell with a snippet, so the data-driven path never becomes a ceiling.","Everything above and below the rows is opt-in, comes wired up, and is one prop rather than a run of four. Passing the prop is what turns the feature on:","That is a table with a working search box, a checkbox column and a pager, holding all three states itself — no `$state` and no `$derived` in your page. Mark a column `sortable` and it sorts too.","Each feature takes an object when you need more from it, always in the same shape: the current state, `manual` if the caller handles that stage, and one `onchange`.","Filters keep the toolbar to one line however many of them there are: each is a chip carrying what you picked — \"Status · paid\" — with its options behind a menu, and every option carries the count it would leave you with. Past the width of the bar the chips scroll sideways rather than wrapping into a second and third row. A filter marked `inline` puts its options in the bar as toggles instead, for the one filter on a screen worth a press rather than two.","When the data lives on a server, `manual` on a feature hands that stage back — the table reports what was asked for through that feature's own `onchange` and renders the rows you give it. `pagination.total` is the row count behind the page.","Every feature is uncontrolled by default and controllable with `bind:` or `onchange` — reach for either only when the page needs to know.","It looks like a spreadsheet by default — `variant=\"grid\"`, every cell ruled, a white page for the rows inside a tinted frame — and reads like one when asked: `group` spans a header over neighbouring columns, `summary` totals a column, `rowNumbers` numbers the rows, `fullscreen` lets it take the screen.","And `<Table {rows} />` with nothing else reads its columns off the rows."],"examples":[{"lang":"svelte","code":"<Table {columns} {rows} search selection pagination={20} />"},{"lang":"svelte","code":"<Table {columns} {rows}\n  search={{ placeholder: 'Find an order…' }}\n  pagination={{ size: 20, sizeOptions: [10, 20, 50] }}\n  selection={{ onchange: (keys) => (picked = keys) }}\n/>"},{"lang":"svelte","code":"<Table {columns} rows={page.orders}\n  sorting={{ manual: true, onchange: load }}\n  pagination={{ manual: true, total: page.count, onchange: load }}\n/>"},{"lang":"svelte","code":"<Table rows={accounts} rowNumbers fullscreen columns={[\n  { key: 'name', header: 'Name' },\n  { key: 'usdDebit', header: 'Debit', group: 'USD', format: 'decimal', summary: 'sum' },\n  { key: 'usdCredit', header: 'Credit', group: 'USD', format: 'decimal', summary: 'sum' }\n]} />"}],"classesType":"TableClasses","parts":[{"name":"root","doc":""},{"name":"toolbar","doc":"Search, filters and actions, above the header."},{"name":"search","doc":"The search box. Its own line on a phone, beside the filters above one."},{"name":"filterBar","doc":"The filter chips. One line that scrolls sideways rather than a block that wraps — a toolbar that grows a second and third row as filters are added is the thing this bar is built not to do. The strip fades at whichever edge it continues past, so a filter scrolled out of the bar still says that it is there — `data-fade` names one edge at a time, so exactly one of these ever applies."},{"name":"toolbarActions","doc":"The trailing edge: the selection count, the column menu, `actions`."},{"name":"scroller","doc":"Scroll container — a wide table scrolls, the page doesn't."},{"name":"table","doc":""},{"name":"head","doc":""},{"name":"headRow","doc":""},{"name":"headCell","doc":""},{"name":"groupCell","doc":"The spanning header over a run of columns that share a `group`."},{"name":"sorter","doc":"The sort control inside a sortable header cell."},{"name":"body","doc":""},{"name":"row","doc":""},{"name":"cell","doc":""},{"name":"pick","doc":"The checkbox column, when rows are selectable."},{"name":"rowNumber","doc":"The `#` column, when `rowNumbers` is on."},{"name":"empty","doc":"The full-width message shown in place of rows."},{"name":"foot","doc":"The summary row, and any rows the `foot` snippet adds."},{"name":"footCell","doc":"A cell of the summary row. The `foot` snippet is handed this too."},{"name":"footer","doc":"Pagination and the row count, under the table."},{"name":"caption","doc":""}],"variants":[{"name":"variant","doc":"","default":"grid","values":[{"name":"plain","doc":""},{"name":"surface","doc":""},{"name":"outlined","doc":"A clean white page for the rows, framed by a tinted header and footer — the eye finds where the data starts without a rule."},{"name":"grid","doc":"The spreadsheet: every cell ruled, the way a sheet reads — you follow a figure down its column and across its row without losing the line. Separate borders rather than collapsed, so a sticky header carries its rules with it as the body scrolls."}]},{"name":"density","doc":"","default":"compact","values":[{"name":"compact","doc":""},{"name":"comfortable","doc":""},{"name":"spacious","doc":""}]},{"name":"striped","doc":"","values":[{"name":"true","doc":""}]},{"name":"hoverable","doc":"","default":"true","values":[{"name":"true","doc":""}]},{"name":"sticky","doc":"Header stays put while the body scrolls under it.","values":[{"name":"true","doc":""}]},{"name":"interactive","doc":"","values":[{"name":"true","doc":""}]},{"name":"framed","doc":"The chrome sits inside the frame when the table has one, on a tint a step down from the rows — toolbar, header, summary and pager read as the frame, the white between them as the data.","values":[{"name":"true","doc":""}]},{"name":"expanded","doc":"Filling the screen: the frame becomes the page, the rows take the rest.","values":[{"name":"true","doc":""}]}],"story":{"title":"Data Display/Table","category":"Data Display","own":true,"stories":["Playground","Custom cells","Zero config","Sortable","A column with gaps","Everything","Filters","Busy toolbar","On a phone","Server-side","Density","Striped and clickable","Loading","Empty","Sticky header","Spreadsheet","Just rows","Full screen open"]},"props":[{"name":"columns","optional":true,"type":"TableColumn<T>[]","bindable":false,"doc":"What to show and how. Leave it out and the columns are read off the first row — every field, a readable header, all sortable.","details":[],"examples":[]},{"name":"rows","optional":false,"type":"T[]","bindable":false,"doc":"","details":[],"examples":[]},{"name":"variant","optional":true,"type":"TableVariant","default":"'grid'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"density","optional":true,"type":"TableDensity","default":"'compact'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"striped","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"hoverable","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"sticky","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Pin the header. Pair with `maxHeight`.","details":[],"examples":[]},{"name":"maxHeight","optional":true,"type":"string","default":"'32rem'","bindable":false,"doc":"Height of the scroll area when `sticky`. Any CSS length.","details":[],"examples":[]},{"name":"rowKey","optional":true,"type":"(row: T, index: number) => Key","bindable":false,"doc":"Stable key per row. Falls back to the index.","details":[],"examples":[]},{"name":"sorting","optional":true,"type":"TableSorting","default":"undefined","bindable":true,"doc":"Current sort. Columns opt in with `sortable`, so this is state rather than a switch — leave it off and sortable columns still sort, the table just keeps the sort itself.","details":[],"examples":[]},{"name":"search","optional":true,"type":"boolean | TableSearch","default":"undefined","bindable":true,"doc":"The search box. Passing it at all is what puts it in the toolbar.","details":[],"examples":[]},{"name":"filtering","optional":true,"type":"TableFilter<T>[] | TableFiltering<T>","default":"undefined","bindable":true,"doc":"The filter bar. An array is the filters; the object form adds the picked state and an `onchange`. Options are derived from the rows when a filter doesn't list its own.","details":[],"examples":[]},{"name":"pagination","optional":true,"type":"boolean | number | TablePagination","default":"undefined","bindable":true,"doc":"Pagination. `true` takes the default page size, a number *is* the page size, and the object form carries the page, the rows-per-page choices and the server-side `total`.","details":[],"examples":[]},{"name":"selection","optional":true,"type":"boolean | TableSelection<Key>","default":"undefined","bindable":true,"doc":"Row selection. Passing it at all is what adds the checkbox column.","details":[],"examples":[]},{"name":"columnVisibility","optional":true,"type":"boolean | TableColumnVisibility","default":"undefined","bindable":true,"doc":"The column-visibility menu. Passing it at all is what adds it.","details":[],"examples":[]},{"name":"fullscreen","optional":true,"type":"boolean | TableFullscreen","default":"undefined","bindable":true,"doc":"A button that lets the table fill the screen, header pinned, for the moment a wide sheet needs every pixel. Escape comes back.","details":[],"examples":[]},{"name":"rowNumbers","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"A leading `#` column numbering the rows, the way a sheet does.","details":[],"examples":[]},{"name":"summaryLabel","optional":true,"type":"string","default":"'Total'","bindable":false,"doc":"Label of the summary row the columns' `summary` builds.","details":[],"examples":[]},{"name":"foot","optional":true,"type":"Snippet<[{ rows: T[]; cell: string; span: number }]>","bindable":false,"doc":"Extra rows under the summary — a net figure spanning two columns, say. Write `<tr>`s; `cell` is the class a footer cell takes, `rows` what the search and filters left, `span` the column count.","details":[],"examples":[]},{"name":"onrowclick","optional":true,"type":"(row: T, index: number) => void","bindable":false,"doc":"Called when a row is pressed. Makes rows interactive.","details":[],"examples":[]},{"name":"loading","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Draw skeletons while the data is on its way.","details":[],"examples":[]},{"name":"loadingRows","optional":true,"type":"number","default":"5","bindable":false,"doc":"","details":[],"examples":[]},{"name":"emptyText","optional":true,"type":"string","default":"'Nothing here yet'","bindable":false,"doc":"Message when there are no rows at all.","details":[],"examples":[]},{"name":"noResultsText","optional":true,"type":"string","default":"'No rows match your filters'","bindable":false,"doc":"Message when the filters or the search excluded everything.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible name for the table.","details":[],"examples":[]},{"name":"caption","optional":true,"type":"string","bindable":false,"doc":"Visible caption under the table.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"TableClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"actions","optional":true,"type":"Snippet","bindable":false,"doc":"Extra controls on the trailing edge of the toolbar.","details":[],"examples":[]},{"name":"selectionActions","optional":true,"type":"Snippet<[Key[]]>","bindable":false,"doc":"Replaces the toolbar's trailing edge while rows are selected.","details":[],"examples":[]},{"name":"empty","optional":true,"type":"Snippet","bindable":false,"doc":"Rich empty state, in place of `emptyText`.","details":[],"examples":[]}]},{"name":"TableFilterControl","dir":"table","entry":"omaris","importPath":"import { TableFilterControl } from 'omaris'","summary":"One filter in a table's toolbar.","details":["The default is a single chip with a menu behind it, because that is what keeps a toolbar to one line: every filter is the same object whatever its option list looks like, and the chip carries what you picked — \"Status · paid\", \"Status · 2\" — so the bar still reads as a summary of the query rather than a wall of toggles.","A filter marked `inline` lays its options out as toggle chips instead, for the one filter on a screen that is worth a press rather than two. Beyond a handful of options that trade stops paying, so the toggles fold back into the menu on their own.","Picked, the chip's chevron becomes a × — clearing one filter never means opening it first."],"examples":[],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Table","category":"Data Display","own":false,"stories":["Playground","Custom cells","Zero config","Sortable","A column with gaps","Everything","Filters","Busy toolbar","On a phone","Server-side","Density","Striped and clickable","Loading","Empty","Sticky header","Spreadsheet","Just rows","Full screen open"]},"props":[{"name":"label","optional":false,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"options","optional":false,"type":"TableFilterOption[]","bindable":false,"doc":"","details":[],"examples":[]},{"name":"selected","optional":false,"type":"string[]","default":"[]","bindable":true,"doc":"Bindable.","details":[],"examples":[]},{"name":"single","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"inline","optional":true,"type":"boolean","bindable":false,"doc":"Lay the options out as toggle chips rather than behind a menu.","details":[],"examples":[]},{"name":"format","optional":true,"type":"(value: string) => string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(selected: string[]) => void","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"TabList","dir":"tabs","entry":"omaris","importPath":"import { TabList } from 'omaris'","summary":"The row of tabs, and the indicator that slides between them.","details":["`scrollable` is the answer to a set too wide for the screen: one line that swipes, rather than tabs squeezed until their labels truncate."],"examples":[],"classesType":null,"parts":[],"variants":[],"story":{"title":"Navigation/Tabs","category":"Navigation","own":false,"stories":["Playground","Primary and secondary","With icons","With badges","Fitted","Vertical","Scrollable","Disabled tab","Swipeable"]},"props":[{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible name for the tab set.","details":[],"examples":[]},{"name":"divider","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Draw the hairline the indicator rides on.","details":[],"examples":[]},{"name":"scrollable","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"One line that scrolls sideways, for a set too wide to fit.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"TabPanel","dir":"tabs","entry":"omaris","importPath":"import { TabPanel } from 'omaris'","summary":"The content behind one tab. Its `value` must match that tab's.","details":["Panels unmount when hidden, which is what you want until it isn't — `keepMounted` keeps scroll position, form state and in-flight work alive. Inside a swipeable `TabPanels` every panel stays mounted regardless; there has to be something beside the current one to drag towards."],"examples":[],"classesType":null,"parts":[],"variants":[],"story":{"title":"Navigation/Tabs","category":"Navigation","own":false,"stories":["Playground","Primary and secondary","With icons","With badges","Fitted","Vertical","Scrollable","Disabled tab","Swipeable"]},"props":[{"name":"value","optional":false,"type":"string","bindable":false,"doc":"Must match the `value` of the tab that opens it.","details":[],"examples":[]},{"name":"keepMounted","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Keep the panel mounted while hidden. Costs memory but preserves scroll position, form state and any in-flight work in the panel.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"TabPanels","dir":"tabs","entry":"omaris","importPath":"import { TabPanels } from 'omaris'","summary":"The viewport the panels live in, and the thing a swipe moves.","details":["Without `swipeable` on the `Tabs` it is a plain wrapper and costs nothing. With it, the panels are laid out in a row and this drags them: the track follows the finger one-to-one, resists past the first and last panel, and settles on the next one from either the distance travelled or the speed it was thrown at — a flick moves a panel even when it barely moved at all.","`touch-action: pan-y` is what keeps the page scrolling normally: the browser keeps the vertical axis and this takes the horizontal one, so a swipe never fights a scroll."],"examples":[{"lang":"svelte","code":"<Tabs swipeable bind:value>\n  <TabList>…</TabList>\n  <TabPanels>\n    <TabPanel value=\"one\">…</TabPanel>\n    <TabPanel value=\"two\">…</TabPanel>\n  </TabPanels>\n</Tabs>"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Navigation/Tabs","category":"Navigation","own":false,"stories":["Playground","Primary and secondary","With icons","With badges","Fitted","Vertical","Scrollable","Disabled tab","Swipeable"]},"props":[{"name":"threshold","optional":true,"type":"number","default":"0.25","bindable":false,"doc":"Fraction of the width a drag has to cover before it counts as a move. A fast flick moves regardless.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Turns the gesture off for this viewport, leaving the layout alone.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"Tabs","dir":"tabs","entry":"omaris","importPath":"import { Tabs } from 'omaris'","summary":"MD3 tabs — a `TabList` of `Tab`s over one `TabPanel` per tab.","details":["`primary` is the top-level set, bigger, with the indicator hugging the label. `secondary` is for a set nested inside a primary tab's content.","`swipeable` adds the gesture a phone expects: wrap the panels in `TabPanels` and they can be dragged sideways, following the finger, with the indicator sliding along at the same fraction rather than jumping when the drag ends."],"examples":[],"classesType":null,"parts":[],"variants":[],"story":{"title":"Navigation/Tabs","category":"Navigation","own":true,"stories":["Playground","Primary and secondary","With icons","With badges","Fitted","Vertical","Scrollable","Disabled tab","Swipeable"]},"props":[{"name":"value","optional":true,"type":"string","default":"undefined","bindable":true,"doc":"The selected tab's value. Bindable.","details":[],"examples":[]},{"name":"variant","optional":true,"type":"TabsVariant","default":"'primary'","bindable":false,"doc":"MD3's two kinds. `primary` is the top-level one — bigger, with the indicator hugging the label. `secondary` sits inside a primary tab's content and runs its indicator the full width of the tab.","details":[],"examples":[]},{"name":"size","optional":true,"type":"TabsSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"fitted","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Share the width evenly rather than hugging the labels.","details":[],"examples":[]},{"name":"swipeable","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Let the panels be dragged sideways. Needs the panels wrapped in `TabPanels`, and mounts them all at once so there is something to drag to — so leave it off for a set whose panels are expensive.","details":[],"examples":[]},{"name":"orientation","optional":true,"type":"TabsOrientation","default":"'horizontal'","bindable":false,"doc":"`vertical` stacks the tabs down the start edge beside the panels — a settings screen's sections. ↑ and ↓ move between them.","details":[],"examples":[]},{"name":"activation","optional":true,"type":"TabsActivation","default":"'automatic'","bindable":false,"doc":"`automatic` shows a tab's panel as soon as the arrow keys reach it. `manual` only moves focus, and Enter or Space opens it — for panels that are expensive to show, or that fetch when they open.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"TagsInput","dir":"tags-input","entry":"omaris","importPath":"import { TagsInput } from 'omaris'","summary":"Free-form tags, typed into one field.","details":["The field is an `Input` frame with the tags sitting in front of the text box, so it reads as one control and wraps onto a second row when it has to. Enter, a comma or Tab turns the text into a tag; a paste with commas or newlines in it becomes several at once.","Backspace in an empty box selects the last tag, and a second press takes it off — so a stray press never deletes something you can't see going. The arrows walk the tags from there, and Delete or Backspace removes the one you're on.","For picking from a fixed list rather than typing, see `MultiSelect`."],"examples":[{"lang":"svelte","code":"<TagsInput bind:value={tags} label=\"Keywords\" max={8} />\n<TagsInput bind:value={emails} validate={(t) => t.includes('@') || 'Not an email.'} />"}],"classesType":"TagsInputClasses","parts":[{"name":"root","doc":"Wrapper: label, field, supporting text."},{"name":"field","doc":"The frame: border, background, height, adornment layout."},{"name":"control","doc":"The bare <input>; the frame owns every decoration."},{"name":"label","doc":""},{"name":"adornment","doc":"Icon slots at either end of the frame."},{"name":"affix","doc":"Flat text glued to the value — \"https://\", \"kg\"."},{"name":"action","doc":"An interactive trailing control: reveal, clear."},{"name":"support","doc":"Helper line under the field, and the counter beside it."},{"name":"counter","doc":""},{"name":"list","doc":"The tags and the text box, wrapped inside the frame."},{"name":"chip","doc":"One tag — a `Chip`, so it is the library's chip and not a lookalike."},{"name":"input","doc":"The bare text box the tags sit in front of."}],"variants":[{"name":"size","doc":"","default":"default","values":[{"name":"sm","doc":""},{"name":"default","doc":""},{"name":"lg","doc":""}]}],"story":{"title":"Inputs/Tags Input","category":"Inputs","own":true,"stories":["Playground","Variants and sizes","Validation","Max","Disabled and read-only","In a Field","Overridden"]},"props":[{"name":"value","optional":true,"type":"string[]","default":"[]","bindable":true,"doc":"The tags, in the order they were added. Bindable.","details":[],"examples":[]},{"name":"query","optional":true,"type":"string","default":"''","bindable":true,"doc":"What is typed but not yet a tag. Bindable — handy for suggestions.","details":[],"examples":[]},{"name":"variant","optional":true,"type":"InputVariant","default":"'outline'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"InputSize","default":"'default'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Label above the field. Wired to the text box, so clicking it focuses.","details":[],"examples":[]},{"name":"supportingText","optional":true,"type":"string","bindable":false,"doc":"Helper line under the field. A rejected tag's reason replaces it.","details":[],"examples":[]},{"name":"invalid","optional":true,"type":"boolean","bindable":false,"doc":"Marks the field invalid. Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"required","optional":true,"type":"boolean","bindable":false,"doc":"Stars the label. Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"max","optional":true,"type":"number","bindable":false,"doc":"Most tags it takes. Adds an `n/max` count under the field.","details":[],"examples":[]},{"name":"unique","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Refuse a tag that is already there, ignoring case.","details":[],"examples":[]},{"name":"validate","optional":true,"type":"(tag: string, value: string[]) => string | true","bindable":false,"doc":"Vets a tag before it goes in. Return `true` to accept it, or the reason it was refused — that text shows under the field and the typed text stays put for fixing.","details":[],"examples":[]},{"name":"duplicateMessage","optional":true,"type":"string","default":"'Already added.'","bindable":false,"doc":"Shown when `unique` refuses a tag.","details":[],"examples":[]},{"name":"maxMessage","optional":true,"type":"string","bindable":false,"doc":"Shown when a tag would go past `max`. Defaults to \"Up to {max}.\"","details":[],"examples":[]},{"name":"removeLabel","optional":true,"type":"(tag: string) => string","default":"(tag: string) => `Remove ${tag}`","bindable":false,"doc":"Accessible name of a tag's ×.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(value: string[]) => void","bindable":false,"doc":"Fires with the new list after every add and remove.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"TagsInputClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"ref","optional":true,"type":"HTMLInputElement | null","default":"null","bindable":true,"doc":"","details":[],"examples":[]}]},{"name":"Text","dir":"text","entry":"omaris","importPath":"import { Text } from 'omaris'","summary":"Text — the one component every string in the app goes through, instead of a `<p>`, a `<span>` or a `<div>` with a size class on it.","details":["Two independent decisions: `variant` is how it looks, `as` is what it means. `<Text variant=\"title-md\" as=\"h3\">` is a card title that is also a real heading. Leave one out and it is inferred — `as=\"h2\"` picks a headline, and a variant on its own renders a `<p>` (or a `<span>` for `label-*`, which is inline).","The variant is the whole type decision. Each one carries size, line height, letter spacing and weight from the token of the same name, so adding `font-semibold` after `variant=\"title-md\"` means the role was wrong, not the weight. Long-form wrapping is set for you too: headings balance, body avoids orphans.","Colour is inherited by default, so a Text inside a coloured surface stays legible without being told. Ask for `tone` when the text itself carries meaning — `muted` for secondary copy, `destructive` for an error."],"examples":[{"lang":"svelte","code":"<Text as=\"h1\">Revenue</Text>\n<Text variant=\"display-sm\" tabular>$48,210</Text>\n<Text tone=\"muted\">Compared to last month.</Text>\n<Text variant=\"label-sm\" tone=\"muted\" lines={1}>{file.name}</Text>"}],"classesType":null,"parts":[],"variants":[{"name":"variant","doc":"Role and size — the type token minus `text-`. Pick by the job the text does: `display` is the one hero number on a screen, `headline` titles a page or section, `title` titles a card or dialog, `body` is prose and cell contents, `label` is buttons, chips, tabs and column headers.","default":"body-md","values":[{"name":"display-lg","doc":"The one number on a screen. Rare in a dashboard."},{"name":"display-md","doc":"A hero figure that shares the screen with something else."},{"name":"display-sm","doc":"The metric at the top of a card — the usual display size here."},{"name":"headline-lg","doc":"Page titles."},{"name":"headline-md","doc":"Section titles."},{"name":"headline-sm","doc":"Sub-sections, dialog headings."},{"name":"title-lg","doc":"Card titles."},{"name":"title-md","doc":"Dialog titles, list group headers."},{"name":"title-sm","doc":"Dense card titles, table captions."},{"name":"body-lg","doc":"Lead paragraphs and long-form prose."},{"name":"body-md","doc":"The default — descriptions, cell contents."},{"name":"body-sm","doc":"Secondary copy, captions, help text."},{"name":"label-lg","doc":"Buttons and tabs."},{"name":"label-md","doc":"Chips, column headers, form labels."},{"name":"label-sm","doc":"Overlines, timestamps, the text inside a badge."}]},{"name":"tone","doc":"Colour role. Inherits from the surface unless you say otherwise.","default":"inherit","values":[{"name":"inherit","doc":"Takes the colour of whatever it sits in."},{"name":"default","doc":"The page's primary text colour, stated."},{"name":"muted","doc":"Secondary copy — captions, hints, timestamps."},{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""},{"name":"inverse","doc":"For text on an inverted surface — a dark tooltip, an inverted toast."}]},{"name":"weight","doc":"Overrides the weight the variant already carries. Rarely needed.","values":[{"name":"normal","doc":""},{"name":"medium","doc":""},{"name":"semibold","doc":""},{"name":"bold","doc":""}]},{"name":"align","doc":"Logical, so it follows the writing direction.","values":[{"name":"start","doc":""},{"name":"center","doc":""},{"name":"end","doc":""},{"name":"justify","doc":""}]},{"name":"wrap","doc":"Overrides the wrapping the variant sets.","values":[{"name":"normal","doc":"Break wherever the line ends."},{"name":"balance","doc":"Even line lengths — good for a heading of two or three lines."},{"name":"pretty","doc":"No single-word last line. The default for `body-*`."},{"name":"nowrap","doc":"One line, however long. Pair with `lines={1}` to clip it."}]},{"name":"lines","doc":"Clamps to N lines with an ellipsis.","values":[{"name":"1","doc":""},{"name":"2","doc":""},{"name":"3","doc":""},{"name":"4","doc":""},{"name":"5","doc":""},{"name":"6","doc":""}]},{"name":"font","doc":"Family. Inherits unless set; Arabic swaps itself out already.","values":[{"name":"sans","doc":""},{"name":"mono","doc":"Ids, hashes, code, anything meant to be compared character by character."}]},{"name":"tabular","doc":"Fixed-width digits, so numbers in a column line up.","values":[{"name":"true","doc":""}]}],"story":{"title":"Data Display/Text","category":"Data Display","own":true,"stories":["Playground","Scale","Semantics","Tones","Truncation","Numbers","Overrides"]},"props":[{"name":"variant","optional":true,"type":"TextVariant","bindable":false,"doc":"How it looks — the type token minus `text-`. Pick by the job the text does: `display` is the one hero number on a screen, `headline` titles a page or section, `title` titles a card or dialog, `body` is prose and cell contents, `label` is buttons, chips, tabs and column headers. Each one carries size, line height, letter spacing and weight together. Defaults to `body-md`, or to the role that matches `as` when that is a heading.","details":[],"examples":[]},{"name":"as","optional":true,"type":"TextElement","bindable":false,"doc":"What it means. Defaults to `span` for `label-*` and `p` for everything else. Use a heading tag for anything that is one — the look does not make it a heading, this does.","details":[],"examples":[]},{"name":"tone","optional":true,"type":"TextTone","default":"'inherit'","bindable":false,"doc":"Colour role. Inherits from the surface by default, so a Text inside a coloured container stays legible; set it when the colour itself means something — `muted` for secondary copy, `destructive` for an error.","details":[],"examples":[]},{"name":"weight","optional":true,"type":"TextWeight","bindable":false,"doc":"Overrides the weight the variant carries. If you want it, the role is probably wrong.","details":[],"examples":[]},{"name":"align","optional":true,"type":"TextAlign","bindable":false,"doc":"Logical, so it follows the writing direction.","details":[],"examples":[]},{"name":"wrap","optional":true,"type":"TextWrap","bindable":false,"doc":"Overrides the wrapping the variant sets — headings balance, body avoids orphans.","details":[],"examples":[]},{"name":"lines","optional":true,"type":"TextLines","bindable":false,"doc":"Clamps to N lines with an ellipsis. `lines={1}` is a single line.","details":[],"examples":[]},{"name":"font","optional":true,"type":"TextFont","bindable":false,"doc":"Family. Inherits unless set; `mono` for ids, hashes and code.","details":[],"examples":[]},{"name":"tabular","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Fixed-width digits, for numbers that sit in a column.","details":[],"examples":[]},{"name":"for","optional":true,"type":"string","bindable":false,"doc":"Only with `as=\"label\"`: the id of the control it labels.","details":[],"examples":[]},{"name":"datetime","optional":true,"type":"string","bindable":false,"doc":"Only with `as=\"time\"`: the machine-readable date.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"Textarea","dir":"textarea","entry":"omaris","importPath":"import { Textarea } from 'omaris'","summary":"Multi-line text field.","details":["Shares the Input's frame — same three variants, same focus bloom, same label/supporting-text layout — so a form mixing the two lines up without fiddling.","`autosize` turns it into a composer: the box tracks how many lines the text actually occupies and grows a line at a time, smoothly, instead of scrolling inside a fixed rectangle. It starts at `rows`, never goes below it, and stops at `maxRows` — past which it scrolls like a normal textarea. Height comes from a mirror of the text rather than from poking the element's own height between measurements, so the growth can be transitioned without the flicker that trick usually brings."],"examples":[],"classesType":"TextareaClasses","parts":[{"name":"root","doc":""},{"name":"field","doc":""},{"name":"well","doc":"Holds the control and, when autosizing, the mirror behind it."},{"name":"control","doc":""},{"name":"mirror","doc":"An invisible copy of the text, laid over the control at the same width and typography. Its height *is* the height the control wants — measured without ever resizing the control itself."},{"name":"label","doc":""},{"name":"support","doc":""},{"name":"counter","doc":""}],"variants":[{"name":"variant","doc":"","default":"outline","values":[{"name":"outline","doc":""},{"name":"filled","doc":""},{"name":"ghost","doc":""}]},{"name":"size","doc":"`--field-line` is the line box the row maths are done in, so it has to be a real length rather than `normal`.","default":"default","values":[{"name":"sm","doc":""},{"name":"default","doc":""},{"name":"lg","doc":""}]},{"name":"invalid","doc":"","default":"false","values":[{"name":"true","doc":""}]},{"name":"autosize","doc":"Autosize owns the height, so the manual grip goes away.","values":[{"name":"true","doc":""}]}],"story":{"title":"Inputs/Textarea","category":"Inputs","own":true,"stories":["Playground","Variants","Sizes","Composer","Autosize","With counter","States"]},"props":[{"name":"variant","optional":true,"type":"TextareaVariant","default":"'outline'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"TextareaSize","default":"'default'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"required","optional":true,"type":"boolean","bindable":false,"doc":"Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"supportingText","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"invalid","optional":true,"type":"boolean","bindable":false,"doc":"Inside a `Field`, defaults to the field's.","details":[],"examples":[]},{"name":"value","optional":true,"type":"string","default":"''","bindable":true,"doc":"","details":[],"examples":[]},{"name":"counter","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Live `n/maxlength` count beside the supporting text.","details":[],"examples":[]},{"name":"autosize","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Grow with the text. The box starts at `rows`, gains a line as the text takes one, and scrolls once it reaches `maxRows`.","details":[],"examples":[]},{"name":"rows","optional":true,"type":"number","default":"3","bindable":false,"doc":"Starting height, in lines — and the floor when `autosize`.","details":[],"examples":[]},{"name":"maxRows","optional":true,"type":"number","bindable":false,"doc":"Ceiling for `autosize`, in lines. Past this it scrolls.","details":[],"examples":[]},{"name":"lines","optional":true,"type":"number","default":"1","bindable":true,"doc":"Lines the text currently occupies. Bindable, and read-only in practice — useful for a \"shift+enter for a new line\" hint or for swapping a send button in once the composer has something in it.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"TextareaClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"supporting","optional":true,"type":"Snippet","bindable":false,"doc":"Richer supporting text — a link, a hint.","details":[],"examples":[]},{"name":"ref","optional":true,"type":"HTMLTextAreaElement | null","default":"null","bindable":true,"doc":"","details":[],"examples":[]}]},{"name":"ThemeSettings","dir":"theme-settings","entry":"omaris","importPath":"import { ThemeSettings } from 'omaris'","summary":"A ready-made appearance screen for the theme store.","details":["Drop it in a dialog, a sheet or a settings page and your users get every knob the library has — color, shape, density, type, motion and contrast — each one a picture of what it does, changing the whole product live and remembered between visits (with `OmarisProvider`). It speaks English, Arabic, Turkish and Sorani Kurdish, and follows the page's `lang` unless you pass `locale`:"],"examples":[{"lang":"svelte","code":"<ThemeSettings />\n<ThemeSettings locale=\"ar\" />\n<ThemeSettings layout=\"stack\" sections={['color', 'shape', 'text']} />"}],"classesType":"ThemeSettingsClasses","parts":[{"name":"root","doc":""},{"name":"section","doc":""},{"name":"heading","doc":""},{"name":"row","doc":""},{"name":"label","doc":""},{"name":"hint","doc":""},{"name":"choices","doc":"A set of picture cards — appearance, corners, density, type, motion."},{"name":"choice","doc":"One picture card."},{"name":"choiceArt","doc":"The picture inside a card."},{"name":"choiceLabel","doc":""},{"name":"swatch","doc":"A preset swatch."},{"name":"swatchDot","doc":""},{"name":"swatchLabel","doc":""},{"name":"footer","doc":""}],"variants":[{"name":"layout","doc":"","default":"tabs","values":[{"name":"tabs","doc":""},{"name":"stack","doc":""}]}],"story":{"title":"Foundations/Theme Settings","category":"Foundations","own":true,"stories":["Playground","In a dialog","Stacked, some sections","Arabic","Kurdish (Sorani)","Turkish","Overridden"]},"props":[{"name":"layout","optional":true,"type":"ThemeSettingsLayout","default":"'tabs'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"sections","optional":true,"type":"ThemeSettingsSection[]","default":"ALL","bindable":false,"doc":"Which groups to show, in order.","details":[],"examples":[]},{"name":"resettable","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Show the \"Reset\" row at the bottom.","details":[],"examples":[]},{"name":"customHue","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Offer the custom hue slider alongside the presets.","details":[],"examples":[]},{"name":"locale","optional":true,"type":"ThemeSettingsLocale","bindable":false,"doc":"The language — `en`, `ar`, `tr` or `ckb` (Sorani Kurdish). Arabic and Kurdish lay the screen out right to left. Leave it out to follow the nearest `lang` attribute on the page, falling back to English.","details":[],"examples":[]},{"name":"labels","optional":true,"type":"Partial<ThemeSettingsLabels>","bindable":false,"doc":"Replace any of the words, over whichever language is showing.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"ThemeSettingsClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"Timeline","dir":"timeline","entry":"omaris","importPath":"import { Timeline } from 'omaris'","summary":"An activity feed or an order's history: events in order, each on a rail with a dot or an icon, joined by the line that makes them read as one sequence rather than a list of unrelated rows.","details":["It is an `<ol>`, because the order is the information. Times are given as dates and written the way a person says them — \"3 minutes ago\" — with the exact moment in a real `<time datetime>` and in the tooltip, and they keep themselves current from one shared clock however long the feed is.","A feed grouped by day is one `Timeline` per day, each with a `heading`."],"examples":[{"lang":"svelte","code":"<Timeline heading=\"Today\">\n  <TimelineItem title=\"Order shipped\" time={shippedAt} tone=\"success\" />\n  <TimelineItem title=\"Out for delivery\" pending />\n</Timeline>"}],"classesType":"TimelineClasses","parts":[{"name":"root","doc":""},{"name":"heading","doc":"The group heading — \"Today\", \"March 2026\"."},{"name":"list","doc":"The `<ol>`."}],"variants":[],"story":{"title":"Data Display/Timeline","category":"Data Display","own":true,"stories":["Playground","With icons","Grouped by day","Rich content","Pending","Absolute dates","Overridden"]},"props":[{"name":"variant","optional":true,"type":"TimelineVariant","default":"'default'","bindable":false,"doc":"`default` gives each event room and icon-sized markers; `compact` is a dense feed.","details":[],"examples":[]},{"name":"heading","optional":true,"type":"string","bindable":false,"doc":"A heading over the list, which also names it for a screen reader — \"Today\", \"Yesterday\". Use one `Timeline` per group.","details":[],"examples":[]},{"name":"level","optional":true,"type":"2 | 3 | 4 | 5 | 6","default":"3","bindable":false,"doc":"Heading level, so the group fits the page outline.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible name for the list when there is no `heading`.","details":[],"examples":[]},{"name":"relative","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Write times relative to now — \"3 minutes ago\". Off, they are written as dates with `dateFormat`. Either way the exact moment is in the `<time datetime>` and the tooltip.","details":[],"examples":[]},{"name":"maxAge","optional":true,"type":"number","bindable":false,"doc":"Past this age, in ms, a relative time switches to the date: a week is `7 * 24 * 3600_000`. \"47 weeks ago\" is not information.","details":[],"examples":[]},{"name":"dateFormat","optional":true,"type":"Intl.DateTimeFormatOptions","bindable":false,"doc":"How absolute dates are written. Defaults to a long date and a short time.","details":[],"examples":[]},{"name":"locale","optional":true,"type":"string","bindable":false,"doc":"Language of the times. English, Arabic, Turkish and Sorani Kurdish are built in; defaults to `<html lang>`. Digits stay Western.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"TimelineClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"header","optional":true,"type":"Snippet","bindable":false,"doc":"Rich heading, in place of `heading`.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"TimelineItem","dir":"timeline","entry":"omaris","importPath":"import { TimelineItem } from 'omaris'","summary":"One event on a `Timeline`: a marker on the rail, a title, when it happened, and whatever else it needs underneath.","details":["The line to the next event is drawn by this item and hidden on the last one, so a feed that grows or shrinks never leaves a line hanging. When the next item is `pending` the line runs dashed into it — the step that has not happened yet."],"examples":[],"classesType":"TimelineItemClasses","parts":[{"name":"root","doc":""},{"name":"rail","doc":"The column the marker and the line live in."},{"name":"marker","doc":"A box the height of the title's line, so the dot centres on it."},{"name":"dot","doc":"The plain dot, when there is no icon."},{"name":"icon","doc":"The tonal circle an `icon` sits in."},{"name":"line","doc":"The connector down to the next item."},{"name":"content","doc":""},{"name":"header","doc":"Title and time, on one line when they fit."},{"name":"title","doc":""},{"name":"time","doc":""},{"name":"description","doc":""},{"name":"body","doc":"Rich content under the description — a quote, a diff, attachments."}],"variants":[{"name":"variant","doc":"","default":"default","values":[{"name":"default","doc":""},{"name":"compact","doc":""}]},{"name":"tone","doc":"","default":"primary","values":[{"name":"neutral","doc":"Past events that do not need attention — the usual case in a long feed."},{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""}]},{"name":"pending","doc":"","values":[{"name":"true","doc":""}]}],"story":{"title":"Data Display/Timeline","category":"Data Display","own":false,"stories":["Playground","With icons","Grouped by day","Rich content","Pending","Absolute dates","Overridden"]},"props":[{"name":"title","optional":true,"type":"string","bindable":false,"doc":"What happened — \"Order shipped\".","details":[],"examples":[]},{"name":"description","optional":true,"type":"string","bindable":false,"doc":"A supporting line under the title.","details":[],"examples":[]},{"name":"time","optional":true,"type":"Date | string | number","bindable":false,"doc":"When it happened. A `Date`, a timestamp or an ISO string is written relative to now and marked up as `<time datetime>`; a string that is not a date (\"Tomorrow, 9–12\") is shown as given.","details":[],"examples":[]},{"name":"tone","optional":true,"type":"TimelineItemTone","default":"'primary'","bindable":false,"doc":"The marker's colour role. `neutral` is a quiet grey dot for events that need no attention; save the tones for the ones that do.","details":[],"examples":[]},{"name":"pending","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"The event that has not happened yet — the courier on the way, the review awaiting. Its marker pulses (and holds still under reduced motion), and the line into it is dashed. Usually the last item.","details":[],"examples":[]},{"name":"pendingLabel","optional":true,"type":"string","default":"'In progress'","bindable":false,"doc":"Spoken after the title of a pending item.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"TimelineItemClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"icon","optional":true,"type":"Snippet","bindable":false,"doc":"An icon in a tonal circle, in place of the dot.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Rich content under the description.","details":[],"examples":[]}]},{"name":"TimePicker","dir":"picker","entry":"omaris","importPath":"import { TimePicker } from 'omaris'","summary":"Hour, minute and AM/PM.","details":["Always twelve-hour with AM/PM — omaris never shows a 24-hour clock. The value is still stored 24-hour — `\"14:30\"` — so it sorts, compares and goes into a database without a second format to agree on; that is data, and the wheels are what a person reads."],"examples":[{"lang":"svelte","code":"<TimePicker bind:value={opensAt} minuteStep={15} />"}],"classesType":"PickerClasses","parts":[{"name":"root","doc":""},{"name":"header","doc":"The title line above the wheels."},{"name":"stage","doc":"Everything the band is drawn behind: the wheels and both fades."},{"name":"band","doc":"The strip marking the centre row."},{"name":"wheels","doc":"The row of wheels. Masked so rows dissolve towards the edges."},{"name":"actions","doc":"The cancel/confirm row. Only rendered when `onconfirm` is given."},{"name":"action","doc":"One of those buttons."}],"variants":[],"story":{"title":"Inputs/Picker","category":"Inputs","own":false,"stories":["Playground","Date","Time","Date and time","Number","Custom columns","Text options","With actions","Sizes and depth","Disabled","Overridden"]},"props":[{"name":"value","optional":true,"type":"string","default":"'09:00'","bindable":true,"doc":"`\"HH:mm\"`, stored 24-hour; the wheels always show 1–12 and AM/PM. Bindable.","details":[],"examples":[]},{"name":"minuteStep","optional":true,"type":"number","default":"1","bindable":false,"doc":"Minutes between rows — 5 or 15 for an opening time, 1 for an alarm.","details":[],"examples":[]},{"name":"loop","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Spin past midnight and noon instead of stopping. On by default.","details":[],"examples":[]},{"name":"labels","optional":true,"type":"{ hour?: string; minute?: string; meridiem?: string; am?: string; pm?: string }","bindable":false,"doc":"Accessible names for the wheels, and the AM/PM row text.","details":[],"examples":[]},{"name":"onchange","optional":true,"type":"(value: string) => void","bindable":false,"doc":"Fires once a wheel settles, with the 24-hour string.","details":[],"examples":[]},{"name":"columnClasses","optional":true,"type":"PickerColumnClasses","bindable":false,"doc":"Per-part overrides for the wheels themselves.","details":[],"examples":[]},{"name":"classes","optional":true,"type":"PickerClasses","bindable":false,"doc":"","details":[],"examples":[]},{"name":"size","optional":true,"type":"PickerSize","bindable":false,"doc":"Row height and type scale.","details":[],"examples":[]},{"name":"surface","optional":true,"type":"PickerSurface","bindable":false,"doc":"How the frame is drawn.","details":[],"examples":[]},{"name":"visible","optional":true,"type":"number","bindable":false,"doc":"Rows on screen at once. Rounded up to the next odd number.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"A title above the wheels.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","bindable":false,"doc":"Disables every wheel inside.","details":[],"examples":[]},{"name":"haptics","optional":true,"type":"boolean","bindable":false,"doc":"Play a tick as each row passes the centre, once haptics are on.","details":[],"examples":[]},{"name":"onconfirm","optional":true,"type":"() => void","bindable":false,"doc":"Renders the action row. Called with the value already committed.","details":[],"examples":[]},{"name":"oncancel","optional":true,"type":"() => void","bindable":false,"doc":"Renders a cancel button beside it.","details":[],"examples":[]},{"name":"confirmLabel","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"cancelLabel","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"footer","optional":true,"type":"Snippet","bindable":false,"doc":"Replaces the built-in action row.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"Toast","dir":"toast","entry":"omaris","importPath":"import { Toast } from 'omaris'","summary":"One toast card.","details":["Usually you don't render this yourself: call `toast(...)` and let `<Toaster />` stack it. It's exported on its own for the cases where a message belongs to one part of the page rather than the app.","The card owns its swipe. The stack transform belongs to the `<Toaster />` wrapper around it, so the two never fight over the same property."],"examples":[],"classesType":"ToastClasses","parts":[{"name":"root","doc":""},{"name":"icon","doc":""},{"name":"body","doc":""},{"name":"title","doc":""},{"name":"description","doc":""},{"name":"actions","doc":"Action and cancel sit on the trailing edge, action first."},{"name":"action","doc":""},{"name":"cancel","doc":""},{"name":"close","doc":"The ×, revealed on hover so it doesn't clutter the resting card — except where there is no hover to reveal it with, on which devices a hidden control is simply a missing one. Same card, same size everywhere; only its resting opacity differs."}],"variants":[{"name":"tone","doc":"","default":"primary","values":[{"name":"primary","doc":""},{"name":"secondary","doc":""},{"name":"tertiary","doc":""},{"name":"destructive","doc":""},{"name":"success","doc":""},{"name":"warning","doc":""},{"name":"info","doc":""}]},{"name":"variant","doc":"","default":"plain","values":[{"name":"plain","doc":"Sonner's default: a neutral card, colour carried by the icon."},{"name":"rich","doc":"The whole card takes the tone, for a message that must land."}]}],"story":{"title":"Communication/Toast","category":"Communication","own":true,"stories":["Playground","Types","Rich colours","Actions","Promise","Stacking","Positions","Touch"]},"props":[{"name":"toast","optional":false,"type":"ToastItem","bindable":false,"doc":"","details":[],"examples":[]},{"name":"variant","optional":true,"type":"ToastVariant","default":"'plain'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"swipe","optional":true,"type":"ToastSwipe","default":"{ x: 0, y: 1 }","bindable":false,"doc":"","details":[],"examples":[]},{"name":"closeButton","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Stack-wide default; the toast's own `closeButton` wins.","details":[],"examples":[]},{"name":"ondismiss","optional":true,"type":"() => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onhold","optional":true,"type":"(held: boolean) => void","bindable":false,"doc":"Held while a finger is on the card, so the timer can pause.","details":[],"examples":[]},{"name":"ontap","optional":true,"type":"() => void","bindable":false,"doc":"A press that turned out to be a press: it ended without becoming a swipe and did not land on a button. The stack uses it as \"expand\" on a touchscreen, where there is no hover to fan the deck with.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"ToastClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"Toaster","dir":"toast","entry":"omaris","importPath":"import { Toaster } from 'omaris'","summary":"Where toasts appear. `OmarisProvider` renders one, so you only need this if you want them somewhere else or stacked differently.","details":[],"examples":[],"classesType":null,"parts":[],"variants":[],"story":{"title":"Communication/Toast","category":"Communication","own":false,"stories":["Playground","Types","Rich colours","Actions","Promise","Stacking","Positions","Touch"]},"props":[{"name":"position","optional":true,"type":"ToastPosition","default":"'bottom-end'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"visible","optional":true,"type":"number","default":"3","bindable":false,"doc":"How many are on screen at once. The rest wait in the deck.","details":[],"examples":[]},{"name":"variant","optional":true,"type":"ToastVariant","default":"'plain'","bindable":false,"doc":"Fill style for every toast the stack renders.","details":[],"examples":[]},{"name":"closeButton","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Show the × on every toast.","details":[],"examples":[]},{"name":"expand","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Keep the deck fanned out instead of expanding on hover.","details":[],"examples":[]},{"name":"gap","optional":true,"type":"number","default":"14","bindable":false,"doc":"Gap between toasts once expanded, in px.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"Toc","dir":"toc","entry":"omaris","importPath":"import { Toc } from 'omaris'","summary":"Toc — the \"on this page\" rail.","details":["A list of the page's headings against a hairline, with a marker that slides and resizes onto the section you are reading. The marker is one element rather than a border per link, which is what makes the movement readable.","Tracking works wherever the page scrolls. The listener is registered on the document in the capture phase, so a column that scrolls inside an `AppShell` — or a dialog, or a panel — is followed as readily as the window. Pass `spy={false}` and `bind:active` to drive it yourself."],"examples":[],"classesType":"TocClasses","parts":[{"name":"root","doc":""},{"name":"title","doc":""},{"name":"rail","doc":"Holds the hairline the marker rides on, and the marker itself."},{"name":"marker","doc":""},{"name":"list","doc":""},{"name":"item","doc":""},{"name":"link","doc":""}],"variants":[{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""}]},{"name":"indent","doc":"Distance from the shallowest heading on the page, in levels.","default":"0","values":[{"name":"0","doc":""},{"name":"1","doc":""},{"name":"2","doc":""},{"name":"3","doc":""}]},{"name":"active","doc":"","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Navigation/Toc","category":"Navigation","own":true,"stories":["Playground","Sizes","Levels","Without the marker","Controlled","Overridden"]},"props":[{"name":"items","optional":true,"type":"TocItem[]","default":"[]","bindable":false,"doc":"The headings, in the order they appear on the page.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","default":"'On this page'","bindable":false,"doc":"Heading above the list, and the nav's accessible name.","details":[],"examples":[]},{"name":"showLabel","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Draw the heading. The accessible name survives either way.","details":[],"examples":[]},{"name":"active","optional":true,"type":"string","default":"undefined","bindable":true,"doc":"The id of the highlighted heading. Bindable.","details":[],"examples":[]},{"name":"spy","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Follow the scroll position. Off leaves `active` to the consumer.","details":[],"examples":[]},{"name":"offset","optional":true,"type":"number","default":"96","bindable":false,"doc":"How far below the top of whatever scrolls — the viewport, or the panel the headings are in — a heading counts as read, in pixels: the height of whatever sticks to the top, plus a little.","details":[],"examples":[]},{"name":"size","optional":true,"type":"TocSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"marker","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Draw the sliding marker. Off leaves the hairline and the colour.","details":[],"examples":[]},{"name":"onnavigate","optional":true,"type":"(id: string) => void","bindable":false,"doc":"Runs when a link is clicked, after `active` has moved.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"TocClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"Tooltip","dir":"tooltip","entry":"omaris","importPath":"import { Tooltip } from 'omaris'","summary":"MD3 tooltip — plain and rich.","details":["Wrap whatever it describes; the wrapper is the anchor, and hover, focus and long-press all open it. The tooltip itself is portalled to the body and positioned with the shared `anchor` action, so it escapes scroll containers and flips when it runs out of room.","A plain tooltip is the trigger's accessible description. A rich one has a title, body and actions, so it's a dialog you can move the pointer into — it stays open while the pointer is over it."],"examples":[],"classesType":"TooltipClasses","parts":[{"name":"root","doc":""},{"name":"surface","doc":""},{"name":"title","doc":""},{"name":"body","doc":""},{"name":"actions","doc":""}],"variants":[{"name":"rich","doc":"","values":[{"name":"true","doc":""}]}],"story":{"title":"Communication/Tooltip","category":"Communication","own":true,"stories":["Playground","Sides","On a toolbar","Rich","Keyboard"]},"props":[{"name":"text","optional":true,"type":"string","bindable":false,"doc":"Plain-tooltip text.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"Heading of a rich tooltip. Its presence turns rich mode on.","details":[],"examples":[]},{"name":"side","optional":true,"type":"AnchorSide","default":"'top'","bindable":false,"doc":"Which side to prefer. Flips when there isn't room.","details":[],"examples":[]},{"name":"align","optional":true,"type":"AnchorAlign","default":"'center'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"offset","optional":true,"type":"number","default":"8","bindable":false,"doc":"Gap between the trigger and the tooltip, in px.","details":[],"examples":[]},{"name":"delay","optional":true,"type":"number","default":"500","bindable":false,"doc":"Delay before opening, in ms. Suppressed once one is already open.","details":[],"examples":[]},{"name":"open","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Keep it open. Useful for a story or a walkthrough.","details":[],"examples":[]},{"name":"disabled","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"TooltipClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"The trigger.","details":[],"examples":[]},{"name":"content","optional":true,"type":"Snippet","bindable":false,"doc":"Rich body, in place of `text`.","details":[],"examples":[]},{"name":"actions","optional":true,"type":"Snippet","bindable":false,"doc":"Buttons along the bottom of a rich tooltip.","details":[],"examples":[]}]},{"name":"TopAppBar","dir":"top-app-bar","entry":"omaris","importPath":"import { TopAppBar } from 'omaris'","summary":"MD3 top app bar — small, medium, large and center-aligned.","details":["The MD3 behaviour that matters is the scroll response, and it's all wired here so a consumer doesn't rebuild it per screen:","- The bar is flat on a page at rest and lifts onto a raised surface once the content scrolls under it. - `flexible` gives a medium or large bar the collapse MD3 calls for: the big headline shrinks and fades on the way up while the same text fades in beside the actions, so the bar ends as a small one. - `hideOnScroll` gets the bar out of the way entirely on the way down and brings it back the moment you scroll up. - `floating` detaches it from the edges — the rounded, blurred bar that hovers over a map or a canvas.","`medium` and `large` drop the headline onto its own line below the actions, which is where MD3 puts it. Put a `SearchBar` in the `search` slot and the bar becomes the search bar of a dashboard."],"examples":[],"classesType":"TopAppBarClasses","parts":[{"name":"root","doc":""},{"name":"bar","doc":"The action row: leading control, title, trailing controls."},{"name":"leading","doc":""},{"name":"title","doc":""},{"name":"actions","doc":""},{"name":"headlineRow","doc":"Clips the second-line headline while it collapses."},{"name":"headline","doc":"The second-line headline on a medium or large bar."},{"name":"search","doc":"Full-width middle slot — a search field, usually."}],"variants":[{"name":"size","doc":"","default":"small","values":[{"name":"small","doc":""},{"name":"center","doc":""},{"name":"medium","doc":""},{"name":"large","doc":""}]},{"name":"variant","doc":"","default":"flat","values":[{"name":"flat","doc":"Sits on the page background until it's scrolled under."},{"name":"surface","doc":"Always on a raised surface."},{"name":"transparent","doc":"No background at all — over a hero image, say."}]},{"name":"raised","doc":"Set by the scroll listener, not by hand.","values":[{"name":"true","doc":""}]},{"name":"sticky","doc":"","values":[{"name":"true","doc":""}]},{"name":"floating","doc":"Off the edges and over the content rather than above it — the bar a map or a canvas gets, and the one Google Maps made the shape everyone now expects: a single capsule, fully round at both ends, lifted off a blurred surface with its controls tucked inside the curve rather than crowding it.","values":[{"name":"true","doc":""}]},{"name":"hidden","doc":"Scrolled out of the way.","values":[{"name":"true","doc":""}]}],"story":{"title":"Navigation/Top App Bar","category":"Navigation","own":true,"stories":["Playground","Sizes","With tabs","Large","Flexible","Hide on scroll","Floating","Floating over a canvas","With search"]},"props":[{"name":"size","optional":true,"type":"TopAppBarSize","default":"'small'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"variant","optional":true,"type":"TopAppBarVariant","default":"'flat'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"Headline text.","details":[],"examples":[]},{"name":"sticky","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Stick to the top of the scroll container.","details":[],"examples":[]},{"name":"floating","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Rounded, blurred and inset from the edges.","details":[],"examples":[]},{"name":"elevateOnScroll","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Lift onto a raised surface once the page is scrolled. Give it a scroll container element to watch something other than the window.","details":[],"examples":[]},{"name":"flexible","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Collapse a medium or large bar into a small one as the page scrolls — MD3's flexible bar.","details":[],"examples":[]},{"name":"collapseDistance","optional":true,"type":"number","bindable":false,"doc":"Scroll distance the collapse runs over, in px. Defaults to the headline's own height, which is the distance it has to travel.","details":[],"examples":[]},{"name":"hideOnScroll","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Slide the bar away while scrolling down; bring it back on the way up.","details":[],"examples":[]},{"name":"scrollContainer","optional":true,"type":"HTMLElement | null","bindable":false,"doc":"What to watch for scrolling. Inside an `AppShell` this is already known — the shell hands over its scrolling column — so it's only needed for a layout that scrolls something else. `null` is the window, explicitly.","details":[],"examples":[]},{"name":"threshold","optional":true,"type":"number","default":"4","bindable":false,"doc":"Scroll distance, in px, before the bar lifts.","details":[],"examples":[]},{"name":"progress","optional":true,"type":"number","default":"0","bindable":true,"doc":"How far the collapse has run, 0…1. Bindable, read-only in practice.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"TopAppBarClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"leading","optional":true,"type":"Snippet","bindable":false,"doc":"Leading control — a back arrow or menu button.","details":[],"examples":[]},{"name":"headline","optional":true,"type":"Snippet","bindable":false,"doc":"Rich headline, in place of `title`.","details":[],"examples":[]},{"name":"actions","optional":true,"type":"Snippet","bindable":false,"doc":"Trailing controls.","details":[],"examples":[]},{"name":"search","optional":true,"type":"Snippet","bindable":false,"doc":"Takes over the middle of the action row, full width — a `SearchBar`, usually. It *replaces* what sits there rather than joining it, so on a small or centred bar `title` is not drawn at all while this is set. A medium or large bar still draws its headline on the row below, so those keep both.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"Anything below the bar — a tab row.","details":[],"examples":[]}]},{"name":"Tour","dir":"tour","entry":"omaris","importPath":"import { Tour } from 'omaris'","summary":"A guided tour: a spotlight on one thing at a time, with a card explaining it.","details":["The scrim is a single element with a hole cut in it — one `box-shadow` with an enormous spread — rather than four rectangles arranged around the target. That matters because the hole then *animates*: moving between steps slides and resizes one box with MD3 easing, so the spotlight travels across the page instead of blinking from place to place. The card travels with it — its position and height are transitioned, and the copy inside fades out, swaps, and fades back in once the card has settled — so a step change reads as one movement, not a cut.","A step names its target with a CSS selector, so a tour is data — it can come from a config file, a feature flag or the server, and it does not need a ref threaded through every component it points at. A step whose target isn't on the page is skipped rather than left pointing at nothing: `Next` walks forward past it, `Back` walks backward past it, and a tour with nothing left to point at finishes. A step with *no* target is different — it is centred, which is how a tour opens and closes.","The card never covers the hole. When a side is too short for it — which on a phone is most sides — the card shrinks into that side and scrolls inside itself rather than sliding over the thing being pointed at, and the step scrolls its target near the top of the screen instead of the middle so there is a side to put it on at all.","The page underneath stays interactive inside the spotlight, so a tour can ask you to actually click the thing. Everywhere else, a click on the scrim ends the tour when it is `dismissible`.","A tour that crosses pages is the same thing with a `path` on the steps that live elsewhere, and a `createTour` controller holding the state so it survives the navigation. Mount that one in `+layout.svelte`, not in a page — a tour that navigates away from the component rendering it takes the component with it."],"examples":[{"lang":"svelte","code":"<Tour bind:open steps={[\n  { target: '#new-order', title: 'Start here', content: 'Every order begins with this button.' }\n]} />"},{"lang":"ts","code":"const tour = createTour(STEPS, { id: 'onboarding', navigate: goto });"},{"lang":"svelte","code":"<Tour {tour} />"}],"classesType":"TourClasses","parts":[{"name":"scrim","doc":"The click-catcher behind the card when the tour is `dismissible`: a transparent sheet with the spotlight cut out of it, so the page stays clickable inside the hole and a click anywhere else ends the tour."},{"name":"spotlight","doc":"The dark layer, with the spotlight cut out of it."},{"name":"card","doc":"The explaining card. Positioned with `translate`, so it glides."},{"name":"scroller","doc":"Holds the card's copy when there is less room beside the target than the card wants — the card is capped to the space it has and this scrolls, so it is never resized over the spotlight."},{"name":"body","doc":"What gets measured: everything inside the card."},{"name":"header","doc":""},{"name":"title","doc":""},{"name":"counter","doc":"`2 / 5`."},{"name":"progress","doc":"The slim track under the header."},{"name":"progressBar","doc":"How much of the tour is done."},{"name":"content","doc":""},{"name":"footer","doc":"Dots, then the buttons."},{"name":"dots","doc":""},{"name":"dot","doc":""},{"name":"actions","doc":""},{"name":"ghost","doc":"Back, and the skip link — `text` buttons."},{"name":"next","doc":"Next / Done — the filled button."}],"variants":[{"name":"scrim","doc":"How dark the page goes behind the spotlight.","default":"soft","values":[{"name":"soft","doc":""},{"name":"strong","doc":""}]}],"story":{"title":"Communication/Tour","category":"Communication","own":true,"stories":["Playground","A tour of a dashboard","Steps that change the page","Long page","Nowhere to put the card","Across pages","Restyled"]},"props":[{"name":"steps","optional":true,"type":"TourStep[]","bindable":false,"doc":"The steps. Omit it when `tour` is given — the controller holds them.","details":[],"examples":[]},{"name":"tour","optional":true,"type":"TourController","bindable":false,"doc":"A controller from `createTour`, holding `steps`, `open` and `index` outside the component. Use one when the tour crosses pages: the state lives in the controller (and, with an `id`, in storage), so a real navigation resumes the tour where it was instead of ending it.","details":[],"examples":[{"lang":"svelte","code":"<Tour {tour} />"}]},{"name":"open","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Whether the tour is running. Bindable. Ignored when `tour` is given.","details":[],"examples":[]},{"name":"index","optional":true,"type":"number","default":"0","bindable":true,"doc":"Which step, from 0. Bindable. Setting it to a step whose target is missing lands on the next one that resolves. Ignored when `tour` is given.","details":[],"examples":[]},{"name":"scrim","optional":true,"type":"TourScrim","default":"'soft'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"padding","optional":true,"type":"number","default":"8","bindable":false,"doc":"Default breathing room around a target, in px.","details":[],"examples":[]},{"name":"width","optional":true,"type":"number | string","default":"320","bindable":false,"doc":"Card width. A number is px, a string any CSS length.","details":[],"examples":[]},{"name":"dismissible","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Let `Escape` and a click on the scrim end the tour.","details":[],"examples":[]},{"name":"dots","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Show the progress dots.","details":[],"examples":[]},{"name":"progress","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Show the slim progress bar under the header.","details":[],"examples":[]},{"name":"labels","optional":true,"type":"{ next?: string; back?: string; done?: string; skip?: string }","bindable":false,"doc":"Button text.","details":[],"examples":[]},{"name":"scrollIntoView","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Bring each target into view before pointing at it.","details":[],"examples":[]},{"name":"wait","optional":true,"type":"number","default":"0","bindable":false,"doc":"How long to wait, in ms, for a step's target to appear before the step is treated as missing and skipped. `0` looks once. Raise it for targets that arrive with a fetch; a step with a `path` waits anyway.","details":[],"examples":[]},{"name":"navigate","optional":true,"type":"(path: string) => void | Promise<void>","bindable":false,"doc":"How a step's `path` is followed. `goto` from `$app/navigation` in a SvelteKit app; a full page load otherwise, which a tour with an `id` survives.","details":[],"examples":[]},{"name":"onfinish","optional":true,"type":"() => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onskip","optional":true,"type":"(index: number) => void","bindable":false,"doc":"","details":[],"examples":[]},{"name":"onstep","optional":true,"type":"(index: number, step: TourStep) => void","bindable":false,"doc":"Fires once per step shown, after its target has been found.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"TourClasses","bindable":false,"doc":"","details":[],"examples":[]}]},{"name":"TreemapChart","dir":"chart","entry":"omaris/chart","importPath":"import { TreemapChart } from 'omaris/chart'","summary":"Treemap — a part-of-a-whole where the parts are too many, or too lopsided, for a pie.","details":["`group` adds the one level of nesting worth having: rows are gathered into blocks, each block gets a colour and a caption, and the rows inside it are shaded from it. Deeper than that and a treemap stops being readable, so it doesn't take a tree.","Labels are dropped from any tile too small to hold them rather than clipped, because half a word is worse than none."],"examples":[{"lang":"svelte","code":"<TreemapChart data={spend} />"}],"classesType":null,"parts":[],"variants":[],"story":{"title":"Data Display/Charts","category":"Data Display","own":false,"stories":["Area","Line","Bar","Pie and donut","Scatter","Sparkline","Empty","References and annotations","Brush and zoom","Legend isolate and CSV","Error","Combo","Radar","Radial bar and gauge","Funnel","Treemap","Candlestick"]},"props":[{"name":"data","optional":false,"type":"T[]","bindable":false,"doc":"","details":[],"examples":[]},{"name":"label","optional":true,"type":"Field<T>","default":"'label'","bindable":false,"doc":"Field naming each tile. Defaults to `row.label`.","details":[],"examples":[]},{"name":"value","optional":true,"type":"Field<T>","default":"'value'","bindable":false,"doc":"Field holding each tile's size. Defaults to `row.value`.","details":[],"examples":[]},{"name":"group","optional":true,"type":"Field<T>","bindable":false,"doc":"Field gathering rows into blocks.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","default":"300","bindable":false,"doc":"Plot height. A number is px; a string is any CSS length.","details":[],"examples":[]},{"name":"gap","optional":true,"type":"number","default":"2","bindable":false,"doc":"Gap between tiles, in px.","details":[],"examples":[]},{"name":"radius","optional":true,"type":"number","default":"4","bindable":false,"doc":"Corner radius on the tiles, in px.","details":[],"examples":[]},{"name":"values","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Print each tile's value under its name.","details":[],"examples":[]},{"name":"tooltip","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"","details":[],"examples":[]},{"name":"format","optional":true,"type":"(value: number) => string","bindable":false,"doc":"How each value reads.","details":[],"examples":[]},{"name":"colors","optional":true,"type":"readonly string[]","default":"CHART_COLORS","bindable":false,"doc":"Palette override, cycled across the tiles or the groups.","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"Accessible description of what the chart shows.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"empty","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]},{"name":"emptyText","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"error","optional":true,"type":"boolean | string | Error","bindable":false,"doc":"Something went wrong. Truthy puts the chart into its error state; a string or an `Error` supplies the message.","details":[],"examples":[]},{"name":"errorText","optional":true,"type":"string","bindable":false,"doc":"The message, when `error` is just `true`.","details":[],"examples":[]},{"name":"errorState","optional":true,"type":"Snippet<[{ message: string }]>","bindable":false,"doc":"Replaces the whole error state.","details":[],"examples":[]},{"name":"onRetry","optional":true,"type":"() => void","bindable":false,"doc":"Offers a \"Try again\" button in the error state.","details":[],"examples":[]},{"name":"csv","optional":true,"type":"boolean | string","default":"false","bindable":false,"doc":"Offer the plotted rows as a CSV download, from a button in the corner. A string names the file.","details":[],"examples":[]},{"name":"csvColumns","optional":true,"type":"(string | { key: string; label?: string; value?: (row: T) => unknown })[]","bindable":false,"doc":"Which fields the download writes, in order. Defaults to every field.","details":[],"examples":[]}]},{"name":"TreeView","dir":"tree-view","entry":"omaris","importPath":"import { TreeView } from 'omaris'","summary":"A tree of rows you can open, close and walk with the keyboard.","details":["Files are the obvious use and not the only one — a category tree, an org chart, a JSON path, a set of nested filters all have the same shape. It is data-driven rather than composed, because a tree is almost always rendered from something recursive and writing the recursion by hand at every call site is how the ARIA comes out wrong.","Keyboard: ↑↓ walk the open rows, → opens a branch then steps into it, ← closes it then steps out, Home/End jump, typing jumps to a matching row, Enter picks. One tab stop for the whole tree."],"examples":[{"lang":"svelte","code":"<TreeView {items} bind:expanded bind:selected onselect={open} />\n<TreeView {items} checkable bind:checked />"}],"classesType":"TreeViewClasses","parts":[{"name":"root","doc":""},{"name":"item","doc":"One row. `data-selected` and `data-active` mark its state."},{"name":"toggle","doc":"The chevron. Rotates a quarter turn when the branch opens."},{"name":"icon","doc":"The leading icon — a folder, a file, or your own."},{"name":"label","doc":"The row's text. Truncates; there is no room to wrap a tree."},{"name":"meta","doc":"The trailing `meta` text."},{"name":"check","doc":"The checkbox drawn when `checkable`."},{"name":"group","doc":"The children of an open branch."},{"name":"guide","doc":"The hairline down the left of a branch's children."}],"variants":[{"name":"size","doc":"","default":"md","values":[{"name":"sm","doc":""},{"name":"md","doc":""}]},{"name":"guides","doc":"Draw the vertical rules that tie a branch's children together.","default":"true","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Data Display/Tree View","category":"Data Display","own":true,"stories":["Playground","Files","Checkable","Loaded on open","Dense, no icons","No guides","Empty","Overridden"]},"props":[{"name":"items","optional":true,"type":"TreeNode[]","default":"[]","bindable":false,"doc":"The tree.","details":[],"examples":[]},{"name":"expanded","optional":true,"type":"string[]","default":"[]","bindable":true,"doc":"Ids of the open branches. Bindable.","details":[],"examples":[]},{"name":"selected","optional":true,"type":"string | null","default":"null","bindable":true,"doc":"Id of the selected row, or `null`. Bindable.","details":[],"examples":[]},{"name":"checked","optional":true,"type":"string[]","default":"[]","bindable":true,"doc":"Ids of the ticked **leaves** — rows with no children. A branch's own state is worked out from them, so a half-ticked folder is a state you never have to store. Bindable.","details":[],"examples":[]},{"name":"checkable","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Give every row a checkbox and tick branches through their leaves.","details":[],"examples":[]},{"name":"size","optional":true,"type":"TreeViewSize","default":"'md'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"guides","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Draw the vertical rules down each open branch.","details":[],"examples":[]},{"name":"icons","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Use the built-in folder and file icons for rows with no `icon`.","details":[],"examples":[]},{"name":"defaultExpanded","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Open every branch on first render.","details":[],"examples":[]},{"name":"label","optional":true,"type":"string","bindable":false,"doc":"Accessible name for the tree.","details":[],"examples":[]},{"name":"onselect","optional":true,"type":"(node: TreeNode) => void","bindable":false,"doc":"Fires when a row is picked — clicked, or Enter on the keyboard.","details":[],"examples":[]},{"name":"onexpand","optional":true,"type":"(node: TreeNode) => void","bindable":false,"doc":"Fires when a branch opens. The place to fetch its children.","details":[],"examples":[]},{"name":"oncollapse","optional":true,"type":"(node: TreeNode) => void","bindable":false,"doc":"Fires when a branch closes.","details":[],"examples":[]},{"name":"row","optional":true,"type":"Snippet<[TreeNode, { depth: number; expanded: boolean; selected: boolean }]>","bindable":false,"doc":"Replaces a row's contents, after the chevron and the checkbox.","details":[],"examples":[]},{"name":"empty","optional":true,"type":"Snippet","bindable":false,"doc":"Shown when `items` is empty.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"TreeViewClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"VideoPlayer","dir":"video-player","entry":"omaris","importPath":"import { VideoPlayer } from 'omaris'","summary":"A video player with its own chrome.","details":["The native controls are a different design system on every platform, so this draws its own: a scrubber whose played half is MD3 Expressive's travelling wave — it rolls while the video plays and flattens the moment you grab it — buffered ranges behind it, chapter marks on top, and a bubble that follows the pointer.","Under the chrome it stays a real `<video>`: every control is a button, both sliders are `<input type=\"range\">` (so keyboard, touch and screen readers work without being re-implemented), and the shortcuts are the ones people already know.","Keys: `space`/`k` play, `←`/`→` ±5s, `j`/`l` ±10s, `↑`/`↓` volume, `m` mute, `c` captions, `f` fullscreen, `0`–`9` jump to a tenth. Click toggles play, double-click goes fullscreen; on touch, a double tap on either half seeks that way."],"examples":[{"lang":"svelte","code":"<VideoPlayer src=\"/clip.mp4\" poster=\"/clip.jpg\" title=\"Onboarding\" />"}],"classesType":"VideoPlayerClasses","parts":[{"name":"root","doc":""},{"name":"video","doc":""},{"name":"surface","doc":"Catches clicks and taps; the controls sit above it."},{"name":"chrome","doc":"Everything that fades out when the player goes idle."},{"name":"top","doc":"Top scrim: title and the actions that belong up there."},{"name":"title","doc":""},{"name":"bottom","doc":"Bottom scrim: scrubber, then the control row."},{"name":"seek","doc":"The scrubber's hit area — taller than the track it draws."},{"name":"track","doc":""},{"name":"range","doc":"Native range on top of the painted track — free a11y and dragging."},{"name":"handle","doc":"The dot at the play head."},{"name":"bubble","doc":"Time (and chapter) bubble that tracks the pointer."},{"name":"controls","doc":""},{"name":"button","doc":"One chrome button."},{"name":"menu","doc":"Speed / captions popover."},{"name":"menuItem","doc":""},{"name":"center","doc":"The big centre button, and the seek pills either side of it."},{"name":"pill","doc":""}],"variants":[{"name":"rounded","doc":"Corner style. `none` is for a player that fills a page.","default":"lg","values":[{"name":"none","doc":""},{"name":"md","doc":""},{"name":"lg","doc":""},{"name":"xl","doc":""}]},{"name":"fit","doc":"How the frame fills the box.","default":"contain","values":[{"name":"contain","doc":""},{"name":"cover","doc":""}]},{"name":"idle","doc":"Chrome state — driven by idleness, not by CSS `:hover`.","default":"false","values":[{"name":"true","doc":""},{"name":"false","doc":""}]}],"story":{"title":"Data display/VideoPlayer","category":"Data Display","own":true,"stories":["Playground","Minimal","Chapters","Captions","Start time and download","Side by side","Cover"]},"props":[{"name":"src","optional":false,"type":"string | VideoSource[]","bindable":false,"doc":"One URL, or several encodings for the browser to choose from.","details":[],"examples":[]},{"name":"poster","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"title","optional":true,"type":"string","bindable":false,"doc":"Shown in the top scrim, and used as the accessible name.","details":[],"examples":[]},{"name":"aspect","optional":true,"type":"string | number","default":"'16/9'","bindable":false,"doc":"`16/9` by default. Any CSS aspect ratio, or a number.","details":[],"examples":[]},{"name":"rounded","optional":true,"type":"VideoPlayerRounded","default":"'lg'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"fit","optional":true,"type":"VideoPlayerFit","default":"'contain'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"start","optional":true,"type":"number","default":"0","bindable":false,"doc":"Second to open at.","details":[],"examples":[]},{"name":"chapters","optional":true,"type":"VideoChapter[]","default":"[]","bindable":false,"doc":"","details":[],"examples":[]},{"name":"tracks","optional":true,"type":"VideoTrack[]","default":"[]","bindable":false,"doc":"","details":[],"examples":[]},{"name":"speeds","optional":true,"type":"number[]","default":"[0.5, 0.75, 1, 1.25, 1.5, 2]","bindable":false,"doc":"Rates the speed menu offers.","details":[],"examples":[]},{"name":"pip","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Offer picture-in-picture, where the browser has it.","details":[],"examples":[]},{"name":"fullscreen","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Offer the fullscreen button.","details":[],"examples":[]},{"name":"download","optional":true,"type":"boolean | string","default":"false","bindable":false,"doc":"Offer a download link — `true` uses `src`, a string names the file.","details":[],"examples":[]},{"name":"idleAfter","optional":true,"type":"number","default":"2600","bindable":false,"doc":"Hide the chrome after this many ms of stillness. `0` keeps it up.","details":[],"examples":[]},{"name":"paused","optional":true,"type":"boolean","default":"true","bindable":true,"doc":"Bindable.","details":[],"examples":[]},{"name":"currentTime","optional":true,"type":"number","default":"0","bindable":true,"doc":"Bindable, in seconds.","details":[],"examples":[]},{"name":"volume","optional":true,"type":"number","default":"1","bindable":true,"doc":"Bindable, 0–1.","details":[],"examples":[]},{"name":"muted","optional":true,"type":"boolean","default":"false","bindable":true,"doc":"Bindable.","details":[],"examples":[]},{"name":"ref","optional":true,"type":"HTMLVideoElement | null","default":"null","bindable":true,"doc":"Bindable — the underlying `<video>`.","details":[],"examples":[]},{"name":"actions","optional":true,"type":"Snippet","bindable":false,"doc":"Extra controls, at the end of the control row.","details":[],"examples":[]},{"name":"cover","optional":true,"type":"Snippet","bindable":false,"doc":"Covers the frame before the first play — a custom poster.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"VideoPlayerClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"VirtualList","dir":"virtual-list","entry":"omaris","importPath":"import { VirtualList } from 'omaris'","summary":"A windowed list: ten thousand rows, and only the thirty on screen exist.","details":["The canvas is sized to the whole list, so the scrollbar tells the truth about how much there is, and the visible slice is one block translated down to where it belongs. Scrolling moves one `translate` and swaps a handful of keyed rows at the edges — nothing is laid out that is not on screen, which is what keeps it at 60fps on a phone.","**Rows can be any height.** Each one is measured by a single shared `ResizeObserver` the moment it renders, and the measurement is cached by key, so a row that grows when its image loads, or wraps differently at a new width, moves everything under it and nothing above it. Until a row has been seen it is assumed to be `estimateSize` tall; the closer the guess, the less the scrollbar thumb resizes as you go. When a row above the viewport turns out taller or shorter than guessed, the scroll position is corrected by the difference, so what you are reading does not jump.","It scrolls itself. Put it in a parent with a height and it fills it, or give it `height`. With neither, it stops at the height of the screen rather than growing to the height of the data — a list ten thousand rows tall with nothing to scroll it would render every one of them.","Infinite scroll is `onend`: it fires once when the end comes within `endThreshold` px, and again only after `items` has grown. Pass `loading` while there is more to fetch, and it is drawn after the last row."],"examples":[{"lang":"svelte","code":"<VirtualList items={rows} estimateSize={56} getKey={(row) => row.id} height={480}>\n  {#snippet children(row, index)}\n    <ListItem headline={row.name} supporting={row.email} />\n  {/snippet}\n</VirtualList>"}],"classesType":"VirtualListClasses","parts":[{"name":"root","doc":""},{"name":"canvas","doc":"Sized to the whole list, so the scrollbar is honest while rows are virtual — and the element that carries `role` and the accessible name, so the list holds its rows and nothing else."},{"name":"window","doc":"The rendered slice, translated to where it starts."},{"name":"item","doc":"The wrapper round each row — what gets measured."},{"name":"loading","doc":"Holds the `loading` snippet, after the last row."},{"name":"empty","doc":"Holds the `empty` snippet when there are no items."}],"variants":[{"name":"horizontal","doc":"","default":"false","values":[{"name":"false","doc":""},{"name":"true","doc":""}]}],"story":{"title":"Data Display/Virtual List","category":"Data Display","own":true,"stories":["Ten thousand rows","Fills its parent","Scroll to index","Infinite scroll","Horizontal","Empty","Overridden"]},"props":[{"name":"items","optional":false,"type":"T[]","bindable":false,"doc":"Everything in the list. Only the rows in view are rendered.","details":[],"examples":[]},{"name":"children","optional":false,"type":"Snippet<[T, number]>","bindable":false,"doc":"One row. Handed the item and its index in `items`.","details":[],"examples":[]},{"name":"estimateSize","optional":true,"type":"number | ((index: number) => number)","default":"48","bindable":false,"doc":"The size of a row not yet measured, in px — height, or width when `horizontal`. A function gets the index, for lists whose rows come in known kinds. Rows are measured as they render; this only has to be close.","details":[],"examples":[]},{"name":"overscan","optional":true,"type":"number","default":"6","bindable":false,"doc":"Rows rendered beyond each edge of the viewport, so a fast flick never shows a gap.","details":[],"examples":[]},{"name":"getKey","optional":true,"type":"(item: T, index: number) => string | number","bindable":false,"doc":"A stable key per item. Measurements are cached under it, so a list that is prepended to or re-sorted keeps its measured sizes. Defaults to the index.","details":[],"examples":[]},{"name":"gap","optional":true,"type":"number","default":"0","bindable":false,"doc":"Space between rows, in px.","details":[],"examples":[]},{"name":"horizontal","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Lay the rows out side by side and scroll sideways.","details":[],"examples":[]},{"name":"height","optional":true,"type":"number | string","bindable":false,"doc":"Height of the scroller. A number is px, a string any CSS length. Defaults to `100%` — fill a parent that has a height — and to `auto` when `horizontal`. A property rather than a class, so `classes.root` can still replace it.","details":[],"examples":[]},{"name":"onend","optional":true,"type":"() => void","bindable":false,"doc":"Called when the end comes within `endThreshold` px — the hook for infinite scroll. Fires once per length of `items`, so appending a page re-arms it.","details":[],"examples":[]},{"name":"endThreshold","optional":true,"type":"number","default":"400","bindable":false,"doc":"How far before the end `onend` fires, in px.","details":[],"examples":[]},{"name":"loading","optional":true,"type":"Snippet","bindable":false,"doc":"Drawn after the last row — pass it while there is more to load. With no items yet it is drawn instead of `empty`: the first page on its way is not an empty list.","details":[],"examples":[]},{"name":"empty","optional":true,"type":"Snippet","bindable":false,"doc":"Drawn in place of the list when `items` is empty.","details":[],"examples":[]},{"name":"itemRole","optional":true,"type":"string","bindable":false,"doc":"Role of each row's wrapper. Defaults to `listitem` under the default `role=\"list\"`, and to none under any other role — a `listbox` brings its own `option`s.","details":[],"examples":[]},{"name":"onscroll","optional":true,"type":"(event: Event) => void","bindable":false,"doc":"Called on every scroll, after the window has been updated.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"VirtualListClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]}]},{"name":"Workspace","dir":"workspace","entry":"omaris","importPath":"import { Workspace } from 'omaris'","summary":"A dockable workspace: panels in tabbed groups, split any way, dragged anywhere, floated into windows, maximized, and remembered.","details":["Every group is drawn absolutely from pure maths on the layout tree, and every panel's content is one element that never leaves its place in the DOM — the workspace only moves the box it is drawn in. So nothing a panel holds is ever unmounted by a rearrangement: an iframe keeps its page, a video keeps playing, a form keeps what was typed, a list its scroll. And because the geometry is CSS rather than measurement, a group flies to its new place under a transition in the same frame the tree changes."],"examples":[],"classesType":"WorkspaceClasses","parts":[{"name":"root","doc":""},{"name":"stage","doc":"The area groups are drawn in, inset half a gap so the outer margin matches the inner."},{"name":"group","doc":"A group of tabs: the card behind a panel."},{"name":"header","doc":"The strip along the top of a group: tabs, then tools."},{"name":"tabs","doc":""},{"name":"tab","doc":"One tab: the pill around the label and the close button."},{"name":"tabButton","doc":"The label part of a tab — the `role=\"tab\"` button."},{"name":"close","doc":"The × on a tab, and the unsaved dot that stands in for it."},{"name":"badge","doc":""},{"name":"tools","doc":"The panel's own actions, maximize and the menu, at the end of the header."},{"name":"sash","doc":"The divider between two groups — and the thing you drag."},{"name":"preview","doc":"Where a dragged tab will land, drawn over the workspace while you drag."},{"name":"caret","doc":"The line between two tabs where a dropped tab goes."},{"name":"ghost","doc":"What follows the pointer while a tab is dragged."},{"name":"handle","doc":"A floating window's resize edges and corners."},{"name":"empty","doc":"What shows when nothing is open."}],"variants":[{"name":"variant","doc":"","default":"cards","values":[{"name":"cards","doc":"MD3 surfaces: rounded cards with a gap between them."},{"name":"flush","doc":"Edge to edge with hairlines between, the way an IDE packs its panes."}]}],"story":{"title":"Layout/Workspace","category":"Layout","own":true,"stories":["Playground","Flush","Floating","Maximized","Compact","Toggles","Documents","ControlledAndHistory","Empty","Locked","Overridden"]},"props":[{"name":"layout","optional":true,"type":"WorkspaceLayout","bindable":true,"doc":"The layout, bindable. Leave it out and the workspace keeps its own, starting from `defaultLayout`; bind it to save it yourself, or to switch between presets by assigning one.","details":[],"examples":[]},{"name":"defaultLayout","optional":true,"type":"WorkspaceLayoutInput","bindable":false,"doc":"Where the panels start, and what `reset()` goes back to. Write it with `row`, `column` and `tabs`: `row('files', column('editor', 'terminal'), { sizes: [20, 80] })`. Left out, every panel sits side by side in the order declared.","details":[],"examples":[]},{"name":"storageKey","optional":true,"type":"string","bindable":false,"doc":"Saves the layout in `localStorage` under this key and restores it on load.","details":[],"examples":[]},{"name":"variant","optional":true,"type":"WorkspaceVariant","default":"'cards'","bindable":false,"doc":"","details":[],"examples":[]},{"name":"compactBelow","optional":true,"type":"number","default":"600","bindable":false,"doc":"Below this width, in px, every panel becomes a tab in one full-size stack — the workspace on a phone. `0` never stacks.","details":[],"examples":[]},{"name":"locked","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Nothing moves: no dragging, resizing, closing or floating. Tabs still switch.","details":[],"examples":[]},{"name":"floating","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Panels may leave the tree for floating windows.","details":[],"examples":[]},{"name":"maximizable","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Groups may be maximized to fill the workspace.","details":[],"examples":[]},{"name":"labels","optional":true,"type":"Partial<WorkspaceLabels>","bindable":false,"doc":"","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"","details":[],"examples":[]},{"name":"classes","optional":true,"type":"WorkspaceClasses","bindable":false,"doc":"Per-part Tailwind overrides. `class` still covers the root.","details":[],"examples":[]},{"name":"empty","optional":true,"type":"Snippet<[{ closed: string[]; show: (id: string) => void }]>","bindable":false,"doc":"What shows when every panel is closed. It gets the closed panels' ids and a way to open one.","details":[],"examples":[]},{"name":"onlayoutchange","optional":true,"type":"(layout: WorkspaceLayout) => void","bindable":false,"doc":"Fires after every change the person makes — a move, a resize, a close.","details":[],"examples":[]},{"name":"onactivate","optional":true,"type":"(id: string) => void","bindable":false,"doc":"A panel was brought to the front.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"The `WorkspacePanel`s.","details":[],"examples":[]}]},{"name":"WorkspacePanel","dir":"workspace","entry":"omaris","importPath":"import { WorkspacePanel } from 'omaris'","summary":"One panel of a `Workspace`: a title for its tab, and the content.","details":["The content is rendered here, once, and stays here — the workspace only moves the box it is drawn in. That is why dragging a panel to another group, into a window, or out to an edge never remounts it. A panel's content mounts the first time it is shown and stays mounted while it is in the layout; `keepAlive` keeps it mounted after it is closed as well."],"examples":[],"classesType":null,"parts":[],"variants":[],"story":{"title":"Layout/Workspace","category":"Layout","own":false,"stories":["Playground","Flush","Floating","Maximized","Compact","Toggles","Documents","ControlledAndHistory","Empty","Locked","Overridden"]},"props":[{"name":"id","optional":false,"type":"string","bindable":false,"doc":"Names the panel in the layout. Unique within the workspace.","details":[],"examples":[]},{"name":"title","optional":false,"type":"string","bindable":false,"doc":"What its tab says.","details":[],"examples":[]},{"name":"icon","optional":true,"type":"Snippet","bindable":false,"doc":"Leading icon for the tab.","details":[],"examples":[]},{"name":"badge","optional":true,"type":"number | string | boolean","bindable":false,"doc":"A count or short word after the title, or `true` for a dot.","details":[],"examples":[]},{"name":"modified","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Unsaved changes: a dot where the close button sits until it is hovered.","details":[],"examples":[]},{"name":"closable","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"Has a close button, and Delete closes it.","details":[],"examples":[]},{"name":"movable","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"May be dragged, split off and moved with the keyboard.","details":[],"examples":[]},{"name":"floatable","optional":true,"type":"boolean","default":"true","bindable":false,"doc":"May go into a floating window.","details":[],"examples":[]},{"name":"minWidth","optional":true,"type":"number","default":"160","bindable":false,"doc":"Smallest width its group may be dragged to, in px.","details":[],"examples":[]},{"name":"minHeight","optional":true,"type":"number","default":"80","bindable":false,"doc":"Smallest height of its content, in px — the tab strip comes on top.","details":[],"examples":[]},{"name":"keepAlive","optional":true,"type":"boolean","default":"false","bindable":false,"doc":"Stay mounted, hidden, while closed — for a panel that is slow to build.","details":[],"examples":[]},{"name":"open","optional":true,"type":"boolean","bindable":true,"doc":"Bindable: whether the panel is in the layout. Set it to open or close the panel from outside — a toolbar toggle, a menu of checkboxes.","details":[],"examples":[]},{"name":"placement","optional":true,"type":"WorkspacePlacement","bindable":false,"doc":"Where it goes when `open` is set and it has no remembered place.","details":[],"examples":[]},{"name":"actions","optional":true,"type":"Snippet","bindable":false,"doc":"Buttons for the group's header while this panel is on show — a refresh, a filter.","details":[],"examples":[]},{"name":"onclose","optional":true,"type":"() => boolean | void | Promise<boolean | void>","bindable":false,"doc":"Asked before closing: return `false`, or a promise of it, to keep the panel.","details":[],"examples":[]},{"name":"class","optional":true,"type":"string","bindable":false,"doc":"Covers the content box: padding, a background, a layout.","details":[],"examples":[]},{"name":"children","optional":true,"type":"Snippet","bindable":false,"doc":"","details":[],"examples":[]}]}]}