neba 1.7.0 → 1.8.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 +7 -7
- package/dist/components/app-logo/AppLogo.d.ts +148 -0
- package/dist/components/app-logo/AppLogo.js +1 -0
- package/dist/components/app-logo/index.d.ts +2 -0
- package/dist/components/app-logo/index.js +1 -0
- package/dist/components/avatar/Avatar.js +1 -1
- package/dist/components/bottom-navigation/BottomNavigation.js +1 -1
- package/dist/components/code-block/CodeBlock.d.ts +170 -0
- package/dist/components/code-block/CodeBlock.js +1 -0
- package/dist/components/code-block/index.d.ts +2 -0
- package/dist/components/code-block/index.js +1 -0
- package/dist/components/color-picker/ColorPicker.d.ts +1 -1
- package/dist/components/drawer/Drawer.js +1 -1
- package/dist/components/footer/Footer.d.ts +85 -0
- package/dist/components/footer/Footer.js +1 -0
- package/dist/components/footer/index.d.ts +2 -0
- package/dist/components/footer/index.js +1 -0
- package/dist/components/header/Header.d.ts +114 -0
- package/dist/components/header/Header.js +1 -0
- package/dist/components/header/index.d.ts +2 -0
- package/dist/components/header/index.js +1 -0
- package/dist/components/how-to-steps/HowToSteps.d.ts +167 -0
- package/dist/components/how-to-steps/HowToSteps.js +1 -0
- package/dist/components/how-to-steps/index.d.ts +2 -0
- package/dist/components/how-to-steps/index.js +1 -0
- package/dist/components/page-layout/PageLayout.d.ts +144 -0
- package/dist/components/page-layout/PageLayout.js +1 -0
- package/dist/components/page-layout/index.d.ts +2 -0
- package/dist/components/page-layout/index.js +1 -0
- package/dist/components/sidebar/Sidebar.d.ts +144 -0
- package/dist/components/sidebar/Sidebar.js +1 -0
- package/dist/components/sidebar/SidebarTrigger.d.ts +36 -0
- package/dist/components/sidebar/SidebarTrigger.js +1 -0
- package/dist/components/sidebar/index.d.ts +4 -0
- package/dist/components/sidebar/index.js +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +1 -1
- package/dist/internal/bottom-navigation.d.ts +4 -3
- package/dist/internal/chart.d.ts +3 -2
- package/dist/internal/color.d.ts +2 -2
- package/dist/internal/date.d.ts +3 -4
- package/dist/internal/highlight.d.ts +97 -0
- package/dist/internal/highlight.js +1 -0
- package/dist/internal/i18n.d.ts +85 -0
- package/dist/internal/i18n.js +1 -1
- package/dist/internal/icons.d.ts +20 -0
- package/dist/internal/icons.js +1 -1
- package/dist/internal/initials.d.ts +24 -0
- package/dist/internal/initials.js +1 -0
- package/dist/internal/page-layout.d.ts +143 -0
- package/dist/internal/page-layout.js +1 -0
- package/dist/internal/styles.d.ts +11 -0
- package/dist/internal/styles.js +1 -1
- package/dist/locales/ar.js +1 -1
- package/dist/locales/de.js +1 -1
- package/dist/locales/es.js +1 -1
- package/dist/locales/fr.js +1 -1
- package/dist/locales/hi.js +1 -1
- package/dist/locales/id.js +1 -1
- package/dist/locales/it.js +1 -1
- package/dist/locales/ja.js +1 -1
- package/dist/locales/ko.js +1 -1
- package/dist/locales/nl.js +1 -1
- package/dist/locales/pl.js +1 -1
- package/dist/locales/pt.js +1 -1
- package/dist/locales/ru.js +1 -1
- package/dist/locales/th.js +1 -1
- package/dist/locales/tr.js +1 -1
- package/dist/locales/vi.js +1 -1
- package/dist/locales/zh-hans.js +1 -1
- package/dist/locales/zh-hant.js +1 -1
- package/dist/styles.css +1 -1
- package/dist/tailwind.css +473 -0
- package/package.json +8 -7
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
3
|
+
import type { NebaAlign, NebaColor, NebaDensity, NebaElevation, NebaPosition, NebaSize, NebaVariant } from '../../types.js';
|
|
4
|
+
export interface HeaderProps extends Omit<React.ComponentPropsWithoutRef<'header'>, 'color' | 'title'> {
|
|
5
|
+
/**
|
|
6
|
+
* The leading slot: the logo, the product's name, the thing that is the same
|
|
7
|
+
* on every page. An [AppLogo] is what usually goes here.
|
|
8
|
+
*
|
|
9
|
+
* It is a slot rather than the first of `children` because the three regions
|
|
10
|
+
* of a bar are laid out against each other — the middle can only be centred
|
|
11
|
+
* in the bar if the two ends are measured — and a caller writing three
|
|
12
|
+
* wrappers by hand is a caller whose header drifts from the next one.
|
|
13
|
+
*/
|
|
14
|
+
brand?: React.ReactNode;
|
|
15
|
+
/**
|
|
16
|
+
* The trailing slot: the account menu, the theme switch, the call to action.
|
|
17
|
+
* Laid out end-aligned, so a row of buttons needs no wrapper of its own.
|
|
18
|
+
*/
|
|
19
|
+
actions?: React.ReactNode;
|
|
20
|
+
/**
|
|
21
|
+
* Where the middle slot sits.
|
|
22
|
+
*
|
|
23
|
+
* - `start` — packed against the brand, taking whatever is left. The
|
|
24
|
+
* arrangement of an application's toolbar, and the default.
|
|
25
|
+
* - `center` — centred in the bar itself, not in the space left over. The two
|
|
26
|
+
* ends are given equal shares for this, so the middle stays on the bar's
|
|
27
|
+
* own midline however wide the brand is.
|
|
28
|
+
* - `end` — packed against the actions.
|
|
29
|
+
* @default 'start'
|
|
30
|
+
*/
|
|
31
|
+
align?: NebaAlign;
|
|
32
|
+
/**
|
|
33
|
+
* How the bar sits in the page's scroll, spelled the way CSS spells it.
|
|
34
|
+
* `sticky` — the default — holds it against the top of the window once the
|
|
35
|
+
* page has scrolled to it, while leaving it in the flow so nothing has to be
|
|
36
|
+
* padded out of its way. `fixed` takes it out of the flow entirely, which a
|
|
37
|
+
* [PageLayout] answers by reserving its height. `static` lets it scroll away.
|
|
38
|
+
* @default 'sticky'
|
|
39
|
+
*/
|
|
40
|
+
position?: NebaPosition;
|
|
41
|
+
/**
|
|
42
|
+
* Weight of the sheet, said the way a *container* says it: the bar is never
|
|
43
|
+
* dyed, because what is on it arrives with colours of its own.
|
|
44
|
+
* @default 'outline'
|
|
45
|
+
*/
|
|
46
|
+
variant?: NebaVariant;
|
|
47
|
+
/**
|
|
48
|
+
* The bar's scale — its height floor, its gutter and the air around its
|
|
49
|
+
* slots. As on Box, `size` here is the size of the *sheet*.
|
|
50
|
+
* @default 'md'
|
|
51
|
+
*/
|
|
52
|
+
size?: NebaSize;
|
|
53
|
+
/** @default 'primary' */
|
|
54
|
+
color?: NebaColor;
|
|
55
|
+
/** @default 'default' */
|
|
56
|
+
density?: NebaDensity;
|
|
57
|
+
/**
|
|
58
|
+
* Drop shadow depth. `0` (the default) is flat: a header is attached to the
|
|
59
|
+
* top of the window rather than floating over the middle of it, and `divider`
|
|
60
|
+
* is what separates it from the content.
|
|
61
|
+
* @default 0
|
|
62
|
+
*/
|
|
63
|
+
elevation?: NebaElevation;
|
|
64
|
+
/**
|
|
65
|
+
* Draws a hairline along the bottom edge, against the content the bar is
|
|
66
|
+
* over. On by default, for BottomNavigation's reason: a bar pinned over a
|
|
67
|
+
* scrolling page has content passing underneath it at every moment, and a
|
|
68
|
+
* translucent sheet with nothing marking its edge reads as part of that.
|
|
69
|
+
* @default true
|
|
70
|
+
*/
|
|
71
|
+
divider?: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Holds the row of slots to a measure and centres it, while the sheet itself
|
|
74
|
+
* still spans the window. On the same ladder Container's own `maxWidth` uses,
|
|
75
|
+
* so a header and the [Container] under it line up on the same edge.
|
|
76
|
+
* @default 'none'
|
|
77
|
+
*/
|
|
78
|
+
maxWidth?: NebaSize | 'none';
|
|
79
|
+
/** The gutter down each side of the row. @default true */
|
|
80
|
+
padded?: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* The name the bar is announced by. Worth writing when a page has more than
|
|
83
|
+
* one `<header>` in it — an article's own header and the site's — because
|
|
84
|
+
* "banner" twice tells a reader which is which not at all.
|
|
85
|
+
*/
|
|
86
|
+
label?: string;
|
|
87
|
+
/**
|
|
88
|
+
* Renders something other than a `<header>`. Base UI's own escape hatch, and
|
|
89
|
+
* rarely what you want: the bar at the top of a page is a banner, and the tag
|
|
90
|
+
* is what says so to a search engine and to a screen reader's landmark list.
|
|
91
|
+
*/
|
|
92
|
+
render?: useRender.RenderProp;
|
|
93
|
+
/** The middle slot. */
|
|
94
|
+
children?: React.ReactNode;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* The bar across the top of a page.
|
|
98
|
+
*
|
|
99
|
+
* A real `<header>`, which is the whole reason it is a component rather than a
|
|
100
|
+
* row of divs: at the top level of a document that tag is the `banner`
|
|
101
|
+
* landmark, and it is what a screen reader's landmark list, a reader mode and a
|
|
102
|
+
* search engine's understanding of the page are all built out of.
|
|
103
|
+
*
|
|
104
|
+
* Its three slots are props rather than compound sub-components, for Card's and
|
|
105
|
+
* Dialog's reason: the arrangement is fixed — brand, middle, actions — and what
|
|
106
|
+
* a caller wants to decide is what goes in each. That the middle can be centred
|
|
107
|
+
* on the bar's own midline is only possible because the ends are the
|
|
108
|
+
* component's to measure.
|
|
109
|
+
*
|
|
110
|
+
* Inside a [PageLayout] it also registers itself, so a sidebar that holds its
|
|
111
|
+
* place knows how far down the window to start. Outside one it is simply a bar,
|
|
112
|
+
* and everything above still works.
|
|
113
|
+
*/
|
|
114
|
+
export declare const Header: React.ForwardRefExoticComponent<HeaderProps & React.RefAttributes<HTMLElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as r from"react";import{useRender as n}from"@base-ui/react/use-render";import{boxPaddingXClasses as t}from"../box/Box.js";import{PageLayoutContext as s}from"../../internal/page-layout.js";import{cx as i,hasContent as l,surfaceClasses as m,surfaceSlots as o,transitionClasses as d}from"../../internal/styles.js";const c={xs:"min-h-10",sm:"min-h-12",md:"min-h-14",lg:"min-h-16",xl:"min-h-20"},x={xs:"gap-1.5",sm:"gap-2",md:"gap-3",lg:"gap-4",xl:"gap-5"},f={xs:"gap-3",sm:"gap-4",md:"gap-6",lg:"gap-8",xl:"gap-10"},p={xs:"max-w-[30rem]",sm:"max-w-[40rem]",md:"max-w-[48rem]",lg:"max-w-[64rem]",xl:"max-w-[80rem]"},u={solid:[m,"text-(--neba-fg) bg-(--n-panel-press)","[box-shadow:var(--n-elev),var(--neba-plate-solid)]"].join(" "),outline:[m,"text-(--neba-fg) bg-(--n-panel)","[box-shadow:var(--n-elev),var(--neba-plate-glass)]"].join(" "),text:"text-(--neba-fg) bg-transparent"},g={static:"",sticky:"sticky top-0 z-30",fixed:"fixed inset-x-0 top-0 z-40"},h={start:"shrink-0",center:"flex-1 basis-0",end:"shrink-0"},b={start:"flex min-w-0 flex-1 items-center justify-start",center:"flex min-w-0 shrink items-center justify-center",end:"flex min-w-0 flex-1 items-center justify-end"};export const Header=/*@__PURE__*/r.forwardRef(function({brand:m,actions:v,align:w="start",position:y="sticky",variant:j="outline",size:N="md",color:k="primary",density:z="default",elevation:C=0,divider:B=!0,maxWidth:H="none",padded:R=!0,label:W,render:q,className:A,style:D,children:E,...F},G){const I=r.useContext(s),{register:J}=I,K=r.useCallback(e=>{J("header",e),"function"==typeof G?G(e):G&&(G.current=e)},[J,G]),L=i("w-full min-w-0",u[j],B?"border-b [border-color:var(--n-line)]":"",g[y],d,A);return n({render:q??e("header",{}),ref:K,props:{"aria-label":W,className:L,style:{...o(k,C),...D},children:a("div",{className:i("flex w-full items-center",c[N],f[N],R?t[z][N]:"","none"===H?"":i(p[H],"mx-auto")),children:[l(m)?e("div",{className:i("flex min-w-0 items-center",h[w],x[N]),children:m}):"center"===w?e("div",{"aria-hidden":"true",className:h[w]}):null,l(E)?e("div",{className:i(b[w],x[N]),children:E}):null,l(v)?e("div",{className:i("flex min-w-0 items-center justify-end",h[w],x[N]),children:v}):"center"===w?e("div",{"aria-hidden":"true",className:h[w]}):null]}),...F}})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{Header}from"./Header.js";
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { NebaColor, NebaDensity, NebaElevation, NebaOrientation, NebaSize, NebaTransition, NebaVariant } from '../../types.js';
|
|
3
|
+
/** One step of the guide. */
|
|
4
|
+
export interface HowToStep {
|
|
5
|
+
/** The heading, shown both in the list and over the step's own body. */
|
|
6
|
+
title: React.ReactNode;
|
|
7
|
+
/**
|
|
8
|
+
* A glyph before the title, over the step's own body.
|
|
9
|
+
*
|
|
10
|
+
* Only there, and not in the list: a row there already carries a numbered
|
|
11
|
+
* disc, and a glyph beside it is a second mark making the same claim about
|
|
12
|
+
* the same row. What an icon is good for is telling a reader *what kind* of
|
|
13
|
+
* step this is — a terminal, a file, a warning — which is a thing to say
|
|
14
|
+
* once, where the step is stated at full size.
|
|
15
|
+
*/
|
|
16
|
+
icon?: React.ReactNode;
|
|
17
|
+
/** What the reader has to do. Anything — prose, a [CodeBlock], a screenshot. */
|
|
18
|
+
content?: React.ReactNode;
|
|
19
|
+
/** A picture above the content, for a step that is easier shown than said. */
|
|
20
|
+
image?: string;
|
|
21
|
+
/** What that picture says for a reader who cannot see it. Defaults to `title`. */
|
|
22
|
+
imageAlt?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface HowToStepsProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'title' | 'content'> {
|
|
25
|
+
/**
|
|
26
|
+
* The steps, in the order they are to be done.
|
|
27
|
+
*
|
|
28
|
+
* An array rather than children, and this is the one place the component
|
|
29
|
+
* genuinely could not be built the other way: the list beside the body and
|
|
30
|
+
* the body itself are two renderings of the same data, and the panel is sized
|
|
31
|
+
* against *every* step rather than the one showing. A component that had to
|
|
32
|
+
* find its steps among its children could do neither.
|
|
33
|
+
*/
|
|
34
|
+
steps: HowToStep[];
|
|
35
|
+
/** The guide's own heading, over both columns. */
|
|
36
|
+
title?: React.ReactNode;
|
|
37
|
+
/** Which step is showing. Pass it to drive the guide yourself. */
|
|
38
|
+
step?: number;
|
|
39
|
+
/** Where an uncontrolled guide starts. @default 0 */
|
|
40
|
+
defaultStep?: number;
|
|
41
|
+
/** Fires with the index whenever the step changes, however it changed. */
|
|
42
|
+
onStepChange?: (step: number) => void;
|
|
43
|
+
/** Whether the guide is finished. Pass it to drive that yourself too. */
|
|
44
|
+
completed?: boolean;
|
|
45
|
+
/** Whether an uncontrolled guide starts finished. @default false */
|
|
46
|
+
defaultCompleted?: boolean;
|
|
47
|
+
/** Fires when the guide is finished, and again when it is started over. */
|
|
48
|
+
onCompletedChange?: (completed: boolean) => void;
|
|
49
|
+
/**
|
|
50
|
+
* Which way the list of steps runs.
|
|
51
|
+
*
|
|
52
|
+
* `vertical` is the default: the numbers run down one side with the body
|
|
53
|
+
* beside them, which takes any number of steps and any amount to say about
|
|
54
|
+
* each. Below `sm` it stacks, because a rail and a paragraph side by side on
|
|
55
|
+
* a phone is two columns too narrow for either. `horizontal` runs the numbers
|
|
56
|
+
* across the top, and is only honest while every title is short.
|
|
57
|
+
* @default 'vertical'
|
|
58
|
+
*/
|
|
59
|
+
orientation?: NebaOrientation;
|
|
60
|
+
/**
|
|
61
|
+
* How tall the guide may get before it scrolls. A number is pixels.
|
|
62
|
+
*
|
|
63
|
+
* Both the list and the body scroll inside it rather than the sheet growing.
|
|
64
|
+
* A guide with twenty steps is what this is for, and twenty rows that pushed
|
|
65
|
+
* the buttons off the bottom of the card would be a guide with no way
|
|
66
|
+
* forward.
|
|
67
|
+
*/
|
|
68
|
+
maxHeight?: number | string;
|
|
69
|
+
/**
|
|
70
|
+
* How wide the list is while it is a column. A number is pixels.
|
|
71
|
+
* @default '15rem'
|
|
72
|
+
*/
|
|
73
|
+
railWidth?: number | string;
|
|
74
|
+
/**
|
|
75
|
+
* The row of buttons under the body. Off, the list is the only way to move,
|
|
76
|
+
* which is what a guide inside a page that has navigation of its own wants.
|
|
77
|
+
* @default true
|
|
78
|
+
*/
|
|
79
|
+
navigation?: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Draws a hairline between the list and the body — down the inner edge while
|
|
82
|
+
* they are two columns, along the bottom of the list once they have stacked.
|
|
83
|
+
*
|
|
84
|
+
* On by default. The two are different kinds of thing — one is a map, the
|
|
85
|
+
* other is the place the map points at — and space alone leaves that to be
|
|
86
|
+
* inferred from a gap that a narrow screen is about to take away.
|
|
87
|
+
* @default true
|
|
88
|
+
*/
|
|
89
|
+
divider?: boolean;
|
|
90
|
+
/**
|
|
91
|
+
* How a step arrives when the reader moves to it, from the same vocabulary
|
|
92
|
+
* `transition` uses everywhere: an effect name, or the object form for the
|
|
93
|
+
* duration, the easing and the rest. `'none'` turns it off.
|
|
94
|
+
*
|
|
95
|
+
* It runs on the panel rather than on anything that is pressed, which is what
|
|
96
|
+
* keeps it inside the library's rule against moving a control: the buttons
|
|
97
|
+
* and the list rows hold still, and what animates is the content they
|
|
98
|
+
* changed.
|
|
99
|
+
*
|
|
100
|
+
* A reduced-motion preference switches it off entirely, as it does every
|
|
101
|
+
* other effect in the library.
|
|
102
|
+
* @default 'fade'
|
|
103
|
+
*/
|
|
104
|
+
transition?: NebaTransition | 'none';
|
|
105
|
+
/**
|
|
106
|
+
* Whether there is a finished state at all.
|
|
107
|
+
*
|
|
108
|
+
* On, the last step's button says "Done" and pressing it replaces the body
|
|
109
|
+
* with a panel that says so and offers to start again. Off, the last step is
|
|
110
|
+
* simply the last step.
|
|
111
|
+
* @default true
|
|
112
|
+
*/
|
|
113
|
+
completion?: boolean;
|
|
114
|
+
/** What the finished panel says, in place of the `locale`'s own sentence. */
|
|
115
|
+
completedContent?: React.ReactNode;
|
|
116
|
+
/**
|
|
117
|
+
* Weight of the sheet, said the way a *container* says it: the guide is never
|
|
118
|
+
* dyed, because what is in it arrives with colours of its own.
|
|
119
|
+
* @default 'outline'
|
|
120
|
+
*/
|
|
121
|
+
variant?: NebaVariant;
|
|
122
|
+
/** @default 'md' */
|
|
123
|
+
size?: NebaSize;
|
|
124
|
+
/** The family the numbers, the connector and the buttons wear. @default 'primary' */
|
|
125
|
+
color?: NebaColor;
|
|
126
|
+
/** @default 'default' */
|
|
127
|
+
density?: NebaDensity;
|
|
128
|
+
/** Drop shadow depth. `0` (the default) is flat. @default 0 */
|
|
129
|
+
elevation?: NebaElevation;
|
|
130
|
+
/**
|
|
131
|
+
* Which language the guide's own words are in — the four buttons and the
|
|
132
|
+
* sentence at the end. A BCP 47 tag such as `ko`, `pt-BR` or `zh-Hant`;
|
|
133
|
+
* unsupported tags fall back to English.
|
|
134
|
+
*/
|
|
135
|
+
locale?: string;
|
|
136
|
+
/** The four button labels, written out over the `locale`. */
|
|
137
|
+
previousLabel?: string;
|
|
138
|
+
nextLabel?: string;
|
|
139
|
+
doneLabel?: string;
|
|
140
|
+
restartLabel?: string;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* A guide the reader walks through: numbered steps down one side, one step's
|
|
144
|
+
* instructions at a time beside them, and a way forward under those.
|
|
145
|
+
*
|
|
146
|
+
* It is [Timeline]'s interactive sibling, and the two are deliberately not one
|
|
147
|
+
* component. A Timeline *reports* — this happened, then this did, and here is
|
|
148
|
+
* where things have got to — and nothing in it is pressed. A HowToSteps *asks*:
|
|
149
|
+
* the reader is meant to do the thing on the screen and then say they have,
|
|
150
|
+
* which needs a current step, a way to change it, and an end.
|
|
151
|
+
*
|
|
152
|
+
* Two things about how it is built are load-bearing rather than incidental.
|
|
153
|
+
*
|
|
154
|
+
* **Every step's body is rendered into the same grid cell**, with the ones not
|
|
155
|
+
* showing left in the document, `invisible` and `inert`. The panel is therefore
|
|
156
|
+
* as tall as the tallest step at every moment, so moving between a one-line
|
|
157
|
+
* step and a five-line one does not resize the card the guide sits in — which,
|
|
158
|
+
* on a page the reader has already scrolled, moves everything under it. The
|
|
159
|
+
* finished panel is in that cell too, for the same reason.
|
|
160
|
+
*
|
|
161
|
+
* **The list is a list of buttons and not a tablist.** A stepper looks like
|
|
162
|
+
* tabs and is not one: the panels are ordered, the reader is expected to arrive
|
|
163
|
+
* at them in that order, and `aria-current="step"` is the attribute that says
|
|
164
|
+
* so. A tablist's roving focus would tell a screen reader that these are
|
|
165
|
+
* interchangeable views of one thing.
|
|
166
|
+
*/
|
|
167
|
+
export declare const HowToSteps: React.ForwardRefExoticComponent<HowToStepsProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as t,Fragment as n}from"react/jsx-runtime";import*as l from"react";import{Button as r}from"../button/Button.js";import{boxPaddingClasses as a}from"../box/Box.js";import{CheckIcon as i,ChevronIcon as o,RestartIcon as s,SuccessIcon as c}from"../../internal/icons.js";import{stepsMessages as m,useMessages as d}from"../../internal/i18n.js";import{transitionProps as p}from"../../internal/animate.js";import{cx as f,hasContent as x,iconClasses as u,metaTextClasses as b,radiusClasses as h,sheetBodyClasses as g,sheetSectionGapClasses as v,sheetTitleClasses as N,srOnlyClasses as w,surfaceClasses as k,surfaceSlots as y,toLength as j,transitionClasses as C}from"../../internal/styles.js";const z={xs:{box:"1.25rem",text:"text-[0.625rem]"},sm:{box:"1.5rem",text:"text-[0.6875rem]"},md:{box:"1.75rem",text:"text-[0.75rem]"},lg:{box:"2rem",text:"text-[0.8125rem]"},xl:{box:"2.25rem",text:"text-[0.875rem]"}},S={default:{xs:"gap-0.5",sm:"gap-1",md:"gap-1",lg:"gap-1.5",xl:"gap-2"},compact:{xs:"gap-0",sm:"gap-0",md:"gap-0.5",lg:"gap-0.5",xl:"gap-1"}},L={solid:[k,"text-(--neba-fg) bg-(--n-panel-hover)","[box-shadow:var(--n-elev),var(--neba-plate-solid)]"].join(" "),outline:[k,"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"};function I(e,t){return e.replace(/\{(\w+)\}/g,(e,n)=>t[n]??e)}function R(e){return"string"==typeof e?e:""}export const HowToSteps=/*@__PURE__*/l.forwardRef(function({steps:k,title:B,step:_,defaultStep:H=0,onStepChange:M,completed:T,defaultCompleted:$=!1,onCompletedChange:A,orientation:E="vertical",maxHeight:F,railWidth:W="15rem",navigation:q=!0,divider:D=!0,transition:G="fade",completion:J=!0,completedContent:K,variant:O="outline",size:P="md",color:Q="primary",density:U="default",elevation:V=0,locale:X,previousLabel:Y,nextLabel:Z,doneLabel:ee,restartLabel:te,className:ne,style:le,...re},ae){const ie=d(m,X),oe=l.useId(),[se,ce]=l.useState(H),[me,de]=l.useState($),pe=void 0!==_,fe=void 0!==T,xe=k.length,ue=Math.min(Math.max(pe?_:se,0),Math.max(xe-1,0)),be=J&&(fe?T:me),he=void 0!==F,ge="vertical"===E,ve=l.useRef(null),Ne=l.useRef(null);if(l.useEffect(()=>{const e=ve.current,t=Ne.current;if(!e||!t)return;const n=e.getBoundingClientRect(),l=t.getBoundingClientRect();ge?l.top<n.top?e.scrollTop-=n.top-l.top:l.bottom>n.bottom&&(e.scrollTop+=l.bottom-n.bottom):l.left<n.left?e.scrollLeft-=n.left-l.left:l.right>n.right&&(e.scrollLeft+=l.right-n.right)},[ue,ge]),0===xe)return null;const we=(e,t=!1)=>{fe||de(t),be!==t&&A?.(t),t||(pe||ce(e),e!==ue&&M?.(e))},ke=0===ue,ye=ue===xe-1,je="none"===G?null:p(G),Ce=t=>{const n=be||t<ue,l=!be&&t===ue;return e("span",{"aria-hidden":"true",className:f("z-1 flex shrink-0 items-center justify-center rounded-full border font-medium","size-(--n-step-mark) [&_svg]:size-[1.15em]",z[P].text,C,n?"bg-(--n-fill) text-(--n-on-solid) [border-color:transparent]":l?"bg-(--neba-surface) text-(--n-accent) [border-color:var(--n-accent)]":"bg-(--neba-surface) text-(--neba-muted-fg) [border-color:var(--n-line)]"),children:n?e(i,{}):t+1})},ze=e("ol",{ref:ve,"aria-label":ie.steps,className:f("m-0 flex list-none p-0",ge?"flex-col":"flex-row",S[U][P],he&&ge?"min-h-0 overflow-y-auto overscroll-contain":"",ge?"":"overflow-x-auto overscroll-contain"),children:k.map((n,l)=>{const r=be||l<ue,a=!be&&l===ue;return t("li",{ref:a?Ne:void 0,className:f("relative",ge?"":"min-w-0 flex-1"),children:[l<xe-1?e("span",{"aria-hidden":"true",className:f("absolute",C,r?"bg-(--n-fill)":"bg-(--n-line)",ge?["w-px","[inset-inline-start:calc(0.25rem+var(--n-step-mark)/2)]","[top:calc(0.25rem+var(--n-step-mark))]","[height:calc(100%-var(--n-step-mark))]"].join(" "):["h-px","[inset-inline-start:calc(50%+var(--n-step-mark)/2)]","[top:calc(0.25rem+var(--n-step-mark)/2)]","[width:calc(100%-var(--n-step-mark))]"].join(" "))}):null,t("button",{type:"button",onClick:()=>we(l),"aria-current":a?"step":void 0,className:f("flex w-full cursor-pointer items-center p-1 text-start",ge?"gap-3":"flex-col gap-1.5 text-center",h.sm,"hover:bg-(--n-soft)",C,"focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-1"),children:[Ce(l),e("span",{className:f("min-w-0",ge?"truncate":"",b[P],a?"font-medium text-(--neba-fg)":"text-(--neba-muted-fg)"),children:n.title}),e("span",{className:w,children:I(ie.step,{index:String(l+1),title:R(n.title)})})]})]},l)})}),Se=t("div",{className:f("grid flex-1 grid-cols-1",he?"min-h-0":""),children:[k.map((n,l)=>{const r=be||l!==ue;return t("div",{"aria-hidden":r,inert:r||void 0,className:f("col-start-1 row-start-1 min-w-0",he?"overflow-y-auto overscroll-contain":"",r?"invisible":je?.className??""),style:r?void 0:je?.style,children:[t("div",{className:"mb-3 flex items-baseline gap-3",children:[x(n.icon)?e("span",{"aria-hidden":"true",className:f("flex h-[1lh] shrink-0 items-center text-(--n-accent)",N[P],u),children:n.icon}):null,e("h4",{className:f("m-0 min-w-0 flex-1 font-medium",N[P]),children:n.title}),e("span",{className:f("shrink-0 text-(--neba-muted-fg) tabular-nums",b[P]),children:I(ie.position,{index:String(l+1),total:String(xe)})})]}),n.image?e("img",{src:n.image,alt:n.imageAlt??R(n.title),className:f("mb-3 max-h-72 w-full object-contain",h[P])}):null,x(n.content)?e("div",{className:f("min-w-0",g[P]),children:n.content}):null]},l)}),J?t("div",{"aria-hidden":!be,inert:!be||void 0,className:f("col-start-1 row-start-1 flex min-w-0 flex-col items-center justify-center gap-2 py-4 text-center",be?je?.className??"":"invisible"),style:be?je?.style:void 0,children:[e("span",{"aria-hidden":"true",className:"text-(--n-accent) [&_svg]:size-9",children:e(c,{})}),e("p",{className:f("m-0 font-medium",g[P]),children:K??ie.completed})]}):null]});return t("div",{ref:ae,"aria-labelledby":x(B)?oe:void 0,className:f("flex min-w-0 flex-col",h[P],a[U][P],v[P],L[O],C,ne),style:{...y(Q,V),"--n-fill":`var(--neba-${Q}-fill)`,"--n-on-solid":`var(--neba-${Q}-on-solid)`,"--n-step-mark":z[P].box,"--n-step-rail":j(W),...he?{maxHeight:j(F)}:null,...le},...re,children:[x(B)?e("h3",{id:oe,className:f("m-0 shrink-0 font-medium",N[P]),children:B}):null,t("div",{className:f("flex min-w-0 flex-1 flex-col",he?"min-h-0":"",ge?"gap-4 sm:flex-row sm:gap-5":"gap-4"),children:[e("div",{className:f("flex min-w-0 flex-col",he?"min-h-0":"",ge?"sm:w-(--n-step-rail) sm:shrink-0":"",D?ge?"border-b pb-4 sm:border-b-0 sm:border-e sm:pb-0 sm:pe-5":"border-b pb-4":"",D?"[border-color:var(--n-line)]":""),children:ze}),t("div",{className:f("flex min-w-0 flex-1 flex-col",he?"min-h-0":"",v[P]),children:[Se,q?e("div",{className:"flex shrink-0 flex-wrap items-center justify-end gap-2",children:be?e(r,{size:P,variant:"outline",color:Q,startIcon:e(s,{}),onClick:()=>we(0),children:te??ie.restart}):t(n,{children:[e(r,{size:P,variant:"outline",color:Q,disabled:ke,startIcon:e("span",{className:"rotate-90 rtl:-rotate-90",children:e(o,{})}),onClick:()=>we(ue-1),children:Y??ie.previous}),e(r,ye&&J?{size:P,variant:"solid",color:Q,startIcon:e(i,{}),onClick:()=>we(ue,!0),children:ee??ie.done}:{size:P,variant:"solid",color:Q,disabled:ye,endIcon:e("span",{className:"-rotate-90 rtl:rotate-90",children:e(o,{})}),onClick:()=>we(ue+1),children:Z??ie.next})]})}):null]})]})]})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{HowToSteps}from"./HowToSteps.js";
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type PageLayoutCollapse, type PageLayoutScroll, type PageLayoutSpan } from '../../internal/page-layout.js';
|
|
3
|
+
import type { NebaColor } from '../../types.js';
|
|
4
|
+
export type { PageLayoutCollapse, PageLayoutScroll, PageLayoutSpan } from '../../internal/page-layout.js';
|
|
5
|
+
export interface PageLayoutProps extends React.ComponentPropsWithoutRef<'div'> {
|
|
6
|
+
/** The bar across the top. A [Header], usually. */
|
|
7
|
+
header?: React.ReactNode;
|
|
8
|
+
/** The sheet at the end. A [Footer], usually. */
|
|
9
|
+
footer?: React.ReactNode;
|
|
10
|
+
/**
|
|
11
|
+
* The leading column — the left of an English page, the right of an Arabic
|
|
12
|
+
* one. A [Sidebar], which is told which end it is on and needs no `side` prop
|
|
13
|
+
* of its own here.
|
|
14
|
+
*/
|
|
15
|
+
sidebar?: React.ReactNode;
|
|
16
|
+
/**
|
|
17
|
+
* The trailing column, for the layouts that have two: navigation down one
|
|
18
|
+
* side and a table of contents, an inspector or a filter panel down the
|
|
19
|
+
* other. Each is a Sidebar with its own width, its own drawer and its own
|
|
20
|
+
* trigger.
|
|
21
|
+
*/
|
|
22
|
+
endSidebar?: React.ReactNode;
|
|
23
|
+
/**
|
|
24
|
+
* Which of the header and the sidebars takes the top corner.
|
|
25
|
+
*
|
|
26
|
+
* - `full` — the header spans the whole width and the sidebars begin
|
|
27
|
+
* underneath it. The arrangement of a website. The default.
|
|
28
|
+
* - `content` — the sidebars run the full height of the window and the header
|
|
29
|
+
* sits between them, belonging to the view rather than to the site. The
|
|
30
|
+
* arrangement of an application.
|
|
31
|
+
* @default 'full'
|
|
32
|
+
*/
|
|
33
|
+
headerSpan?: PageLayoutSpan;
|
|
34
|
+
/**
|
|
35
|
+
* The same question for the footer, and it is worth answering separately: a
|
|
36
|
+
* dashboard with a full-height navigation rail still usually wants its
|
|
37
|
+
* copyright line under the content rather than under the rail.
|
|
38
|
+
* @default 'full'
|
|
39
|
+
*/
|
|
40
|
+
footerSpan?: PageLayoutSpan;
|
|
41
|
+
/**
|
|
42
|
+
* What scrolls: the document, or only the region between the header and the
|
|
43
|
+
* footer.
|
|
44
|
+
*
|
|
45
|
+
* `page` is the default and is what almost every page wants — the browser's
|
|
46
|
+
* own address bar hides on a phone, the scroll position is restored on a back
|
|
47
|
+
* navigation, and the header holds its place with `position: sticky` without
|
|
48
|
+
* anything having to be padded out of its way. Reach for `content` when the
|
|
49
|
+
* page is a workspace rather than a document.
|
|
50
|
+
* @default 'page'
|
|
51
|
+
*/
|
|
52
|
+
scroll?: PageLayoutScroll;
|
|
53
|
+
/**
|
|
54
|
+
* How tall the layout is.
|
|
55
|
+
*
|
|
56
|
+
* - `viewport` — the window's, which is what a page wants: a short page still
|
|
57
|
+
* pushes its footer to the bottom of the screen, and with `scroll="content"`
|
|
58
|
+
* the layout is exactly one screen tall. The default.
|
|
59
|
+
* - `auto` — its parent's, for a layout that is not the page. An app shell
|
|
60
|
+
* inside a [Mockup]'s screen, a preview, a pane of a larger tool.
|
|
61
|
+
* - a length — a number in pixels, or any CSS length.
|
|
62
|
+
*
|
|
63
|
+
* It sets a floor while the page scrolls and an exact height while only the
|
|
64
|
+
* content does, which is the same difference `scroll` makes everywhere else.
|
|
65
|
+
* @default 'viewport'
|
|
66
|
+
*/
|
|
67
|
+
height?: 'viewport' | 'auto' | number | string;
|
|
68
|
+
/**
|
|
69
|
+
* The window width below which the sidebars stop being columns and become
|
|
70
|
+
* drawers, with a [SidebarTrigger] as the way to open them. `none` keeps them
|
|
71
|
+
* as columns at every width.
|
|
72
|
+
* @default 'md'
|
|
73
|
+
*/
|
|
74
|
+
collapseBelow?: PageLayoutCollapse;
|
|
75
|
+
/**
|
|
76
|
+
* Whether the leading sidebar's drawer is open. Use with
|
|
77
|
+
* `onSidebarOpenChange` for a controlled layout — a route change that should
|
|
78
|
+
* close the drawer behind it, a state the app already stores.
|
|
79
|
+
*/
|
|
80
|
+
sidebarOpen?: boolean;
|
|
81
|
+
/** Which state it starts in. @default false */
|
|
82
|
+
defaultSidebarOpen?: boolean;
|
|
83
|
+
onSidebarOpenChange?: (open: boolean) => void;
|
|
84
|
+
/** The same three for the trailing sidebar. */
|
|
85
|
+
endSidebarOpen?: boolean;
|
|
86
|
+
defaultEndSidebarOpen?: boolean;
|
|
87
|
+
onEndSidebarOpenChange?: (open: boolean) => void;
|
|
88
|
+
/**
|
|
89
|
+
* Puts a "Skip to content" link first in the document, drawn only while it
|
|
90
|
+
* holds the focus.
|
|
91
|
+
*
|
|
92
|
+
* On by default, and it is the one thing here that is not a style decision. A
|
|
93
|
+
* keyboard reader arriving on a page whose navigation holds forty links has
|
|
94
|
+
* to walk past all forty on every page before reaching the article, and this
|
|
95
|
+
* is the one link that spares them. It costs a sighted reader nothing,
|
|
96
|
+
* because it is invisible until it is tabbed to.
|
|
97
|
+
* @default true
|
|
98
|
+
*/
|
|
99
|
+
skipLink?: boolean;
|
|
100
|
+
/** What that link says. Defaults to the `locale`'s word for it. */
|
|
101
|
+
skipLabel?: string;
|
|
102
|
+
/**
|
|
103
|
+
* The `id` the skip link jumps to, put on the `<main>`.
|
|
104
|
+
* @default 'main'
|
|
105
|
+
*/
|
|
106
|
+
mainId?: string;
|
|
107
|
+
/** Anything else the `<main>` needs — a `className`, an `aria-label`. */
|
|
108
|
+
mainProps?: Omit<React.ComponentPropsWithoutRef<'main'>, 'id' | 'children'>;
|
|
109
|
+
/**
|
|
110
|
+
* Which language the layout's own words are in — a BCP 47 tag such as `ko`,
|
|
111
|
+
* `pt-BR` or `zh-Hant`. Inherited by every Sidebar and SidebarTrigger inside
|
|
112
|
+
* it, so it is written once per page.
|
|
113
|
+
*/
|
|
114
|
+
locale?: string;
|
|
115
|
+
/** The colour family the skip link and the focus rings light up in. @default 'primary' */
|
|
116
|
+
color?: NebaColor;
|
|
117
|
+
/** The page. Rendered inside the `<main>`. */
|
|
118
|
+
children?: React.ReactNode;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* The skeleton a page is hung on: a header, a footer, one sidebar or two, and
|
|
122
|
+
* the content between them.
|
|
123
|
+
*
|
|
124
|
+
* What it is really for is the landmarks. A page assembled out of divs is a
|
|
125
|
+
* page a screen reader offers as one undifferentiated region and a search
|
|
126
|
+
* engine reads as one undifferentiated blob; the same page built out of
|
|
127
|
+
* `<header>`, `<nav>`, `<aside>`, `<main>` and `<footer>` is a page with a
|
|
128
|
+
* table of contents. Those tags come from the four components this one arranges
|
|
129
|
+
* — it draws no surface of its own and contributes exactly one element to the
|
|
130
|
+
* document, plus the `<main>` and the skip link that jumps to it.
|
|
131
|
+
*
|
|
132
|
+
* The arrangement is flexbox and media queries, which is deliberate rather than
|
|
133
|
+
* incidental: everything that decides where a column goes is stated in CSS, so
|
|
134
|
+
* the layout is right in the first frame the browser paints and right in a page
|
|
135
|
+
* with JavaScript turned off. The only things measured are the header's and the
|
|
136
|
+
* footer's heights, and only because a sidebar that holds its place has to
|
|
137
|
+
* start below a bar whose height nobody but the bar knows.
|
|
138
|
+
*
|
|
139
|
+
* It draws no gutter and no measure. That is [Container]'s job, and a layout
|
|
140
|
+
* that also did it would be a second spelling of one idea — put a Container
|
|
141
|
+
* inside, where a page can have a wide dashboard on one route and a narrow
|
|
142
|
+
* article on the next.
|
|
143
|
+
*/
|
|
144
|
+
export declare const PageLayout: React.ForwardRefExoticComponent<PageLayoutProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as n}from"react/jsx-runtime";import*as o from"react";import{layoutMessages as l,useMessages as t}from"../../internal/i18n.js";import{PageLayoutContext as r,SidebarSideContext as s}from"../../internal/page-layout.js";import{controlSlots as a,cx as i,hasContent as u,toLength as c}from"../../internal/styles.js";const d=["header","footer"];export const PageLayout=/*@__PURE__*/o.forwardRef(function({header:f,footer:p,sidebar:h,endSidebar:m,headerSpan:v="full",footerSpan:x="full",scroll:y="page",height:b="viewport",collapseBelow:w="md",sidebarOpen:g,defaultSidebarOpen:S=!1,onSidebarOpenChange:k,endSidebarOpen:C,defaultEndSidebarOpen:P=!1,onEndSidebarOpenChange:O,skipLink:N=!0,skipLabel:j,mainId:$="main",mainProps:R,locale:z,color:E="primary",className:L,style:B,children:H,...M},_){const I=t(l,z),[T,q]=o.useState(S),[A,D]=o.useState(P),F=o.useMemo(()=>({start:g??T,end:C??A}),[g,T,C,A]),G=o.useCallback((e,n)=>{if("start"===e)return void 0===g&&q(n),void k?.(n);void 0===C&&D(n),O?.(n)},[g,C,k,O]),J=o.useRef(null),K=o.useCallback(e=>{J.current=e,"function"==typeof _?_(e):_&&(_.current=e)},[_]),Q=o.useRef({header:null,footer:null}),U=o.useRef(null),V=o.useCallback(()=>{const e=J.current;if(e)for(const n of d){const o=Q.current[n],l="header"===n?v:x;if(!o){e.style.setProperty(`--n-layout-${n}`,"0px"),e.style.setProperty(`--n-layout-${n}-inset`,"0px");continue}const t=getComputedStyle(o).position,r=`${o.offsetHeight}px`,s="sticky"===t||"fixed"===t;e.style.setProperty(`--n-layout-${n}`,s&&"full"===l?r:"0px"),e.style.setProperty(`--n-layout-${n}-inset`,"fixed"===t?r:"0px")}},[v,x]),W=o.useCallback(()=>{const e=U.current;if(e){e.disconnect();for(const n of d){const o=Q.current[n];o&&e.observe(o)}}V()},[V]);o.useEffect(()=>(U.current=new ResizeObserver(()=>V()),W(),()=>{U.current?.disconnect(),U.current=null}),[V,W]);const X=o.useCallback((e,n)=>{Q.current[e]=n,W()},[W]),Y=o.useMemo(()=>({present:!0,register:X,collapseBelow:w,open:F,setOpen:G,scroll:y,locale:z}),[X,w,F,G,y,z]),Z="content"===y,ee=c("viewport"===b||"auto"===b?void 0:b),ne=void 0!==ee?"":"auto"===b?Z?"h-full":"min-h-full":Z?"h-dvh":"min-h-dvh",oe=u(f)?f:null,le=u(p)?p:null;return e(r.Provider,{value:Y,children:n("div",{ref:K,className:i("relative flex w-full flex-col",Z?"overflow-hidden":"",ne,"full"===v?"[padding-top:var(--n-layout-header-inset,0px)]":"","full"===x?"[padding-bottom:var(--n-layout-footer-inset,0px)]":"",L),style:void 0===ee?B:{...Z?{height:ee}:{minHeight:ee},...B},...M,children:[N?e("a",{href:`#${$}`,className:i("absolute start-3 top-3 z-50 size-px overflow-hidden whitespace-nowrap","[clip-path:inset(50%)] focus:size-auto focus:overflow-visible focus:[clip-path:none]","focus:rounded-(--neba-radius-md) focus:bg-(--n-fill) focus:px-4 focus:py-2","focus:font-medium focus:text-(--n-on-solid) focus:no-underline","focus:[box-shadow:var(--neba-shadow-2),var(--neba-plate-solid)]","focus:[outline:2px_solid_var(--n-ring)] focus:outline-offset-2"),style:a(E,2,"solid"),children:j??I.skipToContent}):null,"full"===v?oe:null,n("div",{className:i("flex w-full flex-1",Z?"min-h-0":""),children:[u(h)?e(s.Provider,{value:"start",children:h}):null,n("div",{className:i("flex min-w-0 flex-1 flex-col",Z?"min-h-0":"","content"===v?"[padding-top:var(--n-layout-header-inset,0px)]":"","content"===x?"[padding-bottom:var(--n-layout-footer-inset,0px)]":""),children:["content"===v?oe:null,e("main",{...R,id:$,className:i("min-w-0 flex-1",Z?"min-h-0 overflow-y-auto":"",R?.className),children:H}),"content"===x?le:null]}),u(m)?e(s.Provider,{value:"end",children:m}):null]}),"full"===x?le:null]})})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{PageLayout}from"./PageLayout.js";
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { PageLayoutCollapse, SidebarSide } from '../../internal/page-layout.js';
|
|
3
|
+
import type { NebaColor, NebaDensity, NebaElevation, NebaSize, NebaVariant } from '../../types.js';
|
|
4
|
+
export type { SidebarSide } from '../../internal/page-layout.js';
|
|
5
|
+
export interface SidebarProps extends Omit<React.ComponentPropsWithoutRef<'aside'>, 'color' | 'title'> {
|
|
6
|
+
/**
|
|
7
|
+
* Which end of the band it takes. Logical rather than physical — `start` is
|
|
8
|
+
* the left of an English page and the right of an Arabic one — because a
|
|
9
|
+
* navigation rail is beside the text it belongs to in every writing
|
|
10
|
+
* direction.
|
|
11
|
+
*
|
|
12
|
+
* Inside a [PageLayout] this is already decided by which slot the sidebar was
|
|
13
|
+
* handed to, and setting it again is only a way of disagreeing with the
|
|
14
|
+
* layout.
|
|
15
|
+
* @default 'start'
|
|
16
|
+
*/
|
|
17
|
+
side?: SidebarSide;
|
|
18
|
+
/**
|
|
19
|
+
* How wide the column is — a number in pixels or any CSS length. Left out, it
|
|
20
|
+
* is the width `size` implies.
|
|
21
|
+
*
|
|
22
|
+
* With `resizable` it is only the width the sidebar *starts* at: dragging
|
|
23
|
+
* writes over it, and the caller hears about it through `onResize`.
|
|
24
|
+
*/
|
|
25
|
+
width?: number | string;
|
|
26
|
+
/** How narrow it may be dragged. @default 160 */
|
|
27
|
+
minWidth?: number | string;
|
|
28
|
+
/** And how wide. @default 480 */
|
|
29
|
+
maxWidth?: number | string;
|
|
30
|
+
/**
|
|
31
|
+
* Lets the reader drag the inner edge to change the column's width.
|
|
32
|
+
*
|
|
33
|
+
* Off by default. A sidebar that can be resized is a sidebar whose width is
|
|
34
|
+
* the reader's to remember, which means a caller who turns this on usually
|
|
35
|
+
* also wants to store what `onResizeEnd` reports.
|
|
36
|
+
* @default false
|
|
37
|
+
*/
|
|
38
|
+
resizable?: boolean;
|
|
39
|
+
/** Fires with the width in pixels while the edge is being dragged. */
|
|
40
|
+
onResize?: (width: number) => void;
|
|
41
|
+
/** Fires once, with the same number, when it is let go. */
|
|
42
|
+
onResizeEnd?: (width: number) => void;
|
|
43
|
+
/**
|
|
44
|
+
* The window width below which the sidebar stops being a column and becomes a
|
|
45
|
+
* drawer that is opened — with a [SidebarTrigger] somewhere on the page as
|
|
46
|
+
* the way to open it. `none` keeps it a column at every width.
|
|
47
|
+
*
|
|
48
|
+
* Defaults to the [PageLayout]'s own `collapseBelow`, and to `none` outside
|
|
49
|
+
* one: a sidebar that collapsed with nothing on the page able to bring it
|
|
50
|
+
* back would be a sidebar the reader has lost.
|
|
51
|
+
*/
|
|
52
|
+
collapseBelow?: PageLayoutCollapse;
|
|
53
|
+
/**
|
|
54
|
+
* Whether the drawer is open. Only meaningful once the sidebar has collapsed;
|
|
55
|
+
* a column is not opened, it is there.
|
|
56
|
+
*
|
|
57
|
+
* Inside a [PageLayout] the layout owns this — it is what a SidebarTrigger
|
|
58
|
+
* anywhere on the page talks to — so control it there rather than here.
|
|
59
|
+
* `onOpenChange` still fires either way.
|
|
60
|
+
*/
|
|
61
|
+
open?: boolean;
|
|
62
|
+
/** Which state it starts in, for an uncontrolled standalone sidebar. @default false */
|
|
63
|
+
defaultOpen?: boolean;
|
|
64
|
+
onOpenChange?: (open: boolean) => void;
|
|
65
|
+
/**
|
|
66
|
+
* Whether the column holds its place while the page scrolls past it.
|
|
67
|
+
*
|
|
68
|
+
* On by default, and it costs nothing when it is not needed: with the page
|
|
69
|
+
* scrolling it becomes a `sticky` column as tall as what is left of the
|
|
70
|
+
* window under the header, and with only the content scrolling it is already
|
|
71
|
+
* as tall as the layout and this changes nothing.
|
|
72
|
+
* @default true
|
|
73
|
+
*/
|
|
74
|
+
sticky?: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* The heading, drawn only while the sidebar is a drawer. A column has the
|
|
77
|
+
* page around it to say what it is; a panel that has covered the page does
|
|
78
|
+
* not.
|
|
79
|
+
*/
|
|
80
|
+
title?: React.ReactNode;
|
|
81
|
+
/**
|
|
82
|
+
* Weight of the sheet, said the way a *container* says it: the panel is never
|
|
83
|
+
* dyed, because what is on it arrives with colours of its own.
|
|
84
|
+
* @default 'outline'
|
|
85
|
+
*/
|
|
86
|
+
variant?: NebaVariant;
|
|
87
|
+
/** The panel's scale — its default width and the air around its content. @default 'md' */
|
|
88
|
+
size?: NebaSize;
|
|
89
|
+
/** @default 'primary' */
|
|
90
|
+
color?: NebaColor;
|
|
91
|
+
/** @default 'default' */
|
|
92
|
+
density?: NebaDensity;
|
|
93
|
+
/** Drop shadow depth. `0` (the default) is flat. @default 0 */
|
|
94
|
+
elevation?: NebaElevation;
|
|
95
|
+
/**
|
|
96
|
+
* Draws a hairline down the inner edge — the one facing the content. The
|
|
97
|
+
* outer edge is against the window, where there is nothing on the other side
|
|
98
|
+
* to be separated from.
|
|
99
|
+
* @default true
|
|
100
|
+
*/
|
|
101
|
+
divider?: boolean;
|
|
102
|
+
/** The gutter and the air above and below the content. @default true */
|
|
103
|
+
padded?: boolean;
|
|
104
|
+
/**
|
|
105
|
+
* The name the region is announced by. Every `<aside>` on a page should have
|
|
106
|
+
* one, and a page with two sidebars *must*, or a screen reader offers two
|
|
107
|
+
* regions called "complementary".
|
|
108
|
+
*
|
|
109
|
+
* Defaults to the `locale`'s word for "Sidebar".
|
|
110
|
+
*/
|
|
111
|
+
label?: string;
|
|
112
|
+
/**
|
|
113
|
+
* Which language the sidebar's own words are in — a BCP 47 tag such as `ko`,
|
|
114
|
+
* `pt-BR` or `zh-Hant`. Unsupported tags fall back to English. Inherited from
|
|
115
|
+
* the [PageLayout] when there is one.
|
|
116
|
+
*/
|
|
117
|
+
locale?: string;
|
|
118
|
+
/** Everything in it: a nav, a filter panel, a table of contents. */
|
|
119
|
+
children?: React.ReactNode;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* A column beside the page's content, and a drawer once the window is too
|
|
123
|
+
* narrow to hold one.
|
|
124
|
+
*
|
|
125
|
+
* Two presentations of one panel, exactly as [Drawer] is: above `collapseBelow`
|
|
126
|
+
* it is an `<aside>` in the layout that the content is laid out around, and
|
|
127
|
+
* below it the same children are a drawer over a scrim with a focus trap, an
|
|
128
|
+
* Escape and a way back to the trigger. They are one component because they are
|
|
129
|
+
* one thing — a caller should not have to swap components at a breakpoint — and
|
|
130
|
+
* because the children only exist once either way, so nothing inside is
|
|
131
|
+
* rendered twice into the document for a screen reader to read twice.
|
|
132
|
+
*
|
|
133
|
+
* Which of the two is showing is a media query, and it is answered in CSS for
|
|
134
|
+
* the first paint and in JavaScript from then on. That split is deliberate: the
|
|
135
|
+
* markup a server sends is the column, so a narrow screen would draw a full
|
|
136
|
+
* width sidebar and throw it away a moment later — the class that hides it
|
|
137
|
+
* below the breakpoint is what stops that, and `matchMedia` is what decides,
|
|
138
|
+
* once there is a window to ask, that the drawer should exist at all.
|
|
139
|
+
*
|
|
140
|
+
* A real `<aside>`, which is the `complementary` landmark: the region a screen
|
|
141
|
+
* reader offers as "related to the page but not the page", and what a search
|
|
142
|
+
* engine reads as navigation chrome rather than as the article.
|
|
143
|
+
*/
|
|
144
|
+
export declare const Sidebar: React.ForwardRefExoticComponent<SidebarProps & React.RefAttributes<HTMLElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as t}from"react/jsx-runtime";import*as r from"react";import{boxPaddingXClasses as n,boxPaddingYClasses as o}from"../box/Box.js";import{Drawer as s}from"../drawer/Drawer.js";import{layoutMessages as i,useMessages as a}from"../../internal/i18n.js";import{drawerSide as l,expandedOnlyClasses as d,PageLayoutContext as c,SidebarSideContext as u,useCollapsed as p}from"../../internal/page-layout.js";import{cx as m,surfaceClasses as f,surfaceSlots as b,toLength as v,transitionClasses as y}from"../../internal/styles.js";const g={xs:"11rem",sm:"13rem",md:"16rem",lg:"18rem",xl:"21rem"},w={solid:[f,"text-(--neba-fg) bg-(--n-panel-press)","[box-shadow:var(--n-elev),var(--neba-plate-solid)]"].join(" "),outline:[f,"text-(--neba-fg) bg-(--n-panel)","[box-shadow:var(--n-elev),var(--neba-plate-glass)]"].join(" "),text:"text-(--neba-fg) bg-transparent"};function x(e,t){if(null==e)return t;if("number"==typeof e)return e;const r=/^\s*(-?[\d.]+)\s*(px|rem|em|%)\s*$/.exec(e);if(!r)return t;const n=Number(r[1]);if(Number.isNaN(n))return t;switch(r[2]){case"px":return n;case"%":return"undefined"==typeof window?t:window.innerWidth*n/100;default:return n*parseFloat(("undefined"==typeof document?"":getComputedStyle(document.documentElement).fontSize)||"16")}}export const Sidebar=/*@__PURE__*/r.forwardRef(function({side:f,width:h,minWidth:k=160,maxWidth:C=480,resizable:j=!1,onResize:z,onResizeEnd:E,collapseBelow:N,open:R,defaultOpen:L=!1,onOpenChange:S,sticky:P=!0,title:B,variant:D="outline",size:O="md",color:A="primary",density:M="default",elevation:W=0,divider:I=!0,padded:T=!0,label:X,locale:$,className:_,style:F,children:K,...V},q){const G=r.useContext(c),H=r.useContext(u),J=f??H??"start",Q=$??G.locale,U=a(i,Q),Y=N??(G.present?G.collapseBelow:"none"),Z=p(Y),[ee,te]=r.useState(L),re=void 0!==R,ne=re?R:G.present?G.open[J]:ee,oe=e=>{re||(G.present?G.setOpen(J,e):te(e)),S?.(e)},se=v(h)??g[O],ie=r.useRef(null),ae=r.useCallback(e=>{ie.current=e,"function"==typeof q?q(e):q&&(q.current=e)},[q]),le=r.useRef(null);r.useEffect(()=>()=>le.current?.(),[]);const de=e=>{const t=ie.current;if(!t)return e;const r=Math.min(x(C,480),Math.max(x(k,160),Math.round(e)));return t.style.setProperty("--n-sidebar-w",`${r}px`),r},ce=e("div",{className:m("min-h-0 flex-1 overflow-y-auto overscroll-contain",T?m(n[M][O],o[M][O]):""),children:K});return Z?e(s,{side:l(J),mode:"overlay",open:ne,onOpenChange:oe,title:B,size:O,color:A,density:M,locale:Q,closeLabel:U.closeSidebar,extent:void 0===h?void 0:se,"aria-label":B?void 0:X??U.sidebar,className:_,style:F,children:K}):t("aside",{ref:ae,"aria-label":X??U.sidebar,className:m("relative flex min-w-0 shrink-0 flex-col","w-(--n-sidebar-w)",w[D],I?m("start"===J?"border-e":"border-s","[border-color:var(--n-line)]"):"","content"===G.scroll?"h-full":P?m("self-start","sticky [top:var(--n-layout-header,0px)]","[height:calc(100dvh-var(--n-layout-header,0px)-var(--n-layout-footer,0px))]"):"",d[Y],y,_),style:{...b(A,W),"--n-sidebar-w":se,...F},...V,children:[ce,j?e("div",{role:"separator","aria-orientation":"vertical","aria-label":U.resizeSidebar,tabIndex:0,className:m("absolute inset-y-0 z-1 w-2 cursor-col-resize","start"===J?"end-0 -me-1":"start-0 -ms-1","bg-transparent hover:bg-(--n-soft) data-[dragging]:bg-(--n-soft)",y,"[outline:none] focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-0"),onPointerDown:e=>{const t=ie.current;if(!t||0!==e.button)return;const r=e.currentTarget;r.setPointerCapture(e.pointerId),r.dataset.dragging="true";const n=document.body.style.getPropertyValue("-webkit-user-select");document.body.style.setProperty("-webkit-user-select","none");const o=e.clientX,s=t.getBoundingClientRect().width,i="rtl"===getComputedStyle(t).direction,a="start"===J===i?-1:1;let l=s;const d=e=>{l=de(s+(e.clientX-o)*a),z?.(l)},c=()=>{le.current=null,r.removeEventListener("pointermove",d),r.removeEventListener("pointerup",u),r.removeEventListener("pointercancel",u),delete r.dataset.dragging,n?document.body.style.setProperty("-webkit-user-select",n):document.body.style.removeProperty("-webkit-user-select")},u=()=>{c(),E?.(l)};le.current=c,r.addEventListener("pointermove",d),r.addEventListener("pointerup",u),r.addEventListener("pointercancel",u)},onKeyDown:e=>{if("ArrowLeft"!==e.key&&"ArrowRight"!==e.key)return;e.preventDefault();const t="rtl"===getComputedStyle(e.currentTarget).direction,r="start"===J===t?-1:1;(e=>{const t=ie.current;if(!t)return;const r=de(t.getBoundingClientRect().width+e);z?.(r),E?.(r)})(("ArrowRight"===e.key?16:-16)*r)}}):null]})});
|