@cloudgrid-io/ui 0.31.3 → 0.31.5

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.
Files changed (109) hide show
  1. package/README.md +32 -0
  2. package/dist/badge/brand.d.ts +8 -0
  3. package/dist/badge/brand.d.ts.map +1 -0
  4. package/dist/badge/brand.js +22 -0
  5. package/dist/badge/brand.js.map +1 -0
  6. package/dist/badge/css-base.d.ts +25 -0
  7. package/dist/badge/css-base.d.ts.map +1 -0
  8. package/dist/badge/css-base.js +103 -0
  9. package/dist/badge/css-base.js.map +1 -0
  10. package/dist/badge/css-owner.d.ts +7 -0
  11. package/dist/badge/css-owner.d.ts.map +1 -0
  12. package/dist/badge/css-owner.js +128 -0
  13. package/dist/badge/css-owner.js.map +1 -0
  14. package/dist/badge/css-visitor.d.ts +7 -0
  15. package/dist/badge/css-visitor.d.ts.map +1 -0
  16. package/dist/badge/css-visitor.js +75 -0
  17. package/dist/badge/css-visitor.js.map +1 -0
  18. package/dist/badge/html.d.ts +26 -0
  19. package/dist/badge/html.d.ts.map +1 -0
  20. package/dist/badge/html.js +55 -0
  21. package/dist/badge/html.js.map +1 -0
  22. package/dist/badge/index.d.ts +43 -0
  23. package/dist/badge/index.d.ts.map +1 -0
  24. package/dist/badge/index.js +46 -0
  25. package/dist/badge/index.js.map +1 -0
  26. package/dist/badge/marks.d.ts +45 -0
  27. package/dist/badge/marks.d.ts.map +1 -0
  28. package/dist/badge/marks.js +126 -0
  29. package/dist/badge/marks.js.map +1 -0
  30. package/dist/badge/owner.d.ts +213 -0
  31. package/dist/badge/owner.d.ts.map +1 -0
  32. package/dist/badge/owner.js +309 -0
  33. package/dist/badge/owner.js.map +1 -0
  34. package/dist/badge/palette.d.ts +23 -0
  35. package/dist/badge/palette.d.ts.map +1 -0
  36. package/dist/badge/palette.js +86 -0
  37. package/dist/badge/palette.js.map +1 -0
  38. package/dist/badge/root.d.ts +24 -0
  39. package/dist/badge/root.d.ts.map +1 -0
  40. package/dist/badge/root.js +11 -0
  41. package/dist/badge/root.js.map +1 -0
  42. package/dist/badge/shared.d.ts +56 -0
  43. package/dist/badge/shared.d.ts.map +1 -0
  44. package/dist/badge/shared.js +53 -0
  45. package/dist/badge/shared.js.map +1 -0
  46. package/dist/badge/visitor.d.ts +96 -0
  47. package/dist/badge/visitor.d.ts.map +1 -0
  48. package/dist/badge/visitor.js +119 -0
  49. package/dist/badge/visitor.js.map +1 -0
  50. package/dist/blocks/confirm-delete-dialog.d.ts +81 -0
  51. package/dist/blocks/confirm-delete-dialog.d.ts.map +1 -0
  52. package/dist/blocks/confirm-delete-dialog.js +89 -0
  53. package/dist/blocks/confirm-delete-dialog.js.map +1 -0
  54. package/dist/blocks/entity-status.d.ts +44 -1
  55. package/dist/blocks/entity-status.d.ts.map +1 -1
  56. package/dist/blocks/entity-status.js +26 -1
  57. package/dist/blocks/entity-status.js.map +1 -1
  58. package/dist/blocks/expiry-notice.d.ts +86 -0
  59. package/dist/blocks/expiry-notice.d.ts.map +1 -0
  60. package/dist/blocks/expiry-notice.js +81 -0
  61. package/dist/blocks/expiry-notice.js.map +1 -0
  62. package/dist/blocks/icons.d.ts +22 -0
  63. package/dist/blocks/icons.d.ts.map +1 -1
  64. package/dist/blocks/icons.js +22 -0
  65. package/dist/blocks/icons.js.map +1 -1
  66. package/dist/blocks/notification-row.d.ts +88 -0
  67. package/dist/blocks/notification-row.d.ts.map +1 -0
  68. package/dist/blocks/notification-row.js +32 -0
  69. package/dist/blocks/notification-row.js.map +1 -0
  70. package/dist/blocks/phosphor-marks.d.ts +10 -0
  71. package/dist/blocks/phosphor-marks.d.ts.map +1 -1
  72. package/dist/blocks/phosphor-marks.js +15 -0
  73. package/dist/blocks/phosphor-marks.js.map +1 -1
  74. package/dist/blocks/shelf.d.ts +384 -0
  75. package/dist/blocks/shelf.d.ts.map +1 -0
  76. package/dist/blocks/shelf.js +489 -0
  77. package/dist/blocks/shelf.js.map +1 -0
  78. package/dist/brand/badge/manrope-latin-wght-normal.woff2 +0 -0
  79. package/dist/brand/badge/space-grotesk-latin-wght-normal.woff2 +0 -0
  80. package/dist/brand/email/headline-activity.png +0 -0
  81. package/dist/brand/email/headline-expired.png +0 -0
  82. package/dist/brand/email/headline-expires-tomorrow.png +0 -0
  83. package/dist/brand/email/headline-expiring-soon.png +0 -0
  84. package/dist/brand/email/headline-invited.png +0 -0
  85. package/dist/brand/email/headline-sign-in-code.png +0 -0
  86. package/dist/brand/email/mesh.png +0 -0
  87. package/dist/brand/email/wordmark.png +0 -0
  88. package/dist/email/assets.d.ts +50 -0
  89. package/dist/email/assets.d.ts.map +1 -0
  90. package/dist/email/assets.js +16 -0
  91. package/dist/email/assets.js.map +1 -0
  92. package/dist/email/index.d.ts +204 -0
  93. package/dist/email/index.d.ts.map +1 -0
  94. package/dist/email/index.js +429 -0
  95. package/dist/email/index.js.map +1 -0
  96. package/dist/email/palette.d.ts +40 -0
  97. package/dist/email/palette.d.ts.map +1 -0
  98. package/dist/email/palette.js +44 -0
  99. package/dist/email/palette.js.map +1 -0
  100. package/dist/index.d.ts +4 -0
  101. package/dist/index.d.ts.map +1 -1
  102. package/dist/index.js +4 -0
  103. package/dist/index.js.map +1 -1
  104. package/dist/shadcn.css +41 -0
  105. package/dist/ui/dropdown-menu.d.ts +8 -1
  106. package/dist/ui/dropdown-menu.d.ts.map +1 -1
  107. package/dist/ui/dropdown-menu.js +9 -2
  108. package/dist/ui/dropdown-menu.js.map +1 -1
  109. package/package.json +17 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/badge/shared.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * The visitor's half of the badge: the feedback bubble and the feedback panel,
