@squadbase/vantage 0.2.0 → 0.2.1
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/README.md +1 -1
- package/dist/{chunk-DIABD3KZ.js → chunk-JC6MT5UU.js} +26 -3
- package/dist/chunk-JC6MT5UU.js.map +1 -0
- package/dist/components/index.d.ts +7 -1
- package/dist/components/index.js +109 -22
- package/dist/components/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/router/index.d.ts +1 -1
- package/dist/router/index.js.map +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +1 -1
- package/docs/en/changelog.md +35 -0
- package/docs/en/components.md +2 -2
- package/docs/en/parts/echart.md +18 -11
- package/docs/en/ui/select.md +16 -10
- package/docs/index.json +2 -2
- package/docs/ja/changelog.md +35 -0
- package/docs/ja/components.md +2 -2
- package/docs/ja/parts/echart.md +16 -9
- package/docs/ja/ui/select.md +17 -10
- package/package.json +1 -1
- package/skills/vantage-app/SKILL.md +64 -233
- package/skills/vantage-pitfalls/SKILL.md +21 -14
- package/templates/AGENTS.md +47 -22
- package/dist/chunk-DIABD3KZ.js.map +0 -1
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runtime/define-page.ts","../src/index.ts"],"names":[],"mappings":";;;AAyCO,SAAS,WAAW,MAAA,EAAgC;AACzD,EAAA,OAAO,MAAA;AACT;;;AChCO,IAAM,OAAA,GAAU","file":"index.js","sourcesContent":["import type { ComponentType, ReactNode } from \"react\"\n\n/**\n * Optional per-page configuration. The only required part of a page module is\n * its default-exported component; `definePage` covers everything else.\n */\nexport interface PageConfig {\n /** Document title applied when this route is active. */\n title?: string\n /** Description metadata for the page. */\n description?: string\n /**\n * Short label for navigation built from `useRoutes()`. Defaults to `title`,\n * which is often too long for a nav (\"Overview · Acme Analytics\").\n */\n navLabel?: string\n /**\n * Component rendered while the route is loading.\n * (Reserved — not yet applied to Vantage's code-split routes in the prototype.)\n */\n pendingComponent?: ComponentType\n /**\n * Component rendered when the route throws.\n * (Reserved — not yet applied to Vantage's code-split routes in the prototype.)\n */\n errorComponent?: ComponentType<{ error: unknown }>\n /**\n * Validate/transform the URL search params for this route.\n * (Reserved — not yet applied to Vantage's code-split routes in the prototype.)\n */\n validateSearch?: (search: Record<string, unknown>) => Record<string, unknown>\n}\n\n/**\n * Declare optional page configuration.\n *\n * ```tsx\n * export const page = definePage({ title: \"Monthly Analysis\" })\n * export default function MonthlyAnalysis() { return <div/> }\n * ```\n */\nexport function definePage(config: PageConfig): PageConfig {\n return config\n}\n\n/** Convenience type for a Vantage page component. */\nexport type PageComponent = ComponentType & { (): ReactNode }\n","/**\n * `@squadbase/vantage` — public runtime surface.\n *\n * The only import most pages need. Server state lives in\n * `@squadbase/vantage/query`, navigation in `@squadbase/vantage/router`,\n * UI in `@squadbase/vantage/ui`, and API types in `@squadbase/vantage/server`.\n */\nexport { definePage } from \"./runtime/define-page\"\nexport type { PageConfig, PageComponent } from \"./runtime/define-page\"\n\n/** Framework version, kept in sync with package.json at build time. */\nexport const VERSION = \"0.2.
|
|
1
|
+
{"version":3,"sources":["../src/runtime/define-page.ts","../src/index.ts"],"names":[],"mappings":";;;AAyCO,SAAS,WAAW,MAAA,EAAgC;AACzD,EAAA,OAAO,MAAA;AACT;;;AChCO,IAAM,OAAA,GAAU","file":"index.js","sourcesContent":["import type { ComponentType, ReactNode } from \"react\"\n\n/**\n * Optional per-page configuration. The only required part of a page module is\n * its default-exported component; `definePage` covers everything else.\n */\nexport interface PageConfig {\n /** Document title applied when this route is active. */\n title?: string\n /** Description metadata for the page. */\n description?: string\n /**\n * Short label for navigation built from `useRoutes()`. Defaults to `title`,\n * which is often too long for a nav (\"Overview · Acme Analytics\").\n */\n navLabel?: string\n /**\n * Component rendered while the route is loading.\n * (Reserved — not yet applied to Vantage's code-split routes in the prototype.)\n */\n pendingComponent?: ComponentType\n /**\n * Component rendered when the route throws.\n * (Reserved — not yet applied to Vantage's code-split routes in the prototype.)\n */\n errorComponent?: ComponentType<{ error: unknown }>\n /**\n * Validate/transform the URL search params for this route.\n * (Reserved — not yet applied to Vantage's code-split routes in the prototype.)\n */\n validateSearch?: (search: Record<string, unknown>) => Record<string, unknown>\n}\n\n/**\n * Declare optional page configuration.\n *\n * ```tsx\n * export const page = definePage({ title: \"Monthly Analysis\" })\n * export default function MonthlyAnalysis() { return <div/> }\n * ```\n */\nexport function definePage(config: PageConfig): PageConfig {\n return config\n}\n\n/** Convenience type for a Vantage page component. */\nexport type PageComponent = ComponentType & { (): ReactNode }\n","/**\n * `@squadbase/vantage` — public runtime surface.\n *\n * The only import most pages need. Server state lives in\n * `@squadbase/vantage/query`, navigation in `@squadbase/vantage/router`,\n * UI in `@squadbase/vantage/ui`, and API types in `@squadbase/vantage/server`.\n */\nexport { definePage } from \"./runtime/define-page\"\nexport type { PageConfig, PageComponent } from \"./runtime/define-page\"\n\n/** Framework version, kept in sync with package.json at build time. */\nexport const VERSION = \"0.2.1\"\n"]}
|
package/dist/router/index.d.ts
CHANGED
|
@@ -67,7 +67,7 @@ interface SearchStateOptions {
|
|
|
67
67
|
*
|
|
68
68
|
* ```tsx
|
|
69
69
|
* const [region, setRegion] = useSearchParam("region", "all")
|
|
70
|
-
* <SegmentedControl value={region}
|
|
70
|
+
* <SegmentedControl value={region} onChange={setRegion} options={REGIONS} />
|
|
71
71
|
* ```
|
|
72
72
|
*
|
|
73
73
|
* Writing the default value (or `null`) drops the key from the URL.
|
package/dist/router/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/router/routes.ts","../../src/router/search.ts","../../src/router/index.ts"],"names":["TanstackLink","useParamsBase","useSearch","useSearchBase","useNavigate","useNavigateBase"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Route-introspection hooks. The route list comes from the generated manifest,\n * so a nav built on `useRoutes()` picks up a new page file the moment it is\n * created — no hand-maintained link array.\n */\nimport { useRouterState } from \"@tanstack/react-router\"\nimport { findRoute, getRoutes, type RouteInfo } from \"./registry\"\n\n/**\n * Every page route in the app, in the framework's scan order (shallow before\n * deep, static before dynamic, alphabetical) — the order a nav wants.\n *\n * ```tsx\n * // Dynamic routes have no single URL, so a nav lists only static ones.\n * const routes = useRoutes().filter((route) => !route.dynamic)\n * routes.map((route) => <Link key={route.path} to={route.to}>{route.label}</Link>)\n * ```\n */\nexport function useRoutes(): readonly RouteInfo[] {\n return getRoutes()\n}\n\n/**\n * The route currently rendered, or `undefined` on the 404 route (no page\n * matched). Use it for breadcrumbs or a page header that mirrors `definePage`.\n */\nexport function useCurrentRoute(): RouteInfo | undefined {\n // Selecting the path string (not the match object) keeps the subscription\n // stable — the component re-renders on navigation, not on every router tick.\n const path = useRouterState({\n select: (state) => {\n const matches = state.matches\n const leaf = matches[matches.length - 1] as\n | { staticData?: { routePath?: string } }\n | undefined\n return leaf?.staticData?.routePath\n },\n })\n return path ? findRoute(path) : undefined\n}\n","/**\n * URL-backed component state. A dashboard's filters belong in the URL: the view\n * survives a reload and can be pasted to a colleague. These hooks read and write\n * a single search-param key with a `useState`-shaped API.\n */\nimport { useCallback } from \"react\"\nimport { useNavigate, useSearch } from \"@tanstack/react-router\"\n\nexport interface SearchStateOptions {\n /**\n * Replace the current history entry instead of pushing a new one.\n * Defaults to `true` so dragging a slider doesn't fill the back button.\n */\n replace?: boolean\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nfunction useRawSearch(): Record<string, unknown> {\n return useSearch({ strict: false }) as any\n}\n\n/**\n * Writer for one key. Passing `undefined` removes the key so defaults never\n * show up in the URL.\n */\nfunction useSearchWriter(key: string, options: SearchStateOptions): (next: unknown) => void {\n const navigate = useNavigate() as any\n const replace = options.replace ?? true\n return useCallback(\n (next: unknown) => {\n // No `to`: TanStack keeps the current route and its path params, so this\n // works unchanged on a dynamic route like `/sales/$customerId`.\n navigate({\n search: (prev: Record<string, unknown>) => {\n const merged = { ...prev }\n if (next === undefined) delete merged[key]\n else merged[key] = next\n return merged\n },\n replace,\n })\n },\n [navigate, key, replace],\n )\n}\n\n/**\n * A string search param, as `useState`. The value is always a string —\n * TanStack parses `?year=2024` into a number, and this hook normalizes it back.\n *\n * ```tsx\n * const [region, setRegion] = useSearchParam(\"region\", \"all\")\n * <SegmentedControl value={region} onValueChange={setRegion} options={REGIONS} />\n * ```\n *\n * Writing the default value (or `null`) drops the key from the URL.\n */\nexport function useSearchParam(\n key: string,\n defaultValue = \"\",\n options: SearchStateOptions = {},\n): [string, (value: string | null) => void] {\n const search = useRawSearch()\n const write = useSearchWriter(key, options)\n\n const raw = search[key]\n const value = raw === undefined || raw === null ? defaultValue : String(raw)\n\n const set = useCallback(\n (next: string | null) => {\n write(next === null || next === defaultValue ? undefined : next)\n },\n [write, defaultValue],\n )\n\n return [value, set]\n}\n\n/**\n * Any JSON-serializable search param, as `useState` — arrays for a multi-select,\n * an object for a whole filter bar. Supports a functional update.\n *\n * ```tsx\n * const [segments, setSegments] = useSearchState<string[]>(\"segments\", [])\n * setSegments((prev) => [...prev, \"enterprise\"])\n * ```\n *\n * Writing a value deep-equal to the default drops the key from the URL.\n */\nexport function useSearchState<T>(\n key: string,\n defaultValue: T,\n options: SearchStateOptions = {},\n): [T, (value: T | ((prev: T) => T)) => void] {\n const search = useRawSearch()\n const write = useSearchWriter(key, options)\n\n const raw = search[key]\n const value = raw === undefined || raw === null ? defaultValue : (raw as T)\n\n const set = useCallback(\n (next: T | ((prev: T) => T)) => {\n const resolved = typeof next === \"function\" ? (next as (prev: T) => T)(value) : next\n // Structural comparison: the parsed value is plain JSON, so stringify is\n // both sufficient and cheap at filter sizes.\n const isDefault = JSON.stringify(resolved) === JSON.stringify(defaultValue)\n write(isDefault ? undefined : resolved)\n },\n [write, value, defaultValue],\n )\n\n return [value, set]\n}\n","/**\n * Vantage's thin router API. Users depend on `@squadbase/vantage/router`\n * instead of `@tanstack/react-router`, so the underlying router can evolve\n * without touching user code. Only the ergonomic, SPA-relevant surface is\n * exposed; typed-route generics are intentionally relaxed to plain strings.\n */\nimport {\n Link as TanstackLink,\n Outlet,\n useNavigate as useNavigateBase,\n useParams as useParamsBase,\n useSearch as useSearchBase,\n useRouterState,\n redirect,\n notFound,\n} from \"@tanstack/react-router\"\nimport { createElement, type ReactNode } from \"react\"\n\nexport { Outlet, useRouterState, redirect, notFound }\n\nexport { useRoutes, useCurrentRoute } from \"./routes\"\nexport type { RouteInfo } from \"./registry\"\n\nexport { useSearchParam, useSearchState } from \"./search\"\nexport type { SearchStateOptions } from \"./search\"\n\nexport interface LinkProps {\n to: string\n params?: Record<string, string>\n search?: Record<string, unknown>\n hash?: string\n replace?: boolean\n className?: string\n activeClassName?: string\n children?: ReactNode\n [key: string]: unknown\n}\n\n/** Client-side navigation link. */\nexport function Link({ activeClassName, className, ...props }: LinkProps): ReactNode {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const anyLink = TanstackLink as any\n return createElement(anyLink, {\n ...props,\n className,\n activeProps: activeClassName ? { className: `${className ?? \"\"} ${activeClassName}`.trim() } : undefined,\n })\n}\n\n/** Route params for the current route (e.g. `{ customerId: \"42\" }`). */\nexport function useParams(): Record<string, string> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return useParamsBase({ strict: false }) as any\n}\n\n/** Validated/raw search params for the current route. */\nexport function useSearch(): Record<string, unknown> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return useSearchBase({ strict: false }) as any\n}\n\n/** Imperative navigation. `navigate({ to: \"/sales/42\" })`. */\nexport function useNavigate(): (opts: { to: string; params?: Record<string, string>; search?: Record<string, unknown>; replace?: boolean }) => void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return useNavigateBase() as any\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/router/routes.ts","../../src/router/search.ts","../../src/router/index.ts"],"names":["TanstackLink","useParamsBase","useSearch","useSearchBase","useNavigate","useNavigateBase"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Route-introspection hooks. The route list comes from the generated manifest,\n * so a nav built on `useRoutes()` picks up a new page file the moment it is\n * created — no hand-maintained link array.\n */\nimport { useRouterState } from \"@tanstack/react-router\"\nimport { findRoute, getRoutes, type RouteInfo } from \"./registry\"\n\n/**\n * Every page route in the app, in the framework's scan order (shallow before\n * deep, static before dynamic, alphabetical) — the order a nav wants.\n *\n * ```tsx\n * // Dynamic routes have no single URL, so a nav lists only static ones.\n * const routes = useRoutes().filter((route) => !route.dynamic)\n * routes.map((route) => <Link key={route.path} to={route.to}>{route.label}</Link>)\n * ```\n */\nexport function useRoutes(): readonly RouteInfo[] {\n return getRoutes()\n}\n\n/**\n * The route currently rendered, or `undefined` on the 404 route (no page\n * matched). Use it for breadcrumbs or a page header that mirrors `definePage`.\n */\nexport function useCurrentRoute(): RouteInfo | undefined {\n // Selecting the path string (not the match object) keeps the subscription\n // stable — the component re-renders on navigation, not on every router tick.\n const path = useRouterState({\n select: (state) => {\n const matches = state.matches\n const leaf = matches[matches.length - 1] as\n | { staticData?: { routePath?: string } }\n | undefined\n return leaf?.staticData?.routePath\n },\n })\n return path ? findRoute(path) : undefined\n}\n","/**\n * URL-backed component state. A dashboard's filters belong in the URL: the view\n * survives a reload and can be pasted to a colleague. These hooks read and write\n * a single search-param key with a `useState`-shaped API.\n */\nimport { useCallback } from \"react\"\nimport { useNavigate, useSearch } from \"@tanstack/react-router\"\n\nexport interface SearchStateOptions {\n /**\n * Replace the current history entry instead of pushing a new one.\n * Defaults to `true` so dragging a slider doesn't fill the back button.\n */\n replace?: boolean\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nfunction useRawSearch(): Record<string, unknown> {\n return useSearch({ strict: false }) as any\n}\n\n/**\n * Writer for one key. Passing `undefined` removes the key so defaults never\n * show up in the URL.\n */\nfunction useSearchWriter(key: string, options: SearchStateOptions): (next: unknown) => void {\n const navigate = useNavigate() as any\n const replace = options.replace ?? true\n return useCallback(\n (next: unknown) => {\n // No `to`: TanStack keeps the current route and its path params, so this\n // works unchanged on a dynamic route like `/sales/$customerId`.\n navigate({\n search: (prev: Record<string, unknown>) => {\n const merged = { ...prev }\n if (next === undefined) delete merged[key]\n else merged[key] = next\n return merged\n },\n replace,\n })\n },\n [navigate, key, replace],\n )\n}\n\n/**\n * A string search param, as `useState`. The value is always a string —\n * TanStack parses `?year=2024` into a number, and this hook normalizes it back.\n *\n * ```tsx\n * const [region, setRegion] = useSearchParam(\"region\", \"all\")\n * <SegmentedControl value={region} onChange={setRegion} options={REGIONS} />\n * ```\n *\n * Writing the default value (or `null`) drops the key from the URL.\n */\nexport function useSearchParam(\n key: string,\n defaultValue = \"\",\n options: SearchStateOptions = {},\n): [string, (value: string | null) => void] {\n const search = useRawSearch()\n const write = useSearchWriter(key, options)\n\n const raw = search[key]\n const value = raw === undefined || raw === null ? defaultValue : String(raw)\n\n const set = useCallback(\n (next: string | null) => {\n write(next === null || next === defaultValue ? undefined : next)\n },\n [write, defaultValue],\n )\n\n return [value, set]\n}\n\n/**\n * Any JSON-serializable search param, as `useState` — arrays for a multi-select,\n * an object for a whole filter bar. Supports a functional update.\n *\n * ```tsx\n * const [segments, setSegments] = useSearchState<string[]>(\"segments\", [])\n * setSegments((prev) => [...prev, \"enterprise\"])\n * ```\n *\n * Writing a value deep-equal to the default drops the key from the URL.\n */\nexport function useSearchState<T>(\n key: string,\n defaultValue: T,\n options: SearchStateOptions = {},\n): [T, (value: T | ((prev: T) => T)) => void] {\n const search = useRawSearch()\n const write = useSearchWriter(key, options)\n\n const raw = search[key]\n const value = raw === undefined || raw === null ? defaultValue : (raw as T)\n\n const set = useCallback(\n (next: T | ((prev: T) => T)) => {\n const resolved = typeof next === \"function\" ? (next as (prev: T) => T)(value) : next\n // Structural comparison: the parsed value is plain JSON, so stringify is\n // both sufficient and cheap at filter sizes.\n const isDefault = JSON.stringify(resolved) === JSON.stringify(defaultValue)\n write(isDefault ? undefined : resolved)\n },\n [write, value, defaultValue],\n )\n\n return [value, set]\n}\n","/**\n * Vantage's thin router API. Users depend on `@squadbase/vantage/router`\n * instead of `@tanstack/react-router`, so the underlying router can evolve\n * without touching user code. Only the ergonomic, SPA-relevant surface is\n * exposed; typed-route generics are intentionally relaxed to plain strings.\n */\nimport {\n Link as TanstackLink,\n Outlet,\n useNavigate as useNavigateBase,\n useParams as useParamsBase,\n useSearch as useSearchBase,\n useRouterState,\n redirect,\n notFound,\n} from \"@tanstack/react-router\"\nimport { createElement, type ReactNode } from \"react\"\n\nexport { Outlet, useRouterState, redirect, notFound }\n\nexport { useRoutes, useCurrentRoute } from \"./routes\"\nexport type { RouteInfo } from \"./registry\"\n\nexport { useSearchParam, useSearchState } from \"./search\"\nexport type { SearchStateOptions } from \"./search\"\n\nexport interface LinkProps {\n to: string\n params?: Record<string, string>\n search?: Record<string, unknown>\n hash?: string\n replace?: boolean\n className?: string\n activeClassName?: string\n children?: ReactNode\n [key: string]: unknown\n}\n\n/** Client-side navigation link. */\nexport function Link({ activeClassName, className, ...props }: LinkProps): ReactNode {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const anyLink = TanstackLink as any\n return createElement(anyLink, {\n ...props,\n className,\n activeProps: activeClassName ? { className: `${className ?? \"\"} ${activeClassName}`.trim() } : undefined,\n })\n}\n\n/** Route params for the current route (e.g. `{ customerId: \"42\" }`). */\nexport function useParams(): Record<string, string> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return useParamsBase({ strict: false }) as any\n}\n\n/** Validated/raw search params for the current route. */\nexport function useSearch(): Record<string, unknown> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return useSearchBase({ strict: false }) as any\n}\n\n/** Imperative navigation. `navigate({ to: \"/sales/42\" })`. */\nexport function useNavigate(): (opts: { to: string; params?: Record<string, string>; search?: Record<string, unknown>; replace?: boolean }) => void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return useNavigateBase() as any\n}\n"]}
|
package/dist/ui/index.d.ts
CHANGED
|
@@ -181,7 +181,7 @@ declare function ProgressValue({ className, ...props }: Progress$1.Value.Props):
|
|
|
181
181
|
declare function ScrollArea({ className, children, ...props }: ScrollArea$1.Root.Props): React$1.JSX.Element;
|
|
182
182
|
declare function ScrollBar({ className, orientation, ...props }: ScrollArea$1.Scrollbar.Props): React$1.JSX.Element;
|
|
183
183
|
|
|
184
|
-
declare
|
|
184
|
+
declare function Select<Value, Multiple extends boolean | undefined = false>({ items, children, ...props }: Select$1.Root.Props<Value, Multiple>): React$1.JSX.Element;
|
|
185
185
|
declare function SelectGroup({ className, ...props }: Select$1.Group.Props): React$1.JSX.Element;
|
|
186
186
|
declare function SelectValue({ className, ...props }: Select$1.Value.Props): React$1.JSX.Element;
|
|
187
187
|
declare function SelectTrigger({ className, size, children, ...props }: Select$1.Trigger.Props & {
|
package/dist/ui/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { Badge, Button, Calendar, CalendarDayButton, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, Popover, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Textarea, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, badgeVariants, buttonVariants, toggleVariants, useIsMobile, useSidebar } from '../chunk-
|
|
1
|
+
export { Badge, Button, Calendar, CalendarDayButton, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, Popover, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Textarea, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, badgeVariants, buttonVariants, toggleVariants, useIsMobile, useSidebar } from '../chunk-JC6MT5UU.js';
|
|
2
2
|
import { cn } from '../chunk-A2UUGASH.js';
|
|
3
3
|
export { cn } from '../chunk-A2UUGASH.js';
|
|
4
4
|
import { Accordion as Accordion$1 } from '@base-ui/react/accordion';
|
package/docs/en/changelog.md
CHANGED
|
@@ -9,6 +9,41 @@ What changed in each Vantage release. Newest is on top.
|
|
|
9
9
|
> minor release may include backwards-incompatible changes. A patch is limited to
|
|
10
10
|
> backwards-compatible additions and bug fixes.
|
|
11
11
|
|
|
12
|
+
## v0.2.1
|
|
13
|
+
|
|
14
|
+
Charts now follow the theme tokens, and `Select` works out the value-to-label
|
|
15
|
+
map for you. Both are backwards-compatible.
|
|
16
|
+
|
|
17
|
+
> [!NOTE]
|
|
18
|
+
> **Chart colours change.** Charts without an explicit `option.color` used to paint
|
|
19
|
+
> in ECharts' own defaults; they now use the theme's `--chart-1` through
|
|
20
|
+
> `--chart-5`. Charts that set `option.color` are unaffected.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- **[`EChart`](parts/echart) follows the theme tokens** — series
|
|
25
|
+
come from `--chart-1` through `--chart-5`, while axes, legend and tooltip are
|
|
26
|
+
built from the text and border tokens, and a light/dark switch is picked up.
|
|
27
|
+
ECharts can't read CSS variables *while painting*, so the tokens are resolved
|
|
28
|
+
once at init. Set `option.color` to override just the series — axes keep
|
|
29
|
+
following the tokens. To paint the whole chart yourself, pass the `theme` prop
|
|
30
|
+
(that turns token-following off entirely).
|
|
31
|
+
- **[`Select`](ui/select) no longer needs `items`** — Base UI's
|
|
32
|
+
`SelectValue` renders the raw selected *value*, so a trigger would read
|
|
33
|
+
`kanto` where the list said "Kanto". Vantage now derives the map from your
|
|
34
|
+
`SelectItem`s. **An explicit `items` still wins**, so existing code is
|
|
35
|
+
unchanged (keep passing it when a separate component returns the options).
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
- The `SegmentedControl` example in `useSearchParam`'s JSDoc passed a
|
|
40
|
+
non-existent `onValueChange` prop (it's `onChange`).
|
|
41
|
+
- Refreshed the bundled `AGENTS.md` and Skills: `vantage add ui|block` can copy
|
|
42
|
+
only `data-table` and `sales-overview`; the mode follows from whether `server/`
|
|
43
|
+
exists rather than being a "promote the SPA to fullstack" procedure; and look
|
|
44
|
+
for already-placed Skills before adding them. A placed `AGENTS.md` is synced by
|
|
45
|
+
`vantage upgrade`.
|
|
46
|
+
|
|
12
47
|
## v0.2.0
|
|
13
48
|
|
|
14
49
|
Makes the destination of `vantage add skill` selectable, and drops the `.js`
|
package/docs/en/components.md
CHANGED
|
@@ -42,8 +42,8 @@ from the Radix build, four differences matter.
|
|
|
42
42
|
- **[`ToggleGroup`](ui/toggle-group)'s `value` is an array.** For single choice, use
|
|
43
43
|
[`SegmentedControl`](parts/segmented-control).
|
|
44
44
|
- **[`Select`](ui/select)'s `onValueChange` gives `string | null`.** You need a
|
|
45
|
-
`null` guard.
|
|
46
|
-
|
|
45
|
+
`null` guard. The value-to-label `items` map is derived from your `SelectItem`s automatically, so
|
|
46
|
+
you rarely write it (only when a separate component returns the options).
|
|
47
47
|
|
|
48
48
|
State is expressed as `data-open` / `data-checked` rather than `data-state="open"`. Vantage's
|
|
49
49
|
`theme.css` declares custom variants that accept both spellings, so classes like
|
package/docs/en/parts/echart.md
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# EChart
|
|
2
2
|
|
|
3
|
-
> A thin Apache ECharts wrapper
|
|
3
|
+
> A thin Apache ECharts wrapper whose colours follow the theme tokens.
|
|
4
4
|
|
|
5
|
-
A thin wrapper around Apache ECharts. It
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
A thin wrapper around Apache ECharts. It handles the canvas lifecycle (init, resize, dispose), the
|
|
6
|
+
loading overlay, event subscriptions and PNG export. **Colours follow the theme tokens** — series
|
|
7
|
+
come from `--chart-1` through `--chart-5`, while axes, legend and tooltip are built from the text
|
|
8
|
+
and border tokens. A light/dark switch is picked up too.
|
|
8
9
|
|
|
9
10
|
```tsx
|
|
10
11
|
import { EChart } from "@squadbase/vantage/components";
|
|
@@ -16,16 +17,21 @@ import type { EChartsOption } from "@squadbase/vantage/components";
|
|
|
16
17
|
| `option` | `EChartsOption` | The ECharts option, passed straight through. |
|
|
17
18
|
| `height` | `string \| number` | Height; a number means px. `className` works too. |
|
|
18
19
|
| `loading` | `boolean` | Show ECharts' loading overlay. |
|
|
19
|
-
| `theme` | `string \| object` | The theme passed to `echarts.init` (a name or a registered theme). |
|
|
20
|
+
| `theme` | `string \| object` | The theme passed to `echarts.init` (a name or a registered theme). Passing one turns token-following off. |
|
|
20
21
|
| `onEvents` | `Record<string, (params: unknown) => void>` | Subscribe to ECharts events such as `click`. |
|
|
21
22
|
| `ariaLabel` | `string` | A description of the chart. |
|
|
22
23
|
| `actions` | `boolean` | Show actions such as save-as-image. |
|
|
23
24
|
| `fileName` | `string` | File name used when saving. |
|
|
24
25
|
|
|
25
|
-
##
|
|
26
|
+
## Overriding the palette
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
By default the theme's `--chart-1` through `--chart-5` become the series colours. ECharts can't read
|
|
29
|
+
CSS variables *while painting*, but `EChart` resolves the tokens once at init with
|
|
30
|
+
`getComputedStyle` and passes them in as an ECharts theme. It watches for the `.dark` class going on
|
|
31
|
+
and off, and re-reads the tokens when it changes.
|
|
32
|
+
|
|
33
|
+
To give series their own colours, set `option.color` (or `series[].itemStyle.color`). Your option
|
|
34
|
+
wins over the theme, so **axes, legend and tooltip keep following the tokens**.
|
|
29
35
|
|
|
30
36
|
```ts
|
|
31
37
|
const option: EChartsOption = {
|
|
@@ -34,9 +40,10 @@ const option: EChartsOption = {
|
|
|
34
40
|
};
|
|
35
41
|
```
|
|
36
42
|
|
|
37
|
-
To
|
|
38
|
-
[`echarts.registerTheme`](https://echarts.apache.org/en/api.html#echarts.registerTheme) and pass
|
|
39
|
-
name
|
|
43
|
+
To paint the whole chart with a theme of your own, register it with
|
|
44
|
+
[`echarts.registerTheme`](https://echarts.apache.org/en/api.html#echarts.registerTheme) and pass the
|
|
45
|
+
name (or the theme object) to `theme`. That turns token-following off entirely — including the
|
|
46
|
+
light/dark switch.
|
|
40
47
|
|
|
41
48
|
## Keeping the legend off the plot
|
|
42
49
|
|
package/docs/en/ui/select.md
CHANGED
|
@@ -39,24 +39,30 @@ import {
|
|
|
39
39
|
> <Select onValueChange={(value) => value !== null && setRegion(value)}>
|
|
40
40
|
> ```
|
|
41
41
|
|
|
42
|
-
> [!
|
|
43
|
-
> `SelectValue`
|
|
44
|
-
> With `value="kanto"` the trigger
|
|
45
|
-
> via `items`.
|
|
42
|
+
> [!NOTE]
|
|
43
|
+
> Base UI's `SelectValue` renders the **raw selected `value`** — it never looks inside `SelectItem`.
|
|
44
|
+
> With `value="kanto"` the trigger would read `kanto`.
|
|
46
45
|
>
|
|
47
|
-
>
|
|
48
|
-
>
|
|
46
|
+
> Vantage's `Select` **absorbs that quirk**: it walks its children, collects each `SelectItem`'s
|
|
47
|
+
> `value` → label pair and hands them to Base UI as `items`, so the code below puts "Kanto" in the
|
|
48
|
+
> trigger. It's the same treatment `SegmentedControl` gives `ToggleGroup`'s array API.
|
|
49
49
|
>
|
|
50
|
-
>
|
|
50
|
+
> ```tsx
|
|
51
|
+
> <Select value={region} onValueChange={…}>
|
|
51
52
|
> <SelectTrigger><SelectValue placeholder="Pick a region" /></SelectTrigger>
|
|
52
|
-
>
|
|
53
|
+
> <SelectContent>
|
|
54
|
+
> <SelectItem value="kanto">Kanto</SelectItem>
|
|
55
|
+
> </SelectContent>
|
|
53
56
|
> </Select>;
|
|
54
57
|
> ```
|
|
55
58
|
>
|
|
56
|
-
>
|
|
59
|
+
> Only `SelectItem`s **written in place** are picked up (a `map` over them counts). When the options
|
|
60
|
+
> come back from a separate component, pass `items` yourself — an explicit `items` always wins.
|
|
57
61
|
>
|
|
58
62
|
> ```tsx
|
|
59
|
-
>
|
|
63
|
+
> const regions = { hokkaido: "Hokkaido", kanto: "Kanto", kansai: "Kansai" };
|
|
64
|
+
>
|
|
65
|
+
> <Select items={regions} value={region} onValueChange={…}>
|
|
60
66
|
> ```
|
|
61
67
|
|
|
62
68
|
`SelectContent` opens over the trigger with the selected item aligned to it. For a plain dropdown
|
package/docs/index.json
CHANGED
|
@@ -549,7 +549,7 @@
|
|
|
549
549
|
"section": "components/parts",
|
|
550
550
|
"sectionTitle": "@squadbase/vantage/components",
|
|
551
551
|
"title": "EChart",
|
|
552
|
-
"description": "Apache ECharts
|
|
552
|
+
"description": "Apache ECharts の薄いラッパー。配色はテーマトークンに追従する。",
|
|
553
553
|
"file": "ja/parts/echart.md",
|
|
554
554
|
"order": 4
|
|
555
555
|
},
|
|
@@ -1230,7 +1230,7 @@
|
|
|
1230
1230
|
"section": "components/parts",
|
|
1231
1231
|
"sectionTitle": "@squadbase/vantage/components",
|
|
1232
1232
|
"title": "EChart",
|
|
1233
|
-
"description": "A thin Apache ECharts wrapper
|
|
1233
|
+
"description": "A thin Apache ECharts wrapper whose colours follow the theme tokens.",
|
|
1234
1234
|
"file": "en/parts/echart.md",
|
|
1235
1235
|
"order": 4
|
|
1236
1236
|
},
|
package/docs/ja/changelog.md
CHANGED
|
@@ -8,6 +8,41 @@ Vantage のリリースごとの変更点です。新しいものが上に来ま
|
|
|
8
8
|
> まだプロトタイプ(**0.x**)です。0.x の間は **minor が実質のメジャー**扱いで、後方互換性の
|
|
9
9
|
> ない変更は minor で入ることがあります。patch は後方互換の機能追加とバグ修正のみです。
|
|
10
10
|
|
|
11
|
+
## v0.2.1
|
|
12
|
+
|
|
13
|
+
チャートをテーマトークンに追従させ、`Select` の値とラベルの対応を Vantage 側で組むように
|
|
14
|
+
しました。API はどちらも後方互換です。
|
|
15
|
+
|
|
16
|
+
> [!NOTE]
|
|
17
|
+
> **チャートの配色が変わります。** これまで `option.color` を書いていないチャートは ECharts の
|
|
18
|
+
> 既定色で描かれていましたが、テーマの `--chart-1` 〜 `--chart-5` で描かれるようになります。
|
|
19
|
+
> 自分で `option.color` を指定しているチャートは今までどおりです。
|
|
20
|
+
|
|
21
|
+
### 変更
|
|
22
|
+
|
|
23
|
+
- **[`EChart`](parts/echart) がテーマトークンに追従するようになりました** ―
|
|
24
|
+
系列色は `--chart-1` 〜 `--chart-5`、軸・凡例・ツールチップは文字色と境界色のトークンから
|
|
25
|
+
組まれ、ライト / ダークの切り替えにも追いかけます。ECharts が CSS 変数を読めないのは
|
|
26
|
+
**キャンバスの描画中**の話なので、init のタイミングでトークンの実値を解決しています。
|
|
27
|
+
系列の色だけ変えたいときは `option.color` で上書きでき、その場合も軸まわりの追従は
|
|
28
|
+
残ります。チャート全体を自前のテーマで描きたいときは `theme` プロップを渡してください
|
|
29
|
+
(このときトークン追従は完全に無効になります)。
|
|
30
|
+
- **[`Select`](ui/select) の `items` を書かなくてよくなりました** ―
|
|
31
|
+
Base UI の `SelectValue` は選択中の *value* をそのまま描く部品で、値とラベルが違うと
|
|
32
|
+
トリガーに `kanto` のような生の値が出ていました。`SelectItem` から対応表を組む処理を
|
|
33
|
+
Vantage 側に入れたので、普通に書けばラベルが出ます。**明示した `items` は今までどおり
|
|
34
|
+
優先される**ので、既存のコードはそのまま動きます(項目を別のコンポーネントが返している
|
|
35
|
+
場合は、これまでどおり `items` を渡してください)。
|
|
36
|
+
|
|
37
|
+
### 修正
|
|
38
|
+
|
|
39
|
+
- `useSearchParam` の JSDoc に載せていた `SegmentedControl` の例が、存在しない
|
|
40
|
+
`onValueChange` を渡していました(正しくは `onChange`)。
|
|
41
|
+
- 同梱の `AGENTS.md` と Skill を更新しました ― `vantage add ui|block` でコピーできるのが
|
|
42
|
+
`data-table` と `sales-overview` の 2 つだけであること、モードは `server/` の有無で決まり
|
|
43
|
+
「SPA から fullstack へ昇格する」手順ではないこと、配置済みの Skill を先に探すこと。
|
|
44
|
+
配置済みの `AGENTS.md` は `vantage upgrade` で同期されます。
|
|
45
|
+
|
|
11
46
|
## v0.2.0
|
|
12
47
|
|
|
13
48
|
`vantage add skill` の配置先を選べるようにし、相対 import の `.js` 指定子の規約を廃止しました。
|
package/docs/ja/components.md
CHANGED
|
@@ -42,8 +42,8 @@ Radix UI から [Base UI](https://base-ui.com) へ切り替えており、Vantag
|
|
|
42
42
|
- **[`ToggleGroup`](ui/toggle-group) の `value` は配列。** 単一選択にしたいときは
|
|
43
43
|
[`SegmentedControl`](parts/segmented-control) を使ってください。
|
|
44
44
|
- **[`Select`](ui/select) の `onValueChange` は `string | null`。** `null` のガードが
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
要ります。値とラベルが違うときの `items` は Vantage 側が `SelectItem` から自動で組むので、
|
|
46
|
+
通常は書かなくて済みます(別コンポーネントが項目を返す形のときだけ明示)。
|
|
47
47
|
|
|
48
48
|
状態は `data-state="open"` ではなく `data-open` / `data-checked` のような属性で表現されます。
|
|
49
49
|
Vantage の `theme.css` は両方の綴りを受ける custom variant を定義しているので、
|
package/docs/ja/parts/echart.md
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# EChart
|
|
2
2
|
|
|
3
|
-
> Apache ECharts
|
|
3
|
+
> Apache ECharts の薄いラッパー。配色はテーマトークンに追従する。
|
|
4
4
|
|
|
5
5
|
Apache ECharts をそのまま使えるようにした薄いラッパーです。キャンバスの初期化・リサイズ・破棄と、
|
|
6
|
-
ローディング表示・イベント購読・PNG
|
|
7
|
-
|
|
6
|
+
ローディング表示・イベント購読・PNG 保存を面倒みます。**配色はテーマトークンに追従します** —
|
|
7
|
+
系列色は `--chart-1` 〜 `--chart-5`、軸・凡例・ツールチップは文字色と境界色のトークンから組まれ、
|
|
8
|
+
ライト / ダークの切り替えにも追いかけます。
|
|
8
9
|
|
|
9
10
|
```tsx
|
|
10
11
|
import { EChart } from "@squadbase/vantage/components";
|
|
@@ -16,16 +17,21 @@ import type { EChartsOption } from "@squadbase/vantage/components";
|
|
|
16
17
|
| `option` | `EChartsOption` | ECharts の option。そのまま渡す。 |
|
|
17
18
|
| `height` | `string \| number` | 高さ。数値は px。`className` で決めても良い。 |
|
|
18
19
|
| `loading` | `boolean` | ECharts のローディング表示を出す。 |
|
|
19
|
-
| `theme` | `string \| object` | `echarts.init`
|
|
20
|
+
| `theme` | `string \| object` | `echarts.init` に渡すテーマ(名前または登録済みテーマ)。渡すとトークン追従は無効になる。 |
|
|
20
21
|
| `onEvents` | `Record<string, (params: unknown) => void>` | ECharts のイベント購読(`click` など)。 |
|
|
21
22
|
| `ariaLabel` | `string` | チャートの説明。 |
|
|
22
23
|
| `actions` | `boolean` | 画像保存などの操作を出す。 |
|
|
23
24
|
| `fileName` | `string` | 保存時のファイル名。 |
|
|
24
25
|
|
|
25
|
-
##
|
|
26
|
+
## 配色を上書きする
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
既定ではテーマの `--chart-1` 〜 `--chart-5` がそのまま系列色になります。ECharts は**描画中**には
|
|
29
|
+
CSS 変数を読めませんが、`EChart` は init のタイミングで `getComputedStyle` からトークンの実値を
|
|
30
|
+
解決し、ECharts のテーマとして渡しています。`.dark` の付け外しを見張っていて、切り替われば
|
|
31
|
+
読み直します。
|
|
32
|
+
|
|
33
|
+
系列に固有の色を当てたいときは `option.color`(または `series[].itemStyle.color`)で上書きします。
|
|
34
|
+
option はテーマより優先されるので、**軸・凡例・ツールチップのトークン追従は残ります**。
|
|
29
35
|
|
|
30
36
|
```ts
|
|
31
37
|
const option: EChartsOption = {
|
|
@@ -34,8 +40,9 @@ const option: EChartsOption = {
|
|
|
34
40
|
};
|
|
35
41
|
```
|
|
36
42
|
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
チャート全体を自前のテーマで描きたいときは、[`echarts.registerTheme`](https://echarts.apache.org/en/api.html#echarts.registerTheme)
|
|
44
|
+
で登録したテーマ名(またはテーマオブジェクト)を `theme` プロップに渡します。この場合は
|
|
45
|
+
トークン追従が**完全に無効**になり、明暗の切り替えにも追従しなくなります。
|
|
39
46
|
|
|
40
47
|
## 凡例と重ならないようにする
|
|
41
48
|
|
package/docs/ja/ui/select.md
CHANGED
|
@@ -40,24 +40,31 @@ import {
|
|
|
40
40
|
> <Select onValueChange={(value) => value !== null && setRegion(value)}>
|
|
41
41
|
> ```
|
|
42
42
|
|
|
43
|
-
> [!
|
|
44
|
-
> `SelectValue`
|
|
45
|
-
>
|
|
46
|
-
> `items` に渡してください。
|
|
43
|
+
> [!NOTE]
|
|
44
|
+
> Base UI の `SelectValue` は**選択中の `value` をそのまま表示する**部品で、`SelectItem` の中身は
|
|
45
|
+
> 見ません。`value="kanto"` ならトリガーには `kanto` と出ます。
|
|
47
46
|
>
|
|
48
|
-
>
|
|
49
|
-
>
|
|
47
|
+
> Vantage の `Select` はこの癖を**吸収します** — children を辿って `SelectItem` の `value` →
|
|
48
|
+
> ラベルの対応を組み、Base UI の `items` に渡すので、下の書き方でトリガーに「関東」と出ます。
|
|
49
|
+
> `SegmentedControl` が `ToggleGroup` の配列 API を吸収しているのと同じ扱いです。
|
|
50
50
|
>
|
|
51
|
-
>
|
|
51
|
+
> ```tsx
|
|
52
|
+
> <Select value={region} onValueChange={…}>
|
|
52
53
|
> <SelectTrigger><SelectValue placeholder="地域を選ぶ" /></SelectTrigger>
|
|
53
|
-
>
|
|
54
|
+
> <SelectContent>
|
|
55
|
+
> <SelectItem value="kanto">関東</SelectItem>
|
|
56
|
+
> </SelectContent>
|
|
54
57
|
> </Select>;
|
|
55
58
|
> ```
|
|
56
59
|
>
|
|
57
|
-
> `
|
|
60
|
+
> 自動で拾えるのは、**その場に書かれた `SelectItem`** だけです(`map` で並べるのは拾えます)。
|
|
61
|
+
> 項目を別のコンポーネントが返す形にしているときは `items` を明示してください。明示した `items`
|
|
62
|
+
> は常に優先されます。
|
|
58
63
|
>
|
|
59
64
|
> ```tsx
|
|
60
|
-
>
|
|
65
|
+
> const regions = { hokkaido: "北海道", kanto: "関東", kansai: "関西" };
|
|
66
|
+
>
|
|
67
|
+
> <Select items={regions} value={region} onValueChange={…}>
|
|
61
68
|
> ```
|
|
62
69
|
|
|
63
70
|
`SelectContent` は既定で選択中の項目をトリガーに重ねて開きます。素直に下へ開かせたいときは
|