@charcuterie/ui 2.0.0 → 2.0.1

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.
@@ -1,7 +1,13 @@
1
1
  import type { ReactNode } from "react";
2
2
  export type DialogSize = "full" | "lg" | "md" | "sm" | "xl";
3
3
  export type DialogProps = {
4
- children: ReactNode;
4
+ /**
5
+ * The scrolling body. Optional: a confirm dialog whose question is
6
+ * its `heading` and whose answers are its `footer` has no body, and
7
+ * the old chrome `Modal` (which extended `<dialog>`'s DOM props)
8
+ * allowed that — `Dialog` keeps it.
9
+ */
10
+ children?: ReactNode;
5
11
  className?: string;
6
12
  /** The footer row. Buttons, usually. */
7
13
  footer?: ReactNode;
@@ -1 +1 @@
1
- {"version":3,"file":"Dialog.d.ts","sourceRoot":"","sources":["../../src/Dialog/Dialog.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAMtC,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAE3D,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,wCAAwC;IACxC,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACxB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,SAAS,EAAE,OAAO,CAAA;IAClB;;;OAGG;IACH,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,IAAI,CAAC,EAAE,UAAU,CAAA;CAClB,CAAA;AAqBD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,MAAM,GAAI,kGAUpB,WAAW,KAAG,SA4ChB,CAAA"}
1
+ {"version":3,"file":"Dialog.d.ts","sourceRoot":"","sources":["../../src/Dialog/Dialog.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAMtC,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAE3D,MAAM,MAAM,WAAW,GAAG;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,wCAAwC;IACxC,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACxB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,SAAS,EAAE,OAAO,CAAA;IAClB;;;OAGG;IACH,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,IAAI,CAAC,EAAE,UAAU,CAAA;CAClB,CAAA;AAqBD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,MAAM,GAAI,kGAUpB,WAAW,KAAG,SA4ChB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"Dialog.js","sourceRoot":"","sources":["../../src/Dialog/Dialog.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAGhD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAsB,CAAA;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAoB,CAAA;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAyB/C;;;;GAIG;AACH,MAAM,UAAU,GAA+B;IAC7C,EAAE,EAAE,+BAA+B;IACnC,EAAE,EAAE,+BAA+B;IACnC,EAAE,EAAE,gCAAgC;IACpC,iEAAiE;IACjE,8DAA8D;IAC9D,6DAA6D;IAC7D,kEAAkE;IAClE,+DAA+D;IAC/D,+DAA+D;IAC/D,EAAE,EAAE,gCAAgC;IACpC,IAAI,EAAE,0DAA0D;CACjE,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,EACrB,QAAQ,EACR,SAAS,EACT,MAAM,EACN,OAAO,EACP,YAAY,GAAG,CAAC,EAChB,aAAa,GAAG,IAAI,EACpB,SAAS,EACT,OAAO,EACP,IAAI,GAAG,IAAI,GACC,EAAa,EAAE;IAC3B,MAAM,SAAS,GAAG,WAAW,EAAE,CAAA;IAE/B,MAAM,OAAO,GAAG,IAAI,YAAY,EAAW,CAAA;IAE3C,OAAO,CACL,MAAC,KAAK,uBACa,SAAS,EAC1B,SAAS,EAAE,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,EACnD,aAAa,EAAE,aAAa,EAC5B,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,OAAO,aAEhB,kBAAQ,SAAS,EAAC,mFAAmF,aACnG,KAAC,OAAO,IACN,SAAS,EAAC,qCAAqC,EAC/C,EAAE,EAAE,SAAS,YAEZ,OAAO,GACA,EAET,aAAa,CAAC,CAAC,CAAC,CACf,KAAC,MAAM,IACL,UAAU,EAAC,OAAO,EAClB,MAAM,EAAC,SAAS,EAChB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAC,IAAI,sBAGF,CACV,CAAC,CAAC,CAAC,IAAI,IACD,EAET,cAAK,SAAS,EAAC,kCAAkC,YAC9C,QAAQ,GACL,EAEL,MAAM,CAAC,CAAC,CAAC,CACR,iBAAQ,SAAS,EAAC,6EAA6E,YAC5F,MAAM,GACA,CACV,CAAC,CAAC,CAAC,IAAI,IACF,CACT,CAAA;AACH,CAAC,CAAA"}
1
+ {"version":3,"file":"Dialog.js","sourceRoot":"","sources":["../../src/Dialog/Dialog.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAGhD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAsB,CAAA;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAoB,CAAA;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AA+B/C;;;;GAIG;AACH,MAAM,UAAU,GAA+B;IAC7C,EAAE,EAAE,+BAA+B;IACnC,EAAE,EAAE,+BAA+B;IACnC,EAAE,EAAE,gCAAgC;IACpC,iEAAiE;IACjE,8DAA8D;IAC9D,6DAA6D;IAC7D,kEAAkE;IAClE,+DAA+D;IAC/D,+DAA+D;IAC/D,EAAE,EAAE,gCAAgC;IACpC,IAAI,EAAE,0DAA0D;CACjE,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,EACrB,QAAQ,EACR,SAAS,EACT,MAAM,EACN,OAAO,EACP,YAAY,GAAG,CAAC,EAChB,aAAa,GAAG,IAAI,EACpB,SAAS,EACT,OAAO,EACP,IAAI,GAAG,IAAI,GACC,EAAa,EAAE;IAC3B,MAAM,SAAS,GAAG,WAAW,EAAE,CAAA;IAE/B,MAAM,OAAO,GAAG,IAAI,YAAY,EAAW,CAAA;IAE3C,OAAO,CACL,MAAC,KAAK,uBACa,SAAS,EAC1B,SAAS,EAAE,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,EACnD,aAAa,EAAE,aAAa,EAC5B,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,OAAO,aAEhB,kBAAQ,SAAS,EAAC,mFAAmF,aACnG,KAAC,OAAO,IACN,SAAS,EAAC,qCAAqC,EAC/C,EAAE,EAAE,SAAS,YAEZ,OAAO,GACA,EAET,aAAa,CAAC,CAAC,CAAC,CACf,KAAC,MAAM,IACL,UAAU,EAAC,OAAO,EAClB,MAAM,EAAC,SAAS,EAChB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAC,IAAI,sBAGF,CACV,CAAC,CAAC,CAAC,IAAI,IACD,EAET,cAAK,SAAS,EAAC,kCAAkC,YAC9C,QAAQ,GACL,EAEL,MAAM,CAAC,CAAC,CAAC,CACR,iBAAQ,SAAS,EAAC,6EAA6E,YAC5F,MAAM,GACA,CACV,CAAC,CAAC,CAAC,IAAI,IACF,CACT,CAAA;AACH,CAAC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@charcuterie/ui",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "The Charcuterie components. Tokens for look, @charcuterie/logic for state, ARIA that agents can actually drive.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -316,6 +316,56 @@ export const Responsive: Story = {
316
316
  * unlike the old native `<dialog>`, a synthetic `userEvent.keyboard`
317
317
  * can now press for real.
318
318
  */
319
+ /**
320
+ * A confirm dialog with **no body**: the question is the `heading`
321
+ * (which is the dialog's accessible name) and the answers are the
322
+ * `footer`. `children` is optional precisely for this shape — the old
323
+ * chrome `Modal` extended `<dialog>`'s DOM props, so it allowed it,
324
+ * and image-viewer's delete-confirm renders exactly this.
325
+ */
326
+ const NoBodyDemo = (): ReactNode => {
327
+ const { hide, isVisible, show } = useVisibility()
328
+
329
+ return (
330
+ <>
331
+ <Button appearance="soft" onClick={show} size="sm">
332
+ Delete the file
333
+ </Button>
334
+
335
+ <Dialog
336
+ footer={
337
+ <>
338
+ <Button
339
+ appearance="soft"
340
+ intent="neutral"
341
+ onClick={hide}
342
+ size="sm"
343
+ >
344
+ Keep it
345
+ </Button>
346
+
347
+ <Button intent="danger" size="sm">
348
+ Delete
349
+ </Button>
350
+ </>
351
+ }
352
+ heading="Delete this file? This cannot be undone."
353
+ isVisible={isVisible}
354
+ onClose={hide}
355
+ />
356
+ </>
357
+ )
358
+ }
359
+
360
+ export const NoBody: Story = {
361
+ args: {
362
+ heading: "Delete this file? This cannot be undone.",
363
+ isVisible: false,
364
+ onClose: () => {},
365
+ },
366
+ render: () => <NoBodyDemo />,
367
+ }
368
+
319
369
  export const Interactive: Story = {
320
370
  args: {
321
371
  heading: "Bay 3",
@@ -15,10 +15,38 @@ const {
15
15
  AllVariants,
16
16
  Default,
17
17
  Interactive,
18
+ NoBody,
18
19
  Responsive,
19
20
  Stacked,
20
21
  } = composeStories(stories)
21
22
 
23
+ test("a dialog with no body renders from heading and footer alone", async () => {
24
+ const { body, canvas } = await mountStory(NoBody)
25
+
26
+ await userEvent.click(
27
+ expectAgentDrivable(canvas, {
28
+ name: "Delete the file",
29
+ role: "button",
30
+ }),
31
+ )
32
+
33
+ // `children` is optional: the question is the accessible name and
34
+ // the answers are the footer, with nothing in between.
35
+ const dialog = expectAgentDrivable(body, {
36
+ name: "Delete this file? This cannot be undone.",
37
+ role: "dialog",
38
+ })
39
+
40
+ await expect(
41
+ expectAgentDrivable(body, {
42
+ name: "Delete",
43
+ role: "button",
44
+ }),
45
+ ).toBeInTheDocument()
46
+
47
+ await expectNoAxeViolations(dialog)
48
+ })
49
+
22
50
  test("the dialog is reachable from a body-scoped query", async () => {
23
51
  const { body, canvas } = await mountStory(Default)
24
52
 
@@ -8,7 +8,13 @@ import { toClassName } from "../toClassName.ts"
8
8
  export type DialogSize = "full" | "lg" | "md" | "sm" | "xl"
9
9
 
10
10
  export type DialogProps = {
11
- children: ReactNode
11
+ /**
12
+ * The scrolling body. Optional: a confirm dialog whose question is
13
+ * its `heading` and whose answers are its `footer` has no body, and
14
+ * the old chrome `Modal` (which extended `<dialog>`'s DOM props)
15
+ * allowed that — `Dialog` keeps it.
16
+ */
17
+ children?: ReactNode
12
18
  className?: string
13
19
  /** The footer row. Buttons, usually. */
14
20
  footer?: ReactNode