@godxjp/ui 15.0.1 → 16.0.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.
@@ -45,8 +45,6 @@ export { Cascader } from "./cascader";
45
45
  export type { CascaderProps, TreeOption, TreeFieldNames } from "./cascader";
46
46
  export { TreeSelect, SHOW_CHILD, SHOW_PARENT, SHOW_ALL } from "./tree-select";
47
47
  export type { TreeSelectProps } from "./tree-select";
48
- export { TimeInput } from "./time-input";
49
- export type { TimeInputProps } from "./time-input";
50
48
  export { Transfer } from "./transfer";
51
49
  export type { TransferProps, TransferItemProp } from "./transfer";
52
50
  export { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, } from "./command";
@@ -35,7 +35,6 @@ import { ColorPicker } from "./color-picker";
35
35
  import { Upload, collectUploadCommitActions, createUploadItem, useUploadDraft } from "./upload";
36
36
  import { Cascader } from "./cascader";
37
37
  import { TreeSelect, SHOW_CHILD, SHOW_PARENT, SHOW_ALL } from "./tree-select";
38
- import { TimeInput } from "./time-input";
39
38
  import { Transfer } from "./transfer";
40
39
  import {
41
40
  Command,
@@ -101,7 +100,6 @@ export {
101
100
  Switch,
102
101
  TagInput,
103
102
  Textarea,
104
- TimeInput,
105
103
  TimePicker,
106
104
  Toggle,
107
105
  ToggleGroup,
@@ -5,7 +5,7 @@ import { usePickerLocales, useTranslation } from "../../i18n/use-translation";
5
5
  import { isValidHhmm, normalizeHhmm } from "../../lib/datetime";
6
6
  import { cn } from "../../lib/utils";
7
7
  import { Button } from "../general/button";
8
- import { Popover, PopoverContent, PopoverTrigger } from "../data-display/popover";
8
+ import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from "../data-display/popover";
9
9
  import { Input } from "./input";
10
10
  function pad2(n) {
11
11
  return String(n).padStart(2, "0");
@@ -233,59 +233,58 @@ function TimePicker({
233
233
  setValue("");
234
234
  setText("");
235
235
  };
236
- return /* @__PURE__ */ jsxs("div", { className: cn("relative", className), children: [
237
- /* @__PURE__ */ jsx(
238
- Input,
239
- {
240
- id,
241
- name,
242
- value: text,
243
- disabled,
244
- placeholder: resolvedPlaceholder,
245
- inputMode: "numeric",
246
- autoComplete: "off",
247
- role: "combobox",
248
- "aria-expanded": open,
249
- "aria-haspopup": "dialog",
250
- className: cn("tabular-nums", showClear ? "pe-16" : "pe-10"),
251
- onClick: () => {
252
- if (!disabled) setOpen(true);
253
- },
254
- onKeyDown: (event) => {
255
- if (event.key === "ArrowDown") {
256
- event.preventDefault();
257
- setOpen(true);
258
- } else if (event.key === "Escape" && open) {
259
- setOpen(false);
236
+ return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
237
+ /* @__PURE__ */ jsx(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxs("div", { className: cn("relative", className), children: [
238
+ /* @__PURE__ */ jsx(
239
+ Input,
240
+ {
241
+ id,
242
+ name,
243
+ value: text,
244
+ disabled,
245
+ placeholder: resolvedPlaceholder,
246
+ inputMode: "numeric",
247
+ autoComplete: "off",
248
+ role: "combobox",
249
+ "aria-expanded": open,
250
+ "aria-haspopup": "dialog",
251
+ className: cn("tabular-nums", "pe-10"),
252
+ onClick: () => {
253
+ if (!disabled) setOpen(true);
254
+ },
255
+ onKeyDown: (event) => {
256
+ if (event.key === "ArrowDown") {
257
+ event.preventDefault();
258
+ setOpen(true);
259
+ } else if (event.key === "Escape" && open) {
260
+ setOpen(false);
261
+ }
262
+ },
263
+ onChange: (event) => {
264
+ setText(event.target.value);
265
+ const normalized = normalizeHhmm(event.target.value);
266
+ if (normalized) setValue(normalized);
267
+ },
268
+ onBlur: (event) => {
269
+ const normalized = normalizeHhmm(event.target.value);
270
+ setText(normalized ?? (isValidHhmm(value) ? value : ""));
260
271
  }
261
- },
262
- onChange: (event) => {
263
- setText(event.target.value);
264
- const normalized = normalizeHhmm(event.target.value);
265
- if (normalized) setValue(normalized);
266
- },
267
- onBlur: (event) => {
268
- const normalized = normalizeHhmm(event.target.value);
269
- setText(normalized ?? (isValidHhmm(value) ? value : ""));
270
272
  }
271
- }
272
- ),
273
- showClear ? /* @__PURE__ */ jsx(
274
- Button,
275
- {
276
- type: "button",
277
- variant: "ghost",
278
- size: "icon",
279
- disabled,
280
- tabIndex: -1,
281
- "aria-label": t("common.clear") ?? "Clear",
282
- className: "text-muted-foreground absolute inset-y-0 end-8 h-full px-2 hover:bg-transparent",
283
- onClick: clear,
284
- children: /* @__PURE__ */ jsx(X, { className: "size-4 shrink-0", "aria-hidden": "true" })
285
- }
286
- ) : null,
287
- /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
288
- /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
273
+ ),
274
+ showClear ? /* @__PURE__ */ jsx(
275
+ Button,
276
+ {
277
+ type: "button",
278
+ variant: "ghost",
279
+ size: "icon",
280
+ disabled,
281
+ tabIndex: -1,
282
+ "aria-label": t("common.clear") ?? "Clear",
283
+ className: "text-muted-foreground absolute inset-y-0 end-0 h-full px-2 hover:bg-transparent",
284
+ onClick: clear,
285
+ children: /* @__PURE__ */ jsx(X, { className: "size-4 shrink-0", "aria-hidden": "true" })
286
+ }
287
+ ) : /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
289
288
  Button,
290
289
  {
291
290
  type: "button",
@@ -297,31 +296,31 @@ function TimePicker({
297
296
  className: "text-muted-foreground absolute inset-y-0 end-0 h-full px-2 hover:bg-transparent",
298
297
  children: /* @__PURE__ */ jsx(Clock, { className: "size-4 shrink-0", "aria-hidden": "true" })
299
298
  }
300
- ) }),
301
- /* @__PURE__ */ jsx(
302
- PopoverContent,
303
- {
304
- className: "w-auto p-0",
305
- align: "end",
306
- onOpenAutoFocus: (event) => event.preventDefault(),
307
- children: /* @__PURE__ */ jsx(
308
- TimePickerPanel,
309
- {
310
- value: value || "09:00",
311
- minuteStep,
312
- use12h,
313
- onChange: (next) => {
314
- setValue(next);
315
- setText(next);
316
- },
317
- onDone: () => {
318
- setOpen(false);
319
- }
299
+ ) })
300
+ ] }) }),
301
+ /* @__PURE__ */ jsx(
302
+ PopoverContent,
303
+ {
304
+ className: "w-auto p-0",
305
+ align: "end",
306
+ onOpenAutoFocus: (event) => event.preventDefault(),
307
+ children: /* @__PURE__ */ jsx(
308
+ TimePickerPanel,
309
+ {
310
+ value: value || "09:00",
311
+ minuteStep,
312
+ use12h,
313
+ onChange: (next) => {
314
+ setValue(next);
315
+ setText(next);
316
+ },
317
+ onDone: () => {
318
+ setOpen(false);
320
319
  }
321
- )
322
- }
323
- )
324
- ] })
320
+ }
321
+ )
322
+ }
323
+ )
325
324
  ] });
