klun-ui 0.1.1 → 0.1.3

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.
@@ -6890,8 +6890,265 @@ var DatePicker = react.forwardRef(
6890
6890
  }
6891
6891
  );
6892
6892
  DatePicker.displayName = "DatePicker";
6893
+ var pad = (n) => String(n).padStart(2, "0");
6894
+ var TimePicker = react.forwardRef(
6895
+ function TimePicker2({ value = "09:00", onChange, className, style, ...props }, ref) {
6896
+ const t = useLocale();
6897
+ const [h, m] = value.split(":").map(Number);
6898
+ const mer = h >= 12 ? "PM" : "AM";
6899
+ const h12 = (h + 11) % 12 + 1;
6900
+ const set = (nh, nm, nmer) => {
6901
+ let hh = nh % 12;
6902
+ if (nmer === "PM") hh += 12;
6903
+ onChange?.(`${pad(hh)}:${pad(nm)}`);
6904
+ };
6905
+ const [open, setOpen] = react.useState(null);
6906
+ const rootRef = react.useRef(null);
6907
+ const setRoot = (node) => {
6908
+ rootRef.current = node;
6909
+ if (typeof ref === "function") ref(node);
6910
+ else if (ref) ref.current = node;
6911
+ };
6912
+ react.useEffect(() => {
6913
+ if (!open) return;
6914
+ const onDown = (e) => {
6915
+ if (rootRef.current && !rootRef.current.contains(e.target)) setOpen(null);
6916
+ };
6917
+ document.addEventListener("mousedown", onDown);
6918
+ return () => document.removeEventListener("mousedown", onDown);
6919
+ }, [open]);
6920
+ const hourOpts = Array.from({ length: 12 }, (_, i) => ({
6921
+ value: String(i + 1),
6922
+ label: pad(i + 1)
6923
+ }));
6924
+ const minOpts = Array.from({ length: 60 }, (_, i) => ({
6925
+ value: String(i),
6926
+ label: pad(i)
6927
+ }));
6928
+ const merOpts = [
6929
+ { value: "AM", label: t.timePicker.am },
6930
+ { value: "PM", label: t.timePicker.pm }
6931
+ ];
6932
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6933
+ "div",
6934
+ {
6935
+ ref: setRoot,
6936
+ className: chunkTPGAXYFU_cjs.cx("klun-time-picker", className),
6937
+ style,
6938
+ ...props,
6939
+ children: [
6940
+ /* @__PURE__ */ jsxRuntime.jsx("i", { className: "ri-time-line klun-time-picker__icon" }),
6941
+ /* @__PURE__ */ jsxRuntime.jsx(
6942
+ TimeColumn,
6943
+ {
6944
+ options: hourOpts,
6945
+ current: String(h12),
6946
+ open: open === "h",
6947
+ onOpen: () => setOpen("h"),
6948
+ onClose: () => setOpen(null),
6949
+ onPick: (v) => {
6950
+ set(Number(v), m, mer);
6951
+ setOpen(null);
6952
+ }
6953
+ }
6954
+ ),
6955
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-time-picker__sep", children: ":" }),
6956
+ /* @__PURE__ */ jsxRuntime.jsx(
6957
+ TimeColumn,
6958
+ {
6959
+ options: minOpts,
6960
+ current: String(m),
6961
+ open: open === "m",
6962
+ onOpen: () => setOpen("m"),
6963
+ onClose: () => setOpen(null),
6964
+ onPick: (v) => {
6965
+ set(h12, Number(v), mer);
6966
+ setOpen(null);
6967
+ }
6968
+ }
6969
+ ),
6970
+ /* @__PURE__ */ jsxRuntime.jsx(
6971
+ TimeColumn,
6972
+ {
6973
+ className: "klun-time-picker__col--meridiem",
6974
+ options: merOpts,
6975
+ current: mer,
6976
+ open: open === "mer",
6977
+ onOpen: () => setOpen("mer"),
6978
+ onClose: () => setOpen(null),
6979
+ onPick: (v) => {
6980
+ set(h12, m, v);
6981
+ setOpen(null);
6982
+ }
6983
+ }
6984
+ )
6985
+ ]
6986
+ }
6987
+ );
6988
+ }
6989
+ );
6990
+ function TimeColumn({
6991
+ options,
6992
+ current,
6993
+ open,
6994
+ onOpen,
6995
+ onClose,
6996
+ onPick,
6997
+ className
6998
+ }) {
6999
+ const colRef = react.useRef(null);
7000
+ const [active, setActive] = react.useState(-1);
7001
+ const selected = options.find((o) => o.value === current);
7002
+ const flipUp = open && typeof window !== "undefined" && colRef.current ? colRef.current.getBoundingClientRect().bottom + 248 > window.innerHeight : false;
7003
+ const panel = () => colRef.current?.querySelector(".klun-select-listbox") ?? null;
7004
+ const scrollTo = (i, center) => {
7005
+ requestAnimationFrame(() => {
7006
+ const p = panel();
7007
+ const el = p?.children[i];
7008
+ if (!p || !el) return;
7009
+ if (center) {
7010
+ p.scrollTop = el.offsetTop - p.clientHeight / 2 + el.offsetHeight / 2;
7011
+ } else if (el.offsetTop < p.scrollTop) {
7012
+ p.scrollTop = el.offsetTop - 4;
7013
+ } else if (el.offsetTop + el.offsetHeight > p.scrollTop + p.clientHeight) {
7014
+ p.scrollTop = el.offsetTop + el.offsetHeight - p.clientHeight + 4;
7015
+ }
7016
+ });
7017
+ };
7018
+ react.useEffect(() => {
7019
+ if (!open) return;
7020
+ const idx = options.findIndex((o) => o.value === current);
7021
+ setActive(idx);
7022
+ scrollTo(idx >= 0 ? idx : 0, true);
7023
+ }, [open]);
7024
+ const step = (dir) => {
7025
+ if (!options.length) return;
7026
+ let i = active;
7027
+ for (let n = 0; n < options.length; n++) {
7028
+ i = (i + dir + options.length) % options.length;
7029
+ if (!options[i].disabled) break;
7030
+ }
7031
+ setActive(i);
7032
+ scrollTo(i, false);
7033
+ };
7034
+ const onKeyDown = (e) => {
7035
+ if (!open) {
7036
+ if (["ArrowDown", "ArrowUp", "Enter", " "].includes(e.key)) {
7037
+ e.preventDefault();
7038
+ onOpen();
7039
+ }
7040
+ return;
7041
+ }
7042
+ switch (e.key) {
7043
+ case "ArrowDown":
7044
+ e.preventDefault();
7045
+ step(1);
7046
+ break;
7047
+ case "ArrowUp":
7048
+ e.preventDefault();
7049
+ step(-1);
7050
+ break;
7051
+ case "Enter":
7052
+ case " ":
7053
+ e.preventDefault();
7054
+ if (options[active]) onPick(options[active].value);
7055
+ break;
7056
+ case "Escape":
7057
+ e.preventDefault();
7058
+ onClose();
7059
+ break;
7060
+ case "Tab":
7061
+ onClose();
7062
+ break;
7063
+ }
7064
+ };
7065
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: colRef, className: chunkTPGAXYFU_cjs.cx("klun-time-picker__col", className), children: [
7066
+ /* @__PURE__ */ jsxRuntime.jsx(
7067
+ "button",
7068
+ {
7069
+ type: "button",
7070
+ className: "klun-time-picker__trigger",
7071
+ "aria-haspopup": "listbox",
7072
+ "aria-expanded": open,
7073
+ "data-open": open || void 0,
7074
+ onClick: () => open ? onClose() : onOpen(),
7075
+ onKeyDown,
7076
+ children: selected ? selected.label : ""
7077
+ }
7078
+ ),
7079
+ open ? /* @__PURE__ */ jsxRuntime.jsx(
7080
+ SelectListbox,
7081
+ {
7082
+ className: chunkTPGAXYFU_cjs.cx("klun-time-picker__listbox", flipUp && "klun-select-listbox--up"),
7083
+ options,
7084
+ current,
7085
+ active,
7086
+ onActivate: setActive,
7087
+ onPick: (o) => onPick(o.value)
7088
+ }
7089
+ ) : null
7090
+ ] });
7091
+ }
7092
+ TimePicker.displayName = "TimePicker";
7093
+ var pad2 = (n) => String(n).padStart(2, "0");
7094
+ var DEFAULT_FORMAT2 = {
7095
+ year: "numeric",
7096
+ month: "short",
7097
+ day: "numeric",
7098
+ hour: "2-digit",
7099
+ minute: "2-digit"
7100
+ };
7101
+ function DateTimePanel({ value, onChange }) {
7102
+ const hhmm = value ? `${pad2(value.getHours())}:${pad2(value.getMinutes())}` : "09:00";
7103
+ const setDate = (d) => {
7104
+ const next = new Date(d);
7105
+ if (value) next.setHours(value.getHours(), value.getMinutes(), 0, 0);
7106
+ else next.setHours(9, 0, 0, 0);
7107
+ onChange(next);
7108
+ };
7109
+ const setTime = (t) => {
7110
+ const [h, m] = t.split(":").map(Number);
7111
+ const next = value ? new Date(value) : /* @__PURE__ */ new Date();
7112
+ next.setHours(h, m, 0, 0);
7113
+ onChange(next);
7114
+ };
7115
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "klun-date-time-picker__panel", children: [
7116
+ /* @__PURE__ */ jsxRuntime.jsx(DatePicker, { inline: true, className: "klun-date-picker--bare", value, onChange: setDate }),
7117
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "klun-date-time-picker__time", children: /* @__PURE__ */ jsxRuntime.jsx(TimePicker, { value: hhmm, onChange: setTime }) })
7118
+ ] });
7119
+ }
7120
+ var DateTimePicker = react.forwardRef(
7121
+ function DateTimePicker2({ value, onChange, inline, placeholder, format = DEFAULT_FORMAT2, align = "left", disabled, className, style, ...props }, ref) {
7122
+ const date = value ? new Date(value) : null;
7123
+ if (inline) {
7124
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: chunkTPGAXYFU_cjs.cx("klun-date-time-picker", className), style, ...props, children: /* @__PURE__ */ jsxRuntime.jsx(DateTimePanel, { value: date, onChange: (d) => onChange?.(d) }) });
7125
+ }
7126
+ const label = date ? date.toLocaleString(void 0, format) : "";
7127
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: chunkTPGAXYFU_cjs.cx("klun-date-time-field", className), style, ...props, children: /* @__PURE__ */ jsxRuntime.jsx(
7128
+ Popover,
7129
+ {
7130
+ align,
7131
+ width: 300,
7132
+ trigger: /* @__PURE__ */ jsxRuntime.jsx(
7133
+ Input,
7134
+ {
7135
+ readOnly: true,
7136
+ disabled,
7137
+ value: label,
7138
+ placeholder: placeholder ?? "Select date & time",
7139
+ leadingIcon: /* @__PURE__ */ jsxRuntime.jsx("i", { className: "ri-calendar-2-line" }),
7140
+ trailingIcon: /* @__PURE__ */ jsxRuntime.jsx("i", { className: "ri-arrow-down-s-line" }),
7141
+ style: { width: "100%", cursor: "pointer" }
7142
+ }
7143
+ ),
7144
+ children: /* @__PURE__ */ jsxRuntime.jsx(DateTimePanel, { value: date, onChange: (d) => onChange?.(d) })
7145
+ }
7146
+ ) });
7147
+ }
7148
+ );
7149
+ DateTimePicker.displayName = "DateTimePicker";
6893
7150
  var norm = (d) => d && new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();
