@novi-ui/tactile 0.4.0 → 0.5.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.
Files changed (53) hide show
  1. package/dist/combo-box/combo-box.d.mts +34 -0
  2. package/dist/combo-box/combo-box.d.mts.map +1 -0
  3. package/dist/combo-box/combo-box.mjs +127 -0
  4. package/dist/combo-box/combo-box.mjs.map +1 -0
  5. package/dist/combo-box/combo-box.styles.d.mts +88 -0
  6. package/dist/combo-box/combo-box.styles.d.mts.map +1 -0
  7. package/dist/combo-box/combo-box.styles.mjs +115 -0
  8. package/dist/combo-box/combo-box.styles.mjs.map +1 -0
  9. package/dist/combo-box/index.d.mts +3 -0
  10. package/dist/date-picker/date-picker.d.mts +16 -0
  11. package/dist/date-picker/date-picker.d.mts.map +1 -0
  12. package/dist/date-picker/date-picker.mjs +162 -0
  13. package/dist/date-picker/date-picker.mjs.map +1 -0
  14. package/dist/date-picker/date-picker.styles.d.mts +103 -0
  15. package/dist/date-picker/date-picker.styles.d.mts.map +1 -0
  16. package/dist/date-picker/date-picker.styles.mjs +134 -0
  17. package/dist/date-picker/date-picker.styles.mjs.map +1 -0
  18. package/dist/date-picker/index.d.mts +3 -0
  19. package/dist/index.d.mts +16 -1
  20. package/dist/index.mjs +11 -1
  21. package/dist/menu/menu.styles.d.mts +6 -6
  22. package/dist/number-field/index.d.mts +3 -0
  23. package/dist/number-field/number-field.d.mts +16 -0
  24. package/dist/number-field/number-field.d.mts.map +1 -0
  25. package/dist/number-field/number-field.mjs +117 -0
  26. package/dist/number-field/number-field.mjs.map +1 -0
  27. package/dist/number-field/number-field.styles.d.mts +76 -0
  28. package/dist/number-field/number-field.styles.d.mts.map +1 -0
  29. package/dist/number-field/number-field.styles.mjs +96 -0
  30. package/dist/number-field/number-field.styles.mjs.map +1 -0
  31. package/dist/pagination/index.d.mts +3 -0
  32. package/dist/pagination/pagination.d.mts +14 -0
  33. package/dist/pagination/pagination.d.mts.map +1 -0
  34. package/dist/pagination/pagination.mjs +100 -0
  35. package/dist/pagination/pagination.mjs.map +1 -0
  36. package/dist/pagination/pagination.styles.d.mts +73 -0
  37. package/dist/pagination/pagination.styles.d.mts.map +1 -0
  38. package/dist/pagination/pagination.styles.mjs +100 -0
  39. package/dist/pagination/pagination.styles.mjs.map +1 -0
  40. package/dist/popover/popover.styles.d.mts +3 -3
  41. package/dist/select/select.d.mts +1 -1
  42. package/dist/select/select.mjs +1 -1
  43. package/dist/select/select.mjs.map +1 -1
  44. package/dist/table/index.d.mts +3 -0
  45. package/dist/table/table.d.mts +104 -0
  46. package/dist/table/table.d.mts.map +1 -0
  47. package/dist/table/table.mjs +172 -0
  48. package/dist/table/table.mjs.map +1 -0
  49. package/dist/table/table.styles.d.mts +58 -0
  50. package/dist/table/table.styles.d.mts.map +1 -0
  51. package/dist/table/table.styles.mjs +83 -0
  52. package/dist/table/table.styles.mjs.map +1 -0
  53. package/package.json +4 -3
