@pallasoft/ps-mobile-components 1.6.0 → 1.8.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 (121) hide show
  1. package/dist/components/ps-accessibility-gate/index.d.ts +2 -0
  2. package/dist/components/ps-accessibility-gate/index.js +2 -0
  3. package/dist/components/ps-accessibility-gate/ps-accessibility-gate-props.d.ts +5 -0
  4. package/dist/components/ps-accessibility-gate/ps-accessibility-gate-props.js +1 -0
  5. package/dist/components/ps-accessibility-gate/ps-accessibility-gate.d.ts +2 -0
  6. package/dist/components/ps-accessibility-gate/ps-accessibility-gate.js +4 -0
  7. package/dist/components/ps-app-lock-screen/ps-app-lock-screen.js +1 -1
  8. package/dist/components/ps-cartesian-chart/ps-cartesian-chart.d.ts +1 -1
  9. package/dist/components/ps-cartesian-chart/ps-cartesian-chart.js +25 -17
  10. package/dist/components/ps-chart-empty-state/ps-chart-empty-state.js +5 -1
  11. package/dist/components/ps-chart-frame/ps-chart-frame.js +10 -1
  12. package/dist/components/ps-chart-legend/ps-chart-legend.js +11 -2
  13. package/dist/components/ps-chart-readout/ps-chart-readout-props.d.ts +1 -0
  14. package/dist/components/ps-chart-readout/ps-chart-readout.d.ts +1 -1
  15. package/dist/components/ps-chart-readout/ps-chart-readout.js +8 -2
  16. package/dist/components/ps-chart-skeleton/ps-chart-skeleton.d.ts +1 -1
  17. package/dist/components/ps-chart-skeleton/ps-chart-skeleton.js +5 -1
  18. package/dist/components/ps-donut-chart/ps-donut-chart.js +23 -5
  19. package/dist/components/ps-kpi-card/ps-kpi-card.js +4 -1
  20. package/dist/components/ps-list/ps-list-select-row.js +8 -4
  21. package/dist/components/ps-menu-popup/ps-menu-popup-divider.js +8 -2
  22. package/dist/components/ps-menu-popup/ps-menu-popup-row.js +21 -9
  23. package/dist/components/ps-menu-popup/ps-menu-popup.js +28 -17
  24. package/dist/components/ps-privacy-cover/ps-privacy-cover-props.d.ts +1 -0
  25. package/dist/components/ps-privacy-cover/ps-privacy-cover.d.ts +1 -1
  26. package/dist/components/ps-privacy-cover/ps-privacy-cover.js +12 -3
  27. package/dist/components/ps-sortable-grid/ps-sortable-grid.js +8 -4
  28. package/dist/components/ps-sortable-grid/ps-sortable-item-props.d.ts +1 -0
  29. package/dist/components/ps-sortable-grid/ps-sortable-item.d.ts +1 -1
  30. package/dist/components/ps-sortable-grid/ps-sortable-item.js +3 -2
  31. package/dist/components/ps-sparkline/ps-sparkline.d.ts +1 -1
  32. package/dist/components/ps-sparkline/ps-sparkline.js +3 -1
  33. package/dist/components/ps-waterfall-chart/ps-waterfall-chart.d.ts +1 -1
  34. package/dist/components/ps-waterfall-chart/ps-waterfall-chart.js +15 -9
  35. package/dist/constants/ps-accessibility-config.d.ts +5 -0
  36. package/dist/constants/ps-accessibility-config.js +5 -0
  37. package/dist/constants/ps-chart-config.d.ts +26 -1
  38. package/dist/constants/ps-chart-config.js +26 -1
  39. package/dist/constants/ps-material-menu-config.d.ts +12 -0
  40. package/dist/constants/ps-material-menu-config.js +12 -0
  41. package/dist/constants/ps-scan-format.d.ts +4 -0
  42. package/dist/constants/ps-scan-format.js +5 -0
  43. package/dist/constants/ps-scan-output-config.d.ts +17 -0
  44. package/dist/constants/ps-scan-output-config.js +23 -0
  45. package/dist/constants/ps-screen-capture-config.d.ts +4 -0
  46. package/dist/constants/ps-screen-capture-config.js +4 -0
  47. package/dist/contexts/ps-widget-fill-context.d.ts +1 -0
  48. package/dist/contexts/ps-widget-fill-context.js +2 -0
  49. package/dist/hooks/use-ps-document-scanner.js +3 -2
  50. package/dist/hooks/use-ps-menu-popup-reveal.d.ts +3 -0
  51. package/dist/hooks/use-ps-menu-popup-reveal.js +28 -0
  52. package/dist/hooks/use-ps-screen-capture-prevention.d.ts +2 -0
  53. package/dist/hooks/use-ps-screen-capture-prevention.js +12 -0
  54. package/dist/hooks/use-ps-widget-fill.d.ts +1 -0
  55. package/dist/hooks/use-ps-widget-fill.js +3 -0
  56. package/dist/index.d.ts +6 -0
  57. package/dist/index.js +6 -0
  58. package/dist/interfaces/ps-capture-options.d.ts +2 -0
  59. package/dist/interfaces/ps-chart-bar-group.d.ts +4 -0
  60. package/dist/interfaces/ps-chart-bar-group.js +1 -0
  61. package/dist/interfaces/ps-chart-x-labels.d.ts +4 -0
  62. package/dist/interfaces/ps-chart-x-labels.js +1 -0
  63. package/dist/interfaces/ps-document-scanner-options.d.ts +2 -0
  64. package/dist/interfaces/ps-donut-chart-layout.d.ts +4 -0
  65. package/dist/interfaces/ps-donut-chart-layout.js +1 -0
  66. package/dist/interfaces/ps-image-manipulator-native.d.ts +19 -0
  67. package/dist/interfaces/ps-image-manipulator-native.js +1 -0
  68. package/dist/interfaces/ps-menu-popup-container-style.d.ts +8 -0
  69. package/dist/interfaces/ps-menu-popup-container-style.js +1 -0
  70. package/dist/interfaces/ps-menu-popup-divider-style.d.ts +4 -0
  71. package/dist/interfaces/ps-menu-popup-divider-style.js +1 -0
  72. package/dist/interfaces/ps-menu-popup-layout.d.ts +1 -0
  73. package/dist/interfaces/ps-menu-popup-row-style.d.ts +6 -0
  74. package/dist/interfaces/ps-menu-popup-row-style.js +1 -0
  75. package/dist/interfaces/ps-menu-popup-size.d.ts +4 -0
  76. package/dist/interfaces/ps-menu-popup-size.js +1 -0
  77. package/dist/interfaces/ps-page-size.d.ts +4 -0
  78. package/dist/interfaces/ps-page-size.js +1 -0
  79. package/dist/interfaces/ps-pdf-page.d.ts +5 -0
  80. package/dist/interfaces/ps-pdf-page.js +1 -0
  81. package/dist/interfaces/ps-scan-format-labels.d.ts +7 -0
  82. package/dist/interfaces/ps-scan-format-labels.js +1 -0
  83. package/dist/interfaces/ps-screen-capture-native.d.ts +4 -0
  84. package/dist/interfaces/ps-screen-capture-native.js +1 -0
  85. package/dist/interfaces/use-ps-screen-capture-prevention-options.d.ts +3 -0
  86. package/dist/interfaces/use-ps-screen-capture-prevention-options.js +1 -0
  87. package/dist/services/ps-capture-picker-service.js +1 -0
  88. package/dist/services/ps-chart-axis-service.d.ts +5 -0
  89. package/dist/services/ps-chart-axis-service.js +32 -0
  90. package/dist/services/ps-chart-bar-service.d.ts +2 -0
  91. package/dist/services/ps-chart-bar-service.js +11 -4
  92. package/dist/services/ps-chart-donut-service.d.ts +3 -0
  93. package/dist/services/ps-chart-donut-service.js +11 -0
  94. package/dist/services/ps-chart-readout-service.d.ts +3 -0
  95. package/dist/services/ps-chart-readout-service.js +25 -0
  96. package/dist/services/ps-chart-scale-service.d.ts +1 -1
  97. package/dist/services/ps-chart-scale-service.js +2 -2
  98. package/dist/services/ps-chart-text-service.d.ts +6 -0
  99. package/dist/services/ps-chart-text-service.js +23 -0
  100. package/dist/services/ps-document-scanner-service.d.ts +2 -0
  101. package/dist/services/ps-document-scanner-service.js +21 -4
  102. package/dist/services/ps-jpeg-size-service.d.ts +4 -0
  103. package/dist/services/ps-jpeg-size-service.js +32 -0
  104. package/dist/services/ps-menu-popup-service.js +1 -0
  105. package/dist/services/ps-menu-popup-style-service.d.ts +13 -0
  106. package/dist/services/ps-menu-popup-style-service.js +55 -0
  107. package/dist/services/ps-scan-format-prompt-service.d.ts +6 -0
  108. package/dist/services/ps-scan-format-prompt-service.js +21 -0
  109. package/dist/services/ps-scan-image-converter-service.d.ts +5 -0
  110. package/dist/services/ps-scan-image-converter-service.js +22 -0
  111. package/dist/services/ps-scan-output-service.d.ts +10 -0
  112. package/dist/services/ps-scan-output-service.js +55 -0
  113. package/dist/services/ps-scan-pdf-service.d.ts +4 -0
  114. package/dist/services/ps-scan-pdf-service.js +6 -0
  115. package/dist/services/ps-screen-capture-service.d.ts +6 -0
  116. package/dist/services/ps-screen-capture-service.js +35 -0
  117. package/dist/services/ps-sortable-grid-service.d.ts +2 -0
  118. package/dist/services/ps-sortable-grid-service.js +10 -3
  119. package/dist/services/ps-waterfall-service.js +2 -3
  120. package/jest-setup.js +1 -1
  121. package/package.json +10 -2
