Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

minitel-standalone

Package Overview
Dependencies
Maintainers
0
Versions
54
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

minitel-standalone - npm Package Compare versions

Comparing version 1.10.2 to 2.0.0

dist/tests/index.d.ts

7

dist/abstract/minitelobject.d.ts

@@ -7,2 +7,3 @@ /// <reference types="node" resolution-mode="require"/>

import { Focusable } from './focusable.js';
import { LocationDescriptor } from '../locationdescriptor.js';
export declare class MinitelObject<T extends MinitelObjectAttributes = MinitelObjectAttributes, U extends Record<string, any[]> = Record<string, any[]>> extends EventEmitter<U> {

@@ -34,2 +35,8 @@ children: MinitelObject[];

has(child: MinitelObject): boolean;
mapLocation(attributes: T, inheritMe: Partial<T>, nextNode: MinitelObject, nodes: MinitelObject[], weAt: number): LocationDescriptor;
mapLocationWrapper(inheritedAttributes: Partial<T>, forcedAttributes: Partial<T>, nodes: MinitelObject[], weAt: number): LocationDescriptor;
get parentList(): MinitelObject[];
scrollIntoView(context?: MinitelObject & {
scrollDelta: [number, number];
}): void;
}

60

dist/abstract/minitelobject.js

@@ -79,9 +79,11 @@ import { EventEmitter } from 'node:events';

if (attributes.width != null)
result.setWidth(attributes.width, 'end');
result.setWidth(attributes.width, 'end', fillChar);
if (attributes.height != null)
result.setHeight(attributes.height, 'end');
result.setHeight(attributes.height, 'end', fillChar);
result.pad(pad, fillChar);
// Descriptor before pad, is this the right choice?
// Future you: Yes. Yes it is.
// Future you 5 minutes later: Actually you know what
if (this.keepElmDesc)
result.locationDescriptors.add(this, new LocationDescriptor(0, 0, result.width, result.height));
result.pad(pad, fillChar);
return result;

@@ -107,2 +109,54 @@ }

}
mapLocation(attributes, inheritMe, nextNode, nodes, weAt) {
return nextNode.mapLocationWrapper(inheritMe, {}, nodes, weAt);
}
mapLocationWrapper(inheritedAttributes, forcedAttributes, nodes, weAt) {
const nextNode = nodes[weAt + 1];
const nextNodeIdx = nextNode && this.children.indexOf(nextNode);
if (nextNodeIdx === -1) {
throw new Error(`Next node was not found in children. This behaviour is unexpected; please contact the owner of minitel-standalone.`);
}
const attributes = Object.assign(Object.assign(Object.assign(Object.assign({}, this.defaultAttributes), inheritedAttributes), this.attributes), forcedAttributes);
const pad = padding.normalise(attributes.pad);
attributes.width = attributes.width != null ? padding.exludeX(attributes.width, pad) : null;
attributes.height = attributes.height != null ? padding.exludeY(attributes.height, pad) : null;
if (!nextNode) {
const dimensions = this.getDimensionsWrapper(attributes, inheritedProps(Object.assign(Object.assign(Object.assign({}, inheritedAttributes), this.attributes), forcedAttributes)));
return new LocationDescriptor(0, 0, dimensions.width, dimensions.height);
}
let result = this.mapLocation(attributes, inheritedProps(Object.assign(Object.assign(Object.assign({}, inheritedAttributes), this.attributes), forcedAttributes)), nextNode, nodes, weAt + 1);
result.x += pad[0];
result.y += pad[3];
return result;
}
get parentList() {
var _a;
return [...(((_a = this.parent) === null || _a === void 0 ? void 0 : _a.parentList) || []), this];
}
scrollIntoView(context) {
if (!context) {
const parentList = this.parentList.filter((v) => 'scrollDelta' in v);
for (let i = 0; i < parentList.length - 1; i += 1)
parentList[i + 1].scrollIntoView(parentList[i]);
this.scrollIntoView(parentList.at(-1));
return;
}
const pathToThis = this.parentList;
const pathToScrollable = context.parentList;
const thisPos = this.minitel.mapLocationWrapper({}, {}, pathToThis, 0);
const scrollablePos = this.minitel.mapLocationWrapper({}, {}, pathToScrollable, 0);
const [relY, relX] = [thisPos.y - scrollablePos.y, thisPos.x - scrollablePos.x];
if (relY < 0) {
context.scrollDelta[0] += relY;
}
else if (relY + thisPos.h > scrollablePos.h) {
context.scrollDelta[0] -= scrollablePos.h - (relY + thisPos.h);
}
if (relX < 0) {
context.scrollDelta[1] += relX;
}
else if (relX + thisPos.w > scrollablePos.w) {
context.scrollDelta[1] -= scrollablePos.w - (relX + thisPos.w);
}
}
}

@@ -109,0 +163,0 @@ MinitelObject.defaultAttributes = {

@@ -5,2 +5,3 @@ import { MinitelObject } from './minitelobject.js';

import type { Minitel } from '../index.js';
import { LocationDescriptor } from '../locationdescriptor.js';
export declare class TextNode extends MinitelObject {

@@ -15,2 +16,3 @@ text: string;

renderLines(inheritedAttributes: Partial<MinitelObjectAttributes>, forcedAttributes: Partial<RenderLinesAttributes>): RichCharGrid[];
mapLocation(attributes: MinitelObjectAttributes, inheritMe: Partial<MinitelObjectAttributes>, nextNode: MinitelObject): LocationDescriptor;
}

@@ -87,2 +87,5 @@ import { MinitelObject } from './minitelobject.js';

}
mapLocation(attributes, inheritMe, nextNode) {
throw new Error('TextNode doesn\'t have children, and therefore can\'t mapLocation');
}
}

2

dist/components/container.d.ts

@@ -7,3 +7,3 @@ import { MinitelObject } from '../abstract/minitelobject.js';

defaultAttributes: T;
constructor(children: never[] | undefined, attributes: Partial<T>, minitel: Minitel);
constructor(children: MinitelObject<MinitelObjectAttributes, Record<string, any[]>>[] | undefined, attributes: Partial<T>, minitel: Minitel);
getDimensions(attributes: T, inheritMe: Partial<T>): {

@@ -10,0 +10,0 @@ width: number;

import { FocusableAttributes as FocusableIfaceAttributes, Focusable as FocusableIface } from '../abstract/focusable.js';
import { MinitelObject } from '../abstract/minitelobject.js';
import { Container, ContainerAttributes } from './container.js';

@@ -13,7 +14,6 @@ import type { Minitel } from './minitel.js';

keepElmDesc: true;
private artificialBlink;
set focused(val: boolean);
get focused(): boolean;
constructor(children: never[] | undefined, attributes: Partial<FocusableAttributes>, minitel: Minitel);
constructor(children: MinitelObject<import("../types.js").MinitelObjectAttributes, Record<string, any[]>>[] | undefined, attributes: Partial<FocusableAttributes>, minitel: Minitel);
get disabled(): boolean;
}

@@ -8,10 +8,13 @@ import { Container } from './container.js';

if (val) {
if (this.minitel.focusedObj)
// console.log(this.minitel.focusedObj, this.minitel.focusedObj === this);
if (this.minitel.focusedObj && this.minitel.focusedObj !== this)
this.minitel.focusedObj.focused = false;
if (this._focused !== val)
(_b = (_a = this.attributes).onFocus) === null || _b === void 0 ? void 0 : _b.call(_a);
this._focused = true;
(_b = (_a = this.attributes).onFocus) === null || _b === void 0 ? void 0 : _b.call(_a);
}
else {
if (this._focused !== val)
(_d = (_c = this.attributes).onBlur) === null || _d === void 0 ? void 0 : _d.call(_c);
this._focused = false;
(_d = (_c = this.attributes).onBlur) === null || _d === void 0 ? void 0 : _d.call(_c);
}

