@breakside/jskit 2026.10.0 → 2026.26.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 (111) hide show
  1. package/Frameworks/DOM.jsframework/Info.json +2 -2
  2. package/Frameworks/DOM.jsframework/io.breakside.JSKit.DOM-bundle.js +2 -2
  3. package/Frameworks/FontKit.jsframework/Info.json +2 -2
  4. package/Frameworks/FontKit.jsframework/JS/FNTOpenTypeFont.js +331 -22
  5. package/Frameworks/FontKit.jsframework/io.breakside.JSKit.FontKit-bundle.js +2 -2
  6. package/Frameworks/Foundation.jsframework/Info.json +2 -2
  7. package/Frameworks/Foundation.jsframework/JS/JSAttributedString.js +13 -1
  8. package/Frameworks/Foundation.jsframework/JS/JSContext.js +44 -17
  9. package/Frameworks/Foundation.jsframework/JS/JSCubicBezier.js +54 -1
  10. package/Frameworks/Foundation.jsframework/JS/JSFont.js +8 -9
  11. package/Frameworks/Foundation.jsframework/JS/JSGradient.js +28 -2
  12. package/Frameworks/Foundation.jsframework/JS/JSImage+HTML.js +27 -1
  13. package/Frameworks/Foundation.jsframework/JS/JSNodeHTTPClient.js +34 -14
  14. package/Frameworks/Foundation.jsframework/JS/JSNodeURLSessionDataTask.js +2 -2
  15. package/Frameworks/Foundation.jsframework/JS/JSNumberFormatter.js +23 -1
  16. package/Frameworks/Foundation.jsframework/JS/JSPath.js +192 -6
  17. package/Frameworks/Foundation.jsframework/JS/JSPoint.js +56 -0
  18. package/Frameworks/Foundation.jsframework/JS/JSTextRun.js +21 -4
  19. package/Frameworks/Foundation.jsframework/JS/JSTextStorage.js +5 -0
  20. package/Frameworks/Foundation.jsframework/JS/JSTextTypesetter.js +6 -1
  21. package/Frameworks/Foundation.jsframework/JS/JSURLRequest.js +3 -0
  22. package/Frameworks/Foundation.jsframework/JS/JSXMLParser.js +1 -1
  23. package/Frameworks/Foundation.jsframework/JS/JSZip.js +155 -1
  24. package/Frameworks/Foundation.jsframework/io.breakside.JSKit.Foundation-bundle.js +2 -2
  25. package/Frameworks/Foundation.jsframework/sources.json +1 -0
  26. package/Frameworks/SecurityKit.jsframework/Info.json +2 -2
  27. package/Frameworks/SecurityKit.jsframework/io.breakside.JSKit.SecurityKit-bundle.js +2 -2
  28. package/Info.json +2 -2
  29. package/Node/Docs/DocClass.js +38 -1
  30. package/Node/Docs/DocComponent.js +26 -1
  31. package/Node/Docs/DocDictionaryProperty.js +8 -0
  32. package/Node/Docs/DocEnum.js +35 -2
  33. package/Node/Docs/DocEnumOption.js +3 -0
  34. package/Node/Docs/DocExtension.js +130 -0
  35. package/Node/Docs/DocFunction.js +8 -0
  36. package/Node/Docs/DocMethod.js +3 -0
  37. package/Node/Docs/DocProperty.js +11 -0
  38. package/Node/Docs/DocProtocol.js +4 -0
  39. package/Node/Docs/DocSpec.js +4 -0
  40. package/Node/Docs/DocSpecProperty.js +8 -0
  41. package/Node/Docs/DocTopicBasedComponent.js +75 -65
  42. package/Node/Documentation.js +73 -4
  43. package/Node/HTMLProjectServer.js +1 -1
  44. package/Node/Markdown.js +2 -2
  45. package/Node/io.breakside.jskit-bundle.js +3 -3
  46. package/Node/jskit +1 -0
  47. package/Resources/doc-default.css +2 -2
  48. package/Root/Frameworks/APIKit/Info.yaml +1 -1
  49. package/Root/Frameworks/APIKitTesting/Info.yaml +1 -1
  50. package/Root/Frameworks/AuthKit/Info.yaml +1 -1
  51. package/Root/Frameworks/CSSOM/Info.yaml +1 -1
  52. package/Root/Frameworks/ChartKit/Info.yaml +1 -1
  53. package/Root/Frameworks/ConferenceKit/Info.yaml +1 -1
  54. package/Root/Frameworks/DBKit/Info.yaml +1 -1
  55. package/Root/Frameworks/DOM/Info.yaml +1 -1
  56. package/Root/Frameworks/Dispatch/Info.yaml +1 -1
  57. package/Root/Frameworks/FontKit/FNTOpenTypeFont.js +331 -22
  58. package/Root/Frameworks/FontKit/Info.yaml +1 -1
  59. package/Root/Frameworks/Foundation/Info.yaml +1 -1
  60. package/Root/Frameworks/Foundation/JSAttributedString.js +13 -1
  61. package/Root/Frameworks/Foundation/JSContext.js +44 -17
  62. package/Root/Frameworks/Foundation/JSCubicBezier.js +54 -1
  63. package/Root/Frameworks/Foundation/JSFont.js +8 -9
  64. package/Root/Frameworks/Foundation/JSGradient.js +28 -2
  65. package/Root/Frameworks/Foundation/JSImage+HTML.js +27 -1
  66. package/Root/Frameworks/Foundation/JSNodeHTTPClient.js +34 -14
  67. package/Root/Frameworks/Foundation/JSNodeURLSessionDataTask.js +2 -2
  68. package/Root/Frameworks/Foundation/JSNumberFormatter.js +23 -1
  69. package/Root/Frameworks/Foundation/JSPath.js +192 -6
  70. package/Root/Frameworks/Foundation/JSPoint.js +56 -0
  71. package/Root/Frameworks/Foundation/JSTextRun.js +21 -4
  72. package/Root/Frameworks/Foundation/JSTextStorage.js +5 -0
  73. package/Root/Frameworks/Foundation/JSTextTypesetter.js +6 -1
  74. package/Root/Frameworks/Foundation/JSURLRequest.js +3 -0
  75. package/Root/Frameworks/Foundation/JSXMLParser.js +1 -1
  76. package/Root/Frameworks/Foundation/JSZip.js +155 -1
  77. package/Root/Frameworks/ImageKit/IKHTMLCanvasBitmapContext.js +187 -101
  78. package/Root/Frameworks/ImageKit/IKNodeBitmapContext.js +4 -4
  79. package/Root/Frameworks/ImageKit/Info.yaml +1 -1
  80. package/Root/Frameworks/MediaKit/Info.yaml +1 -1
  81. package/Root/Frameworks/MediaKitUI/Info.yaml +1 -1
  82. package/Root/Frameworks/NotificationKit/Info.yaml +1 -1
  83. package/Root/Frameworks/PDFKit/Info.yaml +1 -1
  84. package/Root/Frameworks/QRKit/Info.yaml +1 -1
  85. package/Root/Frameworks/SearchKit/Info.yaml +1 -1
  86. package/Root/Frameworks/SecurityKit/Info.yaml +1 -1
  87. package/Root/Frameworks/ServerKit/Info.yaml +1 -1
  88. package/Root/Frameworks/ServerKitTesting/Info.yaml +1 -1
  89. package/Root/Frameworks/TestKit/Info.yaml +1 -1
  90. package/Root/Frameworks/TestKit/TKAssert.js +4 -4
  91. package/Root/Frameworks/UIKit/Info.yaml +1 -1
  92. package/Root/Frameworks/UIKit/UIApplication.js +9 -1
  93. package/Root/Frameworks/UIKit/UICollectionView.js +4 -0
  94. package/Root/Frameworks/UIKit/UIColorPanel.js +46 -0
  95. package/Root/Frameworks/UIKit/UIColorWell.js +8 -0
  96. package/Root/Frameworks/UIKit/UIHTMLDisplayServer.js +21 -2
  97. package/Root/Frameworks/UIKit/UIHTMLDisplayServerCanvasContext.js +150 -69
  98. package/Root/Frameworks/UIKit/UIHTMLTextRun.js +5 -0
  99. package/Root/Frameworks/UIKit/UIHTMLTextTypesetter.js +18 -3
  100. package/Root/Frameworks/UIKit/UIListView.js +7 -5
  101. package/Root/Frameworks/UIKit/UIMenu.js +50 -32
  102. package/Root/Frameworks/UIKit/UIMenuItem.js +12 -0
  103. package/Root/Frameworks/UIKit/UIMenuView.js +27 -5
  104. package/Root/Frameworks/UIKit/UIPlatform.js +7 -0
  105. package/Root/Frameworks/UIKit/UIPopupButton.js +7 -1
  106. package/Root/Frameworks/UIKit/UIResponder.js +8 -0
  107. package/Root/Frameworks/UIKit/UITextEditor.js +14 -7
  108. package/Root/Frameworks/UIKit/UITokenField.js +65 -0
  109. package/Root/Frameworks/UIKit/UIToolbar.js +1 -1
  110. package/Root/Frameworks/UIKitTesting/Info.yaml +1 -1
  111. package/package.json +1 -1