3
+ * with its sign-in step. Markup only; the badge wires the behaviour.
4
+ *
5
+ * Import from `@cloudgrid-io/ui/badge/visitor` in the badge's main file. The
6
+ * stylesheet for this half is `BADGE_BASE_CSS + BADGE_VISITOR_CSS`.
7
+ *
8
+ * Copy follows the spec of 2026-10-12. The word "React" is never used: the
9
+ * bubble's name is "Leave feedback on this app".
10
+ */
11
+ import { type SelectOption } from "./shared.js";
12
+ export { BADGE_BASE_CSS } from "./css-base.js";
13
+ export { BADGE_VISITOR_CSS } from "./css-visitor.js";
14
+ export { panel, scrim, select, switchControl, toggleRow } from "./shared.js";
15
+ export type { BadgeSide, PanelOptions, SelectOption, SelectOptions } from "./shared.js";
16
+ export { esc, href, glyph, wordmark, sign } from "./html.js";
17
+ export { badgeRoot, type BadgeRootOptions } from "./root.js";
18
+ export interface BubbleOptions {
19
+ /** The bubble's accessible name. */
20
+ label?: string;
21
+ /** The close x's accessible name. The bubble comes back on reload. */
22
+ closeLabel?: string;
23
+ }
24
+ /**
25
+ * The feedback bubble: a white speech bubble with a tail and no text, three
26
+ * icons (thumbs-up purple, wrench blue, chat green), drifting gently unless the
27
+ * viewer asks for reduced motion. A small x hides it until reload; it shows on
28
+ * hover, and always on a touch screen.
29
+ *
30
+ * Actions: `open-feedback` on the bubble, `hide-bubble` on the x.
31
+ */
32
+ export declare function bubble({ label, closeLabel, }?: BubbleOptions): string;
33
+ /** The five reaction kinds, as the API stores them. */
34
+ export type ReactionKind = "like" | "dislike" | "idea" | "ship" | "broken";
35
+ /** Each kind's glyph and its name, which is the button's accessible name and tooltip. */
36
+ export declare const REACTIONS: ReadonlyArray<{
37
+ kind: ReactionKind;
38
+ label: string;
39
+ paths: readonly string[];
40
+ }>;
41
+ /** Like and Dislike exclude each other: picking one clears the other. The rest combine freely. */
42
+ export declare function toggleReaction(pressed: readonly ReactionKind[], kind: ReactionKind): ReactionKind[];
43
+ /** The note's categories, as today's badge sends them. Other is the default. */
44
+ export declare const NOTE_CATEGORIES: readonly SelectOption[];
45
+ export interface VisitorPanelOptions {
46
+ /** The app's name. */
47
+ name: string;
48
+ /** Counts per kind. Each renders above zero, on all five reactions. */
49
+ counts?: Partial<Record<ReactionKind, number>>;
50
+ /** The kinds this visitor has already picked. */
51
+ pressed?: readonly ReactionKind[];
52
+ /** The note's category. Default `other`. */
53
+ category?: string;
54
+ /** Render the category menu open. */
55
+ categoryOpen?: boolean;
56
+ /** The note's text, when re-rendering. */
57
+ message?: string;
58
+ /** "Signed in as dana@atomiclabs.io". Absent: no hint. */
59
+ signedInAs?: string;
60
+ /** After Send: the note section is replaced by the sent line. */
61
+ sent?: boolean;
62
+ /** "This page is live on the grid. Learn more" points here. */
63
+ learnMoreUrl?: string;
64
+ /** `corner` (default) above the bubble. A phone shows a bottom sheet whatever this says. */
65
+ side?: "corner" | "right" | "left";
66
+ }
67
+ /**
68
+ * The feedback panel: the question, five reactions, and "Leave a note" under a
69
+ * divider. Actions: `reaction` (with `data-value` = the kind) on each reaction,
70
+ * `category` and `category-pick` on the menu, `send` on Send, `close`.
71
+ */
72
+ export declare function visitorPanel({ name, counts, pressed, category, categoryOpen, message, signedInAs, sent, learnMoreUrl, side, }: VisitorPanelOptions): string;
73
+ export interface VisitorSignInOptions {
74
+ name: string;
75
+ /** The line above the methods. Default "Sign in to leave feedback." */
76
+ line?: string;
77
+ /** Offer "Continue with Google" (`login-google`). Default true. */
78
+ google?: boolean;
79
+ /** The email field's value, when re-rendering. */
80
+ email?: string;
81
+ /** The status line beside Send sign-in link: "Check your inbox for the link." */
82
+ status?: string;
83
+ /** "Sign in on CloudGrid", the fallback that leaves the page. */
84
+ signInUrl: string;
85
+ learnMoreUrl?: string;
86
+ side?: "corner" | "right" | "left";
87
+ }
88
+ /**
89
+ * The sign-in step, today's badge restyled: on an app that requires sign-in, a
90
+ * signed-out visitor's panel opens here, then shows the reactions. Google,
91
+ * then an email link, then the CloudGrid sign-in page as the fallback.
92
+ *
93
+ * Actions: `login-google`, `login-email` (read `#cgb-email`), `signin` (a link).
94
+ */
95
+ export declare function visitorSignIn({ name, line, google, email, status, signInUrl, learnMoreUrl, side, }: VisitorSignInOptions): string;
96
+ //# sourceMappingURL=visitor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visitor.d.ts","sourceRoot":"","sources":["../../src/badge/visitor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * The visitor's half of the badge: the feedback bubble and the feedback panel,
3
+ * with its sign-in step. Markup only; the badge wires the behaviour.
4
+ *
5
+ * Import from `@cloudgrid-io/ui/badge/visitor` in the badge's main file. The
6
+ * stylesheet for this half is `BADGE_BASE_CSS + BADGE_VISITOR_CSS`.
7
+ *
8
+ * Copy follows the spec of 2026-10-12. The word "React" is never used: the
9
+ * bubble's name is "Leave feedback on this app".
10
+ */
11
+ import { BUG, CHAT_CIRCLE, CHECK_CIRCLE, GOOGLE_LOGO, LIGHTBULB_FILAMENT, ROCKET_LAUNCH, THUMBS_DOWN, THUMBS_UP, WRENCH, X } from "./marks.js";
12
+ import { esc, glyph, href } from "./html.js";
13
+ import { panel, select } from "./shared.js";
14
+ export { BADGE_BASE_CSS } from "./css-base.js";
15
+ export { BADGE_VISITOR_CSS } from "./css-visitor.js";
16
+ export { panel, scrim, select, switchControl, toggleRow } from "./shared.js";
17
+ export { esc, href, glyph, wordmark, sign } from "./html.js";
18
+ export { badgeRoot } from "./root.js";
19
+ /**
20
+ * The feedback bubble: a white speech bubble with a tail and no text, three
21
+ * icons (thumbs-up purple, wrench blue, chat green), drifting gently unless the
22
+ * viewer asks for reduced motion. A small x hides it until reload; it shows on
23
+ * hover, and always on a touch screen.
24
+ *
25
+ * Actions: `open-feedback` on the bubble, `hide-bubble` on the x.
26
+ */
27
+ export function bubble({ label = "Leave feedback on this app", closeLabel = "Hide feedback until you reload", } = {}) {
28
+ return (`<div class="cgb-bubble-wrap">` +
29
+ `<button class="cgb-bubble" type="button" data-action="open-feedback" aria-label="${esc(label)}" aria-haspopup="dialog">` +
30
+ `<span class="cgb-bubble-ic" data-tone="like">${glyph(THUMBS_UP)}</span>` +
31
+ `<span class="cgb-bubble-ic" data-tone="fix">${glyph(WRENCH)}</span>` +
32
+ `<span class="cgb-bubble-ic" data-tone="talk">${glyph(CHAT_CIRCLE)}</span>` +
33
+ `</button>` +
34
+ `<button class="cgb-bubble-x" type="button" data-action="hide-bubble" aria-label="${esc(closeLabel)}">${glyph(X)}</button>` +
35
+ `</div>`);
36
+ }
37
+ /** Each kind's glyph and its name, which is the button's accessible name and tooltip. */
38
+ export const REACTIONS = [
39
+ { kind: "like", label: "Like", paths: THUMBS_UP },
40
+ { kind: "dislike", label: "Dislike", paths: THUMBS_DOWN },
41
+ { kind: "idea", label: "Clever idea", paths: LIGHTBULB_FILAMENT },
42
+ { kind: "ship", label: "Ship it", paths: ROCKET_LAUNCH },
43
+ { kind: "broken", label: "Something’s broken", paths: BUG },
44
+ ];
45
+ /** Like and Dislike exclude each other: picking one clears the other. The rest combine freely. */
46
+ export function toggleReaction(pressed, kind) {
47
+ if (pressed.includes(kind))
48
+ return pressed.filter((k) => k !== kind);
49
+ const rival = kind === "like" ? "dislike" : kind === "dislike" ? "like" : null;
50
+ return [...pressed.filter((k) => k !== rival), kind];
51
+ }
52
+ // ---- the note ------------------------------------------------------------------
53
+ /** The note's categories, as today's badge sends them. Other is the default. */
54
+ export const NOTE_CATEGORIES = [
55
+ { value: "bug", label: "Bug" },
56
+ { value: "idea", label: "Idea" },
57
+ { value: "praise", label: "Praise" },
58
+ { value: "question", label: "Question" },
59
+ { value: "other", label: "Other" },
60
+ ];
61
+ const LEARN_MORE = "https://cloudgrid.io";
62
+ const footer = (url) => `<a class="cgb-made" href="${href(url)}" target="_blank" rel="noopener">This page is live on the grid. Learn more</a>`;
63
+ const title = (name) => `<h2 class="cgb-title">What do you think of ${esc(name)}?</h2>`;
64
+ /**
65
+ * The feedback panel: the question, five reactions, and "Leave a note" under a
66
+ * divider. Actions: `reaction` (with `data-value` = the kind) on each reaction,
67
+ * `category` and `category-pick` on the menu, `send` on Send, `close`.
68
+ */
69
+ export function visitorPanel({ name, counts = {}, pressed = [], category = "other", categoryOpen = false, message = "", signedInAs, sent = false, learnMoreUrl = LEARN_MORE, side = "corner", }) {
70
+ const reactions = REACTIONS.map(({ kind, label, paths }) => {
71
+ // Every kind shows its count to visitors, Dislike and Something's broken
72
+ // included (founder, 2026-10-12, reversing the positive-only rule).
73
+ const n = counts[kind];
74
+ const count = typeof n === "number" && n > 0 ? `<span class="cgb-rxc">${esc(n)}</span>` : "";
75
+ return (`<button class="cgb-rxb" type="button" data-action="reaction" data-value="${kind}" aria-pressed="${pressed.includes(kind)}" aria-label="${esc(label)}" title="${esc(label)}">` +
76
+ glyph(paths) +
77
+ count +
78
+ `</button>`);
79
+ }).join("");
80
+ const note = sent
81
+ ? `<p class="cgb-sent" role="status">${glyph(CHECK_CIRCLE)}Sent. The maker sees it on their Feedback page.</p>`
82
+ : `<div class="cgb-note">` +
83
+ `<div class="cgb-note-head"><label class="cgb-note-label" for="cgb-msg">Leave a note</label>` +
84
+ select({ label: "Category", options: NOTE_CATEGORIES, value: category, action: "category", open: categoryOpen }) +
85
+ `</div>` +
86
+ `<textarea class="cgb-textarea" id="cgb-msg" rows="3" placeholder="Optional. Tell the maker what you noticed.">${esc(message)}</textarea>` +
87
+ `<div class="cgb-note-actions"><span class="cgb-hint">${signedInAs ? `Signed in as ${esc(signedInAs)}` : ""}</span>` +
88
+ `<button class="cgb-btn" type="button" data-action="send">Send</button></div>` +
89
+ `</div>`;
90
+ return panel({
91
+ label: `Send feedback on ${name}`,
92
+ side,
93
+ body: title(name) + `<div class="cgb-rx" role="group" aria-label="Reactions">${reactions}</div>` + note + footer(learnMoreUrl),
94
+ });
95
+ }
96
+ /**
97
+ * The sign-in step, today's badge restyled: on an app that requires sign-in, a
98
+ * signed-out visitor's panel opens here, then shows the reactions. Google,
99
+ * then an email link, then the CloudGrid sign-in page as the fallback.
100
+ *
101
+ * Actions: `login-google`, `login-email` (read `#cgb-email`), `signin` (a link).
102
+ */
103
+ export function visitorSignIn({ name, line = "Sign in to leave feedback.", google = true, email = "", status = "", signInUrl, learnMoreUrl = LEARN_MORE, side = "corner", }) {
104
+ const body = title(name) +
105
+ `<p class="cgb-desc">${esc(line)}</p>` +
106
+ `<div class="cgb-signin">` +
107
+ (google
108
+ ? `<button class="cgb-method" type="button" data-action="login-google">${glyph(GOOGLE_LOGO)}Continue with Google</button><div class="cgb-or" aria-hidden="true">OR</div>`
109
+ : "") +
110
+ `<label class="cgb-field-label" for="cgb-email">Email</label>` +
111
+ `<input class="cgb-input" id="cgb-email" type="email" autocomplete="email" placeholder="you@example.com" value="${esc(email)}">` +
112
+ `<div class="cgb-note-actions"><span class="cgb-hint" role="status">${esc(status)}</span>` +
113
+ `<button class="cgb-btn" type="button" data-action="login-email">Send sign-in link</button></div>` +
114
+ `<a class="cgb-link" href="${href(signInUrl)}" target="_top" data-action="signin">Sign in on CloudGrid</a>` +
115
+ `</div>` +
116
+ footer(learnMoreUrl);
117
+ return panel({ label: `Send feedback on ${name}`, side, body });
118
+ }
119
+ //# sourceMappingURL=visitor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visitor.js","sourceRoot":"","sources":["../../src/badge/visitor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,81 @@
1
+ import * as React from "react";
2
+ /**
3
+ * Type-to-confirm delete (Shelf spec 2026-10-07, Part B).
4
+ *
5
+ * The library's one destructive confirmation. The Console built its own,
6
+ * `components/entity/DeleteEntityModal.tsx`, which this replaces: same gate (the
7
+ * button stays disabled until the typed text matches), same refusal to close
8
+ * while the request is in flight, same error slot under the field. What changed
9
+ * is the copy, because Delete is now a real delete (Part D): the old modal said
10
+ * the record is retained, and that stops being true.
11
+ *
12
+ * ```
13
+ * Delete Top 10 Mobile? [x]
14
+ * This removes it from CloudGrid for good. Its link stops
15
+ * working and it can't be brought back.
16
+ * Type top-10-mobile to confirm
17
+ * [ top-10-mobile ]
18
+ * [Cancel] [Delete]
19
+ * ```
20
+ *
21
+ * ## Generic on purpose
22
+ *
23
+ * Nothing here knows about the Shelf. `name` is what the title says, and
24
+ * `confirmText` is what the reader types: the Figma frame types the SLUG
25
+ * (`top-10-mobile`) under a title that shows the display name, which is the
26
+ * right split, because a slug is unambiguous and has no capitals or spaces to
27
+ * get wrong. `confirmText` falls back to `name` for a caller with no slug.
28
+ *
29
+ * ## The gate
30
+ *
31
+ * The typed text is trimmed and compared exactly. Not case-folded: a slug is
32
+ * lower case by construction, and a display name typed with the wrong case is
33
+ * the reader not looking, which is what the gate is for. Enter submits through
34
+ * a real `<form>`, so the keyboard path is the same gate as the button.
35
+ *
36
+ * ## While pending
37
+ *
38
+ * `pending` disables the field and both buttons and swallows every close
39
+ * (Escape, the scrim, the close glyph): a dialog that closes on a request still
40
+ * running leaves the reader no place to see it fail. The caller closes it
41
+ * (`onOpenChange(false)`) when the request resolves, and passes `error` when it
42
+ * rejects.
43
+ *
44
+ * ## The red
45
+ *
46
+ * The filled Delete is `--cg-danger-strong` under `--cg-text-on-primary`: the
47
+ * Figma frame's red is the Console's "Failed" status, which the library already
48
+ * carries as `danger-strong` (5.70:1 on white; white on it measures above 5:1).
49
+ * `--cg-danger` itself is still a placeholder in `tokens.css`, which is the
50
+ * known gap CLAUDE.md records; this reads the strong rung so the button does not
51
+ * move if the placeholder is retuned.
52
+ */
53
+ /** The consequence line under the title, when the caller does not pass one. */
54
+ export declare const CONFIRM_DELETE_DESCRIPTION = "This removes it from CloudGrid for good. Its link stops working and it can't be brought back.";
55
+ export type ConfirmDeleteDialogProps = {
56
+ open: boolean;
57
+ onOpenChange: (open: boolean) => void;
58
+ /** What the title names: "Delete {name}?". */
59
+ name: string;
60
+ /** What the reader types to arm the button. Defaults to `name`. */
61
+ confirmText?: string;
62
+ /** Runs when the armed button is pressed or Enter is hit in the field. */
63
+ onConfirm: () => void | Promise<void>;
64
+ /** The request is in flight: everything is disabled and the dialog will not close. */
65
+ pending?: boolean;
66
+ /** Shown under the field, announced as an alert. */
67
+ error?: React.ReactNode;
68
+ /** Overrides the title. */
69
+ title?: React.ReactNode;
70
+ /** Overrides the consequence line. */
71
+ description?: React.ReactNode;
72
+ /** The armed button's word. */
73
+ confirmLabel?: string;
74
+ /** The button's word while `pending`. */
75
+ pendingLabel?: string;
76
+ cancelLabel?: string;
77
+ className?: string;
78
+ };
79
+ declare function ConfirmDeleteDialog({ open, onOpenChange, name, confirmText, onConfirm, pending, error, title, description, confirmLabel, pendingLabel, cancelLabel, className, }: ConfirmDeleteDialogProps): React.JSX.Element;
80
+ export { ConfirmDeleteDialog };
81
+ //# sourceMappingURL=confirm-delete-dialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirm-delete-dialog.d.ts","sourceRoot":"","sources":["../../src/blocks/confirm-delete-dialog.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAa9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAEH,+EAA+E;AAC/E,eAAO,MAAM,0BAA0B,kGAC0D,CAAA;AAEjG,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAA;IACZ,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,0EAA0E;IAC1E,SAAS,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACrC,sFAAsF;IACtF,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,oDAAoD;IACpD,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,sCAAsC;IACtC,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,+BAA+B;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,yCAAyC;IACzC,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,iBAAS,mBAAmB,CAAC,EAC3B,IAAI,EACJ,YAAY,EACZ,IAAI,EACJ,WAAW,EACX,SAAS,EACT,OAAe,EACf,KAAK,EACL,KAAK,EACL,WAAwC,EACxC,YAAuB,EACvB,YAAyB,EACzB,WAAsB,EACtB,SAAS,GACV,EAAE,wBAAwB,qBAsF1B;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAA"}
@@ -0,0 +1,89 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cn } from "../lib/cloudgrid-cn.js";
5
+ import { Button } from "../ui/button.js";
6
+ import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from "../ui/dialog.js";
7
+ import { Input } from "../ui/input.js";
8
+ /**
9
+ * Type-to-confirm delete (Shelf spec 2026-10-07, Part B).
10
+ *
11
+ * The library's one destructive confirmation. The Console built its own,
12
+ * `components/entity/DeleteEntityModal.tsx`, which this replaces: same gate (the
13
+ * button stays disabled until the typed text matches), same refusal to close
14
+ * while the request is in flight, same error slot under the field. What changed
15
+ * is the copy, because Delete is now a real delete (Part D): the old modal said
16
+ * the record is retained, and that stops being true.
17
+ *
18
+ * ```
19
+ * Delete Top 10 Mobile? [x]
20
+ * This removes it from CloudGrid for good. Its link stops
21
+ * working and it can't be brought back.
22
+ * Type top-10-mobile to confirm
23
+ * [ top-10-mobile ]
24
+ * [Cancel] [Delete]
25
+ * ```
26
+ *
27
+ * ## Generic on purpose
28
+ *
29
+ * Nothing here knows about the Shelf. `name` is what the title says, and
30
+ * `confirmText` is what the reader types: the Figma frame types the SLUG
31
+ * (`top-10-mobile`) under a title that shows the display name, which is the
32
+ * right split, because a slug is unambiguous and has no capitals or spaces to
33
+ * get wrong. `confirmText` falls back to `name` for a caller with no slug.
34
+ *
35
+ * ## The gate
36
+ *
37
+ * The typed text is trimmed and compared exactly. Not case-folded: a slug is
38
+ * lower case by construction, and a display name typed with the wrong case is
39
+ * the reader not looking, which is what the gate is for. Enter submits through
40
+ * a real `<form>`, so the keyboard path is the same gate as the button.
41
+ *
42
+ * ## While pending
43
+ *
44
+ * `pending` disables the field and both buttons and swallows every close
45
+ * (Escape, the scrim, the close glyph): a dialog that closes on a request still
46
+ * running leaves the reader no place to see it fail. The caller closes it
47
+ * (`onOpenChange(false)`) when the request resolves, and passes `error` when it
48
+ * rejects.
49
+ *
50
+ * ## The red
51
+ *
52
+ * The filled Delete is `--cg-danger-strong` under `--cg-text-on-primary`: the
53
+ * Figma frame's red is the Console's "Failed" status, which the library already
54
+ * carries as `danger-strong` (5.70:1 on white; white on it measures above 5:1).
55
+ * `--cg-danger` itself is still a placeholder in `tokens.css`, which is the
56
+ * known gap CLAUDE.md records; this reads the strong rung so the button does not
57
+ * move if the placeholder is retuned.
58
+ */
59
+ /** The consequence line under the title, when the caller does not pass one. */
60
+ export const CONFIRM_DELETE_DESCRIPTION = "This removes it from CloudGrid for good. Its link stops working and it can't be brought back.";
61
+ function ConfirmDeleteDialog({ open, onOpenChange, name, confirmText, onConfirm, pending = false, error, title, description = CONFIRM_DELETE_DESCRIPTION, confirmLabel = "Delete", pendingLabel = "Deleting", cancelLabel = "Cancel", className, }) {
62
+ const target = confirmText ?? name;
63
+ const [typed, setTyped] = React.useState("");
64
+ const fieldId = React.useId();
65
+ const errorId = React.useId();
66
+ const field = React.useRef(null);
67
+ const matches = typed.trim() === target;
68
+ // A fresh field every time the dialog opens. Clearing on close instead would
69
+ // empty the field during the closing animation, which reads as the dialog
70
+ // undoing what the reader typed.
71
+ React.useEffect(() => {
72
+ if (open)
73
+ setTyped("");
74
+ }, [open]);
75
+ function changeOpen(next) {
76
+ if (!next && pending)
77
+ return;
78
+ onOpenChange(next);
79
+ }
80
+ function submit(event) {
81
+ event.preventDefault();
82
+ if (!matches || pending)
83
+ return;
84
+ void onConfirm();
85
+ }
86
+ return (_jsx(Dialog, { open: open, onOpenChange: changeOpen, children: _jsxs(DialogContent, { "data-slot": "confirm-delete-dialog", initialFocus: field, className: cn("gap-5 p-6 sm:max-w-md", className), children: [_jsxs(DialogHeader, { className: "gap-3 pr-8", children: [_jsx(DialogTitle, { className: "text-heading-sm leading-tight", children: title ?? `Delete ${name}?` }), _jsx(DialogDescription, { className: "text-body-sm text-body", children: description })] }), _jsxs("form", { className: "grid gap-5", onSubmit: submit, noValidate: true, children: [_jsxs("div", { className: "grid gap-2", children: [_jsxs("label", { htmlFor: fieldId, className: "text-body-sm font-medium text-ink", children: ["Type ", _jsx("span", { className: "font-mono text-mono", children: target }), " to confirm"] }), _jsx(Input, { ref: field, id: fieldId, value: typed, onChange: (event) => setTyped(event.target.value), disabled: pending, autoComplete: "off", autoCapitalize: "off", spellCheck: false, "aria-describedby": error ? errorId : undefined, "data-slot": "confirm-delete-field" }), error ? (_jsx("p", { id: errorId, role: "alert", className: "m-0 text-caption text-danger-strong", children: error })) : null] }), _jsxs("div", { className: "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", children: [_jsx(Button, { type: "button", variant: "outline", disabled: pending, onClick: () => changeOpen(false), children: cancelLabel }), _jsx(Button, { type: "submit", disabled: !matches || pending, "data-slot": "confirm-delete-submit", className: "bg-danger-strong text-on-primary hover:bg-danger-strong/90 focus-visible:border-danger-strong focus-visible:ring-danger-border", children: pending ? pendingLabel : confirmLabel })] })] })] }) }));
87
+ }
88
+ export { ConfirmDeleteDialog };
89
+ //# sourceMappingURL=confirm-delete-dialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirm-delete-dialog.js","sourceRoot":"","sources":["../../src/blocks/confirm-delete-dialog.tsx"],"names":[],"mappings":"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"}
@@ -132,5 +132,48 @@ declare function EntityStateDot({ status, label, className, ...props }: Omit<Rea
132
132
  /** Overrides the announced word. There is no visible word to override. */
133
133
  label?: React.ReactNode;
134
134
  }): import("react").JSX.Element;
