@techfides/ui-library-core 0.5.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 TechFides
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,10 @@
1
+ # @techfides/ui-library-core
2
+
3
+ The framework-free logic of the TechFides UI library: the words every component says on its own
4
+ behalf and the languages that translate them, the number tally that counts a figure up, the
5
+ chart option builders, field state, and the DOM maths shared by every binding.
6
+
7
+ You do not install this directly. `@techfides/ui-library-vue` depends on it and brings it along;
8
+ a future React binding will do the same, so the two bindings cannot disagree on behaviour.
9
+
10
+ ESM only, Node 24 or newer. MIT.
package/dist/aria.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ //#region src/aria.d.ts
2
+ declare const regionOf: (label: string | undefined) => Record<string, string>;
3
+ //#endregion
4
+ export { regionOf };
package/dist/aria.js ADDED
@@ -0,0 +1,12 @@
1
+ //#region src/aria.ts
2
+ const EMPTY = "";
3
+ const regionOf = (label) => {
4
+ const spoken = label ?? EMPTY;
5
+ if (spoken === EMPTY) return {};
6
+ return {
7
+ "aria-label": spoken,
8
+ role: "region"
9
+ };
10
+ };
11
+ //#endregion
12
+ export { regionOf };
@@ -0,0 +1,12 @@
1
+ //#region src/charts/animation.ts
2
+ const CHART_EASING = "cubicOut";
3
+ const chartAnimation = (durationMs) => ({
4
+ animation: true,
5
+ animationDuration: durationMs,
6
+ animationDurationUpdate: durationMs,
7
+ animationEasing: CHART_EASING,
8
+ animationEasingUpdate: CHART_EASING
9
+ });
10
+ const chartStagger = (stepMs) => (index) => index * stepMs;
11
+ //#endregion
12
+ export { CHART_EASING, chartAnimation, chartStagger };
@@ -0,0 +1,21 @@
1
+ import { EChartsOption } from "echarts";
2
+ //#region src/charts/bars.d.ts
3
+ interface BarsAccent {
4
+ hi: string;
5
+ surface: string;
6
+ }
7
+ interface BarsPoint {
8
+ label: string;
9
+ value: number | null;
10
+ }
11
+ interface BarsOptionInput {
12
+ accent: BarsAccent;
13
+ durationMs: number;
14
+ labelColor: string;
15
+ radius: number;
16
+ stateDurationMs: number;
17
+ values: readonly BarsPoint[];
18
+ }
19
+ declare const barsOption: (input: BarsOptionInput) => EChartsOption;
20
+ //#endregion
21
+ export { type BarsAccent, type BarsOptionInput, type BarsPoint, barsOption };
@@ -0,0 +1,59 @@
1
+ import { CHART_EASING, chartAnimation, chartStagger } from "./animation.js";
2
+ import { verticalGradient } from "./paint.js";
3
+ import { chartTooltip, formatCallbackValue } from "./tooltip.js";
4
+ //#region src/charts/bars.ts
5
+ const GRID = {
6
+ bottom: 22,
7
+ left: 4,
8
+ right: 4,
9
+ top: 8
10
+ };
11
+ const BAR_CATEGORY_GAP = "35%";
12
+ const LABEL_FONT_SIZE = 11;
13
+ const STAGGER_MS = 40;
14
+ const EMPTY_LENGTH = 0;
15
+ const FIRST_INDEX = 0;
16
+ const barPointFormatter = (params) => {
17
+ const point = params[FIRST_INDEX];
18
+ if (!point) return "";
19
+ return `${point.name}: ${formatCallbackValue(point.value)}`;
20
+ };
21
+ const barsOption = (input) => {
22
+ if (input.values.length === EMPTY_LENGTH) return { series: [] };
23
+ return {
24
+ ...chartAnimation(input.durationMs),
25
+ grid: GRID,
26
+ series: [{
27
+ animationDelay: chartStagger(STAGGER_MS),
28
+ barCategoryGap: BAR_CATEGORY_GAP,
29
+ data: input.values.map((point) => point.value),
30
+ emphasis: { disabled: true },
31
+ itemStyle: {
32
+ borderRadius: input.radius,
33
+ color: verticalGradient(input.accent.hi, input.accent.surface)
34
+ },
35
+ stateAnimation: {
36
+ duration: input.stateDurationMs,
37
+ easing: CHART_EASING
38
+ },
39
+ type: "bar"
40
+ }],
41
+ tooltip: chartTooltip(barPointFormatter),
42
+ xAxis: {
43
+ axisLabel: {
44
+ color: input.labelColor,
45
+ fontSize: LABEL_FONT_SIZE
46
+ },
47
+ axisLine: { show: false },
48
+ axisTick: { show: false },
49
+ data: input.values.map((point) => point.label),
50
+ type: "category"
51
+ },
52
+ yAxis: {
53
+ show: false,
54
+ type: "value"
55
+ }
56
+ };
57
+ };
58
+ //#endregion
59
+ export { barsOption };
@@ -0,0 +1,19 @@
1
+ import { EChartsOption } from "echarts";
2
+ //#region src/charts/groupedBars.d.ts
3
+ interface GroupedBarsSeries {
4
+ color: string;
5
+ name: string;
6
+ values: readonly (number | null)[];
7
+ }
8
+ interface GroupedBarsOptionInput {
9
+ categories: readonly string[];
10
+ durationMs: number;
11
+ labelColor: string;
12
+ radius: number;
13
+ series: readonly GroupedBarsSeries[];
14
+ stateDurationMs: number;
15
+ valueFormat?: (value: number) => string;
16
+ }
17
+ declare const groupedBarsOption: (input: GroupedBarsOptionInput) => EChartsOption;
18
+ //#endregion
19
+ export { type GroupedBarsOptionInput, type GroupedBarsSeries, groupedBarsOption };
@@ -0,0 +1,80 @@
1
+ import { CHART_EASING, chartAnimation } from "./animation.js";
2
+ import { chartTooltip, formatCallbackValue } from "./tooltip.js";
3
+ //#region src/charts/groupedBars.ts
4
+ const GRID = {
5
+ bottom: 22,
6
+ left: 4,
7
+ right: 4,
8
+ top: 8
9
+ };
10
+ const BAR_CATEGORY_GAP = "35%";
11
+ const LABEL_FONT_SIZE = 11;
12
+ const EMPTY_LENGTH = 0;
13
+ const FIRST_INDEX = 0;
14
+ const DOT_CLASS = "inline-block size-2 flex-none rounded-tf-pill";
15
+ const ROW_CLASS = "flex items-center justify-between gap-3";
16
+ const NAME_CLASS = "flex items-center gap-1.5";
17
+ const VALUE_CLASS = "font-semibold tabular-nums";
18
+ const formatValue = (value, valueFormat) => {
19
+ if (typeof value === "number") return valueFormat(value);
20
+ return formatCallbackValue(value);
21
+ };
22
+ const NO_COLOR = "";
23
+ const colorOf = (point) => {
24
+ if (typeof point.color === "string") return point.color;
25
+ return NO_COLOR;
26
+ };
27
+ const groupedBarRow = (point, valueFormat) => {
28
+ const color = colorOf(point);
29
+ const name = formatCallbackValue(point.seriesName);
30
+ return `<div class="${ROW_CLASS}"><span class="${NAME_CLASS}"><span aria-hidden="true" class="${DOT_CLASS}" style="background:${color}"></span>${name}</span><span class="${VALUE_CLASS}">${formatValue(point.value, valueFormat)}</span></div>`;
31
+ };
32
+ const groupedBarsFormatter = (valueFormat) => (params) => {
33
+ const first = params[FIRST_INDEX];
34
+ if (!first) return "";
35
+ return `<div class="flex flex-col gap-1"><span class="font-semibold">${formatCallbackValue(first.name)}</span>${params.map((point) => groupedBarRow(point, valueFormat)).join("")}</div>`;
36
+ };
37
+ const IDENTITY_FORMAT = String;
38
+ const AXIS_SHADOW_COLOR = "rgb(255 255 255 / 9%)";
39
+ const groupedBarsOption = (input) => {
40
+ if (input.categories.length === EMPTY_LENGTH) return { series: [] };
41
+ const valueFormat = input.valueFormat ?? IDENTITY_FORMAT;
42
+ return {
43
+ ...chartAnimation(input.durationMs),
44
+ grid: GRID,
45
+ series: input.series.map((series) => ({
46
+ barCategoryGap: BAR_CATEGORY_GAP,
47
+ data: [...series.values],
48
+ itemStyle: {
49
+ borderRadius: input.radius,
50
+ color: series.color
51
+ },
52
+ name: series.name,
53
+ stateAnimation: {
54
+ duration: input.stateDurationMs,
55
+ easing: CHART_EASING
56
+ },
57
+ type: "bar"
58
+ })),
59
+ tooltip: chartTooltip(groupedBarsFormatter(valueFormat), "axis", {
60
+ shadowStyle: { color: AXIS_SHADOW_COLOR },
61
+ type: "shadow"
62
+ }),
63
+ xAxis: {
64
+ axisLabel: {
65
+ color: input.labelColor,
66
+ fontSize: LABEL_FONT_SIZE
67
+ },
68
+ axisLine: { show: false },
69
+ axisTick: { show: false },
70
+ data: [...input.categories],
71
+ type: "category"
72
+ },
73
+ yAxis: {
74
+ show: false,
75
+ type: "value"
76
+ }
77
+ };
78
+ };
79
+ //#endregion
80
+ export { groupedBarsOption };
@@ -0,0 +1,24 @@
1
+ //#region src/charts/paint.ts
2
+ const TOP = 0;
3
+ const BOTTOM = 1;
4
+ const LEFT = 0;
5
+ const START = 0;
6
+ const END = 1;
7
+ const verticalGradient = (from, to) => ({
8
+ colorStops: [{
9
+ color: from,
10
+ offset: START
11
+ }, {
12
+ color: to,
13
+ offset: END
14
+ }],
15
+ global: false,
16
+ type: "linear",
17
+ x: LEFT,
18
+ x2: LEFT,
19
+ y: TOP,
20
+ y2: BOTTOM
21
+ });
22
+ const TRANSPARENT = "rgba(0, 0, 0, 0)";
23
+ //#endregion
24
+ export { TRANSPARENT, verticalGradient };
@@ -0,0 +1,16 @@
1
+ import { BarsAccent } from "./bars.js";
2
+ import { EChartsOption } from "echarts";
3
+ import { StatSparkShape } from "@techfides/ui-library-design";
4
+ //#region src/charts/spark.d.ts
5
+ type SparkAccent = BarsAccent;
6
+ interface SparkOptionInput {
7
+ accent: SparkAccent;
8
+ durationMs: number;
9
+ stateDurationMs: number;
10
+ radius: number;
11
+ shape: StatSparkShape;
12
+ values: readonly number[];
13
+ }
14
+ declare const sparkOption: (input: SparkOptionInput) => EChartsOption;
15
+ //#endregion
16
+ export { type SparkAccent, type SparkOptionInput, sparkOption };
@@ -0,0 +1,157 @@
1
+ import { CHART_EASING, chartAnimation, chartStagger } from "./animation.js";
2
+ import { TRANSPARENT, verticalGradient } from "./paint.js";
3
+ import { chartTooltip } from "./tooltip.js";
4
+ //#region src/charts/spark.ts
5
+ const LINE_WIDTH = 2;
6
+ const MARKER_SIZE = 5;
7
+ const MIN_SPAN = 1;
8
+ const EMPTY_LENGTH = 0;
9
+ const LAST_INDEX_OFFSET = 1;
10
+ const NO_GAP = 0;
11
+ const LINE_BOUNDARY_GAP = [NO_GAP, NO_GAP];
12
+ const LINE_GRID = {
13
+ bottom: 4,
14
+ left: 4,
15
+ right: 4,
16
+ top: 4
17
+ };
18
+ const BAR_GRID = {
19
+ bottom: 0,
20
+ left: 0,
21
+ right: 0,
22
+ top: 0
23
+ };
24
+ const BAR_CATEGORY_GAP = "25%";
25
+ const MIN_HEIGHT_RATIO = .15;
26
+ const BAR_AXIS_MAX = 1;
27
+ const BAR_AXIS_MIN = 0;
28
+ const AREA_OPACITY = .32;
29
+ const STAGGER_MS = 30;
30
+ const lastIndexOf = (values) => values.length - LAST_INDEX_OFFSET;
31
+ const NO_VALUE = 0;
32
+ const FIRST_INDEX = 0;
33
+ const pointFormatter = (values) => (params) => {
34
+ const point = params[FIRST_INDEX];
35
+ if (!point || typeof point.dataIndex !== "number") return String(NO_VALUE);
36
+ return String(values[point.dataIndex] ?? NO_VALUE);
37
+ };
38
+ const yRange = (values) => {
39
+ const min = Math.min(...values);
40
+ const max = Math.max(...values);
41
+ if (max === min) return {
42
+ max: min + MIN_SPAN,
43
+ min
44
+ };
45
+ return {
46
+ max,
47
+ min
48
+ };
49
+ };
50
+ const lineOption = (input) => {
51
+ const last = lastIndexOf(input.values);
52
+ const range = yRange(input.values);
53
+ const lastValue = input.values[last] ?? range.min;
54
+ return {
55
+ ...chartAnimation(input.durationMs),
56
+ grid: LINE_GRID,
57
+ series: [{
58
+ areaStyle: {
59
+ color: verticalGradient(input.accent.hi, TRANSPARENT),
60
+ opacity: AREA_OPACITY
61
+ },
62
+ data: input.values.map((value, index) => [index, value]),
63
+ emphasis: { disabled: true },
64
+ lineStyle: {
65
+ cap: "round",
66
+ color: input.accent.surface,
67
+ join: "round",
68
+ width: LINE_WIDTH
69
+ },
70
+ markPoint: {
71
+ animation: true,
72
+ data: [{
73
+ coord: [last, lastValue],
74
+ name: ""
75
+ }],
76
+ itemStyle: { color: input.accent.hi },
77
+ label: { show: false },
78
+ symbol: "circle",
79
+ symbolSize: MARKER_SIZE
80
+ },
81
+ showSymbol: false,
82
+ stateAnimation: {
83
+ duration: input.stateDurationMs,
84
+ easing: CHART_EASING
85
+ },
86
+ symbolSize: MARKER_SIZE,
87
+ type: "line"
88
+ }],
89
+ tooltip: chartTooltip(pointFormatter(input.values), "axis"),
90
+ xAxis: {
91
+ boundaryGap: LINE_BOUNDARY_GAP,
92
+ max: last,
93
+ min: 0,
94
+ show: false,
95
+ type: "value"
96
+ },
97
+ yAxis: {
98
+ max: range.max,
99
+ min: range.min,
100
+ show: false,
101
+ type: "value"
102
+ }
103
+ };
104
+ };
105
+ const barHeightRatio = (value, range) => {
106
+ const ratio = (value - range.min) / (range.max - range.min);
107
+ return Math.max(ratio, MIN_HEIGHT_RATIO);
108
+ };
109
+ const barOption = (input) => {
110
+ const last = lastIndexOf(input.values);
111
+ const range = yRange(input.values);
112
+ return {
113
+ ...chartAnimation(input.durationMs),
114
+ grid: BAR_GRID,
115
+ series: [{
116
+ animationDelay: chartStagger(STAGGER_MS),
117
+ barCategoryGap: BAR_CATEGORY_GAP,
118
+ data: input.values.map((value, index) => {
119
+ const height = barHeightRatio(value, range);
120
+ if (index === last) return {
121
+ itemStyle: { color: input.accent.hi },
122
+ value: height
123
+ };
124
+ return height;
125
+ }),
126
+ emphasis: { disabled: true },
127
+ itemStyle: {
128
+ borderRadius: input.radius,
129
+ color: verticalGradient(input.accent.hi, input.accent.surface)
130
+ },
131
+ stateAnimation: {
132
+ duration: input.stateDurationMs,
133
+ easing: CHART_EASING
134
+ },
135
+ type: "bar"
136
+ }],
137
+ tooltip: chartTooltip(pointFormatter(input.values)),
138
+ xAxis: {
139
+ data: input.values.map((_value, index) => String(index)),
140
+ show: false,
141
+ type: "category"
142
+ },
143
+ yAxis: {
144
+ max: BAR_AXIS_MAX,
145
+ min: BAR_AXIS_MIN,
146
+ show: false,
147
+ type: "value"
148
+ }
149
+ };
150
+ };
151
+ const sparkOption = (input) => {
152
+ if (input.values.length === EMPTY_LENGTH) return { series: [] };
153
+ if (input.shape === "bars") return barOption(input);
154
+ return lineOption(input);
155
+ };
156
+ //#endregion
157
+ export { sparkOption };
@@ -0,0 +1,39 @@
1
+ //#region src/charts/tooltip.ts
2
+ const TOOLTIP_CLASS = ["tf-edge-sweep tf-edge-plain rounded-tf-inline bg-tf-glass px-2 py-1", "font-tf-body text-tf-caption-sm text-tf-fg shadow-tf-float backdrop-blur-tf-glass"].join(" ");
3
+ const NO_CHROME_CSS = "box-shadow: none; pointer-events: none;";
4
+ const NO_CONTENT = "";
5
+ const SNAP_TO_CURSOR = 0;
6
+ const EMPTY_LENGTH = 0;
7
+ const DEFAULT_AXIS_POINTER = { type: "none" };
8
+ const appendToBody = () => document.body;
9
+ const formatCallbackValue = (value) => {
10
+ if (typeof value === "string" || typeof value === "number") return String(value);
11
+ return NO_CONTENT;
12
+ };
13
+ const asParams = (raw) => {
14
+ if (Array.isArray(raw)) return raw;
15
+ return [raw];
16
+ };
17
+ const chartTooltip = (formatter, trigger = "item", axisPointer = DEFAULT_AXIS_POINTER) => {
18
+ const base = {
19
+ appendTo: appendToBody,
20
+ backgroundColor: "transparent",
21
+ borderWidth: 0,
22
+ extraCssText: NO_CHROME_CSS,
23
+ formatter: (raw) => {
24
+ const params = asParams(raw);
25
+ if (params.length === EMPTY_LENGTH) return NO_CONTENT;
26
+ return `<div class="${TOOLTIP_CLASS}">${formatter(params)}</div>`;
27
+ },
28
+ padding: 0,
29
+ transitionDuration: SNAP_TO_CURSOR,
30
+ trigger
31
+ };
32
+ if (trigger === "axis") return {
33
+ ...base,
34
+ axisPointer
35
+ };
36
+ return base;
37
+ };
38
+ //#endregion
39
+ export { chartTooltip, formatCallbackValue };
@@ -0,0 +1,8 @@
1
+ //#region src/cookie.d.ts
2
+ declare const SIDEBAR_COOKIE = "tf-sidebar";
3
+ declare const cookieValue: (name: string) => string;
4
+ declare const rememberCookie: (name: string, value: string) => void;
5
+ declare const sidebarCookieValue: (collapsed: boolean) => string;
6
+ declare const sidebarCollapsedFrom: (value: string, fallback: boolean) => boolean;
7
+ //#endregion
8
+ export { SIDEBAR_COOKIE, cookieValue, rememberCookie, sidebarCollapsedFrom, sidebarCookieValue };
package/dist/cookie.js ADDED
@@ -0,0 +1,31 @@
1
+ //#region src/cookie.ts
2
+ const PATH = "path=/";
3
+ const SAME_SITE = "SameSite=Lax";
4
+ const WEEK_SECONDS = 604800;
5
+ const AFTER_NAME = 1;
6
+ const SIDEBAR_COOKIE = "tf-sidebar";
7
+ const NOTHING = "";
8
+ const inBrowser = () => typeof document !== "undefined";
9
+ const cookieValue = (name) => {
10
+ if (!inBrowser()) return NOTHING;
11
+ const found = document.cookie.split("; ").find((one) => one.startsWith(`${name}=`));
12
+ if (typeof found !== "string") return NOTHING;
13
+ return found.slice(name.length + AFTER_NAME);
14
+ };
15
+ const rememberCookie = (name, value) => {
16
+ if (!inBrowser()) return;
17
+ document.cookie = `${name}=${value}; ${PATH}; max-age=${String(WEEK_SECONDS)}; ${SAME_SITE}`;
18
+ };
19
+ const SIDEBAR_RAIL = "1";
20
+ const SIDEBAR_OPEN = "0";
21
+ const sidebarCookieValue = (collapsed) => {
22
+ if (collapsed) return SIDEBAR_RAIL;
23
+ return SIDEBAR_OPEN;
24
+ };
25
+ const sidebarCollapsedFrom = (value, fallback) => {
26
+ if (value === SIDEBAR_RAIL) return true;
27
+ if (value === SIDEBAR_OPEN) return false;
28
+ return fallback;
29
+ };
30
+ //#endregion
31
+ export { SIDEBAR_COOKIE, cookieValue, rememberCookie, sidebarCollapsedFrom, sidebarCookieValue };
@@ -0,0 +1,5 @@
1
+ import { Language } from "./words.js";
2
+ //#region src/czech.d.ts
3
+ declare const czech: Language;
4
+ //#endregion
5
+ export { czech };
package/dist/czech.js ADDED
@@ -0,0 +1,98 @@
1
+ //#region src/czech.ts
2
+ const SINGLE = 1;
3
+ const FEW_FIRST = 2;
4
+ const FEW_LAST = 4;
5
+ const results = (count, written) => {
6
+ if (count === SINGLE) return "1 výsledek";
7
+ if (count >= FEW_FIRST && count <= FEW_LAST) return `${written} výsledky`;
8
+ return `${written} výsledků`;
9
+ };
10
+ const czech = {
11
+ locale: "cs-CZ",
12
+ words: {
13
+ datePicker: {
14
+ calendar: "Kalendář",
15
+ choose: (day) => `Vybrat ${day}`,
16
+ chosen: (day) => `Vybráno, ${day}`,
17
+ clear: "Smazat data",
18
+ close: "Zavřít kalendář",
19
+ nextDecade: "Další dekáda",
20
+ nextMonth: "Další měsíc",
21
+ nextYear: "Další rok",
22
+ open: "Otevřít kalendář",
23
+ patternDay: "dd",
24
+ patternMonth: "mm",
25
+ patternYear: "rrrr",
26
+ pickMonth: "Vyberte měsíc",
27
+ pickYear: "Vyberte rok",
28
+ preset: (span) => `Vybrat ${span}`,
29
+ previousDecade: "Předchozí dekáda",
30
+ previousMonth: "Předchozí měsíc",
31
+ previousYear: "Předchozí rok",
32
+ rangeFrom: (day) => `Začít rozsah na ${day}`,
33
+ rangeTo: (day) => `Ukončit rozsah na ${day}`,
34
+ showDays: "Zobrazit dny",
35
+ showMonths: "Zobrazit měsíce",
36
+ showYears: "Zobrazit roky",
37
+ unavailable: (day) => `Nedostupné, ${day}`,
38
+ week: "Týd.",
39
+ weekNumber: (week) => `${week}. týden`
40
+ },
41
+ dialog: { close: "Zavřít" },
42
+ listbox: { empty: "Není z čeho vybírat" },
43
+ queue: { label: "Fronta" },
44
+ search: {
45
+ dismiss: "Esc zavře",
46
+ nothing: "Tomu nic neodpovídá",
47
+ results
48
+ },
49
+ select: { clear: "Zrušit výběr" },
50
+ sidebar: {
51
+ collapse: "Sbalit panel",
52
+ expand: "Rozbalit panel",
53
+ openMenu: "Otevřít menu"
54
+ },
55
+ stat: {
56
+ change: "Změna",
57
+ fell: "dolů",
58
+ rose: "nahoru"
59
+ },
60
+ table: {
61
+ actions: "Akce",
62
+ anything: "Cokoli",
63
+ clear: "Zrušit",
64
+ clearAll: "Zrušit filtry",
65
+ clearFilter: (column) => `Zrušit filtr na ${column}`,
66
+ clearSelection: "Zrušit označení",
67
+ done: "Hotovo",
68
+ emptyHint: "Až tu něco bude, uvidíte to zde.",
69
+ emptyTitle: "Zatím tu nic není",
70
+ expandRow: (row) => `Zobrazit více o řádku ${row}`,
71
+ filterBy: (column) => `Filtrovat ${column}`,
72
+ filterPick: (column) => `Vyberte z ${column}`,
73
+ filterRange: (column) => `Rozsah ${column}`,
74
+ filterSearch: (column) => `Hledat v ${column}`,
75
+ from: "Od",
76
+ nextPage: "Další stránka",
77
+ noRows: "Žádné řádky",
78
+ nothingHint: "Zrušte jednu z podmínek, nebo smažte hledání.",
79
+ nothingTitle: "Těmto filtrům nic neodpovídá",
80
+ pages: "Stránky",
81
+ previousPage: "Předchozí stránka",
82
+ rowsPerPage: "Řádků na stránku",
83
+ selectAll: "Označit řádky na této stránce",
84
+ selectRow: (row) => `Označit řádek ${row}`,
85
+ selected: (_count, written) => `${written} označeno`,
86
+ shown: (from, to, total) => `${from}–${to} z ${total}`,
87
+ sortAscending: (column) => `Řadit ${column} od nejmenšího`,
88
+ sortBy: (column) => `Řadit podle ${column}`,
89
+ sortClear: (column) => `Přestat řadit podle ${column}`,
90
+ sortDescending: (column) => `Řadit ${column} od největšího`,
91
+ to: "Do"
92
+ },
93
+ tail: { empty: "Žádné řádky logu" },
94
+ userMenu: { account: "účet" }
95
+ }
96
+ };
97
+ //#endregion
98
+ export { czech };
@@ -0,0 +1,11 @@
1
+ //#region src/field.d.ts
2
+ interface FieldFlags {
3
+ disabled: boolean;
4
+ invalid: boolean;
5
+ readOnly: boolean;
6
+ required: boolean;
7
+ }
8
+ declare const fieldStateOf: ({ disabled, invalid, readOnly, required }: FieldFlags) => Record<string, boolean>;
9
+ declare const heldOf: ({ readOnly }: Pick<FieldFlags, "readOnly">) => Record<string, string>;
10
+ //#endregion
11
+ export { fieldStateOf, heldOf };
package/dist/field.js ADDED
@@ -0,0 +1,14 @@
1
+ //#region src/field.ts
2
+ const fieldStateOf = ({ disabled, invalid, readOnly, required }) => {
3
+ const state = { invalid };
4
+ if (disabled) state.disabled = true;
5
+ if (readOnly) state.readOnly = true;
6
+ if (required) state.required = true;
7
+ return state;
8
+ };
9
+ const heldOf = ({ readOnly }) => {
10
+ if (readOnly) return { "data-readonly": "true" };
11
+ return {};
12
+ };
13
+ //#endregion
14
+ export { fieldStateOf, heldOf };
@@ -0,0 +1,2 @@
1
+ import { Hotkey } from "@tanstack/hotkeys";
2
+ export type { Hotkey };
@@ -0,0 +1,16 @@
1
+ import { regionOf } from "./aria.js";
2
+ import { BarsAccent, BarsOptionInput, BarsPoint, barsOption } from "./charts/bars.js";
3
+ import { GroupedBarsOptionInput, GroupedBarsSeries, groupedBarsOption } from "./charts/groupedBars.js";
4
+ import { SparkAccent, SparkOptionInput, sparkOption } from "./charts/spark.js";
5
+ import { SIDEBAR_COOKIE, cookieValue, rememberCookie, sidebarCollapsedFrom, sidebarCookieValue } from "./cookie.js";
6
+ import { DatePickerWords, DialogWords, Language, SearchWords, SelectWords, SidebarWords, StatWords, TableWords, TailWords, UserMenuWords, Words, english } from "./words.js";
7
+ import { czech } from "./czech.js";
8
+ import { fieldStateOf, heldOf } from "./field.js";
9
+ import { Hotkey } from "./hotkey.js";
10
+ import { IndicatorSpot, NOWHERE_AT_ALL, indicatorSpotIn, indicatorStyle } from "./indicator.js";
11
+ import { paintedLength } from "./measure.js";
12
+ import { Tally, WHOLE, tallyAt, tallyOf } from "./tally.js";
13
+ import { readDuration, readToken } from "./tokens.js";
14
+ import { TONE_ICON_NAME, ToneIconName } from "./toneIcons.js";
15
+ import { NOWHERE, NOWHERE_NEAR, Spot, highlightedIn, listOf, spotIn, stateOf, travelStyle } from "./travel.js";
16
+ export { type BarsAccent, type BarsOptionInput, type BarsPoint, type DatePickerWords, type DialogWords, type GroupedBarsOptionInput, type GroupedBarsSeries, type Hotkey, type IndicatorSpot, type Language, NOWHERE, NOWHERE_AT_ALL, NOWHERE_NEAR, SIDEBAR_COOKIE, type SearchWords, type SelectWords, type SidebarWords, type SparkAccent, type SparkOptionInput, type Spot, type StatWords, TONE_ICON_NAME, type TableWords, type TailWords, type Tally, type ToneIconName, type UserMenuWords, WHOLE, type Words, barsOption, cookieValue, czech, english, fieldStateOf, groupedBarsOption, heldOf, highlightedIn, indicatorSpotIn, indicatorStyle, listOf, paintedLength, readDuration, readToken, regionOf, rememberCookie, sidebarCollapsedFrom, sidebarCookieValue, sparkOption, spotIn, stateOf, tallyAt, tallyOf, travelStyle };
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ import { regionOf } from "./aria.js";
2
+ import { barsOption } from "./charts/bars.js";
3
+ import { groupedBarsOption } from "./charts/groupedBars.js";
4
+ import { sparkOption } from "./charts/spark.js";
5
+ import { SIDEBAR_COOKIE, cookieValue, rememberCookie, sidebarCollapsedFrom, sidebarCookieValue } from "./cookie.js";
6
+ import { czech } from "./czech.js";
7
+ import { fieldStateOf, heldOf } from "./field.js";
8
+ import { NOWHERE_AT_ALL, indicatorSpotIn, indicatorStyle } from "./indicator.js";
9
+ import { paintedLength } from "./measure.js";
10
+ import { WHOLE, tallyAt, tallyOf } from "./tally.js";
11
+ import { readDuration, readToken } from "./tokens.js";
12
+ import { TONE_ICON_NAME } from "./toneIcons.js";
13
+ import { NOWHERE, NOWHERE_NEAR, highlightedIn, listOf, spotIn, stateOf, travelStyle } from "./travel.js";
14
+ import { english } from "./words.js";
15
+ export { NOWHERE, NOWHERE_AT_ALL, NOWHERE_NEAR, SIDEBAR_COOKIE, TONE_ICON_NAME, WHOLE, barsOption, cookieValue, czech, english, fieldStateOf, groupedBarsOption, heldOf, highlightedIn, indicatorSpotIn, indicatorStyle, listOf, paintedLength, readDuration, readToken, regionOf, rememberCookie, sidebarCollapsedFrom, sidebarCookieValue, sparkOption, spotIn, stateOf, tallyAt, tallyOf, travelStyle };
@@ -0,0 +1,10 @@
1
+ //#region src/indicator.d.ts
2
+ interface IndicatorSpot {
3
+ left: number;
4
+ width: number;
5
+ }
6
+ declare const NOWHERE_AT_ALL: IndicatorSpot;
7
+ declare const indicatorSpotIn: (host: HTMLElement | null) => IndicatorSpot;
8
+ declare const indicatorStyle: (spot: IndicatorSpot) => Record<string, string>;
9
+ //#endregion
10
+ export { type IndicatorSpot, NOWHERE_AT_ALL, indicatorSpotIn, indicatorStyle };
@@ -0,0 +1,28 @@
1
+ //#region src/indicator.ts
2
+ const NOWHERE = 0;
3
+ const HIDDEN = "0";
4
+ const SHOWN = "1";
5
+ const NOWHERE_AT_ALL = {
6
+ left: NOWHERE,
7
+ width: NOWHERE
8
+ };
9
+ const indicatorSpotIn = (host) => {
10
+ if (!host) return NOWHERE_AT_ALL;
11
+ const chosen = host.querySelector("[data-selected]");
12
+ if (!chosen) return NOWHERE_AT_ALL;
13
+ return {
14
+ left: chosen.offsetLeft,
15
+ width: chosen.offsetWidth
16
+ };
17
+ };
18
+ const shownAt = (width) => {
19
+ if (width === NOWHERE) return HIDDEN;
20
+ return SHOWN;
21
+ };
22
+ const indicatorStyle = (spot) => ({
23
+ "--left": `${String(spot.left)}px`,
24
+ "--width": `${String(spot.width)}px`,
25
+ opacity: shownAt(spot.width)
26
+ });
27
+ //#endregion
28
+ export { NOWHERE_AT_ALL, indicatorSpotIn, indicatorStyle };
@@ -0,0 +1,4 @@
1
+ //#region src/measure.d.ts
2
+ declare const paintedLength: (length: string) => number;
3
+ //#endregion
4
+ export { paintedLength };
@@ -0,0 +1,12 @@
1
+ //#region src/measure.ts
2
+ const paintedLength = (length) => {
3
+ const probe = document.createElement("span");
4
+ probe.style.position = "absolute";
5
+ probe.style.height = length;
6
+ document.body.append(probe);
7
+ const painted = probe.getBoundingClientRect().height;
8
+ probe.remove();
9
+ return painted;
10
+ };
11
+ //#endregion
12
+ export { paintedLength };
@@ -0,0 +1,16 @@
1
+ //#region src/tally.d.ts
2
+ declare const WHOLE = 1;
3
+ interface Tally {
4
+ counts: boolean;
5
+ group: string;
6
+ head: string;
7
+ places: number;
8
+ point: string;
9
+ tail: string;
10
+ target: number;
11
+ whole: string;
12
+ }
13
+ declare const tallyOf: (value: string) => Tally;
14
+ declare const tallyAt: (tally: Tally, part: number) => string;
15
+ //#endregion
16
+ export { type Tally, WHOLE, tallyAt, tallyOf };
package/dist/tally.js ADDED
@@ -0,0 +1,73 @@
1
+ //#region src/tally.ts
2
+ const RUN = /\d(?:[\S\s]*\d)?/u;
3
+ const MARKS = /\D/gu;
4
+ const LAST = -1;
5
+ const ONCE = 1;
6
+ const ONE = 1;
7
+ const NONE = 0;
8
+ const WHOLE = 1;
9
+ const GROUP_SIZE = 3;
10
+ const DECIMAL_MAX = 2;
11
+ const marksIn = (run) => run.match(MARKS) ?? [];
12
+ const pointOf = (run) => {
13
+ const marks = marksIn(run);
14
+ const last = marks.at(LAST) ?? "";
15
+ if (last === "" || marks.filter((mark) => mark === last).length > ONCE) return "";
16
+ if (run.length - run.lastIndexOf(last) - ONE > DECIMAL_MAX) return "";
17
+ return last;
18
+ };
19
+ const groupOf = (run, point) => marksIn(run).filter((mark) => mark !== point).at(LAST) ?? "";
20
+ const NOT_DIGITS = /[^\d]/gu;
21
+ const targetOf = (run, point) => {
22
+ if (point === "") return Number(run.replace(NOT_DIGITS, ""));
23
+ const [body = "", fraction = ""] = run.split(point);
24
+ return Number(`${body.replace(NOT_DIGITS, "")}.${fraction.replace(NOT_DIGITS, "")}`);
25
+ };
26
+ const placesOf = (run, point) => {
27
+ if (point === "") return NONE;
28
+ return run.length - run.lastIndexOf(point) - ONE;
29
+ };
30
+ const RESTS = {
31
+ counts: false,
32
+ group: "",
33
+ head: "",
34
+ places: NONE,
35
+ point: "",
36
+ tail: "",
37
+ target: NONE,
38
+ whole: ""
39
+ };
40
+ const tallyOf = (value) => {
41
+ const found = RUN.exec(value);
42
+ if (!found) return {
43
+ ...RESTS,
44
+ whole: value
45
+ };
46
+ const [run] = found;
47
+ const point = pointOf(run);
48
+ return {
49
+ counts: true,
50
+ group: groupOf(run, point),
51
+ head: value.slice(NONE, found.index),
52
+ places: placesOf(run, point),
53
+ point,
54
+ tail: value.slice(found.index + run.length),
55
+ target: targetOf(run, point),
56
+ whole: value
57
+ };
58
+ };
59
+ const grouped = (body, group) => {
60
+ if (group === "") return body;
61
+ const parts = [];
62
+ for (let edge = body.length; edge > NONE; edge -= GROUP_SIZE) parts.unshift(body.slice(Math.max(edge - GROUP_SIZE, NONE), edge));
63
+ return parts.join(group);
64
+ };
65
+ const tallyAt = (tally, part) => {
66
+ if (!tally.counts || part >= 1) return tally.whole;
67
+ const [body = "", fraction = ""] = (tally.target * part).toFixed(tally.places).split(".");
68
+ const shown = grouped(body, tally.group);
69
+ if (tally.point === "") return `${tally.head}${shown}${tally.tail}`;
70
+ return `${tally.head}${shown}${tally.point}${fraction}${tally.tail}`;
71
+ };
72
+ //#endregion
73
+ export { WHOLE, tallyAt, tallyOf };
@@ -0,0 +1,5 @@
1
+ //#region src/tokens.d.ts
2
+ declare const readToken: (name: string) => string;
3
+ declare const readDuration: (name: string) => number;
4
+ //#endregion
5
+ export { readDuration, readToken };
package/dist/tokens.js ADDED
@@ -0,0 +1,15 @@
1
+ //#region src/tokens.ts
2
+ const MS = "ms";
3
+ const NOTHING = "";
4
+ const NO_DURATION = 0;
5
+ const readToken = (name) => {
6
+ if (typeof document === "undefined") return NOTHING;
7
+ return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
8
+ };
9
+ const readDuration = (name) => {
10
+ const value = readToken(name);
11
+ if (value === NOTHING) return NO_DURATION;
12
+ return Number(value.replace(MS, ""));
13
+ };
14
+ //#endregion
15
+ export { readDuration, readToken };
@@ -0,0 +1,6 @@
1
+ import { Tone } from "@techfides/ui-library-design";
2
+ //#region src/toneIcons.d.ts
3
+ type ToneIconName = 'circle-alert' | 'circle-check' | 'info' | 'triangle-alert';
4
+ declare const TONE_ICON_NAME: Record<Exclude<Tone, 'accent'>, ToneIconName>;
5
+ //#endregion
6
+ export { TONE_ICON_NAME, type ToneIconName };
@@ -0,0 +1,9 @@
1
+ //#region src/toneIcons.ts
2
+ const TONE_ICON_NAME = {
3
+ danger: "circle-alert",
4
+ info: "info",
5
+ success: "circle-check",
6
+ warning: "triangle-alert"
7
+ };
8
+ //#endregion
9
+ export { TONE_ICON_NAME };
@@ -0,0 +1,14 @@
1
+ //#region src/travel.d.ts
2
+ declare const NOWHERE = "";
3
+ interface Spot {
4
+ down: number;
5
+ tall: number;
6
+ }
7
+ declare const NOWHERE_NEAR: Spot;
8
+ declare const spotIn: (host: HTMLElement, value: string) => Spot;
9
+ declare const listOf: (mark: HTMLElement | null) => HTMLElement | false;
10
+ declare const highlightedIn: (list: HTMLElement) => string;
11
+ declare const stateOf: (lit: string, travelling: boolean) => Record<string, string>;
12
+ declare const travelStyle: (spot: Spot) => Record<string, string>;
13
+ //#endregion
14
+ export { NOWHERE, NOWHERE_NEAR, type Spot, highlightedIn, listOf, spotIn, stateOf, travelStyle };
package/dist/travel.js ADDED
@@ -0,0 +1,37 @@
1
+ //#region src/travel.ts
2
+ const NOTHING = 0;
3
+ const NOWHERE = "";
4
+ const NOWHERE_NEAR = {
5
+ down: NOTHING,
6
+ tall: NOTHING
7
+ };
8
+ const spotIn = (host, value) => {
9
+ for (const row of host.querySelectorAll("[data-part=\"item\"]")) if (row.dataset.value === value) return {
10
+ down: row.offsetTop,
11
+ tall: row.offsetHeight
12
+ };
13
+ return NOWHERE_NEAR;
14
+ };
15
+ const listOf = (mark) => {
16
+ if (!mark) return false;
17
+ const list = mark.parentElement;
18
+ if (!list) return false;
19
+ return list;
20
+ };
21
+ const highlightedIn = (list) => {
22
+ const already = list.querySelector("[data-highlighted]");
23
+ if (!already) return "";
24
+ return already.dataset.value ?? "";
25
+ };
26
+ const stateOf = (lit, travelling) => {
27
+ const state = {};
28
+ if (lit !== "") state["data-lit"] = "";
29
+ if (!travelling) state["data-placing"] = "";
30
+ return state;
31
+ };
32
+ const travelStyle = (spot) => ({
33
+ "--tf-travel-height": `${String(spot.tall)}px`,
34
+ translate: `0 ${String(spot.down)}px`
35
+ });
36
+ //#endregion
37
+ export { NOWHERE, NOWHERE_NEAR, highlightedIn, listOf, spotIn, stateOf, travelStyle };
@@ -0,0 +1,115 @@
1
+ //#region src/words.d.ts
2
+ interface TableWords {
3
+ actions: string;
4
+ anything: string;
5
+ clear: string;
6
+ clearAll: string;
7
+ clearFilter: (column: string) => string;
8
+ clearSelection: string;
9
+ done: string;
10
+ emptyHint: string;
11
+ emptyTitle: string;
12
+ expandRow: (row: string) => string;
13
+ filterBy: (column: string) => string;
14
+ filterPick: (column: string) => string;
15
+ filterRange: (column: string) => string;
16
+ filterSearch: (column: string) => string;
17
+ from: string;
18
+ nextPage: string;
19
+ noRows: string;
20
+ pages: string;
21
+ nothingHint: string;
22
+ nothingTitle: string;
23
+ previousPage: string;
24
+ rowsPerPage: string;
25
+ selectAll: string;
26
+ selectRow: (row: string) => string;
27
+ selected: (count: number, written: string) => string;
28
+ shown: (from: string, to: string, total: string) => string;
29
+ sortAscending: (column: string) => string;
30
+ sortBy: (column: string) => string;
31
+ sortClear: (column: string) => string;
32
+ sortDescending: (column: string) => string;
33
+ to: string;
34
+ }
35
+ interface DatePickerWords {
36
+ calendar: string;
37
+ choose: (day: string) => string;
38
+ chosen: (day: string) => string;
39
+ clear: string;
40
+ close: string;
41
+ nextDecade: string;
42
+ nextMonth: string;
43
+ nextYear: string;
44
+ open: string;
45
+ patternDay: string;
46
+ patternMonth: string;
47
+ patternYear: string;
48
+ pickMonth: string;
49
+ pickYear: string;
50
+ preset: (span: string) => string;
51
+ previousDecade: string;
52
+ previousMonth: string;
53
+ previousYear: string;
54
+ rangeFrom: (day: string) => string;
55
+ rangeTo: (day: string) => string;
56
+ showDays: string;
57
+ showMonths: string;
58
+ showYears: string;
59
+ unavailable: (day: string) => string;
60
+ week: string;
61
+ weekNumber: (week: string) => string;
62
+ }
63
+ interface DialogWords {
64
+ close: string;
65
+ }
66
+ interface SidebarWords {
67
+ collapse: string;
68
+ expand: string;
69
+ openMenu: string;
70
+ }
71
+ interface StatWords {
72
+ change: string;
73
+ fell: string;
74
+ rose: string;
75
+ }
76
+ interface SearchWords {
77
+ dismiss: string;
78
+ nothing: string;
79
+ results: (count: number, written: string) => string;
80
+ }
81
+ interface ListboxWords {
82
+ empty: string;
83
+ }
84
+ interface QueueWords {
85
+ label: string;
86
+ }
87
+ interface SelectWords {
88
+ clear: string;
89
+ }
90
+ interface TailWords {
91
+ empty: string;
92
+ }
93
+ interface UserMenuWords {
94
+ account: string;
95
+ }
96
+ interface Words {
97
+ datePicker: DatePickerWords;
98
+ dialog: DialogWords;
99
+ listbox: ListboxWords;
100
+ queue: QueueWords;
101
+ search: SearchWords;
102
+ select: SelectWords;
103
+ sidebar: SidebarWords;
104
+ stat: StatWords;
105
+ table: TableWords;
106
+ tail: TailWords;
107
+ userMenu: UserMenuWords;
108
+ }
109
+ interface Language {
110
+ locale?: string;
111
+ words: Words;
112
+ }
113
+ declare const english: Language;
114
+ //#endregion
115
+ export { type DatePickerWords, type DialogWords, type Language, type SearchWords, type SelectWords, type SidebarWords, type StatWords, type TableWords, type TailWords, type UserMenuWords, type Words, english };
package/dist/words.js ADDED
@@ -0,0 +1,94 @@
1
+ //#region src/words.ts
2
+ const SINGLE = 1;
3
+ const english = {
4
+ locale: "en-US",
5
+ words: {
6
+ datePicker: {
7
+ calendar: "Calendar",
8
+ choose: (day) => `Choose ${day}`,
9
+ chosen: (day) => `Chosen, ${day}`,
10
+ clear: "Clear the dates",
11
+ close: "Close the calendar",
12
+ nextDecade: "Next decade",
13
+ nextMonth: "Next month",
14
+ nextYear: "Next year",
15
+ open: "Open the calendar",
16
+ patternDay: "dd",
17
+ patternMonth: "mm",
18
+ patternYear: "yyyy",
19
+ pickMonth: "Pick a month",
20
+ pickYear: "Pick a year",
21
+ preset: (span) => `Choose ${span}`,
22
+ previousDecade: "Previous decade",
23
+ previousMonth: "Previous month",
24
+ previousYear: "Previous year",
25
+ rangeFrom: (day) => `Start the range at ${day}`,
26
+ rangeTo: (day) => `End the range at ${day}`,
27
+ showDays: "Show the days",
28
+ showMonths: "Show the months",
29
+ showYears: "Show the years",
30
+ unavailable: (day) => `Not available, ${day}`,
31
+ week: "Wk",
32
+ weekNumber: (week) => `Week ${week}`
33
+ },
34
+ dialog: { close: "Close" },
35
+ listbox: { empty: "Nothing to choose from" },
36
+ queue: { label: "Queue" },
37
+ search: {
38
+ dismiss: "Esc closes",
39
+ nothing: "Nothing matches that",
40
+ results: (count, written) => {
41
+ if (count === SINGLE) return "1 result";
42
+ return `${written} results`;
43
+ }
44
+ },
45
+ select: { clear: "Clear" },
46
+ sidebar: {
47
+ collapse: "Collapse the sidebar",
48
+ expand: "Expand the sidebar",
49
+ openMenu: "Open menu"
50
+ },
51
+ stat: {
52
+ change: "Change",
53
+ fell: "down",
54
+ rose: "up"
55
+ },
56
+ table: {
57
+ actions: "Actions",
58
+ anything: "Anything",
59
+ clear: "Clear",
60
+ clearAll: "Clear the filters",
61
+ clearFilter: (column) => `Remove the filter on ${column}`,
62
+ clearSelection: "Clear selection",
63
+ done: "Done",
64
+ emptyHint: "Items will show up here once there are some.",
65
+ emptyTitle: "No items yet",
66
+ expandRow: (row) => `Show more about row ${row}`,
67
+ filterBy: (column) => `Filter ${column}`,
68
+ filterPick: (column) => `Pick from ${column}`,
69
+ filterRange: (column) => `Range of ${column}`,
70
+ filterSearch: (column) => `Search in ${column}`,
71
+ from: "From",
72
+ nextPage: "Next page",
73
+ noRows: "No rows",
74
+ nothingHint: "Drop one of the conditions, or clear the search.",
75
+ nothingTitle: "Nothing matches those filters",
76
+ pages: "Pages",
77
+ previousPage: "Previous page",
78
+ rowsPerPage: "Rows per page",
79
+ selectAll: "Select the rows on this page",
80
+ selectRow: (row) => `Select row ${row}`,
81
+ selected: (_count, written) => `${written} selected`,
82
+ shown: (from, to, total) => `${from}–${to} of ${total}`,
83
+ sortAscending: (column) => `Sort ${column} smallest first`,
84
+ sortBy: (column) => `Sort by ${column}`,
85
+ sortClear: (column) => `Stop sorting by ${column}`,
86
+ sortDescending: (column) => `Sort ${column} largest first`,
87
+ to: "To"
88
+ },
89
+ tail: { empty: "No log lines" },
90
+ userMenu: { account: "account" }
91
+ }
92
+ };
93
+ //#endregion
94
+ export { english };
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "@techfides/ui-library-core",
3
+ "version": "0.5.0",
4
+ "description": "Framework-agnostic logic for the TechFides UI library: words and languages, number tallies, chart options, field state and shared DOM maths",
5
+ "keywords": [
6
+ "design-system",
7
+ "headless",
8
+ "i18n"
9
+ ],
10
+ "license": "MIT",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/TechFides/ui-library.git",
14
+ "directory": "packages/core"
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "type": "module",
20
+ "sideEffects": false,
21
+ "imports": {
22
+ "#*": "./src/*.ts"
23
+ },
24
+ "exports": {
25
+ ".": {
26
+ "types": "./dist/index.d.ts",
27
+ "default": "./dist/index.js"
28
+ },
29
+ "./package.json": "./package.json"
30
+ },
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "dependencies": {
35
+ "@tanstack/hotkeys": "^0.8.0",
36
+ "@techfides/ui-library-design": "^0.5.0"
37
+ },
38
+ "devDependencies": {
39
+ "@arethetypeswrong/core": "^0.18.5",
40
+ "echarts": "^6.1.0",
41
+ "publint": "^0.3.24",
42
+ "tsdown": "^0.22.14",
43
+ "typescript": "~6.0.3",
44
+ "@techfides/tsconfig": "0.0.0"
45
+ },
46
+ "peerDependencies": {
47
+ "echarts": "^6.1.0"
48
+ },
49
+ "peerDependenciesMeta": {
50
+ "echarts": {
51
+ "optional": true
52
+ }
53
+ },
54
+ "engines": {
55
+ "node": ">=24"
56
+ },
57
+ "scripts": {
58
+ "build": "tsdown",
59
+ "dev": "tsdown --watch",
60
+ "lint": "eslint . --max-warnings=0",
61
+ "typecheck": "tsc --noEmit"
62
+ },
63
+ "module": "./dist/index.js",
64
+ "types": "./dist/index.d.ts"
65
+ }