@@ -27,3 +30,2 @@ }

this.keepElmDesc = true;
this.artificialBlink = null;
}

@@ -30,0 +32,0 @@ get disabled() {

@@ -53,10 +53,12 @@ import { MinitelObject } from '../abstract/minitelobject.js';

if (val) {
if (this.minitel.focusedObj)
if (this.minitel.focusedObj && this.minitel.focusedObj !== this)
this.minitel.focusedObj.focused = false;
if (this._focused !== val)
(_b = (_a = this.attributes).onFocus) === null || _b === void 0 ? void 0 : _b.call(_a);
this._focused = true;
(_b = (_a = this.attributes).onFocus) === null || _b === void 0 ? void 0 : _b.call(_a);
}
else {
if (this._focused !== val)
(_d = (_c = this.attributes).onBlur) === null || _d === void 0 ? void 0 : _d.call(_c);
this._focused = false;
(_d = (_c = this.attributes).onBlur) === null || _d === void 0 ? void 0 : _d.call(_c);
}

@@ -63,0 +65,0 @@ }

@@ -89,3 +89,2 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {

current = current.next;
debugger;
}

@@ -139,2 +138,3 @@ if (current) {

if (err instanceof InvalidRender) {
console.error(err);
return this.renderString();

@@ -153,2 +153,3 @@ }

let lastChar = null;
// console.log(this.previousRender.toString());
for (let lineIdx in renderGrid.grid) {

@@ -180,3 +181,3 @@ if (+lineIdx === 0 && this.settings.statusBar)

lastAttributes = char.attributes;
outputString.push(typeof char.char === 'string' ? char.char : ['', ' '][char.delta[0]]);
outputString.push(typeof char.char === 'string' ? char.char : ['', ' '].at(char.delta[0]));
skippedACharCounter = 0;

@@ -219,3 +220,4 @@ }

const isInTree = this.has(this.focusedObj);
this.focusedObj.focused = isInTree;
if (this.focusedObj.focused !== isInTree)
this.focusedObj.focused = isInTree;
if (isInTree)

@@ -228,3 +230,3 @@ return;

this.focusedObj = focusables[oneWithAutofocusIdx];
if (this.focusedObj)
if (this.focusedObj && !this.focusedObj.focused)
this.focusedObj.focused = true;

@@ -243,3 +245,3 @@ }

curr %= focusables.length;
if (this.focusedObj)
if (this.focusedObj && this.focusedObj.focused)
this.focusedObj.focused = false;

@@ -246,0 +248,0 @@ this.focusedObj = focusables[curr];

@@ -7,2 +7,3 @@ import { MinitelObject } from '../abstract/minitelobject.js';

import { Span } from './span.js';
import { LocationDescriptor } from '../locationdescriptor.js';
export declare class Paragraph extends MinitelObject {

@@ -15,3 +16,4 @@ children: (TextNode | Span)[];

};
mapLocation(attributes: MinitelObjectAttributes, inheritMe: Partial<MinitelObjectAttributes>, nextNode: MinitelObject<MinitelObjectAttributes, Record<string, any[]>>, nodes: MinitelObject<MinitelObjectAttributes, Record<string, any[]>>[], weAt: number): LocationDescriptor;
render(attributes: MinitelObjectAttributes, inheritMe: Partial<MinitelObjectAttributes>): RichCharGrid;
}

@@ -31,2 +31,25 @@ import { MinitelObject } from '../abstract/minitelobject.js';

}
mapLocation(attributes, inheritMe, nextNode, nodes, weAt) {
const originalLocationDescriptor = nextNode.mapLocationWrapper(inheritMe, {}, nodes, weAt);
const lines = [new RichCharGrid([[]])]; // Again, if someone smarter than me can figure out an elegant way, suit urself
for (let child of this.children) {
if (child === nextNode) {
originalLocationDescriptor.x += lines.at(-1).width;
originalLocationDescriptor.y += lines.length;
return originalLocationDescriptor;
}
const render = child.renderLines(inheritMe, {
width: attributes.width,
forcedIndent: lines.at(-1).width,
});
const newMaxIdx = lines.length - 1;
for (let lineIdx in render) {
if (+lineIdx !== 0) {
lines[newMaxIdx + +lineIdx] = new RichCharGrid([[]]);
}
lines[newMaxIdx + +lineIdx].mergeX(render[+lineIdx], 'end');
}
}
throw new Error("Something unexpected happened: Provided nextNode was not among my children!");
}
render(attributes, inheritMe) {

@@ -33,0 +56,0 @@ const fillChar = new RichChar(attributes.fillChar, attributes).noSize();

import { Focusable } from '../abstract/focusable.js';
import { MinitelObject } from '../abstract/minitelobject.js';
import { LocationDescriptor } from '../locationdescriptor.js';
import { RichCharGrid } from '../richchargrid.js';

@@ -21,3 +23,3 @@ import { Container, ContainerAttributes } from './container.js';

blinkHandler(): void;
constructor(children: never[] | undefined, attributes: Partial<ScrollableAttributes>, minitel: Minitel);
constructor(children: MinitelObject<import("../types.js").MinitelObjectAttributes, Record<string, any[]>>[] | undefined, attributes: Partial<ScrollableAttributes>, minitel: Minitel);
pushPrevScrollDelta(): void;

@@ -31,2 +33,3 @@ popPrevScrollDelta(callback: (_arg0: [number, number]) => unknown): void;

};
mapLocation(attributes: ScrollableAttributes, inheritMe: Partial<ScrollableAttributes>, nextNode: MinitelObject, nodes: MinitelObject[], weAt: number): LocationDescriptor;
render(attributes: ScrollableAttributes, inheritMe: Partial<ScrollableAttributes>): RichCharGrid;

@@ -33,0 +36,0 @@ get disabled(): boolean;

@@ -18,10 +18,12 @@ import { RichChar } from '../richchar.js';

if (val) {
if (this.minitel.focusedObj)
if (this.minitel.focusedObj && this.minitel.focusedObj !== this)
this.minitel.focusedObj.focused = false;
if (this._focused !== val)
(_b = (_a = this.attributes).onFocus) === null || _b === void 0 ? void 0 : _b.call(_a);
this._focused = true;
(_b = (_a = this.attributes).onFocus) === null || _b === void 0 ? void 0 : _b.call(_a);
}
else {
if (this._focused !== val)
(_d = (_c = this.attributes).onBlur) === null || _d === void 0 ? void 0 : _d.call(_c);
this._focused = false;
(_d = (_c = this.attributes).onBlur) === null || _d === void 0 ? void 0 : _d.call(_c);
}