135
- export { EntityStatus, EntityStateDot };
135
+ /**
136
+ * HOW SOON SOMETHING EXPIRES. The tag a card and the page header show from five
137
+ * days before expiry (ui#295, spec "Expiry warning and Keep", 2026-10-11).
138
+ *
139
+ * Not a status. "Expires in 5 days" is not something an entity IS: the
140
+ * platform's status for the same page is still `live`, or `charged` for an app
141
+ * that was never published. So it is its own component beside `EntityStatus`
142
+ * rather than an eleventh row in the status table, and the ten statuses above
143
+ * are unchanged. A surface shows this INSTEAD of the status chip while
144
+ * something is about to expire, which is the spec's rule for the card.
145
+ *
146
+ * ## Two tones, from the number
147
+ *
148
+ * More than one day left is the amber of `expired` (`soon`). One day left, or
149
+ * less, is the red of `error` (`urgent`): the spec's "urgent on the last day".
150
+ * The caller passes the whole days left and nothing else, so no surface can
151
+ * paint "Expires tomorrow" amber.
152
+ *
153
+ * ## The word is coloured here, unlike `EntityStatus`
154
+ *
155
+ * The founder-approved mock draws the word in the state colour with a border,
156
+ * and the tokens for it exist: `--cg-expired-strong` and `--cg-danger-strong`
157
+ * are the TEXT tones of those states (7.63:1 and 5.02:1 on their fills, per their
158
+ * notes in tokens.css), not the indicator tones `EntityStatus` refuses to put
159
+ * on a word. On the purple and ink surfaces both strong tokens resolve to the
160
+ * surface's own text colour and the fill to a translucent wash, so the chip
161
+ * flips with no help. The dot stays, and the word always renders, so the tone
162
+ * is never colour alone: the urgent chip SAYS "tomorrow".
163
+ */
164
+ export type EntityExpiryTone = "soon" | "urgent";
165
+ /** `urgent` on the last day (one day left or fewer), `soon` before it. */
166
+ export declare function entityExpiryTone(daysLeft: number): EntityExpiryTone;
167
+ /**
168
+ * The words, from whole days left. "Expires in 5 days", "Expires tomorrow",
169
+ * "Expires today". The number is always the real one.
170
+ */
171
+ export declare function entityExpiryLabel(daysLeft: number): string;
172
+ declare function EntityExpiryStatus({ daysLeft, label, className, ...props }: Omit<React.ComponentProps<"span">, "children"> & {
173
+ /** Whole days until expiry. 1 is tomorrow, 0 is today. */
174
+ daysLeft: number;
175
+ /** Overrides the default words. The tone still follows `daysLeft`. */
176
+ label?: React.ReactNode;
177
+ }): import("react").JSX.Element;
178
+ export { EntityStatus, EntityStateDot, EntityExpiryStatus };
136
179
  //# sourceMappingURL=entity-status.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"entity-status.d.ts","sourceRoot":"","sources":["../../src/blocks/entity-status.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,qHAWtB,CAAA;AAEV,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAA;AAEnE,kEAAkE;AAClE,MAAM,MAAM,gBAAgB,GACxB,QAAQ,GACR,WAAW,GACX,SAAS,GACT,SAAS,GACT,SAAS,GACT,QAAQ,CAAA;AAEZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,gBAAgB,EAAE,gBAAgB,CAWzE,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAehE,CAAA;AAmBD,iBAAS,YAAY,CAAC,EACpB,MAAM,EACN,KAAK,EACL,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,GAAG;IAClD,MAAM,EAAE,gBAAgB,CAAA;IACxB,sFAAsF;IACtF,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CACxB,+BAqCA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,iBAAS,cAAc,CAAC,EACtB,MAAM,EACN,KAAK,EACL,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,GAAG;IAClD,MAAM,EAAE,gBAAgB,CAAA;IACxB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CACxB,+BAwBA;AAED,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,CAAA"}
