@pallasoft/ps-mobile-components 1.12.0 → 1.13.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 (63) hide show
  1. package/dist/components/ps-action-sheet/ps-action-sheet.js +18 -2
  2. package/dist/components/ps-barcode-scanner-sheet/ps-barcode-scanner-sheet.js +2 -1
  3. package/dist/components/ps-document-viewer/ps-document-viewer.js +2 -1
  4. package/dist/components/ps-document-zoom-image/ps-document-zoom-image.js +10 -0
  5. package/dist/components/ps-infinite-list/ps-infinite-list-props.d.ts +2 -0
  6. package/dist/components/ps-infinite-list/ps-infinite-list.d.ts +1 -1
  7. package/dist/components/ps-infinite-list/ps-infinite-list.js +12 -5
  8. package/dist/components/ps-list/ps-list-props.d.ts +2 -0
  9. package/dist/components/ps-list/ps-list.d.ts +1 -1
  10. package/dist/components/ps-list/ps-list.js +1 -1
  11. package/dist/components/ps-menu-popup/ps-menu-popup.js +3 -2
  12. package/dist/components/ps-screen/ps-screen-props.d.ts +2 -0
  13. package/dist/components/ps-screen/ps-screen.d.ts +1 -1
  14. package/dist/components/ps-screen/ps-screen.js +12 -5
  15. package/dist/components/ps-sheet-content/ps-sheet-content.js +4 -2
  16. package/dist/components/ps-sheet-presenter/ps-sheet-presenter.ios.js +15 -5
  17. package/dist/components/ps-sheet-presenter/ps-sheet-presenter.js +16 -3
  18. package/dist/components/ps-sortable-grid/ps-sortable-grid.js +4 -1
  19. package/dist/components/ps-widget-list/ps-widget-grid.js +16 -7
  20. package/dist/components/ps-widget-list/ps-widget-list-props.d.ts +2 -0
  21. package/dist/components/ps-widget-list/ps-widget-list.d.ts +1 -1
  22. package/dist/components/ps-widget-list/ps-widget-list.js +12 -5
  23. package/dist/constants/ps-content-width.d.ts +6 -0
  24. package/dist/constants/ps-content-width.js +5 -0
  25. package/dist/constants/ps-document-search-config.d.ts +0 -3
  26. package/dist/constants/ps-document-search-config.js +0 -3
  27. package/dist/constants/ps-layout-class-config.d.ts +12 -0
  28. package/dist/constants/ps-layout-class-config.js +12 -0
  29. package/dist/constants/ps-layout-class.d.ts +5 -0
  30. package/dist/constants/ps-layout-class.js +4 -0
  31. package/dist/constants/ps-menu-popup-config.d.ts +1 -0
  32. package/dist/constants/ps-menu-popup-config.js +1 -0
  33. package/dist/constants/ps-orientation-config.d.ts +3 -0
  34. package/dist/constants/ps-orientation-config.js +3 -0
  35. package/dist/constants/ps-sheet-config.d.ts +1 -0
  36. package/dist/constants/ps-sheet-config.js +1 -0
  37. package/dist/constants/ps-sortable-grid-config.d.ts +2 -0
  38. package/dist/constants/ps-sortable-grid-config.js +2 -0
  39. package/dist/hooks/use-ps-layout-class.d.ts +2 -0
  40. package/dist/hooks/use-ps-layout-class.js +6 -0
  41. package/dist/hooks/use-ps-menu-anchor.d.ts +1 -1
  42. package/dist/hooks/use-ps-menu-anchor.js +14 -2
  43. package/dist/index.d.ts +4 -0
  44. package/dist/index.js +4 -0
  45. package/dist/interfaces/ps-document-search-match.d.ts +2 -4
  46. package/dist/interfaces/ps-document-text-box.d.ts +2 -6
  47. package/dist/interfaces/ps-document-text-layer-word.d.ts +2 -5
  48. package/dist/interfaces/ps-document-text-layer.d.ts +2 -6
  49. package/dist/interfaces/ps-document-text-segment.d.ts +2 -4
  50. package/dist/interfaces/ps-menu-popup-insets.d.ts +2 -0
  51. package/dist/interfaces/ps-menu-popup-layout.d.ts +1 -0
  52. package/dist/services/ps-document-search-service.d.ts +0 -4
  53. package/dist/services/ps-document-search-service.js +9 -96
  54. package/dist/services/ps-layout-service.d.ts +12 -0
  55. package/dist/services/ps-layout-service.js +41 -0
  56. package/dist/services/ps-menu-popup-service.js +8 -4
  57. package/dist/services/ps-sheet-service.d.ts +5 -2
  58. package/dist/services/ps-sheet-service.js +17 -4
  59. package/dist/services/ps-sortable-grid-service.d.ts +3 -2
  60. package/dist/services/ps-sortable-grid-service.js +26 -22
  61. package/package.json +2 -2
  62. package/dist/interfaces/ps-document-normalized-text.d.ts +0 -5
  63. package/dist/interfaces/ps-document-normalized-text.js +0 -1