@@ -0,0 +1,2 @@
1
+ export * from './ps-accessibility-gate';
2
+ export * from './ps-accessibility-gate-props';
@@ -0,0 +1,2 @@
1
+ export * from './ps-accessibility-gate';
2
+ export * from './ps-accessibility-gate-props';
@@ -0,0 +1,5 @@
1
+ import type { ReactNode } from 'react';
2
+ export interface PsAccessibilityGateProps {
3
+ children: ReactNode;
4
+ isHidden: boolean;
5
+ }
@@ -0,0 +1,2 @@
1
+ import type { PsAccessibilityGateProps } from './ps-accessibility-gate-props';
2
+ export declare const PsAccessibilityGate: ({ children, isHidden }: PsAccessibilityGateProps) => import("react").JSX.Element;
@@ -0,0 +1,4 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { View } from 'react-native';
3
+ import { PsAccessibilityConfig } from '../../constants/ps-accessibility-config';
4
+ export const PsAccessibilityGate = ({ children, isHidden }) => (_jsx(View, { accessibilityElementsHidden: isHidden, importantForAccessibility: isHidden ? PsAccessibilityConfig.hiddenImportance : PsAccessibilityConfig.visibleImportance, style: { flex: 1 }, testID: 'ps-accessibility-gate', children: children }));
@@ -5,7 +5,7 @@ import { PsAppLockConfig } from '../../constants/ps-app-lock-config';
5
5
  import { PsButton } from '../ps-button/ps-button';
6
6
  import { PsPrivacyCover } from '../ps-privacy-cover/ps-privacy-cover';
7
7
  import { PsTextLink } from '../ps-text-link/ps-text-link';
