@kopexa/grc 0.0.3 → 0.0.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.
@@ -13,7 +13,7 @@ import { EditIcon } from "@kopexa/icons";
13
13
  import { Button, Card, Chip, Heading, Select, Textarea } from "@kopexa/sight";
14
14
  import { impactCard } from "@kopexa/theme";
15
15
  import { useState } from "react";
16
- import { jsx, jsxs } from "react/jsx-runtime";
16
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
17
17
  function ImpactItemRow({
18
18
  label,
19
19
  shortLabel,
@@ -82,15 +82,18 @@ function ImpactCard({
82
82
  showAuthenticity = false,
83
83
  readOnly = false,
84
84
  scale = "risk",
85
- title
85
+ title,
86
+ variant = "card"
86
87
  }) {
87
88
  var _a, _b;
88
89
  const intl = useSafeIntl();
90
+ const isInline = variant === "inline";
89
91
  const [isEditing, setIsEditing] = useState(false);
90
92
  const [editValues, setEditValues] = useState(
91
93
  value || defaultImpact
92
94
  );
93
- const styles = impactCard({ editing: isEditing });
95
+ const effectiveIsEditing = isInline ? !readOnly : isEditing;
96
+ const styles = impactCard({ editing: !isInline && isEditing });
94
97
  const scaleConfig = typeof scale === "string" ? getScale(scale) : scale;
95
98
  const formatLabel = (level) => {
96
99
  const config = scaleConfig[level];
@@ -126,18 +129,28 @@ function ImpactCard({
126
129
  setEditValues(value || defaultImpact);
127
130
  setIsEditing(true);
128
131
  };
129
- const currentImpact = isEditing ? editValues : value || defaultImpact;
132
+ const currentImpact = isInline ? value || defaultImpact : isEditing ? editValues : value || defaultImpact;
130
133
  const handleLevelChange = (key) => (level) => {
131
- setEditValues((prev) => ({
132
- ...prev,
134
+ const newValues = {
135
+ ...isInline ? value || defaultImpact : editValues,
133
136
  [key]: level
134
- }));
137
+ };
138
+ if (isInline) {
139
+ onChange == null ? void 0 : onChange(newValues);
140
+ } else {
141
+ setEditValues(newValues);
142
+ }
135
143
  };
136
144
  const handleJustificationChange = (justification) => {
137
- setEditValues((prev) => ({
138
- ...prev,
145
+ const newValues = {
146
+ ...isInline ? value || defaultImpact : editValues,
139
147
  impactJustification: justification || void 0
140
- }));
148
+ };
149
+ if (isInline) {
150
+ onChange == null ? void 0 : onChange(newValues);
151
+ } else {
152
+ setEditValues(newValues);
153
+ }
141
154
  };
142
155
  const highestImpact = Math.max(
143
156
  currentImpact.impactConfidentiality,
@@ -149,6 +162,87 @@ function ImpactCard({
149
162
  const justificationHint = intl.formatMessage(messages.justification_hint, {
150
163
  level: highestLabel
151
164
  });
165
+ const impactRows = /* @__PURE__ */ jsxs(Fragment, { children: [
166
+ /* @__PURE__ */ jsx(
167
+ ImpactItemRow,
168
+ {
169
+ label: t.confidentiality,
170
+ shortLabel: "C",
171
+ value: currentImpact.impactConfidentiality,
172
+ isEditing: effectiveIsEditing,
173
+ scale: scaleConfig,
174
+ formatLabel,
175
+ onLevelChange: handleLevelChange("impactConfidentiality")
176
+ }
177
+ ),
178
+ /* @__PURE__ */ jsx(
179
+ ImpactItemRow,
180
+ {
181
+ label: t.integrity,
182
+ shortLabel: "I",
183
+ value: currentImpact.impactIntegrity,
184
+ isEditing: effectiveIsEditing,
185
+ scale: scaleConfig,
186
+ formatLabel,
187
+ onLevelChange: handleLevelChange("impactIntegrity")
188
+ }
189
+ ),
190
+ /* @__PURE__ */ jsx(
191
+ ImpactItemRow,
192
+ {
193
+ label: t.availability,
194
+ shortLabel: "A",
195
+ value: currentImpact.impactAvailability,
196
+ isEditing: effectiveIsEditing,
197
+ scale: scaleConfig,
198
+ formatLabel,
199
+ onLevelChange: handleLevelChange("impactAvailability")
200
+ }
201
+ ),
202
+ showAuthenticity && /* @__PURE__ */ jsx(
203
+ ImpactItemRow,
204
+ {
205
+ label: t.authenticity,
206
+ shortLabel: "Au",
207
+ value: (_b = currentImpact.impactAuthenticity) != null ? _b : 0,
208
+ isEditing: effectiveIsEditing,
209
+ scale: scaleConfig,
210
+ formatLabel,
211
+ onLevelChange: handleLevelChange("impactAuthenticity")
212
+ }
213
+ )
214
+ ] });
215
+ const justificationContent = showJustification && /* @__PURE__ */ jsxs("div", { className: styles.justificationSection(), children: [
216
+ /* @__PURE__ */ jsxs(
217
+ "label",
218
+ {
219
+ htmlFor: "impact-justification",
220
+ className: styles.justificationLabel(),
221
+ children: [
222
+ t.justification,
223
+ highestImpact > 0 && /* @__PURE__ */ jsx("span", { className: styles.justificationHint(), children: justificationHint })
224
+ ]
225
+ }
226
+ ),
227
+ effectiveIsEditing ? /* @__PURE__ */ jsx(
228
+ Textarea,
229
+ {
230
+ id: "impact-justification",
231
+ value: currentImpact.impactJustification || "",
232
+ onChange: (e) => handleJustificationChange(e.target.value),
233
+ placeholder: t.justificationPlaceholder,
234
+ rows: 3,
235
+ className: "text-sm"
236
+ }
237
+ ) : currentImpact.impactJustification ? /* @__PURE__ */ jsx("p", { className: styles.justificationText(), children: currentImpact.impactJustification }) : /* @__PURE__ */ jsx("p", { className: styles.justificationEmpty(), children: t.noJustification })
238
+ ] });
239
+ if (isInline) {
240
+ return /* @__PURE__ */ jsxs("div", { className: styles.wrapper(), children: [
241
+ title && /* @__PURE__ */ jsx("div", { className: styles.inlineHeader(), children: /* @__PURE__ */ jsx(Heading, { level: "h4", className: "text-sm font-medium", children: title }) }),
242
+ impactRows,
243
+ justificationContent
244
+ ] });
245
+ }
152
246
  return /* @__PURE__ */ jsxs(Card.Root, { className: styles.root(), children: [
153
247
  /* @__PURE__ */ jsxs(Card.Header, { className: "flex flex-row items-center justify-between", children: [
154
248
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
@@ -170,78 +264,8 @@ function ImpactCard({
170
264
  ] }))
171
265
  ] }),
172
266
  /* @__PURE__ */ jsxs(Card.Body, { className: "space-y-3", children: [
173
- /* @__PURE__ */ jsx(
174
- ImpactItemRow,
175
- {
176
- label: t.confidentiality,
177
- shortLabel: "C",
178
- value: currentImpact.impactConfidentiality,
179
- isEditing,
180
- scale: scaleConfig,
181
- formatLabel,
182
- onLevelChange: handleLevelChange("impactConfidentiality")
183
- }
184
- ),
185
- /* @__PURE__ */ jsx(
186
- ImpactItemRow,
187
- {
188
- label: t.integrity,
189
- shortLabel: "I",
190
- value: currentImpact.impactIntegrity,
191
- isEditing,
192
- scale: scaleConfig,
193
- formatLabel,
194
- onLevelChange: handleLevelChange("impactIntegrity")
195
- }
196
- ),
197
- /* @__PURE__ */ jsx(
198
- ImpactItemRow,
199
- {
200
- label: t.availability,
201
- shortLabel: "A",
202
- value: currentImpact.impactAvailability,
203
- isEditing,
204
- scale: scaleConfig,
205
- formatLabel,
206
- onLevelChange: handleLevelChange("impactAvailability")
207
- }
208
- ),
209
- showAuthenticity && /* @__PURE__ */ jsx(
210
- ImpactItemRow,
211
- {
212
- label: t.authenticity,
213
- shortLabel: "Au",
214
- value: (_b = currentImpact.impactAuthenticity) != null ? _b : 0,
215
- isEditing,
216
- scale: scaleConfig,
217
- formatLabel,
218
- onLevelChange: handleLevelChange("impactAuthenticity")
219
- }
220
- ),
221
- showJustification && /* @__PURE__ */ jsxs("div", { className: styles.justificationSection(), children: [
222
- /* @__PURE__ */ jsxs(
223
- "label",
224
- {
225
- htmlFor: "impact-justification",
226
- className: styles.justificationLabel(),
227
- children: [
228
- t.justification,
229
- highestImpact > 0 && /* @__PURE__ */ jsx("span", { className: styles.justificationHint(), children: justificationHint })
230
- ]
231
- }
232
- ),
233
- isEditing ? /* @__PURE__ */ jsx(
234
- Textarea,
235
- {
236
- id: "impact-justification",
237
- value: currentImpact.impactJustification || "",
238
- onChange: (e) => handleJustificationChange(e.target.value),
239
- placeholder: t.justificationPlaceholder,
240
- rows: 3,
241
- className: "text-sm"
242
- }
243
- ) : currentImpact.impactJustification ? /* @__PURE__ */ jsx("p", { className: styles.justificationText(), children: currentImpact.impactJustification }) : /* @__PURE__ */ jsx("p", { className: styles.justificationEmpty(), children: t.noJustification })
244
- ] })
267
+ impactRows,
268
+ justificationContent
245
269
  ] })
246
270
  ] });
247
271
  }
@@ -29,7 +29,13 @@ interface ImpactCardProps {
29
29
  scale?: ImpactScalePreset | ImpactScaleConfig;
30
30
  /** Custom title for the card */
31
31
  title?: string;
32
+ /**
33
+ * Display variant:
34
+ * - `card`: Wrapped in a Card with edit/save/cancel buttons (default)
35
+ * - `inline`: No card wrapper, always editable, changes propagate immediately
36
+ */
37
+ variant?: "card" | "inline";
32
38
  }
33
- declare function ImpactCard({ value, onChange, showJustification, showAuthenticity, readOnly, scale, title, }: ImpactCardProps): react_jsx_runtime.JSX.Element;
39
+ declare function ImpactCard({ value, onChange, showJustification, showAuthenticity, readOnly, scale, title, variant, }: ImpactCardProps): react_jsx_runtime.JSX.Element;
34
40
 
35
41
  export { ImpactCard, type ImpactCardProps, type ImpactValue };
@@ -29,7 +29,13 @@ interface ImpactCardProps {
29
29
  scale?: ImpactScalePreset | ImpactScaleConfig;
30
30
  /** Custom title for the card */
31
31
  title?: string;
32
+ /**
33
+ * Display variant:
34
+ * - `card`: Wrapped in a Card with edit/save/cancel buttons (default)
35
+ * - `inline`: No card wrapper, always editable, changes propagate immediately
36
+ */
37
+ variant?: "card" | "inline";
32
38
  }
33
- declare function ImpactCard({ value, onChange, showJustification, showAuthenticity, readOnly, scale, title, }: ImpactCardProps): react_jsx_runtime.JSX.Element;
39
+ declare function ImpactCard({ value, onChange, showJustification, showAuthenticity, readOnly, scale, title, variant, }: ImpactCardProps): react_jsx_runtime.JSX.Element;
34
40
 
35
41
  export { ImpactCard, type ImpactCardProps, type ImpactValue };
@@ -382,15 +382,18 @@ function ImpactCard({
382
382
  showAuthenticity = false,
383
383
  readOnly = false,
384
384
  scale = "risk",
385
- title
385
+ title,
386
+ variant = "card"
386
387
  }) {
387
388
  var _a, _b;
388
389
  const intl = (0, import_i18n2.useSafeIntl)();
390
+ const isInline = variant === "inline";
389
391
  const [isEditing, setIsEditing] = (0, import_react.useState)(false);
390
392
  const [editValues, setEditValues] = (0, import_react.useState)(
391
393
  value || defaultImpact
392
394
  );
393
- const styles = (0, import_theme.impactCard)({ editing: isEditing });
395
+ const effectiveIsEditing = isInline ? !readOnly : isEditing;
396
+ const styles = (0, import_theme.impactCard)({ editing: !isInline && isEditing });
394
397
  const scaleConfig = typeof scale === "string" ? getScale(scale) : scale;
395
398
  const formatLabel = (level) => {
396
399
  const config = scaleConfig[level];
@@ -426,18 +429,28 @@ function ImpactCard({
426
429
  setEditValues(value || defaultImpact);
427
430
  setIsEditing(true);
428
431
  };
429
- const currentImpact = isEditing ? editValues : value || defaultImpact;
432
+ const currentImpact = isInline ? value || defaultImpact : isEditing ? editValues : value || defaultImpact;
430
433
  const handleLevelChange = (key) => (level) => {
431
- setEditValues((prev) => ({
432
- ...prev,
434
+ const newValues = {
435
+ ...isInline ? value || defaultImpact : editValues,
433
436
  [key]: level
434
- }));
437
+ };
438
+ if (isInline) {
439
+ onChange == null ? void 0 : onChange(newValues);
440
+ } else {
441
+ setEditValues(newValues);
442
+ }
435
443
  };
436
444
  const handleJustificationChange = (justification) => {
437
- setEditValues((prev) => ({
438
- ...prev,
445
+ const newValues = {
446
+ ...isInline ? value || defaultImpact : editValues,
439
447
  impactJustification: justification || void 0
440
- }));
448
+ };
449
+ if (isInline) {
450
+ onChange == null ? void 0 : onChange(newValues);
451
+ } else {
452
+ setEditValues(newValues);
453
+ }
441
454
  };
442
455
  const highestImpact = Math.max(
443
456
  currentImpact.impactConfidentiality,
@@ -449,6 +462,87 @@ function ImpactCard({
449
462
  const justificationHint = intl.formatMessage(messages.justification_hint, {
450
463
  level: highestLabel
451
464
  });
465
+ const impactRows = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
466
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
467
+ ImpactItemRow,
468
+ {
469
+ label: t.confidentiality,
470
+ shortLabel: "C",
471
+ value: currentImpact.impactConfidentiality,
472
+ isEditing: effectiveIsEditing,
473
+ scale: scaleConfig,
474
+ formatLabel,
475
+ onLevelChange: handleLevelChange("impactConfidentiality")
476
+ }
477
+ ),
478
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
479
+ ImpactItemRow,
480
+ {
481
+ label: t.integrity,
482
+ shortLabel: "I",
483
+ value: currentImpact.impactIntegrity,
484
+ isEditing: effectiveIsEditing,
485
+ scale: scaleConfig,
486
+ formatLabel,
487
+ onLevelChange: handleLevelChange("impactIntegrity")
488
+ }
489
+ ),
490
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
491
+ ImpactItemRow,
492
+ {
493
+ label: t.availability,
494
+ shortLabel: "A",
495
+ value: currentImpact.impactAvailability,
496
+ isEditing: effectiveIsEditing,
497
+ scale: scaleConfig,
498
+ formatLabel,
499
+ onLevelChange: handleLevelChange("impactAvailability")
500
+ }
501
+ ),
502
+ showAuthenticity && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
503
+ ImpactItemRow,
504
+ {
505
+ label: t.authenticity,
506
+ shortLabel: "Au",
507
+ value: (_b = currentImpact.impactAuthenticity) != null ? _b : 0,
508
+ isEditing: effectiveIsEditing,
509
+ scale: scaleConfig,
510
+ formatLabel,
511
+ onLevelChange: handleLevelChange("impactAuthenticity")
512
+ }
513
+ )
514
+ ] });
515
+ const justificationContent = showJustification && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.justificationSection(), children: [
516
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
517
+ "label",
518
+ {
519
+ htmlFor: "impact-justification",
520
+ className: styles.justificationLabel(),
521
+ children: [
522
+ t.justification,
523
+ highestImpact > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: styles.justificationHint(), children: justificationHint })
524
+ ]
525
+ }
526
+ ),
527
+ effectiveIsEditing ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
528
+ import_sight.Textarea,
529
+ {
530
+ id: "impact-justification",
531
+ value: currentImpact.impactJustification || "",
532
+ onChange: (e) => handleJustificationChange(e.target.value),
533
+ placeholder: t.justificationPlaceholder,
534
+ rows: 3,
535
+ className: "text-sm"
536
+ }
537
+ ) : currentImpact.impactJustification ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: styles.justificationText(), children: currentImpact.impactJustification }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: styles.justificationEmpty(), children: t.noJustification })
538
+ ] });
539
+ if (isInline) {
540
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.wrapper(), children: [
541
+ title && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.inlineHeader(), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_sight.Heading, { level: "h4", className: "text-sm font-medium", children: title }) }),
542
+ impactRows,
543
+ justificationContent
544
+ ] });
545
+ }
452
546
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_sight.Card.Root, { className: styles.root(), children: [
453
547
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_sight.Card.Header, { className: "flex flex-row items-center justify-between", children: [
454
548
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2", children: [
@@ -470,78 +564,8 @@ function ImpactCard({
470
564
  ] }))
471
565
  ] }),
