@ankhorage/zora 25.1.0 → 25.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +1 -1
  3. package/dist/features/explorer/adapters/inbound/Explorer.d.ts.map +1 -1
  4. package/dist/features/explorer/adapters/inbound/Explorer.js +43 -2
  5. package/dist/features/explorer/adapters/inbound/Explorer.js.map +1 -1
  6. package/dist/features/explorer/application/shouldDispatchExplorerPageRequest.d.ts +8 -0
  7. package/dist/features/explorer/application/shouldDispatchExplorerPageRequest.d.ts.map +1 -0
  8. package/dist/features/explorer/application/shouldDispatchExplorerPageRequest.js +9 -0
  9. package/dist/features/explorer/application/shouldDispatchExplorerPageRequest.js.map +1 -0
  10. package/dist/features/explorer/application/shouldRequestExplorerPage.d.ts +4 -0
  11. package/dist/features/explorer/application/shouldRequestExplorerPage.d.ts.map +1 -0
  12. package/dist/features/explorer/application/shouldRequestExplorerPage.js +14 -0
  13. package/dist/features/explorer/application/shouldRequestExplorerPage.js.map +1 -0
  14. package/dist/features/explorer/meta.d.ts +110 -0
  15. package/dist/features/explorer/meta.d.ts.map +1 -1
  16. package/dist/features/explorer/meta.js +25 -0
  17. package/dist/features/explorer/meta.js.map +1 -1
  18. package/dist/features/explorer/public.d.ts +1 -1
  19. package/dist/features/explorer/public.d.ts.map +1 -1
  20. package/dist/features/explorer/public.js.map +1 -1
  21. package/dist/types/explorer.d.ts +28 -0
  22. package/dist/types/explorer.d.ts.map +1 -1
  23. package/dist/types/explorer.js.map +1 -1
  24. package/package.json +5 -5
  25. package/src/capabilities/index.test.ts +10 -6
  26. package/src/features/explorer/adapters/inbound/Explorer.tsx +82 -13
  27. package/src/features/explorer/application/shouldDispatchExplorerPageRequest.test.ts +43 -0
  28. package/src/features/explorer/application/shouldDispatchExplorerPageRequest.ts +18 -0
  29. package/src/features/explorer/application/shouldRequestExplorerPage.test.ts +93 -0
  30. package/src/features/explorer/application/shouldRequestExplorerPage.ts +26 -0
  31. package/src/features/explorer/meta.test.ts +55 -0
  32. package/src/features/explorer/meta.ts +25 -0
  33. package/src/features/explorer/public.ts +2 -0
  34. package/src/types/explorer.ts +30 -0
  35. package/web-dist/chunks/{Accordion-fmn31fgf.js → Accordion-kkr7xfh2.js} +88 -12
  36. package/web-dist/components/explorer/Explorer.js +1 -1
  37. package/web-dist/components/file-explorer/FileExplorer.js +1 -1
  38. package/web-dist/components/media-explorer/MediaExplorer.js +1 -1
  39. package/web-dist/components/uploader/Uploader.js +1 -1
  40. package/web-dist/manifest.json +4 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## 25.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 67a39fe: Update dependencies: `@ankhorage/ankh`.
8
+
9
+ ## 25.2.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 92ed809: Finish the Explorer migration with provider-neutral paging and permission presentation, and extend
14
+ the runnable GridView workspace example with paged, limited-access, and Uploader interactions.
15
+
3
16
  ## 25.1.0
4
17
 
5
18
  ### Minor Changes
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  # @ankhorage/zora
5
5
 
6
- ![license: MIT](././paradox/badges/license.svg) ![npm: v25.1.0](././paradox/badges/npm.svg) ![runtime: bun](././paradox/badges/runtime.svg) ![typescript: strict](././paradox/badges/typescript.svg) ![eslint: checked](././paradox/badges/eslint.svg) ![prettier: checked](././paradox/badges/prettier.svg) ![build: checked](././paradox/badges/build.svg) ![tests: checked](././paradox/badges/tests.svg) ![paradox: warnings](././paradox/badges/docs.svg)
6
+ ![license: MIT](././paradox/badges/license.svg) ![npm: v25.2.1](././paradox/badges/npm.svg) ![runtime: bun](././paradox/badges/runtime.svg) ![typescript: strict](././paradox/badges/typescript.svg) ![eslint: checked](././paradox/badges/eslint.svg) ![prettier: checked](././paradox/badges/prettier.svg) ![build: checked](././paradox/badges/build.svg) ![tests: checked](././paradox/badges/tests.svg) ![paradox: warnings](././paradox/badges/docs.svg)
7
7
 
8
8
  Opinionated React Native and React Native Web UI kit built on @ankhorage/surface.
9
9
 
