@mucsi96/react-ui 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +132 -0
- package/dist/components/app-layout/app-layout.d.ts +7 -0
- package/dist/components/dialog/dialog.d.ts +7 -2
- package/dist/components/empty-state/empty-state.d.ts +9 -0
- package/dist/components/forms/controls.d.ts +9 -1
- package/dist/components/forms/number-field.d.ts +11 -0
- package/dist/components/forms/select.d.ts +4 -2
- package/dist/components/skeleton/skeleton.d.ts +11 -0
- package/dist/components/tabs/tabs.d.ts +17 -0
- package/dist/index.d.ts +14 -4
- package/dist/index.js +706 -488
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,6 +44,46 @@ the font to the document root, so applications need no font-family declarations
|
|
|
44
44
|
or token overrides. No font downloads are needed.
|
|
45
45
|
The optional stylesheet does not import fonts or reset page layouts.
|
|
46
46
|
|
|
47
|
+
## Application layout
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
import { AppHeader, AppHeaderActions, AppMain } from '@mucsi96/react-ui';
|
|
51
|
+
|
|
52
|
+
<AppHeader>
|
|
53
|
+
<a href="/">My application</a>
|
|
54
|
+
<AppHeaderActions>
|
|
55
|
+
<nav aria-label="Main navigation">{/* Application links */}</nav>
|
|
56
|
+
<ProfileMenu />
|
|
57
|
+
</AppHeaderActions>
|
|
58
|
+
</AppHeader>
|
|
59
|
+
<AppMain id="main-content">{/* Page content */}</AppMain>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`AppHeader` renders a native `header` with a width-constrained inner flex row.
|
|
63
|
+
Its safe-area top padding sits outside the row's minimum height, so iOS status
|
|
64
|
+
bars do not compress controls. Children wrap as needed. `AppHeaderActions` is a
|
|
65
|
+
wrapping, end-aligned `div`; make any nested navigation groups wrap as well.
|
|
66
|
+
`AppMain` renders a native `main` with matching horizontal gutters, page spacing,
|
|
67
|
+
and bottom safe-area padding. All three accept native element props, including
|
|
68
|
+
`className`, `style`, and React 19 `ref`. They use ordinary document flow.
|
|
69
|
+
|
|
70
|
+
Set these inherited CSS variables on a common ancestor to customize the layout:
|
|
71
|
+
|
|
72
|
+
| Variable | Default | Purpose |
|
|
73
|
+
| ------------------------ | ------- | ---------------------------------------------------- |
|
|
74
|
+
| `--bt-app-max-width` | `90rem` | Header row and main maximum width, including gutters |
|
|
75
|
+
| `--bt-app-gutter` | `1rem` | Minimum horizontal and bottom page padding |
|
|
76
|
+
| `--bt-app-header-height` | `4rem` | Minimum header row height, excluding top safe area |
|
|
77
|
+
| `--bt-app-header-gap` | `1rem` | Space between header children and actions |
|
|
78
|
+
| `--bt-app-content-gap` | `3rem` | Main content top padding |
|
|
79
|
+
|
|
80
|
+
The host document should reset the body margin and include
|
|
81
|
+
`<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">`
|
|
82
|
+
for edge-to-edge safe-area handling. The library does not modify document metadata
|
|
83
|
+
or global layout. Keep routing, profile fetching, navigation labels, and menu
|
|
84
|
+
contents in the application; compose profile menus with `MenuTrigger` and
|
|
85
|
+
`Button variant="avatar"`.
|
|
86
|
+
|
|
47
87
|
## Buttons
|
|
48
88
|
|
|
49
89
|
```tsx
|
|
@@ -79,6 +119,12 @@ const options = [{ id: 'apple', label: 'Apple' }, { id: 'pear', label: 'Pear' }]
|
|
|
79
119
|
<Select label="Fruit" options={options} />
|
|
80
120
|
<ComboBox label="Search fruits" options={options} />
|
|
81
121
|
<Checkbox defaultSelected>Subscribe</Checkbox>
|
|
122
|
+
<NumberField label="Daily limit" name="limit" minValue={1} maxValue={100} step={1} isRequired />
|
|
123
|
+
<CheckboxGroup label="Card types" name="types" isRequired>
|
|
124
|
+
<Checkbox value="vocabulary">Vocabulary</Checkbox>
|
|
125
|
+
<Checkbox value="grammar">Grammar</Checkbox>
|
|
126
|
+
</CheckboxGroup>
|
|
127
|
+
<MultiSelect label="Fruits" options={options} />
|
|
82
128
|
<RadioGroup label="Size" defaultValue="medium">
|
|
83
129
|
<Radio value="small">Small</Radio>
|
|
84
130
|
<Radio value="medium">Medium</Radio>
|
|
@@ -90,6 +136,22 @@ Labels, descriptions, and validation messages are associated with the input auto
|
|
|
90
136
|
|
|
91
137
|
Select options have `{ id, label, isDisabled? }`; React Aria handles selection, typeahead, and filtering. Checkbox and switch controlled state uses `isSelected`/`onChange`; radio group state uses `value`/`onChange`. React Aria form `name` props support native form submissions.
|
|
92
138
|
|
|
139
|
+
`NumberField` uses numeric `value`/`onChange` or `defaultValue`, with `minValue`,
|
|
140
|
+
`maxValue`, `step`, locale-aware `formatOptions`, and increment/decrement buttons.
|
|
141
|
+
An empty field reports `NaN`; validate before persisting rather than substituting
|
|
142
|
+
zero. React Aria commits and clamps typed values on blur. Use `isRequired` to
|
|
143
|
+
prevent empty native form submission. It supports the same `appearance`,
|
|
144
|
+
`description`, `error`, and `validationBehavior` API as the other fields.
|
|
145
|
+
|
|
146
|
+
`CheckboxGroup` owns a string-array `value`/`onChange` or `defaultValue`; each
|
|
147
|
+
child `Checkbox` supplies a `value`. Group labels, descriptions, required
|
|
148
|
+
validation, and errors are associated automatically. `name` submits each selected
|
|
149
|
+
value as a separate form entry. `MultiSelect` provides the same compact field as
|
|
150
|
+
`Select` with `selectionMode="multiple"` fixed internally. Use its React Aria
|
|
151
|
+
`value`/`onChange` or `defaultValue` array API for selection; options remain open
|
|
152
|
+
while selecting, and Escape returns focus to the trigger. Disabled options cannot
|
|
153
|
+
be selected. Both controls accept `description`, `error`, and `isRequired`.
|
|
154
|
+
|
|
93
155
|
### Field and button sizing
|
|
94
156
|
|
|
95
157
|
Fields default to `appearance="filled"`, with always-visible floating labels and
|
|
@@ -177,6 +239,62 @@ For nested actions, compose `SubmenuTrigger` with a `MenuItem` and another `Menu
|
|
|
177
239
|
|
|
178
240
|
Dialog focus is trapped while open and restored to the trigger on close. Escape and outside interaction dismiss by default; `isDismissable={false}` disables outside dismissal, and `isKeyboardDismissDisabled` disables Escape. Use `role="alertdialog"` for important confirmations. Dialogs also support controlled `isOpen`/`onOpenChange` without a `DialogTrigger`. Forms and action layouts are composed as ordinary children. Tooltips accept a single pressable child, `content`, optional `placement`, and `delay`.
|
|
179
241
|
|
|
242
|
+
Use `size="small" | "medium" | "large"` (24, 32, or 48rem; medium by default)
|
|
243
|
+
to size the outer modal, or `maxWidth` for a CSS width override. All sizes are
|
|
244
|
+
constrained to the viewport with safe-area gutters. The optional `footer` node
|
|
245
|
+
or `({ close }) => ReactNode` keeps actions and the title visible while the body
|
|
246
|
+
scrolls, including in a reduced visual viewport. `className` still styles the
|
|
247
|
+
inner dialog. Keep the form in the body and connect footer submit buttons with
|
|
248
|
+
native `form`/`id` attributes:
|
|
249
|
+
|
|
250
|
+
```tsx
|
|
251
|
+
<Dialog
|
|
252
|
+
title="Edit source"
|
|
253
|
+
size="large"
|
|
254
|
+
footer={({ close }) => (
|
|
255
|
+
<>
|
|
256
|
+
<Button variant="text" onPress={close}>
|
|
257
|
+
Cancel
|
|
258
|
+
</Button>
|
|
259
|
+
<Button type="submit" form="source-form">
|
|
260
|
+
Save
|
|
261
|
+
</Button>
|
|
262
|
+
</>
|
|
263
|
+
)}
|
|
264
|
+
>
|
|
265
|
+
<form id="source-form" onSubmit={save}>
|
|
266
|
+
<TextField label="Source name" isRequired />
|
|
267
|
+
</form>
|
|
268
|
+
</Dialog>
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Tabs and empty states
|
|
272
|
+
|
|
273
|
+
```tsx
|
|
274
|
+
<Tabs defaultSelectedKey="items">
|
|
275
|
+
<TabList aria-label="Collection views">
|
|
276
|
+
<Tab id="items">Items</Tab>
|
|
277
|
+
<Tab id="summary">Summary</Tab>
|
|
278
|
+
</TabList>
|
|
279
|
+
<TabPanel id="items">
|
|
280
|
+
<EmptyState
|
|
281
|
+
title="No items yet"
|
|
282
|
+
description="Create an item to get started."
|
|
283
|
+
action={<Button onPress={create}>Add item</Button>}
|
|
284
|
+
/>
|
|
285
|
+
</TabPanel>
|
|
286
|
+
<TabPanel id="summary">Summary content</TabPanel>
|
|
287
|
+
</Tabs>
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Tabs support controlled `selectedKey`/`onSelectionChange`, disabled tabs,
|
|
291
|
+
`orientation="vertical"`, and React Aria's keyboard activation and focus
|
|
292
|
+
behavior. Match tab and panel IDs. Panels unmount by default; use
|
|
293
|
+
`shouldForceMount` on `TabPanel` to preserve state in an inactive, hidden panel.
|
|
294
|
+
`EmptyState` owns no business behavior: supply the title, description, action,
|
|
295
|
+
and optional children. Its heading defaults to level 2; set `headingLevel` to
|
|
296
|
+
match the surrounding document.
|
|
297
|
+
|
|
180
298
|
## Notifications
|
|
181
299
|
|
|
182
300
|
```tsx
|
|
@@ -247,6 +365,20 @@ This is a semantic HTML table. Columns with `compare` have three-state sorting (
|
|
|
247
365
|
|
|
248
366
|
All loading animations respect reduced motion. `Card` supports `outlined` and `elevated`; `Badge` accepts semantic tones and `neutral`. `Heading` supports semantic levels 1–6, `Text` supports `muted`, and `Code` provides inline monospace styling.
|
|
249
367
|
|
|
368
|
+
Compose stable placeholders with `Skeleton` (`variant="text" | "image" | "row"`,
|
|
369
|
+
optional `width`/`height` CSS values). Each shape is decorative and hidden from
|
|
370
|
+
assistive technology. Wrap a set in `SkeletonGroup label="Loading collection"`
|
|
371
|
+
for one visually hidden status label. Place row placeholders inside table cells,
|
|
372
|
+
not directly inside a `tbody`. Animations stop under reduced motion.
|
|
373
|
+
|
|
374
|
+
```tsx
|
|
375
|
+
<SkeletonGroup label="Loading collection">
|
|
376
|
+
<Skeleton variant="image" />
|
|
377
|
+
<Skeleton width="70%" />
|
|
378
|
+
<Skeleton variant="row" />
|
|
379
|
+
</SkeletonGroup>
|
|
380
|
+
```
|
|
381
|
+
|
|
250
382
|
## Customize with CSS Modules
|
|
251
383
|
|
|
252
384
|
```css
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ComponentPropsWithRef } from 'react';
|
|
2
|
+
export type AppHeaderProps = ComponentPropsWithRef<'header'>;
|
|
3
|
+
export type AppHeaderActionsProps = ComponentPropsWithRef<'div'>;
|
|
4
|
+
export type AppMainProps = ComponentPropsWithRef<'main'>;
|
|
5
|
+
export declare function AppHeader({ children, className, ...props }: AppHeaderProps): import("react").JSX.Element;
|
|
6
|
+
export declare function AppHeaderActions({ className, ...props }: AppHeaderActionsProps): import("react").JSX.Element;
|
|
7
|
+
export declare function AppMain({ className, ...props }: AppMainProps): import("react").JSX.Element;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
1
|
+
import type { CSSProperties, ReactNode } from 'react';
|
|
2
2
|
import type { ModalOverlayProps } from 'react-aria-components';
|
|
3
3
|
export { DialogTrigger } from 'react-aria-components';
|
|
4
4
|
export interface DialogProps extends Omit<ModalOverlayProps, 'children' | 'className'> {
|
|
@@ -9,5 +9,10 @@ export interface DialogProps extends Omit<ModalOverlayProps, 'children' | 'class
|
|
|
9
9
|
}) => ReactNode);
|
|
10
10
|
role?: 'dialog' | 'alertdialog';
|
|
11
11
|
className?: string;
|
|
12
|
+
size?: 'small' | 'medium' | 'large';
|
|
13
|
+
maxWidth?: CSSProperties['maxWidth'];
|
|
14
|
+
footer?: ReactNode | ((props: {
|
|
15
|
+
close: () => void;
|
|
16
|
+
}) => ReactNode);
|
|
12
17
|
}
|
|
13
|
-
export declare function Dialog({ title, description, children, role, className, isDismissable, ...props }: DialogProps): import("react").JSX.Element;
|
|
18
|
+
export declare function Dialog({ title, description, children, role, className, size, maxWidth, footer, isDismissable, ...props }: DialogProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ComponentPropsWithRef, ReactNode } from 'react';
|
|
2
|
+
import type { HeadingProps } from '../surface/surface';
|
|
3
|
+
export interface EmptyStateProps extends Omit<ComponentPropsWithRef<'section'>, 'title'> {
|
|
4
|
+
title: string;
|
|
5
|
+
description?: ReactNode;
|
|
6
|
+
action?: ReactNode;
|
|
7
|
+
headingLevel?: HeadingProps['level'];
|
|
8
|
+
}
|
|
9
|
+
export declare function EmptyState({ title, description, action, headingLevel, children, className, ...props }: EmptyStateProps): import("react").JSX.Element;
|
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
import type { CheckboxProps as AriaCheckboxProps, RadioGroupProps as AriaRadioGroupProps, RadioProps as AriaRadioProps, SwitchProps as AriaSwitchProps } from 'react-aria-components';
|
|
1
|
+
import type { CheckboxProps as AriaCheckboxProps, CheckboxGroupProps as AriaCheckboxGroupProps, RadioGroupProps as AriaRadioGroupProps, RadioProps as AriaRadioProps, SwitchProps as AriaSwitchProps } from 'react-aria-components';
|
|
2
2
|
import type { ReactNode } from 'react';
|
|
3
3
|
export interface CheckboxProps extends Omit<AriaCheckboxProps, 'children' | 'className'> {
|
|
4
4
|
children: ReactNode;
|
|
5
5
|
className?: string;
|
|
6
6
|
}
|
|
7
7
|
export declare function Checkbox({ children, className, ...props }: CheckboxProps): import("react").JSX.Element;
|
|
8
|
+
export interface CheckboxGroupProps extends Omit<AriaCheckboxGroupProps, 'children' | 'className'> {
|
|
9
|
+
label: string;
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
description?: ReactNode;
|
|
12
|
+
error?: ReactNode;
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function CheckboxGroup({ label, children, description, error, className, ...props }: CheckboxGroupProps): import("react").JSX.Element;
|
|
8
16
|
export interface RadioGroupProps extends Omit<AriaRadioGroupProps, 'children' | 'className'> {
|
|
9
17
|
label: string;
|
|
10
18
|
children: ReactNode;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { NumberFieldProps as AriaNumberFieldProps } from 'react-aria-components';
|
|
2
|
+
import type { ReactNode, Ref } from 'react';
|
|
3
|
+
export interface NumberFieldProps extends Omit<AriaNumberFieldProps, 'children' | 'className'> {
|
|
4
|
+
label: string;
|
|
5
|
+
description?: ReactNode;
|
|
6
|
+
error?: ReactNode;
|
|
7
|
+
appearance?: 'outlined' | 'filled';
|
|
8
|
+
className?: string;
|
|
9
|
+
ref?: Ref<HTMLDivElement>;
|
|
10
|
+
}
|
|
11
|
+
export declare function NumberField({ label, description, error, appearance, className, ref, ...props }: NumberFieldProps): import("react").JSX.Element;
|
|
@@ -14,10 +14,12 @@ interface FieldProps {
|
|
|
14
14
|
appearance?: 'outlined' | 'filled';
|
|
15
15
|
className?: string;
|
|
16
16
|
}
|
|
17
|
-
export interface SelectProps extends Omit<AriaSelectProps<SelectOption>, keyof FieldProps | 'children' | 'items'>, FieldProps {
|
|
17
|
+
export interface SelectProps<M extends 'single' | 'multiple' = 'single'> extends Omit<AriaSelectProps<SelectOption, M>, keyof FieldProps | 'children' | 'items'>, FieldProps {
|
|
18
18
|
}
|
|
19
|
-
export declare function Select({ label, options, description, error, placeholder, appearance, className, ...props }: SelectProps): import("react").JSX.Element;
|
|
19
|
+
export declare function Select<M extends 'single' | 'multiple' = 'single'>({ label, options, description, error, placeholder, appearance, className, ...props }: SelectProps<M>): import("react").JSX.Element;
|
|
20
20
|
export interface ComboBoxProps extends Omit<AriaComboBoxProps<SelectOption>, keyof FieldProps | 'children' | 'items' | 'defaultItems'>, FieldProps {
|
|
21
21
|
}
|
|
22
|
+
export type MultiSelectProps = Omit<SelectProps<'multiple'>, 'selectionMode' | 'selectedKey' | 'defaultSelectedKey' | 'onSelectionChange'>;
|
|
23
|
+
export declare function MultiSelect(props: MultiSelectProps): import("react").JSX.Element;
|
|
22
24
|
export declare function ComboBox({ label, options, description, error, placeholder, appearance, className, ...props }: ComboBoxProps): import("react").JSX.Element;
|
|
23
25
|
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ComponentPropsWithRef, CSSProperties } from 'react';
|
|
2
|
+
export interface SkeletonProps extends Omit<ComponentPropsWithRef<'div'>, 'children'> {
|
|
3
|
+
variant?: 'text' | 'image' | 'row';
|
|
4
|
+
width?: CSSProperties['width'];
|
|
5
|
+
height?: CSSProperties['height'];
|
|
6
|
+
}
|
|
7
|
+
export declare function Skeleton({ variant, width, height, className, style, ...props }: SkeletonProps): import("react").JSX.Element;
|
|
8
|
+
export interface SkeletonGroupProps extends ComponentPropsWithRef<'div'> {
|
|
9
|
+
label: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function SkeletonGroup({ label, children, className, ...props }: SkeletonGroupProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { TabsProps as AriaTabsProps, TabListProps as AriaTabListProps, TabProps as AriaTabProps, TabPanelProps as AriaTabPanelProps } from 'react-aria-components';
|
|
2
|
+
export interface TabsProps extends Omit<AriaTabsProps, 'className'> {
|
|
3
|
+
className?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface TabListProps<T extends object> extends Omit<AriaTabListProps<T>, 'className'> {
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface TabProps extends Omit<AriaTabProps, 'className'> {
|
|
9
|
+
className?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface TabPanelProps extends Omit<AriaTabPanelProps, 'className'> {
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function Tabs({ className, ...props }: TabsProps): import("react").JSX.Element;
|
|
15
|
+
export declare function TabList<T extends object>({ className, ...props }: TabListProps<T>): import("react").JSX.Element;
|
|
16
|
+
export declare function Tab({ className, ...props }: TabProps): import("react").JSX.Element;
|
|
17
|
+
export declare function TabPanel({ className, ...props }: TabPanelProps): import("react").JSX.Element;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
|
+
export { AppHeader, AppHeaderActions, AppMain } from './components/app-layout/app-layout';
|
|
2
|
+
export type { AppHeaderProps, AppHeaderActionsProps, AppMainProps, } from './components/app-layout/app-layout';
|
|
1
3
|
export { Button, LinkButton } from './components/button/button';
|
|
2
4
|
export type { ButtonProps, ButtonVariant, LinkButtonProps } from './components/button/button';
|
|
3
5
|
export { TextField } from './components/forms/text-field';
|
|
4
6
|
export type { TextFieldProps } from './components/forms/text-field';
|
|
5
|
-
export {
|
|
6
|
-
export type {
|
|
7
|
-
export {
|
|
8
|
-
export type {
|
|
7
|
+
export { NumberField } from './components/forms/number-field';
|
|
8
|
+
export type { NumberFieldProps } from './components/forms/number-field';
|
|
9
|
+
export { Select, MultiSelect, ComboBox } from './components/forms/select';
|
|
10
|
+
export type { SelectProps, MultiSelectProps, ComboBoxProps, SelectOption, } from './components/forms/select';
|
|
11
|
+
export { Checkbox, CheckboxGroup, Radio, RadioGroup, Switch } from './components/forms/controls';
|
|
12
|
+
export type { CheckboxProps, CheckboxGroupProps, RadioProps, RadioGroupProps, SwitchProps, } from './components/forms/controls';
|
|
9
13
|
export { DonutSlider } from './components/donut-slider/donut-slider';
|
|
10
14
|
export type { DonutSliderProps } from './components/donut-slider/donut-slider';
|
|
11
15
|
export { Menu, MenuItem, MenuPopover, MenuSeparator, MenuTrigger, SubmenuTrigger, } from './components/menu/menu';
|
|
@@ -25,3 +29,9 @@ export type { BarLoaderProps, ProgressBarProps } from './components/loader/loade
|
|
|
25
29
|
export { Card, Badge, Heading, Text, Code, Divider } from './components/surface/surface';
|
|
26
30
|
export type { CardProps, BadgeProps, HeadingProps, TextProps } from './components/surface/surface';
|
|
27
31
|
export type { Tone } from './types';
|
|
32
|
+
export { Tabs, TabList, Tab, TabPanel } from './components/tabs/tabs';
|
|
33
|
+
export type { TabsProps, TabListProps, TabProps, TabPanelProps } from './components/tabs/tabs';
|
|
34
|
+
export { Skeleton, SkeletonGroup } from './components/skeleton/skeleton';
|
|
35
|
+
export type { SkeletonProps, SkeletonGroupProps } from './components/skeleton/skeleton';
|
|
36
|
+
export { EmptyState } from './components/empty-state/empty-state';
|
|
37
|
+
export type { EmptyStateProps } from './components/empty-state/empty-state';
|