@skalfa/skalfa-component 1.0.27 → 1.0.29
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/dist/input/InputContent.component.js +119 -63
- package/dist/supervision/FormSupervision.component.d.ts +3 -1
- package/dist/supervision/FormSupervision.component.js +3 -1
- package/package.json +1 -1
- package/src/input/InputContent.component.tsx +162 -107
- package/src/supervision/FormSupervision.component.tsx +11 -3
|
@@ -308,7 +308,102 @@ function InputContentComponent({ label, tip, className = "", value, invalid, val
|
|
|
308
308
|
saveSelection();
|
|
309
309
|
handleEditorChange();
|
|
310
310
|
}, [restoreSelection, saveSelection, handleEditorChange]);
|
|
311
|
+
const updateActiveStates = (0, react_1.useCallback)(() => {
|
|
312
|
+
const sel = window.getSelection();
|
|
313
|
+
let inH2 = false;
|
|
314
|
+
if (sel && sel.rangeCount > 0) {
|
|
315
|
+
let node = sel.anchorNode;
|
|
316
|
+
while (node && node !== editorRef.current) {
|
|
317
|
+
if (node.nodeType === Node.ELEMENT_NODE && node.tagName === "H2") {
|
|
318
|
+
inH2 = true;
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
node = node.parentNode;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
setActiveStates({
|
|
325
|
+
header: inH2,
|
|
326
|
+
bold: isCommandActive("bold"),
|
|
327
|
+
italic: isCommandActive("italic"),
|
|
328
|
+
underline: isCommandActive("underline"),
|
|
329
|
+
strikeThrough: isCommandActive("strikeThrough"),
|
|
330
|
+
justifyLeft: isCommandActive("justifyLeft"),
|
|
331
|
+
justifyCenter: isCommandActive("justifyCenter"),
|
|
332
|
+
justifyRight: isCommandActive("justifyRight"),
|
|
333
|
+
justifyFull: isCommandActive("justifyFull"),
|
|
334
|
+
insertUnorderedList: isCommandActive("insertUnorderedList"),
|
|
335
|
+
insertOrderedList: isCommandActive("insertOrderedList"),
|
|
336
|
+
});
|
|
337
|
+
if (sel && sel.rangeCount > 0) {
|
|
338
|
+
let node = sel.anchorNode;
|
|
339
|
+
let detectedColor = "normal";
|
|
340
|
+
let detectedSize = null;
|
|
341
|
+
while (node && node !== editorRef.current) {
|
|
342
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
343
|
+
const el = node;
|
|
344
|
+
if (el.dataset.color && detectedColor === "normal") {
|
|
345
|
+
detectedColor = el.dataset.color;
|
|
346
|
+
}
|
|
347
|
+
if (el.dataset.size && detectedSize === null) {
|
|
348
|
+
const parsed = parseInt(el.dataset.size);
|
|
349
|
+
if (!isNaN(parsed))
|
|
350
|
+
detectedSize = parsed;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
node = node.parentNode;
|
|
354
|
+
}
|
|
355
|
+
setActiveColor(detectedColor);
|
|
356
|
+
if (detectedSize !== null) {
|
|
357
|
+
setTextSize(detectedSize);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}, [isCommandActive]);
|
|
361
|
+
(0, react_1.useEffect)(() => {
|
|
362
|
+
_utils_1.shortcut.register("ctrl+b", () => handleBold(), "Bold text");
|
|
363
|
+
_utils_1.shortcut.register("ctrl+i", () => handleItalic(), "Italic text");
|
|
364
|
+
_utils_1.shortcut.register("ctrl+u", () => handleUnderline(), "Underline text");
|
|
365
|
+
_utils_1.shortcut.register("ctrl+shift+x", () => handleStrikethrough(), "Strikethrough text");
|
|
366
|
+
_utils_1.shortcut.register("ctrl+k", () => handleLink(), "Insert link");
|
|
367
|
+
return () => {
|
|
368
|
+
_utils_1.shortcut.unregister("ctrl+b");
|
|
369
|
+
_utils_1.shortcut.unregister("ctrl+i");
|
|
370
|
+
_utils_1.shortcut.unregister("ctrl+u");
|
|
371
|
+
_utils_1.shortcut.unregister("ctrl+shift+x");
|
|
372
|
+
_utils_1.shortcut.unregister("ctrl+k");
|
|
373
|
+
};
|
|
374
|
+
}, [handleBold, handleItalic, handleUnderline, handleStrikethrough, handleLink]);
|
|
311
375
|
const handleKeyDown = (0, react_1.useCallback)((e) => {
|
|
376
|
+
const isMod = e.ctrlKey || e.metaKey;
|
|
377
|
+
const key = e.key.toLowerCase();
|
|
378
|
+
if (isMod && !e.shiftKey && !e.altKey && key === "b") {
|
|
379
|
+
e.preventDefault();
|
|
380
|
+
handleBold();
|
|
381
|
+
updateActiveStates();
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
if (isMod && !e.shiftKey && !e.altKey && key === "i") {
|
|
385
|
+
e.preventDefault();
|
|
386
|
+
handleItalic();
|
|
387
|
+
updateActiveStates();
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
if (isMod && !e.shiftKey && !e.altKey && key === "u") {
|
|
391
|
+
e.preventDefault();
|
|
392
|
+
handleUnderline();
|
|
393
|
+
updateActiveStates();
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
if (isMod && e.shiftKey && !e.altKey && key === "x") {
|
|
397
|
+
e.preventDefault();
|
|
398
|
+
handleStrikethrough();
|
|
399
|
+
updateActiveStates();
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
if (isMod && !e.shiftKey && !e.altKey && key === "k") {
|
|
403
|
+
e.preventDefault();
|
|
404
|
+
handleLink();
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
312
407
|
if (e.key === "Backspace") {
|
|
313
408
|
const sel = window.getSelection();
|
|
314
409
|
if (sel && sel.rangeCount > 0 && sel.isCollapsed) {
|
|
@@ -362,75 +457,41 @@ function InputContentComponent({ label, tip, className = "", value, invalid, val
|
|
|
362
457
|
}
|
|
363
458
|
}
|
|
364
459
|
}
|
|
365
|
-
}, [handleEditorChange]);
|
|
366
|
-
const updateActiveStates = (0, react_1.useCallback)(() => {
|
|
367
|
-
const sel = window.getSelection();
|
|
368
|
-
let inH2 = false;
|
|
369
|
-
if (sel && sel.rangeCount > 0) {
|
|
370
|
-
let node = sel.anchorNode;
|
|
371
|
-
while (node && node !== editorRef.current) {
|
|
372
|
-
if (node.nodeType === Node.ELEMENT_NODE && node.tagName === "H2") {
|
|
373
|
-
inH2 = true;
|
|
374
|
-
break;
|
|
375
|
-
}
|
|
376
|
-
node = node.parentNode;
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
setActiveStates({
|
|
380
|
-
header: inH2,
|
|
381
|
-
bold: isCommandActive("bold"),
|
|
382
|
-
italic: isCommandActive("italic"),
|
|
383
|
-
underline: isCommandActive("underline"),
|
|
384
|
-
strikeThrough: isCommandActive("strikeThrough"),
|
|
385
|
-
justifyLeft: isCommandActive("justifyLeft"),
|
|
386
|
-
justifyCenter: isCommandActive("justifyCenter"),
|
|
387
|
-
justifyRight: isCommandActive("justifyRight"),
|
|
388
|
-
justifyFull: isCommandActive("justifyFull"),
|
|
389
|
-
insertUnorderedList: isCommandActive("insertUnorderedList"),
|
|
390
|
-
insertOrderedList: isCommandActive("insertOrderedList"),
|
|
391
|
-
});
|
|
392
|
-
if (sel && sel.rangeCount > 0) {
|
|
393
|
-
let node = sel.anchorNode;
|
|
394
|
-
let detectedColor = "normal";
|
|
395
|
-
let detectedSize = null;
|
|
396
|
-
while (node && node !== editorRef.current) {
|
|
397
|
-
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
398
|
-
const el = node;
|
|
399
|
-
if (el.dataset.color && detectedColor === "normal") {
|
|
400
|
-
detectedColor = el.dataset.color;
|
|
401
|
-
}
|
|
402
|
-
if (el.dataset.size && detectedSize === null) {
|
|
403
|
-
const parsed = parseInt(el.dataset.size);
|
|
404
|
-
if (!isNaN(parsed))
|
|
405
|
-
detectedSize = parsed;
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
node = node.parentNode;
|
|
409
|
-
}
|
|
410
|
-
setActiveColor(detectedColor);
|
|
411
|
-
if (detectedSize !== null) {
|
|
412
|
-
setTextSize(detectedSize);
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
}, [isCommandActive]);
|
|
460
|
+
}, [handleBold, handleItalic, handleUnderline, handleStrikethrough, handleLink, handleEditorChange, updateActiveStates]);
|
|
416
461
|
const renderControlItem = (0, react_1.useCallback)((item, index) => {
|
|
417
462
|
if (typeof item !== "string") {
|
|
418
463
|
return (0, jsx_runtime_1.jsx)("div", { children: item }, index);
|
|
419
464
|
}
|
|
420
465
|
switch (item) {
|
|
421
|
-
case "HEADER":
|
|
422
|
-
|
|
466
|
+
// case "HEADER":
|
|
467
|
+
// return (
|
|
468
|
+
// <ButtonComponent
|
|
469
|
+
// key={index}
|
|
470
|
+
// variant={activeStates.header ? "light" : "simple"}
|
|
471
|
+
// paint="primary"
|
|
472
|
+
// size="sm"
|
|
473
|
+
// icon="solid/text-h"
|
|
474
|
+
// tips="Header"
|
|
475
|
+
// className={cn("toolbar-btn", activeStates.header && "toolbar-btn-active")}
|
|
476
|
+
// onClick={(e: any) => { e?.preventDefault?.(); handleHeader(); }}
|
|
477
|
+
// />
|
|
478
|
+
// );
|
|
423
479
|
case "TEXT_SIZE":
|
|
424
480
|
case "FONT_SIZE":
|
|
425
481
|
return ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-0.5", children: [(0, jsx_runtime_1.jsx)(Button_component_1.ButtonComponent, { variant: "simple", paint: "primary", size: "sm", icon: "solid/minus", tips: "Decrease Font Size", className: "toolbar-btn", onClick: (e) => { e?.preventDefault?.(); handleFontSizeChange(textSize - 1); } }), (0, jsx_runtime_1.jsx)("input", { type: "number", value: textSize, onChange: (e) => handleFontSizeChange(parseInt(e.target.value) || 14), onFocus: () => saveSelection(), className: "w-10 h-7 text-xs text-center border border-stroke rounded focus:outline-none focus:border-primary bg-background text-foreground select-none" }), (0, jsx_runtime_1.jsx)(Button_component_1.ButtonComponent, { variant: "simple", paint: "primary", size: "sm", icon: "solid/plus", tips: "Increase Font Size", className: "toolbar-btn", onClick: (e) => { e?.preventDefault?.(); handleFontSizeChange(textSize + 1); } })] }, index));
|
|
482
|
+
case "COLOR":
|
|
483
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "relative", children: [(0, jsx_runtime_1.jsx)(Button_component_1.ButtonComponent, { variant: activeColor !== "normal" ? "light" : "simple", paint: "primary", size: "sm", label: (0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)("div", { className: "skcontent-color-dot", style: { backgroundColor: ContentWrapper_component_1.COLOR_MAP[activeColor]?.css || ContentWrapper_component_1.COLOR_MAP.normal.css } }) }), tips: `Text Color (${ContentWrapper_component_1.COLOR_MAP[activeColor]?.label || "Normal"})`, className: (0, _utils_1.cn)("toolbar-btn", (activeColor !== "normal" || showColorPicker) && "toolbar-btn-active"), onClick: (e) => { e?.preventDefault?.(); setShowColorPicker(!showColorPicker); } }), showColorPicker && ((0, jsx_runtime_1.jsx)("div", { className: "skcontent-dropdown skcontent-color-picker", children: Object.entries(ContentWrapper_component_1.COLOR_MAP).map(([key, info]) => ((0, jsx_runtime_1.jsx)("button", { type: "button", title: info.label, className: (0, _utils_1.cn)("skcontent-color-dot", activeColor === key && "scale-125 border-2 border-primary"), style: { backgroundColor: info.css }, onMouseDown: (e) => {
|
|
484
|
+
e.preventDefault();
|
|
485
|
+
handleColor(key);
|
|
486
|
+
} }, key))) }))] }, index));
|
|
426
487
|
case "BOLD":
|
|
427
|
-
return ((0, jsx_runtime_1.jsx)(Button_component_1.ButtonComponent, { variant: activeStates.bold ? "light" : "simple", paint: "primary", size: "sm", icon: "solid/text-b", tips: "Bold", className: (0, _utils_1.cn)("toolbar-btn", activeStates.bold && "toolbar-btn-active"), onClick: (e) => { e?.preventDefault?.(); handleBold(); } }, index));
|
|
488
|
+
return ((0, jsx_runtime_1.jsx)(Button_component_1.ButtonComponent, { variant: activeStates.bold ? "light" : "simple", paint: "primary", size: "sm", icon: "solid/text-b", tips: "Bold (Ctrl+B)", className: (0, _utils_1.cn)("toolbar-btn", activeStates.bold && "toolbar-btn-active"), onClick: (e) => { e?.preventDefault?.(); handleBold(); } }, index));
|
|
428
489
|
case "ITALIC":
|
|
429
|
-
return ((0, jsx_runtime_1.jsx)(Button_component_1.ButtonComponent, { variant: activeStates.italic ? "light" : "simple", paint: "primary", size: "sm", icon: "solid/text-italic", tips: "Italic", className: (0, _utils_1.cn)("toolbar-btn", activeStates.italic && "toolbar-btn-active"), onClick: (e) => { e?.preventDefault?.(); handleItalic(); } }, index));
|
|
490
|
+
return ((0, jsx_runtime_1.jsx)(Button_component_1.ButtonComponent, { variant: activeStates.italic ? "light" : "simple", paint: "primary", size: "sm", icon: "solid/text-italic", tips: "Italic (Ctrl+I)", className: (0, _utils_1.cn)("toolbar-btn", activeStates.italic && "toolbar-btn-active"), onClick: (e) => { e?.preventDefault?.(); handleItalic(); } }, index));
|
|
430
491
|
case "UNDERLINE":
|
|
431
|
-
return ((0, jsx_runtime_1.jsx)(Button_component_1.ButtonComponent, { variant: activeStates.underline ? "light" : "simple", paint: "primary", size: "sm", icon: "solid/text-underline", tips: "Underline", className: (0, _utils_1.cn)("toolbar-btn", activeStates.underline && "toolbar-btn-active"), onClick: (e) => { e?.preventDefault?.(); handleUnderline(); } }, index));
|
|
492
|
+
return ((0, jsx_runtime_1.jsx)(Button_component_1.ButtonComponent, { variant: activeStates.underline ? "light" : "simple", paint: "primary", size: "sm", icon: "solid/text-underline", tips: "Underline (Ctrl+U)", className: (0, _utils_1.cn)("toolbar-btn", activeStates.underline && "toolbar-btn-active"), onClick: (e) => { e?.preventDefault?.(); handleUnderline(); } }, index));
|
|
432
493
|
case "STRIKETHROUGH":
|
|
433
|
-
return ((0, jsx_runtime_1.jsx)(Button_component_1.ButtonComponent, { variant: activeStates.strikeThrough ? "light" : "simple", paint: "primary", size: "sm", icon: "solid/text-slash", tips: "Strikethrough", className: (0, _utils_1.cn)("toolbar-btn", activeStates.strikeThrough && "toolbar-btn-active"), onClick: (e) => { e?.preventDefault?.(); handleStrikethrough(); } }, index));
|
|
494
|
+
return ((0, jsx_runtime_1.jsx)(Button_component_1.ButtonComponent, { variant: activeStates.strikeThrough ? "light" : "simple", paint: "primary", size: "sm", icon: "solid/text-slash", tips: "Strikethrough (Ctrl+Shift+X)", className: (0, _utils_1.cn)("toolbar-btn", activeStates.strikeThrough && "toolbar-btn-active"), onClick: (e) => { e?.preventDefault?.(); handleStrikethrough(); } }, index));
|
|
434
495
|
case "ALIGN_LEFT":
|
|
435
496
|
return ((0, jsx_runtime_1.jsx)(Button_component_1.ButtonComponent, { variant: activeStates.justifyLeft ? "light" : "simple", paint: "primary", size: "sm", icon: "solid/text-left", tips: "Align Left", className: (0, _utils_1.cn)("toolbar-btn", activeStates.justifyLeft && "toolbar-btn-active"), onClick: (e) => { e?.preventDefault?.(); handleAlign("left"); } }, index));
|
|
436
497
|
case "ALIGN_CENTER":
|
|
@@ -440,7 +501,7 @@ function InputContentComponent({ label, tip, className = "", value, invalid, val
|
|
|
440
501
|
case "ALIGN_JUSTIFY":
|
|
441
502
|
return ((0, jsx_runtime_1.jsx)(Button_component_1.ButtonComponent, { variant: activeStates.justifyFull ? "light" : "simple", paint: "primary", size: "sm", icon: "solid/text-justify", tips: "Align Justify", className: (0, _utils_1.cn)("toolbar-btn", activeStates.justifyFull && "toolbar-btn-active"), onClick: (e) => { e?.preventDefault?.(); handleAlign("justify"); } }, index));
|
|
442
503
|
case "LINK":
|
|
443
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "relative", children: [(0, jsx_runtime_1.jsx)(Button_component_1.ButtonComponent, { variant: showLinkInput ? "light" : "simple", paint: "primary", size: "sm", icon: "solid/link", tips: "Link", className: (0, _utils_1.cn)("toolbar-btn", showLinkInput && "toolbar-btn-active"), onClick: (e) => { e?.preventDefault?.(); handleLink(); } }), showLinkInput && ((0, jsx_runtime_1.jsxs)("div", { className: "skcontent-dropdown skcontent-link-input", children: [(0, jsx_runtime_1.jsx)("input", { type: "url", placeholder: "https://...", value: linkUrl, onChange: (e) => setLinkUrl(e.target.value), onKeyDown: (e) => {
|
|
504
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "relative", children: [(0, jsx_runtime_1.jsx)(Button_component_1.ButtonComponent, { variant: showLinkInput ? "light" : "simple", paint: "primary", size: "sm", icon: "solid/link", tips: "Link (Ctrl+K)", className: (0, _utils_1.cn)("toolbar-btn", showLinkInput && "toolbar-btn-active"), onClick: (e) => { e?.preventDefault?.(); handleLink(); } }), showLinkInput && ((0, jsx_runtime_1.jsxs)("div", { className: "skcontent-dropdown skcontent-link-input", children: [(0, jsx_runtime_1.jsx)("input", { type: "url", placeholder: "https://...", value: linkUrl, onChange: (e) => setLinkUrl(e.target.value), onKeyDown: (e) => {
|
|
444
505
|
if (e.key === "Enter") {
|
|
445
506
|
e.preventDefault();
|
|
446
507
|
handleLinkSubmit();
|
|
@@ -449,11 +510,6 @@ function InputContentComponent({ label, tip, className = "", value, invalid, val
|
|
|
449
510
|
setShowLinkInput(false);
|
|
450
511
|
}
|
|
451
512
|
}, className: "skcontent-link-url-input", autoFocus: true }), (0, jsx_runtime_1.jsx)(Button_component_1.ButtonComponent, { variant: "solid", paint: "primary", size: "xs", icon: "solid/check", onClick: (e) => { e?.preventDefault?.(); handleLinkSubmit(); } })] }))] }, index));
|
|
452
|
-
case "COLOR":
|
|
453
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "relative", children: [(0, jsx_runtime_1.jsx)(Button_component_1.ButtonComponent, { variant: activeColor !== "normal" ? "light" : "simple", paint: "primary", size: "sm", label: (0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)("div", { className: "skcontent-color-dot", style: { backgroundColor: ContentWrapper_component_1.COLOR_MAP[activeColor]?.css || ContentWrapper_component_1.COLOR_MAP.normal.css } }) }), tips: `Text Color (${ContentWrapper_component_1.COLOR_MAP[activeColor]?.label || "Normal"})`, className: (0, _utils_1.cn)("toolbar-btn", (activeColor !== "normal" || showColorPicker) && "toolbar-btn-active"), onClick: (e) => { e?.preventDefault?.(); setShowColorPicker(!showColorPicker); } }), showColorPicker && ((0, jsx_runtime_1.jsx)("div", { className: "skcontent-dropdown skcontent-color-picker", children: Object.entries(ContentWrapper_component_1.COLOR_MAP).map(([key, info]) => ((0, jsx_runtime_1.jsx)("button", { type: "button", title: info.label, className: (0, _utils_1.cn)("skcontent-color-dot", activeColor === key && "scale-125 border-2 border-primary"), style: { backgroundColor: info.css }, onMouseDown: (e) => {
|
|
454
|
-
e.preventDefault();
|
|
455
|
-
handleColor(key);
|
|
456
|
-
} }, key))) }))] }, index));
|
|
457
513
|
case "LIST_BULLET":
|
|
458
514
|
case "BULLET_LIST":
|
|
459
515
|
return ((0, jsx_runtime_1.jsx)(Button_component_1.ButtonComponent, { variant: activeStates.insertUnorderedList ? "light" : "simple", paint: "primary", size: "sm", icon: "solid/list-bullet", tips: "Bullet List", className: (0, _utils_1.cn)("toolbar-btn", activeStates.insertUnorderedList && "toolbar-btn-active"), onClick: (e) => { e?.preventDefault?.(); handleBulletList(); } }, index));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
2
|
import { ApiType, FormErrorType, FormRegisterType, FormValueType, ValidationRules, DBSchema } from "@utils";
|
|
3
|
-
import { InputProps, InputCheckboxProps, InputCurrencyProps, InputDateProps, InputNumberProps, InputRadioProps, SelectProps, InputPasswordProps, InputOtpProps, InputTimeProps, InputImageProps, InputDateTimeProps } from "../";
|
|
3
|
+
import { InputProps, InputCheckboxProps, InputCurrencyProps, InputDateProps, InputNumberProps, InputRadioProps, SelectProps, InputPasswordProps, InputOtpProps, InputTimeProps, InputImageProps, InputDateTimeProps, TextareaProps, InputContentProps } from "../";
|
|
4
4
|
type formCustomConstructionProps = ({ formControl, values, setValues, setRegister, errors, setErrors, }: {
|
|
5
5
|
formControl: (name: string) => {
|
|
6
6
|
register: (regName: string, regValidations?: ValidationRules | undefined) => void;
|
|
@@ -42,6 +42,8 @@ type ConstructionMap = {
|
|
|
42
42
|
select: SelectProps;
|
|
43
43
|
"enter-password": InputPasswordProps;
|
|
44
44
|
otp: InputOtpProps;
|
|
45
|
+
textarea: TextareaProps;
|
|
46
|
+
content: InputContentProps;
|
|
45
47
|
custom: formCustomConstructionProps;
|
|
46
48
|
};
|
|
47
49
|
type TypeKeys = keyof ConstructionMap;
|
|
@@ -181,6 +181,8 @@ function FormSupervisionComponent({ title, fields, submitControl, confirmation,
|
|
|
181
181
|
"enter-password": __1.InputPasswordComponent,
|
|
182
182
|
otp: __1.InputOtpComponent,
|
|
183
183
|
image: __1.InputImageComponent,
|
|
184
|
+
textarea: __1.TextareaComponent,
|
|
185
|
+
content: __1.InputContentComponent,
|
|
184
186
|
cluster: () => null,
|
|
185
187
|
custom: () => null,
|
|
186
188
|
};
|
|
@@ -235,7 +237,7 @@ function FormSupervisionComponent({ title, fields, submitControl, confirmation,
|
|
|
235
237
|
setValues(updatedValues);
|
|
236
238
|
};
|
|
237
239
|
const clusterError = errors?.find((err) => err.name === groupKey || err.name === mapName)?.error;
|
|
238
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, _utils_1.cn)("flex flex-col gap-4", generateColClass(form.col || "12")), children: [label && (0, jsx_runtime_1.jsx)("p", { className: "input-label", children: label }), clusterError && (0, jsx_runtime_1.jsx)("small", { className: "input-error-message", children: clusterError }), group.map((gIndex) => ((0, jsx_runtime_1.jsxs)("div", { className: (0, _utils_1.cn)("relative pr-8", wrap && "
|
|
240
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, _utils_1.cn)("flex flex-col gap-4", generateColClass(form.col || "12")), children: [label && (0, jsx_runtime_1.jsx)("p", { className: "input-label", children: label }), clusterError && (0, jsx_runtime_1.jsx)("small", { className: "input-error-message", children: clusterError }), group.map((gIndex) => ((0, jsx_runtime_1.jsxs)("div", { className: (0, _utils_1.cn)("relative pr-8", wrap && "form-supervision-cluster-item-wrapped", className), children: [label && (0, jsx_runtime_1.jsxs)("p", { className: "input-label", children: [label, " ", gIndex + 1] }), tip && (0, jsx_runtime_1.jsx)("small", { className: (0, _utils_1.cn)("input-tip"), children: tip }), (label || tip) && (0, jsx_runtime_1.jsx)("div", { className: "mb-2" }), (0, jsx_runtime_1.jsx)("div", { className: "w-full grid grid-cols-12 gap-4", children: innerForms.map((inner, i) => renderInput(inner, i, `${groupKey}[${gIndex}]`)) }), showDeleteButton && ((0, jsx_runtime_1.jsx)(__1.ButtonComponent, { icon: "solid/times", paint: "danger", variant: "outline", size: "xs", className: (0, _utils_1.cn)("form-supervision-cluster-remove-btn", wrap && "form-supervision-cluster-remove-btn-wrapped"), onClick: () => removeGroup(gIndex) }))] }, gIndex))), (0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)(__1.ButtonComponent, { icon: "solid/plus", label: `${l.base.add ? l.base.add() : "Add"} ${label || "Lainnya"}`, variant: "outline", size: "sm", onClick: addGroup }) })] }, key));
|
|
239
241
|
}
|
|
240
242
|
if (inputType === "custom") {
|
|
241
243
|
const customRender = form.construction;
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { ReactNode, Ref, useCallback, useEffect, useRef, useState } from "react";
|
|
4
4
|
import { Icon } from "@skalfa/skalfa-icon";
|
|
5
|
-
import { cn, pcn, useInputHandler, useInputRandomId, useValidation, ValidationRules } from "@utils";
|
|
5
|
+
import { cn, pcn, shortcut, useInputHandler, useInputRandomId, useValidation, ValidationRules } from "@utils";
|
|
6
6
|
import { COLOR_MAP, parseContentToHtml, parseHtmlToContent } from "../wrap/ContentWrapper.component";
|
|
7
7
|
import { ButtonComponent } from "../button/Button.component";
|
|
8
8
|
|
|
@@ -408,7 +408,114 @@ export function InputContentComponent({
|
|
|
408
408
|
handleEditorChange();
|
|
409
409
|
}, [restoreSelection, saveSelection, handleEditorChange]);
|
|
410
410
|
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
const updateActiveStates = useCallback(() => {
|
|
414
|
+
const sel = window.getSelection();
|
|
415
|
+
let inH2 = false;
|
|
416
|
+
if (sel && sel.rangeCount > 0) {
|
|
417
|
+
let node: Node | null = sel.anchorNode;
|
|
418
|
+
while (node && node !== editorRef.current) {
|
|
419
|
+
if (node.nodeType === Node.ELEMENT_NODE && (node as HTMLElement).tagName === "H2") {
|
|
420
|
+
inH2 = true;
|
|
421
|
+
break;
|
|
422
|
+
}
|
|
423
|
+
node = node.parentNode;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
setActiveStates({
|
|
428
|
+
header: inH2,
|
|
429
|
+
bold: isCommandActive("bold"),
|
|
430
|
+
italic: isCommandActive("italic"),
|
|
431
|
+
underline: isCommandActive("underline"),
|
|
432
|
+
strikeThrough: isCommandActive("strikeThrough"),
|
|
433
|
+
justifyLeft: isCommandActive("justifyLeft"),
|
|
434
|
+
justifyCenter: isCommandActive("justifyCenter"),
|
|
435
|
+
justifyRight: isCommandActive("justifyRight"),
|
|
436
|
+
justifyFull: isCommandActive("justifyFull"),
|
|
437
|
+
insertUnorderedList: isCommandActive("insertUnorderedList"),
|
|
438
|
+
insertOrderedList: isCommandActive("insertOrderedList"),
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
if (sel && sel.rangeCount > 0) {
|
|
442
|
+
let node: Node | null = sel.anchorNode;
|
|
443
|
+
let detectedColor = "normal";
|
|
444
|
+
let detectedSize: number | null = null;
|
|
445
|
+
while (node && node !== editorRef.current) {
|
|
446
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
447
|
+
const el = node as HTMLElement;
|
|
448
|
+
if (el.dataset.color && detectedColor === "normal") {
|
|
449
|
+
detectedColor = el.dataset.color;
|
|
450
|
+
}
|
|
451
|
+
if (el.dataset.size && detectedSize === null) {
|
|
452
|
+
const parsed = parseInt(el.dataset.size);
|
|
453
|
+
if (!isNaN(parsed)) detectedSize = parsed;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
node = node.parentNode;
|
|
457
|
+
}
|
|
458
|
+
setActiveColor(detectedColor);
|
|
459
|
+
if (detectedSize !== null) {
|
|
460
|
+
setTextSize(detectedSize);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}, [isCommandActive]);
|
|
464
|
+
|
|
465
|
+
useEffect(() => {
|
|
466
|
+
shortcut.register("ctrl+b", () => handleBold(), "Bold text");
|
|
467
|
+
shortcut.register("ctrl+i", () => handleItalic(), "Italic text");
|
|
468
|
+
shortcut.register("ctrl+u", () => handleUnderline(), "Underline text");
|
|
469
|
+
shortcut.register("ctrl+shift+x", () => handleStrikethrough(), "Strikethrough text");
|
|
470
|
+
shortcut.register("ctrl+k", () => handleLink(), "Insert link");
|
|
471
|
+
|
|
472
|
+
return () => {
|
|
473
|
+
shortcut.unregister("ctrl+b");
|
|
474
|
+
shortcut.unregister("ctrl+i");
|
|
475
|
+
shortcut.unregister("ctrl+u");
|
|
476
|
+
shortcut.unregister("ctrl+shift+x");
|
|
477
|
+
shortcut.unregister("ctrl+k");
|
|
478
|
+
};
|
|
479
|
+
}, [handleBold, handleItalic, handleUnderline, handleStrikethrough, handleLink]);
|
|
480
|
+
|
|
411
481
|
const handleKeyDown = useCallback((e: React.KeyboardEvent) => {
|
|
482
|
+
const isMod = e.ctrlKey || e.metaKey;
|
|
483
|
+
const key = e.key.toLowerCase();
|
|
484
|
+
|
|
485
|
+
if (isMod && !e.shiftKey && !e.altKey && key === "b") {
|
|
486
|
+
e.preventDefault();
|
|
487
|
+
handleBold();
|
|
488
|
+
updateActiveStates();
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
if (isMod && !e.shiftKey && !e.altKey && key === "i") {
|
|
493
|
+
e.preventDefault();
|
|
494
|
+
handleItalic();
|
|
495
|
+
updateActiveStates();
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
if (isMod && !e.shiftKey && !e.altKey && key === "u") {
|
|
500
|
+
e.preventDefault();
|
|
501
|
+
handleUnderline();
|
|
502
|
+
updateActiveStates();
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
if (isMod && e.shiftKey && !e.altKey && key === "x") {
|
|
507
|
+
e.preventDefault();
|
|
508
|
+
handleStrikethrough();
|
|
509
|
+
updateActiveStates();
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
if (isMod && !e.shiftKey && !e.altKey && key === "k") {
|
|
514
|
+
e.preventDefault();
|
|
515
|
+
handleLink();
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
|
|
412
519
|
if (e.key === "Backspace") {
|
|
413
520
|
const sel = window.getSelection();
|
|
414
521
|
if (sel && sel.rangeCount > 0 && sel.isCollapsed) {
|
|
@@ -465,59 +572,7 @@ export function InputContentComponent({
|
|
|
465
572
|
}
|
|
466
573
|
}
|
|
467
574
|
}
|
|
468
|
-
}, [handleEditorChange]);
|
|
469
|
-
|
|
470
|
-
const updateActiveStates = useCallback(() => {
|
|
471
|
-
const sel = window.getSelection();
|
|
472
|
-
let inH2 = false;
|
|
473
|
-
if (sel && sel.rangeCount > 0) {
|
|
474
|
-
let node: Node | null = sel.anchorNode;
|
|
475
|
-
while (node && node !== editorRef.current) {
|
|
476
|
-
if (node.nodeType === Node.ELEMENT_NODE && (node as HTMLElement).tagName === "H2") {
|
|
477
|
-
inH2 = true;
|
|
478
|
-
break;
|
|
479
|
-
}
|
|
480
|
-
node = node.parentNode;
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
setActiveStates({
|
|
485
|
-
header: inH2,
|
|
486
|
-
bold: isCommandActive("bold"),
|
|
487
|
-
italic: isCommandActive("italic"),
|
|
488
|
-
underline: isCommandActive("underline"),
|
|
489
|
-
strikeThrough: isCommandActive("strikeThrough"),
|
|
490
|
-
justifyLeft: isCommandActive("justifyLeft"),
|
|
491
|
-
justifyCenter: isCommandActive("justifyCenter"),
|
|
492
|
-
justifyRight: isCommandActive("justifyRight"),
|
|
493
|
-
justifyFull: isCommandActive("justifyFull"),
|
|
494
|
-
insertUnorderedList: isCommandActive("insertUnorderedList"),
|
|
495
|
-
insertOrderedList: isCommandActive("insertOrderedList"),
|
|
496
|
-
});
|
|
497
|
-
|
|
498
|
-
if (sel && sel.rangeCount > 0) {
|
|
499
|
-
let node: Node | null = sel.anchorNode;
|
|
500
|
-
let detectedColor = "normal";
|
|
501
|
-
let detectedSize: number | null = null;
|
|
502
|
-
while (node && node !== editorRef.current) {
|
|
503
|
-
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
504
|
-
const el = node as HTMLElement;
|
|
505
|
-
if (el.dataset.color && detectedColor === "normal") {
|
|
506
|
-
detectedColor = el.dataset.color;
|
|
507
|
-
}
|
|
508
|
-
if (el.dataset.size && detectedSize === null) {
|
|
509
|
-
const parsed = parseInt(el.dataset.size);
|
|
510
|
-
if (!isNaN(parsed)) detectedSize = parsed;
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
node = node.parentNode;
|
|
514
|
-
}
|
|
515
|
-
setActiveColor(detectedColor);
|
|
516
|
-
if (detectedSize !== null) {
|
|
517
|
-
setTextSize(detectedSize);
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
}, [isCommandActive]);
|
|
575
|
+
}, [handleBold, handleItalic, handleUnderline, handleStrikethrough, handleLink, handleEditorChange, updateActiveStates]);
|
|
521
576
|
|
|
522
577
|
const renderControlItem = useCallback((item: ToolbarControlItem, index: number) => {
|
|
523
578
|
if (typeof item !== "string") {
|
|
@@ -525,19 +580,19 @@ export function InputContentComponent({
|
|
|
525
580
|
}
|
|
526
581
|
|
|
527
582
|
switch (item) {
|
|
528
|
-
case "HEADER":
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
583
|
+
// case "HEADER":
|
|
584
|
+
// return (
|
|
585
|
+
// <ButtonComponent
|
|
586
|
+
// key={index}
|
|
587
|
+
// variant={activeStates.header ? "light" : "simple"}
|
|
588
|
+
// paint="primary"
|
|
589
|
+
// size="sm"
|
|
590
|
+
// icon="solid/text-h"
|
|
591
|
+
// tips="Header"
|
|
592
|
+
// className={cn("toolbar-btn", activeStates.header && "toolbar-btn-active")}
|
|
593
|
+
// onClick={(e: any) => { e?.preventDefault?.(); handleHeader(); }}
|
|
594
|
+
// />
|
|
595
|
+
// );
|
|
541
596
|
case "TEXT_SIZE":
|
|
542
597
|
case "FONT_SIZE":
|
|
543
598
|
return (
|
|
@@ -569,6 +624,41 @@ export function InputContentComponent({
|
|
|
569
624
|
/>
|
|
570
625
|
</div>
|
|
571
626
|
);
|
|
627
|
+
case "COLOR":
|
|
628
|
+
return (
|
|
629
|
+
<div className="relative" key={index}>
|
|
630
|
+
<ButtonComponent
|
|
631
|
+
variant={activeColor !== "normal" ? "light" : "simple"}
|
|
632
|
+
paint="primary"
|
|
633
|
+
size="sm"
|
|
634
|
+
label={<div><div className="skcontent-color-dot" style={{ backgroundColor: COLOR_MAP[activeColor]?.css || COLOR_MAP.normal.css }} /></div>}
|
|
635
|
+
tips={`Text Color (${COLOR_MAP[activeColor]?.label || "Normal"})`}
|
|
636
|
+
className={cn("toolbar-btn", (activeColor !== "normal" || showColorPicker) && "toolbar-btn-active")}
|
|
637
|
+
onClick={(e: any) => { e?.preventDefault?.(); setShowColorPicker(!showColorPicker); }}
|
|
638
|
+
/>
|
|
639
|
+
|
|
640
|
+
{showColorPicker && (
|
|
641
|
+
<div className="skcontent-dropdown skcontent-color-picker">
|
|
642
|
+
{Object.entries(COLOR_MAP).map(([key, info]) => (
|
|
643
|
+
<button
|
|
644
|
+
key={key}
|
|
645
|
+
type="button"
|
|
646
|
+
title={info.label}
|
|
647
|
+
className={cn(
|
|
648
|
+
"skcontent-color-dot",
|
|
649
|
+
activeColor === key && "scale-125 border-2 border-primary"
|
|
650
|
+
)}
|
|
651
|
+
style={{ backgroundColor: info.css }}
|
|
652
|
+
onMouseDown={(e) => {
|
|
653
|
+
e.preventDefault();
|
|
654
|
+
handleColor(key);
|
|
655
|
+
}}
|
|
656
|
+
/>
|
|
657
|
+
))}
|
|
658
|
+
</div>
|
|
659
|
+
)}
|
|
660
|
+
</div>
|
|
661
|
+
);
|
|
572
662
|
case "BOLD":
|
|
573
663
|
return (
|
|
574
664
|
<ButtonComponent
|
|
@@ -577,7 +667,7 @@ export function InputContentComponent({
|
|
|
577
667
|
paint="primary"
|
|
578
668
|
size="sm"
|
|
579
669
|
icon="solid/text-b"
|
|
580
|
-
tips="Bold"
|
|
670
|
+
tips="Bold (Ctrl+B)"
|
|
581
671
|
className={cn("toolbar-btn", activeStates.bold && "toolbar-btn-active")}
|
|
582
672
|
onClick={(e: any) => { e?.preventDefault?.(); handleBold(); }}
|
|
583
673
|
/>
|
|
@@ -590,7 +680,7 @@ export function InputContentComponent({
|
|
|
590
680
|
paint="primary"
|
|
591
681
|
size="sm"
|
|
592
682
|
icon="solid/text-italic"
|
|
593
|
-
tips="Italic"
|
|
683
|
+
tips="Italic (Ctrl+I)"
|
|
594
684
|
className={cn("toolbar-btn", activeStates.italic && "toolbar-btn-active")}
|
|
595
685
|
onClick={(e: any) => { e?.preventDefault?.(); handleItalic(); }}
|
|
596
686
|
/>
|
|
@@ -603,7 +693,7 @@ export function InputContentComponent({
|
|
|
603
693
|
paint="primary"
|
|
604
694
|
size="sm"
|
|
605
695
|
icon="solid/text-underline"
|
|
606
|
-
tips="Underline"
|
|
696
|
+
tips="Underline (Ctrl+U)"
|
|
607
697
|
className={cn("toolbar-btn", activeStates.underline && "toolbar-btn-active")}
|
|
608
698
|
onClick={(e: any) => { e?.preventDefault?.(); handleUnderline(); }}
|
|
609
699
|
/>
|
|
@@ -616,7 +706,7 @@ export function InputContentComponent({
|
|
|
616
706
|
paint="primary"
|
|
617
707
|
size="sm"
|
|
618
708
|
icon="solid/text-slash"
|
|
619
|
-
tips="Strikethrough"
|
|
709
|
+
tips="Strikethrough (Ctrl+Shift+X)"
|
|
620
710
|
className={cn("toolbar-btn", activeStates.strikeThrough && "toolbar-btn-active")}
|
|
621
711
|
onClick={(e: any) => { e?.preventDefault?.(); handleStrikethrough(); }}
|
|
622
712
|
/>
|
|
@@ -681,7 +771,7 @@ export function InputContentComponent({
|
|
|
681
771
|
paint="primary"
|
|
682
772
|
size="sm"
|
|
683
773
|
icon="solid/link"
|
|
684
|
-
tips="Link"
|
|
774
|
+
tips="Link (Ctrl+K)"
|
|
685
775
|
className={cn("toolbar-btn", showLinkInput && "toolbar-btn-active")}
|
|
686
776
|
onClick={(e: any) => { e?.preventDefault?.(); handleLink(); }}
|
|
687
777
|
/>
|
|
@@ -716,41 +806,6 @@ export function InputContentComponent({
|
|
|
716
806
|
)}
|
|
717
807
|
</div>
|
|
718
808
|
);
|
|
719
|
-
case "COLOR":
|
|
720
|
-
return (
|
|
721
|
-
<div className="relative" key={index}>
|
|
722
|
-
<ButtonComponent
|
|
723
|
-
variant={activeColor !== "normal" ? "light" : "simple"}
|
|
724
|
-
paint="primary"
|
|
725
|
-
size="sm"
|
|
726
|
-
label={<div><div className="skcontent-color-dot" style={{ backgroundColor: COLOR_MAP[activeColor]?.css || COLOR_MAP.normal.css }} /></div>}
|
|
727
|
-
tips={`Text Color (${COLOR_MAP[activeColor]?.label || "Normal"})`}
|
|
728
|
-
className={cn("toolbar-btn", (activeColor !== "normal" || showColorPicker) && "toolbar-btn-active")}
|
|
729
|
-
onClick={(e: any) => { e?.preventDefault?.(); setShowColorPicker(!showColorPicker); }}
|
|
730
|
-
/>
|
|
731
|
-
|
|
732
|
-
{showColorPicker && (
|
|
733
|
-
<div className="skcontent-dropdown skcontent-color-picker">
|
|
734
|
-
{Object.entries(COLOR_MAP).map(([key, info]) => (
|
|
735
|
-
<button
|
|
736
|
-
key={key}
|
|
737
|
-
type="button"
|
|
738
|
-
title={info.label}
|
|
739
|
-
className={cn(
|
|
740
|
-
"skcontent-color-dot",
|
|
741
|
-
activeColor === key && "scale-125 border-2 border-primary"
|
|
742
|
-
)}
|
|
743
|
-
style={{ backgroundColor: info.css }}
|
|
744
|
-
onMouseDown={(e) => {
|
|
745
|
-
e.preventDefault();
|
|
746
|
-
handleColor(key);
|
|
747
|
-
}}
|
|
748
|
-
/>
|
|
749
|
-
))}
|
|
750
|
-
</div>
|
|
751
|
-
)}
|
|
752
|
-
</div>
|
|
753
|
-
);
|
|
754
809
|
case "LIST_BULLET":
|
|
755
810
|
case "BULLET_LIST":
|
|
756
811
|
return (
|
|
@@ -29,6 +29,10 @@ import {
|
|
|
29
29
|
InputDatetimeComponent,
|
|
30
30
|
InputTimeComponent,
|
|
31
31
|
InputImageComponent,
|
|
32
|
+
TextareaComponent,
|
|
33
|
+
TextareaProps,
|
|
34
|
+
InputContentComponent,
|
|
35
|
+
InputContentProps,
|
|
32
36
|
} from "../";
|
|
33
37
|
import { Icon } from "@skalfa/skalfa-icon";
|
|
34
38
|
import { useLang } from "@skalfa/skalfa-lang";
|
|
@@ -85,6 +89,8 @@ type ConstructionMap = {
|
|
|
85
89
|
select : SelectProps;
|
|
86
90
|
"enter-password" : InputPasswordProps;
|
|
87
91
|
otp : InputOtpProps;
|
|
92
|
+
textarea : TextareaProps;
|
|
93
|
+
content : InputContentProps;
|
|
88
94
|
custom : formCustomConstructionProps;
|
|
89
95
|
};
|
|
90
96
|
|
|
@@ -366,6 +372,8 @@ export function FormSupervisionComponent({
|
|
|
366
372
|
"enter-password" : InputPasswordComponent,
|
|
367
373
|
otp : InputOtpComponent,
|
|
368
374
|
image : InputImageComponent,
|
|
375
|
+
textarea : TextareaComponent,
|
|
376
|
+
content : InputContentComponent,
|
|
369
377
|
cluster : () => null,
|
|
370
378
|
custom : () => null,
|
|
371
379
|
};
|
|
@@ -438,7 +446,7 @@ export function FormSupervisionComponent({
|
|
|
438
446
|
{label && <p className="input-label">{label}</p>}
|
|
439
447
|
{clusterError && <small className="input-error-message">{clusterError}</small>}
|
|
440
448
|
{group.map((gIndex) => (
|
|
441
|
-
<div key={gIndex} className={cn("relative pr-8", wrap && "
|
|
449
|
+
<div key={gIndex} className={cn("relative pr-8", wrap && "form-supervision-cluster-item-wrapped", className)}>
|
|
442
450
|
{label && <p className="input-label">{label} {gIndex + 1}</p>}
|
|
443
451
|
{tip && <small className={cn("input-tip")}>{tip}</small>}
|
|
444
452
|
{(label || tip) && <div className="mb-2"></div>}
|
|
@@ -453,7 +461,7 @@ export function FormSupervisionComponent({
|
|
|
453
461
|
paint="danger"
|
|
454
462
|
variant="outline"
|
|
455
463
|
size="xs"
|
|
456
|
-
className={cn("
|
|
464
|
+
className={cn("form-supervision-cluster-remove-btn", wrap && "form-supervision-cluster-remove-btn-wrapped")}
|
|
457
465
|
onClick={() => removeGroup(gIndex)}
|
|
458
466
|
/>
|
|
459
467
|
)}
|
|
@@ -463,7 +471,7 @@ export function FormSupervisionComponent({
|
|
|
463
471
|
<div>
|
|
464
472
|
<ButtonComponent
|
|
465
473
|
icon={"solid/plus"}
|
|
466
|
-
label={`${l.base.add ? l.base.add() : "Add"} ${label ||
|
|
474
|
+
label={`${l.base.add ? l.base.add() : "Add"} ${label || "Lainnya"}`}
|
|
467
475
|
variant="outline"
|
|
468
476
|
size="sm"
|
|
469
477
|
onClick={addGroup}
|