@@ -477,6 +477,7 @@ JSClass("UIMenuWindowStyler", UIMenuStyler, {
477
477
  borderWidth: JSDynamicProperty('_borderWidth', 0.5),
478
478
  itemContentInsets: JSDynamicProperty('_itemContentInsets', JSInsets(2, 3, 2, 7)),
479
479
  indentationSize: JSDynamicProperty('_indentationSize', 10),
480
+ submenuIndicatorIcon: null,
480
481
  separatorSize: 10,
481
482
  separatorLineWidth: 1,
482
483
  separatorColor: null,
@@ -490,6 +491,7 @@ JSClass("UIMenuWindowStyler", UIMenuStyler, {
490
491
  this.shadowColor = JSColor.menuShadow;
491
492
  this.shadowOffset = JSPoint.Zero;
492
493
  this.separatorColor = this.disabledTextColor;
494
+ this.submenuIndicatorIcon = JSImage.initWithResourceName("UIMenuItemSubmenu", this.bundle).imageWithRenderMode(JSImage.RenderMode.template);
493
495
  },
494
496
 
495
497
  initWithSpec: function(spec){
@@ -552,8 +554,17 @@ JSClass("UIMenuWindowStyler", UIMenuStyler, {
552
554
  if (spec.containsKey('indentationSize')){
553
555
  this.indentationSize = spec.valueForKey("indentationSize", Number);
554
556
  }
557
+ if (spec.containsKey('submenuIndicatorIcon')){
558
+ this.submenuIndicatorIcon = spec.valueForKey("submenuIndicatorIcon", Number);
559
+ }else{
560
+ this.submenuIndicatorIcon = JSImage.initWithResourceName("UIMenuItemSubmenu", this.bundle).imageWithRenderMode(JSImage.RenderMode.template);
561
+ }
555
562
  },
556
563
 
564
+ bundle: JSLazyInitProperty(function(){
565
+ return JSBundle.initWithIdentifier("io.breakside.JSKit.UIKit");
566
+ }),
567
+
557
568
  presentMenuAdjacentToView: function(menu, view, preferredPlacement, spacing){
558
569
  if (preferredPlacement === undefined){
559
570
  preferredPlacement = UIMenu.Placement.below;
@@ -857,46 +868,47 @@ JSClass("UIMenuWindowStyler", UIMenuStyler, {
857
868
  invalidateMenuPresentation: function(menu){
858
869
  var window = menu.stylerProperties.window || null;
859
870
  if (window !== null && window.screen !== null){
860
- menu.updateEnabled();
861
- window.update();
862
-
863
- var screenMetrics = this.metricsForScreen(window.screen);
864
- var size = JSSize(window.frame.size);
871
+ window.invalidate();
872
+ }
873
+ },
865
874
 
866
- // Ensure we're at least the minimum width
867
- // (although max width will take precedence)
868
- if (size.width < menu._minimumWidth){
869
- size.width = menu._minimumWidth;
870
- }
875
+ repositionWindow: function(window){
876
+ var menu = window._menu;
877
+ var screenMetrics = this.metricsForScreen(window.screen);
878
+ var size = JSSize(window.frame.size);
871
879
 
872
- // Limit width to the max screen width
873
- if (size.width > screenMetrics.maximumWidth){
874
- size.width = screenMetrics.maximumWidth;
875
- }
880
+ // Ensure we're at least the minimum width
881
+ // (although max width will take precedence)
882
+ if (size.width < menu._minimumWidth){
883
+ size.width = menu._minimumWidth;
884
+ }
876
885
 
877
- // Set our origin so the origin of the target item matches the given location
878
- var origin = JSPoint(window.frame.origin);
886
+ // Limit width to the max screen width
887
+ if (size.width > screenMetrics.maximumWidth){
888
+ size.width = screenMetrics.maximumWidth;
889
+ }
879
890
 
880
- // Adjust our x position if we've overflowed
881
- var over = origin.x + size.width - screenMetrics.safeFrame.origin.x - screenMetrics.safeFrame.size.width;
882
- if (over > 0){
883
- origin.x -= over;
884
- }
885
- if (origin.x < screenMetrics.safeFrame.origin.x){
886
- origin.x = screenMetrics.safeFrame.origin.x;
887
- }
891
+ // Set our origin so the origin of the target item matches the given location
892
+ var origin = JSPoint(window.frame.origin);
888
893
 
889
- var offset = JSPoint.Zero;
894
+ // Adjust our x position if we've overflowed
895
+ var over = origin.x + size.width - screenMetrics.safeFrame.origin.x - screenMetrics.safeFrame.size.width;
896
+ if (over > 0){
897
+ origin.x -= over;
898
+ }
899
+ if (origin.x < screenMetrics.safeFrame.origin.x){
900
+ origin.x = screenMetrics.safeFrame.origin.x;
901
+ }
890
902
 
891
- // If we extend beyond the bottom, adjust our height
892
- over = origin.y + size.height - screenMetrics.safeFrame.origin.y - screenMetrics.safeFrame.size.height;
893
- if (over > 0){
894
- size.height -= over;
895
- }
903
+ var offset = JSPoint.Zero;
896
904
 
897
- window.frame = JSRect(origin, size);
898
- window.layoutIfNeeded();
905
+ // If we extend beyond the bottom, adjust our height
906
+ over = origin.y + size.height - screenMetrics.safeFrame.origin.y - screenMetrics.safeFrame.size.height;
907
+ if (over > 0){
908
+ size.height -= over;
899
909
  }
910
+
911
+ window.frame = JSRect(origin, size);
900
912
  },
901
913
 
902
914
  metricsForScreen: function(screen){
@@ -1009,6 +1021,12 @@ UIMenu.keyEquivalentCodeForKeyCode = function(keyCode){
1009
1021
  case 0xBD:
1010
1022
  characterCode = 0x2D; // -
1011
1023
  break;
1024
+ case 0xDB:
1025
+ characterCode = 0x5B; // [
1026
+ break;
1027
+ case 0xDD:
1028
+ characterCode = 0x5D; // [
1029
+ break;
1012
1030
  }
1013
1031
  }
1014
1032
  return UIMenu.keyEquivalentCodeForCharacterCode(characterCode);
@@ -25,6 +25,7 @@ JSClass("UIMenuItem", JSObject, {
25
25
  index: 0,
26
26
  title: JSDynamicProperty('_title', null),
27
27
  keyEquivalent: JSDynamicProperty('_keyEquivalent', null),
28
+ unmodifiedKeyEquivalent: JSDynamicProperty('_unmodifiedKeyEquivalent', null),
28
29
  _keyEquivalentCode: 0,
29
30
  keyModifiers: JSDynamicProperty('_keyModifiers', 0),
30
31
  image: JSDynamicProperty('_image', null),
@@ -132,11 +133,21 @@ JSClass("UIMenuItem", JSObject, {
132
133
  }
133
134
  },
134
135
 
136
+ setState: function(state){
137
+ this._state = state;
138
+ if (this.menu !== null){
139
+ this.menu._styler.invalidateMenuPresentation(this.menu);
140
+ }
141
+ },
142
+
135
143
  setEnabled: function(isEnabled){
136
144
  if (this._isSeparator){
137
145
  return;
138
146
  }
139
147
  this._isEnabled = isEnabled;
148
+ if (this.menu !== null){
149
+ this.menu._styler.invalidateMenuPresentation(this.menu);
150
+ }
140
151
  },
141
152
 
142
153
  setTag: function(tag){
@@ -160,6 +171,7 @@ JSClass("UIMenuItem", JSObject, {
160
171
  this._submenu = submenu;
161
172
  if (this._submenu !== null){
162
173
  this._submenu.supermenu = this.menu;
174
+ this._isEnabled = true;
163
175
  }
164
176
  },
165
177
 
@@ -127,6 +127,13 @@ JSClass("UIMenuWindow", UIWindow, {
127
127
  // -----------------------------------------------------------------------
128
128
  // MARK: - Upating the Window Contents
129
129
 
130
+ invalidate: function(){
131
+ this.needsUpdate = true;
132
+ this.setNeedsLayout();
133
+ },
134
+
135
+ needsUpdate: false,
136
+
130
137
  update: function(){
131
138
  var item;
132
139
  var itemView;
@@ -208,6 +215,12 @@ JSClass("UIMenuWindow", UIWindow, {
208
215
  // MARK: - Layout
209
216
 
210
217
  layoutSubviews: function(){
218
+ if (this.needsUpdate){
219
+ this._menu.updateEnabled();
220
+ this.update();
221
+ this.needsUpdate = false;
222
+ this._menu.styler.repositionWindow(this);
223
+ }
211
224
  UIMenuWindow.$super.layoutSubviews.call(this);
212
225
  var contentView = this.contentView;
213
226
  this.clipView.frame = contentView.bounds.rectWithInsets(this._capSize, 0);
@@ -928,7 +941,7 @@ JSClass("UIMenuItemView", UIView, {
928
941
  },
929
942
 
930
943
  _createSubmenuImageView: function(){
931
- this._submenuImageView = UIImageView.initWithImage(images.submenu);
944
+ this._submenuImageView = UIImageView.init();
932
945
  this.insertSubviewAboveSibling(this._submenuImageView, this.titleLabel);
933
946
  return this._submenuImageView;
934
947
  },
@@ -968,6 +981,7 @@ JSClass("UIMenuItemView", UIView, {
968
981
  }
969
982
  if (item.submenu){
970
983
  this.submenuImageView.hidden = false;
984
+ this.submenuImageView.image = item.menu.styler.submenuIndicatorIcon;
971
985
  }else if (this._submenuImageView !== null){
972
986
  this._submenuImageView.hidden = true;
973
987
  }
@@ -976,6 +990,10 @@ JSClass("UIMenuItemView", UIView, {
976
990
  this.keyLabel.text = item.keyEquivalent.toUpperCase();
977
991
  var modifierText = UIPlatform.shared.stringForKeyModifiers(item.keyModifiers);
978
992
  this.keyModifierLabel.text = modifierText;
993
+ }else if (item.unmodifiedKeyEquivalent !== null){
994
+ this.keyLabel.hidden = false;
995
+ this.keyLabel.text = item.unmodifiedKeyEquivalent.toUpperCase();
996
+ this.keyModifierLabel.text = "";
979
997
  }else if (this._keyLabel !== null){
980
998
  this._keyLabel.hidden = true;
981
999
  this._keyModifierLabel.hidden = true;
@@ -1018,7 +1036,7 @@ JSClass("UIMenuItemView", UIView, {
1018
1036
  if (this._submenuImageView !== null){
1019
1037
  this.submenuImageView.templateColor = textColor;
1020
1038
  }
1021
- if (item.keyEquivalent){
1039
+ if (item.keyEquivalent || item.unmodifiedKeyEquivalent){
1022
1040
  this.keyLabel.font = item.menu.font;
1023
1041
  this.keyLabel.textColor = textColor;
1024
1042
  this.keyModifierLabel.font = item.menu.font;
@@ -1042,6 +1060,10 @@ JSClass("UIMenuItemView", UIView, {
1042
1060
  this.addSubview(this._accessoryView);
1043
1061
  }
1044
1062
  }
1063
+ }else{
1064
+ if (this._accessoryView !== null){
1065
+ this._accessoryView.removeFromSuperview();
1066
+ }
1045
1067
  }
1046
1068
  this._accessorySize = item.accessorySize;
1047
1069
  this.setNeedsLayout();
@@ -1121,7 +1143,7 @@ JSClass("UIMenuItemView", UIView, {
1121
1143
  right -= this._submenuImageView.frame.size.width + this.contentInsets.right;
1122
1144
  }else if (this._keyLabel !== null && !this._keyLabel.hidden){
1123
1145
  this._keyLabel.frame = JSRect(right - this.keyWidth, this.contentInsets.top, this.keyWidth, this._keyLabel.font.displayLineHeight);
1124
- right -= this.keyWidth;
1146
+ right -= this.keyWidth + 2;
1125
1147
  this._keyModifierLabel.frame = JSRect(right - this._keyModifierLabel.frame.size.width, this.contentInsets.top, this._keyModifierLabel.frame.size.width, this._keyModifierLabel.font.displayLineHeight);
1126
1148
  right -= this._keyModifierLabel.frame.size.width + this.contentInsets.right;
1127
1149
  }else if (this._accessoryView !== null){
@@ -1157,9 +1179,9 @@ JSClass("UIMenuItemView", UIView, {
1157
1179
  size.width += this.titleLabel.frame.size.width;
1158
1180
  if (item.submenu !== null){
1159
1181
  size.width += this._submenuImageView.frame.size.width + this.contentInsets.right;
1160
- }else if (item.keyEquivalent){
1182
+ }else if (item.keyEquivalent || item.unmodifiedKeyEquivalent){
1161
1183
  this._keyModifierLabel.sizeToFit();
1162
- size.width += this.keyWidth + this._keyModifierLabel.frame.size.width + this.contentInsets.right;
1184
+ size.width += this.keyWidth + this._keyModifierLabel.frame.size.width + this.contentInsets.right + 2;
1163
1185
  }else{
1164
1186
  // make sure the right padding is as much as the left
1165
1187
  size.width += this.contentInsets.left - this.contentInsets.right;
@@ -23,11 +23,13 @@ JSClass("UIPlatform", JSObject, {
23
23
 
24
24
  identifier: null,
25
25
  commandModifier: UIEvent.Modifier.command,
26
+ commandKey: UIEvent.Key.command,
26
27
 
27
28
  initWithIdentifier: function(identifier){
28
29
  this.identifier = identifier;
29
30
  if (this.identifier in CommandModifiers){
30
31
  this.commandModifier = CommandModifiers[this.identifier];
32
+ this.commandKey = CommandKeys[this.identifier];
31
33
  }
32
34
  this._cachedModifierStrings = {};
33
35
  },
@@ -66,6 +68,11 @@ var CommandModifiers = {
66
68
  mac: UIEvent.Modifier.command
67
69
  };
68
70
 
71
+ var CommandKeys = {
72
+ win: UIEvent.Key.control,
73
+ mac: UIEvent.Key.command
74
+ };
75
+
69
76
  var OrderedModifiers = {
70
77
  win: [UIEvent.Modifier.option, UIEvent.Modifier.shift, UIEvent.Modifier.command, UIEvent.Modifier.control],
71
78
  mac: [UIEvent.Modifier.option, UIEvent.Modifier.control, UIEvent.Modifier.shift, UIEvent.Modifier.command]
@@ -28,7 +28,7 @@ JSClass("UIPopupButton", UIControl, {
28
28
  titleInsets: JSDynamicProperty('_titleInsets', null),
29
29
  imageView: JSReadOnlyProperty('_imageView', null),
30
30
  indicatorView: JSReadOnlyProperty('_indicatorView', null),
31
- menu: JSReadOnlyProperty('_menu', null),
31
+ menu: JSDynamicProperty('_menu', null),
32
32
  selectedIndex: JSDynamicProperty('_selectedIndex', -1),
33
33
  selectedTag: JSDynamicProperty(),
34
34
  _selectedItem: null,
@@ -280,6 +280,12 @@ JSClass("UIPopupButton", UIControl, {
280
280
 
281
281
  menuAdoptsTitleFont: true,
282
282
 
283
+ setMenu: function(menu){
284
+ this._menu = menu;
285
+ this.menuAdoptsTitleFont = false;
286
+ this.invalidateIntrinsicSize();
287
+ },
288
+
283
289
  openMenu: function(){
284
290
  if (this.menu.items.length > 0){
285
291
  if (this.menuAdoptsTitleFont){
@@ -211,4 +211,12 @@ JSClass("UIResponder", JSObject, {
211
211
  }
212
212
  },
213
213
 
214
+ getShortcutMenu: function(){
215
+ var next = this.getNextResponder();
216
+ if (next !== null){
217
+ return next.getShortcutMenu();
218
+ }
219
+ return null;
220
+ },
221
+
214
222
  });
@@ -43,6 +43,7 @@ JSClass("UITextEditor", JSObject, {
43
43
  _selectionHighlightLayers: null,
44
44
  _selectionHighlightColor: null,
45
45
  _draggingSelectionIndex: null,
46
+ _showsSelectionWhenNotFirstResponder: false,
46
47
 
47
48
  initWithTextLayer: function(textLayer){
48
49
  this.layoutLayer = textLayer;
@@ -318,8 +319,10 @@ JSClass("UITextEditor", JSObject, {
318
319
  },
319
320
 
320
321
  didResignFirstResponder: function(){
321
- this._hideCursors();
322
- this._hideSelections();
322
+ if (!this._showsSelectionWhenNotFirstResponder){
323
+ this._hideCursors();
324
+ this._hideSelections();
325
+ }
323
326
  this._isFirstResponder = false;
324
327
  this.undoManager.clear();
325
328
  },
@@ -362,8 +365,10 @@ JSClass("UITextEditor", JSObject, {
362
365
  },
363
366
 
364
367
  _positionCursors: function(){
365
- if (!this._isFirstResponder || !this._isWindowKey){
366
- return;
368
+ if (!this._showsSelectionWhenNotFirstResponder){
369
+ if (!this._isFirstResponder || !this._isWindowKey){
370
+ return;
371
+ }
367
372
  }
368
373
  var i, l;
369
374
  for (i = this._cursorLayers.length, l = this.selections.length; i < l; ++i){
@@ -452,8 +457,10 @@ JSClass("UITextEditor", JSObject, {
452
457
  // MARK: - Selection Highlights
453
458
 
454
459
  _positionSelectionHighlights: function(){
455
- if (!this._isFirstResponder || !this._isWindowKey){
456
- return;
460
+ if (!this._showsSelectionWhenNotFirstResponder){
461
+ if (!this._isFirstResponder || !this._isWindowKey){
462
+ return;
463
+ }
457
464
  }
458
465
  // TODO: show paragraph marks when highlighting
459
466
  var selectionsWithLengths = [];
@@ -883,7 +890,7 @@ JSClass("UITextEditor", JSObject, {
883
890
  if (selection.range.location >= range.end){
884
891
  selection.range = JSRange(selection.range.location + locationAdjustment, selection.range.length);
885
892
  }else if (selection.range.location >= range.location){
886
- selection.range = JSRange(range.location, Math.max(0, selection.range.length + locationAdjustment));
893
+ selection.range = JSRange(selection.range.location, Math.max(0, selection.range.length + locationAdjustment));
887
894
  }else{
888
895
  break;
889
896
  }
@@ -99,6 +99,71 @@ JSClass("UITokenField", UITextField, {
99
99
  }
100
100
  },
101
101
 
102
+ deleteBackward: function(){
103
+ var l = this.representedObjects.length;
104
+ UITokenField.$super.deleteBackward.call(this);
105
+ if (this.representedObjects.length !== l){
106
+ this.sendActionsForEvents(UIControl.Event.valueChanged);
107
+ }
108
+ },
109
+
110
+ deleteWordBackward: function(){
111
+ var l = this.representedObjects.length;
112
+ UITokenField.$super.deleteWordBackward.call(this);
113
+ if (this.representedObjects.length !== l){
114
+ this.sendActionsForEvents(UIControl.Event.valueChanged);
115
+ }
116
+ },
117
+
118
+ deleteToBeginningOfLine: function(){
119
+ var l = this.representedObjects.length;
120
+ UITokenField.$super.deleteToBeginningOfLine.call(this);
121
+ if (this.representedObjects.length !== l){
122
+ this.sendActionsForEvents(UIControl.Event.valueChanged);
123
+ }
124
+ },
125
+
126
+ deleteToBeginningOfDocument: function(){
127
+ var l = this.representedObjects.length;
128
+ UITokenField.$super.deleteToBeginningOfDocument.call(this);
129
+ if (this.representedObjects.length !== l){
130
+ this.sendActionsForEvents(UIControl.Event.valueChanged);
131
+ }
132
+ },
133
+
134
+ deleteForward: function(){
135
+ var l = this.representedObjects.length;
136
+ UITokenField.$super.deleteForward.call(this);
137
+ if (this.representedObjects.length !== l){
138
+ this.sendActionsForEvents(UIControl.Event.valueChanged);
139
+ }
140
+ },
141
+
142
+ deleteWordForward: function(){
143
+ var l = this.representedObjects.length;
144
+ UITokenField.$super.deleteWordForward.call(this);
145
+ if (this.representedObjects.length !== l){
146
+ this.sendActionsForEvents(UIControl.Event.valueChanged);
147
+ }
148
+ },
149
+
150
+ deleteToEndOfLine: function(){
151
+ var l = this.representedObjects.length;
152
+ UITokenField.$super.deleteToEndOfLine.call(this);
153
+ if (this.representedObjects.length !== l){
154
+ this.sendActionsForEvents(UIControl.Event.valueChanged);
155
+ }
156
+ },
157
+
158
+ deleteToEndOfDocument: function(){
159
+ var l = this.representedObjects.length;
160
+ UITokenField.$super.deleteToEndOfDocument.call(this);
161
+ if (this.representedObjects.length !== l){
162
+ this.sendActionsForEvents(UIControl.Event.valueChanged);
163
+ }
164
+ },
165
+
166
+
102
167
  resignFirstResponder: function(){
103
168
  UITokenField.$super.resignFirstResponder.call(this);
104
169
  this._tokenize();
@@ -524,7 +524,7 @@ JSClass("UIToolbarCustomStyler", UIToolbarStyler, {
524
524
 
525
525
  _fillInMissingStyles: function(){
526
526
  if (this.itemFont === null){
527
- this.itemFont = JSFont.systemFontOfSize(JSFont.Size.detail).fontWithWeight(JSFont.Weight.normal);
527
+ this.itemFont = JSFont.systemFontOfSize(JSFont.Size.detail).fontWithWeight(JSFont.Weight.regular);
528
528
  }
529
529
  if (this.itemColor === null){
530
530
  this.itemColor = JSColor.initWithUIStyles(JSColor.black.colorWithAlpha(0.7), JSColor.white.colorWithAlpha(0.7));
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.UIKitTesting
3
- JSBundleVersion: 2026.10.0
3
+ JSBundleVersion: 2026.26.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
package/package.json CHANGED
@@ -12,7 +12,7 @@
12
12
  "node": ">=10.10.0"
13
13
  },
14
14
  "name": "@breakside/jskit",
15
- "version": "2026.10.0",
15
+ "version": "2026.26.0",
16
16
  "license": "SEE LICENSE IN LICENSE.txt",
17
17
  "files": [
18
18
  "*"