@drakkar.software/octospaces-ui 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -334,7 +334,19 @@ interface DiscoverScreenProps {
334
334
  * @default true
335
335
  */
336
336
  searchEnabled?: boolean;
337
+ /**
338
+ * Optional ref whose `.current` is set to a `reload()` function once mounted.
339
+ * Lets a host (e.g. a tab screen) trigger a soft-refresh on focus without
340
+ * blanking the existing list — identical to pull-to-refresh behaviour.
341
+ *
342
+ * ```tsx
343
+ * const reloadRef = useRef<() => void>(null);
344
+ * useFocusEffect(useCallback(() => { reloadRef.current?.(); }, []));
345
+ * <DiscoverScreen reloadRef={reloadRef} ... />
346
+ * ```
347
+ */
348
+ reloadRef?: React.RefObject<(() => void) | null>;
337
349
  }
338
- declare function DiscoverScreen({ loadEntries, renderIcon, onOpen, title, emptyMessage, emptySearchMessage, searchEnabled, }: DiscoverScreenProps): React.JSX.Element;
350
+ declare function DiscoverScreen({ loadEntries, renderIcon, onOpen, title, emptyMessage, emptySearchMessage, searchEnabled, reloadRef, }: DiscoverScreenProps): React.JSX.Element;
339
351
 
340
352
  export { type ColorScheme, type DiscoverEntry, DiscoverList, type DiscoverListProps, DiscoverRow, type DiscoverRowProps, DiscoverScreen, type DiscoverScreenProps, type Easing, type Fonts, type LabelTracking, type Layers, type Layout, type Motion, type MotionToken, OctoSpacesThemeProvider, type OctoSpacesThemeProviderProps, type Opacity, type Palette, type Radii, type ShadowToken, type Shadows, type Spacing, type Swatches, type Theme, type TypeScale, type Typography, avatarTint, filterDiscoverEntries, focusRingStyle, glowShadow, paperBorder, presenceColor, sortDiscoverEntries, statusColor, swatch, useOctoSpacesTheme, verificationColor };
