@ankhorage/zora 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +129 -5
  3. package/dist/components/app-bar/AppBar.d.ts +4 -0
  4. package/dist/components/app-bar/AppBar.d.ts.map +1 -0
  5. package/dist/components/app-bar/AppBar.js +63 -0
  6. package/dist/components/app-bar/AppBar.js.map +1 -0
  7. package/dist/components/app-bar/index.d.ts +3 -0
  8. package/dist/components/app-bar/index.d.ts.map +1 -0
  9. package/dist/components/app-bar/index.js +3 -0
  10. package/dist/components/app-bar/index.js.map +1 -0
  11. package/dist/components/app-bar/types.d.ts +31 -0
  12. package/dist/components/app-bar/types.d.ts.map +1 -0
  13. package/dist/components/app-bar/types.js +2 -0
  14. package/dist/components/app-bar/types.js.map +1 -0
  15. package/dist/components/input/types.d.ts +1 -1
  16. package/dist/components/input/types.d.ts.map +1 -1
  17. package/dist/components/input/types.js.map +1 -1
  18. package/dist/components/toolbar/types.d.ts +1 -1
  19. package/dist/components/toolbar/types.d.ts.map +1 -1
  20. package/dist/components/toolbar/types.js.map +1 -1
  21. package/dist/index.d.ts +7 -3
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +2 -0
  24. package/dist/index.js.map +1 -1
  25. package/dist/internal/resolveZoraNavigationItems.d.ts +4 -3
  26. package/dist/internal/resolveZoraNavigationItems.d.ts.map +1 -1
  27. package/dist/internal/resolveZoraNavigationItems.js.map +1 -1
  28. package/dist/patterns/list/types.d.ts +2 -2
  29. package/dist/patterns/list/types.d.ts.map +1 -1
  30. package/dist/patterns/list/types.js.map +1 -1
  31. package/dist/patterns/responsive-panel/types.d.ts +1 -1
  32. package/dist/patterns/responsive-panel/types.d.ts.map +1 -1
  33. package/dist/patterns/responsive-panel/types.js.map +1 -1
  34. package/dist/patterns/selection/SelectableItem.d.ts +4 -0
  35. package/dist/patterns/selection/SelectableItem.d.ts.map +1 -0
  36. package/dist/patterns/selection/SelectableItem.js +72 -0
  37. package/dist/patterns/selection/SelectableItem.js.map +1 -0
  38. package/dist/patterns/selection/SelectionProvider.d.ts +5 -0
  39. package/dist/patterns/selection/SelectionProvider.d.ts.map +1 -0
  40. package/dist/patterns/selection/SelectionProvider.js +64 -0
  41. package/dist/patterns/selection/SelectionProvider.js.map +1 -0
  42. package/dist/patterns/selection/index.d.ts +4 -0
  43. package/dist/patterns/selection/index.d.ts.map +1 -0
  44. package/dist/patterns/selection/index.js +3 -0
  45. package/dist/patterns/selection/index.js.map +1 -0
  46. package/dist/patterns/selection/resolveSelectionNextIds.d.ts +15 -0
  47. package/dist/patterns/selection/resolveSelectionNextIds.d.ts.map +1 -0
  48. package/dist/patterns/selection/resolveSelectionNextIds.js +44 -0
  49. package/dist/patterns/selection/resolveSelectionNextIds.js.map +1 -0
  50. package/dist/patterns/selection/types.d.ts +38 -0
  51. package/dist/patterns/selection/types.d.ts.map +1 -0
  52. package/dist/patterns/selection/types.js +2 -0
  53. package/dist/patterns/selection/types.js.map +1 -0
  54. package/package.json +8 -9
  55. package/src/components/app-bar/AppBar.tsx +133 -0
  56. package/src/components/app-bar/index.ts +2 -0
  57. package/src/components/app-bar/types.ts +36 -0
  58. package/src/components/input/types.ts +1 -1
  59. package/src/components/toolbar/types.ts +2 -2
  60. package/src/index.ts +19 -3
  61. package/src/internal/resolveZoraNavigationItems.ts +3 -3
  62. package/src/patterns/list/types.ts +2 -2
  63. package/src/patterns/responsive-panel/types.ts +2 -2
  64. package/src/patterns/selection/SelectableItem.tsx +93 -0
  65. package/src/patterns/selection/SelectionProvider.tsx +102 -0
  66. package/src/patterns/selection/index.ts +10 -0
  67. package/src/patterns/selection/resolveSelectionNextIds.test.ts +61 -0
  68. package/src/patterns/selection/resolveSelectionNextIds.ts +71 -0
  69. package/src/patterns/selection/types.ts +43 -0
  70. package/src/showcaseCoverage.test.ts +4 -0
  71. package/src/theme/themeScopeStructure.test.ts +2 -0
