@ankhorage/zora 2.5.0 → 2.5.2

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 (56) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +593 -1
  3. package/dist/components/button/Button.d.ts +12 -0
  4. package/dist/components/button/Button.d.ts.map +1 -1
  5. package/dist/components/button/Button.js +12 -0
  6. package/dist/components/button/Button.js.map +1 -1
  7. package/dist/components/card/Card.d.ts +12 -0
  8. package/dist/components/card/Card.d.ts.map +1 -1
  9. package/dist/components/card/Card.js +12 -0
  10. package/dist/components/card/Card.js.map +1 -1
  11. package/dist/components/heading/Heading.d.ts +12 -0
  12. package/dist/components/heading/Heading.d.ts.map +1 -1
  13. package/dist/components/heading/Heading.js +12 -0
  14. package/dist/components/heading/Heading.js.map +1 -1
  15. package/dist/components/input/Input.d.ts +12 -0
  16. package/dist/components/input/Input.d.ts.map +1 -1
  17. package/dist/components/input/Input.js +12 -0
  18. package/dist/components/input/Input.js.map +1 -1
  19. package/dist/components/text/Text.d.ts +12 -0
  20. package/dist/components/text/Text.d.ts.map +1 -1
  21. package/dist/components/text/Text.js +12 -0
  22. package/dist/components/text/Text.js.map +1 -1
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/layout/app-shell/AppShell.d.ts +12 -0
  27. package/dist/layout/app-shell/AppShell.d.ts.map +1 -1
  28. package/dist/layout/app-shell/AppShell.js +12 -0
  29. package/dist/layout/app-shell/AppShell.js.map +1 -1
  30. package/dist/patterns/empty-state/EmptyState.d.ts +12 -0
  31. package/dist/patterns/empty-state/EmptyState.d.ts.map +1 -1
  32. package/dist/patterns/empty-state/EmptyState.js +12 -0
  33. package/dist/patterns/empty-state/EmptyState.js.map +1 -1
  34. package/dist/patterns/responsive-panel/ResponsivePanel.d.ts +12 -0
  35. package/dist/patterns/responsive-panel/ResponsivePanel.d.ts.map +1 -1
  36. package/dist/patterns/responsive-panel/ResponsivePanel.js +72 -7
  37. package/dist/patterns/responsive-panel/ResponsivePanel.js.map +1 -1
  38. package/dist/patterns/responsive-panel/types.d.ts +4 -0
  39. package/dist/patterns/responsive-panel/types.d.ts.map +1 -1
  40. package/dist/patterns/responsive-panel/types.js.map +1 -1
  41. package/dist/theme/ZoraProvider.d.ts +12 -0
  42. package/dist/theme/ZoraProvider.d.ts.map +1 -1
  43. package/dist/theme/ZoraProvider.js +12 -0
  44. package/dist/theme/ZoraProvider.js.map +1 -1
  45. package/package.json +1 -1
  46. package/src/components/button/Button.tsx +12 -0
  47. package/src/components/card/Card.tsx +12 -0
  48. package/src/components/heading/Heading.tsx +12 -0
  49. package/src/components/input/Input.tsx +12 -0
  50. package/src/components/text/Text.tsx +12 -0
  51. package/src/index.ts +2 -0
  52. package/src/layout/app-shell/AppShell.tsx +12 -0
  53. package/src/patterns/empty-state/EmptyState.tsx +12 -0
  54. package/src/patterns/responsive-panel/ResponsivePanel.tsx +90 -6
  55. package/src/patterns/responsive-panel/types.ts +4 -0
  56. package/src/theme/ZoraProvider.tsx +12 -0
@@ -1,4 +1,16 @@
1
1
  import React from 'react';
2
2
  import type { ResponsivePanelProps } from './types';
3
+ /***
4
+ * Adaptive secondary surface that can render as an inline panel, drawer, or modal.
5
+ *
6
+ * Use `ResponsivePanel` for tool panes and admin/detail flows that need the same
7
+ * content to work across compact mobile screens and wider desktop layouts.
8
+ *
9
+ * @readme
10
+ * @example Scrollable wide panel
11
+ * ```tsx
12
+ * <ResponsivePanel open title="APIs" size="wide" scroll="content">...</ResponsivePanel>
13
+ * ```
14
+ */
3
15
  export declare const ResponsivePanel: (props: ResponsivePanelProps) => React.ReactElement | null;
4
16
  //# sourceMappingURL=ResponsivePanel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ResponsivePanel.d.ts","sourceRoot":"","sources":["../../../src/patterns/responsive-panel/ResponsivePanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAoEpD,eAAO,MAAM,eAAe,4DAA2C,CAAC"}
