ywana-core8 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.css +2 -0
- package/dist/index.css.map +1 -0
- package/dist/index.modern.js +2 -0
- package/dist/index.modern.js.map +1 -0
- package/dist/index.umd.js +2 -0
- package/dist/index.umd.js.map +1 -0
- package/package.json +27 -0
- package/publish.sh +5 -0
- package/src/css/fonts.css +162 -0
- package/src/css/html.css +36 -0
- package/src/css/theme.css +89 -0
- package/src/css/theme_dark.css +85 -0
- package/src/css/theme_light.css +87 -0
- package/src/domain/CollectionPage.css +34 -0
- package/src/domain/CollectionPage.js +346 -0
- package/src/domain/ContentEditor.css +174 -0
- package/src/domain/ContentEditor.js +425 -0
- package/src/domain/ContentForm.js +74 -0
- package/src/domain/ContentType.js +187 -0
- package/src/domain/CreateContentDialog.js +59 -0
- package/src/domain/EditContentDialog.js +50 -0
- package/src/domain/TablePage.css +29 -0
- package/src/domain/TablePage.js +395 -0
- package/src/domain/index.js +5 -0
- package/src/fonts/Assistant-Bold.ttf +0 -0
- package/src/fonts/Assistant-ExtraBold.ttf +0 -0
- package/src/fonts/Assistant-ExtraLight.ttf +0 -0
- package/src/fonts/Assistant-Light.ttf +0 -0
- package/src/fonts/Assistant-Medium.ttf +0 -0
- package/src/fonts/Assistant-Regular.ttf +0 -0
- package/src/fonts/Assistant-SemiBold.ttf +0 -0
- package/src/fonts/Assistant-VariableFont_wght.ttf +0 -0
- package/src/html/button.css +79 -0
- package/src/html/button.js +26 -0
- package/src/html/checkbox.css +51 -0
- package/src/html/checkbox.js +33 -0
- package/src/html/chip.css +63 -0
- package/src/html/chip.js +39 -0
- package/src/html/form.css +17 -0
- package/src/html/form.js +80 -0
- package/src/html/header.css +64 -0
- package/src/html/header.js +30 -0
- package/src/html/icon.css +53 -0
- package/src/html/icon.js +21 -0
- package/src/html/index.js +18 -0
- package/src/html/list.css +72 -0
- package/src/html/list.js +78 -0
- package/src/html/menu.css +76 -0
- package/src/html/menu.js +80 -0
- package/src/html/progress.css +20 -0
- package/src/html/progress.js +27 -0
- package/src/html/property.css +18 -0
- package/src/html/property.js +16 -0
- package/src/html/radio.css +50 -0
- package/src/html/radio.js +25 -0
- package/src/html/section.css +6 -0
- package/src/html/section.js +31 -0
- package/src/html/tab.css +45 -0
- package/src/html/tab.js +68 -0
- package/src/html/table.css +56 -0
- package/src/html/table.js +186 -0
- package/src/html/text.js +20 -0
- package/src/html/textfield-outlined.css +52 -0
- package/src/html/textfield.css +130 -0
- package/src/html/textfield.js +99 -0
- package/src/html/tokenfield.css +51 -0
- package/src/html/tokenfield.js +74 -0
- package/src/html/tree.css +63 -0
- package/src/html/tree.js +49 -0
- package/src/http/client.js +62 -0
- package/src/http/index.js +2 -0
- package/src/http/session.js +39 -0
- package/src/index.js +9 -0
- package/src/site/details.css +58 -0
- package/src/site/dialog.css +63 -0
- package/src/site/dialog.js +43 -0
- package/src/site/index.js +3 -0
- package/src/site/layouts.css +27 -0
- package/src/site/page.css +44 -0
- package/src/site/page.js +36 -0
- package/src/site/site.css +85 -0
- package/src/site/site.js +234 -0
- package/src/site/siteContext.js +4 -0
- package/src/site/workspace.js +57 -0
- package/src/upload/UploadArea.js +64 -0
- package/src/upload/UploadDialog.js +41 -0
- package/src/upload/UploadFile.js +31 -0
- package/src/upload/index.js +1 -0
- package/src/upload/uploader.css +57 -0
- package/src/upload/uploader.js +69 -0
- package/src/widgets/index.js +4 -0
- package/src/widgets/kanban/Kanban.css +80 -0
- package/src/widgets/kanban/Kanban.js +65 -0
- package/src/widgets/login/LoginBox.css +89 -0
- package/src/widgets/login/LoginBox.js +66 -0
- package/src/widgets/login/ResetPasswordBox.css +50 -0
- package/src/widgets/login/ResetPasswordBox.js +56 -0
- package/src/widgets/viewer/Viewer.css +87 -0
- package/src/widgets/viewer/Viewer.js +47 -0
package/src/html/menu.js
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
import React, { useContext, useState } from 'react'
|
2
|
+
import { Icon } from './icon';
|
3
|
+
import './menu.css'
|
4
|
+
|
5
|
+
|
6
|
+
/**
|
7
|
+
* Page Context
|
8
|
+
*/
|
9
|
+
export const MenuContext = React.createContext({})
|
10
|
+
|
11
|
+
/**
|
12
|
+
* Menu
|
13
|
+
**/
|
14
|
+
export const Menu = (props) => {
|
15
|
+
const { children } = props
|
16
|
+
return (
|
17
|
+
<ul>
|
18
|
+
{children}
|
19
|
+
</ul>
|
20
|
+
)
|
21
|
+
}
|
22
|
+
|
23
|
+
/**
|
24
|
+
* Menu Icon
|
25
|
+
*/
|
26
|
+
export const MenuIcon = (props) => {
|
27
|
+
|
28
|
+
const { icon = "more_vert", children, align } = props
|
29
|
+
const [open, setOpen] = useState(false)
|
30
|
+
|
31
|
+
function toggle() {
|
32
|
+
setOpen(!open)
|
33
|
+
}
|
34
|
+
|
35
|
+
return (
|
36
|
+
<MenuContext.Provider value={[open, setOpen]}>
|
37
|
+
<div className="menu-icon">
|
38
|
+
<Icon icon={icon} clickable action={toggle} />
|
39
|
+
{open ? (
|
40
|
+
<menu className={`${align}`}>
|
41
|
+
{children}
|
42
|
+
</menu>
|
43
|
+
) : null}
|
44
|
+
{open ? <div className="overlay" onClick={toggle}/> : null}
|
45
|
+
</div>
|
46
|
+
</MenuContext.Provider>
|
47
|
+
)
|
48
|
+
}
|
49
|
+
|
50
|
+
/**
|
51
|
+
* Menu Item
|
52
|
+
*/
|
53
|
+
export const MenuItem = (props) => {
|
54
|
+
|
55
|
+
const { id, icon, label, meta, onSelect } = props
|
56
|
+
const [open, setOpen] = useContext(MenuContext)
|
57
|
+
|
58
|
+
function select() {
|
59
|
+
if (onSelect) onSelect()
|
60
|
+
setOpen(false)
|
61
|
+
}
|
62
|
+
return (
|
63
|
+
<li className="menu-item" onClick={select}>
|
64
|
+
{icon ? <Icon icon={icon} /> : null}
|
65
|
+
<label>{label}</label>
|
66
|
+
{meta ? <div className="meta">{meta}</div> : null}
|
67
|
+
</li>
|
68
|
+
)
|
69
|
+
}
|
70
|
+
|
71
|
+
/**
|
72
|
+
* Menu Separator
|
73
|
+
*/
|
74
|
+
export const MenuSeparator = (props) => {
|
75
|
+
return (
|
76
|
+
<li>
|
77
|
+
menuSeparator
|
78
|
+
</li>
|
79
|
+
)
|
80
|
+
}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
@keyframes rotating {
|
2
|
+
from {
|
3
|
+
-ms-transform: rotate(0deg);
|
4
|
+
-moz-transform: rotate(0deg);
|
5
|
+
-webkit-transform: rotate(0deg);
|
6
|
+
-o-transform: rotate(0deg);
|
7
|
+
transform: rotate(0deg);
|
8
|
+
}
|
9
|
+
to {
|
10
|
+
-ms-transform: rotate(360deg);
|
11
|
+
-moz-transform: rotate(360deg);
|
12
|
+
-webkit-transform: rotate(360deg);
|
13
|
+
-o-transform: rotate(360deg);
|
14
|
+
transform: rotate(360deg);
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
.circular-progress {
|
19
|
+
animation: rotating 2s linear infinite;
|
20
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import { Icon } from './icon'
|
2
|
+
import './progress.css'
|
3
|
+
|
4
|
+
/**
|
5
|
+
* Circular Progress
|
6
|
+
*/
|
7
|
+
export const CircularProgress = (props) => {
|
8
|
+
return (
|
9
|
+
<div className="circular-progress">
|
10
|
+
<Icon icon="refresh" size="small" />
|
11
|
+
</div>
|
12
|
+
)
|
13
|
+
}
|
14
|
+
|
15
|
+
/**
|
16
|
+
* Linear Progress
|
17
|
+
*/
|
18
|
+
export const LinearProgress = (props) => {
|
19
|
+
|
20
|
+
const { progress= 0, max = 100 } = props
|
21
|
+
|
22
|
+
return (
|
23
|
+
<div className="linear-progress">
|
24
|
+
<progress value={progress} max={max}/>
|
25
|
+
</div>
|
26
|
+
)
|
27
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
.property {
|
2
|
+
flex:1;
|
3
|
+
display: flex;
|
4
|
+
}
|
5
|
+
|
6
|
+
.property-name {
|
7
|
+
flex: 1;
|
8
|
+
overflow: hidden;
|
9
|
+
text-overflow: ellipsis;
|
10
|
+
white-space: nowrap;
|
11
|
+
}
|
12
|
+
|
13
|
+
.property-value {
|
14
|
+
flex: 1;
|
15
|
+
overflow: hidden;
|
16
|
+
text-overflow: ellipsis;
|
17
|
+
white-space: nowrap;
|
18
|
+
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import './property.css'
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Property
|
5
|
+
*/
|
6
|
+
export const Property = (props) => {
|
7
|
+
|
8
|
+
const { name, value} = props
|
9
|
+
|
10
|
+
return (
|
11
|
+
<div className="property">
|
12
|
+
<div className="property-name">{name}</div>
|
13
|
+
<div className="property-value">{value}</div>
|
14
|
+
</div>
|
15
|
+
)
|
16
|
+
}
|
@@ -0,0 +1,50 @@
|
|
1
|
+
.radio {
|
2
|
+
flex: 1;
|
3
|
+
overflow: hidden;
|
4
|
+
display: flex;
|
5
|
+
align-items: center;
|
6
|
+
position: relative;
|
7
|
+
}
|
8
|
+
|
9
|
+
.radio .checkmark {
|
10
|
+
width: 1.5rem;
|
11
|
+
height: 1.5rem;
|
12
|
+
display: flex;
|
13
|
+
align-items: center;
|
14
|
+
justify-content: center;
|
15
|
+
margin: 0.3rem;
|
16
|
+
border: solid 1px var(--primary-color);
|
17
|
+
background-color: var(--paper-color);
|
18
|
+
border-radius: 3rem;
|
19
|
+
}
|
20
|
+
|
21
|
+
.radio .checkmark:after {
|
22
|
+
content: "";
|
23
|
+
width: .4rem;
|
24
|
+
height: .4rem;
|
25
|
+
border: solid 5px var(--primary-color);
|
26
|
+
border-radius: 5rem;
|
27
|
+
background-color: var(--primary-color);
|
28
|
+
display: none;
|
29
|
+
z-index: 0;
|
30
|
+
}
|
31
|
+
|
32
|
+
.radio > input {
|
33
|
+
position: absolute;
|
34
|
+
flex: 1;
|
35
|
+
width: 2rem;
|
36
|
+
height: 2rem;
|
37
|
+
opacity: 0;
|
38
|
+
z-index: 1;
|
39
|
+
}
|
40
|
+
|
41
|
+
input:checked ~ .checkmark:after {
|
42
|
+
display: block;
|
43
|
+
}
|
44
|
+
|
45
|
+
.radio > label {
|
46
|
+
color: var(--text-color-light);
|
47
|
+
font-size: 1rem;
|
48
|
+
font-weight: normal;
|
49
|
+
}
|
50
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import { Text } from './text';
|
3
|
+
import './radio.css'
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Radio Button
|
7
|
+
*/
|
8
|
+
export const RadioButton = (props) => {
|
9
|
+
|
10
|
+
const { id, name, label, placeholder, value, onChange } = props
|
11
|
+
|
12
|
+
function change(event) {
|
13
|
+
const value = event.target.value
|
14
|
+
if (onChange) onChange(id, value)
|
15
|
+
}
|
16
|
+
|
17
|
+
const labelTxt = <Text>{label}</Text>
|
18
|
+
return (
|
19
|
+
<div className="radio">
|
20
|
+
<input id={id} name={name} type="radio" placeholder={placeholder} value={value} onClick={change} />
|
21
|
+
<span class="checkmark" />
|
22
|
+
<label htmlFor={id}>{labelTxt}</label>
|
23
|
+
</div>
|
24
|
+
)
|
25
|
+
}
|
@@ -0,0 +1,31 @@
|
|
1
|
+
import React, { useEffect, useState } from 'react'
|
2
|
+
import { Icon } from './icon';
|
3
|
+
import { Header } from './header';
|
4
|
+
import './section.css'
|
5
|
+
|
6
|
+
/**
|
7
|
+
* Section
|
8
|
+
*/
|
9
|
+
export const Section = (props) => {
|
10
|
+
|
11
|
+
const { icon, title = '', canCollapse = true, open = false, actions, children, className } = props
|
12
|
+
const [isOpen, setOpen] = useState(open)
|
13
|
+
|
14
|
+
useEffect(() => {
|
15
|
+
setOpen(open)
|
16
|
+
}, [open])
|
17
|
+
|
18
|
+
const toggle = () => {
|
19
|
+
setOpen(!open)
|
20
|
+
}
|
21
|
+
|
22
|
+
return (
|
23
|
+
<section className={`section2 ${className}`}>
|
24
|
+
<Header icon={{ icon }} title={title}>
|
25
|
+
{actions}
|
26
|
+
{canCollapse ? <Icon icon="expand_more" onIcon="expand_less" clickable action={toggle} /> : ''}
|
27
|
+
</Header>
|
28
|
+
{isOpen ? (<main>{children}</main>) : ''}
|
29
|
+
</section>
|
30
|
+
)
|
31
|
+
}
|
package/src/html/tab.css
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
.tabs {
|
2
|
+
flex: 1;
|
3
|
+
display: flex;
|
4
|
+
overflow-x: auto;
|
5
|
+
align-items: flex-end;
|
6
|
+
max-height: 3rem;
|
7
|
+
}
|
8
|
+
|
9
|
+
.tab, .tab-filler {
|
10
|
+
padding: 0 1rem;
|
11
|
+
text-transform: uppercase;
|
12
|
+
overflow: hidden;
|
13
|
+
cursor: pointer;
|
14
|
+
display: flex;
|
15
|
+
justify-content: center;
|
16
|
+
align-items: center;
|
17
|
+
height: 2rem;
|
18
|
+
border-bottom: solid 1px var(--divider-color);
|
19
|
+
background-color: transparent !important;
|
20
|
+
min-width: 5rem;
|
21
|
+
font-size: .9rem;
|
22
|
+
color: var(--text-color-light);
|
23
|
+
}
|
24
|
+
|
25
|
+
.tab-filler {
|
26
|
+
flex: 1;
|
27
|
+
}
|
28
|
+
|
29
|
+
.tab:hover {
|
30
|
+
background-color: var(--background-color);
|
31
|
+
cursor: pointer;
|
32
|
+
}
|
33
|
+
|
34
|
+
.tab.selected {
|
35
|
+
background-color: var(--paper-color) !important;
|
36
|
+
color: var(--text-color);
|
37
|
+
border: solid 1px var(--divider-color);
|
38
|
+
border-bottom-width: 0;
|
39
|
+
min-height: 2.2rem;
|
40
|
+
border-radius: 0;
|
41
|
+
}
|
42
|
+
|
43
|
+
.tab.small {
|
44
|
+
padding: .2rem;
|
45
|
+
}
|
package/src/html/tab.js
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
import React, { useState } from 'react'
|
2
|
+
import { Fragment } from 'react'
|
3
|
+
import './tab.css'
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Tabs
|
7
|
+
*/
|
8
|
+
export const Tabs = (props) => {
|
9
|
+
|
10
|
+
const { children, selected, onChange } = props
|
11
|
+
|
12
|
+
const tabs = React.Children.map(children, (child, index) => {
|
13
|
+
|
14
|
+
function select() {
|
15
|
+
if (onChange) onChange(index)
|
16
|
+
}
|
17
|
+
|
18
|
+
return React.cloneElement(child, {
|
19
|
+
selected: index === selected,
|
20
|
+
onSelect: select
|
21
|
+
})
|
22
|
+
})
|
23
|
+
|
24
|
+
return (
|
25
|
+
<div class="tabs">
|
26
|
+
{tabs}
|
27
|
+
<div class="tab-filler" />
|
28
|
+
</div>
|
29
|
+
)
|
30
|
+
}
|
31
|
+
|
32
|
+
/**
|
33
|
+
* Tab
|
34
|
+
*/
|
35
|
+
export const Tab = (props) => {
|
36
|
+
|
37
|
+
const { label, selected, actions, onSelect } = props
|
38
|
+
|
39
|
+
function select() {
|
40
|
+
if (onSelect) onSelect()
|
41
|
+
}
|
42
|
+
|
43
|
+
const style = selected ? "selected" : ""
|
44
|
+
return (
|
45
|
+
<div className={`tab ${style}`} onClick={select}>
|
46
|
+
{label}
|
47
|
+
{actions ? actions : null}
|
48
|
+
</div>
|
49
|
+
)
|
50
|
+
}
|
51
|
+
|
52
|
+
/**
|
53
|
+
* Stack
|
54
|
+
*/
|
55
|
+
export const Stack = (props) => {
|
56
|
+
|
57
|
+
const { selected = 0 } = props
|
58
|
+
|
59
|
+
const child = React.Children
|
60
|
+
.toArray(props.children)
|
61
|
+
.filter((child, index) => index === selected )[0]
|
62
|
+
|
63
|
+
return (
|
64
|
+
<Fragment>
|
65
|
+
{child}
|
66
|
+
</Fragment>
|
67
|
+
)
|
68
|
+
}
|
@@ -0,0 +1,56 @@
|
|
1
|
+
.datatable8 {
|
2
|
+
max-height: 40rem;
|
3
|
+
overflow: hidden;
|
4
|
+
border: solid 0px var(--divider-color);
|
5
|
+
background-color: var(--paper-color);
|
6
|
+
}
|
7
|
+
|
8
|
+
.datatable8.outlined {
|
9
|
+
border: solid 1px var(--divider-color);
|
10
|
+
}
|
11
|
+
|
12
|
+
.datatable8 table {
|
13
|
+
width: 100%;
|
14
|
+
}
|
15
|
+
|
16
|
+
.datatable8 thead {
|
17
|
+
position: sticky;
|
18
|
+
top: 0px;
|
19
|
+
background-color: rgba(200,200,200,.4);
|
20
|
+
overflow: hidden;
|
21
|
+
color: var(--text-color-lighter);
|
22
|
+
}
|
23
|
+
|
24
|
+
.datatable8 thead tr {
|
25
|
+
border-bottom: solid 1px var(--divider-color);
|
26
|
+
}
|
27
|
+
|
28
|
+
.datatable8 thead th {
|
29
|
+
padding: 0 1rem;
|
30
|
+
text-align: left;
|
31
|
+
font-weight: 600 !important;
|
32
|
+
}
|
33
|
+
|
34
|
+
.datatable8 tbody {
|
35
|
+
overflow: visible;
|
36
|
+
height: 5rem;
|
37
|
+
}
|
38
|
+
|
39
|
+
.datatable8 tbody tr {
|
40
|
+
border-bottom: solid 1px var(--divider-color);
|
41
|
+
}
|
42
|
+
|
43
|
+
.datatable8 tbody tr:hover {
|
44
|
+
background-color: rgba(200,200,200,.2);
|
45
|
+
cursor: pointer
|
46
|
+
}
|
47
|
+
|
48
|
+
.datatable8 tbody td {
|
49
|
+
height: 3rem;
|
50
|
+
padding: 0 1rem;
|
51
|
+
overflow: visible;
|
52
|
+
text-overflow: ellipsis;
|
53
|
+
white-space: nowrap;
|
54
|
+
max-width: 10rem;
|
55
|
+
color: var(--text-color-light);
|
56
|
+
}
|
@@ -0,0 +1,186 @@
|
|
1
|
+
import { Fragment, useState } from 'react'
|
2
|
+
import { CheckBox } from './checkbox'
|
3
|
+
import { Icon } from './icon'
|
4
|
+
import { Text } from './text'
|
5
|
+
import { DropDown, TextField } from './textfield'
|
6
|
+
import './table.css'
|
7
|
+
|
8
|
+
/**
|
9
|
+
* DataTable
|
10
|
+
*/
|
11
|
+
export const DataTable = (props) => {
|
12
|
+
|
13
|
+
const { columns = [], rows = [], onRowSelection, onSort, editable, outlined } = props
|
14
|
+
const [sortDir, setSortDir] = useState({})
|
15
|
+
|
16
|
+
function multiSort(array, sortObject = {}) {
|
17
|
+
|
18
|
+
const sortKeys = Object.keys(sortObject);
|
19
|
+
|
20
|
+
if (!sortKeys.length) {
|
21
|
+
return array;
|
22
|
+
}
|
23
|
+
|
24
|
+
const keySort = (a, b, direction) => {
|
25
|
+
direction = direction !== null ? direction : 1;
|
26
|
+
|
27
|
+
if (a === b) { // If the values are the same, do not switch positions.
|
28
|
+
return 0;
|
29
|
+
}
|
30
|
+
|
31
|
+
// If b > a, multiply by -1 to get the reverse direction.
|
32
|
+
return a > b ? direction : -1 * direction;
|
33
|
+
};
|
34
|
+
|
35
|
+
return array.sort((a, b) => {
|
36
|
+
let sorted = 0;
|
37
|
+
let index = 0;
|
38
|
+
|
39
|
+
// Loop until sorted (-1 or 1) or until the sort keys have been processed.
|
40
|
+
while (sorted === 0 && index < sortKeys.length) {
|
41
|
+
const key = sortKeys[index];
|
42
|
+
|
43
|
+
if (key) {
|
44
|
+
const direction = sortObject[key];
|
45
|
+
|
46
|
+
sorted = keySort(a[key], b[key], direction);
|
47
|
+
index++;
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
return sorted;
|
52
|
+
});
|
53
|
+
}
|
54
|
+
|
55
|
+
function select(row, event) {
|
56
|
+
if (onRowSelection) onRowSelection(row, event)
|
57
|
+
}
|
58
|
+
|
59
|
+
function sort(dragged, dropped) {
|
60
|
+
if (onSort) onSort(dragged, dropped)
|
61
|
+
}
|
62
|
+
|
63
|
+
const style = outlined ? "outlined" : ""
|
64
|
+
return (
|
65
|
+
<div className={`datatable8 ${style}`}>
|
66
|
+
<table>
|
67
|
+
<thead>
|
68
|
+
<tr>
|
69
|
+
{columns.map(({ id, label, sortable }) => {
|
70
|
+
const sort = sortDir[id] ? sortDir[id] : null
|
71
|
+
return (
|
72
|
+
<th>
|
73
|
+
<Text>{label}</Text>
|
74
|
+
{sortable ? <Icon icon="arrow_up" size="small" clickable /> : null}
|
75
|
+
</th>
|
76
|
+
)
|
77
|
+
})}
|
78
|
+
</tr>
|
79
|
+
</thead>
|
80
|
+
<tbody>
|
81
|
+
{
|
82
|
+
multiSort(rows, sortDir).map(row => (
|
83
|
+
<DataTableRow key={row.id} row={row} columns={columns} onSelect={select} onDrop={sort} editable={editable}/>
|
84
|
+
))
|
85
|
+
}
|
86
|
+
</tbody>
|
87
|
+
</table>
|
88
|
+
</div>
|
89
|
+
)
|
90
|
+
}
|
91
|
+
|
92
|
+
/**
|
93
|
+
* DataTable Row
|
94
|
+
*/
|
95
|
+
const DataTableRow = (props) => {
|
96
|
+
const { row, columns = [], onSelect, editable } = props
|
97
|
+
const [isInfoOpen, toggleInfo] = useState(false)
|
98
|
+
const infoIcon = isInfoOpen ? 'expand_more' : 'expand_less'
|
99
|
+
|
100
|
+
const isFunction = value => value && (Object.prototype.toString.call(value) === "[object Function]" || "function" === typeof value || value instanceof Function);
|
101
|
+
|
102
|
+
return (
|
103
|
+
<Fragment>
|
104
|
+
<tr onClick={ev => onSelect(row, ev)}>
|
105
|
+
{columns.map(column => <DataTableCell row={row} column={column} cell={row[column.id]} editable={editable}/>)}
|
106
|
+
{row.info ? <Icon icon={infoIcon} clickable action={() => toggleInfo(!isInfoOpen)} /> : null}
|
107
|
+
</tr>
|
108
|
+
{row.info && isInfoOpen ? (
|
109
|
+
<tr className="table-row-info">
|
110
|
+
{isFunction(row.info) ? row.info() : row.info}
|
111
|
+
</tr>
|
112
|
+
) : null}
|
113
|
+
</Fragment>
|
114
|
+
)
|
115
|
+
}
|
116
|
+
|
117
|
+
/**
|
118
|
+
* DataTable Cell
|
119
|
+
*/
|
120
|
+
const DataTableCell = ({ row, column, cell, editable }) => {
|
121
|
+
|
122
|
+
const render = (type) => {
|
123
|
+
const { id, disabled = false, min, max, onChange, options } = column
|
124
|
+
if (editable && onChange) {
|
125
|
+
switch (type) {
|
126
|
+
case "ICON": return <Icon icon={cell} />
|
127
|
+
case "BOOLEAN": return <CheckBox id={id} value={cell} onChange={(id, value) => onChange(row.id, id, value)} disabled={disabled} />
|
128
|
+
case "Boolean": return <CheckBox id={id} value={cell} onChange={(id, value) => onChange(row.id, id, value)} disabled={disabled} />
|
129
|
+
case "SELECTION": return <DropDown id={id} value={cell} placeholder="--Select--" options={options} onChange={(id, value) => onChange(row.id, id, value)} />
|
130
|
+
case "CHECK": return <CheckBox id={id} value={cell} onChange={(id, value) => onChange(row.id, id, value)} disabled={row.disabled} />
|
131
|
+
case "CHECKABLE": return cell && cell.value ? <CheckBox id={id} value={cell.checked || false} label={cell.value} onChange={(id, checked) => onChange(row.id, id, cell.value, checked, cell)} /> : ''
|
132
|
+
case "TEXTFIELD": return <TextField id={id} value={cell} onChange={(id, value) => onChange(row.id, id, value)} />
|
133
|
+
case "String": return <StringCellEditor id={id} value={cell} options={options} onChange={(id, value) => onChange(row.id, id, value)} />
|
134
|
+
case "Number": return <TextField id={id} type="number" value={cell} min={min} max={max} onChange={(id, value) => onChange(row.id, id, value)} />
|
135
|
+
default: return cell
|
136
|
+
}
|
137
|
+
} else {
|
138
|
+
switch (type) {
|
139
|
+
case "ICON": return <Icon icon={cell} />
|
140
|
+
case "Boolean": return <BooleanCellViewer id={id} value={cell} />
|
141
|
+
case "String": return <StringCellViewer id={id} value={cell} options={options} />
|
142
|
+
default: return cell
|
143
|
+
}
|
144
|
+
}
|
145
|
+
}
|
146
|
+
|
147
|
+
return (
|
148
|
+
<td className={column.id}>{render(column.type)}</td>
|
149
|
+
)
|
150
|
+
}
|
151
|
+
|
152
|
+
/**
|
153
|
+
* Boolean Cell Viewer
|
154
|
+
*/
|
155
|
+
const BooleanCellViewer = ({ id, value = false }) => {
|
156
|
+
const icon = value === true ? "check_box" : "check_box_outline_blank"
|
157
|
+
return <Icon icon={icon} />
|
158
|
+
}
|
159
|
+
|
160
|
+
/**
|
161
|
+
* String Cell Viewer
|
162
|
+
*/
|
163
|
+
const StringCellViewer = ({ id, value, options }) => {
|
164
|
+
const option = options ? options.find( o => o.value === value) : null
|
165
|
+
const text = option ? option.label : value
|
166
|
+
return (<div className="field-editor string-editor">{text}</div>)
|
167
|
+
}
|
168
|
+
|
169
|
+
/**
|
170
|
+
* String Cell Editor
|
171
|
+
*/
|
172
|
+
export const StringCellEditor = ({ id, value = '', options, onChange }) => {
|
173
|
+
|
174
|
+
function change(id, value) {
|
175
|
+
if (onChange) onChange(id, value)
|
176
|
+
}
|
177
|
+
|
178
|
+
return (
|
179
|
+
<div className='field-editor string-editor'>
|
180
|
+
{options ?
|
181
|
+
<DropDown outlined id={id} value={value} onChange={change} options={options} />
|
182
|
+
: <TextField outlined id={id} value={value} onChange={change} />
|
183
|
+
}
|
184
|
+
</div>
|
185
|
+
)
|
186
|
+
}
|
package/src/html/text.js
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
import { useContext } from "react"
|
2
|
+
import { SiteContext } from "../site/siteContext"
|
3
|
+
|
4
|
+
/**
|
5
|
+
* Text
|
6
|
+
*/
|
7
|
+
export const Text = ({ children }) => {
|
8
|
+
|
9
|
+
const site = useContext(SiteContext)
|
10
|
+
|
11
|
+
if (site) {
|
12
|
+
const { lang, dictionary = {}} = site
|
13
|
+
const term = dictionary[children]
|
14
|
+
const text = term ? term[lang] : children
|
15
|
+
return text ? <span>{text}</span> : ''
|
16
|
+
}
|
17
|
+
|
18
|
+
return children ? <span>{children}</span> : ''
|
19
|
+
|
20
|
+
}
|