@nixxie-cms/core 2.0.0 → 2.2.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/admin-ui/components/dist/nixxie-cms-core-admin-ui-components.cjs.js +7 -7
- package/admin-ui/components/dist/nixxie-cms-core-admin-ui-components.esm.js +7 -7
- package/admin-ui/context/dist/nixxie-cms-core-admin-ui-context.cjs.js +2 -2
- package/admin-ui/context/dist/nixxie-cms-core-admin-ui-context.esm.js +2 -2
- package/admin-ui/utils/dist/nixxie-cms-core-admin-ui-utils.cjs.js +5 -5
- package/admin-ui/utils/dist/nixxie-cms-core-admin-ui-utils.esm.js +3 -3
- package/dist/{CreateItemDialog-7008b050.esm.js → CreateItemDialog-66621fe8.esm.js} +3 -3
- package/dist/{CreateItemDialog-a0cab315.cjs.js → CreateItemDialog-96b044ce.cjs.js} +4 -4
- package/dist/{Field-47f85161.esm.js → Field-1820c4e6.esm.js} +1 -0
- package/dist/{Field-ed8d7627.cjs.js → Field-38d3cdf9.cjs.js} +1 -0
- package/dist/GraphQLErrorNotice-7594a9f8.esm.js +64 -0
- package/dist/GraphQLErrorNotice-c8890f80.cjs.js +66 -0
- package/dist/{PageContainer-5ae731cc.esm.js → PageContainer-355cfbfa.esm.js} +362 -156
- package/dist/{PageContainer-abd7159f.cjs.js → PageContainer-4095555a.cjs.js} +361 -155
- package/dist/{context-af9957ed.esm.js → context-2924eaaa.esm.js} +53 -58
- package/dist/{context-b5204629.cjs.js → context-2ce61d0b.cjs.js} +53 -58
- package/dist/declarations/src/admin-ui/components/GraphQLErrorNotice.d.ts.map +1 -1
- package/dist/declarations/src/admin-ui/components/Navigation.d.ts.map +1 -1
- package/dist/declarations/src/admin-ui/components/PageContainer.d.ts.map +1 -1
- package/dist/declarations/src/admin-ui/context.d.ts.map +1 -1
- package/dist/declarations/src/admin-ui/utils/useCreateItem.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/bigInt/views/index.d.ts +2 -1
- package/dist/declarations/src/fields/types/bigInt/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/bytes/views/index.d.ts +2 -1
- package/dist/declarations/src/fields/types/bytes/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/calendarDay/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/decimal/views/index.d.ts +2 -1
- package/dist/declarations/src/fields/types/decimal/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/float/views/index.d.ts +2 -1
- package/dist/declarations/src/fields/types/float/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/integer/views/index.d.ts +2 -1
- package/dist/declarations/src/fields/types/integer/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/json/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/multiselect/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/relationship/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/select/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/text/views/index.d.ts +2 -1
- package/dist/declarations/src/fields/types/text/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/timestamp/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/virtual/views/index.d.ts.map +1 -1
- package/dist/declarations/src/internal-unstable/admin-ui/pages/HomePage/index.d.ts.map +1 -1
- package/dist/declarations/src/internal-unstable/admin-ui/pages/ItemPage/index.d.ts.map +1 -1
- package/dist/pick-4c785a54.esm.js +34 -0
- package/dist/pick-906341bb.cjs.js +37 -0
- package/dist/{useCreateItem-1f94d252.esm.js → useCreateItem-36a75f1c.esm.js} +26 -26
- package/dist/{useCreateItem-1be4987e.cjs.js → useCreateItem-acf06f77.cjs.js} +37 -37
- package/dist/{useFilter-acc9d413.cjs.js → useFilter-c29f17a8.cjs.js} +1 -1
- package/dist/{useFilter-9b6db1f9.esm.js → useFilter-f79b2abb.esm.js} +1 -1
- package/dist/{Fields-956d9a14.esm.js → usePreventNavigation-093389dd.esm.js} +28 -2
- package/dist/{Fields-e2c28056.cjs.js → usePreventNavigation-d4f9f4fa.cjs.js} +27 -0
- package/fields/types/bigInt/views/dist/nixxie-cms-core-fields-types-bigInt-views.cjs.js +8 -0
- package/fields/types/bigInt/views/dist/nixxie-cms-core-fields-types-bigInt-views.esm.js +8 -1
- package/fields/types/bytes/views/dist/nixxie-cms-core-fields-types-bytes-views.cjs.js +14 -3
- package/fields/types/bytes/views/dist/nixxie-cms-core-fields-types-bytes-views.esm.js +15 -5
- package/fields/types/calendarDay/views/dist/nixxie-cms-core-fields-types-calendarDay-views.cjs.js +2 -1
- package/fields/types/calendarDay/views/dist/nixxie-cms-core-fields-types-calendarDay-views.esm.js +2 -1
- package/fields/types/decimal/views/dist/nixxie-cms-core-fields-types-decimal-views.cjs.js +10 -1
- package/fields/types/decimal/views/dist/nixxie-cms-core-fields-types-decimal-views.esm.js +10 -2
- package/fields/types/file/views/dist/nixxie-cms-core-fields-types-file-views.cjs.js +1 -1
- package/fields/types/file/views/dist/nixxie-cms-core-fields-types-file-views.esm.js +2 -2
- package/fields/types/float/views/dist/nixxie-cms-core-fields-types-float-views.cjs.js +10 -1
- package/fields/types/float/views/dist/nixxie-cms-core-fields-types-float-views.esm.js +10 -2
- package/fields/types/image/views/dist/nixxie-cms-core-fields-types-image-views.cjs.js +2 -1
- package/fields/types/image/views/dist/nixxie-cms-core-fields-types-image-views.esm.js +2 -1
- package/fields/types/integer/views/dist/nixxie-cms-core-fields-types-integer-views.cjs.js +8 -0
- package/fields/types/integer/views/dist/nixxie-cms-core-fields-types-integer-views.esm.js +8 -1
- package/fields/types/json/views/dist/nixxie-cms-core-fields-types-json-views.cjs.js +19 -4
- package/fields/types/json/views/dist/nixxie-cms-core-fields-types-json-views.esm.js +19 -4
- package/fields/types/multiselect/views/dist/nixxie-cms-core-fields-types-multiselect-views.cjs.js +18 -3
- package/fields/types/multiselect/views/dist/nixxie-cms-core-fields-types-multiselect-views.esm.js +18 -3
- package/fields/types/password/views/dist/nixxie-cms-core-fields-types-password-views.cjs.js +1 -1
- package/fields/types/password/views/dist/nixxie-cms-core-fields-types-password-views.esm.js +1 -1
- package/fields/types/relationship/views/dist/nixxie-cms-core-fields-types-relationship-views.cjs.js +9 -7
- package/fields/types/relationship/views/dist/nixxie-cms-core-fields-types-relationship-views.esm.js +9 -7
- package/fields/types/select/views/dist/nixxie-cms-core-fields-types-select-views.cjs.js +3 -2
- package/fields/types/select/views/dist/nixxie-cms-core-fields-types-select-views.esm.js +3 -2
- package/fields/types/text/views/dist/nixxie-cms-core-fields-types-text-views.cjs.js +14 -3
- package/fields/types/text/views/dist/nixxie-cms-core-fields-types-text-views.esm.js +15 -5
- package/fields/types/timestamp/views/dist/nixxie-cms-core-fields-types-timestamp-views.cjs.js +2 -1
- package/fields/types/timestamp/views/dist/nixxie-cms-core-fields-types-timestamp-views.esm.js +2 -1
- package/fields/types/virtual/views/dist/nixxie-cms-core-fields-types-virtual-views.cjs.js +13 -1
- package/fields/types/virtual/views/dist/nixxie-cms-core-fields-types-virtual-views.esm.js +14 -2
- package/internal-unstable/admin-ui/pages/App/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-App.cjs.js +3 -3
- package/internal-unstable/admin-ui/pages/App/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-App.esm.js +3 -3
- package/internal-unstable/admin-ui/pages/CreateItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-CreateItemPage.cjs.js +7 -7
- package/internal-unstable/admin-ui/pages/CreateItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-CreateItemPage.esm.js +6 -6
- package/internal-unstable/admin-ui/pages/HomePage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-HomePage.cjs.js +34 -33
- package/internal-unstable/admin-ui/pages/HomePage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-HomePage.esm.js +35 -34
- package/internal-unstable/admin-ui/pages/ItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ItemPage.cjs.js +53 -13
- package/internal-unstable/admin-ui/pages/ItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ItemPage.esm.js +52 -12
- package/internal-unstable/admin-ui/pages/ListPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ListPage.cjs.js +36 -25
- package/internal-unstable/admin-ui/pages/ListPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ListPage.esm.js +36 -25
- package/package.json +2 -2
- package/src/admin-ui/components/CommandPalette.tsx +134 -27
- package/src/admin-ui/components/CreateButtonLink.tsx +20 -46
- package/src/admin-ui/components/GraphQLErrorNotice.tsx +39 -33
- package/src/admin-ui/components/Logo.tsx +5 -5
- package/src/admin-ui/components/Navigation.tsx +41 -27
- package/src/admin-ui/components/PageContainer.tsx +171 -15
- package/src/admin-ui/components/WelcomeDialog.tsx +14 -14
- package/src/admin-ui/context.tsx +5 -2
- package/src/admin-ui/utils/useCreateItem.ts +21 -1
- package/src/fields/types/bigInt/views/index.tsx +10 -1
- package/src/fields/types/bytes/views/index.tsx +14 -1
- package/src/fields/types/calendarDay/views/index.tsx +2 -1
- package/src/fields/types/decimal/views/index.tsx +7 -1
- package/src/fields/types/file/views/Field.tsx +1 -1
- package/src/fields/types/float/views/index.tsx +7 -1
- package/src/fields/types/image/views/index.tsx +1 -1
- package/src/fields/types/integer/views/index.tsx +5 -0
- package/src/fields/types/json/views/index.tsx +20 -2
- package/src/fields/types/multiselect/views/index.tsx +7 -3
- package/src/fields/types/password/views/index.tsx +1 -1
- package/src/fields/types/relationship/views/index.tsx +1 -0
- package/src/fields/types/select/views/index.tsx +2 -1
- package/src/fields/types/text/views/index.tsx +14 -1
- package/src/fields/types/timestamp/views/__tests__/index.tsx +68 -68
- package/src/fields/types/timestamp/views/index.tsx +2 -1
- package/src/fields/types/virtual/views/index.tsx +17 -2
- package/src/internal-unstable/admin-ui/pages/HomePage/index.tsx +40 -31
- package/src/internal-unstable/admin-ui/pages/ItemPage/index.tsx +36 -3
- package/src/internal-unstable/admin-ui/pages/ListPage/PaginationControls.tsx +20 -33
- package/src/internal-unstable/admin-ui/pages/ListPage/index.tsx +24 -16
- package/tests/conditional-filters.test.ts +333 -326
- package/dist/GraphQLErrorNotice-cd74180d.cjs.js +0 -57
- package/dist/GraphQLErrorNotice-d9f0931b.esm.js +0 -55
- package/dist/pick-5fe45878.cjs.js +0 -71
- package/dist/pick-b7ef3115.esm.js +0 -68
|
@@ -8,7 +8,8 @@ import {
|
|
|
8
8
|
useMemo,
|
|
9
9
|
} from 'react'
|
|
10
10
|
|
|
11
|
-
import { css } from '@keystar/ui/style'
|
|
11
|
+
import { css, tokenSchema } from '@keystar/ui/style'
|
|
12
|
+
import { useId } from '@react-aria/utils'
|
|
12
13
|
|
|
13
14
|
import { useNixxie } from '../context'
|
|
14
15
|
import { getHrefFromList } from './Navigation'
|
|
@@ -76,6 +77,8 @@ export function CommandPalette({ isOpen, onClose }: CommandPaletteProps) {
|
|
|
76
77
|
const [activeIndex, setActiveIndex] = useState(0)
|
|
77
78
|
const inputRef = useRef<HTMLInputElement>(null)
|
|
78
79
|
const listRef = useRef<HTMLUListElement>(null)
|
|
80
|
+
const panelRef = useRef<HTMLDivElement>(null)
|
|
81
|
+
const listboxId = useId()
|
|
79
82
|
const commands = useCommands()
|
|
80
83
|
|
|
81
84
|
const filtered = useMemo(() => {
|
|
@@ -107,8 +110,27 @@ export function CommandPalette({ isOpen, onClose }: CommandPaletteProps) {
|
|
|
107
110
|
if (!isOpen) return
|
|
108
111
|
setQuery('')
|
|
109
112
|
setActiveIndex(0)
|
|
113
|
+
|
|
114
|
+
// FOCUS RESTORE: remember what was focused before the palette opened.
|
|
115
|
+
const previouslyFocused = document.activeElement as HTMLElement | null
|
|
116
|
+
|
|
117
|
+
// SCROLL LOCK: prevent the page behind the modal from scrolling.
|
|
118
|
+
const prevOverflow = document.body.style.overflow
|
|
119
|
+
document.body.style.overflow = 'hidden'
|
|
120
|
+
|
|
110
121
|
const t = setTimeout(() => inputRef.current?.focus(), 10)
|
|
111
|
-
|
|
122
|
+
|
|
123
|
+
return () => {
|
|
124
|
+
clearTimeout(t)
|
|
125
|
+
// Restore scroll position behaviour.
|
|
126
|
+
document.body.style.overflow = prevOverflow
|
|
127
|
+
// Restore focus to whatever held it before we opened.
|
|
128
|
+
try {
|
|
129
|
+
previouslyFocused?.focus?.()
|
|
130
|
+
} catch {
|
|
131
|
+
/* element may be gone from the DOM — ignore */
|
|
132
|
+
}
|
|
133
|
+
}
|
|
112
134
|
}, [isOpen])
|
|
113
135
|
|
|
114
136
|
useEffect(() => {
|
|
@@ -130,6 +152,49 @@ export function CommandPalette({ isOpen, onClose }: CommandPaletteProps) {
|
|
|
130
152
|
}
|
|
131
153
|
}
|
|
132
154
|
|
|
155
|
+
// FOCUS TRAP + panel-level ESCAPE. Runs for any child of the panel so the
|
|
156
|
+
// modal closes regardless of which element currently holds focus, and Tab /
|
|
157
|
+
// Shift+Tab stay contained within the panel's focusable descendants.
|
|
158
|
+
function onPanelKeyDown(e: KeyboardEvent) {
|
|
159
|
+
if (e.key === 'Escape') {
|
|
160
|
+
e.preventDefault()
|
|
161
|
+
onClose()
|
|
162
|
+
return
|
|
163
|
+
}
|
|
164
|
+
if (e.key !== 'Tab') return
|
|
165
|
+
|
|
166
|
+
const panel = panelRef.current
|
|
167
|
+
if (!panel) return
|
|
168
|
+
|
|
169
|
+
let focusables: HTMLElement[]
|
|
170
|
+
try {
|
|
171
|
+
focusables = Array.from(
|
|
172
|
+
panel.querySelectorAll<HTMLElement>(
|
|
173
|
+
'a[href], button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'
|
|
174
|
+
)
|
|
175
|
+
).filter(el => el.offsetParent !== null || el === document.activeElement)
|
|
176
|
+
} catch {
|
|
177
|
+
return
|
|
178
|
+
}
|
|
179
|
+
if (focusables.length === 0) return
|
|
180
|
+
|
|
181
|
+
const first = focusables[0]
|
|
182
|
+
const last = focusables[focusables.length - 1]
|
|
183
|
+
const current = document.activeElement as HTMLElement | null
|
|
184
|
+
|
|
185
|
+
if (e.shiftKey) {
|
|
186
|
+
if (current === first || !panel.contains(current)) {
|
|
187
|
+
e.preventDefault()
|
|
188
|
+
last.focus()
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
if (current === last || !panel.contains(current)) {
|
|
192
|
+
e.preventDefault()
|
|
193
|
+
first.focus()
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
133
198
|
function onKeyDown(e: KeyboardEvent) {
|
|
134
199
|
if (e.key === 'ArrowDown') {
|
|
135
200
|
e.preventDefault()
|
|
@@ -154,6 +219,12 @@ export function CommandPalette({ isOpen, onClose }: CommandPaletteProps) {
|
|
|
154
219
|
return map
|
|
155
220
|
}, [flatList])
|
|
156
221
|
|
|
222
|
+
// Stable per-option id derived from the listbox id, used for both the rendered
|
|
223
|
+
// <li role="option"> ids and the input's aria-activedescendant.
|
|
224
|
+
const optionId = (cmdId: string) => `${listboxId}-opt-${cmdId}`
|
|
225
|
+
const activeCommand = flatList[activeIndex]
|
|
226
|
+
const activeOptionId = activeCommand ? optionId(activeCommand.id) : undefined
|
|
227
|
+
|
|
157
228
|
if (!isOpen) return null
|
|
158
229
|
|
|
159
230
|
return (
|
|
@@ -164,7 +235,7 @@ export function CommandPalette({ isOpen, onClose }: CommandPaletteProps) {
|
|
|
164
235
|
className={css({
|
|
165
236
|
position: 'fixed',
|
|
166
237
|
inset: 0,
|
|
167
|
-
backgroundColor:
|
|
238
|
+
backgroundColor: tokenSchema.color.alias.blanket,
|
|
168
239
|
zIndex: 200,
|
|
169
240
|
backdropFilter: 'blur(3px)',
|
|
170
241
|
})}
|
|
@@ -172,9 +243,11 @@ export function CommandPalette({ isOpen, onClose }: CommandPaletteProps) {
|
|
|
172
243
|
|
|
173
244
|
{/* Panel */}
|
|
174
245
|
<div
|
|
246
|
+
ref={panelRef}
|
|
175
247
|
role="dialog"
|
|
176
248
|
aria-modal="true"
|
|
177
249
|
aria-label="Command palette"
|
|
250
|
+
onKeyDown={onPanelKeyDown}
|
|
178
251
|
className={css({
|
|
179
252
|
position: 'fixed',
|
|
180
253
|
top: '14vh',
|
|
@@ -185,7 +258,7 @@ export function CommandPalette({ isOpen, onClose }: CommandPaletteProps) {
|
|
|
185
258
|
maxHeight: '62vh',
|
|
186
259
|
display: 'flex',
|
|
187
260
|
flexDirection: 'column',
|
|
188
|
-
backgroundColor:
|
|
261
|
+
backgroundColor: tokenSchema.color.background.canvas,
|
|
189
262
|
borderRadius: 10,
|
|
190
263
|
boxShadow: '0 24px 64px rgba(0,0,0,0.22), 0 0 0 1px rgba(0,0,0,0.07)',
|
|
191
264
|
zIndex: 201,
|
|
@@ -199,7 +272,7 @@ export function CommandPalette({ isOpen, onClose }: CommandPaletteProps) {
|
|
|
199
272
|
alignItems: 'center',
|
|
200
273
|
gap: 10,
|
|
201
274
|
padding: '12px 16px',
|
|
202
|
-
borderBottom:
|
|
275
|
+
borderBottom: `1px solid ${tokenSchema.color.border.muted}`,
|
|
203
276
|
})}
|
|
204
277
|
>
|
|
205
278
|
<svg
|
|
@@ -207,7 +280,8 @@ export function CommandPalette({ isOpen, onClose }: CommandPaletteProps) {
|
|
|
207
280
|
height="15"
|
|
208
281
|
viewBox="0 0 15 15"
|
|
209
282
|
fill="none"
|
|
210
|
-
|
|
283
|
+
aria-hidden="true"
|
|
284
|
+
style={{ flexShrink: 0, color: tokenSchema.color.foreground.neutralSecondary }}
|
|
211
285
|
>
|
|
212
286
|
<circle cx="6.5" cy="6.5" r="4.5" stroke="currentColor" strokeWidth="1.4" />
|
|
213
287
|
<line
|
|
@@ -226,15 +300,21 @@ export function CommandPalette({ isOpen, onClose }: CommandPaletteProps) {
|
|
|
226
300
|
onChange={(e: ChangeEvent<HTMLInputElement>) => setQuery(e.target.value)}
|
|
227
301
|
onKeyDown={onKeyDown}
|
|
228
302
|
placeholder="Search commands, lists, actions…"
|
|
303
|
+
role="combobox"
|
|
304
|
+
aria-label="Search commands"
|
|
305
|
+
aria-expanded={flatList.length > 0}
|
|
306
|
+
aria-controls={listboxId}
|
|
307
|
+
aria-autocomplete="list"
|
|
308
|
+
aria-activedescendant={activeOptionId}
|
|
229
309
|
className={css({
|
|
230
310
|
flex: 1,
|
|
231
311
|
border: 'none',
|
|
232
312
|
outline: 'none',
|
|
233
313
|
fontSize: 14.5,
|
|
234
|
-
color:
|
|
314
|
+
color: tokenSchema.color.foreground.neutralEmphasis,
|
|
235
315
|
background: 'transparent',
|
|
236
316
|
fontFamily: "'Inter', -apple-system, BlinkMacSystemFont, sans-serif",
|
|
237
|
-
'&::placeholder': { color:
|
|
317
|
+
'&::placeholder': { color: tokenSchema.color.foreground.neutralSecondary },
|
|
238
318
|
})}
|
|
239
319
|
/>
|
|
240
320
|
<kbd
|
|
@@ -243,11 +323,11 @@ export function CommandPalette({ isOpen, onClose }: CommandPaletteProps) {
|
|
|
243
323
|
alignItems: 'center',
|
|
244
324
|
gap: 2,
|
|
245
325
|
padding: '2px 7px',
|
|
246
|
-
backgroundColor:
|
|
247
|
-
border:
|
|
326
|
+
backgroundColor: tokenSchema.color.background.surfaceSecondary,
|
|
327
|
+
border: `1px solid ${tokenSchema.color.border.muted}`,
|
|
248
328
|
borderRadius: 5,
|
|
249
329
|
fontSize: 11,
|
|
250
|
-
color:
|
|
330
|
+
color: tokenSchema.color.foreground.neutralSecondary,
|
|
251
331
|
fontFamily: 'inherit',
|
|
252
332
|
flexShrink: 0,
|
|
253
333
|
})}
|
|
@@ -259,7 +339,9 @@ export function CommandPalette({ isOpen, onClose }: CommandPaletteProps) {
|
|
|
259
339
|
{/* Results */}
|
|
260
340
|
<ul
|
|
261
341
|
ref={listRef}
|
|
342
|
+
id={listboxId}
|
|
262
343
|
role="listbox"
|
|
344
|
+
aria-label="Commands"
|
|
263
345
|
className={css({
|
|
264
346
|
flex: 1,
|
|
265
347
|
overflowY: 'auto',
|
|
@@ -267,7 +349,10 @@ export function CommandPalette({ isOpen, onClose }: CommandPaletteProps) {
|
|
|
267
349
|
margin: 0,
|
|
268
350
|
listStyle: 'none',
|
|
269
351
|
'&::-webkit-scrollbar': { width: 4 },
|
|
270
|
-
'&::-webkit-scrollbar-thumb': {
|
|
352
|
+
'&::-webkit-scrollbar-thumb': {
|
|
353
|
+
background: tokenSchema.color.border.muted,
|
|
354
|
+
borderRadius: 4,
|
|
355
|
+
},
|
|
271
356
|
})}
|
|
272
357
|
>
|
|
273
358
|
{grouped.size === 0 ? (
|
|
@@ -275,16 +360,20 @@ export function CommandPalette({ isOpen, onClose }: CommandPaletteProps) {
|
|
|
275
360
|
className={css({
|
|
276
361
|
padding: '28px 16px',
|
|
277
362
|
textAlign: 'center',
|
|
278
|
-
color:
|
|
363
|
+
color: tokenSchema.color.foreground.neutralSecondary,
|
|
279
364
|
fontSize: 13.5,
|
|
280
365
|
})}
|
|
281
366
|
>
|
|
282
367
|
No results for “{query}”
|
|
283
368
|
</li>
|
|
284
369
|
) : (
|
|
285
|
-
Array.from(grouped.entries()).map(([category, items]) =>
|
|
286
|
-
|
|
370
|
+
Array.from(grouped.entries()).map(([category, items], groupIdx) => {
|
|
371
|
+
const headerId = `${listboxId}-cat-${groupIdx}`
|
|
372
|
+
return (
|
|
373
|
+
<li key={category} role="presentation">
|
|
287
374
|
<p
|
|
375
|
+
id={headerId}
|
|
376
|
+
role="presentation"
|
|
288
377
|
className={css({
|
|
289
378
|
margin: 0,
|
|
290
379
|
padding: '8px 16px 3px',
|
|
@@ -292,18 +381,23 @@ export function CommandPalette({ isOpen, onClose }: CommandPaletteProps) {
|
|
|
292
381
|
fontWeight: 600,
|
|
293
382
|
letterSpacing: '0.10em',
|
|
294
383
|
textTransform: 'uppercase',
|
|
295
|
-
color:
|
|
384
|
+
color: tokenSchema.color.foreground.neutralSecondary,
|
|
296
385
|
})}
|
|
297
386
|
>
|
|
298
387
|
{category}
|
|
299
388
|
</p>
|
|
300
|
-
<ul
|
|
389
|
+
<ul
|
|
390
|
+
role="group"
|
|
391
|
+
aria-labelledby={headerId}
|
|
392
|
+
className={css({ listStyle: 'none', margin: 0, padding: 0 })}
|
|
393
|
+
>
|
|
301
394
|
{items.map(cmd => {
|
|
302
395
|
const idx = cmdFlatIndex.get(cmd.id) ?? 0
|
|
303
396
|
const isActive = idx === activeIndex
|
|
304
397
|
return (
|
|
305
398
|
<li
|
|
306
399
|
key={cmd.id}
|
|
400
|
+
id={optionId(cmd.id)}
|
|
307
401
|
role="option"
|
|
308
402
|
aria-selected={isActive}
|
|
309
403
|
data-active={isActive}
|
|
@@ -315,10 +409,14 @@ export function CommandPalette({ isOpen, onClose }: CommandPaletteProps) {
|
|
|
315
409
|
gap: 10,
|
|
316
410
|
padding: '7px 16px',
|
|
317
411
|
cursor: 'pointer',
|
|
318
|
-
backgroundColor: isActive
|
|
412
|
+
backgroundColor: isActive
|
|
413
|
+
? tokenSchema.color.scale.black
|
|
414
|
+
: 'transparent',
|
|
319
415
|
transition: 'background 100ms',
|
|
320
416
|
'&:hover': {
|
|
321
|
-
backgroundColor: isActive
|
|
417
|
+
backgroundColor: isActive
|
|
418
|
+
? tokenSchema.color.scale.black
|
|
419
|
+
: tokenSchema.color.background.surfaceSecondary,
|
|
322
420
|
},
|
|
323
421
|
})}
|
|
324
422
|
>
|
|
@@ -331,10 +429,14 @@ export function CommandPalette({ isOpen, onClose }: CommandPaletteProps) {
|
|
|
331
429
|
width: 28,
|
|
332
430
|
height: 28,
|
|
333
431
|
borderRadius: 6,
|
|
334
|
-
backgroundColor: isActive
|
|
432
|
+
backgroundColor: isActive
|
|
433
|
+
? '#2a2a2a'
|
|
434
|
+
: tokenSchema.color.background.surfaceSecondary,
|
|
335
435
|
fontSize: 12,
|
|
336
436
|
fontWeight: 500,
|
|
337
|
-
color: isActive
|
|
437
|
+
color: isActive
|
|
438
|
+
? tokenSchema.color.foreground.onEmphasis
|
|
439
|
+
: tokenSchema.color.foreground.neutralSecondary,
|
|
338
440
|
flexShrink: 0,
|
|
339
441
|
transition: 'background 100ms, color 100ms',
|
|
340
442
|
fontFamily: 'monospace',
|
|
@@ -350,7 +452,9 @@ export function CommandPalette({ isOpen, onClose }: CommandPaletteProps) {
|
|
|
350
452
|
display: 'block',
|
|
351
453
|
fontSize: 13.5,
|
|
352
454
|
fontWeight: 500,
|
|
353
|
-
color: isActive
|
|
455
|
+
color: isActive
|
|
456
|
+
? tokenSchema.color.foreground.onEmphasis
|
|
457
|
+
: tokenSchema.color.foreground.neutralEmphasis,
|
|
354
458
|
whiteSpace: 'nowrap',
|
|
355
459
|
overflow: 'hidden',
|
|
356
460
|
textOverflow: 'ellipsis',
|
|
@@ -364,7 +468,9 @@ export function CommandPalette({ isOpen, onClose }: CommandPaletteProps) {
|
|
|
364
468
|
className={css({
|
|
365
469
|
display: 'block',
|
|
366
470
|
fontSize: 12,
|
|
367
|
-
color: isActive
|
|
471
|
+
color: isActive
|
|
472
|
+
? tokenSchema.color.foreground.inverseSecondary
|
|
473
|
+
: tokenSchema.color.foreground.neutralSecondary,
|
|
368
474
|
whiteSpace: 'nowrap',
|
|
369
475
|
overflow: 'hidden',
|
|
370
476
|
textOverflow: 'ellipsis',
|
|
@@ -381,7 +487,7 @@ export function CommandPalette({ isOpen, onClose }: CommandPaletteProps) {
|
|
|
381
487
|
<kbd
|
|
382
488
|
className={css({
|
|
383
489
|
fontSize: 11,
|
|
384
|
-
color:
|
|
490
|
+
color: tokenSchema.color.foreground.inverseSecondary,
|
|
385
491
|
background: '#2a2a2a',
|
|
386
492
|
border: '1px solid #3a3a3a',
|
|
387
493
|
borderRadius: 4,
|
|
@@ -398,7 +504,8 @@ export function CommandPalette({ isOpen, onClose }: CommandPaletteProps) {
|
|
|
398
504
|
})}
|
|
399
505
|
</ul>
|
|
400
506
|
</li>
|
|
401
|
-
|
|
507
|
+
)
|
|
508
|
+
})
|
|
402
509
|
)}
|
|
403
510
|
</ul>
|
|
404
511
|
|
|
@@ -409,9 +516,9 @@ export function CommandPalette({ isOpen, onClose }: CommandPaletteProps) {
|
|
|
409
516
|
alignItems: 'center',
|
|
410
517
|
gap: 14,
|
|
411
518
|
padding: '8px 16px',
|
|
412
|
-
borderTop:
|
|
519
|
+
borderTop: `1px solid ${tokenSchema.color.border.muted}`,
|
|
413
520
|
fontSize: 11,
|
|
414
|
-
color:
|
|
521
|
+
color: tokenSchema.color.foreground.neutralSecondary,
|
|
415
522
|
})}
|
|
416
523
|
>
|
|
417
524
|
<span>
|
|
@@ -1,46 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
fontSize: 13,
|
|
22
|
-
fontWeight: 500,
|
|
23
|
-
fontFamily: 'inherit',
|
|
24
|
-
textDecoration: 'none',
|
|
25
|
-
cursor: 'pointer',
|
|
26
|
-
whiteSpace: 'nowrap',
|
|
27
|
-
flexShrink: 0,
|
|
28
|
-
letterSpacing: '-0.01em',
|
|
29
|
-
transition: 'background 130ms',
|
|
30
|
-
|
|
31
|
-
'&:hover': { backgroundColor: '#1f2937' },
|
|
32
|
-
'&:active': { backgroundColor: '#374151' },
|
|
33
|
-
|
|
34
|
-
'&:focus-visible': {
|
|
35
|
-
outline: '2px solid #111827',
|
|
36
|
-
outlineOffset: 2,
|
|
37
|
-
},
|
|
38
|
-
})}
|
|
39
|
-
>
|
|
40
|
-
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" aria-hidden>
|
|
41
|
-
<path d="M6 1.5v9M1.5 6h9" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
|
|
42
|
-
</svg>
|
|
43
|
-
{children}
|
|
44
|
-
</a>
|
|
45
|
-
)
|
|
46
|
-
}
|
|
1
|
+
import { Button } from '@keystar/ui/button'
|
|
2
|
+
import { Icon } from '@keystar/ui/icon'
|
|
3
|
+
import { plusIcon } from '@keystar/ui/icon/icons/plusIcon'
|
|
4
|
+
import { Text } from '@keystar/ui/typography'
|
|
5
|
+
|
|
6
|
+
import type { CollectionMeta } from '../../types'
|
|
7
|
+
|
|
8
|
+
export function CreateButtonLink(props: { children?: string; list: CollectionMeta }) {
|
|
9
|
+
const { list, children = `New ${list.singular}` } = props
|
|
10
|
+
return (
|
|
11
|
+
<Button
|
|
12
|
+
href={`/${list.path}/create`}
|
|
13
|
+
aria-label={`New ${list.singular}`}
|
|
14
|
+
prominence="high"
|
|
15
|
+
>
|
|
16
|
+
<Icon src={plusIcon} />
|
|
17
|
+
<Text>{children}</Text>
|
|
18
|
+
</Button>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
@@ -34,45 +34,51 @@ export function GraphQLErrorNotice({
|
|
|
34
34
|
})
|
|
35
35
|
if (!errors.length) return null
|
|
36
36
|
|
|
37
|
+
// The Notice already sets role="alert" for the critical tone, but with
|
|
38
|
+
// aria-live="polite". Wrap it in an assertive live region (without a second
|
|
39
|
+
// role, to avoid a double role) so screen readers announce the failure
|
|
40
|
+
// immediately (WCAG 4.1.3 Status Messages).
|
|
37
41
|
return (
|
|
38
|
-
<
|
|
39
|
-
<
|
|
40
|
-
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
<Text key={i++} elementType="li">
|
|
50
|
-
{line}
|
|
51
|
-
</Text>
|
|
52
|
-
)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (
|
|
56
|
-
'result' in error &&
|
|
57
|
-
typeof error.result === 'object' &&
|
|
58
|
-
error.result !== null &&
|
|
59
|
-
'errors' in error.result &&
|
|
60
|
-
Array.isArray(error.result.errors)
|
|
61
|
-
) {
|
|
62
|
-
for (const { message } of error.result.errors) {
|
|
63
|
-
if (typeof message !== 'string') continue
|
|
42
|
+
<div aria-live="assertive" aria-atomic="true">
|
|
43
|
+
<Notice tone="critical">
|
|
44
|
+
<Heading>Errors</Heading>
|
|
45
|
+
<Content>
|
|
46
|
+
<VStack elementType="ul" gap="large">
|
|
47
|
+
{[
|
|
48
|
+
...(function* () {
|
|
49
|
+
let i = 0
|
|
50
|
+
for (const error of errors) {
|
|
51
|
+
const lines = error.message.split('\n')
|
|
52
|
+
for (const line of lines) {
|
|
64
53
|
yield (
|
|
65
54
|
<Text key={i++} elementType="li">
|
|
66
|
-
{
|
|
55
|
+
{line}
|
|
67
56
|
</Text>
|
|
68
57
|
)
|
|
69
58
|
}
|
|
59
|
+
|
|
60
|
+
if (
|
|
61
|
+
'result' in error &&
|
|
62
|
+
typeof error.result === 'object' &&
|
|
63
|
+
error.result !== null &&
|
|
64
|
+
'errors' in error.result &&
|
|
65
|
+
Array.isArray(error.result.errors)
|
|
66
|
+
) {
|
|
67
|
+
for (const { message } of error.result.errors) {
|
|
68
|
+
if (typeof message !== 'string') continue
|
|
69
|
+
yield (
|
|
70
|
+
<Text key={i++} elementType="li">
|
|
71
|
+
{message}
|
|
72
|
+
</Text>
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
70
76
|
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
</
|
|
75
|
-
</
|
|
76
|
-
</
|
|
77
|
+
})(),
|
|
78
|
+
]}
|
|
79
|
+
</VStack>
|
|
80
|
+
</Content>
|
|
81
|
+
</Notice>
|
|
82
|
+
</div>
|
|
77
83
|
)
|
|
78
84
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Link from 'next/link'
|
|
2
2
|
|
|
3
|
-
import { css } from '@keystar/ui/style'
|
|
3
|
+
import { css, tokenSchema } from '@keystar/ui/style'
|
|
4
4
|
|
|
5
5
|
import { useNixxie } from '../context'
|
|
6
6
|
|
|
@@ -22,7 +22,7 @@ function DefaultLogo() {
|
|
|
22
22
|
outline: 0,
|
|
23
23
|
flexShrink: 0,
|
|
24
24
|
'&:focus-visible': {
|
|
25
|
-
outline:
|
|
25
|
+
outline: `2px solid ${tokenSchema.color.scale.black}`,
|
|
26
26
|
outlineOffset: 3,
|
|
27
27
|
borderRadius: 4,
|
|
28
28
|
},
|
|
@@ -37,14 +37,14 @@ function DefaultLogo() {
|
|
|
37
37
|
width: 28,
|
|
38
38
|
height: 28,
|
|
39
39
|
borderRadius: 6,
|
|
40
|
-
backgroundColor:
|
|
40
|
+
backgroundColor: tokenSchema.color.scale.black,
|
|
41
41
|
flexShrink: 0,
|
|
42
42
|
})}
|
|
43
43
|
>
|
|
44
44
|
<svg width="13" height="13" viewBox="0 0 14 14" fill="none">
|
|
45
45
|
<path
|
|
46
46
|
d="M2.5 11V3L11.5 11V3"
|
|
47
|
-
stroke=
|
|
47
|
+
stroke={tokenSchema.color.scale.white}
|
|
48
48
|
strokeWidth="1.8"
|
|
49
49
|
strokeLinecap="round"
|
|
50
50
|
strokeLinejoin="round"
|
|
@@ -58,7 +58,7 @@ function DefaultLogo() {
|
|
|
58
58
|
fontSize: 14,
|
|
59
59
|
fontWeight: 600,
|
|
60
60
|
letterSpacing: '-0.03em',
|
|
61
|
-
color:
|
|
61
|
+
color: tokenSchema.color.foreground.neutralEmphasis,
|
|
62
62
|
lineHeight: 1,
|
|
63
63
|
fontFamily: "'Inter', -apple-system, BlinkMacSystemFont, sans-serif",
|
|
64
64
|
})}
|