diff --git a/apps/docs/content/docs/components/actions/button.mdx b/apps/docs/content/docs/components/actions/button.mdx index 2f14a3ee..1b8c3d07 100644 --- a/apps/docs/content/docs/components/actions/button.mdx +++ b/apps/docs/content/docs/components/actions/button.mdx @@ -1,97 +1,103 @@ --- title: Button -description: Action button with semantic tone and appearance options. +description: A labelled control for actions in an interface. --- -`Button` expects the Luke UI theme class at the app or root level. See -[Getting Started](/docs/getting-started). +`Button` triggers an action, such as saving a form, opening a dialog, or deleting an item. Use +[`Link`](/components/actions/link) when the interaction takes someone to another URL or route. ```tsx - +import { Button } from '@luke-ui/react/button'; + +; ``` -## Best practices +## Appearance + +Use `appearance` to set a button's visual weight. `solid` is the default. Choose `subtle` or `ghost` +for secondary actions that should recede beside the main action. Appearance sets emphasis; it does +not communicate intent. -| Guidance | Practices | -| -------- | -------------------------------------------------------------------------------------------------------------- | -| Do | Use `tone="accent"` for the main action. Use a subtle or ghost appearance for secondary actions. | -| Do | Write a label that names the action, such as "Save changes" or "Delete account". Avoid vague labels like "OK". | -| Do | Set `isPending` while an action is in flight so the user can see that work is still happening. | -| Don't | Use `Button` for navigation. If the control only moves the user to another page, use `Link`. | + -## Tone and appearance +## Tone -Tone communicates intent: `neutral` (default), `accent`, or `danger`. Appearance controls emphasis: -`solid` (default), `subtle`, or `ghost`. Every tone supports every appearance. +Use `tone` to communicate intent. `neutral` is the default, `accent` identifies a primary action, +and `danger` marks a destructive one. Tone and appearance are independent, so every combination is +available. ## Size -`Button` has two sizes: `medium` (default) and `small`. +`medium` is the default size. Use `small` in dense toolbars, tables, and other compact interfaces. +Keep related controls at the same size. -## Icons +## Block layout -Use `startIcon` and `endIcon` to place an icon before or after the label. The icon inherits the -button size, so the icon does not need its own `size` prop. +Set `isBlock` when the button should fill the inline size of its container. This is useful for a +primary action at the end of a narrow form or panel. ```tsx -import { Icon } from '@luke-ui/react/icon'; - -; + ``` -## Disabled +## Icons -Disabled buttons cannot be focused or pressed. +Use `startIcon` or `endIcon` with a visible label. `Button` supplies the icon size, so the nested +`Icon` does not need its own `size` prop. Use [`IconButton`](/components/actions/icon-button) only +when the icon is familiar without a text label. ```tsx - +import { Icon } from '@luke-ui/react/icon'; + +; ``` -## Pending +## Pending and disabled states -Set `isPending` while an action is in flight. A spinner replaces the label. The button remains -focusable and reports its pending state, but cannot be pressed again. It uses the same muted visual -treatment as a disabled button while keeping the spinner visible. +Set `isPending` while an action is running. The button remains focusable, ignores further presses, +and overlays its label with a spinner. Update the visible label when the status matters, for example +from “Save” to “Saving”. + +Set `isDisabled` only when the action is unavailable. Disabled buttons cannot receive focus or be +pressed. -## Full width - -Set `isBlock` to make the button fill the inline size of its container. - -```tsx - -``` - ## Accessibility -`Button` wraps its children in `Text`, so visible text usually provides the accessible name. You -normally do not need `aria-label`. +The visible label provides the accessible name, so most buttons do not need `aria-label`. Write a +label that describes the action, such as “Save changes” or “Delete account”, rather than a vague +label such as “OK”. -The pending spinner is `aria-hidden` and does not announce busy state to screen readers. If screen -reader users need to hear the pending state, change the label text itself, for example to "Saving", -while `isPending` is set. +The spinner is hidden from assistive technology. Change the label when pending status needs to be +announced. -## Primitive +## Button primitive -Use the [button primitive](/docs/components/primitives/button) when you need full control over -children, custom loading states, render-prop children, or non-standard content. +`Button` is the composed component for application UI. It wraps its label for truncation, provides +icon slots, and supplies the pending spinner. Use the +[button primitive](/components/primitives/button) when building a custom control and you need to own +the child layout or loading treatment. ## Props diff --git a/apps/docs/content/docs/components/actions/icon-button.mdx b/apps/docs/content/docs/components/actions/icon-button.mdx index c8173473..6a04934c 100644 --- a/apps/docs/content/docs/components/actions/icon-button.mdx +++ b/apps/docs/content/docs/components/actions/icon-button.mdx @@ -1,61 +1,56 @@ --- title: Icon Button -description: Compact icon-only action button with an accessible label. +description: A compact icon-only control for an action. --- -Use `IconButton` for compact actions where an icon can carry the visible UI. Always provide an -accessible label. +`IconButton` triggers a familiar compact action, such as closing a panel, deleting a row, or adding +an item. Give every icon button an accessible name because it has no visible label. ```tsx - +import { IconButton } from '@luke-ui/react/icon-button'; + +; ``` -## Best practices +## Accessibility + +Provide `aria-label` or `aria-labelledby` for every icon button. Name the action, not the icon. + +```tsx + +``` -| Guidance | Practices | -| -------- | ---------------------------------------------------------------------------- | -| Do | Name the action in `aria-label`, such as "Delete row". Do not name the icon. | -| Do | Use `tone="danger"` for destructive icon actions such as delete. | +Use a labelled [`Button`](/components/actions/button) when the icon is unfamiliar or visible text +would make the action clearer. -## Tone and appearance +## Appearance -`IconButton` shares Button's appearance API. Tone can be `neutral` (default), `accent`, or `danger`. -Appearance can be `solid` (default), `subtle`, or `ghost`. +`IconButton` uses the same `tone` and `appearance` options as +[`Button`](/components/actions/button). Use `danger` for a destructive action. Choose `subtle` or +`ghost` when a secondary control needs less emphasis. ## Size +`medium` is the default. Use `small` for compact toolbars and dense row actions. Keep controls in a +group at the same size. + -## Pending - -Set `isPending` while an action is in flight. The button remains focusable but cannot be pressed -again. It uses the disabled visual treatment and replaces the icon with a busy cue. - -## Accessibility - -`IconButton` has no visible text label. Always provide `aria-label` or `aria-labelledby`. Without -one, screen readers have no way to announce the button's purpose. - -```tsx - -``` - -## When to use vs Button - -Use `IconButton` when the icon alone communicates the action and space is tight, such as in -toolbars, table row actions, or close buttons. +## Pending and disabled states -Use `Button` when you need a visible text label. Labels are clearer for unfamiliar users. +Set `isPending` while an action is running. The control remains focusable, ignores further presses, +and replaces its icon with a busy cue. Set `isDisabled` when the action is unavailable. Disabled +controls cannot receive focus or be pressed. ## Props diff --git a/apps/docs/content/docs/components/actions/link.mdx b/apps/docs/content/docs/components/actions/link.mdx index 0191956e..7e771d87 100644 --- a/apps/docs/content/docs/components/actions/link.mdx +++ b/apps/docs/content/docs/components/actions/link.mdx @@ -1,65 +1,57 @@ --- title: Link -description: Link component for inline and standalone navigation. +description: A styled link for inline and standalone navigation. --- -`Link` expects the Luke UI theme class at the app or root level. See -[Getting Started](/docs/getting-started). +`Link` navigates to another URL or route. Use [`Button`](/components/actions/button) for an action +such as saving, submitting, or opening a dialog. ```tsx -Help center -``` - -## Best practices +import { Link } from '@luke-ui/react/link'; -| Guidance | Practices | -| -------- | ---------------------------------------------------------------------------------------------------------------------------------- | -| Do | Use the default `accent` tone for links that should draw attention. | -| Do | Use `isStandalone` for links that are not part of a sentence, such as card links and nav items. Leave it `false` for inline links. | +Help centre; +``` ## Tone -`Link` has two tones: `accent` (default) and `neutral`. Use `neutral` when the surrounding content -should have more emphasis. +`accent` is the default tone and draws attention to the destination. Use `neutral` when a link sits +within content that needs more visual emphasis. -## Standalone +## Inline and standalone links -Use `isStandalone` when a link stands on its own. Leave it `false` for links inside paragraph text. +Use the default link inside a sentence. Its underline remains visible so people can recognise it in +running text. -- `isStandalone={true}`: no underline until hover or press and a structural target of at least 24 × - 24 CSS pixels. -- `isStandalone={false}`: underlined inline link style that retains the target-size exception for - links within prose. +Set `isStandalone` for a link outside prose, such as a card link or navigation item. Standalone +links show their underline on hover or press and have a 24 × 24 CSS-pixel structural target. -## Disabled +## Disabled links + +Set `isDisabled` only when a destination is temporarily unavailable. A disabled link cannot receive +focus or be activated. Explain why nearby when someone needs that information. ## Accessibility -Screen readers announce a disabled link as unavailable, but not why. Put the reason in nearby -visible text instead of relying on disabled state alone. - -## When to use vs Button - -Use `Link` to navigate to a new URL or route. Use `Button` for in-page actions, such as saving, -submitting, or opening a dialog. +Write link text that names the destination and makes sense outside its surrounding sentence. Avoid +generic labels such as “Click here”. ## Props diff --git a/apps/docs/content/docs/components/feedback/loading-skeleton.mdx b/apps/docs/content/docs/components/feedback/loading-skeleton.mdx index 489bfa5a..4bd1f11c 100644 --- a/apps/docs/content/docs/components/feedback/loading-skeleton.mdx +++ b/apps/docs/content/docs/components/feedback/loading-skeleton.mdx @@ -1,91 +1,81 @@ --- title: Loading Skeleton -description: Loading placeholder that keeps the same footprint as the final content. +description: Replaces content with a placeholder that keeps its shape while it loads. --- -`LoadingSkeleton` expects the Luke UI theme class at the app or root level. See -[Getting Started](/docs/getting-started). - -Use it when loading content should keep the same footprint as the loaded state. Text renders as an -inline skeleton. Elements keep their layout while the skeleton surface is painted over them. +Use `LoadingSkeleton` when content is loading but its layout is known. Wrap the content that will +appear so the placeholder occupies the same space. -All mounted skeletons use the same pulse timing, even when they mount at different times. - -## Best practices - -| Guidance | Practices | -| -------- | ------------------------------------------------------------------------------------------------------------------- | -| Do | Wrap real content so the skeleton matches the final size exactly. | -| Don't | Use `LoadingSkeleton` for content whose final size is unknown. Size mismatch causes layout shift when loading ends. | - -## Loading state - -`isLoading` defaults to `true`. Pass `isLoading={false}` when content is ready. - -```tsx - - - -``` +## With text -## Multi-line text +Wrap text itself, rather than its parent. The placeholder then follows each line of text. If you +wrap the parent element, the skeleton covers the whole block instead. -Wrap text directly when the copy spans more than one line. Each line gets its own skeleton shape. +This matters most for copy that wraps across several lines. `LoadingSkeleton` renders non-element +children inline, so it follows the text without changing the line layout. -## Element type +## With components -`LoadingSkeleton` renders a `span` by default. Use `elementType` when the surrounding markup needs -another element. +Wrap an element to keep its dimensions while the skeleton covers it. Use this for controls, avatars, +and other content with a fixed shape. -## LoadingSkeletonProvider - -Use `LoadingSkeletonProvider` when one loading state controls a group of skeletons. The provider -value overrides descendant `isLoading` props. +Set `radius` when the direct child has square corners but a visible descendant is rounded. This is +useful when a `TextField` is the child because its input control is rounded inside the field +wrapper. -## Border radius +## Loading state + +`isLoading` is `true` by default. Set it to `false` when the content is ready. The component then +returns its children without a wrapper. -Use `borderRadius` when the wrapped child has no radius, but the visible control inside it does. +```tsx + + + +``` + +Use `LoadingSkeletonProvider` when one loading state controls a section. Its value overrides +`isLoading` on every descendant skeleton, so a section changes together. -## Custom dimensions +## Element type -Wrap an element with explicit dimensions when you need a placeholder for a fixed shape, such as an -avatar. +`LoadingSkeleton` renders a `span` by default. Set `elementType` when the parent requires another +element, such as an `li` inside a list. ## Accessibility -While loading, skeleton content is hidden from assistive technology and cannot be focused or -clicked. `LoadingSkeleton` sets `aria-hidden`, `inert`, `tabIndex={-1}`, and disables pointer -events. +While loading, the content is hidden from assistive technology, removed from the tab order, and +cannot receive pointer input. It becomes available again when `isLoading` is `false`. ## Props diff --git a/apps/docs/content/docs/components/feedback/loading-spinner.mdx b/apps/docs/content/docs/components/feedback/loading-spinner.mdx index d67101f9..e0777b5b 100644 --- a/apps/docs/content/docs/components/feedback/loading-spinner.mdx +++ b/apps/docs/content/docs/components/feedback/loading-spinner.mdx @@ -1,50 +1,56 @@ --- title: Loading Spinner -description: Spinner for indeterminate and determinate progress. +description: Animated indicator for work that is still in progress. --- -`LoadingSpinner` expects the Luke UI theme class at the app or root level. See -[Getting Started](/docs/getting-started). +Use `LoadingSpinner` when work is in progress. Omit `value` when you cannot report completion. -All mounted indeterminate spinners rotate and pulse in sync, even when they mount at different -times. +Indeterminate spinners rotate and pulse in sync, including spinners that mount at different times. -## Progress mode +## Progress -Omit `value` for indeterminate progress. Pass `value` for determinate progress. +Pass `value` when you can report progress. `minValue` and `maxValue` set the range and default to +`0` and `100`. Values outside that range are clamped before the indicator is drawn. ## Size +Use `size` to match the surrounding control or content. The default is `medium`. A surrounding icon +size context can also set the size. + -## Color +## Colour + +Use `color` to apply a semantic content colour. When you omit it, the spinner inherits the +surrounding text colour. ## Accessibility -`aria-label` defaults to `"pending"` when omitted. Override it with what is loading, such as -"Loading profile", for a clearer announcement. +The spinner has `progressbar` semantics. Its accessible name defaults to `pending`. Provide an +`aria-label` that names the work, such as `Loading profile`. A determinate spinner also exposes its +current, minimum, and maximum values. ## Props diff --git a/apps/docs/content/docs/components/forms/combobox-field.mdx b/apps/docs/content/docs/components/forms/combobox-field.mdx index 74c7be4f..e7088571 100644 --- a/apps/docs/content/docs/components/forms/combobox-field.mdx +++ b/apps/docs/content/docs/components/forms/combobox-field.mdx @@ -1,138 +1,110 @@ --- title: Combobox Field -description: Single-select combobox field with label, validation, and async options. +description: Searchable single-select field with label, validation, and option list. --- -Use `ComboboxField` for a single-select combobox with label, description, error, popover, listbox, -and optional async loading built in. +Use `ComboboxField` when people need to search for or choose one option from a list. It combines an +input, label, description, validation message, popover, and listbox. -## Best practices +## Items and selection -| Guidance | Practices | -| -------- | ------------------------------------------------------------------------------------------------------- | -| Do | Use `defaultItems` for a static list. Use `items` with `loadingState` when options load asynchronously. | -| Don't | Use `ComboboxField` for multi-select. It is single-select only in v1. | +Use `defaultItems` for a static collection. Use `items` with `loadingState` when results load or +filter asynchronously. `ComboboxField` supports one selected value. Use another component for +multiple selection. -## API shape +## Select and clear an option -- Root props follow React Aria `ComboBox` naming. -- Composed convenience props include `label`, `description`, `errorMessage`, `necessityIndicator`, - `size`, and `placeholder`. -- `children` renders items from `items` or `defaultItems`. -- `listBoxProps` and `loadMoreItem` are lower-level escape hatches. - -## Selection indicators - -The selected option shows a checkmark in the listbox. When the control has a selection, it shows a -clear button before the trigger. Pressing the clear button clears the selection and input text. - -The clear button is omitted when the field is disabled or read-only. +Pass static children or a render function to create options. The listbox marks the selected option. +When there is a selection, the field shows a clear button before the trigger. Clearing removes the +selection and input text. The clear button is unavailable for disabled and read-only fields. ```tsx - + {(item) => {item.label}} ``` ## Required fields -Use `isRequired` with `necessityIndicator` to show that the field is mandatory. +Set `isRequired` to make a selection mandatory. Use `necessityIndicator` to choose how it appears +beside the label. ## Validation -Pass field-level validation through React Aria `Form`. Use `errorMessage` to render the validation -message. +Use `errorMessage` to render a validation message. Pass server errors through React Aria `Form`. ```tsx import { Form } from 'react-aria-components';
validation.validationErrors.join(' ')} + label="Country" + name="country" > {(item) => {item.label}}
; ``` -## Grouped options +## Groups -Use `ComboboxSection` to group related options inside the listbox. +Use `ComboboxSection` to group related static options. -## Async options +## Async results -Pass `loadingState` for built-in loading and empty states. Control the option collection with -`items`. +Pass `items` and `loadingState` when results load or filter asynchronously. If the list is empty +while loading or filtering, the field shows a loading indicator. An empty completed result shows “No +results”. ```tsx {(item) => {item.label}} ``` -## Infinite scroll - -Use `onLoadMore` for automatic sentinel-based loading, or `loadMoreItem` when you need full control -over the load-more row. - -```tsx - - {(item) => {item.label}} - -``` +Pass `onLoadMore` for incremental results. It adds the built-in load-more row and spinner. Use +`loadMoreItem` when that row needs custom content. `listBoxProps` and `popoverProps` configure the +underlying listbox and popover. `menuWidth` sets the popover width. -## Mobile tray +## Mobile behaviour -Below the `small` breakpoint (640px) the popover renders as a bottom tray instead of a positioned -popover, following -[Adobe Spectrum's combobox pattern](https://react-aria.adobe.com/blog/building-a-combobox). The tray -spans the full viewport width, slides up from the bottom edge on open and back down on close, and -keeps clear of the on-screen keyboard using the -[Visual Viewport API](https://developer.mozilla.org/en-US/docs/Web/API/Visual_Viewport_API). A scrim -dims the page behind the tray, and a grab-handle affordance marks its top edge. In browsers that -support `calc-size()`, the tray keeps a usable minimum height even when the viewport is cramped, -while still hugging shorter lists instead of leaving empty space. +Below the `small` breakpoint (640px), options appear in a bottom tray instead of a positioned +popover. The tray follows the visual viewport so it stays above the on-screen keyboard. The tray +motion and desktop popover fade respect reduced-motion preferences. ## Accessibility -The tray's slide transition (and the desktop popover's fade) is disabled for users who request -`prefers-reduced-motion: reduce`. +Provide a visible `label` where possible. The field passes React Aria combobox interactions and form +semantics to its input, trigger, listbox, and validation message. ## Primitive -Use the [combobox primitives](/docs/components/primitives/combobox) when you need a custom combobox +Use the [combobox primitives](/components/primitives/combobox) when you need a custom combobox layout. ## Props diff --git a/apps/docs/content/docs/components/forms/text-field.mdx b/apps/docs/content/docs/components/forms/text-field.mdx index 0680127c..222eeaa8 100644 --- a/apps/docs/content/docs/components/forms/text-field.mdx +++ b/apps/docs/content/docs/components/forms/text-field.mdx @@ -1,93 +1,85 @@ --- title: Text Field -description: Single-line text input with label, validation, and adornments. +description: Captures a single line of text with a label, validation, and optional adornments. --- -Use `TextField` for a single text input with label, description, validation, and optional adornments -built in. +Use `TextField` to collect a single line of text. It combines an input with a label, description, +and validation message. -## Best practices +## Labels and placeholders -| Guidance | Practices | -| -------- | --------------------------------------------------------------------------------------------------------------------------- | -| Do | Use `label` for every field where possible. It works better with assistive technology and autofill than `aria-label` alone. | -| Don't | Use `placeholder` as a label substitute. It disappears after typing and often fails colour contrast requirements. | +Give the field a visible `label` where possible. Use `placeholder` for an example value or input +format, not as the label. A placeholder disappears while the person types and is not a reliable +accessible name. + +When a nearby heading already names the field, omit `label` and use `aria-label` or +`aria-labelledby` instead. + +```tsx + +``` ## Required fields -Use `isRequired` and `necessityIndicator` to communicate mandatory fields. `'icon'` renders a visual -required marker. `'label'` appends "(required)" to the label text. +Set `isRequired` for required fields. `necessityIndicator="icon"` adds a visual marker. +`necessityIndicator="label"` appends “(required)” to the label. ## Validation -Pass field-level validation through React Aria `Form`. Use `errorMessage` to render the validation -message. +Use `errorMessage` to render a validation message. For client validation, use React Aria validation +props. For server validation, pass errors through React Aria `Form`. ```tsx import { Form } from 'react-aria-components';
validation.validationErrors.join(' ')} + label="Username" + name="username" /> ; ``` ## Adornments -Use `adornmentStart` and `adornmentEnd` to place non-editable content inside the input chrome. -Adornments accept any `ReactNode`. If an adornment is interactive, you are responsible for its -semantics. +Use `adornmentStart` and `adornmentEnd` for content inside the input, such as a search icon, +currency code, or URL prefix. Both accept any `ReactNode`. Give interactive adornments an accessible +name and keyboard behaviour. ## Size -`size` controls height and typography. The HTML numeric `` attribute is intentionally -omitted because `size` is reserved for the design-system variant. - -| Value | Description | -| ---------- | --------------------- | -| `'small'` | Compact input height. | -| `'medium'` | Default input height. | +Use `size` to set the input height and typography. Use `small` in compact layouts. `medium` is the +default. The HTML numeric `size` attribute is unavailable because `size` is the Luke UI variant. -## Accessibility - -When visual context already communicates purpose, you may omit `label` and provide an accessible -name with `aria-label` or `aria-labelledby` on the field. - -```tsx - -``` - ## Primitive -Use the [TextInput primitive](/docs/components/primitives/text-input) when you need the input -without the label, description, and error slots that `TextField` provides. +Use the [TextInput primitive](/components/primitives/text-input) when you need an input without the +label, description, and error slots. ## Props diff --git a/apps/docs/content/docs/components/layout/box.mdx b/apps/docs/content/docs/components/layout/box.mdx index 1a782945..bfa1c24a 100644 --- a/apps/docs/content/docs/components/layout/box.mdx +++ b/apps/docs/content/docs/components/layout/box.mdx @@ -1,10 +1,11 @@ --- title: Box -description: Responsive layout container backed by Luke UI Sprinkles. +description: A div with responsive Luke UI layout properties. --- -`Box` is a `div` by default. Use its responsive layout, spacing, sizing, positioning, overflow, -flex, and grid-child props to build layout without adding styling props to other components. +`Box` is a `div` that accepts Luke UI Sprinkles properties. Use it to place content in a layout, add +token spacing, constrain an element's size, or control a flex or grid child. Use a normal `div` when +no supported layout property is needed. -Spacing props use `0` or the semantic space steps `100`, `200`, `300`, `400`, `600`, `800`, `1000`, -`1200`, and `1600`. Responsive objects use the `xsmall`, `small`, `medium`, `large`, `xlarge`, and -`xxlarge` breakpoints. +## Layout properties -## Custom div component +Box supports display, logical margin and padding, inline and block sizing, positioning, overflow, +gap, flex, and grid-child properties. It does not set grid container properties. Keep grid-template +rules in the application CSS or a component that owns that layout. -Use `render` with a compatible custom `div` component, such as a motion or presentational wrapper. -Spread the provided props onto the actual `div` so the generated class, inline variables, ref, -accessibility attributes, and event handlers are preserved. The callback does not change Box's DOM -element contract to another element type. +Use logical properties such as `paddingInline`, `marginBlockStart`, and `maxInlineSize`. They adapt +to the writing direction without left and right variants. + +```tsx + + {children} + +``` + +## Responsive values + +Pass a direct value when it does not change. Use an object keyed by breakpoint when it does. Values +cascade upward from `xsmall`, so only specify the changes. + +```tsx + + {children} + +``` + +The breakpoints are `xsmall` (base), `small` (640px), `medium` (768px), `large` (1024px), `xlarge` +(1280px), and `xxlarge` (1536px). + +## Spacing values + +Padding, gap, and margin accept `0` and the semantic steps `100`, `200`, `300`, `400`, `600`, `800`, +`1000`, `1200`, and `1600`. Margin also accepts `auto`. Sizing, inset, flex-basis, order, and +grid-placement properties accept their CSS values. + +## Render a custom div + +Use `render` for a compatible custom `div`, such as a motion wrapper. Spread the supplied props on +the final element so it receives Box's class name, inline style, ref, accessibility attributes, and +event handlers. `render` does not make Box polymorphic. It must return a `div`. ```tsx }> @@ -29,8 +64,21 @@ element contract to another element type. ``` -Semantic colour and typography are deliberately not Box props. Use component APIs or public semantic -variables from `@luke-ui/react/theme` for sanctioned custom styling. +## Visual styles + +Box only covers layout. Use a component API for visual states and typography. When a custom element +needs a colour, radius, or depth value, use the public variables from `@luke-ui/react/theme`. + +```tsx +import { vars } from '@luke-ui/react/theme'; + + + Account summary +; +``` ## Props diff --git a/apps/docs/content/docs/components/primitives/button.mdx b/apps/docs/content/docs/components/primitives/button.mdx index 993788af..87e996d4 100644 --- a/apps/docs/content/docs/components/primitives/button.mdx +++ b/apps/docs/content/docs/components/primitives/button.mdx @@ -1,10 +1,11 @@ --- title: Button primitive -description: Lower-level button primitive for custom button composition. +description: Lower-level button styles and behaviour for custom composed controls. --- -Use the button primitive when you need Luke UI button styling without the composed `Button` children -wrapper, icon props, or pending-label behaviour. +Use the button primitive to build a custom button pattern. It provides Luke UI button styles and +React Aria button behaviour, while leaving child layout and loading treatment to you. For ordinary +application actions, use [`Button`](/components/actions/button). ```tsx import { Button } from '@luke-ui/react/button/primitive'; @@ -14,21 +15,30 @@ import { Button } from '@luke-ui/react/button/primitive'; ; ``` -## When to use +## Composition -Use `@luke-ui/react/button/primitive` when you need full control over children layout, render-prop -children, custom loading states, or non-standard button content. +Use the primitive when a composed control needs custom children, render-prop children, or its own +loading layout. The composed `Button` adds a truncating label, start and end icon slots, and a +pending spinner. The primitive does not. -Use [`Button`](/docs/components/actions/button) for most app actions. +## Appearance and size -## Behaviour +Use `tone` and `appearance` to set visual emphasis. Use `size` to match nearby controls. Set +`isBlock` when the button should take up its container's inline size. The primitive renders a native +` + + ); +} +``` + +## Change the theme + +Tactile is the default bundled identity. Paper uses the same component APIs with a flatter visual +treatment. Switch the CSS import and class together. + +```tsx +import '@luke-ui/react/themes/paper.css'; +import { paperThemeClassName } from '@luke-ui/react/themes'; + +
{children}
; +``` + +Set `data-color-mode="light"` or `data-color-mode="dark"` on a themed element when the application +must use a specific mode. Without it, Luke UI follows the system preference. + +## Continue learning + + + + Learn how component APIs, recipes, utilities, and tokens fit together. + + + Build responsive structure with Box and Sprinkles. + + + Understand identities, modes, and custom foundations. + + + Browse the components available to application developers. + + diff --git a/apps/docs/content/docs/overview/layout.mdx b/apps/docs/content/docs/overview/layout.mdx new file mode 100644 index 00000000..26ff84f2 --- /dev/null +++ b/apps/docs/content/docs/overview/layout.mdx @@ -0,0 +1,73 @@ +--- +title: Layout +description: Build responsive structure with Box and token-aware layout utilities. +--- + +Use `Box` or `createSprinkles` for layout. They keep structure, spacing, sizing, positioning, +overflow, flex, and grid-child rules separate from a component's content and behaviour. + +## Box + +`Box` is a `div` with the supported Sprinkles properties. Use it to space child content, constrain +its size, place an item in a flex or grid layout, or hide content at a breakpoint. + +```tsx +import { Box } from '@luke-ui/react/box'; + + + {children} +; +``` + +Use a normal `div` when no layout properties are needed. Box is a layout tool, not a replacement for +every element. + +## Responsive values + +Every Sprinkles property accepts a direct value or an object keyed by breakpoint. Values cascade +from `xsmall`, so specify only the points where the layout changes. + +```tsx + + {children} + +``` + +The available breakpoints are `xsmall` (base), `small` (640px), `medium` (768px), `large` (1024px), +`xlarge` (1280px), and `xxlarge` (1536px). + + + +## Spacing and sizing + +Padding, gap, and margin use the theme spacing steps: `0`, `100`, `200`, `300`, `400`, `600`, `800`, +`1000`, `1200`, and `1600`. Margin also accepts `auto`. Sizing and grid-placement properties accept +their CSS values. + +Use logical properties such as `paddingInline`, `marginBlockStart`, and `maxInlineSize`. They work +in both writing directions without a second layout rule. + +## Use visual styles elsewhere + +Sprinkles excludes semantic colour, typography, and interaction states. Choose a component API for +those concerns. When a custom element needs a visual token, use `vars` from `@luke-ui/react/theme` +rather than a palette value or component selector. + +## Continue learning + + + + See the Box example, props, and custom div rendering contract. + + + Learn where layout utilities sit beside components and recipes. + + diff --git a/apps/docs/content/docs/overview/meta.json b/apps/docs/content/docs/overview/meta.json new file mode 100644 index 00000000..9f346ce1 --- /dev/null +++ b/apps/docs/content/docs/overview/meta.json @@ -0,0 +1,4 @@ +{ + "title": "Overview", + "pages": ["getting-started", "styling", "layout", "theme", "color", "color-mode", "typography"] +} diff --git a/apps/docs/content/docs/overview/styling.mdx b/apps/docs/content/docs/overview/styling.mdx new file mode 100644 index 00000000..f2b34d6c --- /dev/null +++ b/apps/docs/content/docs/overview/styling.mdx @@ -0,0 +1,79 @@ +--- +title: Styling +description: Use Luke UI components, layout utilities, recipes, and semantic variables together. +--- + +Luke UI ships static CSS. It does not inject styles at runtime and does not add a general `css` or +`sx` prop. Import the shared stylesheet and a theme stylesheet once, then use component props for +the variations each component supports. + +## What you get + +Components are intentionally opinionated. Their public props cover supported variants, states, and +behaviour. The active theme provides the semantic colours, typography, spacing, radii, and depth +that make those components work together. + +Luke UI also exports the public `vars` token contract. Use it for a custom element that needs to +belong to the active theme. + +```tsx +import { vars } from '@luke-ui/react/theme'; + +