@alfakit/react 0.1.8 → 0.1.10
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/CHANGELOG.md +14 -0
- package/dist/components/actions/action-modals.js +1 -1
- package/dist/components/actions/action-modals.js.map +1 -1
- package/dist/components/dev-tools/dev-tools-inspector.js +1 -1
- package/dist/components/dev-tools/dev-tools-inspector.js.map +1 -1
- package/dist/components/fields/checkbox-list.js +2 -2
- package/dist/components/fields/checkbox-list.js.map +1 -1
- package/dist/components/fields/rich-editor-extensions.js +14 -4
- package/dist/components/fields/rich-editor-extensions.js.map +1 -1
- package/dist/components/file-manager/file-manager.js +2 -0
- package/dist/components/file-manager/file-manager.js.map +1 -1
- package/dist/components/form/form-block.d.ts.map +1 -1
- package/dist/components/form/form-block.js +6 -3
- package/dist/components/form/form-block.js.map +1 -1
- package/dist/components/layout/elements.d.ts.map +1 -1
- package/dist/components/layout/elements.js +16 -5
- package/dist/components/layout/elements.js.map +1 -1
- package/dist/components/layout/mixed-content.d.ts +6 -4
- package/dist/components/layout/mixed-content.d.ts.map +1 -1
- package/dist/components/layout/mixed-content.js +6 -4
- package/dist/components/layout/mixed-content.js.map +1 -1
- package/dist/components/layout/section.js +4 -2
- package/dist/components/layout/section.js.map +1 -1
- package/dist/components/notifications/notifications-menu.d.ts.map +1 -1
- package/dist/components/notifications/notifications-menu.js +45 -17
- package/dist/components/notifications/notifications-menu.js.map +1 -1
- package/dist/components/panel/app-sidebar.js +3 -3
- package/dist/components/panel/app-sidebar.js.map +1 -1
- package/dist/components/panel/bottom-nav.js +2 -2
- package/dist/components/panel/bottom-nav.js.map +1 -1
- package/dist/components/panel/keyboard-shortcuts.js +1 -1
- package/dist/components/panel/keyboard-shortcuts.js.map +1 -1
- package/dist/components/panel/shortcuts-overlay.js +13 -10
- package/dist/components/panel/shortcuts-overlay.js.map +1 -1
- package/dist/components/table/column-manager.js +4 -4
- package/dist/components/table/column-manager.js.map +1 -1
- package/dist/components/table/spreadsheet.js +8 -1
- package/dist/components/table/spreadsheet.js.map +1 -1
- package/dist/components/translation-manager/translation-manager.js +1 -1
- package/dist/components/translation-manager/translation-manager.js.map +1 -1
- package/dist/components/ui/tooltip.d.ts.map +1 -1
- package/dist/components/ui/tooltip.js +1 -1
- package/dist/components/ui/tooltip.js.map +1 -1
- package/dist/components/widgets/stats-overview.js +3 -3
- package/dist/components/widgets/stats-overview.js.map +1 -1
- package/dist/eject-manifest.json +2 -2
- package/dist/layouts/top-nav-layout.js +3 -3
- package/dist/layouts/top-nav-layout.js.map +1 -1
- package/dist/pages/page.d.ts.map +1 -1
- package/dist/pages/page.js +4 -7
- package/dist/pages/page.js.map +1 -1
- package/dist/standalone/alfakit-component.d.ts +0 -10
- package/dist/standalone/alfakit-component.d.ts.map +1 -1
- package/dist/standalone/alfakit-component.js +20 -9
- package/dist/standalone/alfakit-component.js.map +1 -1
- package/dist/standalone/runtime.js +2 -1
- package/dist/standalone/runtime.js.map +1 -1
- package/dist/standalone.css +12 -7
- package/dist/starter-kit/navigation.d.ts +6 -1
- package/dist/starter-kit/navigation.d.ts.map +1 -1
- package/dist/starter-kit/navigation.js +3 -2
- package/dist/starter-kit/navigation.js.map +1 -1
- package/dist/starter-kit/starter-kit.d.ts.map +1 -1
- package/dist/starter-kit/starter-kit.js +7 -2
- package/dist/starter-kit/starter-kit.js.map +1 -1
- package/dist/styles.css +2 -1
- package/dist/themes.css +4 -0
- package/package.json +2 -2
- package/src/components/actions/action-modals.tsx +2 -0
- package/src/components/dev-tools/dev-tools-inspector.tsx +1 -1
- package/src/components/fields/checkbox-list.tsx +2 -2
- package/src/components/fields/rich-editor-extensions.tsx +24 -2
- package/src/components/file-manager/file-manager.tsx +3 -1
- package/src/components/form/form-block.tsx +15 -2
- package/src/components/layout/elements.tsx +27 -4
- package/src/components/layout/mixed-content.tsx +8 -4
- package/src/components/layout/section.tsx +2 -2
- package/src/components/notifications/notifications-menu.tsx +42 -1
- package/src/components/panel/app-sidebar.tsx +3 -3
- package/src/components/panel/bottom-nav.tsx +2 -2
- package/src/components/panel/keyboard-shortcuts.tsx +1 -1
- package/src/components/panel/shortcuts-overlay.tsx +29 -24
- package/src/components/table/column-manager.tsx +6 -4
- package/src/components/table/spreadsheet.tsx +18 -7
- package/src/components/translation-manager/translation-manager.tsx +1 -1
- package/src/components/ui/tooltip.tsx +10 -1
- package/src/components/widgets/stats-overview.tsx +6 -3
- package/src/layouts/top-nav-layout.tsx +3 -3
- package/src/pages/page.tsx +7 -3
- package/src/standalone/alfakit-component.tsx +18 -3
- package/src/standalone/runtime.ts +3 -0
- package/src/starter-kit/navigation.ts +12 -1
- package/src/starter-kit/starter-kit.tsx +10 -1
- package/src/styles.css +2 -1
|
@@ -539,14 +539,25 @@ export function Spreadsheet({ table, token, component, onClose }: SpreadsheetPro
|
|
|
539
539
|
<DialogHeader>
|
|
540
540
|
<DialogTitle>{t('table.spreadsheet.paste_title', {}, 'Paste cells')}</DialogTitle>
|
|
541
541
|
<DialogDescription>
|
|
542
|
-
{
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
542
|
+
{/* One line per count: translations can't join two sentences. */}
|
|
543
|
+
<span className="block">
|
|
544
|
+
{choice(
|
|
545
|
+
'table.spreadsheet.paste_summary',
|
|
546
|
+
preview?.plan.changes.length ?? 0,
|
|
547
|
+
{},
|
|
548
|
+
':count cell will change|:count cells will change',
|
|
549
|
+
)}
|
|
550
|
+
</span>
|
|
551
|
+
{(preview?.plan.skipped ?? 0) > 0 && (
|
|
552
|
+
<span className="block" data-slot="spreadsheet-paste-skipped">
|
|
553
|
+
{choice(
|
|
554
|
+
'table.spreadsheet.paste_skipped',
|
|
555
|
+
preview?.plan.skipped ?? 0,
|
|
556
|
+
{},
|
|
557
|
+
':count read-only cell is skipped|:count read-only cells are skipped',
|
|
558
|
+
)}
|
|
559
|
+
</span>
|
|
547
560
|
)}
|
|
548
|
-
{(preview?.plan.skipped ?? 0) > 0 &&
|
|
549
|
-
` ${choice('table.spreadsheet.paste_skipped', preview?.plan.skipped ?? 0, {}, ':count read-only cell is skipped|:count read-only cells are skipped')}`}
|
|
550
561
|
</DialogDescription>
|
|
551
562
|
</DialogHeader>
|
|
552
563
|
<div data-slot="spreadsheet-paste" className="flex flex-col gap-3">
|
|
@@ -330,7 +330,7 @@ function TranslationManagerView({ schema }: { schema: TranslationManagerSchema }
|
|
|
330
330
|
<tr>
|
|
331
331
|
<th
|
|
332
332
|
scope="col"
|
|
333
|
-
className="bg-
|
|
333
|
+
className="bg-card sticky start-0 z-10 min-w-56 border-b [background-image:linear-gradient(var(--muted),var(--muted))] px-3 py-2 text-start font-medium"
|
|
334
334
|
>
|
|
335
335
|
{t('translation-manager.key', {}, 'Key')}
|
|
336
336
|
</th>
|
|
@@ -20,7 +20,16 @@ function Tooltip({ ...props }: ComponentProps<typeof TooltipPrimitive.Root>) {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
function TooltipTrigger({ ...props }: ComponentProps<typeof TooltipPrimitive.Trigger>) {
|
|
23
|
-
|
|
23
|
+
// With asChild the child keeps its own data-slot (an action's `button`, which the
|
|
24
|
+
// button-shape and touch-target CSS select).
|
|
25
|
+
// (The key must be left out, not set to undefined: Slot passes it on and the child's own
|
|
26
|
+
// `{...props}` would erase its data-slot.)
|
|
27
|
+
return (
|
|
28
|
+
<TooltipPrimitive.Trigger
|
|
29
|
+
{...(props.asChild ? {} : { 'data-slot': 'tooltip-trigger' })}
|
|
30
|
+
{...props}
|
|
31
|
+
/>
|
|
32
|
+
)
|
|
24
33
|
}
|
|
25
34
|
|
|
26
35
|
function TooltipContent({
|
|
@@ -71,7 +71,9 @@ function StatCard({ stat }: { stat: StatSchema }) {
|
|
|
71
71
|
>
|
|
72
72
|
<div className="flex items-start justify-between gap-3">
|
|
73
73
|
<div className="flex flex-col gap-1">
|
|
74
|
-
<span className="text-muted-foreground text-sm font-medium">
|
|
74
|
+
<span className="text-muted-foreground text-sm font-medium">
|
|
75
|
+
<bdi>{stat.label}</bdi>
|
|
76
|
+
</span>
|
|
75
77
|
{(stat.value === null || stat.value === '') && stat.placeholder ? (
|
|
76
78
|
<span
|
|
77
79
|
className="text-muted-foreground text-2xl font-semibold tracking-tight"
|
|
@@ -86,7 +88,7 @@ function StatCard({ stat }: { stat: StatSchema }) {
|
|
|
86
88
|
stat.color && textColorClasses[stat.color],
|
|
87
89
|
)}
|
|
88
90
|
>
|
|
89
|
-
{stat.value}
|
|
91
|
+
<bdi>{stat.value}</bdi>
|
|
90
92
|
</span>
|
|
91
93
|
)}
|
|
92
94
|
{stat.description && (
|
|
@@ -101,7 +103,8 @@ function StatCard({ stat }: { stat: StatSchema }) {
|
|
|
101
103
|
{stat.descriptionIcon && stat.descriptionIconPosition !== 'after' && (
|
|
102
104
|
<Icon name={stat.descriptionIcon} className="size-3.5" />
|
|
103
105
|
)}
|
|
104
|
-
{
|
|
106
|
+
{/* Mixed-direction text (a Latin "-3% this month" in Arabic) keeps its order. */}
|
|
107
|
+
<bdi>{stat.description}</bdi>
|
|
105
108
|
{stat.descriptionIcon && stat.descriptionIconPosition === 'after' && (
|
|
106
109
|
<Icon name={stat.descriptionIcon} className="size-3.5" />
|
|
107
110
|
)}
|
|
@@ -118,7 +118,7 @@ function TopNavMenu({
|
|
|
118
118
|
</DropdownMenuTrigger>
|
|
119
119
|
<DropdownMenuContent align="start" className="min-w-48">
|
|
120
120
|
{items.map((item) => (
|
|
121
|
-
<DropdownMenuItem key={item.label} asChild>
|
|
121
|
+
<DropdownMenuItem key={item.url ?? item.label} asChild>
|
|
122
122
|
<Link
|
|
123
123
|
{...extraProps(item.extraAttributes, cn('w-full', item.active && 'font-medium'))}
|
|
124
124
|
href={item.url ?? '#'}
|
|
@@ -150,7 +150,7 @@ function TopNavGroup({ group }: { group: NavigationGroupSchema }) {
|
|
|
150
150
|
return (
|
|
151
151
|
<>
|
|
152
152
|
{group.items.map((item) => (
|
|
153
|
-
<TopNavLink key={item.label} item={item} />
|
|
153
|
+
<TopNavLink key={item.url ?? item.label} item={item} />
|
|
154
154
|
))}
|
|
155
155
|
</>
|
|
156
156
|
)
|
|
@@ -181,7 +181,7 @@ function MobileNav({ onNavigate }: { onNavigate: () => void }) {
|
|
|
181
181
|
.flatMap((item) => [item, ...(item.children ?? [])])
|
|
182
182
|
.map((item) => (
|
|
183
183
|
<Link
|
|
184
|
-
key={item.label}
|
|
184
|
+
key={item.url ?? item.label}
|
|
185
185
|
href={item.url ?? '#'}
|
|
186
186
|
onClick={onNavigate}
|
|
187
187
|
data-active={item.active ? 'true' : undefined}
|
package/src/pages/page.tsx
CHANGED
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
} from '@alfakit/core'
|
|
12
12
|
import {
|
|
13
13
|
applyBodyAttributes,
|
|
14
|
+
customPageProps,
|
|
14
15
|
hasRelationManagerTabs,
|
|
15
16
|
isLazyPlaceholder,
|
|
16
17
|
openDefaultAction,
|
|
@@ -102,9 +103,12 @@ export function AlfakitPage() {
|
|
|
102
103
|
return (
|
|
103
104
|
<PageActionProvider value={{ token: page.token, component: 'page' }}>
|
|
104
105
|
<Head title={title} />
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
{/* The component brings its own PageShell (as in panel mode, where it is the Inertia
|
|
107
|
+
page itself) and takes the live props, so `reloadProps()` reaches it. */}
|
|
108
|
+
<Custom
|
|
109
|
+
{...customPageProps(page.view.props, props as Record<string, unknown>)}
|
|
110
|
+
page={page}
|
|
111
|
+
/>
|
|
108
112
|
</PageActionProvider>
|
|
109
113
|
)
|
|
110
114
|
}
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from '@alfakit/core'
|
|
9
9
|
import { usePage } from '@inertiajs/react'
|
|
10
10
|
import { Direction } from 'radix-ui'
|
|
11
|
-
import { useEffect, useMemo, useState, type ReactNode } from 'react'
|
|
11
|
+
import { useEffect, useLayoutEffect, useMemo, useState, type ReactNode } from 'react'
|
|
12
12
|
import { PageActionProvider } from '../components/actions/action-context'
|
|
13
13
|
import { ActionList } from '../components/actions/action-list'
|
|
14
14
|
import { ActionModals } from '../components/actions/action-modals'
|
|
@@ -55,6 +55,9 @@ export interface AlfakitComponentProps {
|
|
|
55
55
|
* <AlfakitComponent component={orders} className="max-w-4xl" />
|
|
56
56
|
* ```
|
|
57
57
|
*/
|
|
58
|
+
// `useLayoutEffect` warns during a server render, where nothing registers anyway.
|
|
59
|
+
const useIsomorphicLayoutEffect = typeof window === 'undefined' ? useEffect : useLayoutEffect
|
|
60
|
+
|
|
58
61
|
export function AlfakitComponent({
|
|
59
62
|
component,
|
|
60
63
|
components,
|
|
@@ -83,8 +86,18 @@ export function AlfakitComponent({
|
|
|
83
86
|
const refresh = (targets: string[]) => state.refresh(targets)
|
|
84
87
|
|
|
85
88
|
if (parent) {
|
|
89
|
+
// Inside a panel page: the panel's registry and translator, but this component's own
|
|
90
|
+
// action runner, so its actions post to its own endpoints with its own token (sharing
|
|
91
|
+
// the panel's runner sent them to the panel's endpoint: 403).
|
|
92
|
+
const own = createStandaloneContext(
|
|
93
|
+
{ action: component.endpoints.action, modal: component.endpoints.modal },
|
|
94
|
+
components,
|
|
95
|
+
poll,
|
|
96
|
+
)
|
|
97
|
+
|
|
86
98
|
return {
|
|
87
99
|
...parent,
|
|
100
|
+
actions: own.actions,
|
|
88
101
|
registry: createStandaloneRegistry(components, parent.registry),
|
|
89
102
|
poll,
|
|
90
103
|
refresh,
|
|
@@ -128,7 +141,9 @@ export function AlfakitComponent({
|
|
|
128
141
|
// Partial reloads (sorting, paging, inline edits) request this component's own prop.
|
|
129
142
|
const propName = findStandalonePropName(props, component)
|
|
130
143
|
|
|
131
|
-
|
|
144
|
+
// A layout effect runs before the children's effects: a `deferLoading()` table's first
|
|
145
|
+
// reload must already ask for this component's prop, not the panel `page` prop.
|
|
146
|
+
useIsomorphicLayoutEffect(() => registerStandaloneProp(propName ?? null), [propName])
|
|
132
147
|
|
|
133
148
|
useEffect(() => {
|
|
134
149
|
void state.loadLazy(component)
|
|
@@ -201,7 +216,7 @@ export function AlfakitComponent({
|
|
|
201
216
|
{footer}
|
|
202
217
|
</div>
|
|
203
218
|
<ActionModals />
|
|
204
|
-
{ownsToaster && <AlfakitToaster claimed />}
|
|
219
|
+
{ownsToaster && <AlfakitToaster claimed dir={direction} />}
|
|
205
220
|
</PageActionProvider>
|
|
206
221
|
)
|
|
207
222
|
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
ComponentRegistry,
|
|
4
4
|
FlashNotificationTracker,
|
|
5
5
|
Translator,
|
|
6
|
+
installPrefetchInvalidation,
|
|
6
7
|
reloadOnExpiredPage,
|
|
7
8
|
resolveRequestErrorNotification,
|
|
8
9
|
type NotificationSchema,
|
|
@@ -27,6 +28,8 @@ export function ensureStandaloneRuntime(): void {
|
|
|
27
28
|
|
|
28
29
|
browserReady = true
|
|
29
30
|
reloadOnExpiredPage()
|
|
31
|
+
// Pages restored by Back after a change are reloaded; shared with a surrounding panel.
|
|
32
|
+
installPrefetchInvalidation()
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
/**
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
starterKitNavigation,
|
|
3
3
|
toStarterKitNavGroups,
|
|
4
|
+
toStarterKitUserMenuItems,
|
|
4
5
|
type StarterKitNavGroup,
|
|
5
6
|
type StarterKitNavigationSchema,
|
|
7
|
+
type StarterKitUserMenuItem,
|
|
6
8
|
} from '@alfakit/core'
|
|
7
9
|
import { usePage } from '@inertiajs/react'
|
|
8
10
|
import { useMemo } from 'react'
|
|
@@ -12,6 +14,11 @@ export interface AlfakitNavigation {
|
|
|
12
14
|
navigation: StarterKitNavigationSchema | null
|
|
13
15
|
/** Its groups as plain items (`title`, `href`, `icon`, `isActive`, `badge`, `children`). */
|
|
14
16
|
groups: StarterKitNavGroup[]
|
|
17
|
+
/**
|
|
18
|
+
* The panel's user menu links (`userMenuItems()`, Billing's entry…) for the kit's user
|
|
19
|
+
* menu: `<AlfakitUserMenuItems />` renders them with the app's dropdown items.
|
|
20
|
+
*/
|
|
21
|
+
userMenuItems: StarterKitUserMenuItem[]
|
|
15
22
|
}
|
|
16
23
|
|
|
17
24
|
/**
|
|
@@ -28,7 +35,11 @@ export function useAlfakitNavigation(panelId?: string): AlfakitNavigation {
|
|
|
28
35
|
const navigation = starterKitNavigation(props, panelId)
|
|
29
36
|
|
|
30
37
|
return useMemo(
|
|
31
|
-
() => ({
|
|
38
|
+
() => ({
|
|
39
|
+
navigation,
|
|
40
|
+
groups: toStarterKitNavGroups(navigation?.groups),
|
|
41
|
+
userMenuItems: toStarterKitUserMenuItems(navigation?.userMenu),
|
|
42
|
+
}),
|
|
32
43
|
[navigation],
|
|
33
44
|
)
|
|
34
45
|
}
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
import { usePage } from '@inertiajs/react'
|
|
17
17
|
import { useEffect, useState, type ComponentType, type ReactNode } from 'react'
|
|
18
18
|
import { setToasterId, showToast } from '../components/notifications/flash-toasts'
|
|
19
|
+
import { DebugPanelSlot } from '../components/panel/debug-panel-slot'
|
|
19
20
|
import { Slot } from '../components/panel/slot'
|
|
20
21
|
import {
|
|
21
22
|
AlfakitProvider,
|
|
@@ -181,7 +182,15 @@ export function AlfakitStarterKitRoot({
|
|
|
181
182
|
lang={panel?.localization?.tag}
|
|
182
183
|
className="contents"
|
|
183
184
|
>
|
|
184
|
-
<AlfakitRoot toasterId={STARTER_KIT_TOASTER_ID}>
|
|
185
|
+
<AlfakitRoot toasterId={STARTER_KIT_TOASTER_ID}>
|
|
186
|
+
{children}
|
|
187
|
+
{/* The debug panel's button lives in AlfaKit's top bar, which a starter kit doesn't
|
|
188
|
+
render: float it in the corner instead (nothing without `alfakitDebug`). The corner is the
|
|
189
|
+
document's right: the kit's sidebar stays on the left in a right-to-left panel language. */}
|
|
190
|
+
<div data-slot="starter-kit-debug-panel" className="fixed right-16 bottom-16 z-40">
|
|
191
|
+
<DebugPanelSlot />
|
|
192
|
+
</div>
|
|
193
|
+
</AlfakitRoot>
|
|
185
194
|
</div>
|
|
186
195
|
</AlfakitProvider>
|
|
187
196
|
)
|
package/src/styles.css
CHANGED
|
@@ -289,7 +289,8 @@
|
|
|
289
289
|
}
|
|
290
290
|
/* Rich editor mentions, merge tags and custom blocks (RichEditor extensions) */
|
|
291
291
|
.alfakit-prose :where(.alfakit-mention):not(:where(.alfakit-not-prose *)) {
|
|
292
|
-
|
|
292
|
+
/* Full-contrast text on the tint (WCAG AA); the ring marks it as a mention. */
|
|
293
|
+
@apply bg-primary/10 text-foreground ring-primary/30 rounded px-1 font-medium ring-1;
|
|
293
294
|
}
|
|
294
295
|
.alfakit-prose :where(.alfakit-merge-tag):not(:where(.alfakit-not-prose *)) {
|
|
295
296
|
@apply bg-muted text-muted-foreground rounded px-1 font-mono text-xs;
|