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.
- package/README.md +21 -1
- package/lib/module/components/area-chart/index.js +18 -1
- package/lib/module/components/area-chart/index.js.map +1 -1
- package/lib/module/components/bar-chart/index.js +18 -1
- package/lib/module/components/bar-chart/index.js.map +1 -1
- package/lib/module/components/candlestick-chart/index.js +18 -1
- package/lib/module/components/candlestick-chart/index.js.map +1 -1
- package/lib/module/components/form/index.js +7 -5
- package/lib/module/components/form/index.js.map +1 -1
- package/lib/module/components/form/typed-form.js +11 -0
- package/lib/module/components/form/typed-form.js.map +1 -0
- package/lib/module/components/form/use-form.js +4 -0
- package/lib/module/components/form/use-form.js.map +1 -1
- package/lib/module/components/heatmap-chart/index.js +27 -1
- package/lib/module/components/heatmap-chart/index.js.map +1 -1
- package/lib/module/components/line-chart/index.js +18 -1
- package/lib/module/components/line-chart/index.js.map +1 -1
- package/lib/module/components/message-scroller/index.js +172 -10
- package/lib/module/components/message-scroller/index.js.map +1 -1
- package/lib/module/components/message-scroller/message-scroller-math.js +23 -0
- package/lib/module/components/message-scroller/message-scroller-math.js.map +1 -1
- package/lib/module/components/meter/index.js +250 -0
- package/lib/module/components/meter/index.js.map +1 -0
- package/lib/module/components/meter/meter-scale.js +88 -0
- package/lib/module/components/meter/meter-scale.js.map +1 -0
- package/lib/module/components/planner/index.js +714 -0
- package/lib/module/components/planner/index.js.map +1 -0
- package/lib/module/components/planner/planner-entries.js +124 -0
- package/lib/module/components/planner/planner-entries.js.map +1 -0
- package/lib/module/components/radar-chart/index.js +18 -1
- package/lib/module/components/radar-chart/index.js.map +1 -1
- package/lib/module/components/scatter-chart/index.js +18 -1
- package/lib/module/components/scatter-chart/index.js.map +1 -1
- package/lib/module/components/skeleton/index.js +45 -7
- package/lib/module/components/skeleton/index.js.map +1 -1
- package/lib/module/components/spinner/index.js +63 -14
- package/lib/module/components/spinner/index.js.map +1 -1
- package/lib/module/components/time-picker/index.js +46 -21
- package/lib/module/components/time-picker/index.js.map +1 -1
- package/lib/module/components/time-picker/ruler-window.js +25 -0
- package/lib/module/components/time-picker/ruler-window.js.map +1 -0
- package/lib/module/hooks/breakpoint-contract.js +29 -0
- package/lib/module/hooks/breakpoint-contract.js.map +1 -0
- package/lib/module/hooks/index.js +1 -1
- package/lib/module/hooks/index.js.map +1 -1
- package/lib/module/hooks/use-breakpoint.js +46 -1
- package/lib/module/hooks/use-breakpoint.js.map +1 -1
- package/lib/module/index.js +3 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/primitives/chart-accessibility.js +68 -0
- package/lib/module/primitives/chart-accessibility.js.map +1 -0
- package/lib/typescript/src/components/area-chart/index.d.ts +2 -1
- package/lib/typescript/src/components/area-chart/index.d.ts.map +1 -1
- package/lib/typescript/src/components/bar-chart/index.d.ts +2 -1
- package/lib/typescript/src/components/bar-chart/index.d.ts.map +1 -1
- package/lib/typescript/src/components/candlestick-chart/index.d.ts +2 -1
- package/lib/typescript/src/components/candlestick-chart/index.d.ts.map +1 -1
- package/lib/typescript/src/components/form/index.d.ts +18 -5
- package/lib/typescript/src/components/form/index.d.ts.map +1 -1
- package/lib/typescript/src/components/form/typed-form.d.ts +7 -0
- package/lib/typescript/src/components/form/typed-form.d.ts.map +1 -0
- package/lib/typescript/src/components/form/use-form.d.ts +4 -0
- package/lib/typescript/src/components/form/use-form.d.ts.map +1 -1
- package/lib/typescript/src/components/heatmap-chart/index.d.ts +2 -1
- package/lib/typescript/src/components/heatmap-chart/index.d.ts.map +1 -1
- package/lib/typescript/src/components/line-chart/index.d.ts +2 -1
- package/lib/typescript/src/components/line-chart/index.d.ts.map +1 -1
- package/lib/typescript/src/components/message-scroller/index.d.ts +30 -2
- package/lib/typescript/src/components/message-scroller/index.d.ts.map +1 -1
- package/lib/typescript/src/components/message-scroller/message-scroller-math.d.ts +10 -0
- package/lib/typescript/src/components/message-scroller/message-scroller-math.d.ts.map +1 -1
- package/lib/typescript/src/components/meter/index.d.ts +270 -0
- package/lib/typescript/src/components/meter/index.d.ts.map +1 -0
- package/lib/typescript/src/components/meter/meter-scale.d.ts +57 -0
- package/lib/typescript/src/components/meter/meter-scale.d.ts.map +1 -0
- package/lib/typescript/src/components/planner/index.d.ts +274 -0
- package/lib/typescript/src/components/planner/index.d.ts.map +1 -0
- package/lib/typescript/src/components/planner/planner-entries.d.ts +75 -0
- package/lib/typescript/src/components/planner/planner-entries.d.ts.map +1 -0
- package/lib/typescript/src/components/radar-chart/index.d.ts +4 -0
- package/lib/typescript/src/components/radar-chart/index.d.ts.map +1 -1
- package/lib/typescript/src/components/scatter-chart/index.d.ts +2 -1
- package/lib/typescript/src/components/scatter-chart/index.d.ts.map +1 -1
- package/lib/typescript/src/components/skeleton/index.d.ts +25 -2
- package/lib/typescript/src/components/skeleton/index.d.ts.map +1 -1
- package/lib/typescript/src/components/spinner/index.d.ts +25 -2
- package/lib/typescript/src/components/spinner/index.d.ts.map +1 -1
- package/lib/typescript/src/components/time-picker/index.d.ts +5 -6
- package/lib/typescript/src/components/time-picker/index.d.ts.map +1 -1
- package/lib/typescript/src/components/time-picker/ruler-window.d.ts +12 -0
- package/lib/typescript/src/components/time-picker/ruler-window.d.ts.map +1 -0
- package/lib/typescript/src/hooks/breakpoint-contract.d.ts +6 -0
- package/lib/typescript/src/hooks/breakpoint-contract.d.ts.map +1 -0
- package/lib/typescript/src/hooks/index.d.ts +1 -1
- package/lib/typescript/src/hooks/index.d.ts.map +1 -1
- package/lib/typescript/src/hooks/use-breakpoint.d.ts +22 -0
- package/lib/typescript/src/hooks/use-breakpoint.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +3 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/primitives/chart-accessibility.d.ts +33 -0
- package/lib/typescript/src/primitives/chart-accessibility.d.ts.map +1 -0
- package/lib/typescript/types/form-api.type-test.d.ts +2 -0
- package/lib/typescript/types/form-api.type-test.d.ts.map +1 -0
- package/package.json +28 -2
- package/src/components/area-chart/index.tsx +27 -2
- package/src/components/bar-chart/index.tsx +27 -2
- package/src/components/candlestick-chart/index.tsx +30 -2
- package/src/components/form/index.tsx +32 -5
- package/src/components/form/typed-form.ts +13 -0
- package/src/components/form/use-form.ts +9 -0
- package/src/components/heatmap-chart/index.tsx +49 -3
- package/src/components/line-chart/index.tsx +27 -2
- package/src/components/message-scroller/index.tsx +234 -6
- package/src/components/message-scroller/message-scroller-math.ts +38 -0
- package/src/components/meter/index.tsx +318 -0
- package/src/components/meter/meter-scale.ts +109 -0
- package/src/components/planner/index.tsx +886 -0
- package/src/components/planner/planner-entries.ts +146 -0
- package/src/components/radar-chart/index.tsx +24 -0
- package/src/components/scatter-chart/index.tsx +27 -2
- package/src/components/skeleton/index.tsx +59 -5
- package/src/components/spinner/index.tsx +80 -13
- package/src/components/time-picker/index.tsx +57 -29
- package/src/components/time-picker/ruler-window.ts +24 -0
- package/src/hooks/breakpoint-contract.ts +31 -0
- package/src/hooks/index.ts +4 -0
- package/src/hooks/use-breakpoint.ts +61 -10
- package/src/index.ts +30 -0
- 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
|
|
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
|
+
}
|