diff --git a/index.js b/index.js index 002b0b8..62dd175 100644 --- a/index.js +++ b/index.js @@ -53,4 +53,3 @@ export * from './src/components/RangeField'; export * from './src/components/Icon'; export * from './src/components/Expander'; export * from './src/components/Label'; -export * from './src/provider'; diff --git a/index.scss b/index.scss deleted file mode 100644 index 89604cb..0000000 --- a/index.scss +++ /dev/null @@ -1,47 +0,0 @@ -/*! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2020, Anders Evenrud - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * @author Anders Evenrud - * @licence Simplified BSD License - */ - -$base-margin: 1em; - -@import "./src/styles/_common.scss"; -@import "./src/styles/_box.scss"; -@import "./src/styles/_button.scss"; -@import "./src/styles/_input.scss"; -@import "./src/styles/_listview.scss"; -@import "./src/styles/_iconview.scss"; -@import "./src/styles/_media.scss"; -@import "./src/styles/_menu.scss"; -@import "./src/styles/_panes.scss"; -@import "./src/styles/_progressbar.scss"; -@import "./src/styles/_statusbar.scss"; -@import "./src/styles/_tabs.scss"; -@import "./src/styles/_toolbar.scss"; -@import "./src/styles/_iframe.scss"; -@import "./src/styles/_expander.scss"; diff --git a/package.json b/package.json index c3e06f7..108ebf7 100644 --- a/package.json +++ b/package.json @@ -4,15 +4,13 @@ "description": "OS.js GUI", "module": "dist/esm.js", "main": "dist/main.js", - "style": "dist/main.css", "scripts": { - "test": "npm run eslint && npm run stylelint", + "test": "npm run eslint", "eslint": "eslint index.js 'src/**/*.js'", "build": "webpack", "build:esm": "rollup -c", "watch": "webpack --watch", "watch:esm": "rollup -c --watch", - "stylelint": "stylelint index.scss src/**/*.scss", "prepublishOnly": "npm run test && rm ./dist/* && NODE_ENV=production npm run build && npm run build:esm" }, "repository": { @@ -27,17 +25,16 @@ "dist/esm.js.map", "dist/main.js", "dist/main.js.map", - "dist/main.css", - "dist/main.css.map", "CHANGELOG.md", "README.md", "LICENSE" ], "dependencies": { - "hyperapp": "^1.2.10", - "hyperapp-nestable": "^1.0.0" + "react": "^17.0.1", + "react-dom": "^17.0.1" }, "devDependencies": { + "@babel/preset-react": "^7.12.1", "@osjs/dev-meta": "^1.0.2", "rollup": "^1.31.0", "rollup-plugin-babel": "^4.3.3", @@ -67,6 +64,7 @@ }, "babel": { "presets": [ + "@babel/preset-react", [ "@babel/preset-env", { diff --git a/src/components/Box.js b/src/components/Box.js index 83749f5..390a48f 100644 --- a/src/components/Box.js +++ b/src/components/Box.js @@ -28,18 +28,17 @@ * @licence Simplified BSD License */ -import {h} from 'hyperapp'; -import {Element} from './Element'; +import { Element } from './Element'; /** * A flexbox * @param {BoxProperties} props Properties * @param {string} [props.orientation='horizontal'] Box orientation - * @param {h[]} children Children */ -export const Box = (props, children) => - h(Element, Object.assign({ - orientation: 'horizontal' - }, props, { - class: ['osjs-gui-box', props.class], - }), children); +export const Box = props => ( + +); diff --git a/src/components/BoxContainer.js b/src/components/BoxContainer.js index 3f42e8d..0d5ccfd 100644 --- a/src/components/BoxContainer.js +++ b/src/components/BoxContainer.js @@ -28,16 +28,13 @@ * @licence Simplified BSD License */ -import {h} from 'hyperapp'; -import {Element} from './Element'; +import { Element } from './Element'; /** * A flexbox container * @param {BoxProperties} props Properties * @param {string} [props.orientation='vertical'] Box orientation - * @param {h[]} children Children */ -export const BoxContainer = (props, children) => - h(Element, Object.assign({}, props, { - class: ['osjs-gui-box-container', props.class] - }), children); +export const BoxContainer = props => ( + +); diff --git a/src/components/BoxStyled.js b/src/components/BoxStyled.js index 312dea5..900fca4 100644 --- a/src/components/BoxStyled.js +++ b/src/components/BoxStyled.js @@ -28,15 +28,12 @@ * @licence Simplified BSD License */ -import {h} from 'hyperapp'; -import {Element} from './Element'; +import { Element } from './Element'; /** * A styled flexbox container * @param {BoxProperties} props Properties - * @param {h[]} children Children */ -export const BoxStyled = (props, children) => - h(Element, Object.assign({}, props, { - class: ['osjs-gui-box-styled', props.class] - }), children); +export const BoxStyled = props => ( + +); diff --git a/src/components/Button.js b/src/components/Button.js index 5fae7f0..e1bd023 100644 --- a/src/components/Button.js +++ b/src/components/Button.js @@ -28,9 +28,8 @@ * @licence Simplified BSD License */ -import {h} from 'hyperapp'; -import {Icon} from './Icon'; -import {createField} from '../element'; +import { Icon } from './Icon'; +import { createField } from '../element'; /** * A button @@ -38,22 +37,16 @@ import {createField} from '../element'; * @param {string} [props.icon] Icon source * @param {string} [props.label] Use this as label instead of children * @param {BoxProperties} [props.box] Box Properties - * @param {h[]} children Children */ -export const Button = (props = {}, children = []) => - createField('button', props, { - }, (fieldProps) => { - const inner = []; - if (props.icon) { - inner.push(h(Icon, props.icon)); - } - - if (typeof props.label === 'string') { - inner.push(h('span', {class: 'osjs-label'}, props.label)); - } - - return h('button', fieldProps, [ - ...inner, - ...children - ]); +export const Button = ({ children, ...props }) => + createField('button', props, {}, fieldProps => { + return ( + + ); }); diff --git a/src/components/Element.js b/src/components/Element.js index 5df4f4f..b82ae6d 100644 --- a/src/components/Element.js +++ b/src/components/Element.js @@ -28,11 +28,9 @@ * @licence Simplified BSD License */ -import {h} from 'hyperapp'; - /** * Elemet Box definition - * @property {string} [class] Container class name + * @property {string} [className] Container className * @property {number} [grow] Flexbox grow value * @property {number} [shrink] Flexbox shrink value * @property {number|string} [basis] Flexbox basis value @@ -40,49 +38,39 @@ import {h} from 'hyperapp'; * @property {string} [justify] Flexbox justifyContent value * @property {number|string} [padding] Margin * @property {number|string} [margin] Margin - * @property {string} [key] Hyperapp element key - * @property {Function} [oncreate] Hyperapp oncreate function - * @property {Function} [onupdate] Hyperapp onupdate function - * @property {Function} [ondestroy] Hyperapp ondestroy function + * @property {string} [key] element key * @typedef BoxProperties */ -const unitValue = (value, unset) => typeof value === 'number' - ? `${value}px` - : (value === false ? unset : value); +const unitValue = (value, unset) => + typeof value === 'number' ? `${value}px` : value === false ? unset : value; const boxPropNames = { - grow: value => ({flexGrow: value}), - shrink: value => ({flexShrink: value}), - basis: value => ({flexBasis: unitValue(value, 'auto')}), - align: value => ({alignItems: value}), - justify: value => ({justifyContent: value}), - padding: value => ({margin: unitValue(value, '0')}), - margin: value => ({margin: unitValue(value, '0')}) + grow: value => ({ flexGrow: value }), + shrink: value => ({ flexShrink: value }), + basis: value => ({ flexBasis: unitValue(value, 'auto') }), + align: value => ({ alignItems: value }), + justify: value => ({ justifyContent: value }), + padding: value => ({ margin: unitValue(value, '0') }), + margin: value => ({ margin: unitValue(value, '0') }), }; /** * A generic OS.js GUI container * @param {Object} props Properties - * @param {h[]} children Children */ -export const Element = (props, children = []) => { - const givenClassNames = props.class instanceof Array - ? props.class - : [props.class]; +export const Element = ({children, ...props}) => { + const givenClassNames = + props.className instanceof Array ? props.className : [props.className]; - const classNames = [ - 'osjs-gui', - ...givenClassNames - ]; + const classNames = ['osjs-gui', ...givenClassNames]; if (props.orientation) { classNames.push('osjs-gui-' + props.orientation); } - const defaultStyle = typeof props.style === 'string' - ? {} - : Object.assign({}, props.style || {}); + const defaultStyle = + typeof props.style === 'string' ? {} : Object.assign({}, props.style || {}); const style = Object.keys(props).reduce((result, prop) => { const value = boxPropNames[prop] @@ -92,10 +80,11 @@ export const Element = (props, children = []) => { return Object.assign({}, result, value); }, defaultStyle); - return h('div', { - oncreate: props.oncreate, - ondestroy: props.ondestroy, - class: classNames.filter(s => !!s).join(' '), - style - }, children); + return ( +
!!s).join(' ')} + style={style}> + {children} +
+ ); }; diff --git a/src/components/Expander.js b/src/components/Expander.js index 1922596..a465d48 100644 --- a/src/components/Expander.js +++ b/src/components/Expander.js @@ -28,61 +28,44 @@ * @licence Simplified BSD License */ -import {h} from 'hyperapp'; -import {Element} from './Element'; -import nestable from 'hyperapp-nestable'; - -const view = (state, actions) => (props, children) => { - return h(Element, Object.assign({}, props.box || {}, { - class: ['osjs-gui-expander-wrapper'] - }), [ - h('div', { - class: 'osjs-gui-expander-header', - onclick: ev => actions.ontoggle({ - ev, - active: !state.active, - ontoggle: props.ontoggle - }) - }, [ - h('div', { - class: 'osjs-gui-expander-header-icon', - 'data-active': String(state.active) - }), - h('div', { - class: 'osjs-gui-expander-header-label' - }, props.label) - ]), - h('div', { - class: 'osjs-gui-expander-content', - style: { - display: state.active === false ? 'none' : undefined - } - }, children) - ]); -}; - -const inner = nestable({ - active: true -}, { - init: props => ({ - ative: props.active !== false - }), - ontoggle: ({ev, active, ontoggle}) => { - const cb = ontoggle || function() {}; - cb(ev, active); - return {active}; - } -}, view, 'div'); +import React from 'react'; +import { Element } from './Element'; /** * A status bar * @param {Object} props Properties * @param {boolean} [props.active] Active state - * @param {Function} [props.ontoggle] Toggle callback => (ev, active) + * @param {Function} [props.onToggle] Toggle callback => (ev, active) * @param {BoxProperties} [props.box] Box Properties - * @param {h[]} children Children */ -export const Expander = (props, children) => - h(inner, Object.assign({}, props, { - class: 'osjs-gui osjs-gui-expander' - }), children); +export const Expander = ({ children, ...props }) => { + const [active, setActive] = React.useState(Boolean(props.active)); + + const onToggle = ev => { + if (props.onToggle) { + props.onToggle(ev, !active); + } + + setActive(!active); + }; + + return ( +
+ +
+
+
{props.label}
+
+
+ {children} +
+
+
+ ); +}; diff --git a/src/components/Icon.js b/src/components/Icon.js index ce992b9..583c270 100644 --- a/src/components/Icon.js +++ b/src/components/Icon.js @@ -28,29 +28,24 @@ * @licence Simplified BSD License */ -import {h} from 'hyperapp'; - /** * An icon * @param {Object} props Properties * @param {string} props.src Icon src * @param {string} [props.name] Icon name - * @param {h[]} children Children */ -export const Icon = (props, children) => { - const i = props && typeof props === 'object' - ? props.src - : props; +export const Icon = props => { + const i = props && typeof props === 'object' ? props.src : props; - const n = props && typeof props === 'object' - ? props.name - : undefined; + const n = props && typeof props === 'object' ? props.name : undefined; - return h('i', { - 'data-icon': n, - class: 'osjs-icon', - style: { - backgroundImage: typeof props === 'string' ? `url(${i})` : undefined - } - }); + return ( + + ); }; diff --git a/src/components/IconView.js b/src/components/IconView.js index 86f7952..9808f45 100644 --- a/src/components/IconView.js +++ b/src/components/IconView.js @@ -28,91 +28,81 @@ * @licence Simplified BSD License */ -import {h} from 'hyperapp'; -import {doubleTap} from '../utils'; -import {Element} from './Element'; -import {Icon} from './Icon'; +import React from 'react'; +import { doubleTap } from '../utils'; +import { Element } from './Element'; +import { Icon } from './Icon'; const tapper = doubleTap(); -export const IconViewEntry = (entry, index, props) => () => { - const icon = entry.icon || {name: 'application-x-executable'}; +export const IconViewEntry = ({ entry, index, ...props }) => { + const elementRef = React.useRef(); + + const icon = entry.icon || { name: 'application-x-executable' }; const selected = props.selectedIndex === index; - return h('div', { - class: 'osjs-gui-icon-view-entry' + (selected ? ' osjs__active' : ''), - ontouchstart: (ev) => tapper(ev, () => props.onactivate({data: entry.data, index, ev})), - ondblclick: (ev) => props.onactivate({data: entry.data, index, ev}), - onclick: (ev) => props.onselect({data: entry.data, index, ev}), - oncontextmenu: (ev) => props.oncontextmenu({data: entry.data, index, ev}), - oncreate: (el) => props.oncreate({data: entry.data, index, el}) - }, [ - h('div', {class: 'osjs__container'}, [ - h('div', {class: 'osjs__image'}, [ - h(Icon, icon) - ]), - h('div', {class: 'osjs__label'}, [ - h('span', {}, entry.label) - ]) - ]) - ]); -}; + React.useEffect(() => { + props.onCreate({ data: entry.data, index, el: elementRef.current }); + }, []); -export const IconView = (props) => { - const inner = h('div', { - class: 'osjs-gui-icon-view-wrapper', - oncreate: el => (el.scrollTop = props.scrollTop), - onupdate: el => { - if (props.selectedIndex < 0) { - el.scrollTop = props.scrollTop; + return ( +
+ tapper(ev, () => props.onactivate({ data: entry.data, index, ev })) } - } - }, props.entries.map((entry, index) => { - return h(IconViewEntry(entry, index, props)); - })); + onDoubleClick={ev => props.onactivate({ data: entry.data, index, ev })} + onClick={ev => props.onselect({ data: entry.data, index, ev })} + onContextMenu={ev => + props.oncontextmenu({ data: entry.data, index, ev }) + }> +
+
+ +
+
+ {entry.label} +
+
+
+ ); +}; + +const defaultHandler = () => {}; - return h(Element, Object.assign({ - class: 'osjs-gui-icon-view' - }, props.box || {}), inner); +const defaultProps = { + selectedIndex: -1, + scrollTop: 0, + entries: [], + onSelect: defaultHandler, + onActivate: defaultHandler, + onContextMenu: defaultHandler, + onCreate: defaultHandler, }; -export const iconView = ({ - component: (state, actions) => { - const newProps = Object.assign({ - entries: [], - onselect: ({data, index, ev}) => { - actions.select({data, index, ev}); - actions.setSelectedIndex(index); - }, - onactivate: ({data, index, ev}) => { - actions.activate({data, index, ev}); - actions.setSelectedIndex(-1); - }, - oncontextmenu: ({data, index, ev}) => { - actions.select({data, index, ev}); - actions.contextmenu({data, index, ev}); - actions.setSelectedIndex(index); - }, - oncreate: (args) => { - actions.created(args); - } - }, state); +export const IconView = props => { + const elementRef = React.useRef(); + + const newProps = { ...defaultProps, ...props }; - return (props = {}) => IconView(Object.assign(newProps, props)); - }, + React.useEffect(() => { + elementRef.current.scrollTop = newProps.scrollTop; + }, []); - state: state => Object.assign({ - selectedIndex: -1, - scrollTop: 0 - }, state), + React.useEffect(() => { + if (newProps.selectedIndex < 0) { + elementRef.current.scrollTop = newProps.scrollTop; + } + }); - actions: actions => Object.assign({ - select: () => () => ({}), - activate: () => () => ({}), - contextmenu: () => () => ({}), - created: () => () => ({}), - setEntries: entries => () => ({entries}), - setScrollTop: scrollTop => state => ({scrollTop}), - setSelectedIndex: selectedIndex => state => ({selectedIndex}), - }, actions || {}) -}); + return ( + +
+ {newProps.entries.map((entry, index) => ( + + ))} +
+
+ ); +}; diff --git a/src/components/Iframe.js b/src/components/Iframe.js index b3f7ab7..ae0f6bb 100644 --- a/src/components/Iframe.js +++ b/src/components/Iframe.js @@ -28,22 +28,17 @@ * @licence Simplified BSD License */ -import {h} from 'hyperapp'; -import {filteredProps} from '../utils'; -import {Element} from './Element'; +import { filteredProps } from '../utils'; +import { Element } from './Element'; /** * A iframe * @param {Object} props Properties * @param {BoxProperties} [props.box] Box Properties - * @param {h[]} children Children */ -export const Iframe = (props, children = []) => - h(Element, Object.assign({}, props.box || {}, { - class: ['osjs-gui-iframe', props.class] - }), [ - h('iframe', Object.assign({ - frameborder: 0 - }, filteredProps(props, ['box']))), - ...children - ]); +export const Iframe = ({ children, ...props }) => ( + +