472
566
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_sight.Card.Body, { className: "space-y-3", children: [
473
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
474
- ImpactItemRow,
475
- {
476
- label: t.confidentiality,
477
- shortLabel: "C",
478
- value: currentImpact.impactConfidentiality,
479
- isEditing,
480
- scale: scaleConfig,
481
- formatLabel,
482
- onLevelChange: handleLevelChange("impactConfidentiality")
483
- }
484
- ),
485
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
486
- ImpactItemRow,
487
- {
488
- label: t.integrity,
489
- shortLabel: "I",
490
- value: currentImpact.impactIntegrity,
491
- isEditing,
492
- scale: scaleConfig,
493
- formatLabel,
494
- onLevelChange: handleLevelChange("impactIntegrity")
495
- }
496
- ),
497
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
498
- ImpactItemRow,
499
- {
500
- label: t.availability,
501
- shortLabel: "A",
502
- value: currentImpact.impactAvailability,
503
- isEditing,
504
- scale: scaleConfig,
505
- formatLabel,
506
- onLevelChange: handleLevelChange("impactAvailability")
507
- }
508
- ),
509
- showAuthenticity && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
510
- ImpactItemRow,
511
- {
512
- label: t.authenticity,
513
- shortLabel: "Au",
514
- value: (_b = currentImpact.impactAuthenticity) != null ? _b : 0,
515
- isEditing,
516
- scale: scaleConfig,
517
- formatLabel,
518
- onLevelChange: handleLevelChange("impactAuthenticity")
519
- }
520
- ),
521
- showJustification && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.justificationSection(), children: [
522
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
523
- "label",
524
- {
525
- htmlFor: "impact-justification",
526
- className: styles.justificationLabel(),
527
- children: [
528
- t.justification,
529
- highestImpact > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: styles.justificationHint(), children: justificationHint })
530
- ]
531
- }
532
- ),
533
- isEditing ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
534
- import_sight.Textarea,
535
- {
536
- id: "impact-justification",
537
- value: currentImpact.impactJustification || "",
538
- onChange: (e) => handleJustificationChange(e.target.value),
539
- placeholder: t.justificationPlaceholder,
540
- rows: 3,
541
- className: "text-sm"
542
- }
543
- ) : currentImpact.impactJustification ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: styles.justificationText(), children: currentImpact.impactJustification }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: styles.justificationEmpty(), children: t.noJustification })
544
- ] })
567
+ impactRows,
568
+ justificationContent
545
569
  ] })
546
570
  ] });
547
571
  }
@@ -2,7 +2,7 @@
2
2
  "use client";
3
3
  import {
4
4
  ImpactCard
5
- } from "../../chunk-TW3S4OE2.mjs";
5
+ } from "../../chunk-AGASJJ7X.mjs";
6
6
  import "../../chunk-KNGEZZFI.mjs";
7
7
  import "../../chunk-GF3WJZVI.mjs";
8
8
  export {