1
+ {"version":3,"file":"entity-status.d.ts","sourceRoot":"","sources":["../../src/blocks/entity-status.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,qHAWtB,CAAA;AAEV,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAA;AAEnE,kEAAkE;AAClE,MAAM,MAAM,gBAAgB,GACxB,QAAQ,GACR,WAAW,GACX,SAAS,GACT,SAAS,GACT,SAAS,GACT,QAAQ,CAAA;AAEZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,gBAAgB,EAAE,gBAAgB,CAWzE,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAehE,CAAA;AAmBD,iBAAS,YAAY,CAAC,EACpB,MAAM,EACN,KAAK,EACL,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,GAAG;IAClD,MAAM,EAAE,gBAAgB,CAAA;IACxB,sFAAsF;IACtF,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CACxB,+BAqCA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,iBAAS,cAAc,CAAC,EACtB,MAAM,EACN,KAAK,EACL,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,GAAG;IAClD,MAAM,EAAE,gBAAgB,CAAA;IACxB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CACxB,+BAwBA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,QAAQ,CAAA;AAEhD,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAEnE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAK1D;AAOD,iBAAS,kBAAkB,CAAC,EAC1B,QAAQ,EACR,KAAK,EACL,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,GAAG;IAClD,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAA;IAChB,sEAAsE;IACtE,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CACxB,+BAwBA;AAED,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAA"}
@@ -192,5 +192,30 @@ function EntityStateDot({ status, label, className, ...props }) {
192
192
  // consumer's repo and a rule in our stylesheet does not.
193
193
  status === "building" && "motion-safe:animate-pulse", className), ...props, children: _jsx("span", { className: "sr-only", children: label ?? ENTITY_STATUS_LABEL[status] }) }));
