neba 1.1.0 → 1.3.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 +12 -7
- package/dist/components/alert/Alert.d.ts +7 -1
- package/dist/components/alert/Alert.js +1 -1
- package/dist/components/animate-appear/AnimateAppear.d.ts +55 -0
- package/dist/components/animate-appear/AnimateAppear.js +1 -0
- package/dist/components/animate-appear/index.d.ts +2 -0
- package/dist/components/animate-appear/index.js +1 -0
- package/dist/components/animate-blink/AnimateBlink.d.ts +31 -0
- package/dist/components/animate-blink/AnimateBlink.js +1 -0
- package/dist/components/animate-blink/index.d.ts +2 -0
- package/dist/components/animate-blink/index.js +1 -0
- package/dist/components/animate-fade/AnimateFade.d.ts +31 -0
- package/dist/components/animate-fade/AnimateFade.js +1 -0
- package/dist/components/animate-fade/index.d.ts +2 -0
- package/dist/components/animate-fade/index.js +1 -0
- package/dist/components/animate-grow/AnimateGrow.d.ts +41 -0
- package/dist/components/animate-grow/AnimateGrow.js +1 -0
- package/dist/components/animate-grow/index.d.ts +2 -0
- package/dist/components/animate-grow/index.js +1 -0
- package/dist/components/animate-headline/AnimateHeadline.d.ts +55 -0
- package/dist/components/animate-headline/AnimateHeadline.js +1 -0
- package/dist/components/animate-headline/index.d.ts +2 -0
- package/dist/components/animate-headline/index.js +1 -0
- package/dist/components/animate-lighting/AnimateLighting.d.ts +62 -0
- package/dist/components/animate-lighting/AnimateLighting.js +1 -0
- package/dist/components/animate-lighting/index.d.ts +2 -0
- package/dist/components/animate-lighting/index.js +1 -0
- package/dist/components/animate-marquee/AnimateMarquee.d.ts +65 -0
- package/dist/components/animate-marquee/AnimateMarquee.js +1 -0
- package/dist/components/animate-marquee/index.d.ts +2 -0
- package/dist/components/animate-marquee/index.js +1 -0
- package/dist/components/animate-rotate/AnimateRotate.d.ts +48 -0
- package/dist/components/animate-rotate/AnimateRotate.js +1 -0
- package/dist/components/animate-rotate/index.d.ts +2 -0
- package/dist/components/animate-rotate/index.js +1 -0
- package/dist/components/animate-slide/AnimateSlide.d.ts +46 -0
- package/dist/components/animate-slide/AnimateSlide.js +1 -0
- package/dist/components/animate-slide/index.d.ts +2 -0
- package/dist/components/animate-slide/index.js +1 -0
- package/dist/components/animate-typing/AnimateTyping.d.ts +58 -0
- package/dist/components/animate-typing/AnimateTyping.js +1 -0
- package/dist/components/animate-typing/index.d.ts +2 -0
- package/dist/components/animate-typing/index.js +1 -0
- package/dist/components/animate-zoom/AnimateZoom.d.ts +37 -0
- package/dist/components/animate-zoom/AnimateZoom.js +1 -0
- package/dist/components/animate-zoom/index.d.ts +2 -0
- package/dist/components/animate-zoom/index.js +1 -0
- package/dist/components/aspect-ratio/AspectRatio.d.ts +63 -0
- package/dist/components/aspect-ratio/AspectRatio.js +1 -0
- package/dist/components/aspect-ratio/index.d.ts +2 -0
- package/dist/components/aspect-ratio/index.js +1 -0
- package/dist/components/avatar/Avatar.d.ts +106 -0
- package/dist/components/avatar/Avatar.js +1 -0
- package/dist/components/avatar/index.d.ts +2 -0
- package/dist/components/avatar/index.js +1 -0
- package/dist/components/blockquote/Blockquote.d.ts +7 -1
- package/dist/components/blockquote/Blockquote.js +1 -1
- package/dist/components/box/Box.d.ts +7 -1
- package/dist/components/box/Box.js +1 -1
- package/dist/components/breadcrumb/Breadcrumb.d.ts +92 -0
- package/dist/components/breadcrumb/Breadcrumb.js +1 -0
- package/dist/components/breadcrumb/index.d.ts +2 -0
- package/dist/components/breadcrumb/index.js +1 -0
- package/dist/components/chat-bubble/ChatBubble.d.ts +114 -0
- package/dist/components/chat-bubble/ChatBubble.js +1 -0
- package/dist/components/chat-bubble/index.d.ts +2 -0
- package/dist/components/chat-bubble/index.js +1 -0
- package/dist/components/chip/Chip.d.ts +7 -1
- package/dist/components/chip/Chip.js +1 -1
- package/dist/components/color-picker/ColorPicker.d.ts +102 -0
- package/dist/components/color-picker/ColorPicker.js +1 -0
- package/dist/components/color-picker/index.d.ts +2 -0
- package/dist/components/color-picker/index.js +1 -0
- package/dist/components/drawer/Drawer.d.ts +145 -0
- package/dist/components/drawer/Drawer.js +1 -0
- package/dist/components/drawer/index.d.ts +2 -0
- package/dist/components/drawer/index.js +1 -0
- package/dist/components/icon/Icon.d.ts +8 -1
- package/dist/components/icon/Icon.js +1 -1
- package/dist/components/otp-field/OtpField.d.ts +85 -0
- package/dist/components/otp-field/OtpField.js +1 -0
- package/dist/components/otp-field/index.d.ts +2 -0
- package/dist/components/otp-field/index.js +1 -0
- package/dist/components/panes/Panes.d.ts +78 -0
- package/dist/components/panes/Panes.js +1 -0
- package/dist/components/panes/index.d.ts +2 -0
- package/dist/components/panes/index.js +1 -0
- package/dist/components/popover/Popover.d.ts +109 -0
- package/dist/components/popover/Popover.js +1 -0
- package/dist/components/popover/index.d.ts +2 -0
- package/dist/components/popover/index.js +1 -0
- package/dist/components/skeleton/Skeleton.d.ts +76 -0
- package/dist/components/skeleton/Skeleton.js +1 -0
- package/dist/components/skeleton/index.d.ts +2 -0
- package/dist/components/skeleton/index.js +1 -0
- package/dist/components/spoiler/Spoiler.d.ts +95 -0
- package/dist/components/spoiler/Spoiler.js +1 -0
- package/dist/components/spoiler/index.d.ts +2 -0
- package/dist/components/spoiler/index.js +1 -0
- package/dist/components/text-link/TextLink.d.ts +82 -0
- package/dist/components/text-link/TextLink.js +1 -0
- package/dist/components/text-link/index.d.ts +2 -0
- package/dist/components/text-link/index.js +1 -0
- package/dist/components/tree-view/TreeView.d.ts +115 -0
- package/dist/components/tree-view/TreeView.js +1 -0
- package/dist/components/tree-view/index.d.ts +2 -0
- package/dist/components/tree-view/index.js +1 -0
- package/dist/components/typography/Typography.d.ts +7 -1
- package/dist/components/typography/Typography.js +1 -1
- package/dist/index.d.ts +24 -0
- package/dist/index.js +1 -1
- package/dist/internal/animate.d.ts +175 -0
- package/dist/internal/animate.js +1 -0
- package/dist/internal/color.d.ts +108 -0
- package/dist/internal/color.js +1 -0
- package/dist/internal/i18n.d.ts +103 -0
- package/dist/internal/i18n.js +1 -0
- package/dist/internal/icons.d.ts +23 -0
- package/dist/internal/icons.js +1 -1
- package/dist/styles.css +1 -1
- package/dist/tailwind.css +504 -0
- package/dist/types.d.ts +112 -0
- package/package.json +14 -14
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
3
|
+
import type { NebaAnimateMode, NebaAnimateProps, NebaSide } from '../../types';
|
|
4
|
+
export interface AnimateSlideProps extends NebaAnimateProps, React.ComponentPropsWithoutRef<'div'> {
|
|
5
|
+
/**
|
|
6
|
+
* Whether the content slides in or slides away. `out` leaves by the same edge
|
|
7
|
+
* it would have come from.
|
|
8
|
+
* @default 'in'
|
|
9
|
+
*/
|
|
10
|
+
mode?: NebaAnimateMode;
|
|
11
|
+
/**
|
|
12
|
+
* Which edge it travels from. Physical, as `NebaSide` is everywhere — a panel
|
|
13
|
+
* sliding down from the top comes from the top in every writing direction.
|
|
14
|
+
* @default 'bottom'
|
|
15
|
+
*/
|
|
16
|
+
from?: NebaSide;
|
|
17
|
+
/**
|
|
18
|
+
* How far it travels — a CSS length, or a number in pixels. `'100%'` is the
|
|
19
|
+
* element's own width or height, which is what makes it appear from behind
|
|
20
|
+
* its own edge.
|
|
21
|
+
* @default '100%'
|
|
22
|
+
*/
|
|
23
|
+
distance?: number | string;
|
|
24
|
+
/**
|
|
25
|
+
* Fades in as it slides.
|
|
26
|
+
* @default true
|
|
27
|
+
*/
|
|
28
|
+
fade?: boolean;
|
|
29
|
+
/** Renders something other than a `<div>`. Base UI's own escape hatch. */
|
|
30
|
+
render?: useRender.RenderProp;
|
|
31
|
+
children?: React.ReactNode;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Content travelling in from one edge.
|
|
35
|
+
*
|
|
36
|
+
* The default distance is the element's own size, so it starts exactly out of
|
|
37
|
+
* frame and arrives without ever having been half drawn somewhere it does not
|
|
38
|
+
* belong. Put it in a box with `overflow: hidden` and the effect is a panel
|
|
39
|
+
* appearing from behind that box's edge.
|
|
40
|
+
*
|
|
41
|
+
* A slide moves the element, so what is *around* it does not move: this is a
|
|
42
|
+
* `translate`, not a change of layout, and nothing on the page reflows while it
|
|
43
|
+
* runs. For a much shorter travel over a list of things, one after another, use
|
|
44
|
+
* AnimateAppear.
|
|
45
|
+
*/
|
|
46
|
+
export declare const AnimateSlide: React.ForwardRefExoticComponent<AnimateSlideProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import*as e from"react";import{useRender as r}from"@base-ui/react/use-render";import{isInfinite as t,slideOffsets as a,useAnimateElement as n}from"../../internal/animate";import{cx as o}from"../../internal/styles";export const AnimateSlide=e.forwardRef(function({duration:e=380,delay:i=0,easing:s,repeat:l=1,alternate:d,paused:m,trigger:p="mount",play:c,once:f=!0,threshold:y=.2,mode:u="in",from:g="bottom",distance:h="100%",fade:x=!0,render:N,className:b,style:w,children:A,...R},S){const{x:j,y:k}=a(g,h),q=n({effect:"slide",duration:e,delay:i,easing:s,repeat:l,alternate:d,mode:u,x:j,y:k,opacity:x?0:1,trigger:p,play:c,once:f,threshold:y,paused:m,infinite:t(l)});return r({render:N,ref:[S,q.ref],props:{...R,className:o(q.className,b),style:{...q.style,...w},...q.props,children:A}})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{AnimateSlide}from"./AnimateSlide";
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { NebaAnimateProps } from '../../types';
|
|
3
|
+
export interface AnimateTypingProps extends Omit<NebaAnimateProps, 'alternate' | 'easing'>, Omit<React.ComponentPropsWithoutRef<'div'>, 'children'> {
|
|
4
|
+
/**
|
|
5
|
+
* The text, when it is easier to pass than to nest. Overrides `children`.
|
|
6
|
+
*/
|
|
7
|
+
text?: string;
|
|
8
|
+
/**
|
|
9
|
+
* How fast it is typed, in characters per second.
|
|
10
|
+
* @default 24
|
|
11
|
+
*/
|
|
12
|
+
speed?: number;
|
|
13
|
+
/**
|
|
14
|
+
* How long the finished text is held before it repeats, in milliseconds.
|
|
15
|
+
* @default 1400
|
|
16
|
+
*/
|
|
17
|
+
hold?: number;
|
|
18
|
+
/**
|
|
19
|
+
* Deletes the text again before repeating, rather than clearing it in one
|
|
20
|
+
* frame. Only means anything when `repeat` is more than once.
|
|
21
|
+
* @default false
|
|
22
|
+
*/
|
|
23
|
+
erase?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* How fast it is deleted, in characters per second. Deleting is usually about
|
|
26
|
+
* twice as fast as typing, which is what a person actually does.
|
|
27
|
+
* @default twice `speed`
|
|
28
|
+
*/
|
|
29
|
+
eraseSpeed?: number;
|
|
30
|
+
/**
|
|
31
|
+
* The block after the text.
|
|
32
|
+
* @default true
|
|
33
|
+
*/
|
|
34
|
+
caret?: boolean;
|
|
35
|
+
/** What the caret is drawn as. @default '|' */
|
|
36
|
+
caretChar?: React.ReactNode;
|
|
37
|
+
/** The text to type. Only text is typed — see below. */
|
|
38
|
+
children?: React.ReactNode;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Text appearing one character at a time.
|
|
42
|
+
*
|
|
43
|
+
* The whole string is in the document from the first frame — in a clipped box
|
|
44
|
+
* for a screen reader, which reads it once and is not made to sit through the
|
|
45
|
+
* performance — and what animates is a visible copy that is `aria-hidden`. So
|
|
46
|
+
* the effect costs a reader who cannot see it nothing, and costs a reader who
|
|
47
|
+
* can nothing either: the box is not laid out from the characters that have
|
|
48
|
+
* arrived, so the text around it does not reflow on every frame.
|
|
49
|
+
*
|
|
50
|
+
* `repeat`, `hold` and `erase` are what make it a loop: type, hold, delete,
|
|
51
|
+
* type again. Without `erase` a repeat clears in one frame, which is right for
|
|
52
|
+
* a line that is being replaced rather than rewritten.
|
|
53
|
+
*
|
|
54
|
+
* Only text is typed. Pass a string, or strings; an element among the children
|
|
55
|
+
* contributes its text and nothing about its markup, because there is no honest
|
|
56
|
+
* way to reveal half of a link.
|
|
57
|
+
*/
|
|
58
|
+
export declare const AnimateTyping: React.ForwardRefExoticComponent<AnimateTypingProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as t}from"react/jsx-runtime";import*as r from"react";import{isInfinite as n,useAnimationRun as a,usePrefersReducedMotion as i}from"../../internal/animate";import{cx as s,srOnlyClasses as o}from"../../internal/styles";function u(e){return"string"==typeof e||"number"==typeof e?String(e):Array.isArray(e)?e.map(u).join(""):""}export const AnimateTyping=r.forwardRef(function({text:c,speed:m=24,hold:f=1400,erase:l=!1,eraseSpeed:d,caret:p=!0,caretChar:h="|",duration:g,delay:y=0,repeat:x=1,paused:T,trigger:j="mount",play:v,once:N=!0,threshold:S=.2,className:w,style:M,children:b,...A},I){const E=a({trigger:j,play:v,once:N,threshold:S,paused:T,infinite:n(x)}),R=i(),C=c??u(b),k=r.useMemo(()=>function(e,t){if("undefined"!=typeof Intl&&"Segmenter"in Intl)return[...new Intl.Segmenter(t,{granularity:"grapheme"}).segment(e)].map(e=>e.segment);return[...e]}(C),[C]),q=k.length,[z,B]=r.useState(0),D=r.useRef(0),F=g&&q>0?g/q:1e3/Math.max(m,1),G=1e3/Math.max(d??2*m,1);return r.useEffect(()=>{D.current=0},[q]),r.useEffect(()=>{if(R||0===q)return void B(q);if(!E.started)return D.current=0,void B(0);if(T)return;let e,t=!1,r=D.current,n=1,a=!1;const i="infinite"===x?1/0:Math.max(1,x);if(r>=q&&1===i)return;const s=()=>{if(!t){if(a)return r-=1,D.current=r,B(r),r<=0&&(a=!1,n+=1),void(e=setTimeout(s,a?G:F));if(r+=1,D.current=r,B(r),r<q)e=setTimeout(s,F);else if(!(n>=i)){if(l)return a=!0,void(e=setTimeout(s,f));n+=1,e=setTimeout(()=>{t||(r=0,D.current=0,B(0),e=setTimeout(s,F))},f)}}};return B(r),e=setTimeout(s,0===r?y:F),()=>{t=!0,clearTimeout(e)}},[E.started,T,R,q,F,G,y,f,l,x]),t("div",{ref:e=>{E.ref(e),"function"==typeof I?I(e):I&&(I.current=e)},className:w,style:M,"data-neba-animation":"typing","data-state":E.state,...E.handlers,...A,children:[e("span",{className:o,children:C}),t("span",{"aria-hidden":"true",className:"whitespace-pre-wrap",children:[k.slice(0,z).join(""),p?e("span",{className:s("neba-typing-caret"),children:h}):null]})]})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{AnimateTyping}from"./AnimateTyping";
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
3
|
+
import type { NebaAnimateMode, NebaAnimateProps } from '../../types';
|
|
4
|
+
export interface AnimateZoomProps extends NebaAnimateProps, React.ComponentPropsWithoutRef<'div'> {
|
|
5
|
+
/**
|
|
6
|
+
* Whether the content comes forward or falls away.
|
|
7
|
+
* @default 'in'
|
|
8
|
+
*/
|
|
9
|
+
mode?: NebaAnimateMode;
|
|
10
|
+
/**
|
|
11
|
+
* The scale it starts from, as a multiple of its final size. Above `1` it
|
|
12
|
+
* arrives oversized and settles back, which reads as coming *towards* the
|
|
13
|
+
* reader rather than up out of the page.
|
|
14
|
+
* @default 0.4
|
|
15
|
+
*/
|
|
16
|
+
from?: number;
|
|
17
|
+
/**
|
|
18
|
+
* Fades in as it zooms.
|
|
19
|
+
* @default true
|
|
20
|
+
*/
|
|
21
|
+
fade?: boolean;
|
|
22
|
+
/** Renders something other than a `<div>`. Base UI's own escape hatch. */
|
|
23
|
+
render?: useRender.RenderProp;
|
|
24
|
+
children?: React.ReactNode;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Content arriving from the middle of where it will end up.
|
|
28
|
+
*
|
|
29
|
+
* The same arithmetic as Grow at more than twice the distance, and always about
|
|
30
|
+
* the centre — which is the whole difference. A Grow unfolds from somewhere; a
|
|
31
|
+
* Zoom comes at you. Use it for the one thing on a screen that is meant to
|
|
32
|
+
* interrupt: a confirmation, a result, a number that just landed.
|
|
33
|
+
*
|
|
34
|
+
* There is no `origin`, on purpose. A zoom anchored to a corner is a grow, and
|
|
35
|
+
* the library does not offer two spellings of one idea.
|
|
36
|
+
*/
|
|
37
|
+
export declare const AnimateZoom: React.ForwardRefExoticComponent<AnimateZoomProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import*as e from"react";import{useRender as r}from"@base-ui/react/use-render";import{isInfinite as t,useAnimateElement as a}from"../../internal/animate";import{cx as n}from"../../internal/styles";export const AnimateZoom=e.forwardRef(function({duration:e=340,delay:o=0,easing:s,repeat:i=1,alternate:l,paused:m,trigger:d="mount",play:c,once:p=!0,threshold:f=.2,mode:u="in",from:y=.4,fade:g=!0,render:h,className:N,style:b,children:w,...x},z){const A=a({effect:"zoom",duration:e,delay:o,easing:s,repeat:i,alternate:l,mode:u,scale:y,opacity:g?0:1,trigger:d,play:c,once:p,threshold:f,paused:m,infinite:t(i)});return r({render:h,ref:[z,A.ref],props:{...x,className:n(A.className,N),style:{transformOrigin:"center",...A.style,...b},...A.props,children:w}})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{AnimateZoom}from"./AnimateZoom";
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
3
|
+
import type { NebaSize } from '../../types';
|
|
4
|
+
/**
|
|
5
|
+
* How the media inside is fitted to the box, spelled the way CSS spells it.
|
|
6
|
+
*
|
|
7
|
+
* These are `object-fit`'s own values rather than a nicer set of words, for the
|
|
8
|
+
* same reason `NebaPosition` keeps `static`/`sticky`/`fixed`: inventing
|
|
9
|
+
* `fill-the-box` would only make a reader look up which CSS it maps to.
|
|
10
|
+
*/
|
|
11
|
+
export type NebaAspectFit = 'cover' | 'contain' | 'fill' | 'none';
|
|
12
|
+
export interface AspectRatioProps extends React.ComponentPropsWithoutRef<'div'> {
|
|
13
|
+
/**
|
|
14
|
+
* The proportion the box holds, written the way CSS writes it — a number
|
|
15
|
+
* (`1.5`) or a ratio (`'16 / 9'`). Both reach `aspect-ratio` untouched.
|
|
16
|
+
* @default 1
|
|
17
|
+
*/
|
|
18
|
+
ratio?: number | string;
|
|
19
|
+
/**
|
|
20
|
+
* How a single piece of media inside is fitted. Applies to an `img`, a
|
|
21
|
+
* `video`, a `canvas`, an `svg` or an `iframe` that is a direct child; those
|
|
22
|
+
* are stretched to the full box and then fitted. Anything else is laid out
|
|
23
|
+
* normally and this prop does not reach it.
|
|
24
|
+
* @default 'cover'
|
|
25
|
+
*/
|
|
26
|
+
fit?: NebaAspectFit;
|
|
27
|
+
/**
|
|
28
|
+
* Rounds the corners to the `size` step of the house radius ladder.
|
|
29
|
+
*
|
|
30
|
+
* Off by default. A layout component draws nothing, and a photograph with its
|
|
31
|
+
* corners cut is a decision about the photograph — but it is such a common one
|
|
32
|
+
* that making the caller reach for a `className` would be perverse.
|
|
33
|
+
* @default false
|
|
34
|
+
*/
|
|
35
|
+
rounded?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Which step of the radius ladder `rounded` uses. As on Box, `size` here is
|
|
38
|
+
* the size of the *sheet* — there is no height and no type scale on a box
|
|
39
|
+
* whose whole job is a proportion.
|
|
40
|
+
* @default 'md'
|
|
41
|
+
*/
|
|
42
|
+
size?: NebaSize;
|
|
43
|
+
/**
|
|
44
|
+
* Renders something other than a `<div>`: `render={<figure />}`,
|
|
45
|
+
* `render={<a href="…" />}`. Base UI's own escape hatch.
|
|
46
|
+
*/
|
|
47
|
+
render?: useRender.RenderProp;
|
|
48
|
+
children?: React.ReactNode;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* A box that keeps a proportion whatever width it is given.
|
|
52
|
+
*
|
|
53
|
+
* It draws nothing — no surface, no border, no shadow — which is what puts it in
|
|
54
|
+
* `layout` beside Container and Grid rather than in `surfaces`. What it does is
|
|
55
|
+
* reserve the space: a card whose image arrives late does not reflow the page
|
|
56
|
+
* around it, and a row of thumbnails is a row of one shape.
|
|
57
|
+
*
|
|
58
|
+
* The proportion is CSS's own `aspect-ratio`, so a caller who already knows
|
|
59
|
+
* `16 / 9` has nothing to translate. `fit` is the one convenience on top: the
|
|
60
|
+
* media inside is stretched to the box and then fitted, which is the pair of
|
|
61
|
+
* declarations every use of this component would otherwise start with.
|
|
62
|
+
*/
|
|
63
|
+
export declare const AspectRatio: React.ForwardRefExoticComponent<AspectRatioProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import*as e from"react";import{useRender as i}from"@base-ui/react/use-render";import{radiusClasses as o}from"../../internal/styles";const t=["[&>img]:size-full","[&>video]:size-full","[&>canvas]:size-full","[&>svg]:size-full","[&>iframe]:size-full","[&>picture]:size-full","[&>picture>img]:size-full"].join(" "),c={cover:"[&>img]:object-cover [&>video]:object-cover [&>picture>img]:object-cover",contain:"[&>img]:object-contain [&>video]:object-contain [&>picture>img]:object-contain",fill:"[&>img]:object-fill [&>video]:object-fill [&>picture>img]:object-fill",none:"[&>img]:object-none [&>video]:object-none [&>picture>img]:object-none"};export const AspectRatio=e.forwardRef(function({ratio:e=1,fit:r="cover",rounded:l=!1,size:n="md",render:s,className:a,style:f,children:m,...u},d){const b=["relative block w-full overflow-hidden",t,c[r],l?o[n]:"",a??""].filter(Boolean).join(" ");return i({render:s,ref:d,props:{className:b,style:{aspectRatio:e,...f},children:m,...u}})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{AspectRatio}from"./AspectRatio";
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { NebaColor, NebaElevation, NebaSize, NebaTransition, NebaVariant } from '../../types';
|
|
3
|
+
/** What Base UI reports about the picture as it loads. */
|
|
4
|
+
export type AvatarLoadingStatus = 'idle' | 'loading' | 'loaded' | 'error';
|
|
5
|
+
/**
|
|
6
|
+
* The crop, not the sheet.
|
|
7
|
+
*
|
|
8
|
+
* `circle` is the default, and it is the one place besides Badge where the
|
|
9
|
+
* library draws something without a flat run along its edge. The reasoning is
|
|
10
|
+
* Badge's: the cut acrylic edge is what says "this is a surface", and an avatar
|
|
11
|
+
* is not a surface — it is a portrait laid on one. A round crop is what a
|
|
12
|
+
* portrait has been for as long as there have been portraits.
|
|
13
|
+
*
|
|
14
|
+
* `square` cuts the corners off instead, which is what a logo or a repository
|
|
15
|
+
* icon wants: those are drawn to the edges of a rectangle and a round crop eats
|
|
16
|
+
* them.
|
|
17
|
+
*/
|
|
18
|
+
export type AvatarShape = 'circle' | 'square';
|
|
19
|
+
export interface AvatarProps extends Omit<React.ComponentPropsWithoutRef<'span'>, 'color'> {
|
|
20
|
+
/**
|
|
21
|
+
* The picture. Until it loads — and forever, if it fails — the fallback is
|
|
22
|
+
* what is drawn, so an avatar is never an empty box.
|
|
23
|
+
*/
|
|
24
|
+
src?: string;
|
|
25
|
+
/** Candidate images at other resolutions, as on any `<img>`. */
|
|
26
|
+
srcSet?: string;
|
|
27
|
+
/**
|
|
28
|
+
* What the picture says, for a reader who cannot see it. Defaults to `name`,
|
|
29
|
+
* and to nothing at all when there is no name — an avatar next to the person's
|
|
30
|
+
* own name in the row is decoration, and reading it out says the name twice.
|
|
31
|
+
*/
|
|
32
|
+
alt?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Who or what this is. One prop doing three jobs: it names the picture, the
|
|
35
|
+
* initials are derived from it, and it is the sentence a screen reader hears
|
|
36
|
+
* instead of those initials.
|
|
37
|
+
*
|
|
38
|
+
* The initials are the first character of the first word plus the first
|
|
39
|
+
* character of the last — "Jane Doe" is `JD`, "홍길동" is `홍`. That rule is
|
|
40
|
+
* wrong for some names, which is what `initials` is for.
|
|
41
|
+
*/
|
|
42
|
+
name?: string;
|
|
43
|
+
/** The initials, written out, for when the rule derived the wrong ones. */
|
|
44
|
+
initials?: string;
|
|
45
|
+
/**
|
|
46
|
+
* The crop.
|
|
47
|
+
* @default 'circle'
|
|
48
|
+
*/
|
|
49
|
+
shape?: AvatarShape;
|
|
50
|
+
/**
|
|
51
|
+
* Weight of the surface behind the fallback. Invisible once a picture has
|
|
52
|
+
* loaded, apart from the edge it keeps.
|
|
53
|
+
* @default 'text'
|
|
54
|
+
*/
|
|
55
|
+
variant?: NebaVariant;
|
|
56
|
+
/**
|
|
57
|
+
* The box the picture is drawn in — the control heights, so an avatar and the
|
|
58
|
+
* button beside it in a toolbar are the same height.
|
|
59
|
+
* @default 'md'
|
|
60
|
+
*/
|
|
61
|
+
size?: NebaSize;
|
|
62
|
+
/** @default 'primary' */
|
|
63
|
+
color?: NebaColor;
|
|
64
|
+
/**
|
|
65
|
+
* Drop shadow depth. `0` (the default) is flat.
|
|
66
|
+
* @default 0
|
|
67
|
+
*/
|
|
68
|
+
elevation?: NebaElevation;
|
|
69
|
+
/**
|
|
70
|
+
* An entrance animation, run once on mount: `transition="fade"`, or an object
|
|
71
|
+
* for the details. For a trigger, a replay or anything under your own
|
|
72
|
+
* control, wrap it in an `Animate*` component instead.
|
|
73
|
+
*/
|
|
74
|
+
transition?: NebaTransition;
|
|
75
|
+
/**
|
|
76
|
+
* How long to wait before drawing the fallback, in milliseconds. Set it to
|
|
77
|
+
* roughly the time a cached image takes and the initials stop flashing up in
|
|
78
|
+
* front of a picture that was about to arrive anyway.
|
|
79
|
+
*/
|
|
80
|
+
delay?: number;
|
|
81
|
+
/** Anything else the `<img>` needs — `loading`, `crossOrigin`, `referrerPolicy`. */
|
|
82
|
+
imageProps?: Omit<React.ComponentPropsWithoutRef<'img'>, 'src' | 'srcSet' | 'alt'>;
|
|
83
|
+
/** Called as the picture moves between `idle`, `loading`, `loaded` and `error`. */
|
|
84
|
+
onLoadingStatusChange?: (status: AvatarLoadingStatus) => void;
|
|
85
|
+
/**
|
|
86
|
+
* The fallback, drawn instead of the initials. An icon, a logo, a single
|
|
87
|
+
* emoji — whatever stands in for this particular thing when there is no
|
|
88
|
+
* picture of it.
|
|
89
|
+
*/
|
|
90
|
+
children?: React.ReactNode;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* A picture of a person or a thing, at a known size, that is never an empty box.
|
|
94
|
+
*
|
|
95
|
+
* Three things can be drawn in it and exactly one of them is at a time: the
|
|
96
|
+
* picture, if `src` is given and loads; otherwise whatever stands in for it —
|
|
97
|
+
* `children`, or `initials`, or the initials derived from `name`; and failing
|
|
98
|
+
* all of those, a silhouette. Which one is showing is Base UI's `Avatar` to
|
|
99
|
+
* decide, because "has the image loaded" is a question with four answers and a
|
|
100
|
+
* race in the middle of it.
|
|
101
|
+
*
|
|
102
|
+
* It carries no status dot of its own. An avatar with a green mark on it is a
|
|
103
|
+
* [Badge](./badge) with an avatar in it, and inventing a second spelling for
|
|
104
|
+
* that would give the library two of them.
|
|
105
|
+
*/
|
|
106
|
+
export declare const Avatar: React.ForwardRefExoticComponent<AvatarProps & React.RefAttributes<HTMLSpanElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as t}from"react/jsx-runtime";import*as r from"react";import{Avatar as n}from"@base-ui/react/avatar";import{transitionProps as a}from"../../internal/animate";import{controlHeightClasses as o,controlSlots as l,controlSquareClasses as s,hasContent as i,srOnlyClasses as d,surfaceClasses as c,transitionClasses as m}from"../../internal/styles";const f={xs:"text-[0.5625rem]",sm:"text-[0.6875rem]",md:"text-[0.8125rem]",lg:"text-[1rem]",xl:"text-[1.1875rem]"},u={xs:"rounded-[0.375rem]",sm:"rounded-[0.4375rem]",md:"rounded-[0.5625rem]",lg:"rounded-[0.6875rem]",xl:"rounded-[0.875rem]"},x={solid:[c,"text-(--n-on-solid) bg-(--n-fill)","[box-shadow:var(--n-elev)]"].join(" "),outline:[c,"border text-(--n-accent) bg-(--n-panel)","[border-color:var(--n-line)]","[box-shadow:var(--n-elev)]"].join(" "),text:"text-(--n-accent) bg-(--n-soft-press) [box-shadow:var(--n-elev)]"},h="after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit]",v={solid:`${h} after:[box-shadow:var(--neba-plate-solid)]`,outline:`${h} after:[box-shadow:var(--neba-plate-glass)]`,text:""},p=["relative inline-flex shrink-0 select-none items-center justify-center overflow-hidden","align-middle font-semibold tracking-wide whitespace-nowrap leading-none","[&_svg]:pointer-events-none [&_svg]:size-[55%]",m].join(" ");function g(){return t("svg",{viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":"true",children:[e("path",{d:"M12 12a4.5 4.5 0 1 0 0-9 4.5 4.5 0 0 0 0 9Z"}),e("path",{d:"M12 14.25c-4.28 0-7.75 2.42-7.75 5.4 0 .75.6 1.35 1.35 1.35h12.8c.75 0 1.35-.6 1.35-1.35 0-2.98-3.47-5.4-7.75-5.4Z"})]})}export const Avatar=r.forwardRef(function({src:r,srcSet:c,alt:m,name:h,initials:b,shape:w="circle",variant:y="text",size:j="md",color:N="primary",elevation:z=0,delay:C,imageProps:A,onLoadingStatusChange:B,transition:S,className:k,style:L,children:F,...M},R){const Z=h?function(e){const t=e.normalize("NFC").trim().split(/\s+/).filter(Boolean);return 0===t.length?"":((Array.from(t[0])[0]??"")+(t.length>1?Array.from(t[t.length-1])[0]??"":"")).toLocaleUpperCase()}(h):"",$=a(S),_=m??h,I=i(F)?F:(b??Z)||e(g,{}),P=i(F)||Boolean(b??Z),U=[p,o[j],s[j],f[j],"circle"===w?"rounded-full":u[j],x[y],v[y],$.className,k??""].filter(Boolean).join(" ");return t(n.Root,{ref:R,className:U,style:{...l(N,z,y),...$.style,...L},...M,children:[r?e(n.Image,{src:r,srcSet:c,alt:_??"",className:"size-full object-cover",onLoadingStatusChange:B,...A}):null,t(n.Fallback,{delay:r?C:void 0,className:"flex size-full items-center justify-center",children:[_&&P?e("span",{className:d,children:_}):null,e("span",{"aria-hidden":!(!_||!P)||void 0,className:"contents",children:I})]})]})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{Avatar}from"./Avatar";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import type { NebaElevation, NebaStyleProps } from '../../types';
|
|
2
|
+
import type { NebaElevation, NebaStyleProps, NebaTransition } from '../../types';
|
|
3
3
|
/**
|
|
4
4
|
* The props are a `<figure>`'s rather than a `<blockquote>`'s, which is a
|
|
5
5
|
* consequence of where the drawing happens: everything a caller passes lands on
|
|
@@ -14,6 +14,12 @@ export interface BlockquoteProps extends NebaStyleProps, Omit<React.ComponentPro
|
|
|
14
14
|
* @default 0
|
|
15
15
|
*/
|
|
16
16
|
elevation?: NebaElevation;
|
|
17
|
+
/**
|
|
18
|
+
* An entrance animation, run once on mount: `transition="fade"`, or an object
|
|
19
|
+
* for the details. For a trigger, a replay or anything under your own
|
|
20
|
+
* control, wrap it in an `Animate*` component instead.
|
|
21
|
+
*/
|
|
22
|
+
transition?: NebaTransition;
|
|
17
23
|
/**
|
|
18
24
|
* Who said it. Its presence is what turns the quote into a `<figure>` with a
|
|
19
25
|
* `<figcaption>`, which is the markup the HTML spec asks for: an attribution
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as e,jsxs as r}from"react/jsx-runtime";import*as t from"react";import{boxPaddingClasses as n}from"../box/Box";import{hasContent as l,metaTextClasses as
|
|
1
|
+
import{jsx as e,jsxs as r}from"react/jsx-runtime";import*as t from"react";import{boxPaddingClasses as n}from"../box/Box";import{transitionProps as a}from"../../internal/animate";import{hasContent as l,metaTextClasses as o,radiusClasses as i,surfaceClasses as s,surfaceSlots as c,transitionClasses as m}from"../../internal/styles";const d={xs:"text-[0.75rem]/[1.25rem]",sm:"text-[0.8125rem]/[1.375rem]",md:"text-[0.9375rem]/[1.625rem]",lg:"text-[1.0625rem]/[1.875rem]",xl:"text-[1.25rem]/[2.125rem]"},x="border-s-2 [border-inline-start-color:var(--n-accent)]",f={solid:[s,"bg-(--n-panel-hover)","[box-shadow:var(--n-elev),var(--neba-plate-solid)]"].join(" "),outline:[s,"border border-s-2 bg-(--n-panel)","[border-color:var(--n-line)]","[box-shadow:var(--n-elev),var(--neba-plate-glass)]"].join(" "),text:"bg-transparent"};function u(){return e("svg",{viewBox:"0 0 16 16",fill:"none","aria-hidden":"true",children:e("path",{d:"M6.4 3.6c-2.3.9-3.7 2.8-3.7 5.1 0 2 1.2 3.3 2.8 3.3 1.4 0 2.5-1 2.5-2.4 0-1.3-.9-2.2-2.1-2.2-.2 0-.4 0-.6.1.3-1 1.1-1.8 2.2-2.3l-1.1-1.6ZM13.3 3.6c-2.3.9-3.7 2.8-3.7 5.1 0 2 1.2 3.3 2.8 3.3 1.4 0 2.5-1 2.5-2.4 0-1.3-.9-2.2-2.1-2.2-.2 0-.4 0-.6.1.3-1 1.1-1.8 2.2-2.3l-1.1-1.6Z",fill:"currentColor"})})}export const Blockquote=t.forwardRef(function({variant:t="text",size:s="md",color:b="primary",density:p="default",elevation:h=0,author:v,source:g,cite:N,icon:j,transition:y,className:w,style:B,children:k,...z},q){const M=a(y),Z=l(v)||l(g),C=void 0===j?e(u,{}):j,R=["flex flex-col text-(--neba-fg)",x,"text"===t?"":`${i[s]} rounded-s-none`,f[t],n[p][s],m,M.className,w??""].filter(Boolean).join(" "),$=r("blockquote",{cite:N,className:d[s],children:[l(C)?e("span",{"aria-hidden":"true",className:"mb-1 block size-[2em] text-(--n-soft-press) [&>svg]:size-full",children:C}):null,k]}),A={...c(b,h),...M.style,...B};return Z?r("figure",{ref:q,className:R,style:A,...z,children:[$,r("figcaption",{className:["mt-2 flex flex-wrap items-baseline gap-x-1.5 text-(--neba-muted-fg)",o[s]].join(" "),children:[l(v)?r("span",{className:"font-medium text-(--neba-fg)",children:[e("span",{"aria-hidden":"true",children:"— "}),v]}):null,l(g)?e("cite",{className:"not-italic",children:g}):null]})]}):e("div",{ref:q,className:R,style:A,...z,children:$})});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { useRender } from '@base-ui/react/use-render';
|
|
3
|
-
import type { NebaDensity, NebaElevation, NebaSize, NebaStyleProps } from '../../types';
|
|
3
|
+
import type { NebaDensity, NebaElevation, NebaSize, NebaStyleProps, NebaTransition } from '../../types';
|
|
4
4
|
export interface BoxProps extends NebaStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color'> {
|
|
5
5
|
/**
|
|
6
6
|
* Drop shadow depth. `0` (the default) is flat — the acrylic edge is what
|
|
@@ -15,6 +15,12 @@ export interface BoxProps extends NebaStyleProps, Omit<React.ComponentPropsWitho
|
|
|
15
15
|
* @default true
|
|
16
16
|
*/
|
|
17
17
|
padded?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* An entrance animation, run once on mount: `transition="fade"`, or an object
|
|
20
|
+
* for the details. For a trigger, a replay or anything under your own
|
|
21
|
+
* control, wrap the Box in an `Animate*` component instead.
|
|
22
|
+
*/
|
|
23
|
+
transition?: NebaTransition;
|
|
18
24
|
/**
|
|
19
25
|
* Renders something other than a `<div>`: `render={<section />}`,
|
|
20
26
|
* `render={<li />}`, or a function for full control. Base UI's own escape
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as e from"react";import{useRender as
|
|
1
|
+
import*as e from"react";import{useRender as a}from"@base-ui/react/use-render";import{transitionProps as s}from"../../internal/animate";import{radiusClasses as o,surfaceClasses as t,surfaceSlots as n,transitionClasses as p}from"../../internal/styles";const l=o;export const boxPaddingClasses={default:{xs:"p-2",sm:"p-3",md:"p-4",lg:"p-5",xl:"p-6"},compact:{xs:"p-1.5",sm:"p-2",md:"p-2.5",lg:"p-3",xl:"p-4"}};export const boxPaddingXClasses={default:{xs:"px-2",sm:"px-3",md:"px-4",lg:"px-5",xl:"px-6"},compact:{xs:"px-1.5",sm:"px-2",md:"px-2.5",lg:"px-3",xl:"px-4"}};export const boxPaddingYClasses={default:{xs:"py-2",sm:"py-3",md:"py-4",lg:"py-5",xl:"py-6"},compact:{xs:"py-1.5",sm:"py-2",md:"py-2.5",lg:"py-3",xl:"py-4"}};const r=["block",p].join(" "),x={solid:[t,"text-(--neba-fg) bg-(--n-panel-hover)","[box-shadow:var(--n-elev),var(--neba-plate-solid)]"].join(" "),outline:[t,"border text-(--neba-fg) bg-(--n-panel)","[border-color:var(--n-line)]","[box-shadow:var(--n-elev),var(--neba-plate-glass)]"].join(" "),text:"text-(--neba-fg) bg-transparent"};export const Box=e.forwardRef(function({variant:e="outline",size:o="md",color:t="primary",density:p="default",elevation:d=0,padded:i=!0,transition:m,render:c,className:b,style:g,children:f,...y},u){const v=s(m),h=[r,l[o],i?boxPaddingClasses[p][o]:"",x[e],v.className,b??""].filter(Boolean).join(" ");return a({render:c,ref:u,props:{className:h,style:{...n(t,d),...v.style,...g},children:f,...y}})});
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { NebaColor, NebaDensity, NebaSize } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* What is drawn between two steps of the trail.
|
|
5
|
+
*
|
|
6
|
+
* Four named marks rather than a free-for-all, because a separator is read
|
|
7
|
+
* hundreds of times a day and the difference between them is meaning, not
|
|
8
|
+
* decoration: a `chevron` and an `arrow` say "and then", a `slash` says "path",
|
|
9
|
+
* a `dot` says "these are peers of one thing". Anything else can still be passed
|
|
10
|
+
* as a node.
|
|
11
|
+
*/
|
|
12
|
+
export type BreadcrumbSeparator = 'chevron' | 'arrow' | 'slash' | 'dot';
|
|
13
|
+
export interface BreadcrumbProps extends Omit<React.ComponentPropsWithoutRef<'nav'>, 'color'> {
|
|
14
|
+
/** @default 'md' */
|
|
15
|
+
size?: NebaSize;
|
|
16
|
+
/** The colour family a link picks up when it is hovered. @default 'primary' */
|
|
17
|
+
color?: NebaColor;
|
|
18
|
+
/** How tightly the steps pack. Spacing only. @default 'default' */
|
|
19
|
+
density?: NebaDensity;
|
|
20
|
+
/**
|
|
21
|
+
* The mark between two steps. One of the four names, or any node.
|
|
22
|
+
* @default 'chevron'
|
|
23
|
+
*/
|
|
24
|
+
separator?: BreadcrumbSeparator | React.ReactNode;
|
|
25
|
+
/**
|
|
26
|
+
* How many steps to show before the middle is folded away behind a `…`.
|
|
27
|
+
* Left out, the whole trail is shown however long it gets.
|
|
28
|
+
*/
|
|
29
|
+
maxItems?: number;
|
|
30
|
+
/** How many steps stay at the front of a folded trail. @default 1 */
|
|
31
|
+
itemsBeforeCollapse?: number;
|
|
32
|
+
/** How many stay at the end. @default 1 */
|
|
33
|
+
itemsAfterCollapse?: number;
|
|
34
|
+
/**
|
|
35
|
+
* Whether pressing the `…` unfolds the trail in place. Turn it off to leave
|
|
36
|
+
* the fold as a plain mark.
|
|
37
|
+
* @default true
|
|
38
|
+
*/
|
|
39
|
+
expandable?: boolean;
|
|
40
|
+
/** The name the trail is announced by. @default 'Breadcrumb' */
|
|
41
|
+
label?: string;
|
|
42
|
+
/** What the `…` is announced as. @default 'Show hidden steps' */
|
|
43
|
+
expandLabel?: string;
|
|
44
|
+
/** The BreadcrumbItems. */
|
|
45
|
+
children?: React.ReactNode;
|
|
46
|
+
}
|
|
47
|
+
export interface BreadcrumbItemProps extends Omit<React.ComponentPropsWithoutRef<'li'>, 'color' | 'onClick'> {
|
|
48
|
+
/** Renders the step as a link. */
|
|
49
|
+
href?: string;
|
|
50
|
+
/** Fires when the step is pressed. Renders it as a button when there is no `href`. */
|
|
51
|
+
onClick?: React.MouseEventHandler<HTMLElement>;
|
|
52
|
+
/** Content before the label — a home glyph, a repository avatar. */
|
|
53
|
+
startIcon?: React.ReactNode;
|
|
54
|
+
/** Content after the label. */
|
|
55
|
+
endIcon?: React.ReactNode;
|
|
56
|
+
/**
|
|
57
|
+
* Marks this step as the page you are on, which stops it being a link.
|
|
58
|
+
*
|
|
59
|
+
* The last step is the current one on its own, so this is only needed for a
|
|
60
|
+
* trail that ends somewhere the reader is not — and setting it anywhere takes
|
|
61
|
+
* the mark off the last step, because only one step in a trail can be it.
|
|
62
|
+
*/
|
|
63
|
+
current?: boolean;
|
|
64
|
+
/** Unavailable. Stops answering, keeps its place in the trail. */
|
|
65
|
+
disabled?: boolean;
|
|
66
|
+
/** The step's label. */
|
|
67
|
+
children?: React.ReactNode;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The trail of pages above the one being read.
|
|
71
|
+
*
|
|
72
|
+
* Two things make this more than a row of links. The first is that the last step
|
|
73
|
+
* is where the reader already is, so it is not a link at all — it carries
|
|
74
|
+
* `aria-current="page"` and stops being pressable, and the component works that
|
|
75
|
+
* out rather than asking every caller to remember it. The second is the fold: a
|
|
76
|
+
* trail seven levels deep is a trail nobody reads, so the middle collapses to a
|
|
77
|
+
* `…` that puts it back when pressed.
|
|
78
|
+
*
|
|
79
|
+
* The separators are drawn by the trail rather than by the steps. A step does
|
|
80
|
+
* not know whether anything follows it, and a mark that belonged to a step would
|
|
81
|
+
* have to be taken off the last one by hand.
|
|
82
|
+
*/
|
|
83
|
+
export declare const Breadcrumb: React.ForwardRefExoticComponent<BreadcrumbProps & React.RefAttributes<HTMLElement>>;
|
|
84
|
+
/**
|
|
85
|
+
* One step of the trail.
|
|
86
|
+
*
|
|
87
|
+
* It renders three different things and the caller picks by what they pass: an
|
|
88
|
+
* `<a>` with an `href`, a `<button>` with an `onClick`, and a plain `<span>` with
|
|
89
|
+
* neither — which is what the last step is, because the page you are already on
|
|
90
|
+
* is not somewhere to go.
|
|
91
|
+
*/
|
|
92
|
+
export declare const BreadcrumbItem: React.ForwardRefExoticComponent<BreadcrumbItemProps & React.RefAttributes<HTMLLIElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as a,Fragment as n}from"react/jsx-runtime";import*as t from"react";import{ArrowRightIcon as s,ChevronIcon as r,EllipsisIcon as l}from"../../internal/icons";import{controlTextClasses as i,cx as c,gapClasses as o,hasContent as m,iconClasses as d,radiusClasses as f,transitionClasses as u}from"../../internal/styles";const h=t.createContext({size:"md",last:!1}),p={default:{xs:"gap-1",sm:"gap-1.5",md:"gap-2",lg:"gap-2.5",xl:"gap-3"},compact:{xs:"gap-0.5",sm:"gap-1",md:"gap-1",lg:"gap-1.5",xl:"gap-2"}},x={xs:f.xs,sm:f.xs,md:f.xs,lg:f.sm,xl:f.sm};const b=["chevron","arrow","slash","dot"];export const Breadcrumb=t.forwardRef(function({size:n="md",color:o="primary",density:m="default",separator:f="chevron",maxItems:x,itemsBeforeCollapse:g=1,itemsAfterCollapse:v=1,expandable:N=!0,label:y="Breadcrumb",expandLabel:w="Show hidden steps",className:k,style:C,children:B,...z},I){const[_,j]=t.useState(!1),M=t.Children.toArray(B).filter(t.isValidElement),$=M.length,A=M.some(e=>!0===e.props.current),F=!_&&void 0!==x&&$>Math.max(x,1)&&$-g-v>1?[...M.slice(0,Math.max(0,g)),null,...M.slice($-Math.max(0,v))]:M,R="string"==typeof(S=f)&&b.includes(S)?function(a){switch(a){case"chevron":return e("span",{className:"flex -rotate-90 items-center rtl:rotate-90",children:e(r,{})});case"arrow":return e("span",{className:"flex items-center rtl:rotate-180",children:e(s,{})});case"slash":return e("span",{className:"opacity-70",children:"/"});case"dot":return e("span",{className:"opacity-70",children:"·"});default:return null}}(f):f;var S;const E=c("inline-flex items-center rounded-(--neba-radius-xs) px-0.5","text-(--neba-muted-fg)",u,d,N?c("cursor-pointer hover:bg-(--n-soft) hover:text-(--n-accent)","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-1"):"");return e("nav",{ref:I,"aria-label":y,className:c("flex",i[n],d,k),style:{"--n-accent":`var(--neba-${o}-accent)`,"--n-soft":`var(--neba-${o}-soft)`,"--n-ring":`var(--neba-${o}-ring)`,...C},...z,children:e("ol",{role:"list",className:c("flex list-none flex-wrap items-center p-0",p[m][n]),children:F.map((s,r)=>a(t.Fragment,{children:[r>0?e("li",{"aria-hidden":"true",className:"flex shrink-0 items-center text-(--neba-muted-fg) select-none",children:R}):null,s?e(h.Provider,{value:{size:n,last:!A&&r===F.length-1},children:s}):e("li",{className:"flex shrink-0 items-center",children:N?e("button",{type:"button",className:E,"aria-label":w,onClick:()=>j(!0),children:e(l,{})}):e("span",{className:E,"aria-hidden":"true",children:e(l,{})})})]},s?s.key??r:"fold"))})})});export const BreadcrumbItem=t.forwardRef(function({href:s,onClick:r,startIcon:l,endIcon:i,current:d,disabled:f=!1,className:p,children:b,...g},v){const{size:N,last:y}=t.useContext(h),w=d??y,k=Boolean(s||r)&&!w&&!f,C=c("inline-flex min-w-0 items-center px-1",o[N],x[N],u,f?"cursor-not-allowed text-(--neba-disabled-fg)":w?"font-medium text-(--neba-fg)":k?c("cursor-pointer text-(--neba-muted-fg)","hover:bg-(--n-soft) hover:text-(--n-accent)","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-1"):"text-(--neba-muted-fg)"),B=a(n,{children:[m(l)?e("span",{className:"flex h-[1lh] shrink-0 items-center",children:l}):null,e("span",{className:"truncate",children:b}),m(i)?e("span",{className:"flex h-[1lh] shrink-0 items-center",children:i}):null]});return e("li",{ref:v,className:c("flex min-w-0 items-center",p),...g,children:k&&s?e("a",{href:s,className:C,onClick:r,children:B}):k?e("button",{type:"button",className:C,onClick:r,children:B}):e("span",{className:C,"aria-current":w?"page":void 0,"aria-disabled":f||void 0,children:B})})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{Breadcrumb,BreadcrumbItem}from"./Breadcrumb";
|