@triniwiz/nativescript-masonkit 1.0.0-beta.85 → 1.0.0-beta.87

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 (70) hide show
  1. package/br/index.windows.d.ts +11 -0
  2. package/br/index.windows.js +31 -0
  3. package/br/index.windows.js.map +1 -0
  4. package/button/index.windows.d.ts +12 -0
  5. package/button/index.windows.js +44 -0
  6. package/button/index.windows.js.map +1 -0
  7. package/common.d.ts +2 -0
  8. package/common.js +257 -19
  9. package/common.js.map +1 -1
  10. package/img/index.windows.d.ts +12 -0
  11. package/img/index.windows.js +48 -0
  12. package/img/index.windows.js.map +1 -0
  13. package/index.windows.d.ts +12 -0
  14. package/index.windows.js +13 -0
  15. package/index.windows.js.map +1 -0
  16. package/input/index.windows.d.ts +14 -0
  17. package/input/index.windows.js +96 -0
  18. package/input/index.windows.js.map +1 -0
  19. package/li/index.windows.d.ts +13 -0
  20. package/li/index.windows.js +50 -0
  21. package/li/index.windows.js.map +1 -0
  22. package/list/common.js +0 -1
  23. package/list/common.js.map +1 -1
  24. package/list/index.ios.js +0 -1
  25. package/list/index.ios.js.map +1 -1
  26. package/list/index.windows.d.ts +21 -0
  27. package/list/index.windows.js +68 -0
  28. package/list/index.windows.js.map +1 -0
  29. package/package.json +6 -3
  30. package/platforms/ios/Mason.xcframework/ios-arm64/Mason.framework/Modules/Mason.swiftmodule/arm64-apple-ios.abi.json +2640 -11192
  31. package/platforms/ios/Mason.xcframework/ios-arm64_x86_64-simulator/Mason.framework/Modules/Mason.swiftmodule/arm64-apple-ios-simulator.abi.json +2640 -11192
  32. package/platforms/ios/Mason.xcframework/ios-arm64_x86_64-simulator/Mason.framework/Modules/Mason.swiftmodule/x86_64-apple-ios-simulator.abi.json +2640 -11192
  33. package/platforms/ios/Mason.xcframework/xros-arm64/Mason.framework/Modules/Mason.swiftmodule/arm64-apple-xros.abi.json +2640 -11192
  34. package/platforms/ios/Mason.xcframework/xros-arm64-simulator/Mason.framework/Modules/Mason.swiftmodule/arm64-apple-xros-simulator.abi.json +2640 -11192
  35. package/platforms/windows/arm64/NativeScript.Mason.dll +0 -0
  36. package/platforms/windows/arm64/NativeScript.Mason.winmd +0 -0
  37. package/platforms/windows/plugin.props +9 -0
  38. package/platforms/windows/plugin.targets +50 -0
  39. package/platforms/windows/x64/NativeScript.Mason.dll +0 -0
  40. package/platforms/windows/x64/NativeScript.Mason.winmd +0 -0
  41. package/scroll/index.windows.d.ts +14 -0
  42. package/scroll/index.windows.js +63 -0
  43. package/scroll/index.windows.js.map +1 -0
  44. package/style.d.ts +3 -0
  45. package/style.js +507 -5
  46. package/style.js.map +1 -1
  47. package/text/index.windows.d.ts +13 -0
  48. package/text/index.windows.js +39 -0
  49. package/text/index.windows.js.map +1 -0
  50. package/text-node/index.windows.d.ts +14 -0
  51. package/text-node/index.windows.js +42 -0
  52. package/text-node/index.windows.js.map +1 -0
  53. package/textarea/index.windows.d.ts +15 -0
  54. package/textarea/index.windows.js +63 -0
  55. package/textarea/index.windows.js.map +1 -0
  56. package/tree/index.windows.d.ts +36 -0
  57. package/tree/index.windows.js +68 -0
  58. package/tree/index.windows.js.map +1 -0
  59. package/utils/index.windows.d.ts +128 -0
  60. package/utils/index.windows.js +155 -0
  61. package/utils/index.windows.js.map +1 -0
  62. package/view/index.windows.d.ts +15 -0
  63. package/view/index.windows.js +52 -0
  64. package/view/index.windows.js.map +1 -0
  65. package/web.d.ts +2 -2
  66. package/web.js +2 -2
  67. package/web.js.map +1 -1
  68. package/windows-panel-helpers.d.ts +2 -0
  69. package/windows-panel-helpers.js +27 -0
  70. package/windows-panel-helpers.js.map +1 -0
package/style.js CHANGED
@@ -212,6 +212,50 @@ var StyleKeys;
212
212
  StyleKeys[StyleKeys["FONT_STRETCH"] = 588] = "FONT_STRETCH";
213
213
  StyleKeys[StyleKeys["FONT_STRETCH_STATE"] = 592] = "FONT_STRETCH_STATE";
