@_unit/unit 1.0.7 → 1.0.8
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/build/web.js +1201 -0
- package/package.json +1 -1
- package/public/_worker.js +294 -103
- package/public/_worker.js.map +4 -4
- package/public/app/html/index.html +74 -0
- package/public/build.json +1 -1
- package/public/index.js +297 -103
- package/public/index.js.map +4 -4
- package/src/API.ts +1 -0
- package/src/Class/Graph/index.ts +14 -1
- package/src/Class/Graph/interface.ts +7 -0
- package/src/Class/Graph/moveSubgraph.ts +25 -25
- package/src/client/component.ts +18 -7
- package/src/client/extractStyle.ts +161 -0
- package/src/client/isTextLike.ts +16 -0
- package/src/client/platform/web/api/document.ts +3 -0
- package/src/debug/graph/watchGraphInternal.ts +2 -0
- package/src/debug/graph/watchGraphSetUnitPinSetIdEvent.ts +39 -0
- package/src/docs/concept/README.md +8 -2
- package/src/interface.ts +1 -0
- package/src/script/build/client.ts +4 -2
- package/src/spec/Lazy.ts +10 -2
- package/src/spec/util.ts +4 -0
- package/src/system/_classes.ts +2 -2
- package/src/system/_ids.ts +1 -1
- package/src/system/_specs.ts +1 -1
- package/src/system/core/unit/MergeInput/spec.json +1 -1
- package/src/system/globalComponent.ts +29 -0
- package/src/system/platform/api/canvas/AddRect/index.ts +2 -6
- package/src/system/platform/api/canvas/ToBlob/index.ts +5 -1
- package/src/system/platform/api/media/MediaRecorder/index.ts +6 -0
- package/src/system/platform/api/media/RequestPictureInPicture/index.ts +10 -5
- package/src/system/platform/api/media/image/{BlobToBitmap → ImageToBitmap}/index.ts +10 -10
- package/src/system/platform/api/media/image/{BlobToBitmap → ImageToBitmap}/spec.json +9 -18
- package/src/system/platform/component/Iframe/Component.ts +2 -0
- package/src/system/platform/component/Inherit/Component.ts +0 -18
- package/src/system/platform/component/app/Editor/Component.ts +214 -77
- package/src/system/platform/component/app/GUI/Component.ts +19 -4
- package/src/system/platform/component/canvas/Canvas/index.ts +2 -2
- package/src/system/platform/component/media/Video/index.ts +15 -2
- package/src/system/platform/core/SetCurrentTime/spec.json +1 -1
- package/src/system/platform/core/SetScale/spec.json +1 -1
- package/src/system/platform/core/api/location/LocationQuery/spec.json +1 -1
- package/src/system/platform/core/asset/IconNames/spec.json +1 -1
- package/src/system/platform/core/canvas/DownloadBlob/spec.json +1 -1
- package/src/system/platform/core/component/Charcode/spec.json +1 -1
- package/src/system/platform/core/download/DownloadGraph/spec.json +1 -1
- package/src/system/platform/core/math/geometry/trigonometry/Hypotenuse/spec.json +1 -1
- package/src/system/platform/core/math/power/Pow2/spec.json +1 -1
- package/src/system/platform/core/string/RemoveNewLine/spec.json +1 -1
- package/src/test/system/core/MergeSort.ts +1 -1
- package/src/types/GraphSpec.ts +0 -1
- package/src/types/interface/B.ts +3 -1
- package/src/types/interface/G.ts +8 -0
- package/src/types/interface/async/$G.ts +3 -0
- package/src/types/interface/async/AsyncG.ts +10 -0
- package/public/metadata.mp4 +0 -0
package/src/API.ts
CHANGED
|
@@ -168,6 +168,7 @@ export type API = {
|
|
|
168
168
|
elementFromPoint(x: number, y: number): Element
|
|
169
169
|
getSelection(): Selection
|
|
170
170
|
createRange(): Range
|
|
171
|
+
exitPictureInPicture(): Promise<void>
|
|
171
172
|
MutationObserver: IMutationObserverConstructor
|
|
172
173
|
PositionObserver: IPositionObserverCostructor
|
|
173
174
|
ResizeObserver: IResizeObserverConstructor
|
package/src/Class/Graph/index.ts
CHANGED
|
@@ -118,7 +118,6 @@ import { C, C_EE } from '../../types/interface/C'
|
|
|
118
118
|
import { ComponentEvents, Component_ } from '../../types/interface/Component'
|
|
119
119
|
import { G, G_EE, G_MoveSubgraphIntoArgs } from '../../types/interface/G'
|
|
120
120
|
import { U } from '../../types/interface/U'
|
|
121
|
-
import { weakMerge } from '../../types/weakMerge'
|
|
122
121
|
import { forEach, insert, remove } from '../../util/array'
|
|
123
122
|
import { callAll } from '../../util/call/callAll'
|
|
124
123
|
import {
|
|
@@ -4535,6 +4534,20 @@ export class Graph<I = any, O = any>
|
|
|
4535
4534
|
)
|
|
4536
4535
|
}
|
|
4537
4536
|
|
|
4537
|
+
setUnitPinSetId(
|
|
4538
|
+
unitId: string,
|
|
4539
|
+
type: IO,
|
|
4540
|
+
pinId: string,
|
|
4541
|
+
newPinId: string,
|
|
4542
|
+
emit: boolean = true
|
|
4543
|
+
): void {
|
|
4544
|
+
const unit = this.getUnit(unitId) as Graph
|
|
4545
|
+
|
|
4546
|
+
unit.setPinSetId(type, pinId, newPinId)
|
|
4547
|
+
|
|
4548
|
+
emit && this.emit('set_unit_pin_set_id', unitId, type, pinId, newPinId, [])
|
|
4549
|
+
}
|
|
4550
|
+
|
|
4538
4551
|
public setUnitPinConstant(
|
|
4539
4552
|
unitId: string,
|
|
4540
4553
|
type: IO,
|
|
@@ -198,6 +198,13 @@ export type GraphSetPinSetFunctionalData = {
|
|
|
198
198
|
functional: boolean
|
|
199
199
|
}
|
|
200
200
|
|
|
201
|
+
export type GraphSetUnitPinSetId = {
|
|
202
|
+
unitId: string
|
|
203
|
+
type: IO
|
|
204
|
+
pinId: string
|
|
205
|
+
nextPinId: string
|
|
206
|
+
}
|
|
207
|
+
|
|
201
208
|
export type GraphSetUnitPinConstant = {
|
|
202
209
|
unitId: string
|
|
203
210
|
type: IO
|
|
@@ -345,7 +345,7 @@ export function moveLinkPinInto(
|
|
|
345
345
|
ignoredUnit: Set<string> = new Set(),
|
|
346
346
|
reverse: boolean
|
|
347
347
|
): void {
|
|
348
|
-
if (ignoredUnit.has(unitId)) {
|
|
348
|
+
if (ignoredUnit.has(unitId) && graphId !== unitId) {
|
|
349
349
|
return
|
|
350
350
|
}
|
|
351
351
|
|
|
@@ -571,29 +571,29 @@ export function moveMerge(
|
|
|
571
571
|
|
|
572
572
|
const pickInput = !isInput && !ignoredUnit.has(unitId)
|
|
573
573
|
|
|
574
|
-
if ((pickInput && nextInput) || (!pickInput && nextOutput)) {
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
574
|
+
// if ((pickInput && nextInput) || (!pickInput && nextOutput)) {
|
|
575
|
+
const {
|
|
576
|
+
mergeId: nextMergeId,
|
|
577
|
+
pinId: nextPinId,
|
|
578
|
+
subPinSpec: nextSubPinSpec,
|
|
579
|
+
} = (pickInput ? nextInput : nextOutput) ?? {}
|
|
580
580
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
}
|
|
581
|
+
moveLinkPinInto(
|
|
582
|
+
source,
|
|
583
|
+
target,
|
|
584
|
+
graphId,
|
|
585
|
+
unitId,
|
|
586
|
+
type,
|
|
587
|
+
pinId,
|
|
588
|
+
data,
|
|
589
|
+
collapseMap,
|
|
590
|
+
nextMergeId,
|
|
591
|
+
nextPinId,
|
|
592
|
+
null,
|
|
593
|
+
ignoredUnit,
|
|
594
|
+
reverse
|
|
595
|
+
)
|
|
596
|
+
// }
|
|
597
597
|
}
|
|
598
598
|
|
|
599
599
|
forEachPinOnMerge(mergeSpec, moveMergePin)
|
|
@@ -981,7 +981,7 @@ export function movePlug(
|
|
|
981
981
|
subPinId
|
|
982
982
|
)
|
|
983
983
|
|
|
984
|
-
const nextSubPinSpec = pathOrDefault(
|
|
984
|
+
const nextSubPinSpec: GraphSubPinSpec = pathOrDefault(
|
|
985
985
|
nextPlugSpec,
|
|
986
986
|
[type, pinId, subPinId],
|
|
987
987
|
undefined
|
|
@@ -1004,7 +1004,7 @@ export function movePlug(
|
|
|
1004
1004
|
return
|
|
1005
1005
|
}
|
|
1006
1006
|
|
|
1007
|
-
const { nextPinId } = nextSubPinSpec
|
|
1007
|
+
const { pinId: nextPinId = subPinSpec.pinId } = nextSubPinSpec
|
|
1008
1008
|
|
|
1009
1009
|
let nextSubPinSpec_ = nextSubPinSpec
|
|
1010
1010
|
|
package/src/client/component.ts
CHANGED
|
@@ -1042,19 +1042,14 @@ export class Component<
|
|
|
1042
1042
|
return getRect(this.$element)
|
|
1043
1043
|
}
|
|
1044
1044
|
|
|
1045
|
-
getBoundingClientRect(): {
|
|
1046
|
-
x: number
|
|
1047
|
-
y: number
|
|
1048
|
-
width: number
|
|
1049
|
-
height: number
|
|
1050
|
-
} {
|
|
1045
|
+
getBoundingClientRect(): Rect {
|
|
1051
1046
|
if (this.$context) {
|
|
1052
1047
|
if (!this.$primitive) {
|
|
1053
1048
|
throw new Error('cannot calculate position of multiple elements.')
|
|
1054
1049
|
}
|
|
1055
1050
|
|
|
1056
1051
|
if (this.$element instanceof Text) {
|
|
1057
|
-
//
|
|
1052
|
+
// TODO
|
|
1058
1053
|
return
|
|
1059
1054
|
}
|
|
1060
1055
|
|
|
@@ -1958,6 +1953,22 @@ export class Component<
|
|
|
1958
1953
|
}
|
|
1959
1954
|
}
|
|
1960
1955
|
|
|
1956
|
+
async requestPictureInPicture(): Promise<void> {
|
|
1957
|
+
const {
|
|
1958
|
+
api: {
|
|
1959
|
+
document: { requestPictureInPictureWindow },
|
|
1960
|
+
},
|
|
1961
|
+
} = this.$system
|
|
1962
|
+
|
|
1963
|
+
const pipWindow = await requestPictureInPictureWindow()
|
|
1964
|
+
|
|
1965
|
+
// @ts-ignore
|
|
1966
|
+
if (pipWindow.document) {
|
|
1967
|
+
// @ts-ignore
|
|
1968
|
+
pipWindow.document.body.appendChild(this.$element)
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1961
1972
|
public insertParentChildAt(
|
|
1962
1973
|
component: Component,
|
|
1963
1974
|
slotName: string,
|
|
@@ -5,6 +5,7 @@ import { Component } from './component'
|
|
|
5
5
|
import { DEFAULT_FONT_SIZE } from './DEFAULT_FONT_SIZE'
|
|
6
6
|
import { extractTrait } from './extractTrait'
|
|
7
7
|
import { IOElement } from './IOElement'
|
|
8
|
+
import { isContentEditable } from './isTextLike'
|
|
8
9
|
import { LayoutNode } from './LayoutNode'
|
|
9
10
|
import { rawExtractStyle } from './rawExtractStyle'
|
|
10
11
|
import { expandSlot } from './reflectComponentBaseTrait'
|
|
@@ -307,3 +308,163 @@ export function _extractStyle(
|
|
|
307
308
|
|
|
308
309
|
return style
|
|
309
310
|
}
|
|
311
|
+
|
|
312
|
+
export function extractFromRawStyle(
|
|
313
|
+
root: Component,
|
|
314
|
+
component: Component,
|
|
315
|
+
element: IOElement,
|
|
316
|
+
style: Style,
|
|
317
|
+
fallbackTrait: LayoutNode,
|
|
318
|
+
measureText: (text: string, fontSize: number) => Size,
|
|
319
|
+
fitContent: boolean = false,
|
|
320
|
+
getLeafStyle: (
|
|
321
|
+
parent_trait: LayoutNode,
|
|
322
|
+
leaf_path: string[],
|
|
323
|
+
leaf_comp: Component
|
|
324
|
+
) => Style = (parent_trait, leaf_path, leaf_comp) =>
|
|
325
|
+
extractStyle(root, leaf_comp, parent_trait, measureText, fitContent)
|
|
326
|
+
): Style {
|
|
327
|
+
const fitWidth = style['width'] === 'fit-content'
|
|
328
|
+
const fitHeight = style['height'] === 'fit-content'
|
|
329
|
+
|
|
330
|
+
if (element instanceof Text) {
|
|
331
|
+
const fontSize = component.getFontSize()
|
|
332
|
+
|
|
333
|
+
const { textContent } = component.$element
|
|
334
|
+
|
|
335
|
+
const { width, height } = measureText(textContent, fontSize)
|
|
336
|
+
|
|
337
|
+
return {
|
|
338
|
+
width: `${width}px`,
|
|
339
|
+
height: `${height}px`,
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (isContentEditable(element) && (fitWidth || fitHeight)) {
|
|
344
|
+
const fontSize = component.getFontSize()
|
|
345
|
+
|
|
346
|
+
const { textContent } = component.$element
|
|
347
|
+
|
|
348
|
+
const { width, height } = measureText(textContent, fontSize)
|
|
349
|
+
|
|
350
|
+
if (fitWidth) {
|
|
351
|
+
style['width'] = `${width}px`
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (fitHeight) {
|
|
355
|
+
style['height'] = `${height}px`
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (style['display'] === 'contents') {
|
|
360
|
+
return {
|
|
361
|
+
width: '100%',
|
|
362
|
+
height: '100%',
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if (element instanceof HTMLCanvasElement) {
|
|
367
|
+
const treatProp = (name: 'width' | 'height') => {
|
|
368
|
+
const prop = component.getProp(name)
|
|
369
|
+
|
|
370
|
+
if (prop !== undefined) {
|
|
371
|
+
if (typeof prop === 'string') {
|
|
372
|
+
if (isFrameRelativeValue(prop)) {
|
|
373
|
+
const prop_num = prop.substring(0, prop.length - 2)
|
|
374
|
+
|
|
375
|
+
style[name] = `${prop_num}%`
|
|
376
|
+
} else {
|
|
377
|
+
// TODO
|
|
378
|
+
}
|
|
379
|
+
} else {
|
|
380
|
+
style[name] = `${prop}px`
|
|
381
|
+
}
|
|
382
|
+
} else {
|
|
383
|
+
style[name] = `${element[name]}px`
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
treatProp('width')
|
|
388
|
+
treatProp('height')
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (element instanceof HTMLInputElement) {
|
|
392
|
+
if (
|
|
393
|
+
element.type === 'text' ||
|
|
394
|
+
element.type === 'number' ||
|
|
395
|
+
element.type === 'password'
|
|
396
|
+
) {
|
|
397
|
+
if (style.height === 'fit-content') {
|
|
398
|
+
const { value } = element
|
|
399
|
+
|
|
400
|
+
const fontSize = element.style.fontSize
|
|
401
|
+
|
|
402
|
+
const fontSizeNum = parseFontSize(fontSize) ?? DEFAULT_FONT_SIZE
|
|
403
|
+
|
|
404
|
+
const { height } = measureText(value, fontSizeNum)
|
|
405
|
+
|
|
406
|
+
style.height = `${height}px`
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
if (element.type === 'range') {
|
|
411
|
+
style.height = '18px'
|
|
412
|
+
}
|
|
413
|
+
} else if (element instanceof HTMLSelectElement) {
|
|
414
|
+
style.height = '18px'
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
if (element instanceof SVGPathElement) {
|
|
418
|
+
const d = element.getAttribute('d')
|
|
419
|
+
|
|
420
|
+
const bb = getPathBoundingBox(d)
|
|
421
|
+
|
|
422
|
+
style['width'] = `${bb.width}px`
|
|
423
|
+
style['height'] = `${bb.height}px`
|
|
424
|
+
|
|
425
|
+
// TODO
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
if (element instanceof SVGRectElement) {
|
|
429
|
+
style['width'] = `${element.width.animVal.value}px`
|
|
430
|
+
style['height'] = `${element.height.animVal.value}px`
|
|
431
|
+
|
|
432
|
+
// TODO
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (element instanceof SVGCircleElement) {
|
|
436
|
+
const r = element.r.animVal.value
|
|
437
|
+
|
|
438
|
+
const width = 2 * r
|
|
439
|
+
const height = width
|
|
440
|
+
|
|
441
|
+
style['width'] = `${width}px`
|
|
442
|
+
style['height'] = `${height}px`
|
|
443
|
+
|
|
444
|
+
// TODO
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
if (fitContent) {
|
|
448
|
+
if (fitWidth || fitHeight) {
|
|
449
|
+
const { width, height } = measureChildren(
|
|
450
|
+
root,
|
|
451
|
+
component,
|
|
452
|
+
style,
|
|
453
|
+
fallbackTrait,
|
|
454
|
+
measureText,
|
|
455
|
+
fitContent,
|
|
456
|
+
getLeafStyle
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
if (fitWidth) {
|
|
460
|
+
style['width'] = `${width}px`
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
if (fitHeight) {
|
|
464
|
+
style['height'] = `${height}px`
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
return style
|
|
470
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { IOElement } from './IOElement'
|
|
2
|
+
import { Component } from './component'
|
|
3
|
+
|
|
4
|
+
export function isTextLike(leaf_comp: Component): boolean {
|
|
5
|
+
const is_text =
|
|
6
|
+
leaf_comp.$element instanceof Text || isContentEditable(leaf_comp.$element)
|
|
7
|
+
|
|
8
|
+
return is_text
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function isContentEditable(element: IOElement): boolean {
|
|
12
|
+
return (
|
|
13
|
+
element instanceof HTMLDivElement &&
|
|
14
|
+
element.getAttribute('contenteditable') === 'true'
|
|
15
|
+
)
|
|
16
|
+
}
|
|
@@ -45,6 +45,9 @@ export function webDocument(
|
|
|
45
45
|
createRange(): Range {
|
|
46
46
|
return document.createRange()
|
|
47
47
|
},
|
|
48
|
+
exitPictureInPicture(): Promise<void> {
|
|
49
|
+
return document.exitPictureInPicture()
|
|
50
|
+
},
|
|
48
51
|
MutationObserver: MutationObserver,
|
|
49
52
|
ResizeObserver: ResizeObserver,
|
|
50
53
|
PositionObserver: PositionObserver,
|
|
@@ -21,6 +21,7 @@ import { watchGraphSetUnitIdEvent } from './watchGraphSetUnitIdEvent'
|
|
|
21
21
|
import { watchGraphSetUnitPinConstant } from './watchGraphSetUnitPinConstantEvent'
|
|
22
22
|
import { watchGraphSetUnitPinData } from './watchGraphSetUnitPinDataEvent'
|
|
23
23
|
import { watchGraphSetUnitPinIgnored } from './watchGraphSetUnitPinIgnoredEvent'
|
|
24
|
+
import { watchGraphSetUnitPinSetId } from './watchGraphSetUnitPinSetIdEvent'
|
|
24
25
|
import { watchGraphUnitComponentAppendEvent } from './watchGraphUnitComponentAppendEvent'
|
|
25
26
|
import { watchGraphUnitComponentRemoveEvent } from './watchGraphUnitComponentRemoveEvent'
|
|
26
27
|
import {
|
|
@@ -54,6 +55,7 @@ export const GRAPH_EVENT_TO_WATCHER: Dict<
|
|
|
54
55
|
reorder_sub_component: watchGraphReorderSubComponent,
|
|
55
56
|
move_sub_component_root: watchGraphMoveSubComponentRoot,
|
|
56
57
|
set_unit_pin_constant: watchGraphSetUnitPinConstant,
|
|
58
|
+
set_unit_pin_set_id: watchGraphSetUnitPinSetId,
|
|
57
59
|
set_unit_pin_ignored: watchGraphSetUnitPinIgnored,
|
|
58
60
|
set_pin_set_functional: watchGraphSetUnitPinFunctional,
|
|
59
61
|
set_pin_set_id: watchGraphSetPinSetId,
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Graph } from '../../Class/Graph'
|
|
2
|
+
import { GraphSetUnitPinSetId } from '../../Class/Graph/interface'
|
|
3
|
+
import { G_EE } from '../../types/interface/G'
|
|
4
|
+
import { Moment } from '../Moment'
|
|
5
|
+
|
|
6
|
+
export interface GraphSetUnitPinSetIdMomentData extends GraphSetUnitPinSetId {
|
|
7
|
+
path: string[]
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface GraphSetUnitPinSetIdMoment
|
|
11
|
+
extends Moment<GraphSetUnitPinSetIdMomentData> {}
|
|
12
|
+
|
|
13
|
+
export function watchGraphSetUnitPinSetId(
|
|
14
|
+
event: 'set_unit_pin_set_id',
|
|
15
|
+
graph: Graph,
|
|
16
|
+
callback: (moment: GraphSetUnitPinSetIdMoment) => void
|
|
17
|
+
): () => void {
|
|
18
|
+
const listener = (
|
|
19
|
+
...[unitId, type, pinId, nextPinId, path]: G_EE['set_unit_pin_set_id']
|
|
20
|
+
) => {
|
|
21
|
+
callback({
|
|
22
|
+
type: 'graph',
|
|
23
|
+
event,
|
|
24
|
+
data: {
|
|
25
|
+
unitId,
|
|
26
|
+
type,
|
|
27
|
+
pinId,
|
|
28
|
+
nextPinId,
|
|
29
|
+
path,
|
|
30
|
+
},
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
graph.prependListener(event, listener)
|
|
35
|
+
|
|
36
|
+
return () => {
|
|
37
|
+
graph.removeListener(event, listener)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -12,7 +12,7 @@ Unit is also heavily inspired by Functional and Reactive Programming, both highl
|
|
|
12
12
|
|
|
13
13
|
The Unit paradigm was specially designed to enable easy visual creation of programs called units, which can be interacted with through their inputs and outputs. A new unit can be built by piping and collapsing together smaller units, in a process called Composition. Unit's fundamentals are not new by themselves - in fact, Unit represents a purposeful re-exploration of Computer Science principles in the context of modern Software Development.
|
|
14
14
|
|
|
15
|
-
The simplicity of Programming in Unit comes from the iterative application of a very small set of principles. One may start out with an initial set of units, which can be linked together forming a new graph unit, in a process called Composition. Symmetrically, a graph can be decomposed and disconnected into its set of smaller units. Moreover any software can be built by
|
|
15
|
+
The simplicity of Programming in Unit comes from the iterative application of a very small set of principles. One may start out with an initial set of units, which can be linked together forming a new graph unit, in a process called Composition. Symmetrically, a graph can be decomposed and disconnected into its set of smaller units. Moreover any software can be built by repeating this process.
|
|
16
16
|
|
|
17
17
|
The concept of a Unit is essentially an advancement of the fundamental concept of a function, common to many Textual Programming Languages, such as JavaScript and C++. A function is supposed to be given an ordered list of arguments as input and it can return a single datum as output. A unit, on the other hand, can receive and send data at any time, in any order and through multiple inputs and outputs. We believe that redefining the fundamental building block of Programming as a unit can exponentially reduce Software Complexity.
|
|
18
18
|
|
|
@@ -30,6 +30,12 @@ That brings us to the world of User Interfaces (UI), which is inseparable from t
|
|
|
30
30
|
|
|
31
31
|
Today, programming a UI is about building a thin visual layer on top of a thick black box, represented by the figure of an "app". Such apps are usually optimized, in logic and design, for a specific set of use cases, invariably rendering the UI either unfit or overfit for real life use cases, which are often unpredictable; the user is not free to arbitrarily mold the interface to his liking. He can neither extend nor extract nor focus on the objects he is currently interested on, so he's forced to content with the lack or interference of a certain UI element. This renders people hostage to the specific design decisions of many one-size-fits-all apps, which are usually borderline impossible to customize or extend.
|
|
32
32
|
|
|
33
|
-
In Unit, the (visual) components that make up a user interface are units! That means they can be composed and decomposed on will. The user can always inspect the layout and logic of anything he can put his eyes on, being that copying, extending, changing or removing. Therefore, like any other unit, every unit website can be unwrapped into its subcomponents, which live side by side with the logical circuitry that controls them
|
|
33
|
+
In Unit, the (visual) components that make up a user interface are units! That means they can be composed and decomposed on will. The user can always inspect the layout and logic of anything he can put his eyes on, being that copying, extending, changing or removing. Therefore, like any other unit, every unit website can be unwrapped into its subcomponents, which live side by side with the logical circuitry that controls them - no context switch between Design and Development.
|
|
34
|
+
|
|
35
|
+
Likewise, in Unit, there is no explicit separation between "frontend" and "backend". All unit processes can contain components, which helps to visualize it, and can be accessed through an array of standard communication channels. Therefore, the Unit programmer is able to debug "client" and "server" logic side by side. More practically, this divide comes down to the presence of centain APIs, such as "HTTP", "File System" and "Database", which are available in Unit regardless of the host system, so the same program can run anywhere seamlessly regardless of the underlying system/engine.
|
|
36
|
+
|
|
37
|
+
Curiously, the Unit Environment is optimized for the case of 0 code. It can be used as day to day system, where the user practices no direct programming at all. The user starts out with an empty infinite canvas that can be conveniently populated with the desired units to build up the user's own personal spaces, some ephemeral, most reusable.
|
|
38
|
+
|
|
39
|
+
There's a curious emergent pattern here: Unit evolves by removing the auto-imposed divide between concepts that can otherwise work very well together: "user" and "programmer", "developer" and "designer", "client" and "server", "local" and "remote", "sync" and "async", "apps" and "systems".
|
|
34
40
|
|
|
35
41
|
Unit shifts the software paradigm in the direction of user empowerment.
|
package/src/interface.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { copy, writeFile } from 'fs-extra'
|
|
2
2
|
import { build } from '../build'
|
|
3
3
|
;(async () => {
|
|
4
4
|
const result = await build({
|
|
@@ -14,7 +14,9 @@ import { build } from '../build'
|
|
|
14
14
|
metafile: true,
|
|
15
15
|
})
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
await writeFile('public/build.json', JSON.stringify(result.metafile ?? {}))
|
|
18
|
+
|
|
19
|
+
await copy('public/index.js', 'build/web.js')
|
|
18
20
|
})()
|
|
19
21
|
|
|
20
22
|
export default null
|
package/src/spec/Lazy.ts
CHANGED
|
@@ -53,8 +53,7 @@ export function lazyFromSpec(
|
|
|
53
53
|
|
|
54
54
|
public __ = ['U', 'G']
|
|
55
55
|
|
|
56
|
-
public
|
|
57
|
-
public __element: boolean = false // RETURN __element
|
|
56
|
+
public __element: boolean = false
|
|
58
57
|
|
|
59
58
|
private __graph: Graph
|
|
60
59
|
|
|
@@ -104,6 +103,15 @@ export function lazyFromSpec(
|
|
|
104
103
|
}
|
|
105
104
|
})
|
|
106
105
|
}
|
|
106
|
+
setUnitPinSetId(
|
|
107
|
+
unitId: string,
|
|
108
|
+
type: IO,
|
|
109
|
+
pinId: string,
|
|
110
|
+
newPinId: string,
|
|
111
|
+
...extra: any[]
|
|
112
|
+
): void {
|
|
113
|
+
throw new Error('Method not implemented.')
|
|
114
|
+
}
|
|
107
115
|
|
|
108
116
|
fork(): void {
|
|
109
117
|
this._ensure()
|
package/src/spec/util.ts
CHANGED
|
@@ -98,6 +98,10 @@ export const getExposedPinSpecs = (graph: GraphSpec) => {
|
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
export const getExposePinSpec = (graph: GraphSpec, type: IO, pinId: string) => {
|
|
102
|
+
return pathOrDefault(graph, [`${type}s`, pinId], undefined)
|
|
103
|
+
}
|
|
104
|
+
|
|
101
105
|
export const getUnitExposedPins = (
|
|
102
106
|
graph: GraphSpec,
|
|
103
107
|
unitId: string
|
package/src/system/_classes.ts
CHANGED
|
@@ -183,7 +183,7 @@ import EnumerateDevices from './platform/api/media/EnumerateDevices'
|
|
|
183
183
|
import GetDisplayMedia from './platform/api/media/GetDisplayMedia'
|
|
184
184
|
import GetVideoTracks from './platform/api/media/GetVideoTracks'
|
|
185
185
|
import GrabFrame from './platform/api/media/GrabFrame'
|
|
186
|
-
import
|
|
186
|
+
import ImageToBitmap from './platform/api/media/image/ImageToBitmap'
|
|
187
187
|
import ImageCapture from './platform/api/media/ImageCapture'
|
|
188
188
|
import MediaRecorder from './platform/api/media/MediaRecorder'
|
|
189
189
|
import RequestPictureInPicture from './platform/api/media/RequestPictureInPicture'
|
|
@@ -510,7 +510,7 @@ export default {
|
|
|
510
510
|
'6705462c-5b47-11eb-9dfc-2f14c58b2789': GetDisplayMedia,
|
|
511
511
|
'0bc0c4ad-d2e0-4e3e-92e8-5b9dfee1cf5e': GetVideoTracks,
|
|
512
512
|
'f238caff-3f71-40d9-b1a9-d992060fea04': GrabFrame,
|
|
513
|
-
'262beb5f-21bd-4848-a62d-185f6f8a78e1':
|
|
513
|
+
'262beb5f-21bd-4848-a62d-185f6f8a78e1': ImageToBitmap,
|
|
514
514
|
'a57383a9-5b24-4dbb-a5d1-0e278d036f89': ImageCapture,
|
|
515
515
|
'7e1b3a4c-be6b-11eb-b098-1b6b9db93f1e': MediaRecorder,
|
|
516
516
|
'3889d2f1-a0ed-4e8c-8e75-7a6683224275': RequestPictureInPicture,
|
package/src/system/_ids.ts
CHANGED
|
@@ -386,7 +386,7 @@ export const ID_ENUMERATE_DEVICES = '3511f756-2a02-4346-b417-8c34502f79d4'
|
|
|
386
386
|
export const ID_GET_DISPLAY_MEDIA = '6705462c-5b47-11eb-9dfc-2f14c58b2789'
|
|
387
387
|
export const ID_GET_VIDEO_TRACKS = '0bc0c4ad-d2e0-4e3e-92e8-5b9dfee1cf5e'
|
|
388
388
|
export const ID_GRAB_FRAME = 'f238caff-3f71-40d9-b1a9-d992060fea04'
|
|
389
|
-
export const
|
|
389
|
+
export const ID_IMAGE_TO_BITMAP = '262beb5f-21bd-4848-a62d-185f6f8a78e1'
|
|
390
390
|
export const ID_IMAGE_CAPTURE = 'a57383a9-5b24-4dbb-a5d1-0e278d036f89'
|
|
391
391
|
export const ID_MEDIA_RECORDER = '7e1b3a4c-be6b-11eb-b098-1b6b9db93f1e'
|
|
392
392
|
export const ID_REQUEST_PICTURE_IN_PICTURE = '3889d2f1-a0ed-4e8c-8e75-7a6683224275'
|