@discuss-ds/ui 0.2.0 → 0.3.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.
- package/CHANGELOG.md +14 -0
- package/dist/index.cjs +38 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +38 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -338,6 +338,17 @@ interface InlineEditProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'on
|
|
|
338
338
|
disabled?: boolean;
|
|
339
339
|
/** Called when editing starts or ends. */
|
|
340
340
|
onEditingChange?: (editing: boolean) => void;
|
|
341
|
+
/** Called on every keystroke while editing (and with the saved value when editing ends), e.g. for a live character counter. */
|
|
342
|
+
onDraftChange?: (value: string) => void;
|
|
343
|
+
/**
|
|
344
|
+
* `default` is a rounded field. A short single-line label shows the pencil and hugs its text; `multiline` (longer
|
|
345
|
+
* text) hides the pencil and fills the width. `question` is for question text: it fills the width with no pencil,
|
|
346
|
+
* has square corners and shows a bottom border on hover and focus (in the input border colour) that turns accent while `selected`. Enter saves; Shift+Enter adds a
|
|
347
|
+
* line break when `multiline`.
|
|
348
|
+
*/
|
|
349
|
+
variant?: 'default' | 'question';
|
|
350
|
+
/** `question` variant: keeps the bottom border while the owning question is selected. */
|
|
351
|
+
selected?: boolean;
|
|
341
352
|
/** Classes for the displayed/edited text, e.g. a heading text style. The field itself keeps the same box. */
|
|
342
353
|
textClassName?: string;
|
|
343
354
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -338,6 +338,17 @@ interface InlineEditProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'on
|
|
|
338
338
|
disabled?: boolean;
|
|
339
339
|
/** Called when editing starts or ends. */
|
|
340
340
|
onEditingChange?: (editing: boolean) => void;
|
|
341
|
+
/** Called on every keystroke while editing (and with the saved value when editing ends), e.g. for a live character counter. */
|
|
342
|
+
onDraftChange?: (value: string) => void;
|
|
343
|
+
/**
|
|
344
|
+
* `default` is a rounded field. A short single-line label shows the pencil and hugs its text; `multiline` (longer
|
|
345
|
+
* text) hides the pencil and fills the width. `question` is for question text: it fills the width with no pencil,
|
|
346
|
+
* has square corners and shows a bottom border on hover and focus (in the input border colour) that turns accent while `selected`. Enter saves; Shift+Enter adds a
|
|
347
|
+
* line break when `multiline`.
|
|
348
|
+
*/
|
|
349
|
+
variant?: 'default' | 'question';
|
|
350
|
+
/** `question` variant: keeps the bottom border while the owning question is selected. */
|
|
351
|
+
selected?: boolean;
|
|
341
352
|
/** Classes for the displayed/edited text, e.g. a heading text style. The field itself keeps the same box. */
|
|
342
353
|
textClassName?: string;
|
|
343
354
|
}
|
package/dist/index.js
CHANGED
|
@@ -1378,6 +1378,9 @@ var InlineEdit = React24.forwardRef(
|
|
|
1378
1378
|
maxLength,
|
|
1379
1379
|
disabled,
|
|
1380
1380
|
onEditingChange,
|
|
1381
|
+
onDraftChange,
|
|
1382
|
+
variant = "default",
|
|
1383
|
+
selected,
|
|
1381
1384
|
"aria-label": ariaLabel,
|
|
1382
1385
|
...props
|
|
1383
1386
|
}, ref) => {
|
|
@@ -1413,26 +1416,32 @@ var InlineEdit = React24.forwardRef(
|
|
|
1413
1416
|
}
|
|
1414
1417
|
setEditing(false);
|
|
1415
1418
|
onEditingChange?.(false);
|
|
1419
|
+
onDraftChange?.(commit ? draft : value);
|
|
1416
1420
|
};
|
|
1417
1421
|
const textClasses = cn("text-ui-input-value text-surface-foreground", textClassName);
|
|
1418
|
-
|
|
1422
|
+
const question = variant === "question";
|
|
1423
|
+
const fill = multiline || question;
|
|
1424
|
+
return /* @__PURE__ */ jsx25("div", { ref, className: cn(fill ? "flex w-full min-w-0" : "inline-flex min-w-0 max-w-full", className), ...props, children: editing ? React24.createElement(multiline ? "textarea" : "input", {
|
|
1419
1425
|
ref: fieldRef,
|
|
1420
1426
|
value: draft,
|
|
1421
1427
|
maxLength,
|
|
1422
1428
|
"aria-label": ariaLabel,
|
|
1423
1429
|
...multiline ? { rows: 1 } : { type: "text" },
|
|
1424
1430
|
className: cn(
|
|
1425
|
-
"w-full
|
|
1431
|
+
"w-full px-3 py-1 outline-none",
|
|
1426
1432
|
multiline && "field-sizing-content resize-none",
|
|
1427
|
-
fieldSurfaceClasses("default"),
|
|
1433
|
+
question ? "rounded-none border-0 border-b-2 border-accent-foreground bg-transparent" : cn("rounded-md focus-visible:border-input-accent", fieldSurfaceClasses("default")),
|
|
1428
1434
|
textClasses
|
|
1429
1435
|
),
|
|
1430
|
-
onChange: (event) =>
|
|
1436
|
+
onChange: (event) => {
|
|
1437
|
+
setDraft(event.target.value);
|
|
1438
|
+
onDraftChange?.(event.target.value);
|
|
1439
|
+
},
|
|
1431
1440
|
onKeyDown: (event) => {
|
|
1432
1441
|
if (event.key === "Escape") {
|
|
1433
1442
|
cancelled.current = true;
|
|
1434
1443
|
finish(false, true);
|
|
1435
|
-
} else if (event.key === "Enter" && (!multiline || event.metaKey || event.ctrlKey)) {
|
|
1444
|
+
} else if (event.key === "Enter" && (!multiline || event.metaKey || event.ctrlKey || question && !event.shiftKey)) {
|
|
1436
1445
|
event.preventDefault();
|
|
1437
1446
|
finish(true, true);
|
|
1438
1447
|
}
|
|
@@ -1449,13 +1458,18 @@ var InlineEdit = React24.forwardRef(
|
|
|
1449
1458
|
"aria-label": `${ariaLabel}: ${value || placeholder}. Edit`,
|
|
1450
1459
|
onClick: start,
|
|
1451
1460
|
className: cn(
|
|
1452
|
-
"group inline-flex min-w-0 max-w-full items-center gap-2
|
|
1453
|
-
|
|
1461
|
+
"group inline-flex min-w-0 max-w-full items-center gap-2 px-3 py-1 text-left outline-none",
|
|
1462
|
+
fill && "w-full",
|
|
1463
|
+
question ? (
|
|
1464
|
+
// Hover and focus use the input border colour; only a selected question takes the accent.
|
|
1465
|
+
cn("rounded-none border-b-2", selected ? "border-accent-foreground" : "border-transparent enabled:hover:border-input enabled:focus-visible:border-input")
|
|
1466
|
+
) : "rounded-md border border-transparent enabled:focus-visible:border-input-accent",
|
|
1467
|
+
"enabled:hover:bg-secondary disabled:cursor-not-allowed disabled:opacity-50",
|
|
1454
1468
|
textClasses
|
|
1455
1469
|
),
|
|
1456
1470
|
children: [
|
|
1457
|
-
/* @__PURE__ */ jsx25("span", { className: cn("min-w-0
|
|
1458
|
-
/* @__PURE__ */ jsx25(
|
|
1471
|
+
/* @__PURE__ */ jsx25("span", { className: cn("min-w-0", multiline ? "whitespace-pre-wrap" : "truncate", fill && "flex-1", !value && "text-muted-foreground"), children: value || placeholder }),
|
|
1472
|
+
!fill && /* @__PURE__ */ jsx25(
|
|
1459
1473
|
PencilSimple,
|
|
1460
1474
|
{
|
|
1461
1475
|
size: 16,
|
|
@@ -2489,10 +2503,12 @@ import { jsx as jsx41, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
|
2489
2503
|
var eyebrow = "text-ui-caption uppercase text-secondary-muted-foreground";
|
|
2490
2504
|
var QuestionHeader = React40.forwardRef(
|
|
2491
2505
|
({ className, number, title, required, error, onDismissError, editor, onTitleChange, actions, maxLength = 2e3, active, showCounter = true, ...props }, ref) => {
|
|
2506
|
+
const [draft, setDraft] = React40.useState(null);
|
|
2492
2507
|
const label = String(number).padStart(2, "0");
|
|
2493
2508
|
const showError = error !== void 0 && error !== false;
|
|
2494
2509
|
if (editor) {
|
|
2495
2510
|
const text = typeof title === "string" ? title : "";
|
|
2511
|
+
const count = (draft ?? text).length;
|
|
2496
2512
|
return /* @__PURE__ */ jsxs28("div", { ref, className: cn("group/header flex w-full flex-col gap-2", className), ...props, children: [
|
|
2497
2513
|
/* @__PURE__ */ jsxs28("div", { className: "flex items-center justify-between", children: [
|
|
2498
2514
|
/* @__PURE__ */ jsxs28(
|
|
@@ -2512,18 +2528,26 @@ var QuestionHeader = React40.forwardRef(
|
|
|
2512
2528
|
actions && /* @__PURE__ */ jsx41("div", { className: "flex items-center gap-2 opacity-0 transition-opacity group-focus-within/header:opacity-100 group-hover/header:opacity-100", children: actions })
|
|
2513
2529
|
] }),
|
|
2514
2530
|
/* @__PURE__ */ jsx41(
|
|
2515
|
-
|
|
2531
|
+
InlineEdit,
|
|
2516
2532
|
{
|
|
2517
|
-
|
|
2533
|
+
variant: "question",
|
|
2534
|
+
multiline: true,
|
|
2535
|
+
selected: active,
|
|
2536
|
+
className: "-mx-3 w-auto",
|
|
2518
2537
|
"aria-label": "Question title",
|
|
2538
|
+
placeholder: "Click to write the question text",
|
|
2519
2539
|
value: text,
|
|
2520
2540
|
maxLength,
|
|
2521
|
-
|
|
2522
|
-
|
|
2541
|
+
onValueChange: onTitleChange,
|
|
2542
|
+
onDraftChange: setDraft,
|
|
2543
|
+
onEditingChange: (editing) => {
|
|
2544
|
+
if (!editing) setDraft(null);
|
|
2545
|
+
},
|
|
2546
|
+
textClassName: "text-heading-h4"
|
|
2523
2547
|
}
|
|
2524
2548
|
),
|
|
2525
2549
|
showCounter && /* @__PURE__ */ jsxs28("p", { className: "text-ui-caption text-secondary-muted-foreground", children: [
|
|
2526
|
-
|
|
2550
|
+
count,
|
|
2527
2551
|
"/",
|
|
2528
2552
|
maxLength,
|
|
2529
2553
|
" characters"
|