326
325
  }
327
326
  export {
@@ -21,7 +21,6 @@ export { Separator } from "./separator";
21
21
  export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from "../feedback/tooltip";
22
22
  export * from "./dropdown-menu";
23
23
  export * from "./input";
24
- export * from "./time-input";
25
24
  export * from "./label";
26
25
  export * from "./pagination";
27
26
  export * from "./password-strength";
@@ -21,7 +21,6 @@ import { Separator } from "./separator";
21
21
  import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from "../feedback/tooltip";
22
22
  export * from "./dropdown-menu";
23
23
  export * from "./input";
24
- export * from "./time-input";
25
24
  export * from "./label";
26
25
  export * from "./pagination";
27
26
  export * from "./password-strength";
@@ -193,6 +193,14 @@
193
193
  border-radius: var(--skeleton-radius);
194
194
  }
195
195
 
196
+ /* Drop the self-frame inside a flush CardContent so the Card supplies the single
197
+ * border — mirrors `.ui-data-table-surface` so the skeleton placeholder and the
198
+ * real DataTable it swaps for sit identically (no nested double border). */
199
+ [data-slot="card-content"][data-flush] .ui-skeleton-table {
200
+ border-width: 0;
201
+ border-radius: 0;
202
+ }
203
+
196
204
  .ui-skeleton-table-head {
197
205
  display: flex;
198
206
  align-items: center;
@@ -17,7 +17,6 @@
17
17
  .ui-context-menu-checkbox-item,
18
18
  .ui-context-menu-radio-item,
19
19
  .ui-context-menu-shortcut,
20
- .ui-context-menu-content > div,
21
20
  .ui-menubar-item,
22
21
  .ui-menubar-label,
23
22
  .ui-menubar-trigger,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@godxjp/ui",
3
- "version": "15.0.1",
3
+ "version": "16.0.0",
4
4
  "type": "module",
5
5
  "packageManager": "pnpm@10.29.1",
6
6
  "sideEffects": false,
@@ -1,9 +0,0 @@
1
- import * as React from "react";
2
- type TimeInputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, "value" | "defaultValue"> & {
3
- value?: string;
4
- defaultValue?: string;
5
- onValueChange?: (value: string) => void;
6
- step?: number;
7
- };
8
- export declare function TimeInput({ value: controlledValue, defaultValue, onValueChange, placeholder, step, className, name, id, ...props }: TimeInputProps): import("react/jsx-runtime").JSX.Element;
9
- export type { TimeInputProps };
@@ -1,137 +0,0 @@
1
- import { jsx } from "react/jsx-runtime";
2
- import * as React from "react";
3
- import { cn } from "../../lib/utils";
4
- import { isValidHhmm, normalizeHhmm } from "../../lib/datetime";
5
- function clampStep(step) {
6
- if (!step || Number.isNaN(step)) return 1;
7
- const parsed = Math.max(1, Math.floor(step));
8
- if (!Number.isFinite(parsed)) return 1;
9
- return Math.min(59, parsed);
10
- }
11
- function applyStep(value, step) {
12
- const normalized = normalizeHhmm(value);
13
- if (!normalized) return value;
14
- const [hourText, minuteText] = normalized.split(":");
15
- const hour = Number(hourText);
16
- const minute = Number(minuteText);
17
- const floored = Math.floor(minute / step) * step;
18
- const safeMinute = Math.min(59, Math.max(0, floored));
19
- return `${String(hour).padStart(2, "0")}:${String(safeMinute).padStart(2, "0")}`;
20
- }
21
- function maskTime(raw) {
22
- const digits = raw.replace(/\D/g, "").slice(0, 4);
23
- if (digits.length <= 2) return digits;
24
- return `${digits.slice(0, 2)}:${digits.slice(2)}`;
25
- }
26
- function stepTime(value, deltaMinutes) {
27
- const normalized = normalizeHhmm(value) ?? "00:00";
28
- const [hourText, minuteText] = normalized.split(":");
29
- const total = (Number(hourText) * 60 + Number(minuteText) + deltaMinutes + 24 * 60) % (24 * 60);
30
- const hour = Math.floor(total / 60);
31
- const minute = total % 60;
32
- return `${String(hour).padStart(2, "0")}:${String(minute).padStart(2, "0")}`;
33
- }
34
- function TimeInput({
35
- value: controlledValue,
36
- defaultValue = "",
37
- onValueChange,
38
- placeholder,
39
- step = 1,
40
- className,
41
- name,
42
- id,
43
- ...props
44
- }) {
45
- const safeStep = clampStep(step);
46
- const [internal, setInternal] = React.useState(defaultValue);
47
- const [displayValue, setDisplayValue] = React.useState(controlledValue ?? defaultValue);
48
- const isControlled = controlledValue !== void 0;
49
- const value = isControlled ? controlledValue ?? "" : internal;
50
- React.useEffect(() => {
51
- if (!isControlled) return;
52
- setDisplayValue(controlledValue ?? "");
53
- }, [controlledValue, isControlled]);
54
- React.useEffect(() => {
55
- if (isControlled) return;
56
- setDisplayValue(internal);
57
- }, [internal, isControlled]);
58
- const commit = React.useCallback(
59
- (next, fromBlur = false) => {
60
- const normalized = normalizeHhmm(next);
61
- if (!normalized) return;
62
- const snapped = applyStep(normalized, safeStep);
63
- if (!isControlled) {
64
- setInternal(snapped);
65
- }
66
- if (isValidHhmm(snapped)) {
67
- onValueChange?.(snapped);
68
- setDisplayValue(snapped);
69
- }
70
- if (fromBlur && value !== snapped) {
71
- onValueChange?.(snapped);
72
- }
73
- },
74
- [isControlled, onValueChange, safeStep, value]
75
- );
76
- const valid = isValidHhmm(value);
77
- return /* @__PURE__ */ jsx(
78
- "input",
79
- {
80
- id,
81
- name,
82
- value: displayValue,
83
- "data-slot": "time-input",
84
- className: cn("ui-time-input", className),
85
- role: "spinbutton",
86
- "aria-valuemin": 0,
87
- "aria-valuemax": 24 * 60 - 1,
88
- "aria-valuenow": valid ? Number(value.slice(0, 2)) * 60 + Number(value.slice(3, 5)) : void 0,
89
- "aria-valuetext": valid ? value : void 0,
90
- "aria-invalid": displayValue !== "" && !isValidHhmm(displayValue) ? "true" : void 0,
91
- placeholder: placeholder ?? "HH:mm",
92
- inputMode: "numeric",
93
- autoComplete: "off",
94
- ...props,
95
- onChange: (event) => {
96
- const masked = maskTime(event.target.value);
97
- setDisplayValue(masked);
98
- const normalized = normalizeHhmm(masked);
99
- if (normalized) {
100
- const snapped = applyStep(normalized, safeStep);
101
- if (!isControlled) {
102
- setInternal(snapped);
103
- }
104
- onValueChange?.(snapped);
105
- setDisplayValue(snapped);
106
- }
107
- props.onChange?.(event);
108
- },
109
- onBlur: (event) => {
110
- commit(event.target.value, true);
111
- const normalized = normalizeHhmm(event.target.value);
112
- if (!normalized) {
113
- setDisplayValue(value);
114
- }
115
- props.onBlur?.(event);
116
- },
117
- onKeyDown: (event) => {
118
- if (event.key === "Enter") {
119
- commit(event.currentTarget.value, true);
120
- } else if (event.key === "ArrowUp" || event.key === "ArrowDown") {
121
- event.preventDefault();
122
- const base = isValidHhmm(displayValue) ? displayValue : value || "00:00";
123
- const next = stepTime(base, event.key === "ArrowUp" ? safeStep : -safeStep);
124
- setDisplayValue(next);
125
- if (!isControlled) {
126
- setInternal(next);
127
- }
128
- onValueChange?.(next);
129
- }
130
- props.onKeyDown?.(event);
131
- }
132
- }
133
- );
134
- }
135
- export {
136
- TimeInput
137
- };
@@ -1 +0,0 @@
1
- export * from "../data-entry/time-input";
@@ -1 +0,0 @@
1
- export * from "../data-entry/time-input";