neba 0.0.1 → 1.0.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 +169 -2
- package/dist/components/accordion/Accordion.d.ts +97 -0
- package/dist/components/accordion/Accordion.js +1 -0
- package/dist/components/accordion/index.d.ts +2 -0
- package/dist/components/accordion/index.js +1 -0
- package/dist/components/alert/Alert.d.ts +47 -0
- package/dist/components/alert/Alert.js +1 -0
- package/dist/components/alert/index.d.ts +2 -0
- package/dist/components/alert/index.js +1 -0
- package/dist/components/badge/Badge.d.ts +80 -0
- package/dist/components/badge/Badge.js +1 -0
- package/dist/components/badge/index.d.ts +2 -0
- package/dist/components/badge/index.js +1 -0
- package/dist/components/box/Box.d.ts +50 -0
- package/dist/components/box/Box.js +1 -0
- package/dist/components/box/index.d.ts +2 -0
- package/dist/components/box/index.js +1 -0
- package/dist/components/button/Button.d.ts +25 -3
- package/dist/components/button/Button.js +1 -1
- package/dist/components/button/index.d.ts +1 -0
- package/dist/components/button-group/ButtonGroup.d.ts +31 -0
- package/dist/components/button-group/ButtonGroup.js +1 -0
- package/dist/components/button-group/index.d.ts +2 -0
- package/dist/components/button-group/index.js +1 -0
- package/dist/components/card/Card.d.ts +45 -0
- package/dist/components/card/Card.js +1 -0
- package/dist/components/card/index.d.ts +2 -0
- package/dist/components/card/index.js +1 -0
- package/dist/components/checkbox/Checkbox.d.ts +39 -0
- package/dist/components/checkbox/Checkbox.js +1 -0
- package/dist/components/checkbox/index.d.ts +2 -0
- package/dist/components/checkbox/index.js +1 -0
- package/dist/components/chip/Chip.d.ts +50 -0
- package/dist/components/chip/Chip.js +1 -0
- package/dist/components/chip/index.d.ts +2 -0
- package/dist/components/chip/index.js +1 -0
- package/dist/components/combobox/Combobox.d.ts +131 -0
- package/dist/components/combobox/Combobox.js +1 -0
- package/dist/components/combobox/index.d.ts +2 -0
- package/dist/components/combobox/index.js +1 -0
- package/dist/components/dialog/Dialog.d.ts +111 -0
- package/dist/components/dialog/Dialog.js +1 -0
- package/dist/components/dialog/index.d.ts +2 -0
- package/dist/components/dialog/index.js +1 -0
- package/dist/components/divider/Divider.d.ts +48 -0
- package/dist/components/divider/Divider.js +1 -0
- package/dist/components/divider/index.d.ts +2 -0
- package/dist/components/divider/index.js +1 -0
- package/dist/components/file-picker/FilePicker.d.ts +103 -0
- package/dist/components/file-picker/FilePicker.js +1 -0
- package/dist/components/file-picker/index.d.ts +2 -0
- package/dist/components/file-picker/index.js +1 -0
- package/dist/components/list/List.d.ts +81 -0
- package/dist/components/list/List.js +1 -0
- package/dist/components/list/index.d.ts +2 -0
- package/dist/components/list/index.js +1 -0
- package/dist/components/menu/Menu.d.ts +216 -0
- package/dist/components/menu/Menu.js +1 -0
- package/dist/components/menu/index.d.ts +2 -0
- package/dist/components/menu/index.js +1 -0
- package/dist/components/number-field/NumberField.d.ts +113 -0
- package/dist/components/number-field/NumberField.js +1 -0
- package/dist/components/number-field/index.d.ts +2 -0
- package/dist/components/number-field/index.js +1 -0
- package/dist/components/overlay/Overlay.d.ts +85 -0
- package/dist/components/overlay/Overlay.js +1 -0
- package/dist/components/overlay/index.d.ts +2 -0
- package/dist/components/overlay/index.js +1 -0
- package/dist/components/pagination/Pagination.d.ts +65 -0
- package/dist/components/pagination/Pagination.js +1 -0
- package/dist/components/pagination/index.d.ts +2 -0
- package/dist/components/pagination/index.js +1 -0
- package/dist/components/progress-box/ProgressBox.d.ts +33 -0
- package/dist/components/progress-box/ProgressBox.js +1 -0
- package/dist/components/progress-box/index.d.ts +2 -0
- package/dist/components/progress-box/index.js +1 -0
- package/dist/components/progress-circular/ProgressCircular.d.ts +19 -0
- package/dist/components/progress-circular/ProgressCircular.js +1 -0
- package/dist/components/progress-circular/index.d.ts +2 -0
- package/dist/components/progress-circular/index.js +1 -0
- package/dist/components/progress-linear/ProgressLinear.d.ts +20 -0
- package/dist/components/progress-linear/ProgressLinear.js +1 -0
- package/dist/components/progress-linear/index.d.ts +2 -0
- package/dist/components/progress-linear/index.js +1 -0
- package/dist/components/radio-group/RadioGroup.d.ts +51 -0
- package/dist/components/radio-group/RadioGroup.js +1 -0
- package/dist/components/radio-group/index.d.ts +2 -0
- package/dist/components/radio-group/index.js +1 -0
- package/dist/components/select/Select.d.ts +76 -0
- package/dist/components/select/Select.js +1 -0
- package/dist/components/select/index.d.ts +2 -0
- package/dist/components/select/index.js +1 -0
- package/dist/components/slider/Slider.d.ts +38 -0
- package/dist/components/slider/Slider.js +1 -0
- package/dist/components/slider/index.d.ts +2 -0
- package/dist/components/slider/index.js +1 -0
- package/dist/components/switch/Switch.d.ts +39 -0
- package/dist/components/switch/Switch.js +1 -0
- package/dist/components/switch/index.d.ts +2 -0
- package/dist/components/switch/index.js +1 -0
- package/dist/components/table/Table.d.ts +80 -0
- package/dist/components/table/Table.js +1 -0
- package/dist/components/table/index.d.ts +2 -0
- package/dist/components/table/index.js +1 -0
- package/dist/components/tabs/Tabs.d.ts +92 -0
- package/dist/components/tabs/Tabs.js +1 -0
- package/dist/components/tabs/index.d.ts +2 -0
- package/dist/components/tabs/index.js +1 -0
- package/dist/components/text-field/TextField.d.ts +63 -0
- package/dist/components/text-field/TextField.js +1 -0
- package/dist/components/text-field/index.d.ts +2 -0
- package/dist/components/text-field/index.js +1 -0
- package/dist/components/toast/Toast.d.ts +116 -0
- package/dist/components/toast/Toast.js +1 -0
- package/dist/components/toast/index.d.ts +2 -0
- package/dist/components/toast/index.js +1 -0
- package/dist/components/tooltip/Tooltip.d.ts +81 -0
- package/dist/components/tooltip/Tooltip.js +1 -0
- package/dist/components/tooltip/index.d.ts +2 -0
- package/dist/components/tooltip/index.js +1 -0
- package/dist/components/typography/Typography.d.ts +62 -0
- package/dist/components/typography/Typography.js +1 -0
- package/dist/components/typography/index.d.ts +2 -0
- package/dist/components/typography/index.js +1 -0
- package/dist/index.d.ts +32 -1
- package/dist/index.js +1 -1
- package/dist/internal/button-group.d.ts +25 -0
- package/dist/internal/button-group.js +1 -0
- package/dist/internal/icons.d.ts +48 -0
- package/dist/internal/icons.js +1 -0
- package/dist/internal/menu.d.ts +20 -0
- package/dist/internal/menu.js +1 -0
- package/dist/internal/progress.d.ts +122 -0
- package/dist/internal/progress.js +1 -0
- package/dist/internal/styles.d.ts +224 -0
- package/dist/internal/styles.js +1 -0
- package/dist/styles.css +758 -0
- package/dist/types.d.ts +77 -0
- package/dist/types.js +8 -0
- package/package.json +75 -19
- package/pnpm-workspace.yaml +0 -2
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { NebaOrientation, NebaStyleProps, NebaVariant } from '../../types';
|
|
3
|
+
/** A tab's value. The same restraint Select puts on its own — an identifier. */
|
|
4
|
+
export type TabValue = string | number;
|
|
5
|
+
export interface TabsProps extends Omit<NebaStyleProps, 'variant'>, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'defaultValue' | 'onChange'> {
|
|
6
|
+
/**
|
|
7
|
+
* Weight of the tab *bar*, not of the panels under it.
|
|
8
|
+
*
|
|
9
|
+
* - `solid` — a segmented control: the bar is a frosted trough and the
|
|
10
|
+
* indicator is a filled tile that slides between the tabs.
|
|
11
|
+
* - `outline` — the classic: a rule along the edge of the bar with the
|
|
12
|
+
* indicator riding on it.
|
|
13
|
+
* - `text` — the same bar with the rule taken away, for tabs inside a Card
|
|
14
|
+
* that already has an edge of its own.
|
|
15
|
+
* @default 'outline'
|
|
16
|
+
*/
|
|
17
|
+
variant?: NebaVariant;
|
|
18
|
+
/** The chosen tab. Use with `onValueChange` for a controlled set. */
|
|
19
|
+
value?: TabValue | null;
|
|
20
|
+
/** Which starts chosen, for an uncontrolled set. */
|
|
21
|
+
defaultValue?: TabValue | null;
|
|
22
|
+
onValueChange?: (value: TabValue | null) => void;
|
|
23
|
+
/**
|
|
24
|
+
* Which way the bar runs. `vertical` puts the tabs down the side and the
|
|
25
|
+
* panel beside them, and moves the arrow keys onto the other axis — which is
|
|
26
|
+
* Base UI's doing, and is what makes a vertical tab bar reachable.
|
|
27
|
+
* @default 'horizontal'
|
|
28
|
+
*/
|
|
29
|
+
orientation?: NebaOrientation;
|
|
30
|
+
/**
|
|
31
|
+
* Whether moving the arrow keys also chooses the tab it lands on.
|
|
32
|
+
*
|
|
33
|
+
* `false` by default. Automatic activation is only kind when every panel is
|
|
34
|
+
* already on the page; the moment one of them fetches, walking past four tabs
|
|
35
|
+
* fires four requests.
|
|
36
|
+
* @default false
|
|
37
|
+
*/
|
|
38
|
+
activateOnFocus?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Whether the arrow keys wrap from the last tab back to the first.
|
|
41
|
+
* @default true
|
|
42
|
+
*/
|
|
43
|
+
loopFocus?: boolean;
|
|
44
|
+
/** The tabs share the bar's full width, each taking an equal share of it. */
|
|
45
|
+
fullWidth?: boolean;
|
|
46
|
+
children?: React.ReactNode;
|
|
47
|
+
}
|
|
48
|
+
export interface TabProps extends Omit<React.ComponentPropsWithoutRef<'button'>, 'value' | 'color'> {
|
|
49
|
+
/** Identifies the tab, and picks out the panel with the same value. */
|
|
50
|
+
value: TabValue;
|
|
51
|
+
/** Content before the label. Sized in `em`, so it tracks the label. */
|
|
52
|
+
startIcon?: React.ReactNode;
|
|
53
|
+
/** Content after the label — a count, a Badge, a status dot. */
|
|
54
|
+
endIcon?: React.ReactNode;
|
|
55
|
+
/** Unavailable, but still listed. */
|
|
56
|
+
disabled?: boolean;
|
|
57
|
+
children?: React.ReactNode;
|
|
58
|
+
}
|
|
59
|
+
export interface TabPanelProps extends React.ComponentPropsWithoutRef<'div'> {
|
|
60
|
+
/** Which tab shows this panel. */
|
|
61
|
+
value: TabValue;
|
|
62
|
+
/**
|
|
63
|
+
* Keeps the panel in the DOM while it is hidden. For a panel that is expensive
|
|
64
|
+
* to build, or that holds form state which should survive being switched away
|
|
65
|
+
* from.
|
|
66
|
+
* @default false
|
|
67
|
+
*/
|
|
68
|
+
keepMounted?: boolean;
|
|
69
|
+
children?: React.ReactNode;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* One tab, and one place a tab differs from a Button: `solid` puts the tile
|
|
73
|
+
* *behind* the tab rather than on it, so the tab needs a stacking context of its
|
|
74
|
+
* own or the indicator would cover the label it is meant to be under.
|
|
75
|
+
*/
|
|
76
|
+
export declare const Tab: React.ForwardRefExoticComponent<TabProps & React.RefAttributes<HTMLButtonElement>>;
|
|
77
|
+
/** The content behind one tab. */
|
|
78
|
+
export declare const TabPanel: React.ForwardRefExoticComponent<TabPanelProps & React.RefAttributes<HTMLDivElement>>;
|
|
79
|
+
/**
|
|
80
|
+
* One set of panels, one of which is shown.
|
|
81
|
+
*
|
|
82
|
+
* Base UI owns everything that makes a tab bar a tab bar rather than a row of
|
|
83
|
+
* buttons: roving focus so the whole bar is one tab stop, the arrow keys on
|
|
84
|
+
* whichever axis the bar runs, Home and End, the `tab` / `tabpanel` roles and
|
|
85
|
+
* the `aria-controls` wiring between them, and the measurement that puts the
|
|
86
|
+
* indicator under the chosen tab. What is here is the surface and the ladders.
|
|
87
|
+
*
|
|
88
|
+
* The tabs and the panels are composed rather than passed as data, unlike
|
|
89
|
+
* Select — because a panel is a subtree, and there is no useful shape for
|
|
90
|
+
* "an array of arbitrary React trees" that is not just children.
|
|
91
|
+
*/
|
|
92
|
+
export declare const Tabs: React.ForwardRefExoticComponent<TabsProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as t}from"react/jsx-runtime";import*as a from"react";import{Tabs as i}from"@base-ui/react/tabs";import{controlHeightClasses as o,controlTextClasses as l,gapClasses as n,hasContent as r,iconClasses as s,paddingXClasses as c,radiusClasses as d,surfaceClasses as f,surfaceSlots as u,transitionClasses as h}from"../../internal/styles";const b=a.createContext({variant:"outline",size:"md",density:"default",orientation:"horizontal",fullWidth:!1}),v={solid:{horizontal:`${f} inline-flex bg-(--n-panel) p-1 [box-shadow:var(--neba-plate-glass)]`,vertical:`${f} inline-flex flex-col bg-(--n-panel) p-1 [box-shadow:var(--neba-plate-glass)]`},outline:{horizontal:"flex border-b [border-color:var(--n-line)]",vertical:"flex flex-col border-e [border-color:var(--n-line)]"},text:{horizontal:"flex",vertical:"flex flex-col"}},p={solid:{horizontal:"absolute left-(--active-tab-left) top-(--active-tab-top) h-(--active-tab-height) w-(--active-tab-width)",vertical:"absolute left-(--active-tab-left) top-(--active-tab-top) h-(--active-tab-height) w-(--active-tab-width)"},outline:{horizontal:"absolute bottom-0 left-(--active-tab-left) h-0.5 w-(--active-tab-width)",vertical:"absolute end-0 top-(--active-tab-top) h-(--active-tab-height) w-0.5"},text:{horizontal:"absolute bottom-0 left-(--active-tab-left) h-0.5 w-(--active-tab-width)",vertical:"absolute end-0 top-(--active-tab-top) h-(--active-tab-height) w-0.5"}},x={solid:`${f} bg-(--n-panel-press) [box-shadow:var(--neba-shadow-1),var(--neba-plate-glass)]`,outline:"bg-(--n-accent)",text:"bg-(--n-accent)"},m={solid:"text-(--neba-muted-fg) hover:text-(--neba-fg) data-[active]:text-(--n-accent)",outline:"text-(--neba-muted-fg) hover:text-(--neba-fg) data-[active]:text-(--n-accent)",text:"text-(--neba-muted-fg) hover:text-(--neba-fg) data-[active]:text-(--n-accent)"};export const Tab=a.forwardRef(function({value:f,startIcon:u,endIcon:v,disabled:p=!1,className:x,children:g,...w},z){const{variant:y,size:N,density:j,fullWidth:k}=a.useContext(b);return t(i.Tab,{ref:z,value:f,disabled:p,className:["relative z-10 inline-flex shrink-0 cursor-pointer items-center justify-center select-none","whitespace-nowrap font-medium","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]",o[N],l[N],n[N],c[j][N],"solid"===y?d[N]:"",h,s,m[y],"focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:[outline-offset:-2px]","data-[disabled]:cursor-not-allowed data-[disabled]:text-(--neba-disabled-fg)",k?"flex-1":"",x??""].filter(Boolean).join(" "),...w,children:[r(u)?e("span",{className:"flex h-[1lh] shrink-0 items-center",children:u}):null,g,r(v)?e("span",{className:"flex h-[1lh] shrink-0 items-center",children:v}):null]})});export const TabPanel=a.forwardRef(function({value:t,keepMounted:o=!1,className:l,children:n,...r},s){const{size:c}=a.useContext(b);return e(i.Panel,{ref:s,value:t,keepMounted:o,className:["min-w-0 flex-1 text-(--neba-fg)","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-2",d[c],l??""].filter(Boolean).join(" "),...r,children:n})});export const Tabs=a.forwardRef(function({variant:o="outline",size:l="md",color:n="primary",density:r="default",value:s,defaultValue:c,onValueChange:f,orientation:h="horizontal",activateOnFocus:m=!1,loopFocus:g=!0,fullWidth:w=!1,className:z,style:y,children:N,...j},k){const C=a.useMemo(()=>({variant:o,size:l,density:r,orientation:h,fullWidth:w}),[o,l,r,h,w]),T=[],V=[];return a.Children.forEach(N,e=>{a.isValidElement(e)&&e.type===TabPanel?V.push(e):null!=e&&!1!==e&&T.push(e)}),e(b.Provider,{value:C,children:t(i.Root,{ref:k,value:s,defaultValue:c,onValueChange:e=>f?.(e),orientation:h,className:["flex min-w-0","vertical"===h?"flex-row gap-4":"flex-col gap-4",z??""].filter(Boolean).join(" "),style:{...u(n,0),...y},...j,children:[t(i.List,{activateOnFocus:m,loopFocus:g,className:["relative shrink-0",v[o][h],"solid"===o?d[l]:"",w&&"horizontal"===h?"w-full":"","horizontal"===h?"overflow-x-auto overflow-y-hidden":""].filter(Boolean).join(" "),children:[T,e(i.Indicator,{className:["pointer-events-none",p[o][h],x[o],"solid"===o?d[l]:"rounded-full","[transition-property:left,top,width,height]","[transition-duration:var(--neba-duration)]","[transition-timing-function:var(--neba-ease)]"].join(" ")})]}),V]})})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{Tab,TabPanel,Tabs}from"./Tabs";
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { NebaElevation, NebaStyleProps } from '../../types';
|
|
3
|
+
/** How the multiline control may be resized by the user. Ignored when single line. */
|
|
4
|
+
export type TextFieldResize = 'none' | 'vertical' | 'horizontal' | 'both';
|
|
5
|
+
/**
|
|
6
|
+
* Native `<input>` attributes, minus the three that collide with the shared
|
|
7
|
+
* vocabulary: `color` and `size` are Neba props here, and `onChange` is widened
|
|
8
|
+
* below so the same handler types against a `<textarea>` in multiline mode.
|
|
9
|
+
*/
|
|
10
|
+
type NativeControlProps = Omit<React.ComponentPropsWithoutRef<'input'>, 'color' | 'size' | 'onChange' | 'children'>;
|
|
11
|
+
export interface TextFieldProps extends NebaStyleProps, NativeControlProps {
|
|
12
|
+
/**
|
|
13
|
+
* Drop shadow depth. `0` (the default) is flat — a field is a well, not a
|
|
14
|
+
* surface that floats, so this is raised even less often than on a Button.
|
|
15
|
+
* @default 0
|
|
16
|
+
*/
|
|
17
|
+
elevation?: NebaElevation;
|
|
18
|
+
/**
|
|
19
|
+
* Renders a `<textarea>` instead of an `<input>`. Everything else — sizing,
|
|
20
|
+
* density, variants, states — stays identical, so switching a field to
|
|
21
|
+
* multiline never changes how it sits in a form.
|
|
22
|
+
* @default false
|
|
23
|
+
*/
|
|
24
|
+
multiline?: boolean;
|
|
25
|
+
/** Visible rows in multiline mode. One row is exactly the single-line height. */
|
|
26
|
+
rows?: number;
|
|
27
|
+
/**
|
|
28
|
+
* Which way the user may drag the multiline control. Horizontal resizing
|
|
29
|
+
* breaks a form's column, so only the vertical axis is on by default.
|
|
30
|
+
* @default 'vertical'
|
|
31
|
+
*/
|
|
32
|
+
resize?: TextFieldResize;
|
|
33
|
+
/**
|
|
34
|
+
* Label above the control, wired to it by Base UI's Field. There is no
|
|
35
|
+
* floating variant on purpose: floating labels need a `transform`, and
|
|
36
|
+
* controls in this library never transform.
|
|
37
|
+
*/
|
|
38
|
+
label?: React.ReactNode;
|
|
39
|
+
/** Helper text below the control. */
|
|
40
|
+
description?: React.ReactNode;
|
|
41
|
+
/** Error message below the control. Its presence also turns the field invalid. */
|
|
42
|
+
error?: React.ReactNode;
|
|
43
|
+
/**
|
|
44
|
+
* Forces the invalid state without a message — for when an external form
|
|
45
|
+
* library owns the validity. Defaults to whether `error` has content.
|
|
46
|
+
*/
|
|
47
|
+
invalid?: boolean;
|
|
48
|
+
/** Content placed before the control. Sized in `em`, so it tracks the text. */
|
|
49
|
+
startIcon?: React.ReactNode;
|
|
50
|
+
/** Content placed after the control. */
|
|
51
|
+
endIcon?: React.ReactNode;
|
|
52
|
+
/**
|
|
53
|
+
* Shows a spinner in place of `endIcon` and marks the field busy. Typing is
|
|
54
|
+
* deliberately still allowed — a field is usually loading *because of* what
|
|
55
|
+
* was typed into it.
|
|
56
|
+
*/
|
|
57
|
+
loading?: boolean;
|
|
58
|
+
/** Stretches to the width of the container. */
|
|
59
|
+
fullWidth?: boolean;
|
|
60
|
+
onChange?: React.ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement>;
|
|
61
|
+
}
|
|
62
|
+
export declare const TextField: React.ForwardRefExoticComponent<TextFieldProps & React.RefAttributes<HTMLInputElement | HTMLTextAreaElement>>;
|
|
63
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as t}from"react/jsx-runtime";import*as n from"react";import{Field as r}from"@base-ui/react/field";import{Input as i}from"@base-ui/react/input";import{controlHeightClasses as l,controlTextLeadingClasses as a,disabledClasses as s,fieldReadOnlyClasses as o,fieldRestClasses as c,focusWithinRingClasses as d,gapClasses as m,iconClasses as u,metaTextClasses as f,paddingXClasses as p,radiusClasses as x,stackGapClasses as h,surfaceSlots as g,transitionClasses as b}from"../../internal/styles";const y={xs:`${m.xs} ${x.xs} ${a.xs}`,sm:`${m.sm} ${x.sm} ${a.sm}`,md:`${m.md} ${x.md} ${a.md}`,lg:`${m.lg} ${x.lg} ${a.lg}`,xl:`${m.xl} ${x.xl} ${a.xl}`},$={xs:"min-h-5.5 py-[3px]",sm:"min-h-6.5 py-[4px]",md:"min-h-8 py-[5px]",lg:"min-h-10 py-[8px]",xl:"min-h-12 py-[10px]"},v={none:"resize-none",vertical:"resize-y",horizontal:"resize-x",both:"resize"},w=["group relative flex w-full cursor-text","[-webkit-tap-highlight-color:transparent]",b,"focus-within:[transition-duration:0ms]",d,u].join(" "),N=c,j=o;function k(){return t("svg",{viewBox:"0 0 16 16",fill:"none","aria-hidden":"true",className:"animate-spin",children:[e("circle",{cx:"8",cy:"8",r:"6.5",stroke:"currentColor",strokeOpacity:"0.25",strokeWidth:"2"}),e("path",{d:"M14.5 8A6.5 6.5 0 0 0 8 1.5",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round"})]})}export const TextField=n.forwardRef(function({variant:a="outline",size:o="md",color:c="primary",density:d="default",elevation:m=0,multiline:u=!1,rows:x=3,resize:b="vertical",label:z,description:B,error:C,invalid:D,startIcon:O,endIcon:R,loading:W=!1,fullWidth:I=!1,readOnly:L=!1,disabled:T=!1,type:A="text",className:E,style:F,...M},P){const q=null!=C&&!1!==C&&""!==C,G=D??q,H=G?"danger":c,J=n.useRef(null),K=n.useCallback(e=>{J.current=e,"function"==typeof P?P(e):P&&(P.current=e)},[P]),Q=[w,y[o],u?`${$[o]} items-start`:`${l[o]} items-center`,p[d][o],T?s[a]:L?j[a]:N[a]].filter(Boolean).join(" "),S=["min-w-0 flex-1 bg-transparent [font:inherit] text-inherit","[outline:none]","placeholder:text-(--neba-muted-fg)","caret-(--n-accent) selection:bg-(--n-soft-press)","disabled:cursor-not-allowed",u?`block ${v[b]}`:"self-stretch"].join(" "),U="inline-flex h-[1lh] shrink-0 items-center text-(--neba-muted-fg) transition-[color] duration-(--neba-duration) group-focus-within:text-(--n-accent)";return t(r.Root,{disabled:T,invalid:G,className:["flex-col align-top",h[o],I?"flex w-full":"inline-flex",E??""].filter(Boolean).join(" "),style:{...g(H,m),...F},children:[z?e(r.Label,{className:[f[o],"font-medium",T?"text-(--neba-disabled-fg)":"text-(--neba-fg)"].join(" "),children:z}):null,t("span",{className:Q,onPointerDown:e=>{e.target!==e.currentTarget||T||(e.preventDefault(),J.current?.focus())},children:[O?e("span",{className:U,children:O}):null,e(i,{ref:K,className:S,disabled:T,readOnly:L,"aria-busy":W||void 0,"data-loading":W||void 0,...u?{render:e("textarea",{rows:x})}:{type:A},...M}),W?e("span",{className:U,children:e(k,{})}):R?e("span",{className:U,children:R}):null]}),B?e(r.Description,{className:[f[o],"text-(--neba-muted-fg)"].join(" "),children:B}):null,q?e(r.Error,{match:!0,className:[f[o],"text-(--n-accent)"].join(" "),children:C}):null]})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{TextField}from"./TextField";
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { NebaAlign, NebaColor, NebaStyleProps, NebaVariant } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* Where the stack sits.
|
|
5
|
+
*
|
|
6
|
+
* Written as two words rather than as a `side` plus an `align` pair, because
|
|
7
|
+
* they are not independent: a toast stack is always pinned to the top or the
|
|
8
|
+
* bottom, never to a side, and offering `left`/`right` as a "side" would invite
|
|
9
|
+
* a stack down the middle of the screen that nothing in the layout survives.
|
|
10
|
+
* The second half is `NebaAlign`, the same word every other component uses.
|
|
11
|
+
*/
|
|
12
|
+
export type ToastPosition = `top-${NebaAlign}` | `bottom-${NebaAlign}`;
|
|
13
|
+
/**
|
|
14
|
+
* The Neba style props a single toast can override, carried in Base UI's
|
|
15
|
+
* per-toast `data`. Anything not set here falls back to the provider.
|
|
16
|
+
*/
|
|
17
|
+
export interface ToastData {
|
|
18
|
+
color?: NebaColor;
|
|
19
|
+
variant?: NebaVariant;
|
|
20
|
+
icon?: React.ReactNode | false;
|
|
21
|
+
}
|
|
22
|
+
export interface ToastOptions extends ToastData {
|
|
23
|
+
/**
|
|
24
|
+
* Reusing an id updates that toast in place and restarts its timer, which is
|
|
25
|
+
* what "uploading… / uploaded" wants: one toast that changed its mind, not two
|
|
26
|
+
* stacked on each other.
|
|
27
|
+
*/
|
|
28
|
+
id?: string;
|
|
29
|
+
/** The headline. */
|
|
30
|
+
title?: React.ReactNode;
|
|
31
|
+
/** The detail under it. A toast with only this is a one-line toast. */
|
|
32
|
+
description?: React.ReactNode;
|
|
33
|
+
/**
|
|
34
|
+
* How long before it dismisses itself, in milliseconds. `0` means it stays
|
|
35
|
+
* until it is closed — which is the right answer for anything the reader has
|
|
36
|
+
* to act on, because a toast that leaves before it is read said nothing.
|
|
37
|
+
*/
|
|
38
|
+
timeout?: number;
|
|
39
|
+
/**
|
|
40
|
+
* `high` interrupts a screen reader; `low` waits for a pause. An error is
|
|
41
|
+
* worth interrupting for and a save confirmation is not.
|
|
42
|
+
* @default 'low'
|
|
43
|
+
*/
|
|
44
|
+
priority?: 'low' | 'high';
|
|
45
|
+
/** The label of the action button. Passing it is what makes the button appear. */
|
|
46
|
+
actionLabel?: React.ReactNode;
|
|
47
|
+
onAction?: (event: React.MouseEvent<HTMLButtonElement>) => void;
|
|
48
|
+
/** Called when the toast closes, however it closed. */
|
|
49
|
+
onClose?: () => void;
|
|
50
|
+
/** Called once it has finished animating out and left the DOM. */
|
|
51
|
+
onRemove?: () => void;
|
|
52
|
+
}
|
|
53
|
+
export interface ToastProviderProps extends Pick<NebaStyleProps, 'variant' | 'size' | 'density'> {
|
|
54
|
+
/** The default colour family. A single toast overrides it in `add`. */
|
|
55
|
+
color?: NebaColor;
|
|
56
|
+
/** @default 'bottom-end' */
|
|
57
|
+
position?: ToastPosition;
|
|
58
|
+
/**
|
|
59
|
+
* How long a toast lasts by default, in milliseconds. `0` keeps every toast
|
|
60
|
+
* up until it is closed.
|
|
61
|
+
* @default 5000
|
|
62
|
+
*/
|
|
63
|
+
timeout?: number;
|
|
64
|
+
/**
|
|
65
|
+
* How many are shown at once. The rest are kept and revealed as the stack
|
|
66
|
+
* drains rather than being thrown away.
|
|
67
|
+
* @default 3
|
|
68
|
+
*/
|
|
69
|
+
limit?: number;
|
|
70
|
+
/** How wide a toast is allowed to get. Numbers are pixels. @default 380 */
|
|
71
|
+
width?: number | string;
|
|
72
|
+
/** Accessible name of every toast's × button. */
|
|
73
|
+
closeLabel?: string;
|
|
74
|
+
children?: React.ReactNode;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Raises toasts from anywhere under a `ToastProvider`.
|
|
78
|
+
*
|
|
79
|
+
* A hook rather than a component, because the thing a caller has at the moment
|
|
80
|
+
* a toast is warranted is a click handler, not a place in the tree — and a
|
|
81
|
+
* `<Toast open={…}/>` they would have to keep mounted, with a piece of state per
|
|
82
|
+
* message, is the shape this component exists to avoid.
|
|
83
|
+
*/
|
|
84
|
+
export declare function useToast(): {
|
|
85
|
+
/** Raises a toast and returns its id. */
|
|
86
|
+
add: (options: ToastOptions) => string;
|
|
87
|
+
/** Closes one toast, or every toast when called with nothing. */
|
|
88
|
+
close: (id?: string) => void;
|
|
89
|
+
/** Changes a toast already on screen. */
|
|
90
|
+
update: (id: string, options: ToastOptions) => void;
|
|
91
|
+
/**
|
|
92
|
+
* One toast that follows a promise: the loading message while it runs,
|
|
93
|
+
* then the success or the error. `timeout: 0` is applied to the loading
|
|
94
|
+
* state by Base UI, so a slow request cannot dismiss its own toast.
|
|
95
|
+
*/
|
|
96
|
+
promise: <Value>(promise: Promise<Value>, options: {
|
|
97
|
+
loading: ToastOptions;
|
|
98
|
+
success: ToastOptions | ((value: Value) => ToastOptions);
|
|
99
|
+
error: ToastOptions | ((error: unknown) => ToastOptions);
|
|
100
|
+
}) => Promise<Value>;
|
|
101
|
+
/** Every toast currently in the stack, newest first. */
|
|
102
|
+
toasts: import("@base-ui/react").ToastObject<ToastData>[];
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Puts the toast stack on the page and lets anything under it raise a message.
|
|
106
|
+
*
|
|
107
|
+
* Wrap the application once. Everything about how a toast *looks* is decided
|
|
108
|
+
* here — where the stack sits, how wide it is, which surface it wears, how long
|
|
109
|
+
* it lasts — so the call site stays the one thing it should be: what happened.
|
|
110
|
+
*
|
|
111
|
+
* Base UI owns the parts of this that are genuinely hard and invisible when
|
|
112
|
+
* they work: the timers and their pausing on hover and on window blur, the
|
|
113
|
+
* limit, the swipe, the F6 focus hotkey, and the live region that makes a
|
|
114
|
+
* message that appeared out of nowhere reach a screen reader at all.
|
|
115
|
+
*/
|
|
116
|
+
export declare function ToastProvider({ variant, size, color, density, position, timeout, limit, width, closeLabel, children }: ToastProviderProps): React.JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as t}from"react/jsx-runtime";import*as o from"react";import{Toast as i}from"@base-ui/react/toast";import{boxPaddingClasses as n}from"../box/Box";import{CloseIcon as s,severityIcons as a}from"../../internal/icons";import{controlSlots as r,focusRingClasses as l,hasContent as c,iconClasses as d,metaTextClasses as p,radiusClasses as u,sheetBodyClasses as m,sheetHeaderGapClasses as f,sheetSectionGapClasses as b,sheetTitleClasses as x,surfaceClasses as v}from"../../internal/styles";const h={"top-start":"top-0 items-start","top-center":"top-0 items-center","top-end":"top-0 items-end","bottom-start":"bottom-0 items-start flex-col-reverse","bottom-center":"bottom-0 items-center flex-col-reverse","bottom-end":"bottom-0 items-end flex-col-reverse"},y={solid:[v,"text-(--n-on-solid) bg-(--n-fill)","[box-shadow:var(--neba-shadow-3),var(--neba-plate-solid)]"].join(" "),outline:[v,"border text-(--neba-fg) bg-(--n-panel-press)","[border-color:var(--n-line)]","[box-shadow:var(--neba-shadow-3),var(--neba-plate-glass)]"].join(" "),text:[v,"text-(--neba-fg) bg-(--n-panel-press)","[box-shadow:var(--neba-shadow-3),var(--neba-plate-glass)]"].join(" ")},g={solid:"",outline:"text-(--n-accent)",text:"text-(--n-accent)"};function w(e){const{color:t,variant:o,icon:i,actionLabel:n,onAction:s,...a}=e;return{...a,data:{color:t,variant:o,icon:i},actionProps:void 0===n?void 0:{children:n,onClick:s}}}export function useToast(){const e=i.useToastManager();return o.useMemo(()=>({add:t=>e.add(w(t)),close:t=>e.close(t),update:(t,o)=>e.update(t,w(o)),promise:(t,o)=>e.promise(t,{loading:w(o.loading),success:e=>w("function"==typeof o.success?o.success(e):o.success),error:e=>w("function"==typeof o.error?o.error(e):o.error)}),toasts:e.toasts}),[e])}function j({toast:o,variant:v,color:h,size:w,density:j,closeLabel:N,swipeDirection:_}){const T=o.data?.variant??v??"outline",z=o.data?.color??h,$=void 0===o.data?.icon?a[z]:o.data.icon,k=g[T],D=c(o.title);return t(i.Root,{toast:o,swipeDirection:_,className:["pointer-events-auto flex w-full items-start",n[j??"default"][w],u[w],b[w],m[w],y[T],d,"[transition:opacity_var(--neba-duration)_var(--neba-ease)]","data-[starting-style]:opacity-0 data-[ending-style]:opacity-0","data-[limited]:hidden",l,"[outline:none]"].filter(Boolean).join(" "),style:r(z,3,T),children:[c($)?e("span",{className:`flex h-[1lh] shrink-0 items-center ${k}`,children:$}):null,t("div",{className:`flex min-w-0 flex-1 flex-col ${f[w]}`,children:[e(i.Title,{className:`neba-title font-semibold ${x[w]} ${k}`}),e(i.Description,{className:D?""+("solid"===T?"":"text-(--neba-muted-fg)"):""})]}),e(i.Action,{className:["flex h-[1lh] shrink-0 cursor-pointer items-center rounded-full px-2","font-medium underline-offset-2",k||"text-(--n-on-solid)","hover:underline","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-2",p[w]].join(" ")}),e("span",{className:"flex h-[1lh] shrink-0 items-center",children:e(i.Close,{"aria-label":N,className:["inline-flex size-[1.15em] cursor-pointer items-center justify-center rounded-full","opacity-70 [transition:opacity_var(--neba-duration)_var(--neba-ease)]","hover:opacity-100 focus-visible:opacity-100","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-2"].join(" "),children:e(s,{})})})]})}function N(t){const{toasts:o}=i.useToastManager(),{position:n,width:s,...a}=t,r=[n.startsWith("top")?"up":"down","left","right"];return e(i.Portal,{children:e(i.Viewport,{className:["neba-portal pointer-events-none fixed inset-x-0 z-50 flex flex-col gap-2 p-4",h[n]].join(" "),children:o.map(t=>e("div",{className:"w-full",style:{maxWidth:"number"==typeof s?`${s}px`:s},children:e(j,{toast:t,swipeDirection:r,...a})},t.id))})})}export function ToastProvider({variant:o="outline",size:n="md",color:s="primary",density:a="default",position:r="bottom-end",timeout:l=5e3,limit:c=3,width:d=380,closeLabel:p="Close",children:u}){return t(i.Provider,{timeout:l,limit:c,children:[u,e(N,{position:r,variant:o,size:n,color:s,density:a,width:d,closeLabel:p})]})}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{ToastProvider,useToast}from"./Toast";
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Tooltip as BaseUITooltip } from '@base-ui/react/tooltip';
|
|
3
|
+
import type { NebaAlign, NebaSide, NebaStyleProps } from '../../types';
|
|
4
|
+
export interface TooltipProps extends Pick<NebaStyleProps, 'size' | 'color' | 'density'> {
|
|
5
|
+
/**
|
|
6
|
+
* What the tooltip says.
|
|
7
|
+
*
|
|
8
|
+
* A short phrase. A tooltip is not a container — it cannot be reached by a
|
|
9
|
+
* pointer on a touch screen, it disappears the moment attention moves, and
|
|
10
|
+
* anything inside it that could be clicked cannot be. Content that needs
|
|
11
|
+
* either of those is a Popover's job, not this one.
|
|
12
|
+
*/
|
|
13
|
+
content: React.ReactNode;
|
|
14
|
+
/**
|
|
15
|
+
* The element the tooltip hangs off. Exactly one element, which must accept a
|
|
16
|
+
* ref and spread props — every Neba component does.
|
|
17
|
+
*/
|
|
18
|
+
children: React.ReactElement;
|
|
19
|
+
/**
|
|
20
|
+
* Which edge of the trigger it appears on. May flip to the opposite side when
|
|
21
|
+
* there is no room, which is Base UI's doing and is the right behaviour.
|
|
22
|
+
* @default 'top'
|
|
23
|
+
*/
|
|
24
|
+
side?: NebaSide;
|
|
25
|
+
/** Where it sits along that edge. @default 'center' */
|
|
26
|
+
align?: NebaAlign;
|
|
27
|
+
/** Distance from the trigger, in pixels. @default 6 */
|
|
28
|
+
sideOffset?: number;
|
|
29
|
+
/**
|
|
30
|
+
* How long the pointer has to rest before it opens, in milliseconds.
|
|
31
|
+
* @default 600
|
|
32
|
+
*/
|
|
33
|
+
delay?: number;
|
|
34
|
+
/** How long it waits before closing once the pointer leaves. @default 0 */
|
|
35
|
+
closeDelay?: number;
|
|
36
|
+
/** Draws the little wedge pointing at the trigger. @default true */
|
|
37
|
+
arrow?: boolean;
|
|
38
|
+
/** Whether the tooltip is open. Use with `onOpenChange` for a controlled one. */
|
|
39
|
+
open?: boolean;
|
|
40
|
+
/** Whether it starts open, for an uncontrolled one. */
|
|
41
|
+
defaultOpen?: boolean;
|
|
42
|
+
onOpenChange?: (open: boolean) => void;
|
|
43
|
+
/**
|
|
44
|
+
* Stops the tooltip from opening at all, without disabling the trigger. For
|
|
45
|
+
* the tooltip that only exists while a label is truncated.
|
|
46
|
+
* @default false
|
|
47
|
+
*/
|
|
48
|
+
disabled?: boolean;
|
|
49
|
+
className?: string;
|
|
50
|
+
style?: React.CSSProperties;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Shares one delay across a group of tooltips: once any of them has opened, its
|
|
54
|
+
* neighbours open instantly, and the wait comes back after a pause.
|
|
55
|
+
*
|
|
56
|
+
* Worth wrapping a toolbar in. Without it, moving along a row of icon buttons
|
|
57
|
+
* means waiting out the full delay at every stop, which is what makes tooltips
|
|
58
|
+
* feel like they are fighting the pointer.
|
|
59
|
+
*/
|
|
60
|
+
export declare const TooltipProvider: React.FC<import("@base-ui/react").TooltipProviderProps>;
|
|
61
|
+
export type TooltipProviderProps = React.ComponentProps<typeof BaseUITooltip.Provider>;
|
|
62
|
+
/**
|
|
63
|
+
* A short label that appears when the pointer rests on something.
|
|
64
|
+
*
|
|
65
|
+
* The whole component is a wrapper: `<Tooltip content="Copy"><Button …/></Tooltip>`.
|
|
66
|
+
* Base UI's Trigger merges itself onto the child rather than rendering a box of
|
|
67
|
+
* its own, so the tooltip adds no element to the layout and the child stays
|
|
68
|
+
* whatever it was — a button, a chip, a truncated cell.
|
|
69
|
+
*
|
|
70
|
+
* Base UI owns the parts that are genuinely hard: the delay and the group
|
|
71
|
+
* timeout, opening on focus but not on a focus that came from a click, closing
|
|
72
|
+
* on Escape, and keeping the popup off the edges of the window.
|
|
73
|
+
*
|
|
74
|
+
* The one thing it deliberately leaves open is the part that makes a tooltip
|
|
75
|
+
* mean anything to a screen reader — `role="tooltip"` on the plate and an
|
|
76
|
+
* `aria-describedby` pointing at it from the trigger — because a popup can be
|
|
77
|
+
* many things and only the caller knows which. Here it is always a tooltip, so
|
|
78
|
+
* this component wires both, and drops the reference while it is closed rather
|
|
79
|
+
* than pointing at an element that is not in the document.
|
|
80
|
+
*/
|
|
81
|
+
export declare function Tooltip({ content, children, size, color, density, side, align, sideOffset, delay, closeDelay, arrow, open, defaultOpen, onOpenChange, disabled, className, style }: TooltipProps): React.JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as t}from"react/jsx-runtime";import*as a from"react";import{Tooltip as o}from"@base-ui/react/tooltip";import{controlSlots as i,metaTextClasses as s,paddingXClasses as n,radiusClasses as l,surfaceClasses as r}from"../../internal/styles";export const TooltipProvider=o.Provider;const d=[r,"max-w-64 text-(--n-on-solid) bg-(--n-fill)","[box-shadow:var(--neba-shadow-3),var(--neba-plate-solid)]","[outline:none]","[transition:opacity_var(--neba-duration)_var(--neba-ease)]","data-[starting-style]:opacity-0 data-[ending-style]:opacity-0","data-[instant]:[transition-duration:0ms]"].join(" "),p={xs:"py-0.5",sm:"py-0.5",md:"py-1",lg:"py-1.5",xl:"py-2"},c={xs:6,sm:7,md:8,lg:9,xl:10};export function Tooltip({content:r,children:m,size:h="sm",color:y="secondary",density:f="default",side:x="top",align:b="center",sideOffset:g=6,delay:u,closeDelay:v,arrow:w=!0,open:j,defaultOpen:O,onOpenChange:N,disabled:P=!1,className:T,style:z}){const B=c[h],C=a.useId(),[D,_]=a.useState(O??!1),k=j??D;return t(o.Root,{open:j,defaultOpen:O,onOpenChange:e=>{_(e),N?.(e)},children:[e(o.Trigger,{render:m,delay:u,closeDelay:v,disabled:P,"aria-describedby":k?C:void 0}),e(o.Portal,{children:e(o.Positioner,{className:"neba-portal z-50 [outline:none]",side:x,align:b,sideOffset:g,children:t(o.Popup,{id:C,role:"tooltip",className:[d,l[h],n[f][h],p[h],s[h],T??""].filter(Boolean).join(" "),style:{...i(y,3,"solid"),...z},children:[w?e(o.Arrow,{className:["data-[side=top]:bottom-[-1px]","data-[side=bottom]:top-[-1px] data-[side=bottom]:rotate-180","data-[side=left]:right-[-1px] data-[side=left]:-rotate-90","data-[side=right]:left-[-1px] data-[side=right]:rotate-90"].join(" "),children:e("svg",{width:B,height:B/2,viewBox:"0 0 10 5","aria-hidden":"true",className:"block",children:e("path",{d:"M0 0h10L5 5z",fill:"var(--n-fill)"})})}):null,r]})})})]})}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{Tooltip,TooltipProvider}from"./Tooltip";
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
3
|
+
import type { NebaColor } from '../../types';
|
|
4
|
+
/**
|
|
5
|
+
* What a piece of text *is*, which decides both its type scale and the element
|
|
6
|
+
* it renders as.
|
|
7
|
+
*
|
|
8
|
+
* This is deliberately not called `variant`. In this library `variant` means the
|
|
9
|
+
* weight of a surface — `solid` / `outline` / `text` — and a second meaning for
|
|
10
|
+
* the same word is exactly what the prop conventions forbid.
|
|
11
|
+
*/
|
|
12
|
+
export type TypographyLevel = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'body' | 'lead' | 'caption' | 'overline';
|
|
13
|
+
export type TypographyAlign = 'start' | 'center' | 'end' | 'justify';
|
|
14
|
+
export type TypographyWeight = 'regular' | 'medium' | 'semibold' | 'bold';
|
|
15
|
+
export interface TypographyProps extends Omit<React.ComponentPropsWithoutRef<'p'>, 'color' | 'children'> {
|
|
16
|
+
/**
|
|
17
|
+
* The type scale, and the element that carries it. `h1`–`h6` render the
|
|
18
|
+
* matching heading, `lead`/`body` a `<p>`, `caption`/`overline` a `<span>`.
|
|
19
|
+
* @default 'body'
|
|
20
|
+
*/
|
|
21
|
+
level?: TypographyLevel;
|
|
22
|
+
/**
|
|
23
|
+
* Semantic colour role. Unlike every other component this has **no default**:
|
|
24
|
+
* text inherits the page's own colour unless a role is asked for, because the
|
|
25
|
+
* common case for a paragraph is to look like the paragraphs around it.
|
|
26
|
+
*/
|
|
27
|
+
color?: NebaColor;
|
|
28
|
+
/** Overrides the weight the level would otherwise pick. */
|
|
29
|
+
weight?: TypographyWeight;
|
|
30
|
+
align?: TypographyAlign;
|
|
31
|
+
/**
|
|
32
|
+
* Clamps the text to this many lines with an ellipsis. `1` is a single-line
|
|
33
|
+
* truncation. Omit it and the text wraps as far as it needs to.
|
|
34
|
+
*/
|
|
35
|
+
lines?: number;
|
|
36
|
+
/**
|
|
37
|
+
* Adds the space below that a run of prose expects. Off by default: a library
|
|
38
|
+
* component that injects margins is one a layout has to fight.
|
|
39
|
+
* @default false
|
|
40
|
+
*/
|
|
41
|
+
gutter?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Renders a different element without changing the type scale — a `h2`-sized
|
|
44
|
+
* line that is semantically a `<p>`, or the other way round. Base UI's own
|
|
45
|
+
* escape hatch, so it behaves the same here as on Box.
|
|
46
|
+
*/
|
|
47
|
+
render?: useRender.RenderProp;
|
|
48
|
+
children?: React.ReactNode;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Text at one of the library's sizes.
|
|
52
|
+
*
|
|
53
|
+
* The type scale is the one thing in a design system that everything else is
|
|
54
|
+
* measured against, and until now it only existed inside the components that
|
|
55
|
+
* happened to need it — a Card's title, a TextField's label. This is that ladder
|
|
56
|
+
* on its own, so a page can use it without wrapping its prose in a card.
|
|
57
|
+
*
|
|
58
|
+
* `level` sets the scale *and* the element, which is the common case. When they
|
|
59
|
+
* have to differ — a subheading that should not enter the document outline, a
|
|
60
|
+
* `<p>` that has to look like an `h3` — `render` breaks the tie.
|
|
61
|
+
*/
|
|
62
|
+
export declare const Typography: React.ForwardRefExoticComponent<TypographyProps & React.RefAttributes<HTMLElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import*as e from"react";import{useRender as t}from"@base-ui/react/use-render";const r={h1:"text-[1.875rem]/[2.25rem] tracking-[-0.02em]",h2:"text-[1.5rem]/[1.875rem] tracking-[-0.015em]",h3:"text-[1.25rem]/[1.625rem] tracking-[-0.01em]",h4:"text-[1.0625rem]/[1.5rem]",h5:"text-[0.9375rem]/[1.375rem]",h6:"text-[0.8125rem]/[1.25rem]",lead:"text-[1.0625rem]/[1.75rem]",body:"text-[0.8125rem]/[1.375rem]",caption:"text-[0.75rem]/[1.125rem]",overline:"text-[0.6875rem]/[1rem] tracking-[0.08em] uppercase"},m={h1:"semibold",h2:"semibold",h3:"semibold",h4:"semibold",h5:"semibold",h6:"semibold",lead:"regular",body:"regular",caption:"regular",overline:"medium"},n={h1:"h1",h2:"h2",h3:"h3",h4:"h4",h5:"h5",h6:"h6",lead:"p",body:"p",caption:"span",overline:"span"},a=new Set(["caption","overline"]),l={h1:"mb-4",h2:"mb-3.5",h3:"mb-3",h4:"mb-2.5",h5:"mb-2",h6:"mb-2",lead:"mb-4",body:"mb-3",caption:"mb-2",overline:"mb-2"},o={regular:"font-normal",medium:"font-medium",semibold:"font-semibold",bold:"font-bold"},i={start:"text-start",center:"text-center",end:"text-end",justify:"text-justify"},c={1:"truncate",2:"line-clamp-2",3:"line-clamp-3",4:"line-clamp-4",5:"line-clamp-5",6:"line-clamp-6"};export const Typography=e.forwardRef(function({level:h="body",color:d,weight:s,align:b,lines:p,gutter:x=!1,render:u,className:f,style:g,children:y,...v},k){const j=[r[h],o[s??m[h]],b?i[b]:"",p?c[p]??"line-clamp-6":"",x?l[h]:"",d?"text-(--n-accent)":a.has(h)?"text-(--neba-muted-fg)":"text-(--neba-fg)",f??""].filter(Boolean).join(" ");return t({render:u??e.createElement(n[h]),ref:k,props:{className:j,style:d?{"--n-accent":`var(--neba-${d}-accent)`,...g}:g,children:y,...v}})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{Typography}from"./Typography";
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1,32 @@
|
|
|
1
|
-
export * from './
|
|
1
|
+
export * from './types';
|
|
2
|
+
export * from './components/accordion';
|
|
3
|
+
export * from './components/alert';
|
|
4
|
+
export * from './components/badge';
|
|
5
|
+
export * from './components/box';
|
|
6
|
+
export * from './components/button';
|
|
7
|
+
export * from './components/button-group';
|
|
8
|
+
export * from './components/card';
|
|
9
|
+
export * from './components/checkbox';
|
|
10
|
+
export * from './components/chip';
|
|
11
|
+
export * from './components/combobox';
|
|
12
|
+
export * from './components/dialog';
|
|
13
|
+
export * from './components/divider';
|
|
14
|
+
export * from './components/file-picker';
|
|
15
|
+
export * from './components/list';
|
|
16
|
+
export * from './components/menu';
|
|
17
|
+
export * from './components/number-field';
|
|
18
|
+
export * from './components/overlay';
|
|
19
|
+
export * from './components/pagination';
|
|
20
|
+
export * from './components/progress-box';
|
|
21
|
+
export * from './components/progress-circular';
|
|
22
|
+
export * from './components/progress-linear';
|
|
23
|
+
export * from './components/radio-group';
|
|
24
|
+
export * from './components/select';
|
|
25
|
+
export * from './components/slider';
|
|
26
|
+
export * from './components/switch';
|
|
27
|
+
export * from './components/table';
|
|
28
|
+
export * from './components/tabs';
|
|
29
|
+
export * from './components/text-field';
|
|
30
|
+
export * from './components/toast';
|
|
31
|
+
export * from './components/tooltip';
|
|
32
|
+
export * from './components/typography';
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export*from"./components/button/
|
|
1
|
+
export*from"./types";export*from"./components/accordion";export*from"./components/alert";export*from"./components/badge";export*from"./components/box";export*from"./components/button";export*from"./components/button-group";export*from"./components/card";export*from"./components/checkbox";export*from"./components/chip";export*from"./components/combobox";export*from"./components/dialog";export*from"./components/divider";export*from"./components/file-picker";export*from"./components/list";export*from"./components/menu";export*from"./components/number-field";export*from"./components/overlay";export*from"./components/pagination";export*from"./components/progress-box";export*from"./components/progress-circular";export*from"./components/progress-linear";export*from"./components/radio-group";export*from"./components/select";export*from"./components/slider";export*from"./components/switch";export*from"./components/table";export*from"./components/tabs";export*from"./components/text-field";export*from"./components/toast";export*from"./components/tooltip";export*from"./components/typography";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { NebaColor, NebaDensity, NebaElevation, NebaSize, NebaVariant } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* What a Button inherits from the ButtonGroup around it.
|
|
5
|
+
*
|
|
6
|
+
* The alternative — `React.Children.map` with `cloneElement` — breaks the moment
|
|
7
|
+
* a caller wraps one of the buttons in a Tooltip, a `<Fragment>` or a `.map()`,
|
|
8
|
+
* which is most of the time. A context reaches the Button wherever it ended up.
|
|
9
|
+
*
|
|
10
|
+
* Every field is optional and every one of them means "not specified": a Button
|
|
11
|
+
* falls back to its own default rather than to a value the group invented, so
|
|
12
|
+
* `<ButtonGroup>` with no props changes nothing except the corners.
|
|
13
|
+
*
|
|
14
|
+
* It lives in `internal/` rather than in the button-group folder so that Button
|
|
15
|
+
* can read it without the two components importing each other.
|
|
16
|
+
*/
|
|
17
|
+
export interface ButtonGroupContextValue {
|
|
18
|
+
variant?: NebaVariant;
|
|
19
|
+
size?: NebaSize;
|
|
20
|
+
color?: NebaColor;
|
|
21
|
+
density?: NebaDensity;
|
|
22
|
+
elevation?: NebaElevation;
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
}
|
|
25
|
+
export declare const ButtonGroupContext: React.Context<ButtonGroupContextValue | null>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import*as t from"react";export const ButtonGroupContext=t.createContext(null);
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { NebaColor } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* The glyphs more than one component draws.
|
|
5
|
+
*
|
|
6
|
+
* All of them are 16×16 with a 1.5px stroke and no fill except where a dot is
|
|
7
|
+
* meant to read as solid, and none of them carries a size: `iconClasses` in
|
|
8
|
+
* `styles.ts` sizes every icon in `em`, so one drawing serves every step of the
|
|
9
|
+
* scale.
|
|
10
|
+
*
|
|
11
|
+
* They live here rather than in the components for the ordinary reason — the ×
|
|
12
|
+
* on a Chip, an Alert, a Dialog and a Toast is one × — and for one that matters
|
|
13
|
+
* more: the severity set is a piece of the design language. An alert that says
|
|
14
|
+
* "this went wrong" only in red says it only to some readers, so the shape has
|
|
15
|
+
* to carry the meaning too, and that only holds if every component uses the
|
|
16
|
+
* same shape for the same family.
|
|
17
|
+
*/
|
|
18
|
+
export declare function CloseIcon(): React.JSX.Element;
|
|
19
|
+
/**
|
|
20
|
+
* The disclosure chevron, drawn pointing **down**.
|
|
21
|
+
*
|
|
22
|
+
* One drawing for every direction: a Select's trigger, an Accordion's header, a
|
|
23
|
+
* submenu's arrow and a Pagination's steppers all want the same wedge turned a
|
|
24
|
+
* different way, and turning it is the one allowance the no-transform rule
|
|
25
|
+
* makes — a glyph has no text in it to resample.
|
|
26
|
+
*/
|
|
27
|
+
export declare function ChevronIcon(): React.JSX.Element;
|
|
28
|
+
/** The tick: a chosen option, a ticked menu item. */
|
|
29
|
+
export declare function CheckIcon(): React.JSX.Element;
|
|
30
|
+
/**
|
|
31
|
+
* The two steppers, and the `+` that offers a value the list does not have.
|
|
32
|
+
*
|
|
33
|
+
* They are a pair and stay one: a minus drawn to a different weight from the
|
|
34
|
+
* plus beside it reads as two toolkits in one control. NumberField draws both;
|
|
35
|
+
* Combobox draws the plus on its "add this" row.
|
|
36
|
+
*/
|
|
37
|
+
export declare function MinusIcon(): React.JSX.Element;
|
|
38
|
+
export declare function PlusIcon(): React.JSX.Element;
|
|
39
|
+
/** The filled dot: the chosen one of a set, where a tick would say "and". */
|
|
40
|
+
export declare function DotIcon(): React.JSX.Element;
|
|
41
|
+
/**
|
|
42
|
+
* One drawing per colour family.
|
|
43
|
+
*
|
|
44
|
+
* `primary` and `secondary` have no severity to draw, so they take the note the
|
|
45
|
+
* informational one uses — three shapes for six families, because the three
|
|
46
|
+
* that mean something are the three worth telling apart.
|
|
47
|
+
*/
|
|
48
|
+
export declare const severityIcons: Record<NebaColor, React.ReactNode>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as r,jsxs as e}from"react/jsx-runtime";export function CloseIcon(){return r("svg",{viewBox:"0 0 16 16",fill:"none","aria-hidden":"true",children:r("path",{d:"m4.5 4.5 7 7m0-7-7 7",stroke:"currentColor",strokeWidth:"1.75",strokeLinecap:"round"})})}export function ChevronIcon(){return r("svg",{viewBox:"0 0 16 16",fill:"none","aria-hidden":"true",children:r("path",{d:"m4.5 6.5 3.5 3.5 3.5-3.5",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})}export function CheckIcon(){return r("svg",{viewBox:"0 0 16 16",fill:"none","aria-hidden":"true",children:r("path",{d:"m3.5 8.5 3 3 6-6",stroke:"currentColor",strokeWidth:"1.75",strokeLinecap:"round",strokeLinejoin:"round"})})}export function MinusIcon(){return r("svg",{viewBox:"0 0 16 16",fill:"none","aria-hidden":"true",children:r("path",{d:"M3.5 8h9",stroke:"currentColor",strokeWidth:"1.75",strokeLinecap:"round"})})}export function PlusIcon(){return r("svg",{viewBox:"0 0 16 16",fill:"none","aria-hidden":"true",children:r("path",{d:"M8 3.5v9M3.5 8h9",stroke:"currentColor",strokeWidth:"1.75",strokeLinecap:"round"})})}export function DotIcon(){return r("svg",{viewBox:"0 0 16 16",fill:"none","aria-hidden":"true",children:r("circle",{cx:"8",cy:"8",r:"3.25",fill:"currentColor"})})}function o(){return e("svg",{viewBox:"0 0 16 16",fill:"none","aria-hidden":"true",children:[r("circle",{cx:"8",cy:"8",r:"6.25",stroke:"currentColor",strokeWidth:"1.5"}),r("path",{d:"M8 7.25v4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round"}),r("circle",{cx:"8",cy:"4.9",r:"0.85",fill:"currentColor"})]})}export const severityIcons={primary:r(o,{}),secondary:r(o,{}),info:r(o,{}),success:e("svg",{viewBox:"0 0 16 16",fill:"none","aria-hidden":"true",children:[r("circle",{cx:"8",cy:"8",r:"6.25",stroke:"currentColor",strokeWidth:"1.5"}),r("path",{d:"m5.25 8.25 1.9 1.9 3.6-3.9",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})]}),warning:e("svg",{viewBox:"0 0 16 16",fill:"none","aria-hidden":"true",children:[r("path",{d:"M7.13 2.6 1.9 11.7a1 1 0 0 0 .87 1.5h10.46a1 1 0 0 0 .87-1.5L8.87 2.6a1 1 0 0 0-1.74 0Z",stroke:"currentColor",strokeWidth:"1.5",strokeLinejoin:"round"}),r("path",{d:"M8 6.1v3",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round"}),r("circle",{cx:"8",cy:"11.2",r:"0.85",fill:"currentColor"})]}),danger:e("svg",{viewBox:"0 0 16 16",fill:"none","aria-hidden":"true",children:[r("circle",{cx:"8",cy:"8",r:"6.25",stroke:"currentColor",strokeWidth:"1.5"}),r("path",{d:"m5.9 5.9 4.2 4.2m0-4.2-4.2 4.2",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round"})]})};
|