@x-plat/design-system 0.11.0 → 0.13.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/dist/components/AutoResizeTextArea/index.cjs +2 -2
- package/dist/components/AutoResizeTextArea/index.js +2 -2
- package/dist/components/ChatInput/index.cjs +2 -2
- package/dist/components/ChatInput/index.js +2 -2
- package/dist/components/CheckBox/index.cjs +2 -2
- package/dist/components/CheckBox/index.js +2 -2
- package/dist/components/DatePicker/index.cjs +109 -75
- package/dist/components/DatePicker/index.d.cts +19 -0
- package/dist/components/DatePicker/index.d.ts +19 -0
- package/dist/components/DatePicker/index.js +109 -75
- package/dist/components/Dropdown/index.cjs +22 -9
- package/dist/components/Dropdown/index.css +3 -0
- package/dist/components/Dropdown/index.js +22 -9
- package/dist/components/Editor/index.cjs +602 -30
- package/dist/components/Editor/index.css +103 -0
- package/dist/components/Editor/index.d.cts +1 -1
- package/dist/components/Editor/index.d.ts +1 -1
- package/dist/components/Editor/index.js +602 -30
- package/dist/components/FieldMessage/index.cjs +2 -2
- package/dist/components/FieldMessage/index.d.cts +8 -0
- package/dist/components/FieldMessage/index.d.ts +8 -0
- package/dist/components/FieldMessage/index.js +2 -2
- package/dist/components/FileUpload/index.cjs +10 -6
- package/dist/components/FileUpload/index.d.cts +15 -2
- package/dist/components/FileUpload/index.d.ts +15 -2
- package/dist/components/FileUpload/index.js +10 -6
- package/dist/components/ImageSelector/index.cjs +7 -6
- package/dist/components/ImageSelector/index.d.cts +15 -2
- package/dist/components/ImageSelector/index.d.ts +15 -2
- package/dist/components/ImageSelector/index.js +7 -6
- package/dist/components/Input/index.cjs +2 -2
- package/dist/components/Input/index.d.cts +4 -0
- package/dist/components/Input/index.d.ts +4 -0
- package/dist/components/Input/index.js +2 -2
- package/dist/components/PopOver/index.cjs +21 -7
- package/dist/components/PopOver/index.css +3 -0
- package/dist/components/PopOver/index.js +21 -7
- package/dist/components/Radio/index.cjs +2 -2
- package/dist/components/Radio/index.js +2 -2
- package/dist/components/Select/index.cjs +23 -10
- package/dist/components/Select/index.css +3 -0
- package/dist/components/Select/index.d.cts +1 -2
- package/dist/components/Select/index.d.ts +1 -2
- package/dist/components/Select/index.js +23 -10
- package/dist/components/Switch/index.cjs +2 -2
- package/dist/components/Switch/index.js +2 -2
- package/dist/components/TextArea/index.cjs +2 -2
- package/dist/components/TextArea/index.js +2 -2
- package/dist/components/TimePicker/index.cjs +23 -10
- package/dist/components/TimePicker/index.css +3 -0
- package/dist/components/TimePicker/index.js +23 -10
- package/dist/components/index.cjs +751 -124
- package/dist/components/index.css +113 -0
- package/dist/components/index.js +751 -124
- package/dist/index.cjs +751 -124
- package/dist/index.css +113 -0
- package/dist/index.js +751 -124
- package/guidelines/Guidelines.md +12 -0
- package/guidelines/MIGRATION.md +270 -0
- package/guidelines/components/datepicker.md +26 -0
- package/guidelines/components/editor.md +58 -3
- package/guidelines/components/file-media.md +21 -4
- package/package.json +1 -1
|
@@ -1633,11 +1633,11 @@ var FieldMessage = (props) => {
|
|
|
1633
1633
|
FieldMessage.displayName = "FieldMessage";
|
|
1634
1634
|
var FieldMessage_default = FieldMessage;
|
|
1635
1635
|
var Field = (props) => {
|
|
1636
|
-
const { label, required = false, htmlFor, validations, children } = props;
|
|
1636
|
+
const { label, required = false, htmlFor, labelId, validations, children } = props;
|
|
1637
1637
|
const hasMessages = !!validations && validations.length > 0;
|
|
1638
1638
|
if (!label && !hasMessages) return /* @__PURE__ */ (0, import_jsx_runtime297.jsx)(import_jsx_runtime297.Fragment, { children });
|
|
1639
1639
|
return /* @__PURE__ */ (0, import_jsx_runtime297.jsxs)("div", { className: "lib-xplat-field", children: [
|
|
1640
|
-
label && /* @__PURE__ */ (0, import_jsx_runtime297.jsxs)("label", { className: "lib-xplat-field-label", htmlFor, children: [
|
|
1640
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime297.jsxs)("label", { className: "lib-xplat-field-label", id: labelId, htmlFor, children: [
|
|
1641
1641
|
label,
|
|
1642
1642
|
required && /* @__PURE__ */ (0, import_jsx_runtime297.jsx)("span", { className: "required", "aria-hidden": "true", children: "*" })
|
|
1643
1643
|
] }),
|
|
@@ -3404,8 +3404,12 @@ var SingleDatePicker = (props) => {
|
|
|
3404
3404
|
highlightDates = [],
|
|
3405
3405
|
locale = "ko",
|
|
3406
3406
|
rangeStart,
|
|
3407
|
-
rangeEnd
|
|
3407
|
+
rangeEnd,
|
|
3408
|
+
label,
|
|
3409
|
+
required,
|
|
3410
|
+
validations
|
|
3408
3411
|
} = props;
|
|
3412
|
+
const labelId = import_react12.default.useId();
|
|
3409
3413
|
const initialYear = value?.getFullYear();
|
|
3410
3414
|
const initialMonth = value?.getMonth();
|
|
3411
3415
|
const { year, month, days, goToPrevMonth, goToNextMonth, setYear, setMonth } = useCalendar(
|
|
@@ -3468,10 +3472,12 @@ var SingleDatePicker = (props) => {
|
|
|
3468
3472
|
const monthLabels = MONTH_LABELS[locale];
|
|
3469
3473
|
const titleText = pickerMode === "days" ? locale === "ko" ? `${year}\uB144 ${monthLabels[month]}` : `${monthLabels[month]} ${year}` : pickerMode === "months" ? `${year}` : `${yearRangeStart} - ${yearRangeStart + 11}`;
|
|
3470
3474
|
const hasRange = rangeStart != null && rangeEnd != null;
|
|
3471
|
-
|
|
3475
|
+
const calendar = /* @__PURE__ */ (0, import_jsx_runtime314.jsxs)(
|
|
3472
3476
|
"div",
|
|
3473
3477
|
{
|
|
3474
3478
|
className: clsx_default("lib-xplat-datepicker", "single"),
|
|
3479
|
+
role: "group",
|
|
3480
|
+
"aria-labelledby": label ? labelId : void 0,
|
|
3475
3481
|
children: [
|
|
3476
3482
|
/* @__PURE__ */ (0, import_jsx_runtime314.jsxs)("div", { className: "datepicker-header", children: [
|
|
3477
3483
|
/* @__PURE__ */ (0, import_jsx_runtime314.jsx)("button", { className: "datepicker-nav", onClick: handlePrev, type: "button", children: /* @__PURE__ */ (0, import_jsx_runtime314.jsx)(ChevronLeftIcon_default, {}) }),
|
|
@@ -3492,18 +3498,18 @@ var SingleDatePicker = (props) => {
|
|
|
3492
3498
|
y
|
|
3493
3499
|
);
|
|
3494
3500
|
}) }),
|
|
3495
|
-
pickerMode === "months" && /* @__PURE__ */ (0, import_jsx_runtime314.jsx)("div", { className: "datepicker-picker-grid", children: monthLabels.map((
|
|
3501
|
+
pickerMode === "months" && /* @__PURE__ */ (0, import_jsx_runtime314.jsx)("div", { className: "datepicker-picker-grid", children: monthLabels.map((label2, i) => /* @__PURE__ */ (0, import_jsx_runtime314.jsx)(
|
|
3496
3502
|
"button",
|
|
3497
3503
|
{
|
|
3498
3504
|
type: "button",
|
|
3499
3505
|
className: clsx_default("datepicker-picker-cell", i === month && "active"),
|
|
3500
3506
|
onClick: () => handleMonthSelect(i),
|
|
3501
|
-
children:
|
|
3507
|
+
children: label2
|
|
3502
3508
|
},
|
|
3503
3509
|
i
|
|
3504
3510
|
)) }),
|
|
3505
3511
|
pickerMode === "days" && /* @__PURE__ */ (0, import_jsx_runtime314.jsxs)(import_jsx_runtime314.Fragment, { children: [
|
|
3506
|
-
/* @__PURE__ */ (0, import_jsx_runtime314.jsx)("div", { className: "datepicker-weekdays", children: weekdays.map((
|
|
3512
|
+
/* @__PURE__ */ (0, import_jsx_runtime314.jsx)("div", { className: "datepicker-weekdays", children: weekdays.map((label2, i) => /* @__PURE__ */ (0, import_jsx_runtime314.jsx)(
|
|
3507
3513
|
"div",
|
|
3508
3514
|
{
|
|
3509
3515
|
className: clsx_default(
|
|
@@ -3511,9 +3517,9 @@ var SingleDatePicker = (props) => {
|
|
|
3511
3517
|
i === 0 && "sunday",
|
|
3512
3518
|
i === 6 && "saturday"
|
|
3513
3519
|
),
|
|
3514
|
-
children:
|
|
3520
|
+
children: label2
|
|
3515
3521
|
},
|
|
3516
|
-
|
|
3522
|
+
label2
|
|
3517
3523
|
)) }),
|
|
3518
3524
|
/* @__PURE__ */ (0, import_jsx_runtime314.jsx)("div", { className: "datepicker-grid", children: days.map((day, idx) => {
|
|
3519
3525
|
const t = day.date.getTime();
|
|
@@ -3545,6 +3551,7 @@ var SingleDatePicker = (props) => {
|
|
|
3545
3551
|
]
|
|
3546
3552
|
}
|
|
3547
3553
|
);
|
|
3554
|
+
return /* @__PURE__ */ (0, import_jsx_runtime314.jsx)(Field, { label, required, labelId, validations, children: calendar });
|
|
3548
3555
|
};
|
|
3549
3556
|
SingleDatePicker.displayName = "SingleDatePicker";
|
|
3550
3557
|
var SingleDatePicker_default = SingleDatePicker;
|
|
@@ -3559,7 +3566,18 @@ var formatDate = (date) => {
|
|
|
3559
3566
|
return `${y}/${m}/${d}`;
|
|
3560
3567
|
};
|
|
3561
3568
|
var InputDatePicker = (props) => {
|
|
3562
|
-
const {
|
|
3569
|
+
const {
|
|
3570
|
+
value,
|
|
3571
|
+
onChange,
|
|
3572
|
+
minDate,
|
|
3573
|
+
maxDate,
|
|
3574
|
+
disabled,
|
|
3575
|
+
locale = "ko",
|
|
3576
|
+
placeholder,
|
|
3577
|
+
label,
|
|
3578
|
+
required,
|
|
3579
|
+
validations
|
|
3580
|
+
} = props;
|
|
3563
3581
|
const [isOpen, setIsOpen] = import_react13.default.useState(false);
|
|
3564
3582
|
const [tempDate, setTempDate] = import_react13.default.useState(value ?? /* @__PURE__ */ new Date());
|
|
3565
3583
|
const handleOpen = () => {
|
|
@@ -3585,6 +3603,9 @@ var InputDatePicker = (props) => {
|
|
|
3585
3603
|
placeholder,
|
|
3586
3604
|
suffix: /* @__PURE__ */ (0, import_jsx_runtime315.jsx)(CalenderIcon_default, {}),
|
|
3587
3605
|
disabled,
|
|
3606
|
+
label,
|
|
3607
|
+
required,
|
|
3608
|
+
validations,
|
|
3588
3609
|
readOnly: true
|
|
3589
3610
|
}
|
|
3590
3611
|
) }),
|
|
@@ -3716,8 +3737,12 @@ var RangePicker = (props) => {
|
|
|
3716
3737
|
onChange,
|
|
3717
3738
|
minDate,
|
|
3718
3739
|
maxDate,
|
|
3719
|
-
locale = "ko"
|
|
3740
|
+
locale = "ko",
|
|
3741
|
+
label,
|
|
3742
|
+
required,
|
|
3743
|
+
validations
|
|
3720
3744
|
} = props;
|
|
3745
|
+
const labelId = import_react16.default.useId();
|
|
3721
3746
|
const [activeTab, setActiveTab] = import_react16.default.useState("start");
|
|
3722
3747
|
const handleStartChange = (date) => {
|
|
3723
3748
|
if (!date) return;
|
|
@@ -3731,70 +3756,79 @@ var RangePicker = (props) => {
|
|
|
3731
3756
|
};
|
|
3732
3757
|
const startMaxDate = maxDate && endDate < maxDate ? endDate : endDate;
|
|
3733
3758
|
const endMinDate = minDate && startDate > minDate ? startDate : startDate;
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3759
|
+
const calendar = /* @__PURE__ */ (0, import_jsx_runtime318.jsxs)(
|
|
3760
|
+
"div",
|
|
3761
|
+
{
|
|
3762
|
+
className: clsx_default("lib-xplat-datepicker", "range"),
|
|
3763
|
+
role: "group",
|
|
3764
|
+
"aria-labelledby": label ? labelId : void 0,
|
|
3765
|
+
children: [
|
|
3766
|
+
/* @__PURE__ */ (0, import_jsx_runtime318.jsx)("div", { className: "datepicker-range-tabs", children: /* @__PURE__ */ (0, import_jsx_runtime318.jsx)(
|
|
3767
|
+
Tab_default,
|
|
3768
|
+
{
|
|
3769
|
+
activeIndex: activeTab === "start" ? 0 : 1,
|
|
3770
|
+
tabs: [
|
|
3771
|
+
{ value: "start", title: locale === "ko" ? "\uC2DC\uC791\uC77C" : "Start" },
|
|
3772
|
+
{ value: "end", title: locale === "ko" ? "\uC885\uB8CC\uC77C" : "End" }
|
|
3773
|
+
],
|
|
3774
|
+
onChange: (tab) => setActiveTab(tab.value),
|
|
3775
|
+
type: "toggle",
|
|
3776
|
+
size: "sm"
|
|
3777
|
+
}
|
|
3778
|
+
) }),
|
|
3779
|
+
/* @__PURE__ */ (0, import_jsx_runtime318.jsxs)("div", { className: "datepicker-range-panels", children: [
|
|
3780
|
+
/* @__PURE__ */ (0, import_jsx_runtime318.jsx)(
|
|
3781
|
+
SingleDatePicker_default,
|
|
3782
|
+
{
|
|
3783
|
+
value: startDate,
|
|
3784
|
+
onChange: handleStartChange,
|
|
3785
|
+
minDate,
|
|
3786
|
+
maxDate: startMaxDate,
|
|
3787
|
+
rangeStart: startDate,
|
|
3788
|
+
rangeEnd: endDate,
|
|
3789
|
+
locale
|
|
3790
|
+
}
|
|
3791
|
+
),
|
|
3792
|
+
/* @__PURE__ */ (0, import_jsx_runtime318.jsx)(
|
|
3793
|
+
SingleDatePicker_default,
|
|
3794
|
+
{
|
|
3795
|
+
value: endDate,
|
|
3796
|
+
onChange: handleEndChange,
|
|
3797
|
+
minDate: endMinDate,
|
|
3798
|
+
maxDate,
|
|
3799
|
+
rangeStart: startDate,
|
|
3800
|
+
rangeEnd: endDate,
|
|
3801
|
+
locale
|
|
3802
|
+
}
|
|
3803
|
+
)
|
|
3804
|
+
] }),
|
|
3805
|
+
/* @__PURE__ */ (0, import_jsx_runtime318.jsx)("div", { className: "datepicker-range-mobile", children: activeTab === "start" ? /* @__PURE__ */ (0, import_jsx_runtime318.jsx)(
|
|
3806
|
+
SingleDatePicker_default,
|
|
3807
|
+
{
|
|
3808
|
+
value: startDate,
|
|
3809
|
+
onChange: handleStartChange,
|
|
3810
|
+
minDate,
|
|
3811
|
+
maxDate: startMaxDate,
|
|
3812
|
+
rangeStart: startDate,
|
|
3813
|
+
rangeEnd: endDate,
|
|
3814
|
+
locale
|
|
3815
|
+
}
|
|
3816
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime318.jsx)(
|
|
3817
|
+
SingleDatePicker_default,
|
|
3818
|
+
{
|
|
3819
|
+
value: endDate,
|
|
3820
|
+
onChange: handleEndChange,
|
|
3821
|
+
minDate: endMinDate,
|
|
3822
|
+
maxDate,
|
|
3823
|
+
rangeStart: startDate,
|
|
3824
|
+
rangeEnd: endDate,
|
|
3825
|
+
locale
|
|
3826
|
+
}
|
|
3827
|
+
) })
|
|
3828
|
+
]
|
|
3829
|
+
}
|
|
3830
|
+
);
|
|
3831
|
+
return /* @__PURE__ */ (0, import_jsx_runtime318.jsx)(Field, { label, required, labelId, validations, children: calendar });
|
|
3798
3832
|
};
|
|
3799
3833
|
RangePicker.displayName = "RangePicker";
|
|
3800
3834
|
var RangePicker_default = RangePicker;
|
|
@@ -3943,8 +3977,10 @@ var import_react19 = __toESM(require("react"), 1);
|
|
|
3943
3977
|
var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
3944
3978
|
const [position, setPosition] = import_react19.default.useState({
|
|
3945
3979
|
position: {},
|
|
3946
|
-
direction: "bottom"
|
|
3980
|
+
direction: "bottom",
|
|
3981
|
+
repositioning: false
|
|
3947
3982
|
});
|
|
3983
|
+
const placedRef = import_react19.default.useRef(false);
|
|
3948
3984
|
const calculatePosition = import_react19.default.useCallback(() => {
|
|
3949
3985
|
if (!triggerRef.current || !popRef.current) return;
|
|
3950
3986
|
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
@@ -3969,11 +4005,16 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
3969
4005
|
if (left < 8) left = 8;
|
|
3970
4006
|
setPosition({
|
|
3971
4007
|
position: { top, left },
|
|
3972
|
-
direction
|
|
4008
|
+
direction,
|
|
4009
|
+
repositioning: placedRef.current
|
|
3973
4010
|
});
|
|
4011
|
+
placedRef.current = true;
|
|
3974
4012
|
}, [triggerRef, popRef]);
|
|
3975
4013
|
import_react19.default.useLayoutEffect(() => {
|
|
3976
|
-
if (!enabled)
|
|
4014
|
+
if (!enabled) {
|
|
4015
|
+
placedRef.current = false;
|
|
4016
|
+
return;
|
|
4017
|
+
}
|
|
3977
4018
|
calculatePosition();
|
|
3978
4019
|
const raf = requestAnimationFrame(calculatePosition);
|
|
3979
4020
|
return () => cancelAnimationFrame(raf);
|
|
@@ -3988,11 +4029,17 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
3988
4029
|
}, [calculatePosition, enabled, popRef]);
|
|
3989
4030
|
import_react19.default.useEffect(() => {
|
|
3990
4031
|
if (!enabled) return;
|
|
3991
|
-
|
|
3992
|
-
|
|
4032
|
+
let raf = 0;
|
|
4033
|
+
const onScrollOrResize = () => {
|
|
4034
|
+
cancelAnimationFrame(raf);
|
|
4035
|
+
raf = requestAnimationFrame(calculatePosition);
|
|
4036
|
+
};
|
|
4037
|
+
window.addEventListener("resize", onScrollOrResize, { passive: true });
|
|
4038
|
+
window.addEventListener("scroll", onScrollOrResize, { passive: true, capture: true });
|
|
3993
4039
|
return () => {
|
|
3994
|
-
|
|
3995
|
-
window.removeEventListener("
|
|
4040
|
+
cancelAnimationFrame(raf);
|
|
4041
|
+
window.removeEventListener("resize", onScrollOrResize);
|
|
4042
|
+
window.removeEventListener("scroll", onScrollOrResize, true);
|
|
3996
4043
|
};
|
|
3997
4044
|
}, [calculatePosition, enabled]);
|
|
3998
4045
|
return position;
|
|
@@ -4033,7 +4080,7 @@ var Dropdown = (props) => {
|
|
|
4033
4080
|
const [visible, setVisible] = import_react21.default.useState(false);
|
|
4034
4081
|
const triggerRef = import_react21.default.useRef(null);
|
|
4035
4082
|
const menuRef = import_react21.default.useRef(null);
|
|
4036
|
-
const { position, direction } = useAutoPosition_default(triggerRef, menuRef, mounted);
|
|
4083
|
+
const { position, direction, repositioning } = useAutoPosition_default(triggerRef, menuRef, mounted);
|
|
4037
4084
|
useClickOutside_default([triggerRef, menuRef], () => setIsOpen(false), isOpen);
|
|
4038
4085
|
useEscapeKey(isOpen, () => {
|
|
4039
4086
|
setIsOpen(false);
|
|
@@ -4068,7 +4115,7 @@ var Dropdown = (props) => {
|
|
|
4068
4115
|
"div",
|
|
4069
4116
|
{
|
|
4070
4117
|
ref: menuRef,
|
|
4071
|
-
className: clsx_default("lib-xplat-dropdown-menu", direction, { visible }),
|
|
4118
|
+
className: clsx_default("lib-xplat-dropdown-menu", direction, { visible }, repositioning && "repositioning"),
|
|
4072
4119
|
style: { top: position.top, left: position.left },
|
|
4073
4120
|
role: "menu",
|
|
4074
4121
|
children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime322.jsx)(
|
|
@@ -4094,6 +4141,111 @@ var Dropdown_default = Dropdown;
|
|
|
4094
4141
|
|
|
4095
4142
|
// src/components/Editor/Editor.tsx
|
|
4096
4143
|
var import_react22 = __toESM(require("react"), 1);
|
|
4144
|
+
|
|
4145
|
+
// src/components/Editor/highlight.ts
|
|
4146
|
+
var CODE_LANGUAGES = [
|
|
4147
|
+
{ value: "plain", label: "\uC5C6\uC74C" },
|
|
4148
|
+
{ value: "javascript", label: "JavaScript" },
|
|
4149
|
+
{ value: "typescript", label: "TypeScript" },
|
|
4150
|
+
{ value: "json", label: "JSON" },
|
|
4151
|
+
{ value: "html", label: "HTML" },
|
|
4152
|
+
{ value: "css", label: "CSS" },
|
|
4153
|
+
{ value: "python", label: "Python" },
|
|
4154
|
+
{ value: "sql", label: "SQL" },
|
|
4155
|
+
{ value: "bash", label: "Bash" }
|
|
4156
|
+
];
|
|
4157
|
+
var KEYWORDS = {
|
|
4158
|
+
plain: [],
|
|
4159
|
+
javascript: "const let var function return if else for while class new this import export from default async await try catch throw typeof instanceof null undefined true false break continue switch case do delete in of yield".split(" "),
|
|
4160
|
+
typescript: "const let var function return if else for while class new this import export from default async await try catch throw typeof instanceof null undefined true false break continue switch case do delete in of yield interface type enum implements extends public private protected readonly as satisfies keyof infer never unknown any".split(" "),
|
|
4161
|
+
json: ["true", "false", "null"],
|
|
4162
|
+
html: [],
|
|
4163
|
+
css: [],
|
|
4164
|
+
python: "def class return if elif else for while import from as try except finally raise with lambda None True False and or not in is pass break continue global nonlocal yield async await".split(" "),
|
|
4165
|
+
sql: "SELECT FROM WHERE INSERT INTO VALUES UPDATE SET DELETE CREATE TABLE ALTER DROP JOIN LEFT RIGHT INNER OUTER ON GROUP BY ORDER HAVING LIMIT OFFSET AS AND OR NOT NULL DISTINCT UNION INDEX PRIMARY KEY FOREIGN REFERENCES DEFAULT".split(" "),
|
|
4166
|
+
bash: "if then else fi for while do done case esac function return export local echo cd ls rm cp mv mkdir sudo source set unset exit".split(" ")
|
|
4167
|
+
};
|
|
4168
|
+
var LINE_COMMENT = {
|
|
4169
|
+
javascript: "//",
|
|
4170
|
+
typescript: "//",
|
|
4171
|
+
css: "",
|
|
4172
|
+
python: "#",
|
|
4173
|
+
sql: "--",
|
|
4174
|
+
bash: "#"
|
|
4175
|
+
};
|
|
4176
|
+
var escape = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
4177
|
+
var wrap = (cls, text) => `<span class="tok-${cls}">${escape(text)}</span>`;
|
|
4178
|
+
var highlight = (code, lang) => {
|
|
4179
|
+
if (lang === "plain" || !code) return escape(code);
|
|
4180
|
+
const keywords = new Set(KEYWORDS[lang]);
|
|
4181
|
+
const lineComment = LINE_COMMENT[lang];
|
|
4182
|
+
const caseInsensitive = lang === "sql";
|
|
4183
|
+
let out = "";
|
|
4184
|
+
let i = 0;
|
|
4185
|
+
while (i < code.length) {
|
|
4186
|
+
const rest = code.slice(i);
|
|
4187
|
+
if ((lang === "javascript" || lang === "typescript" || lang === "css") && rest.startsWith("/*")) {
|
|
4188
|
+
const end = code.indexOf("*/", i + 2);
|
|
4189
|
+
const stop = end === -1 ? code.length : end + 2;
|
|
4190
|
+
out += wrap("comment", code.slice(i, stop));
|
|
4191
|
+
i = stop;
|
|
4192
|
+
continue;
|
|
4193
|
+
}
|
|
4194
|
+
if (lineComment && rest.startsWith(lineComment)) {
|
|
4195
|
+
const nl = code.indexOf("\n", i);
|
|
4196
|
+
const stop = nl === -1 ? code.length : nl;
|
|
4197
|
+
out += wrap("comment", code.slice(i, stop));
|
|
4198
|
+
i = stop;
|
|
4199
|
+
continue;
|
|
4200
|
+
}
|
|
4201
|
+
const q = rest[0];
|
|
4202
|
+
if (q === '"' || q === "'" || q === "`") {
|
|
4203
|
+
let j = 1;
|
|
4204
|
+
while (j < rest.length) {
|
|
4205
|
+
if (rest[j] === "\\") {
|
|
4206
|
+
j += 2;
|
|
4207
|
+
continue;
|
|
4208
|
+
}
|
|
4209
|
+
if (rest[j] === q) {
|
|
4210
|
+
j += 1;
|
|
4211
|
+
break;
|
|
4212
|
+
}
|
|
4213
|
+
if (rest[j] === "\n" && q !== "`") break;
|
|
4214
|
+
j += 1;
|
|
4215
|
+
}
|
|
4216
|
+
out += wrap("string", rest.slice(0, j));
|
|
4217
|
+
i += j;
|
|
4218
|
+
continue;
|
|
4219
|
+
}
|
|
4220
|
+
const num = /^\d+(\.\d+)?/.exec(rest);
|
|
4221
|
+
if (num && !/[\w$]/.test(code[i - 1] ?? "")) {
|
|
4222
|
+
out += wrap("number", num[0]);
|
|
4223
|
+
i += num[0].length;
|
|
4224
|
+
continue;
|
|
4225
|
+
}
|
|
4226
|
+
const word = /^[A-Za-z_$][\w$]*/.exec(rest);
|
|
4227
|
+
if (word) {
|
|
4228
|
+
const w = word[0];
|
|
4229
|
+
const hit = caseInsensitive ? keywords.has(w.toUpperCase()) : keywords.has(w);
|
|
4230
|
+
out += hit ? wrap("keyword", w) : escape(w);
|
|
4231
|
+
i += w.length;
|
|
4232
|
+
continue;
|
|
4233
|
+
}
|
|
4234
|
+
if (lang === "html" && rest.startsWith("<")) {
|
|
4235
|
+
const tag = /^<\/?[A-Za-z][\w-]*/.exec(rest);
|
|
4236
|
+
if (tag) {
|
|
4237
|
+
out += wrap("keyword", tag[0]);
|
|
4238
|
+
i += tag[0].length;
|
|
4239
|
+
continue;
|
|
4240
|
+
}
|
|
4241
|
+
}
|
|
4242
|
+
out += escape(code[i]);
|
|
4243
|
+
i += 1;
|
|
4244
|
+
}
|
|
4245
|
+
return out;
|
|
4246
|
+
};
|
|
4247
|
+
|
|
4248
|
+
// src/components/Editor/Editor.tsx
|
|
4097
4249
|
var import_jsx_runtime323 = require("react/jsx-runtime");
|
|
4098
4250
|
var DEFAULT_TOOLBAR = [
|
|
4099
4251
|
"bold",
|
|
@@ -4101,14 +4253,27 @@ var DEFAULT_TOOLBAR = [
|
|
|
4101
4253
|
"underline",
|
|
4102
4254
|
"strikethrough",
|
|
4103
4255
|
"code",
|
|
4104
|
-
"heading",
|
|
4256
|
+
"heading-1",
|
|
4257
|
+
"heading-2",
|
|
4258
|
+
"heading-3",
|
|
4105
4259
|
"list",
|
|
4106
4260
|
"ordered-list",
|
|
4107
4261
|
"blockquote",
|
|
4108
4262
|
"code-block",
|
|
4109
4263
|
"link",
|
|
4110
4264
|
"image",
|
|
4111
|
-
"divider"
|
|
4265
|
+
"divider",
|
|
4266
|
+
"checklist",
|
|
4267
|
+
"table",
|
|
4268
|
+
"align-left",
|
|
4269
|
+
"align-center",
|
|
4270
|
+
"align-right",
|
|
4271
|
+
"highlight",
|
|
4272
|
+
"superscript",
|
|
4273
|
+
"subscript",
|
|
4274
|
+
"clear-format",
|
|
4275
|
+
"undo",
|
|
4276
|
+
"redo"
|
|
4112
4277
|
];
|
|
4113
4278
|
var ALLOWED_TAGS = /* @__PURE__ */ new Set([
|
|
4114
4279
|
"p",
|
|
@@ -4137,11 +4302,41 @@ var ALLOWED_TAGS = /* @__PURE__ */ new Set([
|
|
|
4137
4302
|
"img",
|
|
4138
4303
|
"hr",
|
|
4139
4304
|
"span",
|
|
4140
|
-
"div"
|
|
4305
|
+
"div",
|
|
4306
|
+
"sub",
|
|
4307
|
+
"sup",
|
|
4308
|
+
"mark",
|
|
4309
|
+
"table",
|
|
4310
|
+
"thead",
|
|
4311
|
+
"tbody",
|
|
4312
|
+
"tr",
|
|
4313
|
+
"th",
|
|
4314
|
+
"td"
|
|
4141
4315
|
]);
|
|
4142
4316
|
var ALLOWED_ATTRS = {
|
|
4143
4317
|
a: ["href", "target", "rel"],
|
|
4144
|
-
img: ["src", "alt"]
|
|
4318
|
+
img: ["src", "alt", "width"],
|
|
4319
|
+
// 정렬·체크리스트는 클래스로만 표현한다. style 을 열면 붙여넣기로 아무 CSS 나 들어온다
|
|
4320
|
+
p: ["class"],
|
|
4321
|
+
h1: ["class"],
|
|
4322
|
+
h2: ["class"],
|
|
4323
|
+
h3: ["class"],
|
|
4324
|
+
h4: ["class"],
|
|
4325
|
+
h5: ["class"],
|
|
4326
|
+
h6: ["class"],
|
|
4327
|
+
ul: ["class"],
|
|
4328
|
+
ol: ["class"],
|
|
4329
|
+
li: ["class", "data-checked"],
|
|
4330
|
+
blockquote: ["class"],
|
|
4331
|
+
div: ["class"],
|
|
4332
|
+
span: ["class"],
|
|
4333
|
+
pre: ["class"],
|
|
4334
|
+
code: ["class"],
|
|
4335
|
+
mark: ["class"],
|
|
4336
|
+
table: ["class"],
|
|
4337
|
+
td: ["class"],
|
|
4338
|
+
th: ["class"],
|
|
4339
|
+
tr: ["class"]
|
|
4145
4340
|
};
|
|
4146
4341
|
var DROP_WITH_CONTENT = /* @__PURE__ */ new Set([
|
|
4147
4342
|
"script",
|
|
@@ -4194,7 +4389,9 @@ var escapeHtml = (text) => {
|
|
|
4194
4389
|
};
|
|
4195
4390
|
var SLASH_ITEMS = [
|
|
4196
4391
|
{ key: "paragraph", label: "\uB2E8\uB77D", hint: "\uAE30\uBCF8 \uD14D\uC2A4\uD2B8" },
|
|
4197
|
-
{ key: "heading", label: "\uC81C\uBAA9 1", hint: "\uD070 \uC81C\uBAA9" },
|
|
4392
|
+
{ key: "heading-1", label: "\uC81C\uBAA9 1", hint: "\uAC00\uC7A5 \uD070 \uC81C\uBAA9" },
|
|
4393
|
+
{ key: "heading-2", label: "\uC81C\uBAA9 2", hint: "" },
|
|
4394
|
+
{ key: "heading-3", label: "\uC81C\uBAA9 3", hint: "" },
|
|
4198
4395
|
{ key: "list", label: "\uAE00\uBA38\uB9AC \uAE30\uD638 \uBAA9\uB85D", hint: "\u2022 \uD56D\uBAA9" },
|
|
4199
4396
|
{ key: "ordered-list", label: "\uBC88\uD638 \uB9E4\uAE30\uAE30 \uBAA9\uB85D", hint: "1. \uD56D\uBAA9" },
|
|
4200
4397
|
{ key: "blockquote", label: "\uC778\uC6A9", hint: "" },
|
|
@@ -4237,6 +4434,8 @@ var Editor = (props) => {
|
|
|
4237
4434
|
el.innerHTML = sanitizeHtml(value || "");
|
|
4238
4435
|
if (!el.firstChild) el.innerHTML = "<p><br></p>";
|
|
4239
4436
|
lastEmittedRef.current = null;
|
|
4437
|
+
historyRef.current = [{ html: el.innerHTML, caret: 0 }];
|
|
4438
|
+
historyIdxRef.current = 0;
|
|
4240
4439
|
updateEmpty();
|
|
4241
4440
|
}, [value]);
|
|
4242
4441
|
const updateEmpty = () => {
|
|
@@ -4281,6 +4480,17 @@ var Editor = (props) => {
|
|
|
4281
4480
|
if (document.queryCommandState("insertOrderedList")) next.add("ordered-list");
|
|
4282
4481
|
const block = String(document.queryCommandValue("formatBlock") || "").toLowerCase();
|
|
4283
4482
|
if (block) next.add(`block:${block}`);
|
|
4483
|
+
if (document.queryCommandState("superscript")) next.add("superscript");
|
|
4484
|
+
if (document.queryCommandState("subscript")) next.add("subscript");
|
|
4485
|
+
} catch {
|
|
4486
|
+
}
|
|
4487
|
+
try {
|
|
4488
|
+
const blockEl = currentBlock();
|
|
4489
|
+
if (blockEl?.classList.contains("align-center")) next.add("align:center");
|
|
4490
|
+
else if (blockEl?.classList.contains("align-right")) next.add("align:right");
|
|
4491
|
+
else if (blockEl) next.add("align:left");
|
|
4492
|
+
if (blockEl?.closest("mark")) next.add("highlight");
|
|
4493
|
+
if (blockEl?.closest("ul.checklist")) next.add("checklist");
|
|
4284
4494
|
} catch {
|
|
4285
4495
|
}
|
|
4286
4496
|
setActiveFormats(next);
|
|
@@ -4294,6 +4504,122 @@ var Editor = (props) => {
|
|
|
4294
4504
|
const setBlock = (tag) => {
|
|
4295
4505
|
exec("formatBlock", tag);
|
|
4296
4506
|
};
|
|
4507
|
+
const toggleBlock = (tag) => {
|
|
4508
|
+
const current = String(document.queryCommandValue("formatBlock") || "").toLowerCase();
|
|
4509
|
+
setBlock(current === tag ? "p" : tag);
|
|
4510
|
+
};
|
|
4511
|
+
const historyRef = import_react22.default.useRef([]);
|
|
4512
|
+
const historyIdxRef = import_react22.default.useRef(-1);
|
|
4513
|
+
const lastPushAtRef = import_react22.default.useRef(0);
|
|
4514
|
+
const isRestoringRef = import_react22.default.useRef(false);
|
|
4515
|
+
const caretOffset = (rootEl) => {
|
|
4516
|
+
const el = rootEl ?? editorRef.current;
|
|
4517
|
+
const sel = window.getSelection();
|
|
4518
|
+
if (!el || !sel || sel.rangeCount === 0 || !el.contains(sel.anchorNode)) return 0;
|
|
4519
|
+
const range = sel.getRangeAt(0).cloneRange();
|
|
4520
|
+
range.selectNodeContents(el);
|
|
4521
|
+
range.setEnd(sel.getRangeAt(0).endContainer, sel.getRangeAt(0).endOffset);
|
|
4522
|
+
return range.toString().length;
|
|
4523
|
+
};
|
|
4524
|
+
const setCaretOffset = (offset, rootEl) => {
|
|
4525
|
+
const el = rootEl ?? editorRef.current;
|
|
4526
|
+
if (!el) return;
|
|
4527
|
+
const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
|
|
4528
|
+
let remaining = offset;
|
|
4529
|
+
let node = null;
|
|
4530
|
+
while (node = walker.nextNode()) {
|
|
4531
|
+
const len = node.textContent?.length ?? 0;
|
|
4532
|
+
if (remaining <= len) {
|
|
4533
|
+
const range = document.createRange();
|
|
4534
|
+
range.setStart(node, remaining);
|
|
4535
|
+
range.collapse(true);
|
|
4536
|
+
const sel = window.getSelection();
|
|
4537
|
+
sel?.removeAllRanges();
|
|
4538
|
+
sel?.addRange(range);
|
|
4539
|
+
return;
|
|
4540
|
+
}
|
|
4541
|
+
remaining -= len;
|
|
4542
|
+
}
|
|
4543
|
+
placeCaretAtEnd(el);
|
|
4544
|
+
};
|
|
4545
|
+
const pushHistory = (force = false) => {
|
|
4546
|
+
const el = editorRef.current;
|
|
4547
|
+
if (!el || isRestoringRef.current) return;
|
|
4548
|
+
const html = el.innerHTML;
|
|
4549
|
+
const hist = historyRef.current;
|
|
4550
|
+
const cur = hist[historyIdxRef.current];
|
|
4551
|
+
if (cur && cur.html === html) return;
|
|
4552
|
+
const now = Date.now();
|
|
4553
|
+
const coalesce = !force && cur && now - lastPushAtRef.current < 500;
|
|
4554
|
+
lastPushAtRef.current = now;
|
|
4555
|
+
if (coalesce) {
|
|
4556
|
+
hist[historyIdxRef.current] = { html, caret: caretOffset() };
|
|
4557
|
+
return;
|
|
4558
|
+
}
|
|
4559
|
+
hist.length = historyIdxRef.current + 1;
|
|
4560
|
+
hist.push({ html, caret: caretOffset() });
|
|
4561
|
+
if (hist.length > 200) hist.shift();
|
|
4562
|
+
historyIdxRef.current = hist.length - 1;
|
|
4563
|
+
};
|
|
4564
|
+
const applySnapshot = (snap) => {
|
|
4565
|
+
const el = editorRef.current;
|
|
4566
|
+
if (!el) return;
|
|
4567
|
+
isRestoringRef.current = true;
|
|
4568
|
+
el.innerHTML = snap.html;
|
|
4569
|
+
setCaretOffset(snap.caret);
|
|
4570
|
+
isRestoringRef.current = false;
|
|
4571
|
+
lastEmittedRef.current = el.innerHTML;
|
|
4572
|
+
onChange?.(el.innerHTML);
|
|
4573
|
+
updateEmpty();
|
|
4574
|
+
updateActiveFormats();
|
|
4575
|
+
};
|
|
4576
|
+
const undo = () => {
|
|
4577
|
+
pushHistory(true);
|
|
4578
|
+
if (historyIdxRef.current <= 0) return;
|
|
4579
|
+
historyIdxRef.current -= 1;
|
|
4580
|
+
applySnapshot(historyRef.current[historyIdxRef.current]);
|
|
4581
|
+
};
|
|
4582
|
+
const redo = () => {
|
|
4583
|
+
if (historyIdxRef.current >= historyRef.current.length - 1) return;
|
|
4584
|
+
historyIdxRef.current += 1;
|
|
4585
|
+
applySnapshot(historyRef.current[historyIdxRef.current]);
|
|
4586
|
+
};
|
|
4587
|
+
const langOf = (pre) => {
|
|
4588
|
+
const cls = Array.from(pre.classList).find((c) => c.startsWith("lang-"));
|
|
4589
|
+
return cls?.slice(5) ?? "plain";
|
|
4590
|
+
};
|
|
4591
|
+
const [codeLang, setCodeLang] = import_react22.default.useState("plain");
|
|
4592
|
+
const highlightRafRef = import_react22.default.useRef(0);
|
|
4593
|
+
const rehighlight = (pre) => {
|
|
4594
|
+
if (composingRef.current) return;
|
|
4595
|
+
const code = pre.querySelector("code");
|
|
4596
|
+
if (!code) return;
|
|
4597
|
+
const lang = langOf(pre);
|
|
4598
|
+
const text = code.textContent || "";
|
|
4599
|
+
const next = highlight(text, lang);
|
|
4600
|
+
if (code.innerHTML === next) return;
|
|
4601
|
+
const caret = caretOffset(code);
|
|
4602
|
+
isRestoringRef.current = true;
|
|
4603
|
+
code.innerHTML = next;
|
|
4604
|
+
setCaretOffset(caret, code);
|
|
4605
|
+
isRestoringRef.current = false;
|
|
4606
|
+
};
|
|
4607
|
+
const scheduleHighlight = () => {
|
|
4608
|
+
const pre = closestPre();
|
|
4609
|
+
if (!pre) return;
|
|
4610
|
+
cancelAnimationFrame(highlightRafRef.current);
|
|
4611
|
+
highlightRafRef.current = requestAnimationFrame(() => rehighlight(pre));
|
|
4612
|
+
};
|
|
4613
|
+
const changeCodeLang = (lang) => {
|
|
4614
|
+
const pre = closestPre();
|
|
4615
|
+
if (!pre) return;
|
|
4616
|
+
pushHistory(true);
|
|
4617
|
+
Array.from(pre.classList).filter((c) => c.startsWith("lang-")).forEach((c) => pre.classList.remove(c));
|
|
4618
|
+
if (lang !== "plain") pre.classList.add(`lang-${lang}`);
|
|
4619
|
+
setCodeLang(lang);
|
|
4620
|
+
rehighlight(pre);
|
|
4621
|
+
handleInput();
|
|
4622
|
+
};
|
|
4297
4623
|
const closestPre = () => {
|
|
4298
4624
|
const sel = window.getSelection();
|
|
4299
4625
|
const node = sel?.anchorNode;
|
|
@@ -4302,6 +4628,7 @@ var Editor = (props) => {
|
|
|
4302
4628
|
return el?.closest("pre") ?? null;
|
|
4303
4629
|
};
|
|
4304
4630
|
const insertCodeBlock = () => {
|
|
4631
|
+
pushHistory(true);
|
|
4305
4632
|
const el = editorRef.current;
|
|
4306
4633
|
const sel = window.getSelection();
|
|
4307
4634
|
if (!el || !sel || sel.rangeCount === 0) return;
|
|
@@ -4384,7 +4711,167 @@ var Editor = (props) => {
|
|
|
4384
4711
|
sel.addRange(r2);
|
|
4385
4712
|
editorRef.current?.focus();
|
|
4386
4713
|
};
|
|
4714
|
+
const clearFormat = () => {
|
|
4715
|
+
exec("removeFormat");
|
|
4716
|
+
exec("unlink");
|
|
4717
|
+
setBlock("p");
|
|
4718
|
+
};
|
|
4719
|
+
const indentList = (outdent) => {
|
|
4720
|
+
exec(outdent ? "outdent" : "indent");
|
|
4721
|
+
};
|
|
4722
|
+
const inListItem = () => {
|
|
4723
|
+
const sel = window.getSelection();
|
|
4724
|
+
const node = sel?.anchorNode;
|
|
4725
|
+
if (!node || !editorRef.current?.contains(node)) return false;
|
|
4726
|
+
const el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
|
|
4727
|
+
return !!el?.closest("li");
|
|
4728
|
+
};
|
|
4729
|
+
const currentBlock = () => {
|
|
4730
|
+
const sel = window.getSelection();
|
|
4731
|
+
const node = sel?.anchorNode;
|
|
4732
|
+
const root = editorRef.current;
|
|
4733
|
+
if (!node || !root?.contains(node)) return null;
|
|
4734
|
+
let el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
|
|
4735
|
+
while (el && el !== root && !/^(P|H[1-6]|LI|BLOCKQUOTE|PRE|DIV|TD|TH)$/.test(el.tagName)) {
|
|
4736
|
+
el = el.parentElement;
|
|
4737
|
+
}
|
|
4738
|
+
return el && el !== root ? el : null;
|
|
4739
|
+
};
|
|
4740
|
+
const setAlign = (align) => {
|
|
4741
|
+
const block = currentBlock();
|
|
4742
|
+
if (!block) return;
|
|
4743
|
+
pushHistory(true);
|
|
4744
|
+
block.classList.remove("align-left", "align-center", "align-right");
|
|
4745
|
+
if (align !== "left") block.classList.add(`align-${align}`);
|
|
4746
|
+
handleInput();
|
|
4747
|
+
};
|
|
4748
|
+
const toggleChecklist = () => {
|
|
4749
|
+
pushHistory(true);
|
|
4750
|
+
const block = currentBlock();
|
|
4751
|
+
const list = block?.closest("ul");
|
|
4752
|
+
if (list?.classList.contains("checklist")) {
|
|
4753
|
+
list.classList.remove("checklist");
|
|
4754
|
+
list.querySelectorAll("li").forEach((li) => li.removeAttribute("data-checked"));
|
|
4755
|
+
handleInput();
|
|
4756
|
+
return;
|
|
4757
|
+
}
|
|
4758
|
+
if (list) {
|
|
4759
|
+
list.classList.add("checklist");
|
|
4760
|
+
list.querySelectorAll("li").forEach((li) => li.setAttribute("data-checked", "false"));
|
|
4761
|
+
handleInput();
|
|
4762
|
+
return;
|
|
4763
|
+
}
|
|
4764
|
+
exec("insertUnorderedList");
|
|
4765
|
+
const made = currentBlock()?.closest("ul");
|
|
4766
|
+
if (made) {
|
|
4767
|
+
made.classList.add("checklist");
|
|
4768
|
+
made.querySelectorAll("li").forEach((li) => li.setAttribute("data-checked", "false"));
|
|
4769
|
+
}
|
|
4770
|
+
handleInput();
|
|
4771
|
+
};
|
|
4772
|
+
const handleEditorClick = (e) => {
|
|
4773
|
+
if (readOnly) return;
|
|
4774
|
+
const target = e.target;
|
|
4775
|
+
const li = target.closest?.("li");
|
|
4776
|
+
if (!li || !li.closest("ul.checklist")) return;
|
|
4777
|
+
const rect = li.getBoundingClientRect();
|
|
4778
|
+
if (e.clientX - rect.left > 20) return;
|
|
4779
|
+
e.preventDefault();
|
|
4780
|
+
pushHistory(true);
|
|
4781
|
+
li.setAttribute("data-checked", li.getAttribute("data-checked") === "true" ? "false" : "true");
|
|
4782
|
+
handleInput();
|
|
4783
|
+
};
|
|
4784
|
+
const toggleHighlight = () => {
|
|
4785
|
+
const sel = window.getSelection();
|
|
4786
|
+
if (!sel || sel.rangeCount === 0 || sel.isCollapsed) return;
|
|
4787
|
+
pushHistory(true);
|
|
4788
|
+
const range = sel.getRangeAt(0);
|
|
4789
|
+
const node = sel.anchorNode;
|
|
4790
|
+
const el = node?.nodeType === Node.ELEMENT_NODE ? node : node?.parentElement;
|
|
4791
|
+
const existing = el?.closest("mark");
|
|
4792
|
+
if (existing) {
|
|
4793
|
+
const parent = existing.parentNode;
|
|
4794
|
+
while (existing.firstChild) parent?.insertBefore(existing.firstChild, existing);
|
|
4795
|
+
parent?.removeChild(existing);
|
|
4796
|
+
handleInput();
|
|
4797
|
+
return;
|
|
4798
|
+
}
|
|
4799
|
+
const mark = document.createElement("mark");
|
|
4800
|
+
try {
|
|
4801
|
+
range.surroundContents(mark);
|
|
4802
|
+
} catch {
|
|
4803
|
+
const frag = range.extractContents();
|
|
4804
|
+
mark.appendChild(frag);
|
|
4805
|
+
range.insertNode(mark);
|
|
4806
|
+
}
|
|
4807
|
+
handleInput();
|
|
4808
|
+
};
|
|
4809
|
+
const insertTable = (cols = 3, rows = 2) => {
|
|
4810
|
+
const sel = window.getSelection();
|
|
4811
|
+
if (!sel || sel.rangeCount === 0) return;
|
|
4812
|
+
pushHistory(true);
|
|
4813
|
+
const table = document.createElement("table");
|
|
4814
|
+
const thead = document.createElement("thead");
|
|
4815
|
+
const headRow = document.createElement("tr");
|
|
4816
|
+
for (let c = 0; c < cols; c++) {
|
|
4817
|
+
const th = document.createElement("th");
|
|
4818
|
+
th.innerHTML = "<br>";
|
|
4819
|
+
headRow.appendChild(th);
|
|
4820
|
+
}
|
|
4821
|
+
thead.appendChild(headRow);
|
|
4822
|
+
table.appendChild(thead);
|
|
4823
|
+
const tbody = document.createElement("tbody");
|
|
4824
|
+
for (let r2 = 0; r2 < rows; r2++) {
|
|
4825
|
+
const tr = document.createElement("tr");
|
|
4826
|
+
for (let c = 0; c < cols; c++) {
|
|
4827
|
+
const td = document.createElement("td");
|
|
4828
|
+
td.innerHTML = "<br>";
|
|
4829
|
+
tr.appendChild(td);
|
|
4830
|
+
}
|
|
4831
|
+
tbody.appendChild(tr);
|
|
4832
|
+
}
|
|
4833
|
+
table.appendChild(tbody);
|
|
4834
|
+
const range = sel.getRangeAt(0);
|
|
4835
|
+
range.deleteContents();
|
|
4836
|
+
range.insertNode(table);
|
|
4837
|
+
ensureParagraphAfter(table);
|
|
4838
|
+
const first = table.querySelector("th");
|
|
4839
|
+
if (first) placeCaretAtEnd(first);
|
|
4840
|
+
handleInput();
|
|
4841
|
+
};
|
|
4842
|
+
const moveTableCell = (backwards) => {
|
|
4843
|
+
const block = currentBlock();
|
|
4844
|
+
const cell = block?.closest("td, th");
|
|
4845
|
+
if (!cell) return false;
|
|
4846
|
+
const table = cell.closest("table");
|
|
4847
|
+
if (!table) return false;
|
|
4848
|
+
const cells = Array.from(table.querySelectorAll("td, th"));
|
|
4849
|
+
const i = cells.indexOf(cell);
|
|
4850
|
+
const next = cells[i + (backwards ? -1 : 1)];
|
|
4851
|
+
if (next) {
|
|
4852
|
+
placeCaretAtEnd(next);
|
|
4853
|
+
return true;
|
|
4854
|
+
}
|
|
4855
|
+
if (!backwards) {
|
|
4856
|
+
pushHistory(true);
|
|
4857
|
+
const lastRow = table.querySelector("tbody")?.lastElementChild;
|
|
4858
|
+
if (lastRow) {
|
|
4859
|
+
const tr = document.createElement("tr");
|
|
4860
|
+
for (let c = 0; c < lastRow.children.length; c++) {
|
|
4861
|
+
const td = document.createElement("td");
|
|
4862
|
+
td.innerHTML = "<br>";
|
|
4863
|
+
tr.appendChild(td);
|
|
4864
|
+
}
|
|
4865
|
+
lastRow.after(tr);
|
|
4866
|
+
placeCaretAtEnd(tr.firstElementChild);
|
|
4867
|
+
handleInput();
|
|
4868
|
+
return true;
|
|
4869
|
+
}
|
|
4870
|
+
}
|
|
4871
|
+
return false;
|
|
4872
|
+
};
|
|
4387
4873
|
const insertDivider = () => {
|
|
4874
|
+
pushHistory(true);
|
|
4388
4875
|
exec("insertHorizontalRule");
|
|
4389
4876
|
const el = editorRef.current;
|
|
4390
4877
|
if (el && el.lastElementChild?.tagName === "HR") {
|
|
@@ -4477,8 +4964,14 @@ var Editor = (props) => {
|
|
|
4477
4964
|
case "paragraph":
|
|
4478
4965
|
setBlock("p");
|
|
4479
4966
|
break;
|
|
4480
|
-
case "heading":
|
|
4481
|
-
|
|
4967
|
+
case "heading-1":
|
|
4968
|
+
toggleBlock("h1");
|
|
4969
|
+
break;
|
|
4970
|
+
case "heading-2":
|
|
4971
|
+
toggleBlock("h2");
|
|
4972
|
+
break;
|
|
4973
|
+
case "heading-3":
|
|
4974
|
+
toggleBlock("h3");
|
|
4482
4975
|
break;
|
|
4483
4976
|
case "list":
|
|
4484
4977
|
exec("insertUnorderedList");
|
|
@@ -4571,6 +5064,8 @@ var Editor = (props) => {
|
|
|
4571
5064
|
if (!el) return;
|
|
4572
5065
|
const html = el.innerHTML;
|
|
4573
5066
|
lastEmittedRef.current = html;
|
|
5067
|
+
pushHistory();
|
|
5068
|
+
scheduleHighlight();
|
|
4574
5069
|
onChange?.(html);
|
|
4575
5070
|
updateEmpty();
|
|
4576
5071
|
updateActiveFormats();
|
|
@@ -4624,6 +5119,15 @@ var Editor = (props) => {
|
|
|
4624
5119
|
return;
|
|
4625
5120
|
}
|
|
4626
5121
|
}
|
|
5122
|
+
if (e.key === "Tab" && moveTableCell(e.shiftKey)) {
|
|
5123
|
+
e.preventDefault();
|
|
5124
|
+
return;
|
|
5125
|
+
}
|
|
5126
|
+
if (e.key === "Tab" && inListItem()) {
|
|
5127
|
+
e.preventDefault();
|
|
5128
|
+
indentList(e.shiftKey);
|
|
5129
|
+
return;
|
|
5130
|
+
}
|
|
4627
5131
|
if (slashOpen) {
|
|
4628
5132
|
if (e.key === "ArrowDown") {
|
|
4629
5133
|
e.preventDefault();
|
|
@@ -4647,6 +5151,21 @@ var Editor = (props) => {
|
|
|
4647
5151
|
return;
|
|
4648
5152
|
}
|
|
4649
5153
|
}
|
|
5154
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "z") {
|
|
5155
|
+
e.preventDefault();
|
|
5156
|
+
if (e.shiftKey) redo();
|
|
5157
|
+
else undo();
|
|
5158
|
+
return;
|
|
5159
|
+
}
|
|
5160
|
+
if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key.toLowerCase() === "v") {
|
|
5161
|
+
plainPasteRef.current = true;
|
|
5162
|
+
return;
|
|
5163
|
+
}
|
|
5164
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "y") {
|
|
5165
|
+
e.preventDefault();
|
|
5166
|
+
redo();
|
|
5167
|
+
return;
|
|
5168
|
+
}
|
|
4650
5169
|
if ((e.metaKey || e.ctrlKey) && !e.shiftKey && !e.altKey) {
|
|
4651
5170
|
const k = e.key.toLowerCase();
|
|
4652
5171
|
if (k === "b") {
|
|
@@ -4680,10 +5199,16 @@ var Editor = (props) => {
|
|
|
4680
5199
|
}
|
|
4681
5200
|
}
|
|
4682
5201
|
};
|
|
5202
|
+
const plainPasteRef = import_react22.default.useRef(false);
|
|
4683
5203
|
const handlePaste = (e) => {
|
|
4684
5204
|
if (readOnly) return;
|
|
4685
5205
|
e.preventDefault();
|
|
4686
5206
|
const text = e.clipboardData.getData("text/plain");
|
|
5207
|
+
if (plainPasteRef.current) {
|
|
5208
|
+
plainPasteRef.current = false;
|
|
5209
|
+
insertTextAtCaret(text);
|
|
5210
|
+
return;
|
|
5211
|
+
}
|
|
4687
5212
|
if (closestPre()) {
|
|
4688
5213
|
insertTextAtCaret(text);
|
|
4689
5214
|
return;
|
|
@@ -4710,9 +5235,11 @@ var Editor = (props) => {
|
|
|
4710
5235
|
};
|
|
4711
5236
|
const handleSelectionUpdate = () => {
|
|
4712
5237
|
updateActiveFormats();
|
|
5238
|
+
const pre = closestPre();
|
|
5239
|
+
setCodeLang(pre ? langOf(pre) : "plain");
|
|
4713
5240
|
};
|
|
4714
5241
|
const onToolbarAction = (item) => {
|
|
4715
|
-
if (closestPre() &&
|
|
5242
|
+
if (closestPre() && !["code-block", "undo", "redo"].includes(item)) return;
|
|
4716
5243
|
switch (item) {
|
|
4717
5244
|
case "bold":
|
|
4718
5245
|
exec("bold");
|
|
@@ -4741,8 +5268,14 @@ var Editor = (props) => {
|
|
|
4741
5268
|
handleInput();
|
|
4742
5269
|
break;
|
|
4743
5270
|
}
|
|
4744
|
-
case "heading":
|
|
4745
|
-
|
|
5271
|
+
case "heading-1":
|
|
5272
|
+
toggleBlock("h1");
|
|
5273
|
+
break;
|
|
5274
|
+
case "heading-2":
|
|
5275
|
+
toggleBlock("h2");
|
|
5276
|
+
break;
|
|
5277
|
+
case "heading-3":
|
|
5278
|
+
toggleBlock("h3");
|
|
4746
5279
|
break;
|
|
4747
5280
|
case "list":
|
|
4748
5281
|
exec("insertUnorderedList");
|
|
@@ -4765,6 +5298,39 @@ var Editor = (props) => {
|
|
|
4765
5298
|
case "divider":
|
|
4766
5299
|
insertDivider();
|
|
4767
5300
|
break;
|
|
5301
|
+
case "checklist":
|
|
5302
|
+
toggleChecklist();
|
|
5303
|
+
break;
|
|
5304
|
+
case "align-left":
|
|
5305
|
+
setAlign("left");
|
|
5306
|
+
break;
|
|
5307
|
+
case "align-center":
|
|
5308
|
+
setAlign("center");
|
|
5309
|
+
break;
|
|
5310
|
+
case "align-right":
|
|
5311
|
+
setAlign("right");
|
|
5312
|
+
break;
|
|
5313
|
+
case "highlight":
|
|
5314
|
+
toggleHighlight();
|
|
5315
|
+
break;
|
|
5316
|
+
case "superscript":
|
|
5317
|
+
exec("superscript");
|
|
5318
|
+
break;
|
|
5319
|
+
case "subscript":
|
|
5320
|
+
exec("subscript");
|
|
5321
|
+
break;
|
|
5322
|
+
case "table":
|
|
5323
|
+
insertTable();
|
|
5324
|
+
break;
|
|
5325
|
+
case "clear-format":
|
|
5326
|
+
clearFormat();
|
|
5327
|
+
break;
|
|
5328
|
+
case "undo":
|
|
5329
|
+
undo();
|
|
5330
|
+
break;
|
|
5331
|
+
case "redo":
|
|
5332
|
+
redo();
|
|
5333
|
+
break;
|
|
4768
5334
|
}
|
|
4769
5335
|
};
|
|
4770
5336
|
return /* @__PURE__ */ (0, import_jsx_runtime323.jsxs)("div", { className: clsx_default("lib-xplat-editor", isFocused && "focused", readOnly && "readonly"), children: [
|
|
@@ -4773,7 +5339,10 @@ var Editor = (props) => {
|
|
|
4773
5339
|
{
|
|
4774
5340
|
items: toolbar,
|
|
4775
5341
|
active: activeFormats,
|
|
4776
|
-
onAction: onToolbarAction
|
|
5342
|
+
onAction: onToolbarAction,
|
|
5343
|
+
codeLang,
|
|
5344
|
+
inCodeBlock: activeFormats.has("block:pre"),
|
|
5345
|
+
onCodeLangChange: changeCodeLang
|
|
4777
5346
|
}
|
|
4778
5347
|
),
|
|
4779
5348
|
/* @__PURE__ */ (0, import_jsx_runtime323.jsxs)("div", { className: "lib-xplat-editor__content", style: { minHeight }, children: [
|
|
@@ -4791,6 +5360,7 @@ var Editor = (props) => {
|
|
|
4791
5360
|
className: "lib-xplat-editor__editable",
|
|
4792
5361
|
onInput: handleInput,
|
|
4793
5362
|
onKeyDown: handleKeyDown,
|
|
5363
|
+
onClick: handleEditorClick,
|
|
4794
5364
|
onKeyUp: handleSelectionUpdate,
|
|
4795
5365
|
onMouseUp: handleSelectionUpdate,
|
|
4796
5366
|
onPaste: handlePaste,
|
|
@@ -4832,14 +5402,27 @@ var TOOLBAR_LABEL = {
|
|
|
4832
5402
|
underline: "U",
|
|
4833
5403
|
strikethrough: "S",
|
|
4834
5404
|
code: "<>",
|
|
4835
|
-
heading: "
|
|
5405
|
+
"heading-1": "H1",
|
|
5406
|
+
"heading-2": "H2",
|
|
5407
|
+
"heading-3": "H3",
|
|
4836
5408
|
list: "\u2022",
|
|
4837
5409
|
"ordered-list": "1.",
|
|
4838
5410
|
blockquote: "\u275D",
|
|
4839
5411
|
"code-block": "[ ]",
|
|
4840
5412
|
link: "\u{1F517}",
|
|
4841
5413
|
image: "\u{1F5BC}",
|
|
4842
|
-
divider: "\u2014"
|
|
5414
|
+
divider: "\u2014",
|
|
5415
|
+
checklist: "\u2611",
|
|
5416
|
+
"align-left": "\u21E4",
|
|
5417
|
+
"align-center": "\u2194",
|
|
5418
|
+
"align-right": "\u21E5",
|
|
5419
|
+
highlight: "\u{1F58D}",
|
|
5420
|
+
superscript: "x\xB2",
|
|
5421
|
+
subscript: "x\u2082",
|
|
5422
|
+
table: "\u25A6",
|
|
5423
|
+
"clear-format": "\u232B",
|
|
5424
|
+
undo: "\u21B6",
|
|
5425
|
+
redo: "\u21B7"
|
|
4843
5426
|
};
|
|
4844
5427
|
var TOOLBAR_TITLE = {
|
|
4845
5428
|
bold: "\uAD75\uAC8C (\u2318B)",
|
|
@@ -4847,36 +5430,74 @@ var TOOLBAR_TITLE = {
|
|
|
4847
5430
|
underline: "\uBC11\uC904 (\u2318U)",
|
|
4848
5431
|
strikethrough: "\uCDE8\uC18C\uC120",
|
|
4849
5432
|
code: "\uC778\uB77C\uC778 \uCF54\uB4DC",
|
|
4850
|
-
heading: "\uC81C\uBAA9",
|
|
5433
|
+
"heading-1": "\uC81C\uBAA9 1",
|
|
5434
|
+
"heading-2": "\uC81C\uBAA9 2",
|
|
5435
|
+
"heading-3": "\uC81C\uBAA9 3",
|
|
4851
5436
|
list: "\uAE00\uBA38\uB9AC \uAE30\uD638 \uBAA9\uB85D",
|
|
4852
5437
|
"ordered-list": "\uBC88\uD638 \uB9E4\uAE30\uAE30 \uBAA9\uB85D",
|
|
4853
5438
|
blockquote: "\uC778\uC6A9",
|
|
4854
5439
|
"code-block": "\uCF54\uB4DC \uBE14\uB85D",
|
|
4855
5440
|
link: "\uB9C1\uD06C (\u2318K)",
|
|
4856
5441
|
image: "\uC774\uBBF8\uC9C0",
|
|
4857
|
-
divider: "\uAD6C\uBD84\uC120"
|
|
5442
|
+
divider: "\uAD6C\uBD84\uC120",
|
|
5443
|
+
checklist: "\uCCB4\uD06C\uB9AC\uC2A4\uD2B8",
|
|
5444
|
+
"align-left": "\uC67C\uCABD \uC815\uB82C",
|
|
5445
|
+
"align-center": "\uAC00\uC6B4\uB370 \uC815\uB82C",
|
|
5446
|
+
"align-right": "\uC624\uB978\uCABD \uC815\uB82C",
|
|
5447
|
+
highlight: "\uD615\uAD11\uD39C",
|
|
5448
|
+
superscript: "\uC704 \uCCA8\uC790",
|
|
5449
|
+
subscript: "\uC544\uB798 \uCCA8\uC790",
|
|
5450
|
+
table: "\uD45C \uC0BD\uC785",
|
|
5451
|
+
"clear-format": "\uC11C\uC2DD \uC9C0\uC6B0\uAE30",
|
|
5452
|
+
undo: "\uB418\uB3CC\uB9AC\uAE30 (\u2318Z)",
|
|
5453
|
+
redo: "\uB2E4\uC2DC\uD558\uAE30 (\u2318\u21E7Z)"
|
|
4858
5454
|
};
|
|
4859
5455
|
var isActive = (item, active) => {
|
|
4860
|
-
if (item === "heading") return active.has("block:h1")
|
|
5456
|
+
if (item === "heading-1") return active.has("block:h1");
|
|
5457
|
+
if (item === "heading-2") return active.has("block:h2");
|
|
5458
|
+
if (item === "heading-3") return active.has("block:h3");
|
|
4861
5459
|
if (item === "blockquote") return active.has("block:blockquote");
|
|
4862
5460
|
if (item === "code-block") return active.has("block:pre");
|
|
5461
|
+
if (item === "align-left") return active.has("align:left");
|
|
5462
|
+
if (item === "align-center") return active.has("align:center");
|
|
5463
|
+
if (item === "align-right") return active.has("align:right");
|
|
4863
5464
|
return active.has(item);
|
|
4864
5465
|
};
|
|
4865
|
-
var EditorToolbar = ({
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
5466
|
+
var EditorToolbar = ({
|
|
5467
|
+
items,
|
|
5468
|
+
active,
|
|
5469
|
+
onAction,
|
|
5470
|
+
codeLang,
|
|
5471
|
+
inCodeBlock,
|
|
5472
|
+
onCodeLangChange
|
|
5473
|
+
}) => {
|
|
5474
|
+
return /* @__PURE__ */ (0, import_jsx_runtime323.jsxs)("div", { className: "lib-xplat-editor__toolbar", children: [
|
|
5475
|
+
items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime323.jsx)(
|
|
5476
|
+
"button",
|
|
5477
|
+
{
|
|
5478
|
+
type: "button",
|
|
5479
|
+
className: clsx_default("lib-xplat-editor__toolbar-btn", isActive(item, active) && "active"),
|
|
5480
|
+
title: TOOLBAR_TITLE[item],
|
|
5481
|
+
onMouseDown: (e) => {
|
|
5482
|
+
e.preventDefault();
|
|
5483
|
+
onAction(item);
|
|
5484
|
+
},
|
|
5485
|
+
children: TOOLBAR_LABEL[item]
|
|
4875
5486
|
},
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
5487
|
+
item
|
|
5488
|
+
)),
|
|
5489
|
+
inCodeBlock && /* @__PURE__ */ (0, import_jsx_runtime323.jsx)(
|
|
5490
|
+
"select",
|
|
5491
|
+
{
|
|
5492
|
+
className: "lib-xplat-editor__lang",
|
|
5493
|
+
value: codeLang,
|
|
5494
|
+
"aria-label": "\uCF54\uB4DC \uC5B8\uC5B4",
|
|
5495
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
5496
|
+
onChange: (e) => onCodeLangChange(e.target.value),
|
|
5497
|
+
children: CODE_LANGUAGES.map((l) => /* @__PURE__ */ (0, import_jsx_runtime323.jsx)("option", { value: l.value, children: l.label }, l.value))
|
|
5498
|
+
}
|
|
5499
|
+
)
|
|
5500
|
+
] });
|
|
4880
5501
|
};
|
|
4881
5502
|
var SlashMenu = ({ position, items, activeIndex, onSelect, onClose }) => {
|
|
4882
5503
|
import_react22.default.useEffect(() => {
|
|
@@ -4980,10 +5601,13 @@ var FileUpload = (props) => {
|
|
|
4980
5601
|
multiple = false,
|
|
4981
5602
|
maxSize,
|
|
4982
5603
|
onChange,
|
|
4983
|
-
|
|
5604
|
+
placeholder = "\uD30C\uC77C\uC744 \uB4DC\uB798\uADF8\uD558\uAC70\uB098 \uD074\uB9AD\uD558\uC5EC \uC5C5\uB85C\uB4DC",
|
|
4984
5605
|
description,
|
|
4985
|
-
validations
|
|
5606
|
+
validations,
|
|
5607
|
+
label,
|
|
5608
|
+
required
|
|
4986
5609
|
} = props;
|
|
5610
|
+
const fieldId = import_react23.default.useId();
|
|
4987
5611
|
const [isDragOver, setIsDragOver] = import_react23.default.useState(false);
|
|
4988
5612
|
const inputRef = import_react23.default.useRef(null);
|
|
4989
5613
|
const handleFiles = (fileList) => {
|
|
@@ -5028,6 +5652,7 @@ var FileUpload = (props) => {
|
|
|
5028
5652
|
"input",
|
|
5029
5653
|
{
|
|
5030
5654
|
ref: inputRef,
|
|
5655
|
+
id: fieldId,
|
|
5031
5656
|
type: "file",
|
|
5032
5657
|
accept,
|
|
5033
5658
|
multiple,
|
|
@@ -5036,12 +5661,12 @@ var FileUpload = (props) => {
|
|
|
5036
5661
|
}
|
|
5037
5662
|
),
|
|
5038
5663
|
/* @__PURE__ */ (0, import_jsx_runtime325.jsx)("div", { className: "upload-icon", children: /* @__PURE__ */ (0, import_jsx_runtime325.jsx)(UploadIcon_default, {}) }),
|
|
5039
|
-
/* @__PURE__ */ (0, import_jsx_runtime325.jsx)("p", { className: "upload-label", children:
|
|
5664
|
+
/* @__PURE__ */ (0, import_jsx_runtime325.jsx)("p", { className: "upload-label", children: placeholder }),
|
|
5040
5665
|
description && /* @__PURE__ */ (0, import_jsx_runtime325.jsx)("p", { className: "upload-description", children: description })
|
|
5041
5666
|
]
|
|
5042
5667
|
}
|
|
5043
5668
|
);
|
|
5044
|
-
return /* @__PURE__ */ (0, import_jsx_runtime325.jsx)(Field, { validations, children: control });
|
|
5669
|
+
return /* @__PURE__ */ (0, import_jsx_runtime325.jsx)(Field, { label, required, htmlFor: fieldId, validations, children: control });
|
|
5045
5670
|
};
|
|
5046
5671
|
FileUpload.displayName = "FileUpload";
|
|
5047
5672
|
var FileUpload_default = FileUpload;
|
|
@@ -5184,7 +5809,8 @@ var HtmlTypeWriter_default = HtmlTypeWriter;
|
|
|
5184
5809
|
var import_react26 = __toESM(require("react"), 1);
|
|
5185
5810
|
var import_jsx_runtime327 = require("react/jsx-runtime");
|
|
5186
5811
|
var ImageSelector = (props) => {
|
|
5187
|
-
const { value,
|
|
5812
|
+
const { value, placeholder, onChange, validations, label, required } = props;
|
|
5813
|
+
const fieldId = import_react26.default.useId();
|
|
5188
5814
|
const [previewUrl, setPreviewUrl] = import_react26.default.useState();
|
|
5189
5815
|
import_react26.default.useEffect(() => {
|
|
5190
5816
|
if (!value) {
|
|
@@ -5214,7 +5840,7 @@ var ImageSelector = (props) => {
|
|
|
5214
5840
|
{
|
|
5215
5841
|
type: "file",
|
|
5216
5842
|
accept: "image/*",
|
|
5217
|
-
id:
|
|
5843
|
+
id: fieldId,
|
|
5218
5844
|
onChange: handleFileChange,
|
|
5219
5845
|
ref: inputRef,
|
|
5220
5846
|
"aria-invalid": hasError(validations) || void 0
|
|
@@ -5226,10 +5852,10 @@ var ImageSelector = (props) => {
|
|
|
5226
5852
|
] }),
|
|
5227
5853
|
/* @__PURE__ */ (0, import_jsx_runtime327.jsx)("div", { className: "content", children: previewUrl ? /* @__PURE__ */ (0, import_jsx_runtime327.jsx)("img", { src: previewUrl, alt: "preview" }) : /* @__PURE__ */ (0, import_jsx_runtime327.jsxs)("div", { className: "skeleton", onClick: handleOpenFileDialog, children: [
|
|
5228
5854
|
/* @__PURE__ */ (0, import_jsx_runtime327.jsx)("div", { className: "icon-wrapper", children: /* @__PURE__ */ (0, import_jsx_runtime327.jsx)(ImageIcon_default, {}) }),
|
|
5229
|
-
/* @__PURE__ */ (0, import_jsx_runtime327.jsx)("div", { className: "label", children:
|
|
5855
|
+
/* @__PURE__ */ (0, import_jsx_runtime327.jsx)("div", { className: "label", children: placeholder || "\uC774\uBBF8\uC9C0 \uCD94\uAC00\uD558\uAE30" })
|
|
5230
5856
|
] }) })
|
|
5231
5857
|
] });
|
|
5232
|
-
return /* @__PURE__ */ (0, import_jsx_runtime327.jsx)(Field, { validations, children: control });
|
|
5858
|
+
return /* @__PURE__ */ (0, import_jsx_runtime327.jsx)(Field, { label, required, htmlFor: fieldId, validations, children: control });
|
|
5233
5859
|
};
|
|
5234
5860
|
ImageSelector.displayName = "ImageSelector";
|
|
5235
5861
|
var ImageSelector_default = ImageSelector;
|
|
@@ -5421,6 +6047,7 @@ var PopOver = (props) => {
|
|
|
5421
6047
|
className: clsx_default(
|
|
5422
6048
|
"lib-xplat-pop-over-content",
|
|
5423
6049
|
position.direction,
|
|
6050
|
+
position.repositioning && "repositioning",
|
|
5424
6051
|
eventTrigger && "visible"
|
|
5425
6052
|
),
|
|
5426
6053
|
ref: popRef,
|
|
@@ -5767,7 +6394,7 @@ var SelectRoot = (props) => {
|
|
|
5767
6394
|
mounted && /* @__PURE__ */ (0, import_jsx_runtime337.jsx)(Portal_default, { children: /* @__PURE__ */ (0, import_jsx_runtime337.jsxs)(
|
|
5768
6395
|
"div",
|
|
5769
6396
|
{
|
|
5770
|
-
className: clsx_default("lib-xplat-select-content", size, position.direction, stateClass),
|
|
6397
|
+
className: clsx_default("lib-xplat-select-content", size, position.direction, stateClass, position.repositioning && "repositioning"),
|
|
5771
6398
|
ref: contentRef,
|
|
5772
6399
|
style: { ...position.position, width: triggerRef.current?.offsetWidth },
|
|
5773
6400
|
role: "listbox",
|
|
@@ -6660,7 +7287,7 @@ var TimePicker = (props) => {
|
|
|
6660
7287
|
"div",
|
|
6661
7288
|
{
|
|
6662
7289
|
ref: contentRef,
|
|
6663
|
-
className: clsx_default("lib-xplat-time-picker-content", size, visible ? "enter" : "exit"),
|
|
7290
|
+
className: clsx_default("lib-xplat-time-picker-content", size, visible ? "enter" : "exit", position.repositioning && "repositioning"),
|
|
6664
7291
|
style: { ...position.position, width: triggerRef.current?.offsetWidth },
|
|
6665
7292
|
role: "listbox",
|
|
6666
7293
|
children: options.map((t) => /* @__PURE__ */ (0, import_jsx_runtime351.jsx)(
|