1
+ {"version":3,"file":"ResponsivePanel.d.ts","sourceRoot":"","sources":["../../../src/patterns/responsive-panel/ResponsivePanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAQ1B,OAAO,KAAK,EAAE,oBAAoB,EAA8C,MAAM,SAAS,CAAC;AA0IhG;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,eAAe,4DAA2C,CAAC"}
@@ -1,27 +1,92 @@
1
1
  import React from 'react';
2
+ import { ScrollView, StyleSheet, View } from 'react-native';
2
3
  import { Drawer } from '../../components/drawer';
3
4
  import { Modal } from '../../components/modal';
4
5
  import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
5
6
  import { Panel } from '../panel';
6
- function ResponsivePanelInner({ themeId: _themeId, mode: _mode, title, description, actions, footer, children, open, onOpenChange, side = 'right', desktopMode = 'inline', mobileMode = 'drawer', compact = true, testID, }) {
7
+ function resolvePanelWidth(size) {
8
+ switch (size) {
9
+ case 'compact':
10
+ return 300;
11
+ case 'wide':
12
+ return 420;
13
+ case 'extraWide':
14
+ return 560;
15
+ case 'default':
16
+ default:
17
+ return 360;
18
+ }
19
+ }
20
+ function resolveModalWidth(size) {
21
+ switch (size) {
22
+ case 'compact':
23
+ return 'narrow';
24
+ case 'wide':
25
+ case 'extraWide':
26
+ return 'wide';
27
+ case 'default':
28
+ return 'default';
29
+ default:
30
+ return undefined;
31
+ }
32
+ }
33
+ function renderPanelBody(children, scroll) {
34
+ if (children == null)
35
+ return null;
36
+ if (scroll === 'content') {
37
+ return (<ScrollView contentContainerStyle={styles.scrollContent} keyboardShouldPersistTaps="handled" showsVerticalScrollIndicator style={styles.scrollBody}>
38
+ {children}
39
+ </ScrollView>);
40
+ }
41
+ return children;
42
+ }
43
+ function ResponsivePanelInner({ themeId: _themeId, mode: _mode, title, description, actions, footer, children, open, onOpenChange, side = 'right', desktopMode = 'inline', mobileMode = 'drawer', compact = true, size, scroll = 'none', testID, }) {
7
44
  if (!open)
8
45
  return null;
46
+ const body = renderPanelBody(children, scroll);
9
47
  // For now, we assume desktopMode determines the rendering.
10
48
  // In a real app, this would react to window size.
11
49
  if (desktopMode === 'floating') {
12
50
  if (mobileMode === 'modal') {
13
- return (<Modal description={description} footer={footer} onDismiss={() => onOpenChange(false)} testID={testID} title={title} visible={open}>
14
- {children}
51
+ const modalWidth = resolveModalWidth(size);
52
+ return (<Modal description={description} footer={footer} onDismiss={() => onOpenChange(false)} testID={testID} title={title} visible={open} width={modalWidth}>
53
+ {body}
15
54
  </Modal>);
16
55
  }
17
56
  return (<Drawer description={description} footer={footer} onDismiss={() => onOpenChange(false)} position={side} testID={testID} title={title} visible={open}>
18
- {children}
57
+ {body}
19
58
  </Drawer>);
20
59
  }
21
- // default: inline -> Panel
22
- return (<Panel actions={actions} compact={compact} description={description} footer={footer} testID={testID} title={title}>
23
- {children}
60
+ const panel = (<Panel actions={actions} compact={compact} description={description} footer={footer} testID={testID} title={title}>
61
+ {body}
24
62
  </Panel>);
63
+ if (size === undefined)
64
+ return panel;
65
+ return <View style={[styles.inlineSizedPanel, { width: resolvePanelWidth(size) }]}>{panel}</View>;
25
66
  }
67
+ const styles = StyleSheet.create({
68
+ inlineSizedPanel: {
69
+ maxWidth: '100%',
70
+ },
71
+ scrollBody: {
72
+ flexGrow: 0,
73
+ maxHeight: '100%',
74
+ },
75
+ scrollContent: {
76
+ flexGrow: 1,
77
+ },
78
+ });
79
+ /***
80
+ * Adaptive secondary surface that can render as an inline panel, drawer, or modal.
81
+ *
82
+ * Use `ResponsivePanel` for tool panes and admin/detail flows that need the same
83
+ * content to work across compact mobile screens and wider desktop layouts.
84
+ *
85
+ * @readme
86
+ * @example Scrollable wide panel
87
+ * ```tsx
88
+ * <ResponsivePanel open title="APIs" size="wide" scroll="content">...</ResponsivePanel>
89
+ * ```
90
+ */
26
91
  export const ResponsivePanel = withZoraThemeScope(ResponsivePanelInner);
27
92
  //# sourceMappingURL=ResponsivePanel.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ResponsivePanel.js","sourceRoot":"","sources":["../../../src/patterns/responsive-panel/ResponsivePanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAGjC,SAAS,oBAAoB,CAAC,EAC5B,OAAO,EAAE,QAAQ,EACjB,IAAI,EAAE,KAAK,EACX,KAAK,EACL,WAAW,EACX,OAAO,EACP,MAAM,EACN,QAAQ,EACR,IAAI,EACJ,YAAY,EACZ,IAAI,GAAG,OAAO,EACd,WAAW,GAAG,QAAQ,EACtB,UAAU,GAAG,QAAQ,EACrB,OAAO,GAAG,IAAI,EACd,MAAM,GACe;IACrB,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAEvB,2DAA2D;IAC3D,kDAAkD;IAClD,IAAI,WAAW,KAAK,UAAU,EAAE,CAAC;QAC/B,IAAI,UAAU,KAAK,OAAO,EAAE,CAAC;YAC3B,OAAO,CACL,CAAC,KAAK,CACJ,WAAW,CAAC,CAAC,WAAW,CAAC,CACzB,MAAM,CAAC,CAAC,MAAM,CAAC,CACf,SAAS,CAAC,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CACrC,MAAM,CAAC,CAAC,MAAM,CAAC,CACf,KAAK,CAAC,CAAC,KAAK,CAAC,CACb,OAAO,CAAC,CAAC,IAAI,CAAC,CAEd;UAAA,CAAC,QAAQ,CACX;QAAA,EAAE,KAAK,CAAC,CACT,CAAC;QACJ,CAAC;QAED,OAAO,CACL,CAAC,MAAM,CACL,WAAW,CAAC,CAAC,WAAW,CAAC,CACzB,MAAM,CAAC,CAAC,MAAM,CAAC,CACf,SAAS,CAAC,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CACrC,QAAQ,CAAC,CAAC,IAAI,CAAC,CACf,MAAM,CAAC,CAAC,MAAM,CAAC,CACf,KAAK,CAAC,CAAC,KAAK,CAAC,CACb,OAAO,CAAC,CAAC,IAAI,CAAC,CAEd;QAAA,CAAC,QAAQ,CACX;MAAA,EAAE,MAAM,CAAC,CACV,CAAC;IACJ,CAAC;IAED,2BAA2B;IAC3B,OAAO,CACL,CAAC,KAAK,CACJ,OAAO,CAAC,CAAC,OAAO,CAAC,CACjB,OAAO,CAAC,CAAC,OAAO,CAAC,CACjB,WAAW,CAAC,CAAC,WAAW,CAAC,CACzB,MAAM,CAAC,CAAC,MAAM,CAAC,CACf,MAAM,CAAC,CAAC,MAAM,CAAC,CACf,KAAK,CAAC,CAAC,KAAK,CAAC,CAEb;MAAA,CAAC,QAAQ,CACX;IAAA,EAAE,KAAK,CAAC,CACT,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,kBAAkB,CAAC,oBAAoB,CAAC,CAAC","sourcesContent":["import React from 'react';\n\nimport { Drawer } from '../../components/drawer';\nimport { Modal } from '../../components/modal';\nimport { withZoraThemeScope } from '../../theme/withZoraThemeScope';\nimport { Panel } from '../panel';\nimport type { ResponsivePanelProps } from './types';\n\nfunction ResponsivePanelInner({\n themeId: _themeId,\n mode: _mode,\n title,\n description,\n actions,\n footer,\n children,\n open,\n onOpenChange,\n side = 'right',\n desktopMode = 'inline',\n mobileMode = 'drawer',\n compact = true,\n testID,\n}: ResponsivePanelProps) {\n if (!open) return null;\n\n // For now, we assume desktopMode determines the rendering.\n // In a real app, this would react to window size.\n if (desktopMode === 'floating') {\n if (mobileMode === 'modal') {\n return (\n <Modal\n description={description}\n footer={footer}\n onDismiss={() => onOpenChange(false)}\n testID={testID}\n title={title}\n visible={open}\n >\n {children}\n </Modal>\n );\n }\n\n return (\n <Drawer\n description={description}\n footer={footer}\n onDismiss={() => onOpenChange(false)}\n position={side}\n testID={testID}\n title={title}\n visible={open}\n >\n {children}\n </Drawer>\n );\n }\n\n // default: inline -> Panel\n return (\n <Panel\n actions={actions}\n compact={compact}\n description={description}\n footer={footer}\n testID={testID}\n title={title}\n >\n {children}\n </Panel>\n );\n}\n\nexport const ResponsivePanel = withZoraThemeScope(ResponsivePanelInner);\n"]}
1
+ {"version":3,"file":"ResponsivePanel.js","sourceRoot":"","sources":["../../../src/patterns/responsive-panel/ResponsivePanel.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport { ScrollView, StyleSheet, View } from 'react-native';\n\nimport { Drawer } from '../../components/drawer';\nimport { Modal } from '../../components/modal';\nimport type { ZoraContentWidth } from '../../internal/recipes';\nimport { withZoraThemeScope } from '../../theme/withZoraThemeScope';\nimport { Panel } from '../panel';\nimport type { ResponsivePanelProps, ResponsivePanelScroll, ResponsivePanelSize } from './types';\n\nfunction resolvePanelWidth(size: ResponsivePanelSize): number {\n switch (size) {\n case 'compact':\n return 300;\n case 'wide':\n return 420;\n case 'extraWide':\n return 560;\n case 'default':\n default:\n return 360;\n }\n}\n\nfunction resolveModalWidth(size: ResponsivePanelSize | undefined): ZoraContentWidth | undefined {\n switch (size) {\n case 'compact':\n return 'narrow';\n case 'wide':\n case 'extraWide':\n return 'wide';\n case 'default':\n return 'default';\n default:\n return undefined;\n }\n}\n\nfunction renderPanelBody(children: React.ReactNode, scroll: ResponsivePanelScroll) {\n if (children == null) return null;\n\n if (scroll === 'content') {\n return (\n <ScrollView\n contentContainerStyle={styles.scrollContent}\n keyboardShouldPersistTaps=\"handled\"\n showsVerticalScrollIndicator\n style={styles.scrollBody}\n >\n {children}\n </ScrollView>\n );\n }\n\n return children;\n}\n\nfunction ResponsivePanelInner({\n themeId: _themeId,\n mode: _mode,\n title,\n description,\n actions,\n footer,\n children,\n open,\n onOpenChange,\n side = 'right',\n desktopMode = 'inline',\n mobileMode = 'drawer',\n compact = true,\n size,\n scroll = 'none',\n testID,\n}: ResponsivePanelProps) {\n if (!open) return null;\n\n const body = renderPanelBody(children, scroll);\n\n // For now, we assume desktopMode determines the rendering.\n // In a real app, this would react to window size.\n if (desktopMode === 'floating') {\n if (mobileMode === 'modal') {\n const modalWidth = resolveModalWidth(size);\n\n return (\n <Modal\n description={description}\n footer={footer}\n onDismiss={() => onOpenChange(false)}\n testID={testID}\n title={title}\n visible={open}\n width={modalWidth}\n >\n {body}\n </Modal>\n );\n }\n\n return (\n <Drawer\n description={description}\n footer={footer}\n onDismiss={() => onOpenChange(false)}\n position={side}\n testID={testID}\n title={title}\n visible={open}\n >\n {body}\n </Drawer>\n );\n }\n\n const panel = (\n <Panel\n actions={actions}\n compact={compact}\n description={description}\n footer={footer}\n testID={testID}\n title={title}\n >\n {body}\n </Panel>\n );\n\n if (size === undefined) return panel;\n\n return <View style={[styles.inlineSizedPanel, { width: resolvePanelWidth(size) }]}>{panel}</View>;\n}\n\nconst styles = StyleSheet.create({\n inlineSizedPanel: {\n maxWidth: '100%',\n },\n scrollBody: {\n flexGrow: 0,\n maxHeight: '100%',\n },\n scrollContent: {\n flexGrow: 1,\n },\n});\n\n/***\n * Adaptive secondary surface that can render as an inline panel, drawer, or modal.\n *\n * Use `ResponsivePanel` for tool panes and admin/detail flows that need the same\n * content to work across compact mobile screens and wider desktop layouts.\n *\n * @readme\n * @example Scrollable wide panel\n * ```tsx\n * <ResponsivePanel open title=\"APIs\" size=\"wide\" scroll=\"content\">...</ResponsivePanel>\n * ```\n */\nexport const ResponsivePanel = withZoraThemeScope(ResponsivePanelInner);\n"]}
@@ -3,6 +3,8 @@ import type { ZoraBaseProps } from '../../theme/ZoraBaseProps';
3
3
  export type ResponsivePanelSide = 'left' | 'right';
4
4
  export type ResponsivePanelDesktopMode = 'inline' | 'floating';
5
5
  export type ResponsivePanelMobileMode = 'drawer' | 'modal';
6
+ export type ResponsivePanelSize = 'compact' | 'default' | 'wide' | 'extraWide';
7
+ export type ResponsivePanelScroll = 'none' | 'content';
6
8
  export interface ResponsivePanelProps extends ZoraBaseProps {
7
9
  title?: React.ReactNode;
8
10
  description?: React.ReactNode;
@@ -15,5 +17,7 @@ export interface ResponsivePanelProps extends ZoraBaseProps {
15
17
  desktopMode?: ResponsivePanelDesktopMode;
16
18
  mobileMode?: ResponsivePanelMobileMode;
17
19
  compact?: boolean;
20
+ size?: ResponsivePanelSize;
21
+ scroll?: ResponsivePanelScroll;
18
22
  }
19
23
  //# sourceMappingURL=types.d.ts.map
@@ -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,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
+ {"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;AAC3D,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,WAAW,CAAC;AAC/E,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,SAAS,CAAC;AAEvD,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;IAClB,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAC3B,MAAM,CAAC,EAAE,qBAAqB,CAAC;CAChC"}
@@ -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\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"]}
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';\nexport type ResponsivePanelSize = 'compact' | 'default' | 'wide' | 'extraWide';\nexport type ResponsivePanelScroll = 'none' | 'content';\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 size?: ResponsivePanelSize;\n scroll?: ResponsivePanelScroll;\n}\n"]}
@@ -5,5 +5,17 @@ export interface ZoraProviderProps {
5
5
  theme?: ZoraTheme;
6
6
  initialMode?: ZoraThemeMode;
7
7
  }
8
+ /***
9
+ * Installs the ZORA theme runtime and underlying Surface theme provider.
10
+ *
11
+ * Wrap an app with `ZoraProvider` once near the root so components, patterns,
12
+ * layouts, and theme hooks resolve the same design tokens and color mode.
13
+ *
14
+ * @readme
15
+ * @example App provider
16
+ * ```tsx
17
+ * <ZoraProvider initialMode="light"><App /></ZoraProvider>
18
+ * ```
19
+ */
8
20
  export declare function ZoraProvider({ children, theme, initialMode, }: ZoraProviderProps): React.JSX.Element;
9
21
  //# sourceMappingURL=ZoraProvider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ZoraProvider.d.ts","sourceRoot":"","sources":["../../src/theme/ZoraProvider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAIxD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,WAAW,CAAC,EAAE,aAAa,CAAC;CAC7B;AAED,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,KAAwB,EACxB,WAAqB,GACtB,EAAE,iBAAiB,qBAUnB"}
1
+ {"version":3,"file":"ZoraProvider.d.ts","sourceRoot":"","sources":["../../src/theme/ZoraProvider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAIxD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,WAAW,CAAC,EAAE,aAAa,CAAC;CAC7B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,KAAwB,EACxB,WAAqB,GACtB,EAAE,iBAAiB,qBAUnB"}
@@ -3,6 +3,18 @@ import React from 'react';
3
3
  import { createZoraThemeConfig } from './createZoraThemeConfig';
4
4
  import { zoraDefaultTheme } from './zoraDefaultTheme';
5
5
  import { ZoraThemeRuntimeContext } from './ZoraThemeRuntimeContext';
6
+ /***
7
+ * Installs the ZORA theme runtime and underlying Surface theme provider.
8
+ *
9
+ * Wrap an app with `ZoraProvider` once near the root so components, patterns,
10
+ * layouts, and theme hooks resolve the same design tokens and color mode.
11
+ *
12
+ * @readme
13
+ * @example App provider
14
+ * ```tsx
15
+ * <ZoraProvider initialMode="light"><App /></ZoraProvider>
16
+ * ```
17
+ */
6
18
  export function ZoraProvider({ children, theme = zoraDefaultTheme, initialMode = 'light', }) {
7
19
  const runtimeValue = React.useMemo(() => ({ sourceTheme: theme, themeId: theme.id }), [theme]);
8
20
  return (<ZoraThemeRuntimeContext.Provider value={runtimeValue}>
@@ -1 +1 @@
1
- {"version":3,"file":"ZoraProvider.js","sourceRoot":"","sources":["../../src/theme/ZoraProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAQpE,MAAM,UAAU,YAAY,CAAC,EAC3B,QAAQ,EACR,KAAK,GAAG,gBAAgB,EACxB,WAAW,GAAG,OAAO,GACH;IAClB,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAE/F,OAAO,CACL,CAAC,uBAAuB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CACpD;MAAA,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,WAAW,CAAC,CACnF;QAAA,CAAC,QAAQ,CACX;MAAA,EAAE,aAAa,CACjB;IAAA,EAAE,uBAAuB,CAAC,QAAQ,CAAC,CACpC,CAAC;AACJ,CAAC","sourcesContent":["import { ThemeProvider } from '@ankhorage/surface';\nimport React from 'react';\n\nimport { createZoraThemeConfig } from './createZoraThemeConfig';\nimport type { ZoraTheme, ZoraThemeMode } from './types';\nimport { zoraDefaultTheme } from './zoraDefaultTheme';\nimport { ZoraThemeRuntimeContext } from './ZoraThemeRuntimeContext';\n\nexport interface ZoraProviderProps {\n children: React.ReactNode;\n theme?: ZoraTheme;\n initialMode?: ZoraThemeMode;\n}\n\nexport function ZoraProvider({\n children,\n theme = zoraDefaultTheme,\n initialMode = 'light',\n}: ZoraProviderProps) {\n const runtimeValue = React.useMemo(() => ({ sourceTheme: theme, themeId: theme.id }), [theme]);\n\n return (\n <ZoraThemeRuntimeContext.Provider value={runtimeValue}>\n <ThemeProvider initialConfig={createZoraThemeConfig(theme)} initialMode={initialMode}>\n {children}\n </ThemeProvider>\n </ZoraThemeRuntimeContext.Provider>\n );\n}\n"]}
1
+ {"version":3,"file":"ZoraProvider.js","sourceRoot":"","sources":["../../src/theme/ZoraProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAQpE;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,YAAY,CAAC,EAC3B,QAAQ,EACR,KAAK,GAAG,gBAAgB,EACxB,WAAW,GAAG,OAAO,GACH;IAClB,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAE/F,OAAO,CACL,CAAC,uBAAuB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CACpD;MAAA,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,WAAW,CAAC,CACnF;QAAA,CAAC,QAAQ,CACX;MAAA,EAAE,aAAa,CACjB;IAAA,EAAE,uBAAuB,CAAC,QAAQ,CAAC,CACpC,CAAC;AACJ,CAAC","sourcesContent":["import { ThemeProvider } from '@ankhorage/surface';\nimport React from 'react';\n\nimport { createZoraThemeConfig } from './createZoraThemeConfig';\nimport type { ZoraTheme, ZoraThemeMode } from './types';\nimport { zoraDefaultTheme } from './zoraDefaultTheme';\nimport { ZoraThemeRuntimeContext } from './ZoraThemeRuntimeContext';\n\nexport interface ZoraProviderProps {\n children: React.ReactNode;\n theme?: ZoraTheme;\n initialMode?: ZoraThemeMode;\n}\n\n/***\n * Installs the ZORA theme runtime and underlying Surface theme provider.\n *\n * Wrap an app with `ZoraProvider` once near the root so components, patterns,\n * layouts, and theme hooks resolve the same design tokens and color mode.\n *\n * @readme\n * @example App provider\n * ```tsx\n * <ZoraProvider initialMode=\"light\"><App /></ZoraProvider>\n * ```\n */\nexport function ZoraProvider({\n children,\n theme = zoraDefaultTheme,\n initialMode = 'light',\n}: ZoraProviderProps) {\n const runtimeValue = React.useMemo(() => ({ sourceTheme: theme, themeId: theme.id }), [theme]);\n\n return (\n <ZoraThemeRuntimeContext.Provider value={runtimeValue}>\n <ThemeProvider initialConfig={createZoraThemeConfig(theme)} initialMode={initialMode}>\n {children}\n </ThemeProvider>\n </ZoraThemeRuntimeContext.Provider>\n );\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ankhorage/zora",
3
3
  "type": "module",
4
- "version": "2.5.0",
4
+ "version": "2.5.2",
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": {
@@ -20,4 +20,16 @@ function ButtonInner({
20
20
  );
21
21
  }
22
22
 
23
+ /***
24
+ * Theme-aware action control for primary, secondary, destructive, and neutral actions.
25
+ *
26
+ * Use `Button` for explicit user actions that should follow ZORA's semantic color,
27
+ * variant, and size recipes across React Native and React Native Web.
28
+ *
29
+ * @readme
30
+ * @example Basic action
31
+ * ```tsx
32
+ * <Button color="primary" variant="solid" onPress={save}>Save</Button>
33
+ * ```
34
+ */
23
35
  export const Button = withZoraThemeScope(ButtonInner);
@@ -70,4 +70,16 @@ function CardInner({
70
70
  );
71
71
  }
72
72
 
73
+ /***
74
+ * Structured content container with built-in heading, description, actions, and footer slots.
75
+ *
76
+ * Use `Card` for reusable content blocks that should inherit ZORA spacing,
77
+ * radius, tone, and responsive header layout without hand-assembling primitives.
78
+ *
79
+ * @readme
80
+ * @example Content card
81
+ * ```tsx
82
+ * <Card title="Project" description="Latest activity">...</Card>
83
+ * ```
84
+ */
73
85
  export const Card = withZoraThemeScope(CardInner);
@@ -91,4 +91,16 @@ function HeadingInner({
91
91
  );
92
92
  }
93
93
 
94
+ /***
95
+ * Structured title primitive for accessible page, section, and card headings.
96
+ *
97
+ * `Heading` gives consumers a ZORA-owned title API with semantic levels,
98
+ * responsive sizes, and theme-aware emphasis while preserving header semantics.
99
+ *
100
+ * @readme
101
+ * @example Section title
102
+ * ```tsx
103
+ * <Heading level={2} size="xl">Account settings</Heading>
104
+ * ```
105
+ */
94
106
  export const Heading = withZoraThemeScope(HeadingInner);
@@ -62,4 +62,16 @@ function InputInner({
62
62
  );
63
63
  }
64
64
 
65
+ /***
66
+ * Theme-aware text input with semantic sizing and optional leading/trailing icon slots.
67
+ *
68
+ * Use `Input` for single-line form controls that need ZORA styling, disabled/read-only
69
+ * handling, and accessible trailing actions without dropping into Surface directly.
70
+ *
71
+ * @readme
72
+ * @example Search input
73
+ * ```tsx
74
+ * <Input placeholder="Search" leadingIcon={{ name: 'search-outline' }} />
75
+ * ```
76
+ */
65
77
  export const Input = withZoraThemeScope(InputInner);
@@ -88,4 +88,16 @@ function TextInner({
88
88
  );
89
89
  }
90
90
 
91
+ /***
92
+ * Structured copy primitive for theme-aware app text.
93
+ *
94
+ * `Text` owns normal body, caption, label, code, and supporting-copy variants so
95
+ * consumers do not need to import lower-level Surface typography directly.
96
+ *
97
+ * @readme
98
+ * @example Muted supporting copy
99
+ * ```tsx
100
+ * <Text variant="bodySmall" emphasis="muted">Updated just now</Text>
101
+ * ```
102
+ */
91
103
  export const Text = withZoraThemeScope(TextInner);
package/src/index.ts CHANGED
@@ -288,7 +288,9 @@ export type {
288
288
  ResponsivePanelDesktopMode,
289
289
  ResponsivePanelMobileMode,
290
290
  ResponsivePanelProps,
291
+ ResponsivePanelScroll,
291
292
  ResponsivePanelSide,
293
+ ResponsivePanelSize,
292
294
  } from './patterns/responsive-panel';
293
295
  export { ResponsivePanel } from './patterns/responsive-panel';
294
296
  export type { SectionHeaderProps } from './patterns/section-header';
@@ -33,6 +33,18 @@ function AppShellInner({
33
33
  );
34
34
  }
35
35
 
36
+ /***
37
+ * Root application shell with stable header, content, footer, and overlay slots.
38
+ *
39
+ * `AppShell` provides the top-level layout frame for cross-platform apps while
40
+ * leaving navigation, toolbars, and overlays composable through explicit slots.
41
+ *
42
+ * @readme
43
+ * @example App frame
44
+ * ```tsx
45
+ * <AppShell header={<AppBar title="Dashboard" />}>...</AppShell>
46
+ * ```
47
+ */
36
48
  export const AppShell = withZoraThemeScope(AppShellInner);
37
49
 
38
50
  const styles = StyleSheet.create({
@@ -55,4 +55,16 @@ function EmptyStateInner({
55
55
  );
56
56
  }
57
57
 
58
+ /***
59
+ * Reusable fallback state for empty lists, missing data, or first-run experiences.
60
+ *
61
+ * `EmptyState` combines concise copy with optional primary and secondary actions
62
+ * so apps can guide users without custom card and button wiring.
63
+ *
64
+ * @readme
65
+ * @example Empty project list
66
+ * ```tsx
67
+ * <EmptyState title="No projects yet" primaryAction={{ label: 'Create project', onPress }} />
68
+ * ```
69
+ */
58
70
  export const EmptyState = withZoraThemeScope(EmptyStateInner);
@@ -1,10 +1,59 @@
1
1
  import React from 'react';
2
+ import { ScrollView, StyleSheet, View } from 'react-native';
2
3
 
3
4
  import { Drawer } from '../../components/drawer';
4
5
  import { Modal } from '../../components/modal';
6
+ import type { ZoraContentWidth } from '../../internal/recipes';
5
7
  import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
6
8
  import { Panel } from '../panel';
7
- import type { ResponsivePanelProps } from './types';
9
+ import type { ResponsivePanelProps, ResponsivePanelScroll, ResponsivePanelSize } from './types';
10
+
11
+ function resolvePanelWidth(size: ResponsivePanelSize): number {
12
+ switch (size) {
13
+ case 'compact':
14
+ return 300;
15
+ case 'wide':
16
+ return 420;
17
+ case 'extraWide':
18
+ return 560;
19
+ case 'default':
20
+ default:
21
+ return 360;
22
+ }
23
+ }
24
+
25
+ function resolveModalWidth(size: ResponsivePanelSize | undefined): ZoraContentWidth | undefined {
26
+ switch (size) {
27
+ case 'compact':
28
+ return 'narrow';
29
+ case 'wide':
30
+ case 'extraWide':
31
+ return 'wide';
32
+ case 'default':
33
+ return 'default';
34
+ default:
35
+ return undefined;
36
+ }
37
+ }
38
+
39
+ function renderPanelBody(children: React.ReactNode, scroll: ResponsivePanelScroll) {
40
+ if (children == null) return null;
41
+
42
+ if (scroll === 'content') {
43
+ return (
44
+ <ScrollView
45
+ contentContainerStyle={styles.scrollContent}
46
+ keyboardShouldPersistTaps="handled"
47
+ showsVerticalScrollIndicator
48
+ style={styles.scrollBody}
49
+ >
50
+ {children}
51
+ </ScrollView>
52
+ );
53
+ }
54
+
55
+ return children;
56
+ }
8
57
 
9
58
  function ResponsivePanelInner({
10
59
  themeId: _themeId,
@@ -20,14 +69,20 @@ function ResponsivePanelInner({
20
69
  desktopMode = 'inline',
21
70
  mobileMode = 'drawer',
22
71
  compact = true,
72
+ size,
73
+ scroll = 'none',
23
74
  testID,
24
75
  }: ResponsivePanelProps) {
25
76
  if (!open) return null;
26
77
 
78
+ const body = renderPanelBody(children, scroll);
79
+
27
80
  // For now, we assume desktopMode determines the rendering.
28
81
  // In a real app, this would react to window size.
29
82
  if (desktopMode === 'floating') {
30
83
  if (mobileMode === 'modal') {
84
+ const modalWidth = resolveModalWidth(size);
85
+
31
86
  return (
32
87
  <Modal
33
88
  description={description}
@@ -36,8 +91,9 @@ function ResponsivePanelInner({
36
91
  testID={testID}
37
92
  title={title}
38
93
  visible={open}
94
+ width={modalWidth}
39
95
  >
40
- {children}
96
+ {body}
41
97
  </Modal>
42
98
  );
43
99
  }
@@ -52,13 +108,12 @@ function ResponsivePanelInner({
52
108
  title={title}
53
109
  visible={open}
54
110
  >
55
- {children}
111
+ {body}
56
112
  </Drawer>
57
113
  );
58
114
  }
59
115
 
60
- // default: inline -> Panel
61
- return (
116
+ const panel = (
62
117
  <Panel
63
118
  actions={actions}
64
119
  compact={compact}
@@ -67,9 +122,38 @@ function ResponsivePanelInner({
67
122
  testID={testID}
68
123
  title={title}
69
124
  >
70
- {children}
125
+ {body}
71
126
  </Panel>
72
127
  );
128
+
129
+ if (size === undefined) return panel;
130
+
131
+ return <View style={[styles.inlineSizedPanel, { width: resolvePanelWidth(size) }]}>{panel}</View>;
73
132
  }
74
133
 
134
+ const styles = StyleSheet.create({
135
+ inlineSizedPanel: {
136
+ maxWidth: '100%',
137
+ },
138
+ scrollBody: {
139
+ flexGrow: 0,
140
+ maxHeight: '100%',
141
+ },
142
+ scrollContent: {
143
+ flexGrow: 1,
144
+ },
145
+ });
146
+
147
+ /***
148
+ * Adaptive secondary surface that can render as an inline panel, drawer, or modal.
149
+ *
150
+ * Use `ResponsivePanel` for tool panes and admin/detail flows that need the same
151
+ * content to work across compact mobile screens and wider desktop layouts.
152
+ *
153
+ * @readme
154
+ * @example Scrollable wide panel
155
+ * ```tsx
156
+ * <ResponsivePanel open title="APIs" size="wide" scroll="content">...</ResponsivePanel>
157
+ * ```
158
+ */
75
159
  export const ResponsivePanel = withZoraThemeScope(ResponsivePanelInner);
@@ -5,6 +5,8 @@ import type { ZoraBaseProps } from '../../theme/ZoraBaseProps';
5
5
  export type ResponsivePanelSide = 'left' | 'right';
6
6
  export type ResponsivePanelDesktopMode = 'inline' | 'floating';
7
7
  export type ResponsivePanelMobileMode = 'drawer' | 'modal';
8
+ export type ResponsivePanelSize = 'compact' | 'default' | 'wide' | 'extraWide';
9
+ export type ResponsivePanelScroll = 'none' | 'content';
8
10
 
9
11
  export interface ResponsivePanelProps extends ZoraBaseProps {
10
12
  title?: React.ReactNode;
@@ -18,4 +20,6 @@ export interface ResponsivePanelProps extends ZoraBaseProps {
18
20
  desktopMode?: ResponsivePanelDesktopMode;
19
21
  mobileMode?: ResponsivePanelMobileMode;
20
22
  compact?: boolean;
23
+ size?: ResponsivePanelSize;
24
+ scroll?: ResponsivePanelScroll;
21
25
  }
@@ -12,6 +12,18 @@ export interface ZoraProviderProps {
12
12
  initialMode?: ZoraThemeMode;
13
13
  }
14
14
 
15
+ /***
16
+ * Installs the ZORA theme runtime and underlying Surface theme provider.
17
+ *
18
+ * Wrap an app with `ZoraProvider` once near the root so components, patterns,
19
+ * layouts, and theme hooks resolve the same design tokens and color mode.
20
+ *
21
+ * @readme
22
+ * @example App provider
23
+ * ```tsx
24
+ * <ZoraProvider initialMode="light"><App /></ZoraProvider>
25
+ * ```
26
+ */
15
27
  export function ZoraProvider({
16
28
  children,
17
29
  theme = zoraDefaultTheme,