@ciromaciel/dashboard-kit 1.0.4 → 1.1.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 CHANGED
@@ -41,7 +41,8 @@ function Projects({ rows, loading }) {
41
41
  | `SectionCard` · `Field` · `FieldStacked` · `CardActions` | The section card |
42
42
  | `PageHeader` | Title and breadcrumb |
43
43
  | `HoldToConfirmButton` · `HoldToConfirmIcon` | The reversible destructive confirm |
44
- | `DeleteModal` · `deleteTitleScale` | The top of the escalation: reversible → hold → this |
44
+ | `DeleteModal` · `deleteTitleScale` | The top of the escalation: reversible → hold → this. `before` holds the way out (backup) |
45
+ | `DangerZone` | The door to `DeleteModal` at the end of a settings page |
45
46
  | `AuthLoader` · `AuthScreen` · `AUTH_LABELS` · `AUTH_TEXTS` | The moment the dashboard does not know who you are |
46
47
  | `Wordmark` | The mark, in two roles (`variant="mark"` / `"label"`). The name comes by prop |
47
48
  | `ZenLabel` · `notify` · `NOTIFICATIONS_PROPS` · `NOTIFY_DESCRIPTION_CSS` · `notificationTheme` | Label and notice |
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@ciromaciel/dashboard-kit",
3
- "version": "1.0.4",
3
+ "version": "1.1.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
- "description": "The components every dashboard shares: table, empty state, loading state, destructive confirm and wordmark.",
6
+ "description": "The components every dashboard shares: table, empty state, loading state, destructive confirm, danger zone and wordmark.",
7
7
  "main": "src/index.js",
8
8
  "files": [
9
9
  "src",
@@ -0,0 +1,25 @@
1
+ /*
2
+ * The row reflows by width: label · description · action on a wide card, one
3
+ * column on a phone. A media query cannot live in inline style, and a
4
+ * `useMediaQuery` would render the wrong layout on the first frame.
5
+ */
6
+ .rlg-danger-zone {
7
+ border: 1px solid var(--mantine-color-red-2);
8
+ background: var(--mantine-color-body, #fff);
9
+ }
10
+
11
+ .rlg-danger-row {
12
+ display: grid;
13
+ grid-template-columns: minmax(0, 1fr);
14
+ gap: 10px;
15
+ align-items: center;
16
+ padding: 16px;
17
+ }
18
+
19
+ @media (min-width: 48em) {
20
+ .rlg-danger-row {
21
+ grid-template-columns: minmax(160px, 220px) minmax(0, 1fr) auto;
22
+ gap: 8px 24px;
23
+ padding: 16px 20px;
24
+ }
25
+ }
@@ -0,0 +1,106 @@
1
+ import { Box, Button, Group, Stack, Text } from '@mantine/core'
2
+ import { IconAlertTriangle, IconTrash } from '@tabler/icons-react'
3
+
4
+ import './DangerZone.css'
5
+
6
+ /**
7
+ * The danger zone — the door to an irreversible action on a settings page.
8
+ *
9
+ * An audit found six versions across seven panels: "Danger Zone" in English,
10
+ * "Zona de perigo", "Zona de risco" with a gray eyebrow, red borders from red.2
11
+ * to red.6, filled, light and outline buttons, and one panel with no zone at
12
+ * all — the delete hidden inside a collapsed "advanced" card. None of it
13
+ * encoded a difference in the product.
14
+ *
15
+ * The door says what happens in one sentence and nothing else. The inventory
16
+ * and the backup exit belong to `DeleteModal`, which measures on open; showing
17
+ * them here too would put the same list in two places and fetch it on every
18
+ * visit to a page people open to rename things.
19
+ *
20
+ * @param {object} props
21
+ * @param {string} props.title The action, verb first: "Excluir projeto".
22
+ * @param {string} props.description What is lost, in one sentence.
23
+ * @param {Function} props.onAction Opens the confirmation. Never deletes directly.
24
+ * @param {string} props.actionLabel Defaults to `${title}…` — the ellipsis says a step follows.
25
+ * @param {string} props.hint
26
+ * @param {boolean} props.disabled
27
+ * @param {boolean} props.loading
28
+ * @param {string} props.eyebrow Same word as DeleteModal's.
29
+ */
30
+ export function DangerZone({ title, description, onAction, actionLabel = `${title}…`, hint = 'Irreversível', disabled = false, loading = false, eyebrow = 'Zona de risco' }) {
31
+ return (
32
+ <Box
33
+ className="rlg-danger-zone"
34
+ component="section"
35
+ aria-label={eyebrow}
36
+ >
37
+ <Group
38
+ gap={6}
39
+ wrap="nowrap"
40
+ px={{ base: 16, sm: 20 }}
41
+ pt={14}
42
+ >
43
+ <IconAlertTriangle
44
+ size={13}
45
+ stroke={2.5}
46
+ style={{ color: 'var(--mantine-color-red-6)', flex: 'none' }}
47
+ />
48
+ <Text
49
+ fz={10}
50
+ fw={800}
51
+ c="red.6"
52
+ tt="uppercase"
53
+ lts="1.5px"
54
+ >
55
+ {eyebrow}
56
+ </Text>
57
+ </Group>
58
+
59
+ <Box className="rlg-danger-row">
60
+ <Stack gap={2}>
61
+ <Text
62
+ fz={13}
63
+ fw={800}
64
+ c="gray.9"
65
+ >
66
+ {title}
67
+ </Text>
68
+ {hint ? (
69
+ <Text
70
+ fz={12}
71
+ c="gray.5"
72
+ lh={1.4}
73
+ >
74
+ {hint}
75
+ </Text>
76
+ ) : null}
77
+ </Stack>
78
+
79
+ <Text
80
+ fz={13}
81
+ c="gray.6"
82
+ lh={1.5}
83
+ >
84
+ {description}
85
+ </Text>
86
+
87
+ <Button
88
+ className="rlg-danger"
89
+ color="red.7"
90
+ variant="outline"
91
+ leftSection={
92
+ <IconTrash
93
+ size={14}
94
+ stroke={1.5}
95
+ />
96
+ }
97
+ onClick={onAction}
98
+ disabled={disabled}
99
+ loading={loading}
100
+ >
101
+ {actionLabel}
102
+ </Button>
103
+ </Box>
104
+ </Box>
105
+ )
106
+ }
@@ -88,6 +88,7 @@ export function deleteTitleScale(value) {
88
88
  * @param {boolean} props.loading
89
89
  * @param {boolean} props.caseSensitive See `matches` below.
90
90
  * @param {string} props.eyebrow
91
+ * @param {ReactNode} props.before The way out before confirming — a backup, an export.
91
92
  */
92
93
  export function DeleteModal({
93
94
  opened,
@@ -102,6 +103,7 @@ export function DeleteModal({
102
103
  loading = false,
103
104
  caseSensitive = false,
104
105
  eyebrow = 'Zona de risco',
106
+ before = null,
105
107
  }) {
106
108
  const [typed, setTyped] = useState('')
107
109
 
@@ -232,6 +234,12 @@ export function DeleteModal({
232
234
  </Box>
233
235
  ) : null}
234
236
 
237
+ {/*
238
+ * The exit comes BEFORE the field: offering the backup after
239
+ * the confirmation is offering it too late.
240
+ */}
241
+ {before ? <Box mt={24}>{before}</Box> : null}
242
+
235
243
  {/*
236
244
  * No rule before the confirmation — the footer's is the only
237
245
  * one. Two hairlines inside 520px cut the modal into three
@@ -319,6 +327,7 @@ export function DeleteModal({
319
327
  gap={8}
320
328
  >
321
329
  <Button
330
+ className="rlg-danger"
322
331
  color="red.7"
323
332
  onClick={confirm}
324
333
  disabled={!canDelete}
@@ -105,6 +105,7 @@ export function HoldToConfirmIcon({ icon, label, onConfirm, disabled, color = 'r
105
105
  />
106
106
  )}
107
107
  <ActionIcon
108
+ className="rlg-danger"
108
109
  color={active ? color : 'gray'}
109
110
  aria-label={label}
110
111
  disabled={disabled}
@@ -128,6 +129,7 @@ export function HoldToConfirmButton({ children, holdingLabel, onConfirm, disable
128
129
 
129
130
  return (
130
131
  <Button
132
+ className="rlg-danger"
131
133
  color="red.6"
132
134
  disabled={disabled}
133
135
  loading={loading}
package/src/index.js CHANGED
@@ -56,6 +56,11 @@ export { HoldToConfirmIcon, HoldToConfirmButton } from './components/HoldToConfi
56
56
  // of them across the seven panels and no two alike, so the shape lives here
57
57
  // now. `design-system/10-modal-de-exclusao.md` says why.
58
58
  export { DeleteModal, deleteTitleScale } from './components/DeleteModal'
59
+
60
+ // ── The danger zone ──────────────────────────────────────────────────────
61
+ // The door to the modal above, at the end of a settings page. One sentence and
62
+ // one button; the inventory and the backup live in the modal.
63
+ export { DangerZone } from './components/DangerZone'
59
64
  export { ZenLabel } from './components/ZenLabel'
60
65
  export { notify } from './components/notify'
61
66
  export { NOTIFICATIONS_PROPS, NOTIFY_DESCRIPTION_CSS, notificationTheme } from './components/notify-theme'
package/src/tokens.css CHANGED
@@ -45,3 +45,14 @@
45
45
  */
46
46
  --rlg-status-up: #16a34a;
47
47
  }
48
+
49
+ /*
50
+ * The focus ring of a destructive control is red.
51
+ *
52
+ * Mantine draws every ring in the primary colour — gray.9 in all seven themes —
53
+ * so a red outline button showed a black ring the moment focus returned to it
54
+ * after closing its modal. `.rlg-danger` marks the kit's destructive controls.
55
+ */
56
+ .rlg-danger:focus-visible {
57
+ outline-color: var(--mantine-color-red-7);
58
+ }