panelui-native 0.66.1 → 0.68.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 (129) hide show
  1. package/README.md +21 -1
  2. package/lib/module/components/area-chart/index.js +18 -1
  3. package/lib/module/components/area-chart/index.js.map +1 -1
  4. package/lib/module/components/bar-chart/index.js +18 -1
  5. package/lib/module/components/bar-chart/index.js.map +1 -1
  6. package/lib/module/components/candlestick-chart/index.js +18 -1
  7. package/lib/module/components/candlestick-chart/index.js.map +1 -1
  8. package/lib/module/components/form/index.js +7 -5
  9. package/lib/module/components/form/index.js.map +1 -1
  10. package/lib/module/components/form/typed-form.js +11 -0
  11. package/lib/module/components/form/typed-form.js.map +1 -0
  12. package/lib/module/components/form/use-form.js +4 -0
  13. package/lib/module/components/form/use-form.js.map +1 -1
  14. package/lib/module/components/heatmap-chart/index.js +27 -1
  15. package/lib/module/components/heatmap-chart/index.js.map +1 -1
  16. package/lib/module/components/line-chart/index.js +18 -1
  17. package/lib/module/components/line-chart/index.js.map +1 -1
  18. package/lib/module/components/message-scroller/index.js +172 -10
  19. package/lib/module/components/message-scroller/index.js.map +1 -1
  20. package/lib/module/components/message-scroller/message-scroller-math.js +23 -0
  21. package/lib/module/components/message-scroller/message-scroller-math.js.map +1 -1
  22. package/lib/module/components/meter/index.js +250 -0
  23. package/lib/module/components/meter/index.js.map +1 -0
  24. package/lib/module/components/meter/meter-scale.js +88 -0
  25. package/lib/module/components/meter/meter-scale.js.map +1 -0
  26. package/lib/module/components/planner/index.js +714 -0
  27. package/lib/module/components/planner/index.js.map +1 -0
  28. package/lib/module/components/planner/planner-entries.js +124 -0
  29. package/lib/module/components/planner/planner-entries.js.map +1 -0
  30. package/lib/module/components/radar-chart/index.js +18 -1
  31. package/lib/module/components/radar-chart/index.js.map +1 -1
  32. package/lib/module/components/scatter-chart/index.js +18 -1
  33. package/lib/module/components/scatter-chart/index.js.map +1 -1
  34. package/lib/module/components/skeleton/index.js +45 -7
  35. package/lib/module/components/skeleton/index.js.map +1 -1
  36. package/lib/module/components/spinner/index.js +63 -14
  37. package/lib/module/components/spinner/index.js.map +1 -1
  38. package/lib/module/components/time-picker/index.js +46 -21
  39. package/lib/module/components/time-picker/index.js.map +1 -1
  40. package/lib/module/components/time-picker/ruler-window.js +25 -0
  41. package/lib/module/components/time-picker/ruler-window.js.map +1 -0
  42. package/lib/module/hooks/breakpoint-contract.js +29 -0
  43. package/lib/module/hooks/breakpoint-contract.js.map +1 -0
  44. package/lib/module/hooks/index.js +1 -1
  45. package/lib/module/hooks/index.js.map +1 -1
  46. package/lib/module/hooks/use-breakpoint.js +46 -1
  47. package/lib/module/hooks/use-breakpoint.js.map +1 -1
  48. package/lib/module/index.js +3 -1
  49. package/lib/module/index.js.map +1 -1
  50. package/lib/module/primitives/chart-accessibility.js +68 -0
  51. package/lib/module/primitives/chart-accessibility.js.map +1 -0
  52. package/lib/typescript/src/components/area-chart/index.d.ts +2 -1
  53. package/lib/typescript/src/components/area-chart/index.d.ts.map +1 -1
  54. package/lib/typescript/src/components/bar-chart/index.d.ts +2 -1
  55. package/lib/typescript/src/components/bar-chart/index.d.ts.map +1 -1
  56. package/lib/typescript/src/components/candlestick-chart/index.d.ts +2 -1
  57. package/lib/typescript/src/components/candlestick-chart/index.d.ts.map +1 -1
  58. package/lib/typescript/src/components/form/index.d.ts +18 -5
  59. package/lib/typescript/src/components/form/index.d.ts.map +1 -1
  60. package/lib/typescript/src/components/form/typed-form.d.ts +7 -0
  61. package/lib/typescript/src/components/form/typed-form.d.ts.map +1 -0
  62. package/lib/typescript/src/components/form/use-form.d.ts +4 -0
  63. package/lib/typescript/src/components/form/use-form.d.ts.map +1 -1
  64. package/lib/typescript/src/components/heatmap-chart/index.d.ts +2 -1
  65. package/lib/typescript/src/components/heatmap-chart/index.d.ts.map +1 -1
  66. package/lib/typescript/src/components/line-chart/index.d.ts +2 -1
  67. package/lib/typescript/src/components/line-chart/index.d.ts.map +1 -1
  68. package/lib/typescript/src/components/message-scroller/index.d.ts +30 -2
  69. package/lib/typescript/src/components/message-scroller/index.d.ts.map +1 -1
  70. package/lib/typescript/src/components/message-scroller/message-scroller-math.d.ts +10 -0
  71. package/lib/typescript/src/components/message-scroller/message-scroller-math.d.ts.map +1 -1
  72. package/lib/typescript/src/components/meter/index.d.ts +270 -0
  73. package/lib/typescript/src/components/meter/index.d.ts.map +1 -0
  74. package/lib/typescript/src/components/meter/meter-scale.d.ts +57 -0
  75. package/lib/typescript/src/components/meter/meter-scale.d.ts.map +1 -0
  76. package/lib/typescript/src/components/planner/index.d.ts +274 -0
  77. package/lib/typescript/src/components/planner/index.d.ts.map +1 -0
  78. package/lib/typescript/src/components/planner/planner-entries.d.ts +75 -0
  79. package/lib/typescript/src/components/planner/planner-entries.d.ts.map +1 -0
  80. package/lib/typescript/src/components/radar-chart/index.d.ts +4 -0
  81. package/lib/typescript/src/components/radar-chart/index.d.ts.map +1 -1
  82. package/lib/typescript/src/components/scatter-chart/index.d.ts +2 -1
  83. package/lib/typescript/src/components/scatter-chart/index.d.ts.map +1 -1
  84. package/lib/typescript/src/components/skeleton/index.d.ts +25 -2
  85. package/lib/typescript/src/components/skeleton/index.d.ts.map +1 -1
  86. package/lib/typescript/src/components/spinner/index.d.ts +25 -2
  87. package/lib/typescript/src/components/spinner/index.d.ts.map +1 -1
  88. package/lib/typescript/src/components/time-picker/index.d.ts +5 -6
  89. package/lib/typescript/src/components/time-picker/index.d.ts.map +1 -1
  90. package/lib/typescript/src/components/time-picker/ruler-window.d.ts +12 -0
  91. package/lib/typescript/src/components/time-picker/ruler-window.d.ts.map +1 -0
  92. package/lib/typescript/src/hooks/breakpoint-contract.d.ts +6 -0
  93. package/lib/typescript/src/hooks/breakpoint-contract.d.ts.map +1 -0
  94. package/lib/typescript/src/hooks/index.d.ts +1 -1
  95. package/lib/typescript/src/hooks/index.d.ts.map +1 -1
  96. package/lib/typescript/src/hooks/use-breakpoint.d.ts +22 -0
  97. package/lib/typescript/src/hooks/use-breakpoint.d.ts.map +1 -1
  98. package/lib/typescript/src/index.d.ts +3 -1
  99. package/lib/typescript/src/index.d.ts.map +1 -1
  100. package/lib/typescript/src/primitives/chart-accessibility.d.ts +33 -0
  101. package/lib/typescript/src/primitives/chart-accessibility.d.ts.map +1 -0
  102. package/lib/typescript/types/form-api.type-test.d.ts +2 -0
  103. package/lib/typescript/types/form-api.type-test.d.ts.map +1 -0
  104. package/package.json +28 -2
  105. package/src/components/area-chart/index.tsx +27 -2
  106. package/src/components/bar-chart/index.tsx +27 -2
  107. package/src/components/candlestick-chart/index.tsx +30 -2
  108. package/src/components/form/index.tsx +32 -5
  109. package/src/components/form/typed-form.ts +13 -0
  110. package/src/components/form/use-form.ts +9 -0
  111. package/src/components/heatmap-chart/index.tsx +49 -3
  112. package/src/components/line-chart/index.tsx +27 -2
  113. package/src/components/message-scroller/index.tsx +234 -6
  114. package/src/components/message-scroller/message-scroller-math.ts +38 -0
  115. package/src/components/meter/index.tsx +318 -0
  116. package/src/components/meter/meter-scale.ts +109 -0
  117. package/src/components/planner/index.tsx +886 -0
  118. package/src/components/planner/planner-entries.ts +146 -0
  119. package/src/components/radar-chart/index.tsx +24 -0
  120. package/src/components/scatter-chart/index.tsx +27 -2
  121. package/src/components/skeleton/index.tsx +59 -5
  122. package/src/components/spinner/index.tsx +80 -13
  123. package/src/components/time-picker/index.tsx +57 -29
  124. package/src/components/time-picker/ruler-window.ts +24 -0
  125. package/src/hooks/breakpoint-contract.ts +31 -0
  126. package/src/hooks/index.ts +4 -0
  127. package/src/hooks/use-breakpoint.ts +61 -10
  128. package/src/index.ts +30 -0
  129. package/src/primitives/chart-accessibility.ts +102 -0
