@octane-xplat/pager 0.14.0 → 0.16.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.
@@ -1,57 +1,95 @@
1
1
  import type { LayoutChildProps, FlexContainerProps } from './props'
2
+ import { mergeStyle } from './style-merge'
2
3
 
3
4
  // start/end shorthand → flex-start/flex-end.
4
5
  const FLEX_JUSTIFY: Record<string, string> = { start: 'flex-start', end: 'flex-end' }
5
6
  const FLEX_ALIGN: Record<string, string> = { start: 'flex-start', end: 'flex-end' }
6
7
 
7
- /** NativeScript reads these attributes from each child view during parent
8
- * layout. Values are forwarded with NativeScript's own property names.
9
- * The flex-container props (justifyContent/alignItems/flexWrap/gap) land on
10
- * the host flexboxlayout itself — its own attributes, not child metadata. */
11
- export function layoutChildProps(props: LayoutChildProps & Partial<FlexContainerProps>) {
12
- const result: Record<string, any> = {}
13
- for (const key of [
14
- 'row',
15
- 'col',
16
- 'rowSpan',
17
- 'colSpan',
18
- 'dock',
19
- 'left',
20
- 'top',
21
- 'flexGrow',
22
- 'flexShrink',
23
- 'alignSelf',
24
- 'order',
25
- ] as const) {
26
- if (props[key] !== undefined) {
27
- result[key] = props[key]
8
+ /** Convert parent-layout metadata + the flex-container contract to the CSS
9
+ * style bag on the host masonview — mirrors layout-child.web.ts so the same
10
+ * component props compile to the same CSS on both targets. `dock` has no
11
+ * CSS equivalent on web (ignored there); on native it becomes absolute
12
+ * insets. Native adds `position: absolute` for edge-placed children since
13
+ * there is no `.vx-absolute > *` stylesheet rule on the mason engine. */
14
+ export function layoutChildProps(
15
+ props: LayoutChildProps & Partial<FlexContainerProps> & { style?: any },
16
+ baseStyle = props.style,
17
+ ) {
18
+ const style: Record<string, any> = { ...(typeof baseStyle === 'object' ? baseStyle : {}) }
19
+ if (props.row !== undefined) {
20
+ style.gridRow = `${props.row + 1} / span ${props.rowSpan ?? 1}`
21
+ } else if (props.rowSpan !== undefined) {
22
+ style.gridRow = `span ${props.rowSpan}`
23
+ }
24
+
25
+ if (props.col !== undefined) {
26
+ style.gridColumn = `${props.col + 1} / span ${props.colSpan ?? 1}`
27
+ } else if (props.colSpan !== undefined) {
28
+ style.gridColumn = `span ${props.colSpan}`
29
+ }
30
+
31
+ if (props.dock !== undefined) {
32
+ style.position = style.position ?? 'absolute'
33
+ if (props.dock === 'left' || props.dock === 'top' || props.dock === 'bottom') {
34
+ style.left = style.left ?? 0
35
+ }
36
+ if (props.dock === 'right' || props.dock === 'top' || props.dock === 'bottom') {
37
+ style.right = style.right ?? 0
38
+ }
39
+ if (props.dock === 'top' || props.dock === 'left' || props.dock === 'right') {
40
+ style.top = style.top ?? 0
41
+ }
42
+ if (props.dock === 'bottom' || props.dock === 'left' || props.dock === 'right') {
43
+ style.bottom = style.bottom ?? 0
28
44
  }
29
45
  }
30
46
 
31
- if (props.justifyContent !== undefined) {
32
- result.justifyContent = FLEX_JUSTIFY[props.justifyContent] ?? props.justifyContent
47
+ if (props.left !== undefined) {
48
+ style.left = props.left
49
+ }
50
+ if (props.top !== undefined) {
51
+ style.top = props.top
52
+ }
53
+ if ((props.left !== undefined || props.top !== undefined) && props.dock === undefined) {
54
+ style.position = style.position ?? 'absolute'
33
55
  }
34
56
 
35
- if (props.alignItems !== undefined) {
36
- result.alignItems = FLEX_ALIGN[props.alignItems] ?? props.alignItems
57
+ if (props.flexGrow !== undefined) {
58
+ style.flexGrow = props.flexGrow
59
+ }
60
+ if (props.flexShrink !== undefined) {
61
+ style.flexShrink = props.flexShrink
62
+ }
63
+ if (props.alignSelf !== undefined) {
64
+ style.alignSelf = props.alignSelf
65
+ }
66
+ if (props.order !== undefined) {
67
+ style.order = props.order
37
68
  }
38
69
 
70
+ // Flex-container props (View/Row/Pressable hosts) — RN vocabulary on the
71
+ // element style.
72
+ if (props.justifyContent !== undefined) {
73
+ style.justifyContent = FLEX_JUSTIFY[props.justifyContent] ?? props.justifyContent
74
+ }
75
+ if (props.alignItems !== undefined) {
76
+ style.alignItems = FLEX_ALIGN[props.alignItems] ?? props.alignItems
77
+ }
39
78
  if (props.flexWrap !== undefined) {
40
- result.flexWrap =
79
+ style.flexWrap =
41
80
  props.flexWrap === true ? 'wrap' : props.flexWrap === false ? 'nowrap' : props.flexWrap
42
81
  }
43
-
44
82
  if (props.gap !== undefined) {
45
- result.gap = props.gap
83
+ style.gap = props.gap
46
84
  }
47
-
48
85
  if (props.rowGap !== undefined) {
49
- result.rowGap = props.rowGap
86
+ style.rowGap = props.rowGap
50
87
  }
51
-
52
88
  if (props.columnGap !== undefined) {
53
- result.columnGap = props.columnGap
89
+ style.columnGap = props.columnGap
54
90
  }
55
91
 
56
- return result
92
+ // A string base is inline CSS — serialize the emitted keys under it so the
93
+ // authored declarations still win.
94
+ return { style: typeof baseStyle === 'string' ? mergeStyle(style, baseStyle) : style }
57
95
  }
@@ -0,0 +1,59 @@
1
+ const kebab = (key: string) => key.replace(/[A-Z]/g, (c) => '-' + c.toLowerCase())
2
+
3
+ /** Anything accepted as a style value, including nested arrays. */
4
+ export type StyleInput =
5
+ | string
6
+ | Record<string, any>
7
+ | null
8
+ | undefined
9
+ | readonly StyleInput[]
10
+
11
+ /** Merge component-emitted style defaults under the authored `style` prop.
12
+ * Authored keys win; array styles fold in order; a string style is appended
13
+ * after the serialized defaults so its declarations override them too. */
14
+ export function mergeStyle(
15
+ base: Record<string, any>,
16
+ style?: Record<string, any> | readonly (Record<string, any> | null | undefined)[] | null,
17
+ ): Record<string, any>
18
+ export function mergeStyle(
19
+ base: Record<string, any>,
20
+ style?: StyleInput,
21
+ ): string | Record<string, any>
22
+ export function mergeStyle(
23
+ base: Record<string, any>,
24
+ style?: StyleInput,
25
+ ): string | Record<string, any> {
26
+ if (style == null) {
27
+ return base
28
+ }
29
+
30
+ let obj: Record<string, any> = { ...base }
31
+ const strings: string[] = []
32
+ const add = (s: StyleInput) => {
33
+ if (s == null) {
34
+ return
35
+ }
36
+ if (typeof s === 'string') {
37
+ strings.push(s)
38
+ } else if (Array.isArray(s)) {
39
+ for (const part of s) {
40
+ add(part)
41
+ }
42
+ } else {
43
+ obj = { ...obj, ...s }
44
+ }
45
+ }
46
+ add(style)
47
+
48
+ if (strings.length === 0) {
49
+ return obj
50
+ }
51
+
52
+ const prefix = Object.entries(obj)
53
+ .filter(([, v]) => v != null)
54
+ .map(([k, v]) => `${kebab(k)}:${v}`)
55
+ .join(';')
56
+ return [prefix, ...strings].filter(Boolean).join(';')
57
+ }
58
+
59
+ export type StyleProp = string | Record<string, any> | readonly StyleProp[] | null | undefined
@@ -1,282 +0,0 @@
1
- import { cx } from "./cx.mobile.js";
2
- import { applyEscapeProps, nativeAccessibilityRole, nativeAccessibilityState } from "./escape-props.mobile.js";
3
- import { layoutChildProps } from "./layout-child.js";
4
- import { __methodDep } from "octane/universal/native";
5
- import { NATIVESCRIPT_RENDERER_ID, createNativeScriptRoot, defineUniversalComponent, hookSlots, memo, registerElement, universalComponent, universalIf, universalPlan, universalProps, universalValue, useCallback, useEffect, useRef } from "@nativescript-community/octane";
6
- import { Pager } from "@nativescript-community/ui-pager";
7
- import { GridLayout } from "@nativescript/core";
8
- //#region src/Pager.tsrx
9
- var _hs$ = /* @__PURE__ */ hookSlots(6);
10
- var _h$0 = /* @__PURE__ */ Symbol(_hs$);
11
- var _h$1 = /* @__PURE__ */ Symbol(_hs$ + 1);
12
- var _h$2 = /* @__PURE__ */ Symbol(_hs$ + 2);
13
- var _h$3 = /* @__PURE__ */ Symbol(_hs$ + 3);
14
- var _h$4 = /* @__PURE__ */ Symbol(_hs$ + 4);
15
- var _h$5 = /* @__PURE__ */ Symbol(_hs$ + 5);
16
- var __octaneUniversalPlan0 = universalPlan("nativescript", {
17
- "kind": "host",
18
- "type": "gridlayout",
19
- "children": [{
20
- "kind": "slot",
21
- "slot": 0
22
- }]
23
- });
24
- var __octaneUniversalPlan1 = universalPlan("nativescript", {
25
- "kind": "host",
26
- "type": "pager",
27
- "propsSlot": 0
28
- });
29
- var __octaneUniversalPlan2 = universalPlan("nativescript", {
30
- "kind": "slot",
31
- "slot": 0
32
- });
33
- var __octaneUniversalPlan3 = universalPlan("nativescript", {
34
- "kind": "range",
35
- "children": [{
36
- "kind": "slot",
37
- "slot": 0
38
- }]
39
- });
40
- var __octaneUniversalPlan4 = universalPlan("nativescript", {
41
- "kind": "slot",
42
- "slot": 0
43
- });
44
- registerElement("pager", Pager);
45
- var cellsByHost = /* @__PURE__ */ new WeakMap();
46
- var cellsByPager = /* @__PURE__ */ new WeakMap();
47
- var PagerCell = defineUniversalComponent(NATIVESCRIPT_RENDERER_ID, (props) => props.renderItem(props.item, props.index));
48
- function cellFor(host) {
49
- let cell = cellsByHost.get(host);
50
- if (!cell) {
51
- cell = {
52
- host,
53
- root: createNativeScriptRoot(host),
54
- pager: null,
55
- renderItem: null,
56
- item: void 0,
57
- index: -1
58
- };
59
- cellsByHost.set(host, cell);
60
- }
61
- return cell;
62
- }
63
- function createPageHost() {
64
- const host = new GridLayout();
65
- cellFor(host);
66
- return host;
67
- }
68
- var PAGER_TEMPLATES = [{
69
- key: "xplat-page",
70
- createView: createPageHost
71
- }];
72
- var selectPageTemplate = () => "xplat-page";
73
- function releasePagerCells(pager) {
74
- const cells = cellsByPager.get(pager);
75
- if (!cells) return;
76
- for (const cell of cells) {
77
- cellsByHost.delete(cell.host);
78
- cell.root.unmount();
79
- }
80
- cellsByPager.delete(pager);
81
- }
82
- var PagerInner = defineUniversalComponent("nativescript", function PagerInner(props) {
83
- const host = useRef(null, _h$0);
84
- const suppressEcho = useRef(false, _h$1);
85
- const pageSeeded = useRef(false, _h$2);
86
- const bindHost = useCallback((v) => {
87
- host.current = v;
88
- }, [], _h$3);
89
- const bindCell = (args) => {
90
- const cell = cellFor(args.view);
91
- cell.pager = args.object;
92
- let owned = cellsByPager.get(cell.pager);
93
- if (!owned) {
94
- owned = /* @__PURE__ */ new Set();
95
- cellsByPager.set(cell.pager, owned);
96
- }
97
- owned.add(cell);
98
- const item = args.bindingContext ?? props.items?.[args.index];
99
- if (cell.renderItem === props.renderItem && cell.index === args.index && Object.is(cell.item, item)) return;
100
- cell.renderItem = props.renderItem;
101
- cell.item = item;
102
- cell.index = args.index;
103
- cell.root.render(PagerCell, {
104
- renderItem: (it, i) => universalValue(__octaneUniversalPlan0, [props.renderItem(it, i)]),
105
- item,
106
- index: args.index
107
- });
108
- };
109
- const disposeCell = (args) => {
110
- const cell = args.view && cellsByHost.get(args.view);
111
- if (cell) {
112
- cellsByHost.delete(args.view);
113
- if (cell.pager) cellsByPager.get(cell.pager)?.delete(cell);
114
- cell.root.unmount();
115
- }
116
- };
117
- useEffect(() => {
118
- const pager = host.current;
119
- if (!pager) return;
120
- pager.itemTemplates = PAGER_TEMPLATES;
121
- pager.itemTemplateSelector = selectPageTemplate;
122
- return () => releasePagerCells(pager);
123
- }, [], _h$4);
124
- useEffect(() => {
125
- const pager = host.current;
126
- if (!pager) return;
127
- applyEscapeProps(pager, props);
128
- if (pager.items !== props.items) pager.items = props.items;
129
- const target = props.page ?? (pageSeeded.current ? void 0 : props.defaultPage);
130
- if (target !== void 0 && pager.selectedIndex !== target) {
131
- suppressEcho.current = true;
132
- try {
133
- pager.selectedIndex = target;
134
- } finally {
135
- suppressEcho.current = false;
136
- }
137
- }
138
- pageSeeded.current = true;
139
- }, [
140
- props,
141
- __methodDep(props, "items", true, true),
142
- __methodDep(props, "page", true, true),
143
- __methodDep(props, "defaultPage", true, true)
144
- ], _h$5);
145
- return universalValue(__octaneUniversalPlan1, [universalProps([
146
- [
147
- "set",
148
- "ref",
149
- bindHost
150
- ],
151
- [
152
- "set",
153
- "id",
154
- props.id
155
- ],
156
- ["spread", layoutChildProps(props)],
157
- [
158
- "set",
159
- "className",
160
- cx("vx-pager", props.className)
161
- ],
162
- [
163
- "set",
164
- "style",
165
- props.style
166
- ],
167
- [
168
- "set",
169
- "onItemLoading",
170
- bindCell
171
- ],
172
- [
173
- "set",
174
- "onItemDisposing",
175
- disposeCell
176
- ],
177
- [
178
- "set",
179
- "onSelectedIndexChange",
180
- (args) => {
181
- if (!suppressEcho.current) props.onPageChange?.(args.value);
182
- }
183
- ],
184
- [
185
- "set",
186
- "accessibilityRole",
187
- nativeAccessibilityRole(props.accessibilityRole)
188
- ],
189
- [
190
- "set",
191
- "accessibilityLabel",
192
- props.accessibilityLabel
193
- ],
194
- [
195
- "set",
196
- "accessibilityHint",
197
- props.accessibilityHint
198
- ],
199
- [
200
- "set",
201
- "accessibilityValue",
202
- props.accessibilityValue
203
- ],
204
- [
205
- "set",
206
- "accessibilityState",
207
- nativeAccessibilityState(props.accessibilityState)
208
- ],
209
- [
210
- "set",
211
- "accessible",
212
- props.accessible
213
- ],
214
- [
215
- "set",
216
- "accessibilityLiveRegion",
217
- props.accessibilityLiveRegion
218
- ]
219
- ])]);
220
- }, { "module": "@nativescript-community/octane" });
221
- var MemoPager = memo(PagerInner, (a, b) => a.items === b.items && a.className === b.className && a.style === b.style && a.id === b.id && a.page === b.page && a.onPageChange === b.onPageChange && a.ios === b.ios && a.android === b.android);
222
- var Pager$1 = defineUniversalComponent("nativescript", function Pager(props) {
223
- return universalValue(__octaneUniversalPlan4, [universalIf(props.items.length > 0, () => {
224
- return universalValue(__octaneUniversalPlan2, [universalComponent("nativescript", MemoPager, universalProps([
225
- [
226
- "set",
227
- "id",
228
- props.id
229
- ],
230
- [
231
- "set",
232
- "className",
233
- props.className
234
- ],
235
- [
236
- "set",
237
- "style",
238
- props.style
239
- ],
240
- [
241
- "set",
242
- "items",
243
- props.items
244
- ],
245
- [
246
- "set",
247
- "renderItem",
248
- props.renderItem
249
- ],
250
- [
251
- "set",
252
- "page",
253
- props.page
254
- ],
255
- [
256
- "set",
257
- "defaultPage",
258
- props.defaultPage
259
- ],
260
- [
261
- "set",
262
- "onPageChange",
263
- props.onPageChange
264
- ],
265
- [
266
- "set",
267
- "ios",
268
- props.ios
269
- ],
270
- [
271
- "set",
272
- "android",
273
- props.android
274
- ],
275
- ["spread", layoutChildProps(props)]
276
- ]))]);
277
- }, () => {
278
- return universalValue(__octaneUniversalPlan3, [props.renderEmpty?.()]);
279
- })]);
280
- }, { "module": "@nativescript-community/octane" });
281
- //#endregion
282
- export { Pager$1 as Pager };
@@ -1,12 +0,0 @@
1
- //#region src/cx.mobile.ts
2
- /** Native renderers now normalize the declarative `className` prop, but
3
- * imperative `view.className` writes still need a pre-joined string — NS
4
- * splits on ' ' only. Native leaves keep normalizing through cx() before
5
- * handing className to an intrinsic so both paths accept the same values.
6
- * (The DOM renderer already flattens arrays, so web leaves don't need
7
- * this.) */
8
- function cx(...parts) {
9
- return parts.flat(Infinity).filter(Boolean).join(" ");
10
- }
11
- //#endregion
12
- export { cx };
@@ -1,39 +0,0 @@
1
- import { isAndroid, isIOS } from "@nativescript/core";
2
- //#region src/escape-props.mobile.ts
3
- /** Apply only the active device's escape bag after the primitive's own props. */
4
- function applyEscapeProps(view, props) {
5
- if (!view) return;
6
- const bag = isIOS ? props.ios : isAndroid ? props.android : void 0;
7
- if (bag) Object.assign(view, bag);
8
- }
9
- var NATIVE_ACCESSIBILITY_ROLES = {
10
- button: "button",
11
- link: "link",
12
- search: "search",
13
- image: "image",
14
- heading: "header",
15
- adjustable: "adjustable",
16
- summary: "summary",
17
- text: "text",
18
- none: "none",
19
- progressbar: "progressBar",
20
- checkbox: "checkbox",
21
- switch: "switch",
22
- radio: "radioButton",
23
- spinbutton: "spinButton",
24
- tab: "button"
25
- };
26
- /** Translate the shared/ARIA spelling to NativeScript's narrower role enum. */
27
- function nativeAccessibilityRole(role) {
28
- return role ? NATIVE_ACCESSIBILITY_ROLES[role] : void 0;
29
- }
30
- /** NativeScript's AccessibilityState is a single enum value, unlike the
31
- * web's independent ARIA booleans. Priority follows the strongest state. */
32
- function nativeAccessibilityState(state) {
33
- if (state?.disabled) return "disabled";
34
- if (state?.selected) return "selected";
35
- if (state?.checked === true) return "checked";
36
- if (state?.checked === false) return "unchecked";
37
- }
38
- //#endregion
39
- export { applyEscapeProps, nativeAccessibilityRole, nativeAccessibilityState };
@@ -1,2 +0,0 @@
1
- import { Pager } from "./Pager.tsrx.js";
2
- export { Pager };
@@ -1,38 +0,0 @@
1
- //#region src/layout-child.ts
2
- var FLEX_JUSTIFY = {
3
- start: "flex-start",
4
- end: "flex-end"
5
- };
6
- var FLEX_ALIGN = {
7
- start: "flex-start",
8
- end: "flex-end"
9
- };
10
- /** NativeScript reads these attributes from each child view during parent
11
- * layout. Values are forwarded with NativeScript's own property names.
12
- * The flex-container props (justifyContent/alignItems/flexWrap/gap) land on
13
- * the host flexboxlayout itself — its own attributes, not child metadata. */
14
- function layoutChildProps(props) {
15
- const result = {};
16
- for (const key of [
17
- "row",
18
- "col",
19
- "rowSpan",
20
- "colSpan",
21
- "dock",
22
- "left",
23
- "top",
24
- "flexGrow",
25
- "flexShrink",
26
- "alignSelf",
27
- "order"
28
- ]) if (props[key] !== void 0) result[key] = props[key];
29
- if (props.justifyContent !== void 0) result.justifyContent = FLEX_JUSTIFY[props.justifyContent] ?? props.justifyContent;
30
- if (props.alignItems !== void 0) result.alignItems = FLEX_ALIGN[props.alignItems] ?? props.alignItems;
31
- if (props.flexWrap !== void 0) result.flexWrap = props.flexWrap === true ? "wrap" : props.flexWrap === false ? "nowrap" : props.flexWrap;
32
- if (props.gap !== void 0) result.gap = props.gap;
33
- if (props.rowGap !== void 0) result.rowGap = props.rowGap;
34
- if (props.columnGap !== void 0) result.columnGap = props.columnGap;
35
- return result;
36
- }
37
- //#endregion
38
- export { layoutChildProps };
@@ -1,8 +0,0 @@
1
- {
2
- "version": 1,
3
- "buildId": "53f3070f-3c61-4426-97a9-b21bdbd7a163",
4
- "mode": "production",
5
- "capabilities": {
6
- "independentHydration": false
7
- }
8
- }