@akira-io/ui 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/inertia.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ReactNode, ReactElement, PropsWithChildren } from 'react';
2
- import { a as LoginFormLabels, e as TourLabels } from './types-1LUmNJf_.js';
2
+ import { a as LoginFormLabels, e as TourLabels } from './types-DEJsTx8E.js';
3
3
  import { U as UrlLike, N as NavGroup, c as NavItem, d as SharedUser, B as BreadcrumbItem, L as LinkComponent } from './types-CMZRvMV5.js';
4
4
  import '@tanstack/react-table';
5
5
  import 'lucide-react';
package/dist/inertia.js CHANGED
@@ -4,7 +4,7 @@
4
4
  import {
5
5
  LoginFormPreset,
6
6
  TourProvider
7
- } from "./chunk-BR3JI3KN.js";
7
+ } from "./chunk-L56VUE3E.js";
8
8
  import "./chunk-BH3B26DK.js";
9
9
  import "./chunk-OS7YY5R4.js";
10
10
  import "./chunk-BP2YDMMI.js";
@@ -14,9 +14,9 @@ import {
14
14
  Breadcrumbs,
15
15
  NavMain,
16
16
  SettingsLayout
17
- } from "./chunk-MCHHCLV3.js";
17
+ } from "./chunk-7DAA3DPJ.js";
18
18
  import "./chunk-PYXUFFMO.js";
19
- import "./chunk-L2H5GIF7.js";
19
+ import "./chunk-VVBBKTC5.js";
20
20
  import "./chunk-EXTOGROG.js";
21
21
  import "./chunk-53V4J7MC.js";