214
214
  })(StyleKeys || (StyleKeys = {}));
215
+ // Windows: the native Style.UpdateGrid takes all grid strings at once. To set one while preserving
216
+ // the others, read the current values back from the Grid*Css getters. (Layout grid props like
217
+ // grid-auto-flow and gap are buffer-stored and already flow through the live style buffer.)
218
+ function windowsSetGrid(nativeView, field, value) {
219
+ const s = nativeView?.Style;
220
+ if (!s)
221
+ return;
222
+ const g = {
223
+ gridAutoRows: s.GridAutoRowsCss,
224
+ gridAutoColumns: s.GridAutoColumnsCss,
225
+ gridColumn: s.GridColumnCss,
226
+ gridColumnStart: s.GridColumnStartCss,
227
+ gridColumnEnd: s.GridColumnEndCss,
228
+ gridRow: s.GridRowCss,
229
+ gridRowStart: s.GridRowStartCss,
230
+ gridRowEnd: s.GridRowEndCss,
231
+ gridTemplateRows: s.GridTemplateRowsCss,
232
+ gridTemplateColumns: s.GridTemplateColumnsCss,
233
+ gridArea: s.GridAreaCss,
234
+ gridTemplateAreas: s.GridTemplateAreasCss,
235
+ };
236
+ g[field] = value ?? '';
237
+ // `grid-row` / `grid-column` are SHORTHANDS for their `{start,end}` pair. UpdateGrid applies the
238
+ // shorthand first and then the start/end parts — and the parts (read back here as their defaults
239
+ // before this change) would overwrite the span we just set, collapsing the item to a single track.
240
+ // Derive start/end from the shorthand so the three stay consistent (`span 2` -> start `span 2`,
241
+ // end auto; `1 / 3` -> start `1`, end `3`).
242
+ if (field === 'gridRow' || field === 'gridColumn') {
243
+ const parts = String(value ?? '')
244
+ .split('/')
245
+ .map((p) => p.trim());
246
+ g[field + 'Start'] = parts[0] ?? '';
247
+ g[field + 'End'] = parts.length > 1 ? (parts[1] ?? '') : '';
248
+ }
249
+ s.UpdateGrid(g.gridAutoRows, g.gridAutoColumns, g.gridColumn, g.gridColumnStart, g.gridColumnEnd, g.gridRow, g.gridRowStart, g.gridRowEnd, g.gridTemplateRows, g.gridTemplateColumns, g.gridArea, g.gridTemplateAreas);
250
+ // UpdateGrid mutates the node's (non-buffer) grid placement directly; unlike a buffer write it does
251
+ // not mark the node dirty / invalidate XAML measure, so a grid ITEM's placement change wouldn't
252
+ // re-run the parent container's grid layout. SyncStyle marks the node dirty + InvalidateMeasure,
253
+ // which propagates up to the container.
254
+ try {
255
+ nativeView.SyncStyle('0', '0');
256
+ }
257
+ catch (_) { }
258
+ }
215
259
  function parseLengthPercentageAuto(type, value) {
216
260
  switch (type) {
217
261
  case 0:
@@ -383,6 +427,233 @@ const getFloat32 = (view, offset) => {
383
427
  const setFloat32 = (view, offset, value) => {
384
428
  view.setFloat32(offset, value, true);
385
429
  };
430
+ // Split a comma-separated list at top level only (commas inside parentheses, e.g. rgba(0,0,0,.5),
431
+ // are kept with their token).
432
+ function splitTopLevelCommas(s) {
433
+ const out = [];
434
+ let depth = 0;
435
+ let cur = '';
436
+ for (const ch of s) {
437
+ if (ch === '(')
438
+ depth++;
439
+ else if (ch === ')')
440
+ depth = Math.max(0, depth - 1);
441
+ if (ch === ',' && depth === 0) {
442
+ out.push(cur);
443
+ cur = '';
444
+ }
445
+ else {
446
+ cur += ch;
447
+ }
448
+ }
449
+ if (cur.trim().length)
450
+ out.push(cur);
451
+ return out;
452
+ }
453
+ // Map a CSS gradient direction token to a CSS angle in degrees (0deg = to top, 90deg = to right).
454
+ function parseGradientAngle(token) {
455
+ const t = token.trim().toLowerCase();
456
+ const deg = /^(-?[\d.]+)deg$/.exec(t);
457
+ if (deg)
458
+ return parseFloat(deg[1]);
459
+ if (/^(-?[\d.]+)turn$/.exec(t))
460
+ return parseFloat(t) * 360;
461
+ if (/^(-?[\d.]+)rad$/.exec(t))
462
+ return (parseFloat(t) * 180) / Math.PI;
463
+ if (t === 'to top')
464
+ return 0;
465
+ if (t === 'to right')
466
+ return 90;
467
+ if (t === 'to bottom')
468
+ return 180;
469
+ if (t === 'to left')
470
+ return 270;
471
+ if (t === 'to top right' || t === 'to right top')
472
+ return 45;
473
+ if (t === 'to bottom right' || t === 'to right bottom')
474
+ return 135;
475
+ if (t === 'to bottom left' || t === 'to left bottom')
476
+ return 225;
477
+ if (t === 'to top left' || t === 'to left top')
478
+ return 315;
479
+ return 180; // CSS default is 'to bottom'
480
+ }
481
+ // Parse `linear-gradient(<dir>?, <color> <stop>?, ...)` into a CSS angle + per-stop argb + offsets.
482
+ function parseLinearGradientCss(value) {
483
+ const m = /linear-gradient\s*\(([\s\S]*)\)\s*$/i.exec(value.trim());
484
+ if (!m)
485
+ return null;
486
+ const parts = splitTopLevelCommas(m[1])
487
+ .map((p) => p.trim())
488
+ .filter(Boolean);
489
+ if (parts.length < 2)
490
+ return null;
491
+ let angle = 180;
492
+ let start = 0;
493
+ if (/^(to\s|-?[\d.]+(deg|rad|turn))/i.test(parts[0])) {
494
+ angle = parseGradientAngle(parts[0]);
495
+ start = 1;
496
+ }
497
+ const colors = [];
498
+ const offsets = [];
499
+ const stops = parts.slice(start);
500
+ for (let i = 0; i < stops.length; i++) {
501
+ // A stop is `<color> [<percentage>]`; the color is everything up to a trailing % offset.
502
+ const stop = stops[i];
503
+ const pct = /\s+(-?[\d.]+)%\s*$/.exec(stop);
504
+ const colorStr = pct ? stop.slice(0, pct.index).trim() : stop;
505
+ const argb = normalizeColorValue(colorStr);
506
+ if (argb == null)
507
+ continue;
508
+ colors.push(argb >>> 0);
509
+ offsets.push(pct ? parseFloat(pct[1]) / 100 : -1);
510
+ }
511
+ if (colors.length < 1)
512
+ return null;
513
+ // Fill any unspecified offsets evenly across [0,1].
514
+ for (let i = 0; i < offsets.length; i++) {
515
+ if (offsets[i] < 0)
516
+ offsets[i] = offsets.length > 1 ? i / (offsets.length - 1) : 0;
517
+ }
518
+ return { angle, offsets, colors };
519
+ }
520
+ // Parse one side of a padding/margin shorthand into a Length the buffer setters accept.
521
+ function parseSideLength(tok) {
522
+ if (typeof tok === 'number')
523
+ return tok;
524
+ const t = String(tok).trim();
525
+ if (t === 'auto')
526
+ return 'auto';
527
+ const m = /^(-?[\d.]+)(px|%)?$/.exec(t);
528
+ if (!m)
529
+ return 0;
530
+ const n = parseFloat(m[1]);
531
+ if (m[2] === 'px')
532
+ return { value: n, unit: 'px' };
533
+ if (m[2] === '%')
534
+ return { value: n, unit: '%' };
535
+ return n; // bare number = dip
536
+ }
537
+ // Expand a CSS padding/margin shorthand (number or 1-4 space-separated values) to per-side lengths.
538
+ function parseSidesShorthand(value) {
539
+ if (typeof value === 'number')
540
+ return { top: value, right: value, bottom: value, left: value };
541
+ const parts = String(value ?? '')
542
+ .trim()
543
+ .split(/\s+/)
544
+ .filter(Boolean)
545
+ .map(parseSideLength);
546
+ switch (parts.length) {
547
+ case 1:
548
+ return { top: parts[0], right: parts[0], bottom: parts[0], left: parts[0] };
549
+ case 2:
550
+ return { top: parts[0], right: parts[1], bottom: parts[0], left: parts[1] };
551
+ case 3:
552
+ return { top: parts[0], right: parts[1], bottom: parts[2], left: parts[1] };
553
+ case 4:
554
+ return { top: parts[0], right: parts[1], bottom: parts[2], left: parts[3] };
555
+ default:
556
+ return { top: 0, right: 0, bottom: 0, left: 0 };
557
+ }
558
+ }
559
+ // Parse a CSS `border-radius` shorthand into per-corner px radii. Handles 1-4 space-separated
560
+ // values (CSS order: top-left, top-right, bottom-right, bottom-left) and ignores the optional
561
+ // `/ <vertical>` part (we treat radii as circular). `parseFloat` strips the `px` unit.
562
+ function parseBorderRadiusShorthand(value) {
563
+ const horizontal = String(value ?? '')
564
+ .split('/')[0]
565
+ .trim();
566
+ const vals = horizontal.length ? horizontal.split(/\s+/).map((v) => parseFloat(v) || 0) : [0];
567
+ switch (vals.length) {
568
+ case 1:
569
+ return { tl: vals[0], tr: vals[0], br: vals[0], bl: vals[0] };
570
+ case 2:
571
+ return { tl: vals[0], tr: vals[1], br: vals[0], bl: vals[1] };
572
+ case 3:
573
+ return { tl: vals[0], tr: vals[1], br: vals[2], bl: vals[1] };
574
+ default:
575
+ return { tl: vals[0], tr: vals[1], br: vals[2], bl: vals[3] };
576
+ }
577
+ }
578
+ // Split on top-level whitespace, keeping parenthesised groups (e.g. `rgba(0,0,0,.5)`) intact.
579
+ function splitTopLevelSpaces(value) {
580
+ const out = [];
581
+ let depth = 0;
582
+ let cur = '';
583
+ for (let i = 0; i < value.length; i++) {
584
+ const ch = value[i];
585
+ if (ch === '(')
586
+ depth++;
587
+ else if (ch === ')')
588
+ depth = Math.max(0, depth - 1);
589
+ if (depth === 0 && /\s/.test(ch)) {
590
+ if (cur.length) {
591
+ out.push(cur);
592
+ cur = '';
593
+ }
594
+ }
595
+ else {
596
+ cur += ch;
597
+ }
598
+ }
599
+ if (cur.length)
600
+ out.push(cur);
601
+ return out;
602
+ }
603
+ // Parse a `border` / `border-<side>` shorthand (`<width> <style> <color>`, any order) into px width,
604
+ // border-style enum and argb color; each is null when absent.
605
+ function parseBorderShorthand(value) {
606
+ let width = null;
607
+ let style = null;
608
+ let color = null;
609
+ for (const tok of splitTopLevelSpaces(String(value ?? '').trim())) {
610
+ const s = borderStyleToEnum(tok);
611
+ if (s !== -1) {
612
+ style = s;
613
+ continue;
614
+ }
615
+ const lower = tok.toLowerCase();
616
+ if (lower === 'thin') {
617
+ width = 1;
618
+ continue;
619
+ }
620
+ if (lower === 'medium') {
621
+ width = 3;
622
+ continue;
623
+ }
624
+ if (lower === 'thick') {
625
+ width = 5;
626
+ continue;
627
+ }
628
+ if (/^-?\d*\.?\d+(px|dip|dp|rem|em|pt)?$/i.test(tok)) {
629
+ const n = parseFloat(tok);
630
+ if (!isNaN(n)) {
631
+ width = n;
632
+ continue;
633
+ }
634
+ }
635
+ const c = normalizeColorValue(tok);
636
+ if (c != null)
637
+ color = c;
638
+ }
639
+ return { width, style, color };
640
+ }
641
+ // Parse a 1-4 token `border-color` shorthand into per-side argb (CSS order top/right/bottom/left).
642
+ function parseSidesColorShorthand(value) {
643
+ const cols = splitTopLevelSpaces(String(value ?? '').trim()).map((t) => normalizeColorValue(t));
644
+ switch (cols.length) {
645
+ case 0:
646
+ return { t: null, r: null, b: null, l: null };
647
+ case 1:
648
+ return { t: cols[0], r: cols[0], b: cols[0], l: cols[0] };
649
+ case 2:
650
+ return { t: cols[0], r: cols[1], b: cols[0], l: cols[1] };
651
+ case 3:
652
+ return { t: cols[0], r: cols[1], b: cols[2], l: cols[1] };
653
+ default:
654
+ return { t: cols[0], r: cols[1], b: cols[2], l: cols[3] };
655
+ }
656
+ }
386
657
  const i8Buffer = new Int8Array(4);
387
658
  const f32Buffer = new Uint8Array(Float32Array.BYTES_PER_ELEMENT * 4);
388
659
  const f32View = new Float32Array(f32Buffer.buffer);
@@ -515,6 +786,20 @@ export class Style {
515
786
  ret.i8View = new Int8Array(buffer);
516
787
  ret.u8View = new Uint8Array(buffer);
517
788
  }
789
+ else if (__WINDOWS__) {
790
+ let style = nativeView?.Style;
791
+ if (!style) {
792
+ style = NativeScript.Mason.Mason.Instance().CreateNode(false).Style;
793
+ }
794
+ // Live IBuffer over the engine's arena style memory; the @nativescript/windows runtime
795
+ // projects it as a writable ArrayBuffer, so the same StyleKeys-offset writes used on
796
+ // iOS/Android land straight in the node's style.
797
+ //@ts-ignore
798
+ const buffer = NSWinRT.interop.arrayBufferFromBuffer(style.Values);
799
+ ret.style_view = new DataView(buffer);
800
+ ret.i8View = new Int8Array(buffer);
801
+ ret.u8View = new Uint8Array(buffer);
802
+ }
518
803
  //console.timeEnd('fromView');
519
804
  return ret;
520
805
  }
@@ -626,6 +911,140 @@ export class Style {
626
911
  applyApple();
627
912
  }
628
913
  }
914
+ if (__WINDOWS__) {
915
+ // Android/Apple parse these CSS-string props in native setters; on Windows we write the
916
+ // buffer-backed ones (border-radius) directly to the live style buffer so VisualApply renders
917
+ // them. Border stroke / box-shadow / gradients still need the Css decoration overlay (TODO).
918
+ this.applyWindowsCssString(name, value);
919
+ }
920
+ }
921
+ // Apply a CSS-string property on Windows. Buffer-backed props (border-radius) are written to the
922
+ // live style buffer for VisualApply; gradients use the native Css helper to paint the Panel
923
+ // background directly.
924
+ applyWindowsCssString(name, value) {
925
+ // `background` shorthand: gradient -> native Css gradient brush; solid color -> BACKGROUND_COLOR
926
+ // buffer (VisualApply paints it). Switching between them must override the other, so a gradient
927
+ // clears the solid bg first, and a solid write lets VisualApply repaint over a prior gradient brush.
928
+ if (name === 'background' || name === 'background-image') {
929
+ const v = typeof value === 'string' ? value : String(value ?? '');
930
+ if (/linear-gradient/i.test(v)) {
931
+ const g = parseLinearGradientCss(v);
932
+ if (g && g.colors.length) {
933
+ if (this.style_view) {
934
+ this.prepareMut();
935
+ setUint32(this.style_view, StyleKeys.BACKGROUND_COLOR, 0);
936
+ this.commitState(StateKeys.BACKGROUND_COLOR);
937
+ }
938
+ try {
939
+ // Pass stops as an "offset:argb,..." string — WinRT array_view params don't marshal
940
+ // reliably from the NS-Windows JS runtime (plain arrays -> E_FAIL, typed arrays -> crash).
941
+ const stops = g.offsets.map((o, i) => o + ':' + (g.colors[i] >>> 0)).join(',');
942
+ NativeScript.Mason.Css.ApplyLinearGradient(this.nativeView, g.angle, stops);
943
+ }
944
+ catch (_) { }
945
+ }
946
+ }
947
+ else if (v.trim().length && !/gradient/i.test(v)) {
948
+ // Solid color background; reuse the backgroundColor buffer setter -> VisualApply repaints,
949
+ // overriding any gradient brush set previously.
950
+ this.backgroundColor = v;
951
+ }
952
+ return;
953
+ }
954
+ // padding / margin SHORTHANDS route here (paddingProperty/marginProperty -> paddingCss/marginCss).
955
+ // Expand to the per-side buffer setters, which Mason already applies in layout.
956
+ if (name === 'padding' || name === 'margin') {
957
+ const s = parseSidesShorthand(value);
958
+ if (name === 'padding') {
959
+ this.paddingTop = s.top;
960
+ this.paddingRight = s.right;
961
+ this.paddingBottom = s.bottom;
962
+ this.paddingLeft = s.left;
963
+ }
964
+ else {
965
+ this.marginTop = s.top;
966
+ this.marginRight = s.right;
967
+ this.marginBottom = s.bottom;
968
+ this.marginLeft = s.left;
969
+ }
970
+ return;
971
+ }
972
+ if (!this.style_view) {
973
+ return;
974
+ }
975
+ if (name === 'border-radius') {
976
+ const r = parseBorderRadiusShorthand(value);
977
+ this.prepareMut();
978
+ setFloat32(this.style_view, StyleKeys.BORDER_RADIUS_TOP_LEFT_X_VALUE, r.tl);
979
+ setFloat32(this.style_view, StyleKeys.BORDER_RADIUS_TOP_LEFT_Y_VALUE, r.tl);
980
+ setFloat32(this.style_view, StyleKeys.BORDER_RADIUS_TOP_RIGHT_X_VALUE, r.tr);
981
+ setFloat32(this.style_view, StyleKeys.BORDER_RADIUS_TOP_RIGHT_Y_VALUE, r.tr);
982
+ setFloat32(this.style_view, StyleKeys.BORDER_RADIUS_BOTTOM_RIGHT_X_VALUE, r.br);
983
+ setFloat32(this.style_view, StyleKeys.BORDER_RADIUS_BOTTOM_RIGHT_Y_VALUE, r.br);
984
+ setFloat32(this.style_view, StyleKeys.BORDER_RADIUS_BOTTOM_LEFT_X_VALUE, r.bl);
985
+ setFloat32(this.style_view, StyleKeys.BORDER_RADIUS_BOTTOM_LEFT_Y_VALUE, r.bl);
986
+ // Type bytes: 0 = length (px).
987
+ setUint8(this.style_view, StyleKeys.BORDER_RADIUS_TOP_LEFT_X_TYPE, 0);
988
+ setUint8(this.style_view, StyleKeys.BORDER_RADIUS_TOP_LEFT_Y_TYPE, 0);
989
+ setUint8(this.style_view, StyleKeys.BORDER_RADIUS_TOP_RIGHT_X_TYPE, 0);
990
+ setUint8(this.style_view, StyleKeys.BORDER_RADIUS_TOP_RIGHT_Y_TYPE, 0);
991
+ setUint8(this.style_view, StyleKeys.BORDER_RADIUS_BOTTOM_RIGHT_X_TYPE, 0);
992
+ setUint8(this.style_view, StyleKeys.BORDER_RADIUS_BOTTOM_RIGHT_Y_TYPE, 0);
993
+ setUint8(this.style_view, StyleKeys.BORDER_RADIUS_BOTTOM_LEFT_X_TYPE, 0);
994
+ setUint8(this.style_view, StyleKeys.BORDER_RADIUS_BOTTOM_LEFT_Y_TYPE, 0);
995
+ this.commitState(StateKeys.BORDER_RADIUS);
996
+ return;
997
+ }
998
+ if (name === 'border' || name === 'border-top' || name === 'border-right' || name === 'border-bottom' || name === 'border-left') {
999
+ const p = parseBorderShorthand(value);
1000
+ let style = p.style;
1001
+ if (style == null && (p.width != null || p.color != null))
1002
+ style = 4; // solid
1003
+ const sides = name === 'border' ? ['left', 'right', 'top', 'bottom'] : name === 'border-left' ? ['left'] : name === 'border-right' ? ['right'] : name === 'border-top' ? ['top'] : ['bottom'];
1004
+ for (const s of sides)
1005
+ this.writeBorderSide(s, p.width, style, p.color);
1006
+ this.commitState(StateKeys.BORDER);
1007
+ this.commitState(StateKeys.BORDER_STYLE);
1008
+ this.commitState(StateKeys.BORDER_COLOR);
1009
+ return;
1010
+ }
1011
+ if (name === 'border-color') {
1012
+ const c = parseSidesColorShorthand(value);
1013
+ this.writeBorderSide('top', null, null, c.t);
1014
+ this.writeBorderSide('right', null, null, c.r);
1015
+ this.writeBorderSide('bottom', null, null, c.b);
1016
+ this.writeBorderSide('left', null, null, c.l);
1017
+ this.commitState(StateKeys.BORDER_COLOR);
1018
+ return;
1019
+ }
1020
+ }
1021
+ // Write one side's border width/style/color into the style buffer; null components are skipped.
1022
+ writeBorderSide(side, width, style, color) {
1023
+ if (!this.style_view)
1024
+ return;
1025
+ const W = side === 'left' ? StyleKeys.BORDER_LEFT_VALUE : side === 'right' ? StyleKeys.BORDER_RIGHT_VALUE : side === 'top' ? StyleKeys.BORDER_TOP_VALUE : StyleKeys.BORDER_BOTTOM_VALUE;
1026
+ const T = side === 'left' ? StyleKeys.BORDER_LEFT_TYPE : side === 'right' ? StyleKeys.BORDER_RIGHT_TYPE : side === 'top' ? StyleKeys.BORDER_TOP_TYPE : StyleKeys.BORDER_BOTTOM_TYPE;
1027
+ const S = side === 'left' ? StyleKeys.BORDER_LEFT_STYLE : side === 'right' ? StyleKeys.BORDER_RIGHT_STYLE : side === 'top' ? StyleKeys.BORDER_TOP_STYLE : StyleKeys.BORDER_BOTTOM_STYLE;
1028
+ const C = side === 'left' ? StyleKeys.BORDER_LEFT_COLOR : side === 'right' ? StyleKeys.BORDER_RIGHT_COLOR : side === 'top' ? StyleKeys.BORDER_TOP_COLOR : StyleKeys.BORDER_BOTTOM_COLOR;
1029
+ this.prepareMut();
1030
+ if (width != null) {
1031
+ setInt8(this.style_view, T, 0);
1032
+ setFloat32(this.style_view, W, width);
1033
+ }
1034
+ if (style != null)
1035
+ setInt8(this.style_view, S, style);
1036
+ if (color != null)
1037
+ setUint32(this.style_view, C, color >>> 0);
1038
+ }
1039
+ setBorderColor(value) {
1040
+ if (!__WINDOWS__ || !this.style_view)
1041
+ return;
1042
+ const c = parseSidesColorShorthand(String(value ?? ''));
1043
+ this.writeBorderSide('top', null, null, c.t);
1044
+ this.writeBorderSide('right', null, null, c.r);
1045
+ this.writeBorderSide('bottom', null, null, c.b);
1046
+ this.writeBorderSide('left', null, null, c.l);
1047
+ this.commitState(StateKeys.BORDER_COLOR);
629
1048
  }