@@ -1,7 +1,14 @@
1
+ import { createContext, createElement, useContext, type ReactNode } from 'react';
1
2
  import { useWindowDimensions } from 'react-native';
3
+ import {
4
+ breakpointAt,
5
+ breakpointEntries,
6
+ type BreakpointDefinition,
7
+ } from './breakpoint-contract';
2
8
 
3
9
  /** Tailwind's breakpoints, minus the ones no phone or tablet reaches. */
4
10
  export const BREAKPOINTS = { sm: 640, md: 768, lg: 1024, xl: 1280 } as const;
11
+ const DEFAULT_ENTRIES = breakpointEntries(BREAKPOINTS);
5
12
 
6
13
  export type Breakpoint = keyof typeof BREAKPOINTS;
7
14
 
@@ -15,6 +22,59 @@ export interface UseBreakpointResult {
15
22
  isLandscape: boolean;
16
23
  }
17
24
 
25
+ export interface BreakpointResult<Name extends string> {
26
+ current: Name | 'base';
27
+ isAtLeast: (breakpoint: Name) => boolean;
28
+ width: number;
29
+ height: number;
30
+ isLandscape: boolean;
31
+ }
32
+
33
+ export interface BreakpointProviderProps {
34
+ children?: ReactNode;
35
+ }
36
+
37
+ export interface BreakpointContract<Name extends string> {
38
+ Provider: (props: BreakpointProviderProps) => ReactNode;
39
+ useBreakpoint: () => BreakpointResult<Name>;
40
+ breakpoints: Readonly<Record<Name, number>>;
41
+ }
42
+
43
+ /**
44
+ * Create app-specific responsive names. One Provider owns the window
45
+ * subscription; every bound hook below it reads the same dimensions.
46
+ */
47
+ export function createBreakpoints<const T extends BreakpointDefinition>(
48
+ definition: T
49
+ ): BreakpointContract<keyof T & string> {
50
+ type Name = keyof T & string;
51
+ const breakpoints = Object.freeze({ ...definition }) as Readonly<T>;
52
+ const entries = breakpointEntries(breakpoints);
53
+ const Context = createContext<{ width: number; height: number } | null>(null);
54
+
55
+ function Provider({ children }: BreakpointProviderProps) {
56
+ const dimensions = useWindowDimensions();
57
+ return createElement(Context.Provider, { value: dimensions }, children);
58
+ }
59
+
60
+ function useBoundBreakpoint(): BreakpointResult<Name> {
61
+ const dimensions = useContext(Context);
62
+ if (!dimensions) {
63
+ throw new Error('This breakpoint hook must be used inside its Breakpoint Provider.');
64
+ }
65
+ const { width, height } = dimensions;
66
+ return {
67
+ current: breakpointAt(entries, width),
68
+ isAtLeast: (name) => width >= breakpoints[name]!,
69
+ width,
70
+ height,
71
+ isLandscape: width > height,
72
+ };
73
+ }
74
+
75
+ return { Provider, useBreakpoint: useBoundBreakpoint, breakpoints };
76
+ }
77
+
18
78
  /**
19
79
  * Responsive state from the window size — the React Native answer to a media
20
80
  * query, which has no equivalent here.
@@ -31,16 +91,7 @@ export interface UseBreakpointResult {
31
91
  export function useBreakpoint(): UseBreakpointResult {
32
92
  const { width, height } = useWindowDimensions();
33
93
 
34
- const current: Breakpoint | 'base' =
35
- width >= BREAKPOINTS.xl
36
- ? 'xl'
37
- : width >= BREAKPOINTS.lg
38
- ? 'lg'
39
- : width >= BREAKPOINTS.md
40
- ? 'md'
41
- : width >= BREAKPOINTS.sm
42
- ? 'sm'
43
- : 'base';
94
+ const current = breakpointAt(DEFAULT_ENTRIES, width);
44
95
 
45
96
  return {
46
97
  current,
package/src/index.ts CHANGED
@@ -485,10 +485,14 @@ export {
485
485
  } from './components/field';
486
486
  export {
487
487
  Form,
488
+ createForm,
488
489
  useForm,
489
490
  useField,
490
491
  type FormProps,
491
492
  type FormFieldProps,
493
+ type TypedForm,
494
+ type TypedFormProps,
495
+ type TypedFormFieldProps,
492
496
  type FormApi,
493
497
  type FieldErrors,
494
498
  type FieldTouched,
@@ -742,6 +746,12 @@ export {
742
746
  type MenuItemVariant,
743
747
  type MenuRadioIndicator,
744
748
  } from './components/menu';
749
+ export {
750
+ Meter,
751
+ type MeterProps,
752
+ type MeterColor,
753
+ type MeterThreshold,
754
+ } from './components/meter';
745
755
  export {
746
756
  MessageScroller,
747
757
  useMessageScroller,
@@ -779,6 +789,26 @@ export {
779
789
  type PopoverAnchorRect,
780
790
  type PopoverAnchorControls,
781
791
  } from './components/popover';
792
+ export {
793
+ Planner,
794
+ type PlannerProps,
795
+ type PlannerEntry,
796
+ type PlannerCategory,
797
+ type PlannerHeaderProps,
798
+ type PlannerTitleProps,
799
+ type PlannerTodayProps,
800
+ type PlannerNavProps,
801
+ type PlannerActionProps,
802
+ type PlannerGridProps,
803
+ type PlannerDayProps,
804
+ type PlannerDayState,
805
+ type PlannerDayRenderer,
806
+ type PlannerLegendProps,
807
+ type PlannerSummaryProps,
808
+ type PlannerFooterProps,
809
+ type PlannerDetailsProps,
810
+ type PlannerCountedCategory,
811
+ } from './components/planner';
782
812
  export {
783
813
  Post,
784
814
  type PostProps,
@@ -0,0 +1,102 @@
1
+ import { createElement } from 'react';
2
+
3
+ export interface ChartAccessibilityProps<Datum> {
4
+ /** Spoken summary. Defaults to the chart family and number of data entries. */
5
+ accessibilityLabel?: string;
6
+ /** Additional guidance spoken after the chart summary. */
7
+ accessibilityHint?: string;
8
+ /** Overrides the spoken label for one data entry. */
9
+ accessibilityLabelForDatum?: (datum: Datum, index: number) => string;
10
+ /** Makes each data entry actionable without making the SVG geometry focusable. */
11
+ onAccessibilityDatumPress?: (datum: Datum, index: number) => void;
12
+ }
13
+
14
+ export interface ChartAccessibilityItem<Datum> {
15
+ datum: Datum;
16
+ index: number;
17
+ label: string;
18
+ }
19
+
20
+ function spoken(value: unknown): string | null {
21
+ if (value instanceof Date) return value.toLocaleDateString();
22
+ if (typeof value === 'string' || typeof value === 'number') return String(value);
23
+ return null;
24
+ }
25
+
26
+ /** Pure semantic projection, shared by tests and the native accessibility tree. */
27
+ export function chartAccessibilityModel<Datum>(
28
+ chart: string,
29
+ data: Datum[],
30
+ valueOf: (datum: Datum) => [string, unknown][],
31
+ labelForDatum?: (datum: Datum, index: number) => string
32
+ ): { summary: string; items: ChartAccessibilityItem<Datum>[] } {
33
+ return {
34
+ summary: `${chart}, ${data.length} ${data.length === 1 ? 'data entry' : 'data entries'}`,
35
+ items: data.map((datum, index) => ({
36
+ datum,
37
+ index,
38
+ label:
39
+ labelForDatum?.(datum, index) ??
40
+ valueOf(datum)
41
+ .map(([label, value]) => {
42
+ const text = spoken(value);
43
+ return text === null ? null : `${label}, ${text}`;
44
+ })
45
+ .filter((part): part is string => part !== null)
46
+ .join('. '),
47
+ })),
48
+ };
49
+ }
50
+
51
+ export interface ChartAccessibilityDataProps<Datum>
52
+ extends ChartAccessibilityProps<Datum> {
53
+ chart: string;
54
+ data: Datum[];
55
+ valueOf: (datum: Datum) => [string, unknown][];
56
+ disabled?: boolean;
57
+ }
58
+
59
+ /**
60
+ * A compact semantic sibling to the visual plot. The SVG remains one
61
+ * decorative subtree while screen readers receive one summary and one entry
62
+ * per datum, rather than every path, grid line and marker.
63
+ */
64
+ export function ChartAccessibilityData<Datum>({
65
+ chart,
66
+ data,
67
+ valueOf,
68
+ disabled = false,
69
+ accessibilityLabel,
70
+ accessibilityHint,
71
+ accessibilityLabelForDatum,
72
+ onAccessibilityDatumPress,
73
+ }: ChartAccessibilityDataProps<Datum>) {
74
+ if (disabled) return null;
75
+ // Keep the pure semantic projection importable by Node tests without asking
76
+ // Node to parse React Native's Flow entry point.
77
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
78
+ const { Pressable, View } = require('react-native') as typeof import('react-native');
79
+ const model = chartAccessibilityModel(chart, data, valueOf, accessibilityLabelForDatum);
80
+
81
+ return createElement(
82
+ View,
83
+ { style: { position: 'absolute', left: -10_000, width: 1, height: 1 } },
84
+ createElement(View, {
85
+ accessible: true,
86
+ accessibilityRole: 'image',
87
+ accessibilityLabel: accessibilityLabel ?? model.summary,
88
+ accessibilityHint,
89
+ }),
90
+ ...model.items.map((item) =>
91
+ createElement(Pressable, {
92
+ key: item.index,
93
+ accessible: true,
94
+ accessibilityRole: onAccessibilityDatumPress ? 'button' : 'text',
95
+ accessibilityLabel: item.label,
96
+ onPress: onAccessibilityDatumPress
97
+ ? () => onAccessibilityDatumPress(item.datum, item.index)
98
+ : undefined,
99
+ })
100
+ )
101
+ );
102
+ }