@@ -1 +1 @@
1
- {"version":3,"file":"Explorer.d.ts","sourceRoot":"","sources":["../../../../../src/features/explorer/adapters/inbound/Explorer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,KAAK,EAAgB,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAW9E,2FAA2F;AAC3F,eAAO,MAAM,QAAQ,qDAAoC,CAAC"}
1
+ {"version":3,"file":"Explorer.d.ts","sourceRoot":"","sources":["../../../../../src/features/explorer/adapters/inbound/Explorer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,KAAK,EAAgB,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAgB9E,2FAA2F;AAC3F,eAAO,MAAM,QAAQ,qDAAoC,CAAC"}
@@ -7,22 +7,51 @@ import { withZoraThemeScope } from '../../../theme/adapters/inbound/withZoraThem
7
7
  import { useZoraTheme } from '../../../theme/composition/useZoraTheme';
8
8
  import { Text } from '../../../typography/public';
9
9
  import { resolveExplorerSelection } from '../../application/resolveExplorerSelection';
10
+ import { shouldDispatchExplorerPageRequest, } from '../../application/shouldDispatchExplorerPageRequest';
11
+ import { shouldRequestExplorerPage } from '../../application/shouldRequestExplorerPage';
10
12
  import { ExplorerKeyboardProxy } from './ExplorerKeyboardProxy';
11
13
  import { useExplorerKeyboardFocus } from './useExplorerKeyboardFocus';
12
14
  /*** Single canonical Explorer implementation for media and file catalogue presentation. */
13
15
  export const Explorer = withZoraThemeScope(ExplorerInner);
14
16
  /*** Presents provider-neutral asset tiles with controlled or uncontrolled selection. */
15
- function ExplorerInner({ items, selectedIds, defaultSelectedIds = [], selectionMode = 'single', onSelectionChange, onActivate, width, height, tileSize = 120, zoom = 1, loading = false, errorText, emptyText = 'No items', disabled = false, readOnly = false, interactionPolicy, testID, }) {
17
+ function ExplorerInner({ items, selectedIds, defaultSelectedIds = [], selectionMode = 'single', onSelectionChange, onActivate, width, height, tileSize = 120, zoom = 1, loading = false, hasMore = false, loadingMore = false, pagingCollectionId, pagingRetryToken, onLoadMore, permissionStatus = 'granted', permissionText, onRequestPermission, errorText, emptyText = 'No items', disabled = false, readOnly = false, interactionPolicy, testID, }) {
16
18
  const { theme } = useZoraTheme();
17
19
  const [internalSelectedIds, setInternalSelectedIds] = React.useState(defaultSelectedIds);
18
20
  const anchorId = React.useRef(null);
19
21
  const [columns, setColumns] = React.useState(1);
20
22
  const [visibleIds, setVisibleIds] = React.useState([]);
23
+ const lastPageRequestRef = React.useRef(null);
21
24
  const effectiveSelectedIds = selectedIds ?? internalSelectedIds;
22
25
  const itemLookup = React.useMemo(() => new Map(items.map((item) => [item.id, item])), [items]);
23
26
  const ids = React.useMemo(() => items.filter((item) => !item.disabled).map((item) => item.id), [items]);
24
27
  const selected = new Set(effectiveSelectedIds);
25
28
  const passive = interactionPolicy === 'passive' || disabled || readOnly;
29
+ React.useEffect(() => {
30
+ const request = {
31
+ collectionId: pagingCollectionId,
32
+ loadedItemCount: items.length,
33
+ retryToken: pagingRetryToken,
34
+ };
35
+ if (!onLoadMore ||
36
+ !shouldDispatchExplorerPageRequest(lastPageRequestRef.current, request) ||
37
+ !shouldRequestExplorerPage(ids, visibleIds, hasMore, loadingMore, loading, errorText, permissionStatus)) {
38
+ return;
39
+ }
40
+ lastPageRequestRef.current = request;
41
+ onLoadMore({ loadedItemCount: items.length });
42
+ }, [
43
+ errorText,
44
+ hasMore,
45
+ ids,
46
+ items.length,
47
+ loading,
48
+ loadingMore,
49
+ onLoadMore,
50
+ pagingCollectionId,
51
+ pagingRetryToken,
52
+ permissionStatus,
53
+ visibleIds,
54
+ ]);
26
55
  const select = (item, intent) => {
27
56
  if (passive || item.disabled)
28
57
  return;
@@ -73,13 +102,25 @@ function ExplorerInner({ items, selectedIds, defaultSelectedIds = [], selectionM
73
102
  </NativePressable>
74
103
  </ExplorerKeyboardProxy>);
75
104
  };
105
+ if (permissionStatus === 'denied' || permissionStatus === 'unavailable') {
106
+ return (<NativeView testID={testID}>
107
+ <Text>{permissionText ?? 'This collection is unavailable without permission.'}</Text>
108
+ {permissionStatus === 'denied' && onRequestPermission ? (<NativePressable accessibilityRole="button" onPress={onRequestPermission}>
109
+ <Text>Grant access</Text>
110
+ </NativePressable>) : null}
111
+ </NativeView>);
112
+ }
76
113
  if (errorText)
77
114
  return <Text testID={testID}>{errorText}</Text>;
78
115
  if (loading)
79
116
  return <Text testID={testID}>Loading…</Text>;
80
117
  if (items.length === 0)
81
118
  return <Text testID={testID}>{emptyText}</Text>;
82
- return (<TileGrid focusedItemId={keyboard.focusedId ?? undefined} height={height} interactionPolicy={interactionPolicy} onColumnsChange={setColumns} onVisibleItemIdsChange={setVisibleIds} items={items} renderItem={renderTile} testID={testID} tileSize={tileSize} width={width} zoom={zoom}/>);
119
+ return (<NativeView>
120
+ {permissionStatus === 'limited' ? (<Text>{permissionText ?? 'Showing the media you have allowed.'}</Text>) : null}
121
+ <TileGrid focusedItemId={keyboard.focusedId ?? undefined} height={height} interactionPolicy={interactionPolicy} onColumnsChange={setColumns} onVisibleItemIdsChange={setVisibleIds} items={items} renderItem={renderTile} testID={testID} tileSize={tileSize} width={width} zoom={zoom}/>
122
+ {loadingMore ? <Text>Loading more…</Text> : null}
123
+ </NativeView>);
83
124
  }
84
125
  /***
85
126
  * Normalize platform press modifiers into selection intents
@@ -1 +1 @@
1
- {"version":3,"file":"Explorer.js","sourceRoot":"","sources":["../../../../../src/features/explorer/adapters/inbound/Explorer.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport { Platform, Pressable as NativePressable, View as NativeView } from 'react-native';\n\nimport type { ExplorerItem, ExplorerProps } from '../../../../types/explorer';\nimport { TileGrid } from '../../../grid-view/public';\nimport { Icon } from '../../../icon/public';\nimport { Image } from '../../../image/public';\nimport { withZoraThemeScope } from '../../../theme/adapters/inbound/withZoraThemeScope';\nimport { useZoraTheme } from '../../../theme/composition/useZoraTheme';\nimport { Text } from '../../../typography/public';\nimport { resolveExplorerSelection } from '../../application/resolveExplorerSelection';\nimport { ExplorerKeyboardProxy } from './ExplorerKeyboardProxy';\nimport { useExplorerKeyboardFocus } from './useExplorerKeyboardFocus';\n\n/*** Single canonical Explorer implementation for media and file catalogue presentation. */\nexport const Explorer = withZoraThemeScope(ExplorerInner);\n\n/*** Presents provider-neutral asset tiles with controlled or uncontrolled selection. */\nfunction ExplorerInner({\n items,\n selectedIds,\n defaultSelectedIds = [],\n selectionMode = 'single',\n onSelectionChange,\n onActivate,\n width,\n height,\n tileSize = 120,\n zoom = 1,\n loading = false,\n errorText,\n emptyText = 'No items',\n disabled = false,\n readOnly = false,\n interactionPolicy,\n testID,\n}: ExplorerProps) {\n const { theme } = useZoraTheme();\n const [internalSelectedIds, setInternalSelectedIds] =\n React.useState<readonly string[]>(defaultSelectedIds);\n const anchorId = React.useRef<string | null>(null);\n const [columns, setColumns] = React.useState(1);\n const [visibleIds, setVisibleIds] = React.useState<readonly string[]>([]);\n const effectiveSelectedIds = selectedIds ?? internalSelectedIds;\n const itemLookup = React.useMemo(() => new Map(items.map((item) => [item.id, item])), [items]);\n const ids = React.useMemo(\n () => items.filter((item) => !item.disabled).map((item) => item.id),\n [items],\n );\n const selected = new Set(effectiveSelectedIds);\n const passive = interactionPolicy === 'passive' || disabled || readOnly;\n\n const select = (item: ExplorerItem, intent: 'replace' | 'toggle' | 'range') => {\n if (passive || item.disabled) return;\n const next = resolveExplorerSelection(\n ids,\n effectiveSelectedIds,\n item.id,\n anchorId.current,\n intent,\n selectionMode,\n );\n if (intent !== 'range') anchorId.current = item.id;\n if (selectedIds === undefined) setInternalSelectedIds(next);\n onSelectionChange?.({ selectedIds: next });\n };\n\n const keyboard = useExplorerKeyboardFocus(\n items,\n columns,\n passive,\n visibleIds,\n (targetId, originId, shiftKey) => {\n if (!shiftKey) return;\n anchorId.current ??= originId;\n const nextItem = itemLookup.get(targetId);\n if (nextItem) select(nextItem, 'range');\n },\n );\n\n const renderTile = (tile: { readonly id: string }) => {\n const item = itemLookup.get(tile.id);\n if (!item) return null;\n const isSelected = selected.has(item.id);\n const canInteract = !passive && !item.disabled;\n return (\n <ExplorerKeyboardProxy\n onKeyDown={(key, shiftKey) => keyboard.onKeyDown(item.id, key, shiftKey)}\n >\n <NativePressable\n accessibilityLabel={item.name}\n accessibilityRole=\"button\"\n accessibilityState={{ selected: isSelected, disabled: !canInteract }}\n disabled={!canInteract}\n focusable={canInteract && (Platform.OS !== 'web' || item.id === keyboard.tabStopId)}\n onFocus={() => keyboard.onFocus(item.id)}\n onLongPress={() => select(item, 'toggle')}\n onPress={(event) => {\n const intent = resolveExplorerPressIntent(event.nativeEvent);\n select(item, intent);\n if (selectionMode === 'single' && intent === 'replace') {\n onActivate?.({ id: item.id });\n }\n }}\n style={{\n flex: 1,\n overflow: 'hidden',\n borderRadius: 8,\n borderWidth: isSelected ? 2 : 1,\n borderColor: isSelected ? theme.colors.primary : theme.semantics.neutral.divider,\n backgroundColor: theme.semantics.neutral.surface,\n padding: 8,\n gap: 4,\n }}\n ref={(node) => keyboard.registerTile(item.id, node)}\n testID={`explorer-item-${item.id}`}\n >\n <NativeView style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>\n {item.thumbnailUri ? (\n <Image\n accessibilityLabel={item.name}\n aspectRatio={1}\n source={item.thumbnailUri}\n width=\"100%\"\n />\n ) : (\n <Icon\n name={item.kind === 'folder' ? 'folder-outline' : 'document-outline'}\n size={32}\n />\n )}\n </NativeView>\n <Text numberOfLines={1} variant=\"caption\">\n {item.name}\n </Text>\n </NativePressable>\n </ExplorerKeyboardProxy>\n );\n };\n\n if (errorText) return <Text testID={testID}>{errorText}</Text>;\n if (loading) return <Text testID={testID}>Loading…</Text>;\n if (items.length === 0) return <Text testID={testID}>{emptyText}</Text>;\n\n return (\n <TileGrid\n focusedItemId={keyboard.focusedId ?? undefined}\n height={height}\n interactionPolicy={interactionPolicy}\n onColumnsChange={setColumns}\n onVisibleItemIdsChange={setVisibleIds}\n items={items}\n renderItem={renderTile}\n testID={testID}\n tileSize={tileSize}\n width={width}\n zoom={zoom}\n />\n );\n}\n\n/***\n * Normalize platform press modifiers into selection intents\n * without passing event objects into the public contracts.\n */\nfunction resolveExplorerPressIntent(event: unknown): 'replace' | 'toggle' | 'range' {\n if (typeof event !== 'object' || event === null) return 'replace';\n if ('shiftKey' in event && event.shiftKey === true) return 'range';\n if ('ctrlKey' in event && event.ctrlKey === true) return 'toggle';\n if ('metaKey' in event && event.metaKey === true) return 'toggle';\n return 'replace';\n}\n"]}
1
+ {"version":3,"file":"Explorer.js","sourceRoot":"","sources":["../../../../../src/features/explorer/adapters/inbound/Explorer.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport { Platform, Pressable as NativePressable, View as NativeView } from 'react-native';\n\nimport type { ExplorerItem, ExplorerProps } from '../../../../types/explorer';\nimport { TileGrid } from '../../../grid-view/public';\nimport { Icon } from '../../../icon/public';\nimport { Image } from '../../../image/public';\nimport { withZoraThemeScope } from '../../../theme/adapters/inbound/withZoraThemeScope';\nimport { useZoraTheme } from '../../../theme/composition/useZoraTheme';\nimport { Text } from '../../../typography/public';\nimport { resolveExplorerSelection } from '../../application/resolveExplorerSelection';\nimport {\n type ExplorerPageRequestSignature,\n shouldDispatchExplorerPageRequest,\n} from '../../application/shouldDispatchExplorerPageRequest';\nimport { shouldRequestExplorerPage } from '../../application/shouldRequestExplorerPage';\nimport { ExplorerKeyboardProxy } from './ExplorerKeyboardProxy';\nimport { useExplorerKeyboardFocus } from './useExplorerKeyboardFocus';\n\n/*** Single canonical Explorer implementation for media and file catalogue presentation. */\nexport const Explorer = withZoraThemeScope(ExplorerInner);\n\n/*** Presents provider-neutral asset tiles with controlled or uncontrolled selection. */\nfunction ExplorerInner({\n items,\n selectedIds,\n defaultSelectedIds = [],\n selectionMode = 'single',\n onSelectionChange,\n onActivate,\n width,\n height,\n tileSize = 120,\n zoom = 1,\n loading = false,\n hasMore = false,\n loadingMore = false,\n pagingCollectionId,\n pagingRetryToken,\n onLoadMore,\n permissionStatus = 'granted',\n permissionText,\n onRequestPermission,\n errorText,\n emptyText = 'No items',\n disabled = false,\n readOnly = false,\n interactionPolicy,\n testID,\n}: ExplorerProps) {\n const { theme } = useZoraTheme();\n const [internalSelectedIds, setInternalSelectedIds] =\n React.useState<readonly string[]>(defaultSelectedIds);\n const anchorId = React.useRef<string | null>(null);\n const [columns, setColumns] = React.useState(1);\n const [visibleIds, setVisibleIds] = React.useState<readonly string[]>([]);\n const lastPageRequestRef = React.useRef<ExplorerPageRequestSignature | null>(null);\n const effectiveSelectedIds = selectedIds ?? internalSelectedIds;\n const itemLookup = React.useMemo(() => new Map(items.map((item) => [item.id, item])), [items]);\n const ids = React.useMemo(\n () => items.filter((item) => !item.disabled).map((item) => item.id),\n [items],\n );\n const selected = new Set(effectiveSelectedIds);\n const passive = interactionPolicy === 'passive' || disabled || readOnly;\n\n React.useEffect(() => {\n const request = {\n collectionId: pagingCollectionId,\n loadedItemCount: items.length,\n retryToken: pagingRetryToken,\n };\n if (\n !onLoadMore ||\n !shouldDispatchExplorerPageRequest(lastPageRequestRef.current, request) ||\n !shouldRequestExplorerPage(\n ids,\n visibleIds,\n hasMore,\n loadingMore,\n loading,\n errorText,\n permissionStatus,\n )\n ) {\n return;\n }\n lastPageRequestRef.current = request;\n onLoadMore({ loadedItemCount: items.length });\n }, [\n errorText,\n hasMore,\n ids,\n items.length,\n loading,\n loadingMore,\n onLoadMore,\n pagingCollectionId,\n pagingRetryToken,\n permissionStatus,\n visibleIds,\n ]);\n\n const select = (item: ExplorerItem, intent: 'replace' | 'toggle' | 'range') => {\n if (passive || item.disabled) return;\n const next = resolveExplorerSelection(\n ids,\n effectiveSelectedIds,\n item.id,\n anchorId.current,\n intent,\n selectionMode,\n );\n if (intent !== 'range') anchorId.current = item.id;\n if (selectedIds === undefined) setInternalSelectedIds(next);\n onSelectionChange?.({ selectedIds: next });\n };\n\n const keyboard = useExplorerKeyboardFocus(\n items,\n columns,\n passive,\n visibleIds,\n (targetId, originId, shiftKey) => {\n if (!shiftKey) return;\n anchorId.current ??= originId;\n const nextItem = itemLookup.get(targetId);\n if (nextItem) select(nextItem, 'range');\n },\n );\n\n const renderTile = (tile: { readonly id: string }) => {\n const item = itemLookup.get(tile.id);\n if (!item) return null;\n const isSelected = selected.has(item.id);\n const canInteract = !passive && !item.disabled;\n return (\n <ExplorerKeyboardProxy\n onKeyDown={(key, shiftKey) => keyboard.onKeyDown(item.id, key, shiftKey)}\n >\n <NativePressable\n accessibilityLabel={item.name}\n accessibilityRole=\"button\"\n accessibilityState={{ selected: isSelected, disabled: !canInteract }}\n disabled={!canInteract}\n focusable={canInteract && (Platform.OS !== 'web' || item.id === keyboard.tabStopId)}\n onFocus={() => keyboard.onFocus(item.id)}\n onLongPress={() => select(item, 'toggle')}\n onPress={(event) => {\n const intent = resolveExplorerPressIntent(event.nativeEvent);\n select(item, intent);\n if (selectionMode === 'single' && intent === 'replace') {\n onActivate?.({ id: item.id });\n }\n }}\n style={{\n flex: 1,\n overflow: 'hidden',\n borderRadius: 8,\n borderWidth: isSelected ? 2 : 1,\n borderColor: isSelected ? theme.colors.primary : theme.semantics.neutral.divider,\n backgroundColor: theme.semantics.neutral.surface,\n padding: 8,\n gap: 4,\n }}\n ref={(node) => keyboard.registerTile(item.id, node)}\n testID={`explorer-item-${item.id}`}\n >\n <NativeView style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>\n {item.thumbnailUri ? (\n <Image\n accessibilityLabel={item.name}\n aspectRatio={1}\n source={item.thumbnailUri}\n width=\"100%\"\n />\n ) : (\n <Icon\n name={item.kind === 'folder' ? 'folder-outline' : 'document-outline'}\n size={32}\n />\n )}\n </NativeView>\n <Text numberOfLines={1} variant=\"caption\">\n {item.name}\n </Text>\n </NativePressable>\n </ExplorerKeyboardProxy>\n );\n };\n\n if (permissionStatus === 'denied' || permissionStatus === 'unavailable') {\n return (\n <NativeView testID={testID}>\n <Text>{permissionText ?? 'This collection is unavailable without permission.'}</Text>\n {permissionStatus === 'denied' && onRequestPermission ? (\n <NativePressable accessibilityRole=\"button\" onPress={onRequestPermission}>\n <Text>Grant access</Text>\n </NativePressable>\n ) : null}\n </NativeView>\n );\n }\n if (errorText) return <Text testID={testID}>{errorText}</Text>;\n if (loading) return <Text testID={testID}>Loading…</Text>;\n if (items.length === 0) return <Text testID={testID}>{emptyText}</Text>;\n\n return (\n <NativeView>\n {permissionStatus === 'limited' ? (\n <Text>{permissionText ?? 'Showing the media you have allowed.'}</Text>\n ) : null}\n <TileGrid\n focusedItemId={keyboard.focusedId ?? undefined}\n height={height}\n interactionPolicy={interactionPolicy}\n onColumnsChange={setColumns}\n onVisibleItemIdsChange={setVisibleIds}\n items={items}\n renderItem={renderTile}\n testID={testID}\n tileSize={tileSize}\n width={width}\n zoom={zoom}\n />\n {loadingMore ? <Text>Loading more…</Text> : null}\n </NativeView>\n );\n}\n\n/***\n * Normalize platform press modifiers into selection intents\n * without passing event objects into the public contracts.\n */\nfunction resolveExplorerPressIntent(event: unknown): 'replace' | 'toggle' | 'range' {\n if (typeof event !== 'object' || event === null) return 'replace';\n if ('shiftKey' in event && event.shiftKey === true) return 'range';\n if ('ctrlKey' in event && event.ctrlKey === true) return 'toggle';\n if ('metaKey' in event && event.metaKey === true) return 'toggle';\n return 'replace';\n}\n"]}
@@ -0,0 +1,8 @@
1
+ export interface ExplorerPageRequestSignature {
2
+ readonly collectionId: string | undefined;
3
+ readonly loadedItemCount: number;
4
+ readonly retryToken: string | undefined;
5
+ }
6
+ /*** Preserves one request per provider page boundary until its collection, row count, or retry token changes. */
7
+ export declare function shouldDispatchExplorerPageRequest(previous: ExplorerPageRequestSignature | null, next: ExplorerPageRequestSignature): boolean;
8
+ //# sourceMappingURL=shouldDispatchExplorerPageRequest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shouldDispatchExplorerPageRequest.d.ts","sourceRoot":"","sources":["../../../../src/features/explorer/application/shouldDispatchExplorerPageRequest.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC;AAED,iHAAiH;AACjH,wBAAgB,iCAAiC,CAC/C,QAAQ,EAAE,4BAA4B,GAAG,IAAI,EAC7C,IAAI,EAAE,4BAA4B,GACjC,OAAO,CAOT"}
@@ -0,0 +1,9 @@
1
+ /*** Preserves one request per provider page boundary until its collection, row count, or retry token changes. */
2
+ export function shouldDispatchExplorerPageRequest(previous, next) {
3
+ if (previous === null)
4
+ return true;
5
+ return (previous.collectionId !== next.collectionId ||
6
+ previous.loadedItemCount !== next.loadedItemCount ||
7
+ previous.retryToken !== next.retryToken);
8
+ }
9
+ //# sourceMappingURL=shouldDispatchExplorerPageRequest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shouldDispatchExplorerPageRequest.js","sourceRoot":"","sources":["../../../../src/features/explorer/application/shouldDispatchExplorerPageRequest.ts"],"names":[],"mappings":"AAMA,iHAAiH;AACjH,MAAM,UAAU,iCAAiC,CAC/C,QAA6C,EAC7C,IAAkC;IAElC,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACnC,OAAO,CACL,QAAQ,CAAC,YAAY,KAAK,IAAI,CAAC,YAAY;QAC3C,QAAQ,CAAC,eAAe,KAAK,IAAI,CAAC,eAAe;QACjD,QAAQ,CAAC,UAAU,KAAK,IAAI,CAAC,UAAU,CACxC,CAAC;AACJ,CAAC","sourcesContent":["export interface ExplorerPageRequestSignature {\n readonly collectionId: string | undefined;\n readonly loadedItemCount: number;\n readonly retryToken: string | undefined;\n}\n\n/*** Preserves one request per provider page boundary until its collection, row count, or retry token changes. */\nexport function shouldDispatchExplorerPageRequest(\n previous: ExplorerPageRequestSignature | null,\n next: ExplorerPageRequestSignature,\n): boolean {\n if (previous === null) return true;\n return (\n previous.collectionId !== next.collectionId ||\n previous.loadedItemCount !== next.loadedItemCount ||\n previous.retryToken !== next.retryToken\n );\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import type { ExplorerPermissionStatus } from '../../../types/explorer';
2
+ /*** Determines whether the mounted, accessible viewport has reached the provider-owned page boundary. */
3
+ export declare function shouldRequestExplorerPage(itemIds: readonly string[], visibleIds: readonly string[], hasMore: boolean, loadingMore: boolean, loading: boolean, errorText: string | undefined, permissionStatus: ExplorerPermissionStatus, threshold?: number): boolean;
4
+ //# sourceMappingURL=shouldRequestExplorerPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shouldRequestExplorerPage.d.ts","sourceRoot":"","sources":["../../../../src/features/explorer/application/shouldRequestExplorerPage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAExE,yGAAyG;AACzG,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,OAAO,EACpB,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,gBAAgB,EAAE,wBAAwB,EAC1C,SAAS,SAAK,GACb,OAAO,CAaT"}
@@ -0,0 +1,14 @@
1
+ /*** Determines whether the mounted, accessible viewport has reached the provider-owned page boundary. */
2
+ export function shouldRequestExplorerPage(itemIds, visibleIds, hasMore, loadingMore, loading, errorText, permissionStatus, threshold = 12) {
3
+ if (!hasMore ||
4
+ loadingMore ||
5
+ loading ||
6
+ errorText !== undefined ||
7
+ (permissionStatus !== 'granted' && permissionStatus !== 'limited') ||
8
+ visibleIds.length === 0) {
9
+ return false;
10
+ }
11
+ const firstPagingIndex = Math.max(0, itemIds.length - threshold);
12
+ return visibleIds.some((id) => itemIds.indexOf(id) >= firstPagingIndex);
13
+ }
14
+ //# sourceMappingURL=shouldRequestExplorerPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shouldRequestExplorerPage.js","sourceRoot":"","sources":["../../../../src/features/explorer/application/shouldRequestExplorerPage.ts"],"names":[],"mappings":"AAEA,yGAAyG;AACzG,MAAM,UAAU,yBAAyB,CACvC,OAA0B,EAC1B,UAA6B,EAC7B,OAAgB,EAChB,WAAoB,EACpB,OAAgB,EAChB,SAA6B,EAC7B,gBAA0C,EAC1C,SAAS,GAAG,EAAE;IAEd,IACE,CAAC,OAAO;QACR,WAAW;QACX,OAAO;QACP,SAAS,KAAK,SAAS;QACvB,CAAC,gBAAgB,KAAK,SAAS,IAAI,gBAAgB,KAAK,SAAS,CAAC;QAClE,UAAU,CAAC,MAAM,KAAK,CAAC,EACvB,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACjE,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,gBAAgB,CAAC,CAAC;AAC1E,CAAC","sourcesContent":["import type { ExplorerPermissionStatus } from '../../../types/explorer';\n\n/*** Determines whether the mounted, accessible viewport has reached the provider-owned page boundary. */\nexport function shouldRequestExplorerPage(\n itemIds: readonly string[],\n visibleIds: readonly string[],\n hasMore: boolean,\n loadingMore: boolean,\n loading: boolean,\n errorText: string | undefined,\n permissionStatus: ExplorerPermissionStatus,\n threshold = 12,\n): boolean {\n if (\n !hasMore ||\n loadingMore ||\n loading ||\n errorText !== undefined ||\n (permissionStatus !== 'granted' && permissionStatus !== 'limited') ||\n visibleIds.length === 0\n ) {\n return false;\n }\n const firstPagingIndex = Math.max(0, itemIds.length - threshold);\n return visibleIds.some((id) => itemIds.indexOf(id) >= firstPagingIndex);\n}\n"]}
@@ -38,6 +38,19 @@ export declare const mediaExplorerMeta: {
38
38
  readonly type: "string";
39
39
  }];
40
40
  };
41
+ readonly loadMore: {
42
+ readonly label: "Load more";
43
+ readonly eventType: "explorer.loadMore";
44
+ readonly payloadFields: readonly [{
45
+ readonly path: "loadedItemCount";
46
+ readonly type: "number";
47
+ }];
48
+ };
49
+ readonly requestPermission: {
50
+ readonly label: "Request permission";
51
+ readonly eventType: "explorer.requestPermission";
52
+ readonly payloadFields: readonly [];
53
+ };
41
54
  };
42
55
  readonly props: {
43
56
  readonly items: {
@@ -110,6 +123,14 @@ export declare const mediaExplorerMeta: {
110
123
  readonly type: "array";
111
124
  readonly category: "Selection";
112
125
  };
126
+ readonly defaultSelectedIds: {
127
+ readonly type: "array";
128
+ readonly category: "Selection";
129
+ };
130
+ readonly width: {
131
+ readonly type: "number";
132
+ readonly category: "Layout";
133
+ };
113
134
  readonly tileSize: {
114
135
  readonly type: "number";
115
136
  readonly category: "Layout";
@@ -129,6 +150,32 @@ export declare const mediaExplorerMeta: {
129
150
  readonly type: "boolean";
130
151
  readonly category: "State";
131
152
  };
153
+ readonly hasMore: {
154
+ readonly type: "boolean";
155
+ readonly category: "Paging";
156
+ };
157
+ readonly loadingMore: {
158
+ readonly type: "boolean";
159
+ readonly category: "Paging";
160
+ };
161
+ readonly pagingCollectionId: {
162
+ readonly type: "string";
163
+ readonly category: "Paging";
164
+ };
165
+ readonly pagingRetryToken: {
166
+ readonly type: "string";
167
+ readonly category: "Paging";
168
+ };
169
+ readonly permissionStatus: {
170
+ readonly type: "enum";
171
+ readonly category: "Permission";
172
+ readonly enum: readonly ["granted", "limited", "denied", "unavailable"];
173
+ readonly default: "granted";
174
+ };
175
+ readonly permissionText: {
176
+ readonly type: "string";
177
+ readonly category: "Permission";
178
+ };
132
179
  readonly errorText: {
133
180
  readonly type: "string";
134
181
  readonly category: "State";
@@ -153,6 +200,14 @@ export declare const mediaExplorerMeta: {
153
200
  readonly type: "action";
154
201
  readonly category: "Events";
155
202
  };
203
+ readonly onLoadMore: {
204
+ readonly type: "action";
205
+ readonly category: "Events";
206
+ };
207
+ readonly onRequestPermission: {
208
+ readonly type: "action";
209
+ readonly category: "Events";
210
+ };
156
211
  };
157
212
  };
158
213
  export declare const fileExplorerMeta: {
@@ -186,6 +241,19 @@ export declare const fileExplorerMeta: {
186
241
  readonly type: "string";
187
242
  }];
188
243
  };
244
+ readonly loadMore: {
245
+ readonly label: "Load more";
246
+ readonly eventType: "explorer.loadMore";
247
+ readonly payloadFields: readonly [{
248
+ readonly path: "loadedItemCount";
249
+ readonly type: "number";
250
+ }];
251
+ };
252
+ readonly requestPermission: {
253
+ readonly label: "Request permission";
254
+ readonly eventType: "explorer.requestPermission";
255
+ readonly payloadFields: readonly [];
256
+ };
189
257
  };
190
258
  readonly props: {
191
259
  readonly items: {
@@ -258,6 +326,14 @@ export declare const fileExplorerMeta: {
258
326
  readonly type: "array";
259
327
  readonly category: "Selection";
260
328
  };
329
+ readonly defaultSelectedIds: {
330
+ readonly type: "array";
331
+ readonly category: "Selection";
332
+ };
333
+ readonly width: {
334
+ readonly type: "number";
335
+ readonly category: "Layout";
336
+ };
261
337
  readonly tileSize: {
262
338
  readonly type: "number";
263
339
  readonly category: "Layout";
@@ -277,6 +353,32 @@ export declare const fileExplorerMeta: {
277
353
  readonly type: "boolean";
278
354
  readonly category: "State";
279
355
  };
356
+ readonly hasMore: {
357
+ readonly type: "boolean";
358
+ readonly category: "Paging";
359
+ };
360
+ readonly loadingMore: {
361
+ readonly type: "boolean";
362
+ readonly category: "Paging";
363
+ };
364
+ readonly pagingCollectionId: {
365
+ readonly type: "string";
366
+ readonly category: "Paging";
367
+ };
368
+ readonly pagingRetryToken: {
369
+ readonly type: "string";
370
+ readonly category: "Paging";
371
+ };
372
+ readonly permissionStatus: {
373
+ readonly type: "enum";
374
+ readonly category: "Permission";
375
+ readonly enum: readonly ["granted", "limited", "denied", "unavailable"];
376
+ readonly default: "granted";
377
+ };
378
+ readonly permissionText: {
379
+ readonly type: "string";
380
+ readonly category: "Permission";
381
+ };
280
382
  readonly errorText: {
281
383
  readonly type: "string";
282
384
  readonly category: "State";
@@ -301,6 +403,14 @@ export declare const fileExplorerMeta: {
301
403
  readonly type: "action";
302
404
  readonly category: "Events";
303
405
  };
406
+ readonly onLoadMore: {
407
+ readonly type: "action";
408
+ readonly category: "Events";
409
+ };
410
+ readonly onRequestPermission: {
411
+ readonly type: "action";
412
+ readonly category: "Events";
413
+ };
304
414
  };
305
415
  };
306
416
  //# sourceMappingURL=meta.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../../../src/features/explorer/meta.ts"],"names":[],"mappings":"AAyDA,0FAA0F;AAC1F,eAAO,MAAM,YAAY;;;;;;;CAOa,CAAC;AAEvC,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYQ,CAAC;AAEvC,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYS,CAAC"}
1
+ {"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../../../src/features/explorer/meta.ts"],"names":[],"mappings":"AAkFA,0FAA0F;AAC1F,eAAO,MAAM,YAAY;;;;;;;CAOa,CAAC;AAEvC,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYQ,CAAC;AAEvC,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYS,CAAC"}
@@ -28,16 +28,31 @@ const explorerProps = {
28
28
  default: 'single',
29
29
  },
30
30
  selectedIds: { type: 'array', category: 'Selection' },
31
+ defaultSelectedIds: { type: 'array', category: 'Selection' },
32
+ width: { type: 'number', category: 'Layout' },
31
33
  tileSize: { type: 'number', category: 'Layout', default: 120 },
32
34
  height: { type: 'number', category: 'Layout', default: 440 },
33
35
  zoom: { type: 'number', category: 'Layout', default: 1 },
34
36
  loading: { type: 'boolean', category: 'State' },
37
+ hasMore: { type: 'boolean', category: 'Paging' },
38
+ loadingMore: { type: 'boolean', category: 'Paging' },
39
+ pagingCollectionId: { type: 'string', category: 'Paging' },
40
+ pagingRetryToken: { type: 'string', category: 'Paging' },
41
+ permissionStatus: {
42
+ type: 'enum',
43
+ category: 'Permission',
44
+ enum: ['granted', 'limited', 'denied', 'unavailable'],
45
+ default: 'granted',
46
+ },
47
+ permissionText: { type: 'string', category: 'Permission' },
35
48
  errorText: { type: 'string', category: 'State' },
36
49
  emptyText: { type: 'string', category: 'Content' },
37
50
  disabled: { type: 'boolean', category: 'State' },
38
51
  readOnly: { type: 'boolean', category: 'State' },
39
52
  onSelectionChange: { type: 'action', category: 'Events' },
40
53
  onActivate: { type: 'action', category: 'Events' },
54
+ onLoadMore: { type: 'action', category: 'Events' },
55
+ onRequestPermission: { type: 'action', category: 'Events' },
41
56
  };
42
57
  const explorerEvents = {
43
58
  selectionChange: {
@@ -50,6 +65,16 @@ const explorerEvents = {
50
65
  eventType: 'explorer.activate',
51
66
  payloadFields: [{ path: 'id', type: 'string' }],
52
67
  },
68
+ loadMore: {
69
+ label: 'Load more',
70
+ eventType: 'explorer.loadMore',
71
+ payloadFields: [{ path: 'loadedItemCount', type: 'number' }],
72
+ },
73
+ requestPermission: {
74
+ label: 'Request permission',
75
+ eventType: 'explorer.requestPermission',
76
+ payloadFields: [],
77
+ },
53
78
  };
54
79
  /** Framework-bound Explorer is a composition primitive, not a separate manifest shape. */
55
80
  export const explorerMeta = {
@@ -1 +1 @@
1
- {"version":3,"file":"meta.js","sourceRoot":"","sources":["../../../src/features/explorer/meta.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ZoraComponentMeta } from '../../types/authoring';\n\nconst explorerProps = {\n items: {\n type: 'array',\n category: 'Data',\n itemSchema: [\n { key: 'id', schema: { type: 'string', category: 'Identity' } },\n {\n key: 'kind',\n schema: {\n type: 'enum',\n category: 'Data',\n enum: ['image', 'video', 'audio', 'document', 'file', 'folder'],\n },\n },\n { key: 'name', schema: { type: 'string', category: 'Content' } },\n { key: 'uri', schema: { type: 'string', category: 'Data' } },\n { key: 'thumbnailUri', schema: { type: 'string', category: 'Media' } },\n { key: 'contentType', schema: { type: 'string', category: 'Data' } },\n { key: 'sizeBytes', schema: { type: 'number', category: 'Data' } },\n { key: 'providerId', schema: { type: 'string', category: 'Identity' } },\n { key: 'disabled', schema: { type: 'boolean', category: 'State' } },\n ],\n },\n selectionMode: {\n type: 'enum',\n category: 'Selection',\n enum: ['single', 'multi'],\n default: 'single',\n },\n selectedIds: { type: 'array', category: 'Selection' },\n tileSize: { type: 'number', category: 'Layout', default: 120 },\n height: { type: 'number', category: 'Layout', default: 440 },\n zoom: { type: 'number', category: 'Layout', default: 1 },\n loading: { type: 'boolean', category: 'State' },\n errorText: { type: 'string', category: 'State' },\n emptyText: { type: 'string', category: 'Content' },\n disabled: { type: 'boolean', category: 'State' },\n readOnly: { type: 'boolean', category: 'State' },\n onSelectionChange: { type: 'action', category: 'Events' },\n onActivate: { type: 'action', category: 'Events' },\n} as const;\n\nconst explorerEvents = {\n selectionChange: {\n label: 'Selection change',\n eventType: 'explorer.selectionChange',\n payloadFields: [{ path: 'selectedIds', type: 'unknown' }],\n },\n activate: {\n label: 'Activate item',\n eventType: 'explorer.activate',\n payloadFields: [{ path: 'id', type: 'string' }],\n },\n} as const;\n\n/** Framework-bound Explorer is a composition primitive, not a separate manifest shape. */\nexport const explorerMeta = {\n name: 'Explorer',\n category: 'pattern',\n directManifestNode: false,\n note: 'Shared code-only Explorer composition; MediaExplorer and FileExplorer own manifest representation.',\n allowedChildren: [],\n props: {},\n} as const satisfies ZoraComponentMeta;\n\nexport const mediaExplorerMeta = {\n name: 'MediaExplorer',\n category: 'pattern',\n description: 'Virtualized media library with normalized selection and activation events.',\n directManifestNode: true,\n allowedChildren: [],\n blueprint: {\n label: 'Media explorer',\n defaultProps: { items: [], selectionMode: 'single', tileSize: 120 },\n },\n events: explorerEvents,\n props: explorerProps,\n} as const satisfies ZoraComponentMeta;\n\nexport const fileExplorerMeta = {\n name: 'FileExplorer',\n category: 'pattern',\n description: 'Virtualized file and folder collection with normalized selection and activation.',\n directManifestNode: true,\n allowedChildren: [],\n blueprint: {\n label: 'File explorer',\n defaultProps: { items: [], selectionMode: 'single', tileSize: 120 },\n },\n events: explorerEvents,\n props: explorerProps,\n} as const satisfies ZoraComponentMeta;\n"]}
1
+ {"version":3,"file":"meta.js","sourceRoot":"","sources":["../../../src/features/explorer/meta.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ZoraComponentMeta } from '../../types/authoring';\n\nconst explorerProps = {\n items: {\n type: 'array',\n category: 'Data',\n itemSchema: [\n { key: 'id', schema: { type: 'string', category: 'Identity' } },\n {\n key: 'kind',\n schema: {\n type: 'enum',\n category: 'Data',\n enum: ['image', 'video', 'audio', 'document', 'file', 'folder'],\n },\n },\n { key: 'name', schema: { type: 'string', category: 'Content' } },\n { key: 'uri', schema: { type: 'string', category: 'Data' } },\n { key: 'thumbnailUri', schema: { type: 'string', category: 'Media' } },\n { key: 'contentType', schema: { type: 'string', category: 'Data' } },\n { key: 'sizeBytes', schema: { type: 'number', category: 'Data' } },\n { key: 'providerId', schema: { type: 'string', category: 'Identity' } },\n { key: 'disabled', schema: { type: 'boolean', category: 'State' } },\n ],\n },\n selectionMode: {\n type: 'enum',\n category: 'Selection',\n enum: ['single', 'multi'],\n default: 'single',\n },\n selectedIds: { type: 'array', category: 'Selection' },\n defaultSelectedIds: { type: 'array', category: 'Selection' },\n width: { type: 'number', category: 'Layout' },\n tileSize: { type: 'number', category: 'Layout', default: 120 },\n height: { type: 'number', category: 'Layout', default: 440 },\n zoom: { type: 'number', category: 'Layout', default: 1 },\n loading: { type: 'boolean', category: 'State' },\n hasMore: { type: 'boolean', category: 'Paging' },\n loadingMore: { type: 'boolean', category: 'Paging' },\n pagingCollectionId: { type: 'string', category: 'Paging' },\n pagingRetryToken: { type: 'string', category: 'Paging' },\n permissionStatus: {\n type: 'enum',\n category: 'Permission',\n enum: ['granted', 'limited', 'denied', 'unavailable'],\n default: 'granted',\n },\n permissionText: { type: 'string', category: 'Permission' },\n errorText: { type: 'string', category: 'State' },\n emptyText: { type: 'string', category: 'Content' },\n disabled: { type: 'boolean', category: 'State' },\n readOnly: { type: 'boolean', category: 'State' },\n onSelectionChange: { type: 'action', category: 'Events' },\n onActivate: { type: 'action', category: 'Events' },\n onLoadMore: { type: 'action', category: 'Events' },\n onRequestPermission: { type: 'action', category: 'Events' },\n} as const;\n\nconst explorerEvents = {\n selectionChange: {\n label: 'Selection change',\n eventType: 'explorer.selectionChange',\n payloadFields: [{ path: 'selectedIds', type: 'unknown' }],\n },\n activate: {\n label: 'Activate item',\n eventType: 'explorer.activate',\n payloadFields: [{ path: 'id', type: 'string' }],\n },\n loadMore: {\n label: 'Load more',\n eventType: 'explorer.loadMore',\n payloadFields: [{ path: 'loadedItemCount', type: 'number' }],\n },\n requestPermission: {\n label: 'Request permission',\n eventType: 'explorer.requestPermission',\n payloadFields: [],\n },\n} as const;\n\n/** Framework-bound Explorer is a composition primitive, not a separate manifest shape. */\nexport const explorerMeta = {\n name: 'Explorer',\n category: 'pattern',\n directManifestNode: false,\n note: 'Shared code-only Explorer composition; MediaExplorer and FileExplorer own manifest representation.',\n allowedChildren: [],\n props: {},\n} as const satisfies ZoraComponentMeta;\n\nexport const mediaExplorerMeta = {\n name: 'MediaExplorer',\n category: 'pattern',\n description: 'Virtualized media library with normalized selection and activation events.',\n directManifestNode: true,\n allowedChildren: [],\n blueprint: {\n label: 'Media explorer',\n defaultProps: { items: [], selectionMode: 'single', tileSize: 120 },\n },\n events: explorerEvents,\n props: explorerProps,\n} as const satisfies ZoraComponentMeta;\n\nexport const fileExplorerMeta = {\n name: 'FileExplorer',\n category: 'pattern',\n description: 'Virtualized file and folder collection with normalized selection and activation.',\n directManifestNode: true,\n allowedChildren: [],\n blueprint: {\n label: 'File explorer',\n defaultProps: { items: [], selectionMode: 'single', tileSize: 120 },\n },\n events: explorerEvents,\n props: explorerProps,\n} as const satisfies ZoraComponentMeta;\n"]}
@@ -1,4 +1,4 @@
1
- export type { ExplorerActivateEvent, ExplorerItem, ExplorerItemKind, ExplorerProps, ExplorerSelectionChangeEvent, ExplorerSelectionMode, } from '../../types/explorer';
1
+ export type { ExplorerActivateEvent, ExplorerItem, ExplorerItemKind, ExplorerPageRequestEvent, ExplorerPermissionStatus, ExplorerProps, ExplorerSelectionChangeEvent, ExplorerSelectionMode, } from '../../types/explorer';
2
2
  export { Explorer } from './adapters/inbound/Explorer';
3
3
  export { FileExplorer } from './adapters/inbound/FileExplorer';
4
4
  export { MediaExplorer } from './adapters/inbound/MediaExplorer';
@@ -1 +1 @@
1
- {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/features/explorer/public.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,qBAAqB,EACrB,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,4BAA4B,EAC5B,qBAAqB,GACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAC9E,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC"}
1
+ {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/features/explorer/public.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,qBAAqB,EACrB,YAAY,EACZ,gBAAgB,EAChB,wBAAwB,EACxB,wBAAwB,EACxB,aAAa,EACb,4BAA4B,EAC5B,qBAAqB,GACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAC9E,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"public.js","sourceRoot":"","sources":["../../../src/features/explorer/public.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAC9E,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC","sourcesContent":["export type {\n ExplorerActivateEvent,\n ExplorerItem,\n ExplorerItemKind,\n ExplorerProps,\n ExplorerSelectionChangeEvent,\n ExplorerSelectionMode,\n} from '../../types/explorer';\nexport { Explorer } from './adapters/inbound/Explorer';\nexport { FileExplorer } from './adapters/inbound/FileExplorer';\nexport { MediaExplorer } from './adapters/inbound/MediaExplorer';\nexport { getExplorerNextFocusId } from './application/getExplorerNextFocusId';\nexport { resolveExplorerSelection } from './application/resolveExplorerSelection';\n"]}
1
+ {"version":3,"file":"public.js","sourceRoot":"","sources":["../../../src/features/explorer/public.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAC9E,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC","sourcesContent":["export type {\n ExplorerActivateEvent,\n ExplorerItem,\n ExplorerItemKind,\n ExplorerPageRequestEvent,\n ExplorerPermissionStatus,\n ExplorerProps,\n ExplorerSelectionChangeEvent,\n ExplorerSelectionMode,\n} from '../../types/explorer';\nexport { Explorer } from './adapters/inbound/Explorer';\nexport { FileExplorer } from './adapters/inbound/FileExplorer';\nexport { MediaExplorer } from './adapters/inbound/MediaExplorer';\nexport { getExplorerNextFocusId } from './application/getExplorerNextFocusId';\nexport { resolveExplorerSelection } from './application/resolveExplorerSelection';\n"]}
@@ -14,12 +14,18 @@ export interface ExplorerItem {
14
14
  readonly disabled?: boolean;
15
15
  }
16
16
  export type ExplorerSelectionMode = 'single' | 'multi';
17
+ /** Provider-owned access state projected into the portable explorer presentation. */
18
+ export type ExplorerPermissionStatus = 'granted' | 'limited' | 'denied' | 'unavailable';
17
19
  export interface ExplorerActivateEvent {
18
20
  readonly id: string;
19
21
  }
20
22
  export interface ExplorerSelectionChangeEvent {
21
23
  readonly selectedIds: readonly string[];
22
24
  }
25
+ /** Requests the next provider page without exposing a provider cursor or native object. */
26
+ export interface ExplorerPageRequestEvent {
27
+ readonly loadedItemCount: number;
28
+ }
23
29
  export interface ExplorerProps extends ZoraBaseProps {
24
30
  items: readonly ExplorerItem[];
25
31
  selectionMode?: ExplorerSelectionMode;
@@ -32,6 +38,28 @@ export interface ExplorerProps extends ZoraBaseProps {
32
38
  tileSize?: number;
33
39
  zoom?: number;
34
40
  loading?: boolean;
41
+ /** Provider paging remains application-owned; Explorer only requests the next page near its end. */
42
+ hasMore?: boolean;
43
+ loadingMore?: boolean;
44
+ /**
45
+ * Stable serializable identity for a provider collection.
46
+ *
47
+ * Supply this whenever paging is enabled so a replacement collection with the same number of
48
+ * loaded rows receives its own initial page request.
49
+ */
50
+ pagingCollectionId?: string;
51
+ /**
52
+ * Provider-controlled retry token for the current page boundary.
53
+ *
54
+ * Change this after a failed request to permit one deliberate retry without causing automatic
55
+ * retry loops.
56
+ */
57
+ pagingRetryToken?: string;
58
+ onLoadMore?: (event: ExplorerPageRequestEvent) => void;
59
+ /** Never pass a native permission object through this presentation boundary. */
60
+ permissionStatus?: ExplorerPermissionStatus;
61
+ permissionText?: string;
62
+ onRequestPermission?: () => void;
35
63
  errorText?: string;
36
64
  emptyText?: string;
37
65
  disabled?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"explorer.d.ts","sourceRoot":"","sources":["../../src/types/explorer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAE5C,4FAA4F;AAC5F,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE5F,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,MAAM,qBAAqB,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEvD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC;AAED,MAAM,WAAW,aAAc,SAAQ,aAAa;IAClD,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IAC/B,aAAa,CAAC,EAAE,qBAAqB,CAAC;IACtC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,4BAA4B,KAAK,IAAI,CAAC;IAClE,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB"}
1
+ {"version":3,"file":"explorer.d.ts","sourceRoot":"","sources":["../../src/types/explorer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAE5C,4FAA4F;AAC5F,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE5F,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,MAAM,qBAAqB,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEvD,qFAAqF;AACrF,MAAM,MAAM,wBAAwB,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,aAAa,CAAC;AAExF,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC;AAED,2FAA2F;AAC3F,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,aAAc,SAAQ,aAAa;IAClD,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IAC/B,aAAa,CAAC,EAAE,qBAAqB,CAAC;IACtC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,4BAA4B,KAAK,IAAI,CAAC;IAClE,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oGAAoG;IACpG,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,wBAAwB,KAAK,IAAI,CAAC;IACvD,gFAAgF;IAChF,gBAAgB,CAAC,EAAE,wBAAwB,CAAC;IAC5C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"explorer.js","sourceRoot":"","sources":["../../src/types/explorer.ts"],"names":[],"mappings":"","sourcesContent":["import type { ZoraBaseProps } from './base';\n\n/** Portable catalogue row. Providers retain permissions, pagination and storage objects. */\nexport type ExplorerItemKind = 'image' | 'video' | 'audio' | 'document' | 'file' | 'folder';\n\nexport interface ExplorerItem {\n readonly id: string;\n readonly kind: ExplorerItemKind;\n readonly name: string;\n readonly thumbnailUri?: string;\n readonly uri?: string;\n readonly contentType?: string;\n readonly sizeBytes?: number;\n readonly durationSeconds?: number;\n readonly providerId?: string;\n readonly disabled?: boolean;\n}\n\nexport type ExplorerSelectionMode = 'single' | 'multi';\n\nexport interface ExplorerActivateEvent {\n readonly id: string;\n}\n\nexport interface ExplorerSelectionChangeEvent {\n readonly selectedIds: readonly string[];\n}\n\nexport interface ExplorerProps extends ZoraBaseProps {\n items: readonly ExplorerItem[];\n selectionMode?: ExplorerSelectionMode;\n selectedIds?: readonly string[];\n defaultSelectedIds?: readonly string[];\n onSelectionChange?: (event: ExplorerSelectionChangeEvent) => void;\n onActivate?: (event: ExplorerActivateEvent) => void;\n width?: number;\n height?: number;\n tileSize?: number;\n zoom?: number;\n loading?: boolean;\n errorText?: string;\n emptyText?: string;\n disabled?: boolean;\n readOnly?: boolean;\n}\n"]}
1
+ {"version":3,"file":"explorer.js","sourceRoot":"","sources":["../../src/types/explorer.ts"],"names":[],"mappings":"","sourcesContent":["import type { ZoraBaseProps } from './base';\n\n/** Portable catalogue row. Providers retain permissions, pagination and storage objects. */\nexport type ExplorerItemKind = 'image' | 'video' | 'audio' | 'document' | 'file' | 'folder';\n\nexport interface ExplorerItem {\n readonly id: string;\n readonly kind: ExplorerItemKind;\n readonly name: string;\n readonly thumbnailUri?: string;\n readonly uri?: string;\n readonly contentType?: string;\n readonly sizeBytes?: number;\n readonly durationSeconds?: number;\n readonly providerId?: string;\n readonly disabled?: boolean;\n}\n\nexport type ExplorerSelectionMode = 'single' | 'multi';\n\n/** Provider-owned access state projected into the portable explorer presentation. */\nexport type ExplorerPermissionStatus = 'granted' | 'limited' | 'denied' | 'unavailable';\n\nexport interface ExplorerActivateEvent {\n readonly id: string;\n}\n\nexport interface ExplorerSelectionChangeEvent {\n readonly selectedIds: readonly string[];\n}\n\n/** Requests the next provider page without exposing a provider cursor or native object. */\nexport interface ExplorerPageRequestEvent {\n readonly loadedItemCount: number;\n}\n\nexport interface ExplorerProps extends ZoraBaseProps {\n items: readonly ExplorerItem[];\n selectionMode?: ExplorerSelectionMode;\n selectedIds?: readonly string[];\n defaultSelectedIds?: readonly string[];\n onSelectionChange?: (event: ExplorerSelectionChangeEvent) => void;\n onActivate?: (event: ExplorerActivateEvent) => void;\n width?: number;\n height?: number;\n tileSize?: number;\n zoom?: number;\n loading?: boolean;\n /** Provider paging remains application-owned; Explorer only requests the next page near its end. */\n hasMore?: boolean;\n loadingMore?: boolean;\n /**\n * Stable serializable identity for a provider collection.\n *\n * Supply this whenever paging is enabled so a replacement collection with the same number of\n * loaded rows receives its own initial page request.\n */\n pagingCollectionId?: string;\n /**\n * Provider-controlled retry token for the current page boundary.\n *\n * Change this after a failed request to permit one deliberate retry without causing automatic\n * retry loops.\n */\n pagingRetryToken?: string;\n onLoadMore?: (event: ExplorerPageRequestEvent) => void;\n /** Never pass a native permission object through this presentation boundary. */\n permissionStatus?: ExplorerPermissionStatus;\n permissionText?: string;\n onRequestPermission?: () => void;\n errorText?: string;\n emptyText?: string;\n disabled?: boolean;\n readOnly?: boolean;\n}\n"]}