630
1049
  resetState() {
631
1050
  this.isDirty = -1n;
@@ -643,6 +1062,11 @@ export class Style {
643
1062
  // @ts-ignore
644
1063
  view.mason_syncStyle(low, high);
645
1064
  }
1065
+ else if (__WINDOWS__) {
1066
+ // @ts-ignore
1067
+ const view = this.view?.windows ?? this.view._view;
1068
+ view.SyncStyle(low, high);
1069
+ }
646
1070
  this.resetState();
647
1071
  }
648
1072
  setOrAppendState(value) {
@@ -709,6 +1133,17 @@ export class Style {
709
1133
  this.i8View = new Int8Array(buffer);
710
1134
  this.u8View = new Uint8Array(buffer);
711
1135
  }
1136
+ if (__WINDOWS__) {
1137
+ let style = this.nativeView?.Style;
1138
+ if (!style) {
1139
+ style = NativeScript.Mason.Mason.Instance().CreateNode(false).Style;
1140
+ }
1141
+ style.PrepareForMutation();
1142
+ const buffer = style.Values;
1143
+ this.style_view = new DataView(buffer);
1144
+ this.i8View = new Int8Array(buffer);
1145
+ this.u8View = new Uint8Array(buffer);
1146
+ }
712
1147
  }
713
1148
  }