194
194
  }
195
- export { EntityStatus, EntityStateDot };
195
+ /** `urgent` on the last day (one day left or fewer), `soon` before it. */
196
+ export function entityExpiryTone(daysLeft) {
197
+ return daysLeft <= 1 ? "urgent" : "soon";
198
+ }
199
+ /**
200
+ * The words, from whole days left. "Expires in 5 days", "Expires tomorrow",
201
+ * "Expires today". The number is always the real one.
202
+ */
203
+ export function entityExpiryLabel(daysLeft) {
204
+ const days = Math.max(0, Math.floor(daysLeft));
205
+ if (days === 0)
206
+ return "Expires today";
207
+ if (days === 1)
208
+ return "Expires tomorrow";
209
+ return `Expires in ${days} days`;
210
+ }
211
+ const EXPIRY_STYLE = {
212
+ soon: { chip: "border-expired-border bg-expired-fill text-expired-strong", dot: "bg-expired" },
213
+ urgent: { chip: "border-danger-border bg-danger-fill text-danger-strong", dot: "bg-danger" },
214
+ };
215
+ function EntityExpiryStatus({ daysLeft, label, className, ...props }) {
216
+ const tone = entityExpiryTone(daysLeft);
217
+ const style = EXPIRY_STYLE[tone];
218
+ return (_jsxs("span", { "data-slot": "entity-expiry-status", "data-tone": tone, "data-days-left": Math.max(0, Math.floor(daysLeft)), className: cn("inline-flex w-fit shrink-0 items-center gap-1.5 rounded-pill border px-2.5 py-0.5 text-caption font-medium whitespace-nowrap", style.chip, className), ...props, children: [_jsx("span", { "aria-hidden": "true", "data-slot": "entity-expiry-status-dot", className: cn("size-1.5 shrink-0 rounded-pill", style.dot) }), label ?? entityExpiryLabel(daysLeft)] }));
219
+ }
220
+ export { EntityStatus, EntityStateDot, EntityExpiryStatus };
196
221
  //# sourceMappingURL=entity-status.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"entity-status.js","sourceRoot":"","sources":["../../src/blocks/entity-status.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"entity-status.js","sourceRoot":"","sources":["../../src/blocks/entity-status.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ import * as React from "react";
