goblin-magic 1.0.3
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/.editorconfig +9 -0
- package/.zou-flow +2 -0
- package/eslint.config.js +65 -0
- package/magicNavigation.js +7 -0
- package/package.json +45 -0
- package/widgets/dialog/widget.js +78 -0
- package/widgets/element-helpers/element-has-direct-text.js +9 -0
- package/widgets/element-helpers/is-empty-area-element.js +17 -0
- package/widgets/element-helpers/is-flat-element.js +52 -0
- package/widgets/get-modifiers/get-modifiers.js +34 -0
- package/widgets/input-group/styles.js +74 -0
- package/widgets/input-group/widget.js +24 -0
- package/widgets/magic-action/styles.js +45 -0
- package/widgets/magic-action/widget.js +44 -0
- package/widgets/magic-background/bg-alps.jpg +0 -0
- package/widgets/magic-background/bg-fur.png +0 -0
- package/widgets/magic-background/bg-milkyway.png +0 -0
- package/widgets/magic-background/bg-space.jpg +0 -0
- package/widgets/magic-background/bg-synth.jpg +0 -0
- package/widgets/magic-background/bg-white.png +0 -0
- package/widgets/magic-background/styles.js +81 -0
- package/widgets/magic-background/widget.js +20 -0
- package/widgets/magic-box/styles.js +10 -0
- package/widgets/magic-box/widget.js +28 -0
- package/widgets/magic-box-old/styles.js +111 -0
- package/widgets/magic-box-old/widget.js +30 -0
- package/widgets/magic-button/styles.js +156 -0
- package/widgets/magic-button/widget.js +89 -0
- package/widgets/magic-checkbox/styles.js +116 -0
- package/widgets/magic-checkbox/widget.js +68 -0
- package/widgets/magic-color-field/styles.js +22 -0
- package/widgets/magic-color-field/widget.js +68 -0
- package/widgets/magic-date-field/styles.js +9 -0
- package/widgets/magic-date-field/widget.js +145 -0
- package/widgets/magic-datetime-field/styles.js +11 -0
- package/widgets/magic-datetime-field/widget.js +95 -0
- package/widgets/magic-dialog/styles.js +39 -0
- package/widgets/magic-dialog/widget.js +116 -0
- package/widgets/magic-div/styles.js +22 -0
- package/widgets/magic-div/widget.js +20 -0
- package/widgets/magic-emoji/styles.js +14 -0
- package/widgets/magic-emoji/widget.js +33 -0
- package/widgets/magic-emoji-picker/styles.js +21 -0
- package/widgets/magic-emoji-picker/widget.js +44 -0
- package/widgets/magic-inplace-input/styles.js +55 -0
- package/widgets/magic-inplace-input/widget.js +26 -0
- package/widgets/magic-input/styles.js +50 -0
- package/widgets/magic-input/widget.js +397 -0
- package/widgets/magic-label/styles.js +20 -0
- package/widgets/magic-label/widget.js +24 -0
- package/widgets/magic-navigation/service.js +1306 -0
- package/widgets/magic-navigation/styles.js +103 -0
- package/widgets/magic-navigation/view-context.js +15 -0
- package/widgets/magic-navigation/widget.js +540 -0
- package/widgets/magic-number-field/styles.js +10 -0
- package/widgets/magic-number-field/widget.js +103 -0
- package/widgets/magic-panel/styles.js +61 -0
- package/widgets/magic-panel/widget.js +63 -0
- package/widgets/magic-radio/styles.js +93 -0
- package/widgets/magic-radio/widget.js +74 -0
- package/widgets/magic-scroll/styles.js +22 -0
- package/widgets/magic-scroll/widget.js +20 -0
- package/widgets/magic-select/styles.js +16 -0
- package/widgets/magic-select/widget.js +134 -0
- package/widgets/magic-table/reducer.js +63 -0
- package/widgets/magic-table/styles.js +170 -0
- package/widgets/magic-table/widget.js +627 -0
- package/widgets/magic-tag/styles.js +32 -0
- package/widgets/magic-tag/widget.js +32 -0
- package/widgets/magic-text-field/styles.js +58 -0
- package/widgets/magic-text-field/widget.js +66 -0
- package/widgets/magic-time-field/styles.js +8 -0
- package/widgets/magic-time-field/widget.js +142 -0
- package/widgets/magic-timer/styles.js +30 -0
- package/widgets/magic-timer/widget.js +162 -0
- package/widgets/magic-zen/styles.js +61 -0
- package/widgets/magic-zen/widget.js +42 -0
- package/widgets/main-tabs/styles.js +106 -0
- package/widgets/main-tabs/widget.js +23 -0
- package/widgets/menu/styles.js +156 -0
- package/widgets/menu/test-menu.html +154 -0
- package/widgets/menu/widget.js +575 -0
- package/widgets/movable/widget.js +80 -0
- package/widgets/splitter/styles.js +57 -0
- package/widgets/splitter/widget.js +40 -0
- package/widgets/tab-layout/styles.js +31 -0
- package/widgets/tab-layout/widget.js +59 -0
- package/widgets/with-computed-size/widget.js +52 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Widget from 'goblin-laboratory/widgets/widget';
|
|
3
|
+
import * as styles from './styles.js';
|
|
4
|
+
import withC from 'goblin-laboratory/widgets/connect-helpers/with-c';
|
|
5
|
+
import MagicTextField from '../magic-text-field/widget.js';
|
|
6
|
+
|
|
7
|
+
import {date as DateConverters} from 'xcraft-core-converters';
|
|
8
|
+
import InputGroup from '../input-group/widget.js';
|
|
9
|
+
import MagicButton from '../magic-button/widget.js';
|
|
10
|
+
import Icon from '@mdi/react';
|
|
11
|
+
import {mdiCalendarMonth} from '@mdi/js';
|
|
12
|
+
|
|
13
|
+
class MagicDateFieldNC extends Widget {
|
|
14
|
+
constructor() {
|
|
15
|
+
super(...arguments);
|
|
16
|
+
this.styles = styles;
|
|
17
|
+
this.inputRef = this.props.inputRef || React.createRef();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get input() {
|
|
21
|
+
return this.inputRef.current;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static parseEdited(value) {
|
|
25
|
+
if (!value) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const edited = DateConverters.parseEdited(value);
|
|
29
|
+
// if (edited.error) {
|
|
30
|
+
// return null;
|
|
31
|
+
// }
|
|
32
|
+
return edited.value;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
parse = (value) => {
|
|
36
|
+
const newValue = MagicDateFieldNC.parseEdited(value);
|
|
37
|
+
if (this.props.required && !newValue) {
|
|
38
|
+
return DateConverters.getNowCanonical();
|
|
39
|
+
}
|
|
40
|
+
return newValue;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
format = (value) => {
|
|
44
|
+
if (!value) {
|
|
45
|
+
return '';
|
|
46
|
+
}
|
|
47
|
+
return DateConverters.getDisplayed(value.split('T', 1)[0]);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
getPositionKind(position) {
|
|
51
|
+
// Value: d d . m m . y y y y
|
|
52
|
+
// Pos: 0 1 2 3 4 5 6 7 8 9 10
|
|
53
|
+
// Kind: 0 | 1 | 2
|
|
54
|
+
if (position <= 2) {
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
if (position <= 5) {
|
|
58
|
+
return 1;
|
|
59
|
+
}
|
|
60
|
+
return 2;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
getSelection(positionKind, max) {
|
|
64
|
+
// Kind: 0 | 1 | 2
|
|
65
|
+
// Pos: 0 1 2 3 4 5 6 7 8 9 10
|
|
66
|
+
// Value: d d . m m . y y y y
|
|
67
|
+
if (positionKind === 0) {
|
|
68
|
+
return [0, 2];
|
|
69
|
+
}
|
|
70
|
+
if (positionKind === 1) {
|
|
71
|
+
return [3, 5];
|
|
72
|
+
}
|
|
73
|
+
return [6, max];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
handleKeyDown = (event) => {
|
|
77
|
+
this.props.onKeyDown?.(event);
|
|
78
|
+
|
|
79
|
+
if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
|
|
80
|
+
const {value, selectionStart, selectionEnd} = event.target;
|
|
81
|
+
const cursorPosition =
|
|
82
|
+
selectionStart < 2
|
|
83
|
+
? selectionStart
|
|
84
|
+
: (selectionStart + selectionEnd) / 2;
|
|
85
|
+
const step = event.shiftKey && cursorPosition <= 2 ? 7 : 1;
|
|
86
|
+
const direction = event.key === 'ArrowUp' ? 1 : -1;
|
|
87
|
+
const result = DateConverters.incEdited(
|
|
88
|
+
value,
|
|
89
|
+
cursorPosition,
|
|
90
|
+
direction,
|
|
91
|
+
step
|
|
92
|
+
);
|
|
93
|
+
if (result.edited) {
|
|
94
|
+
this.input.changeAndSelect(
|
|
95
|
+
result.edited,
|
|
96
|
+
result.selectionStart,
|
|
97
|
+
result.selectionEnd
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
event.preventDefault();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (event.ctrlKey && event.key === 'ArrowRight') {
|
|
104
|
+
const {value, selectionEnd} = event.target;
|
|
105
|
+
const positionKind = this.getPositionKind(selectionEnd);
|
|
106
|
+
const newKind = positionKind < 2 ? positionKind + 1 : 2;
|
|
107
|
+
this.input.htmlInput.setSelectionRange(
|
|
108
|
+
...this.getSelection(newKind, value.length)
|
|
109
|
+
);
|
|
110
|
+
event.preventDefault();
|
|
111
|
+
}
|
|
112
|
+
if (event.ctrlKey && event.key === 'ArrowLeft') {
|
|
113
|
+
const {value, selectionStart} = event.target;
|
|
114
|
+
const positionKind = this.getPositionKind(selectionStart);
|
|
115
|
+
const newKind = positionKind > 0 ? positionKind - 1 : 0;
|
|
116
|
+
this.input.htmlInput.setSelectionRange(
|
|
117
|
+
...this.getSelection(newKind, value.length)
|
|
118
|
+
);
|
|
119
|
+
event.preventDefault();
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
render() {
|
|
124
|
+
const {className = '', required, ...props} = this.props;
|
|
125
|
+
return (
|
|
126
|
+
<InputGroup>
|
|
127
|
+
<MagicTextField
|
|
128
|
+
inputRef={this.inputRef}
|
|
129
|
+
format={this.format}
|
|
130
|
+
parse={this.parse}
|
|
131
|
+
{...props}
|
|
132
|
+
onKeyDown={this.handleKeyDown}
|
|
133
|
+
className={this.styles.classNames.dateField + ' ' + className}
|
|
134
|
+
/>
|
|
135
|
+
<MagicButton disabled>
|
|
136
|
+
<Icon path={mdiCalendarMonth} size={0.8} />
|
|
137
|
+
</MagicButton>
|
|
138
|
+
</InputGroup>
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const MagicDateField = withC(MagicDateFieldNC, {value: 'onChange'});
|
|
143
|
+
MagicDateField.displayName = 'MagicDateField';
|
|
144
|
+
|
|
145
|
+
export default MagicDateField;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Widget from 'goblin-laboratory/widgets/widget';
|
|
3
|
+
import * as styles from './styles.js';
|
|
4
|
+
import withC from 'goblin-laboratory/widgets/connect-helpers/with-c';
|
|
5
|
+
import MagicDateField from '../magic-date-field/widget.js';
|
|
6
|
+
import MagicTimeField from '../magic-time-field/widget.js';
|
|
7
|
+
import {
|
|
8
|
+
nowZonedDateTimeISO,
|
|
9
|
+
parseZonedDateTime,
|
|
10
|
+
zonedDateTimeFromParts,
|
|
11
|
+
} from 'xcraft-core-utils/lib/calendar.js';
|
|
12
|
+
|
|
13
|
+
class MagicDatetimeFieldNC extends Widget {
|
|
14
|
+
constructor() {
|
|
15
|
+
super(...arguments);
|
|
16
|
+
this.styles = styles;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
changeDate = (date) => {
|
|
20
|
+
const {value} = this.props;
|
|
21
|
+
let newDate;
|
|
22
|
+
if (date && value && value.includes('T')) {
|
|
23
|
+
const afterDate = value.slice(value.indexOf('T') + 1);
|
|
24
|
+
newDate = `${date}T${afterDate}`;
|
|
25
|
+
} else {
|
|
26
|
+
newDate = date;
|
|
27
|
+
}
|
|
28
|
+
this.props.onChange?.(newDate);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
changeTime = (time) => {
|
|
32
|
+
const {value, initialDate} = this.props;
|
|
33
|
+
let newDate;
|
|
34
|
+
if (value) {
|
|
35
|
+
const current = parseZonedDateTime(value);
|
|
36
|
+
if (time) {
|
|
37
|
+
const timezone = current.time
|
|
38
|
+
? current.timezone
|
|
39
|
+
: Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
40
|
+
newDate = zonedDateTimeFromParts({...current, time, timezone});
|
|
41
|
+
} else {
|
|
42
|
+
newDate = current.date;
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
if (time) {
|
|
46
|
+
const initial = parseZonedDateTime(
|
|
47
|
+
initialDate || nowZonedDateTimeISO()
|
|
48
|
+
);
|
|
49
|
+
const timezone = initial.time
|
|
50
|
+
? initial.timezone
|
|
51
|
+
: Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
52
|
+
newDate = zonedDateTimeFromParts({
|
|
53
|
+
...initial,
|
|
54
|
+
time,
|
|
55
|
+
timezone,
|
|
56
|
+
});
|
|
57
|
+
} else {
|
|
58
|
+
newDate = null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
this.props.onChange?.(newDate);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
render() {
|
|
65
|
+
const {
|
|
66
|
+
value,
|
|
67
|
+
onChange,
|
|
68
|
+
requiredDate,
|
|
69
|
+
requiredTime,
|
|
70
|
+
dispatch,
|
|
71
|
+
...props
|
|
72
|
+
} = this.props;
|
|
73
|
+
const {date, time} = value ? parseZonedDateTime(value) : {};
|
|
74
|
+
return (
|
|
75
|
+
<div className={this.styles.classNames.datetimeContainer}>
|
|
76
|
+
<MagicDateField
|
|
77
|
+
{...props}
|
|
78
|
+
value={date}
|
|
79
|
+
onChange={this.changeDate}
|
|
80
|
+
required={requiredDate || requiredTime}
|
|
81
|
+
/>
|
|
82
|
+
<MagicTimeField
|
|
83
|
+
{...props}
|
|
84
|
+
value={time}
|
|
85
|
+
onChange={this.changeTime}
|
|
86
|
+
required={requiredTime}
|
|
87
|
+
/>
|
|
88
|
+
</div>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const MagicDatetimeField = withC(MagicDatetimeFieldNC, {value: 'onChange'});
|
|
93
|
+
MagicDatetimeField.displayName = 'MagicDatetimeField';
|
|
94
|
+
|
|
95
|
+
export default MagicDatetimeField;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export default function styles() {
|
|
2
|
+
const dialog = {
|
|
3
|
+
'border': 'none',
|
|
4
|
+
'backgroundColor': 'transparent',
|
|
5
|
+
'padding': '0',
|
|
6
|
+
'maxHeight': '100%',
|
|
7
|
+
'position': 'fixed',
|
|
8
|
+
'top': '0',
|
|
9
|
+
'left': '0',
|
|
10
|
+
'right': '0',
|
|
11
|
+
'bottom': '0',
|
|
12
|
+
'margin': 'auto',
|
|
13
|
+
'overflow': 'visible',
|
|
14
|
+
|
|
15
|
+
'&::backdrop': {
|
|
16
|
+
backgroundColor: 'rgba(0,0,0,0.3)',
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
'&[data-modal=false]': {
|
|
20
|
+
boxShadow:
|
|
21
|
+
'rgba(0, 0, 0, 0.2) 0px 4px 120px, rgba(0, 0, 0, 0.1) 0px 4px 80px',
|
|
22
|
+
borderRadius: '8px',
|
|
23
|
+
// '&:not(:focus-within)': {
|
|
24
|
+
// 'boxShadow': 'rgba(0, 0, 0, 0.2) 0px 4px 120px',
|
|
25
|
+
// '& :not(div)': {
|
|
26
|
+
// opacity: 0.7,
|
|
27
|
+
// },
|
|
28
|
+
// },
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
'& > *': {
|
|
32
|
+
maxHeight: '95vh',
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
dialog,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Widget from 'goblin-laboratory/widgets/widget';
|
|
3
|
+
import * as styles from './styles.js';
|
|
4
|
+
import Dialog from '../dialog/widget.js';
|
|
5
|
+
import Movable from '../movable/widget.js';
|
|
6
|
+
import isEmptyAreaElement from '../element-helpers/is-empty-area-element.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @param {PointerEvent} event1
|
|
10
|
+
* @param {PointerEvent} event2
|
|
11
|
+
* @returns {number}
|
|
12
|
+
*/
|
|
13
|
+
function eventDistance(event1, event2) {
|
|
14
|
+
return Math.sqrt(
|
|
15
|
+
Math.pow(event2.clientX - event1.clientX, 2) +
|
|
16
|
+
Math.pow(event2.clientY - event1.clientY, 2)
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
class MagicDialog extends Widget {
|
|
21
|
+
constructor() {
|
|
22
|
+
super(...arguments);
|
|
23
|
+
this.styles = styles;
|
|
24
|
+
/** @type {React.RefObject<Dialog>} */
|
|
25
|
+
this.dialog = React.createRef();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
componentDidMount() {
|
|
29
|
+
this.updateOutsideClickHandler();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
componentDidUpdate() {
|
|
33
|
+
this.updateOutsideClickHandler();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
componentWillUnmount() {
|
|
37
|
+
this.removeOutsideClickHandler();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
updateOutsideClickHandler() {
|
|
41
|
+
if (!this.props.modal && this.props.onClose && this.props.open) {
|
|
42
|
+
this.addOutsideClickHandler();
|
|
43
|
+
} else {
|
|
44
|
+
this.removeOutsideClickHandler();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
addOutsideClickHandler() {
|
|
49
|
+
window.addEventListener('pointerdown', this.handlePointerDown);
|
|
50
|
+
window.addEventListener('pointerup', this.handlePointerUp);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
removeOutsideClickHandler() {
|
|
54
|
+
window.removeEventListener('pointerdown', this.handlePointerDown);
|
|
55
|
+
window.removeEventListener('pointerup', this.handlePointerUp);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
handlePointerDown = (event) => {
|
|
59
|
+
const {target} = event;
|
|
60
|
+
const dialog = this.dialog.current?.dialog.current;
|
|
61
|
+
if (dialog && !dialog.contains(target)) {
|
|
62
|
+
if (isEmptyAreaElement(target)) {
|
|
63
|
+
this.downEvent = event;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
handlePointerUp = (event) => {
|
|
70
|
+
if (this.downEvent) {
|
|
71
|
+
const distance = eventDistance(event, this.downEvent);
|
|
72
|
+
this.downEvent = null;
|
|
73
|
+
if (distance < 8) {
|
|
74
|
+
this.dialog.current.close();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
handleKeyDown = (event) => {
|
|
80
|
+
this.props.onKeyDown?.(event);
|
|
81
|
+
if (event.defaultPrevented) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (event.key === 'Escape') {
|
|
85
|
+
this.dialog.current.close();
|
|
86
|
+
event.stopPropagation();
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
render() {
|
|
91
|
+
const {className = '', ...props} = this.props;
|
|
92
|
+
return (
|
|
93
|
+
<Movable>
|
|
94
|
+
{(moveableProps) => (
|
|
95
|
+
<Dialog
|
|
96
|
+
{...props}
|
|
97
|
+
{...moveableProps}
|
|
98
|
+
onKeyDown={
|
|
99
|
+
!this.props.modal && this.props.onClose
|
|
100
|
+
? this.handleKeyDown
|
|
101
|
+
: undefined
|
|
102
|
+
}
|
|
103
|
+
ref={this.dialog}
|
|
104
|
+
className={this.styles.classNames.dialog + ' ' + className}
|
|
105
|
+
open={this.props.open}
|
|
106
|
+
modal={this.props.modal}
|
|
107
|
+
data-modal={this.props.modal || false}
|
|
108
|
+
onClose={this.props.onClose}
|
|
109
|
+
/>
|
|
110
|
+
)}
|
|
111
|
+
</Movable>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export default MagicDialog;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export default function styles() {
|
|
2
|
+
const div = {
|
|
3
|
+
'--border-radius': '8px',
|
|
4
|
+
// 'color': 'white',
|
|
5
|
+
'background': 'rgba(248, 241, 248, 0.1)',
|
|
6
|
+
'borderRadius': '8px',
|
|
7
|
+
'boxShadow': '0 4px 30px rgba(0, 0, 0, 0.1)',
|
|
8
|
+
'backdropFilter': 'blur(10px) saturate(100%)',
|
|
9
|
+
'border':
|
|
10
|
+
'1px solid color-mix(in srgb, var(--text-color), transparent 78%)',
|
|
11
|
+
|
|
12
|
+
'@media (prefers-color-scheme: light)': {
|
|
13
|
+
background: 'rgba(248, 241, 248, 0.85)',
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
div,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/******************************************************************************/
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Widget from 'goblin-laboratory/widgets/widget';
|
|
3
|
+
import * as styles from './styles.js';
|
|
4
|
+
|
|
5
|
+
export default class MagicDiv extends Widget {
|
|
6
|
+
constructor() {
|
|
7
|
+
super(...arguments);
|
|
8
|
+
this.styles = styles;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
render() {
|
|
12
|
+
const {className = '', ...props} = this.props;
|
|
13
|
+
return (
|
|
14
|
+
<div
|
|
15
|
+
className={this.styles.classNames.div + ' ' + className}
|
|
16
|
+
{...props}
|
|
17
|
+
/>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Widget from 'goblin-laboratory/widgets/widget';
|
|
3
|
+
import * as styles from './styles.js';
|
|
4
|
+
import Menu from '../menu/widget.js';
|
|
5
|
+
import withC from 'goblin-laboratory/widgets/connect-helpers/with-c.js';
|
|
6
|
+
import MagicEmojiPickerNC from '../magic-emoji-picker/widget.js';
|
|
7
|
+
|
|
8
|
+
class MagicEmojiNC extends Widget {
|
|
9
|
+
constructor() {
|
|
10
|
+
super(...arguments);
|
|
11
|
+
this.styles = styles;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
render() {
|
|
15
|
+
const {onChange, ...props} = this.props;
|
|
16
|
+
const onEmojiSelect = (emoji) => onChange(emoji?.native);
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<Menu>
|
|
20
|
+
<Menu.Button className={this.styles.classNames.button}>
|
|
21
|
+
{props.value}
|
|
22
|
+
</Menu.Button>
|
|
23
|
+
<Menu.Content className={this.styles.classNames.content}>
|
|
24
|
+
<MagicEmojiPickerNC onEmojiSelect={onEmojiSelect} {...props} />
|
|
25
|
+
</Menu.Content>
|
|
26
|
+
</Menu>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const MagicEmoji = withC(MagicEmojiNC, {value: 'onChange'});
|
|
32
|
+
|
|
33
|
+
export default MagicEmoji;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export default function styles(theme) {
|
|
2
|
+
const picker = {
|
|
3
|
+
'& div > em-emoji-picker': {
|
|
4
|
+
'--font-family': theme.typo.font,
|
|
5
|
+
'--border-radius': '4px',
|
|
6
|
+
|
|
7
|
+
'--rgb-background': '25, 45, 70, 1',
|
|
8
|
+
'--rgb-accent': '255, 255, 255',
|
|
9
|
+
'--shadow': '0 0 1px 1px rgba(255, 255, 255, 0.4)',
|
|
10
|
+
'@media (prefers-color-scheme: light)': {
|
|
11
|
+
'--rgb-background': '237, 234, 242, 1',
|
|
12
|
+
'--rgb-accent': '0, 0, 0',
|
|
13
|
+
'--shadow': '0 0 1px 1px rgba(0, 0, 0, 0.4)',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
picker,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Widget from 'goblin-laboratory/widgets/widget';
|
|
3
|
+
import * as styles from './styles.js';
|
|
4
|
+
import data from '@emoji-mart/data';
|
|
5
|
+
import Picker from '@emoji-mart/react';
|
|
6
|
+
|
|
7
|
+
class MagicEmojiPickerNC extends Widget {
|
|
8
|
+
constructor() {
|
|
9
|
+
super(...arguments);
|
|
10
|
+
this.styles = styles;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
render() {
|
|
14
|
+
const {className = '', ...props} = this.props;
|
|
15
|
+
|
|
16
|
+
let theme = 'light';
|
|
17
|
+
let emojiButtonColors = 'rgba(0, 0, 0, 0.1)';
|
|
18
|
+
if (
|
|
19
|
+
window.matchMedia &&
|
|
20
|
+
window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
21
|
+
) {
|
|
22
|
+
theme = 'dark';
|
|
23
|
+
emojiButtonColors = 'rgba(255, 255, 255, 0.2)';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<div className={this.styles.classNames.picker + ' ' + className}>
|
|
28
|
+
<Picker
|
|
29
|
+
data={data}
|
|
30
|
+
locale="fr"
|
|
31
|
+
set="native"
|
|
32
|
+
theme={theme}
|
|
33
|
+
previewPosition="none"
|
|
34
|
+
autoFocus={true}
|
|
35
|
+
emojiButtonRadius="4px"
|
|
36
|
+
emojiButtonColors={[emojiButtonColors]}
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export default MagicEmojiPickerNC;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/******************************************************************************/
|
|
2
|
+
|
|
3
|
+
export default function styles() {
|
|
4
|
+
const disabledStyle = {
|
|
5
|
+
':hover': {
|
|
6
|
+
outline: 'none',
|
|
7
|
+
backgroundColor: 'transparent',
|
|
8
|
+
},
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const inplaceInput = {
|
|
12
|
+
'display': 'flex',
|
|
13
|
+
'width': '100%',
|
|
14
|
+
'minHeight': '1em', // For contenteditable
|
|
15
|
+
'backgroundColor': 'transparent',
|
|
16
|
+
'borderRadius': '5px',
|
|
17
|
+
'border': 'none',
|
|
18
|
+
'padding': '0',
|
|
19
|
+
'marginTop': '0',
|
|
20
|
+
'fontSize': 'inherit',
|
|
21
|
+
'color': 'inherit',
|
|
22
|
+
'resize': 'vertical',
|
|
23
|
+
'::placeholder': {
|
|
24
|
+
color: 'color-mix(in srgb, var(--text-color), transparent 75%)',
|
|
25
|
+
fontWeight: 'bold',
|
|
26
|
+
},
|
|
27
|
+
':hover': {
|
|
28
|
+
outline:
|
|
29
|
+
'1px solid color-mix(in srgb, var(--text-color), transparent 70%)',
|
|
30
|
+
backgroundColor:
|
|
31
|
+
'color-mix(in srgb, var(--field-background-color), transparent 20%)',
|
|
32
|
+
marginLeft: '-0.3em',
|
|
33
|
+
paddingLeft: '0.3em',
|
|
34
|
+
},
|
|
35
|
+
':focus': {
|
|
36
|
+
outline:
|
|
37
|
+
'1px solid color-mix(in srgb, var(--text-color), transparent 70%)',
|
|
38
|
+
backgroundColor:
|
|
39
|
+
'color-mix(in srgb, var(--field-background-color), transparent 20%)',
|
|
40
|
+
marginLeft: '-0.3em',
|
|
41
|
+
paddingLeft: '0.3em',
|
|
42
|
+
},
|
|
43
|
+
'&::selection': {
|
|
44
|
+
backgroundColor: 'rgba(0,170,255,0.55)',
|
|
45
|
+
},
|
|
46
|
+
'&[data-disabled=true]': disabledStyle,
|
|
47
|
+
'&:disabled': disabledStyle,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
inplaceInput,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/******************************************************************************/
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Widget from 'goblin-laboratory/widgets/widget';
|
|
3
|
+
import * as styles from './styles.js';
|
|
4
|
+
import withC from 'goblin-laboratory/widgets/connect-helpers/with-c';
|
|
5
|
+
import MagicInput from '../magic-input/widget.js';
|
|
6
|
+
|
|
7
|
+
class MagicInplaceInputNC extends Widget {
|
|
8
|
+
constructor() {
|
|
9
|
+
super(...arguments);
|
|
10
|
+
this.styles = styles;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
render() {
|
|
14
|
+
const {className = '', ...props} = this.props;
|
|
15
|
+
return (
|
|
16
|
+
<MagicInput
|
|
17
|
+
{...props}
|
|
18
|
+
className={this.styles.classNames.inplaceInput + ' ' + className}
|
|
19
|
+
/>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const MagicInplaceInput = withC(MagicInplaceInputNC, {value: 'onChange'});
|
|
25
|
+
MagicInplaceInput.displayName = 'MagicInplaceInput';
|
|
26
|
+
export default MagicInplaceInput;
|