22
22
  import "./chunk-PPWJK5T3.js";
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/inertia.ts","../src/inertia-table-filters.ts","../src/inertia-tour-progress.ts"],"sourcesContent":["'use client';\n\nimport { Form, Link, router, usePage } from '@inertiajs/react';\nimport {\n createElement,\n type ComponentType,\n type PropsWithChildren,\n type ReactElement,\n type ReactNode,\n} from 'react';\n\nimport { LoginFormPreset, type LoginFormLabels } from '@/blocks/login-form';\nimport {\n TourProvider as BaseTourProvider,\n type TourLabels,\n type TourProgress,\n} from '@/blocks/tour';\nimport {\n createTableFiltersHook,\n type TableFilters,\n type TableFiltersOptions,\n type TableFiltersRouter,\n type TableFilterValue,\n} from '@/inertia-table-filters';\nimport { recordTourProgress } from '@/inertia-tour-progress';\nimport { AppSidebar as BaseAppSidebar } from '@/shells/app-sidebar';\nimport { AppSidebarHeader as BaseAppSidebarHeader } from '@/shells/app-sidebar-header';\nimport { Breadcrumbs as BaseBreadcrumbs } from '@/shells/breadcrumbs';\nimport { NavMain as BaseNavMain } from '@/shells/nav-main';\nimport { SettingsLayout as BaseSettingsLayout } from '@/shells/settings-layout';\nimport type {\n BreadcrumbItem,\n LinkComponent,\n NavGroup,\n NavItem,\n SharedUser,\n UrlLike,\n} from '@/types';\n\nexport const InertiaLink = Link as unknown as LinkComponent;\n\nexport type {\n TableFilters,\n TableFiltersOptions,\n TableFiltersRouter,\n TableFilterValue,\n};\n\nexport const useTableFilters = createTableFiltersHook(router);\n\nexport function useCurrentUrl(): string {\n return usePage().url;\n}\n\nexport function AppSidebar(props: {\n logo: ReactNode;\n logoHref: UrlLike;\n groups: NavGroup[];\n footerItems?: NavItem[];\n user: SharedUser;\n settingsHref: UrlLike;\n logoutHref: UrlLike;\n collapsibleGroups?: boolean;\n collapsedGroups?: string[];\n onCollapsedChange?: (collapsedGroups: string[]) => void;\n onSettingsClick?: () => void;\n onLogout?: () => void;\n}): ReactElement {\n return createElement(BaseAppSidebar, {\n ...props,\n currentUrl: usePage().url,\n linkComponent: InertiaLink,\n });\n}\n\nexport function AppSidebarHeader(props: {\n breadcrumbs?: BreadcrumbItem[];\n onSearchClick?: () => void;\n searchLabel?: string;\n}): ReactElement {\n return createElement(BaseAppSidebarHeader, {\n ...props,\n linkComponent: InertiaLink,\n });\n}\n\nexport function Breadcrumbs(props: {\n breadcrumbs: BreadcrumbItem[];\n}): ReactElement {\n return createElement(BaseBreadcrumbs, {\n ...props,\n linkComponent: InertiaLink,\n });\n}\n\nexport function NavMain(props: {\n items: NavItem[];\n label?: string;\n collapsible?: boolean;\n defaultOpen?: boolean;\n collapsedGroups?: string[];\n onCollapsedChange?: (collapsedGroups: string[]) => void;\n}): ReactElement {\n return createElement(BaseNavMain, {\n ...props,\n currentUrl: usePage().url,\n linkComponent: InertiaLink,\n });\n}\n\nexport function SettingsLayout(\n props: PropsWithChildren<{\n items: NavItem[];\n title?: string;\n description?: string;\n wide?: boolean;\n }>,\n): ReactElement {\n return createElement(BaseSettingsLayout, {\n ...props,\n currentPath: usePage().url,\n linkComponent: InertiaLink,\n });\n}\n\ninterface LoginPostFormRenderProps {\n processing: boolean;\n errors: Partial<Record<'email' | 'password' | 'remember', string>>;\n}\n\ninterface LoginPostFormProps {\n action: string;\n method: 'post';\n resetOnSuccess: string[];\n className?: string;\n 'data-slot': string;\n children: (props: LoginPostFormRenderProps) => ReactNode;\n}\n\nconst LoginPostForm = Form as unknown as ComponentType<LoginPostFormProps>;\n\nexport function InertiaLoginForm({\n action,\n status,\n forgotPasswordHref,\n labels,\n className,\n slotName = 'inertia-login-form',\n}: {\n action: string;\n status?: string;\n forgotPasswordHref?: UrlLike;\n labels?: Partial<LoginFormLabels>;\n className?: string;\n slotName?: string;\n}): ReactElement {\n return createElement(LoginPostForm, {\n action,\n method: 'post',\n resetOnSuccess: ['password'],\n className,\n 'data-slot': slotName,\n children: ({ processing, errors }) =>\n createElement(LoginFormPreset, {\n errors,\n processing,\n status,\n forgotPasswordHref,\n labels,\n linkComponent: InertiaLink,\n }),\n });\n}\n\nexport function InertiaTourProvider({\n children,\n progressUrl,\n labels,\n}: PropsWithChildren<{\n progressUrl: (tour: string) => string;\n labels?: Partial<TourLabels>;\n}>): ReactElement {\n const seen = (usePage().props.tours ?? {}) as Record<string, number>;\n\n return createElement(BaseTourProvider, {\n seen,\n labels,\n children,\n onProgress: (progress: TourProgress) =>\n recordTourProgress(progressUrl(progress.tour), progress),\n });\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\n\nexport type TableFilterValue = string | string[] | number | null | undefined;\n\nexport type TableFilterQuery = Record<string, string | string[]>;\n\nexport interface TableFiltersVisitOptions {\n data: TableFilterQuery;\n only?: string[];\n preserveState: boolean;\n preserveScroll: boolean;\n replace: boolean;\n onCancelToken: (token: { cancel: () => void }) => void;\n}\n\nexport interface TableFiltersRouter {\n visit: (url: string, options: TableFiltersVisitOptions) => void;\n}\n\nexport interface TableFiltersOptions {\n url: string;\n filters: Record<string, TableFilterValue>;\n only?: string[];\n searchKey?: string;\n pageKey?: string;\n debounce?: number;\n}\n\nexport interface TableFilters {\n search: string;\n setSearch: (value: string) => void;\n filterValues: Record<string, string[]>;\n setFilter: (key: string, values: string[]) => void;\n clearFilters: () => void;\n setPage: (pageIndex: number) => void;\n apply: (changes: Record<string, TableFilterValue>) => void;\n}\n\nexport type UseTableFilters = (options: TableFiltersOptions) => TableFilters;\n\nconst DEFAULT_DEBOUNCE = 300;\n\nexport function toQuery(\n filters: Record<string, TableFilterValue>,\n): TableFilterQuery {\n const query: TableFilterQuery = {};\n\n for (const [key, value] of Object.entries(filters)) {\n if (Array.isArray(value)) {\n const values = value.filter((entry) => entry !== '');\n\n if (values.length > 0) {\n query[key] = values;\n }\n\n continue;\n }\n\n if (value === null || value === undefined || value === '') {\n continue;\n }\n\n query[key] = String(value);\n }\n\n return query;\n}\n\nexport function toFilterValues(\n filters: Record<string, TableFilterValue>,\n exclude: string[] = [],\n): Record<string, string[]> {\n const values: Record<string, string[]> = {};\n\n for (const [key, value] of Object.entries(toQuery(filters))) {\n if (exclude.includes(key)) {\n continue;\n }\n\n values[key] = Array.isArray(value) ? value : [value];\n }\n\n return values;\n}\n\nexport function createTableFiltersHook(\n router: TableFiltersRouter,\n): UseTableFilters {\n return function useTableFilters({\n url,\n filters,\n only,\n searchKey = 'search',\n pageKey = 'page',\n debounce = DEFAULT_DEBOUNCE,\n }: TableFiltersOptions): TableFilters {\n const initialSearch = filters[searchKey];\n const [search, setSearchState] = useState(\n typeof initialSearch === 'string' ? initialSearch : '',\n );\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const pending = useRef<{ cancel: () => void } | null>(null);\n const state = useRef({ url, filters, only, searchKey, pageKey });\n\n state.current = { url, filters, only, searchKey, pageKey };\n\n const visit = useCallback(\n (changes: Record<string, TableFilterValue>) => {\n const current = state.current;\n\n pending.current?.cancel();\n\n router.visit(current.url, {\n data: toQuery({ ...current.filters, ...changes }),\n only: current.only,\n preserveState: true,\n preserveScroll: true,\n replace: true,\n onCancelToken: (token) => {\n pending.current = token;\n },\n });\n },\n [],\n );\n\n const cancelPendingSearch = useCallback(() => {\n if (timer.current !== null) {\n clearTimeout(timer.current);\n timer.current = null;\n }\n }, []);\n\n useEffect(() => cancelPendingSearch, [cancelPendingSearch]);\n\n const setSearch = useCallback(\n (value: string) => {\n setSearchState(value);\n cancelPendingSearch();\n\n timer.current = setTimeout(() => {\n timer.current = null;\n visit({\n [state.current.searchKey]: value,\n [state.current.pageKey]: null,\n });\n }, debounce);\n },\n [cancelPendingSearch, debounce, visit],\n );\n\n const setFilter = useCallback(\n (key: string, values: string[]) => {\n cancelPendingSearch();\n visit({ [key]: values, [state.current.pageKey]: null });\n },\n [cancelPendingSearch, visit],\n );\n\n const clearFilters = useCallback(() => {\n cancelPendingSearch();\n setSearchState('');\n\n const current = state.current;\n const cleared = Object.fromEntries(\n Object.keys(current.filters).map((key) => [key, null]),\n );\n\n visit({ ...cleared, [current.pageKey]: null });\n }, [cancelPendingSearch, visit]);\n\n const setPage = useCallback(\n (pageIndex: number) => {\n visit({\n [state.current.pageKey]:\n pageIndex > 0 ? pageIndex + 1 : null,\n });\n },\n [visit],\n );\n\n const apply = useCallback(\n (changes: Record<string, TableFilterValue>) => {\n cancelPendingSearch();\n visit({ ...changes, [state.current.pageKey]: null });\n },\n [cancelPendingSearch, visit],\n );\n\n return {\n search,\n setSearch,\n filterValues: toFilterValues(filters, [searchKey, pageKey]),\n setFilter,\n clearFilters,\n setPage,\n apply,\n };\n };\n}\n","import type { TourProgress } from '@/blocks/tour';\n\nexport function xsrfToken(): string {\n const cookie = document.cookie\n .split('; ')\n .find((entry) => entry.startsWith('XSRF-TOKEN='));\n\n return cookie ? decodeURIComponent(cookie.slice('XSRF-TOKEN='.length)) : '';\n}\n\nexport function recordTourProgress(url: string, progress: TourProgress): void {\n void fetch(url, {\n method: 'POST',\n credentials: 'same-origin',\n keepalive: true,\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n 'X-Requested-With': 'XMLHttpRequest',\n 'X-XSRF-TOKEN': xsrfToken(),\n },\n body: JSON.stringify({\n version: progress.version,\n last_step: progress.lastStep,\n outcome: progress.outcome,\n }),\n });\n}\n"],"mappings":"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","names":["router","useTableFilters","AppSidebar","AppSidebarHeader","Breadcrumbs","NavMain","SettingsLayout"]}
1
+ {"version":3,"sources":["../src/inertia.ts","../src/inertia-table-filters.ts","../src/inertia-tour-progress.ts"],"sourcesContent":["'use client';\n\nimport { Form, Link, router, usePage } from '@inertiajs/react';\nimport {\n createElement,\n type ComponentProps,\n type ComponentType,\n type PropsWithChildren,\n type ReactElement,\n type ReactNode,\n} from 'react';\n\nimport { LoginFormPreset, type LoginFormLabels } from '@/blocks/login-form';\nimport {\n TourProvider as BaseTourProvider,\n type TourLabels,\n type TourProgress,\n} from '@/blocks/tour';\nimport {\n createTableFiltersHook,\n type TableFilters,\n type TableFiltersOptions,\n type TableFiltersRouter,\n type TableFilterValue,\n} from '@/inertia-table-filters';\nimport { recordTourProgress } from '@/inertia-tour-progress';\nimport { AppSidebar as BaseAppSidebar } from '@/shells/app-sidebar';\nimport { AppSidebarHeader as BaseAppSidebarHeader } from '@/shells/app-sidebar-header';\nimport { Breadcrumbs as BaseBreadcrumbs } from '@/shells/breadcrumbs';\nimport { NavMain as BaseNavMain } from '@/shells/nav-main';\nimport { SettingsLayout as BaseSettingsLayout } from '@/shells/settings-layout';\nimport type {\n BreadcrumbItem,\n LinkComponent,\n NavGroup,\n NavItem,\n SharedUser,\n UrlLike,\n} from '@/types';\n\nexport const InertiaLink = Link as unknown as LinkComponent;\n\nexport type {\n TableFilters,\n TableFiltersOptions,\n TableFiltersRouter,\n TableFilterValue,\n};\n\nexport const useTableFilters = createTableFiltersHook(router);\n\nexport function useCurrentUrl(): string {\n return usePage().url;\n}\n\nexport function AppSidebar(props: {\n logo: ReactNode;\n logoHref: UrlLike;\n groups: NavGroup[];\n footerItems?: NavItem[];\n user: SharedUser;\n settingsHref: UrlLike;\n logoutHref: UrlLike;\n collapsibleGroups?: boolean;\n collapsedGroups?: string[];\n onCollapsedChange?: (collapsedGroups: string[]) => void;\n onSettingsClick?: () => void;\n onLogout?: () => void;\n}): ReactElement {\n return createElement(BaseAppSidebar, {\n ...props,\n currentUrl: usePage().url,\n linkComponent: InertiaLink,\n });\n}\n\nexport function AppSidebarHeader(props: {\n breadcrumbs?: BreadcrumbItem[];\n onSearchClick?: () => void;\n searchLabel?: string;\n}): ReactElement {\n return createElement(BaseAppSidebarHeader, {\n ...props,\n linkComponent: InertiaLink,\n });\n}\n\nexport function Breadcrumbs(props: {\n breadcrumbs: BreadcrumbItem[];\n}): ReactElement {\n return createElement(BaseBreadcrumbs, {\n ...props,\n linkComponent: InertiaLink,\n });\n}\n\nexport function NavMain(props: {\n items: NavItem[];\n label?: string;\n collapsible?: boolean;\n defaultOpen?: boolean;\n collapsedGroups?: string[];\n onCollapsedChange?: (collapsedGroups: string[]) => void;\n}): ReactElement {\n return createElement(BaseNavMain, {\n ...props,\n currentUrl: usePage().url,\n linkComponent: InertiaLink,\n });\n}\n\nexport function SettingsLayout(\n props: PropsWithChildren<{\n items: NavItem[];\n title?: string;\n description?: string;\n wide?: boolean;\n }>,\n): ReactElement {\n return createElement(BaseSettingsLayout, {\n ...props,\n currentPath: usePage().url,\n linkComponent: InertiaLink,\n });\n}\n\ninterface LoginPostFormRenderProps {\n processing: boolean;\n errors: Partial<Record<'email' | 'password' | 'remember', string>>;\n}\n\ninterface LoginPostFormProps extends Pick<\n ComponentProps<typeof Form>,\n 'action' | 'method' | 'className'\n> {\n resetOnSuccess: string[];\n 'data-slot': string;\n children: (props: LoginPostFormRenderProps) => ReactNode;\n}\n\nconst LoginPostForm: ComponentType<LoginPostFormProps> = Form;\n\nexport function InertiaLoginForm({\n action,\n status,\n forgotPasswordHref,\n labels,\n className,\n slotName = 'inertia-login-form',\n}: {\n action: string;\n status?: string;\n forgotPasswordHref?: UrlLike;\n labels?: Partial<LoginFormLabels>;\n className?: string;\n slotName?: string;\n}): ReactElement {\n return createElement(LoginPostForm, {\n action,\n method: 'post',\n resetOnSuccess: ['password'],\n className,\n 'data-slot': slotName,\n children: ({ processing, errors }) =>\n createElement(LoginFormPreset, {\n errors,\n processing,\n status,\n forgotPasswordHref,\n labels,\n linkComponent: InertiaLink,\n }),\n });\n}\n\nexport function InertiaTourProvider({\n children,\n progressUrl,\n labels,\n}: PropsWithChildren<{\n progressUrl: (tour: string) => string;\n labels?: Partial<TourLabels>;\n}>): ReactElement {\n const seen = (usePage().props.tours ?? {}) as Record<string, number>;\n\n return createElement(BaseTourProvider, {\n seen,\n labels,\n children,\n onProgress: (progress: TourProgress) =>\n recordTourProgress(progressUrl(progress.tour), progress),\n });\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\n\nexport type TableFilterValue = string | string[] | number | null | undefined;\n\nexport type TableFilterQuery = Record<string, string | string[]>;\n\nexport interface TableFiltersVisitOptions {\n data: TableFilterQuery;\n only?: string[];\n preserveState: boolean;\n preserveScroll: boolean;\n replace: boolean;\n onCancelToken: (token: { cancel: () => void }) => void;\n}\n\nexport interface TableFiltersRouter {\n visit: (url: string, options: TableFiltersVisitOptions) => void;\n}\n\nexport interface TableFiltersOptions {\n url: string;\n filters: Record<string, TableFilterValue>;\n only?: string[];\n searchKey?: string;\n pageKey?: string;\n debounce?: number;\n}\n\nexport interface TableFilters {\n search: string;\n setSearch: (value: string) => void;\n filterValues: Record<string, string[]>;\n setFilter: (key: string, values: string[]) => void;\n clearFilters: () => void;\n setPage: (pageIndex: number) => void;\n apply: (changes: Record<string, TableFilterValue>) => void;\n}\n\nexport type UseTableFilters = (options: TableFiltersOptions) => TableFilters;\n\nconst DEFAULT_DEBOUNCE = 300;\n\nexport function toQuery(\n filters: Record<string, TableFilterValue>,\n): TableFilterQuery {\n const query: TableFilterQuery = {};\n\n for (const [key, value] of Object.entries(filters)) {\n if (Array.isArray(value)) {\n const values = value.filter((entry) => entry !== '');\n\n if (values.length > 0) {\n query[key] = values;\n }\n\n continue;\n }\n\n if (value === null || value === undefined || value === '') {\n continue;\n }\n\n query[key] = String(value);\n }\n\n return query;\n}\n\nexport function toFilterValues(\n filters: Record<string, TableFilterValue>,\n exclude: string[] = [],\n): Record<string, string[]> {\n const values: Record<string, string[]> = {};\n\n for (const [key, value] of Object.entries(toQuery(filters))) {\n if (exclude.includes(key)) {\n continue;\n }\n\n values[key] = Array.isArray(value) ? value : [value];\n }\n\n return values;\n}\n\nexport function createTableFiltersHook(\n router: TableFiltersRouter,\n): UseTableFilters {\n return function useTableFilters({\n url,\n filters,\n only,\n searchKey = 'search',\n pageKey = 'page',\n debounce = DEFAULT_DEBOUNCE,\n }: TableFiltersOptions): TableFilters {\n const initialSearch = filters[searchKey];\n const [search, setSearchState] = useState(\n typeof initialSearch === 'string' ? initialSearch : '',\n );\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const pending = useRef<{ cancel: () => void } | null>(null);\n const state = useRef({ url, filters, only, searchKey, pageKey });\n\n state.current = { url, filters, only, searchKey, pageKey };\n\n const visit = useCallback(\n (changes: Record<string, TableFilterValue>) => {\n const current = state.current;\n\n pending.current?.cancel();\n\n router.visit(current.url, {\n data: toQuery({ ...current.filters, ...changes }),\n only: current.only,\n preserveState: true,\n preserveScroll: true,\n replace: true,\n onCancelToken: (token) => {\n pending.current = token;\n },\n });\n },\n [],\n );\n\n const cancelPendingSearch = useCallback(() => {\n if (timer.current !== null) {\n clearTimeout(timer.current);\n timer.current = null;\n }\n }, []);\n\n useEffect(() => cancelPendingSearch, [cancelPendingSearch]);\n\n const setSearch = useCallback(\n (value: string) => {\n setSearchState(value);\n cancelPendingSearch();\n\n timer.current = setTimeout(() => {\n timer.current = null;\n visit({\n [state.current.searchKey]: value,\n [state.current.pageKey]: null,\n });\n }, debounce);\n },\n [cancelPendingSearch, debounce, visit],\n );\n\n const setFilter = useCallback(\n (key: string, values: string[]) => {\n cancelPendingSearch();\n visit({ [key]: values, [state.current.pageKey]: null });\n },\n [cancelPendingSearch, visit],\n );\n\n const clearFilters = useCallback(() => {\n cancelPendingSearch();\n setSearchState('');\n\n const current = state.current;\n const cleared = Object.fromEntries(\n Object.keys(current.filters).map((key) => [key, null]),\n );\n\n visit({ ...cleared, [current.pageKey]: null });\n }, [cancelPendingSearch, visit]);\n\n const setPage = useCallback(\n (pageIndex: number) => {\n visit({\n [state.current.pageKey]:\n pageIndex > 0 ? pageIndex + 1 : null,\n });\n },\n [visit],\n );\n\n const apply = useCallback(\n (changes: Record<string, TableFilterValue>) => {\n cancelPendingSearch();\n visit({ ...changes, [state.current.pageKey]: null });\n },\n [cancelPendingSearch, visit],\n );\n\n return {\n search,\n setSearch,\n filterValues: toFilterValues(filters, [searchKey, pageKey]),\n setFilter,\n clearFilters,\n setPage,\n apply,\n };\n };\n}\n","import type { TourProgress } from '@/blocks/tour';\n\nexport function xsrfToken(): string {\n const cookie = document.cookie\n .split('; ')\n .find((entry) => entry.startsWith('XSRF-TOKEN='));\n\n return cookie ? decodeURIComponent(cookie.slice('XSRF-TOKEN='.length)) : '';\n}\n\nexport function recordTourProgress(url: string, progress: TourProgress): void {\n void fetch(url, {\n method: 'POST',\n credentials: 'same-origin',\n keepalive: true,\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n 'X-Requested-With': 'XMLHttpRequest',\n 'X-XSRF-TOKEN': xsrfToken(),\n },\n body: JSON.stringify({\n version: progress.version,\n last_step: progress.lastStep,\n outcome: progress.outcome,\n }),\n });\n}\n"],"mappings":"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","names":["router","useTableFilters","AppSidebar","AppSidebarHeader","Breadcrumbs","NavMain","SettingsLayout"]}
@@ -1,6 +1,6 @@
1
- import { G as AlertLabels, J as AppearanceToggleLabels, M as ComboboxLabels, ar as CommandPaletteLabels, Q as ConfirmDialogLabels, C as CopyButtonLabels, W as DataTableFacetedFilterLabels, Y as DataTableLabels, a as DateFilterLabels, b as DateFilterOption, a0 as DatePickerLabels, a3 as DateRangeFilterLabels, F as FloatingSheetLabels, as as FullUiLabels, a7 as PasswordInputLabels, ab as SaveStatusLabels, q as SettingsLabels } from '../context-Dqf-5Qne.js';
1
+ import { G as AlertLabels, J as AppearanceToggleLabels, M as ComboboxLabels, ar as CommandPaletteLabels, Q as ConfirmDialogLabels, C as CopyButtonLabels, W as DataTableFacetedFilterLabels, Y as DataTableLabels, a as DateFilterLabels, b as DateFilterOption, a0 as DatePickerLabels, a3 as DateRangeFilterLabels, F as FloatingSheetLabels, as as FullUiLabels, a7 as PasswordInputLabels, ab as SaveStatusLabels, q as SettingsLabels } from '../context-CWkgje9v.js';
2
2
  import { e as DangerZoneLabels, a as FormOverlayLabels, i as TwoFactorLabels } from '../types-CfAUvz--.js';