8
- export const PsAppLockScreen = ({ children, isUnlocking = false, onSignOut, onUnlock, signOutLabel, unlockLabel, }) => (_jsx(PsPrivacyCover, { children: _jsx(SafeAreaView, { style: {
8
+ export const PsAppLockScreen = ({ children, isUnlocking = false, onSignOut, onUnlock, signOutLabel, unlockLabel, }) => (_jsx(PsPrivacyCover, { shouldTakeFocus: true, children: _jsx(SafeAreaView, { style: {
9
9
  alignItems: 'center',
10
10
  flex: 1,
11
11
  justifyContent: 'center',
@@ -1,2 +1,2 @@
1
1
  import type { PsCartesianChartProps } from './ps-cartesian-chart-props';
2
- export declare const PsCartesianChart: ({ data, emptyLabel, formatTick, formatValue, height, isLoading, kind, series, showLegend, }: PsCartesianChartProps) => import("react").JSX.Element;
2
+ export declare const PsCartesianChart: ({ data, emptyLabel, formatTick, formatValue, height: baseHeight, isLoading, kind, series, showLegend, }: PsCartesianChartProps) => import("react").JSX.Element;
@@ -7,47 +7,55 @@ import { usePsChartReveal } from '../../hooks/use-ps-chart-reveal';
7
7
  import { usePsChartScrub } from '../../hooks/use-ps-chart-scrub';
8
8
  import { usePsChartWidth } from '../../hooks/use-ps-chart-width';
9
9
  import { usePsMobileTheme } from '../../hooks/use-ps-mobile-theme';
10
+ import { usePsWidgetFill } from '../../hooks/use-ps-widget-fill';
11
+ import { PsChartAxisService } from '../../services/ps-chart-axis-service';
10
12
  import { PsChartBarService } from '../../services/ps-chart-bar-service';
11
13
  import { PsChartKindService } from '../../services/ps-chart-kind-service';
12
14
  import { PsChartReadoutService } from '../../services/ps-chart-readout-service';
13
15
  import { PsChartScaleService } from '../../services/ps-chart-scale-service';
14
16
  import { PsChartSeriesService } from '../../services/ps-chart-series-service';
15
17
  import { PsChartShapeService } from '../../services/ps-chart-shape-service';
18
+ import { PsChartTextService } from '../../services/ps-chart-text-service';
16
19
  import { PsChartBar } from '../ps-chart-bar/ps-chart-bar';
17
20
  import { PsChartEmptyState } from '../ps-chart-empty-state/ps-chart-empty-state';
18
21
  import { PsChartLegend } from '../ps-chart-legend/ps-chart-legend';
19
22
  import { PsChartLine } from '../ps-chart-line/ps-chart-line';
20
23
  import { PsChartReadout } from '../ps-chart-readout/ps-chart-readout';
21
24
  import { PsChartSkeleton } from '../ps-chart-skeleton/ps-chart-skeleton';
22
- export const PsCartesianChart = ({ data, emptyLabel, formatTick, formatValue, height = PsChartConfig.chartHeight, isLoading = false, kind, series, showLegend = true, }) => {
25
+ export const PsCartesianChart = ({ data, emptyLabel, formatTick, formatValue, height: baseHeight = PsChartConfig.chartHeight, isLoading = false, kind, series, showLegend = true, }) => {
23
26
  const theme = usePsMobileTheme();
24
27
  const { onLayout, width } = usePsChartWidth();
28
+ const height = baseHeight + usePsWidgetFill();
25
29
  const isBars = PsChartKindService.isBars(kind);
26
30
  const isStacked = kind === PsCartesianChartKind.StackedBar;
27
- const plot = PsChartScaleService.plot(width, height);
31
+ const barIndexes = PsChartShapeService.barIndexes(kind, series);
32
+ const lineIndexes = PsChartShapeService.lineIndexes(kind, series);
33
+ const barSeries = barIndexes.map((position) => series[position]);
34
+ const lineSeries = lineIndexes.map((position) => series[position]);
35
+ const domain = PsChartScaleService.domain(isStacked
36
+ ? [
37
+ ...PsChartSeriesService.stackedValues(data, barSeries),
38
+ ...PsChartSeriesService.values(data, lineSeries),
39
+ ]
40
+ : PsChartSeriesService.values(data, series));
41
+ const tickLabels = PsChartScaleService.ticks(domain).map((tick) => formatTick(tick));
42
+ const yAxisWidth = PsChartAxisService.yAxisWidth(tickLabels, width);
43
+ const plot = PsChartScaleService.plot(width, height, yAxisWidth);
28
44
  const { index, panHandlers } = usePsChartScrub(data.length, isBars, plot);
29
45
  const progress = usePsChartReveal(PsChartSeriesService.signature(kind, data, series));
30
46
  if (isLoading)
31
- return _jsx(PsChartSkeleton, { height: height, variant: PsChartKindService.skeletonVariant(kind) });
47
+ return (_jsx(PsChartSkeleton, { height: baseHeight, variant: PsChartKindService.skeletonVariant(kind) }));
32
48
  if (data.length === 0 || PsChartSeriesService.isEmpty(data, series))
33
- return _jsx(PsChartEmptyState, { height: height, label: emptyLabel });
49
+ return _jsx(PsChartEmptyState, { height: baseHeight, label: emptyLabel });
34
50
  const colors = series.map((entry, position) => PsChartSeriesService.color({
35
51
  count: series.length,
36
52
  explicit: entry.color,
37
53
  index: position,
38
54
  theme,
39
55
  }));
40
- const barIndexes = PsChartShapeService.barIndexes(kind, series);
41
- const lineIndexes = PsChartShapeService.lineIndexes(kind, series);
42
- const barSeries = barIndexes.map((position) => series[position]);
43
56
  const barColors = barIndexes.map((position) => colors[position]);
44
- const lineSeries = lineIndexes.map((position) => series[position]);
45
- const domain = PsChartScaleService.domain(isStacked
46
- ? [
47
- ...PsChartSeriesService.stackedValues(data, barSeries),
48
- ...PsChartSeriesService.values(data, lineSeries),
49
- ]
50
- : PsChartSeriesService.values(data, series));
57
+ const xLabels = PsChartAxisService.xLabels(data.map((row) => row.label), plot.right - plot.left, isBars);
58
+ const readoutLines = PsChartReadoutService.maxLines(data.map((row) => PsChartReadoutService.items(row, series, colors, formatValue)), width);
51
59
  const selected = index === null ? data.length - 1 : index;
52
60
  const datum = data[selected];
53
61
  const items = PsChartReadoutService.items(datum, series, colors, formatValue);
@@ -57,10 +65,10 @@ export const PsCartesianChart = ({ data, emptyLabel, formatTick, formatValue, he
57
65
  : isStacked
58
66
  ? PsChartBarService.stacked(data, barSeries, barColors, domain, plot)
59
67
  : PsChartBarService.grouped(data, barSeries, barColors, domain, plot);
60
- return (_jsxs(View, { style: { gap: 8 }, children: [_jsx(PsChartReadout, { items: items, title: datum.label }), _jsx(View, { accessible: true, accessibilityLabel: PsChartReadoutService.summary(datum.label, items), accessibilityRole: 'image', onLayout: onLayout, style: { height }, children: width === 0 ? null : (_jsxs(_Fragment, { children: [_jsxs(Svg, { height: height, pointerEvents: 'none', width: width, children: [PsChartScaleService.ticks(domain).map((tick) => {
68
+ return (_jsxs(View, { style: { gap: 8 }, children: [_jsx(PsChartReadout, { items: items, lines: readoutLines, title: datum.label }), _jsx(View, { accessible: true, accessibilityLabel: PsChartReadoutService.summary(datum.label, items), accessibilityRole: 'image', onLayout: onLayout, style: { height }, children: width === 0 ? null : (_jsxs(_Fragment, { children: [_jsxs(Svg, { height: height, pointerEvents: 'none', width: width, children: [PsChartScaleService.ticks(domain).map((tick, tickIndex) => {
61
69
  const y = PsChartScaleService.y(tick, domain, plot);
62
- return (_jsxs(G, { children: [_jsx(Line, { stroke: theme.line, strokeWidth: PsChartConfig.gridLineWidth, x1: plot.left, x2: plot.right, y1: y, y2: y }), _jsx(SvgText, { fill: theme.muted, fontFamily: theme.fonts.medium, fontSize: PsChartConfig.axisLabelSize, textAnchor: 'end', x: plot.left - 6, y: y + 3, children: formatTick(tick) })] }, tick));
63
- }), PsChartScaleService.labelIndexes(data.length).map((position) => (_jsx(SvgText, { fill: theme.muted, fontFamily: theme.fonts.medium, fontSize: PsChartConfig.axisLabelSize, textAnchor: PsChartScaleService.labelAnchor(position, data.length, isBars), x: xAt(position), y: height - 6, children: data[position].label }, position))), rects.map((rect) => (_jsx(PsChartBar, { progress: progress, rect: rect }, rect.id))), lineSeries.map((entry, lineIndex) => {
70
+ return (_jsxs(G, { children: [_jsx(Line, { stroke: theme.line, strokeWidth: PsChartConfig.gridLineWidth, x1: plot.left, x2: plot.right, y1: y, y2: y }), _jsx(SvgText, { fill: theme.muted, fontFamily: theme.fonts.medium, fontSize: PsChartConfig.axisLabelSize, textAnchor: 'end', x: plot.left - PsChartConfig.axisTickGap, y: y + PsChartConfig.axisLabelSize / 3, children: PsChartTextService.fit(tickLabels[tickIndex], plot.left - PsChartConfig.axisTickGap, PsChartConfig.axisLabelSize) })] }, tick));
71
+ }), xLabels.indexes.map((position) => (_jsx(SvgText, { fill: theme.muted, fontFamily: theme.fonts.medium, fontSize: PsChartConfig.axisLabelSize, textAnchor: PsChartScaleService.labelAnchor(position, data.length, isBars), x: xAt(position), y: height - 6, children: PsChartTextService.fit(data[position].label, xLabels.maxWidth, PsChartConfig.axisLabelSize) }, position))), rects.map((rect) => (_jsx(PsChartBar, { progress: progress, rect: rect }, rect.id))), lineSeries.map((entry, lineIndex) => {
64
72
  const position = lineIndexes[lineIndex];
65
73
  const points = data.map((row, rowIndex) => ({
66
74
  x: xAt(rowIndex),
@@ -1,5 +1,9 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { View } from 'react-native';
3
3
  import { PsChartConfig } from '../../constants/ps-chart-config';
4
+ import { usePsWidgetFill } from '../../hooks/use-ps-widget-fill';
4
5
  import { PsText } from '../ps-text/ps-text';
5
- export const PsChartEmptyState = ({ height = PsChartConfig.chartHeight, label, }) => (_jsx(View, { style: { alignItems: 'center', height, justifyContent: 'center' }, testID: 'ps-chart-empty-state', children: _jsx(PsText, { align: 'center', tone: 'muted', children: label }) }));
6
+ export const PsChartEmptyState = ({ height = PsChartConfig.chartHeight, label, }) => {
7
+ const fill = usePsWidgetFill();
8
+ return (_jsx(View, { style: { alignItems: 'center', height: height + fill, justifyContent: 'center' }, testID: 'ps-chart-empty-state', children: _jsx(PsText, { align: 'center', tone: 'muted', children: label }) }));
9
+ };
@@ -1,6 +1,15 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { View } from 'react-native';
3
+ import { PsChartConfig } from '../../constants/ps-chart-config';
4
+ import { usePsChartWidth } from '../../hooks/use-ps-chart-width';
5
+ import { PsChartTextService } from '../../services/ps-chart-text-service';
3
6
  import { PsCard } from '../ps-card/ps-card';
4
7
  import { PsChartDeltaBadge } from '../ps-chart-delta-badge/ps-chart-delta-badge';
5
8
  import { PsText } from '../ps-text/ps-text';
6
- export const PsChartFrame = ({ children, delta, period, title, value }) => (_jsx(PsCard, { style: { gap: 12 }, children: _jsxs(View, { style: { gap: 12 }, testID: 'ps-chart-frame', children: [title === undefined && value === undefined ? null : (_jsxs(View, { style: { gap: 4 }, children: [title === undefined ? null : (_jsx(PsText, { numberOfLines: 1, tone: 'muted', variant: 'label', children: title })), value === undefined ? null : (_jsx(PsText, { numberOfLines: 1, style: { fontSize: 24, lineHeight: 30 }, variant: 'numeric', weight: 'bold', children: value })), delta === undefined ? null : _jsx(PsChartDeltaBadge, { ...delta }), period === undefined ? null : (_jsx(PsText, { tone: 'muted', variant: 'caption', children: period }))] })), children] }) }));
9
+ export const PsChartFrame = ({ children, delta, period, title, value }) => {
10
+ const { onLayout, width } = usePsChartWidth();
11
+ const size = value === undefined
12
+ ? PsChartConfig.kpiValueFontMax
13
+ : PsChartTextService.fontSize(value, width, PsChartConfig.kpiValueFontMax, PsChartConfig.kpiValueFontMin);
14
+ return (_jsx(PsCard, { style: { gap: 12 }, children: _jsxs(View, { onLayout: onLayout, style: { gap: 12 }, testID: 'ps-chart-frame', children: [title === undefined && value === undefined ? null : (_jsxs(View, { style: { gap: 4 }, children: [title === undefined ? null : (_jsx(PsText, { numberOfLines: 1, tone: 'muted', variant: 'label', children: title })), value === undefined ? null : (_jsx(PsText, { numberOfLines: 1, style: { fontSize: size, lineHeight: Math.round(size * 1.25) }, variant: 'numeric', weight: 'bold', children: value })), delta === undefined ? null : _jsx(PsChartDeltaBadge, { ...delta }), period === undefined ? null : (_jsx(PsText, { tone: 'muted', variant: 'caption', children: period }))] })), children] }) }));
15
+ };
@@ -3,15 +3,24 @@ import { Pressable, View } from 'react-native';
3
3
  import { PsChartConfig } from '../../constants/ps-chart-config';
4
4
  import { PsText } from '../ps-text/ps-text';
5
5
  export const PsChartLegend = ({ activeIndex = null, items, onPressItem }) => {
6
- return (_jsx(View, { style: { gap: 6 }, testID: 'ps-chart-legend', children: items.map((item, index) => (_jsxs(Pressable, { disabled: onPressItem === undefined, onPress: () => (onPressItem === undefined ? undefined : onPressItem(index)), style: {
6
+ const isWrapped = items.every((item) => item.value === undefined);
7
+ return (_jsx(View, { style: isWrapped
8
+ ? {
9
+ columnGap: PsChartConfig.readoutItemGap,
10
+ flexDirection: 'row',
11
+ flexWrap: 'wrap',
12
+ rowGap: 6,
13
+ }
14
+ : { gap: 6 }, testID: 'ps-chart-legend', children: items.map((item, index) => (_jsxs(Pressable, { hitSlop: PsChartConfig.legendHitSlop, disabled: onPressItem === undefined, onPress: () => (onPressItem === undefined ? undefined : onPressItem(index)), style: {
7
15
  alignItems: 'center',
8
16
  flexDirection: 'row',
9
17
  gap: 8,
18
+ maxWidth: '100%',
10
19
  opacity: activeIndex === null || activeIndex === index ? 1 : 0.5,
11
20
  }, children: [_jsx(View, { style: {
12
21
  backgroundColor: item.color,
13
22
  borderRadius: PsChartConfig.legendDot,
14
23
  height: PsChartConfig.legendDot,
15
24
  width: PsChartConfig.legendDot,
16
- } }), _jsx(PsText, { numberOfLines: 1, style: { flex: 1 }, variant: 'label', children: item.label }), item.value === undefined ? null : (_jsx(PsText, { tone: 'muted', variant: 'numeric', weight: 'semibold', children: item.value }))] }, item.label))) }));
25
+ } }), _jsx(PsText, { numberOfLines: 1, style: isWrapped ? { flexShrink: 1 } : { flex: 1 }, variant: 'label', children: item.label }), item.value === undefined ? null : (_jsx(PsText, { tone: 'muted', variant: 'numeric', weight: 'semibold', children: item.value }))] }, item.label))) }));
17
26
  };
@@ -1,5 +1,6 @@
1
1
  import type { PsChartReadoutItem } from '../../interfaces/ps-chart-readout-item';
2
2
  export interface PsChartReadoutProps {
3
3
  items: PsChartReadoutItem[];
4
+ lines?: number;
4
5
  title: string;
5
6
  }
@@ -1,2 +1,2 @@
1
1
  import type { PsChartReadoutProps } from './ps-chart-readout-props';
2
- export declare const PsChartReadout: ({ items, title }: PsChartReadoutProps) => import("react").JSX.Element;
2
+ export declare const PsChartReadout: ({ items, lines, title }: PsChartReadoutProps) => import("react").JSX.Element;
@@ -1,9 +1,15 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { View } from 'react-native';
3
3
  import { PsChartConfig } from '../../constants/ps-chart-config';
4
+ import { PsChartReadoutService } from '../../services/ps-chart-readout-service';
4
5
  import { PsText } from '../ps-text/ps-text';
5
- export const PsChartReadout = ({ items, title }) => {
6
- return (_jsxs(View, { style: { height: PsChartConfig.readoutHeight, justifyContent: 'center' }, children: [_jsx(PsText, { tone: 'muted', variant: 'caption', children: title }), _jsx(View, { style: { flexDirection: 'row', flexWrap: 'wrap', gap: 12 }, children: items.map((item) => (_jsxs(View, { style: { alignItems: 'center', flexDirection: 'row', gap: 6 }, children: [_jsx(View, { style: {
6
+ export const PsChartReadout = ({ items, lines = 1, title }) => {
7
+ return (_jsxs(View, { style: { height: PsChartReadoutService.height(lines), justifyContent: 'center' }, children: [_jsx(PsText, { tone: 'muted', variant: 'caption', children: title }), _jsx(View, { style: {
8
+ columnGap: PsChartConfig.readoutItemGap,
9
+ flexDirection: 'row',
10
+ flexWrap: 'wrap',
11
+ rowGap: PsChartConfig.readoutRowGap,
12
+ }, children: items.map((item) => (_jsxs(View, { style: { alignItems: 'center', flexDirection: 'row', gap: 6 }, children: [_jsx(View, { style: {
7
13
  backgroundColor: item.color,
8
14
  borderRadius: PsChartConfig.legendDot,
9
15
  height: PsChartConfig.legendDot,
@@ -1,2 +1,2 @@
1
1
  import type { PsChartSkeletonProps } from './ps-chart-skeleton-props';
2
- export declare const PsChartSkeleton: ({ height, label, }: PsChartSkeletonProps) => import("react").JSX.Element;
2
+ export declare const PsChartSkeleton: ({ height: baseHeight, label, }: PsChartSkeletonProps) => import("react").JSX.Element;
@@ -2,5 +2,9 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { View } from 'react-native';
3
3
  import { PsChartConfig } from '../../constants/ps-chart-config';
4
4
  import { PsSkeletonShape } from '../../constants/ps-skeleton-shape';
5
+ import { usePsWidgetFill } from '../../hooks/use-ps-widget-fill';
5
6
  import { PsSkeleton } from '../ps-skeleton/ps-skeleton';
6
- export const PsChartSkeleton = ({ height = PsChartConfig.chartHeight, label, }) => (_jsx(View, { accessibilityLabel: label, accessibilityRole: 'progressbar', accessibilityState: { busy: true }, style: { height }, testID: 'ps-chart-skeleton', children: _jsx(PsSkeleton, { height: height, shape: PsSkeletonShape.Block }) }));
7
+ export const PsChartSkeleton = ({ height: baseHeight = PsChartConfig.chartHeight, label, }) => {
8
+ const height = baseHeight + usePsWidgetFill();
9
+ return (_jsx(View, { accessibilityLabel: label, accessibilityRole: 'progressbar', accessibilityState: { busy: true }, style: { height }, testID: 'ps-chart-skeleton', children: _jsx(PsSkeleton, { height: height, shape: PsSkeletonShape.Block }) }));
10
+ };
@@ -5,7 +5,9 @@ import Svg from 'react-native-svg';
5
5
  import { PsChartConfig } from '../../constants/ps-chart-config';
6
6
  import { PsChartSkeletonVariant } from '../../constants/ps-chart-skeleton-variant';
7
7
  import { usePsChartReveal } from '../../hooks/use-ps-chart-reveal';
8
+ import { usePsChartWidth } from '../../hooks/use-ps-chart-width';
8
9
  import { usePsMobileTheme } from '../../hooks/use-ps-mobile-theme';
10
+ import { usePsWidgetFill } from '../../hooks/use-ps-widget-fill';
9
11
  import { PsChartDonutService } from '../../services/ps-chart-donut-service';
10
12
  import { PsChartEmptyState } from '../ps-chart-empty-state/ps-chart-empty-state';
11
13
  import { PsChartLegend } from '../ps-chart-legend/ps-chart-legend';
@@ -14,14 +16,18 @@ import { PsDonutSlice } from '../ps-donut-slice/ps-donut-slice';
14
16
  import { PsText } from '../ps-text/ps-text';
15
17
  export const PsDonutChart = ({ centerLabel, centerValue, data, emptyLabel, formatShare, height = PsChartConfig.donutHeight, isLoading = false, }) => {
16
18
  const theme = usePsMobileTheme();
19
+ const { onLayout, width } = usePsChartWidth();
20
+ const fill = usePsWidgetFill();
17
21
  const [selected, setSelected] = useState(null);
18
22
  const progress = usePsChartReveal(data.map((datum) => `${datum.id}:${datum.share}`).join(','));
19
23
  if (isLoading)
20
24
  return _jsx(PsChartSkeleton, { height: height, variant: PsChartSkeletonVariant.Donut });
21
- const slices = PsChartDonutService.slices(data, theme.chart, height);
25
+ const layout = PsChartDonutService.layout(width, height);
26
+ const size = layout.size;
27
+ const slices = PsChartDonutService.slices(data, theme.chart, size);
22
28
  if (slices.length === 0)
23
29
  return _jsx(PsChartEmptyState, { height: height, label: emptyLabel });
24
- const circumference = PsChartDonutService.circumference(height);
30
+ const circumference = PsChartDonutService.circumference(size);
25
31
  const chosen = selected === null ? null : data[selected];
26
32
  const readValue = chosen === null
27
33
  ? centerValue
@@ -29,16 +35,28 @@ export const PsDonutChart = ({ centerLabel, centerValue, data, emptyLabel, forma
29
35
  ? formatShare(chosen.share)
30
36
  : chosen.amountLabel;
31
37
  const readLabel = chosen === null ? centerLabel : chosen.label;
32
- return (_jsxs(View, { style: { alignItems: 'center', flexDirection: 'row', gap: 16 }, children: [_jsxs(View, { style: { height, width: height }, children: [_jsx(Svg, { height: height, width: height, children: slices.map((slice, index) => (_jsx(PsDonutSlice, { circumference: circumference, isDimmed: selected !== null && selected !== index, onPress: () => setSelected(selected === index ? null : index), progress: progress, size: height, slice: slice }, slice.id))) }), _jsxs(View, { pointerEvents: 'none', style: {
38
+ if (width === 0)
39
+ return _jsx(View, { onLayout: onLayout, style: { minHeight: height }, testID: 'ps-donut-chart' });
40
+ const centerSize = readValue === undefined
41
+ ? PsChartConfig.donutCenterFontMax
42
+ : PsChartDonutService.centerFontSize(readValue, size);
43
+ return (_jsxs(View, { onLayout: onLayout, style: {
44
+ alignItems: 'center',
45
+ columnGap: PsChartConfig.donutGap,
46
+ flexDirection: layout.isStacked ? 'column' : 'row',
47
+ justifyContent: 'center',
48
+ minHeight: height + fill,
49
+ rowGap: PsChartConfig.donutGap,
50
+ }, testID: 'ps-donut-chart', children: [_jsxs(View, { style: { height: size, width: size }, children: [_jsx(Svg, { height: size, width: size, children: slices.map((slice, index) => (_jsx(PsDonutSlice, { circumference: circumference, isDimmed: selected !== null && selected !== index, onPress: () => setSelected(selected === index ? null : index), progress: progress, size: size, slice: slice }, slice.id))) }), _jsxs(View, { pointerEvents: 'none', style: {
33
51
  alignItems: 'center',
34
52
  bottom: 0,
35
53
  justifyContent: 'center',
36
54
  left: 0,
37
- padding: PsChartConfig.donutThickness + 8,
55
+ padding: PsChartConfig.donutThickness + PsChartConfig.donutCenterPadding,
38
56
  position: 'absolute',
39
57
  right: 0,
40
58
  top: 0,
41
- }, children: [readValue === undefined ? null : (_jsx(PsText, { numberOfLines: 1, style: { fontSize: 18, lineHeight: 24 }, variant: 'numeric', weight: 'bold', children: readValue })), readLabel === undefined ? null : (_jsx(PsText, { align: 'center', numberOfLines: 2, tone: 'muted', variant: 'caption', children: readLabel }))] })] }), _jsx(View, { style: { flex: 1 }, children: _jsx(PsChartLegend, { activeIndex: selected, items: data.map((datum, index) => ({
59
+ }, children: [readValue === undefined ? null : (_jsx(PsText, { numberOfLines: 1, style: { fontSize: centerSize, lineHeight: Math.round((centerSize * 4) / 3) }, variant: 'numeric', weight: 'bold', children: readValue })), readLabel === undefined ? null : (_jsx(PsText, { align: 'center', numberOfLines: 2, tone: 'muted', variant: 'caption', children: readLabel }))] })] }), _jsx(View, { style: layout.isStacked ? { alignSelf: 'stretch' } : { flex: 1 }, children: _jsx(PsChartLegend, { activeIndex: selected, items: data.map((datum, index) => ({
42
60
  color: slices[index].color,
43
61
  label: datum.label,
44
62
  value: datum.amountLabel === undefined ? formatShare(datum.share) : datum.amountLabel,
@@ -1,11 +1,14 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { View } from 'react-native';
2
3
  import { PsChartConfig } from '../../constants/ps-chart-config';
3
4
  import { PsChartSkeletonVariant } from '../../constants/ps-chart-skeleton-variant';
5
+ import { usePsWidgetFill } from '../../hooks/use-ps-widget-fill';
4
6
  import { PsChartFrame } from '../ps-chart-frame/ps-chart-frame';
5
7
  import { PsChartSkeleton } from '../ps-chart-skeleton/ps-chart-skeleton';
6
8
  import { PsSparkline } from '../ps-sparkline/ps-sparkline';
7
9
  export const PsKpiCard = ({ delta, isLoading = false, period, title, value, values, }) => {
10
+ const fill = usePsWidgetFill();
8
11
  if (isLoading)
9
12
  return (_jsx(PsChartFrame, { children: _jsx(PsChartSkeleton, { height: PsChartConfig.sparklineHeight * 2, variant: PsChartSkeletonVariant.Line }) }));
10
- return (_jsx(PsChartFrame, { delta: delta, period: period, title: title, value: value, children: values === undefined ? null : _jsx(PsSparkline, { values: values }) }));
13
+ return (_jsx(PsChartFrame, { delta: delta, period: period, title: title, value: value, children: values === undefined ? (fill > 0 ? (_jsx(View, { style: { height: fill } })) : null) : (_jsx(PsSparkline, { values: values })) }));
11
14
  };
@@ -1,10 +1,12 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { PsIconKey } from '@pallasoft/ps-icons';
3
- import { View } from 'react-native';
3
+ import { Pressable, View } from 'react-native';
4
4
  import { PsLayoutConfig } from '../../constants/ps-layout-config';
5
5
  import { PsMobileControlConfig } from '../../constants/ps-mobile-control-config';
6
+ import { PsRippleKind } from '../../constants/ps-ripple-kind';
6
7
  import { usePsMobileTheme } from '../../hooks/use-ps-mobile-theme';
7
8
  import { PsNativeMenuService } from '../../services/ps-native-menu-service';
9
+ import { PsRippleService } from '../../services/ps-ripple-service';
8
10
  import { PsSelectService } from '../../services/ps-select-service';
9
11
  import { PsStateService } from '../../services/ps-state-service';
10
12
  import { PsIcon } from '../ps-icon/ps-icon';
@@ -15,14 +17,16 @@ export const PsListSelectRow = ({ isDisabled = false, isLoading = false, onChang
15
17
  const theme = usePsMobileTheme();
16
18
  if (isLoading)
17
19
  return _jsx(PsListRowSkeleton, { subtitle: subtitle, value: value });
18
- return (_jsx(PsNativeMenu, { isDisabled: isDisabled, isFullWidth: true, items: PsNativeMenuService.items(options, value), label: title, onSelect: onChange, children: () => (_jsxs(View, { accessibilityRole: 'button', accessibilityValue: { text: PsSelectService.selectedLabel(options, value) }, style: {
20
+ return (_jsx(PsNativeMenu, { isDisabled: isDisabled, isFullWidth: true, items: PsNativeMenuService.items(options, value), label: title, onSelect: onChange, children: ({ open }) => (_jsxs(Pressable, { accessibilityLabel: title, accessibilityRole: 'button', accessibilityState: { disabled: isDisabled }, accessibilityValue: { text: PsSelectService.selectedLabel(options, value) }, android_ripple: PsRippleService.resolve(theme, PsRippleKind.Surface), disabled: isDisabled, onPress: open, style: ({ pressed }) => ({
19
21
  alignItems: 'center',
20
- backgroundColor: theme.surface,
22
+ backgroundColor: pressed
23
+ ? PsStateService.pressedFill(theme, theme.surface)
24
+ : theme.surface,
21
25
  flexDirection: 'row',
22
26
  gap: PsLayoutConfig.headerSlotGap,
23
27
  minHeight: PsLayoutConfig.rowMinHeight,
24
28
  opacity: isDisabled ? PsStateService.disabledOpacity() : 1,
25
29
  paddingHorizontal: PsLayoutConfig.gutter,
26
30
  paddingVertical: PsLayoutConfig.rowPaddingVertical,
27
- }, testID: 'ps-list-select-row', children: [_jsxs(View, { style: { flex: 1, gap: PsLayoutConfig.rowLineGap }, children: [_jsx(PsText, { numberOfLines: 1, weight: 'semibold', children: title }), subtitle === undefined ? null : (_jsx(PsText, { tone: 'muted', variant: 'small', children: subtitle }))] }), valueAccessory, _jsx(PsText, { numberOfLines: 1, style: { maxWidth: PsLayoutConfig.rowValueMaxWidth }, tone: 'muted', children: PsSelectService.selectedLabel(options, value) }), _jsx(PsIcon, { color: theme.muted, iconKey: PsIconKey.Sort, size: PsMobileControlConfig.iconSizeInline })] })) }));
31
+ }), testID: 'ps-list-select-row', children: [_jsxs(View, { style: { flex: 1, gap: PsLayoutConfig.rowLineGap }, children: [_jsx(PsText, { numberOfLines: 1, weight: 'semibold', children: title }), subtitle === undefined ? null : (_jsx(PsText, { tone: 'muted', variant: 'small', children: subtitle }))] }), valueAccessory, _jsx(PsText, { numberOfLines: 1, style: { maxWidth: PsLayoutConfig.rowValueMaxWidth }, tone: 'muted', children: PsSelectService.selectedLabel(options, value) }), _jsx(PsIcon, { color: theme.muted, iconKey: PsIconKey.Sort, size: PsMobileControlConfig.iconSizeInline })] })) }));
28
32
  };
@@ -1,7 +1,13 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { View } from 'react-native';
3
+ import { usePsMaterialScheme } from '../../hooks/use-ps-material-scheme';
3
4
  import { usePsMobileTheme } from '../../hooks/use-ps-mobile-theme';
5
+ import { PsMenuPopupStyleService } from '../../services/ps-menu-popup-style-service';
4
6
  export const PsMenuPopupDivider = () => {
5
- const theme = usePsMobileTheme();
6
- return _jsx(View, { style: { backgroundColor: theme.line, height: 1 } });
7
+ const divider = PsMenuPopupStyleService.divider(usePsMobileTheme(), usePsMaterialScheme(), PsMenuPopupStyleService.isMaterial());
8
+ return (_jsx(View, { style: {
9
+ backgroundColor: divider.backgroundColor,
10
+ height: 1,
11
+ marginVertical: divider.marginVertical,
12
+ } }));
7
13
  };
@@ -3,20 +3,32 @@ import { PsIconKey } from '@pallasoft/ps-icons';
3
3
  import { Pressable, View } from 'react-native';
4
4
  import { PsMenuPopupConfig } from '../../constants/ps-menu-popup-config';
5
5
  import { PsMobileControlConfig } from '../../constants/ps-mobile-control-config';
6
+ import { PsRippleKind } from '../../constants/ps-ripple-kind';
7
+ import { usePsMaterialScheme } from '../../hooks/use-ps-material-scheme';
6
8
  import { usePsMobileTheme } from '../../hooks/use-ps-mobile-theme';
9
+ import { PsMenuPopupStyleService } from '../../services/ps-menu-popup-style-service';
10
+ import { PsRippleService } from '../../services/ps-ripple-service';
7
11
  import { PsStateService } from '../../services/ps-state-service';
8
12
  import { PsIcon } from '../ps-icon/ps-icon';
9
13
  import { PsText } from '../ps-text/ps-text';
10
14
  export const PsMenuPopupRow = ({ iconKey, isChecked = false, isDanger = false, isDisabled = false, isWarning = false, label, onPress, subtitle, }) => {
11
15
  const theme = usePsMobileTheme();
16
+ const scheme = usePsMaterialScheme();
17
+ const isMaterial = PsMenuPopupStyleService.isMaterial();
12
18
  const tint = isDanger ? theme.danger : theme.ink;
13
- return (_jsxs(Pressable, { accessibilityRole: 'menuitem', accessibilityState: { disabled: isDisabled, selected: isChecked }, disabled: isDisabled, onPress: onPress, style: ({ pressed }) => ({
14
- alignItems: 'center',
15
- backgroundColor: pressed ? theme.primarySoft : 'transparent',
16
- flexDirection: 'row',
17
- gap: PsMobileControlConfig.rowSpacing,
18
- minHeight: PsMenuPopupConfig.rowHeight,
19
- opacity: isDisabled ? PsStateService.disabledOpacity() : 1,
20
- paddingHorizontal: PsMenuPopupConfig.rowPaddingHorizontal,
21
- }), children: [iconKey === undefined ? null : _jsx(PsIcon, { color: tint, iconKey: iconKey }), _jsxs(View, { style: { flex: 1 }, children: [_jsx(PsText, { numberOfLines: 1, tone: isDanger ? 'danger' : 'ink', weight: isChecked ? 'semibold' : 'regular', children: label }), subtitle === undefined ? null : (_jsx(PsText, { numberOfLines: 1, tone: isWarning ? 'warning' : 'muted', variant: 'small', children: subtitle }))] }), isChecked ? _jsx(PsIcon, { color: theme.primaryText, iconKey: PsIconKey.Check }) : null] }));
19
+ return (_jsxs(Pressable, { accessibilityRole: 'menuitem', accessibilityState: { disabled: isDisabled, selected: isChecked }, android_ripple: PsRippleService.resolve(theme, isDanger ? PsRippleKind.Danger : PsRippleKind.Surface), disabled: isDisabled, onPress: onPress, style: ({ pressed }) => {
20
+ const row = PsMenuPopupStyleService.row(theme, scheme, isMaterial, isChecked, pressed);
21
+ return {
22
+ alignItems: 'center',
23
+ backgroundColor: row.backgroundColor,
24
+ borderRadius: row.borderRadius,
25
+ flexDirection: 'row',
26
+ gap: PsMobileControlConfig.rowSpacing,
27
+ marginHorizontal: row.marginHorizontal,
28
+ minHeight: PsMenuPopupConfig.rowHeight,
29
+ opacity: isDisabled ? PsStateService.disabledOpacity() : 1,
30
+ overflow: 'hidden',
31
+ paddingHorizontal: row.paddingHorizontal,
32
+ };
33
+ }, children: [iconKey === undefined ? null : _jsx(PsIcon, { color: tint, iconKey: iconKey }), _jsxs(View, { style: { flex: 1 }, children: [_jsx(PsText, { numberOfLines: 1, tone: isDanger ? 'danger' : 'ink', weight: PsMenuPopupStyleService.labelWeight(isMaterial, isChecked), children: label }), subtitle === undefined ? null : (_jsx(PsText, { numberOfLines: 1, tone: isWarning ? 'warning' : 'muted', variant: 'small', children: subtitle }))] }), isChecked ? _jsx(PsIcon, { color: theme.primaryText, iconKey: PsIconKey.Check }) : null] }));
22
34
  };
@@ -1,35 +1,46 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState } from 'react';
3
- import { Modal, Pressable, ScrollView, StyleSheet, View, useWindowDimensions } from 'react-native';
3
+ import { Modal, Pressable, ScrollView, StyleSheet, useWindowDimensions } from 'react-native';
4
+ import Animated from 'react-native-reanimated';
4
5
  import { PsMenuPopupConfig } from '../../constants/ps-menu-popup-config';
6
+ import { usePsMaterialScheme } from '../../hooks/use-ps-material-scheme';
7
+ import { usePsMenuPopupReveal } from '../../hooks/use-ps-menu-popup-reveal';
5
8
  import { usePsMobileTheme } from '../../hooks/use-ps-mobile-theme';
6
9
  import { PsMenuPopupService } from '../../services/ps-menu-popup-service';
10
+ import { PsMenuPopupStyleService } from '../../services/ps-menu-popup-style-service';
7
11
  export const PsMenuPopup = ({ anchor, children, isFullWidth = false, onClose, }) => {
8
12
  const theme = usePsMobileTheme();
13
+ const scheme = usePsMaterialScheme();
9
14
  const window = useWindowDimensions();
15
+ const isMaterial = PsMenuPopupStyleService.isMaterial();
10
16
  const [size, setSize] = useState(undefined);
11
17
  const layout = size === undefined
12
18
  ? undefined
13
19
  : PsMenuPopupService.layout(anchor, window, size.height, size.width, isFullWidth);
14
- return (_jsxs(Modal, { animationType: 'fade', navigationBarTranslucent: true, onRequestClose: onClose, statusBarTranslucent: true, transparent: true, visible: true, children: [_jsx(Pressable, { accessibilityElementsHidden: true, onPress: onClose, style: StyleSheet.absoluteFill, testID: 'ps-menu-popup-backdrop' }), _jsx(View, { onLayout: (event) => {
20
+ const container = PsMenuPopupStyleService.container(theme, scheme, isMaterial);
21
+ const reveal = usePsMenuPopupReveal(layout !== undefined, layout === undefined || layout.isBelow, isMaterial);
22
+ return (_jsxs(Modal, { animationType: isMaterial ? 'none' : 'fade', navigationBarTranslucent: true, onRequestClose: onClose, statusBarTranslucent: true, transparent: true, visible: true, children: [_jsx(Pressable, { accessibilityElementsHidden: true, onPress: onClose, style: StyleSheet.absoluteFill, testID: 'ps-menu-popup-backdrop' }), _jsx(Animated.View, { onLayout: (event) => {
15
23
  if (size === undefined)
16
24
  setSize({
17
25
  height: event.nativeEvent.layout.height,
18
26
  width: event.nativeEvent.layout.width,
19
27
  });
20
- }, pointerEvents: layout === undefined ? 'none' : 'auto', style: {
21
- backgroundColor: theme.surface,
22
- borderColor: theme.line,
23
- borderRadius: PsMenuPopupConfig.radius,
24
- borderWidth: 1,
25
- left: layout === undefined ? 0 : layout.left,
26
- maxHeight: layout === undefined ? undefined : layout.maxHeight,
27
- maxWidth: PsMenuPopupConfig.maxWidth,
28
- minWidth: isFullWidth ? undefined : PsMenuPopupConfig.minWidth,
29
- opacity: layout === undefined ? 0 : 1,
30
- overflow: 'hidden',
31
- position: 'absolute',
32
- top: layout === undefined ? 0 : layout.top,
33
- width: layout === undefined ? undefined : layout.width,
34
- }, testID: 'ps-menu-popup', children: _jsx(ScrollView, { bounces: false, contentContainerStyle: { paddingVertical: PsMenuPopupConfig.paddingVertical }, children: children }) })] }));
28
+ }, pointerEvents: layout === undefined ? 'none' : 'auto', style: [
29
+ {
30
+ backgroundColor: container.backgroundColor,
31
+ borderColor: container.borderColor,
32
+ borderRadius: container.borderRadius,
33
+ borderWidth: container.borderWidth,
34
+ elevation: container.elevation,
35
+ left: layout === undefined ? 0 : layout.left,
36
+ maxHeight: layout === undefined ? undefined : layout.maxHeight,
37
+ maxWidth: PsMenuPopupConfig.maxWidth,
38
+ minWidth: isFullWidth ? undefined : PsMenuPopupConfig.minWidth,
39
+ overflow: 'hidden',
40
+ position: 'absolute',
41
+ top: layout === undefined ? 0 : layout.top,
42
+ width: layout === undefined ? undefined : layout.width,
43
+ },
44
+ reveal,
45
+ ], testID: 'ps-menu-popup', children: _jsx(ScrollView, { bounces: false, contentContainerStyle: { paddingVertical: container.paddingVertical }, children: children }) })] }));
35
46
  };
@@ -1,4 +1,5 @@
1
1
  import type { ReactNode } from 'react';
2
2
  export interface PsPrivacyCoverProps {
3
3
  children?: ReactNode;
4
+ shouldTakeFocus?: boolean;
4
5
  }
@@ -1,2 +1,2 @@
1
1
  import type { PsPrivacyCoverProps } from './ps-privacy-cover-props';
2
- export declare const PsPrivacyCover: ({ children }: PsPrivacyCoverProps) => import("react").JSX.Element;
2
+ export declare const PsPrivacyCover: ({ children, shouldTakeFocus }: PsPrivacyCoverProps) => import("react").JSX.Element;
@@ -1,11 +1,20 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef } from 'react';
2
3
  import { PallasoftZIndex } from '@pallasoft/ps-design-system';
3
- import { StyleSheet, View } from 'react-native';
4
+ import { AccessibilityInfo, StyleSheet, View } from 'react-native';
5
+ import { PsAccessibilityConfig } from '../../constants/ps-accessibility-config';
4
6
  import { usePsMobileTheme } from '../../hooks/use-ps-mobile-theme';
5
7
  import { PsPageBackdrop } from '../ps-page-backdrop/ps-page-backdrop';
6
- export const PsPrivacyCover = ({ children }) => {
8
+ export const PsPrivacyCover = ({ children, shouldTakeFocus = false }) => {
7
9
  const theme = usePsMobileTheme();
8
- return (_jsxs(View, { accessibilityViewIsModal: true, style: [
10
+ const ref = useRef(null);
11
+ useEffect(() => {
12
+ if (!shouldTakeFocus)
13
+ return;
14
+ if (ref.current !== null)
15
+ AccessibilityInfo.sendAccessibilityEvent(ref.current, PsAccessibilityConfig.focusEvent);
16
+ }, [shouldTakeFocus]);
17
+ return (_jsxs(View, { accessibilityViewIsModal: true, importantForAccessibility: 'yes', ref: ref, style: [
9
18
  StyleSheet.absoluteFill,
10
19
  {
11
20
  alignItems: 'center',
@@ -31,7 +31,10 @@ export const PsSortableGrid = ({ getItemSpan, isDisabled = false, items, labels,
31
31
  });
32
32
  const ids = useMemo(() => PsSortableGridService.ids(order), [order]);
33
33
  const rects = useMemo(() => PsSortableGridService.layout(order.map((item) => getItemSpan(item)), PsSortableGridService.heights(ids, measured), width), [getItemSpan, ids, measured, order, width]);
34
+ const extras = useMemo(() => PsSortableGridService.extras(rects, PsSortableGridService.heights(ids, measured)), [ids, measured, rects]);
34
35
  const isReady = PsSortableGridService.isMeasured(ids, measured, width);
36
+ const applied = useRef({});
37
+ applied.current = Object.fromEntries(ids.map((id, index) => [id, isReady ? extras[index] : 0]));
35
38
  const latest = useRef({ items, onReorder, order, rects, scroll, windowHeight, insets });
36
39
  latest.current = { insets, items, onReorder, order, rects, scroll, windowHeight };
37
40
  useEffect(() => {
@@ -131,10 +134,11 @@ export const PsSortableGrid = ({ getItemSpan, isDisabled = false, items, labels,
131
134
  notify(next);
132
135
  PsHapticService.play('selection', hasHaptics);
133
136
  }, [hasHaptics]);
134
- const measure = useCallback((id, height) => {
135
- setMeasured((current) => current[id] !== undefined && Math.abs(current[id] - height) < 0.5
137
+ const measure = useCallback((id, total) => {
138
+ const natural = PsSortableGridService.natural(total, applied.current[id] === undefined ? 0 : applied.current[id]);
139
+ setMeasured((current) => current[id] !== undefined && Math.abs(current[id] - natural) < 0.5
136
140
  ? current
137
- : { ...current, [id]: height });
141
+ : { ...current, [id]: natural });
138
142
  }, []);
139
- return (_jsx(View, { onLayout: (event) => setWidth(event.nativeEvent.layout.width), style: { height: PsSortableGridService.contentHeight(rects) }, children: order.map((item, index) => (_jsx(PsSortableItem, { canMoveDown: index < order.length - 1, canMoveUp: index > 0, dragX: dragX, dragY: dragY, id: item.id, isActive: item.id === activeId, isDisabled: isDisabled, isReady: isReady, label: item.label, labels: labels, onEnd: end, onMeasure: measure, onMove: moveBy, onStart: start, onUpdate: update, rect: rects[index], children: renderItem({ isActive: item.id === activeId, item }) }, item.id))) }));
143
+ return (_jsx(View, { onLayout: (event) => setWidth(event.nativeEvent.layout.width), style: { height: PsSortableGridService.contentHeight(rects) }, children: order.map((item, index) => (_jsx(PsSortableItem, { canMoveDown: index < order.length - 1, canMoveUp: index > 0, dragX: dragX, dragY: dragY, extra: extras[index], id: item.id, isActive: item.id === activeId, isDisabled: isDisabled, isReady: isReady, label: item.label, labels: labels, onEnd: end, onMeasure: measure, onMove: moveBy, onStart: start, onUpdate: update, rect: rects[index], children: renderItem({ isActive: item.id === activeId, item }) }, item.id))) }));
140
144
  };
@@ -8,6 +8,7 @@ export interface PsSortableItemProps {
8
8
  children: ReactNode;
9
9
  dragX: SharedValue<number>;
10
10
  dragY: SharedValue<number>;
11
+ extra: number;
11
12
  id: string;
12
13
  isActive: boolean;
13
14
  isDisabled: boolean;
@@ -1,2 +1,2 @@
1
1
  import type { PsSortableItemProps } from './ps-sortable-item-props';
2
- export declare const PsSortableItem: ({ canMoveDown, canMoveUp, children, dragX, dragY, id, isActive, isDisabled, isReady, label, labels, onEnd, onMeasure, onMove, onStart, onUpdate, rect, }: PsSortableItemProps) => import("react").JSX.Element;
2
+ export declare const PsSortableItem: ({ canMoveDown, canMoveUp, children, dragX, dragY, extra, id, isActive, isDisabled, isReady, label, labels, onEnd, onMeasure, onMove, onStart, onUpdate, rect, }: PsSortableItemProps) => import("react").JSX.Element;
@@ -3,8 +3,9 @@ import { useEffect, useRef } from 'react';
3
3
  import { GestureDetector, usePanGesture } from 'react-native-gesture-handler';
4
4
  import Animated, { useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated';
5
5
  import { PsSortableGridConfig } from '../../constants/ps-sortable-grid-config';
6
+ import { PsWidgetFillContext } from '../../contexts/ps-widget-fill-context';
6
7
  import { usePsMobileTheme } from '../../hooks/use-ps-mobile-theme';
7
- export const PsSortableItem = ({ canMoveDown, canMoveUp, children, dragX, dragY, id, isActive, isDisabled, isReady, label, labels, onEnd, onMeasure, onMove, onStart, onUpdate, rect, }) => {
8
+ export const PsSortableItem = ({ canMoveDown, canMoveUp, children, dragX, dragY, extra, id, isActive, isDisabled, isReady, label, labels, onEnd, onMeasure, onMove, onStart, onUpdate, rect, }) => {
8
9
  const theme = usePsMobileTheme();
9
10
  const left = useSharedValue(rect.x);
10
11
  const top = useSharedValue(rect.y);
@@ -70,5 +71,5 @@ export const PsSortableItem = ({ canMoveDown, canMoveUp, children, dragX, dragY,
70
71
  }
71
72
  : undefined,
72
73
  animatedStyle,
73
- ], children: children }) }));
74
+ ], children: _jsx(PsWidgetFillContext.Provider, { value: isReady ? extra : 0, children: children }) }) }));
74
75
  };