@duro-app/ui 5.5.0 → 5.7.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/dist/{Table-DYN-bp0e.js → Table-Dj7PXqO_.js} +405 -387
- package/dist/Table-Dj7PXqO_.js.map +1 -0
- package/dist/components/Button/Button.d.ts +2 -1
- package/dist/components/Button/Button.d.ts.map +1 -1
- package/dist/components/Button/styles.css.d.ts +1 -0
- package/dist/components/Button/styles.css.d.ts.map +1 -1
- package/dist/components/ButtonGroup/ButtonGroup.stories.d.ts +14 -0
- package/dist/components/ButtonGroup/ButtonGroup.stories.d.ts.map +1 -1
- package/dist/components/DragDrop/DragDrop.d.ts +95 -14
- package/dist/components/DragDrop/DragDrop.d.ts.map +1 -1
- package/dist/components/DragDrop/DragDrop.meta.d.ts.map +1 -1
- package/dist/components/DragDrop/DragDropBoard.stories.d.ts +69 -0
- package/dist/components/DragDrop/DragDropBoard.stories.d.ts.map +1 -0
- package/dist/components/DragDrop/styles.css.d.ts +80 -3
- package/dist/components/DragDrop/styles.css.d.ts.map +1 -1
- package/dist/components/LinkButton/styles.css.d.ts +1 -0
- package/dist/components/LinkButton/styles.css.d.ts.map +1 -1
- package/dist/components/Menu/Menu.d.ts +4 -1
- package/dist/components/Menu/Menu.d.ts.map +1 -1
- package/dist/components/Menu/styles.css.d.ts +14 -0
- package/dist/components/Menu/styles.css.d.ts.map +1 -1
- package/dist/components/Meter/Meter.d.ts +17 -0
- package/dist/components/Meter/Meter.d.ts.map +1 -0
- package/dist/components/Meter/Meter.meta.d.ts +3 -0
- package/dist/components/Meter/Meter.meta.d.ts.map +1 -0
- package/dist/components/Meter/Meter.stories.d.ts +12 -0
- package/dist/components/Meter/Meter.stories.d.ts.map +1 -0
- package/dist/components/Meter/styles.css.d.ts +34 -0
- package/dist/components/Meter/styles.css.d.ts.map +1 -0
- package/dist/components/Popover/Popover.d.ts +14 -2
- package/dist/components/Popover/Popover.d.ts.map +1 -1
- package/dist/components/Popover/Popover.meta.d.ts.map +1 -1
- package/dist/components/Popover/PopoverLayerContext.d.ts +3 -0
- package/dist/components/Popover/PopoverLayerContext.d.ts.map +1 -1
- package/dist/components/Popover/PopoverRaised.stories.d.ts +28 -0
- package/dist/components/Popover/PopoverRaised.stories.d.ts.map +1 -0
- package/dist/components/Popover/styles.css.d.ts +15 -0
- package/dist/components/Popover/styles.css.d.ts.map +1 -1
- package/dist/components/Select/Select.d.ts +4 -1
- package/dist/components/Select/Select.d.ts.map +1 -1
- package/dist/components/Select/styles.css.d.ts +9 -0
- package/dist/components/Select/styles.css.d.ts.map +1 -1
- package/dist/components/Timeline/Timeline.d.ts +71 -0
- package/dist/components/Timeline/Timeline.d.ts.map +1 -0
- package/dist/components/Timeline/Timeline.meta.d.ts +3 -0
- package/dist/components/Timeline/Timeline.meta.d.ts.map +1 -0
- package/dist/components/Timeline/Timeline.stories.d.ts +26 -0
- package/dist/components/Timeline/Timeline.stories.d.ts.map +1 -0
- package/dist/components/Timeline/styles.css.d.ts +158 -0
- package/dist/components/Timeline/styles.css.d.ts.map +1 -0
- package/dist/components/Toast/Toast.meta.d.ts.map +1 -1
- package/dist/components/Toast/Toast.stories.d.ts +9 -0
- package/dist/components/Toast/Toast.stories.d.ts.map +1 -1
- package/dist/components/Toast/ToastProvider.d.ts +11 -5
- package/dist/components/Toast/ToastProvider.d.ts.map +1 -1
- package/dist/components/Toast/index.d.ts +1 -1
- package/dist/components/Toast/index.d.ts.map +1 -1
- package/dist/components/Toast/styles.css.d.ts +6 -0
- package/dist/components/Toast/styles.css.d.ts.map +1 -1
- package/dist/components/Toggle/Toggle.d.ts +2 -1
- package/dist/components/Toggle/Toggle.d.ts.map +1 -1
- package/dist/components/Toggle/styles.css.d.ts +1 -0
- package/dist/components/Toggle/styles.css.d.ts.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4992 -3845
- package/dist/index.js.map +1 -1
- package/dist/shared/ModalContext.d.ts +7 -0
- package/dist/shared/ModalContext.d.ts.map +1 -1
- package/dist/shared/exports.typecheck.d.ts +9 -0
- package/dist/shared/exports.typecheck.d.ts.map +1 -0
- package/dist/shared/types.d.ts +2 -0
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/table.js +1 -1
- package/package.json +2 -2
- package/src/components/Button/Button.tsx +2 -1
- package/src/components/Button/styles.css.ts +3 -0
- package/src/components/ButtonGroup/ButtonGroup.stories.tsx +172 -14
- package/src/components/DragDrop/DragDrop.meta.ts +22 -21
- package/src/components/DragDrop/DragDrop.tsx +1147 -246
- package/src/components/DragDrop/DragDropBoard.stories.tsx +668 -0
- package/src/components/DragDrop/styles.css.ts +74 -4
- package/src/components/LinkButton/styles.css.ts +4 -0
- package/src/components/Menu/Menu.meta.ts +1 -1
- package/src/components/Menu/Menu.tsx +17 -2
- package/src/components/Menu/styles.css.ts +18 -0
- package/src/components/Meter/Meter.meta.ts +24 -0
- package/src/components/Meter/Meter.stories.tsx +64 -0
- package/src/components/Meter/Meter.tsx +55 -0
- package/src/components/Meter/styles.css.ts +30 -0
- package/src/components/Popover/Popover.meta.ts +2 -1
- package/src/components/Popover/Popover.tsx +29 -4
- package/src/components/Popover/PopoverLayerContext.ts +3 -0
- package/src/components/Popover/PopoverRaised.stories.tsx +334 -0
- package/src/components/Popover/styles.css.ts +21 -0
- package/src/components/Select/Select.meta.ts +1 -1
- package/src/components/Select/Select.tsx +5 -1
- package/src/components/Select/styles.css.ts +12 -0
- package/src/components/Timeline/Timeline.meta.ts +46 -0
- package/src/components/Timeline/Timeline.stories.tsx +238 -0
- package/src/components/Timeline/Timeline.tsx +332 -0
- package/src/components/Timeline/styles.css.ts +162 -0
- package/src/components/Toast/Toast.meta.ts +2 -1
- package/src/components/Toast/Toast.stories.tsx +84 -0
- package/src/components/Toast/ToastProvider.tsx +49 -11
- package/src/components/Toast/index.ts +7 -1
- package/src/components/Toast/styles.css.ts +2 -0
- package/src/components/Toggle/Toggle.tsx +2 -1
- package/src/components/Toggle/styles.css.ts +2 -0
- package/src/index.ts +18 -0
- package/src/shared/ModalContext.ts +8 -1
- package/src/shared/exports.typecheck.ts +16 -0
- package/src/shared/types.ts +3 -0
- package/dist/Table-DYN-bp0e.js.map +0 -1
|
@@ -10,5 +10,12 @@
|
|
|
10
10
|
* closes on a nested modal opening; no consumer needs it yet.
|
|
11
11
|
*/
|
|
12
12
|
export declare const ModalContext: import('react').Context<boolean>;
|
|
13
|
+
/**
|
|
14
|
+
* True inside a Dialog or Drawer, false outside. A floating surface that is not
|
|
15
|
+
* a Duro Popover picks its layer with it, the way a Popover does:
|
|
16
|
+
* `useInModal() ? layers.popover : layers.floating`, and for one that must
|
|
17
|
+
* cover another floating surface (a link editor over a format bar)
|
|
18
|
+
* `useInModal() ? layers.popoverRaised : layers.floatingRaised`.
|
|
19
|
+
*/
|
|
13
20
|
export declare function useInModal(): boolean;
|
|
14
21
|
//# sourceMappingURL=ModalContext.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModalContext.d.ts","sourceRoot":"","sources":["../../src/shared/ModalContext.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,kCAAuB,CAAA;AAEhD,wBAAgB,UAAU,
|
|
1
|
+
{"version":3,"file":"ModalContext.d.ts","sourceRoot":"","sources":["../../src/shared/ModalContext.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,kCAAuB,CAAA;AAEhD;;;;;;GAMG;AACH,wBAAgB,UAAU,IAAI,OAAO,CAEpC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ButtonSize, ControlSize, ToggleSize, useInModal } from '../index';
|
|
2
|
+
type Same<T, U> = [T] extends [U] ? ([U] extends [T] ? true : false) : false;
|
|
3
|
+
export declare const useInModalIsBoolean: Same<ReturnType<typeof useInModal>, boolean>;
|
|
4
|
+
export declare const useInModalTakesNothing: Same<Parameters<typeof useInModal>, []>;
|
|
5
|
+
export declare const controlSizes: Same<ControlSize, 'default' | 'small'>;
|
|
6
|
+
export declare const buttonSizeIsControlSize: Same<ButtonSize, ControlSize>;
|
|
7
|
+
export declare const toggleSizeIsControlSize: Same<ToggleSize, ControlSize>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=exports.typecheck.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exports.typecheck.d.ts","sourceRoot":"","sources":["../../src/shared/exports.typecheck.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAC,MAAM,UAAU,CAAA;AAE7E,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,KAAK,CAAC,GAAG,KAAK,CAAA;AAG5E,eAAO,MAAM,mBAAmB,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,UAAU,CAAC,EAAE,OAAO,CAAQ,CAAA;AACrF,eAAO,MAAM,sBAAsB,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,UAAU,CAAC,EAAE,EAAE,CAAQ,CAAA;AAGnF,eAAO,MAAM,YAAY,EAAE,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,OAAO,CAAQ,CAAA;AACxE,eAAO,MAAM,uBAAuB,EAAE,IAAI,CAAC,UAAU,EAAE,WAAW,CAAQ,CAAA;AAC1E,eAAO,MAAM,uBAAuB,EAAE,IAAI,CAAC,UAAU,EAAE,WAAW,CAAQ,CAAA"}
|
package/dist/shared/types.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/shared/types.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,UAAU,CAAA"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/shared/types.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,UAAU,CAAA;AAEnD,gGAAgG;AAChG,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,OAAO,CAAA"}
|
package/dist/table.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { M as F, m as xt, R as rt, H as kt, n as pt, o as bt, p as ft, q as mt, k as ht, t as yt, r as St, v as Tt } from "./Table-
|
|
1
|
+
import { M as F, m as xt, R as rt, H as kt, n as pt, o as bt, p as ft, q as mt, k as ht, t as yt, r as St, v as Tt } from "./Table-Dj7PXqO_.js";
|
|
2
2
|
import { jsx as u, jsxs as q } from "react/jsx-runtime";
|
|
3
3
|
import { c as H, m as p, d as b } from "./compiler-runtime-B2IcI8_O.js";
|
|
4
4
|
import { flexRender as E, useReactTable as it, getPaginationRowModel as Ct, getFilteredRowModel as vt, getSortedRowModel as at, getCoreRowModel as st } from "@tanstack/react-table";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@duro-app/ui",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.7.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
68
|
"@tanstack/react-virtual": "^3.14.6",
|
|
69
|
-
"@duro-app/tokens": "^5.
|
|
69
|
+
"@duro-app/tokens": "^5.7.0"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@babel/preset-typescript": "^7.28.0",
|
|
@@ -2,11 +2,12 @@ import type {ReactNode, Ref} from 'react'
|
|
|
2
2
|
import {html} from 'react-strict-dom'
|
|
3
3
|
import {isNative} from '../../platform'
|
|
4
4
|
import {mergeRefs} from '../../shared/mergeRefs'
|
|
5
|
+
import type {ControlSize} from '../../shared/types'
|
|
5
6
|
import {useGroupedControl} from '../ButtonGroup/useGroupedControl'
|
|
6
7
|
import {styles} from './styles.css'
|
|
7
8
|
|
|
8
9
|
export type ButtonVariant = 'primary' | 'secondary' | 'inverseSecondary' | 'link' | 'danger'
|
|
9
|
-
export type ButtonSize =
|
|
10
|
+
export type ButtonSize = ControlSize
|
|
10
11
|
|
|
11
12
|
interface ButtonProps {
|
|
12
13
|
variant?: ButtonVariant
|
|
@@ -4,6 +4,7 @@ import {spacing, radii} from '@duro-app/tokens/tokens/spacing.css'
|
|
|
4
4
|
import {typography} from '@duro-app/tokens/tokens/typography.css'
|
|
5
5
|
import {duration, easing} from '@duro-app/tokens/tokens/motion.css'
|
|
6
6
|
import {borders} from '@duro-app/tokens/tokens/borders.css'
|
|
7
|
+
import {sizes} from '@duro-app/tokens/tokens/sizes.css'
|
|
7
8
|
|
|
8
9
|
export const styles = css.create({
|
|
9
10
|
base: {
|
|
@@ -62,6 +63,8 @@ export const styles = css.create({
|
|
|
62
63
|
paddingLeft: spacing.sm,
|
|
63
64
|
paddingRight: spacing.sm,
|
|
64
65
|
fontSize: typography.fontSizeXs,
|
|
66
|
+
// Every small control is at least controlSm tall, whatever it holds (5.6).
|
|
67
|
+
minHeight: sizes.controlSm,
|
|
65
68
|
},
|
|
66
69
|
primary: {
|
|
67
70
|
backgroundColor: {
|
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
import {useState} from 'react'
|
|
2
2
|
import type {Meta, StoryObj} from '@storybook/react'
|
|
3
|
-
import {expect, userEvent, within} from 'storybook/test'
|
|
4
|
-
import {
|
|
3
|
+
import {expect, userEvent, waitFor, within} from 'storybook/test'
|
|
4
|
+
import {
|
|
5
|
+
BORDERS_PX,
|
|
6
|
+
FONT_SIZE_REM,
|
|
7
|
+
LAYERS,
|
|
8
|
+
RADII_PX,
|
|
9
|
+
SIZES_PX,
|
|
10
|
+
SPACING_PX,
|
|
11
|
+
} from '@duro-app/tokens/keys'
|
|
12
|
+
import {withCoarsePointer, withFinePointer} from '../../docs/coarsePointer'
|
|
5
13
|
import {ButtonGroup} from './ButtonGroup'
|
|
14
|
+
import type {ControlSize} from '../../shared/types'
|
|
6
15
|
import {Button} from '../Button/Button'
|
|
16
|
+
import {Icon} from '../Icon/Icon'
|
|
17
|
+
import {Inline} from '../Inline/Inline'
|
|
18
|
+
import {Menu} from '../Menu/Menu'
|
|
7
19
|
import {Popover} from '../Popover/Popover'
|
|
8
20
|
import {Select} from '../Select/Select'
|
|
9
21
|
import {Stack} from '../Stack/Stack'
|
|
@@ -146,11 +158,11 @@ async function expectJoined(controls: Element[]) {
|
|
|
146
158
|
}
|
|
147
159
|
}
|
|
148
160
|
|
|
149
|
-
function TextStyleSelects({named = false}: {named?: boolean}) {
|
|
161
|
+
function TextStyleSelects({named = false, size}: {named?: boolean; size?: ControlSize}) {
|
|
150
162
|
return (
|
|
151
163
|
<ButtonGroup attached aria-label="Text style">
|
|
152
164
|
<Select.Root name={named ? 'block' : undefined} defaultValue="normal">
|
|
153
|
-
<Select.Trigger aria-label="Block type">
|
|
165
|
+
<Select.Trigger aria-label="Block type" size={size}>
|
|
154
166
|
<Select.Value />
|
|
155
167
|
<Select.Icon />
|
|
156
168
|
</Select.Trigger>
|
|
@@ -160,7 +172,7 @@ function TextStyleSelects({named = false}: {named?: boolean}) {
|
|
|
160
172
|
</Select.Popup>
|
|
161
173
|
</Select.Root>
|
|
162
174
|
<Select.Root name={named ? 'font' : undefined} defaultValue="arial">
|
|
163
|
-
<Select.Trigger aria-label="Font">
|
|
175
|
+
<Select.Trigger aria-label="Font" size={size}>
|
|
164
176
|
<Select.Value />
|
|
165
177
|
<Select.Icon />
|
|
166
178
|
</Select.Trigger>
|
|
@@ -170,7 +182,7 @@ function TextStyleSelects({named = false}: {named?: boolean}) {
|
|
|
170
182
|
</Select.Popup>
|
|
171
183
|
</Select.Root>
|
|
172
184
|
<Select.Root name={named ? 'size' : undefined} defaultValue="15">
|
|
173
|
-
<Select.Trigger aria-label="Font size">
|
|
185
|
+
<Select.Trigger aria-label="Font size" size={size}>
|
|
174
186
|
<Select.Value />
|
|
175
187
|
<Select.Icon />
|
|
176
188
|
</Select.Trigger>
|
|
@@ -242,25 +254,37 @@ export const AttachedFocusMiddle: Story = {
|
|
|
242
254
|
},
|
|
243
255
|
}
|
|
244
256
|
|
|
245
|
-
function FormatGroup() {
|
|
257
|
+
function FormatGroup({size}: {size?: ControlSize}) {
|
|
246
258
|
const [pressed, setPressed] = useState<Record<string, boolean>>({u: true})
|
|
247
259
|
const toggle = (key: string) => (next: boolean) => setPressed((p) => ({...p, [key]: next}))
|
|
248
260
|
return (
|
|
249
261
|
<ButtonGroup attached aria-label="Format">
|
|
250
|
-
<Toggle aria-label="Bold" pressed={!!pressed.b} onPressedChange={toggle('b')}>
|
|
262
|
+
<Toggle aria-label="Bold" size={size} pressed={!!pressed.b} onPressedChange={toggle('b')}>
|
|
251
263
|
B
|
|
252
264
|
</Toggle>
|
|
253
|
-
<Toggle aria-label="Italic" pressed={!!pressed.i} onPressedChange={toggle('i')}>
|
|
265
|
+
<Toggle aria-label="Italic" size={size} pressed={!!pressed.i} onPressedChange={toggle('i')}>
|
|
254
266
|
I
|
|
255
267
|
</Toggle>
|
|
256
|
-
<Toggle
|
|
268
|
+
<Toggle
|
|
269
|
+
aria-label="Underline"
|
|
270
|
+
size={size}
|
|
271
|
+
pressed={!!pressed.u}
|
|
272
|
+
onPressedChange={toggle('u')}
|
|
273
|
+
>
|
|
257
274
|
U
|
|
258
275
|
</Toggle>
|
|
259
|
-
<Toggle
|
|
276
|
+
<Toggle
|
|
277
|
+
aria-label="Code"
|
|
278
|
+
size={size}
|
|
279
|
+
pressed={!!pressed.code}
|
|
280
|
+
onPressedChange={toggle('code')}
|
|
281
|
+
>
|
|
260
282
|
{'<>'}
|
|
261
283
|
</Toggle>
|
|
262
284
|
<Popover.Root>
|
|
263
|
-
<Popover.Trigger aria-label="Link"
|
|
285
|
+
<Popover.Trigger aria-label="Link" size={size}>
|
|
286
|
+
↗
|
|
287
|
+
</Popover.Trigger>
|
|
264
288
|
<Popover.Popup label="Link">
|
|
265
289
|
<Stack gap="sm">
|
|
266
290
|
<Text>Paste a URL.</Text>
|
|
@@ -268,10 +292,10 @@ function FormatGroup() {
|
|
|
268
292
|
</Stack>
|
|
269
293
|
</Popover.Popup>
|
|
270
294
|
</Popover.Root>
|
|
271
|
-
<Button variant="secondary" aria-label="Clear formatting">
|
|
295
|
+
<Button variant="secondary" size={size} aria-label="Clear formatting">
|
|
272
296
|
T
|
|
273
297
|
</Button>
|
|
274
|
-
<Button variant="secondary" aria-label="Highlight">
|
|
298
|
+
<Button variant="secondary" size={size} aria-label="Highlight">
|
|
275
299
|
H
|
|
276
300
|
</Button>
|
|
277
301
|
</ButtonGroup>
|
|
@@ -372,3 +396,137 @@ export const BothPressedFocusSecond: Story = {
|
|
|
372
396
|
await expect(drawnAt(bold, b.left + b.width / 2, ringPixels(b).bottom)).toBe(true)
|
|
373
397
|
},
|
|
374
398
|
}
|
|
399
|
+
|
|
400
|
+
// --- Small triggers (5.6) ---
|
|
401
|
+
|
|
402
|
+
/** fontSizeXs in px, from the root font size. */
|
|
403
|
+
const smallFontPx = () =>
|
|
404
|
+
`${parseFloat(getComputedStyle(document.documentElement).fontSize) * FONT_SIZE_REM.fontSizeXs}px`
|
|
405
|
+
|
|
406
|
+
/** [Normal | Arial | 15px] at size="small": joined like the default size. */
|
|
407
|
+
export const AttachedSelectsSmall: Story = {
|
|
408
|
+
render: () => <TextStyleSelects size="small" />,
|
|
409
|
+
play: async ({canvas}) => {
|
|
410
|
+
const triggers = canvas.getAllByRole('combobox')
|
|
411
|
+
await expectJoined(triggers)
|
|
412
|
+
for (const el of triggers) {
|
|
413
|
+
await expect(getComputedStyle(el).fontSize).toBe(smallFontPx())
|
|
414
|
+
}
|
|
415
|
+
},
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/** The mixed format group at size="small": Toggles, the Popover trigger and
|
|
419
|
+
* the Buttons stay joined. */
|
|
420
|
+
export const AttachedMixedSmall: Story = {
|
|
421
|
+
render: () => <FormatGroup size="small" />,
|
|
422
|
+
play: async ({canvas}) => {
|
|
423
|
+
const group = canvas.getByRole('group', {name: 'Format'})
|
|
424
|
+
await expectJoined(within(group).getAllByRole('button'))
|
|
425
|
+
},
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function SmallControlsRow() {
|
|
429
|
+
return (
|
|
430
|
+
<Inline gap="sm" align="center">
|
|
431
|
+
<Toggle size="small" aria-label="Bold">
|
|
432
|
+
B
|
|
433
|
+
</Toggle>
|
|
434
|
+
<Toggle size="small" aria-label="Search">
|
|
435
|
+
<Icon name="search" size="md" />
|
|
436
|
+
</Toggle>
|
|
437
|
+
<Button size="small" variant="secondary">
|
|
438
|
+
Clear
|
|
439
|
+
</Button>
|
|
440
|
+
<Select.Root defaultValue="normal">
|
|
441
|
+
<Select.Trigger size="small" aria-label="Block type">
|
|
442
|
+
<Select.Value />
|
|
443
|
+
<Select.Icon />
|
|
444
|
+
</Select.Trigger>
|
|
445
|
+
<Select.Popup>
|
|
446
|
+
<Select.Item value="normal">Normal</Select.Item>
|
|
447
|
+
<Select.Item value="h1">Heading 1</Select.Item>
|
|
448
|
+
</Select.Popup>
|
|
449
|
+
</Select.Root>
|
|
450
|
+
<Menu.Root>
|
|
451
|
+
<Menu.Trigger size="small">Insert</Menu.Trigger>
|
|
452
|
+
<Menu.Popup>
|
|
453
|
+
<Menu.Item onClick={() => undefined}>Image</Menu.Item>
|
|
454
|
+
</Menu.Popup>
|
|
455
|
+
</Menu.Root>
|
|
456
|
+
<Popover.Root>
|
|
457
|
+
<Popover.Trigger size="small" aria-label="Text colour">
|
|
458
|
+
A
|
|
459
|
+
</Popover.Trigger>
|
|
460
|
+
<Popover.Popup label="Text colour">
|
|
461
|
+
<Text>Pick a colour.</Text>
|
|
462
|
+
</Popover.Popup>
|
|
463
|
+
</Popover.Root>
|
|
464
|
+
<Menu.Root>
|
|
465
|
+
<Menu.Trigger size="small" variant="ghost" aria-label="More">
|
|
466
|
+
<Icon name="menu" size="sm" />
|
|
467
|
+
</Menu.Trigger>
|
|
468
|
+
<Menu.Popup>
|
|
469
|
+
<Menu.Item onClick={() => undefined}>Settings</Menu.Item>
|
|
470
|
+
</Menu.Popup>
|
|
471
|
+
</Menu.Root>
|
|
472
|
+
</Inline>
|
|
473
|
+
)
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/** Small Toggles (text and an 18px icon), a small Button and small Select,
|
|
477
|
+
* Menu and Popover triggers in a plain Inline (no attached group to stretch
|
|
478
|
+
* them): every one is controlSm tall whatever it holds, with Toggle's
|
|
479
|
+
* padding and font. The ghost Menu trigger is the small icon-button size. */
|
|
480
|
+
export const SmallTriggersRow: Story = {
|
|
481
|
+
render: () => <SmallControlsRow />,
|
|
482
|
+
play: async ({canvas}) => {
|
|
483
|
+
await withFinePointer()
|
|
484
|
+
const controls = [
|
|
485
|
+
canvas.getByRole('button', {name: 'Bold'}),
|
|
486
|
+
canvas.getByRole('button', {name: 'Search'}),
|
|
487
|
+
canvas.getByRole('button', {name: 'Clear'}),
|
|
488
|
+
]
|
|
489
|
+
const triggers = [
|
|
490
|
+
canvas.getByRole('combobox', {name: 'Block type'}),
|
|
491
|
+
canvas.getByRole('button', {name: 'Insert'}),
|
|
492
|
+
canvas.getByRole('button', {name: 'Text colour'}),
|
|
493
|
+
]
|
|
494
|
+
for (const el of [...controls, ...triggers]) {
|
|
495
|
+
await expect(el.offsetHeight).toBe(SIZES_PX.controlSm)
|
|
496
|
+
}
|
|
497
|
+
for (const el of triggers) {
|
|
498
|
+
const cs = getComputedStyle(el)
|
|
499
|
+
await expect(cs.paddingTop).toBe(`${SPACING_PX.xs}px`)
|
|
500
|
+
await expect(cs.paddingLeft).toBe(`${SPACING_PX.sm}px`)
|
|
501
|
+
await expect(cs.fontSize).toBe(smallFontPx())
|
|
502
|
+
}
|
|
503
|
+
const ghost = canvas.getByRole('button', {name: 'More'})
|
|
504
|
+
await expect(ghost.offsetHeight).toBe(SIZES_PX.iconButtonSm)
|
|
505
|
+
await expect(ghost.offsetWidth).toBe(SIZES_PX.iconButtonSm)
|
|
506
|
+
await expect(getComputedStyle(ghost).fontSize).toBe(smallFontPx())
|
|
507
|
+
},
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/** The same row under a coarse pointer: Toggle and the three triggers reach
|
|
511
|
+
* touchTarget, the ghost Menu too. Button has no touch size at any size, so the small Button stays
|
|
512
|
+
* controlSm (the 5.5 plan's addendum). */
|
|
513
|
+
export const SmallTriggersRowCoarsePointer: Story = {
|
|
514
|
+
render: () => <SmallControlsRow />,
|
|
515
|
+
play: async ({canvas}) => {
|
|
516
|
+
const touch = [
|
|
517
|
+
canvas.getByRole('button', {name: 'Bold'}),
|
|
518
|
+
canvas.getByRole('button', {name: 'Search'}),
|
|
519
|
+
canvas.getByRole('combobox', {name: 'Block type'}),
|
|
520
|
+
canvas.getByRole('button', {name: 'Insert'}),
|
|
521
|
+
canvas.getByRole('button', {name: 'Text colour'}),
|
|
522
|
+
canvas.getByRole('button', {name: 'More'}),
|
|
523
|
+
]
|
|
524
|
+
const button = canvas.getByRole('button', {name: 'Clear'})
|
|
525
|
+
await withCoarsePointer(async () => {
|
|
526
|
+
for (const el of touch) {
|
|
527
|
+
await waitFor(() => expect(el.offsetHeight).toBe(SIZES_PX.touchTarget))
|
|
528
|
+
}
|
|
529
|
+
await expect(button.offsetHeight).toBe(SIZES_PX.controlSm)
|
|
530
|
+
})
|
|
531
|
+
},
|
|
532
|
+
}
|
|
@@ -2,15 +2,15 @@ import type {ComponentMeta} from '../component-meta'
|
|
|
2
2
|
|
|
3
3
|
export const meta: ComponentMeta = {
|
|
4
4
|
description:
|
|
5
|
-
'Move items between zones
|
|
6
|
-
anatomy: {required: ['Root', 'Zone', 'Item']},
|
|
5
|
+
'Move items between zones by pointer (mouse, pen and touch through one pointer-event path; touch holds briefly, then drags) or by keyboard (a Handle per item: Space picks up, arrows move, Space drops, Escape cancels). The innermost accepting zone wins, so a zone nested in an Item (a card in a column) takes its own drops; a zone can refuse with a reason that is shown and announced. Placeholders, edge auto-scroll and list-style announcements (through `announce`, for catalog strings) come with it.',
|
|
6
|
+
anatomy: {required: ['Root', 'Zone', 'Item'], optional: ['Handle']},
|
|
7
7
|
whenToUse: [
|
|
8
8
|
'Slotting things into places — people into approval gates, cards into columns, files into folders',
|
|
9
9
|
'Reordering a short row or list when the order is visible and meaningful',
|
|
10
|
+
'A board: columns as labelled lists (`list`), cards with a Handle, an attach zone nested in each card',
|
|
10
11
|
],
|
|
11
12
|
whenNotToUse: [
|
|
12
|
-
'As the ONLY way to do something —
|
|
13
|
-
'Long lists that scroll while dragging — the ghost follows the pointer but zones do not auto-scroll',
|
|
13
|
+
'As the ONLY way to do something — WCAG 2.5.7 asks for a single-pointer alternative to dragging (a button or menu that moves the item); a Handle adds the keyboard path, not a click one',
|
|
14
14
|
'Sorting tabular data — sort the Table instead',
|
|
15
15
|
'React Native — Item renders its children without drag behaviour there',
|
|
16
16
|
],
|
|
@@ -26,24 +26,25 @@ export const meta: ComponentMeta = {
|
|
|
26
26
|
relationship: 'ScrollArea drags a thumb along one axis; DragDrop moves items between zones',
|
|
27
27
|
},
|
|
28
28
|
],
|
|
29
|
-
example: `<DragDrop.Root
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
example: `<DragDrop.Root
|
|
30
|
+
onDrop={({item, target}) => move(item.id, target.zone, target.index)}
|
|
31
|
+
renderPlaceholder={({label}) => <Text variant="caption">→ {label}</Text>}
|
|
32
|
+
announce={(e) => t(\`board.drag.\${e.kind}\`, e)}
|
|
33
|
+
>
|
|
34
|
+
{columns.map((col) => (
|
|
35
|
+
<DragDrop.Zone key={col.id} id={col.id} label={col.name} orientation="vertical" list
|
|
36
|
+
accepts={(item) => item.data.kind === 'task' || {ok: false, reason: t('board.attachOnCard')}}>
|
|
37
|
+
{col.cards.map((card) => (
|
|
38
|
+
<DragDrop.Item key={card.id} id={card.id} zone={col.id} label={card.title} data={card}>
|
|
39
|
+
<DragDrop.Handle>
|
|
40
|
+
<DragDrop.Zone id={\`attach:\${card.id}\`} label={card.title}
|
|
41
|
+
accepts={(item) => item.data.kind === 'activity'}>
|
|
42
|
+
<Card>{card.title}</Card>
|
|
43
|
+
</DragDrop.Zone>
|
|
44
|
+
</DragDrop.Handle>
|
|
35
45
|
</DragDrop.Item>
|
|
36
46
|
))}
|
|
37
|
-
</
|
|
38
|
-
|
|
39
|
-
<DragDrop.Zone id="gates" label="Gates" orientation="horizontal">
|
|
40
|
-
<Inline gap="sm">
|
|
41
|
-
{gates.map((g) => (
|
|
42
|
-
<DragDrop.Item key={g.id} id={g.id} zone="gates" label={g.name} data={g}>
|
|
43
|
-
<Tag removable onRemove={() => unslot(g)}>{g.name}</Tag>
|
|
44
|
-
</DragDrop.Item>
|
|
45
|
-
))}
|
|
46
|
-
</Inline>
|
|
47
|
-
</DragDrop.Zone>
|
|
47
|
+
</DragDrop.Zone>
|
|
48
|
+
))}
|
|
48
49
|
</DragDrop.Root>`,
|
|
49
50
|
}
|