3
- import { a as LoginFormLabels, e as TourLabels } from '../types-1LUmNJf_.js';
3
+ import { a as LoginFormLabels, e as TourLabels } from '../types-DEJsTx8E.js';
4
4
  import { a as CodeBlockLabels, c as JsonViewerLabels } from '../json-viewer-Bssv9mTD.js';
5
5
  import { f as FieldLabels } from '../field-C1TdmC2t.js';
6
6
  import 'react';
@@ -1,6 +1,6 @@
1
- import { G as AlertLabels, J as AppearanceToggleLabels, M as ComboboxLabels, ar as CommandPaletteLabels, Q as ConfirmDialogLabels, C as CopyButtonLabels, W as DataTableFacetedFilterLabels, Y as DataTableLabels, a as DateFilterLabels, b as DateFilterOption, a0 as DatePickerLabels, a3 as DateRangeFilterLabels, F as FloatingSheetLabels, a7 as PasswordInputLabels, as as FullUiLabels, ab as SaveStatusLabels, q as SettingsLabels } from '../context-Dqf-5Qne.js';
1
+ import { G as AlertLabels, J as AppearanceToggleLabels, M as ComboboxLabels, ar as CommandPaletteLabels, Q as ConfirmDialogLabels, C as CopyButtonLabels, W as DataTableFacetedFilterLabels, Y as DataTableLabels, a as DateFilterLabels, b as DateFilterOption, a0 as DatePickerLabels, a3 as DateRangeFilterLabels, F as FloatingSheetLabels, a7 as PasswordInputLabels, as as FullUiLabels, ab as SaveStatusLabels, q as SettingsLabels } from '../context-CWkgje9v.js';
2
2
  import { e as DangerZoneLabels, a as FormOverlayLabels, i as TwoFactorLabels } from '../types-CfAUvz--.js';