@@ -1 +1 @@
1
- {"version":3,"file":"resolveZoraNavigationItems.js","sourceRoot":"","sources":["../../src/internal/resolveZoraNavigationItems.ts"],"names":[],"mappings":"AAyDA,MAAM,UAAU,iBAAiB,CAAC,EAChC,KAAK,EACL,QAAQ,EACR,UAAU,EACV,IAAI,GAML;IACC,IAAI,QAAQ,EAAE,KAAK,KAAK,SAAS,EAAE,CAAC;QAClC,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IACvD,CAAC;IAED,MAAM,OAAO,GAAG,UAAU,EAAE,OAAO,CAAC;IACpC,MAAM,QAAQ,GACZ,IAAI,KAAK,KAAK;QACZ,CAAC,CAAC,CAAC,OAAO,EAAE,WAAW,IAAI,OAAO,EAAE,KAAK,CAAC;QAC1C,CAAC,CAAC,CAAC,OAAO,EAAE,WAAW,IAAI,OAAO,EAAE,KAAK,CAAC,CAAC;IAE/C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;IACnD,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,EACrC,KAAK,EACL,WAAW,EACX,QAAQ,EACR,IAAI,GAML;IACC,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAE9C,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QAChC,MAAM,QAAQ,GAAG,QAAQ,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACxC,MAAM,UAAU,GAAG,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC5C,MAAM,EAAE,KAAK,EAAE,GAAG,iBAAiB,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3E,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAE7C,OAAO;YACL,KAAK;YACL,QAAQ;YACR,KAAK;YACL,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,KAAK,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK;YAC3D,QAAQ;SACT,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,EAC3C,IAAI,EACJ,UAAU,GAIX;IACC,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QACjC,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,GAAG,EAAE;QACV,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC;YAC/B,IAAI,EAAE,UAAU;YAChB,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG;YACtB,iBAAiB,EAAE,IAAI;SACxB,CAAC,CAAC;QAEH,IAAI,MAAM,EAAE,gBAAgB,EAAE,CAAC;YAC7B,OAAO;QACT,CAAC;QAED,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACvC,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,EAC3C,IAAI,EACJ,UAAU,GAIX;IACC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,GAAG,EAAE;QACV,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACrC,UAAU,CAAC,WAAW,EAAE,EAAE,CAAC;IAC7B,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import type React from 'react';\n\nimport type {\n ZoraNavigationRouteMetadata,\n ZoraNavigationRouteState,\n} from '../components/navigation-item';\nimport type { ZoraNavigationRouteMap } from '../components/navigation-list';\n\nexport interface ZoraNavigationDescriptorOptions {\n title?: string;\n tabBarLabel?: string | React.ReactNode;\n drawerLabel?: string | React.ReactNode;\n}\n\nexport interface ZoraNavigationDescriptor {\n options?: ZoraNavigationDescriptorOptions;\n}\n\nexport type ZoraNavigationDescriptors = Readonly<\n Record<string, ZoraNavigationDescriptor | undefined>\n>;\n\nexport interface ZoraNavigationState {\n index: number;\n routes: readonly ZoraNavigationRouteState[];\n}\n\nexport interface ZoraTabPressEvent {\n type: 'tabPress';\n target: string;\n canPreventDefault: true;\n}\n\nexport interface ZoraTabPressEventResult {\n defaultPrevented: boolean;\n}\n\nexport interface ZoraTabBarNavigation {\n emit?: (event: ZoraTabPressEvent) => ZoraTabPressEventResult;\n navigate: (name: string) => void;\n}\n\nexport interface ZoraDrawerNavigation {\n navigate: (name: string) => void;\n closeDrawer?: () => void;\n}\n\nexport interface ZoraResolvedNavigationItem {\n route: ZoraNavigationRouteState;\n metadata?: ZoraNavigationRouteMetadata;\n label: React.ReactNode;\n active: boolean;\n disabled: boolean;\n}\n\nexport type ZoraRouteLabelSource = 'routeMap' | 'descriptor' | 'name';\n\nexport function resolveRouteLabel({\n route,\n metadata,\n descriptor,\n kind,\n}: {\n route: ZoraNavigationRouteState;\n metadata: ZoraNavigationRouteMetadata | undefined;\n descriptor: ZoraNavigationDescriptor | undefined;\n kind: 'tab' | 'drawer';\n}): { label: React.ReactNode; source: ZoraRouteLabelSource } {\n if (metadata?.label !== undefined) {\n return { label: metadata.label, source: 'routeMap' };\n }\n\n const options = descriptor?.options;\n const fallback =\n kind === 'tab'\n ? (options?.tabBarLabel ?? options?.title)\n : (options?.drawerLabel ?? options?.title);\n\n if (fallback !== undefined) {\n return { label: fallback, source: 'descriptor' };\n }\n\n return { label: route.name, source: 'name' };\n}\n\nexport function resolveNavigationItems({\n state,\n descriptors,\n routeMap,\n kind,\n}: {\n state: ZoraNavigationState;\n descriptors?: ZoraNavigationDescriptors | undefined;\n routeMap?: ZoraNavigationRouteMap | undefined;\n kind: 'tab' | 'drawer';\n}): readonly ZoraResolvedNavigationItem[] {\n const activeRoute = state.routes[state.index];\n\n return state.routes.map((route) => {\n const metadata = routeMap?.[route.name];\n const descriptor = descriptors?.[route.key];\n const { label } = resolveRouteLabel({ route, metadata, descriptor, kind });\n const disabled = Boolean(metadata?.disabled);\n\n return {\n route,\n metadata,\n label,\n active: activeRoute ? activeRoute.key === route.key : false,\n disabled,\n };\n });\n}\n\nexport function createTabBarItemPressHandler({\n item,\n navigation,\n}: {\n item: ZoraResolvedNavigationItem;\n navigation: ZoraTabBarNavigation;\n}): (() => void) | undefined {\n if (item.disabled || item.active) {\n return undefined;\n }\n\n return () => {\n const result = navigation.emit?.({\n type: 'tabPress',\n target: item.route.key,\n canPreventDefault: true,\n });\n\n if (result?.defaultPrevented) {\n return;\n }\n\n navigation.navigate(item.route.name);\n };\n}\n\nexport function createDrawerItemPressHandler({\n item,\n navigation,\n}: {\n item: ZoraResolvedNavigationItem;\n navigation: ZoraDrawerNavigation;\n}): (() => void) | undefined {\n if (item.disabled) {\n return undefined;\n }\n\n return () => {\n navigation.navigate(item.route.name);\n navigation.closeDrawer?.();\n };\n}\n"]}
1
+ {"version":3,"file":"resolveZoraNavigationItems.js","sourceRoot":"","sources":["../../src/internal/resolveZoraNavigationItems.ts"],"names":[],"mappings":"AAyDA,MAAM,UAAU,iBAAiB,CAAC,EAChC,KAAK,EACL,QAAQ,EACR,UAAU,EACV,IAAI,GAML;IACC,IAAI,QAAQ,EAAE,KAAK,KAAK,SAAS,EAAE,CAAC;QAClC,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IACvD,CAAC;IAED,MAAM,OAAO,GAAG,UAAU,EAAE,OAAO,CAAC;IACpC,MAAM,QAAQ,GACZ,IAAI,KAAK,KAAK;QACZ,CAAC,CAAC,CAAC,OAAO,EAAE,WAAW,IAAI,OAAO,EAAE,KAAK,CAAC;QAC1C,CAAC,CAAC,CAAC,OAAO,EAAE,WAAW,IAAI,OAAO,EAAE,KAAK,CAAC,CAAC;IAE/C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;IACnD,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,EACrC,KAAK,EACL,WAAW,EACX,QAAQ,EACR,IAAI,GAML;IACC,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAE9C,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QAChC,MAAM,QAAQ,GAAG,QAAQ,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACxC,MAAM,UAAU,GAAG,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC5C,MAAM,EAAE,KAAK,EAAE,GAAG,iBAAiB,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3E,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAE7C,OAAO;YACL,KAAK;YACL,QAAQ;YACR,KAAK;YACL,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,KAAK,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK;YAC3D,QAAQ;SACT,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,EAC3C,IAAI,EACJ,UAAU,GAIX;IACC,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QACjC,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,GAAG,EAAE;QACV,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC;YAC/B,IAAI,EAAE,UAAU;YAChB,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG;YACtB,iBAAiB,EAAE,IAAI;SACxB,CAAC,CAAC;QAEH,IAAI,MAAM,EAAE,gBAAgB,EAAE,CAAC;YAC7B,OAAO;QACT,CAAC;QAED,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACvC,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,EAC3C,IAAI,EACJ,UAAU,GAIX;IACC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,GAAG,EAAE;QACV,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACrC,UAAU,CAAC,WAAW,EAAE,EAAE,CAAC;IAC7B,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import type React from 'react';\n\nimport type {\n ZoraNavigationRouteMetadata,\n ZoraNavigationRouteState,\n} from '../components/navigation-item';\nimport type { ZoraNavigationRouteMap } from '../components/navigation-list';\n\ninterface ZoraNavigationDescriptorOptions {\n title?: string;\n tabBarLabel?: string | React.ReactNode;\n drawerLabel?: string | React.ReactNode;\n}\n\nexport interface ZoraNavigationDescriptor {\n options?: ZoraNavigationDescriptorOptions;\n}\n\nexport type ZoraNavigationDescriptors = Readonly<\n Record<string, ZoraNavigationDescriptor | undefined>\n>;\n\nexport interface ZoraNavigationState {\n index: number;\n routes: readonly ZoraNavigationRouteState[];\n}\n\ninterface ZoraTabPressEvent {\n type: 'tabPress';\n target: string;\n canPreventDefault: true;\n}\n\ninterface ZoraTabPressEventResult {\n defaultPrevented: boolean;\n}\n\nexport interface ZoraTabBarNavigation {\n emit?: (event: ZoraTabPressEvent) => ZoraTabPressEventResult;\n navigate: (name: string) => void;\n}\n\nexport interface ZoraDrawerNavigation {\n navigate: (name: string) => void;\n closeDrawer?: () => void;\n}\n\nexport interface ZoraResolvedNavigationItem {\n route: ZoraNavigationRouteState;\n metadata?: ZoraNavigationRouteMetadata;\n label: React.ReactNode;\n active: boolean;\n disabled: boolean;\n}\n\nexport type ZoraRouteLabelSource = 'routeMap' | 'descriptor' | 'name';\n\nexport function resolveRouteLabel({\n route,\n metadata,\n descriptor,\n kind,\n}: {\n route: ZoraNavigationRouteState;\n metadata: ZoraNavigationRouteMetadata | undefined;\n descriptor: ZoraNavigationDescriptor | undefined;\n kind: 'tab' | 'drawer';\n}): { label: React.ReactNode; source: ZoraRouteLabelSource } {\n if (metadata?.label !== undefined) {\n return { label: metadata.label, source: 'routeMap' };\n }\n\n const options = descriptor?.options;\n const fallback =\n kind === 'tab'\n ? (options?.tabBarLabel ?? options?.title)\n : (options?.drawerLabel ?? options?.title);\n\n if (fallback !== undefined) {\n return { label: fallback, source: 'descriptor' };\n }\n\n return { label: route.name, source: 'name' };\n}\n\nexport function resolveNavigationItems({\n state,\n descriptors,\n routeMap,\n kind,\n}: {\n state: ZoraNavigationState;\n descriptors?: ZoraNavigationDescriptors | undefined;\n routeMap?: ZoraNavigationRouteMap | undefined;\n kind: 'tab' | 'drawer';\n}): readonly ZoraResolvedNavigationItem[] {\n const activeRoute = state.routes[state.index];\n\n return state.routes.map((route) => {\n const metadata = routeMap?.[route.name];\n const descriptor = descriptors?.[route.key];\n const { label } = resolveRouteLabel({ route, metadata, descriptor, kind });\n const disabled = Boolean(metadata?.disabled);\n\n return {\n route,\n metadata,\n label,\n active: activeRoute ? activeRoute.key === route.key : false,\n disabled,\n };\n });\n}\n\nexport function createTabBarItemPressHandler({\n item,\n navigation,\n}: {\n item: ZoraResolvedNavigationItem;\n navigation: ZoraTabBarNavigation;\n}): (() => void) | undefined {\n if (item.disabled || item.active) {\n return undefined;\n }\n\n return () => {\n const result = navigation.emit?.({\n type: 'tabPress',\n target: item.route.key,\n canPreventDefault: true,\n });\n\n if (result?.defaultPrevented) {\n return;\n }\n\n navigation.navigate(item.route.name);\n };\n}\n\nexport function createDrawerItemPressHandler({\n item,\n navigation,\n}: {\n item: ZoraResolvedNavigationItem;\n navigation: ZoraDrawerNavigation;\n}): (() => void) | undefined {\n if (item.disabled) {\n return undefined;\n }\n\n return () => {\n navigation.navigate(item.route.name);\n navigation.closeDrawer?.();\n };\n}\n"]}
@@ -34,7 +34,7 @@ export interface ListChildrenProps extends ZoraBaseProps {
34
34
  children: React.ReactNode;
35
35
  }
