tungsten 0.2.7 → 0.2.8

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.d.ts +3 -1
  2. package/dist/Components.d.ts.map +1 -1
  3. package/dist/Components.js +100 -51
  4. package/dist/DomNodes.js +2 -2
  5. package/dist/FrameworkConfig.d.ts +2 -0
  6. package/dist/FrameworkConfig.d.ts.map +1 -1
  7. package/dist/FunctionComponentStandIn.d.ts +2 -0
  8. package/dist/FunctionComponentStandIn.d.ts.map +1 -1
  9. package/dist/FunctionComponentStandIn.js +16 -3
  10. package/dist/Instance/ClientRuntimeContext.d.ts +8 -0
  11. package/dist/Instance/ClientRuntimeContext.d.ts.map +1 -0
  12. package/dist/Instance/ClientRuntimeContext.js +1 -0
  13. package/dist/Instance/Instance.d.ts +20 -1
  14. package/dist/Instance/Instance.d.ts.map +1 -1
  15. package/dist/Instance/Instance.js +59 -11
  16. package/dist/Servers/loadEnvsDev.d.ts +1 -1
  17. package/dist/Servers/loadEnvsDev.d.ts.map +1 -1
  18. package/dist/Servers/loadEnvsDev.js +18 -3
  19. package/dist/Store/makeStore.d.ts.map +1 -1
  20. package/dist/Store/makeStore.js +7 -14
  21. package/dist/babelPlugins/BabelTransformPackageImports.d.ts +1 -0
  22. package/dist/babelPlugins/BabelTransformPackageImports.d.ts.map +1 -1
  23. package/dist/babelPlugins/BabelTransformPackageImports.js +109 -70
  24. package/dist/bin/commands/compile.sxyt.js +76 -1
  25. package/dist/build/compileJavascript.d.ts.map +1 -1
  26. package/dist/build/compileJavascript.js +13 -1
  27. package/dist/build/makeBabelUserDevConfig.d.ts +1 -1
  28. package/dist/build/makeBabelUserDevConfig.d.ts.map +1 -1
  29. package/dist/build/makeBabelUserDevConfig.js +2 -1
  30. package/dist/findUserConfig.d.ts +1 -1
  31. package/dist/findUserConfig.d.ts.map +1 -1
  32. package/dist/findUserConfig.js +2 -2
  33. package/dist/frameworkConfigSchema.d.ts +4 -0
  34. package/dist/frameworkConfigSchema.d.ts.map +1 -1
  35. package/dist/frameworkConfigSchema.js +1 -0
  36. package/dist/getUserConfig.d.ts +1 -1
  37. package/dist/getUserConfig.d.ts.map +1 -1
  38. package/dist/getUserConfig.js +2 -2
  39. package/dist/hooks/useState.js +1 -1
  40. package/dist/indexInner.d.ts +0 -1
  41. package/dist/indexInner.d.ts.map +1 -1
  42. package/dist/indexInner.js +1 -1
  43. package/dist/testing/createTestApp.sxyt.d.ts +2 -0
  44. package/dist/testing/createTestApp.sxyt.d.ts.map +1 -0
  45. package/dist/testing/createTestApp.sxyt.js +424 -0
  46. package/dist/testing/ensureTestEnvLoaded.d.ts +2 -0
  47. package/dist/testing/ensureTestEnvLoaded.d.ts.map +1 -0
  48. package/dist/testing/ensureTestEnvLoaded.js +19 -0
  49. package/dist/testing/index.d.ts +36 -0
  50. package/dist/testing/index.d.ts.map +1 -0
  51. package/dist/testing/index.js +156 -0
  52. package/dist/update/UpdateScheduler.d.ts +17 -0
  53. package/dist/update/UpdateScheduler.d.ts.map +1 -0
  54. package/dist/update/UpdateScheduler.js +113 -0
  55. package/dist/update/integrateUpdateVdom.d.ts +11 -1
  56. package/dist/update/integrateUpdateVdom.d.ts.map +1 -1
  57. package/dist/update/integrateUpdateVdom.js +117 -59
  58. package/dist/{react-zone.d.ts → zones/react.d.ts} +5 -5
  59. package/dist/zones/react.d.ts.map +1 -0
  60. package/dist/{react-zone.js → zones/react.js} +3 -3
  61. package/package.json +4 -2
  62. package/readme.md +80 -0
  63. package/dist/react-zone.d.ts.map +0 -1