6894
- var DEFAULT_FORMAT2 = { month: "short", day: "numeric" };
7151
+ var DEFAULT_FORMAT3 = { month: "short", day: "numeric" };
6895
7152
  var RangeCalendar = react.forwardRef(function RangeCalendar2({ start, end, onPick, className, style }, ref) {
6896
7153
  const { datePicker } = useLocale();
6897
7154
  const base = start ? new Date(start) : /* @__PURE__ */ new Date();
@@ -6950,7 +7207,7 @@ var RangeCalendar = react.forwardRef(function RangeCalendar2({ start, end, onPic
6950
7207
  ] });
6951
7208
  });
6952
7209
  var DateRangePicker = react.forwardRef(
6953
- function DateRangePicker2({ start, end, onChange, inline, placeholder, format = DEFAULT_FORMAT2, align = "left", disabled, className, style, ...props }, ref) {
7210
+ function DateRangePicker2({ start, end, onChange, inline, placeholder, format = DEFAULT_FORMAT3, align = "left", disabled, className, style, ...props }, ref) {
6954
7211
  if (inline) {
6955
7212
  return /* @__PURE__ */ jsxRuntime.jsx(
6956
7213
  RangeCalendar,
@@ -8241,205 +8498,6 @@ var Textarea = react.forwardRef(function Textarea2({ error = false, disabled = f
8241
8498
  );
8242
8499
  });
8243
8500
  Textarea.displayName = "Textarea";
8244
- var pad = (n) => String(n).padStart(2, "0");
8245
- var TimePicker = react.forwardRef(
8246
- function TimePicker2({ value = "09:00", onChange, className, style, ...props }, ref) {
8247
- const t = useLocale();
8248
- const [h, m] = value.split(":").map(Number);
8249
- const mer = h >= 12 ? "PM" : "AM";
8250
- const h12 = (h + 11) % 12 + 1;
8251
- const set = (nh, nm, nmer) => {
8252
- let hh = nh % 12;
8253
- if (nmer === "PM") hh += 12;
8254
- onChange?.(`${pad(hh)}:${pad(nm)}`);
8255
- };
8256
- const [open, setOpen] = react.useState(null);
8257
- const rootRef = react.useRef(null);
8258
- const setRoot = (node) => {
8259
- rootRef.current = node;
8260
- if (typeof ref === "function") ref(node);
8261
- else if (ref) ref.current = node;
8262
- };
8263
- react.useEffect(() => {
8264
- if (!open) return;
8265
- const onDown = (e) => {
8266
- if (rootRef.current && !rootRef.current.contains(e.target)) setOpen(null);
8267
- };
8268
- document.addEventListener("mousedown", onDown);
8269
- return () => document.removeEventListener("mousedown", onDown);
8270
- }, [open]);
8271
- const hourOpts = Array.from({ length: 12 }, (_, i) => ({
8272
- value: String(i + 1),
8273
- label: pad(i + 1)
8274
- }));
8275
- const minOpts = Array.from({ length: 60 }, (_, i) => ({
8276
- value: String(i),
8277
- label: pad(i)
8278
- }));
8279
- const merOpts = [
8280
- { value: "AM", label: t.timePicker.am },
8281
- { value: "PM", label: t.timePicker.pm }
8282
- ];
8283
- return /* @__PURE__ */ jsxRuntime.jsxs(
8284
- "div",
8285
- {
8286
- ref: setRoot,
8287
- className: chunkTPGAXYFU_cjs.cx("klun-time-picker", className),
8288
- style,
8289
- ...props,
8290
- children: [
8291
- /* @__PURE__ */ jsxRuntime.jsx("i", { className: "ri-time-line klun-time-picker__icon" }),
8292
- /* @__PURE__ */ jsxRuntime.jsx(
8293
- TimeColumn,
8294
- {
8295
- options: hourOpts,
8296
- current: String(h12),
8297
- open: open === "h",
8298
- onOpen: () => setOpen("h"),
8299
- onClose: () => setOpen(null),
8300
- onPick: (v) => {
8301
- set(Number(v), m, mer);
8302
- setOpen(null);
8303
- }
8304
- }
8305
- ),
8306
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "klun-time-picker__sep", children: ":" }),
8307
- /* @__PURE__ */ jsxRuntime.jsx(
8308
- TimeColumn,
8309
- {
8310
- options: minOpts,
8311
- current: String(m),
8312
- open: open === "m",
8313
- onOpen: () => setOpen("m"),
8314
- onClose: () => setOpen(null),
8315
- onPick: (v) => {
8316
- set(h12, Number(v), mer);
8317
- setOpen(null);
8318
- }
8319
- }
8320
- ),
8321
- /* @__PURE__ */ jsxRuntime.jsx(
8322
- TimeColumn,
8323
- {
8324
- className: "klun-time-picker__col--meridiem",
8325
- options: merOpts,
8326
- current: mer,
8327
- open: open === "mer",
8328
- onOpen: () => setOpen("mer"),
8329
- onClose: () => setOpen(null),
8330
- onPick: (v) => {
8331
- set(h12, m, v);
8332
- setOpen(null);
8333
- }
8334
- }
8335
- )
8336
- ]
8337
- }
8338
- );
8339
- }
8340
- );
8341
- function TimeColumn({
8342
- options,
8343
- current,
8344
- open,
8345
- onOpen,
8346
- onClose,
8347
- onPick,
8348
- className
8349
- }) {
8350
- const colRef = react.useRef(null);
8351
- const [active, setActive] = react.useState(-1);
8352
- const selected = options.find((o) => o.value === current);
8353
- const panel = () => colRef.current?.querySelector(".klun-select-listbox") ?? null;
8354
- const scrollTo = (i, center) => {
8355
- requestAnimationFrame(() => {
8356
- const p = panel();
8357
- const el = p?.children[i];
8358
- if (!p || !el) return;
8359
- if (center) {
8360
- p.scrollTop = el.offsetTop - p.clientHeight / 2 + el.offsetHeight / 2;
8361
- } else if (el.offsetTop < p.scrollTop) {
8362
- p.scrollTop = el.offsetTop - 4;
8363
- } else if (el.offsetTop + el.offsetHeight > p.scrollTop + p.clientHeight) {
8364
- p.scrollTop = el.offsetTop + el.offsetHeight - p.clientHeight + 4;
8365
- }
8366
- });
8367
- };
8368
- react.useEffect(() => {
8369
- if (!open) return;
8370
- const idx = options.findIndex((o) => o.value === current);
8371
- setActive(idx);
8372
- scrollTo(idx >= 0 ? idx : 0, true);
8373
- }, [open]);
8374
- const step = (dir) => {
8375
- if (!options.length) return;
8376
- let i = active;
8377
- for (let n = 0; n < options.length; n++) {
8378
- i = (i + dir + options.length) % options.length;
8379
- if (!options[i].disabled) break;
8380
- }
8381
- setActive(i);
8382
- scrollTo(i, false);
8383
- };
8384
- const onKeyDown = (e) => {
8385
- if (!open) {
8386
- if (["ArrowDown", "ArrowUp", "Enter", " "].includes(e.key)) {
8387
- e.preventDefault();
8388
- onOpen();
8389
- }
8390
- return;
8391
- }
8392
- switch (e.key) {
8393
- case "ArrowDown":
8394
- e.preventDefault();
8395
- step(1);
8396
- break;
8397
- case "ArrowUp":
8398
- e.preventDefault();
8399
- step(-1);
8400
- break;
8401
- case "Enter":
8402
- case " ":
8403
- e.preventDefault();
8404
- if (options[active]) onPick(options[active].value);
8405
- break;
8406
- case "Escape":
8407
- e.preventDefault();
8408
- onClose();
8409
- break;
8410
- case "Tab":
8411
- onClose();
8412
- break;
8413
- }
8414
- };
8415
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: colRef, className: chunkTPGAXYFU_cjs.cx("klun-time-picker__col", className), children: [
8416
- /* @__PURE__ */ jsxRuntime.jsx(
8417
- "button",
8418
- {
8419
- type: "button",
8420
- className: "klun-time-picker__trigger",
8421
- "aria-haspopup": "listbox",
8422
- "aria-expanded": open,
8423
- "data-open": open || void 0,
8424
- onClick: () => open ? onClose() : onOpen(),
8425
- onKeyDown,
8426
- children: selected ? selected.label : ""
8427
- }
8428
- ),
8429
- open ? /* @__PURE__ */ jsxRuntime.jsx(
8430
- SelectListbox,
8431
- {
8432
- className: "klun-time-picker__listbox",
8433
- options,
8434
- current,
8435
- active,
8436
- onActivate: setActive,
8437
- onPick: (o) => onPick(o.value)
8438
- }
8439
- ) : null
8440
- ] });
8441
- }
8442
- TimePicker.displayName = "TimePicker";
8443
8501
  var Card = react.forwardRef(function Card2({ variant = "stroke", padding, className, style, children, ...props }, ref) {
8444
8502
  return /* @__PURE__ */ jsxRuntime.jsx(
8445
8503
  "div",
@@ -10048,6 +10106,7 @@ exports.CopyButton = CopyButton;
10048
10106
  exports.CounterInput = CounterInput;
10049
10107
  exports.DatePicker = DatePicker;
10050
10108
  exports.DateRangePicker = DateRangePicker;
10109
+ exports.DateTimePicker = DateTimePicker;
10051
10110
  exports.Descriptions = Descriptions;
10052
10111
  exports.DigitInput = DigitInput;
10053
10112
  exports.Divider = Divider;
@@ -10153,5 +10212,5 @@ exports.useSize = useSize;
10153
10212
  exports.viVN = viVN;
10154
10213
  exports.zhCN = zhCN;
10155
10214
  exports.zhTW = zhTW;
10156
- //# sourceMappingURL=chunk-2MTDM5CL.cjs.map
10157
- //# sourceMappingURL=chunk-2MTDM5CL.cjs.map
10215
+ //# sourceMappingURL=chunk-SUH5CQ55.cjs.map
10216
+ //# sourceMappingURL=chunk-SUH5CQ55.cjs.map