@novi-ui/raster 0.6.0 → 0.7.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/combo-box/combo-box.d.mts +36 -0
- package/dist/combo-box/combo-box.d.mts.map +1 -0
- package/dist/combo-box/combo-box.mjs +128 -0
- package/dist/combo-box/combo-box.mjs.map +1 -0
- package/dist/combo-box/combo-box.styles.d.mts +88 -0
- package/dist/combo-box/combo-box.styles.d.mts.map +1 -0
- package/dist/combo-box/combo-box.styles.mjs +110 -0
- package/dist/combo-box/combo-box.styles.mjs.map +1 -0
- package/dist/combo-box/index.d.mts +3 -0
- package/dist/date-picker/date-picker.d.mts +15 -0
- package/dist/date-picker/date-picker.d.mts.map +1 -0
- package/dist/date-picker/date-picker.mjs +161 -0
- package/dist/date-picker/date-picker.mjs.map +1 -0
- package/dist/date-picker/date-picker.styles.d.mts +103 -0
- package/dist/date-picker/date-picker.styles.d.mts.map +1 -0
- package/dist/date-picker/date-picker.styles.mjs +126 -0
- package/dist/date-picker/date-picker.styles.mjs.map +1 -0
- package/dist/date-picker/index.d.mts +3 -0
- package/dist/index.d.mts +16 -1
- package/dist/index.mjs +11 -1
- package/dist/number-field/index.d.mts +3 -0
- package/dist/number-field/number-field.d.mts +15 -0
- package/dist/number-field/number-field.d.mts.map +1 -0
- package/dist/number-field/number-field.mjs +114 -0
- package/dist/number-field/number-field.mjs.map +1 -0
- package/dist/number-field/number-field.styles.d.mts +76 -0
- package/dist/number-field/number-field.styles.d.mts.map +1 -0
- package/dist/number-field/number-field.styles.mjs +90 -0
- package/dist/number-field/number-field.styles.mjs.map +1 -0
- package/dist/pagination/index.d.mts +3 -0
- package/dist/pagination/pagination.d.mts +13 -0
- package/dist/pagination/pagination.d.mts.map +1 -0
- package/dist/pagination/pagination.mjs +97 -0
- package/dist/pagination/pagination.mjs.map +1 -0
- package/dist/pagination/pagination.styles.d.mts +73 -0
- package/dist/pagination/pagination.styles.d.mts.map +1 -0
- package/dist/pagination/pagination.styles.mjs +95 -0
- package/dist/pagination/pagination.styles.mjs.map +1 -0
- package/dist/select/select.d.mts +1 -1
- package/dist/select/select.mjs +1 -1
- package/dist/select/select.mjs.map +1 -1
- package/dist/table/index.d.mts +3 -0
- package/dist/table/table.d.mts +104 -0
- package/dist/table/table.d.mts.map +1 -0
- package/dist/table/table.mjs +172 -0
- package/dist/table/table.mjs.map +1 -0
- package/dist/table/table.styles.d.mts +58 -0
- package/dist/table/table.styles.d.mts.map +1 -0
- package/dist/table/table.styles.mjs +82 -0
- package/dist/table/table.styles.mjs.map +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { disabledState, focusRing } from "../styles/focus-ring.mjs";
|
|
2
|
+
import { tv } from "tailwind-variants";
|
|
3
|
+
//#region src/number-field/number-field.styles.ts
|
|
4
|
+
/** 増減ボタン。1px の縦線で区切るだけで、面は持たない(Raster の規律)。 */
|
|
5
|
+
const stepper = [
|
|
6
|
+
"shrink-0 self-stretch inline-flex items-center justify-center w-7",
|
|
7
|
+
"text-[var(--novi-color-muted)]",
|
|
8
|
+
"border-l border-[var(--novi-color-border)]",
|
|
9
|
+
"outline-none",
|
|
10
|
+
"hover:text-[var(--novi-color-fg)] hover:bg-[var(--novi-color-subtle)]",
|
|
11
|
+
"data-[focus-visible]:text-[var(--novi-color-fg)]",
|
|
12
|
+
"data-[disabled]:opacity-40 data-[disabled]:cursor-default",
|
|
13
|
+
"transition-[color,background-color]",
|
|
14
|
+
"duration-[var(--novi-duration-fast)] ease-[var(--novi-ease-standard)]"
|
|
15
|
+
].join(" ");
|
|
16
|
+
const slots = {
|
|
17
|
+
root: "flex flex-col gap-1.5",
|
|
18
|
+
label: "text-[length:var(--novi-text-sm)] font-medium text-[var(--novi-color-fg)]",
|
|
19
|
+
inputWrapper: [
|
|
20
|
+
"text-[var(--novi-color-fg)]",
|
|
21
|
+
"flex items-center w-full overflow-hidden",
|
|
22
|
+
"bg-[var(--novi-color-bg)]",
|
|
23
|
+
"border border-[var(--novi-color-border-strong)]",
|
|
24
|
+
"transition-[border-color,opacity]",
|
|
25
|
+
"duration-[var(--novi-duration-fast)] ease-[var(--novi-ease-standard)]",
|
|
26
|
+
"data-[invalid]:border-[var(--novi-color-danger)]",
|
|
27
|
+
focusRing,
|
|
28
|
+
disabledState
|
|
29
|
+
].join(" "),
|
|
30
|
+
input: [
|
|
31
|
+
"w-full min-w-0 bg-transparent outline-none",
|
|
32
|
+
"text-[var(--novi-color-fg)] tabular-nums",
|
|
33
|
+
"placeholder:text-[var(--novi-color-muted)]"
|
|
34
|
+
].join(" "),
|
|
35
|
+
decrement: stepper,
|
|
36
|
+
increment: stepper,
|
|
37
|
+
description: "text-[length:var(--novi-text-xs)] text-[var(--novi-color-muted)]",
|
|
38
|
+
errorMessage: "text-[length:var(--novi-text-xs)] text-[var(--novi-color-danger)]"
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* NumberField のスタイル定義。
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* import { numberFieldStyles } from '@novi-ui/raster'
|
|
45
|
+
* import { tv } from 'tailwind-variants'
|
|
46
|
+
*
|
|
47
|
+
* const myField = tv({ extend: numberFieldStyles, slots: { input: 'text-right' } })
|
|
48
|
+
*/
|
|
49
|
+
const numberFieldStyles = tv({
|
|
50
|
+
slots,
|
|
51
|
+
variants: {
|
|
52
|
+
variant: {
|
|
53
|
+
solid: { inputWrapper: "bg-[var(--novi-color-subtle)] border-[var(--novi-color-border-strong)]" },
|
|
54
|
+
outline: { inputWrapper: "bg-[var(--novi-color-bg)] border-[var(--novi-color-border-strong)]" },
|
|
55
|
+
soft: { inputWrapper: "bg-[var(--novi-color-subtle)] border-transparent" },
|
|
56
|
+
ghost: { inputWrapper: "bg-transparent border-transparent border-b-[var(--novi-color-border-strong)]" },
|
|
57
|
+
plain: { inputWrapper: "bg-transparent border-transparent" }
|
|
58
|
+
},
|
|
59
|
+
size: {
|
|
60
|
+
sm: {
|
|
61
|
+
inputWrapper: "h-8",
|
|
62
|
+
input: "px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-sm)]"
|
|
63
|
+
},
|
|
64
|
+
md: {
|
|
65
|
+
inputWrapper: "h-10",
|
|
66
|
+
input: "px-[var(--novi-pad-control-x-md)] text-[length:var(--novi-text-base)]"
|
|
67
|
+
},
|
|
68
|
+
lg: {
|
|
69
|
+
inputWrapper: "h-12",
|
|
70
|
+
input: "px-[var(--novi-pad-control-x-lg)] text-[length:var(--novi-text-base)]"
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
radius: {
|
|
74
|
+
none: { inputWrapper: "rounded-[var(--novi-radius-none)]" },
|
|
75
|
+
sm: { inputWrapper: "rounded-[var(--novi-radius-sm)]" },
|
|
76
|
+
md: { inputWrapper: "rounded-[var(--novi-radius-md)]" },
|
|
77
|
+
lg: { inputWrapper: "rounded-[var(--novi-radius-lg)]" },
|
|
78
|
+
full: { inputWrapper: "rounded-[var(--novi-radius-full)]" }
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
defaultVariants: {
|
|
82
|
+
variant: "outline",
|
|
83
|
+
size: "md",
|
|
84
|
+
radius: "md"
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
//#endregion
|
|
88
|
+
export { numberFieldStyles };
|
|
89
|
+
|
|
90
|
+
//# sourceMappingURL=number-field.styles.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"number-field.styles.mjs","names":[],"sources":["../../src/number-field/number-field.styles.ts"],"sourcesContent":["import type {\n NoviRadius,\n NoviSize,\n NoviVariant,\n numberFieldRequiredSlots,\n numberFieldSlots,\n SlotMap,\n VariantMap,\n} from '@novi-ui/core'\nimport { tv } from 'tailwind-variants'\nimport { disabledState, focusRing } from '../styles/focus-ring'\n\n/** 増減ボタン。1px の縦線で区切るだけで、面は持たない(Raster の規律)。 */\nconst stepper = [\n 'shrink-0 self-stretch inline-flex items-center justify-center w-7',\n 'text-[var(--novi-color-muted)]',\n 'border-l border-[var(--novi-color-border)]',\n 'outline-none',\n 'hover:text-[var(--novi-color-fg)] hover:bg-[var(--novi-color-subtle)]',\n 'data-[focus-visible]:text-[var(--novi-color-fg)]',\n 'data-[disabled]:opacity-40 data-[disabled]:cursor-default',\n 'transition-[color,background-color]',\n 'duration-[var(--novi-duration-fast)] ease-[var(--novi-ease-standard)]',\n].join(' ')\n\nconst slots = {\n root: 'flex flex-col gap-1.5',\n label: 'text-[length:var(--novi-text-sm)] font-medium text-[var(--novi-color-fg)]',\n // Input と同じ枠。右端の増減ボタンを枠の縁まで届かせるため、左右の余白は input 側に置く\n inputWrapper: [\n 'text-[var(--novi-color-fg)]',\n 'flex items-center w-full overflow-hidden',\n 'bg-[var(--novi-color-bg)]',\n 'border border-[var(--novi-color-border-strong)]',\n 'transition-[border-color,opacity]',\n 'duration-[var(--novi-duration-fast)] ease-[var(--novi-ease-standard)]',\n 'data-[invalid]:border-[var(--novi-color-danger)]',\n focusRing,\n disabledState,\n ].join(' '),\n input: [\n 'w-full min-w-0 bg-transparent outline-none',\n 'text-[var(--novi-color-fg)] tabular-nums',\n 'placeholder:text-[var(--novi-color-muted)]',\n ].join(' '),\n decrement: stepper,\n increment: stepper,\n description: 'text-[length:var(--novi-text-xs)] text-[var(--novi-color-muted)]',\n // 色だけに頼らずテキストを必ず伴う(WCAG 1.4.1)\n errorMessage: 'text-[length:var(--novi-text-xs)] text-[var(--novi-color-danger)]',\n} satisfies SlotMap<typeof numberFieldSlots, (typeof numberFieldRequiredSlots)[number]>\n\nconst variant: VariantMap<NoviVariant, { inputWrapper: string }> = {\n solid: {\n inputWrapper: 'bg-[var(--novi-color-subtle)] border-[var(--novi-color-border-strong)]',\n },\n outline: { inputWrapper: 'bg-[var(--novi-color-bg)] border-[var(--novi-color-border-strong)]' },\n soft: { inputWrapper: 'bg-[var(--novi-color-subtle)] border-transparent' },\n ghost: {\n inputWrapper: 'bg-transparent border-transparent border-b-[var(--novi-color-border-strong)]',\n },\n plain: { inputWrapper: 'bg-transparent border-transparent' },\n}\n\n/** 高さは Button / Input と揃える。32 / 40 / 48px。 */\nconst size: VariantMap<NoviSize, { inputWrapper: string; input: string }> = {\n sm: {\n inputWrapper: 'h-8',\n input: 'px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-sm)]',\n },\n md: {\n inputWrapper: 'h-10',\n input: 'px-[var(--novi-pad-control-x-md)] text-[length:var(--novi-text-base)]',\n },\n lg: {\n inputWrapper: 'h-12',\n input: 'px-[var(--novi-pad-control-x-lg)] text-[length:var(--novi-text-base)]',\n },\n}\n\nconst radius: VariantMap<NoviRadius, { inputWrapper: string }> = {\n none: { inputWrapper: 'rounded-[var(--novi-radius-none)]' },\n sm: { inputWrapper: 'rounded-[var(--novi-radius-sm)]' },\n md: { inputWrapper: 'rounded-[var(--novi-radius-md)]' },\n lg: { inputWrapper: 'rounded-[var(--novi-radius-lg)]' },\n full: { inputWrapper: 'rounded-[var(--novi-radius-full)]' },\n}\n\n/**\n * NumberField のスタイル定義。\n *\n * @example\n * import { numberFieldStyles } from '@novi-ui/raster'\n * import { tv } from 'tailwind-variants'\n *\n * const myField = tv({ extend: numberFieldStyles, slots: { input: 'text-right' } })\n */\nexport const numberFieldStyles = tv({\n slots,\n variants: { variant, size, radius },\n defaultVariants: { variant: 'outline', size: 'md', radius: 'md' },\n})\n\nexport type NumberFieldStyleProps = Parameters<typeof numberFieldStyles>[0]\n"],"mappings":";;;;AAaA,MAAM,UAAU;CACd;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC,CAAC,KAAK,GAAG;AAEV,MAAM,QAAQ;CACZ,MAAM;CACN,OAAO;CAEP,cAAc;EACZ;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,GAAG;CACV,OAAO;EACL;EACA;EACA;CACF,CAAC,CAAC,KAAK,GAAG;CACV,WAAW;CACX,WAAW;CACX,aAAa;CAEb,cAAc;AAChB;;;;;;;;;;AA+CA,MAAa,oBAAoB,GAAG;CAClC;CACA,UAAU;EAAE;GA9CZ,OAAO,EACL,cAAc,yEAChB;GACA,SAAS,EAAE,cAAc,qEAAqE;GAC9F,MAAM,EAAE,cAAc,mDAAmD;GACzE,OAAO,EACL,cAAc,+EAChB;GACA,OAAO,EAAE,cAAc,oCAAoC;EAsC/C;EAAS;GAjCrB,IAAI;IACF,cAAc;IACd,OAAO;GACT;GACA,IAAI;IACF,cAAc;IACd,OAAO;GACT;GACA,IAAI;IACF,cAAc;IACd,OAAO;GACT;EAsBqB;EAAM;GAlB3B,MAAM,EAAE,cAAc,oCAAoC;GAC1D,IAAI,EAAE,cAAc,kCAAkC;GACtD,IAAI,EAAE,cAAc,kCAAkC;GACtD,IAAI,EAAE,cAAc,kCAAkC;GACtD,MAAM,EAAE,cAAc,oCAAoC;EAc/B;CAAO;CAClC,iBAAiB;EAAE,SAAS;EAAW,MAAM;EAAM,QAAQ;CAAK;AAClE,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { PaginationProps } from "@novi-ui/core";
|
|
2
|
+
//#region src/pagination/pagination.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* 一覧のページを移動する。数字だけを並べ、現在地は下辺の線で示す
|
|
5
|
+
* (Tactile は面を塗り、Flatlay は罫線で区切った枠を反転させる)。
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* <Pagination total={10} page={page} onChange={setPage} />
|
|
9
|
+
*/
|
|
10
|
+
declare function Pagination({ size, radius, total, page, defaultPage, onChange, siblingCount, boundaryCount, isDisabled, 'aria-label': ariaLabel, className, classNames, id }: PaginationProps): import("react").JSX.Element;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { Pagination };
|
|
13
|
+
//# sourceMappingURL=pagination.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.d.mts","names":[],"sources":["../../src/pagination/pagination.tsx"],"mappings":";;;;;;;;;iBAwBgB,aACd,MACA,QACA,OACA,MACA,aACA,UACA,cACA,eACA,0BACc,WACd,WACA,YACA,MACC,kCAAe,IAAA"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { paginationStyles } from "./pagination.styles.mjs";
|
|
3
|
+
import { Button } from "react-aria-components";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { useState } from "react";
|
|
6
|
+
import { paginationRange } from "@novi-ui/core/client";
|
|
7
|
+
//#region src/pagination/pagination.tsx
|
|
8
|
+
function ChevronIcon({ direction }) {
|
|
9
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
10
|
+
viewBox: "0 0 16 16",
|
|
11
|
+
width: "0.75em",
|
|
12
|
+
height: "0.75em",
|
|
13
|
+
fill: "none",
|
|
14
|
+
"aria-hidden": "true",
|
|
15
|
+
children: /* @__PURE__ */ jsx("path", {
|
|
16
|
+
d: direction === "prev" ? "M10 4l-4 4 4 4" : "M6 4l4 4-4 4",
|
|
17
|
+
stroke: "currentColor",
|
|
18
|
+
strokeWidth: "1.5"
|
|
19
|
+
})
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 一覧のページを移動する。数字だけを並べ、現在地は下辺の線で示す
|
|
24
|
+
* (Tactile は面を塗り、Flatlay は罫線で区切った枠を反転させる)。
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* <Pagination total={10} page={page} onChange={setPage} />
|
|
28
|
+
*/
|
|
29
|
+
function Pagination({ size, radius, total, page, defaultPage = 1, onChange, siblingCount, boundaryCount, isDisabled, "aria-label": ariaLabel = "ページ送り", className, classNames, id }) {
|
|
30
|
+
const s = paginationStyles({
|
|
31
|
+
size,
|
|
32
|
+
radius
|
|
33
|
+
});
|
|
34
|
+
const [internal, setInternal] = useState(defaultPage);
|
|
35
|
+
const clamp = (n) => Math.min(Math.max(n, 1), Math.max(total, 1));
|
|
36
|
+
const current = clamp(page ?? internal);
|
|
37
|
+
const go = (n) => {
|
|
38
|
+
const next = clamp(n);
|
|
39
|
+
if (next === current) return;
|
|
40
|
+
if (page === void 0) setInternal(next);
|
|
41
|
+
onChange?.(next);
|
|
42
|
+
};
|
|
43
|
+
const slots = paginationRange(current, total, {
|
|
44
|
+
siblingCount,
|
|
45
|
+
boundaryCount
|
|
46
|
+
});
|
|
47
|
+
const entries = slots.map((slot, i) => ({
|
|
48
|
+
slot,
|
|
49
|
+
key: slot === "ellipsis" ? `ellipsis-after-${slots[i - 1]}` : `page-${slot}`
|
|
50
|
+
}));
|
|
51
|
+
return /* @__PURE__ */ jsx("nav", {
|
|
52
|
+
id,
|
|
53
|
+
"aria-label": ariaLabel,
|
|
54
|
+
"data-slot": "root",
|
|
55
|
+
className: s.root({ class: [className, classNames?.root] }),
|
|
56
|
+
children: /* @__PURE__ */ jsxs("ul", {
|
|
57
|
+
"data-slot": "list",
|
|
58
|
+
className: s.list({ class: classNames?.list }),
|
|
59
|
+
children: [
|
|
60
|
+
/* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(Button, {
|
|
61
|
+
"data-slot": "prev",
|
|
62
|
+
"aria-label": "前のページ",
|
|
63
|
+
isDisabled: isDisabled || current <= 1,
|
|
64
|
+
onPress: () => go(current - 1),
|
|
65
|
+
className: s.prev({ class: classNames?.prev }),
|
|
66
|
+
children: /* @__PURE__ */ jsx(ChevronIcon, { direction: "prev" })
|
|
67
|
+
}) }),
|
|
68
|
+
entries.map(({ slot, key }) => slot === "ellipsis" ? /* @__PURE__ */ jsx("li", {
|
|
69
|
+
"data-slot": "ellipsis",
|
|
70
|
+
"aria-hidden": "true",
|
|
71
|
+
className: s.ellipsis({ class: classNames?.ellipsis }),
|
|
72
|
+
children: "…"
|
|
73
|
+
}, key) : /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(Button, {
|
|
74
|
+
"data-slot": "item",
|
|
75
|
+
"aria-label": `${slot}ページ`,
|
|
76
|
+
"aria-current": slot === current ? "page" : void 0,
|
|
77
|
+
isDisabled,
|
|
78
|
+
onPress: () => go(slot),
|
|
79
|
+
className: s.item({ class: classNames?.item }),
|
|
80
|
+
children: slot
|
|
81
|
+
}) }, key)),
|
|
82
|
+
/* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(Button, {
|
|
83
|
+
"data-slot": "next",
|
|
84
|
+
"aria-label": "次のページ",
|
|
85
|
+
isDisabled: isDisabled || current >= total,
|
|
86
|
+
onPress: () => go(current + 1),
|
|
87
|
+
className: s.next({ class: classNames?.next }),
|
|
88
|
+
children: /* @__PURE__ */ jsx(ChevronIcon, { direction: "next" })
|
|
89
|
+
}) })
|
|
90
|
+
]
|
|
91
|
+
})
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
//#endregion
|
|
95
|
+
export { Pagination };
|
|
96
|
+
|
|
97
|
+
//# sourceMappingURL=pagination.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.mjs","names":[],"sources":["../../src/pagination/pagination.tsx"],"sourcesContent":["'use client'\n\nimport type { PaginationProps } from '@novi-ui/core'\nimport { paginationRange } from '@novi-ui/core/client'\nimport { useState } from 'react'\nimport { Button } from 'react-aria-components'\nimport { paginationStyles } from './pagination.styles'\n\nfunction ChevronIcon({ direction }: { direction: 'prev' | 'next' }) {\n const d = direction === 'prev' ? 'M10 4l-4 4 4 4' : 'M6 4l4 4-4 4'\n return (\n <svg viewBox=\"0 0 16 16\" width=\"0.75em\" height=\"0.75em\" fill=\"none\" aria-hidden=\"true\">\n <path d={d} stroke=\"currentColor\" strokeWidth=\"1.5\" />\n </svg>\n )\n}\n\n/**\n * 一覧のページを移動する。数字だけを並べ、現在地は下辺の線で示す\n * (Tactile は面を塗り、Flatlay は罫線で区切った枠を反転させる)。\n *\n * @example\n * <Pagination total={10} page={page} onChange={setPage} />\n */\nexport function Pagination({\n size,\n radius,\n total,\n page,\n defaultPage = 1,\n onChange,\n siblingCount,\n boundaryCount,\n isDisabled,\n 'aria-label': ariaLabel = 'ページ送り',\n className,\n classNames,\n id,\n}: PaginationProps) {\n const s = paginationStyles({ size, radius })\n const [internal, setInternal] = useState(defaultPage)\n const clamp = (n: number) => Math.min(Math.max(n, 1), Math.max(total, 1))\n const current = clamp(page ?? internal)\n\n const go = (n: number) => {\n const next = clamp(n)\n if (next === current) return\n if (page === undefined) setInternal(next)\n onChange?.(next)\n }\n\n // 省略記号は最大 2 つ出る。配列の添字ではなく「どの数字の直後か」で区別する\n const slots = paginationRange(current, total, { siblingCount, boundaryCount })\n const entries = slots.map((slot, i) => ({\n slot,\n key: slot === 'ellipsis' ? `ellipsis-after-${slots[i - 1]}` : `page-${slot}`,\n }))\n\n return (\n <nav\n id={id}\n aria-label={ariaLabel}\n data-slot=\"root\"\n className={s.root({ class: [className, classNames?.root] })}\n >\n <ul data-slot=\"list\" className={s.list({ class: classNames?.list })}>\n <li>\n <Button\n data-slot=\"prev\"\n aria-label=\"前のページ\"\n isDisabled={isDisabled || current <= 1}\n onPress={() => go(current - 1)}\n className={s.prev({ class: classNames?.prev })}\n >\n <ChevronIcon direction=\"prev\" />\n </Button>\n </li>\n\n {entries.map(({ slot, key }) =>\n slot === 'ellipsis' ? (\n <li\n key={key}\n data-slot=\"ellipsis\"\n aria-hidden=\"true\"\n className={s.ellipsis({ class: classNames?.ellipsis })}\n >\n …\n </li>\n ) : (\n <li key={key}>\n <Button\n data-slot=\"item\"\n aria-label={`${slot}ページ`}\n aria-current={slot === current ? 'page' : undefined}\n isDisabled={isDisabled}\n onPress={() => go(slot)}\n className={s.item({ class: classNames?.item })}\n >\n {slot}\n </Button>\n </li>\n ),\n )}\n\n <li>\n <Button\n data-slot=\"next\"\n aria-label=\"次のページ\"\n isDisabled={isDisabled || current >= total}\n onPress={() => go(current + 1)}\n className={s.next({ class: classNames?.next })}\n >\n <ChevronIcon direction=\"next\" />\n </Button>\n </li>\n </ul>\n </nav>\n )\n}\n"],"mappings":";;;;;;;AAQA,SAAS,YAAY,EAAE,aAA6C;CAElE,OACE,oBAAC,OAAD;EAAK,SAAQ;EAAY,OAAM;EAAS,QAAO;EAAS,MAAK;EAAO,eAAY;EAC9E,UAAA,oBAAC,QAAD;GAAM,GAHA,cAAc,SAAS,mBAAmB;GAGpC,QAAO;GAAe,aAAY;EAAO,CAAA;CAClD,CAAA;AAET;;;;;;;;AASA,SAAgB,WAAW,EACzB,MACA,QACA,OACA,MACA,cAAc,GACd,UACA,cACA,eACA,YACA,cAAc,YAAY,SAC1B,WACA,YACA,MACkB;CAClB,MAAM,IAAI,iBAAiB;EAAE;EAAM;CAAO,CAAC;CAC3C,MAAM,CAAC,UAAU,eAAe,SAAS,WAAW;CACpD,MAAM,SAAS,MAAc,KAAK,IAAI,KAAK,IAAI,GAAG,CAAC,GAAG,KAAK,IAAI,OAAO,CAAC,CAAC;CACxE,MAAM,UAAU,MAAM,QAAQ,QAAQ;CAEtC,MAAM,MAAM,MAAc;EACxB,MAAM,OAAO,MAAM,CAAC;EACpB,IAAI,SAAS,SAAS;EACtB,IAAI,SAAS,KAAA,GAAW,YAAY,IAAI;EACxC,WAAW,IAAI;CACjB;CAGA,MAAM,QAAQ,gBAAgB,SAAS,OAAO;EAAE;EAAc;CAAc,CAAC;CAC7E,MAAM,UAAU,MAAM,KAAK,MAAM,OAAO;EACtC;EACA,KAAK,SAAS,aAAa,kBAAkB,MAAM,IAAI,OAAO,QAAQ;CACxE,EAAE;CAEF,OACE,oBAAC,OAAD;EACM;EACJ,cAAY;EACZ,aAAU;EACV,WAAW,EAAE,KAAK,EAAE,OAAO,CAAC,WAAW,YAAY,IAAI,EAAE,CAAC;EAE1D,UAAA,qBAAC,MAAD;GAAI,aAAU;GAAO,WAAW,EAAE,KAAK,EAAE,OAAO,YAAY,KAAK,CAAC;GAAlE,UAAA;IACE,oBAAC,MAAD,EAAA,UACE,oBAAC,QAAD;KACE,aAAU;KACV,cAAW;KACX,YAAY,cAAc,WAAW;KACrC,eAAe,GAAG,UAAU,CAAC;KAC7B,WAAW,EAAE,KAAK,EAAE,OAAO,YAAY,KAAK,CAAC;KAE7C,UAAA,oBAAC,aAAD,EAAa,WAAU,OAAQ,CAAA;IACzB,CAAA,EACN,CAAA;IAEH,QAAQ,KAAK,EAAE,MAAM,UACpB,SAAS,aACP,oBAAC,MAAD;KAEE,aAAU;KACV,eAAY;KACZ,WAAW,EAAE,SAAS,EAAE,OAAO,YAAY,SAAS,CAAC;KACtD,UAAA;IAEG,GANG,GAMH,IAEJ,oBAAC,MAAD,EAAA,UACE,oBAAC,QAAD;KACE,aAAU;KACV,cAAY,GAAG,KAAK;KACpB,gBAAc,SAAS,UAAU,SAAS,KAAA;KAC9B;KACZ,eAAe,GAAG,IAAI;KACtB,WAAW,EAAE,KAAK,EAAE,OAAO,YAAY,KAAK,CAAC;KAE5C,UAAA;IACK,CAAA,EACN,GAXK,GAWL,CAER;IAEA,oBAAC,MAAD,EAAA,UACE,oBAAC,QAAD;KACE,aAAU;KACV,cAAW;KACX,YAAY,cAAc,WAAW;KACrC,eAAe,GAAG,UAAU,CAAC;KAC7B,WAAW,EAAE,KAAK,EAAE,OAAO,YAAY,KAAK,CAAC;KAE7C,UAAA,oBAAC,aAAD,EAAa,WAAU,OAAQ,CAAA;IACzB,CAAA,EACN,CAAA;GACF;;CACD,CAAA;AAET"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { VariantMap } from "@novi-ui/core";
|
|
2
|
+
//#region src/pagination/pagination.styles.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Pagination のスタイル定義。
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* import { paginationStyles } from '@novi-ui/raster'
|
|
8
|
+
* import { tv } from 'tailwind-variants'
|
|
9
|
+
*
|
|
10
|
+
* const myPagination = tv({ extend: paginationStyles, slots: { list: 'gap-2' } })
|
|
11
|
+
*/
|
|
12
|
+
declare const paginationStyles: import("tailwind-variants").TVReturnType<{
|
|
13
|
+
size: VariantMap<"sm" | "md" | "lg", {
|
|
14
|
+
item: string;
|
|
15
|
+
prev: string;
|
|
16
|
+
next: string;
|
|
17
|
+
ellipsis: string;
|
|
18
|
+
}>;
|
|
19
|
+
radius: VariantMap<"sm" | "md" | "lg" | "none" | "full", {
|
|
20
|
+
item: string;
|
|
21
|
+
prev: string;
|
|
22
|
+
next: string;
|
|
23
|
+
}>;
|
|
24
|
+
}, {
|
|
25
|
+
root: string;
|
|
26
|
+
list: string;
|
|
27
|
+
item: string;
|
|
28
|
+
prev: string;
|
|
29
|
+
next: string;
|
|
30
|
+
ellipsis: string;
|
|
31
|
+
}, undefined, {
|
|
32
|
+
size: VariantMap<"sm" | "md" | "lg", {
|
|
33
|
+
item: string;
|
|
34
|
+
prev: string;
|
|
35
|
+
next: string;
|
|
36
|
+
ellipsis: string;
|
|
37
|
+
}>;
|
|
38
|
+
radius: VariantMap<"sm" | "md" | "lg" | "none" | "full", {
|
|
39
|
+
item: string;
|
|
40
|
+
prev: string;
|
|
41
|
+
next: string;
|
|
42
|
+
}>;
|
|
43
|
+
}, {
|
|
44
|
+
root: string;
|
|
45
|
+
list: string;
|
|
46
|
+
item: string;
|
|
47
|
+
prev: string;
|
|
48
|
+
next: string;
|
|
49
|
+
ellipsis: string;
|
|
50
|
+
}, import("tailwind-variants").TVReturnTypeLike<{
|
|
51
|
+
size: VariantMap<"sm" | "md" | "lg", {
|
|
52
|
+
item: string;
|
|
53
|
+
prev: string;
|
|
54
|
+
next: string;
|
|
55
|
+
ellipsis: string;
|
|
56
|
+
}>;
|
|
57
|
+
radius: VariantMap<"sm" | "md" | "lg" | "none" | "full", {
|
|
58
|
+
item: string;
|
|
59
|
+
prev: string;
|
|
60
|
+
next: string;
|
|
61
|
+
}>;
|
|
62
|
+
}, {
|
|
63
|
+
root: string;
|
|
64
|
+
list: string;
|
|
65
|
+
item: string;
|
|
66
|
+
prev: string;
|
|
67
|
+
next: string;
|
|
68
|
+
ellipsis: string;
|
|
69
|
+
}>>;
|
|
70
|
+
type PaginationStyleProps = Parameters<typeof paginationStyles>[0];
|
|
71
|
+
//#endregion
|
|
72
|
+
export { PaginationStyleProps, paginationStyles };
|
|
73
|
+
//# sourceMappingURL=pagination.styles.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.styles.d.mts","names":[],"sources":["../../src/pagination/pagination.styles.ts"],"mappings":";;;;;;;;;;;cAgGa,8CAAgB;;IA1DY;IAAc;IAAc;IAAkB;;;IAqB1C;IAAc;IAAc;;;;;;;;;;;IArBhC;IAAc;IAAc;IAAkB;;;IAqB1C;IAAc;IAAc;;;;;;;;;;;IArBhC;IAAc;IAAc;IAAkB;;;IAqB1C;IAAc;IAAc;;;;;;;;;;KA2C7D,uBAAuB,kBAAkB"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { disabledState, focusRing } from "../styles/focus-ring.mjs";
|
|
2
|
+
import { tv } from "tailwind-variants";
|
|
3
|
+
//#region src/pagination/pagination.styles.ts
|
|
4
|
+
/**
|
|
5
|
+
* ページ番号と前後のボタンに共通の面。**数字だけを並べ、面を持たない。**
|
|
6
|
+
* 現在地は下辺の 1px の線で示す(塗らない。Raster は線と余白で階層を作る)。
|
|
7
|
+
*/
|
|
8
|
+
const cell = [
|
|
9
|
+
"inline-flex items-center justify-center",
|
|
10
|
+
"text-[var(--novi-color-fg)] tabular-nums",
|
|
11
|
+
"border-b border-transparent",
|
|
12
|
+
"outline-none",
|
|
13
|
+
"hover:bg-[var(--novi-color-subtle)]",
|
|
14
|
+
"aria-[current=page]:font-medium aria-[current=page]:border-[var(--novi-color-fg)]",
|
|
15
|
+
"transition-[background-color,border-color]",
|
|
16
|
+
"duration-[var(--novi-duration-fast)] ease-[var(--novi-ease-standard)]",
|
|
17
|
+
focusRing,
|
|
18
|
+
disabledState
|
|
19
|
+
].join(" ");
|
|
20
|
+
/**
|
|
21
|
+
* Pagination のスタイル定義。
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* import { paginationStyles } from '@novi-ui/raster'
|
|
25
|
+
* import { tv } from 'tailwind-variants'
|
|
26
|
+
*
|
|
27
|
+
* const myPagination = tv({ extend: paginationStyles, slots: { list: 'gap-2' } })
|
|
28
|
+
*/
|
|
29
|
+
const paginationStyles = tv({
|
|
30
|
+
slots: {
|
|
31
|
+
root: "inline-flex",
|
|
32
|
+
list: "flex items-center gap-1 list-none m-0 p-0",
|
|
33
|
+
item: cell,
|
|
34
|
+
prev: cell,
|
|
35
|
+
next: cell,
|
|
36
|
+
ellipsis: "inline-flex items-center justify-center text-[var(--novi-color-muted)] select-none"
|
|
37
|
+
},
|
|
38
|
+
variants: {
|
|
39
|
+
size: {
|
|
40
|
+
sm: {
|
|
41
|
+
item: "h-8 min-w-8 px-1.5 text-[length:var(--novi-text-sm)]",
|
|
42
|
+
prev: "h-8 min-w-8 px-1.5 text-[length:var(--novi-text-sm)]",
|
|
43
|
+
next: "h-8 min-w-8 px-1.5 text-[length:var(--novi-text-sm)]",
|
|
44
|
+
ellipsis: "h-8 min-w-8 text-[length:var(--novi-text-sm)]"
|
|
45
|
+
},
|
|
46
|
+
md: {
|
|
47
|
+
item: "h-10 min-w-10 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-base)]",
|
|
48
|
+
prev: "h-10 min-w-10 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-base)]",
|
|
49
|
+
next: "h-10 min-w-10 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-base)]",
|
|
50
|
+
ellipsis: "h-10 min-w-10 text-[length:var(--novi-text-base)]"
|
|
51
|
+
},
|
|
52
|
+
lg: {
|
|
53
|
+
item: "h-12 min-w-12 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-base)]",
|
|
54
|
+
prev: "h-12 min-w-12 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-base)]",
|
|
55
|
+
next: "h-12 min-w-12 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-base)]",
|
|
56
|
+
ellipsis: "h-12 min-w-12 text-[length:var(--novi-text-base)]"
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
radius: {
|
|
60
|
+
none: {
|
|
61
|
+
item: "rounded-[var(--novi-radius-none)]",
|
|
62
|
+
prev: "rounded-[var(--novi-radius-none)]",
|
|
63
|
+
next: "rounded-[var(--novi-radius-none)]"
|
|
64
|
+
},
|
|
65
|
+
sm: {
|
|
66
|
+
item: "rounded-[var(--novi-radius-sm)]",
|
|
67
|
+
prev: "rounded-[var(--novi-radius-sm)]",
|
|
68
|
+
next: "rounded-[var(--novi-radius-sm)]"
|
|
69
|
+
},
|
|
70
|
+
md: {
|
|
71
|
+
item: "rounded-[var(--novi-radius-md)]",
|
|
72
|
+
prev: "rounded-[var(--novi-radius-md)]",
|
|
73
|
+
next: "rounded-[var(--novi-radius-md)]"
|
|
74
|
+
},
|
|
75
|
+
lg: {
|
|
76
|
+
item: "rounded-[var(--novi-radius-lg)]",
|
|
77
|
+
prev: "rounded-[var(--novi-radius-lg)]",
|
|
78
|
+
next: "rounded-[var(--novi-radius-lg)]"
|
|
79
|
+
},
|
|
80
|
+
full: {
|
|
81
|
+
item: "rounded-[var(--novi-radius-full)]",
|
|
82
|
+
prev: "rounded-[var(--novi-radius-full)]",
|
|
83
|
+
next: "rounded-[var(--novi-radius-full)]"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
defaultVariants: {
|
|
88
|
+
size: "md",
|
|
89
|
+
radius: "md"
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
//#endregion
|
|
93
|
+
export { paginationStyles };
|
|
94
|
+
|
|
95
|
+
//# sourceMappingURL=pagination.styles.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.styles.mjs","names":[],"sources":["../../src/pagination/pagination.styles.ts"],"sourcesContent":["import type {\n NoviRadius,\n NoviSize,\n paginationRequiredSlots,\n paginationSlots,\n SlotMap,\n VariantMap,\n} from '@novi-ui/core'\nimport { tv } from 'tailwind-variants'\nimport { disabledState, focusRing } from '../styles/focus-ring'\n\n/**\n * ページ番号と前後のボタンに共通の面。**数字だけを並べ、面を持たない。**\n * 現在地は下辺の 1px の線で示す(塗らない。Raster は線と余白で階層を作る)。\n */\nconst cell = [\n 'inline-flex items-center justify-center',\n 'text-[var(--novi-color-fg)] tabular-nums',\n 'border-b border-transparent',\n 'outline-none',\n 'hover:bg-[var(--novi-color-subtle)]',\n 'aria-[current=page]:font-medium aria-[current=page]:border-[var(--novi-color-fg)]',\n 'transition-[background-color,border-color]',\n 'duration-[var(--novi-duration-fast)] ease-[var(--novi-ease-standard)]',\n focusRing,\n disabledState,\n].join(' ')\n\nconst slots = {\n root: 'inline-flex',\n list: 'flex items-center gap-1 list-none m-0 p-0',\n item: cell,\n prev: cell,\n next: cell,\n ellipsis: 'inline-flex items-center justify-center text-[var(--novi-color-muted)] select-none',\n} satisfies SlotMap<typeof paginationSlots, (typeof paginationRequiredSlots)[number]>\n\n/** 高さは Button と揃える。32 / 40 / 48px。幅は最小で正方形 */\nconst size: VariantMap<NoviSize, { item: string; prev: string; next: string; ellipsis: string }> = {\n sm: {\n item: 'h-8 min-w-8 px-1.5 text-[length:var(--novi-text-sm)]',\n prev: 'h-8 min-w-8 px-1.5 text-[length:var(--novi-text-sm)]',\n next: 'h-8 min-w-8 px-1.5 text-[length:var(--novi-text-sm)]',\n ellipsis: 'h-8 min-w-8 text-[length:var(--novi-text-sm)]',\n },\n md: {\n item: 'h-10 min-w-10 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-base)]',\n prev: 'h-10 min-w-10 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-base)]',\n next: 'h-10 min-w-10 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-base)]',\n ellipsis: 'h-10 min-w-10 text-[length:var(--novi-text-base)]',\n },\n lg: {\n item: 'h-12 min-w-12 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-base)]',\n prev: 'h-12 min-w-12 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-base)]',\n next: 'h-12 min-w-12 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-base)]',\n ellipsis: 'h-12 min-w-12 text-[length:var(--novi-text-base)]',\n },\n}\n\nconst radius: VariantMap<NoviRadius, { item: string; prev: string; next: string }> = {\n none: {\n item: 'rounded-[var(--novi-radius-none)]',\n prev: 'rounded-[var(--novi-radius-none)]',\n next: 'rounded-[var(--novi-radius-none)]',\n },\n sm: {\n item: 'rounded-[var(--novi-radius-sm)]',\n prev: 'rounded-[var(--novi-radius-sm)]',\n next: 'rounded-[var(--novi-radius-sm)]',\n },\n md: {\n item: 'rounded-[var(--novi-radius-md)]',\n prev: 'rounded-[var(--novi-radius-md)]',\n next: 'rounded-[var(--novi-radius-md)]',\n },\n lg: {\n item: 'rounded-[var(--novi-radius-lg)]',\n prev: 'rounded-[var(--novi-radius-lg)]',\n next: 'rounded-[var(--novi-radius-lg)]',\n },\n full: {\n item: 'rounded-[var(--novi-radius-full)]',\n prev: 'rounded-[var(--novi-radius-full)]',\n next: 'rounded-[var(--novi-radius-full)]',\n },\n}\n\n/**\n * Pagination のスタイル定義。\n *\n * @example\n * import { paginationStyles } from '@novi-ui/raster'\n * import { tv } from 'tailwind-variants'\n *\n * const myPagination = tv({ extend: paginationStyles, slots: { list: 'gap-2' } })\n */\nexport const paginationStyles = tv({\n slots,\n variants: { size, radius },\n defaultVariants: { size: 'md', radius: 'md' },\n})\n\nexport type PaginationStyleProps = Parameters<typeof paginationStyles>[0]\n"],"mappings":";;;;;;;AAeA,MAAM,OAAO;CACX;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC,CAAC,KAAK,GAAG;;;;;;;;;;AAsEV,MAAa,mBAAmB,GAAG;CACjC;EApEA,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,UAAU;CA+DV;CACA,UAAU;EAAE;GA3DZ,IAAI;IACF,MAAM;IACN,MAAM;IACN,MAAM;IACN,UAAU;GACZ;GACA,IAAI;IACF,MAAM;IACN,MAAM;IACN,MAAM;IACN,UAAU;GACZ;GACA,IAAI;IACF,MAAM;IACN,MAAM;IACN,MAAM;IACN,UAAU;GACZ;EA0CY;EAAM;GAtClB,MAAM;IACJ,MAAM;IACN,MAAM;IACN,MAAM;GACR;GACA,IAAI;IACF,MAAM;IACN,MAAM;IACN,MAAM;GACR;GACA,IAAI;IACF,MAAM;IACN,MAAM;IACN,MAAM;GACR;GACA,IAAI;IACF,MAAM;IACN,MAAM;IACN,MAAM;GACR;GACA,MAAM;IACJ,MAAM;IACN,MAAM;IACN,MAAM;GACR;EAckB;CAAO;CACzB,iBAAiB;EAAE,MAAM;EAAM,QAAQ;CAAK;AAC9C,CAAC"}
|
package/dist/select/select.d.mts
CHANGED
|
@@ -19,7 +19,7 @@ declare function SelectItem({ id, isDisabled, children, className }: SelectItemP
|
|
|
19
19
|
* 一覧から1つ選ぶ。矢印キーで移動、Escape で閉じてトリガーへフォーカスが戻る。
|
|
20
20
|
*
|
|
21
21
|
* トリガーは `<button>` で編集可能要素ではないため IME の変換は発生しない。
|
|
22
|
-
* テキスト入力を伴う選択が必要な場合は ComboBox
|
|
22
|
+
* テキスト入力を伴う選択が必要な場合は ComboBox を使う。
|
|
23
23
|
*
|
|
24
24
|
* @example
|
|
25
25
|
* <Select label="都道府県" selectedKey={pref} onSelectionChange={setPref}>
|
package/dist/select/select.mjs
CHANGED
|
@@ -38,7 +38,7 @@ function SelectItem({ id, isDisabled, children, className }) {
|
|
|
38
38
|
* 一覧から1つ選ぶ。矢印キーで移動、Escape で閉じてトリガーへフォーカスが戻る。
|
|
39
39
|
*
|
|
40
40
|
* トリガーは `<button>` で編集可能要素ではないため IME の変換は発生しない。
|
|
41
|
-
* テキスト入力を伴う選択が必要な場合は ComboBox
|
|
41
|
+
* テキスト入力を伴う選択が必要な場合は ComboBox を使う。
|
|
42
42
|
*
|
|
43
43
|
* @example
|
|
44
44
|
* <Select label="都道府県" selectedKey={pref} onSelectionChange={setPref}>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"select.mjs","names":["Select","RACSelect"],"sources":["../../src/select/select.tsx"],"sourcesContent":["'use client'\n\nimport type { SelectProps } from '@novi-ui/core'\nimport type { ReactNode } from 'react'\nimport {\n Button,\n FieldError,\n Label,\n ListBox,\n ListBoxItem,\n Popover,\n Select as RACSelect,\n SelectValue,\n Text,\n} from 'react-aria-components'\nimport { selectStyles } from './select.styles'\n\n/** 開閉を示す記号。三角矢印を回転させず、上下の線で描く(Raster の規律)。 */\nfunction TriggerIcon() {\n return (\n <svg viewBox=\"0 0 16 16\" width=\"0.75em\" height=\"0.75em\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M4 6.5l4 4 4-4\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n </svg>\n )\n}\n\nexport interface SelectItemProps {\n /** 選択値。`onSelectionChange` に渡る */\n id: string\n isDisabled?: boolean\n children?: ReactNode\n className?: string\n}\n\n/**\n * Select の選択肢。`Select` の子として置く。\n *\n * @example\n * <SelectItem id=\"tokyo\">東京都</SelectItem>\n */\nexport function SelectItem({ id, isDisabled, children, className }: SelectItemProps) {\n return (\n <ListBoxItem\n id={id}\n isDisabled={isDisabled}\n textValue={typeof children === 'string' ? children : undefined}\n data-slot=\"option\"\n className={className ?? selectStyles().option()}\n >\n {children}\n </ListBoxItem>\n )\n}\n\n/**\n * 一覧から1つ選ぶ。矢印キーで移動、Escape で閉じてトリガーへフォーカスが戻る。\n *\n * トリガーは `<button>` で編集可能要素ではないため IME の変換は発生しない。\n * テキスト入力を伴う選択が必要な場合は ComboBox
|
|
1
|
+
{"version":3,"file":"select.mjs","names":["Select","RACSelect"],"sources":["../../src/select/select.tsx"],"sourcesContent":["'use client'\n\nimport type { SelectProps } from '@novi-ui/core'\nimport type { ReactNode } from 'react'\nimport {\n Button,\n FieldError,\n Label,\n ListBox,\n ListBoxItem,\n Popover,\n Select as RACSelect,\n SelectValue,\n Text,\n} from 'react-aria-components'\nimport { selectStyles } from './select.styles'\n\n/** 開閉を示す記号。三角矢印を回転させず、上下の線で描く(Raster の規律)。 */\nfunction TriggerIcon() {\n return (\n <svg viewBox=\"0 0 16 16\" width=\"0.75em\" height=\"0.75em\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M4 6.5l4 4 4-4\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n </svg>\n )\n}\n\nexport interface SelectItemProps {\n /** 選択値。`onSelectionChange` に渡る */\n id: string\n isDisabled?: boolean\n children?: ReactNode\n className?: string\n}\n\n/**\n * Select の選択肢。`Select` の子として置く。\n *\n * @example\n * <SelectItem id=\"tokyo\">東京都</SelectItem>\n */\nexport function SelectItem({ id, isDisabled, children, className }: SelectItemProps) {\n return (\n <ListBoxItem\n id={id}\n isDisabled={isDisabled}\n textValue={typeof children === 'string' ? children : undefined}\n data-slot=\"option\"\n className={className ?? selectStyles().option()}\n >\n {children}\n </ListBoxItem>\n )\n}\n\n/**\n * 一覧から1つ選ぶ。矢印キーで移動、Escape で閉じてトリガーへフォーカスが戻る。\n *\n * トリガーは `<button>` で編集可能要素ではないため IME の変換は発生しない。\n * テキスト入力を伴う選択が必要な場合は ComboBox を使う。\n *\n * @example\n * <Select label=\"都道府県\" selectedKey={pref} onSelectionChange={setPref}>\n * <SelectItem id=\"tokyo\">東京都</SelectItem>\n * <SelectItem id=\"osaka\">大阪府</SelectItem>\n * </Select>\n */\nexport function Select({\n variant,\n size,\n radius,\n label,\n placeholder = '選択してください',\n description,\n errorMessage,\n name,\n selectedKey,\n defaultSelectedKey,\n onSelectionChange,\n isOpen,\n defaultOpen,\n onOpenChange,\n isDisabled,\n isRequired,\n isInvalid,\n children,\n className,\n classNames,\n id,\n}: SelectProps) {\n const s = selectStyles({ variant, size, radius })\n\n return (\n <RACSelect\n id={id}\n name={name}\n selectedKey={selectedKey}\n defaultSelectedKey={defaultSelectedKey}\n onSelectionChange={(key) => onSelectionChange?.(key === null ? null : String(key))}\n isOpen={isOpen}\n defaultOpen={defaultOpen}\n onOpenChange={onOpenChange}\n isDisabled={isDisabled}\n isRequired={isRequired}\n isInvalid={isInvalid}\n placeholder={placeholder}\n data-slot=\"root\"\n // trigger 側から invalid 状態を参照するために group を付ける\n className={`group ${s.root({ class: [className, classNames?.root] })}`}\n >\n {label !== undefined && (\n <Label data-slot=\"label\" className={s.label({ class: classNames?.label })}>\n {label}\n </Label>\n )}\n\n <Button data-slot=\"trigger\" className={s.trigger({ class: classNames?.trigger })}>\n <SelectValue data-slot=\"value\" className={s.value({ class: classNames?.value })} />\n <span data-slot=\"icon\" className={s.icon({ class: classNames?.icon })}>\n <TriggerIcon />\n </span>\n </Button>\n\n {description !== undefined && (\n <Text\n slot=\"description\"\n data-slot=\"description\"\n className={s.description({ class: classNames?.description })}\n >\n {description}\n </Text>\n )}\n\n <FieldError\n data-slot=\"errorMessage\"\n className={s.errorMessage({ class: classNames?.errorMessage })}\n >\n {errorMessage}\n </FieldError>\n\n <Popover data-slot=\"popover\" className={s.popover({ class: classNames?.popover })}>\n <ListBox data-slot=\"listbox\" className={s.listbox({ class: classNames?.listbox })}>\n {children}\n </ListBox>\n </Popover>\n </RACSelect>\n )\n}\n"],"mappings":";;;;;;AAkBA,SAAS,cAAc;CACrB,OACE,oBAAC,OAAD;EAAK,SAAQ;EAAY,OAAM;EAAS,QAAO;EAAS,MAAK;EAAO,eAAY;EAC9E,UAAA,oBAAC,QAAD;GAAM,GAAE;GAAiB,QAAO;GAAe,aAAY;EAAO,CAAA;CAC/D,CAAA;AAET;;;;;;;AAgBA,SAAgB,WAAW,EAAE,IAAI,YAAY,UAAU,aAA8B;CACnF,OACE,oBAAC,aAAD;EACM;EACQ;EACZ,WAAW,OAAO,aAAa,WAAW,WAAW,KAAA;EACrD,aAAU;EACV,WAAW,aAAa,aAAa,CAAC,CAAC,OAAO;EAE7C;CACU,CAAA;AAEjB;;;;;;;;;;;;;AAcA,SAAgBA,SAAO,EACrB,SACA,MACA,QACA,OACA,cAAc,YACd,aACA,cACA,MACA,aACA,oBACA,mBACA,QACA,aACA,cACA,YACA,YACA,WACA,UACA,WACA,YACA,MACc;CACd,MAAM,IAAI,aAAa;EAAE;EAAS;EAAM;CAAO,CAAC;CAEhD,OACE,qBAACC,QAAD;EACM;EACE;EACO;EACO;EACpB,oBAAoB,QAAQ,oBAAoB,QAAQ,OAAO,OAAO,OAAO,GAAG,CAAC;EACzE;EACK;EACC;EACF;EACA;EACD;EACE;EACb,aAAU;EAEV,WAAW,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,WAAW,YAAY,IAAI,EAAE,CAAC;EAfrE,UAAA;GAiBG,UAAU,KAAA,KACT,oBAAC,OAAD;IAAO,aAAU;IAAQ,WAAW,EAAE,MAAM,EAAE,OAAO,YAAY,MAAM,CAAC;IACrE,UAAA;GACI,CAAA;GAGT,qBAAC,QAAD;IAAQ,aAAU;IAAU,WAAW,EAAE,QAAQ,EAAE,OAAO,YAAY,QAAQ,CAAC;IAA/E,UAAA,CACE,oBAAC,aAAD;KAAa,aAAU;KAAQ,WAAW,EAAE,MAAM,EAAE,OAAO,YAAY,MAAM,CAAC;IAAI,CAAA,GAClF,oBAAC,QAAD;KAAM,aAAU;KAAO,WAAW,EAAE,KAAK,EAAE,OAAO,YAAY,KAAK,CAAC;KAClE,UAAA,oBAAC,aAAD,CAAc,CAAA;IACV,CAAA,CACA;;GAEP,gBAAgB,KAAA,KACf,oBAAC,MAAD;IACE,MAAK;IACL,aAAU;IACV,WAAW,EAAE,YAAY,EAAE,OAAO,YAAY,YAAY,CAAC;IAE1D,UAAA;GACG,CAAA;GAGR,oBAAC,YAAD;IACE,aAAU;IACV,WAAW,EAAE,aAAa,EAAE,OAAO,YAAY,aAAa,CAAC;IAE5D,UAAA;GACS,CAAA;GAEZ,oBAAC,SAAD;IAAS,aAAU;IAAU,WAAW,EAAE,QAAQ,EAAE,OAAO,YAAY,QAAQ,CAAC;IAC9E,UAAA,oBAAC,SAAD;KAAS,aAAU;KAAU,WAAW,EAAE,QAAQ,EAAE,OAAO,YAAY,QAAQ,CAAC;KAC7E;IACM,CAAA;GACF,CAAA;EACA;;AAEf"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { Table, TableBody, TableBodyProps, TableCell, TableCellProps, TableColumn, TableColumnProps, TableHeader, TableHeaderProps, TableRow, TableRowProps } from "./table.mjs";
|
|
2
|
+
import { TableStyleProps, tableStyles } from "./table.styles.mjs";
|
|
3
|
+
export { Table, TableBody, type TableBodyProps, TableCell, type TableCellProps, TableColumn, type TableColumnProps, TableHeader, type TableHeaderProps, TableRow, type TableRowProps, type TableStyleProps, tableStyles };
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import { TableProps } from "@novi-ui/core";
|
|
3
|
+
//#region src/table/table.d.ts
|
|
4
|
+
interface TableHeaderProps {
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 見出し行。`TableColumn` を並べる。
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* <TableHeader>
|
|
13
|
+
* <TableColumn id="name" isRowHeader>商品名</TableColumn>
|
|
14
|
+
* </TableHeader>
|
|
15
|
+
*/
|
|
16
|
+
declare function TableHeader({ children, className }: TableHeaderProps): import("react").JSX.Element;
|
|
17
|
+
interface TableColumnProps {
|
|
18
|
+
/** 列の id。`sortDescriptor.column` に入る */
|
|
19
|
+
id: string;
|
|
20
|
+
/** この列で並べ替えられる。見出しが押せるようになり `aria-sort` が付く */
|
|
21
|
+
allowsSorting?: boolean;
|
|
22
|
+
/** 行の名前になる列。少なくとも 1 列に付ける */
|
|
23
|
+
isRowHeader?: boolean;
|
|
24
|
+
/** 金額や数量は `end`(右寄せ) */
|
|
25
|
+
align?: 'start' | 'end';
|
|
26
|
+
children?: ReactNode;
|
|
27
|
+
className?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 見出しのセル。
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* <TableColumn id="amount" allowsSorting align="end">金額</TableColumn>
|
|
34
|
+
*/
|
|
35
|
+
declare function TableColumn({ id, allowsSorting, isRowHeader, align, children, className }: TableColumnProps): import("react").JSX.Element;
|
|
36
|
+
interface TableBodyProps {
|
|
37
|
+
children?: ReactNode;
|
|
38
|
+
/** 行が 0 件のときに本体へ出す内容 */
|
|
39
|
+
renderEmptyState?: () => ReactNode;
|
|
40
|
+
className?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 本体。`TableRow` を並べる。行が無いときは `renderEmptyState` の内容が出る。
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* <TableBody renderEmptyState={() => '該当する注文はありません'}>
|
|
47
|
+
* {rows}
|
|
48
|
+
* </TableBody>
|
|
49
|
+
*/
|
|
50
|
+
declare function TableBody({ children, renderEmptyState, className }: TableBodyProps): import("react").JSX.Element;
|
|
51
|
+
interface TableRowProps {
|
|
52
|
+
/** 行の id。選択と `onRowAction` に渡る */
|
|
53
|
+
id: string;
|
|
54
|
+
isDisabled?: boolean;
|
|
55
|
+
children?: ReactNode;
|
|
56
|
+
className?: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 行。`TableCell` を列の数だけ並べる。
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* <TableRow id="1042">
|
|
63
|
+
* <TableCell>#1042</TableCell>
|
|
64
|
+
* </TableRow>
|
|
65
|
+
*/
|
|
66
|
+
declare function TableRow({ id, isDisabled, children, className }: TableRowProps): import("react").JSX.Element;
|
|
67
|
+
interface TableCellProps {
|
|
68
|
+
/** 金額や数量は `end`(右寄せ)。見出しと揃える */
|
|
69
|
+
align?: 'start' | 'end';
|
|
70
|
+
children?: ReactNode;
|
|
71
|
+
className?: string;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* セル。
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* <TableCell align="end">¥12,800</TableCell>
|
|
78
|
+
*/
|
|
79
|
+
declare function TableCell({ align, children, className }: TableCellProps): import("react").JSX.Element;
|
|
80
|
+
/**
|
|
81
|
+
* 一覧を行と列で見せる。横罫だけで組み、列の揃えと余白で読ませる
|
|
82
|
+
* (Tactile は行に面と余白、Flatlay は縦横の罫線の帳票)。
|
|
83
|
+
*
|
|
84
|
+
* 行の選択は行そのものを押す(チェックボックスは出さない)。
|
|
85
|
+
* 狭い画面では表そのものが横にスクロールする。`overflow-x-auto` の枠で包むこと。
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* <Table aria-label="注文一覧" sortDescriptor={sort} onSortChange={setSort}>
|
|
89
|
+
* <TableHeader>
|
|
90
|
+
* <TableColumn id="no" isRowHeader>注文番号</TableColumn>
|
|
91
|
+
* <TableColumn id="amount" allowsSorting align="end">金額</TableColumn>
|
|
92
|
+
* </TableHeader>
|
|
93
|
+
* <TableBody>
|
|
94
|
+
* <TableRow id="1042">
|
|
95
|
+
* <TableCell>#1042</TableCell>
|
|
96
|
+
* <TableCell align="end">¥12,800</TableCell>
|
|
97
|
+
* </TableRow>
|
|
98
|
+
* </TableBody>
|
|
99
|
+
* </Table>
|
|
100
|
+
*/
|
|
101
|
+
declare function Table({ 'aria-label': ariaLabel, size, sortDescriptor, onSortChange, selectionMode, selectedKeys, defaultSelectedKeys, onSelectionChange, disabledKeys, onRowAction, children, className, classNames }: TableProps): import("react").JSX.Element;
|
|
102
|
+
//#endregion
|
|
103
|
+
export { Table, TableBody, TableBodyProps, TableCell, TableCellProps, TableColumn, TableColumnProps, TableHeader, TableHeaderProps, TableRow, TableRowProps };
|
|
104
|
+
//# sourceMappingURL=table.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"table.d.mts","names":[],"sources":["../../src/table/table.tsx"],"mappings":";;;UA0CiB;EACf,WAAW;EACX;;;;;;;;;;iBAWc,cAAc,UAAU,aAAa,mCAAgB,IAAA;UAYpD;;EAEf;;EAEA;;EAEA;;EAEA;EACA,WAAW;EACX;;;;;;;;iBASc,cACd,IACA,eACA,aACA,OACA,UACA,aACC,mCAAgB,IAAA;UAwBF;EACf,WAAW;;EAEX,yBAAyB;EACzB;;;;;;;;;;iBAWc,YAAY,UAAU,kBAAkB,aAAa,iCAAc,IAAA;UAqBlE;;EAEf;EACA;EACA,WAAW;EACX;;;;;;;;;;iBAWc,WAAW,IAAI,YAAY,UAAU,aAAa,gCAAa,IAAA;UAc9D;;EAEf;EACA,WAAW;EACX;;;;;;;;iBASc,YAAY,OAAiB,UAAU,aAAa,iCAAc,IAAA;;;;;;;;;;;;;;;;;;;;;;iBAmClE,sBACA,WACd,MACA,gBACA,cACA,eACA,cACA,qBACA,mBACA,cACA,aACA,UACA,WACA,cACC,6BAAU,IAAA"}
|