package/dist/index.js CHANGED
@@ -237,7 +237,7 @@ function DiscoverList({
237
237
  }
238
238
 
239
239
  // src/discover/DiscoverScreen.tsx
240
- import React4, { useCallback as useCallback3, useEffect, useRef, useState } from "react";
240
+ import React4, { useCallback as useCallback3, useEffect, useImperativeHandle, useRef, useState } from "react";
241
241
  import { ActivityIndicator, Pressable as Pressable2, Text as Text3, TextInput, View as View3 } from "react-native";
242
242
  function DiscoverScreen({
243
243
  loadEntries,
@@ -246,7 +246,8 @@ function DiscoverScreen({
246
246
  title = "Discover",
247
247
  emptyMessage = "No public objects yet",
248
248
  emptySearchMessage,
249
- searchEnabled = true
249
+ searchEnabled = true,
250
+ reloadRef
250
251
  }) {
251
252
  const theme = useOctoSpacesTheme();
252
253
  const [state, setState] = useState({ status: "idle" });
@@ -278,6 +279,7 @@ function DiscoverScreen({
278
279
  if (!cancelledRef.current) setRefreshing(false);
279
280
  }
280
281
  }, [loadEntries]);
282
+ useImperativeHandle(reloadRef, () => handleRefresh, [handleRefresh]);
281
283
  useEffect(() => {
282
284
  cancelledRef.current = false;
283
285
  void load();
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/theme/provider.tsx","../src/theme/helpers.ts","../src/discover/filter.ts","../src/discover/DiscoverRow.tsx","../src/discover/DiscoverList.tsx","../src/discover/DiscoverScreen.tsx"],"sourcesContent":["/**\n * Theme injection plumbing — provider + hook.\n *\n * The package carries ZERO theme values. The host app builds a concrete {@link Theme}\n * and wraps its tree in `<OctoSpacesThemeProvider theme={resolvedTheme}>`.\n * All primitives then call `useOctoSpacesTheme()` to read the active theme.\n */\nimport React, { createContext, useContext } from 'react';\nimport type { Theme } from './types.js';\n\nconst ThemeContext = createContext<Theme | null>(null);\n\nexport interface OctoSpacesThemeProviderProps {\n theme: Theme;\n children: React.ReactNode;\n}\n\n/**\n * Wrap your root component with this provider to inject the resolved Theme into\n * every primitive from `@drakkar.software/octospaces-ui`.\n *\n * @example\n * ```tsx\n * import { OctoSpacesThemeProvider } from '@drakkar.software/octospaces-ui';\n * import { resolvedTheme } from '@/theme'; // your app's theme\n *\n * export default function App() {\n * return (\n * <OctoSpacesThemeProvider theme={resolvedTheme}>\n * <RootNavigator />\n * </OctoSpacesThemeProvider>\n * );\n * }\n * ```\n */\nexport function OctoSpacesThemeProvider({ theme, children }: OctoSpacesThemeProviderProps) {\n return <ThemeContext.Provider value={theme}>{children}</ThemeContext.Provider>;\n}\n\n/**\n * Read the active theme. Throws if called outside an `<OctoSpacesThemeProvider>` —\n * this is intentional: a missing provider means primitives have no colors/spacing,\n * so a hard failure with a clear message is better than a silent rendering bug.\n */\nexport function useOctoSpacesTheme(): Theme {\n const theme = useContext(ThemeContext);\n if (!theme) {\n throw new Error(\n '[octospaces-ui] useOctoSpacesTheme() called outside of <OctoSpacesThemeProvider>. ' +\n 'Wrap your root component with <OctoSpacesThemeProvider theme={…}>.',\n );\n }\n return theme;\n}\n","/**\n * Pure palette-helper functions over a {@link Palette}. No theme values live here —\n * only functions that DERIVE from the injected palette (or from passed-in colors).\n *\n * Import these from `@drakkar.software/octospaces-ui` (re-exported by `src/index.ts`).\n */\nimport type { Palette, ShadowToken, Theme } from './types.js';\n\n// ── Presence ──────────────────────────────────────────────────────────────────\n\n/** Map a presence status string to the corresponding palette color. */\nexport function presenceColor(\n palette: Palette,\n status: 'online' | 'away' | 'busy' | 'offline' | string,\n): string {\n switch (status) {\n case 'online': return palette.presenceOnline;\n case 'away': return palette.presenceAway;\n case 'busy': return palette.presenceBusy;\n default: return palette.presenceOffline;\n }\n}\n\n// ── Verification ──────────────────────────────────────────────────────────────\n\n/** Map a verification level to the corresponding palette color. */\nexport function verificationColor(\n palette: Palette,\n level: 'verified' | 'partial' | 'none' | string,\n): string {\n switch (level) {\n case 'verified': return palette.verificationVerified;\n case 'partial': return palette.verificationPartial;\n default: return palette.verificationNone;\n }\n}\n\n// ── Avatar ────────────────────────────────────────────────────────────────────\n\nconst AVATAR_TINT_KEYS = [\n 'primary', 'success', 'warning', 'danger', 'info',\n] as const;\n\n/** Stable avatar background tint derived from a userId string. */\nexport function avatarTint(palette: Palette, userId: string): string {\n let hash = 0;\n for (let i = 0; i < userId.length; i++) hash = (hash * 31 + userId.charCodeAt(i)) | 0;\n const key = AVATAR_TINT_KEYS[Math.abs(hash) % AVATAR_TINT_KEYS.length];\n return (palette as unknown as Record<string, string>)[key] ?? palette.primary;\n}\n\n// ── Swatch ────────────────────────────────────────────────────────────────────\n\n/** Look up a named swatch; falls back to `palette.primary` if absent. */\nexport function swatch(theme: Theme, name: string): string {\n return theme.swatches[name] ?? theme.colors.primary;\n}\n\n// ── Borders ───────────────────────────────────────────────────────────────────\n\n/** Derive a `borderColor` value for a \"paper\" (elevated surface) border. */\nexport function paperBorder(palette: Palette): string {\n return palette.borderSubtle;\n}\n\n// ── Shadows ───────────────────────────────────────────────────────────────────\n\n/** Build a glow shadow token from a base color (used for focus rings, highlights). */\nexport function glowShadow(color: string, radius = 8, opacity = 0.4): ShadowToken {\n return {\n shadowColor: color,\n shadowOffset: { width: 0, height: 0 },\n shadowOpacity: opacity,\n shadowRadius: radius,\n elevation: 4,\n };\n}\n\n// ── Focus ring ────────────────────────────────────────────────────────────────\n\n/** Style object for a keyboard-focus indicator (web + React Native). */\nexport function focusRingStyle(\n palette: Palette,\n width = 2,\n): {\n borderWidth: number;\n borderColor: string;\n borderStyle: 'solid';\n} {\n return { borderWidth: width, borderColor: palette.focus, borderStyle: 'solid' };\n}\n\n// ── Status color ──────────────────────────────────────────────────────────────\n\n/** Map a semantic status name to its palette color. */\nexport function statusColor(\n palette: Palette,\n status: 'success' | 'warning' | 'danger' | 'info' | string,\n muted = false,\n): string {\n if (muted) {\n switch (status) {\n case 'success': return palette.successMuted;\n case 'warning': return palette.warningMuted;\n case 'danger': return palette.dangerMuted;\n default: return palette.infoMuted;\n }\n }\n switch (status) {\n case 'success': return palette.success;\n case 'warning': return palette.warning;\n case 'danger': return palette.danger;\n default: return palette.info;\n }\n}\n","import type { DiscoverEntry } from './types.js';\n\n/**\n * Case-insensitive substring filter over a `DiscoverEntry[]`.\n *\n * Returns the original array reference unchanged when `query` is blank so the\n * caller can skip a re-render. Pure function — no side effects.\n */\nexport function filterDiscoverEntries(\n entries: DiscoverEntry[],\n query: string,\n): DiscoverEntry[] {\n const q = query.trim().toLowerCase();\n if (!q) return entries;\n return entries.filter((e) => e.title.toLowerCase().includes(q));\n}\n\n/**\n * Sort discover entries by updatedAt descending (most recent first).\n * Entries without an `updatedAt` field sort last. Pure function.\n */\nexport function sortDiscoverEntries(entries: DiscoverEntry[]): DiscoverEntry[] {\n return [...entries].sort((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0));\n}\n","/**\n * A single row in the Discover list — shows the object's emoji/icon, title,\n * and type. All app-specific behaviour is injected via props:\n * - `renderIcon` — render a type/emoji icon; receives the entry and must\n * return a ReactNode (null for no icon).\n * - `onOpen` — called when the row is pressed.\n *\n * Styled entirely from the injected {@link Theme} via `useOctoSpacesTheme()`.\n */\nimport React, { useCallback } from 'react';\nimport { Pressable, Text, View } from 'react-native';\n\nimport { useOctoSpacesTheme } from '../theme/provider.js';\nimport type { DiscoverEntry } from './types.js';\n\nexport interface DiscoverRowProps {\n entry: DiscoverEntry;\n /** Render a leading icon for the entry. Return `null` to show nothing. */\n renderIcon?: (entry: DiscoverEntry) => React.ReactNode;\n /** Called when the user taps the row. */\n onOpen: (entry: DiscoverEntry) => void;\n}\n\nexport function DiscoverRow({ entry, renderIcon, onOpen }: DiscoverRowProps) {\n const theme = useOctoSpacesTheme();\n\n const handlePress = useCallback(() => {\n onOpen(entry);\n }, [entry, onOpen]);\n\n const icon = renderIcon ? renderIcon(entry) : null;\n const displayEmoji = !icon && entry.emoji ? entry.emoji : null;\n\n return (\n <Pressable\n onPress={handlePress}\n style={({ pressed }) => ({\n flexDirection: 'row',\n alignItems: 'center',\n paddingVertical: (theme.spacing['3'] as number) ?? 12,\n paddingHorizontal: (theme.spacing['4'] as number) ?? 16,\n backgroundColor: pressed\n ? (theme.colors.surface ?? '#f5f5f5')\n : 'transparent',\n borderRadius: (theme.radii['sm'] as number) ?? 6,\n })}\n accessibilityRole=\"button\"\n accessibilityLabel={entry.title || 'Untitled'}\n >\n {/* Leading icon / emoji */}\n {(icon || displayEmoji) && (\n <View\n style={{\n width: 28,\n height: 28,\n marginRight: (theme.spacing['2'] as number) ?? 8,\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}\n >\n {icon ?? (\n <Text style={{ fontSize: 18, lineHeight: 24 }}>{displayEmoji}</Text>\n )}\n </View>\n )}\n\n {/* Title + type subtitle */}\n <View style={{ flex: 1, minWidth: 0 }}>\n <Text\n numberOfLines={1}\n style={{\n fontSize: (theme.type['body']?.size ?? 15),\n lineHeight: (theme.type['body']?.lineHeight ?? 22),\n color: entry.title ? theme.colors.text : theme.colors.textTertiary,\n fontFamily: theme.fonts['body'] ?? undefined,\n }}\n >\n {entry.title || 'Untitled'}\n </Text>\n <Text\n numberOfLines={1}\n style={{\n fontSize: (theme.type['caption']?.size ?? 12),\n lineHeight: (theme.type['caption']?.lineHeight ?? 18),\n color: theme.colors.textSecondary,\n marginTop: 1,\n textTransform: 'capitalize',\n }}\n >\n {entry.type}\n </Text>\n </View>\n </Pressable>\n );\n}\n","/**\n * A themed FlatList wrapper that renders a list of {@link DiscoverEntry} rows.\n *\n * All app-specific behaviour is injected via props so this component has zero\n * imports from any specific OctoSpaces app.\n */\nimport React, { useCallback } from 'react';\nimport { FlatList, RefreshControl, Text, View } from 'react-native';\n\nimport { useOctoSpacesTheme } from '../theme/provider.js';\nimport { DiscoverRow } from './DiscoverRow.js';\nimport type { DiscoverEntry } from './types.js';\n\nexport interface DiscoverListProps {\n entries: DiscoverEntry[];\n /** Render a leading icon for each row — see {@link DiscoverRowProps.renderIcon}. */\n renderIcon?: (entry: DiscoverEntry) => React.ReactNode;\n /** Called when a row is tapped. */\n onOpen: (entry: DiscoverEntry) => void;\n /** Text shown when `entries` is empty (default: \"No public objects found\"). */\n emptyMessage?: string;\n /** Whether a pull-to-refresh is currently in progress. */\n refreshing?: boolean;\n /** Called when the user pulls to refresh. */\n onRefresh?: () => void;\n}\n\nexport function DiscoverList({\n entries,\n renderIcon,\n onOpen,\n emptyMessage = 'No public objects found',\n refreshing,\n onRefresh,\n}: DiscoverListProps) {\n const theme = useOctoSpacesTheme();\n\n const renderItem = useCallback(\n ({ item }: { item: DiscoverEntry }) => (\n <DiscoverRow entry={item} renderIcon={renderIcon} onOpen={onOpen} />\n ),\n [renderIcon, onOpen],\n );\n\n const keyExtractor = useCallback(\n (item: DiscoverEntry) => `${item.spaceId}:${item.id}`,\n [],\n );\n\n if (entries.length === 0) {\n return (\n <View\n style={{\n flex: 1,\n alignItems: 'center',\n justifyContent: 'center',\n paddingHorizontal: (theme.spacing['6'] as number) ?? 24,\n }}\n >\n <Text\n style={{\n fontSize: theme.type['body']?.size ?? 15,\n color: theme.colors.textSecondary,\n textAlign: 'center',\n }}\n >\n {emptyMessage}\n </Text>\n </View>\n );\n }\n\n return (\n <FlatList\n data={entries}\n renderItem={renderItem}\n keyExtractor={keyExtractor}\n contentContainerStyle={{ paddingVertical: (theme.spacing['1'] as number) ?? 4 }}\n showsVerticalScrollIndicator={false}\n removeClippedSubviews\n refreshControl={\n onRefresh ? (\n <RefreshControl\n refreshing={refreshing ?? false}\n onRefresh={onRefresh}\n tintColor={theme.colors.primary}\n />\n ) : undefined\n }\n />\n );\n}\n","/**\n * Generic public-object discovery screen.\n *\n * Loads the world-readable public-object directory via `loadEntries`, renders a\n * search bar, and delegates row rendering + tap behaviour to the injected props.\n * No app-specific logic lives here — all customisation is via props:\n *\n * ```tsx\n * <DiscoverScreen\n * loadEntries={readObjectDirectory}\n * renderIcon={(e) => <TypeIcon entry={e} />}\n * onOpen={(e) => router.push({ pathname: routeForNode(e), params: { id: e.id, spaceId: e.spaceId } })}\n * />\n * ```\n *\n * State machine:\n * idle → loading → (ready | error)\n * Any pull of `loadEntries` updates the entries; errors show a retry button.\n */\nimport React, { useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react';\nimport { ActivityIndicator, Pressable, Text, TextInput, View, type TextStyle } from 'react-native';\n\nimport { useOctoSpacesTheme } from '../theme/provider.js';\nimport { DiscoverList } from './DiscoverList.js';\nimport { filterDiscoverEntries, sortDiscoverEntries } from './filter.js';\nimport type { DiscoverEntry } from './types.js';\n\nexport interface DiscoverScreenProps {\n /**\n * Async function that resolves to the current public-object directory.\n * Typically `readObjectDirectory` from `@drakkar.software/octospaces-sdk`.\n * Called on mount and when `refresh()` is triggered.\n */\n loadEntries: () => Promise<DiscoverEntry[]>;\n /** Render a leading icon for each row. */\n renderIcon?: (entry: DiscoverEntry) => React.ReactNode;\n /** Called when the user taps a row — navigate to the object. */\n onOpen: (entry: DiscoverEntry) => void;\n /**\n * Optional heading text shown above the search bar.\n * @default \"Discover\"\n */\n title?: string;\n /**\n * Text shown when the directory is empty after loading.\n * @default \"No public objects yet\"\n */\n emptyMessage?: string;\n /**\n * Text shown when the directory is empty due to an active search query.\n * @default \"No results for «query»\"\n */\n emptySearchMessage?: string;\n /**\n * Whether to show the inline search bar.\n * @default true\n */\n searchEnabled?: boolean;\n}\n\ntype State =\n | { status: 'idle' }\n | { status: 'loading' }\n | { status: 'ready'; entries: DiscoverEntry[] }\n | { status: 'error'; message: string };\n\nexport function DiscoverScreen({\n loadEntries,\n renderIcon,\n onOpen,\n title = 'Discover',\n emptyMessage = 'No public objects yet',\n emptySearchMessage,\n searchEnabled = true,\n}: DiscoverScreenProps) {\n const theme = useOctoSpacesTheme();\n const [state, setState] = useState<State>({ status: 'idle' });\n const [query, setQuery] = useState('');\n const [refreshing, setRefreshing] = useState(false);\n const cancelledRef = useRef(false);\n\n const load = useCallback(async () => {\n setState({ status: 'loading' });\n try {\n const raw = await loadEntries();\n if (cancelledRef.current) return;\n setState({ status: 'ready', entries: sortDiscoverEntries(raw) });\n } catch (err) {\n if (cancelledRef.current) return;\n setState({\n status: 'error',\n message: err instanceof Error ? err.message : 'Failed to load directory',\n });\n }\n }, [loadEntries]);\n\n /** Pull-to-refresh: re-fetches without blanking the existing list. */\n const handleRefresh = useCallback(async () => {\n setRefreshing(true);\n try {\n const raw = await loadEntries();\n if (cancelledRef.current) return;\n setState({ status: 'ready', entries: sortDiscoverEntries(raw) });\n } catch {\n // keep the existing list on refresh failure; the retry button remains for error state\n } finally {\n if (!cancelledRef.current) setRefreshing(false);\n }\n }, [loadEntries]);\n\n useEffect(() => {\n cancelledRef.current = false;\n void load();\n return () => {\n cancelledRef.current = true;\n };\n }, [load]);\n\n // ── Derived list ─────────────────────────────────────────────────────────\n const allEntries = state.status === 'ready' ? state.entries : [];\n const visibleEntries = filterDiscoverEntries(allEntries, query);\n const noSearchResults = !!query.trim() && visibleEntries.length === 0 && allEntries.length > 0;\n const resolvedEmptyMessage = noSearchResults\n ? (emptySearchMessage ?? `No results for \"${query.trim()}\"`)\n : emptyMessage;\n\n // ── Palette shortcuts ─────────────────────────────────────────────────────\n const sp2 = (theme.spacing['2'] as number) ?? 8;\n const sp3 = (theme.spacing['3'] as number) ?? 12;\n const sp4 = (theme.spacing['4'] as number) ?? 16;\n const radMd = (theme.radii['md'] as number) ?? 8;\n\n return (\n <View style={{ flex: 1, backgroundColor: theme.colors.background }}>\n {/* Header */}\n <View\n style={{\n paddingHorizontal: sp4,\n paddingTop: sp4,\n paddingBottom: sp2,\n }}\n >\n <Text\n style={{\n fontSize: theme.type['title2']?.size ?? 22,\n fontWeight: (theme.type['title2']?.weight as TextStyle['fontWeight']) ?? '700',\n lineHeight: theme.type['title2']?.lineHeight ?? 28,\n color: theme.colors.text,\n fontFamily: theme.fonts['heading'] ?? undefined,\n marginBottom: sp3,\n }}\n >\n {title}\n </Text>\n\n {/* Search bar */}\n {searchEnabled && (\n <View\n style={{\n flexDirection: 'row',\n alignItems: 'center',\n backgroundColor: theme.colors.surfaceInput ?? theme.colors.surface,\n borderRadius: radMd,\n borderWidth: 1,\n borderColor: theme.colors.borderSubtle,\n paddingHorizontal: sp3,\n height: 40,\n }}\n >\n <TextInput\n placeholder=\"Search…\"\n placeholderTextColor={theme.colors.textTertiary}\n value={query}\n onChangeText={setQuery}\n style={{\n flex: 1,\n fontSize: theme.type['body']?.size ?? 15,\n color: theme.colors.text,\n fontFamily: theme.fonts['body'] ?? undefined,\n }}\n returnKeyType=\"search\"\n clearButtonMode=\"while-editing\"\n accessibilityLabel=\"Search discover\"\n />\n </View>\n )}\n </View>\n\n {/* Body */}\n {state.status === 'loading' ? (\n <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>\n <ActivityIndicator color={theme.colors.primary} />\n </View>\n ) : state.status === 'error' ? (\n <View\n style={{\n flex: 1,\n alignItems: 'center',\n justifyContent: 'center',\n paddingHorizontal: sp4,\n }}\n >\n <Text\n style={{\n color: theme.colors.textSecondary,\n fontSize: theme.type['body']?.size ?? 15,\n textAlign: 'center',\n marginBottom: sp3,\n }}\n >\n {state.message}\n </Text>\n <Pressable\n onPress={load}\n style={{\n paddingHorizontal: sp4,\n paddingVertical: sp2,\n backgroundColor: theme.colors.primary,\n borderRadius: radMd,\n }}\n >\n <Text style={{ color: theme.colors.textOnPrimary, fontWeight: '600' }}>\n Retry\n </Text>\n </Pressable>\n </View>\n ) : (\n <DiscoverList\n entries={visibleEntries}\n renderIcon={renderIcon}\n onOpen={onOpen}\n emptyMessage={resolvedEmptyMessage}\n refreshing={refreshing}\n onRefresh={handleRefresh}\n />\n )}\n </View>\n );\n}\n"],"mappings":"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","names":["React","React","React","useCallback","Text","View","useCallback","React","View","Text","React","useCallback","Pressable","Text","View","useCallback","React","View","Text","Pressable"]}
1
+ {"version":3,"sources":["../src/theme/provider.tsx","../src/theme/helpers.ts","../src/discover/filter.ts","../src/discover/DiscoverRow.tsx","../src/discover/DiscoverList.tsx","../src/discover/DiscoverScreen.tsx"],"sourcesContent":["/**\n * Theme injection plumbing — provider + hook.\n *\n * The package carries ZERO theme values. The host app builds a concrete {@link Theme}\n * and wraps its tree in `<OctoSpacesThemeProvider theme={resolvedTheme}>`.\n * All primitives then call `useOctoSpacesTheme()` to read the active theme.\n */\nimport React, { createContext, useContext } from 'react';\nimport type { Theme } from './types.js';\n\nconst ThemeContext = createContext<Theme | null>(null);\n\nexport interface OctoSpacesThemeProviderProps {\n theme: Theme;\n children: React.ReactNode;\n}\n\n/**\n * Wrap your root component with this provider to inject the resolved Theme into\n * every primitive from `@drakkar.software/octospaces-ui`.\n *\n * @example\n * ```tsx\n * import { OctoSpacesThemeProvider } from '@drakkar.software/octospaces-ui';\n * import { resolvedTheme } from '@/theme'; // your app's theme\n *\n * export default function App() {\n * return (\n * <OctoSpacesThemeProvider theme={resolvedTheme}>\n * <RootNavigator />\n * </OctoSpacesThemeProvider>\n * );\n * }\n * ```\n */\nexport function OctoSpacesThemeProvider({ theme, children }: OctoSpacesThemeProviderProps) {\n return <ThemeContext.Provider value={theme}>{children}</ThemeContext.Provider>;\n}\n\n/**\n * Read the active theme. Throws if called outside an `<OctoSpacesThemeProvider>` —\n * this is intentional: a missing provider means primitives have no colors/spacing,\n * so a hard failure with a clear message is better than a silent rendering bug.\n */\nexport function useOctoSpacesTheme(): Theme {\n const theme = useContext(ThemeContext);\n if (!theme) {\n throw new Error(\n '[octospaces-ui] useOctoSpacesTheme() called outside of <OctoSpacesThemeProvider>. ' +\n 'Wrap your root component with <OctoSpacesThemeProvider theme={…}>.',\n );\n }\n return theme;\n}\n","/**\n * Pure palette-helper functions over a {@link Palette}. No theme values live here —\n * only functions that DERIVE from the injected palette (or from passed-in colors).\n *\n * Import these from `@drakkar.software/octospaces-ui` (re-exported by `src/index.ts`).\n */\nimport type { Palette, ShadowToken, Theme } from './types.js';\n\n// ── Presence ──────────────────────────────────────────────────────────────────\n\n/** Map a presence status string to the corresponding palette color. */\nexport function presenceColor(\n palette: Palette,\n status: 'online' | 'away' | 'busy' | 'offline' | string,\n): string {\n switch (status) {\n case 'online': return palette.presenceOnline;\n case 'away': return palette.presenceAway;\n case 'busy': return palette.presenceBusy;\n default: return palette.presenceOffline;\n }\n}\n\n// ── Verification ──────────────────────────────────────────────────────────────\n\n/** Map a verification level to the corresponding palette color. */\nexport function verificationColor(\n palette: Palette,\n level: 'verified' | 'partial' | 'none' | string,\n): string {\n switch (level) {\n case 'verified': return palette.verificationVerified;\n case 'partial': return palette.verificationPartial;\n default: return palette.verificationNone;\n }\n}\n\n// ── Avatar ────────────────────────────────────────────────────────────────────\n\nconst AVATAR_TINT_KEYS = [\n 'primary', 'success', 'warning', 'danger', 'info',\n] as const;\n\n/** Stable avatar background tint derived from a userId string. */\nexport function avatarTint(palette: Palette, userId: string): string {\n let hash = 0;\n for (let i = 0; i < userId.length; i++) hash = (hash * 31 + userId.charCodeAt(i)) | 0;\n const key = AVATAR_TINT_KEYS[Math.abs(hash) % AVATAR_TINT_KEYS.length];\n return (palette as unknown as Record<string, string>)[key] ?? palette.primary;\n}\n\n// ── Swatch ────────────────────────────────────────────────────────────────────\n\n/** Look up a named swatch; falls back to `palette.primary` if absent. */\nexport function swatch(theme: Theme, name: string): string {\n return theme.swatches[name] ?? theme.colors.primary;\n}\n\n// ── Borders ───────────────────────────────────────────────────────────────────\n\n/** Derive a `borderColor` value for a \"paper\" (elevated surface) border. */\nexport function paperBorder(palette: Palette): string {\n return palette.borderSubtle;\n}\n\n// ── Shadows ───────────────────────────────────────────────────────────────────\n\n/** Build a glow shadow token from a base color (used for focus rings, highlights). */\nexport function glowShadow(color: string, radius = 8, opacity = 0.4): ShadowToken {\n return {\n shadowColor: color,\n shadowOffset: { width: 0, height: 0 },\n shadowOpacity: opacity,\n shadowRadius: radius,\n elevation: 4,\n };\n}\n\n// ── Focus ring ────────────────────────────────────────────────────────────────\n\n/** Style object for a keyboard-focus indicator (web + React Native). */\nexport function focusRingStyle(\n palette: Palette,\n width = 2,\n): {\n borderWidth: number;\n borderColor: string;\n borderStyle: 'solid';\n} {\n return { borderWidth: width, borderColor: palette.focus, borderStyle: 'solid' };\n}\n\n// ── Status color ──────────────────────────────────────────────────────────────\n\n/** Map a semantic status name to its palette color. */\nexport function statusColor(\n palette: Palette,\n status: 'success' | 'warning' | 'danger' | 'info' | string,\n muted = false,\n): string {\n if (muted) {\n switch (status) {\n case 'success': return palette.successMuted;\n case 'warning': return palette.warningMuted;\n case 'danger': return palette.dangerMuted;\n default: return palette.infoMuted;\n }\n }\n switch (status) {\n case 'success': return palette.success;\n case 'warning': return palette.warning;\n case 'danger': return palette.danger;\n default: return palette.info;\n }\n}\n","import type { DiscoverEntry } from './types.js';\n\n/**\n * Case-insensitive substring filter over a `DiscoverEntry[]`.\n *\n * Returns the original array reference unchanged when `query` is blank so the\n * caller can skip a re-render. Pure function — no side effects.\n */\nexport function filterDiscoverEntries(\n entries: DiscoverEntry[],\n query: string,\n): DiscoverEntry[] {\n const q = query.trim().toLowerCase();\n if (!q) return entries;\n return entries.filter((e) => e.title.toLowerCase().includes(q));\n}\n\n/**\n * Sort discover entries by updatedAt descending (most recent first).\n * Entries without an `updatedAt` field sort last. Pure function.\n */\nexport function sortDiscoverEntries(entries: DiscoverEntry[]): DiscoverEntry[] {\n return [...entries].sort((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0));\n}\n","/**\n * A single row in the Discover list — shows the object's emoji/icon, title,\n * and type. All app-specific behaviour is injected via props:\n * - `renderIcon` — render a type/emoji icon; receives the entry and must\n * return a ReactNode (null for no icon).\n * - `onOpen` — called when the row is pressed.\n *\n * Styled entirely from the injected {@link Theme} via `useOctoSpacesTheme()`.\n */\nimport React, { useCallback } from 'react';\nimport { Pressable, Text, View } from 'react-native';\n\nimport { useOctoSpacesTheme } from '../theme/provider.js';\nimport type { DiscoverEntry } from './types.js';\n\nexport interface DiscoverRowProps {\n entry: DiscoverEntry;\n /** Render a leading icon for the entry. Return `null` to show nothing. */\n renderIcon?: (entry: DiscoverEntry) => React.ReactNode;\n /** Called when the user taps the row. */\n onOpen: (entry: DiscoverEntry) => void;\n}\n\nexport function DiscoverRow({ entry, renderIcon, onOpen }: DiscoverRowProps) {\n const theme = useOctoSpacesTheme();\n\n const handlePress = useCallback(() => {\n onOpen(entry);\n }, [entry, onOpen]);\n\n const icon = renderIcon ? renderIcon(entry) : null;\n const displayEmoji = !icon && entry.emoji ? entry.emoji : null;\n\n return (\n <Pressable\n onPress={handlePress}\n style={({ pressed }) => ({\n flexDirection: 'row',\n alignItems: 'center',\n paddingVertical: (theme.spacing['3'] as number) ?? 12,\n paddingHorizontal: (theme.spacing['4'] as number) ?? 16,\n backgroundColor: pressed\n ? (theme.colors.surface ?? '#f5f5f5')\n : 'transparent',\n borderRadius: (theme.radii['sm'] as number) ?? 6,\n })}\n accessibilityRole=\"button\"\n accessibilityLabel={entry.title || 'Untitled'}\n >\n {/* Leading icon / emoji */}\n {(icon || displayEmoji) && (\n <View\n style={{\n width: 28,\n height: 28,\n marginRight: (theme.spacing['2'] as number) ?? 8,\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}\n >\n {icon ?? (\n <Text style={{ fontSize: 18, lineHeight: 24 }}>{displayEmoji}</Text>\n )}\n </View>\n )}\n\n {/* Title + type subtitle */}\n <View style={{ flex: 1, minWidth: 0 }}>\n <Text\n numberOfLines={1}\n style={{\n fontSize: (theme.type['body']?.size ?? 15),\n lineHeight: (theme.type['body']?.lineHeight ?? 22),\n color: entry.title ? theme.colors.text : theme.colors.textTertiary,\n fontFamily: theme.fonts['body'] ?? undefined,\n }}\n >\n {entry.title || 'Untitled'}\n </Text>\n <Text\n numberOfLines={1}\n style={{\n fontSize: (theme.type['caption']?.size ?? 12),\n lineHeight: (theme.type['caption']?.lineHeight ?? 18),\n color: theme.colors.textSecondary,\n marginTop: 1,\n textTransform: 'capitalize',\n }}\n >\n {entry.type}\n </Text>\n </View>\n </Pressable>\n );\n}\n","/**\n * A themed FlatList wrapper that renders a list of {@link DiscoverEntry} rows.\n *\n * All app-specific behaviour is injected via props so this component has zero\n * imports from any specific OctoSpaces app.\n */\nimport React, { useCallback } from 'react';\nimport { FlatList, RefreshControl, Text, View } from 'react-native';\n\nimport { useOctoSpacesTheme } from '../theme/provider.js';\nimport { DiscoverRow } from './DiscoverRow.js';\nimport type { DiscoverEntry } from './types.js';\n\nexport interface DiscoverListProps {\n entries: DiscoverEntry[];\n /** Render a leading icon for each row — see {@link DiscoverRowProps.renderIcon}. */\n renderIcon?: (entry: DiscoverEntry) => React.ReactNode;\n /** Called when a row is tapped. */\n onOpen: (entry: DiscoverEntry) => void;\n /** Text shown when `entries` is empty (default: \"No public objects found\"). */\n emptyMessage?: string;\n /** Whether a pull-to-refresh is currently in progress. */\n refreshing?: boolean;\n /** Called when the user pulls to refresh. */\n onRefresh?: () => void;\n}\n\nexport function DiscoverList({\n entries,\n renderIcon,\n onOpen,\n emptyMessage = 'No public objects found',\n refreshing,\n onRefresh,\n}: DiscoverListProps) {\n const theme = useOctoSpacesTheme();\n\n const renderItem = useCallback(\n ({ item }: { item: DiscoverEntry }) => (\n <DiscoverRow entry={item} renderIcon={renderIcon} onOpen={onOpen} />\n ),\n [renderIcon, onOpen],\n );\n\n const keyExtractor = useCallback(\n (item: DiscoverEntry) => `${item.spaceId}:${item.id}`,\n [],\n );\n\n if (entries.length === 0) {\n return (\n <View\n style={{\n flex: 1,\n alignItems: 'center',\n justifyContent: 'center',\n paddingHorizontal: (theme.spacing['6'] as number) ?? 24,\n }}\n >\n <Text\n style={{\n fontSize: theme.type['body']?.size ?? 15,\n color: theme.colors.textSecondary,\n textAlign: 'center',\n }}\n >\n {emptyMessage}\n </Text>\n </View>\n );\n }\n\n return (\n <FlatList\n data={entries}\n renderItem={renderItem}\n keyExtractor={keyExtractor}\n contentContainerStyle={{ paddingVertical: (theme.spacing['1'] as number) ?? 4 }}\n showsVerticalScrollIndicator={false}\n removeClippedSubviews\n refreshControl={\n onRefresh ? (\n <RefreshControl\n refreshing={refreshing ?? false}\n onRefresh={onRefresh}\n tintColor={theme.colors.primary}\n />\n ) : undefined\n }\n />\n );\n}\n","/**\n * Generic public-object discovery screen.\n *\n * Loads the world-readable public-object directory via `loadEntries`, renders a\n * search bar, and delegates row rendering + tap behaviour to the injected props.\n * No app-specific logic lives here — all customisation is via props:\n *\n * ```tsx\n * <DiscoverScreen\n * loadEntries={readObjectDirectory}\n * renderIcon={(e) => <TypeIcon entry={e} />}\n * onOpen={(e) => router.push({ pathname: routeForNode(e), params: { id: e.id, spaceId: e.spaceId } })}\n * />\n * ```\n *\n * State machine:\n * idle → loading → (ready | error)\n * Any pull of `loadEntries` updates the entries; errors show a retry button.\n */\nimport React, { useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react';\nimport { ActivityIndicator, Pressable, Text, TextInput, View, type TextStyle } from 'react-native';\n\nimport { useOctoSpacesTheme } from '../theme/provider.js';\nimport { DiscoverList } from './DiscoverList.js';\nimport { filterDiscoverEntries, sortDiscoverEntries } from './filter.js';\nimport type { DiscoverEntry } from './types.js';\n\nexport interface DiscoverScreenProps {\n /**\n * Async function that resolves to the current public-object directory.\n * Typically `readObjectDirectory` from `@drakkar.software/octospaces-sdk`.\n * Called on mount and when `refresh()` is triggered.\n */\n loadEntries: () => Promise<DiscoverEntry[]>;\n /** Render a leading icon for each row. */\n renderIcon?: (entry: DiscoverEntry) => React.ReactNode;\n /** Called when the user taps a row — navigate to the object. */\n onOpen: (entry: DiscoverEntry) => void;\n /**\n * Optional heading text shown above the search bar.\n * @default \"Discover\"\n */\n title?: string;\n /**\n * Text shown when the directory is empty after loading.\n * @default \"No public objects yet\"\n */\n emptyMessage?: string;\n /**\n * Text shown when the directory is empty due to an active search query.\n * @default \"No results for «query»\"\n */\n emptySearchMessage?: string;\n /**\n * Whether to show the inline search bar.\n * @default true\n */\n searchEnabled?: boolean;\n /**\n * Optional ref whose `.current` is set to a `reload()` function once mounted.\n * Lets a host (e.g. a tab screen) trigger a soft-refresh on focus without\n * blanking the existing list — identical to pull-to-refresh behaviour.\n *\n * ```tsx\n * const reloadRef = useRef<() => void>(null);\n * useFocusEffect(useCallback(() => { reloadRef.current?.(); }, []));\n * <DiscoverScreen reloadRef={reloadRef} ... />\n * ```\n */\n reloadRef?: React.RefObject<(() => void) | null>;\n}\n\ntype State =\n | { status: 'idle' }\n | { status: 'loading' }\n | { status: 'ready'; entries: DiscoverEntry[] }\n | { status: 'error'; message: string };\n\nexport function DiscoverScreen({\n loadEntries,\n renderIcon,\n onOpen,\n title = 'Discover',\n emptyMessage = 'No public objects yet',\n emptySearchMessage,\n searchEnabled = true,\n reloadRef,\n}: DiscoverScreenProps) {\n const theme = useOctoSpacesTheme();\n const [state, setState] = useState<State>({ status: 'idle' });\n const [query, setQuery] = useState('');\n const [refreshing, setRefreshing] = useState(false);\n const cancelledRef = useRef(false);\n\n const load = useCallback(async () => {\n setState({ status: 'loading' });\n try {\n const raw = await loadEntries();\n if (cancelledRef.current) return;\n setState({ status: 'ready', entries: sortDiscoverEntries(raw) });\n } catch (err) {\n if (cancelledRef.current) return;\n setState({\n status: 'error',\n message: err instanceof Error ? err.message : 'Failed to load directory',\n });\n }\n }, [loadEntries]);\n\n /** Pull-to-refresh: re-fetches without blanking the existing list. */\n const handleRefresh = useCallback(async () => {\n setRefreshing(true);\n try {\n const raw = await loadEntries();\n if (cancelledRef.current) return;\n setState({ status: 'ready', entries: sortDiscoverEntries(raw) });\n } catch {\n // keep the existing list on refresh failure; the retry button remains for error state\n } finally {\n if (!cancelledRef.current) setRefreshing(false);\n }\n }, [loadEntries]);\n\n // Expose handleRefresh via reloadRef so a host can trigger a soft reload on focus.\n useImperativeHandle(reloadRef, () => handleRefresh, [handleRefresh]);\n\n useEffect(() => {\n cancelledRef.current = false;\n void load();\n return () => {\n cancelledRef.current = true;\n };\n }, [load]);\n\n // ── Derived list ─────────────────────────────────────────────────────────\n const allEntries = state.status === 'ready' ? state.entries : [];\n const visibleEntries = filterDiscoverEntries(allEntries, query);\n const noSearchResults = !!query.trim() && visibleEntries.length === 0 && allEntries.length > 0;\n const resolvedEmptyMessage = noSearchResults\n ? (emptySearchMessage ?? `No results for \"${query.trim()}\"`)\n : emptyMessage;\n\n // ── Palette shortcuts ─────────────────────────────────────────────────────\n const sp2 = (theme.spacing['2'] as number) ?? 8;\n const sp3 = (theme.spacing['3'] as number) ?? 12;\n const sp4 = (theme.spacing['4'] as number) ?? 16;\n const radMd = (theme.radii['md'] as number) ?? 8;\n\n return (\n <View style={{ flex: 1, backgroundColor: theme.colors.background }}>\n {/* Header */}\n <View\n style={{\n paddingHorizontal: sp4,\n paddingTop: sp4,\n paddingBottom: sp2,\n }}\n >\n <Text\n style={{\n fontSize: theme.type['title2']?.size ?? 22,\n fontWeight: (theme.type['title2']?.weight as TextStyle['fontWeight']) ?? '700',\n lineHeight: theme.type['title2']?.lineHeight ?? 28,\n color: theme.colors.text,\n fontFamily: theme.fonts['heading'] ?? undefined,\n marginBottom: sp3,\n }}\n >\n {title}\n </Text>\n\n {/* Search bar */}\n {searchEnabled && (\n <View\n style={{\n flexDirection: 'row',\n alignItems: 'center',\n backgroundColor: theme.colors.surfaceInput ?? theme.colors.surface,\n borderRadius: radMd,\n borderWidth: 1,\n borderColor: theme.colors.borderSubtle,\n paddingHorizontal: sp3,\n height: 40,\n }}\n >\n <TextInput\n placeholder=\"Search…\"\n placeholderTextColor={theme.colors.textTertiary}\n value={query}\n onChangeText={setQuery}\n style={{\n flex: 1,\n fontSize: theme.type['body']?.size ?? 15,\n color: theme.colors.text,\n fontFamily: theme.fonts['body'] ?? undefined,\n }}\n returnKeyType=\"search\"\n clearButtonMode=\"while-editing\"\n accessibilityLabel=\"Search discover\"\n />\n </View>\n )}\n </View>\n\n {/* Body */}\n {state.status === 'loading' ? (\n <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>\n <ActivityIndicator color={theme.colors.primary} />\n </View>\n ) : state.status === 'error' ? (\n <View\n style={{\n flex: 1,\n alignItems: 'center',\n justifyContent: 'center',\n paddingHorizontal: sp4,\n }}\n >\n <Text\n style={{\n color: theme.colors.textSecondary,\n fontSize: theme.type['body']?.size ?? 15,\n textAlign: 'center',\n marginBottom: sp3,\n }}\n >\n {state.message}\n </Text>\n <Pressable\n onPress={load}\n style={{\n paddingHorizontal: sp4,\n paddingVertical: sp2,\n backgroundColor: theme.colors.primary,\n borderRadius: radMd,\n }}\n >\n <Text style={{ color: theme.colors.textOnPrimary, fontWeight: '600' }}>\n Retry\n </Text>\n </Pressable>\n </View>\n ) : (\n <DiscoverList\n entries={visibleEntries}\n renderIcon={renderIcon}\n onOpen={onOpen}\n emptyMessage={resolvedEmptyMessage}\n refreshing={refreshing}\n onRefresh={handleRefresh}\n />\n )}\n </View>\n );\n}\n"],"mappings":"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","names":["React","React","React","useCallback","Text","View","useCallback","React","View","Text","React","useCallback","Pressable","Text","View","useCallback","React","View","Text","Pressable"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drakkar.software/octospaces-ui",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Shared headless-themed UI primitives for OctoSpaces apps. Theme values are injected by the host app; this package ships only types + plumbing + primitives.",
5
5
  "type": "module",
6
6
  "sideEffects": false,