@ankhorage/zora 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - e33b114: feat(zora): redesign AppShell as structural root layout with header/footer/overlay slots
8
+
9
+ ## 0.4.1
10
+
11
+ ### Patch Changes
12
+
13
+ - 37681ac: Update README.md with CheckboxGroup & RadioGroup
14
+
3
15
  ## 0.4.0
4
16
 
5
17
  ### Minor Changes
package/README.md CHANGED
@@ -525,25 +525,47 @@ Picks these Surface `DrawerProps`: `closeOnBackdrop`, `onDismiss`, `position`,
525
525
 
526
526
  ### `AppShell`
527
527
 
528
- Theme-aware application root shell with optional topbar and full-height content
529
- area. Use it as the outer app chrome inside `ZoraProvider`.
528
+ Theme-aware application root shell providing the structural frame for an app.
529
+ It defines the top-level layout slots (`header`, `body`, `footer`, `overlay`)
530
+ and ensures a full-height, flexible container.
531
+
532
+ Use it as the outer layout inside `ZoraProvider`. Combine it with layout
533
+ primitives like `SidebarLayout` or `Page` to structure inner content.
530
534
 
531
535
  ```tsx
532
- <AppShell topbar={<Toolbar position="inline">{actions}</Toolbar>}>
536
+ <AppShell
537
+ header={<Toolbar position="inline">{actions}</Toolbar>}
538
+ footer={<BottomBar />}
539
+ >
533
540
  <Page header={<PageHeader title="Dashboard" />}>{content}</Page>
534
541
  </AppShell>
535
542
  ```
536
543
 
544
+ Example with overlay (e.g. mobile panel or drawer):
545
+
546
+ ```tsx
547
+ <AppShell
548
+ footer={<BottomBar />}
549
+ overlay={isOpen ? <MyDrawer onClose={close} /> : null}
550
+ >
551
+ {content}
552
+ </AppShell>
553
+ ```
554
+
537
555
  <details>
538
556
  <summary>Props</summary>
539
557
 
540
558
  ZORA props:
541
559
 
542
- | Prop | Type | Default | Notes |
543
- | --- | --- | --- | --- |
544
- | `children` | `React.ReactNode` | - | Main app content. |
545
- | `topbar` | `React.ReactNode` | - | Optional top app bar rendered above content. |
546
- | `testID` | `string` | - | Forwarded to the root Surface background container. |
560
+ | Prop | Type | Default | Notes |
561
+ | ----------- | ---------------------- | ------- | ------------------------------------------------------------------------------------ |
562
+ | `children` | `React.ReactNode` | - | Main application content. |
563
+ | `header` | `React.ReactNode` | - | Optional top section (e.g. toolbar or navigation). |
564
+ | `footer` | `React.ReactNode` | - | Optional bottom section (e.g. tab bar or actions). |
565
+ | `overlay` | `React.ReactNode` | - | Optional overlay layer rendered above content (e.g. drawer, modal, floating panels). |
566
+ | `style` | `StyleProp<ViewStyle>` | - | Style applied to the root container. |
567
+ | `bodyStyle` | `StyleProp<ViewStyle>` | - | Style applied to the main content container. |
568
+ | `testID` | `string` | - | Forwarded to the root Surface container. |
547
569
 
548
570
  Inherited props:
549
571
 
@@ -551,6 +573,21 @@ No inherited props. `AppShellProps` is declared directly by ZORA.
551
573
 
552
574
  </details>
553
575
 
576
+ ---
577
+
578
+ ### Design notes
579
+
580
+ - `AppShell` is a **structural primitive**, not a page layout.
581
+
582
+ - It does **not manage sidebars or content splits** — use `SidebarLayout` for that.
583
+
584
+ - It does **not provide theming** — wrap with `ZoraProvider`.
585
+
586
+ - `overlay` is rendered using absolute positioning and should be used for
587
+ drawers, mobile panels, or floating UI.
588
+
589
+ - All inner content must support flexible layouts (`flex: 1`, `minHeight: 0`)
590
+ to behave correctly inside the shell.
554
591
 
555
592
  ### `Page`
556
593
 
@@ -1,4 +1,4 @@
1
1
  import React from 'react';
2
2
  import type { AppShellProps } from './types';
3
- export declare function AppShell({ children, topbar, testID }: AppShellProps): React.JSX.Element;
3
+ export declare function AppShell({ children, header, footer, overlay, style, bodyStyle, testID, }: AppShellProps): React.JSX.Element;
4
4
  //# sourceMappingURL=AppShell.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AppShell.d.ts","sourceRoot":"","sources":["../../../src/layout/app-shell/AppShell.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,wBAAgB,QAAQ,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,aAAa,qBASnE"}
