Fix build for ring-UI

This commit is contained in:
Alexander Nozik 2021-05-09 15:49:18 +03:00
parent 65c0183ba7
commit e615fcc2bc
15 changed files with 366 additions and 44 deletions

View File

@ -16,6 +16,15 @@ kotlin {
jvm { jvm {
withJava() withJava()
} }
js{
useCommonJs()
browser {
commonWebpackConfig {
sourceMaps = false
cssSupport.enabled = false
}
}
}
sourceSets { sourceSets {
commonMain { commonMain {
dependencies { dependencies {
@ -31,6 +40,7 @@ kotlin {
jsMain { jsMain {
dependencies { dependencies {
implementation(project(":ui:bootstrap")) implementation(project(":ui:bootstrap"))
implementation(project(":ui:ring"))
implementation(project(":visionforge-threejs")) implementation(project(":visionforge-threejs"))
implementation(npm("react-file-drop", "3.0.6")) implementation(npm("react-file-drop", "3.0.6"))
} }

View File

@ -14,10 +14,10 @@ import space.kscience.gdml.decodeFromString
import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision
import space.kscience.visionforge.bootstrap.gridRow import space.kscience.visionforge.bootstrap.gridRow
import space.kscience.visionforge.bootstrap.nameCrumbs import space.kscience.visionforge.bootstrap.nameCrumbs
import space.kscience.visionforge.bootstrap.threeControls
import space.kscience.visionforge.gdml.toVision import space.kscience.visionforge.gdml.toVision
import space.kscience.visionforge.react.ThreeCanvasComponent import space.kscience.visionforge.react.ThreeCanvasComponent
import space.kscience.visionforge.react.flexColumn import space.kscience.visionforge.react.flexColumn
import space.kscience.visionforge.ring.ringThreeControls
import space.kscience.visionforge.solid.Solid import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.Solids import space.kscience.visionforge.solid.Solids
import space.kscience.visionforge.solid.specifications.Canvas3DOptions import space.kscience.visionforge.solid.specifications.Canvas3DOptions
@ -31,14 +31,6 @@ external interface GDMLAppProps : RProps {
var selected: Name? var selected: Name?
} }
//private val canvasConfig = Canvas3DOptions {
// camera = Camera {
// distance = 2100.0
// latitude = PI / 6
// azimuth = PI + PI / 6
// }
//}
@JsExport @JsExport
val GDMLApp = functionalComponent<GDMLAppProps>("GDMLApp") { props -> val GDMLApp = functionalComponent<GDMLAppProps>("GDMLApp") { props ->
var selected by useState { props.selected } var selected by useState { props.selected }
@ -120,7 +112,7 @@ val GDMLApp = functionalComponent<GDMLAppProps>("GDMLApp") { props ->
} }
} }
canvas?.let { canvas?.let {
threeControls(it, selected, onSelect) ringThreeControls(it, selected, onSelect)
} }
} }
} }

3
demo/gdml/webpack.config.d/01.ring.js vendored Normal file
View File

@ -0,0 +1,3 @@
const ringConfig = require('@jetbrains/ring-ui/webpack.config').config;
config.module.rules.push(...ringConfig.module.rules)

View File

@ -0,0 +1,7 @@
config.module.rules.push({
test: /\.css$/,
include: [
require.resolve('bootstrap/dist/css/bootstrap.min.css')
],
use: ['style-loader', 'css-loader']
});

View File

@ -49,7 +49,6 @@ public external interface PropertyEditorProps : RProps {
*/ */
public var descriptor: NodeDescriptor? public var descriptor: NodeDescriptor?
/** /**
* A coroutine scope for updates * A coroutine scope for updates
*/ */

View File

@ -7,6 +7,11 @@ val dataforgeVersion: String by rootProject.extra
kotlin{ kotlin{
js{ js{
useCommonJs() useCommonJs()
browser {
commonWebpackConfig {
cssSupport.enabled = false
}
}
} }
} }
@ -15,4 +20,8 @@ dependencies{
implementation(npm("@jetbrains/icons", "3.14.1")) implementation(npm("@jetbrains/icons", "3.14.1"))
implementation(npm("@jetbrains/ring-ui", "4.0.7")) implementation(npm("@jetbrains/ring-ui", "4.0.7"))
implementation(npm("core-js","3.12.1"))
compileOnly(npm("url-loader","4.1.1"))
compileOnly(npm("postcss-loader","5.2.0"))
compileOnly(npm("source-map-loader","2.0.1"))
} }

View File

@ -20,11 +20,11 @@ public external interface AlertProps : WithClassName {
public typealias AlertType = String public typealias AlertType = String
public object AlertTypes { public object AlertTypes {
public var ERROR = "error" public var ERROR: String = "error"
public var MESSAGE = "message" public var MESSAGE: String = "message"
public var SUCCESS = "success" public var SUCCESS: String = "success"
public var WARNING = "warning" public var WARNING: String = "warning"
public var LOADING = "loading" public var LOADING: String = "loading"
} }
public fun RBuilder.ringAlert(handler: RHandler<AlertProps>) { public fun RBuilder.ringAlert(handler: RHandler<AlertProps>) {

View File

@ -9,15 +9,15 @@ import react.dom.WithClassName
public external interface LinkProps : WithClassName { public external interface LinkProps : WithClassName {
public var innerClassName: String public var innerClassName: String
public var active: Boolean public var active: Boolean
var inherit: Boolean public var inherit: Boolean
var pseudo: Boolean public var pseudo: Boolean
var hover: Boolean public var hover: Boolean
var href: String public var href: String
var onPlainLeftClick: (MouseEvent) -> Unit public var onPlainLeftClick: (MouseEvent) -> Unit
var onClick: (MouseEvent) -> Unit public var onClick: (MouseEvent) -> Unit
} }
fun RBuilder.ringLink(handler: RHandler<LinkProps>) { public fun RBuilder.ringLink(handler: RHandler<LinkProps>) {
RingUI.Link { RingUI.Link {
handler() handler()
} }

View File

@ -25,6 +25,16 @@ public fun RBuilder.ringIsland(handler: RHandler<IslandProps>) {
} }
} }
public fun RBuilder.ringIsland(header: String, handler: RHandler<IslandContentProps>) {
ringIsland {
ringIslandHeader {
+header
}
ringIslandContent(handler)
}
}
public fun RBuilder.ringAdaptiveIsland(handler: RHandler<IslandProps>) { public fun RBuilder.ringAdaptiveIsland(handler: RHandler<IslandProps>) {
IslandModule.AdaptiveIsland { IslandModule.AdaptiveIsland {
handler() handler()

View File

@ -0,0 +1,21 @@
package ringui.tabs
import react.RBuilder
import react.RHandler
import react.dom.WithClassName
public external interface SmartTabsProps: WithClassName {
public var initSelected: String
}
public fun RBuilder.ringSmartTabs(active: String? = null, handler: RHandler<SmartTabsProps>){
TabsModule.SmartTabs{
active?.let{
attrs {
initSelected = active
}
}
handler()
}
}

View File

@ -0,0 +1,50 @@
package ringui.tabs
import react.RBuilder
import react.RClass
import react.RHandler
import react.dom.WithClassName
@JsModule("@jetbrains/ring-ui/components/tabs/tabs")
internal external object TabsModule {
val Tabs: RClass<TabsProps>
val Tab: RClass<TabProps>
val SmartTabs: RClass<SmartTabsProps>
//val CustomItem: RClass<CustomItemProps>
}
//https://github.com/JetBrains/ring-ui/blob/master/components/tabs/tabs.js
public external interface TabsProps : WithClassName {
public var theme: String
public var selected: String
public var onSelect: (String) -> Unit
public var href: String
public var autoCollapse: Boolean
}
public external interface CustomItemProps : WithClassName
public external interface TabProps : WithClassName {
public var title: dynamic // PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired,
public var id: String
}
public fun RBuilder.ringTabs(active: String? = null, handler: RHandler<TabsProps>) {
TabsModule.Tabs {
active?.let{
attrs {
selected = active
}
}
handler()
}
}
public fun RBuilder.ringTab(title: dynamic, handler: RHandler<TabProps>) {
TabsModule.Tab {
attrs {
this.title = title
}
handler()
}
}

View File

@ -0,0 +1,75 @@
package space.kscience.visionforge.ring
import org.w3c.dom.Element
import react.RBuilder
import react.dom.render
import ringui.island.ringIsland
import ringui.island.ringIslandContent
import ringui.island.ringIslandHeader
import ringui.tabs.ringSmartTabs
import ringui.tabs.ringTab
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
import space.kscience.visionforge.*
import space.kscience.visionforge.react.metaViewer
import space.kscience.visionforge.react.propertyEditor
import space.kscience.visionforge.solid.SolidReference
public fun RBuilder.ringPropertyEditor(
vision: Vision,
descriptor: NodeDescriptor? = vision.descriptor,
key: Any? = null,
) {
ringIsland {
ringIslandHeader {
attrs {
border = true
}
+"Properties"
}
ringIslandContent {
propertyEditor(
ownProperties = vision.ownProperties,
allProperties = vision.allProperties(),
updateFlow = vision.propertyChanges,
descriptor = descriptor,
key = key
)
}
}
val styles = if (vision is SolidReference) {
(vision.styles + vision.prototype.styles).distinct()
} else {
vision.styles
}
if (styles.isNotEmpty()) {
ringIsland {
ringIslandHeader {
attrs {
border = true
}
+"Styles"
}
ringIslandContent {
ringSmartTabs {
}
styles.forEach { styleName ->
val style = vision.getStyle(styleName)
if (style != null) {
ringTab(styleName) {
metaViewer(style)
}
}
}
}
}
}
}
public fun Element.ringPropertyEditor(
item: Vision,
descriptor: NodeDescriptor? = item.descriptor,
): Unit = render(this) {
ringPropertyEditor(item, descriptor = descriptor)
}

View File

@ -0,0 +1,150 @@
package space.kscience.visionforge.ring
import kotlinx.css.*
import kotlinx.css.properties.border
import kotlinx.html.js.onClickFunction
import org.w3c.dom.events.Event
import org.w3c.files.Blob
import org.w3c.files.BlobPropertyBag
import react.*
import react.dom.button
import react.dom.h2
import ringui.island.ringIsland
import ringui.tabs.ringSmartTabs
import ringui.tabs.ringTab
import space.kscience.dataforge.meta.descriptors.defaultMeta
import space.kscience.dataforge.meta.withDefault
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.isEmpty
import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionGroup
import space.kscience.visionforge.react.flexColumn
import space.kscience.visionforge.react.flexRow
import space.kscience.visionforge.react.objectTree
import space.kscience.visionforge.react.propertyEditor
import space.kscience.visionforge.solid.SolidGroup
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
import space.kscience.visionforge.solid.three.ThreeCanvas
import styled.css
import styled.styledDiv
internal fun saveData(event: Event, fileName: String, mimeType: String = "text/plain", dataBuilder: () -> String) {
event.stopPropagation();
event.preventDefault();
val fileSaver = kotlinext.js.require("file-saver")
val blob = Blob(arrayOf(dataBuilder()), BlobPropertyBag("$mimeType;charset=utf-8"))
fileSaver.saveAs(blob, fileName)
}
internal fun RBuilder.canvasControls(canvas: ThreeCanvas): ReactElement {
return child(CanvasControls) {
attrs {
this.canvas = canvas
}
}
}
internal external interface CanvasControlsProps : RProps {
public var canvas: ThreeCanvas
}
internal val CanvasControls: FunctionalComponent<CanvasControlsProps> = functionalComponent("CanvasControls") { props ->
val visionManager = useMemo(
{ props.canvas.three.solids.visionManager },
arrayOf(props.canvas)
)
flexColumn {
flexRow {
css {
border(1.px, BorderStyle.solid, Color.blue)
padding(4.px)
}
button {
+"Export"
attrs {
onClickFunction = {
val json = (props.canvas.content as? SolidGroup)?.let { group ->
visionManager.encodeToString(group)
}
if (json != null) {
saveData(it, "object.json", "text/json") {
json
}
}
}
}
}
}
propertyEditor(
ownProperties = props.canvas.options,
allProperties = props.canvas.options.withDefault(Canvas3DOptions.descriptor.defaultMeta()),
descriptor = Canvas3DOptions.descriptor,
expanded = false
)
}
}
public external interface ThreeControlsProps : RProps {
public var canvas: ThreeCanvas
public var selected: Name?
public var onSelect: (Name) -> Unit
}
@JsExport
public val ThreeControls: FunctionalComponent<ThreeControlsProps> = functionalComponent { props ->
val vision = props.canvas.content
ringSmartTabs(if (props.selected != null) "Properties" else null) {
ringTab("Canvas") {
ringIsland("Canvas configuration") {
canvasControls(props.canvas)
}
}
ringTab("Tree") {
styledDiv {
css {
border(1.px, BorderStyle.solid, Color.lightGray)
padding(10.px)
}
h2 { +"Object tree" }
styledDiv {
css {
flex(1.0, 1.0, FlexBasis.inherit)
}
props.canvas.content?.let {
objectTree(it, props.selected, props.onSelect)
}
}
}
}
ringTab("Properties") {
props.selected.let { selected ->
val selectedObject: Vision? = when {
selected == null -> null
selected.isEmpty() -> vision
else -> (vision as? VisionGroup)?.get(selected)
}
if (selectedObject != null) {
ringPropertyEditor(selectedObject, key = selected)
}
}
}
props.children()
}
}
public fun RBuilder.ringThreeControls(
canvas: ThreeCanvas,
selected: Name?,
onSelect: (Name) -> Unit = {},
builder: RBuilder.() -> Unit = {},
): ReactElement = child(ThreeControls) {
attrs {
this.canvas = canvas
this.selected = selected
this.onSelect = onSelect
}
builder()
}

View File

@ -1,6 +1,3 @@
// wrap is useful, because declaring variables in module can be already declared
// module creates own lexical environment
(function (config) {
const ringConfig = require('@jetbrains/ring-ui/webpack.config').config; const ringConfig = require('@jetbrains/ring-ui/webpack.config').config;
config.module.rules.push(...ringConfig.module.rules);
})(config); config.module.rules.push(...ringConfig.module.rules)

View File

@ -1,8 +1,7 @@
package space.kscience.visionforge.solid package space.kscience.visionforge.solid
import javafx.application.Platform import javafx.application.Platform
import javafx.beans.binding.Binding import javafx.beans.binding.*
import javafx.beans.binding.ObjectBinding
import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.*
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.startsWith import space.kscience.dataforge.names.startsWith
@ -46,18 +45,18 @@ public class VisualObjectFXBinding(public val fx: FX3DPlugin, public val obj: Vi
} }
public fun ObjectBinding<MetaItem?>.value(): Binding<Value?> = objectBinding { it.value } public fun ObjectBinding<MetaItem?>.value(): Binding<Value?> = objectBinding { it.value }
fun ObjectBinding<MetaItem?>.string() = stringBinding { it.string } public fun ObjectBinding<MetaItem?>.string(): StringBinding = stringBinding { it.string }
fun ObjectBinding<MetaItem?>.number() = objectBinding { it.number } public fun ObjectBinding<MetaItem?>.number(): Binding<Number?> = objectBinding { it.number }
fun ObjectBinding<MetaItem?>.double() = objectBinding { it.double } public fun ObjectBinding<MetaItem?>.double(): Binding<Double?> = objectBinding { it.double }
fun ObjectBinding<MetaItem?>.float() = objectBinding { it.float } public fun ObjectBinding<MetaItem?>.float(): Binding<Float?> = objectBinding { it.float }
fun ObjectBinding<MetaItem?>.int() = objectBinding { it.int } public fun ObjectBinding<MetaItem?>.int(): Binding<Int?> = objectBinding { it.int }
fun ObjectBinding<MetaItem?>.long() = objectBinding { it.long } public fun ObjectBinding<MetaItem?>.long(): Binding<Long?> = objectBinding { it.long }
fun ObjectBinding<MetaItem?>.node() = objectBinding { it.node } public fun ObjectBinding<MetaItem?>.node(): Binding<Meta?> = objectBinding { it.node }
fun ObjectBinding<MetaItem?>.string(default: String) = stringBinding { it.string ?: default } public fun ObjectBinding<MetaItem?>.string(default: String): StringBinding = stringBinding { it.string ?: default }
fun ObjectBinding<MetaItem?>.double(default: Double) = doubleBinding { it.double ?: default } public fun ObjectBinding<MetaItem?>.double(default: Double): DoubleBinding = doubleBinding { it.double ?: default }
fun ObjectBinding<MetaItem?>.float(default: Float) = floatBinding { it.float ?: default } public fun ObjectBinding<MetaItem?>.float(default: Float): FloatBinding = floatBinding { it.float ?: default }
fun ObjectBinding<MetaItem?>.int(default: Int) = integerBinding { it.int ?: default } public fun ObjectBinding<MetaItem?>.int(default: Int): IntegerBinding = integerBinding { it.int ?: default }
fun ObjectBinding<MetaItem?>.long(default: Long) = longBinding { it.long ?: default } public fun ObjectBinding<MetaItem?>.long(default: Long): LongBinding = longBinding { it.long ?: default }
fun <T> ObjectBinding<MetaItem?>.transform(transform: (MetaItem) -> T) = objectBinding { it?.let(transform) } public fun <T> ObjectBinding<MetaItem?>.transform(transform: (MetaItem) -> T): Binding<T?> = objectBinding { it?.let(transform) }