2
+ /**
3
+ * THE EXPIRY NOTICE. The row an item's page shows while it is about to expire,
4
+ * or after it has (ui#295, spec "Expiry warning and Keep", 2026-10-11).
5
+ *
6
+ * ```
7
+ * This page expires in 5 days. [ Keep ]
8
+ * Nobody has opened it in 25 days. Keep it and it won't expire.
9
+ * ```
10
+ *
11
+ * It is the Console's app-page status row (`AppStateBanner`, the row that says
12
+ * Paused, Building and the rest) with a ground: one sentence, one reason, at
13
+ * most one action, the action under the sentence on a phone. The type matches
14
+ * that row: the sentence 16px semibold, the reason a step down in the secondary
15
+ * tone. The founder-approved mock tints it so it reads as a warning rather than
16
+ * a resting state.
17
+ *
18
+ * ## Variants
19
+ *
20
+ * - `soon`: five days to one day before. The amber of the expired state.
21
+ * - `urgent`: the last day. The danger fill.
22
+ * - `from-email`: the reader arrived from the warning email's Keep link. The
23
+ * brand tint with a 2px brand outline, and the Console passes `focusAction` so
24
+ * Keep has focus and is one press away. The link never keeps by itself, since
25
+ * email scanners open every link; this is the click that does.
26
+ * - `expired`: after expiry, before the Shelf. The same amber as `soon`; the
27
+ * words are what differ ("This page expired.").
28
+ *
29
+ * No action is a variant of its own in effect, not a value: leave `action` out
30
+ * for a member who is not the owner or a grid admin and cannot keep it. The
31
+ * row still says what is happening and the reason line says who can act.
32
+ *
33
+ * ## Accessibility
34
+ *
35
+ * `role="status"`, like the Console row it matches: a polite region, so a
36
+ * notice that appears while the reader is on the page is announced without
37
+ * taking focus. Not `alert`: nothing here is an error and nothing interrupts.
38
+ * The region is named (`label`, "Expiry" by default) so a reader moving by
39
+ * region hears what it is about.
40
+ *
41
+ * The action is a real `<button>`, described by the sentence
42
+ * (`aria-describedby`), so a screen reader that lands on "Keep" hears what it
43
+ * keeps and when it expires. The tone is never colour alone: the sentence
44
+ * carries it ("expires tomorrow", "expired"), and the from-email outline is a
45
+ * shape as well as a colour.
46
+ *
47
+ * ## Surfaces
48
+ *
49
+ * `soon`, `urgent` and `expired` are tokens all the way down: on the purple
50
+ * panel and on ink the fills resolve to a translucent wash and the words to the
51
+ * surface's text, with no help. `from-email` is a self-contained light card on
52
+ * every surface (`data-theme="default"`, the base scope tokens.css declares
53
+ * beside `:root`), the arrangement `EntityCard`'s panel and `ShowcaseScroll`
54
+ * use: `--cg-primary-tint` does not flip, so ink-on-tint has to be kept inside
55
+ * it rather than inherited as white-on-tint.
56
+ */
57
+ export declare const EXPIRY_NOTICE_VARIANTS: readonly ["soon", "urgent", "from-email", "expired"];
58
+ export type ExpiryNoticeVariant = (typeof EXPIRY_NOTICE_VARIANTS)[number];
59
+ export interface ExpiryNoticeAction {
60
+ /** The word on the button. "Keep" in every spec'd case. */
61
+ label: string;
62
+ onClick: () => void;
63
+ /** While the request is in flight: the button is disabled and says `pendingLabel`. */
64
+ pending?: boolean;
65
+ /** Defaults to "Keeping…". */
66
+ pendingLabel?: string;
67
+ }
68
+ export interface ExpiryNoticeProps extends Omit<React.ComponentProps<"section">, "title" | "children"> {
69
+ variant: ExpiryNoticeVariant;
70
+ /** The sentence. "This page expires in 5 days." */
71
+ title: React.ReactNode;
72
+ /** The reason, or who can act. "Nobody has opened it in 25 days. Keep it and it won't expire." */
73
+ reason?: React.ReactNode;
74
+ /** Leave out for a reader who cannot keep it. */
75
+ action?: ExpiryNoticeAction;
76
+ /**
77
+ * Focus the action when the notice mounts. For the arrival from the email
78
+ * (`from-email`); ignored when there is no action.
79
+ */
80
+ focusAction?: boolean;
81
+ /** The region's name. Defaults to "Expiry". */
82
+ label?: string;
83
+ }
84
+ declare function ExpiryNotice({ variant, title, reason, action, focusAction, label, className, ...props }: ExpiryNoticeProps): React.JSX.Element;
85
+ export { ExpiryNotice };
86
+ //# sourceMappingURL=expiry-notice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expiry-notice.d.ts","sourceRoot":"","sources":["../../src/blocks/expiry-notice.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAK9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AAEH,eAAO,MAAM,sBAAsB,sDAAuD,CAAA;AAE1F,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAA;AAEzE,MAAM,WAAW,kBAAkB;IACjC,2DAA2D;IAC3D,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,sFAAsF;IACtF,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,8BAA8B;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,iBACf,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;IACnE,OAAO,EAAE,mBAAmB,CAAA;IAC5B,mDAAmD;IACnD,KAAK,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,kGAAkG;IAClG,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACxB,iDAAiD;IACjD,MAAM,CAAC,EAAE,kBAAkB,CAAA;IAC3B;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AASD,iBAAS,YAAY,CAAC,EACpB,OAAO,EACP,KAAK,EACL,MAAM,EACN,MAAM,EACN,WAAmB,EACnB,KAAgB,EAChB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,iBAAiB,qBA6DnB;AAED,OAAO,EAAE,YAAY,EAAE,CAAA"}