1
+ {"version":3,"file":"AppShell.d.ts","sourceRoot":"","sources":["../../../src/layout/app-shell/AppShell.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,wBAAgB,QAAQ,CAAC,EACvB,QAAQ,EACR,MAAM,EACN,MAAM,EACN,OAAO,EACP,KAAK,EACL,SAAS,EACT,MAAM,GACP,EAAE,aAAa,qBAkBf"}
@@ -1,11 +1,38 @@
1
- import { Box, Stack } from '@ankhorage/surface';
1
+ import { Box } from '@ankhorage/surface';
2
2
  import React from 'react';
3
- export function AppShell({ children, topbar, testID }) {
4
- return (<Box bg="background" flex={1} testID={testID}>
5
- <Stack gap="none">
6
- {topbar ? <Box>{topbar}</Box> : null}
7
- <Box flex={1}>{children}</Box>
8
- </Stack>
3
+ import { StyleSheet, View } from 'react-native';
4
+ export function AppShell({ children, header, footer, overlay, style, bodyStyle, testID, }) {
5
+ return (<Box bg="background" flex={1} style={style} testID={testID}>
6
+ <View style={styles.root}>
7
+ {header ? <View style={styles.slot}>{header}</View> : null}
8
+
9
+ <View style={[styles.body, bodyStyle]}>{children}</View>
10
+
11
+ {footer ? <View style={styles.slot}>{footer}</View> : null}
12
+
13
+ {overlay ? (<View pointerEvents="box-none" style={styles.overlay}>
14
+ {overlay}
15
+ </View>) : null}
16
+ </View>
9
17
  </Box>);
10
18
  }
19
+ const styles = StyleSheet.create({
20
+ root: {
21
+ flex: 1,
22
+ minHeight: 0,
23
+ position: 'relative',
24
+ },
25
+ body: {
26
+ flex: 1,
27
+ minHeight: 0,
28
+ minWidth: 0,
29
+ },
30
+ slot: {
31
+ flexShrink: 0,
32
+ },
33
+ overlay: {
34
+ ...StyleSheet.absoluteFillObject,
35
+ zIndex: 10,
36
+ },
37
+ });
11
38
  //# sourceMappingURL=AppShell.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AppShell.js","sourceRoot":"","sources":["../../../src/layout/app-shell/AppShell.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,MAAM,UAAU,QAAQ,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAiB;IAClE,OAAO,CACL,CAAC,GAAG,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAC3C;MAAA,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CACf;QAAA,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CACpC;QAAA,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,GAAG,CAC/B;MAAA,EAAE,KAAK,CACT;IAAA,EAAE,GAAG,CAAC,CACP,CAAC;AACJ,CAAC","sourcesContent":["import { Box, Stack } from '@ankhorage/surface';\nimport React from 'react';\n\nimport type { AppShellProps } from './types';\n\nexport function AppShell({ children, topbar, testID }: AppShellProps) {\n return (\n <Box bg=\"background\" flex={1} testID={testID}>\n <Stack gap=\"none\">\n {topbar ? <Box>{topbar}</Box> : null}\n <Box flex={1}>{children}</Box>\n </Stack>\n </Box>\n );\n}\n"]}
1
+ {"version":3,"file":"AppShell.js","sourceRoot":"","sources":["../../../src/layout/app-shell/AppShell.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AACzC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAIhD,MAAM,UAAU,QAAQ,CAAC,EACvB,QAAQ,EACR,MAAM,EACN,MAAM,EACN,OAAO,EACP,KAAK,EACL,SAAS,EACT,MAAM,GACQ;IACd,OAAO,CACL,CAAC,GAAG,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CACzD;MAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CACvB;QAAA,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAE1D;;QAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAI,CAEvD;;QAAA,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAE1D;;QAAA,CAAC,OAAO,CAAC,CAAC,CAAC,CACT,CAAC,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CACnD;YAAA,CAAC,OAAO,CACV;UAAA,EAAE,IAAI,CAAC,CACR,CAAC,CAAC,CAAC,IAAI,CACV;MAAA,EAAE,IAAI,CACR;IAAA,EAAE,GAAG,CAAC,CACP,CAAC;AACJ,CAAC;AAED,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;IAC/B,IAAI,EAAE;QACJ,IAAI,EAAE,CAAC;QACP,SAAS,EAAE,CAAC;QACZ,QAAQ,EAAE,UAAU;KACrB;IACD,IAAI,EAAE;QACJ,IAAI,EAAE,CAAC;QACP,SAAS,EAAE,CAAC;QACZ,QAAQ,EAAE,CAAC;KACZ;IACD,IAAI,EAAE;QACJ,UAAU,EAAE,CAAC;KACd;IACD,OAAO,EAAE;QACP,GAAG,UAAU,CAAC,kBAAkB;QAChC,MAAM,EAAE,EAAE;KACX;CACF,CAAC,CAAC","sourcesContent":["import { Box } from '@ankhorage/surface';\nimport React from 'react';\nimport { StyleSheet, View } from 'react-native';\n\nimport type { AppShellProps } from './types';\n\nexport function AppShell({\n children,\n header,\n footer,\n overlay,\n style,\n bodyStyle,\n testID,\n}: AppShellProps) {\n return (\n <Box bg=\"background\" flex={1} style={style} testID={testID}>\n <View style={styles.root}>\n {header ? <View style={styles.slot}>{header}</View> : null}\n\n <View style={[styles.body, bodyStyle]}>{children}</View>\n\n {footer ? <View style={styles.slot}>{footer}</View> : null}\n\n {overlay ? (\n <View pointerEvents=\"box-none\" style={styles.overlay}>\n {overlay}\n </View>\n ) : null}\n </View>\n </Box>\n );\n}\n\nconst styles = StyleSheet.create({\n root: {\n flex: 1,\n minHeight: 0,\n position: 'relative',\n },\n body: {\n flex: 1,\n minHeight: 0,\n minWidth: 0,\n },\n slot: {\n flexShrink: 0,\n },\n overlay: {\n ...StyleSheet.absoluteFillObject,\n zIndex: 10,\n },\n});\n"]}
@@ -1,7 +1,12 @@
1
1
  import type React from 'react';
2
+ import type { StyleProp, ViewStyle } from 'react-native';
2
3
  export interface AppShellProps {
3
4
  children?: React.ReactNode;
4
- topbar?: React.ReactNode;
5
+ header?: React.ReactNode;
6
+ footer?: React.ReactNode;
7
+ overlay?: React.ReactNode;
8
+ style?: StyleProp<ViewStyle>;
9
+ bodyStyle?: StyleProp<ViewStyle>;
5
10
  testID?: string;
6
11
  }
7
12
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/layout/app-shell/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/layout/app-shell/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,SAAS,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/layout/app-shell/types.ts"],"names":[],"mappings":"","sourcesContent":["import type React from 'react';\n\nexport interface AppShellProps {\n children?: React.ReactNode;\n topbar?: React.ReactNode;\n testID?: string;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/layout/app-shell/types.ts"],"names":[],"mappings":"","sourcesContent":["import type React from 'react';\nimport type { StyleProp, ViewStyle } from 'react-native';\n\nexport interface AppShellProps {\n children?: React.ReactNode;\n header?: React.ReactNode;\n footer?: React.ReactNode;\n overlay?: React.ReactNode;\n style?: StyleProp<ViewStyle>;\n bodyStyle?: StyleProp<ViewStyle>;\n testID?: string;\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ankhorage/zora",
3
3
  "type": "module",
4
- "version": "0.4.0",
4
+ "version": "0.5.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": {
@@ -1,15 +1,53 @@
1
- import { Box, Stack } from '@ankhorage/surface';
1
+ import { Box } from '@ankhorage/surface';
2
2
  import React from 'react';
3
+ import { StyleSheet, View } from 'react-native';
3
4
 
4
5
  import type { AppShellProps } from './types';
5
6
 
6
- export function AppShell({ children, topbar, testID }: AppShellProps) {
7
+ export function AppShell({
8
+ children,
9
+ header,
10
+ footer,
11
+ overlay,
12
+ style,
13
+ bodyStyle,
14
+ testID,
15
+ }: AppShellProps) {
7
16
  return (
8
- <Box bg="background" flex={1} testID={testID}>
9
- <Stack gap="none">
10
- {topbar ? <Box>{topbar}</Box> : null}
11
- <Box flex={1}>{children}</Box>
12
- </Stack>
17
+ <Box bg="background" flex={1} style={style} testID={testID}>
18
+ <View style={styles.root}>
19
+ {header ? <View style={styles.slot}>{header}</View> : null}
20
+
21
+ <View style={[styles.body, bodyStyle]}>{children}</View>
22
+
23
+ {footer ? <View style={styles.slot}>{footer}</View> : null}
24
+
25
+ {overlay ? (
26
+ <View pointerEvents="box-none" style={styles.overlay}>
27
+ {overlay}
28
+ </View>
29
+ ) : null}
30
+ </View>
13
31
  </Box>
14
32
  );
15
33
  }
34
+
35
+ const styles = StyleSheet.create({
36
+ root: {
37
+ flex: 1,
38
+ minHeight: 0,
39
+ position: 'relative',
40
+ },
41
+ body: {
42
+ flex: 1,
43
+ minHeight: 0,
44
+ minWidth: 0,
45
+ },
46
+ slot: {
47
+ flexShrink: 0,
48
+ },
49
+ overlay: {
50
+ ...StyleSheet.absoluteFillObject,
51
+ zIndex: 10,
52
+ },
53
+ });
@@ -1,7 +1,12 @@
1
1
  import type React from 'react';
2
+ import type { StyleProp, ViewStyle } from 'react-native';
2
3
 
3
4
  export interface AppShellProps {
4
5
  children?: React.ReactNode;
5
- topbar?: React.ReactNode;
6
+ header?: React.ReactNode;
7
+ footer?: React.ReactNode;
8
+ overlay?: React.ReactNode;
9
+ style?: StyleProp<ViewStyle>;
10
+ bodyStyle?: StyleProp<ViewStyle>;
6
11
  testID?: string;
7
12
  }