@@ -140,2 +142,8 @@ }

}
mapLocation(attributes, inheritMe, nextNode, nodes, weAt) {
const location = nextNode.mapLocationWrapper(inheritMe, {}, nodes, weAt);
location.x -= this.scrollDelta[1];
location.y -= this.scrollDelta[0];
return location;
}
render(attributes, inheritMe) {

@@ -158,3 +166,5 @@ // now its 3 am and i don't know how i'll read back

const width = attributes.width != null && attributes.overflowX === 'hidden'
? attributes.width - 1
? attributes.overflowY === 'noscrollbar'
? attributes.width
: attributes.width - 1
: null;

@@ -174,3 +184,7 @@ renderAttributes = Object.assign(Object.assign({}, attributes), { width, height: null });

if (!autoedX) {
const height = attributes.height != null ? attributes.height - 1 : null;
const height = attributes.height != null // && attributes.overflowX === 'hidden' // we already know that
? attributes.overflowX === 'noscrollbar'
? attributes.height
: attributes.height - 1
: null;
renderAttributes = Object.assign(Object.assign({}, attributes), { height, width: null });

@@ -177,0 +191,0 @@ }

import { MinitelObject } from '../abstract/minitelobject.js';
import { LocationDescriptor } from '../locationdescriptor.js';
import { RichCharGrid } from '../richchargrid.js';

@@ -8,3 +9,3 @@ import { Align, MinitelObjectAttributes } from '../types.js';

defaultAttributes: XJoinAttributes;
constructor(children: MinitelObject[], attributes: Partial<MinitelObjectAttributes>, minitel: Minitel);
constructor(children: MinitelObject[], attributes: Partial<XJoinAttributes>, minitel: Minitel);
getDimensions(attributes: XJoinAttributes, inheritMe: Partial<XJoinAttributes>): {

@@ -14,2 +15,3 @@ width: number;

};
mapLocation(attributes: XJoinAttributes, inheritMe: Partial<XJoinAttributes>, nextNode: MinitelObject, nodes: MinitelObject<MinitelObjectAttributes, Record<string, any[]>>[], weAt: number): LocationDescriptor;
render(attributes: XJoinAttributes, inheritMe: Partial<XJoinAttributes>): RichCharGrid;

@@ -16,0 +18,0 @@ }

import { MinitelObject } from '../abstract/minitelobject.js';
import { LocationDescriptor } from '../locationdescriptor.js';
import { RichChar } from '../richchar.js';
import { RichCharGrid } from '../richchargrid.js';
import { getDeltaFromSetting } from '../utils.js';
import { alignInvrt } from '../utils.js';

@@ -48,2 +50,83 @@ export class XJoin extends MinitelObject {

}
mapLocation(attributes, inheritMe, nextNode, nodes, weAt) {
const heightIfStretch = attributes.height || this.children.reduce((p, c) => {
const h = c.getDimensionsWrapper(inheritMe).height;
if (h == null)
return p;
return Math.max(p, h);
}, -Infinity);
let cumulatedWidth = 0;
let nextMapLocation = null;
const rendersNoFlexGrow = this.children.map((v) => {
if (v.attributes.flexGrow)
return null;
const newOptions = Object.assign({}, (attributes.heightAlign === 'stretch' ? { height: heightIfStretch } : {}));
if (v === nextNode)
nextMapLocation = v.mapLocationWrapper(inheritMe, newOptions, nodes, weAt);
const render = v.getDimensionsWrapper(inheritMe, newOptions);
cumulatedWidth += render.width;
return [v, render];
});
const flexGrowTotal = this.children.reduce((p, c) => p + +(c.attributes.flexGrow || 0), 0);
const remainingSpace = attributes.width != null ? attributes.width - cumulatedWidth : null;
const unitOfFlexGrowSpace = remainingSpace != null ? remainingSpace / flexGrowTotal : null;
let usedRemainingSpace = 0;
const rendersYesFlexGrow = this.children.map((v) => {
if (!v.attributes.flexGrow)
return null;
let newOptions = {};
if (unitOfFlexGrowSpace != null && remainingSpace != null) {
const prevUsedRemSpace = usedRemainingSpace;
usedRemainingSpace += unitOfFlexGrowSpace;
newOptions = Object.assign(Object.assign({}, (attributes.heightAlign === 'stretch' ? { height: heightIfStretch } : {})), { width: Math.round(usedRemainingSpace) - Math.round(prevUsedRemSpace) });
}
if (v === nextNode)
nextMapLocation = v.mapLocationWrapper(inheritMe, newOptions, nodes, weAt);
return [v, v.getDimensionsWrapper(inheritMe, newOptions)];
});
if (!(nextMapLocation instanceof LocationDescriptor))
throw new Error('nextNode was not within children; this is fatal for xjoin');
const renders = rendersNoFlexGrow.map((v, i) => v != null ? v : rendersYesFlexGrow[i]);
const height = attributes.heightAlign === 'stretch'
? heightIfStretch
: attributes.height || Math.max(...renders.map((v) => v[1].height));
const contentsWidth = renders.reduce((c, v) => c + v[1].width, 0);
// space-between: w / (n - 1)
// space-around: w / n
// space-evenly: w / (n + 1)
let gapWidth;
if (typeof attributes.gap === 'number') {
gapWidth = attributes.gap;
}
else if (attributes.width != null) {
const mappingTable = {
'space-between': renders.length - 1,
'space-around': renders.length,
'space-evenly': renders.length + 1,
};
gapWidth = (attributes.width - contentsWidth) / mappingTable[attributes.gap];
}
else {
gapWidth = 0;
}
let gapCumul = 0;
let xCumul = 0;
for (let render of renders) {
if (render !== renders[0]) {
const lastCumul = gapCumul;
gapCumul += gapWidth;
xCumul += Math.round(gapCumul) - Math.round(lastCumul);
}
if (render[0] === nextNode) {
if (attributes.heightAlign !== 'stretch') {
nextMapLocation.y += getDeltaFromSetting(nextMapLocation.h, height, alignInvrt[attributes.heightAlign]);
}
nextMapLocation.x += xCumul;
}
else {
xCumul += render[1].width;
}
}
return nextMapLocation;
}
render(attributes, inheritMe) {

@@ -50,0 +133,0 @@ const fillChar = new RichChar(attributes.fillChar, attributes).noSize();

import { MinitelObject } from '../abstract/minitelobject.js';
import { LocationDescriptor } from '../locationdescriptor.js';
import { RichCharGrid } from '../richchargrid.js';

@@ -8,3 +9,3 @@ import { Align, MinitelObjectAttributes } from '../types.js';

defaultAttributes: YJoinAttributes;
constructor(children: MinitelObject[], attributes: Partial<MinitelObjectAttributes>, minitel: Minitel);
constructor(children: MinitelObject[], attributes: Partial<YJoinAttributes>, minitel: Minitel);
getDimensions(attributes: YJoinAttributes, inheritMe: Partial<YJoinAttributes>): {

@@ -14,2 +15,3 @@ width: number;

};
mapLocation(attributes: YJoinAttributes, inheritMe: Partial<YJoinAttributes>, nextNode: MinitelObject<MinitelObjectAttributes, Record<string, any[]>>, nodes: MinitelObject[], weAt: number): LocationDescriptor;
render(attributes: YJoinAttributes, inheritMe: Partial<YJoinAttributes>): RichCharGrid;

@@ -16,0 +18,0 @@ }

import { MinitelObject } from '../abstract/minitelobject.js';
import { LocationDescriptor } from '../locationdescriptor.js';
import { RichChar } from '../richchar.js';
import { RichCharGrid } from '../richchargrid.js';
import { getDeltaFromSetting } from '../utils.js';
import { alignInvrt } from '../utils.js';