@@ -393,7 +393,7 @@ async function updateHtmlElement(tungstenElement, instance, newNode, oldNode, do
393
393
  debug('updating html node', newNode[$type]);
394
394
  // !!!! update
395
395
  const domNode = oldNode.domNode;
396
- updateAttributes(newNode, oldNode, domNode);
396
+ updateAttributes(tungstenElement, instance, newNode, oldNode, domNode);
397
397
  domPointer.increment();
398
398
  debug(`!!!!dom pointer index is`, domPointer.index, 'after updating html node');
399
399
  // !!! handle children
@@ -477,8 +477,9 @@ function moveDomNode(domNode, domPointer) {
477
477
  //console.log('moving domNode', domNode)
478
478
  if (domPointer.positionOf(domNode) !== domPointer.index) {
479
479
  //console.log('document.activeElement', document.activeElement, domNode == document.activeElement, domNode === document.activeElement)
480
- const hasFocus = domNode === document.activeElement;
481
- const activeElement = document.activeElement;
480
+ const ownerDocument = domNode.ownerDocument;
481
+ const hasFocus = domNode === ownerDocument.activeElement;
482
+ const activeElement = ownerDocument.activeElement;
482
483
  if (domPointer.index >= domPointer.parent.childNodes.length) {
483
484
  //console.log('appending', domNode)
484
485
  domPointer.parent.appendChild(domNode);
@@ -493,7 +494,7 @@ function moveDomNode(domNode, domPointer) {
493
494
  }
494
495
  domPointer.increment();
495
496
  }
496
- function deleteNodeIfRendered(node) {
497
+ export function deleteNodeIfRendered(node) {
497
498
  //console.log('-deleteNodeIfRendered', node)
498
499
  debug('-deleteNodeIfRendered', node);
499
500
  if (node !== $contentNull && !RenderedContentNodeIsNonRendered(node)) {
@@ -511,7 +512,10 @@ function deleteNodeIfRendered(node) {
511
512
  throwError('deleteNodeIfRendered', 'has been asked to remove the head node, this should not occur');
512
513
  } else if (RenderedContentNodeSingleIsHtml(node)) {
513
514
  debug('delete node html', node);
514
- //node
515
+ deleteNodeIfRendered(node.renderedChildren);
516
+ if ('ref' in node[$props] && node[$props].ref?.current === node.domNode) {
517
+ node[$props].ref.current = null;
518
+ }
515
519
  node.domNode.remove();
516
520
  } else if (RenderedContentNodeSingleIsComponent(node)) {
517
521
  //console.log('***delete component', node.element.__currentContent)
@@ -578,7 +582,7 @@ function createComment({
578
582
  }) {
579
583
  debug('-createComment');
580
584
  //console.log('createComment', text)
581
- const comment = document.createComment(text);
585
+ const comment = documentFromParent(domPointer.parent).createComment(text);
582
586
  if (domPointer.index >= domPointer.parent.childNodes.length) {
583
587
  domPointer.parent.appendChild(comment);
584
588
  } else {
@@ -727,7 +731,7 @@ function createLiteral(value, domPointer) {
727
731
  const text = String(value);
728
732
  debug('dom parent', domPointer.parent);
729
733
  debug('dom index', domPointer.index);
730
- const textNode = document.createTextNode(text);
734
+ const textNode = documentFromParent(domPointer.parent).createTextNode(text);
731
735
  if (domPointer.parent.childNodes.length === domPointer.index) {
732
736
  domPointer.parent.appendChild(textNode);
733
737
  } else {
@@ -752,8 +756,8 @@ async function createHtmlElement(tungstenElement, instance, node, domPointer, pa
752
756
  //console.log('Process HTML El')
753
757
  processHtmlNode(node, parentNode);
754
758
  debug('-createHtmlElement', node);
755
- const htmlEl = document.createElement(node[$type]);
756
- addAttributes(node, htmlEl);
759
+ const htmlEl = documentFromParent(domPointer.parent).createElement(node[$type]);
760
+ addAttributes(tungstenElement, instance, node, htmlEl);
757
761
  if (node[$type] === 'head') {
758
762
  for (const el of instance.persistentHeadChildren) {
759
763
  htmlEl.appendChild(el.cloneNode(true));
@@ -801,7 +805,7 @@ async function createHtmlElement(tungstenElement, instance, node, domPointer, pa
801
805
  function removeAttribute(htmlElement, attr) {
802
806
  if (attr === 'checked') htmlElement.checked = false;else htmlElement.removeAttribute(attr);
803
807
  }
804
- function addAttributes(node, domNode) {
808
+ function addAttributes(tungstenElement, instance, node, domNode) {
805
809
  //console.log('-addAttributes', node)
806
810
  const attributes = processAttributes(node);
807
811
  debug('attributes', attributes);
@@ -812,7 +816,7 @@ function addAttributes(node, domNode) {
812
816
  const eventName = htmlEvents[key];
813
817
  todo('addAttributes() warning - ensure type safety of event names');
814
818
  todo('addAttributes() warning - ensure type safety of event listener'); // we need to set all possible event listeners to take only EventListener funcs
815
- const handler = attributes[key];
819
+ const handler = makeEventListener(tungstenElement, instance, eventName, attributes[key]);
816
820
  // // if its a button without type="submit", prevent default to stop it from submitting forms
817
821
  // const handler = (key === 'onClick' && node[$type] === 'button' && node[$props].type !== 'submit')
818
822
  // ? (event: Event) => { event.preventDefault(); return (attributes[key] as EventListener)(event) }
@@ -835,8 +839,7 @@ function addAttributes(node, domNode) {
835
839
  domNode.__tungsten_oldAttributes = attributes;
836
840
  return attributes;
837
841
  }
838
- const clickEvents = [['onClick', 'click']];
839
- function updateAttributes(node, oldNode, domNodeHTMLElement) {
842
+ function updateAttributes(tungstenElement, instance, node, oldNode, domNodeHTMLElement) {
840
843
  //console.log('-updateAttributes node', node)
841
844
  //console.log('domNodeHTMLElement', domNodeHTMLElement)
842
845
  const domNode = domNodeHTMLElement;
@@ -853,8 +856,14 @@ function updateAttributes(node, oldNode, domNodeHTMLElement) {
853
856
  debug('oldAttributes', oldAttributes);
854
857
  for (const attr in oldAttributes) {
855
858
  if (!(attr in newAttributes)) {
856
- debug('remove attr', attr);
857
- removeAttribute(domNode, attr);
859
+ if (StringIsHtmlEvent(attr)) {
860
+ const eventName = htmlEvents[attr];
861
+ const listener = domNode[htmlEventHandlerKey(eventName)];
862
+ if (listener !== undefined) domNode.removeEventListener(eventName, listener);
863
+ } else {
864
+ debug('remove attr', attr);
865
+ removeAttribute(domNode, attr);
866
+ }
858
867
  }
859
868
  }
860
869
  // for (const attr of domNode.attributes) {
@@ -863,57 +872,48 @@ function updateAttributes(node, oldNode, domNodeHTMLElement) {
863
872
  // removeAttribute(domNode, attr.name)
864
873
  // }
865
874
  // }
866
- //if (attributes.onClick !== undefined)
867
- for (const [event, eventName] of clickEvents) {
868
- if (newAttributes[event] === undefined) {
869
- debug('remove event', eventName);
870
- //!!
871
- domNode.removeEventListener(eventName, domNode[htmlEventHandlerKey(eventName)]);
872
- }
873
- }
874
875
  for (const key in newAttributes) {
875
- switch (key) {
876
- case 'onClick':
877
- {
878
- debug('add onclick');
879
- const clickHandlerKey = htmlEventHandlerKey('click');
880
- debug('domNode.' + clickHandlerKey, domNode[clickHandlerKey]);
881
- if ('clickHandlerKey' in domNode) {
882
- domNode.removeEventListener('click', domNode[clickHandlerKey]);
883
- }
884
- // if its a button without type="submit", prevent default to stop it from submitting forms
885
- const handler = newAttributes[key];
886
- // const handler = (key === 'onClick' && node[$type] === 'button' && node[$props].type !== 'submit')
887
- // ? (event: Event) => { event.preventDefault(); return (attributes[key] as EventListener)(event) }
888
- // : attributes[key] as EventListener
889
- todo(`Ensure type safety on event listener`);
890
- domNode.addEventListener('click', handler);
891
- domNode[clickHandlerKey] = handler;
892
- debug('added event handler', domNode[clickHandlerKey]);
893
- break;
894
- }
895
- default:
896
- {
897
- //console.log('add/set attr', domNode, key, attributes[key], String(attributes[key]))
898
- //if (domNode.tagName === 'input' || domNode.tagName === 'INPUT') continue
899
- // try to set value directly for inputs that aren't updating with the below code
900
- if (key === 'value') {
901
- domNode.value = String(newAttributes[key]);
902
- } else {
903
- if (typeof newAttributes[key] === 'boolean') {
904
- if (newAttributes[key]) domNode.setAttribute(key, '');else removeAttribute(domNode, key);
905
- } else if (newAttributes[key] === undefined || newAttributes[key] === null) {
906
- removeAttribute(domNode, key);
907
- } else {
908
- domNode.setAttribute(key, String(newAttributes[key]));
909
- }
910
- }
876
+ if (StringIsHtmlEvent(key)) {
877
+ const eventName = htmlEvents[key];
878
+ const listenerKey = htmlEventHandlerKey(eventName);
879
+ const oldHandler = oldAttributes?.[key];
880
+ if (oldHandler !== newAttributes[key]) {
881
+ const oldListener = domNode[listenerKey];
882
+ if (oldListener !== undefined) domNode.removeEventListener(eventName, oldListener);
883
+ const listener = makeEventListener(tungstenElement, instance, eventName, newAttributes[key]);
884
+ domNode.addEventListener(eventName, listener);
885
+ domNode[listenerKey] = listener;
886
+ }
887
+ } else {
888
+ //console.log('add/set attr', domNode, key, attributes[key], String(attributes[key]))
889
+ //if (domNode.tagName === 'input' || domNode.tagName === 'INPUT') continue
890
+ // try to set value directly for inputs that aren't updating with the below code
891
+ if (key === 'value') {
892
+ domNode.value = String(newAttributes[key]);
893
+ } else {
894
+ if (typeof newAttributes[key] === 'boolean') {
895
+ if (newAttributes[key]) domNode.setAttribute(key, '');else removeAttribute(domNode, key);
896
+ } else if (newAttributes[key] === undefined || newAttributes[key] === null) {
897
+ removeAttribute(domNode, key);
898
+ } else {
899
+ domNode.setAttribute(key, String(newAttributes[key]));
911
900
  }
901
+ }
912
902
  }
913
903
  }
914
904
  domNode.__tungsten_oldAttributes = newAttributes;
915
905
  return newAttributes;
916
906
  }
907
+ function documentFromParent(parent) {
908
+ if (parent.nodeType === 9) return parent;
909
+ if (parent.ownerDocument === null) throw new Error('Tungsten DOM parent has no owner document.');
910
+ return parent.ownerDocument;
911
+ }
912
+ function makeEventListener(tungstenElement, instance, eventName, handler) {
913
+ return event => {
914
+ instance.trackWork(() => handler(event), `${tungstenElement.constructor.name} ${eventName} event handler`);
915
+ };
916
+ }
917
917
  // const ignoreAttributes = {
918
918
  // 'ref': true,
919
919
  // //'key': true
@@ -1001,6 +1001,64 @@ export async function createTungstenComponent({
1001
1001
  // need to set a domRegion
1002
1002
  // element.__domRegion = domRegion
1003
1003
  }
1004
+ export async function createTungstenRootComponent(RootComponent, props, routeParams, routeData, instance, container) {
1005
+ const domPointer = new DomPointer(container, container.childNodes.length);
1006
+ const domStartIndex = domPointer.index;
1007
+ const component = new RootComponent({
1008
+ props,
1009
+ routeParams,
1010
+ routeData,
1011
+ instance,
1012
+ parentElement: null
1013
+ });
1014
+ try {
1015
+ await component.__init();
1016
+ const content = await component.__initialContent();
1017
+ const componentName = RootComponent.displayName ?? RootComponent.name;
1018
+ const openingComment = createComment({
1019
+ text: printComponentNamesInSource ? componentName : '',
1020
+ domPointer
1021
+ });
1022
+ const renderedContent = await createNode({
1023
+ tungstenElement: component,
1024
+ instance,
1025
+ newNode: content,
1026
+ domPointer,
1027
+ parentNode: null
1028
+ });
1029
+ const closingComment = createComment({
1030
+ text: printComponentNamesInSource ? `/${componentName}` : '',
1031
+ domPointer
1032
+ });
1033
+ component.__domRegion = new DomRegion(container, domStartIndex, domPointer.index - domStartIndex);
1034
+ component.__currentContent = renderedContent;
1035
+ component.__didMount();
1036
+ return {
1037
+ component,
1038
+ openingComment,
1039
+ closingComment
1040
+ };
1041
+ } catch (error) {
1042
+ component.__delete();
1043
+ while (container.childNodes.length > domStartIndex) {
1044
+ container.removeChild(container.childNodes[domStartIndex]);
1045
+ }
1046
+ component.__deleted();
1047
+ throw error;
1048
+ }
1049
+ }
1050
+ export function deleteTungstenRoot(root) {
1051
+ const {
1052
+ component,
1053
+ openingComment,
1054
+ closingComment
1055
+ } = root;
1056
+ component.__delete();
1057
+ deleteNodeIfRendered(component.__currentContent);
1058
+ openingComment.remove();
1059
+ closingComment.remove();
1060
+ component.__deleted();
1061
+ }
1004
1062
  let cc = 0; // debugging aid
1005
1063
  async function createTungstenClassComponent(parent, instance, node, domPointer) {
1006
1064
  //console.log('creating tung class comp', node[$type].name)
@@ -1,7 +1,7 @@
1
- import { TungstenSimpleComponent } from './Components.jsx';
2
- import { type TungstenElementRef } from './createRef.js';
3
- import type { CssNames } from './CssNames.js';
4
- import type { ContentNode } from './ContentNode.js';
1
+ import { TungstenSimpleComponent } from '../Components.jsx';
2
+ import { type TungstenElementRef } from '../createRef.js';
3
+ import type { CssNames } from '../CssNames.js';
4
+ import type { ContentNode } from '../ContentNode.js';
5
5
  export type ReactZoneComponent<Props extends object> = ((props: Props) => unknown) | (new (...args: any[]) => unknown);
6
6
  type ReactZoneRoot = {
7
7
  render(children: unknown): void;
@@ -50,4 +50,4 @@ export declare class ReactZone<Props extends object> extends TungstenSimpleCompo
50
50
  private reportError;
51
51
  }
52
52
  export {};
53
- //# sourceMappingURL=react-zone.d.ts.map
53
+ //# sourceMappingURL=react.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../../src/zones/react.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,EAAoB,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAC3E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAGpD,MAAM,MAAM,kBAAkB,CAAC,KAAK,SAAS,MAAM,IAC7C,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,GAC3B,CAAC,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,CAAA;AAEvC,KAAK,aAAa,GAAG;IACjB,MAAM,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAA;IAC/B,OAAO,IAAI,IAAI,CAAA;CAClB,CAAA;AAED,KAAK,kBAAkB,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE,GAAG,QAAQ,EAAE,OAAO,EAAE,KAAK,OAAO,CAAA;AAE7F,MAAM,MAAM,gBAAgB,GAAG;IAC3B,KAAK,EAAE;QACH,SAAS,EAAE,GAAG,CAAA;QACd,aAAa,EAAE,kBAAkB,CAAA;KACpC,CAAA;IACD,MAAM,EAAE;QACJ,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,aAAa,CAAA;QACxC,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAG,aAAa,CAAA;KAC/D,CAAA;IACD,MAAM,EAAE;QACJ,cAAc,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAA;KAC5C,CAAA;CACJ,CAAA;AAED,MAAM,MAAM,cAAc,CAAC,KAAK,SAAS,MAAM,IAAI;IAC/C,SAAS,EAAE,kBAAkB,CAAC,KAAK,CAAC,CAAA;IACpC,KAAK,EAAE,KAAK,CAAA;IACZ,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,QAAQ,CAAA;IACjB,OAAO,EAAE,gBAAgB,CAAA;CAC5B,CAAA;AAED,qBAAa,SAAS,CAAC,KAAK,SAAS,MAAM,CAAE,SAAQ,uBAAuB,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;IAC/F,OAAO,EAAE,kBAAkB,CAAC,cAAc,CAAC,CAAqC;IAChF,SAAS,EAAE,aAAa,GAAG,SAAS,CAAA;IACpC,kBAAkB,EAAE,kBAAkB,GAAG,SAAS,CAAA;IAClD,aAAa,EAAE,OAAO,GAAG,SAAS,CAAA;IAClC,SAAS,UAAQ;IAEjB,OAAO,QAAa,OAAO,CAAC,WAAW,CAAC,CAsBvC;IAED,iBAAiB,QAAO,IAAI,CAG3B;IAED,kBAAkB,QAAO,IAAI,CAE5B;IAED,oBAAoB,QAAO,IAAI,CAM9B;IAED,OAAO,CAAC,UAAU;IAyBlB,OAAO,CAAC,mBAAmB;IA2B3B,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,WAAW;CAOtB"}
@@ -1,9 +1,9 @@
1
1
  function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
2
2
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
3
3
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
4
- import { TungstenSimpleComponent } from "./Components.js";
5
- import { createElementRef } from "./createRef.js";
6
- import { isServer } from "./isServer.js";
4
+ import { TungstenSimpleComponent } from "../Components.js";
5
+ import { createElementRef } from "../createRef.js";
6
+ import { isServer } from "../isServer.js";
7
7
  import { jsx as _jsx } from "tungsten/jsxRuntime.js";
8
8
  export class ReactZone extends TungstenSimpleComponent {
9
9
  constructor(...args) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tungsten",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "bin": {
@@ -9,7 +9,8 @@
9
9
  "main": "dist/index.js",
10
10
  "exports": {
11
11
  ".": "./dist/index.js",
12
- "./react-zone": "./dist/react-zone.js",
12
+ "./react-zone": "./dist/zones/react.js",
13
+ "./testing": "./dist/testing/index.js",
13
14
  "./*": "./dist/*",
14
15
  "./types/*": "./types/*"
15
16
  },
@@ -123,6 +124,7 @@
123
124
  "eslint-import-resolver-typescript": "^2.7.1",
124
125
  "eslint-plugin-import": "^2.32.0",
125
126
  "eslint-plugin-no-type-assertion": "^1.3.0",
127
+ "happy-dom": "^20.10.6",
126
128
  "progress-webpack-plugin": "^1.0.16",
127
129
  "prop-types": "^15.8.1",
128
130
  "rimraf": "^5.0.10",
package/readme.md CHANGED
@@ -2,6 +2,71 @@
2
2
 
3
3
  [Docs](https://robertsandiford.co.uk/tungsten)
4
4
 
5
+ ## Component testing
6
+
7
+ Test-specific APIs are available from `tungsten/testing` and are not exported
8
+ from Tungsten's main entry point. A test project supplies its own DOM
9
+ implementation, such as happy-dom or jsdom:
10
+
11
+ ```tsx
12
+ import { Window } from 'happy-dom'
13
+ import { createTestApp } from 'tungsten/testing'
14
+
15
+ describe('RootComponent', () => {
16
+ it('responds to a button click', async () => {
17
+ const window = new Window()
18
+ const testApp = await createTestApp(RootComponent, {
19
+ document: window.document as unknown as Document,
20
+ props: { initialName: 'Robert' },
21
+ location: '/',
22
+ })
23
+
24
+ try {
25
+ const button = testApp.container.querySelector('button')
26
+ expect(button).not.toBeNull()
27
+
28
+ button!.dispatchEvent(new window.Event('click') as unknown as Event)
29
+ await testApp.resolved()
30
+
31
+ expect(testApp.container.textContent).toContain('Robert')
32
+ } finally {
33
+ await testApp.unmount()
34
+ }
35
+ })
36
+ })
37
+ ```
38
+
39
+ The casts are only needed when a DOM package publishes types which are not
40
+ structurally compatible with the TypeScript DOM library version used by the
41
+ test project.
42
+
43
+ `createTestApp()` completes the initial client render before returning.
44
+ `resolved()` subsequently waits for Tungsten updates, DOM reconciliation,
45
+ lifecycle-triggered updates, and promises returned by registered event
46
+ handlers. It does not wait for unrelated timers, network requests, or promises
47
+ which the application has not returned to Tungsten.
48
+
49
+ An automatically created container is appended to the supplied document body
50
+ and removed by `unmount()`. A caller-supplied container must be empty; it is
51
+ emptied but retained during unmount.
52
+
53
+ Registered stores are created independently for each test application. Use
54
+ `testStore()` to initialize one before the root component starts:
55
+
56
+ ```ts
57
+ import { createTestApp, testStore } from 'tungsten/testing'
58
+
59
+ const testApp = await createTestApp(RootComponent, {
60
+ document,
61
+ stores: [testStore(userStore, store => {
62
+ store.user.set(mockUser)
63
+ })],
64
+ })
65
+ ```
66
+
67
+ Tests containing Tungsten JSX must be compiled through `tungsten compile` so
68
+ they use Tungsten's JSX runtime and application transforms.
69
+
5
70
  ## Preparing code for tests
6
71
 
7
72
  Run a one-shot development compilation without starting a server:
@@ -58,3 +123,18 @@ per-file transformation messages while retaining errors and cycle status:
58
123
  tungsten compile --watch --output .tungsten/test \
59
124
  --ready-file .tungsten/test.ready --quiet
60
125
  ```
126
+
127
+ ## Preserving package imports in selected files
128
+
129
+ Use `skipPackageCompilation` in `tungsten.config.js` for files that should be
130
+ transformed and emitted without Tungsten traversing or copying their package
131
+ dependencies. Bare package imports in matching files are left unchanged:
132
+
133
+ ```js
134
+ export default {
135
+ skipPackageCompilation: '**/*.domTest.js'
136
+ }
137
+ ```
138
+
139
+ The option accepts one glob or an array of globs. Patterns match the actual
140
+ JavaScript files received by Tungsten; extensions are not translated.
@@ -1 +0,0 @@
1
- {"version":3,"file":"react-zone.d.ts","sourceRoot":"","sources":["../src/react-zone.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAA;AAC1D,OAAO,EAAoB,KAAK,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAC1E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAGnD,MAAM,MAAM,kBAAkB,CAAC,KAAK,SAAS,MAAM,IAC7C,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,GAC3B,CAAC,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,CAAA;AAEvC,KAAK,aAAa,GAAG;IACjB,MAAM,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAA;IAC/B,OAAO,IAAI,IAAI,CAAA;CAClB,CAAA;AAED,KAAK,kBAAkB,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE,GAAG,QAAQ,EAAE,OAAO,EAAE,KAAK,OAAO,CAAA;AAE7F,MAAM,MAAM,gBAAgB,GAAG;IAC3B,KAAK,EAAE;QACH,SAAS,EAAE,GAAG,CAAA;QACd,aAAa,EAAE,kBAAkB,CAAA;KACpC,CAAA;IACD,MAAM,EAAE;QACJ,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,aAAa,CAAA;QACxC,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAG,aAAa,CAAA;KAC/D,CAAA;IACD,MAAM,EAAE;QACJ,cAAc,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAA;KAC5C,CAAA;CACJ,CAAA;AAED,MAAM,MAAM,cAAc,CAAC,KAAK,SAAS,MAAM,IAAI;IAC/C,SAAS,EAAE,kBAAkB,CAAC,KAAK,CAAC,CAAA;IACpC,KAAK,EAAE,KAAK,CAAA;IACZ,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,QAAQ,CAAA;IACjB,OAAO,EAAE,gBAAgB,CAAA;CAC5B,CAAA;AAED,qBAAa,SAAS,CAAC,KAAK,SAAS,MAAM,CAAE,SAAQ,uBAAuB,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;IAC/F,OAAO,EAAE,kBAAkB,CAAC,cAAc,CAAC,CAAqC;IAChF,SAAS,EAAE,aAAa,GAAG,SAAS,CAAA;IACpC,kBAAkB,EAAE,kBAAkB,GAAG,SAAS,CAAA;IAClD,aAAa,EAAE,OAAO,GAAG,SAAS,CAAA;IAClC,SAAS,UAAQ;IAEjB,OAAO,QAAa,OAAO,CAAC,WAAW,CAAC,CAsBvC;IAED,iBAAiB,QAAO,IAAI,CAG3B;IAED,kBAAkB,QAAO,IAAI,CAE5B;IAED,oBAAoB,QAAO,IAAI,CAM9B;IAED,OAAO,CAAC,UAAU;IAyBlB,OAAO,CAAC,mBAAmB;IA2B3B,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,WAAW;CAOtB"}