@@ -0,0 +1,96 @@
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
+ /**
5
+ * 増減ボタン。**指で押す面**なので、枠の高さいっぱいの正方形にする(40 / 48 / 56px)。
6
+ * 入力欄の左右に置き、親指で届く位置に来る(Raster は右端に細く並べる)。
7
+ * 押した手応えは Button と同じ縮み(scale は押下にだけ許される)。
8
+ */
9
+ const stepper = [
10
+ "shrink-0 self-stretch aspect-square inline-flex items-center justify-center",
11
+ "text-[var(--novi-color-fg)]",
12
+ "bg-[var(--novi-color-subtle)]",
13
+ "outline-none",
14
+ "data-[pressed]:scale-[0.97]",
15
+ "motion-reduce:data-[pressed]:scale-100",
16
+ "data-[focus-visible]:bg-[var(--novi-color-border)]",
17
+ "data-[disabled]:opacity-40 data-[disabled]:cursor-default",
18
+ "transition-[background-color,transform]",
19
+ "duration-[var(--novi-duration-fast)] ease-[var(--novi-ease-standard)]"
20
+ ].join(" ");
21
+ const slots = {
22
+ root: "flex flex-col gap-1.5",
23
+ label: "text-[length:var(--novi-text-sm)] font-medium text-[var(--novi-color-fg)]",
24
+ inputWrapper: [
25
+ "text-[var(--novi-color-fg)]",
26
+ "flex items-center w-full overflow-hidden",
27
+ "bg-[var(--novi-color-surface)]",
28
+ "shadow-[var(--novi-shadow-sm)]",
29
+ "rounded-[var(--novi-radius-md)]",
30
+ "transition-[opacity,box-shadow]",
31
+ "duration-[var(--novi-duration-fast)] ease-[var(--novi-ease-standard)]",
32
+ "data-[invalid]:ring-1 data-[invalid]:ring-[var(--novi-color-danger)]",
33
+ focusRing,
34
+ disabledState
35
+ ].join(" "),
36
+ input: [
37
+ "w-full min-w-0 bg-transparent outline-none text-center",
38
+ "text-[var(--novi-color-fg)] tabular-nums",
39
+ "placeholder:text-[var(--novi-color-muted)]"
40
+ ].join(" "),
41
+ decrement: stepper,
42
+ increment: stepper,
43
+ description: "text-[length:var(--novi-text-sm)] text-[var(--novi-color-muted)]",
44
+ errorMessage: "text-[length:var(--novi-text-sm)] text-[var(--novi-color-danger)]"
45
+ };
46
+ /**
47
+ * NumberField のスタイル定義。
48
+ *
49
+ * @example
50
+ * import { numberFieldStyles } from '@novi-ui/tactile'
51
+ * import { tv } from 'tailwind-variants'
52
+ *
53
+ * const myField = tv({ extend: numberFieldStyles, slots: { input: 'text-left' } })
54
+ */
55
+ const numberFieldStyles = tv({
56
+ slots,
57
+ variants: {
58
+ variant: {
59
+ solid: { inputWrapper: "bg-[var(--novi-color-surface)] shadow-[var(--novi-shadow-sm)]" },
60
+ outline: { inputWrapper: "bg-transparent shadow-[var(--novi-shadow-none)] ring-1 ring-[var(--novi-color-border-strong)]" },
61
+ soft: { inputWrapper: "bg-[var(--novi-color-subtle)] shadow-[var(--novi-shadow-none)]" },
62
+ ghost: { inputWrapper: "bg-transparent shadow-[var(--novi-shadow-none)]" },
63
+ plain: { inputWrapper: "bg-transparent shadow-[var(--novi-shadow-none)] rounded-[var(--novi-radius-none)] border-b border-[var(--novi-color-border-strong)]" }
64
+ },
65
+ size: {
66
+ sm: {
67
+ inputWrapper: "h-10",
68
+ input: "px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-base)]"
69
+ },
70
+ md: {
71
+ inputWrapper: "h-12",
72
+ input: "px-[var(--novi-pad-control-x-md)] text-[length:var(--novi-text-base)]"
73
+ },
74
+ lg: {
75
+ inputWrapper: "h-14",
76
+ input: "px-[var(--novi-pad-control-x-lg)] text-[length:var(--novi-text-lg)]"
77
+ }
78
+ },
79
+ radius: {
80
+ none: { inputWrapper: "rounded-[var(--novi-radius-none)]" },
81
+ sm: { inputWrapper: "rounded-[var(--novi-radius-sm)]" },
82
+ md: { inputWrapper: "rounded-[var(--novi-radius-md)]" },
83
+ lg: { inputWrapper: "rounded-[var(--novi-radius-lg)]" },
84
+ full: { inputWrapper: "rounded-[var(--novi-radius-full)]" }
85
+ }
86
+ },
87
+ defaultVariants: {
88
+ variant: "outline",
89
+ size: "md",
90
+ radius: "md"
91
+ }
92
+ });
93
+ //#endregion
94
+ export { numberFieldStyles };
95
+
96
+ //# 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/**\n * 増減ボタン。**指で押す面**なので、枠の高さいっぱいの正方形にする(40 / 48 / 56px)。\n * 入力欄の左右に置き、親指で届く位置に来る(Raster は右端に細く並べる)。\n * 押した手応えは Button と同じ縮み(scale は押下にだけ許される)。\n */\nconst stepper = [\n 'shrink-0 self-stretch aspect-square inline-flex items-center justify-center',\n 'text-[var(--novi-color-fg)]',\n 'bg-[var(--novi-color-subtle)]',\n 'outline-none',\n 'data-[pressed]:scale-[0.97]',\n 'motion-reduce:data-[pressed]:scale-100',\n 'data-[focus-visible]:bg-[var(--novi-color-border)]',\n 'data-[disabled]:opacity-40 data-[disabled]:cursor-default',\n 'transition-[background-color,transform]',\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-surface)]',\n 'shadow-[var(--novi-shadow-sm)]',\n 'rounded-[var(--novi-radius-md)]',\n 'transition-[opacity,box-shadow]',\n 'duration-[var(--novi-duration-fast)] ease-[var(--novi-ease-standard)]',\n 'data-[invalid]:ring-1 data-[invalid]:ring-[var(--novi-color-danger)]',\n focusRing,\n disabledState,\n ].join(' '),\n input: [\n 'w-full min-w-0 bg-transparent outline-none text-center',\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-sm)] text-[var(--novi-color-muted)]',\n // 色だけに頼らずテキストを必ず伴う(WCAG 1.4.1)\n errorMessage: 'text-[length:var(--novi-text-sm)] text-[var(--novi-color-danger)]',\n} satisfies SlotMap<typeof numberFieldSlots, (typeof numberFieldRequiredSlots)[number]>\n\nconst variant: VariantMap<NoviVariant, { inputWrapper: string }> = {\n solid: { inputWrapper: 'bg-[var(--novi-color-surface)] shadow-[var(--novi-shadow-sm)]' },\n outline: {\n inputWrapper:\n 'bg-transparent shadow-[var(--novi-shadow-none)] ring-1 ring-[var(--novi-color-border-strong)]',\n },\n soft: { inputWrapper: 'bg-[var(--novi-color-subtle)] shadow-[var(--novi-shadow-none)]' },\n ghost: { inputWrapper: 'bg-transparent shadow-[var(--novi-shadow-none)]' },\n plain: {\n inputWrapper:\n 'bg-transparent shadow-[var(--novi-shadow-none)] rounded-[var(--novi-radius-none)] border-b border-[var(--novi-color-border-strong)]',\n },\n}\n\n/** 高さは Button / Input と揃える。40 / 48 / 56px。 */\nconst size: VariantMap<NoviSize, { inputWrapper: string; input: string }> = {\n sm: {\n inputWrapper: 'h-10',\n input: 'px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-base)]',\n },\n md: {\n inputWrapper: 'h-12',\n input: 'px-[var(--novi-pad-control-x-md)] text-[length:var(--novi-text-base)]',\n },\n lg: {\n inputWrapper: 'h-14',\n input: 'px-[var(--novi-pad-control-x-lg)] text-[length:var(--novi-text-lg)]',\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/tactile'\n * import { tv } from 'tailwind-variants'\n *\n * const myField = tv({ extend: numberFieldStyles, slots: { input: 'text-left' } })\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":";;;;;;;;AAiBA,MAAM,UAAU;CACd;CACA;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;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;;;;;;;;;;AAiDA,MAAa,oBAAoB,GAAG;CAClC;CACA,UAAU;EAAE;GAhDZ,OAAO,EAAE,cAAc,gEAAgE;GACvF,SAAS,EACP,cACE,gGACJ;GACA,MAAM,EAAE,cAAc,iEAAiE;GACvF,OAAO,EAAE,cAAc,kDAAkD;GACzE,OAAO,EACL,cACE,sIACJ;EAsCY;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,3 @@
1
+ import { Pagination } from "./pagination.mjs";
2
+ import { PaginationStyleProps, paginationStyles } from "./pagination.styles.mjs";
3
+ export { Pagination, type PaginationStyleProps, paginationStyles };
@@ -0,0 +1,14 @@
1
+ import { PaginationProps } from "@novi-ui/core";
2
+ //#region src/pagination/pagination.d.ts
3
+ /**
4
+ * 一覧のページを移動する。**押す面を持ち、現在地は primary で塗る**
5
+ * (Raster は数字だけを並べ、Flatlay は罫線で区切った枠を反転させる)。
6
+ * どの size でも 40px 以上の面で、親指で押せる。
7
+ *
8
+ * @example
9
+ * <Pagination total={10} page={page} onChange={setPage} />
10
+ */
11
+ declare function Pagination({ size, radius, total, page, defaultPage, onChange, siblingCount, boundaryCount, isDisabled, 'aria-label': ariaLabel, className, classNames, id }: PaginationProps): import("react").JSX.Element;
12
+ //#endregion
13
+ export { Pagination };
14
+ //# sourceMappingURL=pagination.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.d.mts","names":[],"sources":["../../src/pagination/pagination.tsx"],"mappings":";;;;;;;;;;iBA+BgB,aACd,MACA,QACA,OACA,MACA,aACA,UACA,cACA,eACA,0BACc,WACd,WACA,YACA,MACC,kCAAe,IAAA"}
@@ -0,0 +1,100 @@
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: "1em",
12
+ height: "1em",
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.75",
19
+ strokeLinecap: "round",
20
+ strokeLinejoin: "round"
21
+ })
22
+ });
23
+ }
24
+ /**
25
+ * 一覧のページを移動する。**押す面を持ち、現在地は primary で塗る**
26
+ * (Raster は数字だけを並べ、Flatlay は罫線で区切った枠を反転させる)。
27
+ * どの size でも 40px 以上の面で、親指で押せる。
28
+ *
29
+ * @example
30
+ * <Pagination total={10} page={page} onChange={setPage} />
31
+ */
32
+ function Pagination({ size, radius, total, page, defaultPage = 1, onChange, siblingCount, boundaryCount, isDisabled, "aria-label": ariaLabel = "ページ送り", className, classNames, id }) {
33
+ const s = paginationStyles({
34
+ size,
35
+ radius
36
+ });
37
+ const [internal, setInternal] = useState(defaultPage);
38
+ const clamp = (n) => Math.min(Math.max(n, 1), Math.max(total, 1));
39
+ const current = clamp(page ?? internal);
40
+ const go = (n) => {
41
+ const next = clamp(n);
42
+ if (next === current) return;
43
+ if (page === void 0) setInternal(next);
44
+ onChange?.(next);
45
+ };
46
+ const slots = paginationRange(current, total, {
47
+ siblingCount,
48
+ boundaryCount
49
+ });
50
+ const entries = slots.map((slot, i) => ({
51
+ slot,
52
+ key: slot === "ellipsis" ? `ellipsis-after-${slots[i - 1]}` : `page-${slot}`
53
+ }));
54
+ return /* @__PURE__ */ jsx("nav", {
55
+ id,
56
+ "aria-label": ariaLabel,
57
+ "data-slot": "root",
58
+ className: s.root({ class: [className, classNames?.root] }),
59
+ children: /* @__PURE__ */ jsxs("ul", {
60
+ "data-slot": "list",
61
+ className: s.list({ class: classNames?.list }),
62
+ children: [
63
+ /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(Button, {
64
+ "data-slot": "prev",
65
+ "aria-label": "前のページ",
66
+ isDisabled: isDisabled || current <= 1,
67
+ onPress: () => go(current - 1),
68
+ className: s.prev({ class: classNames?.prev }),
69
+ children: /* @__PURE__ */ jsx(ChevronIcon, { direction: "prev" })
70
+ }) }),
71
+ entries.map(({ slot, key }) => slot === "ellipsis" ? /* @__PURE__ */ jsx("li", {
72
+ "data-slot": "ellipsis",
73
+ "aria-hidden": "true",
74
+ className: s.ellipsis({ class: classNames?.ellipsis }),
75
+ children: "…"
76
+ }, key) : /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(Button, {
77
+ "data-slot": "item",
78
+ "aria-label": `${slot}ページ`,
79
+ "aria-current": slot === current ? "page" : void 0,
80
+ isDisabled,
81
+ onPress: () => go(slot),
82
+ className: s.item({ class: classNames?.item }),
83
+ children: slot
84
+ }) }, key)),
85
+ /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(Button, {
86
+ "data-slot": "next",
87
+ "aria-label": "次のページ",
88
+ isDisabled: isDisabled || current >= total,
89
+ onPress: () => go(current + 1),
90
+ className: s.next({ class: classNames?.next }),
91
+ children: /* @__PURE__ */ jsx(ChevronIcon, { direction: "next" })
92
+ }) })
93
+ ]
94
+ })
95
+ });
96
+ }
97
+ //#endregion
98
+ export { Pagination };
99
+
100
+ //# 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=\"1em\" height=\"1em\" fill=\"none\" aria-hidden=\"true\">\n <path\n d={d}\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n )\n}\n\n/**\n * 一覧のページを移動する。**押す面を持ち、現在地は primary で塗る**\n * (Raster は数字だけを並べ、Flatlay は罫線で区切った枠を反転させる)。\n * どの size でも 40px 以上の面で、親指で押せる。\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;EAAM,QAAO;EAAM,MAAK;EAAO,eAAY;EACxE,UAAA,oBAAC,QAAD;GACE,GAJI,cAAc,SAAS,mBAAmB;GAK9C,QAAO;GACP,aAAY;GACZ,eAAc;GACd,gBAAe;EAChB,CAAA;CACE,CAAA;AAET;;;;;;;;;AAUA,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/tactile'
8
+ * import { tv } from 'tailwind-variants'
9
+ *
10
+ * const myPagination = tv({ extend: paginationStyles, slots: { list: 'gap-3' } })
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":";;;;;;;;;;;cAqGa,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,100 @@
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
+ * 現在地は primary で塗る(Raster は線、Flatlay は反転)。
7
+ * 押した手応えは Button と同じ縮み(scale は押下にだけ許される)。
8
+ */
9
+ const cell = [
10
+ "inline-flex items-center justify-center",
11
+ "text-[var(--novi-color-fg)] tabular-nums",
12
+ "bg-transparent",
13
+ "outline-none",
14
+ "hover:bg-[var(--novi-color-subtle)]",
15
+ "data-[pressed]:scale-[0.97]",
16
+ "motion-reduce:data-[pressed]:scale-100",
17
+ "aria-[current=page]:bg-[var(--novi-color-primary)]",
18
+ "aria-[current=page]:text-[var(--novi-color-primary-fg)]",
19
+ "aria-[current=page]:font-medium",
20
+ "transition-[background-color,transform]",
21
+ "duration-[var(--novi-duration-fast)] ease-[var(--novi-ease-standard)]",
22
+ focusRing,
23
+ disabledState
24
+ ].join(" ");
25
+ /**
26
+ * Pagination のスタイル定義。
27
+ *
28
+ * @example
29
+ * import { paginationStyles } from '@novi-ui/tactile'
30
+ * import { tv } from 'tailwind-variants'
31
+ *
32
+ * const myPagination = tv({ extend: paginationStyles, slots: { list: 'gap-3' } })
33
+ */
34
+ const paginationStyles = tv({
35
+ slots: {
36
+ root: "inline-flex",
37
+ list: "flex items-center gap-1.5 list-none m-0 p-0",
38
+ item: cell,
39
+ prev: cell,
40
+ next: cell,
41
+ ellipsis: "inline-flex items-center justify-center text-[var(--novi-color-muted)] select-none"
42
+ },
43
+ variants: {
44
+ size: {
45
+ sm: {
46
+ item: "h-10 min-w-10 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-sm)]",
47
+ prev: "h-10 min-w-10 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-sm)]",
48
+ next: "h-10 min-w-10 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-sm)]",
49
+ ellipsis: "h-10 min-w-10 text-[length:var(--novi-text-sm)]"
50
+ },
51
+ md: {
52
+ item: "h-12 min-w-12 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-base)]",
53
+ prev: "h-12 min-w-12 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-base)]",
54
+ next: "h-12 min-w-12 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-base)]",
55
+ ellipsis: "h-12 min-w-12 text-[length:var(--novi-text-base)]"
56
+ },
57
+ lg: {
58
+ item: "h-14 min-w-14 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-lg)]",
59
+ prev: "h-14 min-w-14 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-lg)]",
60
+ next: "h-14 min-w-14 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-lg)]",
61
+ ellipsis: "h-14 min-w-14 text-[length:var(--novi-text-lg)]"
62
+ }
63
+ },
64
+ radius: {
65
+ none: {
66
+ item: "rounded-[var(--novi-radius-none)]",
67
+ prev: "rounded-[var(--novi-radius-none)]",
68
+ next: "rounded-[var(--novi-radius-none)]"
69
+ },
70
+ sm: {
71
+ item: "rounded-[var(--novi-radius-sm)]",
72
+ prev: "rounded-[var(--novi-radius-sm)]",
73
+ next: "rounded-[var(--novi-radius-sm)]"
74
+ },
75
+ md: {
76
+ item: "rounded-[var(--novi-radius-md)]",
77
+ prev: "rounded-[var(--novi-radius-md)]",
78
+ next: "rounded-[var(--novi-radius-md)]"
79
+ },
80
+ lg: {
81
+ item: "rounded-[var(--novi-radius-lg)]",
82
+ prev: "rounded-[var(--novi-radius-lg)]",
83
+ next: "rounded-[var(--novi-radius-lg)]"
84
+ },
85
+ full: {
86
+ item: "rounded-[var(--novi-radius-full)]",
87
+ prev: "rounded-[var(--novi-radius-full)]",
88
+ next: "rounded-[var(--novi-radius-full)]"
89
+ }
90
+ }
91
+ },
92
+ defaultVariants: {
93
+ size: "md",
94
+ radius: "md"
95
+ }
96
+ });
97
+ //#endregion
98
+ export { paginationStyles };
99
+
100
+ //# 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 * 現在地は primary で塗る(Raster は線、Flatlay は反転)。\n * 押した手応えは Button と同じ縮み(scale は押下にだけ許される)。\n */\nconst cell = [\n 'inline-flex items-center justify-center',\n 'text-[var(--novi-color-fg)] tabular-nums',\n 'bg-transparent',\n 'outline-none',\n 'hover:bg-[var(--novi-color-subtle)]',\n 'data-[pressed]:scale-[0.97]',\n 'motion-reduce:data-[pressed]:scale-100',\n 'aria-[current=page]:bg-[var(--novi-color-primary)]',\n 'aria-[current=page]:text-[var(--novi-color-primary-fg)]',\n 'aria-[current=page]:font-medium',\n 'transition-[background-color,transform]',\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.5 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 と揃える。40 / 48 / 56px。幅は最小で正方形 */\nconst size: VariantMap<NoviSize, { item: string; prev: string; next: string; ellipsis: string }> = {\n sm: {\n item: 'h-10 min-w-10 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-sm)]',\n prev: 'h-10 min-w-10 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-sm)]',\n next: 'h-10 min-w-10 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-sm)]',\n ellipsis: 'h-10 min-w-10 text-[length:var(--novi-text-sm)]',\n },\n md: {\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 lg: {\n item: 'h-14 min-w-14 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-lg)]',\n prev: 'h-14 min-w-14 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-lg)]',\n next: 'h-14 min-w-14 px-[var(--novi-pad-control-x-sm)] text-[length:var(--novi-text-lg)]',\n ellipsis: 'h-14 min-w-14 text-[length:var(--novi-text-lg)]',\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/tactile'\n * import { tv } from 'tailwind-variants'\n *\n * const myPagination = tv({ extend: paginationStyles, slots: { list: 'gap-3' } })\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":";;;;;;;;AAgBA,MAAM,OAAO;CACX;CACA;CACA;CACA;CACA;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"}
@@ -41,16 +41,16 @@ declare const tooltipStyles: import("tailwind-variants").TVReturnType<{
41
41
  [key: string]: {
42
42
  [key: string]: import("tailwind-variants").ClassValue | {
43
43
  root?: import("tailwind-variants").ClassValue;
44
- content?: import("tailwind-variants").ClassValue;
45
44
  arrow?: import("tailwind-variants").ClassValue;
45
+ content?: import("tailwind-variants").ClassValue;
46
46
  };
47
47
  };
48
48
  } | {
49
49
  [x: string]: {
50
50
  [x: string]: import("tailwind-variants").ClassValue | {
51
51
  root?: import("tailwind-variants").ClassValue;
52
- content?: import("tailwind-variants").ClassValue;
53
52
  arrow?: import("tailwind-variants").ClassValue;
53
+ content?: import("tailwind-variants").ClassValue;
54
54
  };
55
55
  };
56
56
  } | {}, {
@@ -61,8 +61,8 @@ declare const tooltipStyles: import("tailwind-variants").TVReturnType<{
61
61
  [key: string]: {
62
62
  [key: string]: import("tailwind-variants").ClassValue | {
63
63
  root?: import("tailwind-variants").ClassValue;
64
- content?: import("tailwind-variants").ClassValue;
65
64
  arrow?: import("tailwind-variants").ClassValue;
65
+ content?: import("tailwind-variants").ClassValue;
66
66
  };
67
67
  };
68
68
  } | {}, {
@@ -20,7 +20,7 @@ declare function SelectItem({ id, isDisabled, children, className }: SelectItemP
20
20
  * 矢印キーで移動、Escape で閉じてトリガーへフォーカスが戻る。
21
21
  *
22
22
  * トリガーは `<button>` で編集可能要素ではないため IME の変換は発生しない。
23
- * テキスト入力を伴う選択が必要な場合は ComboBox を使う(MVP の対象外)。
23
+ * テキスト入力を伴う選択が必要な場合は ComboBox を使う。
24
24
  *
25
25
  * @example
26
26
  * <Select label="都道府県" selectedKey={pref} onSelectionChange={setPref}>
@@ -60,7 +60,7 @@ function SelectItem({ id, isDisabled, children, className }) {
60
60
  * 矢印キーで移動、Escape で閉じてトリガーへフォーカスが戻る。
61
61
  *
62
62
  * トリガーは `<button>` で編集可能要素ではないため IME の変換は発生しない。
63
- * テキスト入力を伴う選択が必要な場合は ComboBox を使う(MVP の対象外)。
63
+ * テキスト入力を伴う選択が必要な場合は ComboBox を使う。
64
64
  *
65
65
  * @example
66
66
  * <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/** 開閉を示す記号。上下の山で「下から出る/しまう」方向を示す。 */\nfunction TriggerIcon() {\n return (\n <svg viewBox=\"0 0 16 16\" width=\"0.9em\" height=\"0.9em\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M5 6.5L8 3.5l3 3M5 9.5l3 3 3-3\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n </svg>\n )\n}\n\n/** 選択済みの印。シートでは行が大きいぶん、選択状態を明示しないと見失う。 */\nfunction SelectedIcon() {\n return (\n <svg viewBox=\"0 0 16 16\" width=\"1em\" height=\"1em\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M3.5 8.5l3 3 6-6\" stroke=\"currentColor\" strokeWidth=\"1.75\" />\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 {({ isSelected }) => (\n <>\n <span className=\"truncate\">{children}</span>\n {isSelected && (\n <span className=\"shrink-0 text-[var(--novi-color-primary)]\">\n <SelectedIcon />\n </span>\n )}\n </>\n )}\n </ListBoxItem>\n )\n}\n\n/**\n * 一覧から1つ選ぶ。**選択肢は画面下端から出るシート**で表示される(Raster はトリガーの隣)。\n * 矢印キーで移動、Escape で閉じてトリガーへフォーカスが戻る。\n *\n * トリガーは `<button>` で編集可能要素ではないため IME の変換は発生しない。\n * テキスト入力を伴う選択が必要な場合は ComboBox を使う(MVP の対象外)。\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;EAAQ,QAAO;EAAQ,MAAK;EAAO,eAAY;EAC5E,UAAA,oBAAC,QAAD;GAAM,GAAE;GAAiC,QAAO;GAAe,aAAY;EAAO,CAAA;CAC/E,CAAA;AAET;;AAGA,SAAS,eAAe;CACtB,OACE,oBAAC,OAAD;EAAK,SAAQ;EAAY,OAAM;EAAM,QAAO;EAAM,MAAK;EAAO,eAAY;EACxE,UAAA,oBAAC,QAAD;GAAM,GAAE;GAAmB,QAAO;GAAe,aAAY;EAAQ,CAAA;CAClE,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;EAE5C,WAAA,EAAE,iBACF,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,QAAD;GAAM,WAAU;GAAY;EAAe,CAAA,GAC1C,cACC,oBAAC,QAAD;GAAM,WAAU;GACd,UAAA,oBAAC,cAAD,CAAe,CAAA;EACX,CAAA,CAER,EAAA,CAAA;CAEO,CAAA;AAEjB;;;;;;;;;;;;;;AAeA,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"}
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/** 開閉を示す記号。上下の山で「下から出る/しまう」方向を示す。 */\nfunction TriggerIcon() {\n return (\n <svg viewBox=\"0 0 16 16\" width=\"0.9em\" height=\"0.9em\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M5 6.5L8 3.5l3 3M5 9.5l3 3 3-3\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n </svg>\n )\n}\n\n/** 選択済みの印。シートでは行が大きいぶん、選択状態を明示しないと見失う。 */\nfunction SelectedIcon() {\n return (\n <svg viewBox=\"0 0 16 16\" width=\"1em\" height=\"1em\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M3.5 8.5l3 3 6-6\" stroke=\"currentColor\" strokeWidth=\"1.75\" />\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 {({ isSelected }) => (\n <>\n <span className=\"truncate\">{children}</span>\n {isSelected && (\n <span className=\"shrink-0 text-[var(--novi-color-primary)]\">\n <SelectedIcon />\n </span>\n )}\n </>\n )}\n </ListBoxItem>\n )\n}\n\n/**\n * 一覧から1つ選ぶ。**選択肢は画面下端から出るシート**で表示される(Raster はトリガーの隣)。\n * 矢印キーで移動、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;EAAQ,QAAO;EAAQ,MAAK;EAAO,eAAY;EAC5E,UAAA,oBAAC,QAAD;GAAM,GAAE;GAAiC,QAAO;GAAe,aAAY;EAAO,CAAA;CAC/E,CAAA;AAET;;AAGA,SAAS,eAAe;CACtB,OACE,oBAAC,OAAD;EAAK,SAAQ;EAAY,OAAM;EAAM,QAAO;EAAM,MAAK;EAAO,eAAY;EACxE,UAAA,oBAAC,QAAD;GAAM,GAAE;GAAmB,QAAO;GAAe,aAAY;EAAQ,CAAA;CAClE,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;EAE5C,WAAA,EAAE,iBACF,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,QAAD;GAAM,WAAU;GAAY;EAAe,CAAA,GAC1C,cACC,oBAAC,QAAD;GAAM,WAAU;GACd,UAAA,oBAAC,cAAD,CAAe,CAAA;EACX,CAAA,CAER,EAAA,CAAA;CAEO,CAAA;AAEjB;;;;;;;;;;;;;;AAeA,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
+ * 一覧を行と列で見せる。**行が指で押せる面**で、40px 以上の高さを持つ
82
+ * (Raster は横罫だけ、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"}