@@ -48,2 +50,83 @@ export class YJoin extends MinitelObject {

}
mapLocation(attributes, inheritMe, nextNode, nodes, weAt) {
const widthIfStretch = attributes.width || this.children.reduce((p, c) => {
const w = c.getDimensionsWrapper(inheritMe).width;
if (w == null)
return p;
return Math.max(p, w);
}, -Infinity);
let cumulatedHeight = 0;
let nextMapLocation = null;
const rendersNoFlexGrow = this.children.map((v) => {
if (v.attributes.flexGrow)
return null;
const newOptions = Object.assign({}, (attributes.widthAlign === 'stretch' ? { width: widthIfStretch } : {}));
if (v === nextNode)
nextMapLocation = v.mapLocationWrapper(inheritMe, newOptions, nodes, weAt);
const render = v.getDimensionsWrapper(inheritMe, newOptions);
cumulatedHeight += render.width;
return [v, render];
});
const flexGrowTotal = this.children.reduce((p, c) => p + +(c.attributes.flexGrow || 0), 0);
const remainingSpace = attributes.height != null ? attributes.height - cumulatedHeight : null;
const unitOfFlexGrowSpace = remainingSpace != null ? remainingSpace / flexGrowTotal : null;
let usedRemainingSpace = 0;
const rendersYesFlexGrow = this.children.map((v) => {
if (!v.attributes.flexGrow)
return null;
let newOptions = {};
if (unitOfFlexGrowSpace != null && remainingSpace != null) {
const prevUsedRemSpace = usedRemainingSpace;
usedRemainingSpace += unitOfFlexGrowSpace;
newOptions = Object.assign(Object.assign({}, (attributes.widthAlign === 'stretch' ? { width: widthIfStretch } : {})), { height: Math.round(usedRemainingSpace) - Math.round(prevUsedRemSpace) });
}
if (v === nextNode)
nextMapLocation = v.mapLocationWrapper(inheritMe, newOptions, nodes, weAt);
return [v, v.getDimensionsWrapper(inheritMe, newOptions)];
});
if (!(nextMapLocation instanceof LocationDescriptor))
throw new Error('nextNode was not within children; this is fatal for xjoin');
const renders = rendersNoFlexGrow.map((v, i) => v != null ? v : rendersYesFlexGrow[i]);
const width = attributes.widthAlign === 'stretch'
? widthIfStretch
: attributes.width || Math.max(...renders.map((v) => v[1].width));
const contentsHeight = renders.reduce((c, v) => c + v[1].height, 0);
// space-between: w / (n - 1)
// space-around: w / n
// space-evenly: w / (n + 1)
let gapWidth;
if (typeof attributes.gap === 'number') {
gapWidth = attributes.gap;
}
else if (attributes.height != null) {
const mappingTable = {
'space-between': renders.length - 1,
'space-around': renders.length,
'space-evenly': renders.length + 1,
};
gapWidth = (attributes.height - contentsHeight) / mappingTable[attributes.gap];
}
else {
gapWidth = 0;
}
let gapCumul = 0;
let yCumul = 0;
for (let render of renders) {
if (render !== renders[0]) {
const lastCumul = gapCumul;
gapCumul += gapWidth;
yCumul += Math.round(gapCumul) - Math.round(lastCumul);
}
if (render[0] === nextNode) {
if (attributes.widthAlign !== 'stretch') {
nextMapLocation.x += getDeltaFromSetting(nextMapLocation.w, width, alignInvrt[attributes.widthAlign]);
}
nextMapLocation.y += yCumul;
}
else {
yCumul += render[1].height;
}
}
return nextMapLocation;
}
render(attributes, inheritMe) {

@@ -50,0 +133,0 @@ const fillChar = new RichChar(attributes.fillChar, attributes).noSize();

import { MinitelObject } from '../abstract/minitelobject.js';
import { LocationDescriptor } from '../locationdescriptor.js';
import { RichCharGrid } from '../richchargrid.js';

@@ -13,2 +14,3 @@ import { Align, MinitelObjectAttributes } from '../types.js';

};
mapLocation(attributes: ZJoinAttributes, inheritMe: Partial<ZJoinAttributes>, nextNode: MinitelObject, nodes: MinitelObject[], weAt: number): LocationDescriptor;
render(attributes: ZJoinAttributes, inheritMe: Partial<ZJoinAttributes>): RichCharGrid;

@@ -15,0 +17,0 @@ }

