diff --git a/.github/workflows/sbt.yml b/.github/workflows/sbt.yml index ace21c63..a8630674 100644 --- a/.github/workflows/sbt.yml +++ b/.github/workflows/sbt.yml @@ -10,33 +10,17 @@ on: jobs: test: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@master - - name: Set up JDK 1.8 - uses: actions/setup-java@v1 - with: - java-version: 1.8 - - name: Style checks - run: sbt styleCheck - - name: Install NPM Dependencies - run: npm install; cd native; npm install; cd .. - - name: Test with SBT (fastopt) - run: sbt scalajsReactInterop/test +tests/test +native/test - - name: Test with SBT (fullopt) - run: sbt "set Global/scalaJSStage := FullOptStage" scalajsReactInterop/test +tests/test +native/test - test-windows: - runs-on: windows-latest + runs-on: ${{ matrix.os }} strategy: fail-fast: false - + matrix: + os: [ubuntu-latest, windows-latest] + scalajs: ["0.6.31", "1.0.0-RC2"] steps: - name: Configure git to disable Windows line feeds run: "git config --global core.autocrlf false" shell: bash - uses: actions/checkout@master - # Pre-installed SBT on Windows-runner is unstable so use more polished 3rd-party action olafurpg/setup-scala. - name: Set up JDK 1.8 and SBT uses: olafurpg/setup-scala@v7 with: @@ -44,21 +28,25 @@ jobs: - name: Style checks run: sbt styleCheck - name: Install NPM Dependencies - run: npm install; cd native; npm install; cd .. + run: npm install; cd tests; npm install; cd ..; cd native; npm install; cd .. shell: bash - - name: Test with SBT (fastopt) - run: sbt scalajsReactInterop/test +tests/test +native/test + - name: Test core and native (fastopt + fullopt) + run: sbt +tests/test +native/test "set scalaJSStage in Global := FullOptStage" +tests/test +native/test + env: + SCALAJS_VERSION: ${{ matrix.scalajs }} shell: bash - - name: Test with SBT (fullopt) - run: sbt "set Global/scalaJSStage := FullOptStage" scalajsReactInterop/test +tests/test +native/test + - name: Test Scala.js React Interop (fastopt + fullopt) + if: matrix.scalajs == '0.6.31' + run: sbt scalajsReactInterop/test "set scalaJSStage in Global := FullOptStage" scalajsReactInterop/test + env: + SCALAJS_VERSION: ${{ matrix.scalajs }} shell: bash build-docs: runs-on: ubuntu-latest - steps: - uses: actions/checkout@master - - name: Set up JDK 1.8 - uses: actions/setup-java@v1 + - name: Set up JDK 1.8 and SBT + uses: olafurpg/setup-scala@v7 with: java-version: 1.8 - name: Install NPM Dependencies @@ -71,24 +59,21 @@ jobs: BUNDLESIZE_TOKEN: N2JjZDIxYjA1OGU1YzkwOWVkZWYzOWQ5MWYyZjRhYTgyMzE3MzY3Mgo= build-intellij-plugin: runs-on: ubuntu-latest - steps: - uses: actions/checkout@master - - name: Set up JDK 1.8 - uses: actions/setup-java@v1 + - name: Set up JDK 1.8 and SBT + uses: olafurpg/setup-scala@v7 with: java-version: 1.8 - name: Build IntelliJ Plugin run: sbt coreIntellijSupport/updateIntellij coreIntellijSupport/compile publish: - # Currently publication doesn't depend on testing results for Windows platform, since primary developers use Linux, - # but it may be changed in the future. needs: [test, build-docs, build-intellij-plugin] runs-on: ubuntu-latest steps: - uses: actions/checkout@master - - name: Set up JDK 1.8 - uses: actions/setup-java@v1 + - name: Set up JDK 1.8 and SBT + uses: olafurpg/setup-scala@v7 with: java-version: 1.8 - run: git fetch --unshallow diff --git a/.scalafmt.conf b/.scalafmt.conf new file mode 100644 index 00000000..38c0ab6a --- /dev/null +++ b/.scalafmt.conf @@ -0,0 +1,10 @@ +version = 2.3.0 +project.git = true +maxColumn = 120 +align = more +assumeStandardLibraryStripMargin = true +rewrite.rules = [AvoidInfix, SortImports, RedundantBraces, RedundantParens, SortModifiers] +rewrite.redundantBraces.stringInterpolation = true +spaces.afterTripleEquals = true +continuationIndent.defnSite = 2 +includeCurlyBraceInSelectChains = false diff --git a/CHANGELOG.md b/CHANGELOG.md index d2913445..5d73cf56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ + Add novalidate attribute to form [PR #315](https://github.com/shadaj/slinky/pull/315) + Add apply method for constructing CustomTag and CustomAttributes [PR #318](https://github.com/shadaj/slinky/pull/318) + Fix types for the useCallback hook and fix its reference equality behavior [PR #302](https://github.com/shadaj/slinky/pull/302) ++ Use js.Object instead of js.Dynamics on attribute style [PR #322](https://github.com/shadaj/slinky/pull/322) ++ Add support for Scala.js 1.0.0-RC2 [PR #321](https://github.com/shadaj/slinky/pull/321) ++ Rewrite the class component logic to patch the component definition once to handle JS data instead of on every initialization [PR #321](https://github.com/shadaj/slinky/pull/321) ++ Add missing inherited props to native ScrollView component [PR #324](https://github.com/shadaj/slinky/pull/324) ## [v0.6.3](https://slinky.dev) ### Highlights :tada: diff --git a/README.md b/README.md index 314ef8a7..1e74fe7d 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,9 @@ - + + + @@ -40,7 +42,7 @@ Slinky is split up into several submodules: + `tests` contains the unit tests for the above modules (except native and vr which have local tests) + `docs` and `docsMacros` contains the documentation site, which is a Slinky app itself -To run the main unit tests, run `sbt tests/test`. +To run the main unit tests, first install the dependencies by running `npm install` inside the `tests` folder, then from the base folder run `sbt tests/test`. Similarly for React Native tests, run `npm install` inside the `native` folder, then from the base folder run `sbt native/test`. Note to IntelliJ IDEA users. When you try to import Slinky SBT definition in IDEA and encounter an exception like `java.nio.file.NoSuchFileException: /Users/someuser/.slinkyPluginIC/sdk/192.6817.14/plugins`, you should diff --git a/build.sbt b/build.sbt index 28c4f6f3..80cb70fb 100644 --- a/build.sbt +++ b/build.sbt @@ -4,34 +4,39 @@ Global / onChangedBuildSource := ReloadOnSourceChanges turbo := true ThisBuild / libraryDependencies += compilerPlugin(scalafixSemanticdb) -addCommandAlias("style", "Compile/scalafix; Test/scalafix") -addCommandAlias("styleCheck", "Compile/scalafix --check; Test/scalafix --check") +addCommandAlias("style", "compile:scalafix; test:scalafix; compile:scalafmt; test:scalafmt; scalafmtSbt") +addCommandAlias( + "styleCheck", + "compile:scalafix --check; test:scalafix --check; compile:scalafmtCheck; test:scalafmtCheck; scalafmtSbtCheck" +) val scala212 = "2.12.10" val scala213 = "2.13.1" ThisBuild / scalaVersion := scala212 -lazy val slinky = project.in(file(".")).aggregate( - readWrite, - core, - web, - history, - reactrouter, - testRenderer, - native, - vr, - hot, - scalajsReactInterop -).settings( - publish := {}, - publishLocal := {} -) +lazy val slinky = project + .in(file(".")) + .aggregate( + readWrite, + core, + web, + history, + reactrouter, + testRenderer, + native, + vr, + hot, + scalajsReactInterop + ) + .settings( + publish := {}, + publishLocal := {} + ) addCommandAlias( "publishSignedAll", - (slinky: ProjectDefinition[ProjectReference]) - .aggregate + (slinky: ProjectDefinition[ProjectReference]).aggregate .map(p => s"+ ${p.asInstanceOf[LocalProject].project}/publishSigned") .mkString(";") ) @@ -86,7 +91,7 @@ lazy val macroAnnotationSettings = Seq( }, libraryDependencies ++= { if (scalaVersion.value == scala213) Seq.empty - else Seq(compilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full)) + else Seq(compilerPlugin(("org.scalamacros" % "paradise" % "2.1.0").cross(CrossVersion.full))) } ) @@ -94,75 +99,112 @@ lazy val generator = project lazy val readWrite = project.settings(librarySettings, crossScalaSettings) -lazy val core = project.settings( - Compile / resourceGenerators += Def.task { - val rootFolder = (Compile / resourceManaged).value / "META-INF" - rootFolder.mkdirs() - - IO.write( - rootFolder / "intellij-compat.json", - s"""{ - | "artifact": "me.shadaj % slinky-core-ijext_2.12 % ${version.value}" - |}""".stripMargin - ) - - Seq(rootFolder / "intellij-compat.json") - }, - macroAnnotationSettings, librarySettings, crossScalaSettings -).dependsOn(readWrite) - -lazy val web = project.settings( - Compile / sourceGenerators += Def.taskDyn[Seq[File]] { - val rootFolder = (Compile / sourceManaged).value / "slinky/web" - rootFolder.mkdirs() - - val html = (generator / Compile / runMain).toTask(Seq("slinky.generator.Generator", "web/html.json", (rootFolder / "html").getAbsolutePath, "slinky.web.html").mkString(" ", " ", "")).map { _ => - (rootFolder / "html" ** "*.scala").get - } - - val svg = (generator / Compile / runMain).toTask(Seq("slinky.generator.Generator", "web/svg.json", (rootFolder / "svg").getAbsolutePath, "slinky.web.svg").mkString(" ", " ", "")).map { _ => - (rootFolder / "svg" ** "*.scala").get - } - - html.zip(svg).flatMap(t => t._1.flatMap(h => t._2.map(s => h ++ s))) - }.taskValue, - Compile / packageSrc / mappings ++= { - val base = (Compile / sourceManaged).value - val files = (Compile / managedSources).value - files.map { f => (f, f.relativeTo(base).get.getPath) } - }, - librarySettings, - crossScalaSettings, -).dependsOn(core) +lazy val core = project + .settings( + Compile / resourceGenerators += Def.task { + val rootFolder = (Compile / resourceManaged).value / "META-INF" + rootFolder.mkdirs() + + IO.write( + rootFolder / "intellij-compat.json", + s"""{ + | "artifact": "me.shadaj % slinky-core-ijext_2.12 % ${version.value}" + |}""".stripMargin + ) + + Seq(rootFolder / "intellij-compat.json") + }, + macroAnnotationSettings, + librarySettings, + crossScalaSettings + ) + .dependsOn(readWrite) + +lazy val web = project + .settings( + Compile / sourceGenerators += Def + .taskDyn[Seq[File]] { + val rootFolder = (Compile / sourceManaged).value / "slinky/web" + rootFolder.mkdirs() + + val html = (generator / Compile / runMain) + .toTask( + Seq("slinky.generator.Generator", "web/html.json", (rootFolder / "html").getAbsolutePath, "slinky.web.html") + .mkString(" ", " ", "") + ) + .map { _ => + (rootFolder / "html" ** "*.scala").get + } + + val svg = (generator / Compile / runMain) + .toTask( + Seq("slinky.generator.Generator", "web/svg.json", (rootFolder / "svg").getAbsolutePath, "slinky.web.svg") + .mkString(" ", " ", "") + ) + .map { _ => + (rootFolder / "svg" ** "*.scala").get + } + + html.zip(svg).flatMap(t => t._1.flatMap(h => t._2.map(s => h ++ s))) + } + .taskValue, + Compile / packageSrc / mappings ++= { + val base = (Compile / sourceManaged).value + val files = (Compile / managedSources).value + files.map { f => + (f, f.relativeTo(base).get.getPath) + } + }, + librarySettings, + crossScalaSettings + ) + .dependsOn(core) lazy val history = project.settings(librarySettings, crossScalaSettings) -lazy val reactrouter = project.settings(macroAnnotationSettings, librarySettings, crossScalaSettings).dependsOn(core, web, history) +lazy val reactrouter = + project.settings(macroAnnotationSettings, librarySettings, crossScalaSettings).dependsOn(core, web, history) lazy val testRenderer = project.settings(macroAnnotationSettings, librarySettings, crossScalaSettings).dependsOn(core) -lazy val native = project.settings(macroAnnotationSettings, librarySettings, crossScalaSettings).dependsOn(core, testRenderer % Test) +lazy val native = + project.settings(macroAnnotationSettings, librarySettings, crossScalaSettings).dependsOn(core, testRenderer % Test) -lazy val vr = project.settings(macroAnnotationSettings, librarySettings, crossScalaSettings).dependsOn(core, testRenderer % Test) +lazy val vr = + project.settings(macroAnnotationSettings, librarySettings, crossScalaSettings).dependsOn(core, testRenderer % Test) lazy val hot = project.settings(macroAnnotationSettings, librarySettings, crossScalaSettings).dependsOn(core) -lazy val scalajsReactInterop = project.settings(macroAnnotationSettings, librarySettings).dependsOn(core, web % Test) +val scalaJSVersion = + Option(System.getenv("SCALAJS_VERSION")).getOrElse("0.6.31") -lazy val tests = project.settings(librarySettings, macroAnnotationSettings, crossScalaSettings).dependsOn(core, web, hot) +lazy val scalajsReactInterop = project + .settings( + macroAnnotationSettings, + librarySettings, + publish / skip := scalaJSVersion != "0.6.31" + ) + .dependsOn(core, web % Test) + +lazy val tests = + project.settings(librarySettings, macroAnnotationSettings, crossScalaSettings).dependsOn(core, web, hot) lazy val docsMacros = project.settings(macroAnnotationSettings).dependsOn(web, hot) -lazy val docs = project.settings(librarySettings, macroAnnotationSettings).dependsOn(web, hot, docsMacros, reactrouter, history) +lazy val docs = + project.settings(librarySettings, macroAnnotationSettings).dependsOn(web, hot, docsMacros, reactrouter, history) ThisBuild / updateIntellij := {} -lazy val coreIntellijSupport = project.enablePlugins(SbtIdeaPlugin).settings( - org.jetbrains.sbtidea.Keys.buildSettings -).settings( - intellijBuild := "192.6817.14", - intellijInternalPlugins += "java", - intellijExternalPlugins += "org.intellij.scala".toPlugin, - packageMethod := PackagingMethod.Standalone(), - intellijMainJars ++= maybeToolsJar -) +lazy val coreIntellijSupport = project + .enablePlugins(SbtIdeaPlugin) + .settings( + org.jetbrains.sbtidea.Keys.buildSettings + ) + .settings( + intellijBuild := "192.6817.14", + intellijInternalPlugins += "java", + intellijExternalPlugins += "org.intellij.scala".toPlugin, + packageMethod := PackagingMethod.Standalone(), + intellijMainJars ++= maybeToolsJar + ) diff --git a/core/build.sbt b/core/build.sbt index 699132e0..809fd1ab 100644 --- a/core/build.sbt +++ b/core/build.sbt @@ -4,6 +4,11 @@ name := "slinky-core" libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value -scalacOptions += "-P:scalajs:sjsDefinedByDefault" - -scalacOptions -= "-Xfatal-warnings" // Needed by useCallback due to false positive warning on implicit evidence \ No newline at end of file +scalacOptions ++= { + if (scalaJSVersion.startsWith("0.6.")) Seq("-P:scalajs:sjsDefinedByDefault") + else Nil +} + +// Needed by useCallback due to false positive warning on implicit evidence +scalacOptions -= "-Ywarn-unused:implicits" +scalacOptions -= "-Wunused:implicits" diff --git a/core/src/main/scala/slinky/core/BaseComponentWrapper.scala b/core/src/main/scala/slinky/core/BaseComponentWrapper.scala index bbb31212..235df3e4 100644 --- a/core/src/main/scala/slinky/core/BaseComponentWrapper.scala +++ b/core/src/main/scala/slinky/core/BaseComponentWrapper.scala @@ -1,6 +1,6 @@ package slinky.core -import slinky.core.facade.{ReactRaw, ReactElement, ReactRef} +import slinky.core.facade.{ReactElement, ReactRaw, ReactRef} import slinky.readwrite.{Reader, Writer} import scala.scalajs.js @@ -44,16 +44,18 @@ object KeyAndRefAddingStage { } val ret = ReactRaw.createElement - .applyDynamic("apply")(ReactRaw, stage.args).asInstanceOf[ReactElement] + .applyDynamic("apply")(ReactRaw, stage.args) + .asInstanceOf[ReactElement] stage.args(0) = null ret } - @inline implicit def buildContainer[D, F[_]](stage: F[KeyAndRefAddingStage[D]])(implicit f: ReactElementContainer[F]): F[ReactElement] = { + @inline implicit def buildContainer[D, F[_]]( + stage: F[KeyAndRefAddingStage[D]] + )(implicit f: ReactElementContainer[F]): F[ReactElement] = f.map(stage)(build) - } } abstract class BaseComponentWrapper(sr: StateReaderProvider, sw: StateWriterProvider) { @@ -68,70 +70,205 @@ abstract class BaseComponentWrapper(sr: StateReaderProvider, sw: StateWriterProv type Definition <: js.Object val getDerivedStateFromProps: (Props, State) => State = null - + val getDerivedStateFromError: js.Error => State = null private[core] val hot_stateReader = sr.asInstanceOf[Reader[State]] private[core] val hot_stateWriter = sw.asInstanceOf[Writer[State]] - def componentConstructor(implicit propsReader: Reader[Props], - stateWriter: Writer[State], stateReader: Reader[State], - constructorTag: ConstructorTag[Def]): js.Object = { - val constructor = constructorTag.constructor - if (!scala.scalajs.LinkingInfo.productionMode) { - constructor.displayName = getClass.getSimpleName + private var patchedConstructor: js.Dynamic = null + + private def getPatchedConstructor(implicit constructorTag: ConstructorTag[Def]) = { + if (patchedConstructor == null) { + val constructor = constructorTag.constructor + val componentPrototype = constructor.prototype + + if (componentPrototype.componentWillMount == DefinitionBase.defaultBase.componentWillMount) { + componentPrototype.componentWillMount = js.undefined + } + + if (componentPrototype.componentDidMount == DefinitionBase.defaultBase.componentDidMount) { + componentPrototype.componentDidMount = js.undefined + } + + if (componentPrototype.componentWillReceiveProps != DefinitionBase.defaultBase.componentWillReceiveProps) { + val orig = componentPrototype.componentWillReceiveProps.asInstanceOf[js.ThisFunction1[Def, Props, Unit]] + componentPrototype.componentWillReceiveProps = ((self: Def, props: js.Object) => { + orig( + self, + self.asInstanceOf[DefinitionBase[Props, _, _]].readPropsValue(props) + ) + }): js.ThisFunction1[Def, js.Object, Unit] + } else { + componentPrototype.componentWillReceiveProps = js.undefined + } + + if (componentPrototype.shouldComponentUpdate != DefinitionBase.defaultBase.shouldComponentUpdate) { + val orig = componentPrototype.shouldComponentUpdate.asInstanceOf[js.ThisFunction2[Def, Props, State, Boolean]] + componentPrototype.shouldComponentUpdate = ((self: Def, nextProps: js.Object, nextState: js.Object) => { + orig( + self, + self.asInstanceOf[DefinitionBase[Props, _, _]].readPropsValue(nextProps), + self.asInstanceOf[DefinitionBase[_, State, _]].readStateValue(nextState) + ) + }): js.ThisFunction2[Def, js.Object, js.Object, Boolean] + } else { + componentPrototype.shouldComponentUpdate = js.undefined + } + + if (componentPrototype.componentWillUpdate != DefinitionBase.defaultBase.componentWillUpdate) { + val orig = componentPrototype.componentWillUpdate.asInstanceOf[js.ThisFunction2[Def, Props, State, Unit]] + componentPrototype.componentWillUpdate = ((self: Def, nextProps: js.Object, nextState: js.Object) => { + orig( + self, + self.asInstanceOf[DefinitionBase[Props, _, _]].readPropsValue(nextProps), + self.asInstanceOf[DefinitionBase[_, State, _]].readStateValue(nextState) + ) + }): js.ThisFunction2[Def, js.Object, js.Object, Unit] + } else { + componentPrototype.componentWillUpdate = js.undefined + } + + if (componentPrototype.getSnapshotBeforeUpdate != DefinitionBase.defaultBase.getSnapshotBeforeUpdate) { + val orig = componentPrototype.getSnapshotBeforeUpdate.asInstanceOf[js.ThisFunction2[Def, Props, State, Any]] + componentPrototype.getSnapshotBeforeUpdate = ((self: Def, prevProps: js.Object, prevState: js.Object) => { + orig( + self, + self.asInstanceOf[DefinitionBase[Props, _, _]].readPropsValue(prevProps), + self.asInstanceOf[DefinitionBase[_, State, _]].readStateValue(prevState) + ) + }): js.ThisFunction2[Def, js.Object, js.Object, Any] + } else { + componentPrototype.getSnapshotBeforeUpdate = js.undefined + } + + if (componentPrototype.componentDidUpdate != DefinitionBase.defaultBase.componentDidUpdate) { + val orig = componentPrototype.componentDidUpdate + componentPrototype.componentDidUpdateScala = orig + componentPrototype.componentDidUpdate = + ((self: Def, prevProps: js.Object, prevState: js.Object, snapshot: js.Any) => { + orig + .asInstanceOf[js.ThisFunction] + .call( + self, + self.asInstanceOf[DefinitionBase[Props, _, _]].readPropsValue(prevProps).asInstanceOf[js.Any], + self.asInstanceOf[DefinitionBase[_, State, _]].readStateValue(prevState).asInstanceOf[js.Any], + snapshot.asInstanceOf[js.Any] + ) + .asInstanceOf[Unit] + }): js.ThisFunction3[Def, js.Object, js.Object, js.Any, Unit] + } else { + componentPrototype.componentDidUpdate = js.undefined + } + + if (componentPrototype.componentWillUnmount == DefinitionBase.defaultBase.componentWillUnmount) { + componentPrototype.componentWillUnmount = js.undefined + } + + if (componentPrototype.componentDidCatch == DefinitionBase.defaultBase.componentDidCatch) { + componentPrototype.componentDidCatch = js.undefined + } + + componentPrototype._base = this.asInstanceOf[js.Any] + + patchedConstructor = constructor } - constructor._base = this.asInstanceOf[js.Any] + patchedConstructor + } - if (this.getDerivedStateFromProps != null) { - constructor.getDerivedStateFromProps = ((props: js.Object, state: js.Object) => { - val propsScala = if (js.typeOf(props) == "object" && props.hasOwnProperty("__")) { - props.asInstanceOf[js.Dynamic].__.asInstanceOf[Props] - } else { - DefinitionBase.readWithWrappingAdjustment(propsReader)(props) - } + private var wrappedConstructor: js.Dynamic = null + private def getWrappedConstructor(implicit constructorTag: ConstructorTag[Def]) = { + if (wrappedConstructor == null) { + val constructor = getPatchedConstructor + val descriptor = js.Object.getOwnPropertyDescriptor(constructor.prototype.asInstanceOf[js.Object], "initialState") + val needsExtraApply = !js.isUndefined(descriptor) && !js.isUndefined(descriptor.asInstanceOf[js.Dynamic].writable) - val stateScala = if (js.typeOf(state) == "object" && state.hasOwnProperty("__")) { - state.asInstanceOf[js.Dynamic].__.asInstanceOf[State] - } else { - DefinitionBase.readWithWrappingAdjustment(stateReader)(state) - } + wrappedConstructor = (((self: Def, props: js.Object) => { + // run the original constructor + constructor.asInstanceOf[js.ThisFunction1[Def, js.Object, Unit]](self, props) - val newState = getDerivedStateFromProps(propsScala, stateScala) + // set initial state of the component after the original constructor + self.asInstanceOf[js.Dynamic].state = { + val initialStateValue = self.asInstanceOf[DefinitionBase[_, _, _]].initialState + val stateWithExtraApplyFix = (if (needsExtraApply) { + initialStateValue.asInstanceOf[js.Function0[State]].apply() + } else initialStateValue).asInstanceOf[State] - if (newState == null) null else { if (BaseComponentWrapper.scalaComponentWritingEnabled) { - DefinitionBase.writeWithWrappingAdjustment(stateWriter)(newState) - } else { - js.Dynamic.literal(__ = newState.asInstanceOf[js.Any]) - } + DefinitionBase.writeWithWrappingAdjustment(self.asInstanceOf[DefinitionBase[_, State, _]].stateWriter)( + stateWithExtraApplyFix + ) + } else js.Dynamic.literal(__ = stateWithExtraApplyFix.asInstanceOf[js.Any]) } - }): js.Function2[js.Object, js.Object, js.Object] - } - - if (this.getDerivedStateFromError != null) { - constructor.getDerivedStateFromError = ((error: js.Error) => { - val newState = getDerivedStateFromError(error) - - if (newState == null) null else { - if (BaseComponentWrapper.scalaComponentWritingEnabled) { - DefinitionBase.writeWithWrappingAdjustment(stateWriter)(newState) - } else { - js.Dynamic.literal(__ = newState.asInstanceOf[js.Any]) + }): js.ThisFunction1[Def, js.Object, Unit]).asInstanceOf[js.Dynamic] + + wrappedConstructor.prototype = constructor.prototype + + if (!scala.scalajs.LinkingInfo.productionMode) { + wrappedConstructor.displayName = getClass.getSimpleName + } + + if (this.getDerivedStateFromProps != null) { + wrappedConstructor.getDerivedStateFromProps = ((props: js.Object, state: js.Object) => { + val propsScala = + DefinitionBase.readValue(props, constructor.prototype._base._propsReader.asInstanceOf[Reader[Props]]) + val stateScala = + DefinitionBase.readValue(state, constructor.prototype._base._stateReader.asInstanceOf[Reader[State]]) + + val newState = getDerivedStateFromProps(propsScala, stateScala) + + if (newState == null) null + else { + if (BaseComponentWrapper.scalaComponentWritingEnabled) { + DefinitionBase.writeWithWrappingAdjustment( + constructor.prototype._base._stateWriter.asInstanceOf[Writer[State]] + )(newState) + } else { + js.Dynamic.literal(__ = newState.asInstanceOf[js.Any]) + } } - } - }): js.Function1[js.Error, js.Object] + }): js.Function2[js.Object, js.Object, js.Object] + } + + if (this.getDerivedStateFromError != null) { + wrappedConstructor.getDerivedStateFromError = ((error: js.Error) => { + val newState = getDerivedStateFromError(error) + + if (newState == null) null + else { + if (BaseComponentWrapper.scalaComponentWritingEnabled) { + DefinitionBase.writeWithWrappingAdjustment( + constructor.prototype._base._stateWriter.asInstanceOf[Writer[State]] + )(newState) + } else { + js.Dynamic.literal(__ = newState.asInstanceOf[js.Any]) + } + } + }): js.Function1[js.Error, js.Object] + } } + wrappedConstructor + } + + def componentConstructor( + implicit propsReader: Reader[Props], + stateWriter: Writer[State], + stateReader: Reader[State], + constructorTag: ConstructorTag[Def] + ): js.Object = { // we only receive non-null reader/writers here when we generate a full typeclass; otherwise we don't set // the reader/writer values since we can just use the fallback ones + // also, we don't overwrite the reader if we already have one since we may have already exported if (propsReader != null) this.asInstanceOf[js.Dynamic]._propsReader = propsReader.asInstanceOf[js.Any] if (stateReader != null) this.asInstanceOf[js.Dynamic]._stateReader = stateReader.asInstanceOf[js.Any] if (stateWriter != null) this.asInstanceOf[js.Dynamic]._stateWriter = stateWriter.asInstanceOf[js.Any] BaseComponentWrapper.componentConstructorMiddleware( - constructor.asInstanceOf[js.Object], this.asInstanceOf[js.Object]) + getWrappedConstructor(constructorTag).asInstanceOf[js.Object], + this.asInstanceOf[js.Object] + ) } private var componentConstructorInstance: js.Object = null @@ -140,29 +277,31 @@ abstract class BaseComponentWrapper(sr: StateReaderProvider, sw: StateWriterProv val propsObj = js.Dictionary("__" -> p.asInstanceOf[js.Any]) if (componentConstructorInstance == null) { - componentConstructorInstance = - componentConstructor( - null, - hot_stateWriter, hot_stateReader, - constructorTag - ) + componentConstructorInstance = componentConstructor( + null, + hot_stateWriter, + hot_stateReader, + constructorTag + ) } - new KeyAndRefAddingStage(js.Array( - componentConstructorInstance, - propsObj - )) + new KeyAndRefAddingStage( + js.Array( + componentConstructorInstance, + propsObj + ) + ) } - def apply()(implicit ev: Unit =:= Props, constructorTag: ConstructorTag[Def]): KeyAndRefAddingStage[Def] = { + def apply()(implicit ev: Unit =:= Props, constructorTag: ConstructorTag[Def]): KeyAndRefAddingStage[Def] = apply(())(constructorTag) - } } object BaseComponentWrapper { - implicit def proplessKeyAndRef[C <: BaseComponentWrapper { type Props = Unit }](c: C)(implicit constructorTag: ConstructorTag[c.Def]): KeyAndRefAddingStage[c.Def] = { + implicit def proplessKeyAndRef[C <: BaseComponentWrapper { type Props = Unit }]( + c: C + )(implicit constructorTag: ConstructorTag[c.Def]): KeyAndRefAddingStage[c.Def] = c.apply(()) - } private var componentConstructorMiddleware = (constructor: js.Object, _: js.Object) => { constructor @@ -175,13 +314,12 @@ object BaseComponentWrapper { * needed for hot loading, where data must be written to a JS object and * then read when the application is reloaded. */ - def enableScalaComponentWriting(): Unit = { + def enableScalaComponentWriting(): Unit = if (scala.scalajs.LinkingInfo.productionMode) { throw new IllegalStateException("Cannot enable Scala component writing in production mode") } else { scalaComponentWritingEnabled = true } - } /** * Inserts a component constructor middleware function, which transforms a component constructor @@ -204,9 +342,13 @@ object StateReaderProvider { def impl(c: whitebox.Context): c.Expr[StateReaderProvider] = { import c.universe._ val compName = c.internal.enclosingOwner.owner.asClass - val q"$_; val x: $typedReaderType = null" = c.typecheck(q"@_root_.scala.annotation.unchecked.uncheckedStable val comp: $compName = null; val x: _root_.slinky.readwrite.Reader[comp.State] = null") // scalafix:ok + val q"$_; val x: $typedReaderType = null" = c.typecheck( + q"@_root_.scala.annotation.unchecked.uncheckedStable val comp: $compName = null; val x: _root_.slinky.readwrite.Reader[comp.State] = null" + ) // scalafix:ok val tpcls = c.inferImplicitValue(typedReaderType.tpe.asInstanceOf[c.Type], silent = false) - c.Expr(q"if (_root_.scala.scalajs.LinkingInfo.productionMode) null else $tpcls.asInstanceOf[_root_.slinky.core.StateReaderProvider]") + c.Expr( + q"if (_root_.scala.scalajs.LinkingInfo.productionMode) null else $tpcls.asInstanceOf[_root_.slinky.core.StateReaderProvider]" + ) } implicit def get: StateReaderProvider = macro impl @@ -217,9 +359,13 @@ object StateWriterProvider { def impl(c: whitebox.Context): c.Expr[StateWriterProvider] = { import c.universe._ val compName = c.internal.enclosingOwner.owner.asClass - val q"$_; val x: $typedReaderType = null" = c.typecheck(q"@_root_.scala.annotation.unchecked.uncheckedStable val comp: $compName = null; val x: _root_.slinky.readwrite.Writer[comp.State] = null") // scalafix:ok + val q"$_; val x: $typedReaderType = null" = c.typecheck( + q"@_root_.scala.annotation.unchecked.uncheckedStable val comp: $compName = null; val x: _root_.slinky.readwrite.Writer[comp.State] = null" + ) // scalafix:ok val tpcls = c.inferImplicitValue(typedReaderType.tpe.asInstanceOf[c.Type], silent = false) - c.Expr(q"if (_root_.scala.scalajs.LinkingInfo.productionMode) null else $tpcls.asInstanceOf[_root_.slinky.core.StateWriterProvider]") + c.Expr( + q"if (_root_.scala.scalajs.LinkingInfo.productionMode) null else $tpcls.asInstanceOf[_root_.slinky.core.StateWriterProvider]" + ) } implicit def get: StateWriterProvider = macro impl diff --git a/core/src/main/scala/slinky/core/Component.scala b/core/src/main/scala/slinky/core/Component.scala index 77cdb13e..6d85b428 100644 --- a/core/src/main/scala/slinky/core/Component.scala +++ b/core/src/main/scala/slinky/core/Component.scala @@ -61,4 +61,4 @@ abstract class StatelessComponent extends Component { object StatelessComponent { type Wrapper = StatelessComponentWrapper -} \ No newline at end of file +} diff --git a/core/src/main/scala/slinky/core/ComponentWrapper.scala b/core/src/main/scala/slinky/core/ComponentWrapper.scala index 8a0c3fb8..4153972e 100644 --- a/core/src/main/scala/slinky/core/ComponentWrapper.scala +++ b/core/src/main/scala/slinky/core/ComponentWrapper.scala @@ -1,5 +1,6 @@ package slinky.core -abstract class ComponentWrapper(implicit sr: StateReaderProvider, sw: StateWriterProvider) extends BaseComponentWrapper(sr, sw) { +abstract class ComponentWrapper(implicit sr: StateReaderProvider, sw: StateWriterProvider) + extends BaseComponentWrapper(sr, sw) { override type Definition = DefinitionBase[Props, State, Snapshot] } diff --git a/core/src/main/scala/slinky/core/DefinitionBase.scala b/core/src/main/scala/slinky/core/DefinitionBase.scala index 1577464d..cdc7465c 100644 --- a/core/src/main/scala/slinky/core/DefinitionBase.scala +++ b/core/src/main/scala/slinky/core/DefinitionBase.scala @@ -11,51 +11,26 @@ abstract class DefinitionBase[Props, State, Snapshot](jsProps: js.Object) extend // we extract out props/state reader/writer from the _base value defined in on the constructor // see componentConstructor in BaseComponentWrapper - @inline private[this] final def stateReader: Reader[State] = - this.asInstanceOf[js.Dynamic].__proto__.constructor._base._stateReader.asInstanceOf[Reader[State]] - @inline private[this] final def stateWriter: Writer[State] = - this.asInstanceOf[js.Dynamic].__proto__.constructor._base._stateWriter.asInstanceOf[Writer[State]] - @inline private[this] final def propsReader: Reader[Props] = - this.asInstanceOf[js.Dynamic].__proto__.constructor._base._propsReader.asInstanceOf[Reader[Props]] + @inline final private[this] def stateReader: Reader[State] = + this.asInstanceOf[js.Dynamic]._base._stateReader.asInstanceOf[Reader[State]] + @inline final private[slinky] def stateWriter: Writer[State] = + this.asInstanceOf[js.Dynamic]._base._stateWriter.asInstanceOf[Writer[State]] + @inline final private[this] def propsReader: Reader[Props] = + this.asInstanceOf[js.Dynamic]._base._propsReader.asInstanceOf[Reader[Props]] def initialState: State - this.asInstanceOf[PrivateComponentClass].stateR = { - val initialStateValue: State = initialState - val stateWithExtraApplyFix = if (initialStateValue.getClass == null) { - initialStateValue.asInstanceOf[js.Function0[State]].apply() - } else initialStateValue + @inline final private[slinky] def readPropsValue(value: js.Object): Props = readValue(value, propsReader) - if (BaseComponentWrapper.scalaComponentWritingEnabled && defaultBase != null) { - writeWithWrappingAdjustment(stateWriter)(stateWithExtraApplyFix) - } else js.Dynamic.literal(__ = stateWithExtraApplyFix.asInstanceOf[js.Any]) - } - - @inline private final def readPropsValue(value: js.Object): Props = { - if (js.typeOf(value) == "object" && value.hasOwnProperty("__")) { - value.asInstanceOf[js.Dynamic].__.asInstanceOf[Props] - } else { - readWithWrappingAdjustment(propsReader)(value) - } - } - - @inline private final def readStateValue(value: js.Object): State = { - if (js.typeOf(value) == "object" && value.hasOwnProperty("__")) { - value.asInstanceOf[js.Dynamic].__.asInstanceOf[State] - } else { - readWithWrappingAdjustment(stateReader)(value) - } - } + @inline final private[slinky] def readStateValue(value: js.Object): State = readValue(value, stateReader) @JSName("props_scala") - @inline final def props: Props = { + @inline final def props: Props = readPropsValue(this.asInstanceOf[PrivateComponentClass].propsR) - } @JSName("state_scala") - @inline final def state: State = { + @inline final def state: State = readStateValue(this.asInstanceOf[PrivateComponentClass].stateR) - } @JSName("setState_scala_1") @inline final def setState(s: State): Unit = { @@ -67,24 +42,22 @@ abstract class DefinitionBase[Props, State, Snapshot](jsProps: js.Object) extend } @JSName("setState_scala_2") - @inline final def setState(fn: State => State): Unit = { - this.asInstanceOf[PrivateComponentClass].setStateR((ps: js.Object) => { + @inline final def setState(fn: State => State): Unit = + this.asInstanceOf[PrivateComponentClass].setStateR { (ps: js.Object) => val s = fn(readStateValue(ps)) if (BaseComponentWrapper.scalaComponentWritingEnabled) { writeWithWrappingAdjustment(stateWriter)(s) } else js.Dynamic.literal(__ = s.asInstanceOf[js.Any]) - }) - } + } @JSName("setState_scala_3") - @inline final def setState(fn: (State, Props) => State): Unit = { - this.asInstanceOf[PrivateComponentClass].setStateR((ps: js.Object, p: js.Object) => { + @inline final def setState(fn: (State, Props) => State): Unit = + this.asInstanceOf[PrivateComponentClass].setStateR { (ps: js.Object, p: js.Object) => val s = fn(readStateValue(ps), readPropsValue(p)) if (BaseComponentWrapper.scalaComponentWritingEnabled) { writeWithWrappingAdjustment(stateWriter)(s) } else js.Dynamic.literal(__ = s.asInstanceOf[js.Any]) - }) - } + } @JSName("setState_scala_4") @inline final def setState(s: State, callback: () => Unit): Unit = { @@ -95,24 +68,32 @@ abstract class DefinitionBase[Props, State, Snapshot](jsProps: js.Object) extend } @JSName("setState_scala_5") - @inline final def setState(fn: State => State, callback: () => Unit): Unit = { - this.asInstanceOf[PrivateComponentClass].setStateR((ps: js.Object) => { - val s = fn(readStateValue(ps)) - if (BaseComponentWrapper.scalaComponentWritingEnabled) { - writeWithWrappingAdjustment(stateWriter)(s) - } else js.Dynamic.literal(__ = s.asInstanceOf[js.Any]) - }, callback) - } + @inline final def setState(fn: State => State, callback: () => Unit): Unit = + this + .asInstanceOf[PrivateComponentClass] + .setStateR( + (ps: js.Object) => { + val s = fn(readStateValue(ps)) + if (BaseComponentWrapper.scalaComponentWritingEnabled) { + writeWithWrappingAdjustment(stateWriter)(s) + } else js.Dynamic.literal(__ = s.asInstanceOf[js.Any]) + }, + callback + ) @JSName("setState_scala_6") - @inline final def setState(fn: (State, Props) => State, callback: () => Unit): Unit = { - this.asInstanceOf[PrivateComponentClass].setStateR((ps: js.Object, p: js.Object) => { - val s = fn(readStateValue(ps), readPropsValue(p)) - if (BaseComponentWrapper.scalaComponentWritingEnabled) { - writeWithWrappingAdjustment(stateWriter)(s) - } else js.Dynamic.literal(__ = s.asInstanceOf[js.Any]) - }, callback) - } + @inline final def setState(fn: (State, Props) => State, callback: () => Unit): Unit = + this + .asInstanceOf[PrivateComponentClass] + .setStateR( + (ps: js.Object, p: js.Object) => { + val s = fn(readStateValue(ps), readPropsValue(p)) + if (BaseComponentWrapper.scalaComponentWritingEnabled) { + writeWithWrappingAdjustment(stateWriter)(s) + } else js.Dynamic.literal(__ = s.asInstanceOf[js.Any]) + }, + callback + ) def componentWillMount(): Unit = {} @@ -126,104 +107,34 @@ abstract class DefinitionBase[Props, State, Snapshot](jsProps: js.Object) extend def getSnapshotBeforeUpdate(prevProps: Props, prevState: State): Snapshot = null.asInstanceOf[Snapshot] - private val origComponentDidUpdate = this.asInstanceOf[js.Dynamic].componentDidUpdate.bind(this).asInstanceOf[js.Function3[Props, State, Any, Unit]] - def componentDidUpdate(prevProps: Props, prevState: State): Unit = {} - def componentDidUpdate(prevProps: Props, prevState: State, snapshot: Snapshot): Unit = { - origComponentDidUpdate.asInstanceOf[js.Function2[Props, State, Unit]].apply(prevProps, prevState) - } + def componentDidUpdate(prevProps: Props, prevState: State, snapshot: Snapshot): Unit = + this + .asInstanceOf[js.Dynamic] + .componentDidUpdateScala(prevProps.asInstanceOf[js.Any], prevState.asInstanceOf[js.Any]) + .asInstanceOf[Unit] def componentWillUnmount(): Unit = {} def componentDidCatch(error: js.Error, info: ErrorBoundaryInfo): Unit = {} def render(): ReactElement - - if (defaultBase != null) { - if (this.asInstanceOf[js.Dynamic].componentWillMount == defaultBase.componentWillMount) { - this.asInstanceOf[js.Dynamic].componentWillMount = js.undefined - } - - if (this.asInstanceOf[js.Dynamic].componentDidMount == defaultBase.componentDidMount) { - this.asInstanceOf[js.Dynamic].componentDidMount = js.undefined - } - - if (this.asInstanceOf[js.Dynamic].componentWillReceiveProps != defaultBase.componentWillReceiveProps) { - val orig = this.asInstanceOf[js.Dynamic].componentWillReceiveProps.bind(this).asInstanceOf[js.Function1[Props, Unit]] - this.asInstanceOf[js.Dynamic].componentWillReceiveProps = (props: js.Object) => { - orig( - readPropsValue(props) - ) - } - } else { - this.asInstanceOf[js.Dynamic].componentWillReceiveProps = js.undefined - } - - if (this.asInstanceOf[js.Dynamic].shouldComponentUpdate != defaultBase.shouldComponentUpdate) { - val orig = this.asInstanceOf[js.Dynamic].shouldComponentUpdate.bind(this).asInstanceOf[js.Function2[Props, State, Boolean]] - this.asInstanceOf[js.Dynamic].shouldComponentUpdate = (nextProps: js.Object, nextState: js.Object) => { - orig( - readPropsValue(nextProps), - readStateValue(nextState) - ) - } - } else { - this.asInstanceOf[js.Dynamic].shouldComponentUpdate = js.undefined - } - - if (this.asInstanceOf[js.Dynamic].componentWillUpdate != defaultBase.componentWillUpdate) { - val orig = this.asInstanceOf[js.Dynamic].componentWillUpdate.bind(this).asInstanceOf[js.Function2[Props, State, Unit]] - this.asInstanceOf[js.Dynamic].componentWillUpdate = (nextProps: js.Object, nextState: js.Object) => { - orig( - readPropsValue(nextProps), - readStateValue(nextState) - ) - } - } else { - this.asInstanceOf[js.Dynamic].componentWillUpdate = js.undefined - } - - if (this.asInstanceOf[js.Dynamic].getSnapshotBeforeUpdate != defaultBase.getSnapshotBeforeUpdate) { - val orig = this.asInstanceOf[js.Dynamic].getSnapshotBeforeUpdate.bind(this).asInstanceOf[js.Function2[Props, State, Any]] - this.asInstanceOf[js.Dynamic].getSnapshotBeforeUpdate = (prevProps: js.Object, prevState: js.Object) => { - orig( - readPropsValue(prevProps), - readStateValue(prevState) - ) - } - } else { - this.asInstanceOf[js.Dynamic].getSnapshotBeforeUpdate = js.undefined - } - - if (this.asInstanceOf[js.Dynamic].componentDidUpdate != defaultBase.componentDidUpdate) { - this.asInstanceOf[js.Dynamic].componentDidUpdate = (prevProps: js.Object, prevState: js.Object, snapshot: Any) => { - origComponentDidUpdate( - readPropsValue(prevProps), - readStateValue(prevState), - snapshot - ) - } - } else { - this.asInstanceOf[js.Dynamic].componentDidUpdate = js.undefined - } - - if (this.asInstanceOf[js.Dynamic].componentWillUnmount == defaultBase.componentWillUnmount) { - this.asInstanceOf[js.Dynamic].componentWillUnmount = js.undefined - } - - if (this.asInstanceOf[js.Dynamic].componentDidCatch == defaultBase.componentDidCatch) { - this.asInstanceOf[js.Dynamic].componentDidCatch = js.undefined - } - } } object DefinitionBase { - private[DefinitionBase] val defaultBase = new DefinitionBase[Unit, Unit, Unit](null) { - override def initialState: Unit = () + private[slinky] val defaultBase = new DefinitionBase[Unit, Unit, Unit](null) { + override def initialState: Unit = () override def render(): ReactElement = null }.asInstanceOf[js.Dynamic] - private[slinky] final def readWithWrappingAdjustment[T](reader: Reader[T])(value: js.Object): T = { + @inline final private[slinky] def readValue[P](value: js.Object, propsReader: => Reader[P]): P = + if (js.typeOf(value) == "object" && value.hasOwnProperty("__")) { + value.asInstanceOf[js.Dynamic].__.asInstanceOf[P] + } else { + readWithWrappingAdjustment(propsReader)(value) + } + + final private[slinky] def readWithWrappingAdjustment[T](reader: Reader[T])(value: js.Object): T = { val __value = value.asInstanceOf[js.Dynamic].__value if (value.hasOwnProperty("__value")) { @@ -233,7 +144,7 @@ object DefinitionBase { } } - private[slinky] final def writeWithWrappingAdjustment[T](writer: Writer[T])(value: T): js.Object = { + final private[slinky] def writeWithWrappingAdjustment[T](writer: Writer[T])(value: T): js.Object = { val __value = writer.write(value) if (js.typeOf(__value) == "object") { diff --git a/core/src/main/scala/slinky/core/ExternalComponent.scala b/core/src/main/scala/slinky/core/ExternalComponent.scala index 98ae6392..7d92a64c 100644 --- a/core/src/main/scala/slinky/core/ExternalComponent.scala +++ b/core/src/main/scala/slinky/core/ExternalComponent.scala @@ -1,6 +1,6 @@ package slinky.core -import slinky.core.facade.{ReactRaw, ReactElement, ReactRef} +import slinky.core.facade.{ReactElement, ReactRaw, ReactRef} import slinky.readwrite.Writer import scala.scalajs.js @@ -60,7 +60,8 @@ object BuildingComponent { } val ret = ReactRaw.createElement - .applyDynamic("apply")(ReactRaw, comp.args).asInstanceOf[ReactElement] + .applyDynamic("apply")(ReactRaw, comp.args) + .asInstanceOf[ReactElement] comp.args(0) = null @@ -68,7 +69,9 @@ object BuildingComponent { } } -abstract class ExternalComponentWithAttributesWithRefType[E <: TagElement, R <: js.Object](implicit pw: ExternalPropsWriterProvider) { +abstract class ExternalComponentWithAttributesWithRefType[E <: TagElement, R <: js.Object]( + implicit pw: ExternalPropsWriterProvider +) { type Props type Element = E type RefType = R @@ -77,25 +80,25 @@ abstract class ExternalComponentWithAttributesWithRefType[E <: TagElement, R <: val component: String | js.Object - def apply(p: Props): BuildingComponent[E, R] = { + def apply(p: Props): BuildingComponent[E, R] = // no need to take key or ref here because those can be passed in through attributes new BuildingComponent(js.Array(component.asInstanceOf[js.Any], writer.write(p))) - } } abstract class ExternalComponentWithAttributes[E <: TagElement](implicit pw: ExternalPropsWriterProvider) - extends ExternalComponentWithAttributesWithRefType[E, js.Object]()(pw) + extends ExternalComponentWithAttributesWithRefType[E, js.Object]()(pw) -abstract class ExternalComponentWithRefType[R <: js.Object](implicit pw: ExternalPropsWriterProvider) extends ExternalComponentWithAttributesWithRefType[Nothing, R]()(pw) +abstract class ExternalComponentWithRefType[R <: js.Object](implicit pw: ExternalPropsWriterProvider) + extends ExternalComponentWithAttributesWithRefType[Nothing, R]()(pw) -abstract class ExternalComponent(implicit pw: ExternalPropsWriterProvider) extends ExternalComponentWithAttributes[Nothing]()(pw) +abstract class ExternalComponent(implicit pw: ExternalPropsWriterProvider) + extends ExternalComponentWithAttributes[Nothing]()(pw) abstract class ExternalComponentNoPropsWithAttributesWithRefType[E <: TagElement, R <: js.Object] { val component: String | js.Object - def apply(mods: TagMod[E]*): BuildingComponent[E, R] = { + def apply(mods: TagMod[E]*): BuildingComponent[E, R] = new BuildingComponent(js.Array(component.asInstanceOf[js.Any], js.Dictionary.empty)).apply(mods: _*) - } def withKey(key: String): BuildingComponent[E, R] = new BuildingComponent(js.Array(component.asInstanceOf[js.Any], js.Dictionary.empty)).withKey(key) @@ -106,10 +109,10 @@ abstract class ExternalComponentNoPropsWithAttributesWithRefType[E <: TagElement } abstract class ExternalComponentNoPropsWithAttributes[T <: TagElement] - extends ExternalComponentNoPropsWithAttributesWithRefType[T, js.Object] + extends ExternalComponentNoPropsWithAttributesWithRefType[T, js.Object] abstract class ExternalComponentNoPropsWithRefType[R <: js.Object] - extends ExternalComponentNoPropsWithAttributesWithRefType[Nothing, R] + extends ExternalComponentNoPropsWithAttributesWithRefType[Nothing, R] abstract class ExternalComponentNoProps extends ExternalComponentNoPropsWithAttributes[Nothing] @@ -119,7 +122,9 @@ object ExternalPropsWriterProvider { def impl(c: whitebox.Context): c.Expr[ExternalPropsWriterProvider] = { import c.universe._ val compName = c.internal.enclosingOwner.owner.asClass - val q"$_; val x: $typedReaderType = null" = c.typecheck(q"@_root_.scala.annotation.unchecked.uncheckedStable val comp: $compName = null; val x: _root_.slinky.readwrite.Writer[comp.Props] = null") // scalafix:ok + val q"$_; val x: $typedReaderType = null" = c.typecheck( + q"@_root_.scala.annotation.unchecked.uncheckedStable val comp: $compName = null; val x: _root_.slinky.readwrite.Writer[comp.Props] = null" + ) // scalafix:ok val tpcls = c.inferImplicitValue(typedReaderType.tpe.asInstanceOf[c.Type]) c.Expr(q"$tpcls.asInstanceOf[_root_.slinky.core.ExternalPropsWriterProvider]") } diff --git a/core/src/main/scala/slinky/core/FunctionalComponent.scala b/core/src/main/scala/slinky/core/FunctionalComponent.scala index e147c24c..43207638 100644 --- a/core/src/main/scala/slinky/core/FunctionalComponent.scala +++ b/core/src/main/scala/slinky/core/FunctionalComponent.scala @@ -1,7 +1,7 @@ package slinky.core import slinky.readwrite.Reader -import slinky.core.facade.{ReactRaw, ReactElement, ReactRef} +import slinky.core.facade.{ReactElement, ReactRaw, ReactRef} import scala.scalajs.js import scala.reflect.macros.whitebox @@ -24,20 +24,22 @@ object KeyAddingStage { } val ret = ReactRaw.createElement - .applyDynamic("apply")(ReactRaw, stage.args).asInstanceOf[ReactElement] + .applyDynamic("apply")(ReactRaw, stage.args) + .asInstanceOf[ReactElement] stage.args(0) = null ret } - @inline implicit def buildContainer[F[_]](stage: F[KeyAddingStage])(implicit f: ReactElementContainer[F]): F[ReactElement] = { + @inline implicit def buildContainer[F[_]]( + stage: F[KeyAddingStage] + )(implicit f: ReactElementContainer[F]): F[ReactElement] = f.map(stage)(build) - } } -final class FunctionalComponent[P] private[core](private[core] val component: js.Function) extends AnyVal { - type Props = P +final class FunctionalComponent[P] private[core] (private[core] val component: js.Function) extends AnyVal { + type Props = P type Result = KeyAddingStage private[core] def componentWithReader(propsReader: Reader[P]) = { @@ -45,15 +47,19 @@ final class FunctionalComponent[P] private[core](private[core] val component: js component } - @inline def apply(props: P): KeyAddingStage = { - new KeyAddingStage(js.Array(component, js.Dynamic.literal( - __ = props.asInstanceOf[js.Any] - ))) - } + @inline def apply(props: P): KeyAddingStage = + new KeyAddingStage( + js.Array( + component, + js.Dynamic.literal( + __ = props.asInstanceOf[js.Any] + ) + ) + ) } -final class FunctionalComponentTakingRef[P, R] private[core](private[core] val component: js.Function) extends AnyVal { - type Props = P +final class FunctionalComponentTakingRef[P, R] private[core] (private[core] val component: js.Function) extends AnyVal { + type Props = P type Result = KeyAddingStage private[core] def componentWithReader(propsReader: Reader[P]) = { @@ -61,15 +67,19 @@ final class FunctionalComponentTakingRef[P, R] private[core](private[core] val c component } - @inline def apply(props: P): KeyAddingStage = { - new KeyAddingStage(js.Array(component, js.Dynamic.literal( - __ = props.asInstanceOf[js.Any] - ))) - } + @inline def apply(props: P): KeyAddingStage = + new KeyAddingStage( + js.Array( + component, + js.Dynamic.literal( + __ = props.asInstanceOf[js.Any] + ) + ) + ) } -final class FunctionalComponentForwardedRef[P, R] private[core](private[core] val component: js.Any) extends AnyVal { - type Props = P +final class FunctionalComponentForwardedRef[P, R] private[core] (private[core] val component: js.Any) extends AnyVal { + type Props = P type Result = KeyAndRefAddingStage[R] private[core] def componentWithReader(propsReader: Reader[P]) = { @@ -77,50 +87,53 @@ final class FunctionalComponentForwardedRef[P, R] private[core](private[core] va component } - @inline def apply(props: P): KeyAndRefAddingStage[R] = { - new KeyAndRefAddingStage[R](js.Array( - component, - js.Dynamic.literal( - __ = props.asInstanceOf[js.Any] + @inline def apply(props: P): KeyAndRefAddingStage[R] = + new KeyAndRefAddingStage[R]( + js.Array( + component, + js.Dynamic.literal( + __ = props.asInstanceOf[js.Any] + ) ) - )) - } + ) } object FunctionalComponent { - def apply[P](fn: P => ReactElement)(implicit name: FunctionalComponentName) = new FunctionalComponent[P]({ - var ret: js.Function1[js.Object, ReactElement] = null - ret = ((obj: js.Object) => { - if (obj.hasOwnProperty("__")) { - fn(obj.asInstanceOf[js.Dynamic].__.asInstanceOf[P]) - } else { - fn(ret.asInstanceOf[js.Dynamic].__propsReader.asInstanceOf[Reader[P]].read(obj)) + def apply[P](fn: P => ReactElement)(implicit name: FunctionalComponentName) = + new FunctionalComponent[P]({ + var ret: js.Function1[js.Object, ReactElement] = null + ret = ((obj: js.Object) => { + if (obj.hasOwnProperty("__")) { + fn(obj.asInstanceOf[js.Dynamic].__.asInstanceOf[P]) + } else { + fn(ret.asInstanceOf[js.Dynamic].__propsReader.asInstanceOf[Reader[P]].read(obj)) + } + }) + + if (!scala.scalajs.LinkingInfo.productionMode) { + ret.asInstanceOf[js.Dynamic].displayName = name.name } - }) - - if (!scala.scalajs.LinkingInfo.productionMode) { - ret.asInstanceOf[js.Dynamic].displayName = name.name - } - ret - }) - - def apply[P, R](fn: (P, ReactRef[R]) => ReactElement)(implicit name: FunctionalComponentName) = new FunctionalComponentTakingRef[P, R]({ - var ret: js.Function2[js.Object, ReactRef[R], ReactElement] = null - ret = ((obj: js.Object, ref: ReactRef[R]) => { - if (obj.hasOwnProperty("__")) { - fn(obj.asInstanceOf[js.Dynamic].__.asInstanceOf[P], ref) - } else { - fn(ret.asInstanceOf[js.Dynamic].__propsReader.asInstanceOf[Reader[P]].read(obj), ref) - } + ret }) - if (!scala.scalajs.LinkingInfo.productionMode) { - ret.asInstanceOf[js.Dynamic].displayName = name.name - } + def apply[P, R](fn: (P, ReactRef[R]) => ReactElement)(implicit name: FunctionalComponentName) = + new FunctionalComponentTakingRef[P, R]({ + var ret: js.Function2[js.Object, ReactRef[R], ReactElement] = null + ret = ((obj: js.Object, ref: ReactRef[R]) => { + if (obj.hasOwnProperty("__")) { + fn(obj.asInstanceOf[js.Dynamic].__.asInstanceOf[P], ref) + } else { + fn(ret.asInstanceOf[js.Dynamic].__propsReader.asInstanceOf[Reader[P]].read(obj), ref) + } + }) + + if (!scala.scalajs.LinkingInfo.productionMode) { + ret.asInstanceOf[js.Dynamic].displayName = name.name + } - ret - }) + ret + }) } final class FunctionalComponentName(val name: String) extends AnyVal @@ -133,19 +146,19 @@ object FunctionalComponentNameMacros { import c.universe._ // from lihaoyi/sourcecode - def isSyntheticName(name: String) = { + def isSyntheticName(name: String) = name == "" || (name.startsWith("")) || name == "component" - } @scala.annotation.tailrec - def findNonSyntheticOwner(current: Symbol): Symbol = { + def findNonSyntheticOwner(current: Symbol): Symbol = if (isSyntheticName(current.name.decodedName.toString.trim)) { findNonSyntheticOwner(current.owner) } else { current } - } - c.Expr(q"new _root_.slinky.core.FunctionalComponentName(${findNonSyntheticOwner(c.internal.enclosingOwner).name.decodedName.toString})") + c.Expr( + q"new _root_.slinky.core.FunctionalComponentName(${findNonSyntheticOwner(c.internal.enclosingOwner).name.decodedName.toString})" + ) } } diff --git a/core/src/main/scala/slinky/core/ReactComponentClass.scala b/core/src/main/scala/slinky/core/ReactComponentClass.scala index f59294e7..4d39703a 100644 --- a/core/src/main/scala/slinky/core/ReactComponentClass.scala +++ b/core/src/main/scala/slinky/core/ReactComponentClass.scala @@ -9,21 +9,26 @@ import scala.scalajs.js.ConstructorTag trait ReactComponentClass[P] extends js.Object object ReactComponentClass { - implicit def wrapperToClass[T <: BaseComponentWrapper](wrapper: T) - (implicit propsReader: Reader[wrapper.Props], - ctag: ConstructorTag[wrapper.Def]): ReactComponentClass[wrapper.Props] = { - wrapper.componentConstructor(propsReader, wrapper.hot_stateWriter, wrapper.hot_stateReader, ctag).asInstanceOf[ReactComponentClass[wrapper.Props]] - } + implicit def wrapperToClass[T <: BaseComponentWrapper](wrapper: T)( + implicit propsReader: Reader[wrapper.Props], + ctag: ConstructorTag[wrapper.Def] + ): ReactComponentClass[wrapper.Props] = + wrapper + .componentConstructor(propsReader, wrapper.hot_stateWriter, wrapper.hot_stateReader, ctag) + .asInstanceOf[ReactComponentClass[wrapper.Props]] - implicit def functionalComponentToClass[P](component: FunctionalComponent[P])(implicit propsReader: Reader[P]): ReactComponentClass[P] = { + implicit def functionalComponentToClass[P]( + component: FunctionalComponent[P] + )(implicit propsReader: Reader[P]): ReactComponentClass[P] = component.componentWithReader(propsReader).asInstanceOf[ReactComponentClass[P]] - } - implicit def functionalComponentTakingRefToClass[P, R <: js.Any](component: FunctionalComponentTakingRef[P, R])(implicit propsReader: Reader[P]): ReactComponentClass[P] = { + implicit def functionalComponentTakingRefToClass[P, R <: js.Any]( + component: FunctionalComponentTakingRef[P, R] + )(implicit propsReader: Reader[P]): ReactComponentClass[P] = component.componentWithReader(propsReader).asInstanceOf[ReactComponentClass[P]] - } - implicit def functionalComponentForwardedRefToClass[P, R <: js.Any](component: FunctionalComponentForwardedRef[P, R])(implicit propsReader: Reader[P]): ReactComponentClass[P] = { + implicit def functionalComponentForwardedRefToClass[P, R <: js.Any]( + component: FunctionalComponentForwardedRef[P, R] + )(implicit propsReader: Reader[P]): ReactComponentClass[P] = component.componentWithReader(propsReader).asInstanceOf[ReactComponentClass[P]] - } } diff --git a/core/src/main/scala/slinky/core/ReactElementContainer.scala b/core/src/main/scala/slinky/core/ReactElementContainer.scala index 185a5c17..9765680c 100644 --- a/core/src/main/scala/slinky/core/ReactElementContainer.scala +++ b/core/src/main/scala/slinky/core/ReactElementContainer.scala @@ -12,7 +12,7 @@ trait ReactElementContainer[F[_]] extends Any { self => } object ReactElementContainer { - def apply[F[_] : ReactElementContainer]: ReactElementContainer[F] = implicitly[ReactElementContainer[F]] + def apply[F[_]: ReactElementContainer]: ReactElementContainer[F] = implicitly[ReactElementContainer[F]] @inline implicit def function0Container: ReactElementContainer[Function0] = new ReactElementContainer[Function0] { override def map[A](fa: () => A)(f: A => ReactElement): () => ReactElement = () => f(fa()) @@ -62,4 +62,4 @@ object ReactElementContainer { @inline implicit def vectorContainer: ReactElementContainer[Vector] = new ReactElementContainer[Vector] { override def map[A](fa: Vector[A])(f: A => ReactElement): Vector[ReactElement] = fa.map(f) } -} \ No newline at end of file +} diff --git a/core/src/main/scala/slinky/core/StatelessComponentWrapper.scala b/core/src/main/scala/slinky/core/StatelessComponentWrapper.scala index 633b1ff4..9afdae1e 100644 --- a/core/src/main/scala/slinky/core/StatelessComponentWrapper.scala +++ b/core/src/main/scala/slinky/core/StatelessComponentWrapper.scala @@ -4,14 +4,16 @@ import slinky.readwrite.{Reader, Writer} import scala.scalajs.js -abstract class StatelessDefinition[Props, Snapshot](jsProps: js.Object) extends DefinitionBase[Props, Unit, Snapshot](jsProps) { +abstract class StatelessDefinition[Props, Snapshot](jsProps: js.Object) + extends DefinitionBase[Props, Unit, Snapshot](jsProps) { override def initialState: Unit = () } -abstract class StatelessComponentWrapper extends BaseComponentWrapper( - Reader.unitReader.asInstanceOf[StateReaderProvider], - Writer.unitWriter.asInstanceOf[StateWriterProvider] -) { +abstract class StatelessComponentWrapper + extends BaseComponentWrapper( + Reader.unitReader.asInstanceOf[StateReaderProvider], + Writer.unitWriter.asInstanceOf[StateWriterProvider] + ) { override type State = Unit override type Definition = StatelessDefinition[Props, Snapshot] diff --git a/core/src/main/scala/slinky/core/SyntheticEvent.scala b/core/src/main/scala/slinky/core/SyntheticEvent.scala index 31019089..6e9b1940 100644 --- a/core/src/main/scala/slinky/core/SyntheticEvent.scala +++ b/core/src/main/scala/slinky/core/SyntheticEvent.scala @@ -3,19 +3,20 @@ package slinky.core import scala.scalajs.js import scala.scalajs.js.annotation.JSName -@js.native trait SyntheticEvent[+TargetType, +EventType] extends js.Object { - val bubbles: Boolean = js.native - val cancelable: Boolean = js.native - val currentTarget: TargetType = js.native - val defaultPrevented: Boolean = js.native - val eventPhase: Int = js.native - val isTrusted: Boolean = js.native - val nativeEvent: EventType = js.native - def preventDefault(): Unit = js.native - def isDefaultPrevented(): Boolean = js.native - def stopPropagation(): Unit = js.native +@js.native +trait SyntheticEvent[+TargetType, +EventType] extends js.Object { + val bubbles: Boolean = js.native + val cancelable: Boolean = js.native + val currentTarget: TargetType = js.native + val defaultPrevented: Boolean = js.native + val eventPhase: Int = js.native + val isTrusted: Boolean = js.native + val nativeEvent: EventType = js.native + def preventDefault(): Unit = js.native + def isDefaultPrevented(): Boolean = js.native + def stopPropagation(): Unit = js.native def isPropagationStopped(): Boolean = js.native - val target: TargetType = js.native - val timeStamp: Int = js.native - @JSName("type") val `type`: String = js.native + val target: TargetType = js.native + val timeStamp: Int = js.native + @JSName("type") val `type`: String = js.native } diff --git a/core/src/main/scala/slinky/core/TagComponent.scala b/core/src/main/scala/slinky/core/TagComponent.scala index 264729df..7ad303f0 100644 --- a/core/src/main/scala/slinky/core/TagComponent.scala +++ b/core/src/main/scala/slinky/core/TagComponent.scala @@ -12,9 +12,8 @@ trait Tag { final class CustomTag(@inline private val name: String) extends Tag { override type tagType = Nothing - @inline def apply(mods: TagMod[tagType]*): WithAttrs[tagType] = { + @inline def apply(mods: TagMod[tagType]*): WithAttrs[tagType] = WithAttrs[tagType](name, mods) - } } object CustomTag { def apply(name: String): CustomTag = new CustomTag(name) @@ -30,7 +29,7 @@ abstract class TagElement { } final class CustomAttribute[T](@inline private val name: String) { - @inline def :=(v: T) = new AttrPair[Any](name, v.asInstanceOf[js.Any]) + @inline def :=(v: T) = new AttrPair[Any](name, v.asInstanceOf[js.Any]) @inline def :=(v: Option[T]) = new OptionalAttrPair[Any](name, v.asInstanceOf[Option[js.Any]]) } object CustomAttribute { @@ -44,18 +43,19 @@ object TagMod { ev(elem) } -@js.native trait ReactElementMod extends TagMod[Any] +@js.native +trait ReactElementMod extends TagMod[Any] -@js.native trait RefAttr[-T] extends js.Object +@js.native +trait RefAttr[-T] extends js.Object object RefAttr { @inline implicit def fromReact[T](in: slinky.core.facade.ReactRef[T]): RefAttr[T] = in.asInstanceOf[RefAttr[T]] } -final class AttrPair[-A](@inline final val name: String, - @inline final val value: js.Any) extends TagMod[A] +final class AttrPair[-A](@inline final val name: String, @inline final val value: js.Any) extends TagMod[A] -final class OptionalAttrPair[-A](@inline final val name: String, - @inline final val value: Option[js.Any]) extends TagMod[A] +final class OptionalAttrPair[-A](@inline final val name: String, @inline final val value: Option[js.Any]) + extends TagMod[A] object OptionalAttrPair { @inline def optionToJsOption[T](o: Option[T])(implicit a: T => js.Any): Option[js.Any] = @@ -95,14 +95,16 @@ object WithAttrs { } val ret = ReactRaw.createElement - .applyDynamic("apply")(ReactRaw, withAttrs.args).asInstanceOf[ReactElement] + .applyDynamic("apply")(ReactRaw, withAttrs.args) + .asInstanceOf[ReactElement] withAttrs.args(0) = null ret } - @inline implicit def buildContainer[F[_]](withAttrs: F[WithAttrs[_]])(implicit f: ReactElementContainer[F]): F[ReactElement] = { + @inline implicit def buildContainer[F[_]]( + withAttrs: F[WithAttrs[_]] + )(implicit f: ReactElementContainer[F]): F[ReactElement] = f.map(withAttrs)(build) - } -} \ No newline at end of file +} diff --git a/core/src/main/scala/slinky/core/annotations/react.scala b/core/src/main/scala/slinky/core/annotations/react.scala index 8e19e44c..b6ce202d 100644 --- a/core/src/main/scala/slinky/core/annotations/react.scala +++ b/core/src/main/scala/slinky/core/annotations/react.scala @@ -33,14 +33,15 @@ object ReactMacrosImpl { import c.universe._ val q"..$_ class ${className: Name} extends ..$parents { $self => ..$stats}" = cls // scalafix:ok val (propsDefinition, applyMethods) = stats.flatMap { - case defn@q"..$_ type Props = ${_}" => + case defn @ q"..$_ type Props = ${_}" => Some((defn, Seq())) - case defn@q"case class Props[..$tparams](...${caseClassparamssRaw}) extends ..$_ { $_ => ..$_ }" => + case defn @ q"case class Props[..$tparams](...${caseClassparamssRaw}) extends ..$_ { $_ => ..$_ }" => val caseClassparamss = caseClassparamssRaw.asInstanceOf[Seq[Seq[ValDef]]] - val childrenParam = caseClassparamss.flatten.find(_.name.toString == "children") + val childrenParam = caseClassparamss.flatten.find(_.name.toString == "children") - val paramssWithoutChildren = caseClassparamss.map(_.filterNot(childrenParam.contains)) + val paramssWithoutChildren = caseClassparamss + .map(_.filterNot(childrenParam.contains)) .filterNot(_.isEmpty) val applyValues = caseClassparamss.map(ps => ps.map(_.name)) @@ -48,11 +49,13 @@ object ReactMacrosImpl { // from https://groups.google.com/forum/#!topic/scala-user/dUOonrP_5K4 val body = c.typecheck(childrenParam.get.tpt, c.TYPEmode).tpe match { case TypeRef(_, sym, _) if sym == definitions.RepeatedParamClass => - val applyValuesChildrenVararg = caseClassparamss.map(ps => ps.map { ps => - if (ps == childrenParam.get) { - q"${ps.name}: _*" - } else q"${ps.name}" - }) + val applyValuesChildrenVararg = caseClassparamss.map { ps => + ps.map { ps => + if (ps == childrenParam.get) { + q"${ps.name}: _*" + } else q"${ps.name}" + } + } q"this.apply(Props.apply[..$tparams](...$applyValuesChildrenVararg))" case _ => @@ -69,25 +72,26 @@ object ReactMacrosImpl { Some((defn, Seq(caseClassApply))) case _ => None - }.headOption.getOrElse(c.abort(c.enclosingPosition, "Components must define a Props type or case class, but none was found.")) + }.headOption + .getOrElse(c.abort(c.enclosingPosition, "Components must define a Props type or case class, but none was found.")) val stateDefinition = stats.flatMap { - case defn@q"..$_ type State = ${_}" => + case defn @ q"..$_ type State = ${_}" => Some(defn) - case defn@q"case class State[..$_](...$_) extends ..$_ { $_ => ..$_ }" => + case defn @ q"case class State[..$_](...$_) extends ..$_ { $_ => ..$_ }" => Some(defn) case _ => None }.headOption val snapshotDefinition = stats.flatMap { - case defn@q"type Snapshot = ${_}" => + case defn @ q"type Snapshot = ${_}" => Some(defn) - case defn@q"case class Snapshot[..$_](...$_) extends ..$_ { $_ => ..$_ }" => + case defn @ q"case class Snapshot[..$_](...$_) extends ..$_ { $_ => ..$_ }" => Some(defn) case _ => None }.headOption - val clazz = TypeName(className.asInstanceOf[Name].toString) + val clazz = TypeName(className.asInstanceOf[Name].toString) val companion = TermName(className.asInstanceOf[Name].toString) val definitionClass = q"type Def = $clazz" @@ -101,10 +105,13 @@ object ReactMacrosImpl { null.asInstanceOf[Snapshot] () }) - ..${stats.filterNot(s => s == propsDefinition || s == stateDefinition.orNull || s == snapshotDefinition.orNull)} + ..${stats.filterNot(s => + s == propsDefinition || s == stateDefinition.orNull || s == snapshotDefinition.orNull + )} }""" - (newClazz, + ( + newClazz, ((q"null.asInstanceOf[${parents.head}]" +: propsDefinition +: stateDefinition.toList) ++ @@ -125,7 +132,10 @@ object ReactMacrosImpl { typeOf[js.Object] } else if (parentsContainsType(c)(parents.asInstanceOf[Seq[c.Tree]], typeOf[ExternalComponentWithRefType[_]])) { typecheckedParent.tpe.typeArgs.head - } else if (parentsContainsType(c)(parents.asInstanceOf[Seq[c.Tree]], typeOf[ExternalComponentWithAttributesWithRefType[_, _]])) { + } else if (parentsContainsType(c)( + parents.asInstanceOf[Seq[c.Tree]], + typeOf[ExternalComponentWithAttributesWithRefType[_, _]] + )) { typecheckedParent.tpe.typeArgs(1) } else { null @@ -137,7 +147,10 @@ object ReactMacrosImpl { typecheckedParent.tpe.typeArgs.head } else if (parentsContainsType(c)(parents.asInstanceOf[Seq[c.Tree]], typeOf[ExternalComponentWithRefType[_]])) { typeOf[Nothing] - } else if (parentsContainsType(c)(parents.asInstanceOf[Seq[c.Tree]], typeOf[ExternalComponentWithAttributesWithRefType[_, _]])) { + } else if (parentsContainsType(c)( + parents.asInstanceOf[Seq[c.Tree]], + typeOf[ExternalComponentWithAttributesWithRefType[_, _]] + )) { typecheckedParent.tpe.typeArgs.head } else { null @@ -183,55 +196,65 @@ object ReactMacrosImpl { (body, refType, elementType) } - def reactImpl(c: whitebox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = { import c.universe._ val outs: List[Tree] = annottees.map(_.tree).toList match { case Seq(cls @ q"..$_ class $className extends ..$parents { $_ => ..$_}") - if parentsContainsType(c)(parents, typeOf[Component]) || - parentsContainsType(c)(parents, typeOf[StatelessComponent]) => + if parentsContainsType(c)(parents, typeOf[Component]) || + parentsContainsType(c)(parents, typeOf[StatelessComponent]) => val (newCls, companionStats) = createComponentBody(c)(cls) - val parent = tq"${TermName(parents.head.toString)}.Wrapper" + val parent = tq"${TermName(parents.head.toString)}.Wrapper" List(newCls, q"object ${TermName(className.decodedName.toString)} extends $parent { ..$companionStats }") - case Seq(cls @ q"..$_ class $className extends ..$parents { $_ => ..$_}", obj @ q"..$_ object $_ extends ..$_ { $_ => ..$objStats }") - if parentsContainsType(c)(parents, typeOf[Component]) || - parentsContainsType(c)(parents, typeOf[StatelessComponent])=> + case Seq( + cls @ q"..$_ class $className extends ..$parents { $_ => ..$_}", + obj @ q"..$_ object $_ extends ..$_ { $_ => ..$objStats }" + ) + if parentsContainsType(c)(parents, typeOf[Component]) || + parentsContainsType(c)(parents, typeOf[StatelessComponent]) => val (newCls, companionStats) = createComponentBody(c)(cls) - val parent = tq"${TermName(parents.head.toString)}.Wrapper" - List(newCls, q"object ${TermName(className.decodedName.toString)} extends $parent { ..${objStats ++ companionStats} }") + val parent = tq"${TermName(parents.head.toString)}.Wrapper" + List( + newCls, + q"object ${TermName(className.decodedName.toString)} extends $parent { ..${objStats ++ companionStats} }" + ) case Seq(obj @ q"..$_ object $objName extends ..$parents { $_ => ..$objStats}") - if parentsContainsType(c)(parents, typeOf[ExternalComponent]) || - parentsContainsType(c)(parents, typeOf[ExternalComponentWithAttributes[_]]) || - parentsContainsType(c)(parents, typeOf[ExternalComponentWithRefType[_]]) || - parentsContainsType(c)(parents, typeOf[ExternalComponentWithAttributesWithRefType[_, _]]) => + if parentsContainsType(c)(parents, typeOf[ExternalComponent]) || + parentsContainsType(c)(parents, typeOf[ExternalComponentWithAttributes[_]]) || + parentsContainsType(c)(parents, typeOf[ExternalComponentWithRefType[_]]) || + parentsContainsType(c)(parents, typeOf[ExternalComponentWithAttributesWithRefType[_, _]]) => val (companionStats, refType, elementType) = createExternalBody(c)(obj) - List(q"object $objName extends _root_.slinky.core.ExternalComponentWithAttributesWithRefType[$elementType, $refType] { ..${objStats ++ companionStats} }") + List( + q"object $objName extends _root_.slinky.core.ExternalComponentWithAttributesWithRefType[$elementType, $refType] { ..${objStats ++ companionStats} }" + ) case Seq(obj @ q"$pre object $objName extends ..$parents { $self => ..$objStats }") if (objStats.exists { - case q"$_ val component: $_ = $_" => true - case _ => false - }) => + case q"$_ val component: $_ = $_" => true + case _ => false + }) => val applyMethods = objStats.flatMap { - case defn@q"case class Props[..$tparams](...${caseClassparamssRaw}) extends ..$_ { $_ => ..$_ }" => + case defn @ q"case class Props[..$tparams](...${caseClassparamssRaw}) extends ..$_ { $_ => ..$_ }" => val caseClassparamss = caseClassparamssRaw.asInstanceOf[Seq[Seq[ValDef]]] - val childrenParam = caseClassparamss.flatten.find(_.name.toString == "children") + val childrenParam = caseClassparamss.flatten.find(_.name.toString == "children") - val paramssWithoutChildren = caseClassparamss.map(_.filterNot(childrenParam.contains)) + val paramssWithoutChildren = caseClassparamss + .map(_.filterNot(childrenParam.contains)) .filterNot(_.isEmpty) val applyValues = caseClassparamss.map(ps => ps.map(_.name)) - + val caseClassApply = if (childrenParam.isDefined) { // from https://groups.google.com/forum/#!topic/scala-user/dUOonrP_5K4 val body = c.typecheck(childrenParam.get.tpt, c.TYPEmode).tpe match { case TypeRef(_, sym, _) if sym == definitions.RepeatedParamClass => - val applyValuesChildrenVararg = caseClassparamss.map(ps => ps.map { ps => - if (ps == childrenParam.get) { - q"${ps.name}: _*" - } else q"${ps.name}" - }) + val applyValuesChildrenVararg = caseClassparamss.map { ps => + ps.map { ps => + if (ps == childrenParam.get) { + q"${ps.name}: _*" + } else q"${ps.name}" + } + } q"component.apply(Props.apply(...$applyValuesChildrenVararg))" case _ => diff --git a/core/src/main/scala/slinky/core/facade/React.scala b/core/src/main/scala/slinky/core/facade/React.scala index 34b3e10f..e19b0d75 100644 --- a/core/src/main/scala/slinky/core/facade/React.scala +++ b/core/src/main/scala/slinky/core/facade/React.scala @@ -12,36 +12,31 @@ import scala.scalajs.js.JSConverters._ trait ReactElement extends js.Object with ReactElementMod object ReactElement { - @inline implicit def stringToElement(s: String): ReactElement = { + @inline implicit def stringToElement(s: String): ReactElement = s.asInstanceOf[ReactElement] - } - @inline implicit def intToElement(i: Int): ReactElement = { + @inline implicit def intToElement(i: Int): ReactElement = i.asInstanceOf[ReactElement] - } - @inline implicit def doubleToElement(d: Double): ReactElement = { + @inline implicit def doubleToElement(d: Double): ReactElement = d.asInstanceOf[ReactElement] - } - @inline implicit def floatToElement(f: Float): ReactElement = { + @inline implicit def floatToElement(f: Float): ReactElement = f.asInstanceOf[ReactElement] - } - @inline implicit def booleanToElement(b: Boolean): ReactElement = { + @inline implicit def booleanToElement(b: Boolean): ReactElement = b.asInstanceOf[ReactElement] - } - @inline implicit def iterableToElement[A, B <: Iterable[A]](e: Iterable[A])(implicit cv: A => ReactElement): ReactElement = { + @inline implicit def iterableToElement[A, B <: Iterable[A]]( + e: Iterable[A] + )(implicit cv: A => ReactElement): ReactElement = e.map(cv).toJSArray.asInstanceOf[ReactElement] - } - @inline implicit def optionToElement[E](o: Option[E])(implicit cv: E => ReactElement): ReactElement = { + @inline implicit def optionToElement[E](o: Option[E])(implicit cv: E => ReactElement): ReactElement = o match { case Some(e) => cv(e) - case None => null.asInstanceOf[ReactElement] + case None => null.asInstanceOf[ReactElement] } - } @inline implicit def jsUndefOrToElement[E](j: js.UndefOr[E])(implicit cv: E => ReactElement): ReactElement = { val x = if (j.isDefined) cv(j.get) else null.asInstanceOf[ReactElement] @@ -49,9 +44,10 @@ object ReactElement { x } - @inline implicit def anyToElementContainer[E, F[_]](e: F[E])(implicit f: ReactElementContainer[F], cv: E => ReactElement): F[ReactElement] = { + @inline implicit def anyToElementContainer[E, F[_]]( + e: F[E] + )(implicit f: ReactElementContainer[F], cv: E => ReactElement): F[ReactElement] = f.map(e)(cv) - } } @js.native @@ -62,15 +58,17 @@ trait ReactChildren extends ReactElement @js.native trait ReactRef[T] extends js.Object { - var current: T @uncheckedVariance = js.native + var current: T @uncheckedVariance = js.native } @js.native @JSImport("react", JSImport.Namespace, "React") private[slinky] object ReactRaw extends js.Object { - def createElement(elementName: String | js.Object, - properties: js.Dictionary[js.Any], - contents: ReactElement*): ReactElement = js.native + def createElement( + elementName: String | js.Object, + properties: js.Dictionary[js.Any], + contents: ReactElement* + ): ReactElement = js.native val createElement: js.Dynamic = js.native // used for WithAttrs @@ -85,9 +83,10 @@ private[slinky] object ReactRaw extends js.Object { @js.native object Children extends js.Object { def map(children: ReactChildren, transformer: js.Function1[ReactElement, ReactElement]): ReactChildren = js.native - def map(children: ReactChildren, transformer: js.Function2[ReactElement, Int, ReactElement]): ReactChildren = js.native + def map(children: ReactChildren, transformer: js.Function2[ReactElement, Int, ReactElement]): ReactChildren = + js.native - def forEach(children: ReactChildren, transformer: js.Function1[ReactElement, Unit]): Unit = js.native + def forEach(children: ReactChildren, transformer: js.Function1[ReactElement, Unit]): Unit = js.native def forEach(children: ReactChildren, transformer: js.Function2[ReactElement, Int, Unit]): Unit = js.native def only(children: ReactChildren): ReactElement = js.native @@ -97,69 +96,66 @@ private[slinky] object ReactRaw extends js.Object { def toArray(children: ReactChildren): js.Array[ReactElement] = js.native } - val Fragment: js.Object = js.native + val Fragment: js.Object = js.native val StrictMode: js.Object = js.native - val Suspense: js.Object = js.native + val Suspense: js.Object = js.native } object React { - def createElement(elementName: String | js.Object, - properties: js.Dictionary[js.Any], - contents: ReactElement*): ReactElement = ReactRaw.createElement(elementName, properties, contents: _*) + def createElement( + elementName: String | js.Object, + properties: js.Dictionary[js.Any], + contents: ReactElement* + ): ReactElement = ReactRaw.createElement(elementName, properties, contents: _*) def createContext[T](defaultValue: T): ReactContext[T] = ReactRaw.createContext[T](defaultValue) def createRef[T]: ReactRef[T] = ReactRaw.createRef[T]() - def forwardRef[P, R](component: FunctionalComponentTakingRef[P, R]): FunctionalComponentForwardedRef[P, R] = { + def forwardRef[P, R](component: FunctionalComponentTakingRef[P, R]): FunctionalComponentForwardedRef[P, R] = new FunctionalComponentForwardedRef(ReactRaw.forwardRef(component.component)) - } - def memo[P](component: FunctionalComponent[P]): FunctionalComponent[P] = { + def memo[P](component: FunctionalComponent[P]): FunctionalComponent[P] = new FunctionalComponent(ReactRaw.memo(component.component, js.undefined)) - } - def memo[P](component: FunctionalComponent[P], compare: (P, P) => Boolean): FunctionalComponent[P] = { - new FunctionalComponent(ReactRaw.memo(component.component, ((oldProps: js.Dynamic, newProps: js.Dynamic) => { - compare(oldProps.__.asInstanceOf[P], newProps.__.asInstanceOf[P]) - }): js.Function2[js.Dynamic, js.Dynamic, Boolean])) - } + def memo[P](component: FunctionalComponent[P], compare: (P, P) => Boolean): FunctionalComponent[P] = + new FunctionalComponent( + ReactRaw.memo( + component.component, + ((oldProps: js.Dynamic, newProps: js.Dynamic) => { + compare(oldProps.__.asInstanceOf[P], newProps.__.asInstanceOf[P]) + }): js.Function2[js.Dynamic, js.Dynamic, Boolean] + ) + ) @JSImport("react", "Component", "React.Component") @js.native class Component(jsProps: js.Object) extends js.Object { - def forceUpdate(): Unit = js.native + def forceUpdate(): Unit = js.native def forceUpdate(callback: js.Function0[Unit]): Unit = js.native } object Children extends js.Object { - def map(children: ReactChildren, transformer: ReactElement => ReactElement): ReactChildren = { + def map(children: ReactChildren, transformer: ReactElement => ReactElement): ReactChildren = ReactRaw.Children.map(children, transformer) - } - def map(children: ReactChildren, transformer: (ReactElement, Int) => ReactElement): ReactChildren = { + def map(children: ReactChildren, transformer: (ReactElement, Int) => ReactElement): ReactChildren = ReactRaw.Children.map(children, transformer) - } - def forEach(children: ReactChildren, transformer: ReactElement => Unit): Unit = { + def forEach(children: ReactChildren, transformer: ReactElement => Unit): Unit = ReactRaw.Children.forEach(children, transformer) - } - def forEach(children: ReactChildren, transformer: (ReactElement, Int) => Unit): Unit = { + def forEach(children: ReactChildren, transformer: (ReactElement, Int) => Unit): Unit = ReactRaw.Children.forEach(children, transformer) - } - def only(children: ReactChildren): ReactElement = { + def only(children: ReactChildren): ReactElement = ReactRaw.Children.only(children) - } - def count(children: ReactChildren): Int = { + def count(children: ReactChildren): Int = ReactRaw.Children.count(children) - } - def toArray(children: ReactChildren): js.Array[ReactElement] = { + def toArray(children: ReactChildren): js.Array[ReactElement] = ReactRaw.Children.toArray(children) - } } } @@ -167,14 +163,18 @@ object React { @JSImport("react", JSImport.Namespace, "React") private[slinky] object HooksRaw extends js.Object { def useState[T](default: T | js.Function0[T]): js.Tuple2[T, js.Function1[js.Any, Unit]] = js.native - - def useEffect(thunk: js.Function0[EffectCallbackReturn]): Unit = js.native + + def useEffect(thunk: js.Function0[EffectCallbackReturn]): Unit = js.native def useEffect(thunk: js.Function0[EffectCallbackReturn], watchedObjects: js.Array[js.Any]): Unit = js.native - + def useContext[T](context: ReactContext[T]): T = js.native def useReducer[T, A](reducer: js.Function2[T, A, T], initialState: T): js.Tuple2[T, js.Function1[A, Unit]] = js.native - def useReducer[T, I, A](reducer: js.Function2[T, A, T], initialState: I, init: js.Function1[I, T]): js.Tuple2[T, js.Function1[A, Unit]] = js.native + def useReducer[T, I, A]( + reducer: js.Function2[T, A, T], + initialState: I, + init: js.Function1[I, T] + ): js.Tuple2[T, js.Function1[A, Unit]] = js.native def useMemo[T](callback: js.Function0[T], watchedObjects: js.Array[js.Any]): T = js.native @@ -182,7 +182,7 @@ private[slinky] object HooksRaw extends js.Object { def useImperativeHandle[R](ref: ReactRef[R], value: js.Function0[R]): Unit = js.native - def useLayoutEffect(thunk: js.Function0[EffectCallbackReturn]): Unit = js.native + def useLayoutEffect(thunk: js.Function0[EffectCallbackReturn]): Unit = js.native def useLayoutEffect(thunk: js.Function0[EffectCallbackReturn], watchedObjects: js.Array[js.Any]): Unit = js.native def useDebugValue(value: String): Unit = js.native @@ -190,25 +190,22 @@ private[slinky] object HooksRaw extends js.Object { // No useCallback, since its usage from Hooks won't be able to implement the reference equality guarantee while converting js.Function to scala.FunctionN, anyway } -@js.native trait EffectCallbackReturn extends js.Object +@js.native +trait EffectCallbackReturn extends js.Object object EffectCallbackReturn { - @inline implicit def fromFunction[T](fn: () => T): EffectCallbackReturn = { + @inline implicit def fromFunction[T](fn: () => T): EffectCallbackReturn = (fn: js.Function0[T]).asInstanceOf[EffectCallbackReturn] - } - @inline implicit def fromAny[T](value: T): EffectCallbackReturn = { + @inline implicit def fromAny[T](value: T): EffectCallbackReturn = js.undefined.asInstanceOf[EffectCallbackReturn] - } } final class SetStateHookCallback[T](private val origFunction: js.Function1[js.Any, Unit]) extends AnyVal { - @inline def apply(newState: T): Unit = { + @inline def apply(newState: T): Unit = origFunction.apply(newState.asInstanceOf[js.Any]) - } - @inline def apply(transformState: T => T): Unit = { + @inline def apply(transformState: T => T): Unit = origFunction.apply(transformState: js.Function1[T, T]) - } } object SetStateHookCallback { @@ -228,16 +225,16 @@ object Hooks { (call._1, new SetStateHookCallback[T](call._2)) } - @inline def useEffect[T](thunk: () => T)(implicit conv: T => EffectCallbackReturn): Unit = { + @inline def useEffect[T](thunk: () => T)(implicit conv: T => EffectCallbackReturn): Unit = HooksRaw.useEffect(() => { conv(thunk()) }) - } - @inline def useEffect[T](thunk: () => T, watchedObjects: Iterable[Any])(implicit conv: T => EffectCallbackReturn): Unit = { + @inline def useEffect[T](thunk: () => T, watchedObjects: Iterable[Any])( + implicit conv: T => EffectCallbackReturn + ): Unit = HooksRaw.useEffect( - () => { conv(thunk()) }, + () => conv(thunk()), watchedObjects.toJSArray.asInstanceOf[js.Array[js.Any]] ) - } @inline def useContext[T](context: ReactContext[T]): T = HooksRaw.useContext[T](context) @@ -251,34 +248,30 @@ object Hooks { (ret._1, ret._2) } - @inline def useCallback[F](callback: F, watchedObjects: Iterable[Any])(implicit ev: F => js.Function): F = { + @inline def useCallback[F](callback: F, watchedObjects: Iterable[Any])(implicit ev: F => js.Function): F = // Do not implement using React's useCallback. Otherwise, converting the js.Function returned by to scala.FunctionN will // produce a new object and thus violating the reference equality guarantee of useCallback useMemo(() => callback, watchedObjects) - } - @inline def useMemo[T](memoValue: () => T, watchedObjects: Iterable[Any]): T = { + @inline def useMemo[T](memoValue: () => T, watchedObjects: Iterable[Any]): T = HooksRaw.useMemo[T](memoValue, watchedObjects.toJSArray.asInstanceOf[js.Array[js.Any]]) - } - @inline def useRef[T](initialValue: T): ReactRef[T] = { + @inline def useRef[T](initialValue: T): ReactRef[T] = HooksRaw.useRef[T](initialValue) - } - @inline def useImperativeHandle[R](ref: ReactRef[R], value: () => R): Unit = { + @inline def useImperativeHandle[R](ref: ReactRef[R], value: () => R): Unit = HooksRaw.useImperativeHandle[R](ref, value) - } - @inline def useLayoutEffect[T](thunk: () => T)(implicit conv: T => EffectCallbackReturn): Unit = { + @inline def useLayoutEffect[T](thunk: () => T)(implicit conv: T => EffectCallbackReturn): Unit = HooksRaw.useLayoutEffect(() => { conv(thunk()) }) - } - @inline def useLayoutEffect[T](thunk: () => T, watchedObjects: Iterable[Any])(implicit conv: T => EffectCallbackReturn): Unit = { + @inline def useLayoutEffect[T](thunk: () => T, watchedObjects: Iterable[Any])( + implicit conv: T => EffectCallbackReturn + ): Unit = HooksRaw.useLayoutEffect( - () => { conv(thunk()) }, + () => conv(thunk()), watchedObjects.toJSArray.asInstanceOf[js.Array[js.Any]] ) - } @inline def useDebugValue(value: String): Unit = HooksRaw.useDebugValue(value) } diff --git a/core/src/main/scala/slinky/core/facade/ReactContext.scala b/core/src/main/scala/slinky/core/facade/ReactContext.scala index e558c9c5..ae1011d1 100644 --- a/core/src/main/scala/slinky/core/facade/ReactContext.scala +++ b/core/src/main/scala/slinky/core/facade/ReactContext.scala @@ -14,13 +14,16 @@ trait ReactContextRaw extends js.Object { case class ContextProviderProps[T](value: T) object ContextProviderProps { - implicit def writer[T]: Writer[ContextProviderProps[T]] = v => js.Dynamic.literal( - value = v.value.asInstanceOf[js.Any] - ) + implicit def writer[T]: Writer[ContextProviderProps[T]] = + v => + js.Dynamic.literal( + value = v.value.asInstanceOf[js.Any] + ) } class ContextProvider[T](orig: ReactContext[T]) { - private object External extends ExternalComponent()(ContextProviderProps.writer[T].asInstanceOf[ExternalPropsWriterProvider]) { + private object External + extends ExternalComponent()(ContextProviderProps.writer[T].asInstanceOf[ExternalPropsWriterProvider]) { override type Props = ContextProviderProps[T] override val component: |[String, js.Object] = orig.asInstanceOf[ReactContextRaw].Provider } @@ -30,26 +33,33 @@ class ContextProvider[T](orig: ReactContext[T]) { case class ContextConsumerProps[T](children: T => ReactElement) object ContextConsumerProps { - implicit def writer[T]: Writer[ContextConsumerProps[T]] = v => js.Dynamic.literal( - children = Writer.function1[T, ReactElement]( - _.asInstanceOf[T], Writer.jsAnyWriter[ReactElement] - ).write(v.children) - ) + implicit def writer[T]: Writer[ContextConsumerProps[T]] = + v => + js.Dynamic.literal( + children = Writer + .function1[T, ReactElement]( + _.asInstanceOf[T], + Writer.jsAnyWriter[ReactElement] + ) + .write(v.children) + ) } class ContextConsumer[T](orig: ReactContext[T]) { - private object External extends ExternalComponent()(ContextConsumerProps.writer[T].asInstanceOf[ExternalPropsWriterProvider]) { + private object External + extends ExternalComponent()(ContextConsumerProps.writer[T].asInstanceOf[ExternalPropsWriterProvider]) { override type Props = ContextConsumerProps[T] override val component: |[String, js.Object] = orig.asInstanceOf[ReactContextRaw].Consumer } - def apply(children: T => ReactElement): BuildingComponent[Nothing, js.Object] = External(ContextConsumerProps(children)) + def apply(children: T => ReactElement): BuildingComponent[Nothing, js.Object] = + External(ContextConsumerProps(children)) } @js.native trait ReactContext[T] extends js.Object object ReactContext { - final implicit class RichReactContext[T](private val orig: ReactContext[T]) extends AnyVal { + implicit final class RichReactContext[T](private val orig: ReactContext[T]) extends AnyVal { def Provider: ContextProvider[T] = new ContextProvider[T](orig) def Consumer: ContextConsumer[T] = new ContextConsumer[T](orig) } diff --git a/core/src/main/scala/slinky/core/facade/Suspense.scala b/core/src/main/scala/slinky/core/facade/Suspense.scala index 0ebd1aba..6ff50adc 100644 --- a/core/src/main/scala/slinky/core/facade/Suspense.scala +++ b/core/src/main/scala/slinky/core/facade/Suspense.scala @@ -6,11 +6,11 @@ import slinky.core.{BuildingComponent, ExternalComponent, ExternalPropsWriterPro import scala.scalajs.js import scala.scalajs.js.| -object Suspense extends ExternalComponent()(new Writer[Suspense.Props] { - override def write(value: Suspense.Props): js.Object = { - js.Dynamic.literal(fallback = value.fallback) - } -}.asInstanceOf[ExternalPropsWriterProvider]) { +object Suspense + extends ExternalComponent()(new Writer[Suspense.Props] { + override def write(value: Suspense.Props): js.Object = + js.Dynamic.literal(fallback = value.fallback) + }.asInstanceOf[ExternalPropsWriterProvider]) { case class Props(fallback: ReactElement) override val component: |[String, js.Object] = ReactRaw.Suspense diff --git a/docs/build.sbt b/docs/build.sbt index 49636be4..a6937d9d 100644 --- a/docs/build.sbt +++ b/docs/build.sbt @@ -29,4 +29,7 @@ fullOptJS / webpackConfigFile := Some(baseDirectory.value / "webpack-opt.config. fastOptJS / webpackDevServerExtraArgs := Seq("--inline", "--hot") fastOptJS / webpackBundlingMode := BundlingMode.LibraryOnly() -scalacOptions += "-P:scalajs:sjsDefinedByDefault" +scalacOptions ++= { + if (scalaJSVersion.startsWith("0.6.")) Seq("-P:scalajs:sjsDefinedByDefault") + else Nil +} diff --git a/history/build.sbt b/history/build.sbt index 69338e94..e10dbec6 100644 --- a/history/build.sbt +++ b/history/build.sbt @@ -2,6 +2,9 @@ enablePlugins(ScalaJSPlugin) name := "slinky-history" -libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "0.9.7" +libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "0.9.8" -scalacOptions += "-P:scalajs:sjsDefinedByDefault" +scalacOptions ++= { + if (scalaJSVersion.startsWith("0.6.")) Seq("-P:scalajs:sjsDefinedByDefault") + else Nil +} diff --git a/history/src/main/scala/slinky/history/History.scala b/history/src/main/scala/slinky/history/History.scala index b69229cf..1dca829a 100644 --- a/history/src/main/scala/slinky/history/History.scala +++ b/history/src/main/scala/slinky/history/History.scala @@ -7,14 +7,14 @@ import scala.scalajs.js.annotation.JSImport @js.native trait RichHistory extends History { - def action: String = js.native - def block(prompt: Boolean = false): Unit = js.native - def createHref(location: String): Unit = js.native - def goBack(): Unit = js.native - def goForward(): Unit = js.native - def listen(listener: js.Function0[Unit]): Unit = js.native - def location: String = js.native - def push(route: String): Unit = js.native + def action: String = js.native + def block(prompt: Boolean = false): Unit = js.native + def createHref(location: String): Unit = js.native + def goBack(): Unit = js.native + def goForward(): Unit = js.native + def listen(listener: js.Function0[Unit]): Unit = js.native + def location: String = js.native + def push(route: String): Unit = js.native def replace(path: String, state: js.Object): Unit = js.native } diff --git a/hot/src/main/scala/slinky/hot/ReactProxy.scala b/hot/src/main/scala/slinky/hot/ReactProxy.scala index 9a0ddb99..fe17fcb3 100644 --- a/hot/src/main/scala/slinky/hot/ReactProxy.scala +++ b/hot/src/main/scala/slinky/hot/ReactProxy.scala @@ -6,6 +6,6 @@ import scala.scalajs.js.annotation.JSImport @JSImport("react-proxy", JSImport.Namespace, "ReactProxy") @js.native object ReactProxy extends js.Object { - def createProxy(componentConstructor: js.Object): js.Object = js.native + def createProxy(componentConstructor: js.Object): js.Object = js.native def getForceUpdate(react: js.Object): js.Function1[js.Object, Unit] = js.native } diff --git a/hot/src/main/scala/slinky/hot/package.scala b/hot/src/main/scala/slinky/hot/package.scala index 5a4e4568..0f9ab29a 100644 --- a/hot/src/main/scala/slinky/hot/package.scala +++ b/hot/src/main/scala/slinky/hot/package.scala @@ -11,7 +11,7 @@ package object hot { js.Dynamic.global.proxies = js.Dynamic.literal() } - BaseComponentWrapper.insertMiddleware((constructor, component) => { + BaseComponentWrapper.insertMiddleware { (constructor, component) => val componentName = component.asInstanceOf[BaseComponentWrapper].getClass.getName if (js.isUndefined(component.asInstanceOf[js.Dynamic]._hot)) { @@ -21,14 +21,16 @@ package object hot { js.Dynamic.global.proxies.updateDynamic(componentName)(ReactProxy.createProxy(constructor)) } else { val forceUpdate = ReactProxy.getForceUpdate(ReactRaw) - js.Dynamic.global.proxies.selectDynamic(componentName) - .update(constructor).asInstanceOf[js.Array[js.Object]] + js.Dynamic.global.proxies + .selectDynamic(componentName) + .update(constructor) + .asInstanceOf[js.Array[js.Object]] .foreach(o => forceUpdate(o)) } } js.Dynamic.global.proxies.selectDynamic(componentName).get().asInstanceOf[js.Object] - }) + } BaseComponentWrapper.enableScalaComponentWriting() } diff --git a/native/build.sbt b/native/build.sbt index b12f7b19..1a535257 100644 --- a/native/build.sbt +++ b/native/build.sbt @@ -1,27 +1,29 @@ enablePlugins(ScalaJSPlugin) -import org.scalajs.core.tools.io.{MemVirtualJSFile, VirtualJSFile} import org.scalajs.jsenv.nodejs.NodeJSEnv import scala.util.Properties name := "slinky-native" -libraryDependencies += "org.scalatest" %%% "scalatest" % "3.0.8" % Test +libraryDependencies += "org.scalatest" %%% "scalatest" % "3.1.0" % Test -scalacOptions += "-P:scalajs:sjsDefinedByDefault" +scalacOptions ++= { + if (scalaJSVersion.startsWith("0.6.")) Seq("-P:scalajs:sjsDefinedByDefault") + else Nil +} -Test / scalaJSModuleKind := ModuleKind.CommonJSModule +scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.CommonJSModule) } +Test / scalaJSLinkerConfig ~= { _.withESFeatures(_.withUseECMAScript2015(false)) } -Test / jsEnv := new NodeJSEnv() { - override def customInitFiles(): Seq[VirtualJSFile] = super.customInitFiles() :+ new MemVirtualJSFile("addReactNativeMock.js").withContent( - s"""require("${escapeBackslashes((baseDirectory.value / "node_modules/react-native-mock-render/mock.js").getAbsolutePath)}");""" - ) -} +Test / jsEnv := new NodeJSEnv( + NodeJSEnv + .Config() + .withArgs(List("-r", baseDirectory.value.getAbsolutePath + "/node_modules/react-native-mock-render/mock.js")) +) -def escapeBackslashes(path: String): String = { +def escapeBackslashes(path: String): String = if (Properties.isWin) path.replace("\\", "\\\\") else path -} diff --git a/native/src/main/scala/slinky/native/ActivityIndicator.scala b/native/src/main/scala/slinky/native/ActivityIndicator.scala index 4cfbddae..cc20f6eb 100644 --- a/native/src/main/scala/slinky/native/ActivityIndicator.scala +++ b/native/src/main/scala/slinky/native/ActivityIndicator.scala @@ -8,10 +8,12 @@ import scala.scalajs.js.annotation.JSImport import scala.scalajs.js.| @react object ActivityIndicator extends ExternalComponent { - case class Props(animating: js.UndefOr[Boolean] = js.undefined, - color: js.UndefOr[String] = js.undefined, - size: js.UndefOr[String | Int] = js.undefined, - hidesWhenStopped: js.UndefOr[Boolean] = js.undefined) + case class Props( + animating: js.UndefOr[Boolean] = js.undefined, + color: js.UndefOr[String] = js.undefined, + size: js.UndefOr[String | Int] = js.undefined, + hidesWhenStopped: js.UndefOr[Boolean] = js.undefined + ) @js.native @JSImport("react-native", "ActivityIndicator") diff --git a/native/src/main/scala/slinky/native/Alert.scala b/native/src/main/scala/slinky/native/Alert.scala index 6f542e03..930dada5 100644 --- a/native/src/main/scala/slinky/native/Alert.scala +++ b/native/src/main/scala/slinky/native/Alert.scala @@ -11,9 +11,11 @@ case class AlertOptions(cancelable: js.UndefOr[Boolean] = js.undefined) @js.native @JSImport("react-native", "Alert") object Alert extends js.Object { - def alert(title: String, - message: js.UndefOr[String] = js.undefined, - buttons: js.UndefOr[ObjectOrWritten[Seq[AlertButton]]] = js.undefined, - options: js.UndefOr[ObjectOrWritten[AlertOptions]] = js.undefined, - `type`: js.UndefOr[String] = js.undefined): Unit = js.native + def alert( + title: String, + message: js.UndefOr[String] = js.undefined, + buttons: js.UndefOr[ObjectOrWritten[Seq[AlertButton]]] = js.undefined, + options: js.UndefOr[ObjectOrWritten[AlertOptions]] = js.undefined, + `type`: js.UndefOr[String] = js.undefined + ): Unit = js.native } diff --git a/native/src/main/scala/slinky/native/Button.scala b/native/src/main/scala/slinky/native/Button.scala index 1f13bdad..db48e079 100644 --- a/native/src/main/scala/slinky/native/Button.scala +++ b/native/src/main/scala/slinky/native/Button.scala @@ -7,13 +7,15 @@ import scala.scalajs.js import scala.scalajs.js.annotation.JSImport @react object Button extends ExternalComponent { - case class Props(onPress: () => Unit, - title: String, - accessibilityLabel: js.UndefOr[String] = js.undefined, - color: js.UndefOr[String] = js.undefined, - disabled: js.UndefOr[Boolean] = js.undefined, - testID: js.UndefOr[String] = js.undefined, - hasTVPreferredFocus: js.UndefOr[Boolean] = js.undefined) + case class Props( + onPress: () => Unit, + title: String, + accessibilityLabel: js.UndefOr[String] = js.undefined, + color: js.UndefOr[String] = js.undefined, + disabled: js.UndefOr[Boolean] = js.undefined, + testID: js.UndefOr[String] = js.undefined, + hasTVPreferredFocus: js.UndefOr[Boolean] = js.undefined + ) @js.native @JSImport("react-native", "Button") diff --git a/native/src/main/scala/slinky/native/Clipboard.scala b/native/src/main/scala/slinky/native/Clipboard.scala index 5d834c81..22a60610 100644 --- a/native/src/main/scala/slinky/native/Clipboard.scala +++ b/native/src/main/scala/slinky/native/Clipboard.scala @@ -7,11 +7,11 @@ import scala.scalajs.js.annotation.JSImport @js.native @JSImport("react-native", "Clipboard") object RawClipboard extends js.Object { - def getString(): js.Promise[String] = js.native + def getString(): js.Promise[String] = js.native def setString(content: String): Unit = js.native } object Clipboard { - def getString: Future[String] = RawClipboard.getString().toFuture + def getString: Future[String] = RawClipboard.getString().toFuture def setString(content: String): Unit = RawClipboard.setString(content) -} \ No newline at end of file +} diff --git a/native/src/main/scala/slinky/native/FlatList.scala b/native/src/main/scala/slinky/native/FlatList.scala index c3a719b1..44df41e4 100644 --- a/native/src/main/scala/slinky/native/FlatList.scala +++ b/native/src/main/scala/slinky/native/FlatList.scala @@ -14,28 +14,37 @@ case class ItemLayout(length: Int, offset: Int, index: Int) case class OnEndReachedInfo(distanceFromEnd: Int) case class OnEndReachedEvent(info: OnEndReachedInfo) -case class ViewToken[T](item: T, key: String, index: js.UndefOr[Int], isViewable: Boolean, section: js.UndefOr[Section[T]]) +case class ViewToken[T]( + item: T, + key: String, + index: js.UndefOr[Int], + isViewable: Boolean, + section: js.UndefOr[Section[T]] +) case class ViewableItemsChangedInfo[T](viewableItems: Seq[js.Object], changed: Seq[js.Object]) case class ViewableItemsChangedEvent[T](info: ViewableItemsChangedInfo[T]) case class ScrollToEndParams(animated: js.UndefOr[Boolean] = js.undefined) -case class ScrollToIndexParams(index: Int, - viewOffset: Int, - animated: js.UndefOr[Boolean] = js.undefined, - viewPosition: js.UndefOr[Double] = js.undefined) +case class ScrollToIndexParams( + index: Int, + viewOffset: Int, + animated: js.UndefOr[Boolean] = js.undefined, + viewPosition: js.UndefOr[Double] = js.undefined +) -case class ScrollToItemParams[T](item: T, - animated: js.UndefOr[Boolean] = js.undefined, - viewPosition: js.UndefOr[Double] = js.undefined) +case class ScrollToItemParams[T]( + item: T, + animated: js.UndefOr[Boolean] = js.undefined, + viewPosition: js.UndefOr[Double] = js.undefined +) -case class ScrollToOffsetParams(offset: Int, - animated: js.UndefOr[Boolean] = js.undefined) +case class ScrollToOffsetParams(offset: Int, animated: js.UndefOr[Boolean] = js.undefined) case class RenderItemInfo[T](item: T, index: Int, separators: Separators) @js.native trait FlatListInstance[T] extends js.Object { - def scrollToEnd(): Unit = js.native + def scrollToEnd(): Unit = js.native def scrollToEnd(params: ObjectOrWritten[ScrollToEndParams]): Unit = js.native def scrollToIndex(params: ObjectOrWritten[ScrollToIndexParams]): Unit = js.native @@ -50,29 +59,31 @@ trait FlatListInstance[T] extends js.Object { } object FlatList extends ExternalComponentWithRefType[FlatListInstance[Any]] { - case class Props(data: Seq[Object], - renderItem: RenderItemInfo[Object] => ReactElement, - ItemSeparatorComponent: js.UndefOr[ReactComponentClass[_]] = js.undefined, - ListEmptyComponent: js.UndefOr[ReactComponentClass[_] | (() => ReactElement) | ReactElement] = js.undefined, - ListFooterComponent: js.UndefOr[ReactComponentClass[_] | (() => ReactElement) | ReactElement] = js.undefined, - ListHeaderComponent: js.UndefOr[ReactComponentClass[_] | (() => ReactElement) | ReactElement] = js.undefined, - columnWrapperStyle: js.UndefOr[js.Object] = js.undefined, - extraData: js.UndefOr[Object] = js.undefined, - getItemLayout: js.UndefOr[(js.Object, Int) => ItemLayout] = js.undefined, - horizontal: js.UndefOr[Boolean] = js.undefined, - initialNumToRender: js.UndefOr[Int] = js.undefined, - initialScrollIndex: js.UndefOr[Int] = js.undefined, - inverted: js.UndefOr[Boolean] = js.undefined, - keyExtractor: js.UndefOr[(Object, Int) => String] = js.undefined, - numColumns: js.UndefOr[Int] = js.undefined, - onEndReached: js.UndefOr[OnEndReachedEvent => Unit] = js.undefined, - onEndReachedThreshold: js.UndefOr[Double] = js.undefined, - onRefresh: js.UndefOr[() => Unit] = js.undefined, - onViewableItemsChanged: js.UndefOr[ViewableItemsChangedEvent[Object] => Unit] = js.undefined, - progressViewOffset: js.UndefOr[Double] = js.undefined, - legacyImplementation: js.UndefOr[Boolean] = js.undefined, - refreshing: js.UndefOr[Boolean] = js.undefined, - removeClippedSubviews: js.UndefOr[Boolean] = js.undefined) + case class Props( + data: Seq[Object], + renderItem: RenderItemInfo[Object] => ReactElement, + ItemSeparatorComponent: js.UndefOr[ReactComponentClass[_]] = js.undefined, + ListEmptyComponent: js.UndefOr[ReactComponentClass[_] |(() => ReactElement) | ReactElement] = js.undefined, + ListFooterComponent: js.UndefOr[ReactComponentClass[_] |(() => ReactElement) | ReactElement] = js.undefined, + ListHeaderComponent: js.UndefOr[ReactComponentClass[_] |(() => ReactElement) | ReactElement] = js.undefined, + columnWrapperStyle: js.UndefOr[js.Object] = js.undefined, + extraData: js.UndefOr[Object] = js.undefined, + getItemLayout: js.UndefOr[(js.Object, Int) => ItemLayout] = js.undefined, + horizontal: js.UndefOr[Boolean] = js.undefined, + initialNumToRender: js.UndefOr[Int] = js.undefined, + initialScrollIndex: js.UndefOr[Int] = js.undefined, + inverted: js.UndefOr[Boolean] = js.undefined, + keyExtractor: js.UndefOr[(Object, Int) => String] = js.undefined, + numColumns: js.UndefOr[Int] = js.undefined, + onEndReached: js.UndefOr[OnEndReachedEvent => Unit] = js.undefined, + onEndReachedThreshold: js.UndefOr[Double] = js.undefined, + onRefresh: js.UndefOr[() => Unit] = js.undefined, + onViewableItemsChanged: js.UndefOr[ViewableItemsChangedEvent[Object] => Unit] = js.undefined, + progressViewOffset: js.UndefOr[Double] = js.undefined, + legacyImplementation: js.UndefOr[Boolean] = js.undefined, + refreshing: js.UndefOr[Boolean] = js.undefined, + removeClippedSubviews: js.UndefOr[Boolean] = js.undefined + ) @js.native @JSImport("react-native", "FlatList") @@ -82,56 +93,62 @@ object FlatList extends ExternalComponentWithRefType[FlatListInstance[Any]] { private val writer = implicitly[Writer[Props]] - def apply[T](data: Seq[T], - renderItem: RenderItemInfo[T] => ReactElement, - ItemSeparatorComponent: js.UndefOr[ReactComponentClass[_]] = js.undefined, - ListEmptyComponent: js.UndefOr[ReactComponentClass[_] | (() => ReactElement) | ReactElement] = js.undefined, - ListFooterComponent: js.UndefOr[ReactComponentClass[_] | (() => ReactElement) | ReactElement] = js.undefined, - ListHeaderComponent: js.UndefOr[ReactComponentClass[_] | (() => ReactElement) | ReactElement] = js.undefined, - columnWrapperStyle: js.UndefOr[js.Object] = js.undefined, - extraData: js.UndefOr[Any] = js.undefined, - getItemLayout: js.UndefOr[(T, Int) => ItemLayout] = js.undefined, - horizontal: js.UndefOr[Boolean] = js.undefined, - initialNumToRender: js.UndefOr[Int] = js.undefined, - initialScrollIndex: js.UndefOr[Int] = js.undefined, - inverted: js.UndefOr[Boolean] = js.undefined, - keyExtractor: js.UndefOr[(T, Int) => String] = js.undefined, - numColumns: js.UndefOr[Int] = js.undefined, - onEndReached: js.UndefOr[OnEndReachedEvent => Unit] = js.undefined, - onEndReachedThreshold: js.UndefOr[Double] = js.undefined, - onRefresh: js.UndefOr[() => Unit] = js.undefined, - onViewableItemsChanged: js.UndefOr[ViewableItemsChangedEvent[T] => Unit] = js.undefined, - progressViewOffset: js.UndefOr[Double] = js.undefined, - legacyImplementation: js.UndefOr[Boolean] = js.undefined, - refreshing: js.UndefOr[Boolean] = js.undefined, - removeClippedSubviews: js.UndefOr[Boolean] = js.undefined): BuildingComponent[FlatListInstance[T], js.Object] = { - new BuildingComponent(js.Array( - component.asInstanceOf[js.Any], - writer.write(Props( - data = data.asInstanceOf[Seq[Object]], - renderItem = o => renderItem(o.asInstanceOf[RenderItemInfo[T]]), - ItemSeparatorComponent = ItemSeparatorComponent, - ListEmptyComponent = ListEmptyComponent, - ListFooterComponent = ListFooterComponent, - ListHeaderComponent = ListHeaderComponent, - columnWrapperStyle = columnWrapperStyle, - extraData = extraData, - getItemLayout = getItemLayout.map(f => (o, i) => f(o.asInstanceOf[T], i)), - horizontal = horizontal, - initialNumToRender = initialNumToRender, - initialScrollIndex = initialScrollIndex, - inverted = inverted, - keyExtractor = keyExtractor.map(f => (o, i) => f(o.asInstanceOf[T], i)), - numColumns = numColumns, - onEndReached = onEndReached, - onEndReachedThreshold = onEndReachedThreshold, - onRefresh = onRefresh, - onViewableItemsChanged = onViewableItemsChanged.map(f => (e) => f(e.asInstanceOf[ViewableItemsChangedEvent[T]])), - progressViewOffset = progressViewOffset, - legacyImplementation = legacyImplementation, - refreshing = refreshing, - removeClippedSubviews = removeClippedSubviews - )) - )) - } + def apply[T]( + data: Seq[T], + renderItem: RenderItemInfo[T] => ReactElement, + ItemSeparatorComponent: js.UndefOr[ReactComponentClass[_]] = js.undefined, + ListEmptyComponent: js.UndefOr[ReactComponentClass[_] |(() => ReactElement) | ReactElement] = js.undefined, + ListFooterComponent: js.UndefOr[ReactComponentClass[_] |(() => ReactElement) | ReactElement] = js.undefined, + ListHeaderComponent: js.UndefOr[ReactComponentClass[_] |(() => ReactElement) | ReactElement] = js.undefined, + columnWrapperStyle: js.UndefOr[js.Object] = js.undefined, + extraData: js.UndefOr[Any] = js.undefined, + getItemLayout: js.UndefOr[(T, Int) => ItemLayout] = js.undefined, + horizontal: js.UndefOr[Boolean] = js.undefined, + initialNumToRender: js.UndefOr[Int] = js.undefined, + initialScrollIndex: js.UndefOr[Int] = js.undefined, + inverted: js.UndefOr[Boolean] = js.undefined, + keyExtractor: js.UndefOr[(T, Int) => String] = js.undefined, + numColumns: js.UndefOr[Int] = js.undefined, + onEndReached: js.UndefOr[OnEndReachedEvent => Unit] = js.undefined, + onEndReachedThreshold: js.UndefOr[Double] = js.undefined, + onRefresh: js.UndefOr[() => Unit] = js.undefined, + onViewableItemsChanged: js.UndefOr[ViewableItemsChangedEvent[T] => Unit] = js.undefined, + progressViewOffset: js.UndefOr[Double] = js.undefined, + legacyImplementation: js.UndefOr[Boolean] = js.undefined, + refreshing: js.UndefOr[Boolean] = js.undefined, + removeClippedSubviews: js.UndefOr[Boolean] = js.undefined + ): BuildingComponent[FlatListInstance[T], js.Object] = + new BuildingComponent( + js.Array( + component.asInstanceOf[js.Any], + writer.write( + Props( + data = data.asInstanceOf[Seq[Object]], + renderItem = o => renderItem(o.asInstanceOf[RenderItemInfo[T]]), + ItemSeparatorComponent = ItemSeparatorComponent, + ListEmptyComponent = ListEmptyComponent, + ListFooterComponent = ListFooterComponent, + ListHeaderComponent = ListHeaderComponent, + columnWrapperStyle = columnWrapperStyle, + extraData = extraData, + getItemLayout = getItemLayout.map(f => (o, i) => f(o.asInstanceOf[T], i)), + horizontal = horizontal, + initialNumToRender = initialNumToRender, + initialScrollIndex = initialScrollIndex, + inverted = inverted, + keyExtractor = keyExtractor.map(f => (o, i) => f(o.asInstanceOf[T], i)), + numColumns = numColumns, + onEndReached = onEndReached, + onEndReachedThreshold = onEndReachedThreshold, + onRefresh = onRefresh, + onViewableItemsChanged = + onViewableItemsChanged.map(f => (e) => f(e.asInstanceOf[ViewableItemsChangedEvent[T]])), + progressViewOffset = progressViewOffset, + legacyImplementation = legacyImplementation, + refreshing = refreshing, + removeClippedSubviews = removeClippedSubviews + ) + ) + ) + ) } diff --git a/native/src/main/scala/slinky/native/Image.scala b/native/src/main/scala/slinky/native/Image.scala index 0239b4a3..c807c4e6 100644 --- a/native/src/main/scala/slinky/native/Image.scala +++ b/native/src/main/scala/slinky/native/Image.scala @@ -10,15 +10,17 @@ import scala.scalajs.js.annotation.JSImport import scala.scalajs.js.| import scala.scalajs.js.JSConverters._ -case class ImageURISource(uri: js.UndefOr[String] = js.undefined, - bundle: js.UndefOr[String] = js.undefined, - method: js.UndefOr[String] = js.undefined, - headers: js.UndefOr[js.Object] = js.undefined, - body: js.UndefOr[String] = js.undefined, - cache: js.UndefOr[String] = js.undefined, - width: js.UndefOr[Int] = js.undefined, - height: js.UndefOr[Int] = js.undefined, - scale: js.UndefOr[Double] = js.undefined) +case class ImageURISource( + uri: js.UndefOr[String] = js.undefined, + bundle: js.UndefOr[String] = js.undefined, + method: js.UndefOr[String] = js.undefined, + headers: js.UndefOr[js.Object] = js.undefined, + body: js.UndefOr[String] = js.undefined, + cache: js.UndefOr[String] = js.undefined, + width: js.UndefOr[Int] = js.undefined, + height: js.UndefOr[Int] = js.undefined, + scale: js.UndefOr[Double] = js.undefined +) @js.native trait ImageInterface extends js.Object @@ -28,31 +30,37 @@ case class ImageErrorEvent(error: js.Error) case class ImageProgressEvent(loaded: Int, total: Int) @react object Image extends ExternalComponent { - case class Props(style: js.UndefOr[js.Object] = js.undefined, - blurRadius: js.UndefOr[Int] = js.undefined, - onLayout: js.UndefOr[NativeSyntheticEvent[LayoutChangeEvent] => Unit] = js.undefined, - onLoad: js.UndefOr[() => Unit] = js.undefined, - onLoadEnd: js.UndefOr[() => Unit] = js.undefined, - onLoadStart: js.UndefOr[() => Unit] = js.undefined, - resizeMode: js.UndefOr[String] = js.undefined, - source: js.UndefOr[ImageURISource | Int | Seq[ImageURISource]] = js.undefined, - loadingIndicatorSource: js.UndefOr[Seq[ImageURISource | Int]] = js.undefined, - onError: js.UndefOr[NativeSyntheticEvent[ImageErrorEvent] => Unit] = js.undefined, - testID: js.UndefOr[String] = js.undefined, - resizeMethod: js.UndefOr[String] = js.undefined, - accessibilityLabel: js.UndefOr[ReactElement] = js.undefined, - accessible: js.UndefOr[Boolean] = js.undefined, - capInsets: js.UndefOr[BoundingBox] = js.undefined, - defaultSource: js.UndefOr[js.Object | Int] = js.undefined, - onPartialLoad: js.UndefOr[() => Unit] = js.undefined, - onProgress: js.UndefOr[NativeSyntheticEvent[ImageProgressEvent] => Unit] = js.undefined) + case class Props( + style: js.UndefOr[js.Object] = js.undefined, + blurRadius: js.UndefOr[Int] = js.undefined, + onLayout: js.UndefOr[NativeSyntheticEvent[LayoutChangeEvent] => Unit] = js.undefined, + onLoad: js.UndefOr[() => Unit] = js.undefined, + onLoadEnd: js.UndefOr[() => Unit] = js.undefined, + onLoadStart: js.UndefOr[() => Unit] = js.undefined, + resizeMode: js.UndefOr[String] = js.undefined, + source: js.UndefOr[ImageURISource | Int | Seq[ImageURISource]] = js.undefined, + loadingIndicatorSource: js.UndefOr[Seq[ImageURISource | Int]] = js.undefined, + onError: js.UndefOr[NativeSyntheticEvent[ImageErrorEvent] => Unit] = js.undefined, + testID: js.UndefOr[String] = js.undefined, + resizeMethod: js.UndefOr[String] = js.undefined, + accessibilityLabel: js.UndefOr[ReactElement] = js.undefined, + accessible: js.UndefOr[Boolean] = js.undefined, + capInsets: js.UndefOr[BoundingBox] = js.undefined, + defaultSource: js.UndefOr[js.Object | Int] = js.undefined, + onPartialLoad: js.UndefOr[() => Unit] = js.undefined, + onProgress: js.UndefOr[NativeSyntheticEvent[ImageProgressEvent] => Unit] = js.undefined + ) @js.native @JSImport("react-native", "Image") object Component extends js.Object { - def getSize(uri: String, success: js.Function2[Int, Int, Unit], failure: js.UndefOr[js.Function1[js.Error, Unit]]): Unit = js.native - def prefetch(uri: String): Int | Unit = js.native - def abortPrefetch(requestId: Int): Unit = js.native + def getSize( + uri: String, + success: js.Function2[Int, Int, Unit], + failure: js.UndefOr[js.Function1[js.Error, Unit]] + ): Unit = js.native + def prefetch(uri: String): Int | Unit = js.native + def abortPrefetch(requestId: Int): Unit = js.native def queryCache(urls: js.Array[String]): js.Promise[js.Dictionary[String]] = js.native } diff --git a/native/src/main/scala/slinky/native/Picker.scala b/native/src/main/scala/slinky/native/Picker.scala index b9d44135..823c7f91 100644 --- a/native/src/main/scala/slinky/native/Picker.scala +++ b/native/src/main/scala/slinky/native/Picker.scala @@ -8,14 +8,16 @@ import scala.scalajs.js.annotation.JSImport import scala.scalajs.js.| @react object Picker extends ExternalComponent { - case class Props(onValueChange: js.UndefOr[(String | Int, Int) => Unit] = js.undefined, - selectedValue: js.UndefOr[String | Int] = js.undefined, - style: js.UndefOr[js.Object] = js.undefined, - testID: js.UndefOr[String] = js.undefined, - enabled: js.UndefOr[Boolean] = js.undefined, - mode: js.UndefOr[String] = js.undefined, - prompt: js.UndefOr[String] = js.undefined, - itemStyle: js.UndefOr[js.Object] = js.undefined) + case class Props( + onValueChange: js.UndefOr[(String | Int, Int) => Unit] = js.undefined, + selectedValue: js.UndefOr[String | Int] = js.undefined, + style: js.UndefOr[js.Object] = js.undefined, + testID: js.UndefOr[String] = js.undefined, + enabled: js.UndefOr[Boolean] = js.undefined, + mode: js.UndefOr[String] = js.undefined, + prompt: js.UndefOr[String] = js.undefined, + itemStyle: js.UndefOr[js.Object] = js.undefined + ) @js.native @JSImport("react-native", "Picker") diff --git a/native/src/main/scala/slinky/native/ScrollView.scala b/native/src/main/scala/slinky/native/ScrollView.scala index efedbbf4..99c1e915 100644 --- a/native/src/main/scala/slinky/native/ScrollView.scala +++ b/native/src/main/scala/slinky/native/ScrollView.scala @@ -14,55 +14,86 @@ case class ScrollOptions(animated: Boolean) @js.native trait ScrollViewInstance extends js.Object { - def scrollTo(target: ObjectOrWritten[ScrollTarget]): Unit = js.native - def scrollToEnd(): Unit = js.native + def scrollTo(target: ObjectOrWritten[ScrollTarget]): Unit = js.native + def scrollToEnd(): Unit = js.native def scrollToEnd(options: ObjectOrWritten[ScrollOptions]): Unit = js.native - def flashScrollIndicators(): Unit = js.native + def flashScrollIndicators(): Unit = js.native } @react object ScrollView extends ExternalComponentWithRefType[ScrollViewInstance] { - case class Props(alwaysBounceVertical: js.UndefOr[Boolean] = js.undefined, - contentContainerStyle: js.UndefOr[js.Object] = js.undefined, - keyboardDismissMode: js.UndefOr[String] = js.undefined, - keyboardShouldPersistTaps: js.UndefOr[String] = js.undefined, - onContentSizeChange: js.UndefOr[(Int, Int) => Unit] = js.undefined, - onMomentumScrollBegin: js.UndefOr[() => Unit] = js.undefined, - onMomentumScrollEnd: js.UndefOr[() => Unit] = js.undefined, - onScroll: js.UndefOr[() => Unit] = js.undefined, - onScrollBeginDrag: js.UndefOr[() => Unit] = js.undefined, - onScrollEndDrag: js.UndefOr[() => Unit] = js.undefined, - pagingEnabled: js.UndefOr[Boolean] = js.undefined, - refreshControl: js.UndefOr[ReactElement] = js.undefined, - removeClippedSubviews: js.UndefOr[Boolean] = js.undefined, - scrollEnabled: js.UndefOr[Boolean] = js.undefined, - showsHorizontalScrollIndicator: js.UndefOr[Boolean] = js.undefined, - showsVerticalScrollIndicator: js.UndefOr[Boolean] = js.undefined, - stickyHeaderIndices: js.UndefOr[Seq[Int]] = js.undefined, - endFillColor: js.UndefOr[String] = js.undefined, - overScrollMode: js.UndefOr[String] = js.undefined, - scrollPerfTag: js.UndefOr[String] = js.undefined, - alwaysBounceHorizontal: js.UndefOr[Boolean] = js.undefined, - horizontal: js.UndefOr[Boolean] = js.undefined, - automaticallyAdjustContentInsets: js.UndefOr[Boolean] = js.undefined, - bounces: js.UndefOr[Boolean] = js.undefined, - bouncesZoom: js.UndefOr[Boolean] = js.undefined, - canCancelContentTouches: js.UndefOr[Boolean] = js.undefined, - centerContent: js.UndefOr[Boolean] = js.undefined, - contentInset: js.UndefOr[BoundingBox] = js.undefined, - contentInsetAdjustmentBehavior: js.UndefOr[String] = js.undefined, - contentOffset: js.UndefOr[ContentOffset] = js.undefined, - decelerationRate: js.UndefOr[String | Double] = js.undefined, - directionalLockEnabled: js.UndefOr[Boolean] = js.undefined, - indicatorStyle: js.UndefOr[String] = js.undefined, - maximumZoomScale: js.UndefOr[Double] = js.undefined, - minimumZoomScale: js.UndefOr[Double] = js.undefined, - pinchGestureEnabled: js.UndefOr[Boolean] = js.undefined, - scrollEventThrottle: js.UndefOr[Int] = js.undefined, - scrollIndicatorInsets: js.UndefOr[BoundingBox] = js.undefined, - scrollsToTop: js.UndefOr[Boolean] = js.undefined, - snapToAlignment: js.UndefOr[String] = js.undefined, - snapToInterval: js.UndefOr[Double] = js.undefined, - zoomScale: js.UndefOr[Double] = js.undefined) + case class Props( + alwaysBounceVertical: js.UndefOr[Boolean] = js.undefined, + contentContainerStyle: js.UndefOr[js.Object] = js.undefined, + keyboardDismissMode: js.UndefOr[String] = js.undefined, + keyboardShouldPersistTaps: js.UndefOr[String] = js.undefined, + onContentSizeChange: js.UndefOr[(Int, Int) => Unit] = js.undefined, + onMomentumScrollBegin: js.UndefOr[() => Unit] = js.undefined, + onMomentumScrollEnd: js.UndefOr[() => Unit] = js.undefined, + onScroll: js.UndefOr[() => Unit] = js.undefined, + onScrollBeginDrag: js.UndefOr[() => Unit] = js.undefined, + onScrollEndDrag: js.UndefOr[() => Unit] = js.undefined, + pagingEnabled: js.UndefOr[Boolean] = js.undefined, + refreshControl: js.UndefOr[ReactElement] = js.undefined, + scrollEnabled: js.UndefOr[Boolean] = js.undefined, + showsHorizontalScrollIndicator: js.UndefOr[Boolean] = js.undefined, + showsVerticalScrollIndicator: js.UndefOr[Boolean] = js.undefined, + stickyHeaderIndices: js.UndefOr[Seq[Int]] = js.undefined, + endFillColor: js.UndefOr[String] = js.undefined, + overScrollMode: js.UndefOr[String] = js.undefined, + scrollPerfTag: js.UndefOr[String] = js.undefined, + alwaysBounceHorizontal: js.UndefOr[Boolean] = js.undefined, + horizontal: js.UndefOr[Boolean] = js.undefined, + automaticallyAdjustContentInsets: js.UndefOr[Boolean] = js.undefined, + bounces: js.UndefOr[Boolean] = js.undefined, + bouncesZoom: js.UndefOr[Boolean] = js.undefined, + canCancelContentTouches: js.UndefOr[Boolean] = js.undefined, + centerContent: js.UndefOr[Boolean] = js.undefined, + contentInset: js.UndefOr[BoundingBox] = js.undefined, + contentInsetAdjustmentBehavior: js.UndefOr[String] = js.undefined, + contentOffset: js.UndefOr[ContentOffset] = js.undefined, + decelerationRate: js.UndefOr[String | Double] = js.undefined, + directionalLockEnabled: js.UndefOr[Boolean] = js.undefined, + indicatorStyle: js.UndefOr[String] = js.undefined, + maximumZoomScale: js.UndefOr[Double] = js.undefined, + minimumZoomScale: js.UndefOr[Double] = js.undefined, + pinchGestureEnabled: js.UndefOr[Boolean] = js.undefined, + scrollEventThrottle: js.UndefOr[Int] = js.undefined, + scrollIndicatorInsets: js.UndefOr[BoundingBox] = js.undefined, + scrollsToTop: js.UndefOr[Boolean] = js.undefined, + snapToAlignment: js.UndefOr[String] = js.undefined, + snapToInterval: js.UndefOr[Double] = js.undefined, + zoomScale: js.UndefOr[Double] = js.undefined, + // start of props inherited from View + onStartShouldSetResponder: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Unit] = js.undefined, + accessibilityLabel: js.UndefOr[ReactElement] = js.undefined, + hitSlop: js.UndefOr[BoundingBox] = js.undefined, + nativeID: js.UndefOr[String] = js.undefined, + onLayout: js.UndefOr[NativeSyntheticEvent[LayoutChangeEvent] => Unit] = js.undefined, + onMagicTap: js.UndefOr[() => Unit] = js.undefined, + onMoveShouldSetResponder: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Boolean] = js.undefined, + onMoveShouldSetResponderCapture: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Boolean] = js.undefined, + onResponderGrant: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Unit] = js.undefined, + onResponderMove: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Unit] = js.undefined, + onResponderReject: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Unit] = js.undefined, + onResponderRelease: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Unit] = js.undefined, + onResponderTerminate: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Unit] = js.undefined, + onResponderTerminationRequest: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Boolean] = js.undefined, + accessible: js.UndefOr[Boolean] = js.undefined, + onStartShouldSetResponderCapture: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Boolean] = js.undefined, + pointerEvents: js.UndefOr[String] = js.undefined, + removeClippedSubviews: js.UndefOr[Boolean] = js.undefined, + style: js.UndefOr[js.Object] = js.undefined, + testID: js.UndefOr[String] = js.undefined, + accessibilityComponentType: js.UndefOr[String] = js.undefined, + accessibilityLiveRegion: js.UndefOr[String] = js.undefined, + collapsable: js.UndefOr[Boolean] = js.undefined, + importantForAccessibility: js.UndefOr[String] = js.undefined, + needsOffscreenAlphaCompositing: js.UndefOr[Boolean] = js.undefined, + renderToHardwareTextureAndroid: js.UndefOr[Boolean] = js.undefined, + accessibilityTraits: js.UndefOr[String | Seq[String]] = js.undefined, + accessibilityViewIsModal: js.UndefOr[Boolean] = js.undefined, + shouldRasterizeIOS: js.UndefOr[Boolean] = js.undefined + ) @js.native @JSImport("react-native", "ScrollView") diff --git a/native/src/main/scala/slinky/native/SectionList.scala b/native/src/main/scala/slinky/native/SectionList.scala index 88845ff8..4bc80371 100644 --- a/native/src/main/scala/slinky/native/SectionList.scala +++ b/native/src/main/scala/slinky/native/SectionList.scala @@ -10,18 +10,20 @@ import scala.scalajs.js.| case class SectionRenderItemInfo[T](item: T, index: Int, section: Section[T], separators: Separators) -case class Section[T](data: Seq[T], - key: js.UndefOr[String] = js.undefined, - renderItem: js.UndefOr[SectionRenderItemInfo[T] => ReactElement] = js.undefined, - ItemSeparatorComponent: js.UndefOr[ReactComponentClass[_]] = js.undefined, - keyExtractor: js.UndefOr[(T, Int) => String] = js.undefined, - extraData: js.Any = js.undefined) +case class Section[T]( + data: Seq[T], + key: js.UndefOr[String] = js.undefined, + renderItem: js.UndefOr[SectionRenderItemInfo[T] => ReactElement] = js.undefined, + ItemSeparatorComponent: js.UndefOr[ReactComponentClass[_]] = js.undefined, + keyExtractor: js.UndefOr[(T, Int) => String] = js.undefined, + extraData: js.Any = js.undefined +) case class RenderSectionInfo[T](section: Section[T]) @js.native trait SectionListInstance[T] extends js.Object { - def scrollToEnd(): Unit = js.native + def scrollToEnd(): Unit = js.native def scrollToEnd(params: ObjectOrWritten[ScrollToEndParams]): Unit = js.native def scrollToIndex(params: ObjectOrWritten[ScrollToIndexParams]): Unit = js.native @@ -36,28 +38,30 @@ trait SectionListInstance[T] extends js.Object { } object SectionList extends ExternalComponentWithRefType[SectionListInstance[js.Any]] { - case class Props(sections: Seq[Section[js.Any]], - initialNumToRender: js.UndefOr[Int] = js.undefined, - keyExtractor: js.UndefOr[(js.Any, Int) => String] = js.undefined, - renderItem: js.UndefOr[SectionRenderItemInfo[js.Any] => ReactElement] = js.undefined, - onEndReached: js.UndefOr[OnEndReachedEvent => Unit] = js.undefined, - extraData: js.Any = js.undefined, - ItemSeparatorComponent: js.UndefOr[ReactComponentClass[_]] = js.undefined, - inverted: js.UndefOr[Boolean] = js.undefined, - ListFooterComponent: js.UndefOr[ReactComponentClass[_] | (() => ReactElement) | ReactElement] = js.undefined, - legacyImplementation: js.UndefOr[Boolean] = js.undefined, - ListEmptyComponent: js.UndefOr[ReactComponentClass[_] | (() => ReactElement) | ReactElement] = js.undefined, - onEndReachedThreshold: js.UndefOr[Double] = js.undefined, - onRefresh: js.UndefOr[() => Unit] = js.undefined, - onViewableItemsChanged: js.UndefOr[ViewableItemsChangedEvent[js.Any] => Unit] = js.undefined, - refreshing: js.UndefOr[Boolean] = js.undefined, - removeClippedSubviews: js.UndefOr[Boolean] = js.undefined, - ListHeaderComponent: js.UndefOr[ReactComponentClass[_] | (() => ReactElement) | ReactElement] = js.undefined, - renderSectionFooter: js.UndefOr[RenderSectionInfo[js.Any] => ReactElement] = js.undefined, - renderSectionHeader: js.UndefOr[RenderSectionInfo[js.Any] => ReactElement] = js.undefined, - SectionSeparatorComponent: js.UndefOr[ReactComponentClass[_]] = js.undefined, - stickySectionHeadersEnabled: js.UndefOr[Boolean] = js.undefined, - getItemLayout: js.UndefOr[(js.Any, Int) => ItemLayout] = js.undefined) + case class Props( + sections: Seq[Section[js.Any]], + initialNumToRender: js.UndefOr[Int] = js.undefined, + keyExtractor: js.UndefOr[(js.Any, Int) => String] = js.undefined, + renderItem: js.UndefOr[SectionRenderItemInfo[js.Any] => ReactElement] = js.undefined, + onEndReached: js.UndefOr[OnEndReachedEvent => Unit] = js.undefined, + extraData: js.Any = js.undefined, + ItemSeparatorComponent: js.UndefOr[ReactComponentClass[_]] = js.undefined, + inverted: js.UndefOr[Boolean] = js.undefined, + ListFooterComponent: js.UndefOr[ReactComponentClass[_] |(() => ReactElement) | ReactElement] = js.undefined, + legacyImplementation: js.UndefOr[Boolean] = js.undefined, + ListEmptyComponent: js.UndefOr[ReactComponentClass[_] |(() => ReactElement) | ReactElement] = js.undefined, + onEndReachedThreshold: js.UndefOr[Double] = js.undefined, + onRefresh: js.UndefOr[() => Unit] = js.undefined, + onViewableItemsChanged: js.UndefOr[ViewableItemsChangedEvent[js.Any] => Unit] = js.undefined, + refreshing: js.UndefOr[Boolean] = js.undefined, + removeClippedSubviews: js.UndefOr[Boolean] = js.undefined, + ListHeaderComponent: js.UndefOr[ReactComponentClass[_] |(() => ReactElement) | ReactElement] = js.undefined, + renderSectionFooter: js.UndefOr[RenderSectionInfo[js.Any] => ReactElement] = js.undefined, + renderSectionHeader: js.UndefOr[RenderSectionInfo[js.Any] => ReactElement] = js.undefined, + SectionSeparatorComponent: js.UndefOr[ReactComponentClass[_]] = js.undefined, + stickySectionHeadersEnabled: js.UndefOr[Boolean] = js.undefined, + getItemLayout: js.UndefOr[(js.Any, Int) => ItemLayout] = js.undefined + ) @js.native @JSImport("react-native", "SectionList") @@ -65,51 +69,55 @@ object SectionList extends ExternalComponentWithRefType[SectionListInstance[js.A override val component = Component - def apply[T](sections: Seq[Section[T]], - initialNumToRender: js.UndefOr[Int] = js.undefined, - keyExtractor: js.UndefOr[(T, Int) => String] = js.undefined, - renderItem: js.UndefOr[SectionRenderItemInfo[T] => ReactElement] = js.undefined, - onEndReached: js.UndefOr[OnEndReachedEvent => Unit] = js.undefined, - extraData: js.Any = js.undefined, - ItemSeparatorComponent: js.UndefOr[ReactComponentClass[_]] = js.undefined, - inverted: js.UndefOr[Boolean] = js.undefined, - ListFooterComponent: js.UndefOr[ReactComponentClass[_] | (() => ReactElement) | ReactElement] = js.undefined, - legacyImplementation: js.UndefOr[Boolean] = js.undefined, - ListEmptyComponent: js.UndefOr[ReactComponentClass[_] | (() => ReactElement) | ReactElement] = js.undefined, - onEndReachedThreshold: js.UndefOr[Double] = js.undefined, - onRefresh: js.UndefOr[() => Unit] = js.undefined, - onViewableItemsChanged: js.UndefOr[ViewableItemsChangedEvent[T] => Unit] = js.undefined, - refreshing: js.UndefOr[Boolean] = js.undefined, - removeClippedSubviews: js.UndefOr[Boolean] = js.undefined, - ListHeaderComponent: js.UndefOr[ReactComponentClass[_] | (() => ReactElement) | ReactElement] = js.undefined, - renderSectionFooter: js.UndefOr[RenderSectionInfo[T] => ReactElement] = js.undefined, - renderSectionHeader: js.UndefOr[RenderSectionInfo[T] => ReactElement] = js.undefined, - SectionSeparatorComponent: js.UndefOr[ReactComponentClass[_]] = js.undefined, - stickySectionHeadersEnabled: js.UndefOr[Boolean] = js.undefined, - getItemLayout: js.UndefOr[(T, Int) => ItemLayout] = js.undefined): BuildingComponent[Nothing, SectionListInstance[T]] = { - apply(Props( - sections = sections.asInstanceOf[Seq[Section[js.Any]]], - initialNumToRender = initialNumToRender, - keyExtractor = keyExtractor.map(f => (a, i) => f(a.asInstanceOf[T], i)), - renderItem = renderItem.map(f => o => f(o.asInstanceOf[SectionRenderItemInfo[T]])), - onEndReached = onEndReached, - extraData = extraData, - ItemSeparatorComponent = ItemSeparatorComponent, - inverted = inverted, - ListFooterComponent = ListFooterComponent, - legacyImplementation = legacyImplementation, - ListEmptyComponent = ListEmptyComponent, - onEndReachedThreshold = onEndReachedThreshold, - onRefresh = onRefresh, - onViewableItemsChanged = onViewableItemsChanged.asInstanceOf[js.UndefOr[ViewableItemsChangedEvent[js.Any] => Unit]], - refreshing = refreshing, - removeClippedSubviews = removeClippedSubviews, - ListHeaderComponent = ListHeaderComponent, - renderSectionFooter = renderSectionFooter.asInstanceOf[js.UndefOr[RenderSectionInfo[js.Any] => ReactElement]], - renderSectionHeader = renderSectionHeader.asInstanceOf[js.UndefOr[RenderSectionInfo[js.Any] => ReactElement]], - SectionSeparatorComponent = SectionSeparatorComponent, - stickySectionHeadersEnabled = stickySectionHeadersEnabled, - getItemLayout = getItemLayout.map(f => (v, i) => f(v.asInstanceOf[T], i)) - )).asInstanceOf[BuildingComponent[Nothing, SectionListInstance[T]]] - } + def apply[T]( + sections: Seq[Section[T]], + initialNumToRender: js.UndefOr[Int] = js.undefined, + keyExtractor: js.UndefOr[(T, Int) => String] = js.undefined, + renderItem: js.UndefOr[SectionRenderItemInfo[T] => ReactElement] = js.undefined, + onEndReached: js.UndefOr[OnEndReachedEvent => Unit] = js.undefined, + extraData: js.Any = js.undefined, + ItemSeparatorComponent: js.UndefOr[ReactComponentClass[_]] = js.undefined, + inverted: js.UndefOr[Boolean] = js.undefined, + ListFooterComponent: js.UndefOr[ReactComponentClass[_] |(() => ReactElement) | ReactElement] = js.undefined, + legacyImplementation: js.UndefOr[Boolean] = js.undefined, + ListEmptyComponent: js.UndefOr[ReactComponentClass[_] |(() => ReactElement) | ReactElement] = js.undefined, + onEndReachedThreshold: js.UndefOr[Double] = js.undefined, + onRefresh: js.UndefOr[() => Unit] = js.undefined, + onViewableItemsChanged: js.UndefOr[ViewableItemsChangedEvent[T] => Unit] = js.undefined, + refreshing: js.UndefOr[Boolean] = js.undefined, + removeClippedSubviews: js.UndefOr[Boolean] = js.undefined, + ListHeaderComponent: js.UndefOr[ReactComponentClass[_] |(() => ReactElement) | ReactElement] = js.undefined, + renderSectionFooter: js.UndefOr[RenderSectionInfo[T] => ReactElement] = js.undefined, + renderSectionHeader: js.UndefOr[RenderSectionInfo[T] => ReactElement] = js.undefined, + SectionSeparatorComponent: js.UndefOr[ReactComponentClass[_]] = js.undefined, + stickySectionHeadersEnabled: js.UndefOr[Boolean] = js.undefined, + getItemLayout: js.UndefOr[(T, Int) => ItemLayout] = js.undefined + ): BuildingComponent[Nothing, SectionListInstance[T]] = + apply( + Props( + sections = sections.asInstanceOf[Seq[Section[js.Any]]], + initialNumToRender = initialNumToRender, + keyExtractor = keyExtractor.map(f => (a, i) => f(a.asInstanceOf[T], i)), + renderItem = renderItem.map(f => o => f(o.asInstanceOf[SectionRenderItemInfo[T]])), + onEndReached = onEndReached, + extraData = extraData, + ItemSeparatorComponent = ItemSeparatorComponent, + inverted = inverted, + ListFooterComponent = ListFooterComponent, + legacyImplementation = legacyImplementation, + ListEmptyComponent = ListEmptyComponent, + onEndReachedThreshold = onEndReachedThreshold, + onRefresh = onRefresh, + onViewableItemsChanged = + onViewableItemsChanged.asInstanceOf[js.UndefOr[ViewableItemsChangedEvent[js.Any] => Unit]], + refreshing = refreshing, + removeClippedSubviews = removeClippedSubviews, + ListHeaderComponent = ListHeaderComponent, + renderSectionFooter = renderSectionFooter.asInstanceOf[js.UndefOr[RenderSectionInfo[js.Any] => ReactElement]], + renderSectionHeader = renderSectionHeader.asInstanceOf[js.UndefOr[RenderSectionInfo[js.Any] => ReactElement]], + SectionSeparatorComponent = SectionSeparatorComponent, + stickySectionHeadersEnabled = stickySectionHeadersEnabled, + getItemLayout = getItemLayout.map(f => (v, i) => f(v.asInstanceOf[T], i)) + ) + ).asInstanceOf[BuildingComponent[Nothing, SectionListInstance[T]]] } diff --git a/native/src/main/scala/slinky/native/Slider.scala b/native/src/main/scala/slinky/native/Slider.scala index 9ed937f0..ba5f1417 100644 --- a/native/src/main/scala/slinky/native/Slider.scala +++ b/native/src/main/scala/slinky/native/Slider.scala @@ -8,22 +8,24 @@ import scala.scalajs.js.annotation.JSImport import scala.scalajs.js.| @react object Slider extends ExternalComponent { - case class Props(style: js.UndefOr[js.Object] = js.undefined, - disabled: js.UndefOr[Boolean] = js.undefined, - maximumValue: js.UndefOr[Double] = js.undefined, - minimumTrackTintColor: js.UndefOr[String] = js.undefined, - minimumValue: js.UndefOr[Double] = js.undefined, - onSlidingComplete: js.UndefOr[Double => Unit] = js.undefined, - onValueChange: js.UndefOr[Double => Unit] = js.undefined, - step: js.UndefOr[Double] = js.undefined, - maximumTrackTintColor: js.UndefOr[String] = js.undefined, - testID: js.UndefOr[String] = js.undefined, - value: js.UndefOr[Double] = js.undefined, - thumbTintColor: js.UndefOr[String] = js.undefined, - maximumTrackImage: js.UndefOr[ImageURISource | Int | Seq[ImageURISource]] = js.undefined, - minimumTrackImage: js.UndefOr[ImageURISource | Int | Seq[ImageURISource]] = js.undefined, - thumbImage: js.UndefOr[ImageURISource | Int | Seq[ImageURISource]] = js.undefined, - trackImage: js.UndefOr[ImageURISource | Int | Seq[ImageURISource]] = js.undefined) + case class Props( + style: js.UndefOr[js.Object] = js.undefined, + disabled: js.UndefOr[Boolean] = js.undefined, + maximumValue: js.UndefOr[Double] = js.undefined, + minimumTrackTintColor: js.UndefOr[String] = js.undefined, + minimumValue: js.UndefOr[Double] = js.undefined, + onSlidingComplete: js.UndefOr[Double => Unit] = js.undefined, + onValueChange: js.UndefOr[Double => Unit] = js.undefined, + step: js.UndefOr[Double] = js.undefined, + maximumTrackTintColor: js.UndefOr[String] = js.undefined, + testID: js.UndefOr[String] = js.undefined, + value: js.UndefOr[Double] = js.undefined, + thumbTintColor: js.UndefOr[String] = js.undefined, + maximumTrackImage: js.UndefOr[ImageURISource | Int | Seq[ImageURISource]] = js.undefined, + minimumTrackImage: js.UndefOr[ImageURISource | Int | Seq[ImageURISource]] = js.undefined, + thumbImage: js.UndefOr[ImageURISource | Int | Seq[ImageURISource]] = js.undefined, + trackImage: js.UndefOr[ImageURISource | Int | Seq[ImageURISource]] = js.undefined + ) @js.native @JSImport("react-native", "Slider") diff --git a/native/src/main/scala/slinky/native/Switch.scala b/native/src/main/scala/slinky/native/Switch.scala index 5edf5f76..3401ca87 100644 --- a/native/src/main/scala/slinky/native/Switch.scala +++ b/native/src/main/scala/slinky/native/Switch.scala @@ -7,13 +7,15 @@ import scala.scalajs.js import scala.scalajs.js.annotation.JSImport @react object Switch extends ExternalComponent { - case class Props(disabled: js.UndefOr[Boolean] = js.undefined, - onTintColor: js.UndefOr[String] = js.undefined, - onValueChange: js.UndefOr[Boolean => Unit] = js.undefined, - testID: js.UndefOr[String] = js.undefined, - thumbTintColor: js.UndefOr[String] = js.undefined, - tintColor: js.UndefOr[String] = js.undefined, - value: js.UndefOr[Boolean] = js.undefined) + case class Props( + disabled: js.UndefOr[Boolean] = js.undefined, + onTintColor: js.UndefOr[String] = js.undefined, + onValueChange: js.UndefOr[Boolean => Unit] = js.undefined, + testID: js.UndefOr[String] = js.undefined, + thumbTintColor: js.UndefOr[String] = js.undefined, + tintColor: js.UndefOr[String] = js.undefined, + value: js.UndefOr[Boolean] = js.undefined + ) @js.native @JSImport("react-native", "Switch") diff --git a/native/src/main/scala/slinky/native/Text.scala b/native/src/main/scala/slinky/native/Text.scala index e3477ff1..d3c19202 100644 --- a/native/src/main/scala/slinky/native/Text.scala +++ b/native/src/main/scala/slinky/native/Text.scala @@ -9,24 +9,26 @@ import scala.scalajs.js.annotation.JSImport case class BoundingBox(top: Double, left: Double, bottom: Double, right: Double) @react object Text extends ExternalComponent { - case class Props(selectable: js.UndefOr[Boolean] = js.undefined, - accessible: js.UndefOr[Boolean] = js.undefined, - ellipsizeMode: js.UndefOr[String] = js.undefined, - nativeID: js.UndefOr[String] = js.undefined, - numberOfLines: js.UndefOr[Int] = js.undefined, - onLayout: js.UndefOr[NativeSyntheticEvent[LayoutChangeEvent] => Unit] = js.undefined, - onLongPress: js.UndefOr[() => Unit] = js.undefined, - onPress: js.UndefOr[() => Unit] = js.undefined, - pressRetentionOffset: js.UndefOr[BoundingBox] = js.undefined, - allowFontScaling: js.UndefOr[Boolean] = js.undefined, - style: js.UndefOr[js.Object] = js.undefined, - testID: js.UndefOr[String] = js.undefined, - disabled: js.UndefOr[Boolean] = js.undefined, - selectionColor: js.UndefOr[String] = js.undefined, - textBreakStrategy: js.UndefOr[String] = js.undefined, - adjustsFontSizeToFit: js.UndefOr[Boolean] = js.undefined, - minimumFontScale: js.UndefOr[Double] = js.undefined, - suppressHighlighting: js.UndefOr[Boolean] = js.undefined) + case class Props( + selectable: js.UndefOr[Boolean] = js.undefined, + accessible: js.UndefOr[Boolean] = js.undefined, + ellipsizeMode: js.UndefOr[String] = js.undefined, + nativeID: js.UndefOr[String] = js.undefined, + numberOfLines: js.UndefOr[Int] = js.undefined, + onLayout: js.UndefOr[NativeSyntheticEvent[LayoutChangeEvent] => Unit] = js.undefined, + onLongPress: js.UndefOr[() => Unit] = js.undefined, + onPress: js.UndefOr[() => Unit] = js.undefined, + pressRetentionOffset: js.UndefOr[BoundingBox] = js.undefined, + allowFontScaling: js.UndefOr[Boolean] = js.undefined, + style: js.UndefOr[js.Object] = js.undefined, + testID: js.UndefOr[String] = js.undefined, + disabled: js.UndefOr[Boolean] = js.undefined, + selectionColor: js.UndefOr[String] = js.undefined, + textBreakStrategy: js.UndefOr[String] = js.undefined, + adjustsFontSizeToFit: js.UndefOr[Boolean] = js.undefined, + minimumFontScale: js.UndefOr[Double] = js.undefined, + suppressHighlighting: js.UndefOr[Boolean] = js.undefined + ) @js.native @JSImport("react-native", "Text") diff --git a/native/src/main/scala/slinky/native/TextInput.scala b/native/src/main/scala/slinky/native/TextInput.scala index cdde11f3..3c604e30 100644 --- a/native/src/main/scala/slinky/native/TextInput.scala +++ b/native/src/main/scala/slinky/native/TextInput.scala @@ -17,57 +17,59 @@ case class KeyPressEvent(key: String) @js.native trait TextInputInstance extends js.Object { def isFocused(): Boolean = js.native - def clear(): Unit = js.native + def clear(): Unit = js.native } @react object TextInput extends ExternalComponentWithRefType[TextInputInstance] { - case class Props(placeholderTextColor: js.UndefOr[String] = js.undefined, - allowFontScaling: js.UndefOr[Boolean] = js.undefined, - autoCorrect: js.UndefOr[Boolean] = js.undefined, - autoFocus: js.UndefOr[Boolean] = js.undefined, - blurOnSubmit: js.UndefOr[Boolean] = js.undefined, - caretHidden: js.UndefOr[Boolean] = js.undefined, - contextMenuHidden: js.UndefOr[Boolean] = js.undefined, - defaultValue: js.UndefOr[String] = js.undefined, - editable: js.UndefOr[Boolean] = js.undefined, - keyboardType: js.UndefOr[String] = js.undefined, - maxHeight: js.UndefOr[Int] = js.undefined, - maxLength: js.UndefOr[Int] = js.undefined, - multiline: js.UndefOr[Boolean] = js.undefined, - onBlur: js.UndefOr[() => Unit] = js.undefined, - onChange: js.UndefOr[() => Unit] = js.undefined, - onChangeText: js.UndefOr[String => Unit] = js.undefined, - onContextSizeChange: js.UndefOr[NativeSyntheticEvent[ContentSizeEvent] => Unit] = js.undefined, - onEndEditing: js.UndefOr[() => Unit] = js.undefined, - onFocus: js.UndefOr[() => Unit] = js.undefined, - onLayout: js.UndefOr[NativeSyntheticEvent[LayoutChangeEvent] => Unit] = js.undefined, - onScroll: js.UndefOr[NativeSyntheticEvent[ContentOffsetEvent] => Unit] = js.undefined, - onSelectionChange: js.UndefOr[NativeSyntheticEvent[SelectionEvent] => Unit] = js.undefined, - onSubmitEditing: js.UndefOr[() => Unit] = js.undefined, - placeholder: js.UndefOr[String] = js.undefined, - autoCapitalize: js.UndefOr[String] = js.undefined, - returnKeyType: js.UndefOr[String] = js.undefined, - secureTextEntry: js.UndefOr[Boolean] = js.undefined, - selectTextOnFocus: js.UndefOr[Boolean] = js.undefined, - selection: js.UndefOr[Selection] = js.undefined, - selectionColor: js.UndefOr[String] = js.undefined, - style: js.UndefOr[js.Object] = js.undefined, - value: js.UndefOr[String] = js.undefined, - disableFullscreenUI: js.UndefOr[Boolean] = js.undefined, - inlineImageLeft: js.UndefOr[String] = js.undefined, - inlineImagePadding: js.UndefOr[Int] = js.undefined, - numberOfLines: js.UndefOr[Int] = js.undefined, - returnKeyLabel: js.UndefOr[String] = js.undefined, - textBreakStrategy: js.UndefOr[String] = js.undefined, - underlineColorAndroid: js.UndefOr[String] = js.undefined, - clearButtonMode: js.UndefOr[String] = js.undefined, - clearTextOnFocus: js.UndefOr[Boolean] = js.undefined, - dataDetectorTypes: js.UndefOr[String] = js.undefined, - enablesReturnKeyAutomatically: js.UndefOr[Boolean] = js.undefined, - keyboardAppearance: js.UndefOr[String] = js.undefined, - onKeyPress: js.UndefOr[NativeSyntheticEvent[KeyPressEvent] => Unit] = js.undefined, - selectionState: js.UndefOr[js.Object] = js.undefined, - spellCheck: js.UndefOr[Boolean] = js.undefined) + case class Props( + placeholderTextColor: js.UndefOr[String] = js.undefined, + allowFontScaling: js.UndefOr[Boolean] = js.undefined, + autoCorrect: js.UndefOr[Boolean] = js.undefined, + autoFocus: js.UndefOr[Boolean] = js.undefined, + blurOnSubmit: js.UndefOr[Boolean] = js.undefined, + caretHidden: js.UndefOr[Boolean] = js.undefined, + contextMenuHidden: js.UndefOr[Boolean] = js.undefined, + defaultValue: js.UndefOr[String] = js.undefined, + editable: js.UndefOr[Boolean] = js.undefined, + keyboardType: js.UndefOr[String] = js.undefined, + maxHeight: js.UndefOr[Int] = js.undefined, + maxLength: js.UndefOr[Int] = js.undefined, + multiline: js.UndefOr[Boolean] = js.undefined, + onBlur: js.UndefOr[() => Unit] = js.undefined, + onChange: js.UndefOr[() => Unit] = js.undefined, + onChangeText: js.UndefOr[String => Unit] = js.undefined, + onContextSizeChange: js.UndefOr[NativeSyntheticEvent[ContentSizeEvent] => Unit] = js.undefined, + onEndEditing: js.UndefOr[() => Unit] = js.undefined, + onFocus: js.UndefOr[() => Unit] = js.undefined, + onLayout: js.UndefOr[NativeSyntheticEvent[LayoutChangeEvent] => Unit] = js.undefined, + onScroll: js.UndefOr[NativeSyntheticEvent[ContentOffsetEvent] => Unit] = js.undefined, + onSelectionChange: js.UndefOr[NativeSyntheticEvent[SelectionEvent] => Unit] = js.undefined, + onSubmitEditing: js.UndefOr[() => Unit] = js.undefined, + placeholder: js.UndefOr[String] = js.undefined, + autoCapitalize: js.UndefOr[String] = js.undefined, + returnKeyType: js.UndefOr[String] = js.undefined, + secureTextEntry: js.UndefOr[Boolean] = js.undefined, + selectTextOnFocus: js.UndefOr[Boolean] = js.undefined, + selection: js.UndefOr[Selection] = js.undefined, + selectionColor: js.UndefOr[String] = js.undefined, + style: js.UndefOr[js.Object] = js.undefined, + value: js.UndefOr[String] = js.undefined, + disableFullscreenUI: js.UndefOr[Boolean] = js.undefined, + inlineImageLeft: js.UndefOr[String] = js.undefined, + inlineImagePadding: js.UndefOr[Int] = js.undefined, + numberOfLines: js.UndefOr[Int] = js.undefined, + returnKeyLabel: js.UndefOr[String] = js.undefined, + textBreakStrategy: js.UndefOr[String] = js.undefined, + underlineColorAndroid: js.UndefOr[String] = js.undefined, + clearButtonMode: js.UndefOr[String] = js.undefined, + clearTextOnFocus: js.UndefOr[Boolean] = js.undefined, + dataDetectorTypes: js.UndefOr[String] = js.undefined, + enablesReturnKeyAutomatically: js.UndefOr[Boolean] = js.undefined, + keyboardAppearance: js.UndefOr[String] = js.undefined, + onKeyPress: js.UndefOr[NativeSyntheticEvent[KeyPressEvent] => Unit] = js.undefined, + selectionState: js.UndefOr[js.Object] = js.undefined, + spellCheck: js.UndefOr[Boolean] = js.undefined + ) @js.native @JSImport("react-native", "TextInput") diff --git a/native/src/main/scala/slinky/native/TouchableHighlight.scala b/native/src/main/scala/slinky/native/TouchableHighlight.scala index 63d9c520..0e6a5165 100644 --- a/native/src/main/scala/slinky/native/TouchableHighlight.scala +++ b/native/src/main/scala/slinky/native/TouchableHighlight.scala @@ -7,12 +7,11 @@ import scala.scalajs.js import scala.scalajs.js.annotation.JSImport @react object TouchableHighlight extends ExternalComponent { - case class Props(onPress: js.UndefOr[() => Unit], - style: js.UndefOr[js.Object] = js.undefined) + case class Props(onPress: js.UndefOr[() => Unit], style: js.UndefOr[js.Object] = js.undefined) @js.native @JSImport("react-native", "TouchableHighlight") object Component extends js.Object override val component = Component -} \ No newline at end of file +} diff --git a/native/src/main/scala/slinky/native/TouchableOpacity.scala b/native/src/main/scala/slinky/native/TouchableOpacity.scala index e924b3af..aa245fbc 100644 --- a/native/src/main/scala/slinky/native/TouchableOpacity.scala +++ b/native/src/main/scala/slinky/native/TouchableOpacity.scala @@ -7,8 +7,7 @@ import scala.scalajs.js import scala.scalajs.js.annotation.JSImport @react object TouchableOpacity extends ExternalComponent { - case class Props(onPress: js.UndefOr[() => Unit], - style: js.UndefOr[js.Object] = js.undefined) + case class Props(onPress: js.UndefOr[() => Unit], style: js.UndefOr[js.Object] = js.undefined) @js.native @JSImport("react-native", "TouchableOpacity") diff --git a/native/src/main/scala/slinky/native/View.scala b/native/src/main/scala/slinky/native/View.scala index 38dca66a..172646b3 100644 --- a/native/src/main/scala/slinky/native/View.scala +++ b/native/src/main/scala/slinky/native/View.scala @@ -8,51 +8,54 @@ import scala.scalajs.js import scala.scalajs.js.annotation.JSImport import scala.scalajs.js.| -case class NativeTouchEvent(changedTouches: Seq[Any], - identifier: String, - locationX: Int, - locationY: Int, - pageX: Int, - pageY: Int, - target: String, - timestamp: Int, - touches: Seq[Any]) - -case class LayoutRectangle(x: Int, y: Int, - width: Int, height: Int) +case class NativeTouchEvent( + changedTouches: Seq[Any], + identifier: String, + locationX: Int, + locationY: Int, + pageX: Int, + pageY: Int, + target: String, + timestamp: Int, + touches: Seq[Any] +) + +case class LayoutRectangle(x: Int, y: Int, width: Int, height: Int) case class LayoutChangeEvent(layout: LayoutRectangle) @react object View extends ExternalComponent { - case class Props(onStartShouldSetResponder: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Unit] = js.undefined, - accessibilityLabel: js.UndefOr[ReactElement] = js.undefined, - hitSlop: js.UndefOr[BoundingBox] = js.undefined, - nativeID: js.UndefOr[String] = js.undefined, - onLayout: js.UndefOr[NativeSyntheticEvent[LayoutChangeEvent] => Unit] = js.undefined, - onMagicTap: js.UndefOr[() => Unit] = js.undefined, - onMoveShouldSetResponder: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Boolean] = js.undefined, - onMoveShouldSetResponderCapture: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Boolean] = js.undefined, - onResponderGrant: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Unit] = js.undefined, - onResponderMove: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Unit] = js.undefined, - onResponderReject: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Unit] = js.undefined, - onResponderRelease: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Unit] = js.undefined, - onResponderTerminate: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Unit] = js.undefined, - onResponderTerminationRequest: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Boolean] = js.undefined, - accessible: js.UndefOr[Boolean] = js.undefined, - onStartShouldSetResponderCapture: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Boolean] = js.undefined, - pointerEvents: js.UndefOr[String] = js.undefined, - removeClippedSubviews: js.UndefOr[Boolean] = js.undefined, - style: js.UndefOr[js.Object] = js.undefined, - testID: js.UndefOr[String] = js.undefined, - accessibilityComponentType: js.UndefOr[String] = js.undefined, - accessibilityLiveRegion: js.UndefOr[String] = js.undefined, - collapsable: js.UndefOr[Boolean] = js.undefined, - importantForAccessibility: js.UndefOr[String] = js.undefined, - needsOffscreenAlphaCompositing: js.UndefOr[Boolean] = js.undefined, - renderToHardwareTextureAndroid: js.UndefOr[Boolean] = js.undefined, - accessibilityTraits: js.UndefOr[String | Seq[String]] = js.undefined, - accessibilityViewIsModal: js.UndefOr[Boolean] = js.undefined, - shouldRasterizeIOS: js.UndefOr[Boolean] = js.undefined) + case class Props( + onStartShouldSetResponder: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Unit] = js.undefined, + accessibilityLabel: js.UndefOr[ReactElement] = js.undefined, + hitSlop: js.UndefOr[BoundingBox] = js.undefined, + nativeID: js.UndefOr[String] = js.undefined, + onLayout: js.UndefOr[NativeSyntheticEvent[LayoutChangeEvent] => Unit] = js.undefined, + onMagicTap: js.UndefOr[() => Unit] = js.undefined, + onMoveShouldSetResponder: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Boolean] = js.undefined, + onMoveShouldSetResponderCapture: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Boolean] = js.undefined, + onResponderGrant: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Unit] = js.undefined, + onResponderMove: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Unit] = js.undefined, + onResponderReject: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Unit] = js.undefined, + onResponderRelease: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Unit] = js.undefined, + onResponderTerminate: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Unit] = js.undefined, + onResponderTerminationRequest: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Boolean] = js.undefined, + accessible: js.UndefOr[Boolean] = js.undefined, + onStartShouldSetResponderCapture: js.UndefOr[NativeSyntheticEvent[NativeTouchEvent] => Boolean] = js.undefined, + pointerEvents: js.UndefOr[String] = js.undefined, + removeClippedSubviews: js.UndefOr[Boolean] = js.undefined, + style: js.UndefOr[js.Object] = js.undefined, + testID: js.UndefOr[String] = js.undefined, + accessibilityComponentType: js.UndefOr[String] = js.undefined, + accessibilityLiveRegion: js.UndefOr[String] = js.undefined, + collapsable: js.UndefOr[Boolean] = js.undefined, + importantForAccessibility: js.UndefOr[String] = js.undefined, + needsOffscreenAlphaCompositing: js.UndefOr[Boolean] = js.undefined, + renderToHardwareTextureAndroid: js.UndefOr[Boolean] = js.undefined, + accessibilityTraits: js.UndefOr[String | Seq[String]] = js.undefined, + accessibilityViewIsModal: js.UndefOr[Boolean] = js.undefined, + shouldRasterizeIOS: js.UndefOr[Boolean] = js.undefined + ) @js.native @JSImport("react-native", "View") diff --git a/native/src/test/scala/slinky/native/NativeComponentRenderTest.scala b/native/src/test/scala/slinky/native/NativeComponentRenderTest.scala index 358d6d66..49616ea4 100644 --- a/native/src/test/scala/slinky/native/NativeComponentRenderTest.scala +++ b/native/src/test/scala/slinky/native/NativeComponentRenderTest.scala @@ -1,44 +1,84 @@ package slinky.native -import org.scalatest.FunSuite +import org.scalatest.funsuite.AnyFunSuite import slinky.testrenderer.TestRenderer import scala.scalajs.js +import scala.scalajs.js.Dynamic.literal -class NativeComponentRenderTest extends FunSuite { +class NativeComponentRenderTest extends AnyFunSuite { test("Can render a button component") { - assert(!js.isUndefined(TestRenderer.create( - Button( - title = "foo", - onPress = () => {} - )("Hello!") - ).toJSON())) + assert( + !js.isUndefined( + TestRenderer + .create( + Button( + title = "foo", + onPress = () => {} + )("Hello!") + ) + .toJSON() + ) + ) } test("Can render a text component") { - assert(!js.isUndefined(TestRenderer.create( - Text( - "Hello!" + assert( + !js.isUndefined( + TestRenderer + .create( + Text( + "Hello!" + ) + ) + .toJSON() ) - ).toJSON())) + ) } test("Can render a view component with children") { - assert(!js.isUndefined(TestRenderer.create( - View( - View() + assert( + !js.isUndefined( + TestRenderer + .create( + View( + View() + ) + ) + .toJSON() ) - ).toJSON())) + ) + } + + val testStyle = literal( + fontSize = 20, + color = "black" + ) + + test("Can render a view component with style") { + assert( + !js.isUndefined( + TestRenderer + .create( + View(style = testStyle)() + ) + .toJSON() + ) + ) } test("Can render an image component") { - assert(!js.isUndefined(TestRenderer.create( - Image( - source = ImageURISource( - uri = "" + assert( + !js.isUndefined( + TestRenderer.create( + Image( + source = ImageURISource( + uri = "" + ) + ) ) ) - ))) + ) } test("Can request prefetch of an image") { @@ -48,56 +88,86 @@ class NativeComponentRenderTest extends FunSuite { } test("Can render a text input") { - assert(!js.isUndefined(TestRenderer.create( - TextInput( - value = "hello" + assert( + !js.isUndefined( + TestRenderer.create( + TextInput( + value = "hello" + ) + ) ) - ))) + ) } test("Can call clear() on a text input instance") { var clearedValue = false - assert(!js.isUndefined(TestRenderer.create( - TextInput( - value = "hello" - ).withRef { i => - i.clear() - clearedValue = true - } - ))) + assert( + !js.isUndefined( + TestRenderer.create( + TextInput( + value = "hello" + ).withRef { i => + i.clear() + clearedValue = true + } + ) + ) + ) assert(clearedValue) } test("Can render a ScrollView with children") { - assert(!js.isUndefined(TestRenderer.create( - ScrollView( - TextInput(value = "hello") + assert( + !js.isUndefined( + TestRenderer.create( + ScrollView( + TextInput(value = "hello") + ) + ) ) - ))) + ) + } + + test("Can render a ScrollView with style") { + assert( + !js.isUndefined( + TestRenderer.create( + ScrollView(style = testStyle)() + ) + ) + ) } test("Can call scrollTo() on a scroll view instance") { var scrolled = false - assert(!js.isUndefined(TestRenderer.create( - ScrollView.withRef { i => - i.scrollTo(ScrollTarget(x = 0, y = 50, animated = true)) - scrolled = true - }( - TextInput(value = "hello") + assert( + !js.isUndefined( + TestRenderer.create( + ScrollView.withRef { i => + i.scrollTo(ScrollTarget(x = 0, y = 50, animated = true)) + scrolled = true + }( + TextInput(value = "hello") + ) + ) ) - ))) + ) assert(scrolled) } test("Can render a picker with items") { - assert(!js.isUndefined(TestRenderer.create( - Picker( - Picker.Item(label = "abc", value = "abc"), - Picker.Item(label = "abc2", value = "abc2") + assert( + !js.isUndefined( + TestRenderer.create( + Picker( + Picker.Item(label = "abc", value = "abc"), + Picker.Item(label = "abc2", value = "abc2") + ) + ) ) - ))) + ) } /* react-native-mock-render does not support Slider yet @@ -108,25 +178,34 @@ class NativeComponentRenderTest extends FunSuite { ) ))) } - */ + */ test("Can render a switch") { - assert(!js.isUndefined(TestRenderer.create( - Switch( - value = true + assert( + !js.isUndefined( + TestRenderer.create( + Switch( + value = true + ) + ) ) - ))) + ) } test("Can render a flatlist") { - assert(!js.isUndefined(TestRenderer.create( - FlatList[Int]( - data = Seq(1, 2), - renderItem = { case RenderItemInfo(d, index, _) => - Text(d.toString) - } + assert( + !js.isUndefined( + TestRenderer.create( + FlatList[Int]( + data = Seq(1, 2), + renderItem = { + case RenderItemInfo(d, index, _) => + Text(d.toString) + } + ) + ) ) - ))) + ) } /* react-native-mock-render does not support SectionList yet @@ -144,11 +223,15 @@ class NativeComponentRenderTest extends FunSuite { ) ))) } - */ + */ test("Can render an activity indicator") { - assert(!js.isUndefined(TestRenderer.create( - ActivityIndicator() - ))) + assert( + !js.isUndefined( + TestRenderer.create( + ActivityIndicator() + ) + ) + ) } } diff --git a/native/src/test/scala/slinky/native/NativeStaticAPITest.scala b/native/src/test/scala/slinky/native/NativeStaticAPITest.scala index 48445999..d9a41e26 100644 --- a/native/src/test/scala/slinky/native/NativeStaticAPITest.scala +++ b/native/src/test/scala/slinky/native/NativeStaticAPITest.scala @@ -1,10 +1,10 @@ package slinky.native -import org.scalatest.FunSuite +import org.scalatest.funsuite.AnyFunSuite import scala.scalajs.js -class NativeStaticAPITest extends FunSuite { +class NativeStaticAPITest extends AnyFunSuite { test("Can fire an alert") { Alert.alert("alert!") } diff --git a/package.json b/package.json index 97bafcf1..6ad555f0 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,5 @@ { + "private": true, "bundlesize": [ { "path": "docs/build/slinky-docs-opt-bundle.js", @@ -6,6 +7,6 @@ } ], "dependencies": { - "jsdom": "^9.9.0" + "jsdom": "^9.12.0" } } diff --git a/project/plugins.sbt b/project/plugins.sbt index 21094fcf..7c45d76c 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,8 +1,33 @@ -addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.31") -addSbtPlugin("ch.epfl.scala" % "sbt-scalajs-bundler-sjs06" % "0.16.0") +val scalaJSVersion = + Option(System.getenv("SCALAJS_VERSION")).getOrElse("0.6.31") + +addSbtPlugin("org.scala-js" % "sbt-scalajs" % scalaJSVersion) + +{ + if (scalaJSVersion.startsWith("0.6.")) Nil + else Seq(addSbtPlugin("org.scala-js" % "sbt-jsdependencies" % "1.0.0-RC2")) +} + +libraryDependencies ++= { + if (scalaJSVersion.startsWith("0.6.")) Nil + else Seq("org.scala-js" %% "scalajs-env-jsdom-nodejs" % "1.0.0-RC3") +} + +{ + if (scalaJSVersion.startsWith("0.6.")) addSbtPlugin("ch.epfl.scala" % "sbt-scalajs-bundler-sjs06" % "0.16.0") + else Seq(addSbtPlugin("ch.epfl.scala" % "sbt-scalajs-bundler" % "0.16.0")) +} + +libraryDependencies ++= { + if (scalaJSVersion.startsWith("0.6.")) Nil + else Seq("org.scala-js" %% "scalajs-linker" % "1.0.0-RC2") +} + addSbtPlugin("com.jsuereth" % "sbt-pgp" % "2.0.0") -addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.8.1") -addSbtPlugin("com.dwijnand" % "sbt-dynver" % "4.0.0") -addSbtPlugin("org.jetbrains" % "sbt-idea-plugin" % "3.3.4") -addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.11") -addSbtPlugin("io.github.davidgregory084" % "sbt-tpolecat" % "0.1.10") + +addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.8.1") +addSbtPlugin("com.dwijnand" % "sbt-dynver" % "4.0.0") +addSbtPlugin("org.jetbrains" % "sbt-idea-plugin" % "3.3.4") +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.3.0") +addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.11") +addSbtPlugin("io.github.davidgregory084" % "sbt-tpolecat" % "0.1.10") diff --git a/publish.sbt b/publish.sbt index fc698682..48a19a4f 100644 --- a/publish.sbt +++ b/publish.sbt @@ -1,6 +1,8 @@ ThisBuild / publishMavenStyle := true -ThisBuild / pomIncludeRepository := { _ => false } +ThisBuild / pomIncludeRepository := { _ => + false +} ThisBuild / Test / publishArtifact := false diff --git a/publish.sh b/publish.sh index ec9a6321..0ff5d680 100644 --- a/publish.sh +++ b/publish.sh @@ -12,4 +12,12 @@ export GPG_TTY=$(tty) cp publishing-setup/credentials.sbt credentials.sbt -sbt publishSignedAll coreIntellijSupport/updateIntellij coreIntellijSupport/publishSigned sonatypeBundleRelease +sbt coreIntellijSupport/updateIntellij coreIntellijSupport/publishSigned + +export SCALAJS_VERSION="0.6.31" +sbt publishSignedAll + +export SCALAJS_VERSION="1.0.0-RC2" +sbt publishSignedAll + +sbt sonatypeBundleRelease diff --git a/reactrouter/build.sbt b/reactrouter/build.sbt index 3a725946..fda2fde5 100644 --- a/reactrouter/build.sbt +++ b/reactrouter/build.sbt @@ -2,4 +2,7 @@ enablePlugins(ScalaJSPlugin) name := "slinky-react-router" -scalacOptions += "-P:scalajs:sjsDefinedByDefault" +scalacOptions ++= { + if (scalaJSVersion.startsWith("0.6.")) Seq("-P:scalajs:sjsDefinedByDefault") + else Nil +} diff --git a/reactrouter/src/main/scala/slinky/reactrouter/ReactRouterDOM.scala b/reactrouter/src/main/scala/slinky/reactrouter/ReactRouterDOM.scala index 44a0131f..d890067b 100644 --- a/reactrouter/src/main/scala/slinky/reactrouter/ReactRouterDOM.scala +++ b/reactrouter/src/main/scala/slinky/reactrouter/ReactRouterDOM.scala @@ -18,15 +18,15 @@ object ReactRouter extends js.Object { @JSImport("react-router-dom", JSImport.Default) @js.native object ReactRouterDOM extends js.Object { - val Router: js.Object = js.native + val Router: js.Object = js.native val BrowserRouter: js.Object = js.native - val HashRouter: js.Object = js.native - val Route: js.Object = js.native - val Switch : js.Object = js.native - val Link: js.Object = js.native - val NavLink: js.Object = js.native - val Redirect: js.Object = js.native - val Prompt: js.Object = js.native + val HashRouter: js.Object = js.native + val Route: js.Object = js.native + val Switch: js.Object = js.native + val Link: js.Object = js.native + val NavLink: js.Object = js.native + val Redirect: js.Object = js.native + val Prompt: js.Object = js.native } @react object StaticRouter extends ExternalComponent { diff --git a/readWrite/build.sbt b/readWrite/build.sbt index 22c86a41..f51bc6c0 100644 --- a/readWrite/build.sbt +++ b/readWrite/build.sbt @@ -4,7 +4,7 @@ enablePlugins(ScalaJSPlugin) name := "slinky-readwrite" -libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value +libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value libraryDependencies += "org.scala-lang" % "scala-compiler" % scalaVersion.value Compile / sourceGenerators += Def.task { @@ -14,8 +14,12 @@ Compile / sourceGenerators += Def.task { val out = new PrintWriter(genFile) val gens = (0 to 22).map { n => s"""implicit def function$n[${(0 until n).map(i => s"I$i, ").mkString} O] - | (implicit ${(0 until n).map(i => s"i${i}Reader: Reader[I$i], ").mkString} oWriter: Writer[O]): Writer[(${(0 until n).map(i => s"I$i").mkString(", ")}) => O] = s => { - | val fn: js.Function$n[${(0 until n).map(_ => "js.Object, ").mkString} js.Object] = (${(0 until n).map(i => s"i$i: js.Object").mkString(", ")}) => { + | (implicit ${(0 until n) + .map(i => s"i${i}Reader: Reader[I$i], ") + .mkString} oWriter: Writer[O]): Writer[(${(0 until n).map(i => s"I$i").mkString(", ")}) => O] = s => { + | val fn: js.Function$n[${(0 until n) + .map(_ => "js.Object, ") + .mkString} js.Object] = (${(0 until n).map(i => s"i$i: js.Object").mkString(", ")}) => { | oWriter.write(s(${(0 until n).map(i => s"i${i}Reader.read(i$i)").mkString(", ")})) | } | @@ -23,18 +27,17 @@ Compile / sourceGenerators += Def.task { |}""".stripMargin } - out.println( - s"""package slinky.readwrite - | - |import scala.scalajs.js - | - |trait Writer[P] { - | def write(p: P): js.Object - |} - | - |object Writer extends CoreWriters { - | ${gens.mkString("\n")} - |}""".stripMargin) + out.println(s"""package slinky.readwrite + | + |import scala.scalajs.js + | + |trait Writer[P] { + | def write(p: P): js.Object + |} + | + |object Writer extends CoreWriters { + | ${gens.mkString("\n")} + |}""".stripMargin) out.close() Seq(genFile) @@ -47,7 +50,9 @@ Compile / sourceGenerators += Def.task { val out = new PrintWriter(genFile) val gens = (0 to 22).map { n => s"""implicit def function$n[${(0 until n).map(i => s"I$i, ").mkString} O] - | (implicit ${(0 until n).map(i => s"i${i}Writer: Writer[I$i], ").mkString} oReader: Reader[O]): Reader[(${(0 until n).map(i => s"I$i").mkString(", ")}) => O] = s => { + | (implicit ${(0 until n) + .map(i => s"i${i}Writer: Writer[I$i], ") + .mkString} oReader: Reader[O]): Reader[(${(0 until n).map(i => s"I$i").mkString(", ")}) => O] = s => { | val fn = s.asInstanceOf[js.Function$n[${(0 until n).map(_ => "js.Object, ").mkString} js.Object]] | (${(0 until n).map(i => s"i$i: I$i").mkString(", ")}) => { | oReader.read(fn(${(0 until n).map(i => s"i${i}Writer.write(i$i)").mkString(", ")})) @@ -55,37 +60,36 @@ Compile / sourceGenerators += Def.task { |}""".stripMargin } - out.println( - s"""package slinky.readwrite - | - |import scala.scalajs.js - | - |trait Reader[P] { - | def read(o: js.Object): P = { - | val ret = if (js.typeOf(o) == "object" && o != null && !js.isUndefined(o.asInstanceOf[js.Dynamic].__)) { - | o.asInstanceOf[js.Dynamic].__.asInstanceOf[P] - | } else { - | forceRead(o) - | } - | - | if (ret.isInstanceOf[WithRaw]) { - | ret.asInstanceOf[js.Dynamic].__slinky_raw = o - | } - | - | ret - | } - | - | protected def forceRead(o: js.Object): P - |} - | - |trait AlwaysReadReader[P] extends Reader[P] { - | override def read(o: js.Object): P = forceRead(o) - | protected def forceRead(o: js.Object): P - |} - | - |object Reader extends CoreReaders { - | ${gens.mkString("\n")} - |}""".stripMargin) + out.println(s"""package slinky.readwrite + | + |import scala.scalajs.js + | + |trait Reader[P] { + | def read(o: js.Object): P = { + | val ret = if (js.typeOf(o) == "object" && o != null && !js.isUndefined(o.asInstanceOf[js.Dynamic].__)) { + | o.asInstanceOf[js.Dynamic].__.asInstanceOf[P] + | } else { + | forceRead(o) + | } + | + | if (ret.isInstanceOf[WithRaw]) { + | ret.asInstanceOf[js.Dynamic].__slinky_raw = o + | } + | + | ret + | } + | + | protected def forceRead(o: js.Object): P + |} + | + |trait AlwaysReadReader[P] extends Reader[P] { + | override def read(o: js.Object): P = forceRead(o) + | protected def forceRead(o: js.Object): P + |} + | + |object Reader extends CoreReaders { + | ${gens.mkString("\n")} + |}""".stripMargin) out.close() Seq(genFile) diff --git a/readWrite/src/main/scala-2.13-/slinky/readwrite/CompatUtil.scala b/readWrite/src/main/scala-2.13-/slinky/readwrite/CompatUtil.scala index 4bf41d84..bcc2a31f 100644 --- a/readWrite/src/main/scala-2.13-/slinky/readwrite/CompatUtil.scala +++ b/readWrite/src/main/scala-2.13-/slinky/readwrite/CompatUtil.scala @@ -5,11 +5,12 @@ object CompatUtil { type Factory[-A, +C] = scala.collection.generic.CanBuildFrom[Nothing, A, C] implicit class FactoryOps[-A, +C](private val factory: Factory[A, C]) { - /** + + /** * @return A collection of type `C` containing the same elements * as the source collection `it`. * @param it Source collection */ - def fromSpecific(it: TraversableOnce[A]): C = (factory() ++= it).result() + def fromSpecific(it: TraversableOnce[A]): C = (factory() ++= it).result() } } diff --git a/readWrite/src/main/scala/slinky/readwrite/CoreReaders.scala b/readWrite/src/main/scala/slinky/readwrite/CoreReaders.scala index 9b76b339..b678e631 100644 --- a/readWrite/src/main/scala/slinky/readwrite/CoreReaders.scala +++ b/readWrite/src/main/scala/slinky/readwrite/CoreReaders.scala @@ -37,7 +37,7 @@ class MacroReadersImpl(_c: whitebox.Context) extends GenericDeriveImpl(_c) { def deferredInstance(forType: c.universe.Type, constantType: c.universe.Type) = q"new _root_.slinky.readwrite.DeferredReader[$forType, $constantType]" - def maybeExtractDeferred(tree: c.Tree): Option[c.Tree] = { + def maybeExtractDeferred(tree: c.Tree): Option[c.Tree] = tree match { case q"new _root_.slinky.readwrite.DeferredReader[$_, $t]()" => Some(t) @@ -45,15 +45,13 @@ class MacroReadersImpl(_c: whitebox.Context) extends GenericDeriveImpl(_c) { Some(t) case _ => None } - } - def createModuleTypeclass(tpe: c.universe.Type, moduleReference: c.Tree): c.Tree = { + def createModuleTypeclass(tpe: c.universe.Type, moduleReference: c.Tree): c.Tree = q"""new _root_.slinky.readwrite.Reader[$tpe] { def forceRead(o: _root_.scala.scalajs.js.Object): $tpe = { $moduleReference } }""" - } def createCaseClassTypeclass(clazz: c.Type, params: Seq[Seq[Param]]): c.Tree = { val paramsTrees = params.map(_.map { p => @@ -73,13 +71,12 @@ class MacroReadersImpl(_c: whitebox.Context) extends GenericDeriveImpl(_c) { }""" } - def createValueClassTypeclass(clazz: c.Type, param: Param): c.Tree = { + def createValueClassTypeclass(clazz: c.Type, param: Param): c.Tree = q"""new _root_.slinky.readwrite.Reader[$clazz] { def forceRead(o: _root_.scala.scalajs.js.Object): $clazz = { new $clazz(${getTypeclass(param.tpe)}.read(o)) } }""" - } def createSealedTraitTypeclass(traitType: c.Type, subclasses: Seq[c.Symbol]): c.Tree = { val cases = subclasses.map { sub => @@ -192,13 +189,14 @@ trait CoreReaders extends MacroReaders with FallbackReaders { } } - implicit def optionReader[T](implicit reader: Reader[T]): Reader[Option[T]] = (s => { - if (js.isUndefined(s) || s == null) { - None - } else { - Some(reader.read(s)) - } - }): AlwaysReadReader[Option[T]] + implicit def optionReader[T](implicit reader: Reader[T]): Reader[Option[T]] = + (s => { + if (js.isUndefined(s) || s == null) { + None + } else { + Some(reader.read(s)) + } + }): AlwaysReadReader[Option[T]] implicit def eitherReader[A, B](implicit aReader: Reader[A], bReader: Reader[B]): Reader[Either[A, B]] = o => { if (o.asInstanceOf[js.Dynamic].isLeft.asInstanceOf[Boolean]) { @@ -208,12 +206,14 @@ trait CoreReaders extends MacroReaders with FallbackReaders { } } - implicit def collectionReader[T, C[A] <: Iterable[A]](implicit reader: Reader[T], - bf: Factory[T, C[T]]): Reader[C[T]] = + implicit def collectionReader[T, C[A] <: Iterable[A]]( + implicit reader: Reader[T], + bf: Factory[T, C[T]] + ): Reader[C[T]] = c => bf.fromSpecific(c.asInstanceOf[js.Array[js.Object]].map(o => reader.read(o))) - implicit def arrayReader[T](implicit reader: Reader[T], classTag: ClassTag[T]): Reader[Array[T]] = { - c => c.asInstanceOf[js.Array[js.Object]].map(o => reader.read(o)).toArray + implicit def arrayReader[T](implicit reader: Reader[T], classTag: ClassTag[T]): Reader[Array[T]] = { c => + c.asInstanceOf[js.Array[js.Object]].map(o => reader.read(o)).toArray } implicit def mapReader[A, B](implicit abReader: Reader[(A, B)]): Reader[Map[A, B]] = o => { diff --git a/readWrite/src/main/scala/slinky/readwrite/CoreWriters.scala b/readWrite/src/main/scala/slinky/readwrite/CoreWriters.scala index a6a33e98..ea621b72 100644 --- a/readWrite/src/main/scala/slinky/readwrite/CoreWriters.scala +++ b/readWrite/src/main/scala/slinky/readwrite/CoreWriters.scala @@ -29,7 +29,7 @@ class MacroWritersImpl(_c: whitebox.Context) extends GenericDeriveImpl(_c) { def deferredInstance(forType: Type, constantType: Type) = q"new _root_.slinky.readwrite.DeferredWriter[$forType, $constantType]" - def maybeExtractDeferred(tree: Tree): Option[Tree] = { + def maybeExtractDeferred(tree: Tree): Option[Tree] = tree match { case q"new _root_.slinky.readwrite.DeferredWriter[$_, $t]()" => Some(t) @@ -37,15 +37,13 @@ class MacroWritersImpl(_c: whitebox.Context) extends GenericDeriveImpl(_c) { Some(t) case _ => None } - } - def createModuleTypeclass(tpe: Type, moduleReference: Tree): Tree = { + def createModuleTypeclass(tpe: Type, moduleReference: Tree): Tree = q"""new _root_.slinky.readwrite.Writer[$tpe] { def write(v: $tpe): _root_.scala.scalajs.js.Object = { _root_.scala.scalajs.js.Dynamic.literal() } }""" - } def createCaseClassTypeclass(clazz: Type, params: Seq[Seq[Param]]): Tree = { val paramsTrees = params.flatMap(_.map { p => @@ -66,13 +64,12 @@ class MacroWritersImpl(_c: whitebox.Context) extends GenericDeriveImpl(_c) { }""" } - def createValueClassTypeclass(clazz: Type, param: Param): Tree = { + def createValueClassTypeclass(clazz: Type, param: Param): Tree = q"""new _root_.slinky.readwrite.Writer[$clazz] { def write(v: $clazz): _root_.scala.scalajs.js.Object = { ${getTypeclass(param.tpe)}.write(v.${param.name.toTermName}) } }""" - } def createSealedTraitTypeclass(traitType: Type, subclasses: Seq[Symbol]): Tree = { val cases = subclasses.map { sub => @@ -121,19 +118,20 @@ trait CoreWriters extends MacroWriters with FallbackWriters { implicit def undefOrWriter[T](implicit writer: Writer[T]): Writer[js.UndefOr[T]] = _.map(v => writer.write(v)).getOrElse(js.undefined.asInstanceOf[js.Object]) - implicit def unionWriter[A: ClassTag, B: ClassTag](implicit aWriter: Writer[A], bWriter: Writer[B]): Writer[A | B] = { v => - if (implicitly[ClassTag[A]].runtimeClass == v.getClass) { - aWriter.write(v.asInstanceOf[A]) - } else if (implicitly[ClassTag[B]].runtimeClass == v.getClass) { - bWriter.write(v.asInstanceOf[B]) - } else { - try { + implicit def unionWriter[A: ClassTag, B: ClassTag](implicit aWriter: Writer[A], bWriter: Writer[B]): Writer[A | B] = { + v => + if (implicitly[ClassTag[A]].runtimeClass == v.getClass) { aWriter.write(v.asInstanceOf[A]) - } catch { - case _: Throwable => - bWriter.write(v.asInstanceOf[B]) + } else if (implicitly[ClassTag[B]].runtimeClass == v.getClass) { + bWriter.write(v.asInstanceOf[B]) + } else { + try { + aWriter.write(v.asInstanceOf[A]) + } catch { + case _: Throwable => + bWriter.write(v.asInstanceOf[B]) + } } - } } implicit def optionWriter[T](implicit writer: Writer[T]): Writer[Option[T]] = @@ -147,8 +145,7 @@ trait CoreWriters extends MacroWriters with FallbackWriters { ) } - implicit def collectionWriter[T, C[_]](implicit writer: Writer[T], - ev: C[T] <:< Iterable[T]): Writer[C[T]] = s => { + implicit def collectionWriter[T, C[_]](implicit writer: Writer[T], ev: C[T] <:< Iterable[T]): Writer[C[T]] = s => { val ret = js.Array[js.Object]() s.foreach { v => ret.push(writer.write(v)) diff --git a/readWrite/src/main/scala/slinky/readwrite/GenericDeriveImpl.scala b/readWrite/src/main/scala/slinky/readwrite/GenericDeriveImpl.scala index 38def9a1..6c5a567f 100644 --- a/readWrite/src/main/scala/slinky/readwrite/GenericDeriveImpl.scala +++ b/readWrite/src/main/scala/slinky/readwrite/GenericDeriveImpl.scala @@ -13,13 +13,12 @@ abstract class GenericDeriveImpl(val c: whitebox.Context) { self => case _ => origTpe } - def transformIfVarArg(tree: Tree): Tree = { + def transformIfVarArg(tree: Tree): Tree = origTpe match { case TypeRef(_, sym, _) if sym == definitions.RepeatedParamClass => q"$tree: _*" case _ => tree } - } } val typeclassType: Type @@ -33,7 +32,7 @@ abstract class GenericDeriveImpl(val c: whitebox.Context) { self => private lazy val typeclassSymbol = typeclassType.typeSymbol - private def replaceDeferred(saveReferencesTo: mutable.Set[String]): Transformer = { + private def replaceDeferred(saveReferencesTo: mutable.Set[String]): Transformer = new Transformer { override def transform(tree: Tree): Tree = maybeExtractDeferred(tree) match { case Some(t) => @@ -44,11 +43,9 @@ abstract class GenericDeriveImpl(val c: whitebox.Context) { self => super.transform(tree) } } - } - def getTypeclass(forType: Type): Tree = { + def getTypeclass(forType: Type): Tree = c.inferImplicitValue(appliedType(typeclassSymbol, forType)) - } private val currentMemo = { GenericDeriveImpl.derivationMemo.get() @@ -105,40 +102,43 @@ abstract class GenericDeriveImpl(val c: whitebox.Context) { self => val deriveTree = if (regularImplicit.isEmpty) { if (symbol.isParameter) { c.abort(c.enclosingPosition, "Cannot derive a typeclass for a type parameter") - } else if (symbol.isModuleClass && c.typecheck(c.parse(symbol.asClass.module.fullName), silent = true).nonEmpty) { + } else if (symbol.isModuleClass && c + .typecheck(c.parse(symbol.asClass.module.fullName), silent = true) + .nonEmpty) { createModuleTypeclass(tTag.tpe, c.parse(symbol.asClass.module.fullName)) } else if (symbol.isClass && symbol.asClass.isCaseClass && symbol.asType.typeParams.size == tTag.tpe.typeArgs.size) { val constructor = symbol.asClass.primaryConstructor - val companion = symbol.asClass.companion + val companion = symbol.asClass.companion if (companion != NoSymbol) { companion.info.decl(TermName("apply")).alternatives.foreach(_.asMethod.typeSignature) } val paramsLists = constructor.asMethod.paramLists memoTree(tTag.tpe) { - val params: Seq[Seq[Param]] = paramsLists.map(_.zipWithIndex.map { case (p, i) => - val transformedValueType = p.typeSignatureIn(tTag.tpe).resultType - Param( - p.name, - transformedValueType.substituteTypes(symbol.asType.typeParams, tTag.tpe.typeArgs), - if (p.asTerm.isParamWithDefault && companion != NoSymbol) { - val defaultTermName = "apply$default$" + (i + 1) - Some(q"$companion.${TermName(defaultTermName)}") - } else None - ) + val params: Seq[Seq[Param]] = paramsLists.map(_.zipWithIndex.map { + case (p, i) => + val transformedValueType = p.typeSignatureIn(tTag.tpe).resultType + Param( + p.name, + transformedValueType.substituteTypes(symbol.asType.typeParams, tTag.tpe.typeArgs), + if (p.asTerm.isParamWithDefault && companion != NoSymbol) { + val defaultTermName = "apply$default$" + (i + 1) + Some(q"$companion.${TermName(defaultTermName)}") + } else None + ) }) createCaseClassTypeclass(tTag.tpe, params) } } else if (symbol.isClass && tTag.tpe <:< typeOf[AnyVal]) { val actualValue = symbol.asClass.primaryConstructor.asMethod.paramLists.head.head - val param = Param(actualValue.name, actualValue.typeSignatureIn(tTag.tpe).resultType, None) + val param = Param(actualValue.name, actualValue.typeSignatureIn(tTag.tpe).resultType, None) memoTree(tTag.tpe)(createValueClassTypeclass(tTag.tpe, param)) } else if (symbol.isClass && symbol.asClass.isSealed && symbol.asType.toType.typeArgs.isEmpty) { def getSubclasses(clazz: ClassSymbol): Set[Symbol] = { // from magnolia - val children = clazz.knownDirectSubclasses + val children = clazz.knownDirectSubclasses val (abstractTypes, concreteTypes) = children.partition(_.isAbstract) abstractTypes.map(_.asClass).flatMap(getSubclasses) ++ concreteTypes @@ -149,7 +149,10 @@ abstract class GenericDeriveImpl(val c: whitebox.Context) { self => } } else { memoTree(tTag.tpe) { - c.echo(c.enclosingPosition, s"Using fallback derivation for type ${tTag.tpe} (derivation: ${getClass.getSimpleName})") + c.echo( + c.enclosingPosition, + s"Using fallback derivation for type ${tTag.tpe} (derivation: ${getClass.getSimpleName})" + ) createFallback(tTag.tpe) } } @@ -165,30 +168,34 @@ abstract class GenericDeriveImpl(val c: whitebox.Context) { self => if (isRoot) { val saveReferences = mutable.Set.empty[String] - val seenImpls = mutable.Set.empty[GenericDeriveImpl] + val seenImpls = mutable.Set.empty[GenericDeriveImpl] - def replaceDeferredAllTypeclasses(tree: Tree): Tree = { + def replaceDeferredAllTypeclasses(tree: Tree): Tree = seenImpls.foldLeft(tree) { (tree, impl) => - impl.replaceDeferred(saveReferences).transform(tree.asInstanceOf[impl.c.universe.Tree]) + impl + .replaceDeferred(saveReferences) + .transform(tree.asInstanceOf[impl.c.universe.Tree]) .asInstanceOf[Tree] } - } - val unwrappedOrder = currentOrder.dequeueAll(_ => true).map { case (impl, name, tpe, t) => - seenImpls.add(impl) - val typeclassTree = c.untypecheck(replaceDeferredAllTypeclasses(t.asInstanceOf[Tree])) - - if (saveReferences.contains(name)) { - ( - Some(q"var ${TermName(name)}: ${appliedType(impl.typeclassSymbol.asInstanceOf[Symbol], tpe.asInstanceOf[Type])} = null"), - q"${TermName(name)} = $typeclassTree" - ) - } else { - ( - None, - q"val ${TermName(name)}: ${appliedType(impl.typeclassSymbol.asInstanceOf[Symbol], tpe.asInstanceOf[Type])} = $typeclassTree" - ) - } + val unwrappedOrder = currentOrder.dequeueAll(_ => true).map { + case (impl, name, tpe, t) => + seenImpls.add(impl) + val typeclassTree = c.untypecheck(replaceDeferredAllTypeclasses(t.asInstanceOf[Tree])) + + if (saveReferences.contains(name)) { + ( + Some( + q"var ${TermName(name)}: ${appliedType(impl.typeclassSymbol.asInstanceOf[Symbol], tpe.asInstanceOf[Type])} = null" + ), + q"${TermName(name)} = $typeclassTree" + ) + } else { + ( + None, + q"val ${TermName(name)}: ${appliedType(impl.typeclassSymbol.asInstanceOf[Symbol], tpe.asInstanceOf[Type])} = $typeclassTree" + ) + } } currentMemo.clear() diff --git a/readWrite/src/main/scala/slinky/readwrite/ObjectOrWritten.scala b/readWrite/src/main/scala/slinky/readwrite/ObjectOrWritten.scala index 4de6d79f..d8fb966b 100644 --- a/readWrite/src/main/scala/slinky/readwrite/ObjectOrWritten.scala +++ b/readWrite/src/main/scala/slinky/readwrite/ObjectOrWritten.scala @@ -6,8 +6,11 @@ import scala.scalajs.js trait ObjectOrWritten[T] extends js.Object object ObjectOrWritten { - implicit def toUndefOrObject[T, O <: js.Object](value: js.Object): js.UndefOr[ObjectOrWritten[T]] = js.UndefOr.any2undefOrA(value.asInstanceOf[ObjectOrWritten[T]]) + implicit def toUndefOrObject[T, O <: js.Object](value: js.Object): js.UndefOr[ObjectOrWritten[T]] = + value.asInstanceOf[js.UndefOr[ObjectOrWritten[T]]] implicit def fromObject[T, O <: js.Object](obj: O): ObjectOrWritten[T] = obj.asInstanceOf[ObjectOrWritten[T]] - implicit def toUndefOrWritten[T](value: T)(implicit writer: Writer[T]): js.UndefOr[ObjectOrWritten[T]] = js.UndefOr.any2undefOrA(writer.write(value).asInstanceOf[ObjectOrWritten[T]]) - implicit def fromWritten[T](v: T)(implicit writer: Writer[T]): ObjectOrWritten[T] = writer.write(v).asInstanceOf[ObjectOrWritten[T]] + implicit def toUndefOrWritten[T](value: T)(implicit writer: Writer[T]): js.UndefOr[ObjectOrWritten[T]] = + writer.write(value).asInstanceOf[js.UndefOr[ObjectOrWritten[T]]] + implicit def fromWritten[T](v: T)(implicit writer: Writer[T]): ObjectOrWritten[T] = + writer.write(v).asInstanceOf[ObjectOrWritten[T]] } diff --git a/scalajsReactInterop/build.sbt b/scalajsReactInterop/build.sbt index f07405db..25f2faff 100644 --- a/scalajsReactInterop/build.sbt +++ b/scalajsReactInterop/build.sbt @@ -3,10 +3,16 @@ enablePlugins(ScalaJSBundlerPlugin) name := "slinky-scalajsreact-interop" libraryDependencies += "com.github.japgolly.scalajs-react" %%% "core" % "1.6.0" -libraryDependencies += "org.scalatest" %%% "scalatest" % "3.0.8" % Test -Test / npmDependencies += "react" -> "16.12.0" + +libraryDependencies += "org.scalatest" %%% "scalatest" % "3.1.0" % Test + +Test / npmDependencies += "react" -> "16.12.0" Test / npmDependencies += "react-dom" -> "16.12.0" Test / requireJsDomEnv := true -jsEnv := new org.scalajs.jsenv.jsdomnodejs.JSDOMNodeJSEnv -scalacOptions += "-P:scalajs:sjsDefinedByDefault" +Test / jsEnv := new org.scalajs.jsenv.jsdomnodejs.JSDOMNodeJSEnv() + +scalacOptions ++= { + if (scalaJSVersion.startsWith("0.6.")) Seq("-P:scalajs:sjsDefinedByDefault") + else Nil +} diff --git a/scalajsReactInterop/src/main/scala/slinky/scalajsreact/Converters.scala b/scalajsReactInterop/src/main/scala/slinky/scalajsreact/Converters.scala index 62619369..8ccf08a9 100644 --- a/scalajsReactInterop/src/main/scala/slinky/scalajsreact/Converters.scala +++ b/scalajsReactInterop/src/main/scala/slinky/scalajsreact/Converters.scala @@ -9,26 +9,22 @@ import slinky.core.facade.ReactElement object Converters { implicit class UnmountedToInstance(unmounted: UnmountedRaw) { - def toSlinky: ReactElement = { + def toSlinky: ReactElement = unmounted.raw.asInstanceOf[ReactElement] - } } implicit class TagToInstance(tag: TagOf[_]) { - def toSlinky: ReactElement = { + def toSlinky: ReactElement = tag.rawNode.asInstanceOf[ReactElement] - } } implicit class VdomToInstance(vdom: VdomElement) { - def toSlinky: ReactElement = { + def toSlinky: ReactElement = vdom.rawNode.asInstanceOf[ReactElement] - } } implicit class ComponentInstanceToVdom[T](component: T)(implicit ev: T => ReactElement) { - def toScalaJSReact: VdomNode = { + def toScalaJSReact: VdomNode = VdomNode(ev(component).asInstanceOf[Element]) - } } } diff --git a/scalajsReactInterop/src/test/scala/slinky/scalajsreact/InteropTest.scala b/scalajsReactInterop/src/test/scala/slinky/scalajsreact/InteropTest.scala index 15c36f23..9dd64bb5 100644 --- a/scalajsReactInterop/src/test/scala/slinky/scalajsreact/InteropTest.scala +++ b/scalajsReactInterop/src/test/scala/slinky/scalajsreact/InteropTest.scala @@ -1,13 +1,13 @@ package slinky.scalajsreact -import org.scalatest.FunSuite +import org.scalatest.funsuite.AnyFunSuite import slinky.web.ReactDOM import org.scalajs.dom.document import japgolly.scalajs.react.vdom.html_<^._ import Converters._ import slinky.web.html.div -class InteropTest extends FunSuite { +class InteropTest extends AnyFunSuite { test("Can convert Scala.js React node to Slinky") { val target = document.createElement("div") ReactDOM.render( diff --git a/testRenderer/src/main/scala/slinky/testrenderer/TestRenderer.scala b/testRenderer/src/main/scala/slinky/testrenderer/TestRenderer.scala index c9737a47..115e0b9f 100644 --- a/testRenderer/src/main/scala/slinky/testrenderer/TestRenderer.scala +++ b/testRenderer/src/main/scala/slinky/testrenderer/TestRenderer.scala @@ -8,12 +8,12 @@ import scala.scalajs.js.annotation.{JSImport, JSName} @js.native trait TestRenderer extends js.Object { - def toJSON(): js.Object = js.native - def toTree(): js.Object = js.native + def toJSON(): js.Object = js.native + def toTree(): js.Object = js.native def update(element: ReactElement): Unit = js.native - def unmount(): Unit = js.native - def getInstance(): js.Object = js.native - val root: TestInstance = js.native + def unmount(): Unit = js.native + def getInstance(): js.Object = js.native + val root: TestInstance = js.native } @js.native @@ -25,16 +25,16 @@ object TestRenderer extends js.Object { @js.native trait TestInstance extends js.Object { def find(test: js.Function1[TestInstance, Boolean]): TestInstance = js.native - def findByType(`type`: ReactComponentClass[_]): TestInstance = js.native - def findByProps(props: js.Object): TestInstance = js.native + def findByType(`type`: ReactComponentClass[_]): TestInstance = js.native + def findByProps(props: js.Object): TestInstance = js.native def findAll(test: js.Function1[TestInstance, Boolean]): js.Array[TestInstance] = js.native - def findAllByType(`type`: ReactComponentClass[_]): js.Array[TestInstance] = js.native - def findAllByProps(props: js.Object): js.Array[TestInstance] = js.native + def findAllByType(`type`: ReactComponentClass[_]): js.Array[TestInstance] = js.native + def findAllByProps(props: js.Object): js.Array[TestInstance] = js.native - val instance: js.Object = js.native + val instance: js.Object = js.native @JSName("type") val `type`: js.Object = js.native - val props: js.Object = js.native - val parent: TestInstance = js.native - val children: js.Array[TestInstance] = js.native + val props: js.Object = js.native + val parent: TestInstance = js.native + val children: js.Array[TestInstance] = js.native } diff --git a/tests/build.sbt b/tests/build.sbt index 0287dee1..c54c2fd3 100644 --- a/tests/build.sbt +++ b/tests/build.sbt @@ -1,20 +1,26 @@ enablePlugins(ScalaJSPlugin) +enablePlugins(JSDependenciesPlugin) -libraryDependencies += "org.scalatest" %%% "scalatest" % "3.0.8" % Test +libraryDependencies += "org.scalatest" %%% "scalatest" % "3.1.0" % Test -jsEnv := new org.scalajs.jsenv.jsdomnodejs.JSDOMNodeJSEnv +Test / jsEnv := new org.scalajs.jsenv.jsdomnodejs.JSDOMNodeJSEnv() -dependencyOverrides += "org.webjars.npm" % "js-tokens" % "3.0.2" % Test +Test / scalaJSLinkerConfig ~= { _.withESFeatures(_.withUseECMAScript2015(false)) } + +Test / unmanagedResourceDirectories += baseDirectory.value / "node_modules" jsDependencies ++= Seq( - "org.webjars.npm" % "react" % "16.12.0" % Test / "umd/react.development.js" - minified "umd/react.production.min.js" commonJSName "React", - "org.webjars.npm" % "react-dom" % "16.12.0" % Test / "umd/react-dom.development.js" - minified "umd/react-dom.production.min.js" dependsOn "umd/react.development.js" commonJSName "ReactDOM", - "org.webjars.npm" % "react-dom" % "16.12.0" % Test / "umd/react-dom-test-utils.development.js" - minified "umd/react-dom-test-utils.production.min.js" dependsOn "umd/react-dom.development.js" commonJSName "ReactTestUtils", - "org.webjars.npm" % "react-dom" % "16.12.0" % Test / "umd/react-dom-server.browser.development.js" - minified "umd/react-dom-server.browser.production.min.js" dependsOn "umd/react-dom.development.js" commonJSName "ReactDOMServer" + (ProvidedJS / "react/umd/react.development.js" + minified "react/umd/react.production.min.js" commonJSName "React") % Test, + (ProvidedJS / "react-dom/umd/react-dom.development.js" + minified "react-dom/umd/react-dom.production.min.js" dependsOn "react/umd/react.development.js" commonJSName "ReactDOM") % Test, + (ProvidedJS / "react-dom/umd/react-dom-test-utils.development.js" + minified "react-dom/umd/react-dom-test-utils.production.min.js" dependsOn "react-dom/umd/react-dom.development.js" commonJSName "ReactTestUtils") % Test, + (ProvidedJS / "react-dom/umd/react-dom-server.browser.development.js" + minified "react-dom/umd/react-dom-server.browser.production.min.js" dependsOn "react-dom/umd/react-dom.development.js" commonJSName "ReactDOMServer") % Test ) -scalacOptions += "-P:scalajs:sjsDefinedByDefault" \ No newline at end of file +scalacOptions ++= { + if (scalaJSVersion.startsWith("0.6.")) Seq("-P:scalajs:sjsDefinedByDefault") + else Nil +} diff --git a/tests/package.json b/tests/package.json new file mode 100644 index 00000000..c1551cc7 --- /dev/null +++ b/tests/package.json @@ -0,0 +1,7 @@ +{ + "private": true, + "dependencies": { + "react": "16.12.0", + "react-dom": "16.12.0" + } +} diff --git a/tests/src/test/scala/slinky/core/ComponentReturnTypeTests.scala b/tests/src/test/scala/slinky/core/ComponentReturnTypeTests.scala index 3f0e3aeb..393c2971 100644 --- a/tests/src/test/scala/slinky/core/ComponentReturnTypeTests.scala +++ b/tests/src/test/scala/slinky/core/ComponentReturnTypeTests.scala @@ -4,9 +4,10 @@ import slinky.core.facade.{Fragment, ReactElement} import slinky.web.ReactDOM import slinky.web.html._ import org.scalajs.dom -import org.scalatest.FunSuite -class ComponentReturnTypeTests extends FunSuite { +import org.scalatest.funsuite.AnyFunSuite + +class ComponentReturnTypeTests extends AnyFunSuite { def testElement(elem: ReactElement): Unit = { assert((div(elem): ReactElement) != null) // test use in another element ReactDOM.render(div(elem), dom.document.createElement("div")) // test rendering to DOM diff --git a/tests/src/test/scala/slinky/core/ComponentTest.scala b/tests/src/test/scala/slinky/core/ComponentTest.scala index d650c1e9..7ac2b8e6 100644 --- a/tests/src/test/scala/slinky/core/ComponentTest.scala +++ b/tests/src/test/scala/slinky/core/ComponentTest.scala @@ -3,12 +3,14 @@ package slinky.core import slinky.core.facade.{ErrorBoundaryInfo, ReactElement} import slinky.web.ReactDOM import org.scalajs.dom -import org.scalatest.{Assertion, AsyncFunSuite} import slinky.readwrite.{Reader, Writer} import scala.concurrent.Promise import scala.scalajs.js +import org.scalatest.Assertion +import org.scalatest.funsuite.AsyncFunSuite + object TestComponent extends ComponentWrapper { type Props = Int => Unit type State = Int diff --git a/tests/src/test/scala/slinky/core/ContextTest.scala b/tests/src/test/scala/slinky/core/ContextTest.scala index 85688378..d96f4de5 100644 --- a/tests/src/test/scala/slinky/core/ContextTest.scala +++ b/tests/src/test/scala/slinky/core/ContextTest.scala @@ -1,12 +1,13 @@ package slinky.core -import org.scalatest.FunSuite import slinky.core.facade.React import slinky.web.ReactDOM import org.scalajs.dom.document import slinky.web.html.div -class ContextTest extends FunSuite { +import org.scalatest.funsuite.AnyFunSuite + +class ContextTest extends AnyFunSuite { test("Can provide and read a simple context value") { val context = React.createContext(-1) var gotValue = 0 diff --git a/tests/src/test/scala/slinky/core/ExportedComponentTest.scala b/tests/src/test/scala/slinky/core/ExportedComponentTest.scala index d8a2ee4c..6cf84914 100644 --- a/tests/src/test/scala/slinky/core/ExportedComponentTest.scala +++ b/tests/src/test/scala/slinky/core/ExportedComponentTest.scala @@ -2,11 +2,12 @@ package slinky.core import slinky.core.facade.{React, ReactElement} import slinky.web.ReactDOM -import org.scalatest.FunSuite import scala.scalajs.js import org.scalajs.dom.document +import org.scalatest.funsuite.AnyFunSuite + object TestExportedComponentWithState extends ComponentWrapper { case class Props(name: String) type State = Int @@ -30,7 +31,7 @@ object TestExportedComponentStateless extends StatelessComponentWrapper { } } -class ExportedComponentTest extends FunSuite { +class ExportedComponentTest extends AnyFunSuite { test("Can construct an instance of an exported component with JS-provided props") { val container = document.createElement("div") ReactDOM.render(React.createElement( diff --git a/tests/src/test/scala/slinky/core/ExternalComponentTest.scala b/tests/src/test/scala/slinky/core/ExternalComponentTest.scala index f74f1a10..7657fbd2 100644 --- a/tests/src/test/scala/slinky/core/ExternalComponentTest.scala +++ b/tests/src/test/scala/slinky/core/ExternalComponentTest.scala @@ -8,7 +8,7 @@ import slinky.core.facade.{React, ReactElement} import slinky.web.ReactDOM import slinky.web.html._ -import org.scalatest.FunSuite +import org.scalatest.funsuite.AnyFunSuite object ExternalSimple extends ExternalComponentNoProps { override val component = "div" @@ -42,7 +42,7 @@ object ExternalSimpleWithWildcardAttributes extends ExternalComponentNoPropsWith override val component = "div" } -class ExternalComponentTest extends FunSuite { +class ExternalComponentTest extends AnyFunSuite { test("Rendering an external component results in appropriate props") { val rendered = ReactDOM.render( ExternalDivWithProps(id = "test"), diff --git a/tests/src/test/scala/slinky/core/FunctionalComponentTest.scala b/tests/src/test/scala/slinky/core/FunctionalComponentTest.scala index e8f4917e..4256fe2d 100644 --- a/tests/src/test/scala/slinky/core/FunctionalComponentTest.scala +++ b/tests/src/test/scala/slinky/core/FunctionalComponentTest.scala @@ -1,11 +1,12 @@ package slinky.core -import org.scalatest.FunSuite import org.scalajs.dom.document import slinky.core.facade.{React, ReactElement} import slinky.web.ReactDOM -class FunctionalComponentTest extends FunSuite { +import org.scalatest.funsuite.AnyFunSuite + +class FunctionalComponentTest extends AnyFunSuite { test("Can render a functional component") { val container = document.createElement("div") val component = FunctionalComponent[Int](_.toString) diff --git a/tests/src/test/scala/slinky/core/HooksComponentTest.scala b/tests/src/test/scala/slinky/core/HooksComponentTest.scala index cdd63a78..e9212b8f 100644 --- a/tests/src/test/scala/slinky/core/HooksComponentTest.scala +++ b/tests/src/test/scala/slinky/core/HooksComponentTest.scala @@ -1,6 +1,6 @@ package slinky.core -import org.scalatest.AsyncFunSuite +import org.scalatest.funsuite.AsyncFunSuite import org.scalajs.dom.document import org.scalajs.dom.Element diff --git a/tests/src/test/scala/slinky/core/ReactChildrenTest.scala b/tests/src/test/scala/slinky/core/ReactChildrenTest.scala index b3b07175..8b9a8169 100644 --- a/tests/src/test/scala/slinky/core/ReactChildrenTest.scala +++ b/tests/src/test/scala/slinky/core/ReactChildrenTest.scala @@ -2,11 +2,12 @@ package slinky.core import slinky.core.facade.{React, ReactChildren, ReactElement} import slinky.web.html.div -import org.scalatest.FunSuite import scala.scalajs.js -class ReactChildrenTest extends FunSuite { +import org.scalatest.funsuite.AnyFunSuite + +class ReactChildrenTest extends AnyFunSuite { import React.Children._ test("Can map over a single element") { diff --git a/tests/src/test/scala/slinky/core/ReactRefTest.scala b/tests/src/test/scala/slinky/core/ReactRefTest.scala index c9b8bfc5..66e4ef56 100644 --- a/tests/src/test/scala/slinky/core/ReactRefTest.scala +++ b/tests/src/test/scala/slinky/core/ReactRefTest.scala @@ -2,13 +2,16 @@ package slinky.core import org.scalajs.dom import org.scalajs.dom.html -import org.scalatest.{Assertion, AsyncFunSuite} + import slinky.core.facade.React import slinky.web.ReactDOM import slinky.web.html.{div, ref} import scala.concurrent.Promise +import org.scalatest.Assertion +import org.scalatest.funsuite.AsyncFunSuite + class ReactRefTest extends AsyncFunSuite { test("Can pass in a ref object to an HTML tag and use it") { val elemRef = React.createRef[html.Div] diff --git a/tests/src/test/scala/slinky/core/ReaderWriterTest.scala b/tests/src/test/scala/slinky/core/ReaderWriterTest.scala index 824117f7..72150fbf 100644 --- a/tests/src/test/scala/slinky/core/ReaderWriterTest.scala +++ b/tests/src/test/scala/slinky/core/ReaderWriterTest.scala @@ -1,11 +1,12 @@ package slinky.core -import slinky.readwrite.{Reader, WithRaw, Writer} -import org.scalatest.FunSuite +import slinky.readwrite.{Reader, WithRaw, Writer, ObjectOrWritten} import scala.scalajs.js import scala.scalajs.js.| +import org.scalatest.funsuite.AnyFunSuite + // cannot be a local class class ValueClass(val int: Int) extends AnyVal @@ -25,7 +26,7 @@ object ContainingPrivateType { val TestInstance = Test } -class ReaderWriterTest extends FunSuite { +class ReaderWriterTest extends AnyFunSuite { private def readWrittenSame[T](v: T, isOpaque: Boolean = false, beSame: Boolean = true, @@ -201,6 +202,26 @@ class ReaderWriterTest extends FunSuite { assert(implicitly[Reader[ClassWithDefault]].read(js.Dynamic.literal()).a == 5) } + test("Can convert Scala instance into ObjectOrWritten") { + assert((SubTypeA(int = 123): ObjectOrWritten[SubTypeA]) + .asInstanceOf[js.Dynamic].int.asInstanceOf[Int] == 123) + } + + test("Can convert Scala instance into js.UndefOr[ObjectOrWritten]") { + assert((SubTypeA(int = 123): js.UndefOr[ObjectOrWritten[SubTypeA]]) + .asInstanceOf[js.Dynamic].int.asInstanceOf[Int] == 123) + } + + test("Can convert js.Object into ObjectOrWritten") { + assert((js.Dynamic.literal(int = 123): ObjectOrWritten[SubTypeA]) + .asInstanceOf[js.Dynamic].int.asInstanceOf[Int] == 123) + } + + test("Can convert js.Object into js.UndefOr[ObjectOrWritten]") { + assert((js.Dynamic.literal(int = 123): js.UndefOr[ObjectOrWritten[SubTypeA]]) + .asInstanceOf[js.Dynamic].int.asInstanceOf[Int] == 123) + } + // compilation test: can use derivation macro with type parameter when typeclass is available def deriveReaderTypeclass[T: Reader]: Reader[T] = { Reader.deriveReader[T] diff --git a/tests/src/test/scala/slinky/core/SVGTest.scala b/tests/src/test/scala/slinky/core/SVGTest.scala index 11c537b6..71ef17a8 100644 --- a/tests/src/test/scala/slinky/core/SVGTest.scala +++ b/tests/src/test/scala/slinky/core/SVGTest.scala @@ -1,12 +1,13 @@ package slinky.core -import org.scalatest.FunSuite import slinky.core.facade.ReactElement import slinky.web.svg._ import scala.scalajs.js -class SVGTest extends FunSuite { +import org.scalatest.funsuite.AnyFunSuite + +class SVGTest extends AnyFunSuite { test("Can specify key attribute for SVG element") { val instance: ReactElement = circle(key := "1") diff --git a/tests/src/test/scala/slinky/core/StrictModeTest.scala b/tests/src/test/scala/slinky/core/StrictModeTest.scala index 13315391..91d3cf74 100644 --- a/tests/src/test/scala/slinky/core/StrictModeTest.scala +++ b/tests/src/test/scala/slinky/core/StrictModeTest.scala @@ -1,12 +1,14 @@ package slinky.core -import org.scalajs.dom -import org.scalatest.FunSuite import slinky.core.facade.StrictMode import slinky.web.ReactDOM import slinky.web.html.div -class StrictModeTest extends FunSuite { +import org.scalajs.dom + +import org.scalatest.funsuite.AnyFunSuite + +class StrictModeTest extends AnyFunSuite { test("Can render a StrictMode component with children") { val target = dom.document.createElement("div") ReactDOM.render( diff --git a/tests/src/test/scala/slinky/core/SuspenseTest.scala b/tests/src/test/scala/slinky/core/SuspenseTest.scala index 2ef8bb6e..da2b6b2b 100644 --- a/tests/src/test/scala/slinky/core/SuspenseTest.scala +++ b/tests/src/test/scala/slinky/core/SuspenseTest.scala @@ -1,12 +1,13 @@ package slinky.core import org.scalajs.dom -import org.scalatest.FunSuite import slinky.core.facade.Suspense import slinky.web.ReactDOM import slinky.web.html.div -class SuspenseTest extends FunSuite { +import org.scalatest.funsuite.AnyFunSuite + +class SuspenseTest extends AnyFunSuite { test("Can render a Suspense component with children") { val target = dom.document.createElement("div") ReactDOM.render( diff --git a/tests/src/test/scala/slinky/core/TagTest.scala b/tests/src/test/scala/slinky/core/TagTest.scala index 6d36818d..80ff308b 100644 --- a/tests/src/test/scala/slinky/core/TagTest.scala +++ b/tests/src/test/scala/slinky/core/TagTest.scala @@ -1,6 +1,5 @@ package slinky.core -import org.scalatest.FunSuite import slinky.core.facade.{React, ReactElement} import slinky.web.{ReactDOM, SyntheticMouseEvent} import slinky.web.html._ @@ -9,6 +8,8 @@ import scala.scalajs.js import org.scalajs.dom import org.scalajs.dom.{Element, html} +import org.scalatest.funsuite.AnyFunSuite + class InnerClassCustom extends js.Object { val customTag = CustomTag("custom-element") val customClass = CustomAttribute[String]("class") @@ -21,7 +22,7 @@ class InnerClassCustom extends js.Object { } } -class TagTest extends FunSuite { +class TagTest extends AnyFunSuite { test("Fails compilation when an incompatible attr is provided") { assertDoesNotCompile("div(width := 1)") } diff --git a/tests/src/test/scala/slinky/core/annotations/ReactAnnotatedComponentTest.scala b/tests/src/test/scala/slinky/core/annotations/ReactAnnotatedComponentTest.scala index dffe7ccd..bf22f91d 100644 --- a/tests/src/test/scala/slinky/core/annotations/ReactAnnotatedComponentTest.scala +++ b/tests/src/test/scala/slinky/core/annotations/ReactAnnotatedComponentTest.scala @@ -5,12 +5,14 @@ import slinky.core.facade.{ErrorBoundaryInfo, Fragment, ReactElement} import slinky.web.ReactDOM import slinky.web.html._ import org.scalajs.dom -import org.scalatest.{Assertion, AsyncFunSuite} import scala.concurrent.{Future, Promise} import scala.scalajs.js import scala.util.Try +import org.scalatest.Assertion +import org.scalatest.funsuite.AsyncFunSuite + @react class TestComponent extends Component { type Props = Int => Unit type State = Int diff --git a/tests/src/test/scala/slinky/core/annotations/ReactAnnotatedFunctionalComponentTest.scala b/tests/src/test/scala/slinky/core/annotations/ReactAnnotatedFunctionalComponentTest.scala index 99900d25..1ec4783c 100644 --- a/tests/src/test/scala/slinky/core/annotations/ReactAnnotatedFunctionalComponentTest.scala +++ b/tests/src/test/scala/slinky/core/annotations/ReactAnnotatedFunctionalComponentTest.scala @@ -4,7 +4,7 @@ import slinky.core.FunctionalComponent import slinky.web.ReactDOM import org.scalajs.dom -import org.scalatest.AsyncFunSuite +import org.scalatest.funsuite.AsyncFunSuite @react object SimpleFunctionalComponent { case class Props[T](in: Seq[T]) diff --git a/tests/src/test/scala/slinky/web/ReactDOMTest.scala b/tests/src/test/scala/slinky/web/ReactDOMTest.scala index 0bee8549..fc25ddf8 100644 --- a/tests/src/test/scala/slinky/web/ReactDOMTest.scala +++ b/tests/src/test/scala/slinky/web/ReactDOMTest.scala @@ -6,7 +6,8 @@ import org.scalajs.dom.{Element, document} import scala.scalajs.js import html._ -import org.scalatest.FunSuite + +import org.scalatest.funsuite.AnyFunSuite object TestComponent extends ComponentWrapper { type Props = Unit @@ -21,7 +22,7 @@ object TestComponent extends ComponentWrapper { } } -class ReactDOMTest extends FunSuite { +class ReactDOMTest extends AnyFunSuite { test("Renders a single element into the DOM") { val target = document.createElement("div") ReactDOM.render( diff --git a/vr/build.sbt b/vr/build.sbt index 2ca2846d..53bd4a0d 100644 --- a/vr/build.sbt +++ b/vr/build.sbt @@ -2,8 +2,11 @@ enablePlugins(ScalaJSPlugin) name := "slinky-vr" -libraryDependencies += "org.scalatest" %%% "scalatest" % "3.0.8" % Test +libraryDependencies += "org.scalatest" %%% "scalatest" % "3.1.0" % Test -scalacOptions += "-P:scalajs:sjsDefinedByDefault" +scalacOptions ++= { + if (scalaJSVersion.startsWith("0.6.")) Seq("-P:scalajs:sjsDefinedByDefault") + else Nil +} -Test / scalaJSModuleKind := ModuleKind.CommonJSModule +scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.CommonJSModule) } diff --git a/vr/src/main/scala/slinky/vr/Environment.scala b/vr/src/main/scala/slinky/vr/Environment.scala index 75e0af5e..34dedb68 100644 --- a/vr/src/main/scala/slinky/vr/Environment.scala +++ b/vr/src/main/scala/slinky/vr/Environment.scala @@ -6,7 +6,7 @@ import scala.scalajs.js.annotation.JSImport @js.native @JSImport("react-360", "Environment") object Environment extends js.Object { - def clearBackground(): Unit = js.native + def clearBackground(): Unit = js.native def setBackgroundImage(url: js.Object, options: js.UndefOr[js.Object] = js.undefined): Unit = js.native - def setBackgroundVideo(handle: String): Unit = js.native + def setBackgroundVideo(handle: String): Unit = js.native } diff --git a/vr/src/main/scala/slinky/vr/NativeModules.scala b/vr/src/main/scala/slinky/vr/NativeModules.scala index c71f1e82..86fcafd1 100644 --- a/vr/src/main/scala/slinky/vr/NativeModules.scala +++ b/vr/src/main/scala/slinky/vr/NativeModules.scala @@ -8,13 +8,13 @@ import scala.scalajs.js.annotation.JSImport object NativeModules extends js.Object { @js.native object VideoModule extends js.Object { - def createPlayer(name: String): Unit = js.native - def destroyPlayer(name: String): Unit = js.native - def play(name: String, options: js.Object): Unit = js.native - def pause(name: String): Unit = js.native - def resume(name: String): Unit = js.native - def stop(name: String): Unit = js.native - def seek(name: String, timeMs: Int): Unit = js.native + def createPlayer(name: String): Unit = js.native + def destroyPlayer(name: String): Unit = js.native + def play(name: String, options: js.Object): Unit = js.native + def pause(name: String): Unit = js.native + def resume(name: String): Unit = js.native + def stop(name: String): Unit = js.native + def seek(name: String, timeMs: Int): Unit = js.native def setParams(name: String, options: js.Object): Unit = js.native } } diff --git a/vr/src/main/scala/slinky/vr/Text.scala b/vr/src/main/scala/slinky/vr/Text.scala index d9a7cd51..01c1d3b0 100644 --- a/vr/src/main/scala/slinky/vr/Text.scala +++ b/vr/src/main/scala/slinky/vr/Text.scala @@ -7,12 +7,14 @@ import scala.scalajs.js import scala.scalajs.js.annotation.JSImport @react object Text extends ExternalComponent { - case class Props(numberOfLines: js.UndefOr[Int] = js.undefined, - onLayout: js.UndefOr[NativeSyntheticEvent[LayoutEvent] => Unit] = js.undefined, - onLongPress: js.UndefOr[() => Unit] = js.undefined, - onPress: js.UndefOr[() => Unit] = js.undefined, - style: js.UndefOr[js.Object] = js.undefined, - testID: js.UndefOr[String] = js.undefined) + case class Props( + numberOfLines: js.UndefOr[Int] = js.undefined, + onLayout: js.UndefOr[NativeSyntheticEvent[LayoutEvent] => Unit] = js.undefined, + onLongPress: js.UndefOr[() => Unit] = js.undefined, + onPress: js.UndefOr[() => Unit] = js.undefined, + style: js.UndefOr[js.Object] = js.undefined, + testID: js.UndefOr[String] = js.undefined + ) @js.native @JSImport("react-360", "Text") diff --git a/vr/src/main/scala/slinky/vr/View.scala b/vr/src/main/scala/slinky/vr/View.scala index 73c8834b..decf2d9b 100644 --- a/vr/src/main/scala/slinky/vr/View.scala +++ b/vr/src/main/scala/slinky/vr/View.scala @@ -12,20 +12,22 @@ case class Layout(x: Double, y: Double, width: Double, height: Double) case class LayoutEvent(layout: Layout) @react object View extends ExternalComponent { - case class Props(billboarding: js.UndefOr[String] = js.undefined, - cursorVisibilitySlop: js.UndefOr[Double | EdgeInsets] = js.undefined, - hitSlop: js.UndefOr[Double | EdgeInsets] = js.undefined, - onEnter: js.UndefOr[() => Unit] = js.undefined, - onExit: js.UndefOr[() => Unit] = js.undefined, - onHeadPose: js.UndefOr[NativeSyntheticEvent[js.Object] => Unit] = js.undefined, - onHeadPoseCaptured: js.UndefOr[() => Unit] = js.undefined, - onInput: js.UndefOr[() => Unit] = js.undefined, - onInputCaptured: js.UndefOr[() => Unit] = js.undefined, - onLayout: js.UndefOr[NativeSyntheticEvent[LayoutEvent] => Unit] = js.undefined, - onMove: js.UndefOr[() => Unit] = js.undefined, - pointerEvents: js.UndefOr[String] = js.undefined, - style: js.UndefOr[js.Object] = js.undefined, - testID: js.UndefOr[String] = js.undefined) + case class Props( + billboarding: js.UndefOr[String] = js.undefined, + cursorVisibilitySlop: js.UndefOr[Double | EdgeInsets] = js.undefined, + hitSlop: js.UndefOr[Double | EdgeInsets] = js.undefined, + onEnter: js.UndefOr[() => Unit] = js.undefined, + onExit: js.UndefOr[() => Unit] = js.undefined, + onHeadPose: js.UndefOr[NativeSyntheticEvent[js.Object] => Unit] = js.undefined, + onHeadPoseCaptured: js.UndefOr[() => Unit] = js.undefined, + onInput: js.UndefOr[() => Unit] = js.undefined, + onInputCaptured: js.UndefOr[() => Unit] = js.undefined, + onLayout: js.UndefOr[NativeSyntheticEvent[LayoutEvent] => Unit] = js.undefined, + onMove: js.UndefOr[() => Unit] = js.undefined, + pointerEvents: js.UndefOr[String] = js.undefined, + style: js.UndefOr[js.Object] = js.undefined, + testID: js.UndefOr[String] = js.undefined + ) @js.native @JSImport("react-360", "View") diff --git a/vr/src/main/scala/slinky/vr/VrButton.scala b/vr/src/main/scala/slinky/vr/VrButton.scala index f3497928..664cb8ae 100644 --- a/vr/src/main/scala/slinky/vr/VrButton.scala +++ b/vr/src/main/scala/slinky/vr/VrButton.scala @@ -7,20 +7,22 @@ import scala.scalajs.js import scala.scalajs.js.annotation.JSImport @react object VrButton extends ExternalComponent { - case class Props(disabled: js.UndefOr[Boolean] = js.undefined, - ignoreLongClick: js.UndefOr[Boolean] = js.undefined, - longClickDelayMS: js.UndefOr[Int] = js.undefined, - onButtonPress: js.UndefOr[() => Unit] = js.undefined, - onButtonRelease: js.UndefOr[() => Unit] = js.undefined, - onClick: js.UndefOr[() => Unit] = js.undefined, - onClickSound: js.UndefOr[js.Object] = js.undefined, - onEnter: js.UndefOr[() => Unit] = js.undefined, - onEnterSound: js.UndefOr[js.Object] = js.undefined, - onExit: js.UndefOr[() => Unit] = js.undefined, - onExitSound: js.UndefOr[js.Object] = js.undefined, - onLongClick: js.UndefOr[() => Unit] = js.undefined, - onLongClickSound: js.UndefOr[js.Object] = js.undefined, - style: js.UndefOr[js.Object] = js.undefined) + case class Props( + disabled: js.UndefOr[Boolean] = js.undefined, + ignoreLongClick: js.UndefOr[Boolean] = js.undefined, + longClickDelayMS: js.UndefOr[Int] = js.undefined, + onButtonPress: js.UndefOr[() => Unit] = js.undefined, + onButtonRelease: js.UndefOr[() => Unit] = js.undefined, + onClick: js.UndefOr[() => Unit] = js.undefined, + onClickSound: js.UndefOr[js.Object] = js.undefined, + onEnter: js.UndefOr[() => Unit] = js.undefined, + onEnterSound: js.UndefOr[js.Object] = js.undefined, + onExit: js.UndefOr[() => Unit] = js.undefined, + onExitSound: js.UndefOr[js.Object] = js.undefined, + onLongClick: js.UndefOr[() => Unit] = js.undefined, + onLongClickSound: js.UndefOr[js.Object] = js.undefined, + style: js.UndefOr[js.Object] = js.undefined + ) @js.native @JSImport("react-360", "VrButton") diff --git a/web/build.sbt b/web/build.sbt index 461dbf25..b7e46fde 100644 --- a/web/build.sbt +++ b/web/build.sbt @@ -2,6 +2,6 @@ enablePlugins(ScalaJSPlugin) name := "slinky-web" -scalacOptions -= "-Xfatal-warnings" - libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "0.9.8" + +scalacOptions -= "-Xfatal-warnings" diff --git a/web/html.json b/web/html.json index 62eb7c1c..0bfbec6d 100644 --- a/web/html.json +++ b/web/html.json @@ -1194,7 +1194,7 @@ }, { "attributeName" : "style", - "attributeType" : "scala.scalajs.js.Dynamic", + "attributeType" : "scala.scalajs.js.Object", "docLines" : [ "Contains \nCSS styling declarations to be applied to the element. Note that it is recommended for styles to be defined in a separate file or files. This attribute and the \n element contains style information for a document, or part of a document. By default, the style instructions written inside that element are expected to be CSS.\" href=\"/en-US/docs/Web/HTML/Element/style\"><style> element have mainly the purpose of allowing for quick styling, for example for testing purposes." ], diff --git a/web/src/main/scala/slinky/web/ReactDOM.scala b/web/src/main/scala/slinky/web/ReactDOM.scala index 6e97aab8..8177dfa2 100644 --- a/web/src/main/scala/slinky/web/ReactDOM.scala +++ b/web/src/main/scala/slinky/web/ReactDOM.scala @@ -9,9 +9,9 @@ import scala.scalajs.js.annotation.JSImport @js.native @JSImport("react-dom", JSImport.Namespace, "ReactDOM") object ReactDOM extends js.Object { - def render(component: ReactElement, target: Element): ReactInstance = js.native + def render(component: ReactElement, target: Element): ReactInstance = js.native def hydrate(component: ReactElement, target: Element): ReactInstance = js.native - def findDOMNode(instance: React.Component): Element = js.native + def findDOMNode(instance: React.Component): Element = js.native def unmountComponentAtNode(container: Element): Unit = js.native @@ -29,9 +29,9 @@ object ReactDOM extends js.Object { @js.native @JSImport("react-dom/server", JSImport.Namespace, "ReactDOMServer") object ReactDOMServer extends js.Object { - def renderToString(element: ReactElement): String = js.native + def renderToString(element: ReactElement): String = js.native def renderToStaticMarkup(element: ReactElement): String = js.native - def renderToNodeStream(element: ReactElement): js.Object = js.native + def renderToNodeStream(element: ReactElement): js.Object = js.native def renderToStaticNodeStream(element: ReactElement): js.Object = js.native } diff --git a/web/src/main/scala/slinky/web/SyntheticAnimationEvent.scala b/web/src/main/scala/slinky/web/SyntheticAnimationEvent.scala index 128cd32d..47f022b8 100644 --- a/web/src/main/scala/slinky/web/SyntheticAnimationEvent.scala +++ b/web/src/main/scala/slinky/web/SyntheticAnimationEvent.scala @@ -6,8 +6,9 @@ import scala.scalajs.js import org.scalajs.dom.AnimationEvent // https://reactjs.org/docs/events.html?#animation-events -@js.native trait SyntheticAnimationEvent[+TargetType] extends SyntheticEvent[TargetType, AnimationEvent] { +@js.native +trait SyntheticAnimationEvent[+TargetType] extends SyntheticEvent[TargetType, AnimationEvent] { val animationName: String = js.native val pseudoElement: String = js.native - val elapsedTime: Float = js.native + val elapsedTime: Float = js.native } diff --git a/web/src/main/scala/slinky/web/SyntheticClipboardEvent.scala b/web/src/main/scala/slinky/web/SyntheticClipboardEvent.scala index 7bfdd814..a343040d 100644 --- a/web/src/main/scala/slinky/web/SyntheticClipboardEvent.scala +++ b/web/src/main/scala/slinky/web/SyntheticClipboardEvent.scala @@ -6,6 +6,7 @@ import scala.scalajs.js import org.scalajs.dom.{ClipboardEvent, DataTransfer} // https://reactjs.org/docs/events.html#clipboard-events -@js.native trait SyntheticClipboardEvent[+TargetType] extends SyntheticEvent[TargetType, ClipboardEvent] { +@js.native +trait SyntheticClipboardEvent[+TargetType] extends SyntheticEvent[TargetType, ClipboardEvent] { val clipboardData: DataTransfer = js.native } diff --git a/web/src/main/scala/slinky/web/SyntheticCompositionEvent.scala b/web/src/main/scala/slinky/web/SyntheticCompositionEvent.scala index 65cb4abf..c19a4757 100644 --- a/web/src/main/scala/slinky/web/SyntheticCompositionEvent.scala +++ b/web/src/main/scala/slinky/web/SyntheticCompositionEvent.scala @@ -6,6 +6,7 @@ import scala.scalajs.js import org.scalajs.dom.CompositionEvent // https://reactjs.org/docs/events.html?#composition-events -@js.native trait SyntheticCompositionEvent[+TargetType] extends SyntheticEvent[TargetType, CompositionEvent] { +@js.native +trait SyntheticCompositionEvent[+TargetType] extends SyntheticEvent[TargetType, CompositionEvent] { val data: String = js.native } diff --git a/web/src/main/scala/slinky/web/SyntheticFocusEvent.scala b/web/src/main/scala/slinky/web/SyntheticFocusEvent.scala index 697dddd4..9e43efdc 100644 --- a/web/src/main/scala/slinky/web/SyntheticFocusEvent.scala +++ b/web/src/main/scala/slinky/web/SyntheticFocusEvent.scala @@ -3,9 +3,10 @@ package slinky.web import slinky.core.SyntheticEvent import scala.scalajs.js -import org.scalajs.dom.{FocusEvent, EventTarget} +import org.scalajs.dom.{EventTarget, FocusEvent} // https://reactjs.org/docs/events.html?#focus-events -@js.native trait SyntheticFocusEvent[+TargetType] extends SyntheticEvent[TargetType, FocusEvent] { +@js.native +trait SyntheticFocusEvent[+TargetType] extends SyntheticEvent[TargetType, FocusEvent] { val relatedTarget: EventTarget = js.native } diff --git a/web/src/main/scala/slinky/web/SyntheticKeyboardEvent.scala b/web/src/main/scala/slinky/web/SyntheticKeyboardEvent.scala index f358d0d2..c8d62bc4 100644 --- a/web/src/main/scala/slinky/web/SyntheticKeyboardEvent.scala +++ b/web/src/main/scala/slinky/web/SyntheticKeyboardEvent.scala @@ -6,17 +6,18 @@ import scala.scalajs.js import org.scalajs.dom.KeyboardEvent // https://reactjs.org/docs/events.html?#keyboard-events -@js.native trait SyntheticKeyboardEvent[+TargetType] extends SyntheticEvent[TargetType, KeyboardEvent] { - val altKey: Boolean = js.native - val charCode: Int = js.native - val ctrlKey: Boolean = js.native +@js.native +trait SyntheticKeyboardEvent[+TargetType] extends SyntheticEvent[TargetType, KeyboardEvent] { + val altKey: Boolean = js.native + val charCode: Int = js.native + val ctrlKey: Boolean = js.native def getModifierState(key: String): Boolean = js.native - val key: String = js.native - val keyCode: Int = js.native - val locale: String = js.native - val location: Int = js.native - val metaKey: Boolean = js.native - val repeat: Boolean = js.native - val shiftKey: Boolean = js.native - val which: Int = js.native + val key: String = js.native + val keyCode: Int = js.native + val locale: String = js.native + val location: Int = js.native + val metaKey: Boolean = js.native + val repeat: Boolean = js.native + val shiftKey: Boolean = js.native + val which: Int = js.native } diff --git a/web/src/main/scala/slinky/web/SyntheticMouseEvent.scala b/web/src/main/scala/slinky/web/SyntheticMouseEvent.scala index 59a197c6..31dd1bdf 100644 --- a/web/src/main/scala/slinky/web/SyntheticMouseEvent.scala +++ b/web/src/main/scala/slinky/web/SyntheticMouseEvent.scala @@ -3,22 +3,23 @@ package slinky.web import slinky.core.SyntheticEvent import scala.scalajs.js -import org.scalajs.dom.{MouseEvent, EventTarget} +import org.scalajs.dom.{EventTarget, MouseEvent} // https://reactjs.org/docs/events.html#mouse-events -@js.native trait SyntheticMouseEvent[+TargetType] extends SyntheticEvent[TargetType, MouseEvent] { - val altKey: Boolean = js.native - val button: Int = js.native - val buttons: Int = js.native - val clientX: Double = js.native - val clientY: Double = js.native - val ctrlKey: Boolean = js.native +@js.native +trait SyntheticMouseEvent[+TargetType] extends SyntheticEvent[TargetType, MouseEvent] { + val altKey: Boolean = js.native + val button: Int = js.native + val buttons: Int = js.native + val clientX: Double = js.native + val clientY: Double = js.native + val ctrlKey: Boolean = js.native def getModifierState(key: String): Boolean = js.native - val metaKey: Boolean = js.native - val pageX: Double = js.native - val pageY: Double = js.native - val relatedTarget: EventTarget = js.native - val screenX: Double = js.native - val screenY: Double = js.native - val shiftKey: Boolean = js.native + val metaKey: Boolean = js.native + val pageX: Double = js.native + val pageY: Double = js.native + val relatedTarget: EventTarget = js.native + val screenX: Double = js.native + val screenY: Double = js.native + val shiftKey: Boolean = js.native } diff --git a/web/src/main/scala/slinky/web/SyntheticPointerEvent.scala b/web/src/main/scala/slinky/web/SyntheticPointerEvent.scala index be8dfa2f..874f9a8b 100644 --- a/web/src/main/scala/slinky/web/SyntheticPointerEvent.scala +++ b/web/src/main/scala/slinky/web/SyntheticPointerEvent.scala @@ -6,15 +6,16 @@ import scala.scalajs.js import org.scalajs.dom.PointerEvent // https://reactjs.org/docs/events.html#pointer-events -@js.native trait SyntheticPointerEvent[+TargetType] extends SyntheticEvent[TargetType, PointerEvent] { - val pointerId: Int = js.native - val width: Double = js.native - val height: Double = js.native - val pressure: Double = js.native +@js.native +trait SyntheticPointerEvent[+TargetType] extends SyntheticEvent[TargetType, PointerEvent] { + val pointerId: Int = js.native + val width: Double = js.native + val height: Double = js.native + val pressure: Double = js.native val tangentialPressure: Double = js.native - val tiltX: Double = js.native - val tiltY: Double = js.native - val twist: Double = js.native - val pointerType: String = js.native - val isPrimary: Boolean = js.native + val tiltX: Double = js.native + val tiltY: Double = js.native + val twist: Double = js.native + val pointerType: String = js.native + val isPrimary: Boolean = js.native } diff --git a/web/src/main/scala/slinky/web/SyntheticTouchEvent.scala b/web/src/main/scala/slinky/web/SyntheticTouchEvent.scala index e4292dba..0abea8c5 100644 --- a/web/src/main/scala/slinky/web/SyntheticTouchEvent.scala +++ b/web/src/main/scala/slinky/web/SyntheticTouchEvent.scala @@ -6,13 +6,14 @@ import scala.scalajs.js import org.scalajs.dom.{TouchEvent, TouchList} // https://reactjs.org/docs/events.html?#touch-events -@js.native trait SyntheticTouchEvent[+TargetType] extends SyntheticEvent[TargetType, TouchEvent] { - val altKey: Boolean = js.native - val changedTouches: TouchList = js.native - val ctrlKey: Boolean = js.native +@js.native +trait SyntheticTouchEvent[+TargetType] extends SyntheticEvent[TargetType, TouchEvent] { + val altKey: Boolean = js.native + val changedTouches: TouchList = js.native + val ctrlKey: Boolean = js.native def getModifierState(key: String): Boolean = js.native - val metaKey: Boolean = js.native - val shiftKey: Boolean = js.native - val targetTouches: TouchList = js.native - val touches: TouchList = js.native + val metaKey: Boolean = js.native + val shiftKey: Boolean = js.native + val targetTouches: TouchList = js.native + val touches: TouchList = js.native } diff --git a/web/src/main/scala/slinky/web/SyntheticTransitionEvent.scala b/web/src/main/scala/slinky/web/SyntheticTransitionEvent.scala index 7606d8ba..bc46063b 100644 --- a/web/src/main/scala/slinky/web/SyntheticTransitionEvent.scala +++ b/web/src/main/scala/slinky/web/SyntheticTransitionEvent.scala @@ -6,8 +6,9 @@ import scala.scalajs.js import org.scalajs.dom.TransitionEvent // https://reactjs.org/docs/events.html?#transition-events -@js.native trait SyntheticTransitionEvent[+TargetType] extends SyntheticEvent[TargetType, TransitionEvent] { - val propertyName: String = js.native +@js.native +trait SyntheticTransitionEvent[+TargetType] extends SyntheticEvent[TargetType, TransitionEvent] { + val propertyName: String = js.native val pseudoElement: String = js.native - val elapsedTime: Float = js.native + val elapsedTime: Float = js.native } diff --git a/web/src/main/scala/slinky/web/SyntheticUIEvent.scala b/web/src/main/scala/slinky/web/SyntheticUIEvent.scala index 0b554ba5..299cca94 100644 --- a/web/src/main/scala/slinky/web/SyntheticUIEvent.scala +++ b/web/src/main/scala/slinky/web/SyntheticUIEvent.scala @@ -6,7 +6,8 @@ import scala.scalajs.js import org.scalajs.dom.{UIEvent, Window} // https://reactjs.org/docs/events.html?#ui-events -@js.native trait SyntheticUIEvent[+TargetType] extends SyntheticEvent[TargetType, UIEvent] { +@js.native +trait SyntheticUIEvent[+TargetType] extends SyntheticEvent[TargetType, UIEvent] { val detail: Double = js.native - val view: Window = js.native + val view: Window = js.native } diff --git a/web/src/main/scala/slinky/web/SyntheticWheelEvent.scala b/web/src/main/scala/slinky/web/SyntheticWheelEvent.scala index 54ab2667..ce82c243 100644 --- a/web/src/main/scala/slinky/web/SyntheticWheelEvent.scala +++ b/web/src/main/scala/slinky/web/SyntheticWheelEvent.scala @@ -6,7 +6,8 @@ import scala.scalajs.js import org.scalajs.dom.WheelEvent // https://reactjs.org/docs/events.html?#wheel-events -@js.native trait SyntheticWheelEvent[+TargetType] extends SyntheticEvent[TargetType, WheelEvent] { +@js.native +trait SyntheticWheelEvent[+TargetType] extends SyntheticEvent[TargetType, WheelEvent] { val deltaMode: Int = js.native val deltaX: Double = js.native val deltaY: Double = js.native