714
1149
  get boxSizing() {
@@ -1212,10 +1647,27 @@ export class Style {
1212
1647
  }
1213
1648
  set width(value) {
1214
1649
  switch (typeof value) {
1215
- case 'string':
1650
+ case 'string': {
1651
+ // Parse the string instead of forcing `auto`. Reactively-applied sizes arrive as strings
1652
+ // ("48", "48px", "50%") — the old stub dropped them to auto (0), so dynamically-added boxes
1653
+ // rendered 0x0. unitless/dip → device pixels; px → as-is; % → percent.
1216
1654
  this.prepareMut();
1217
- setInt8(this.style_view, StyleKeys.WIDTH_TYPE, 0);
1655
+ const t = value.trim();
1656
+ if (t === '' || t === 'auto') {
1657
+ setInt8(this.style_view, StyleKeys.WIDTH_TYPE, 0);
1658
+ setFloat32(this.style_view, StyleKeys.WIDTH_VALUE, 0);
1659
+ }
1660
+ else if (t.endsWith('%')) {
1661
+ setInt8(this.style_view, StyleKeys.WIDTH_TYPE, 2);
1662
+ setFloat32(this.style_view, StyleKeys.WIDTH_VALUE, parseFloat(t) || 0);
1663
+ }
1664
+ else {
1665
+ const n = parseFloat(t) || 0;
1666
+ setInt8(this.style_view, StyleKeys.WIDTH_TYPE, 1);
1667
+ setFloat32(this.style_view, StyleKeys.WIDTH_VALUE, t.endsWith('px') ? n : layout.toDevicePixels(n));
1668
+ }
1218
1669
  break;
1670
+ }
1219
1671
  case 'number':
1220
1672
  this.prepareMut();
1221
1673
  setInt8(this.style_view, StyleKeys.WIDTH_TYPE, 1);
@@ -1250,11 +1702,25 @@ export class Style {
1250
1702
  }
1251
1703
  set height(value) {
1252
1704
  switch (typeof value) {
1253
- case 'string':
1705
+ case 'string': {
1706
+ // Parse the string (see width setter) — the old stub forced auto/0, breaking string sizes.
1254
1707
  this.prepareMut();
1255
- setInt8(this.style_view, StyleKeys.HEIGHT_TYPE, 0);
1256
- setFloat32(this.style_view, StyleKeys.HEIGHT_VALUE, 0);
1708
+ const t = value.trim();
1709
+ if (t === '' || t === 'auto') {
1710
+ setInt8(this.style_view, StyleKeys.HEIGHT_TYPE, 0);
1711
+ setFloat32(this.style_view, StyleKeys.HEIGHT_VALUE, 0);
1712
+ }
1713
+ else if (t.endsWith('%')) {
1714
+ setInt8(this.style_view, StyleKeys.HEIGHT_TYPE, 2);
1715
+ setFloat32(this.style_view, StyleKeys.HEIGHT_VALUE, parseFloat(t) || 0);
1716
+ }
1717
+ else {
1718
+ const n = parseFloat(t) || 0;
1719
+ setInt8(this.style_view, StyleKeys.HEIGHT_TYPE, 1);
1720
+ setFloat32(this.style_view, StyleKeys.HEIGHT_VALUE, t.endsWith('px') ? n : layout.toDevicePixels(n));
1721
+ }
1257
1722
  break;
1723
+ }
1258
1724
  case 'number':
1259
1725
  this.prepareMut();
1260
1726
  setInt8(this.style_view, StyleKeys.HEIGHT_TYPE, 1);
@@ -2520,6 +2986,9 @@ export class Style {
2520
2986
  if (__APPLE__) {
2521
2987
  this.nativeView.style.gridAutoRows = value;
2522
2988
  }
2989
+ if (__WINDOWS__) {
2990
+ windowsSetGrid(this.nativeView, 'gridAutoRows', value);
2991
+ }
2523
2992
  }
2524
2993
  get gridAutoColumns() {
2525
2994
  if (!this.nativeView) {
@@ -2543,6 +3012,9 @@ export class Style {
2543
3012
  if (__APPLE__) {
2544
3013
  this.nativeView.style.gridAutoColumns = value;
2545
3014
  }
3015
+ if (__WINDOWS__) {
3016
+ windowsSetGrid(this.nativeView, 'gridAutoColumns', value);
3017
+ }
2546
3018
  }
2547
3019
  get gridAutoFlow() {
2548
3020
  switch (getInt8(this.style_view, StyleKeys.GRID_AUTO_FLOW)) {
@@ -2586,6 +3058,9 @@ export class Style {
2586
3058
  if (__APPLE__) {
2587
3059
  this.nativeView.style.gridColumn = value;
2588
3060
  }
3061
+ if (__WINDOWS__) {
3062
+ windowsSetGrid(this.nativeView, 'gridColumn', value);
3063
+ }
2589
3064
  }
2590
3065
  get gridColumn() {
2591
3066
  if (!this.nativeView) {
@@ -2621,6 +3096,9 @@ export class Style {
2621
3096
  if (__APPLE__) {
2622
3097
  this.nativeView.style.gridColumnStart = value;
2623
3098
  }
3099
+ if (__WINDOWS__) {
3100
+ windowsSetGrid(this.nativeView, 'gridColumnStart', value);
3101
+ }
2624
3102
  }
2625
3103
  get gridColumnEnd() {
2626
3104
  if (!this.nativeView) {
@@ -2644,6 +3122,9 @@ export class Style {
2644
3122
  if (__APPLE__) {
2645
3123
  this.nativeView.style.gridColumnEnd = value;
2646
3124
  }
3125
+ if (__WINDOWS__) {
3126
+ windowsSetGrid(this.nativeView, 'gridColumnEnd', value);
3127
+ }
2647
3128
  }
2648
3129
  set gridRow(value) {
2649
3130
  if (!this.nativeView) {
@@ -2655,6 +3136,9 @@ export class Style {
2655
3136
  if (__APPLE__) {
2656
3137
  this.nativeView.style.gridRow = value;
2657
3138
  }
3139
+ if (__WINDOWS__) {
3140
+ windowsSetGrid(this.nativeView, 'gridRow', value);
3141
+ }
2658
3142
  }
2659
3143
  get gridRow() {
2660
3144
  if (!this.nativeView) {
@@ -2690,6 +3174,9 @@ export class Style {
2690
3174
  if (__APPLE__) {
2691
3175
  this.nativeView.style.gridRowStart = value;
2692
3176
  }
3177
+ if (__WINDOWS__) {
3178
+ windowsSetGrid(this.nativeView, 'gridRowStart', value);
3179
+ }
2693
3180
  }
2694
3181
  get gridRowEnd() {
2695
3182
  if (!this.nativeView) {
@@ -2713,6 +3200,9 @@ export class Style {
2713
3200
  if (__APPLE__) {
2714
3201
  this.nativeView.style.gridRowEnd = value;
2715
3202
  }
3203
+ if (__WINDOWS__) {
3204
+ windowsSetGrid(this.nativeView, 'gridRowEnd', value);
3205
+ }
2716
3206
  }
2717
3207
  set gridArea(value) {
2718
3208
  if (!this.nativeView) {
@@ -2724,6 +3214,9 @@ export class Style {
2724
3214
  if (__APPLE__) {
2725
3215
  this.nativeView.style.gridArea = value;
2726
3216
  }
3217
+ if (__WINDOWS__) {
3218
+ windowsSetGrid(this.nativeView, 'gridArea', value);
3219
+ }
2727
3220
  }
2728
3221
  get gridArea() {
2729
3222
  if (!this.nativeView) {
@@ -2750,6 +3243,9 @@ export class Style {
2750
3243
  if (__APPLE__) {
2751
3244
  this.nativeView.style.gridTemplateRows = value;
2752
3245
  }
3246
+ if (__WINDOWS__) {
3247
+ windowsSetGrid(this.nativeView, 'gridTemplateRows', value);
3248
+ }
2753
3249
  }
2754
3250
  get gridTemplateRows() {
2755
3251
  if (!this.nativeView) {
@@ -2788,6 +3284,9 @@ export class Style {
2788
3284
  if (__APPLE__) {
2789
3285
  this.nativeView.style.gridTemplateColumns = value;
2790
3286
  }
3287
+ if (__WINDOWS__) {
3288
+ windowsSetGrid(this.nativeView, 'gridTemplateColumns', value);
3289
+ }
2791
3290
  }
2792
3291
  get gridTemplateAreas() {
2793
3292
  if (!this.nativeView) {
@@ -2813,6 +3312,9 @@ export class Style {
2813
3312
  if (__APPLE__) {
2814
3313
  this.nativeView.style.gridTemplateAreas = value;
2815
3314
  }
3315
+ if (__WINDOWS__) {
3316
+ windowsSetGrid(this.nativeView, 'gridTemplateAreas', value);
3317
+ }
2816
3318
  }
2817
3319
  get overflow() {
2818
3320
  const x = this.overflowX;