import { MinitelObject } from '../abstract/minitelobject.js';
import { RichChar } from '../richchar.js';
import { RichCharGrid } from '../richchargrid.js';
import { getDeltaFromSetting } from '../utils.js';
export class ZJoin extends MinitelObject {

@@ -15,2 +16,18 @@ constructor(children, attributes, minitel) {

}
mapLocation(attributes, inheritMe, nextNode, nodes, weAt) {
const renders = this.children.map((v) => [v, v.getDimensionsWrapper(inheritMe, {
width: attributes.width,
height: attributes.height,
})]);
const maxWidth = Math.max(...renders.map((v) => v[1].width));
const maxHeight = Math.max(...renders.map((v) => v[1].height));
const relevant = renders.find((v) => v[0] === nextNode);
const prevLocation = nextNode.mapLocationWrapper(inheritMe, {
width: attributes.width,
height: attributes.height,
}, nodes, weAt);
prevLocation.x += getDeltaFromSetting(relevant[1].width, maxWidth, attributes.widthAlign);
prevLocation.y += getDeltaFromSetting(relevant[1].height, maxWidth, attributes.heightAlign);
return prevLocation;
}
render(attributes, inheritMe) {

@@ -17,0 +34,0 @@ const fillChar = new RichChar(attributes.fillChar, attributes).noSize();

@@ -18,6 +18,8 @@ import { LocationDescriptors } from './locationdescriptor.js';

pad(fullPad: FullPadding, fillChar: RichChar<string>): this;
forceIntegrityOn(y: number, x: number): void;
forceIntegrityOnTheSides(): void;
cutHeight(height: number, heightAlign: Align): this;
cutWidth(width: number, widthAlign: Align): this;
setHeight(height: number, heightAlign: Align, char?: RichChar<string>): this;
setWidth(width: number, widthAlign: Align, char?: RichChar<string>): this;
setHeight(height: number, heightAlign: Align, char: RichChar<string>): this;
setWidth(width: number, widthAlign: Align, char: RichChar<string>): this;
mergeLocationDescriptors(operand: RichCharGrid): void;

@@ -24,0 +26,0 @@ mergeY(operand: RichCharGrid, heightAlign?: string): void;

@@ -93,2 +93,32 @@ import { LocationDescriptors } from './locationdescriptor.js';

}
forceIntegrityOn(y, x) {
const cell = this.grid[y][x];
if (!cell.delta)
return;
const newY = y + cell.delta[0];
const newX = x + cell.delta[1];
if (!(newY in this.grid) || !(newX in this.grid[newY])) {
this.grid[y][x] = cell.copy();
this.grid[y][x].delta = undefined;
this.grid[y][x].actualChar = undefined;
if (x === 0)
this.grid[y][x].char = '<';
else
this.grid[y][x].char = '>';
}
}
forceIntegrityOnTheSides() {
for (let side = 0; side < 2; side += 1) {
for (let y = 0; y < this.height; y += 1) {
const currY = y;
const currX = side * (this.width - 1);
this.forceIntegrityOn(currY, currX);
}
for (let x = 0; x < this.width; x += 1) {
const currX = x;
const currY = side * (this.height - 1);
this.forceIntegrityOn(currY, currX);
}
}
}
cutHeight(height, heightAlign) {

@@ -105,2 +135,3 @@ const prevHeight = this.height;

this.locationDescriptors.cut(this.height, this.width);
this.forceIntegrityOnTheSides();
return this;

@@ -111,2 +142,3 @@ case 'middle':

this.cutHeight(height, 'end');
this.forceIntegrityOnTheSides();
return this;

@@ -126,2 +158,3 @@ }

this.locationDescriptors.cut(this.height, this.width);
this.forceIntegrityOnTheSides();
return this;

@@ -132,6 +165,7 @@ case 'middle':

this.cutWidth(width, 'end');
this.forceIntegrityOnTheSides();
return this;
}
}
setHeight(height, heightAlign, char = new RichChar(' ')) {
setHeight(height, heightAlign, char) {
if (this.height === height)

@@ -156,3 +190,3 @@ return this;

}
setWidth(width, widthAlign, char = new RichChar(' ')) {
setWidth(width, widthAlign, char) {
if (this.width === width)

@@ -159,0 +193,0 @@ return this;

@@ -11,2 +11,3 @@ export interface CharAttributes {

}
export type CharAttributesWithoutDouble = Omit<CharAttributes, 'doubleHeight' | 'doubleWidth'>;
export type ApplicableCharAttributes = Omit<CharAttributes, 'charset'>;

@@ -13,0 +14,0 @@ export type Align = 'start' | 'middle' | 'end';

@@ -10,1 +10,2 @@ import { Align, FullPadding, MinitelObjectAttributes, Padding } from './types.js';

export declare function toBitArray(char: string): number[];
export declare function getDeltaFromSetting(size: number, setInto: number, align: Align): number;

@@ -7,3 +7,3 @@ export const alignInvrt = {

export function inheritedProps(props) {
const inheritedProps = ['fillChar', 'fg', 'textAlign', 'bg', 'underline', 'noBlink', 'invert', 'doubleWidth', 'doubleHeight', 'wrap'];
const inheritedProps = ['fillChar', 'fg', 'textAlign', 'bg', 'underline', 'doubleWidth', 'doubleHeight', 'noBlink', 'invert', 'wrap'];
const result = {};

@@ -45,1 +45,8 @@ let inheritedProp;

}
export function getDeltaFromSetting(size, setInto, align) {
if (align === 'start')
return 0;
if (align === 'end')
return setInto - size;
return Math.floor((setInto - size) / 2);
}
{
"name": "minitel-standalone",
"version": "1.10.2",
"version": "2.0.0",
"description": "A standalone package for minitel components",

@@ -24,3 +24,5 @@ "main": "dist/index.js",

"@types/node": "^20.12.12",
"typescript": "^5.4.5"
"typescript": "^5.4.5",
"ws": "^8.18.0",
"ws-duplex-bridge": "^1.0.1"
},

@@ -27,0 +29,0 @@ "dependencies": {

@@ -119,10 +119,12 @@ import { EventEmitter } from 'node:events';

if (attributes.width != null) result.setWidth(attributes.width, 'end');
if (attributes.height != null) result.setHeight(attributes.height, 'end');
if (attributes.width != null) result.setWidth(attributes.width, 'end', fillChar);
if (attributes.height != null) result.setHeight(attributes.height, 'end', fillChar);
result.pad(pad, fillChar);
// Descriptor before pad, is this the right choice?
// Future you: Yes. Yes it is.
// Future you 5 minutes later: Actually you know what
if (this.keepElmDesc) result.locationDescriptors.add(this, new LocationDescriptor(0, 0, result.width, result.height));
result.pad(pad, fillChar);
return result;

@@ -149,2 +151,79 @@ }

}
mapLocation(attributes: T, inheritMe: Partial<T>, nextNode: MinitelObject, nodes: MinitelObject[], weAt: number): LocationDescriptor {
return nextNode.mapLocationWrapper(inheritMe, {}, nodes, weAt)
}
mapLocationWrapper(inheritedAttributes: Partial<T>, forcedAttributes: Partial<T>, nodes: MinitelObject[], weAt: number): LocationDescriptor {
const nextNode: MinitelObject | undefined = nodes[weAt + 1];
const nextNodeIdx = nextNode && this.children.indexOf(nextNode);
if (nextNodeIdx === -1) {
throw new Error(`Next node was not found in children. This behaviour is unexpected; please contact the owner of minitel-standalone.`);
}
const attributes: T = {
...this.defaultAttributes,
...inheritedAttributes,
...this.attributes,
...forcedAttributes,
};
const pad = padding.normalise(attributes.pad);
attributes.width = attributes.width != null ? padding.exludeX(attributes.width, pad) : null;
attributes.height = attributes.height != null ? padding.exludeY(attributes.height, pad) : null;
if (!nextNode) {
const dimensions = this.getDimensionsWrapper(attributes, inheritedProps({
...inheritedAttributes,
...this.attributes,
...forcedAttributes,
}));
return new LocationDescriptor(0, 0, dimensions.width, dimensions.height);
}
let result = this.mapLocation(attributes, inheritedProps({
...inheritedAttributes,
...this.attributes,
...forcedAttributes,
}), nextNode, nodes, weAt + 1);
result.x += pad[0];
result.y += pad[3];
return result;
}
get parentList(): MinitelObject[] {
return [...(this.parent?.parentList || []), this];
}
scrollIntoView(context?: MinitelObject & { scrollDelta: [number, number] }): void {
if (!context) {
const parentList = this.parentList.filter((v): v is MinitelObject & { scrollDelta: [number, number] } => 'scrollDelta' in v);
for (let i = 0; i < parentList.length - 1; i += 1) parentList[i + 1].scrollIntoView(parentList[i]);
this.scrollIntoView(parentList.at(-1));
return;
}
const pathToThis = this.parentList;
const pathToScrollable = context.parentList;
const thisPos = this.minitel.mapLocationWrapper({}, {}, pathToThis, 0);
const scrollablePos = this.minitel.mapLocationWrapper({}, {}, pathToScrollable, 0);
const [relY, relX] = [thisPos.y - scrollablePos.y, thisPos.x - scrollablePos.x];
if (relY < 0) {
context.scrollDelta[0] += relY;
} else if (relY + thisPos.h > scrollablePos.h) {
context.scrollDelta[0] -= scrollablePos.h - (relY + thisPos.h);
}
if (relX < 0) {
context.scrollDelta[1] += relX;
} else if (relX + thisPos.w > scrollablePos.w) {
context.scrollDelta[1] -= scrollablePos.w - (relX + thisPos.w);
}
}
}

@@ -7,2 +7,3 @@ import { MinitelObject } from './minitelobject.js';

import type { Minitel } from '../index.js';
import { LocationDescriptor } from '../locationdescriptor.js';

@@ -102,2 +103,6 @@ export class TextNode extends MinitelObject {

}
mapLocation(attributes: MinitelObjectAttributes, inheritMe: Partial<MinitelObjectAttributes>, nextNode: MinitelObject): LocationDescriptor {
throw new Error('TextNode doesn\'t have children, and therefore can\'t mapLocation');
}
}

@@ -15,3 +15,3 @@ import { MinitelObject } from '../abstract/minitelobject.js';

defaultAttributes = Container.defaultAttributes as T;
constructor(children = [], attributes: Partial<T>, minitel: Minitel) {
constructor(children: MinitelObject[] = [], attributes: Partial<T>, minitel: Minitel) {
if (children.length > 1) throw new Error('Container must only include one element');

@@ -18,0 +18,0 @@ super([], attributes, minitel);

import { FocusableAttributes as FocusableIfaceAttributes, Focusable as FocusableIface } from '../abstract/focusable.js';
import { MinitelObject } from '../abstract/minitelobject.js';
import { Container, ContainerAttributes } from './container.js';

@@ -20,12 +21,12 @@ import type { Minitel } from './minitel.js';

keepElmDesc: true = true;
private artificialBlink: NodeJS.Timeout | null = null;
set focused(val) {
if (this._focused !== val) this.minitel.invalidateRender();
if (val) {
if (this.minitel.focusedObj) this.minitel.focusedObj.focused = false;
// console.log(this.minitel.focusedObj, this.minitel.focusedObj === this);
if (this.minitel.focusedObj && this.minitel.focusedObj !== this) this.minitel.focusedObj.focused = false;
if (this._focused !== val) this.attributes.onFocus?.();
this._focused = true;
this.attributes.onFocus?.();
} else {
if (this._focused !== val) this.attributes.onBlur?.();
this._focused = false;
this.attributes.onBlur?.();
}

@@ -36,3 +37,3 @@ }

}
constructor(children = [], attributes: Partial<FocusableAttributes>, minitel: Minitel) {
constructor(children: MinitelObject[] = [], attributes: Partial<FocusableAttributes>, minitel: Minitel) {
super(children, attributes, minitel);

@@ -39,0 +40,0 @@ }

@@ -73,8 +73,8 @@ import { Focusable, FocusableAttributes } from '../abstract/focusable.js';

if (val) {
if (this.minitel.focusedObj) this.minitel.focusedObj.focused = false;
if (this.minitel.focusedObj && this.minitel.focusedObj !== this) this.minitel.focusedObj.focused = false;
if (this._focused !== val) this.attributes.onFocus?.();
this._focused = true;
this.attributes.onFocus?.();
} else {
if (this._focused !== val) this.attributes.onBlur?.();
this._focused = false;
this.attributes.onBlur?.();
}

@@ -81,0 +81,0 @@ }

import { Duplex } from 'stream';
import { Container, ContainerAttributes } from './container.js';
import { RichCharGrid } from '../richchargrid.js';
import { CharAttributes, MinitelObjectAttributes } from '../types.js';
import { CharAttributes } from '../types.js';
import { SingletonArray } from '../singleton.js';

@@ -127,3 +127,2 @@ import { MinitelObject } from '../abstract/minitelobject.js';

current = current.next;
debugger;
}

@@ -176,2 +175,3 @@ if (current) {

if (err instanceof InvalidRender) {
console.error(err);
return this.renderString();

@@ -194,2 +194,4 @@ } else {

// console.log(this.previousRender.toString());
for (let lineIdx in renderGrid.grid) {

@@ -240,3 +242,3 @@ if (+lineIdx === 0 && this.settings.statusBar) outputString.push('\x1f\x40\x41');

outputString.push(typeof char.char === 'string' ? char.char : ['', ' '][char.delta[0]])
outputString.push(typeof char.char === 'string' ? char.char : ['', ' '].at(char.delta[0])!)
skippedACharCounter = 0;

@@ -286,3 +288,3 @@ }

const isInTree = this.has(this.focusedObj);
this.focusedObj.focused = isInTree;
if (this.focusedObj.focused !== isInTree) this.focusedObj.focused = isInTree;
if (isInTree) return;

@@ -295,3 +297,3 @@ this.focusedObj = null;

if (this.focusedObj) this.focusedObj.focused = true;
if (this.focusedObj && !this.focusedObj.focused) this.focusedObj.focused = true;
}

@@ -311,3 +313,3 @@ focusDelta(delta: 1 | -1) {

if (this.focusedObj) this.focusedObj.focused = false;
if (this.focusedObj && this.focusedObj.focused) this.focusedObj.focused = false;
this.focusedObj = focusables[curr];

@@ -314,0 +316,0 @@ this.focusedObj.focused = true;

@@ -9,2 +9,3 @@ import { MinitelObject } from '../abstract/minitelobject.js';

import { Span } from './span.js';
import { LocationDescriptor } from '../locationdescriptor.js';

@@ -41,2 +42,26 @@ export class Paragraph extends MinitelObject {

}
mapLocation(attributes: MinitelObjectAttributes, inheritMe: Partial<MinitelObjectAttributes>, nextNode: MinitelObject<MinitelObjectAttributes, Record<string, any[]>>, nodes: MinitelObject<MinitelObjectAttributes, Record<string, any[]>>[], weAt: number): LocationDescriptor {
const originalLocationDescriptor = nextNode.mapLocationWrapper(inheritMe, {}, nodes, weAt);
const lines = [new RichCharGrid([[]])]; // Again, if someone smarter than me can figure out an elegant way, suit urself
for (let child of this.children) {
if (child === nextNode) {
originalLocationDescriptor.x += lines.at(-1)!.width;
originalLocationDescriptor.y += lines.length;
return originalLocationDescriptor;
}
const render = child.renderLines(inheritMe, {
width: attributes.width,
forcedIndent: lines.at(-1)!.width,
});
const newMaxIdx = lines.length - 1;
for (let lineIdx in render) {
if (+lineIdx !== 0) {
lines[newMaxIdx + +lineIdx] = new RichCharGrid([[]]);
}
lines[newMaxIdx + +lineIdx].mergeX(render[+lineIdx], 'end');
}
}
throw new Error("Something unexpected happened: Provided nextNode was not among my children!");
}
render(attributes: MinitelObjectAttributes, inheritMe: Partial<MinitelObjectAttributes>) {

@@ -43,0 +68,0 @@ const fillChar = new RichChar(attributes.fillChar, attributes).noSize();

import { Focusable } from '../abstract/focusable.js';
import { MinitelObject } from '../abstract/minitelobject.js';
import { LocationDescriptor } from '../locationdescriptor.js';
import { RichChar } from '../richchar.js';

@@ -42,8 +44,8 @@ import { RichCharGrid } from '../richchargrid.js';

if (val) {
if (this.minitel.focusedObj) this.minitel.focusedObj.focused = false;
if (this.minitel.focusedObj && this.minitel.focusedObj !== this) this.minitel.focusedObj.focused = false;
if (this._focused !== val) this.attributes.onFocus?.();
this._focused = true;
this.attributes.onFocus?.();
} else {
if (this._focused !== val) this.attributes.onBlur?.();
this._focused = false;
this.attributes.onBlur?.();
}

@@ -67,3 +69,3 @@ }

}
constructor(children = [], attributes: Partial<ScrollableAttributes>, minitel: Minitel) {
constructor(children: MinitelObject[] = [], attributes: Partial<ScrollableAttributes>, minitel: Minitel) {
super(children, attributes, minitel);

@@ -170,2 +172,9 @@

}
mapLocation(attributes: ScrollableAttributes, inheritMe: Partial<ScrollableAttributes>, nextNode: MinitelObject, nodes: MinitelObject[], weAt: number): LocationDescriptor {
const location = nextNode.mapLocationWrapper(inheritMe, {}, nodes, weAt);
location.x -= this.scrollDelta[1];
location.y -= this.scrollDelta[0];
return location;
}
render(attributes: ScrollableAttributes, inheritMe: Partial<ScrollableAttributes>) {

@@ -196,3 +205,5 @@ // now its 3 am and i don't know how i'll read back

const width = attributes.width != null && attributes.overflowX === 'hidden'
? attributes.width - 1
? attributes.overflowY === 'noscrollbar'
? attributes.width
: attributes.width - 1
: null;

@@ -216,4 +227,8 @@

if (!autoedX) {
const height = attributes.height != null ? attributes.height - 1 : null;
const height = attributes.height != null // && attributes.overflowX === 'hidden' // we already know that
? attributes.overflowX === 'noscrollbar'
? attributes.height
: attributes.height - 1
: null;
renderAttributes = { ...attributes, height, width: null };

@@ -236,3 +251,2 @@ }

const maxScrollSizeY = attributes.overflowX !== 'hidden' && attributes.overflowX !== 'noscrollbar' && !autoedX && attributes.height != null

@@ -239,0 +253,0 @@ ? attributes.height - 1

import { MinitelObject } from '../abstract/minitelobject.js';
import { LocationDescriptor } from '../locationdescriptor.js';
import { RichChar } from '../richchar.js';
import { RichCharGrid } from '../richchargrid.js';
import { Align, MinitelObjectAttributes } from '../types.js';
import { getDeltaFromSetting } from '../utils.js';
import { alignInvrt } from '../utils.js';

@@ -16,3 +18,3 @@ import type { Minitel } from './minitel.js';

defaultAttributes = XJoin.defaultAttributes;
constructor(children: MinitelObject[], attributes: Partial<MinitelObjectAttributes>, minitel: Minitel) {
constructor(children: MinitelObject[], attributes: Partial<XJoinAttributes>, minitel: Minitel) {
super(children, attributes, minitel);

@@ -71,2 +73,99 @@ }

}
mapLocation(attributes: XJoinAttributes, inheritMe: Partial<XJoinAttributes>, nextNode: MinitelObject, nodes: MinitelObject<MinitelObjectAttributes, Record<string, any[]>>[], weAt: number): LocationDescriptor {
const heightIfStretch = attributes.height || this.children.reduce((p, c) => {
const h = c.getDimensionsWrapper(inheritMe).height;
if (h == null) return p;
return Math.max(p, h);
}, -Infinity);
let cumulatedWidth = 0;
let nextMapLocation: LocationDescriptor | null = null as LocationDescriptor | null;
const rendersNoFlexGrow = this.children.map((v) => {
if (v.attributes.flexGrow) return null;
const newOptions = {
...(attributes.heightAlign === 'stretch' ? { height: heightIfStretch } : {}),
};
if (v === nextNode) nextMapLocation = v.mapLocationWrapper(inheritMe, newOptions, nodes, weAt);
const render = v.getDimensionsWrapper(inheritMe, newOptions);
cumulatedWidth += render.width;
return [v, render];
});
const flexGrowTotal = this.children.reduce((p, c) => p + +(c.attributes.flexGrow || 0), 0);
const remainingSpace = attributes.width != null ? attributes.width - cumulatedWidth : null;
const unitOfFlexGrowSpace = remainingSpace != null ? remainingSpace / flexGrowTotal : null;
let usedRemainingSpace = 0;
const rendersYesFlexGrow = this.children.map((v) => {
if (!v.attributes.flexGrow) return null;
let newOptions = {};
if (unitOfFlexGrowSpace != null && remainingSpace != null) {
const prevUsedRemSpace = usedRemainingSpace;
usedRemainingSpace += unitOfFlexGrowSpace;
newOptions = {
...(attributes.heightAlign === 'stretch' ? { height: heightIfStretch } : {}),
width: Math.round(usedRemainingSpace) - Math.round(prevUsedRemSpace),
};
}
if (v === nextNode) nextMapLocation = v.mapLocationWrapper(inheritMe, newOptions, nodes, weAt);
return [v, v.getDimensionsWrapper(inheritMe, newOptions)];
});
if (!(nextMapLocation instanceof LocationDescriptor)) throw new Error('nextNode was not within children; this is fatal for xjoin');
const renders = rendersNoFlexGrow.map((v, i) => v != null ? v : rendersYesFlexGrow[i]) as [MinitelObject, {
width: number;
height: number;
}][];
const height = attributes.heightAlign === 'stretch'
? heightIfStretch
: attributes.height || Math.max(...renders.map((v) => v[1].height));
const contentsWidth = renders.reduce((c, v) => c + v[1].width, 0);
// space-between: w / (n - 1)
// space-around: w / n
// space-evenly: w / (n + 1)
let gapWidth: number;
if (typeof attributes.gap === 'number') {
gapWidth = attributes.gap;
} else if (attributes.width != null) {
const mappingTable = {
'space-between': renders.length - 1,
'space-around': renders.length,
'space-evenly': renders.length + 1,
};
gapWidth = (attributes.width - contentsWidth) / mappingTable[attributes.gap];
} else {
gapWidth = 0;
}
let gapCumul = 0;
let xCumul = 0;
for (let render of renders) {
if (render !== renders[0]) {
const lastCumul = gapCumul;
gapCumul += gapWidth;
xCumul += Math.round(gapCumul) - Math.round(lastCumul);
}
if (render[0] === nextNode) {
if (attributes.heightAlign !== 'stretch') {
nextMapLocation.y += getDeltaFromSetting(nextMapLocation.h, height, alignInvrt[attributes.heightAlign]);
}
nextMapLocation.x += xCumul;
} else {
xCumul += render[1].width;
}
}
return nextMapLocation;
}
render(attributes: XJoinAttributes, inheritMe: Partial<XJoinAttributes>) {

@@ -73,0 +172,0 @@ const fillChar = new RichChar(attributes.fillChar, attributes).noSize();

import { MinitelObject } from '../abstract/minitelobject.js';
import { LocationDescriptor } from '../locationdescriptor.js';
import { RichChar } from '../richchar.js';
import { RichCharGrid } from '../richchargrid.js';
import { Align, MinitelObjectAttributes } from '../types.js';
import { getDeltaFromSetting } from '../utils.js';
import { alignInvrt, inheritedProps } from '../utils.js';

@@ -16,3 +18,3 @@ import type { Minitel } from './minitel.js';

defaultAttributes = YJoin.defaultAttributes;
constructor(children: MinitelObject[], attributes: Partial<MinitelObjectAttributes>, minitel: Minitel) {
constructor(children: MinitelObject[], attributes: Partial<YJoinAttributes>, minitel: Minitel) {
super(children, attributes, minitel);

@@ -71,2 +73,100 @@ }

}
mapLocation(attributes: YJoinAttributes, inheritMe: Partial<YJoinAttributes>, nextNode: MinitelObject<MinitelObjectAttributes, Record<string, any[]>>, nodes: MinitelObject[], weAt: number): LocationDescriptor {
const widthIfStretch = attributes.width || this.children.reduce((p, c) => {
const w = c.getDimensionsWrapper(inheritMe).width;
if (w == null) return p;
return Math.max(p, w);
}, -Infinity);
let cumulatedHeight = 0;
let nextMapLocation: LocationDescriptor | null = null as LocationDescriptor | null;
const rendersNoFlexGrow = this.children.map((v) => {
if (v.attributes.flexGrow) return null;
const newOptions = {
...(attributes.widthAlign === 'stretch' ? { width: widthIfStretch } : {}),
};
if (v === nextNode) nextMapLocation = v.mapLocationWrapper(inheritMe, newOptions, nodes, weAt);
const render = v.getDimensionsWrapper(inheritMe, newOptions);
cumulatedHeight += render.width;
return [v, render];
});
const flexGrowTotal = this.children.reduce((p, c) => p + +(c.attributes.flexGrow || 0), 0);
const remainingSpace = attributes.height != null ? attributes.height - cumulatedHeight : null;
const unitOfFlexGrowSpace = remainingSpace != null ? remainingSpace / flexGrowTotal : null;
let usedRemainingSpace = 0;
const rendersYesFlexGrow = this.children.map((v) => {
if (!v.attributes.flexGrow) return null;
let newOptions = {};
if (unitOfFlexGrowSpace != null && remainingSpace != null) {
const prevUsedRemSpace = usedRemainingSpace;
usedRemainingSpace += unitOfFlexGrowSpace;
newOptions = {
...(attributes.widthAlign === 'stretch' ? { width: widthIfStretch } : {}),
height: Math.round(usedRemainingSpace) - Math.round(prevUsedRemSpace),
};
}
if (v === nextNode) nextMapLocation = v.mapLocationWrapper(inheritMe, newOptions, nodes, weAt);
return [v, v.getDimensionsWrapper(inheritMe, newOptions)];
});
if (!(nextMapLocation instanceof LocationDescriptor)) throw new Error('nextNode was not within children; this is fatal for xjoin');
const renders = rendersNoFlexGrow.map((v, i) => v != null ? v : rendersYesFlexGrow[i]) as [MinitelObject, {
width: number;
height: number;
}][];
const width = attributes.widthAlign === 'stretch'
? widthIfStretch
: attributes.width || Math.max(...renders.map((v) => v[1].width));
const contentsHeight = renders.reduce((c, v) => c + v[1].height, 0);
// space-between: w / (n - 1)
// space-around: w / n
// space-evenly: w / (n + 1)
let gapWidth: number;
if (typeof attributes.gap === 'number') {
gapWidth = attributes.gap;
} else if (attributes.height != null) {
const mappingTable = {
'space-between': renders.length - 1,
'space-around': renders.length,
'space-evenly': renders.length + 1,
};
gapWidth = (attributes.height - contentsHeight) / mappingTable[attributes.gap];
} else {
gapWidth = 0;
}
let gapCumul = 0;
let yCumul = 0;
for (let render of renders) {
if (render !== renders[0]) {
const lastCumul = gapCumul;
gapCumul += gapWidth;
yCumul += Math.round(gapCumul) - Math.round(lastCumul);
}
if (render[0] === nextNode) {
if (attributes.widthAlign !== 'stretch') {
nextMapLocation.x += getDeltaFromSetting(nextMapLocation.w, width, alignInvrt[attributes.widthAlign]);
}
nextMapLocation.y += yCumul;
} else {
yCumul += render[1].height;
}
}
return nextMapLocation;
}
render(attributes: YJoinAttributes, inheritMe: Partial<YJoinAttributes>) {

@@ -73,0 +173,0 @@ const fillChar = new RichChar(attributes.fillChar, attributes).noSize();

import { MinitelObject } from '../abstract/minitelobject.js';
import { LocationDescriptor } from '../locationdescriptor.js';
import { RichChar } from '../richchar.js';
import { RichCharGrid } from '../richchargrid.js';
import { Align, MinitelObjectAttributes } from '../types.js';
import { getDeltaFromSetting } from '../utils.js';
import { alignInvrt, inheritedProps } from '../utils.js';

@@ -31,2 +33,23 @@ import type { Minitel } from './minitel.js';

}
mapLocation(attributes: ZJoinAttributes, inheritMe: Partial<ZJoinAttributes>, nextNode: MinitelObject, nodes: MinitelObject[], weAt: number): LocationDescriptor {
const renders = this.children.map((v) => [v, v.getDimensionsWrapper(inheritMe, {
width: attributes.width,
height: attributes.height,
})] as const);
const maxWidth = Math.max(...renders.map((v) => v[1].width));
const maxHeight = Math.max(...renders.map((v) => v[1].height));
const relevant = renders.find((v) => v[0] === nextNode)!;
const prevLocation = nextNode.mapLocationWrapper(inheritMe, {
width: attributes.width,
height: attributes.height,
}, nodes, weAt);
prevLocation.x += getDeltaFromSetting(relevant[1].width, maxWidth, attributes.widthAlign);
prevLocation.y += getDeltaFromSetting(relevant[1].height, maxWidth, attributes.heightAlign);
return prevLocation;
}
render(attributes: ZJoinAttributes, inheritMe: Partial<ZJoinAttributes>) {

@@ -33,0 +56,0 @@ const fillChar = new RichChar(attributes.fillChar, attributes).noSize();

@@ -1,2 +0,2 @@

import { CharAttributes } from './types.js';
import { CharAttributes, CharAttributesWithoutDouble } from './types.js';

@@ -30,3 +30,3 @@ export class RichChar<T> {

const result = [];
const offsets: Record<keyof Omit<CharAttributes, 'doubleHeight' | 'doubleWidth'>, number | number[]> = {
const offsets: Record<keyof CharAttributesWithoutDouble, number | number[]> = {
charset: [0x0f, 0x0e, 0x19],

@@ -39,3 +39,3 @@ noBlink: 0x48,

};
let attribute: keyof Omit<CharAttributes, 'doubleHeight' | 'doubleWidth'>;
let attribute: keyof CharAttributesWithoutDouble;
for (attribute in offsets) {

@@ -42,0 +42,0 @@ if (attribute in attributes) {

import { LocationDescriptors } from './locationdescriptor.js';
import { RichChar } from './richchar.js';
import { Align, CharAttributes, FullPadding, Padding } from './types.js';
import { Align, CharAttributes, FullPadding } from './types.js';

@@ -98,2 +98,30 @@ export class RichCharGrid {

forceIntegrityOn(y: number, x: number) {
const cell = this.grid[y][x];
if (!cell.delta) return;
const newY = y + cell.delta[0];
const newX = x + cell.delta[1];
if (!(newY in this.grid) || !(newX in this.grid[newY])) {
this.grid[y][x] = cell.copy();
this.grid[y][x].delta = undefined;
this.grid[y][x].actualChar = undefined;
if (x === 0) this.grid[y][x].char = '<';
else this.grid[y][x].char = '>';
}
}
forceIntegrityOnTheSides() {
for (let side = 0; side < 2; side += 1) {
for (let y = 0; y < this.height; y += 1) {
const currY = y;
const currX = side * (this.width - 1);
this.forceIntegrityOn(currY, currX);
}
for (let x = 0; x < this.width; x += 1) {
const currX = x;
const currY = side * (this.height - 1);
this.forceIntegrityOn(currY, currX);
}
}
}
cutHeight(height: number, heightAlign: Align) {

@@ -112,2 +140,3 @@ const prevHeight = this.height;

this.locationDescriptors.cut(this.height, this.width);
this.forceIntegrityOnTheSides();
return this;

@@ -119,2 +148,3 @@ case 'middle':

this.cutHeight(height, 'end');
this.forceIntegrityOnTheSides();
return this;

@@ -136,2 +166,3 @@ }

this.locationDescriptors.cut(this.height, this.width);
this.forceIntegrityOnTheSides();
return this;

@@ -143,2 +174,3 @@ case 'middle':

this.cutWidth(width, 'end');
this.forceIntegrityOnTheSides();
return this;

@@ -148,3 +180,3 @@ }

setHeight(height: number, heightAlign: Align, char = new RichChar(' ')) {
setHeight(height: number, heightAlign: Align, char: RichChar<string>) {
if (this.height === height) return this;

@@ -167,3 +199,3 @@ if (this.height > height) return this.cutHeight(height, heightAlign);

}
setWidth(width: number, widthAlign: Align, char = new RichChar(' ')) {
setWidth(width: number, widthAlign: Align, char: RichChar<string>) {
if (this.width === width) return this;

@@ -170,0 +202,0 @@ if (this.width > width) return this.cutWidth(width, widthAlign);

@@ -17,2 +17,3 @@ // import { InputAttributes } fr``om './components/input.js';

}
export type CharAttributesWithoutDouble = Omit<CharAttributes, 'doubleHeight' | 'doubleWidth'>;
export type ApplicableCharAttributes = Omit<CharAttributes, 'charset'>;

@@ -19,0 +20,0 @@ export type Align = 'start' | 'middle' | 'end';

@@ -10,3 +10,3 @@ import { Align, FullPadding, MinitelObjectAttributes, Padding } from './types.js';

export function inheritedProps<T extends MinitelObjectAttributes> (props: Partial<T>): Partial<T> {
const inheritedProps = ['fillChar', 'fg', 'textAlign', 'bg', 'underline', 'noBlink', 'invert', 'doubleWidth', 'doubleHeight', 'wrap'] as const;
const inheritedProps = ['fillChar', 'fg', 'textAlign', 'bg', 'underline', 'doubleWidth', 'doubleHeight', 'noBlink', 'invert', 'wrap'] as const;
const result: Partial<T> = {};

@@ -49,1 +49,8 @@

}
export function getDeltaFromSetting(size: number, setInto: number, align: Align) {
if (align === 'start') return 0;
if (align === 'end') return setInto - size;
return Math.floor((setInto - size) / 2);
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc