@ntmats/hc-ui 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/dist/index.d.ts +120 -45
- package/dist/index.js +42 -24
- package/dist/styles.css +62 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,6 +50,19 @@ Both open below the trigger, aligned by its end, 4px away (`side="bottom|top"`,
|
|
|
50
50
|
|
|
51
51
|
`SortMenu` (experimental) is HCUI's desktop sort control: a `Chip` (`size="sm"` by default, `triggerClassName` for a class) showing the current option, named "`label`: option", that opens a `Menu` with a `MenuRadioGroup` of `options` (`value`, `label`, optional `hint` and `disabled`), with the `Menu` keyboard and focus. `applied` marks a choice in effect with the ring; other `Menu` props (`align`, `side`, `portal`, `open`, `onOpenChange`) pass through. On phones, compose instead: `IconButton variant="outline" size="lg"` with `aria-haspopup="dialog"` opens a `Sheet` with `SheetOptions` (its card look, as every sheet list).
|
|
52
52
|
|
|
53
|
+
Options for HCUI's remaining local pieces (unreleased, experimental; opt-in, except the visible changes listed in the CHANGELOG):
|
|
54
|
+
|
|
55
|
+
- `Button`: `variant="ghost"` (no fill, only the hover and press veil) and `tone="danger"` (danger text on `secondary`, `outline` and `ghost`), e.g. `variant="ghost" tone="danger"` for a text-only destructive action. As a popup trigger (`aria-haspopup`) that is open (`aria-expanded="true"`), `secondary`, `outline` and `ghost` draw the 1.5px ring in the text color, as `Chip`.
|
|
56
|
+
- `IconButton`: `size="xs"` (28px, keeping a 44px touch target) and `tone="muted"` (text-muted). A `ghost` popup trigger keeps its hover fill while open.
|
|
57
|
+
- `Chip`: `variant="muted"` (gray fill without ring; with `onClear` at `md`/`sm`, the main button fills the height and the × is 26px, 5px from the end), `badgePlacement="corner"` (the badge on the top right corner, brand fill, a 2px ring of `--hc-chip-badge-ring`, default `bg-page`), a chip with an `icon` and no label is a circle, and `informative` (disabled but not dimmed).
|
|
58
|
+
- `SheetChips`: `size`, passed to every `Chip`.
|
|
59
|
+
- `Dialog` and `Sheet`: `bodyClassName` (the scrolling body's class). `Sheet header={false}` drops the header (no title, no close button) for content with its own heading and floating close; `aria-label` names the dialog (required by the type), and the body has no padding. The entry animations no longer leave a transform on the dialog, so fixed popups portaled into it are not clipped; a touch inside a portaled popup (`.hc-ui-portal`) does not drag the sheet.
|
|
60
|
+
- `portalContainerFor(node)`: the open `<dialog>` around `node`, else `document.body` (null on the server). Use it for the app's own tips, so they show above a modal `Dialog` or `Sheet` and receive touches instead of staying behind the top layer; `Menu` and `Popover` with `portal` already do this.
|
|
61
|
+
- `Surface`: `as` (`div`, `section`, `article`, `aside`, `ul`, `ol`, `li`) and `tone="muted"` (the `bg-muted-2` card: 20px corners, `shadow-card`).
|
|
62
|
+
- `FilterBar`: `bleed` (negative margin of `--hc-filter-bar-bleed-start`/`-end`, default `--hc-filter-bar-bleed`, given back as padding) and `rowClassName`; the row is `position: relative`, so an absolute popup placed in it is anchored to it.
|
|
63
|
+
- `Dialog size="sm"` no longer forces 38px buttons: they keep their own size.
|
|
64
|
+
- `SegmentedControl`: `optionMinWidth` (px).
|
|
65
|
+
|
|
53
66
|
`Table` (experimental) is a dense data table on a semantic `<table>`: HCUI's desktop Meta table. `columns` describe it (`key`, `header`, `cell(row, index)` with free content, `align` `start`/`center`/`end`, `numeric` for end-aligned tabular figures, `width` in px or any CSS length, `tone` `muted` or `secondary` for the header and cells, `className` for the header and every cell, such as a class that hides an optional column in a narrow container, and `rowHeader` for the cell that names the row, rendered as `<th scope="row">`); `rows` and `rowKey` give the data, already filtered, formatted and in order. A `sortable` column puts its header text in a button and carries `aria-sort` (`none` until sorted); `sort` (`{ key, direction }`) marks the sorted column, which shows a 12px arrow, and `onSort(key)` reports a press: the new order (toggle, default direction) and sorting the rows are the caller's. `stickyHeader` sticks the header row to the top of the scrolling ancestor at `--hc-table-sticky-top` (HCUI: under its filter band). `onRowClick` makes the rows react to a press and puts the row header's content in a button, so the keyboard reaches each row once (its press does not also reach the row); give a `rowHeader` column, or rows can only be pressed with a pointer. `selectedKey` fills the row open elsewhere (a side panel) with `bg-muted` and sets `aria-current` on its button. Rows are 4px 8px cells with a line under each and the `bg-muted-2` hover; the header is 11px muted text on the surface fill with a line under it. Focus rings are the shared 2px ring unless `--hc-focus-ring-offset` is set. Empty states, pagination ("show more") and the cell content styles are the caller's. It forwards its ref to the `<table>`.
|
|
54
67
|
|
|
55
68
|
`PageHeader` (experimental) is HCUI's desktop page heading: a row of at least 40px with the `title` (22px semibold on a 27.5px line, pulled up 4px to drop the font's inner space; an `h1` by default, `level` 2 or 3 change only the tag), an optional `count` in muted 13px text inside the heading after a space (hidden at 0) and `actions` at the end, 8px apart. The row wraps when it does not fit. `visuallyHidden` keeps the heading only for assistive technology, for a page whose content already shows its title. Spacing around it is the caller's. As in HCUI, the title's font is set with the `font` shorthand, which drops the `ROND` axis: this reproduces HCUI's look. It forwards its ref to the `<header>`.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
import { type ButtonHTMLAttributes, type Dispatch, type HTMLAttributes, type InputHTMLAttributes, type KeyboardEvent, type MouseEvent, type ReactElement, type ReactNode, type Ref, type SetStateAction } from 'react';
|
|
2
|
-
export type SurfaceTone = 'page' | 'main' | 'content' | 'elevated' | 'overlay' | 'card';
|
|
3
|
-
|
|
1
|
+
import { type ButtonHTMLAttributes, type Dispatch, type ForwardRefExoticComponent, type RefAttributes, type HTMLAttributes, type InputHTMLAttributes, type KeyboardEvent, type MouseEvent, type ReactElement, type ReactNode, type Ref, type SetStateAction } from 'react';
|
|
2
|
+
export type SurfaceTone = 'page' | 'main' | 'content' | 'elevated' | 'overlay' | 'card' | 'muted';
|
|
3
|
+
/** Elements a `Surface` may render as. */
|
|
4
|
+
export type SurfaceElement = 'div' | 'section' | 'article' | 'aside' | 'ul' | 'ol' | 'li';
|
|
5
|
+
export interface SurfaceProps extends HTMLAttributes<HTMLElement> {
|
|
4
6
|
tone?: SurfaceTone;
|
|
5
|
-
/** Corner radius of the rounded tones (`content`, `elevated`, `overlay`, `card`): 16, 20 or 24px.
|
|
6
|
-
* Defaults to `md` (16px), and to `lg` (20px) for `card`, as HCUI's `surface` mixin. */
|
|
7
|
+
/** Corner radius of the rounded tones (`content`, `elevated`, `overlay`, `card`, `muted`): 16, 20 or 24px.
|
|
8
|
+
* Defaults to `md` (16px), and to `lg` (20px) for `card` and `muted`, as HCUI's `surface` mixin. */
|
|
7
9
|
radius?: 'md' | 'lg' | 'xl';
|
|
10
|
+
/** Element to render: `div` (default), or `section`, `article`, `aside`, `ul`, `ol`, `li`
|
|
11
|
+
* (a list drawn as a card). Lists keep the browser's margin, padding and markers: reset them in the caller's class. */
|
|
12
|
+
as?: SurfaceElement;
|
|
8
13
|
}
|
|
9
14
|
/** Semantic color role only; placement, elevation and overlay behavior stay local. */
|
|
10
|
-
export declare function Surface({ tone, radius, className, ...props }: SurfaceProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export declare function Surface({ tone, radius, as: Element, className, ...props }: SurfaceProps): import("react/jsx-runtime").JSX.Element;
|
|
11
16
|
export interface SegmentedOption<T extends string> {
|
|
12
17
|
value: T;
|
|
13
18
|
label: string;
|
|
@@ -31,12 +36,24 @@ export interface SegmentedControlProps<T extends string> extends Omit<HTMLAttrib
|
|
|
31
36
|
equalWidth?: boolean;
|
|
32
37
|
/** Fixed width of each option in px; implies `equalWidth`. */
|
|
33
38
|
optionWidth?: number;
|
|
39
|
+
/** Minimum width of each option in px (HCUI's 92px Coleções/Unidades toggle); a longer label still widens its option. */
|
|
40
|
+
optionMinWidth?: number;
|
|
34
41
|
}
|
|
35
42
|
/** Controlled, single-choice control with radio semantics and roving focus. */
|
|
36
|
-
export declare function SegmentedControl<T extends string>({ label, value, options, onChange, density, orientation, hideLabels, indicator, equalWidth, optionWidth, className, style, ...props }: SegmentedControlProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
37
|
-
export type ButtonVariant = 'secondary' | 'primary' | 'outline' | 'danger';
|
|
43
|
+
export declare function SegmentedControl<T extends string>({ label, value, options, onChange, density, orientation, hideLabels, indicator, equalWidth, optionWidth, optionMinWidth, className, style, ...props }: SegmentedControlProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
44
|
+
export type ButtonVariant = 'secondary' | 'primary' | 'outline' | 'danger' | 'ghost';
|
|
38
45
|
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
46
|
+
/**
|
|
47
|
+
* `secondary` (default, muted fill), `primary`, `outline`, `danger` (filled) or `ghost`
|
|
48
|
+
* (no fill, only the hover and press veil). A popup trigger (`aria-haspopup`) that is open
|
|
49
|
+
* (`aria-expanded="true"`) draws a 1.5px ring in the text color, as `Chip` (not on `primary` and `danger`).
|
|
50
|
+
*/
|
|
39
51
|
variant?: ButtonVariant;
|
|
52
|
+
/**
|
|
53
|
+
* Text color of the unfilled variants (`secondary`, `outline`, `ghost`): `default` or `danger`
|
|
54
|
+
* (HCUI's "Fechar e descartar alterações": `variant="ghost" tone="danger"`). Ignored by `primary` and `danger`.
|
|
55
|
+
*/
|
|
56
|
+
tone?: 'default' | 'danger';
|
|
40
57
|
/** 36, 44 or 52px. */
|
|
41
58
|
size?: 'sm' | 'md' | 'lg';
|
|
42
59
|
/** Decorative icon before the label; pass it already sized (18px in HCUI). */
|
|
@@ -53,17 +70,19 @@ export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
|
53
70
|
wrap?: boolean;
|
|
54
71
|
}
|
|
55
72
|
/** Pill button. The caller supplies the label text and handles the action. */
|
|
56
|
-
export declare const Button:
|
|
73
|
+
export declare const Button: ForwardRefExoticComponent<ButtonProps & RefAttributes<HTMLButtonElement>>;
|
|
57
74
|
export interface IconButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'children' | 'aria-label'> {
|
|
58
75
|
/** Accessible name and tooltip; required because the button has no text. */
|
|
59
76
|
label: string;
|
|
60
77
|
icon: ReactNode;
|
|
61
|
-
/** 36, 40 or 44px.
|
|
62
|
-
size?: 'sm' | 'md' | 'lg';
|
|
63
|
-
|
|
78
|
+
/** 28 (`xs`, dense toolbars and ⋯ triggers), 36, 40 or 44px. `xs` and `sm` keep a 44px touch target. */
|
|
79
|
+
size?: 'xs' | 'sm' | 'md' | 'lg';
|
|
80
|
+
/** Icon color: `primary` (default), `secondary` or `muted` (text-muted, HCUI's ⋯ triggers). */
|
|
81
|
+
tone?: 'primary' | 'secondary' | 'muted';
|
|
64
82
|
/** Fill: `muted` (default, HCUI `icon-button`), `surface` (surface with the card ring
|
|
65
83
|
* and shadow, HCUI's mobile theme button), `outline` (surface with a 1px border ring,
|
|
66
|
-
* HCUI's mobile sort button) or `ghost` (no fill until hover
|
|
84
|
+
* HCUI's mobile sort button) or `ghost` (no fill until hover; an open popup trigger,
|
|
85
|
+
* `aria-haspopup` with `aria-expanded="true"`, keeps the hover look). */
|
|
67
86
|
variant?: 'muted' | 'surface' | 'outline' | 'ghost';
|
|
68
87
|
/** `circle` (default) or `rounded` (a 12px-radius square, HCUI's desktop utilities). */
|
|
69
88
|
shape?: 'circle' | 'rounded';
|
|
@@ -74,7 +93,7 @@ export interface IconButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonEle
|
|
|
74
93
|
iconKey?: string | number;
|
|
75
94
|
}
|
|
76
95
|
/** Round icon-only button (back, close, options). */
|
|
77
|
-
export declare const IconButton:
|
|
96
|
+
export declare const IconButton: ForwardRefExoticComponent<IconButtonProps & RefAttributes<HTMLButtonElement>>;
|
|
78
97
|
interface ChipBaseProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
79
98
|
/** Toggle state for filters; omit for a plain action chip. */
|
|
80
99
|
selected?: boolean;
|
|
@@ -85,8 +104,12 @@ interface ChipBaseProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
|
85
104
|
* desktop quick filters and chosen-value tags); selected turns to the contrast fill.
|
|
86
105
|
*/
|
|
87
106
|
size?: 'md' | 'sm' | 'xs';
|
|
88
|
-
/**
|
|
89
|
-
|
|
107
|
+
/**
|
|
108
|
+
* `outline` (default); `quiet`: lighter ring and secondary text, bolder once applied (HCUI's rule
|
|
109
|
+
* filter pills); `muted`: gray fill without ring (HCUI's search conditions). With `onClear`, a
|
|
110
|
+
* `muted` chip of `md` or `sm` draws its × at 26px, concentric with the pill's end.
|
|
111
|
+
*/
|
|
112
|
+
variant?: 'outline' | 'quiet' | 'muted';
|
|
90
113
|
/** A filter with values applied: a 1.5px ring in the primary text color (and primary, bolder text when `quiet`). */
|
|
91
114
|
applied?: boolean;
|
|
92
115
|
/**
|
|
@@ -99,6 +122,17 @@ interface ChipBaseProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
|
99
122
|
* `undefined` (e.g. `badge={n || undefined}`) to hide it when nothing is applied.
|
|
100
123
|
*/
|
|
101
124
|
badge?: ReactNode;
|
|
125
|
+
/**
|
|
126
|
+
* Where the badge goes: `inline` (default, after the label) or `corner` (on the top right
|
|
127
|
+
* corner, in the brand color with a ring of `--hc-chip-badge-ring`, default `bg-page`; HCUI's
|
|
128
|
+
* mobile Meta filter button). A chip with an `icon` and no label is a circle.
|
|
129
|
+
*/
|
|
130
|
+
badgePlacement?: 'inline' | 'corner';
|
|
131
|
+
/**
|
|
132
|
+
* Information, not an action: the chip cannot be pressed (the button is disabled) but keeps
|
|
133
|
+
* its full color instead of dimming (HCUI's Meta era chip when only one era fits the format).
|
|
134
|
+
*/
|
|
135
|
+
informative?: boolean;
|
|
102
136
|
/**
|
|
103
137
|
* Down chevron at the end. On by default when the chip opens a popup (`aria-haspopup`,
|
|
104
138
|
* which `Menu` and `Popover` give their trigger); `aria-expanded="true"` draws the ring.
|
|
@@ -127,7 +161,7 @@ export type ChipProps = ChipBaseProps & ({
|
|
|
127
161
|
* trigger it takes a `badge` with the number of values applied, `applied`, and the
|
|
128
162
|
* chevron and ring of an open popup; `onClear` adds a remove button.
|
|
129
163
|
*/
|
|
130
|
-
export declare const Chip:
|
|
164
|
+
export declare const Chip: ForwardRefExoticComponent<ChipProps & RefAttributes<HTMLButtonElement>>;
|
|
131
165
|
export interface FilterBarProps extends HTMLAttributes<HTMLDivElement> {
|
|
132
166
|
/** Accessible name of the group (e.g. "Filtros"). */
|
|
133
167
|
label: string;
|
|
@@ -147,13 +181,25 @@ export interface FilterBarProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
147
181
|
density?: 'comfortable' | 'compact';
|
|
148
182
|
/** A band that sticks to the top of the scrolling panel, with the surface fill and 8px above and below (HCUI's desktop filter bar). The offset is `--hc-filter-bar-top`. */
|
|
149
183
|
sticky?: boolean;
|
|
184
|
+
/**
|
|
185
|
+
* The bar reaches the panel's edges: a negative margin of `--hc-filter-bar-bleed-start` and
|
|
186
|
+
* `--hc-filter-bar-bleed-end` (both default to `--hc-filter-bar-bleed`, else 0) given back as
|
|
187
|
+
* padding, so the content stays in place and a sticky band covers the full width (HCUI's
|
|
188
|
+
* `.desktop-filter-bar`, which content bleeding to the edge passes under).
|
|
189
|
+
*/
|
|
190
|
+
bleed?: boolean;
|
|
191
|
+
/**
|
|
192
|
+
* Class of the row that holds the filters. The row is `position: relative`, so a popup the
|
|
193
|
+
* caller places with `position: absolute` inside it is anchored to the row (HCUI's "Mais filtros").
|
|
194
|
+
*/
|
|
195
|
+
rowClassName?: string;
|
|
150
196
|
}
|
|
151
197
|
/**
|
|
152
198
|
* Layout of a row of filters (`Chip`s) with optional `start`, `end` and `footer` slots.
|
|
153
199
|
* Presentation only: which filters exist, their values, the search rules and persistence
|
|
154
200
|
* are the caller's. A scrolling row bleeds into the page gutter by `--hc-filter-bar-bleed`.
|
|
155
201
|
*/
|
|
156
|
-
export declare const FilterBar:
|
|
202
|
+
export declare const FilterBar: ForwardRefExoticComponent<FilterBarProps & RefAttributes<HTMLDivElement>>;
|
|
157
203
|
export interface FieldProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size'> {
|
|
158
204
|
/** Accessible name. Visible above the field unless `hideLabel` is set. */
|
|
159
205
|
label: string;
|
|
@@ -169,7 +215,7 @@ export interface FieldProps extends Omit<InputHTMLAttributes<HTMLInputElement>,
|
|
|
169
215
|
error?: ReactNode;
|
|
170
216
|
}
|
|
171
217
|
/** Filled pill text field. Value, validation and messages stay with the caller. */
|
|
172
|
-
export declare const Field:
|
|
218
|
+
export declare const Field: ForwardRefExoticComponent<FieldProps & RefAttributes<HTMLInputElement>>;
|
|
173
219
|
export interface SkeletonProps extends HTMLAttributes<HTMLSpanElement> {
|
|
174
220
|
width?: string | number;
|
|
175
221
|
height?: string | number;
|
|
@@ -218,7 +264,7 @@ export type MeterProps = MeterOwnProps & (
|
|
|
218
264
|
* Bar of a value against a limit (`role="meter"`), with an over-the-limit tone. It
|
|
219
265
|
* renders only spans, so it fits inside a button. Placement (absolute, grid) is the caller's.
|
|
220
266
|
*/
|
|
221
|
-
export declare const Meter:
|
|
267
|
+
export declare const Meter: ForwardRefExoticComponent<MeterProps & RefAttributes<HTMLSpanElement>>;
|
|
222
268
|
export interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'type'> {
|
|
223
269
|
/** 20px (touch lists, sheets) or 16px (dense desktop lists). */
|
|
224
270
|
size?: 'sm' | 'md';
|
|
@@ -230,7 +276,7 @@ export interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement
|
|
|
230
276
|
* and `<label>` behave as usual. Wrap it in a `<label>` (the whole row becomes the
|
|
231
277
|
* target) or pass `aria-label`; the caller supplies the text.
|
|
232
278
|
*/
|
|
233
|
-
export declare const Checkbox:
|
|
279
|
+
export declare const Checkbox: ForwardRefExoticComponent<CheckboxProps & RefAttributes<HTMLInputElement>>;
|
|
234
280
|
export interface DialogProps extends Omit<HTMLAttributes<HTMLDialogElement>, 'title' | 'open' | 'onClose' | 'onCancel'> {
|
|
235
281
|
/** Controlled: the dialog shows while `open` is true and plays its exit before unmounting. */
|
|
236
282
|
open: boolean;
|
|
@@ -254,17 +300,17 @@ export interface DialogProps extends Omit<HTMLAttributes<HTMLDialogElement>, 'ti
|
|
|
254
300
|
size?: 'sm' | 'md';
|
|
255
301
|
/** Esc and a backdrop click ask to close. Default true. */
|
|
256
302
|
dismissible?: boolean;
|
|
303
|
+
/** Class of the body that holds the children (and scrolls in `md`), e.g. to reserve the scrollbar's gutter. */
|
|
304
|
+
bodyClassName?: string;
|
|
257
305
|
}
|
|
258
306
|
/**
|
|
259
307
|
* Centered modal dialog on the native `<dialog>` and `showModal()`: the browser
|
|
260
308
|
* keeps it in the top layer, makes the rest of the page inert and traps Tab.
|
|
261
309
|
* The caller owns `open` and the texts; the dialog only asks to close.
|
|
262
310
|
*/
|
|
263
|
-
export declare const Dialog:
|
|
311
|
+
export declare const Dialog: ForwardRefExoticComponent<DialogProps & RefAttributes<HTMLDialogElement>>;
|
|
264
312
|
export type SheetPresentation = 'bottom' | 'center' | 'auto';
|
|
265
|
-
|
|
266
|
-
/** Accessible name of the close button, which every sheet shows. */
|
|
267
|
-
closeLabel: string;
|
|
313
|
+
interface SheetBaseProps extends Omit<DialogProps, 'size' | 'actions' | 'description' | 'closeLabel' | 'title'> {
|
|
268
314
|
/** Slot under the scrolling body, for the buttons (Clear | Done). */
|
|
269
315
|
footer?: ReactNode;
|
|
270
316
|
/**
|
|
@@ -276,6 +322,25 @@ export interface SheetProps extends Omit<DialogProps, 'size' | 'actions' | 'desc
|
|
|
276
322
|
/** Maximum width of the centered panel, in px. Default 440. */
|
|
277
323
|
width?: number;
|
|
278
324
|
}
|
|
325
|
+
/**
|
|
326
|
+
* `Sheet` props. By default the sheet has a header with the title (its accessible name) and a
|
|
327
|
+
* close button. `header={false}` drops both: the content brings its own heading and floating
|
|
328
|
+
* close button (HCUI's unit sheet), and `aria-label` names the dialog. The body then has no
|
|
329
|
+
* padding, and at the bottom the grabber (drawn above the content) covers its top 16px.
|
|
330
|
+
*/
|
|
331
|
+
export type SheetProps = SheetBaseProps & ({
|
|
332
|
+
header?: true;
|
|
333
|
+
/** Visible heading; it names the sheet. */
|
|
334
|
+
title: ReactNode;
|
|
335
|
+
/** Accessible name of the close button, which every sheet with a header shows. */
|
|
336
|
+
closeLabel: string;
|
|
337
|
+
} | {
|
|
338
|
+
header: false;
|
|
339
|
+
'aria-label': string;
|
|
340
|
+
title?: never;
|
|
341
|
+
closeLabel?: never;
|
|
342
|
+
closeIcon?: never;
|
|
343
|
+
});
|
|
279
344
|
/**
|
|
280
345
|
* Modal sheet on the `Dialog` base (native `<dialog>`, `showModal()`): the same focus,
|
|
281
346
|
* Tab trap, Esc, focus return, scroll lock, stacking and controlled `open`/`onClose`.
|
|
@@ -283,7 +348,7 @@ export interface SheetProps extends Omit<DialogProps, 'size' | 'actions' | 'desc
|
|
|
283
348
|
* flick) and drag up from the grabber or header to full height; content that has
|
|
284
349
|
* scrolled down scrolls back before the sheet moves.
|
|
285
350
|
*/
|
|
286
|
-
export declare const Sheet:
|
|
351
|
+
export declare const Sheet: ForwardRefExoticComponent<SheetProps & RefAttributes<HTMLDialogElement>>;
|
|
287
352
|
export interface SheetOption<T extends string> {
|
|
288
353
|
value: T;
|
|
289
354
|
label: ReactNode;
|
|
@@ -315,9 +380,11 @@ export interface SheetChipsProps<T extends string> extends SheetChoiceProps<T> {
|
|
|
315
380
|
label: ReactNode;
|
|
316
381
|
disabled?: boolean;
|
|
317
382
|
}[];
|
|
383
|
+
/** Size of every chip, as `Chip`'s: `md` (default), `sm` or `xs`. */
|
|
384
|
+
size?: ChipProps['size'];
|
|
318
385
|
}
|
|
319
386
|
/** Single-choice group of `Chip`s that wrap (HCUI's SheetChips), for inside a sheet. */
|
|
320
|
-
export declare function SheetChips<T extends string>({ label, options, value, onChange, className, ...props }: SheetChipsProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
387
|
+
export declare function SheetChips<T extends string>({ label, options, value, onChange, size, className, ...props }: SheetChipsProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
321
388
|
export type PopupSide = 'bottom' | 'top';
|
|
322
389
|
export type PopupAlign = 'start' | 'end';
|
|
323
390
|
/** Props a trigger receives: spread them on the element that opens the popup. */
|
|
@@ -368,6 +435,14 @@ export declare function placePopup(trigger: Rect, size: {
|
|
|
368
435
|
side: PopupSide;
|
|
369
436
|
align: PopupAlign;
|
|
370
437
|
};
|
|
438
|
+
/**
|
|
439
|
+
* Where to portal something that floats over `node` (a tip, a tooltip): the open `<dialog>`
|
|
440
|
+
* around it, else `document.body`. A modal dialog (`Dialog`, `Sheet`) is in the top layer and
|
|
441
|
+
* makes the rest of the page inert, so a tip portaled to `body` from inside it would stay
|
|
442
|
+
* behind it and get no touches; inside the dialog it shows above it. `Menu` and `Popover`
|
|
443
|
+
* with `portal` already do this. On the server (no document) it returns null.
|
|
444
|
+
*/
|
|
445
|
+
export declare function portalContainerFor(node: Element | null | undefined): HTMLElement | null;
|
|
371
446
|
export interface MenuProps extends PopupBaseProps, Omit<HTMLAttributes<HTMLDivElement>, 'role' | 'children'> {
|
|
372
447
|
/** Accessible name of the menu (`aria-label`). */
|
|
373
448
|
label: string;
|
|
@@ -381,7 +456,7 @@ export interface MenuProps extends PopupBaseProps, Omit<HTMLAttributes<HTMLDivEl
|
|
|
381
456
|
* typing move between items; Enter/Space choose; Esc closes and returns focus to the
|
|
382
457
|
* trigger; Tab closes and moves on; a press outside closes.
|
|
383
458
|
*/
|
|
384
|
-
export declare const Menu:
|
|
459
|
+
export declare const Menu: ForwardRefExoticComponent<MenuProps & RefAttributes<HTMLDivElement>>;
|
|
385
460
|
interface MenuItemBaseProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'role' | 'onSelect'> {
|
|
386
461
|
/** Decorative icon at the end of the row; pass it already sized (15px in HCUI). */
|
|
387
462
|
icon?: ReactNode;
|
|
@@ -395,7 +470,7 @@ export interface MenuItemProps extends MenuItemBaseProps {
|
|
|
395
470
|
onSelect?: (event: MouseEvent<HTMLButtonElement>) => void;
|
|
396
471
|
}
|
|
397
472
|
/** An action (`menuitem`). It closes the menu; focus returns to the trigger unless the action moved it. */
|
|
398
|
-
export declare const MenuItem:
|
|
473
|
+
export declare const MenuItem: ForwardRefExoticComponent<MenuItemProps & RefAttributes<HTMLButtonElement>>;
|
|
399
474
|
export interface MenuRadioGroupProps<T extends string> extends Omit<HTMLAttributes<HTMLDivElement>, 'role' | 'onChange'> {
|
|
400
475
|
value: T;
|
|
401
476
|
onValueChange: (value: NoInfer<T>) => void;
|
|
@@ -408,7 +483,7 @@ export interface MenuItemRadioProps extends MenuItemBaseProps {
|
|
|
408
483
|
value: string;
|
|
409
484
|
}
|
|
410
485
|
/** A `menuitemradio`: the chosen one is bold with a check. Choosing closes the menu and returns focus to the trigger. */
|
|
411
|
-
export declare const MenuItemRadio:
|
|
486
|
+
export declare const MenuItemRadio: ForwardRefExoticComponent<MenuItemRadioProps & RefAttributes<HTMLButtonElement>>;
|
|
412
487
|
export interface MenuItemCheckboxProps extends MenuItemBaseProps {
|
|
413
488
|
checked: boolean;
|
|
414
489
|
onCheckedChange: (checked: boolean) => void;
|
|
@@ -416,7 +491,7 @@ export interface MenuItemCheckboxProps extends MenuItemBaseProps {
|
|
|
416
491
|
closeOnSelect?: boolean;
|
|
417
492
|
}
|
|
418
493
|
/** A `menuitemcheckbox`: toggles in place, with a check while on. */
|
|
419
|
-
export declare const MenuItemCheckbox:
|
|
494
|
+
export declare const MenuItemCheckbox: ForwardRefExoticComponent<MenuItemCheckboxProps & RefAttributes<HTMLButtonElement>>;
|
|
420
495
|
/** A line between groups of items. */
|
|
421
496
|
export declare function MenuSeparator({ className, ...props }: Omit<HTMLAttributes<HTMLDivElement>, 'role'>): import("react/jsx-runtime").JSX.Element;
|
|
422
497
|
/** Plain text inside the menu, such as a question before a destructive choice. Not focusable. */
|
|
@@ -465,7 +540,7 @@ export interface PopoverProps extends PopupBaseProps, Omit<HTMLAttributes<HTMLDi
|
|
|
465
540
|
* not trapped. The caller supplies the content and its texts. Esc is taken before it
|
|
466
541
|
* reaches the content (so an enclosing Dialog stays open): a field inside cannot use it.
|
|
467
542
|
*/
|
|
468
|
-
export declare const Popover:
|
|
543
|
+
export declare const Popover: ForwardRefExoticComponent<PopoverProps & RefAttributes<HTMLDivElement>>;
|
|
469
544
|
export type TableSortDirection = 'ascending' | 'descending';
|
|
470
545
|
export interface TableColumn<Row> {
|
|
471
546
|
/** Stable id of the column; it is what `sort.key` and `onSort` name. */
|
|
@@ -530,7 +605,7 @@ export interface PageHeaderProps extends Omit<HTMLAttributes<HTMLElement>, 'titl
|
|
|
530
605
|
visuallyHidden?: boolean;
|
|
531
606
|
}
|
|
532
607
|
/** Desktop page header: one line with the title (22px, semibold) and actions at the end. */
|
|
533
|
-
export declare const PageHeader:
|
|
608
|
+
export declare const PageHeader: ForwardRefExoticComponent<PageHeaderProps & RefAttributes<HTMLElement>>;
|
|
534
609
|
export interface PanelHeaderStep {
|
|
535
610
|
label: string;
|
|
536
611
|
/** Goes back to this step. The last step is the current one and is never a button. */
|
|
@@ -569,14 +644,14 @@ export interface PanelHeaderProps extends Omit<HTMLAttributes<HTMLElement>, 'tit
|
|
|
569
644
|
closeIcon?: ReactNode;
|
|
570
645
|
}
|
|
571
646
|
/** Header of a panel or section: title (or a trail), optional eyebrow, subtitle, icon, actions and close button. */
|
|
572
|
-
export declare const PanelHeader:
|
|
647
|
+
export declare const PanelHeader: ForwardRefExoticComponent<PanelHeaderProps & RefAttributes<HTMLElement>>;
|
|
573
648
|
export type ListRowProps = ButtonHTMLAttributes<HTMLButtonElement>;
|
|
574
649
|
/**
|
|
575
650
|
* A tappable list row (HCUI's `list-row` mixin): full width, at least 56px, 8px 16px of padding,
|
|
576
651
|
* a 12px gap between its children, a translucent veil on hover and press and the focus ring inside.
|
|
577
652
|
* The content and its semantics (`aria-pressed`, `role="option"`) are the caller's.
|
|
578
653
|
*/
|
|
579
|
-
export declare const ListRow:
|
|
654
|
+
export declare const ListRow: ForwardRefExoticComponent<ListRowProps & RefAttributes<HTMLButtonElement>>;
|
|
580
655
|
export interface CommandPaletteItem {
|
|
581
656
|
/** Unique among all items. */
|
|
582
657
|
key: string;
|
|
@@ -640,7 +715,7 @@ export interface CommandPaletteProps extends Omit<HTMLAttributes<HTMLDialogEleme
|
|
|
640
715
|
* into view; Enter selects, ⌘/Ctrl+Enter takes the alternative; the pointer activates the
|
|
641
716
|
* item under it. Texts, results and actions come from the caller.
|
|
642
717
|
*/
|
|
643
|
-
export declare const CommandPalette:
|
|
718
|
+
export declare const CommandPalette: ForwardRefExoticComponent<CommandPaletteProps & RefAttributes<HTMLDialogElement>>;
|
|
644
719
|
/**
|
|
645
720
|
* Walks a list of image addresses: starts at the first and moves to the next on
|
|
646
721
|
* each load error. Starts over when the list changes. `src` is `undefined` once
|
|
@@ -682,7 +757,7 @@ export interface MiniDialViewProps {
|
|
|
682
757
|
* The dial summarized in small squares: one column per click, one row per value
|
|
683
758
|
* (speed, attack, defense, damage). The cell size is `--hc-mini-dial-cell` (7px).
|
|
684
759
|
*/
|
|
685
|
-
export declare const MiniDialView:
|
|
760
|
+
export declare const MiniDialView: ForwardRefExoticComponent<MiniDialViewProps & RefAttributes<HTMLSpanElement>>;
|
|
686
761
|
export interface PowerIconViewProps {
|
|
687
762
|
/** Power color (the circle's fill). */
|
|
688
763
|
color: string;
|
|
@@ -693,7 +768,7 @@ export interface PowerIconViewProps {
|
|
|
693
768
|
size?: number;
|
|
694
769
|
}
|
|
695
770
|
/** Power icon: a circle in the power color with the value symbol on top. */
|
|
696
|
-
export declare const PowerIconView:
|
|
771
|
+
export declare const PowerIconView: ForwardRefExoticComponent<PowerIconViewProps & RefAttributes<HTMLSpanElement>>;
|
|
697
772
|
export interface StatGlyphViewProps {
|
|
698
773
|
/** Address of the symbol, already built. */
|
|
699
774
|
src: string;
|
|
@@ -702,7 +777,7 @@ export interface StatGlyphViewProps {
|
|
|
702
777
|
size?: number;
|
|
703
778
|
}
|
|
704
779
|
/** The value symbol alone (no circle), in neutral gray. Used in the dial legend. */
|
|
705
|
-
export declare const StatGlyphView:
|
|
780
|
+
export declare const StatGlyphView: ForwardRefExoticComponent<StatGlyphViewProps & RefAttributes<HTMLImageElement>>;
|
|
706
781
|
export interface SpecialIconViewProps {
|
|
707
782
|
/** Round white background (the image server's `sp/white.svg`), already built. */
|
|
708
783
|
backgroundSrc: string;
|
|
@@ -711,7 +786,7 @@ export interface SpecialIconViewProps {
|
|
|
711
786
|
size?: number;
|
|
712
787
|
}
|
|
713
788
|
/** Special power and trait icon: a white circle with a symbol in the middle. */
|
|
714
|
-
export declare const SpecialIconView:
|
|
789
|
+
export declare const SpecialIconView: ForwardRefExoticComponent<SpecialIconViewProps & RefAttributes<HTMLSpanElement>>;
|
|
715
790
|
export interface EquipmentIconProps {
|
|
716
791
|
size?: number;
|
|
717
792
|
}
|
|
@@ -752,7 +827,7 @@ export interface AvatarViewProps {
|
|
|
752
827
|
* `fallbackSrc` (with `data-fallback` and the muted fill). The image cannot be
|
|
753
828
|
* dragged, selected or opened in a context menu.
|
|
754
829
|
*/
|
|
755
|
-
export declare const AvatarView:
|
|
830
|
+
export declare const AvatarView: ForwardRefExoticComponent<AvatarViewProps & RefAttributes<HTMLImageElement>>;
|
|
756
831
|
export interface SetIconViewProps {
|
|
757
832
|
/** Addresses of the set icon, in the order to try. Empty: renders nothing. */
|
|
758
833
|
sources: readonly string[];
|
|
@@ -761,7 +836,7 @@ export interface SetIconViewProps {
|
|
|
761
836
|
title?: string;
|
|
762
837
|
}
|
|
763
838
|
/** Set icon. Tries each address in order and disappears when none loads. Decorative: the set name is next to it. */
|
|
764
|
-
export declare const SetIconView:
|
|
839
|
+
export declare const SetIconView: ForwardRefExoticComponent<SetIconViewProps & RefAttributes<HTMLImageElement>>;
|
|
765
840
|
/** Value rows of the dial, top to bottom (the top row is the click number). */
|
|
766
841
|
export declare const COMBAT_DIAL_STATS: readonly ["speed", "attack", "defense", "damage"];
|
|
767
842
|
export type CombatDialStat = (typeof COMBAT_DIAL_STATS)[number];
|
|
@@ -888,7 +963,7 @@ export interface CombatDialViewProps {
|
|
|
888
963
|
* printed card, the header with the point values. Hover, touch and keyboard on
|
|
889
964
|
* the cells open the tip through `onTipChange`; the caller draws the tip.
|
|
890
965
|
*/
|
|
891
|
-
export declare const CombatDialView:
|
|
966
|
+
export declare const CombatDialView: ForwardRefExoticComponent<CombatDialViewProps & RefAttributes<HTMLElement>>;
|
|
892
967
|
export declare const PHYSICAL_CARD_WIDTH = 375;
|
|
893
968
|
export declare const PHYSICAL_CARD_HEIGHT = 525;
|
|
894
969
|
export declare const PHYSICAL_CARD_BACK_TABLE_HEIGHT = 440;
|
|
@@ -1225,7 +1300,7 @@ export declare function PhysicalCardFocusView({ label, onClose, children }: Phys
|
|
|
1225
1300
|
* holding to open the focus view and flipping in it, and opens the tips through
|
|
1226
1301
|
* `onTipChange`; drawing the tip, translating and copying are the caller's.
|
|
1227
1302
|
*/
|
|
1228
|
-
export declare const PhysicalCardView:
|
|
1303
|
+
export declare const PhysicalCardView: ForwardRefExoticComponent<PhysicalCardViewProps & RefAttributes<HTMLDivElement>>;
|
|
1229
1304
|
/**
|
|
1230
1305
|
* A faithful port of hcmaps.net's map drawing engine (map.js / tile.js / edge.js /
|
|
1231
1306
|
* wall.js), the same engine HCUnits uses to draw the map's canvas. It reads the
|
|
@@ -1516,7 +1591,7 @@ export interface MapBoardViewProps extends Omit<HTMLAttributes<HTMLDivElement>,
|
|
|
1516
1591
|
* the tooltip shows are the caller's. Other attributes (role, focus, keyboard,
|
|
1517
1592
|
* `aria-*`, `data-*`) go to the container.
|
|
1518
1593
|
*/
|
|
1519
|
-
export declare const MapBoardView:
|
|
1594
|
+
export declare const MapBoardView: ForwardRefExoticComponent<MapBoardViewProps & RefAttributes<HTMLDivElement>>;
|
|
1520
1595
|
export interface MapBoardPlaceholderProps {
|
|
1521
1596
|
/** Read by screen readers while the map loads (e.g. "Loading map"). */
|
|
1522
1597
|
label: string;
|
package/dist/index.js
CHANGED
|
@@ -6,8 +6,8 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
6
6
|
import { cloneElement, createContext, forwardRef, Fragment, useCallback, useContext, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
7
7
|
import { createPortal } from "react-dom";
|
|
8
8
|
import { Fragment as Fragment2, jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
-
function Surface({ tone = "content", radius, className, ...props }) {
|
|
10
|
-
return /* @__PURE__ */ jsx(
|
|
9
|
+
function Surface({ tone = "content", radius, as: Element = "div", className, ...props }) {
|
|
10
|
+
return /* @__PURE__ */ jsx(Element, { ...props, className: ["hc-ui-surface", className].filter(Boolean).join(" "), "data-tone": tone, "data-radius": radius });
|
|
11
11
|
}
|
|
12
12
|
function SegmentedControl({
|
|
13
13
|
label,
|
|
@@ -20,6 +20,7 @@ function SegmentedControl({
|
|
|
20
20
|
indicator = "static",
|
|
21
21
|
equalWidth = false,
|
|
22
22
|
optionWidth,
|
|
23
|
+
optionMinWidth,
|
|
23
24
|
className,
|
|
24
25
|
style,
|
|
25
26
|
...props
|
|
@@ -33,7 +34,8 @@ function SegmentedControl({
|
|
|
33
34
|
const layout = {
|
|
34
35
|
...equal ? { "--hc-segmented-count": options.length } : {},
|
|
35
36
|
...slide ? { "--hc-segmented-index": Math.max(knobIndex, 0) } : {},
|
|
36
|
-
...optionWidth !== void 0 ? { "--hc-segmented-option-width": `${optionWidth}px` } : {}
|
|
37
|
+
...optionWidth !== void 0 ? { "--hc-segmented-option-width": `${optionWidth}px` } : {},
|
|
38
|
+
...optionMinWidth !== void 0 ? { "--hc-segmented-option-min-width": `${optionMinWidth}px` } : {}
|
|
37
39
|
};
|
|
38
40
|
const move = (index, key) => {
|
|
39
41
|
if (!["ArrowRight", "ArrowLeft", "ArrowDown", "ArrowUp", "Home", "End"].includes(key)) return false;
|
|
@@ -103,7 +105,7 @@ function SegmentedControl({
|
|
|
103
105
|
);
|
|
104
106
|
}
|
|
105
107
|
var classes = (...names) => names.filter(Boolean).join(" ");
|
|
106
|
-
var Button = forwardRef(function Button2({ variant = "secondary", size = "md", icon, iconEnd, fullWidth = false, loading = false, wrap = false, type = "button", className, children, onClick, ...props }, ref) {
|
|
108
|
+
var Button = forwardRef(function Button2({ variant = "secondary", tone = "default", size = "md", icon, iconEnd, fullWidth = false, loading = false, wrap = false, type = "button", className, children, onClick, ...props }, ref) {
|
|
107
109
|
const handleClick = (event) => {
|
|
108
110
|
if (loading) event.preventDefault();
|
|
109
111
|
else onClick?.(event);
|
|
@@ -120,6 +122,7 @@ var Button = forwardRef(function Button2({ variant = "secondary", size = "md", i
|
|
|
120
122
|
"aria-disabled": loading || props["aria-disabled"],
|
|
121
123
|
"data-variant": variant,
|
|
122
124
|
"data-size": size,
|
|
125
|
+
"data-tone": tone === "default" ? void 0 : tone,
|
|
123
126
|
"data-full-width": fullWidth || void 0,
|
|
124
127
|
"data-wrap": wrap || void 0,
|
|
125
128
|
children: [
|
|
@@ -153,31 +156,33 @@ var glyph = (size, d) => /* @__PURE__ */ jsx("svg", { width: size, height: size,
|
|
|
153
156
|
var CHEVRON_DOWN = "M6 9L12 15L18 9";
|
|
154
157
|
var XMARK = "M6.75827 17.2426L12.0009 12M17.2435 6.75736L12.0009 12M12.0009 12L6.75827 6.75736M12.0009 12L17.2435 17.2426";
|
|
155
158
|
var visible = (node) => node !== void 0 && node !== null && node !== false && node !== "";
|
|
156
|
-
var Chip = forwardRef(function Chip2({ selected, icon, size = "md", variant = "outline", applied = false, count, badge, chevron, onClear, clearLabel, type = "button", className, children, ...props }, ref) {
|
|
159
|
+
var Chip = forwardRef(function Chip2({ selected, icon, size = "md", variant = "outline", applied = false, count, badge, badgePlacement = "inline", informative = false, chevron, onClear, clearLabel, type = "button", className, children, ...props }, ref) {
|
|
157
160
|
const popup = props["aria-haspopup"];
|
|
158
161
|
const withChevron = chevron ?? (popup !== void 0 && popup !== false && popup !== "false");
|
|
159
162
|
const look = {
|
|
160
163
|
"data-size": size === "md" ? void 0 : size,
|
|
161
164
|
"data-variant": variant === "outline" ? void 0 : variant,
|
|
162
|
-
"data-applied": applied || void 0
|
|
165
|
+
"data-applied": applied || void 0,
|
|
166
|
+
"data-icon-only": icon && !visible(children) || void 0,
|
|
167
|
+
"data-informative": informative || void 0
|
|
163
168
|
};
|
|
164
169
|
const content = /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
165
170
|
icon && /* @__PURE__ */ jsx("span", { className: "hc-ui-chip__icon", "aria-hidden": "true", children: icon }),
|
|
166
171
|
children,
|
|
167
172
|
visible(count) && /* @__PURE__ */ jsx("span", { className: "hc-ui-chip__count", children: count }),
|
|
168
|
-
visible(badge) && /* @__PURE__ */ jsx("span", { className: "hc-ui-chip__badge", children: badge }),
|
|
173
|
+
visible(badge) && /* @__PURE__ */ jsx("span", { className: "hc-ui-chip__badge", "data-placement": badgePlacement === "corner" ? "corner" : void 0, children: badge }),
|
|
169
174
|
withChevron && /* @__PURE__ */ jsx("span", { className: "hc-ui-chip__chevron", "aria-hidden": "true", children: glyph(size === "xs" ? 12 : 14, CHEVRON_DOWN) })
|
|
170
175
|
] });
|
|
171
176
|
if (!onClear) {
|
|
172
|
-
return /* @__PURE__ */ jsx("button", { ...props, ref, type, "aria-pressed": selected, className: classes("hc-ui-chip", className), ...look, children: content });
|
|
177
|
+
return /* @__PURE__ */ jsx("button", { ...props, ...informative ? { disabled: true } : {}, ref, type, "aria-pressed": selected, className: classes("hc-ui-chip", className), ...look, children: content });
|
|
173
178
|
}
|
|
174
179
|
const { style, id, onClick, disabled, ...rest } = props;
|
|
175
180
|
return /* @__PURE__ */ jsxs("span", { className: classes("hc-ui-chip", className), style, ...look, "data-clearable": "", "data-selected": selected || void 0, "data-disabled": disabled || void 0, children: [
|
|
176
|
-
onClick ? /* @__PURE__ */ jsx("button", { ...rest, id, ref, type, disabled, "aria-pressed": selected, className: "hc-ui-chip__main", onClick, children: content }) : /* @__PURE__ */ jsx("span", { id, className: "hc-ui-chip__main", children: content }),
|
|
181
|
+
onClick ? /* @__PURE__ */ jsx("button", { ...rest, id, ref, type, disabled: informative || disabled, "aria-pressed": selected, className: "hc-ui-chip__main", onClick, children: content }) : /* @__PURE__ */ jsx("span", { id, className: "hc-ui-chip__main", children: content }),
|
|
177
182
|
/* @__PURE__ */ jsx("button", { type: "button", className: "hc-ui-chip__clear", "aria-label": clearLabel, title: clearLabel, disabled, onClick: onClear, children: glyph(12, XMARK) })
|
|
178
183
|
] });
|
|
179
184
|
});
|
|
180
|
-
var FilterBar = forwardRef(function FilterBar2({ label, start, end, footer, layout = "auto", density = "comfortable", sticky = false, className, children, ...props }, ref) {
|
|
185
|
+
var FilterBar = forwardRef(function FilterBar2({ label, start, end, footer, layout = "auto", density = "comfortable", sticky = false, bleed = false, rowClassName, className, children, ...props }, ref) {
|
|
181
186
|
return /* @__PURE__ */ jsxs(
|
|
182
187
|
"div",
|
|
183
188
|
{
|
|
@@ -189,10 +194,11 @@ var FilterBar = forwardRef(function FilterBar2({ label, start, end, footer, layo
|
|
|
189
194
|
"data-layout": layout,
|
|
190
195
|
"data-density": density === "comfortable" ? void 0 : density,
|
|
191
196
|
"data-sticky": sticky || void 0,
|
|
197
|
+
"data-bleed": bleed || void 0,
|
|
192
198
|
children: [
|
|
193
199
|
/* @__PURE__ */ jsxs("div", { className: "hc-ui-filter-bar__line", children: [
|
|
194
200
|
start && /* @__PURE__ */ jsx("div", { className: "hc-ui-filter-bar__start", children: start }),
|
|
195
|
-
/* @__PURE__ */ jsx("div", { className: "hc-ui-filter-bar__row", children }),
|
|
201
|
+
/* @__PURE__ */ jsx("div", { className: classes("hc-ui-filter-bar__row", rowClassName), children }),
|
|
196
202
|
end && /* @__PURE__ */ jsx("div", { className: "hc-ui-filter-bar__end", children: end })
|
|
197
203
|
] }),
|
|
198
204
|
footer && /* @__PURE__ */ jsx("div", { className: "hc-ui-filter-bar__footer", children: footer })
|
|
@@ -323,7 +329,7 @@ var outside = (element, x, y) => {
|
|
|
323
329
|
const box = element.getBoundingClientRect();
|
|
324
330
|
return x < box.left || x > box.right || y < box.top || y > box.bottom;
|
|
325
331
|
};
|
|
326
|
-
var
|
|
332
|
+
var DialogBase = forwardRef(function Dialog({
|
|
327
333
|
open,
|
|
328
334
|
onClose,
|
|
329
335
|
title,
|
|
@@ -334,6 +340,8 @@ var Dialog = forwardRef(function Dialog2({
|
|
|
334
340
|
closeIcon,
|
|
335
341
|
size = "md",
|
|
336
342
|
dismissible = true,
|
|
343
|
+
bodyClassName,
|
|
344
|
+
headerless = false,
|
|
337
345
|
className,
|
|
338
346
|
onClick,
|
|
339
347
|
onPointerDown,
|
|
@@ -348,6 +356,7 @@ var Dialog = forwardRef(function Dialog2({
|
|
|
348
356
|
}, [ref]);
|
|
349
357
|
const id = useId();
|
|
350
358
|
const titleId = `${id}-title`;
|
|
359
|
+
const bodyId = `${id}-body`;
|
|
351
360
|
const descriptionId = description ? `${id}-description` : void 0;
|
|
352
361
|
const [mounted, setMounted] = useState(open);
|
|
353
362
|
const [closing, setClosing] = useState(false);
|
|
@@ -362,7 +371,7 @@ var Dialog = forwardRef(function Dialog2({
|
|
|
362
371
|
});
|
|
363
372
|
const keepFocus = useRef(null);
|
|
364
373
|
const handleMount = useCallback(() => {
|
|
365
|
-
const dialog = document.getElementById(titleId)?.closest("dialog");
|
|
374
|
+
const dialog = (document.getElementById(titleId) ?? document.getElementById(bodyId))?.closest("dialog");
|
|
366
375
|
if (!dialog) return () => {
|
|
367
376
|
};
|
|
368
377
|
const trigger = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
@@ -381,7 +390,7 @@ var Dialog = forwardRef(function Dialog2({
|
|
|
381
390
|
if (lost && !dialog.open && trigger?.isConnected) trigger.focus({ preventScroll: true });
|
|
382
391
|
});
|
|
383
392
|
};
|
|
384
|
-
}, [titleId]);
|
|
393
|
+
}, [titleId, bodyId]);
|
|
385
394
|
useEffect(() => {
|
|
386
395
|
const dialog = dialogRef.current;
|
|
387
396
|
if (!closing || !dialog) return;
|
|
@@ -428,7 +437,7 @@ var Dialog = forwardRef(function Dialog2({
|
|
|
428
437
|
if (fromBackdrop && latest.current.dismissible && !latest.current.closing) latest.current.onClose();
|
|
429
438
|
};
|
|
430
439
|
if (!mounted) return null;
|
|
431
|
-
const hasBody = Boolean(description) || children !== void 0 && children !== null && children !== false;
|
|
440
|
+
const hasBody = headerless || Boolean(description) || children !== void 0 && children !== null && children !== false;
|
|
432
441
|
return /* @__PURE__ */ jsxs(
|
|
433
442
|
"dialog",
|
|
434
443
|
{
|
|
@@ -437,7 +446,8 @@ var Dialog = forwardRef(function Dialog2({
|
|
|
437
446
|
className: classes("hc-ui-dialog", className),
|
|
438
447
|
"data-size": size,
|
|
439
448
|
"data-closing": closing || void 0,
|
|
440
|
-
"
|
|
449
|
+
"data-headerless": headerless || void 0,
|
|
450
|
+
"aria-labelledby": headerless ? void 0 : titleId,
|
|
441
451
|
"aria-describedby": classes(descriptionId, describedBy) || void 0,
|
|
442
452
|
onCancel: handleCancel,
|
|
443
453
|
onClose: handleNativeClose,
|
|
@@ -445,11 +455,11 @@ var Dialog = forwardRef(function Dialog2({
|
|
|
445
455
|
onClick: handleClick,
|
|
446
456
|
children: [
|
|
447
457
|
/* @__PURE__ */ jsx(DialogMount, { onMount: handleMount }),
|
|
448
|
-
/* @__PURE__ */ jsxs("div", { className: "hc-ui-dialog__header", children: [
|
|
458
|
+
!headerless && /* @__PURE__ */ jsxs("div", { className: "hc-ui-dialog__header", children: [
|
|
449
459
|
/* @__PURE__ */ jsx("h2", { className: "hc-ui-dialog__title", id: titleId, children: title }),
|
|
450
460
|
closeLabel && /* @__PURE__ */ jsx(IconButton, { className: "hc-ui-dialog__close", label: closeLabel, icon: closeIcon ?? closeGlyph, size: "sm", tone: "secondary", onClick: () => latest.current.onClose() })
|
|
451
461
|
] }),
|
|
452
|
-
hasBody && /* @__PURE__ */ jsxs("div", { className: "hc-ui-dialog__body", children: [
|
|
462
|
+
hasBody && /* @__PURE__ */ jsxs("div", { className: classes("hc-ui-dialog__body", bodyClassName), id: headerless ? bodyId : void 0, children: [
|
|
453
463
|
description && /* @__PURE__ */ jsx("p", { className: "hc-ui-dialog__description", id: descriptionId, children: description }),
|
|
454
464
|
children
|
|
455
465
|
] }),
|
|
@@ -458,8 +468,9 @@ var Dialog = forwardRef(function Dialog2({
|
|
|
458
468
|
}
|
|
459
469
|
);
|
|
460
470
|
});
|
|
471
|
+
var Dialog2 = DialogBase;
|
|
461
472
|
var SHEET_EASE = "cubic-bezier(0.32, 0.72, 0, 1)";
|
|
462
|
-
var NO_DRAG = 'input, textarea, select, [contenteditable="true"], [data-hc-sheet-nodrag]';
|
|
473
|
+
var NO_DRAG = 'input, textarea, select, [contenteditable="true"], [data-hc-sheet-nodrag], .hc-ui-portal';
|
|
463
474
|
function useSheetDrag(sheet, latest) {
|
|
464
475
|
useEffect(() => {
|
|
465
476
|
const el = sheet;
|
|
@@ -591,7 +602,7 @@ function useSheetDrag(sheet, latest) {
|
|
|
591
602
|
};
|
|
592
603
|
}, [sheet, latest]);
|
|
593
604
|
}
|
|
594
|
-
var Sheet = forwardRef(function Sheet2({ presentation = "auto", width = 440, footer, dismissible = true, onClose, className, style, ...props }, ref) {
|
|
605
|
+
var Sheet = forwardRef(function Sheet2({ presentation = "auto", width = 440, footer, dismissible = true, header = true, onClose, className, style, ...props }, ref) {
|
|
595
606
|
const [node, setNode] = useState(null);
|
|
596
607
|
const setRef = useCallback((element) => {
|
|
597
608
|
setNode(element);
|
|
@@ -604,7 +615,7 @@ var Sheet = forwardRef(function Sheet2({ presentation = "auto", width = 440, foo
|
|
|
604
615
|
useSheetDrag(node, latest);
|
|
605
616
|
const sized = width === 440 ? style : { ...style, "--hc-sheet-width": `${width}px` };
|
|
606
617
|
return /* @__PURE__ */ jsx(
|
|
607
|
-
|
|
618
|
+
DialogBase,
|
|
608
619
|
{
|
|
609
620
|
...props,
|
|
610
621
|
ref: setRef,
|
|
@@ -612,6 +623,7 @@ var Sheet = forwardRef(function Sheet2({ presentation = "auto", width = 440, foo
|
|
|
612
623
|
actions: footer,
|
|
613
624
|
dismissible,
|
|
614
625
|
onClose,
|
|
626
|
+
headerless: !header,
|
|
615
627
|
className: classes("hc-ui-sheet", className),
|
|
616
628
|
style: sized,
|
|
617
629
|
"data-presentation": presentation
|
|
@@ -676,7 +688,7 @@ function SheetOptions({ label, options, value, onChange, className, ...props })
|
|
|
676
688
|
);
|
|
677
689
|
}) });
|
|
678
690
|
}
|
|
679
|
-
function SheetChips({ label, options, value, onChange, className, ...props }) {
|
|
691
|
+
function SheetChips({ label, options, value, onChange, size = "md", className, ...props }) {
|
|
680
692
|
const item = useRovingRadios(options, value);
|
|
681
693
|
return /* @__PURE__ */ jsx("div", { ...props, className: classes("hc-ui-sheet-chips", className), role: "radiogroup", "aria-label": label, children: options.map((option, index) => /* @__PURE__ */ jsx(
|
|
682
694
|
"button",
|
|
@@ -687,6 +699,7 @@ function SheetChips({ label, options, value, onChange, className, ...props }) {
|
|
|
687
699
|
"aria-checked": option.value === value,
|
|
688
700
|
disabled: option.disabled,
|
|
689
701
|
className: "hc-ui-chip",
|
|
702
|
+
"data-size": size === "md" ? void 0 : size,
|
|
690
703
|
onClick: () => onChange(option.value),
|
|
691
704
|
children: option.label
|
|
692
705
|
},
|
|
@@ -716,6 +729,10 @@ function placePopup(trigger, size, boundary, side, align) {
|
|
|
716
729
|
const finalAlign = !fits(align) && fits(align === "end" ? "start" : "end") ? align === "end" ? "start" : "end" : align;
|
|
717
730
|
return { side: finalSide, align: finalAlign };
|
|
718
731
|
}
|
|
732
|
+
function portalContainerFor(node) {
|
|
733
|
+
if (typeof document === "undefined") return null;
|
|
734
|
+
return node?.closest("dialog[open]") ?? document.body;
|
|
735
|
+
}
|
|
719
736
|
var layers = [];
|
|
720
737
|
function themeOf(element) {
|
|
721
738
|
const scoped = element?.closest("[data-theme]")?.getAttribute("data-theme");
|
|
@@ -761,7 +778,7 @@ function usePopup({ kind, trigger, open: openProp, defaultOpen = false, onOpenCh
|
|
|
761
778
|
setContainer(null);
|
|
762
779
|
return;
|
|
763
780
|
}
|
|
764
|
-
const element = portal instanceof HTMLElement ? portal : triggerRef.current
|
|
781
|
+
const element = portal instanceof HTMLElement ? portal : portalContainerFor(triggerRef.current) ?? document.body;
|
|
765
782
|
setContainer({ element, theme: theme ?? themeOf(triggerRef.current) });
|
|
766
783
|
}, [open, portal, theme]);
|
|
767
784
|
const place = useCallback(() => {
|
|
@@ -3233,7 +3250,7 @@ export {
|
|
|
3233
3250
|
Chip,
|
|
3234
3251
|
CombatDialView,
|
|
3235
3252
|
CommandPalette,
|
|
3236
|
-
Dialog,
|
|
3253
|
+
Dialog2 as Dialog,
|
|
3237
3254
|
EquipmentIcon,
|
|
3238
3255
|
Field,
|
|
3239
3256
|
FilterBar,
|
|
@@ -3313,6 +3330,7 @@ export {
|
|
|
3313
3330
|
physicalCardTiltStyles,
|
|
3314
3331
|
pickMapScene,
|
|
3315
3332
|
placePopup,
|
|
3333
|
+
portalContainerFor,
|
|
3316
3334
|
renderMapThumbnail,
|
|
3317
3335
|
requestPhysicalCardMotionAccess,
|
|
3318
3336
|
useImageChain,
|
package/dist/styles.css
CHANGED
|
@@ -29,6 +29,13 @@
|
|
|
29
29
|
border-radius: var(--hc-radius-lg);
|
|
30
30
|
box-shadow: var(--hc-shadow-card);
|
|
31
31
|
}
|
|
32
|
+
/* Muted: the card with the `bg-muted-2` fill (HCUI's `surface` mixin over `bg-muted-2`, as the
|
|
33
|
+
`SheetOptions` card and HCUI's action lists in sheets). */
|
|
34
|
+
[data-hc-ds] .hc-ui-surface[data-tone='muted'] {
|
|
35
|
+
background: var(--hc-color-bg-muted-2);
|
|
36
|
+
border-radius: var(--hc-radius-lg);
|
|
37
|
+
box-shadow: var(--hc-shadow-card);
|
|
38
|
+
}
|
|
32
39
|
[data-hc-ds] .hc-ui-surface:not([data-tone='page'], [data-tone='main'])[data-radius='md'] { border-radius: var(--hc-radius-md); }
|
|
33
40
|
[data-hc-ds] .hc-ui-surface:not([data-tone='page'], [data-tone='main'])[data-radius='lg'] { border-radius: var(--hc-radius-lg); }
|
|
34
41
|
[data-hc-ds] .hc-ui-surface:not([data-tone='page'], [data-tone='main'])[data-radius='xl'] { border-radius: var(--hc-radius-xl); }
|
|
@@ -53,7 +60,8 @@
|
|
|
53
60
|
align-items: center;
|
|
54
61
|
justify-content: center;
|
|
55
62
|
gap: 6px;
|
|
56
|
-
|
|
63
|
+
/* `optionMinWidth` sets the custom property; without it, 0 as before. */
|
|
64
|
+
min-width: var(--hc-segmented-option-min-width, 0);
|
|
57
65
|
min-height: 38px;
|
|
58
66
|
margin: 0;
|
|
59
67
|
padding: 0 var(--hc-space-3);
|
|
@@ -224,6 +232,11 @@
|
|
|
224
232
|
[data-hc-ds] .hc-ui-button[data-variant='primary'] { color: var(--hc-color-text-inverse); background-color: var(--hc-color-accent); }
|
|
225
233
|
[data-hc-ds] .hc-ui-button[data-variant='outline'] { background-color: transparent; box-shadow: inset 0 0 0 1px var(--hc-color-border-strong); }
|
|
226
234
|
[data-hc-ds] .hc-ui-button[data-variant='danger'] { color: var(--hc-color-text-on-danger); background-color: var(--hc-color-bg-danger); }
|
|
235
|
+
/* Ghost: no fill, only the veil; `tone="danger"` is HCUI's danger in text only (team-save-menu__btn--danger). */
|
|
236
|
+
[data-hc-ds] .hc-ui-button[data-variant='ghost'] { background-color: transparent; }
|
|
237
|
+
[data-hc-ds] .hc-ui-button:is([data-variant='secondary'], [data-variant='outline'], [data-variant='ghost'])[data-tone='danger'] { color: var(--hc-color-danger); }
|
|
238
|
+
/* An open popup trigger: the 1.5px ring in the text color, as Chip (HCUI's Importar, Entrar and Convidar). */
|
|
239
|
+
[data-hc-ds] .hc-ui-button:is([data-variant='secondary'], [data-variant='outline'], [data-variant='ghost'])[aria-haspopup]:not([aria-haspopup='false'])[aria-expanded='true'] { box-shadow: inset 0 0 0 1.5px var(--hc-color-text-primary); }
|
|
227
240
|
[data-hc-ds] .hc-ui-button[data-size='sm'] { min-height: var(--hc-control-height-chip); padding: 0 var(--hc-space-4); font-size: var(--hc-font-size-sm); }
|
|
228
241
|
[data-hc-ds] .hc-ui-button[data-size='lg'] { min-height: var(--hc-control-height-lg); padding: 0 var(--hc-space-6); font-size: var(--hc-font-size-base); }
|
|
229
242
|
[data-hc-ds] .hc-ui-button[data-full-width] { width: 100%; }
|
|
@@ -257,9 +270,12 @@
|
|
|
257
270
|
}
|
|
258
271
|
[data-hc-ds] .hc-ui-icon-button[data-size='sm'] { width: 36px; height: 36px; overflow: visible; }
|
|
259
272
|
[data-hc-ds] .hc-ui-icon-button[data-size='lg'] { width: 44px; height: 44px; }
|
|
273
|
+
[data-hc-ds] .hc-ui-icon-button[data-size='xs'] { width: 28px; height: 28px; overflow: visible; }
|
|
260
274
|
[data-hc-ds] .hc-ui-icon-button[data-tone='secondary'] { color: var(--hc-color-text-secondary); }
|
|
261
|
-
|
|
275
|
+
[data-hc-ds] .hc-ui-icon-button[data-tone='muted'] { color: var(--hc-color-text-muted); }
|
|
276
|
+
/* 36 and 28px keep a 44px touch target; the veil stays clipped to the circle. */
|
|
262
277
|
[data-hc-ds] .hc-ui-icon-button[data-size='sm']::before { content: ''; position: absolute; inset: -4px; }
|
|
278
|
+
[data-hc-ds] .hc-ui-icon-button[data-size='xs']::before { content: ''; position: absolute; inset: -8px; }
|
|
263
279
|
/* Fills: surface (HCUI's mobile theme button: surface, card ring and shadow) and ghost
|
|
264
280
|
(HCUI's desktop utilities: no fill, muted fill and primary text on hover). */
|
|
265
281
|
[data-hc-ds] .hc-ui-icon-button[data-variant='surface'] { background-color: var(--hc-color-bg-surface); box-shadow: var(--hc-shadow-card); }
|
|
@@ -268,6 +284,8 @@
|
|
|
268
284
|
@media (hover: hover) {
|
|
269
285
|
[data-hc-ds] .hc-ui-icon-button[data-variant='ghost']:hover:not(:disabled, [aria-pressed='true']) { color: var(--hc-color-text-primary); background-color: var(--hc-color-bg-muted); }
|
|
270
286
|
}
|
|
287
|
+
/* An open popup trigger keeps the hover look, with a mouse or not (HCUI's ⋯ menus). */
|
|
288
|
+
[data-hc-ds] .hc-ui-icon-button[data-variant='ghost'][aria-haspopup]:not([aria-haspopup='false'])[aria-expanded='true']:not([aria-pressed='true']) { color: var(--hc-color-text-primary); background-color: var(--hc-color-bg-muted); }
|
|
271
289
|
[data-hc-ds] .hc-ui-icon-button[data-shape='rounded'] { border-radius: var(--hc-radius-sm); }
|
|
272
290
|
[data-hc-ds] .hc-ui-icon-button[aria-pressed='true'] { color: var(--hc-color-text-inverse); background-color: var(--hc-color-accent); }
|
|
273
291
|
/* iconKey: the new icon turns in (HCUI's theme sun and moon). */
|
|
@@ -381,6 +399,33 @@
|
|
|
381
399
|
[data-hc-ds] .hc-ui-chip[data-size='xs']:is([aria-pressed='true'], [aria-checked='true'], [data-selected]):hover { color: var(--hc-color-text-on-contrast); background-color: var(--hc-color-bg-contrast); }
|
|
382
400
|
[data-hc-ds] .hc-ui-chip:is([aria-pressed='true'], [aria-checked='true'], [data-selected]) .hc-ui-chip__count { color: inherit; }
|
|
383
401
|
[data-hc-ds] .hc-ui-chip[data-selected] .hc-ui-chip__clear { color: inherit; }
|
|
402
|
+
/* Muted: gray fill without ring (HCUI's search conditions, .search-page__cond). */
|
|
403
|
+
[data-hc-ds] .hc-ui-chip[data-variant='muted'] { background-color: var(--hc-color-bg-muted); box-shadow: none; }
|
|
404
|
+
/* Removable at md and sm: the whole height is the main button, and the 26px × sits 5px from the
|
|
405
|
+
end, concentric with the pill's curve ((36 - 26) / 2), in the muted color. */
|
|
406
|
+
[data-hc-ds] .hc-ui-chip[data-clearable][data-variant='muted']:not([data-size='xs']) { gap: 0; padding: 0 5px 0 0; }
|
|
407
|
+
[data-hc-ds] .hc-ui-chip[data-clearable][data-variant='muted']:not([data-size='xs']) .hc-ui-chip__main { align-self: stretch; padding: 0 var(--hc-space-1) 0 14px; }
|
|
408
|
+
[data-hc-ds] .hc-ui-chip[data-clearable][data-variant='muted'][data-size='sm'] .hc-ui-chip__main { padding-left: var(--hc-space-3); }
|
|
409
|
+
[data-hc-ds] .hc-ui-chip[data-clearable][data-variant='muted']:not([data-size='xs']) .hc-ui-chip__clear { width: 26px; height: 26px; color: var(--hc-color-text-muted); }
|
|
410
|
+
[data-hc-ds] .hc-ui-chip[data-clearable][data-variant='muted']:not([data-size='xs']) .hc-ui-chip__clear svg { width: 14px; height: 14px; }
|
|
411
|
+
/* Only an icon: a circle as tall as the chip. */
|
|
412
|
+
[data-hc-ds] .hc-ui-chip[data-icon-only] { width: var(--hc-control-height-chip); padding: 0; }
|
|
413
|
+
[data-hc-ds] .hc-ui-chip[data-icon-only][data-size='xs'] { width: 26px; }
|
|
414
|
+
/* Corner badge: on the top right corner, brand fill, a ring of the page around it (HCUI's .meta-fchip__count). */
|
|
415
|
+
[data-hc-ds] .hc-ui-chip__badge[data-placement='corner'] {
|
|
416
|
+
position: absolute;
|
|
417
|
+
top: -4px;
|
|
418
|
+
right: -4px;
|
|
419
|
+
padding: 0 var(--hc-space-1);
|
|
420
|
+
color: var(--hc-color-text-inverse);
|
|
421
|
+
background-color: var(--hc-color-brand);
|
|
422
|
+
box-shadow: 0 0 0 2px var(--hc-chip-badge-ring, var(--hc-color-bg-page));
|
|
423
|
+
font-family: var(--hc-font-mono);
|
|
424
|
+
font-weight: var(--hc-font-weight-semibold);
|
|
425
|
+
animation: hc-ui-check-in 260ms var(--hc-ease-pop);
|
|
426
|
+
}
|
|
427
|
+
/* Informative: it cannot be pressed (disabled) but keeps its full color. */
|
|
428
|
+
[data-hc-ds] .hc-ui-chip[data-informative]:disabled { opacity: 1; cursor: default; }
|
|
384
429
|
|
|
385
430
|
/* FilterBar — a row of filters with start, end and footer slots (HCUI's .desktop-filter-bar,
|
|
386
431
|
.desktop-filter-bar--sheet and .quick-filters). Placement stays with the caller. */
|
|
@@ -395,7 +440,13 @@
|
|
|
395
440
|
[data-hc-ds] .hc-ui-filter-bar__line { display: flex; align-items: center; gap: var(--hc-space-2); min-width: 0; }
|
|
396
441
|
[data-hc-ds] :is(.hc-ui-filter-bar__start, .hc-ui-filter-bar__end) { display: flex; flex: 0 0 auto; align-items: center; gap: var(--hc-space-2); }
|
|
397
442
|
[data-hc-ds] .hc-ui-filter-bar__end { margin-inline-start: auto; }
|
|
398
|
-
|
|
443
|
+
/* Bleed: the bar reaches the panel's edges and gives the space back as padding. */
|
|
444
|
+
[data-hc-ds] .hc-ui-filter-bar[data-bleed] {
|
|
445
|
+
margin-inline: calc(-1 * var(--hc-filter-bar-bleed-start, var(--hc-filter-bar-bleed, 0px))) calc(-1 * var(--hc-filter-bar-bleed-end, var(--hc-filter-bar-bleed, 0px)));
|
|
446
|
+
padding-inline: var(--hc-filter-bar-bleed-start, var(--hc-filter-bar-bleed, 0px)) var(--hc-filter-bar-bleed-end, var(--hc-filter-bar-bleed, 0px));
|
|
447
|
+
}
|
|
448
|
+
/* The row anchors what the caller places in it with position: absolute (a popup). */
|
|
449
|
+
[data-hc-ds] .hc-ui-filter-bar__row { position: relative; display: flex; flex: 1 1 auto; flex-wrap: wrap; align-items: center; gap: var(--hc-space-2); min-width: 0; }
|
|
399
450
|
[data-hc-ds] .hc-ui-filter-bar[data-density='compact'] .hc-ui-filter-bar__row { gap: var(--hc-space-1); }
|
|
400
451
|
[data-hc-ds] .hc-ui-filter-bar__footer { margin-top: var(--hc-space-2); }
|
|
401
452
|
/* One line that scrolls sideways. 4px of padding above and below, taken back by the margin,
|
|
@@ -503,6 +554,7 @@
|
|
|
503
554
|
[data-hc-ds] :is(.hc-ui-segmented[data-indicator='slide'], .hc-ui-segmented__indicator) { transition: none; }
|
|
504
555
|
[data-hc-ds] .hc-ui-segmented[data-indicator='slide']:has(.hc-ui-segmented__option:active:not(:disabled)) { transform: none; }
|
|
505
556
|
[data-hc-ds] .hc-ui-icon-button__icon[data-swap] { animation: none; }
|
|
557
|
+
[data-hc-ds] .hc-ui-chip__badge[data-placement='corner'] { animation: none; }
|
|
506
558
|
[data-hc-ds] :is(.hc-ui-button, .hc-ui-icon-button, .hc-ui-chip) { transition: none; }
|
|
507
559
|
[data-hc-ds] .hc-ui-field__control { transition: none; }
|
|
508
560
|
[data-hc-ds] .hc-ui-button__spinner { animation: none; }
|
|
@@ -660,7 +712,9 @@
|
|
|
660
712
|
font-variation-settings: 'ROND' var(--hc-rond);
|
|
661
713
|
line-height: var(--hc-line-height-md);
|
|
662
714
|
outline: none;
|
|
663
|
-
|
|
715
|
+
/* `backwards`, not `both`: once in, no transform stays on the dialog. A transform would make
|
|
716
|
+
it the containing block of fixed popups portaled into it, and its overflow would cut them. */
|
|
717
|
+
animation: hc-ui-dialog-in var(--hc-dur-medium) var(--hc-ease-standard) backwards;
|
|
664
718
|
}
|
|
665
719
|
[data-hc-ds] .hc-ui-dialog[open] { display: grid; align-content: start; gap: var(--hc-space-2); }
|
|
666
720
|
[data-hc-ds] .hc-ui-dialog::backdrop {
|
|
@@ -702,8 +756,6 @@
|
|
|
702
756
|
gap: var(--hc-space-2);
|
|
703
757
|
margin-top: var(--hc-space-3);
|
|
704
758
|
}
|
|
705
|
-
/* HCUI's confirmation buttons are 38px, between Button sm (36) and md (44). */
|
|
706
|
-
[data-hc-ds] .hc-ui-dialog[data-size='sm'] .hc-ui-dialog__actions .hc-ui-button[data-size='sm'] { min-height: 38px; }
|
|
707
759
|
|
|
708
760
|
[data-hc-ds] .hc-ui-dialog[data-size='md'] {
|
|
709
761
|
width: min(440px, calc(100vw - 2 * var(--hc-space-6)));
|
|
@@ -739,6 +791,8 @@
|
|
|
739
791
|
box-shadow: 0 -1px 0 var(--hc-color-border);
|
|
740
792
|
}
|
|
741
793
|
[data-hc-ds] .hc-ui-dialog[data-size='md'] .hc-ui-dialog__actions > * { flex: 1 1 0; }
|
|
794
|
+
/* Header-less (Sheet header={false}): the content brings its own spacing, heading and close. */
|
|
795
|
+
[data-hc-ds] .hc-ui-dialog[data-size='md'][data-headerless] .hc-ui-dialog__body { gap: 0; padding: 0; }
|
|
742
796
|
|
|
743
797
|
@keyframes hc-ui-dialog-in {
|
|
744
798
|
from { opacity: 0; transform: translateY(8px) scale(0.97); }
|
|
@@ -776,7 +830,7 @@
|
|
|
776
830
|
padding-bottom: max(env(safe-area-inset-bottom, 0px), var(--hc-space-3));
|
|
777
831
|
border-radius: var(--hc-radius-sheet) var(--hc-radius-sheet) 0 0;
|
|
778
832
|
touch-action: pan-y;
|
|
779
|
-
animation: hc-ui-sheet-up var(--hc-dur-large) var(--hc-ease-sheet)
|
|
833
|
+
animation: hc-ui-sheet-up var(--hc-dur-large) var(--hc-ease-sheet) backwards;
|
|
780
834
|
transition: height 320ms var(--hc-ease-sheet), max-height 320ms var(--hc-ease-sheet);
|
|
781
835
|
}
|
|
782
836
|
[data-hc-ds] .hc-ui-sheet[data-presentation='bottom']::before {
|
|
@@ -811,7 +865,7 @@
|
|
|
811
865
|
padding-bottom: max(env(safe-area-inset-bottom, 0px), var(--hc-space-3));
|
|
812
866
|
border-radius: var(--hc-radius-sheet) var(--hc-radius-sheet) 0 0;
|
|
813
867
|
touch-action: pan-y;
|
|
814
|
-
animation: hc-ui-sheet-up var(--hc-dur-large) var(--hc-ease-sheet)
|
|
868
|
+
animation: hc-ui-sheet-up var(--hc-dur-large) var(--hc-ease-sheet) backwards;
|
|
815
869
|
transition: height 320ms var(--hc-ease-sheet), max-height 320ms var(--hc-ease-sheet);
|
|
816
870
|
}
|
|
817
871
|
[data-hc-ds] .hc-ui-sheet[data-presentation='auto']::before {
|