3
- import { a as LoginFormLabels, e as TourLabels } from '../types-1LUmNJf_.js';
3
+ import { a as LoginFormLabels, e as TourLabels } from '../types-DEJsTx8E.js';
4
4
  import { a as CodeBlockLabels, c as JsonViewerLabels } from '../json-viewer-Bssv9mTD.js';
5
5
  import { f as FieldLabels } from '../field-C1TdmC2t.js';
6
6
  import 'react';
package/dist/shells.js CHANGED
@@ -22,7 +22,7 @@ import {
22
22
  UserMenuContent,
23
23
  useCollapsedGroup,
24
24
  useInitials
25
- } from "./chunk-MCHHCLV3.js";
25
+ } from "./chunk-7DAA3DPJ.js";
26
26
  import {
27
27
  SidebarInset,
28
28
  SidebarProvider,
@@ -30,7 +30,7 @@ import {
30
30
  } from "./chunk-PYXUFFMO.js";
31
31
  import {
32
32
  hrefToString
33
- } from "./chunk-L2H5GIF7.js";
33
+ } from "./chunk-VVBBKTC5.js";
34
34
  import "./chunk-EXTOGROG.js";
35
35
  import "./chunk-53V4J7MC.js";
36
36
  import {
@@ -10,6 +10,7 @@ interface LoginFormLabels {
10
10
  }
11
11
  declare const loginFormLabels: LoginFormLabels;
12
12
  type LoginFormErrors = Record<string, string | string[] | undefined>;
13
+ declare function fieldError(errors: LoginFormErrors, field: string): string | undefined;
13
14
 
14
15
  type TourBreakpoint = 'mobile' | 'desktop';
15
16
  type TourOutcome = 'completed' | 'skipped' | 'dismissed';
@@ -38,4 +39,4 @@ interface TourLabels {
38
39
  }
39
40
  declare const DEFAULT_TOUR_LABELS: TourLabels;
40
41
 
41
- export { DEFAULT_TOUR_LABELS as D, type LoginFormErrors as L, type TourStep as T, type LoginFormLabels as a, type TourDefinition as b, type TourBreakpoint as c, type TourProgress as d, type TourLabels as e, type TourOutcome as f, loginFormLabels as l };
42
+ export { DEFAULT_TOUR_LABELS as D, type LoginFormErrors as L, type TourStep as T, type LoginFormLabels as a, type TourDefinition as b, type TourBreakpoint as c, type TourProgress as d, type TourLabels as e, type TourOutcome as f, fieldError as g, loginFormLabels as l };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akira-io/ui",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "Open-source React component library: the full shadcn/ui set on an OKLCH design-token system with swappable brand palettes.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -170,6 +170,7 @@
170
170
  "@tiptap/pm": "3.29.2",
171
171
  "@tiptap/react": "3.29.2",
172
172
  "@tiptap/starter-kit": "3.29.2",
173
+ "@types/node": "^22",
173
174
  "@types/react": "^19.2.10",
174
175
  "@types/react-dom": "^19.2.3",
175
176
  "esbuild-plugin-preserve-directives": "^0.0.11",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/blocks/login-form/types.ts","../src/blocks/login-form/context.tsx","../src/blocks/login-form/parts.tsx","../src/blocks/login-form/preset.tsx","../src/blocks/login-form/index.ts","../src/blocks/tour/gate.ts","../src/blocks/tour/types.ts","../src/blocks/tour/tour.tsx"],"sourcesContent":["export interface LoginFormLabels {\n emailLabel: string;\n emailPlaceholder: string;\n passwordLabel: string;\n passwordPlaceholder: string;\n forgotPasswordLabel: string;\n rememberLabel: string;\n submitLabel: string;\n submittingLabel: string;\n}\n\nexport const loginFormLabels: LoginFormLabels = {\n emailLabel: 'Email address',\n emailPlaceholder: 'email@example.com',\n passwordLabel: 'Password',\n passwordPlaceholder: 'Password',\n forgotPasswordLabel: 'Forgot your password?',\n rememberLabel: 'Remember me',\n submitLabel: 'Log in',\n submittingLabel: 'Signing in',\n};\n\nexport type LoginFormErrors = Record<string, string | string[] | undefined>;\n\nexport function fieldError(\n errors: LoginFormErrors,\n field: string,\n): string | undefined {\n const value = errors[field];\n\n if (!value) {\n return undefined;\n }\n\n const messages = Array.isArray(value) ? value : [value];\n\n return messages.find(\n (message) => typeof message === 'string' && message.length > 0,\n );\n}\n","import {\n loginFormLabels,\n type LoginFormErrors,\n type LoginFormLabels,\n} from '@/blocks/login-form/types';\nimport { useUiLabels } from '@/locales/context';\nimport type { LinkComponent } from '@/types';\nimport { createContext, useContext, type ReactNode } from 'react';\n\nexport interface LoginFormContextValue {\n errors: LoginFormErrors;\n processing: boolean;\n linkComponent?: LinkComponent;\n labels?: Partial<LoginFormLabels>;\n}\n\nconst LoginFormContext = createContext<LoginFormContextValue>({\n errors: {},\n processing: false,\n});\n\nexport function useLoginFormContext(): LoginFormContextValue & {\n labels: LoginFormLabels;\n} {\n const context = useContext(LoginFormContext);\n const labels = useUiLabels('loginForm', loginFormLabels, context.labels);\n\n return { ...context, labels };\n}\n\nexport function LoginFormProvider({\n errors = {},\n processing = false,\n linkComponent,\n labels,\n children,\n}: {\n errors?: LoginFormErrors;\n processing?: boolean;\n linkComponent?: LinkComponent;\n labels?: Partial<LoginFormLabels>;\n children: ReactNode;\n}) {\n return (\n <LoginFormContext.Provider\n value={{\n errors,\n processing,\n linkComponent,\n labels,\n }}\n >\n {children}\n </LoginFormContext.Provider>\n );\n}\n","import {\n LoginFormProvider,\n useLoginFormContext,\n} from '@/blocks/login-form/context';\nimport {\n fieldError,\n type LoginFormErrors,\n type LoginFormLabels,\n} from '@/blocks/login-form/types';\nimport { Alert, AlertDescription } from '@/components/ui/alert';\nimport { Button } from '@/components/ui/button';\nimport { Checkbox } from '@/components/ui/checkbox';\nimport { Field, FieldControl, FieldLabel } from '@/components/ui/field';\nimport { Input } from '@/components/ui/input';\nimport { Label } from '@/components/ui/label';\nimport { PasswordInput } from '@/components/ui/password-input';\nimport { resolveLink } from '@/lib/href';\nimport { cn } from '@/lib/utils';\nimport type { LinkComponent, SlotNameProps, UrlLike } from '@/types';\nimport type { ReactNode } from 'react';\n\nexport interface LoginFormRootProps {\n errors?: LoginFormErrors;\n processing?: boolean;\n linkComponent?: LinkComponent;\n labels?: Partial<LoginFormLabels>;\n children: ReactNode;\n className?: string;\n}\n\nexport function LoginFormRoot({\n errors,\n processing,\n linkComponent,\n labels,\n children,\n className,\n slotName = 'login-form',\n}: LoginFormRootProps & SlotNameProps) {\n return (\n <LoginFormProvider\n errors={errors}\n processing={processing}\n linkComponent={linkComponent}\n labels={labels}\n >\n <div data-slot={slotName} className={cn('gap-6 grid', className)}>\n {children}\n </div>\n </LoginFormProvider>\n );\n}\n\nexport interface LoginFormStatusProps {\n message?: string;\n}\n\nexport function LoginFormStatus({\n message,\n slotName = 'login-form-status',\n}: LoginFormStatusProps & SlotNameProps) {\n if (!message) {\n return null;\n }\n\n return (\n <Alert slotName={slotName}>\n <AlertDescription>{message}</AlertDescription>\n </Alert>\n );\n}\n\nexport interface LoginFormEmailProps {\n id?: string;\n name?: string;\n label?: string;\n placeholder?: string;\n error?: string;\n tabIndex?: number;\n autoFocus?: boolean;\n required?: boolean;\n}\n\nexport function LoginFormEmail({\n id = 'email',\n name = 'email',\n label,\n placeholder,\n error,\n tabIndex,\n autoFocus = true,\n required = true,\n slotName = 'login-form-email',\n}: LoginFormEmailProps & SlotNameProps) {\n const { errors, labels } = useLoginFormContext();\n const message = error ?? fieldError(errors, name);\n\n return (\n <Field id={id} error={message} required={required} slotName={slotName}>\n <FieldLabel>{label ?? labels.emailLabel}</FieldLabel>\n <FieldControl>\n <Input\n name={name}\n type=\"email\"\n required={required}\n autoFocus={autoFocus}\n autoComplete=\"email\"\n tabIndex={tabIndex}\n placeholder={placeholder ?? labels.emailPlaceholder}\n />\n </FieldControl>\n </Field>\n );\n}\n\nexport interface LoginFormPasswordProps {\n id?: string;\n name?: string;\n label?: string;\n placeholder?: string;\n error?: string;\n tabIndex?: number;\n autoFocus?: boolean;\n required?: boolean;\n forgotPasswordHref?: UrlLike;\n forgotPasswordLabel?: string;\n linkComponent?: LinkComponent;\n}\n\nexport function LoginFormPassword({\n id = 'password',\n name = 'password',\n label,\n placeholder,\n error,\n tabIndex,\n autoFocus = false,\n required = true,\n forgotPasswordHref,\n forgotPasswordLabel,\n linkComponent,\n slotName = 'login-form-password',\n}: LoginFormPasswordProps & SlotNameProps) {\n const context = useLoginFormContext();\n const message = error ?? fieldError(context.errors, name);\n const Link = resolveLink(linkComponent ?? context.linkComponent);\n\n return (\n <Field id={id} error={message} required={required} slotName={slotName}>\n <FieldLabel>{label ?? context.labels.passwordLabel}</FieldLabel>\n <FieldControl>\n <PasswordInput\n name={name}\n required={required}\n autoFocus={autoFocus}\n autoComplete=\"current-password\"\n tabIndex={tabIndex}\n placeholder={\n placeholder ?? context.labels.passwordPlaceholder\n }\n />\n </FieldControl>\n {forgotPasswordHref && (\n <Link\n href={forgotPasswordHref}\n className=\"mr-1 text-xs font-medium self-end text-muted-foreground underline-offset-4 transition-colors hover:text-foreground hover:underline\"\n >\n {forgotPasswordLabel ?? context.labels.forgotPasswordLabel}\n </Link>\n )}\n </Field>\n );\n}\n\nexport interface LoginFormRememberProps {\n id?: string;\n name?: string;\n label?: string;\n tabIndex?: number;\n}\n\nexport function LoginFormRemember({\n id = 'remember',\n name = 'remember',\n label,\n tabIndex,\n slotName = 'login-form-remember',\n}: LoginFormRememberProps & SlotNameProps) {\n const { labels } = useLoginFormContext();\n\n return (\n <div data-slot={slotName} className=\"gap-3 flex items-center\">\n <Checkbox id={id} name={name} tabIndex={tabIndex} />\n <Label htmlFor={id}>{label ?? labels.rememberLabel}</Label>\n </div>\n );\n}\n\nexport interface LoginFormSubmitProps {\n label?: string;\n submittingLabel?: string;\n processing?: boolean;\n tabIndex?: number;\n}\n\nexport function LoginFormSubmit({\n label,\n submittingLabel,\n processing,\n tabIndex,\n slotName = 'login-form-submit',\n}: LoginFormSubmitProps & SlotNameProps) {\n const context = useLoginFormContext();\n const pending = processing ?? context.processing;\n const pendingLabel = submittingLabel ?? context.labels.submittingLabel;\n\n return (\n <Button\n slotName={slotName}\n type=\"submit\"\n className=\"w-full\"\n tabIndex={tabIndex}\n aria-label={pending ? pendingLabel : undefined}\n loading={pending}\n loadingLabel={pendingLabel}\n >\n {pending ? pendingLabel : (label ?? context.labels.submitLabel)}\n </Button>\n );\n}\n","import {\n LoginFormEmail,\n LoginFormPassword,\n LoginFormRemember,\n LoginFormRoot,\n LoginFormStatus,\n LoginFormSubmit,\n} from '@/blocks/login-form/parts';\nimport type {\n LoginFormErrors,\n LoginFormLabels,\n} from '@/blocks/login-form/types';\nimport type { LinkComponent, SlotNameProps, UrlLike } from '@/types';\n\nexport interface LoginFormPresetProps {\n errors?: LoginFormErrors;\n processing?: boolean;\n linkComponent?: LinkComponent;\n labels?: Partial<LoginFormLabels>;\n status?: string;\n forgotPasswordHref?: UrlLike;\n className?: string;\n}\n\nexport function LoginFormPreset({\n errors,\n processing,\n linkComponent,\n labels,\n status,\n forgotPasswordHref,\n className,\n slotName = 'login-form',\n}: LoginFormPresetProps & SlotNameProps) {\n return (\n <LoginFormRoot\n errors={errors}\n processing={processing}\n linkComponent={linkComponent}\n labels={labels}\n className={className}\n slotName={slotName}\n >\n <LoginFormStatus message={status} />\n <LoginFormEmail />\n <LoginFormPassword forgotPasswordHref={forgotPasswordHref} />\n <LoginFormRemember />\n <LoginFormSubmit />\n </LoginFormRoot>\n );\n}\n","import {\n LoginFormEmail,\n LoginFormPassword,\n LoginFormRemember,\n LoginFormRoot,\n LoginFormStatus,\n LoginFormSubmit,\n} from '@/blocks/login-form/parts';\n\nexport const LoginForm = {\n Root: LoginFormRoot,\n Status: LoginFormStatus,\n Email: LoginFormEmail,\n Password: LoginFormPassword,\n Remember: LoginFormRemember,\n Submit: LoginFormSubmit,\n};\n\nexport {\n LoginFormProvider,\n useLoginFormContext,\n type LoginFormContextValue,\n} from '@/blocks/login-form/context';\nexport {\n LoginFormEmail,\n LoginFormPassword,\n LoginFormRemember,\n LoginFormRoot,\n LoginFormStatus,\n LoginFormSubmit,\n type LoginFormEmailProps,\n type LoginFormPasswordProps,\n type LoginFormRememberProps,\n type LoginFormRootProps,\n type LoginFormStatusProps,\n type LoginFormSubmitProps,\n} from '@/blocks/login-form/parts';\nexport {\n LoginFormPreset,\n type LoginFormPresetProps,\n} from '@/blocks/login-form/preset';\nexport {\n loginFormLabels,\n type LoginFormErrors,\n type LoginFormLabels,\n} from '@/blocks/login-form/types';\n","import type {\n TourBreakpoint,\n TourDefinition,\n TourStep,\n} from '@/blocks/tour/types';\n\nexport function stepsForBreakpoint(\n steps: TourStep[],\n breakpoint: TourBreakpoint,\n): TourStep[] {\n return steps.filter(\n (step) => !step.breakpoints || step.breakpoints.includes(breakpoint),\n );\n}\n\nexport function resolveSteps(\n steps: TourStep[],\n isPresent: (target: string) => boolean,\n): TourStep[] {\n return steps.filter((step) => isPresent(step.target));\n}\n\nexport function shouldStartTour(input: {\n definition: TourDefinition;\n seen: Record<string, number>;\n resolvedStepCount: number;\n force?: boolean;\n}): boolean {\n if (input.resolvedStepCount === 0) {\n return false;\n }\n\n if (input.force) {\n return true;\n }\n\n return input.definition.version > (input.seen[input.definition.id] ?? 0);\n}\n","export type TourBreakpoint = 'mobile' | 'desktop';\n\nexport type TourOutcome = 'completed' | 'skipped' | 'dismissed';\n\nexport interface TourStep {\n target: string;\n title: string;\n description: string;\n breakpoints?: TourBreakpoint[];\n}\n\nexport interface TourDefinition {\n id: string;\n version: number;\n steps: TourStep[];\n}\n\nexport interface TourProgress {\n tour: string;\n version: number;\n lastStep: number;\n outcome: TourOutcome;\n}\n\nexport interface TourLabels {\n next: string;\n previous: string;\n done: string;\n progress: string;\n}\n\nexport const DEFAULT_TOUR_LABELS: TourLabels = {\n next: 'Next',\n previous: 'Previous',\n done: 'Done',\n progress: '{{current}} of {{total}}',\n};\n","import { driver, type Driver } from 'driver.js';\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n type PropsWithChildren,\n type ReactElement,\n} from 'react';\n\nimport 'driver.js/dist/driver.css';\n\nimport { shouldStartTour, stepsForBreakpoint } from '@/blocks/tour/gate';\nimport {\n DEFAULT_TOUR_LABELS,\n type TourBreakpoint,\n type TourDefinition,\n type TourLabels,\n type TourOutcome,\n type TourProgress,\n} from '@/blocks/tour/types';\nimport { useUiLabels } from '@/locales/context';\n\ninterface TourControllerValue {\n startTour: (\n definition: TourDefinition,\n options?: { force?: boolean },\n ) => void;\n}\n\nconst TourContext = createContext<TourControllerValue | null>(null);\n\nconst MOBILE_BREAKPOINT = 768;\n\nconst WAIT_FOR_TARGET = 4000;\n\nfunction currentBreakpoint(): TourBreakpoint {\n return window.innerWidth < MOBILE_BREAKPOINT ? 'mobile' : 'desktop';\n}\n\nfunction outcomeOf(instance: Driver, highlighted: boolean): TourOutcome {\n if (!highlighted) {\n return 'dismissed';\n }\n\n return instance.hasNextStep() ? 'skipped' : 'completed';\n}\n\nexport function TourProvider({\n children,\n seen,\n onProgress,\n labels,\n}: PropsWithChildren<{\n seen: Record<string, number>;\n onProgress: (progress: TourProgress) => void;\n labels?: Partial<TourLabels>;\n}>): ReactElement {\n const seenRef = useRef(seen);\n seenRef.current = seen;\n\n const onProgressRef = useRef(onProgress);\n onProgressRef.current = onProgress;\n\n const driverRef = useRef<Driver | null>(null);\n const activeRef = useRef<{\n definition: TourDefinition;\n lastStep: number;\n highlighted: boolean;\n } | null>(null);\n\n const { next, previous, done, progress } = useUiLabels(\n 'tour',\n DEFAULT_TOUR_LABELS,\n labels,\n );\n\n const report = useCallback((outcome: TourOutcome): void => {\n const active = activeRef.current;\n\n if (!active) {\n return;\n }\n\n activeRef.current = null;\n\n onProgressRef.current({\n tour: active.definition.id,\n version: active.definition.version,\n lastStep: active.lastStep,\n outcome,\n });\n }, []);\n\n const startTour = useCallback(\n (definition: TourDefinition, options?: { force?: boolean }): void => {\n const alreadyRunning =\n activeRef.current?.definition.id === definition.id;\n\n if (alreadyRunning && !options?.force) {\n return;\n }\n\n const steps = stepsForBreakpoint(\n definition.steps,\n currentBreakpoint(),\n );\n\n const allowed = shouldStartTour({\n definition,\n seen: seenRef.current,\n resolvedStepCount: steps.length,\n force: options?.force,\n });\n\n if (!allowed) {\n return;\n }\n\n driverRef.current?.destroy();\n activeRef.current = { definition, lastStep: 0, highlighted: false };\n\n const instance = driver({\n showProgress: true,\n progressText: progress,\n nextBtnText: next,\n prevBtnText: previous,\n doneBtnText: done,\n popoverClass: 'akira-tour',\n waitForElement: WAIT_FOR_TARGET,\n skipMissingElement: true,\n steps: steps.map((step) => ({\n element: step.target,\n popover: {\n title: step.title,\n description: step.description,\n },\n })),\n onHighlightStarted: () => {\n if (activeRef.current) {\n activeRef.current.lastStep =\n instance.getActiveIndex() ?? 0;\n activeRef.current.highlighted = true;\n }\n },\n onDestroyStarted: () => {\n report(\n outcomeOf(\n instance,\n activeRef.current?.highlighted ?? false,\n ),\n );\n instance.destroy();\n },\n });\n\n driverRef.current = instance;\n instance.drive();\n },\n [report, next, previous, done, progress],\n );\n\n useEffect(\n () => () => {\n report('dismissed');\n driverRef.current?.destroy();\n driverRef.current = null;\n },\n [report],\n );\n\n const value = useMemo(() => ({ startTour }), [startTour]);\n\n return (\n <TourContext.Provider value={value}>{children}</TourContext.Provider>\n );\n}\n\nexport function useTourController(): TourControllerValue {\n const context = useContext(TourContext);\n\n if (!context) {\n throw new Error(\n 'useTourController must be used inside a TourProvider.',\n );\n }\n\n return context;\n}\n\nexport function useTour(\n definition: TourDefinition,\n options?: { enabled?: boolean },\n): { restart: () => void } {\n const { startTour } = useTourController();\n const enabled = options?.enabled ?? true;\n\n const definitionRef = useRef(definition);\n definitionRef.current = definition;\n\n useEffect(() => {\n if (!enabled) {\n return;\n }\n\n const frame = window.requestAnimationFrame(() =>\n startTour(definitionRef.current),\n );\n\n return () => window.cancelAnimationFrame(frame);\n }, [definition.id, definition.version, enabled, startTour]);\n\n return { restart: () => startTour(definitionRef.current, { force: true }) };\n}\n"],"mappings":"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","names":["jsx","jsx","jsxs","createContext","useContext","jsx","createContext","useContext"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/href.ts"],"sourcesContent":["import type { ComponentType } from 'react';\nimport { createElement } from 'react';\n\nimport type { LinkComponent, LinkProps, UrlLike } from '@/types';\n\nexport function hrefToString(href: UrlLike): string {\n return typeof href === 'string' ? href : href.url;\n}\n\nexport const DefaultLink: ComponentType<LinkProps> = ({\n href,\n children,\n prefetch: _prefetch,\n as: _as,\n ...props\n}) => {\n return createElement('a', { href: hrefToString(href), ...props }, children);\n};\n\nexport function resolveLink(linkComponent?: LinkComponent): LinkComponent {\n return linkComponent ?? DefaultLink;\n}\n"],"mappings":";AACA,SAAS,qBAAqB;AAIvB,SAAS,aAAa,MAAuB;AAChD,SAAO,OAAO,SAAS,WAAW,OAAO,KAAK;AAClD;AAEO,IAAM,cAAwC,CAAC;AAAA,EAClD;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV,IAAI;AAAA,EACJ,GAAG;AACP,MAAM;AACF,SAAO,cAAc,KAAK,EAAE,MAAM,aAAa,IAAI,GAAG,GAAG,MAAM,GAAG,QAAQ;AAC9E;AAEO,SAAS,YAAY,eAA8C;AACtE,SAAO,iBAAiB;AAC5B;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/hooks/use-collapsed-groups.tsx","../src/hooks/use-initials.tsx","../src/shells/nav-footer.tsx","../src/shells/nav-main.tsx","../src/shells/user-info.tsx","../src/shells/user-menu-content.tsx","../src/shells/nav-user.tsx","../src/shells/app-sidebar.tsx","../src/shells/breadcrumbs.tsx","../src/shells/app-sidebar-header.tsx","../src/shells/heading.tsx","../src/shells/settings-layout.tsx"],"sourcesContent":["import { useCallback, useState } from 'react';\n\nexport const SIDEBAR_COLLAPSED_GROUPS_KEY = 'akira-ui:collapsed-nav-groups';\n\nfunction readCollapsedGroups(): string[] | null {\n if (typeof window === 'undefined') {\n return null;\n }\n\n try {\n const raw = window.localStorage.getItem(SIDEBAR_COLLAPSED_GROUPS_KEY);\n\n if (raw === null) {\n return null;\n }\n\n const parsed: unknown = JSON.parse(raw);\n\n return Array.isArray(parsed)\n ? parsed.filter(\n (entry): entry is string => typeof entry === 'string',\n )\n : null;\n } catch {\n return null;\n }\n}\n\nfunction writeCollapsedGroups(groups: string[]): void {\n if (typeof window === 'undefined') {\n return;\n }\n\n try {\n window.localStorage.setItem(\n SIDEBAR_COLLAPSED_GROUPS_KEY,\n JSON.stringify(groups),\n );\n } catch {\n return;\n }\n}\n\nfunction withGroup(groups: string[], group: string, collapsed: boolean) {\n if (!collapsed) {\n return groups.filter((entry) => entry !== group);\n }\n\n return groups.includes(group) ? groups : [...groups, group];\n}\n\nexport interface CollapsedGroupsOptions {\n group: string;\n defaultOpen?: boolean;\n collapsedGroups?: string[];\n onCollapsedChange?: (collapsedGroups: string[]) => void;\n}\n\nexport function useCollapsedGroup({\n group,\n defaultOpen = true,\n collapsedGroups,\n onCollapsedChange,\n}: CollapsedGroupsOptions) {\n const isControlled =\n collapsedGroups !== undefined && onCollapsedChange !== undefined;\n\n const [storedGroups, setStoredGroups] = useState<string[]>(\n () => readCollapsedGroups() ?? (defaultOpen ? [] : [group]),\n );\n\n const setOpen = useCallback(\n (open: boolean) => {\n if (isControlled) {\n onCollapsedChange(withGroup(collapsedGroups, group, !open));\n\n return;\n }\n\n const next = withGroup(\n readCollapsedGroups() ?? storedGroups,\n group,\n !open,\n );\n\n setStoredGroups(next);\n writeCollapsedGroups(next);\n },\n [collapsedGroups, group, isControlled, onCollapsedChange, storedGroups],\n );\n\n const source = isControlled ? collapsedGroups : storedGroups;\n\n return { open: !source.includes(group), setOpen };\n}\n","import { useCallback } from 'react';\n\nexport function useInitials() {\n return useCallback((fullName: string): string => {\n const names = fullName.trim().split(' ');\n\n if (names.length === 0) return '';\n if (names.length === 1) return names[0].charAt(0).toUpperCase();\n\n const firstInitial = names[0].charAt(0);\n const lastInitial = names[names.length - 1].charAt(0);\n\n return `${firstInitial}${lastInitial}`.toUpperCase();\n }, []);\n}\n","import { type ComponentPropsWithoutRef } from 'react';\n\nimport { Icon } from '@/components/ui/icon';\nimport {\n SidebarGroup,\n SidebarGroupContent,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n} from '@/components/ui/sidebar';\nimport { hrefToString } from '@/lib/href';\nimport type { NavItem } from '@/types';\n\nexport function NavFooter({\n items,\n className,\n ...props\n}: ComponentPropsWithoutRef<typeof SidebarGroup> & {\n items: NavItem[];\n}) {\n return (\n <SidebarGroup\n {...props}\n className={`group-data-[collapsible=icon]:p-0 ${className || ''}`}\n >\n <SidebarGroupContent>\n <SidebarMenu>\n {items.map((item) => (\n <SidebarMenuItem key={item.title}>\n <SidebarMenuButton\n asChild\n className=\"text-muted-foreground hover:text-foreground\"\n >\n <a\n href={hrefToString(item.href)}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {item.icon && (\n <Icon\n iconNode={item.icon}\n className=\"h-5 w-5\"\n />\n )}\n <span>{item.title}</span>\n </a>\n </SidebarMenuButton>\n </SidebarMenuItem>\n ))}\n </SidebarMenu>\n </SidebarGroupContent>\n </SidebarGroup>\n );\n}\n","import { ChevronDown } from 'lucide-react';\n\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from '@/components/ui/collapsible';\nimport {\n SidebarGroup,\n SidebarGroupLabel,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n} from '@/components/ui/sidebar';\nimport { useCollapsedGroup } from '@/hooks/use-collapsed-groups';\nimport { hrefToString, resolveLink } from '@/lib/href';\nimport { cn } from '@/lib/utils';\nimport type { LinkComponent, NavItem } from '@/types';\n\nfunction isItemActive(item: NavItem, currentUrl: string): boolean {\n if (item.isActive !== undefined) {\n return item.isActive;\n }\n\n if (!currentUrl) {\n return false;\n }\n\n return currentUrl.startsWith(hrefToString(item.href));\n}\n\nexport interface NavMainProps {\n items: NavItem[];\n label?: string;\n currentUrl?: string;\n linkComponent?: LinkComponent;\n collapsible?: boolean;\n defaultOpen?: boolean;\n collapsedGroups?: string[];\n onCollapsedChange?: (collapsedGroups: string[]) => void;\n}\n\nexport function NavMain({\n items = [],\n label = 'Platform',\n currentUrl = '',\n linkComponent,\n collapsible = false,\n defaultOpen = true,\n collapsedGroups,\n onCollapsedChange,\n}: NavMainProps) {\n const Link = resolveLink(linkComponent);\n const holdsCurrentRoute = items.some((item) =>\n isItemActive(item, currentUrl),\n );\n const { open, setOpen } = useCollapsedGroup({\n group: label,\n defaultOpen,\n collapsedGroups,\n onCollapsedChange,\n });\n const expanded = open || holdsCurrentRoute;\n\n const menu = (\n <SidebarMenu>\n {items.map((item) => (\n <SidebarMenuItem key={item.title}>\n <SidebarMenuButton\n asChild\n isActive={isItemActive(item, currentUrl)}\n tooltip={{ children: item.title }}\n >\n <Link href={item.href} prefetch>\n {item.icon && <item.icon />}\n <span>{item.title}</span>\n </Link>\n </SidebarMenuButton>\n </SidebarMenuItem>\n ))}\n </SidebarMenu>\n );\n\n if (!collapsible || !label) {\n return (\n <SidebarGroup className=\"px-2 py-0\">\n {label && <SidebarGroupLabel>{label}</SidebarGroupLabel>}\n {menu}\n </SidebarGroup>\n );\n }\n\n return (\n <SidebarGroup className=\"px-2 py-0\">\n <Collapsible open={expanded} onOpenChange={setOpen}>\n <CollapsibleTrigger asChild>\n <SidebarGroupLabel className=\"w-full cursor-pointer justify-between\">\n {label}\n <ChevronDown\n className={cn(\n 'size-4 transition-transform',\n !expanded && '-rotate-90',\n )}\n />\n </SidebarGroupLabel>\n </CollapsibleTrigger>\n <CollapsibleContent>{menu}</CollapsibleContent>\n </Collapsible>\n </SidebarGroup>\n );\n}\n","import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';\nimport { useInitials } from '@/hooks/use-initials';\nimport { compactRadius } from '@/lib/language';\nimport { cn } from '@/lib/utils';\nimport type { SharedUser } from '@/types';\n\nexport function UserInfo({\n user,\n showEmail = false,\n}: {\n user: SharedUser;\n showEmail?: boolean;\n}) {\n const getInitials = useInitials();\n\n return (\n <>\n <Avatar\n className={cn(\n compactRadius,\n 'group-data-[collapsible=icon]:size-10',\n )}\n >\n <AvatarImage src={user.avatar} alt={user.name} />\n <AvatarFallback\n className={cn(compactRadius, 'bg-muted text-foreground')}\n >\n {getInitials(user.name)}\n </AvatarFallback>\n </Avatar>\n <div\n data-slot=\"user-info-identity\"\n className=\"text-sm leading-tight grid flex-1 text-left group-data-[collapsible=icon]:hidden\"\n >\n <span className=\"font-medium truncate\">{user.name}</span>\n {showEmail && (\n <span className=\"text-xs truncate text-muted-foreground\">\n {user.email}\n </span>\n )}\n </div>\n </>\n );\n}\n","import { LogOut, Settings } from 'lucide-react';\n\nimport {\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n} from '@/components/ui/dropdown-menu';\nimport { resolveLink } from '@/lib/href';\nimport type { LinkComponent, SharedUser, UrlLike } from '@/types';\nimport { UserInfo } from './user-info';\n\ninterface UserMenuContentProps {\n user: SharedUser;\n settingsHref: UrlLike;\n logoutHref: UrlLike;\n linkComponent?: LinkComponent;\n onSettingsClick?: () => void;\n onLogout?: () => void;\n settingsLabel?: string;\n logoutLabel?: string;\n}\n\nexport function UserMenuContent({\n user,\n settingsHref,\n logoutHref,\n linkComponent,\n onSettingsClick,\n onLogout,\n settingsLabel = 'Settings',\n logoutLabel = 'Log out',\n}: UserMenuContentProps) {\n const Link = resolveLink(linkComponent);\n\n return (\n <>\n <DropdownMenuLabel className=\"p-0 font-normal\">\n <div className=\"gap-2 px-1 py-1.5 text-sm flex items-center text-left\">\n <UserInfo user={user} showEmail={true} />\n </div>\n </DropdownMenuLabel>\n <DropdownMenuSeparator />\n <DropdownMenuGroup>\n <DropdownMenuItem asChild>\n <Link\n className=\"block w-full\"\n href={settingsHref}\n as=\"button\"\n prefetch\n onClick={onSettingsClick}\n >\n <Settings className=\"mr-2\" />\n {settingsLabel}\n </Link>\n </DropdownMenuItem>\n </DropdownMenuGroup>\n <DropdownMenuSeparator />\n <DropdownMenuItem asChild>\n <Link\n className=\"block w-full\"\n href={logoutHref}\n as=\"button\"\n onClick={onLogout}\n data-test=\"logout-button\"\n >\n <LogOut className=\"mr-2\" />\n {logoutLabel}\n </Link>\n </DropdownMenuItem>\n </>\n );\n}\n","import { ChevronsUpDown } from 'lucide-react';\n\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu';\nimport {\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n useSidebar,\n} from '@/components/ui/sidebar';\nimport { useIsMobile } from '@/hooks/use-mobile';\nimport type { LinkComponent, SharedUser, UrlLike } from '@/types';\nimport { UserInfo } from './user-info';\nimport { UserMenuContent } from './user-menu-content';\n\ninterface NavUserProps {\n user: SharedUser;\n settingsHref: UrlLike;\n logoutHref: UrlLike;\n linkComponent?: LinkComponent;\n onSettingsClick?: () => void;\n onLogout?: () => void;\n}\n\nexport function NavUser({\n user,\n settingsHref,\n logoutHref,\n linkComponent,\n onSettingsClick,\n onLogout,\n}: NavUserProps) {\n const { state } = useSidebar();\n const isMobile = useIsMobile();\n\n return (\n <SidebarMenu>\n <SidebarMenuItem>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <SidebarMenuButton\n className=\"group group-data-[collapsible=icon]:p-0! cursor-pointer bg-sidebar-accent text-sidebar-accent-foreground hover:bg-sidebar-accent-hover data-[state=open]:bg-sidebar-accent-hover\"\n data-test=\"sidebar-menu-button\"\n >\n <UserInfo user={user} />\n <ChevronsUpDown\n data-slot=\"nav-user-chevron\"\n className=\"size-4 ml-auto group-data-[collapsible=icon]:hidden\"\n />\n </SidebarMenuButton>\n </DropdownMenuTrigger>\n <DropdownMenuContent\n className=\"min-w-56 rounded-xl w-(--radix-dropdown-menu-trigger-width)\"\n align=\"end\"\n side={\n isMobile\n ? 'bottom'\n : state === 'collapsed'\n ? 'left'\n : 'bottom'\n }\n >\n <UserMenuContent\n user={user}\n settingsHref={settingsHref}\n logoutHref={logoutHref}\n linkComponent={linkComponent}\n onSettingsClick={onSettingsClick}\n onLogout={onLogout}\n />\n </DropdownMenuContent>\n </DropdownMenu>\n </SidebarMenuItem>\n </SidebarMenu>\n );\n}\n","import { type ReactNode } from 'react';\n\nimport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarHeader,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n} from '@/components/ui/sidebar';\nimport { hrefToString, resolveLink } from '@/lib/href';\nimport type {\n LinkComponent,\n NavGroup,\n NavItem,\n SharedUser,\n UrlLike,\n} from '@/types';\nimport { NavFooter } from './nav-footer';\nimport { NavMain } from './nav-main';\nimport { NavUser } from './nav-user';\n\nfunction mostSpecificActiveHref(\n groups: NavGroup[],\n currentUrl: string,\n): string {\n let best = '';\n for (const group of groups) {\n for (const item of group.items) {\n const href = hrefToString(item.href);\n const matches =\n currentUrl === href || currentUrl.startsWith(`${href}/`);\n if (matches && href.length > best.length) {\n best = href;\n }\n }\n }\n return best;\n}\n\ninterface AppSidebarProps {\n logo: ReactNode;\n logoHref: UrlLike;\n groups: NavGroup[];\n footerItems?: NavItem[];\n user: SharedUser;\n settingsHref: UrlLike;\n logoutHref: UrlLike;\n currentUrl?: string;\n linkComponent?: LinkComponent;\n collapsibleGroups?: boolean;\n collapsedGroups?: string[];\n onCollapsedChange?: (collapsedGroups: string[]) => void;\n onSettingsClick?: () => void;\n onLogout?: () => void;\n}\n\nexport function AppSidebar({\n logo,\n logoHref,\n groups,\n footerItems = [],\n user,\n settingsHref,\n logoutHref,\n currentUrl = '',\n linkComponent,\n collapsibleGroups = false,\n collapsedGroups,\n onCollapsedChange,\n onSettingsClick,\n onLogout,\n}: AppSidebarProps) {\n const Link = resolveLink(linkComponent);\n const activeHref = mostSpecificActiveHref(groups, currentUrl);\n const resolvedGroups = groups.map((group) => ({\n ...group,\n items: group.items.map((item) => ({\n ...item,\n isActive: hrefToString(item.href) === activeHref,\n })),\n }));\n\n return (\n <Sidebar collapsible=\"icon\" variant=\"inset\">\n <SidebarHeader>\n <SidebarMenu>\n <SidebarMenuItem>\n <SidebarMenuButton asChild>\n <Link href={logoHref} prefetch>\n {logo}\n </Link>\n </SidebarMenuButton>\n </SidebarMenuItem>\n </SidebarMenu>\n </SidebarHeader>\n\n <SidebarContent>\n {resolvedGroups.map((group, index) => (\n <NavMain\n key={group.label ?? index}\n items={group.items}\n label={group.label ?? ''}\n currentUrl={currentUrl}\n linkComponent={linkComponent}\n collapsible={collapsibleGroups}\n collapsedGroups={collapsedGroups}\n onCollapsedChange={onCollapsedChange}\n />\n ))}\n </SidebarContent>\n\n <SidebarFooter>\n {footerItems.length > 0 && (\n <NavFooter items={footerItems} className=\"mt-auto\" />\n )}\n <NavUser\n user={user}\n settingsHref={settingsHref}\n logoutHref={logoutHref}\n linkComponent={linkComponent}\n onSettingsClick={onSettingsClick}\n onLogout={onLogout}\n />\n </SidebarFooter>\n </Sidebar>\n );\n}\n","import { Fragment } from 'react';\n\nimport {\n Breadcrumb,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from '@/components/ui/breadcrumb';\nimport { resolveLink } from '@/lib/href';\nimport type {\n BreadcrumbItem as BreadcrumbItemType,\n LinkComponent,\n} from '@/types';\n\nexport function Breadcrumbs({\n breadcrumbs,\n linkComponent,\n}: {\n breadcrumbs: BreadcrumbItemType[];\n linkComponent?: LinkComponent;\n}) {\n const Link = resolveLink(linkComponent);\n\n if (breadcrumbs.length === 0) {\n return null;\n }\n\n return (\n <Breadcrumb>\n <BreadcrumbList>\n {breadcrumbs.map((item, index) => {\n const isLast = index === breadcrumbs.length - 1;\n return (\n <Fragment key={index}>\n <BreadcrumbItem>\n {isLast ? (\n <BreadcrumbPage>\n {item.title}\n </BreadcrumbPage>\n ) : (\n <BreadcrumbLink asChild>\n <Link href={item.href}>\n {item.title}\n </Link>\n </BreadcrumbLink>\n )}\n </BreadcrumbItem>\n {!isLast && <BreadcrumbSeparator />}\n </Fragment>\n );\n })}\n </BreadcrumbList>\n </Breadcrumb>\n );\n}\n","import { Search } from 'lucide-react';\nimport { useEffect, useState } from 'react';\n\nimport { SidebarTrigger } from '@/components/ui/sidebar';\nimport type {\n BreadcrumbItem as BreadcrumbItemType,\n LinkComponent,\n} from '@/types';\nimport { Breadcrumbs } from './breadcrumbs';\n\ninterface AppSidebarHeaderProps {\n breadcrumbs?: BreadcrumbItemType[];\n linkComponent?: LinkComponent;\n onSearchClick?: () => void;\n searchLabel?: string;\n}\n\nexport function AppSidebarHeader({\n breadcrumbs = [],\n linkComponent,\n onSearchClick,\n searchLabel = 'Search...',\n}: AppSidebarHeaderProps) {\n const [modifier, setModifier] = useState('Ctrl');\n\n useEffect(() => {\n const platform = navigator.userAgent;\n setModifier(/Mac|iPhone|iPad|iPod/.test(platform) ? '⌘' : 'Ctrl');\n }, []);\n\n return (\n <header className=\"h-16 gap-2 px-6 group-has-data-[collapsible=icon]/sidebar-wrapper:h-12 md:px-4 flex shrink-0 items-center border-b border-sidebar-border/50 transition-[width,height] ease-linear\">\n <div className=\"gap-2 flex items-center\">\n <SidebarTrigger className=\"-ml-1\" />\n <Breadcrumbs\n breadcrumbs={breadcrumbs}\n linkComponent={linkComponent}\n />\n </div>\n\n {onSearchClick && (\n <button\n type=\"button\"\n onClick={onSearchClick}\n className=\"h-9 w-56 gap-2 rounded-xl px-3 text-sm ml-auto flex items-center border border-border/60 bg-muted/30 text-muted-foreground transition-colors hover:bg-muted/50\"\n >\n <Search className=\"size-4\" />\n <span>{searchLabel}</span>\n <kbd className=\"gap-0.5 px-1.5 py-0.5 font-semibold rounded-xl ml-auto inline-flex items-center border border-border/60 bg-background font-sans text-[10px] text-muted-foreground\">\n <span>{modifier}</span>\n <span>K</span>\n </kbd>\n </button>\n )}\n </header>\n );\n}\n","export function Heading({\n title,\n description,\n}: {\n title: string;\n description?: string;\n}) {\n return (\n <div className=\"mb-8 space-y-0.5\">\n <h2 className=\"text-xl font-semibold tracking-tight\">{title}</h2>\n {description && (\n <p className=\"text-sm text-muted-foreground\">{description}</p>\n )}\n </div>\n );\n}\n","import { type PropsWithChildren } from 'react';\n\nimport { Button } from '@/components/ui/button';\nimport { Separator } from '@/components/ui/separator';\nimport { hrefToString, resolveLink } from '@/lib/href';\nimport { cn } from '@/lib/utils';\nimport type { LinkComponent, NavItem } from '@/types';\nimport { Heading } from './heading';\n\nexport interface SettingsLayoutProps {\n items: NavItem[];\n linkComponent?: LinkComponent;\n currentPath?: string;\n title?: string;\n description?: string;\n wide?: boolean;\n}\n\nexport function SettingsLayout({\n items,\n linkComponent,\n currentPath,\n title = 'Settings',\n description = 'Manage your profile and account settings',\n wide = false,\n children,\n}: PropsWithChildren<SettingsLayoutProps>) {\n const Link = resolveLink(linkComponent);\n const activePath =\n currentPath ??\n (typeof window === 'undefined' ? '' : window.location.pathname);\n\n return (\n <div className=\"px-4 py-6\">\n <Heading title={title} description={description} />\n\n <div className=\"lg:flex-row lg:space-x-12 flex flex-col\">\n <aside className=\"max-w-xl lg:w-48 w-full\">\n <nav className=\"space-y-1 space-x-0 flex flex-col\">\n {items.map((item, index) => {\n const href = hrefToString(item.href);\n return (\n <Button\n key={`${href}-${index}`}\n size=\"sm\"\n variant=\"ghost\"\n asChild\n className={cn('w-full justify-start', {\n 'bg-muted': activePath === href,\n })}\n >\n <Link href={item.href}>\n {item.icon && (\n <item.icon className=\"h-4 w-4\" />\n )}\n {item.title}\n </Link>\n </Button>\n );\n })}\n </nav>\n </aside>\n\n <Separator className=\"my-6 lg:hidden\" />\n\n <div\n className={cn(\n wide ? 'min-w-0 flex-1' : 'md:max-w-2xl flex-1',\n )}\n >\n <section\n className={cn(\n 'space-y-12',\n wide ? 'max-w-5xl' : 'max-w-xl',\n )}\n >\n {children}\n </section>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["useCallback","jsx","jsxs","jsx","jsxs","Fragment","jsx","jsxs","jsx","jsxs","jsx","jsxs","Fragment","jsx","jsxs","Fragment","useState","jsx","jsxs","useState","jsx","jsxs","jsx","jsxs"]}