@@ -5,6 +5,7 @@ export const PsMenuPopupConfig = {
5
5
  minWidth: 168,
6
6
  paddingVertical: 8,
7
7
  radius: 12,
8
+ remeasureMs: 250,
8
9
  rowHeight: 48,
9
10
  rowPaddingHorizontal: 16,
10
11
  };
@@ -0,0 +1,3 @@
1
+ export declare const PsOrientationConfig: {
2
+ readonly all: readonly ["portrait", "portrait-upside-down", "landscape", "landscape-left", "landscape-right"];
3
+ };
@@ -0,0 +1,3 @@
1
+ export const PsOrientationConfig = {
2
+ all: ['portrait', 'portrait-upside-down', 'landscape', 'landscape-left', 'landscape-right'],
3
+ };
@@ -2,6 +2,7 @@ export declare const PsSheetConfig: {
2
2
  readonly actionMinWidth: 44;
3
3
  readonly actionSpinnerGap: 6;
4
4
  readonly cornerRadius: 20;
5
+ readonly formSizingMinIos: 18;
5
6
  readonly headerMinHeight: 64;
6
7
  readonly headerPaddingBottom: 12;
7
8
  readonly headerPaddingHorizontal: 16;
@@ -2,6 +2,7 @@ export const PsSheetConfig = {
2
2
  actionMinWidth: 44,
3
3
  actionSpinnerGap: 6,
4
4
  cornerRadius: 20,
5
+ formSizingMinIos: 18,
5
6
  headerMinHeight: 64,
6
7
  headerPaddingBottom: 12,
7
8
  headerPaddingHorizontal: 16,
@@ -2,7 +2,9 @@ export declare const PsSortableGridConfig: {
2
2
  readonly activeScale: 1.03;
3
3
  readonly activeZIndex: 10;
4
4
  readonly columnGap: 12;
5
+ readonly compactUnits: 2;
5
6
  readonly edgeRatio: 0.14;
7
+ readonly fullUnits: 2;
6
8
  readonly holdTolerance: 8;
7
9
  readonly longPressMs: 400;
8
10
  readonly maxScrollStep: 18;
@@ -4,7 +4,9 @@ export const PsSortableGridConfig = {
4
4
  activeScale: 1.03,
5
5
  activeZIndex: 10,
6
6
  columnGap: PsChartConfig.kpiGap,
7
+ compactUnits: 2,
7
8
  edgeRatio: 0.14,
9
+ fullUnits: 2,
8
10
  holdTolerance: 8,
9
11
  longPressMs: 400,
10
12
  maxScrollStep: 18,
@@ -0,0 +1,2 @@
1
+ import type { PsLayoutClass } from '../constants/ps-layout-class';
2
+ export declare const usePsLayoutClass: () => PsLayoutClass;
@@ -0,0 +1,6 @@
1
+ import { useWindowDimensions } from 'react-native';
2
+ import { PsLayoutService } from '../services/ps-layout-service';
3
+ export const usePsLayoutClass = () => {
4
+ const { height, width } = useWindowDimensions();
5
+ return PsLayoutService.classOf(width, height);
6
+ };
@@ -1,5 +1,5 @@
1
1
  import { type ElementRef, type RefObject } from 'react';
2
- import type { View } from 'react-native';
2
+ import { type View } from 'react-native';
3
3
  import type { PsMenuAnchor } from '../interfaces/ps-menu-anchor';
4
4
  export interface PsMenuAnchorResult {
5
5
  anchor: PsMenuAnchor | undefined;
@@ -1,12 +1,24 @@
1
- import { useRef, useState } from 'react';
1
+ import { useEffect, useRef, useState } from 'react';
2
+ import { useWindowDimensions } from 'react-native';
3
+ import { PsMenuPopupConfig } from '../constants/ps-menu-popup-config';
2
4
  export const usePsMenuAnchor = () => {
3
5
  const ref = useRef(null);
4
6
  const [anchor, setAnchor] = useState(undefined);
7
+ const { height, width } = useWindowDimensions();
8
+ const isOpen = anchor !== undefined;
9
+ useEffect(() => {
10
+ if (!isOpen)
11
+ return;
12
+ const timer = setTimeout(() => {
13
+ ref.current?.measureInWindow((x, y, anchorWidth, anchorHeight) => setAnchor({ height: anchorHeight, width: anchorWidth, x, y }));
14
+ }, PsMenuPopupConfig.remeasureMs);
15
+ return () => clearTimeout(timer);
16
+ }, [height, isOpen, width]);
5
17
  return {
6
18
  anchor,
7
19
  close: () => setAnchor(undefined),
8
20
  open: () => {
9
- ref.current?.measureInWindow((x, y, width, height) => setAnchor({ height, width, x, y }));
21
+ ref.current?.measureInWindow((x, y, anchorWidth, anchorHeight) => setAnchor({ height: anchorHeight, width: anchorWidth, x, y }));
10
22
  },
11
23
  ref,
12
24
  };
package/dist/index.d.ts CHANGED
@@ -194,3 +194,7 @@ export * from './interfaces/ps-infinite-data-result';
194
194
  export * from './interfaces/ps-infinite-data-update';
195
195
  export * from './interfaces/ps-infinite-page';
196
196
  export { usePsDebouncedValue } from '@pallasoft/ps-utilities/react';
197
+ export * from './constants/ps-layout-class';
198
+ export * from './constants/ps-content-width';
199
+ export * from './hooks/use-ps-layout-class';
200
+ export { PsLayoutService } from './services/ps-layout-service';
package/dist/index.js CHANGED
@@ -189,3 +189,7 @@ export * from './interfaces/ps-infinite-data-result';
189
189
  export * from './interfaces/ps-infinite-data-update';
190
190
  export * from './interfaces/ps-infinite-page';
191
191
  export { usePsDebouncedValue } from '@pallasoft/ps-utilities/react';
192
+ export * from './constants/ps-layout-class';
193
+ export * from './constants/ps-content-width';
194
+ export * from './hooks/use-ps-layout-class';
195
+ export { PsLayoutService } from './services/ps-layout-service';
@@ -1,4 +1,2 @@
1
- export interface PsDocumentSearchMatch {
2
- end: number;
3
- start: number;
4
- }
1
+ import type { TextMatch } from '@pallasoft/ps-utilities';
2
+ export type PsDocumentSearchMatch = TextMatch;
@@ -1,6 +1,2 @@
1
- export interface PsDocumentTextBox {
2
- height: number;
3
- left: number;
4
- top: number;
5
- width: number;
6
- }
1
+ import type { TextLayerBox } from '@pallasoft/ps-utilities';
2
+ export type PsDocumentTextBox = TextLayerBox;
@@ -1,5 +1,2 @@
1
- import type { PsDocumentTextBox } from './ps-document-text-box';
2
- export interface PsDocumentTextLayerWord {
3
- box: PsDocumentTextBox;
4
- text: string;
5
- }
1
+ import type { TextLayerWord } from '@pallasoft/ps-utilities';
2
+ export type PsDocumentTextLayerWord = TextLayerWord;
@@ -1,6 +1,2 @@
1
- import type { PsDocumentTextLayerWord } from './ps-document-text-layer-word';
2
- export interface PsDocumentTextLayer {
3
- height: number;
4
- width: number;
5
- words: PsDocumentTextLayerWord[];
6
- }
1
+ import type { TextLayer } from '@pallasoft/ps-utilities';
2
+ export type PsDocumentTextLayer = TextLayer;
@@ -1,4 +1,2 @@
1
- export interface PsDocumentTextSegment {
2
- matchIndex: number | null;
3
- text: string;
4
- }
1
+ import type { TextSegment } from '@pallasoft/ps-utilities';
2
+ export type PsDocumentTextSegment = TextSegment;
@@ -1,4 +1,6 @@
1
1
  export interface PsMenuPopupInsets {
2
2
  bottom: number;
3
+ left: number;
4
+ right: number;
3
5
  top: number;
4
6
  }
@@ -2,6 +2,7 @@ export interface PsMenuPopupLayout {
2
2
  isBelow: boolean;
3
3
  left: number;
4
4
  maxHeight: number;
5
+ maxWidth: number;
5
6
  top: number;
6
7
  width: number | undefined;
7
8
  }
@@ -1,7 +1,6 @@
1
1
  import type { PsDocumentHighlightRect } from '../interfaces/ps-document-highlight-rect';
2
2
  import type { PsDocumentItem } from '../interfaces/ps-document-item';
3
3
  import type { PsDocumentLabels } from '../interfaces/ps-document-labels';
4
- import type { PsDocumentNormalizedText } from '../interfaces/ps-document-normalized-text';
5
4
  import type { PsDocumentPoint } from '../interfaces/ps-document-point';
6
5
  import type { PsDocumentSearchLabels } from '../interfaces/ps-document-search-labels';
7
6
  import type { PsDocumentSearchLocation } from '../interfaces/ps-document-search-location';
@@ -14,11 +13,9 @@ import type { PsDocumentViewerEntry } from '../interfaces/ps-document-viewer-ent
14
13
  import type { PsDocumentWordMatch } from '../interfaces/ps-document-word-match';
15
14
  import type { PsSize } from '../interfaces/ps-size';
16
15
  export declare class PsDocumentSearchService {
17
- static normalize(text: string): PsDocumentNormalizedText;
18
16
  static terms(query: string): string[];
19
17
  static matches(text: string, query: string): PsDocumentSearchMatch[];
20
18
  static segments(text: string, matches: PsDocumentSearchMatch[]): PsDocumentTextSegment[];
21
- static joinedWords(layer: PsDocumentTextLayer): string;
22
19
  static wordMatches(layer: PsDocumentTextLayer, query: string): PsDocumentWordMatch[];
23
20
  static fit(layer: PsDocumentTextLayer, container: PsSize): PsDocumentTextBox;
24
21
  static rect(box: PsDocumentTextBox, layer: PsDocumentTextLayer, container: PsSize): PsDocumentTextBox;
@@ -36,5 +33,4 @@ export declare class PsDocumentSearchService {
36
33
  static countLabel(template: string, current: number, total: number): string;
37
34
  static labels(labels: PsDocumentLabels): PsDocumentSearchLabels | null;
38
35
  static isSearchable(items: PsDocumentItem[]): boolean;
39
- private static merge;
40
36
  }
@@ -1,104 +1,29 @@
1
+ import { Common } from '@pallasoft/ps-utilities';
1
2
  import { PsDocumentKind } from '../constants/ps-document-kind';
2
3
  import { PsDocumentSearchConfig } from '../constants/ps-document-search-config';
3
4
  export class PsDocumentSearchService {
4
- static normalize(text) {
5
- const starts = [];
6
- const ends = [];
7
- let value = '';
8
- let offset = 0;
9
- for (const character of Array.from(text)) {
10
- const folded = character
11
- .normalize('NFD')
12
- .replace(PsDocumentSearchConfig.combiningMarkPattern, '')
13
- .toLowerCase();
14
- for (let position = 0; position < folded.length; position += 1) {
15
- starts.push(offset);
16
- ends.push(offset + character.length);
17
- }
18
- value += folded;
19
- offset += character.length;
20
- }
21
- return { ends, starts, value };
22
- }
23
5
  static terms(query) {
24
- return PsDocumentSearchService.normalize(query)
25
- .value.split(PsDocumentSearchConfig.termSeparatorPattern)
26
- .filter((term) => term !== '');
6
+ return Common.TextSearchService.terms(query);
27
7
  }
28
8
  static matches(text, query) {
29
- const terms = PsDocumentSearchService.terms(query);
30
- if (terms.length === 0)
31
- return [];
32
- const normalized = PsDocumentSearchService.normalize(text);
33
- const ranges = [];
34
- for (const term of terms) {
35
- let from = normalized.value.indexOf(term);
36
- while (from >= 0) {
37
- ranges.push({ end: from + term.length, start: from });
38
- from = normalized.value.indexOf(term, from + term.length);
39
- }
40
- }
41
- return PsDocumentSearchService.merge(ranges).map((range) => ({
42
- end: normalized.ends[range.end - 1],
43
- start: normalized.starts[range.start],
44
- }));
9
+ return Common.TextSearchService.findTerms(text, query);
45
10
  }
46
11
  static segments(text, matches) {
47
- const segments = [];
48
- let cursor = 0;
49
- matches.forEach((match, index) => {
50
- if (match.start > cursor)
51
- segments.push({ matchIndex: null, text: text.slice(cursor, match.start) });
52
- segments.push({ matchIndex: index, text: text.slice(match.start, match.end) });
53
- cursor = match.end;
54
- });
55
- if (cursor < text.length)
56
- segments.push({ matchIndex: null, text: text.slice(cursor) });
57
- return segments;
58
- }
59
- static joinedWords(layer) {
60
- return layer.words.map((word) => word.text).join(PsDocumentSearchConfig.wordSeparator);
12
+ return Common.TextSearchService.segments(text, matches);
61
13
  }
62
14
  static wordMatches(layer, query) {
63
- const matches = PsDocumentSearchService.matches(PsDocumentSearchService.joinedWords(layer), query);
64
- const bounds = [];
65
- let cursor = 0;
66
- for (const word of layer.words) {
67
- bounds.push({ end: cursor + word.text.length, start: cursor });
68
- cursor += word.text.length + PsDocumentSearchConfig.wordSeparator.length;
69
- }
70
- return matches.map((match) => ({
71
- wordIndices: bounds.flatMap((bound, index) => bound.start < match.end && bound.end > match.start ? [index] : []),
15
+ return Common.TextLayerService.termMatches(layer, query).map((match) => ({
16
+ wordIndices: match.parts.map((part) => part.itemIndex),
72
17
  }));
73
18
  }
74
19
  static fit(layer, container) {
75
- if (layer.width <= 0 || layer.height <= 0)
76
- return { height: 0, left: 0, top: 0, width: 0 };
77
- const scale = Math.min(container.width / layer.width, container.height / layer.height);
78
- const width = layer.width * scale;
79
- const height = layer.height * scale;
80
- return {
81
- height,
82
- left: (container.width - width) / 2,
83
- top: (container.height - height) / 2,
84
- width,
85
- };
20
+ return Common.TextLayerService.fit(layer, container);
86
21
  }
87
22
  static rect(box, layer, container) {
88
- const fitted = PsDocumentSearchService.fit(layer, container);
89
- const scale = layer.width <= 0 ? 0 : fitted.width / layer.width;
90
- return {
91
- height: box.height * scale,
92
- left: fitted.left + box.left * scale,
93
- top: fitted.top + box.top * scale,
94
- width: box.width * scale,
95
- };
23
+ return Common.TextLayerService.rect(box, layer, container);
96
24
  }
97
25
  static highlights(layer, query, container, activeIndex) {
98
- return PsDocumentSearchService.wordMatches(layer, query).flatMap((match, matchIndex) => match.wordIndices.map((wordIndex) => ({
99
- box: PsDocumentSearchService.rect(layer.words[wordIndex].box, layer, container),
100
- isActive: matchIndex === activeIndex,
101
- })));
26
+ return Common.TextLayerService.wordRects(layer, Common.TextLayerService.termMatches(layer, query), container).map((rect) => ({ box: rect.box, isActive: rect.matchIndex === activeIndex }));
102
27
  }
103
28
  static center(box) {
104
29
  return { x: box.left + box.width / 2, y: box.top + box.height / 2 };
@@ -186,16 +111,4 @@ export class PsDocumentSearchService {
186
111
  item.textLayer !== undefined ||
187
112
  (item.pageTextLayers !== undefined && item.pageTextLayers.length > 0));
188
113
  }
189
- static merge(ranges) {
190
- const sorted = [...ranges].sort((a, b) => a.start === b.start ? a.end - b.end : a.start - b.start);
191
- const merged = [];
192
- for (const range of sorted) {
193
- const last = merged[merged.length - 1];
194
- if (last !== undefined && range.start < last.end)
195
- merged[merged.length - 1] = { end: Math.max(last.end, range.end), start: last.start };
196
- else
197
- merged.push({ ...range });
198
- }
199
- return merged;
200
- }
201
114
  }
@@ -0,0 +1,12 @@
1
+ import type { ViewStyle } from 'react-native';
2
+ import { PsContentWidth } from '../constants/ps-content-width';
3
+ import { PsLayoutClass } from '../constants/ps-layout-class';
4
+ export declare class PsLayoutService {
5
+ static classOf(width: number, height: number): PsLayoutClass;
6
+ static maxWidth(layoutClass: PsLayoutClass, contentWidth: PsContentWidth): number | undefined;
7
+ static frame(layoutClass: PsLayoutClass, contentWidth: PsContentWidth): ViewStyle;
8
+ static gridUnits(layoutClass: PsLayoutClass): number;
9
+ static widgetBasis(layoutClass: PsLayoutClass): string;
10
+ static widgetWidth(containerWidth: number, layoutClass: PsLayoutClass, gap: number): number | undefined;
11
+ static menuMaxWidth(windowWidth: number, edgeMargin: number): number;
12
+ }
@@ -0,0 +1,41 @@
1
+ import { PsContentWidth } from '../constants/ps-content-width';
2
+ import { PsLayoutClass } from '../constants/ps-layout-class';
3
+ import { PsLayoutClassConfig } from '../constants/ps-layout-class-config';
4
+ export class PsLayoutService {
5
+ static classOf(width, height) {
6
+ return width >= PsLayoutClassConfig.regularMinWidth &&
7
+ height >= PsLayoutClassConfig.regularMinHeight
8
+ ? PsLayoutClass.regular
9
+ : PsLayoutClass.compact;
10
+ }
11
+ static maxWidth(layoutClass, contentWidth) {
12
+ if (layoutClass === PsLayoutClass.compact || contentWidth === PsContentWidth.full)
13
+ return undefined;
14
+ return contentWidth === PsContentWidth.wide
15
+ ? PsLayoutClassConfig.wideMaxWidth
16
+ : PsLayoutClassConfig.readableMaxWidth;
17
+ }
18
+ static frame(layoutClass, contentWidth) {
19
+ const maxWidth = PsLayoutService.maxWidth(layoutClass, contentWidth);
20
+ return maxWidth === undefined ? {} : { alignSelf: 'center', maxWidth, width: '100%' };
21
+ }
22
+ static gridUnits(layoutClass) {
23
+ return layoutClass === PsLayoutClass.regular
24
+ ? PsLayoutClassConfig.regularGridUnits
25
+ : PsLayoutClassConfig.compactGridUnits;
26
+ }
27
+ static widgetBasis(layoutClass) {
28
+ return layoutClass === PsLayoutClass.regular
29
+ ? PsLayoutClassConfig.regularWidgetBasis
30
+ : PsLayoutClassConfig.compactWidgetBasis;
31
+ }
32
+ static widgetWidth(containerWidth, layoutClass, gap) {
33
+ if (layoutClass === PsLayoutClass.compact || containerWidth <= 0)
34
+ return undefined;
35
+ const columns = PsLayoutService.gridUnits(layoutClass);
36
+ return Math.max((containerWidth - gap * (columns - 1)) / columns, 0);
37
+ }
38
+ static menuMaxWidth(windowWidth, edgeMargin) {
39
+ return Math.max(windowWidth - edgeMargin * 2, 0);
40
+ }
41
+ }
@@ -3,20 +3,24 @@ export class PsMenuPopupService {
3
3
  static layout(anchor, window, insets, contentHeight, contentWidth, isFullWidth) {
4
4
  const margin = PsMenuPopupConfig.edgeMargin;
5
5
  const gap = PsMenuPopupConfig.anchorGap;
6
- const width = isFullWidth ? anchor.width : undefined;
7
- const menuWidth = width === undefined ? contentWidth : width;
6
+ const minX = Math.max(margin, insets.left);
7
+ const maxX = window.width - Math.max(margin, insets.right);
8
+ const maxWidth = Math.max(maxX - minX, 0);
9
+ const width = isFullWidth ? Math.min(anchor.width, maxWidth) : undefined;
10
+ const menuWidth = Math.min(width === undefined ? contentWidth : width, maxWidth);
8
11
  const below = window.height - (anchor.y + anchor.height) - gap - Math.max(margin, insets.bottom);
9
12
  const above = anchor.y - gap - Math.max(margin, insets.top);
10
13
  const isBelow = contentHeight <= below || below >= above;
11
14
  const room = isBelow ? below : above;
12
15
  const height = Math.min(contentHeight, Math.max(room, 0));
13
16
  const top = isBelow ? anchor.y + anchor.height + gap : anchor.y - gap - height;
14
- const alignedRight = anchor.x + menuWidth > window.width - margin;
17
+ const alignedRight = anchor.x + menuWidth > maxX;
15
18
  const left = alignedRight ? anchor.x + anchor.width - menuWidth : anchor.x;
16
19
  return {
17
20
  isBelow,
18
- left: Math.max(margin, Math.min(left, window.width - margin - menuWidth)),
21
+ left: Math.max(minX, Math.min(left, maxX - menuWidth)),
19
22
  maxHeight: Math.max(room, 0),
23
+ maxWidth,
20
24
  top,
21
25
  width,
22
26
  };
@@ -1,11 +1,14 @@
1
1
  import type { ViewStyle } from 'react-native';
2
+ import { PsLayoutClass } from '../constants/ps-layout-class';
2
3
  import type { PsSheetAction } from '../interfaces/ps-sheet-action';
3
4
  import type { PsSheetLeadingKind } from '../interfaces/ps-sheet-leading-kind';
4
5
  export declare class PsSheetService {
5
- static maxHeight(windowHeight: number): number;
6
+ static maxHeight(windowHeight: number, layoutClass?: PsLayoutClass): number;
7
+ static fittedMaxWidth(windowWidth: number, layoutClass: PsLayoutClass): number | undefined;
8
+ static supportsFormSizing(iosVersion: string | number): boolean;
6
9
  static handlesInset(os: string): boolean;
7
10
  static bottomPadding(isFloating: boolean, bottomInset: number): number;
8
- static fittedHeight(headerHeight: number, bodyHeight: number, windowHeight: number): number;
11
+ static fittedHeight(headerHeight: number, bodyHeight: number, windowHeight: number, layoutClass?: PsLayoutClass): number;
9
12
  static raisedHeight(height: number, keyboardHeight: number, windowHeight: number, topInset: number): number;
10
13
  static closeAction(label: string | undefined, onPress: () => void): PsSheetAction | undefined;
11
14
  static isActionInactive(action: PsSheetAction): boolean;
@@ -1,8 +1,21 @@
1
+ import { PsLayoutClass } from '../constants/ps-layout-class';
2
+ import { PsLayoutClassConfig } from '../constants/ps-layout-class-config';
1
3
  import { PsLayoutConfig } from '../constants/ps-layout-config';
2
4
  import { PsSheetConfig } from '../constants/ps-sheet-config';
3
5
  export class PsSheetService {
4
- static maxHeight(windowHeight) {
5
- return Math.floor(windowHeight * PsSheetConfig.maxHeightFraction);
6
+ static maxHeight(windowHeight, layoutClass = PsLayoutClass.compact) {
7
+ return Math.floor(windowHeight *
8
+ (layoutClass === PsLayoutClass.regular
9
+ ? PsLayoutClassConfig.formSheetMaxHeightFraction
10
+ : PsSheetConfig.maxHeightFraction));
11
+ }
12
+ static fittedMaxWidth(windowWidth, layoutClass) {
13
+ return layoutClass === PsLayoutClass.regular
14
+ ? Math.min(PsLayoutClassConfig.formSheetWidth, windowWidth)
15
+ : undefined;
16
+ }
17
+ static supportsFormSizing(iosVersion) {
18
+ return Number.parseInt(String(iosVersion), 10) >= PsSheetConfig.formSizingMinIos;
6
19
  }
7
20
  static handlesInset(os) {
8
21
  return os === 'ios' || os === 'android';
@@ -10,8 +23,8 @@ export class PsSheetService {
10
23
  static bottomPadding(isFloating, bottomInset) {
11
24
  return PsLayoutConfig.sheetGutter + (isFloating ? 0 : bottomInset);
12
25
  }
13
- static fittedHeight(headerHeight, bodyHeight, windowHeight) {
14
- return Math.min(Math.ceil(headerHeight + bodyHeight), PsSheetService.maxHeight(windowHeight));
26
+ static fittedHeight(headerHeight, bodyHeight, windowHeight, layoutClass = PsLayoutClass.compact) {
27
+ return Math.min(Math.ceil(headerHeight + bodyHeight), PsSheetService.maxHeight(windowHeight, layoutClass));
15
28
  }
16
29
  static raisedHeight(height, keyboardHeight, windowHeight, topInset) {
17
30
  return Math.min(height + keyboardHeight, windowHeight - topInset);
@@ -8,8 +8,9 @@ export declare class PsSortableGridService {
8
8
  id: string;
9
9
  }>(items: T[]): string[];
10
10
  static isSameOrder(first: string[], second: string[]): boolean;
11
- static rows(spans: PsSortableGridSpan[]): number[][];
12
- static layout(spans: PsSortableGridSpan[], heights: number[], width: number): PsSortableRect[];
11
+ static units(span: PsSortableGridSpan): number;
12
+ static rows(spans: PsSortableGridSpan[], capacity?: number): number[][];
13
+ static layout(spans: PsSortableGridSpan[], heights: number[], width: number, capacity?: number): PsSortableRect[];
13
14
  static extras(rects: PsSortableRect[], heights: number[]): number[];
14
15
  static natural(total: number, extra: number): number;
15
16
  static contentHeight(rects: PsSortableRect[]): number;
@@ -16,34 +16,38 @@ export class PsSortableGridService {
16
16
  static isSameOrder(first, second) {
17
17
  return first.length === second.length && first.every((id, index) => id === second[index]);
18
18
  }
19
- static rows(spans) {
20
- return spans.reduce((rows, span, index) => {
19
+ static units(span) {
20
+ return span === PsSortableGridSpan.half ? 1 : PsSortableGridConfig.fullUnits;
21
+ }
22
+ static rows(spans, capacity = PsSortableGridConfig.compactUnits) {
23
+ const rows = [];
24
+ let used = 0;
25
+ spans.forEach((span, index) => {
26
+ const units = PsSortableGridService.units(span);
21
27
  const last = rows[rows.length - 1];
22
- const canJoin = span === PsSortableGridSpan.half &&
23
- last !== undefined &&
24
- last.length === 1 &&
25
- spans[last[0]] === PsSortableGridSpan.half;
26
- if (canJoin)
28
+ if (last !== undefined && used + units <= capacity) {
27
29
  last.push(index);
28
- else
29
- rows.push([index]);
30
- return rows;
31
- }, []);
30
+ used += units;
31
+ return;
32
+ }
33
+ rows.push([index]);
34
+ used = units;
35
+ });
36
+ return rows;
32
37
  }
33
- static layout(spans, heights, width) {
34
- const half = PsSortableGridService.halfWidth(width);
38
+ static layout(spans, heights, width, capacity = PsSortableGridConfig.compactUnits) {
39
+ const gap = PsSortableGridConfig.columnGap;
35
40
  const rects = [];
36
41
  let top = 0;
37
- PsSortableGridService.rows(spans).forEach((row) => {
42
+ PsSortableGridService.rows(spans, capacity).forEach((row) => {
38
43
  const rowHeight = Math.max(...row.map((index) => heights[index]));
39
- row.forEach((index, column) => {
40
- const isHalf = spans[index] === PsSortableGridSpan.half && row.length === 2;
41
- rects[index] = {
42
- height: rowHeight,
43
- width: isHalf ? half : width,
44
- x: column === 0 ? 0 : half + PsSortableGridConfig.columnGap,
45
- y: top,
46
- };
44
+ const units = row.reduce((sum, index) => sum + PsSortableGridService.units(spans[index]), 0);
45
+ const unitWidth = Math.max(width - gap * (row.length - 1), 0) / units;
46
+ let left = 0;
47
+ row.forEach((index) => {
48
+ const itemWidth = unitWidth * PsSortableGridService.units(spans[index]);
49
+ rects[index] = { height: rowHeight, width: itemWidth, x: left, y: top };
50
+ left += itemWidth + gap;
47
51
  });
48
52
  top += rowHeight + PsSortableGridConfig.rowGap;
49
53
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pallasoft/ps-mobile-components",
3
- "version": "1.12.0",
3
+ "version": "1.13.0",
4
4
  "private": false,
5
5
  "description": "Native iOS (SwiftUI) and Android (Jetpack Compose) Ps components for Pallasoft mobile apps",
6
6
  "main": "./dist/index.js",
@@ -36,7 +36,7 @@
36
36
  "dependencies": {
37
37
  "@pallasoft/ps-design-system": "^1.19.0",
38
38
  "@pallasoft/ps-icons": "^1.12.0",
39
- "@pallasoft/ps-utilities": "^2.29.0"
39
+ "@pallasoft/ps-utilities": "^2.30.0"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "@expo/ui": "~58.0.0",
@@ -1,5 +0,0 @@
1
- export interface PsDocumentNormalizedText {
2
- ends: number[];
3
- starts: number[];
4
- value: string;
5
- }
@@ -1 +0,0 @@
1
- export {};