36
36
  export type ListProps = ListItemsProps | ListChildrenProps;
37
- export interface ListSectionItemsProps extends ZoraBaseProps {
37
+ interface ListSectionItemsProps extends ZoraBaseProps {
38
38
  title?: React.ReactNode;
39
39
  description?: React.ReactNode;
40
40
  eyebrow?: React.ReactNode;
@@ -43,7 +43,7 @@ export interface ListSectionItemsProps extends ZoraBaseProps {
43
43
  rowVariant?: ListRowVariant;
44
44
  compact?: boolean;
45
45
  }
46
- export interface ListSectionChildrenProps extends ZoraBaseProps {
46
+ interface ListSectionChildrenProps extends ZoraBaseProps {
47
47
  title?: React.ReactNode;
48
48
  description?: React.ReactNode;
49
49
  eyebrow?: React.ReactNode;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/patterns/list/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE/D,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,MAAM,CAAC;AAEhD,UAAU,gBAAiB,SAAQ,aAAa;IAC9C,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B;AAED,UAAU,qBAAqB;IAC7B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,CAAC,EAAE,KAAK,CAAC;CAChB;AAED,UAAU,kBAAkB;IAC1B,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,OAAO,CAAC,EAAE,KAAK,CAAC;CACjB;AAED,UAAU,kBAAkB;IAC1B,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,OAAO,CAAC,EAAE,KAAK,CAAC;CACjB;AAED,MAAM,MAAM,YAAY,GAAG,gBAAgB,GACzC,CAAC,qBAAqB,GAAG,kBAAkB,GAAG,kBAAkB,CAAC,CAAC;AAEpE,MAAM,WAAW,cAAe,SAAQ,aAAa;IACnD,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IAC/B,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,MAAM,MAAM,SAAS,GAAG,cAAc,GAAG,iBAAiB,CAAC;AAE3D,MAAM,WAAW,qBAAsB,SAAQ,aAAa;IAC1D,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IAC/B,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,wBAAyB,SAAQ,aAAa;IAC7D,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,MAAM,MAAM,gBAAgB,GAAG,qBAAqB,GAAG,wBAAwB,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/patterns/list/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE/D,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,MAAM,CAAC;AAEhD,UAAU,gBAAiB,SAAQ,aAAa;IAC9C,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B;AAED,UAAU,qBAAqB;IAC7B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,CAAC,EAAE,KAAK,CAAC;CAChB;AAED,UAAU,kBAAkB;IAC1B,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,OAAO,CAAC,EAAE,KAAK,CAAC;CACjB;AAED,UAAU,kBAAkB;IAC1B,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,OAAO,CAAC,EAAE,KAAK,CAAC;CACjB;AAED,MAAM,MAAM,YAAY,GAAG,gBAAgB,GACzC,CAAC,qBAAqB,GAAG,kBAAkB,GAAG,kBAAkB,CAAC,CAAC;AAEpE,MAAM,WAAW,cAAe,SAAQ,aAAa;IACnD,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IAC/B,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,MAAM,MAAM,SAAS,GAAG,cAAc,GAAG,iBAAiB,CAAC;AAE3D,UAAU,qBAAsB,SAAQ,aAAa;IACnD,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IAC/B,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,UAAU,wBAAyB,SAAQ,aAAa;IACtD,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,MAAM,MAAM,gBAAgB,GAAG,qBAAqB,GAAG,wBAAwB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/patterns/list/types.ts"],"names":[],"mappings":"","sourcesContent":["import type React from 'react';\n\nimport type { ZoraBaseProps } from '../../theme/ZoraBaseProps';\n\nexport type ListRowVariant = 'divider' | 'card';\n\ninterface ListRowBaseProps extends ZoraBaseProps {\n title: React.ReactNode;\n description?: React.ReactNode;\n meta?: React.ReactNode;\n leading?: React.ReactNode;\n trailing?: React.ReactNode;\n selected?: boolean;\n disabled?: boolean;\n compact?: boolean;\n variant?: ListRowVariant;\n}\n\ninterface ListRowPressableProps {\n onPress: () => void;\n action?: never;\n}\n\ninterface ListRowActionProps {\n action: React.ReactNode;\n onPress?: never;\n}\n\ninterface ListRowStaticProps {\n action?: never;\n onPress?: never;\n}\n\nexport type ListRowProps = ListRowBaseProps &\n (ListRowPressableProps | ListRowActionProps | ListRowStaticProps);\n\nexport interface ListItemsProps extends ZoraBaseProps {\n items: readonly ListRowProps[];\n rowVariant?: ListRowVariant;\n compact?: boolean;\n}\n\nexport interface ListChildrenProps extends ZoraBaseProps {\n children: React.ReactNode;\n}\n\nexport type ListProps = ListItemsProps | ListChildrenProps;\n\nexport interface ListSectionItemsProps extends ZoraBaseProps {\n title?: React.ReactNode;\n description?: React.ReactNode;\n eyebrow?: React.ReactNode;\n actions?: React.ReactNode;\n items: readonly ListRowProps[];\n rowVariant?: ListRowVariant;\n compact?: boolean;\n}\n\nexport interface ListSectionChildrenProps extends ZoraBaseProps {\n title?: React.ReactNode;\n description?: React.ReactNode;\n eyebrow?: React.ReactNode;\n actions?: React.ReactNode;\n children: React.ReactNode;\n}\n\nexport type ListSectionProps = ListSectionItemsProps | ListSectionChildrenProps;\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/patterns/list/types.ts"],"names":[],"mappings":"","sourcesContent":["import type React from 'react';\n\nimport type { ZoraBaseProps } from '../../theme/ZoraBaseProps';\n\nexport type ListRowVariant = 'divider' | 'card';\n\ninterface ListRowBaseProps extends ZoraBaseProps {\n title: React.ReactNode;\n description?: React.ReactNode;\n meta?: React.ReactNode;\n leading?: React.ReactNode;\n trailing?: React.ReactNode;\n selected?: boolean;\n disabled?: boolean;\n compact?: boolean;\n variant?: ListRowVariant;\n}\n\ninterface ListRowPressableProps {\n onPress: () => void;\n action?: never;\n}\n\ninterface ListRowActionProps {\n action: React.ReactNode;\n onPress?: never;\n}\n\ninterface ListRowStaticProps {\n action?: never;\n onPress?: never;\n}\n\nexport type ListRowProps = ListRowBaseProps &\n (ListRowPressableProps | ListRowActionProps | ListRowStaticProps);\n\nexport interface ListItemsProps extends ZoraBaseProps {\n items: readonly ListRowProps[];\n rowVariant?: ListRowVariant;\n compact?: boolean;\n}\n\nexport interface ListChildrenProps extends ZoraBaseProps {\n children: React.ReactNode;\n}\n\nexport type ListProps = ListItemsProps | ListChildrenProps;\n\ninterface ListSectionItemsProps extends ZoraBaseProps {\n title?: React.ReactNode;\n description?: React.ReactNode;\n eyebrow?: React.ReactNode;\n actions?: React.ReactNode;\n items: readonly ListRowProps[];\n rowVariant?: ListRowVariant;\n compact?: boolean;\n}\n\ninterface ListSectionChildrenProps extends ZoraBaseProps {\n title?: React.ReactNode;\n description?: React.ReactNode;\n eyebrow?: React.ReactNode;\n actions?: React.ReactNode;\n children: React.ReactNode;\n}\n\nexport type ListSectionProps = ListSectionItemsProps | ListSectionChildrenProps;\n"]}
@@ -1,8 +1,8 @@
1
1
  import type React from 'react';
2
+ import type { ZoraBaseProps } from '../../theme/ZoraBaseProps';
2
3
  export type ResponsivePanelSide = 'left' | 'right';
3
4
  export type ResponsivePanelDesktopMode = 'inline' | 'floating';
4
5
  export type ResponsivePanelMobileMode = 'drawer' | 'modal';
5
- import type { ZoraBaseProps } from '../../theme/ZoraBaseProps';
6
6
  export interface ResponsivePanelProps extends ZoraBaseProps {
7
7
  title?: React.ReactNode;
8
8
  description?: React.ReactNode;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/patterns/responsive-panel/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,OAAO,CAAC;AACnD,MAAM,MAAM,0BAA0B,GAAG,QAAQ,GAAG,UAAU,CAAC;AAC/D,MAAM,MAAM,yBAAyB,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE/D,MAAM,WAAW,oBAAqB,SAAQ,aAAa;IACzD,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAC3B,WAAW,CAAC,EAAE,0BAA0B,CAAC;IACzC,UAAU,CAAC,EAAE,yBAAyB,CAAC;IACvC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/patterns/responsive-panel/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE/D,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,OAAO,CAAC;AACnD,MAAM,MAAM,0BAA0B,GAAG,QAAQ,GAAG,UAAU,CAAC;AAC/D,MAAM,MAAM,yBAAyB,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE3D,MAAM,WAAW,oBAAqB,SAAQ,aAAa;IACzD,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAC3B,WAAW,CAAC,EAAE,0BAA0B,CAAC;IACzC,UAAU,CAAC,EAAE,yBAAyB,CAAC;IACvC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/patterns/responsive-panel/types.ts"],"names":[],"mappings":"","sourcesContent":["import type React from 'react';\n\nexport type ResponsivePanelSide = 'left' | 'right';\nexport type ResponsivePanelDesktopMode = 'inline' | 'floating';\nexport type ResponsivePanelMobileMode = 'drawer' | 'modal';\n\nimport type { ZoraBaseProps } from '../../theme/ZoraBaseProps';\n\nexport interface ResponsivePanelProps extends ZoraBaseProps {\n title?: React.ReactNode;\n description?: React.ReactNode;\n actions?: React.ReactNode;\n footer?: React.ReactNode;\n children?: React.ReactNode;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n side?: ResponsivePanelSide;\n desktopMode?: ResponsivePanelDesktopMode;\n mobileMode?: ResponsivePanelMobileMode;\n compact?: boolean;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/patterns/responsive-panel/types.ts"],"names":[],"mappings":"","sourcesContent":["import type React from 'react';\n\nimport type { ZoraBaseProps } from '../../theme/ZoraBaseProps';\n\nexport type ResponsivePanelSide = 'left' | 'right';\nexport type ResponsivePanelDesktopMode = 'inline' | 'floating';\nexport type ResponsivePanelMobileMode = 'drawer' | 'modal';\n\nexport interface ResponsivePanelProps extends ZoraBaseProps {\n title?: React.ReactNode;\n description?: React.ReactNode;\n actions?: React.ReactNode;\n footer?: React.ReactNode;\n children?: React.ReactNode;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n side?: ResponsivePanelSide;\n desktopMode?: ResponsivePanelDesktopMode;\n mobileMode?: ResponsivePanelMobileMode;\n compact?: boolean;\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ import type { SelectableItemProps } from './types';
3
+ export declare function SelectableItem({ id, trigger, disabled, children }: SelectableItemProps): React.JSX.Element;
4
+ //# sourceMappingURL=SelectableItem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SelectableItem.d.ts","sourceRoot":"","sources":["../../../src/patterns/selection/SelectableItem.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,KAAK,EAAE,mBAAmB,EAAyC,MAAM,SAAS,CAAC;AAY1F,wBAAgB,cAAc,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,QAAgB,EAAE,QAAQ,EAAE,EAAE,mBAAmB,qBA2E9F"}
@@ -0,0 +1,72 @@
1
+ import { ButtonBase } from '@ankhorage/surface';
2
+ import React from 'react';
3
+ import { useSelection } from './SelectionProvider';
4
+ function resolveTrigger(trigger) {
5
+ return trigger ?? 'manual';
6
+ }
7
+ function isRenderProp(children) {
8
+ return typeof children === 'function';
9
+ }
10
+ export function SelectableItem({ id, trigger, disabled = false, children }) {
11
+ const selection = useSelection();
12
+ const resolvedTrigger = resolveTrigger(trigger);
13
+ const resolvedDisabled = selection.disabled || disabled;
14
+ const selected = selection.isSelected(id);
15
+ const select = React.useCallback(() => {
16
+ if (resolvedDisabled)
17
+ return;
18
+ selection.select(id);
19
+ }, [id, resolvedDisabled, selection]);
20
+ const toggle = React.useCallback(() => {
21
+ if (resolvedDisabled)
22
+ return;
23
+ selection.toggle(id);
24
+ }, [id, resolvedDisabled, selection]);
25
+ const clear = React.useCallback(() => {
26
+ if (selection.disabled)
27
+ return;
28
+ selection.clear();
29
+ }, [selection]);
30
+ const itemState = React.useMemo(() => {
31
+ return {
32
+ id,
33
+ selected,
34
+ disabled: resolvedDisabled,
35
+ mode: selection.mode,
36
+ select,
37
+ toggle,
38
+ clear,
39
+ };
40
+ }, [clear, id, resolvedDisabled, select, selected, selection.mode, toggle]);
41
+ // IMPORTANT:
42
+ // Do not pass `children` directly into ButtonBase. ButtonBase also supports function children,
43
+ // but its function signature receives interaction state, not SelectableItemState.
44
+ const content = isRenderProp(children) ? children(itemState) : children;
45
+ if (resolvedTrigger === 'manual') {
46
+ return <>{content}</>;
47
+ }
48
+ const handlePress = (event) => {
49
+ event.stopPropagation();
50
+ if (resolvedDisabled)
51
+ return;
52
+ if (selection.mode === 'single') {
53
+ selection.select(id);
54
+ return;
55
+ }
56
+ selection.toggle(id);
57
+ };
58
+ const handleLongPress = (event) => {
59
+ event.stopPropagation();
60
+ if (resolvedDisabled)
61
+ return;
62
+ if (selection.mode === 'single') {
63
+ selection.select(id);
64
+ return;
65
+ }
66
+ selection.toggle(id);
67
+ };
68
+ return (<ButtonBase accessibilityRole="button" accessibilityState={{ disabled: resolvedDisabled, selected }} disabled={resolvedDisabled} onLongPress={resolvedTrigger === 'longPress' ? handleLongPress : undefined} onPress={resolvedTrigger === 'press' ? handlePress : undefined}>
69
+ {content}
70
+ </ButtonBase>);
71
+ }
72
+ //# sourceMappingURL=SelectableItem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SelectableItem.js","sourceRoot":"","sources":["../../../src/patterns/selection/SelectableItem.tsx"],"names":[],"mappings":"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","sourcesContent":["import { ButtonBase } from '@ankhorage/surface';\nimport React from 'react';\nimport type { GestureResponderEvent } from 'react-native';\n\nimport { useSelection } from './SelectionProvider';\nimport type { SelectableItemProps, SelectableItemState, SelectionTrigger } from './types';\n\nfunction resolveTrigger(trigger: SelectionTrigger | undefined): SelectionTrigger {\n return trigger ?? 'manual';\n}\n\nfunction isRenderProp(\n children: SelectableItemProps['children'],\n): children is (state: SelectableItemState) => React.ReactNode {\n return typeof children === 'function';\n}\n\nexport function SelectableItem({ id, trigger, disabled = false, children }: SelectableItemProps) {\n const selection = useSelection();\n const resolvedTrigger = resolveTrigger(trigger);\n const resolvedDisabled = selection.disabled || disabled;\n const selected = selection.isSelected(id);\n\n const select = React.useCallback(() => {\n if (resolvedDisabled) return;\n selection.select(id);\n }, [id, resolvedDisabled, selection]);\n\n const toggle = React.useCallback(() => {\n if (resolvedDisabled) return;\n selection.toggle(id);\n }, [id, resolvedDisabled, selection]);\n\n const clear = React.useCallback(() => {\n if (selection.disabled) return;\n selection.clear();\n }, [selection]);\n\n const itemState = React.useMemo<SelectableItemState>(() => {\n return {\n id,\n selected,\n disabled: resolvedDisabled,\n mode: selection.mode,\n select,\n toggle,\n clear,\n };\n }, [clear, id, resolvedDisabled, select, selected, selection.mode, toggle]);\n\n // IMPORTANT:\n // Do not pass `children` directly into ButtonBase. ButtonBase also supports function children,\n // but its function signature receives interaction state, not SelectableItemState.\n const content = isRenderProp(children) ? children(itemState) : children;\n\n if (resolvedTrigger === 'manual') {\n return <>{content}</>;\n }\n\n const handlePress = (event: GestureResponderEvent) => {\n event.stopPropagation();\n if (resolvedDisabled) return;\n if (selection.mode === 'single') {\n selection.select(id);\n return;\n }\n\n selection.toggle(id);\n };\n\n const handleLongPress = (event: GestureResponderEvent) => {\n event.stopPropagation();\n if (resolvedDisabled) return;\n if (selection.mode === 'single') {\n selection.select(id);\n return;\n }\n\n selection.toggle(id);\n };\n\n return (\n <ButtonBase\n accessibilityRole=\"button\"\n accessibilityState={{ disabled: resolvedDisabled, selected }}\n disabled={resolvedDisabled}\n onLongPress={resolvedTrigger === 'longPress' ? handleLongPress : undefined}\n onPress={resolvedTrigger === 'press' ? handlePress : undefined}\n >\n {content}\n </ButtonBase>\n );\n}\n"]}
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ import type { SelectionProviderProps, UseSelectionResult } from './types';
3
+ export declare function useSelection(): UseSelectionResult;
4
+ export declare function SelectionProvider({ children, selectedIds, defaultSelectedIds, mode, disabled, onSelectionChange, }: SelectionProviderProps): React.JSX.Element;
5
+ //# sourceMappingURL=SelectionProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SelectionProvider.d.ts","sourceRoot":"","sources":["../../../src/patterns/selection/SelectionProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,KAAK,EAAiB,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAiBzF,wBAAgB,YAAY,IAAI,kBAAkB,CAOjD;AAED,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EACR,WAAW,EACX,kBAAkB,EAClB,IAAI,EACJ,QAAQ,EACR,iBAAiB,GAClB,EAAE,sBAAsB,qBAiExB"}
@@ -0,0 +1,64 @@
1
+ import React from 'react';
2
+ import { areIdsEqual, clearIds, normalizeIds, selectId, toggleId } from './resolveSelectionNextIds';
3
+ const MISSING_CONTEXT_MESSAGE = 'ZORA selection context is missing. Wrap this tree in <SelectionProvider>.';
4
+ const SelectionContext = React.createContext(null);
5
+ function resolveMode(mode) {
6
+ return mode ?? 'single';
7
+ }
8
+ function resolveDisabled(disabled) {
9
+ return disabled ?? false;
10
+ }
11
+ export function useSelection() {
12
+ const value = React.useContext(SelectionContext);
13
+ if (!value) {
14
+ throw new Error(MISSING_CONTEXT_MESSAGE);
15
+ }
16
+ return value;
17
+ }
18
+ export function SelectionProvider({ children, selectedIds, defaultSelectedIds, mode, disabled, onSelectionChange, }) {
19
+ const resolvedMode = resolveMode(mode);
20
+ const resolvedDisabled = resolveDisabled(disabled);
21
+ const isControlled = selectedIds !== undefined;
22
+ const [uncontrolledIds, setUncontrolledIds] = React.useState(defaultSelectedIds ?? []);
23
+ const rawIds = isControlled ? selectedIds : uncontrolledIds;
24
+ const currentNormalizedIds = normalizeIds(rawIds, resolvedMode);
25
+ const selectedIdSet = React.useMemo(() => new Set(currentNormalizedIds), [currentNormalizedIds]);
26
+ const commitSelectionChange = React.useCallback((nextNormalizedIds) => {
27
+ if (resolvedDisabled)
28
+ return;
29
+ if (areIdsEqual(nextNormalizedIds, currentNormalizedIds))
30
+ return;
31
+ onSelectionChange?.(nextNormalizedIds);
32
+ if (!isControlled) {
33
+ setUncontrolledIds(nextNormalizedIds);
34
+ }
35
+ }, [currentNormalizedIds, isControlled, onSelectionChange, resolvedDisabled]);
36
+ const clear = React.useCallback(() => {
37
+ commitSelectionChange(normalizeIds(clearIds(), resolvedMode));
38
+ }, [commitSelectionChange, resolvedMode]);
39
+ const select = React.useCallback((id) => {
40
+ const nextIds = selectId({ mode: resolvedMode, ids: currentNormalizedIds, id });
41
+ const nextNormalizedIds = normalizeIds(nextIds, resolvedMode);
42
+ commitSelectionChange(nextNormalizedIds);
43
+ }, [commitSelectionChange, currentNormalizedIds, resolvedMode]);
44
+ const toggle = React.useCallback((id) => {
45
+ const nextIds = toggleId({ mode: resolvedMode, ids: currentNormalizedIds, id });
46
+ const nextNormalizedIds = normalizeIds(nextIds, resolvedMode);
47
+ commitSelectionChange(nextNormalizedIds);
48
+ }, [commitSelectionChange, currentNormalizedIds, resolvedMode]);
49
+ const value = React.useMemo(() => {
50
+ return {
51
+ mode: resolvedMode,
52
+ disabled: resolvedDisabled,
53
+ selectedIds: currentNormalizedIds,
54
+ selectedCount: currentNormalizedIds.length,
55
+ hasSelection: currentNormalizedIds.length > 0,
56
+ isSelected: (id) => selectedIdSet.has(id),
57
+ select,
58
+ toggle,
59
+ clear,
60
+ };
61
+ }, [clear, currentNormalizedIds, resolvedDisabled, resolvedMode, select, selectedIdSet, toggle]);
62
+ return <SelectionContext.Provider value={value}>{children}</SelectionContext.Provider>;
63
+ }
64
+ //# sourceMappingURL=SelectionProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SelectionProvider.js","sourceRoot":"","sources":["../../../src/patterns/selection/SelectionProvider.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\n\nimport { areIdsEqual, clearIds, normalizeIds, selectId, toggleId } from './resolveSelectionNextIds';\nimport type { SelectionMode, SelectionProviderProps, UseSelectionResult } from './types';\n\nconst MISSING_CONTEXT_MESSAGE =\n 'ZORA selection context is missing. Wrap this tree in <SelectionProvider>.';\n\ntype SelectionContextValue = UseSelectionResult;\n\nconst SelectionContext = React.createContext<SelectionContextValue | null>(null);\n\nfunction resolveMode(mode: SelectionMode | undefined): SelectionMode {\n return mode ?? 'single';\n}\n\nfunction resolveDisabled(disabled: boolean | undefined): boolean {\n return disabled ?? false;\n}\n\nexport function useSelection(): UseSelectionResult {\n const value = React.useContext(SelectionContext);\n if (!value) {\n throw new Error(MISSING_CONTEXT_MESSAGE);\n }\n\n return value;\n}\n\nexport function SelectionProvider({\n children,\n selectedIds,\n defaultSelectedIds,\n mode,\n disabled,\n onSelectionChange,\n}: SelectionProviderProps) {\n const resolvedMode = resolveMode(mode);\n const resolvedDisabled = resolveDisabled(disabled);\n const isControlled = selectedIds !== undefined;\n\n const [uncontrolledIds, setUncontrolledIds] = React.useState<readonly string[]>(\n defaultSelectedIds ?? [],\n );\n\n const rawIds = isControlled ? selectedIds : uncontrolledIds;\n const currentNormalizedIds = normalizeIds(rawIds, resolvedMode);\n\n const selectedIdSet = React.useMemo(() => new Set(currentNormalizedIds), [currentNormalizedIds]);\n\n const commitSelectionChange = React.useCallback(\n (nextNormalizedIds: readonly string[]) => {\n if (resolvedDisabled) return;\n if (areIdsEqual(nextNormalizedIds, currentNormalizedIds)) return;\n\n onSelectionChange?.(nextNormalizedIds);\n\n if (!isControlled) {\n setUncontrolledIds(nextNormalizedIds);\n }\n },\n [currentNormalizedIds, isControlled, onSelectionChange, resolvedDisabled],\n );\n\n const clear = React.useCallback(() => {\n commitSelectionChange(normalizeIds(clearIds(), resolvedMode));\n }, [commitSelectionChange, resolvedMode]);\n\n const select = React.useCallback(\n (id: string) => {\n const nextIds = selectId({ mode: resolvedMode, ids: currentNormalizedIds, id });\n const nextNormalizedIds = normalizeIds(nextIds, resolvedMode);\n commitSelectionChange(nextNormalizedIds);\n },\n [commitSelectionChange, currentNormalizedIds, resolvedMode],\n );\n\n const toggle = React.useCallback(\n (id: string) => {\n const nextIds = toggleId({ mode: resolvedMode, ids: currentNormalizedIds, id });\n const nextNormalizedIds = normalizeIds(nextIds, resolvedMode);\n commitSelectionChange(nextNormalizedIds);\n },\n [commitSelectionChange, currentNormalizedIds, resolvedMode],\n );\n\n const value = React.useMemo<UseSelectionResult>(() => {\n return {\n mode: resolvedMode,\n disabled: resolvedDisabled,\n selectedIds: currentNormalizedIds,\n selectedCount: currentNormalizedIds.length,\n hasSelection: currentNormalizedIds.length > 0,\n isSelected: (id: string) => selectedIdSet.has(id),\n select,\n toggle,\n clear,\n };\n }, [clear, currentNormalizedIds, resolvedDisabled, resolvedMode, select, selectedIdSet, toggle]);\n\n return <SelectionContext.Provider value={value}>{children}</SelectionContext.Provider>;\n}\n"]}
@@ -0,0 +1,4 @@
1
+ export { SelectableItem } from './SelectableItem';
2
+ export { SelectionProvider, useSelection } from './SelectionProvider';
3
+ export type { SelectableItemProps, SelectableItemState, SelectionMode, SelectionProviderProps, SelectionTrigger, UseSelectionResult, } from './types';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/patterns/selection/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACtE,YAAY,EACV,mBAAmB,EACnB,mBAAmB,EACnB,aAAa,EACb,sBAAsB,EACtB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,SAAS,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { SelectableItem } from './SelectableItem';
2
+ export { SelectionProvider, useSelection } from './SelectionProvider';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/patterns/selection/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC","sourcesContent":["export { SelectableItem } from './SelectableItem';\nexport { SelectionProvider, useSelection } from './SelectionProvider';\nexport type {\n SelectableItemProps,\n SelectableItemState,\n SelectionMode,\n SelectionProviderProps,\n SelectionTrigger,\n UseSelectionResult,\n} from './types';\n"]}
@@ -0,0 +1,15 @@
1
+ import type { SelectionMode } from './types';
2
+ export declare function normalizeIds(ids: readonly string[] | undefined, mode: SelectionMode): readonly string[];
3
+ export declare function areIdsEqual(a: readonly string[], b: readonly string[]): boolean;
4
+ export declare function clearIds(): readonly string[];
5
+ export declare function selectId({ mode, ids, id, }: {
6
+ mode: SelectionMode;
7
+ ids: readonly string[];
8
+ id: string;
9
+ }): readonly string[];
10
+ export declare function toggleId({ mode, ids, id, }: {
11
+ mode: SelectionMode;
12
+ ids: readonly string[];
13
+ id: string;
14
+ }): readonly string[];
15
+ //# sourceMappingURL=resolveSelectionNextIds.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveSelectionNextIds.d.ts","sourceRoot":"","sources":["../../../src/patterns/selection/resolveSelectionNextIds.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,wBAAgB,YAAY,CAC1B,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EAClC,IAAI,EAAE,aAAa,GAClB,SAAS,MAAM,EAAE,CAYnB;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,SAAS,MAAM,EAAE,EAAE,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAO/E;AAED,wBAAgB,QAAQ,IAAI,SAAS,MAAM,EAAE,CAE5C;AAED,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,GAAG,EACH,EAAE,GACH,EAAE;IACD,IAAI,EAAE,aAAa,CAAC;IACpB,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;IACvB,EAAE,EAAE,MAAM,CAAC;CACZ,GAAG,SAAS,MAAM,EAAE,CAUpB;AAED,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,GAAG,EACH,EAAE,GACH,EAAE;IACD,IAAI,EAAE,aAAa,CAAC;IACpB,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;IACvB,EAAE,EAAE,MAAM,CAAC;CACZ,GAAG,SAAS,MAAM,EAAE,CAUpB"}
@@ -0,0 +1,44 @@
1
+ export function normalizeIds(ids, mode) {
2
+ const uniqueIds = [];
3
+ const seen = new Set();
4
+ for (const id of ids ?? []) {
5
+ if (seen.has(id))
6
+ continue;
7
+ seen.add(id);
8
+ uniqueIds.push(id);
9
+ if (mode === 'single')
10
+ break;
11
+ }
12
+ return uniqueIds;
13
+ }
14
+ export function areIdsEqual(a, b) {
15
+ if (a.length !== b.length)
16
+ return false;
17
+ for (let index = 0; index < a.length; index += 1) {
18
+ if (a[index] !== b[index])
19
+ return false;
20
+ }
21
+ return true;
22
+ }
23
+ export function clearIds() {
24
+ return [];
25
+ }
26
+ export function selectId({ mode, ids, id, }) {
27
+ if (mode === 'single') {
28
+ return [id];
29
+ }
30
+ if (ids.includes(id)) {
31
+ return ids;
32
+ }
33
+ return [...ids, id];
34
+ }
35
+ export function toggleId({ mode, ids, id, }) {
36
+ if (ids.includes(id)) {
37
+ return ids.filter((existingId) => existingId !== id);
38
+ }
39
+ if (mode === 'single') {
40
+ return [id];
41
+ }
42
+ return [...ids, id];
43
+ }
44
+ //# sourceMappingURL=resolveSelectionNextIds.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveSelectionNextIds.js","sourceRoot":"","sources":["../../../src/patterns/selection/resolveSelectionNextIds.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,YAAY,CAC1B,GAAkC,EAClC,IAAmB;IAEnB,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,KAAK,MAAM,EAAE,IAAI,GAAG,IAAI,EAAE,EAAE,CAAC;QAC3B,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,SAAS;QAC3B,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACb,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnB,IAAI,IAAI,KAAK,QAAQ;YAAE,MAAM;IAC/B,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,CAAoB,EAAE,CAAoB;IACpE,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACxC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACjD,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;IAC1C,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,EACvB,IAAI,EACJ,GAAG,EACH,EAAE,GAKH;IACC,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,OAAO,CAAC,EAAE,CAAC,CAAC;IACd,CAAC;IAED,IAAI,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;QACrB,OAAO,GAAG,CAAC;IACb,CAAC;IAED,OAAO,CAAC,GAAG,GAAG,EAAE,EAAE,CAAC,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,EACvB,IAAI,EACJ,GAAG,EACH,EAAE,GAKH;IACC,IAAI,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;QACrB,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,KAAK,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,OAAO,CAAC,EAAE,CAAC,CAAC;IACd,CAAC;IAED,OAAO,CAAC,GAAG,GAAG,EAAE,EAAE,CAAC,CAAC;AACtB,CAAC","sourcesContent":["import type { SelectionMode } from './types';\n\nexport function normalizeIds(\n ids: readonly string[] | undefined,\n mode: SelectionMode,\n): readonly string[] {\n const uniqueIds: string[] = [];\n const seen = new Set<string>();\n\n for (const id of ids ?? []) {\n if (seen.has(id)) continue;\n seen.add(id);\n uniqueIds.push(id);\n if (mode === 'single') break;\n }\n\n return uniqueIds;\n}\n\nexport function areIdsEqual(a: readonly string[], b: readonly string[]): boolean {\n if (a.length !== b.length) return false;\n for (let index = 0; index < a.length; index += 1) {\n if (a[index] !== b[index]) return false;\n }\n\n return true;\n}\n\nexport function clearIds(): readonly string[] {\n return [];\n}\n\nexport function selectId({\n mode,\n ids,\n id,\n}: {\n mode: SelectionMode;\n ids: readonly string[];\n id: string;\n}): readonly string[] {\n if (mode === 'single') {\n return [id];\n }\n\n if (ids.includes(id)) {\n return ids;\n }\n\n return [...ids, id];\n}\n\nexport function toggleId({\n mode,\n ids,\n id,\n}: {\n mode: SelectionMode;\n ids: readonly string[];\n id: string;\n}): readonly string[] {\n if (ids.includes(id)) {\n return ids.filter((existingId) => existingId !== id);\n }\n\n if (mode === 'single') {\n return [id];\n }\n\n return [...ids, id];\n}\n"]}
@@ -0,0 +1,38 @@
1
+ import type React from 'react';
2
+ export type SelectionMode = 'single' | 'multi';
3
+ export type SelectionTrigger = 'press' | 'longPress' | 'manual';
4
+ export interface SelectionProviderProps {
5
+ children: React.ReactNode;
6
+ selectedIds?: readonly string[];
7
+ defaultSelectedIds?: readonly string[];
8
+ mode?: SelectionMode;
9
+ disabled?: boolean;
10
+ onSelectionChange?: (ids: readonly string[]) => void;
11
+ }
12
+ export interface UseSelectionResult {
13
+ mode: SelectionMode;
14
+ disabled: boolean;
15
+ selectedIds: readonly string[];
16
+ selectedCount: number;
17
+ hasSelection: boolean;
18
+ isSelected: (id: string) => boolean;
19
+ select: (id: string) => void;
20
+ toggle: (id: string) => void;
21
+ clear: () => void;
22
+ }
23
+ export interface SelectableItemState {
24
+ id: string;
25
+ selected: boolean;
26
+ disabled: boolean;
27
+ mode: SelectionMode;
28
+ select: () => void;
29
+ toggle: () => void;
30
+ clear: () => void;
31
+ }
32
+ export interface SelectableItemProps {
33
+ id: string;
34
+ trigger?: SelectionTrigger;
35
+ disabled?: boolean;
36
+ children: React.ReactNode | ((state: SelectableItemState) => React.ReactNode);
37
+ }
38
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/patterns/selection/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE/C,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,WAAW,GAAG,QAAQ,CAAC;AAEhE,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,KAAK,IAAI,CAAC;CACtD;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,aAAa,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;IACpC,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,KAAK,EAAE,mBAAmB,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;CAC/E"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/patterns/selection/types.ts"],"names":[],"mappings":"","sourcesContent":["import type React from 'react';\n\nexport type SelectionMode = 'single' | 'multi';\n\nexport type SelectionTrigger = 'press' | 'longPress' | 'manual';\n\nexport interface SelectionProviderProps {\n children: React.ReactNode;\n selectedIds?: readonly string[];\n defaultSelectedIds?: readonly string[];\n mode?: SelectionMode;\n disabled?: boolean;\n onSelectionChange?: (ids: readonly string[]) => void;\n}\n\nexport interface UseSelectionResult {\n mode: SelectionMode;\n disabled: boolean;\n selectedIds: readonly string[];\n selectedCount: number;\n hasSelection: boolean;\n isSelected: (id: string) => boolean;\n select: (id: string) => void;\n toggle: (id: string) => void;\n clear: () => void;\n}\n\nexport interface SelectableItemState {\n id: string;\n selected: boolean;\n disabled: boolean;\n mode: SelectionMode;\n select: () => void;\n toggle: () => void;\n clear: () => void;\n}\n\nexport interface SelectableItemProps {\n id: string;\n trigger?: SelectionTrigger;\n disabled?: boolean;\n children: React.ReactNode | ((state: SelectableItemState) => React.ReactNode);\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ankhorage/zora",
3
3
  "type": "module",
4
- "version": "1.1.0",
4
+ "version": "1.3.0",
5
5
  "description": "Opinionated React Native and React Native Web UI kit built on @ankhorage/surface.",
6
6
  "homepage": "https://github.com/ankhorage/zora#readme",
7
7
  "bugs": {
@@ -45,7 +45,7 @@
45
45
  "dependencies": {
46
46
  "@ankhorage/color-theory": "^0.0.4",
47
47
  "@ankhorage/contracts": "^1.2.0",
48
- "@ankhorage/surface": "^1.2.0"
48
+ "@ankhorage/surface": "^1.3.0"
49
49
  },
50
50
  "files": [
51
51
  "dist",
@@ -72,25 +72,24 @@
72
72
  "build": "rm -rf dist tsconfig.tsbuildinfo && bun x tsc -p tsconfig.json",
73
73
  "changeset": "changeset",
74
74
  "changeset:status": "changeset status --since=origin/main",
75
- "knip": "knip",
76
- "lint": "eslint . --max-warnings=0",
77
- "lint:fix": "eslint . --fix --max-warnings=0",
78
- "format": "prettier --write .",
79
- "format:check": "prettier --check .",
75
+ "knip": "ankhorage-knip",
76
+ "lint": "ankhorage-eslint . --max-warnings=0",
77
+ "lint:fix": "ankhorage-eslint . --fix --max-warnings=0",
78
+ "format": "ankhorage-prettier --write .",
79
+ "format:check": "ankhorage-prettier --check .",
80
80
  "prepack": "bun run build",
81
81
  "test": "bun test src",
82
82
  "typecheck": "bun x tsc --noEmit -p tsconfig.json",
83
83
  "version-packages": "changeset version"
84
84
  },
85
85
  "devDependencies": {
86
- "@ankhorage/devtools": "^1.0.1",
86
+ "@ankhorage/devtools": "^1.0.5",
87
87
  "@changesets/cli": "^2.31.0",
88
88
  "@expo/vector-icons": "^15.1.1",
89
89
  "@react-native-picker/picker": "^2.11.4",
90
90
  "@types/bun": "^1.3.13",
91
91
  "@types/node": "^25.6.0",
92
92
  "@types/react": "^19.2.14",
93
- "knip": "^5.88.1",
94
93
  "react": "19.1.0",
95
94
  "react-native": "0.81.5",
96
95
  "typescript": "^5.9.3"
@@ -0,0 +1,133 @@
1
+ import { AppBar as SurfaceAppBar } from '@ankhorage/surface';
2
+ import React from 'react';
3
+
4
+ import { Box, Inline, Stack } from '../../foundation';
5
+ import { useZoraTheme } from '../../theme/useZoraTheme';
6
+ import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
7
+ import { Heading } from '../heading';
8
+ import { IconButton } from '../icon-button';
9
+ import { Text } from '../text';
10
+ import type { AppBarMode, AppBarOverflowAction, AppBarProps } from './types';
11
+
12
+ const DEFAULT_CANCEL_ICON = { name: 'close-outline' };
13
+ const DEFAULT_OVERFLOW_ICON = { name: 'ellipsis-vertical' };
14
+
15
+ function resolveMode(mode: AppBarMode | undefined): AppBarMode {
16
+ return mode ?? { type: 'default' };
17
+ }
18
+
19
+ function resolveSelectionLabel({ count, label }: { count?: number; label: string }): string {
20
+ if (count === undefined) {
21
+ return label;
22
+ }
23
+
24
+ return `${label} (${count})`;
25
+ }
26
+
27
+ function resolveOverflowLabel(overflow: AppBarOverflowAction): string {
28
+ return overflow.label ?? 'More options';
29
+ }
30
+
31
+ function resolveCancelLabel(mode: Extract<AppBarMode, { type: 'selection' }>): string {
32
+ return mode.cancelLabel ?? 'Cancel selection';
33
+ }
34
+
35
+ function AppBarInner({
36
+ themeId: _themeId,
37
+ mode: _mode,
38
+ title,
39
+ subtitle,
40
+ leading,
41
+ actions,
42
+ overflow,
43
+ appMode,
44
+ children,
45
+ safeAreaTop = true,
46
+ divider = true,
47
+ testID,
48
+ }: AppBarProps) {
49
+ const { theme } = useZoraTheme();
50
+ const resolvedMode = resolveMode(appMode);
51
+ const isSelectionMode = resolvedMode.type === 'selection';
52
+
53
+ const resolvedLeading =
54
+ leading ??
55
+ (isSelectionMode ? (
56
+ <IconButton
57
+ icon={resolvedMode.cancelIcon ?? DEFAULT_CANCEL_ICON}
58
+ label={resolveCancelLabel(resolvedMode)}
59
+ emphasis="ghost"
60
+ size="m"
61
+ tone="neutral"
62
+ onPress={resolvedMode.onCancel}
63
+ />
64
+ ) : undefined);
65
+
66
+ const overflowButton = overflow?.onPress ? (
67
+ <IconButton
68
+ disabled={overflow.disabled}
69
+ icon={overflow.icon ?? DEFAULT_OVERFLOW_ICON}
70
+ label={resolveOverflowLabel(overflow)}
71
+ emphasis="ghost"
72
+ size="m"
73
+ tone="neutral"
74
+ onPress={overflow.onPress}
75
+ />
76
+ ) : null;
77
+
78
+ const resolvedTrailing =
79
+ actions || overflowButton ? (
80
+ <Inline align="center" gap="s" wrap="nowrap">
81
+ {actions}
82
+ {overflowButton}
83
+ </Inline>
84
+ ) : undefined;
85
+
86
+ const resolvedCenter = (() => {
87
+ if (children !== undefined) {
88
+ return children;
89
+ }
90
+
91
+ if (isSelectionMode) {
92
+ return (
93
+ <Text numberOfLines={1} tone="default" variant="label" weight="semiBold">
94
+ {resolveSelectionLabel(resolvedMode)}
95
+ </Text>
96
+ );
97
+ }
98
+
99
+ if (title == null && subtitle == null) {
100
+ return null;
101
+ }
102
+
103
+ return (
104
+ <Stack gap="xs">
105
+ {title != null ? (
106
+ <Heading ellipsizeMode="tail" level={3} numberOfLines={1} size="h5">
107
+ {title}
108
+ </Heading>
109
+ ) : null}
110
+ {subtitle != null ? (
111
+ <Text ellipsizeMode="tail" numberOfLines={1} tone="muted" variant="bodySmall">
112
+ {subtitle}
113
+ </Text>
114
+ ) : null}
115
+ </Stack>
116
+ );
117
+ })();
118
+
119
+ return (
120
+ <SurfaceAppBar
121
+ bg={isSelectionMode ? theme.semantics.action.primary.softBg : undefined}
122
+ divider={divider}
123
+ leading={resolvedLeading}
124
+ safeAreaTop={safeAreaTop}
125
+ testID={testID}
126
+ trailing={resolvedTrailing}
127
+ >
128
+ {resolvedCenter ? <Box style={{ minWidth: 0 }}>{resolvedCenter}</Box> : null}
129
+ </SurfaceAppBar>
130
+ );
131
+ }
132
+
133
+ export const AppBar = withZoraThemeScope(AppBarInner);
@@ -0,0 +1,2 @@
1
+ export * from './AppBar';
2
+ export * from './types';