@bouku/core 0.4.6 → 0.4.8
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/assets/icons/calendar.svg +6 -0
- package/dist/components/date/_.d.ts +2 -1
- package/dist/components/date/_.js +2 -1
- package/dist/components/date/picker.d.ts +38 -0
- package/dist/components/date/picker.js +52 -0
- package/dist/components/date/range-picker.d.ts +13 -0
- package/dist/components/date/range-picker.js +28 -0
- package/dist/components/table/date-range.js +2 -2
- package/dist/components/table/utils/date.d.ts +0 -1
- package/dist/components/table/utils/date.js +0 -10
- package/package.json +1 -1
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640" width="1em" height="1em">
|
|
2
|
+
<path
|
|
3
|
+
d="M224 64C206.3 64 192 78.3 192 96L192 128L160 128C124.7 128 96 156.7 96 192L96 240L544 240L544 192C544 156.7 515.3 128 480 128L448 128L448 96C448 78.3 433.7 64 416 64C398.3 64 384 78.3 384 96L384 128L256 128L256 96C256 78.3 241.7 64 224 64zM96 288L96 480C96 515.3 124.7 544 160 544L480 544C515.3 544 544 515.3 544 480L544 288L96 288z"
|
|
4
|
+
fill="currentColor"
|
|
5
|
+
/>
|
|
6
|
+
</svg>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
type FieldProps<T> = {
|
|
3
|
+
id?: string;
|
|
4
|
+
label?: string;
|
|
5
|
+
style?: string;
|
|
6
|
+
value?: T;
|
|
7
|
+
update?: (x: T) => void;
|
|
8
|
+
updateForm?: (id: string, x: T) => void;
|
|
9
|
+
required?: boolean;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
note?: ReactNode;
|
|
12
|
+
};
|
|
13
|
+
type Variant = "normal" | "ghost";
|
|
14
|
+
type DatePickerProps = FieldProps<string> & {
|
|
15
|
+
variant?: Variant;
|
|
16
|
+
size?: "sm" | "md";
|
|
17
|
+
style?: string;
|
|
18
|
+
min?: string;
|
|
19
|
+
max?: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Date picker field component.
|
|
23
|
+
*
|
|
24
|
+
* Wraps the native `input[type="date"]` element with custom styling.
|
|
25
|
+
* It displays an optional label and note, and can be marked as required.
|
|
26
|
+
* The value is controlled externally as an ISO date string (`YYYY-MM-DD`).
|
|
27
|
+
*
|
|
28
|
+
* Variants:
|
|
29
|
+
* - `normal`: Standard input with primary color scheme.
|
|
30
|
+
* - `ghost`: Transparent for injecting input inside another component.
|
|
31
|
+
*
|
|
32
|
+
* @param {Variant} variant - Visual style variant. (optional, default = normal)
|
|
33
|
+
* @param {string} style - Additional class names for styling. (optional)
|
|
34
|
+
* @param {string} min - Earliest selectable date in `YYYY-MM-DD` format. (optional)
|
|
35
|
+
* @param {string} max - Latest selectable date in `YYYY-MM-DD` format. (optional)
|
|
36
|
+
*/
|
|
37
|
+
export declare function DatePicker({ id, variant, size, value, update, updateForm, disabled, min, max, ...props }: DatePickerProps): import("react").JSX.Element;
|
|
38
|
+
export default DatePicker;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from "../../utils/functions/style.js";
|
|
4
|
+
import { tv } from "tailwind-variants";
|
|
5
|
+
function Field({ style, label, required = true, note, children }) {
|
|
6
|
+
return (_jsxs("div", { className: cn(fieldStyles.container, style), children: [label && _jsxs("span", { className: fieldStyles.label, children: [label, " ", !required ? _jsx("span", { className: "italic text-slate-400", children: "(optional)" }) : ""] }), children, note && _jsx("span", { className: fieldStyles.note, children: note })] }));
|
|
7
|
+
}
|
|
8
|
+
const fieldStyles = {
|
|
9
|
+
container: "flex flex-col shrink-0 gap-2 overflow-hidden",
|
|
10
|
+
label: "text-xs text-primary-dark",
|
|
11
|
+
note: "mt-1 text-xs text-slate-500 whitespace-pre-line"
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Date picker field component.
|
|
15
|
+
*
|
|
16
|
+
* Wraps the native `input[type="date"]` element with custom styling.
|
|
17
|
+
* It displays an optional label and note, and can be marked as required.
|
|
18
|
+
* The value is controlled externally as an ISO date string (`YYYY-MM-DD`).
|
|
19
|
+
*
|
|
20
|
+
* Variants:
|
|
21
|
+
* - `normal`: Standard input with primary color scheme.
|
|
22
|
+
* - `ghost`: Transparent for injecting input inside another component.
|
|
23
|
+
*
|
|
24
|
+
* @param {Variant} variant - Visual style variant. (optional, default = normal)
|
|
25
|
+
* @param {string} style - Additional class names for styling. (optional)
|
|
26
|
+
* @param {string} min - Earliest selectable date in `YYYY-MM-DD` format. (optional)
|
|
27
|
+
* @param {string} max - Latest selectable date in `YYYY-MM-DD` format. (optional)
|
|
28
|
+
*/
|
|
29
|
+
export function DatePicker({ id, variant, size = "md", value, update, updateForm, disabled = false, min, max, ...props }) {
|
|
30
|
+
const handleUpdate = (value) => {
|
|
31
|
+
if (id && updateForm)
|
|
32
|
+
updateForm(id, value);
|
|
33
|
+
else
|
|
34
|
+
update?.(value);
|
|
35
|
+
};
|
|
36
|
+
return (_jsx(Field, { ...props, children: _jsx("input", { type: "date", className: styles({ variant, size }), value: value || "", onChange: ({ target: { value } }) => handleUpdate(value), autoComplete: "off", disabled: disabled, min: min, max: max }) }));
|
|
37
|
+
}
|
|
38
|
+
const styles = tv({
|
|
39
|
+
base: "px-3 py-2 duration-200 rounded placeholder:text-primary-darker text-primary disabled:brightness-90 disabled:cursor-not-allowed",
|
|
40
|
+
defaultVariants: { variant: "normal", size: "md" },
|
|
41
|
+
variants: {
|
|
42
|
+
variant: {
|
|
43
|
+
normal: "bg-input border border-outline focus:border-outline-light outline-none",
|
|
44
|
+
ghost: "p-0 bg-transparent border-none outline-none"
|
|
45
|
+
},
|
|
46
|
+
size: {
|
|
47
|
+
sm: "px-2 text-xs",
|
|
48
|
+
md: "text-xs sm:text-sm"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
export default DatePicker;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type DateRange = {
|
|
2
|
+
from: string;
|
|
3
|
+
to: string;
|
|
4
|
+
};
|
|
5
|
+
type Props = DateRange & {
|
|
6
|
+
size?: "xs" | "sm";
|
|
7
|
+
min?: string;
|
|
8
|
+
update: (next: DateRange) => void;
|
|
9
|
+
initial: DateRange;
|
|
10
|
+
};
|
|
11
|
+
export declare function DateRangePicker({ from, to, size, min, update, initial }: Props): import("react").JSX.Element;
|
|
12
|
+
export declare const formatDateLabel: (value: string) => string;
|
|
13
|
+
export default DateRangePicker;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Dropdown } from "../miscellaneous/dropdown/normal.js";
|
|
3
|
+
import { DatePicker } from "./picker.js";
|
|
4
|
+
import { Button } from "../button/normal.js";
|
|
5
|
+
import Trash from "../../assets/icons/trash.svg";
|
|
6
|
+
import Calendar from "../../assets/icons/calendar.svg";
|
|
7
|
+
export function DateRangePicker({ from, to, size = "sm", min, update, initial }) {
|
|
8
|
+
const label = from && to
|
|
9
|
+
? `${formatDateLabel(from)} – ${formatDateLabel(to)}`
|
|
10
|
+
: from
|
|
11
|
+
? `Since ${formatDateLabel(from)}`
|
|
12
|
+
: to
|
|
13
|
+
? `Until ${formatDateLabel(to)}`
|
|
14
|
+
: null;
|
|
15
|
+
const Trigger = (_jsx(Button, { size: size, style: "bg-surface-dark border-border-darker", icon: label ? undefined : _jsx(Calendar, {}), children: label ?? "Filter Date" }));
|
|
16
|
+
return (_jsxs(Dropdown, { trigger: Trigger, align: "right", style: "gap-3 min-w-56 p-4", children: [_jsx(DatePicker, { id: "from", label: "From", size: "sm", style: "gap-1", min: min, max: to || undefined, value: from, update: v => update({ from: v, to }) }), _jsx(DatePicker, { id: "to", label: "To", size: "sm", style: "gap-1", min: from || min, value: to, update: v => update({ from, to: v }) }), (from || to) && (_jsx(Button, { size: "xs", style: "mx-auto py-1 px-2 gap-1", variant: "error", icon: _jsx(Trash, {}), action: () => update(initial), children: "Clear" }))] }));
|
|
17
|
+
}
|
|
18
|
+
export const formatDateLabel = (value) => {
|
|
19
|
+
if (!value)
|
|
20
|
+
return "";
|
|
21
|
+
const [year, month, day] = value.split("-").map(Number);
|
|
22
|
+
return new Date(year, month - 1, day).toLocaleDateString(undefined, {
|
|
23
|
+
month: "short",
|
|
24
|
+
day: "numeric",
|
|
25
|
+
year: "numeric"
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
export default DateRangePicker;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Dropdown } from "../miscellaneous/dropdown/normal.js";
|
|
3
|
-
import { DatePicker } from "../date/
|
|
3
|
+
import { DatePicker } from "../date/picker.js";
|
|
4
4
|
import { Button } from "../button/normal.js";
|
|
5
5
|
import Trash from "../../assets/icons/trash.svg";
|
|
6
|
-
import { formatDateLabel } from "
|
|
6
|
+
import { formatDateLabel } from "../date/range-picker.js";
|
|
7
7
|
export default function DateRange({ from, to, update, initial }) {
|
|
8
8
|
const Trigger = (_jsxs(Button, { size: "xs", style: "bg-surface-dark border-border-darker", children: [formatDateLabel(from), " \u2013 ", formatDateLabel(to)] }));
|
|
9
9
|
return (_jsxs(Dropdown, { trigger: Trigger, align: "right", style: "gap-3 min-w-56 p-4", children: [_jsx(DatePicker, { id: "from", label: "From", size: "sm", style: "gap-1", value: from, update: v => update(prev => ({ ...prev, from: v })) }), _jsx(DatePicker, { id: "to", label: "To", size: "sm", style: "gap-1", value: to, update: v => update(prev => ({ ...prev, to: v })) }), (from || to) && (_jsx(Button, { size: "xs", style: "mx-auto py-1 px-2 gap-1", variant: "error", icon: _jsx(Trash, {}), action: () => update(initial), disabled: from === initial.from && to === initial.to, children: "Clear" }))] }));
|
|
@@ -2,5 +2,4 @@ import type { DateRange, TableRow, CellValue } from "./types.js";
|
|
|
2
2
|
export declare const parseDate: (value: CellValue) => Date;
|
|
3
3
|
export declare const formatDateInput: (value: CellValue) => string;
|
|
4
4
|
export declare const getDateRange: <T extends TableRow>(items: T[], column?: keyof T) => DateRange;
|
|
5
|
-
export declare const formatDateLabel: (value: string) => string;
|
|
6
5
|
export declare const isDateLike: (value: CellValue) => boolean;
|
|
@@ -31,16 +31,6 @@ export const getDateRange = (items, column) => {
|
|
|
31
31
|
to: formatDateInput(dates[dates.length - 1])
|
|
32
32
|
};
|
|
33
33
|
};
|
|
34
|
-
export const formatDateLabel = (value) => {
|
|
35
|
-
if (!value)
|
|
36
|
-
return "";
|
|
37
|
-
const [year, month, day] = value.split("-").map(Number);
|
|
38
|
-
return new Date(year, month - 1, day).toLocaleDateString(undefined, {
|
|
39
|
-
month: "short",
|
|
40
|
-
day: "numeric",
|
|
41
|
-
year: "numeric"
|
|
42
|
-
});
|
|
43
|
-
};
|
|
44
34
|
export const isDateLike = (value) => value instanceof Date ||
|
|
45
35
|
(typeof value === "string" &&
|
|
46
36
|
!Number.isNaN(Date.parse(value)) &&
|