@happyvertical/smrt-svelte 0.55.7 → 0.55.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +7 -44
- package/README.md +112 -1
- package/agents/browser-ai.md +47 -0
- package/agents/command-palette.md +85 -0
- package/agents/import-export.md +62 -0
- package/agents/overview-surfaces.md +255 -0
- package/agents/screens.md +57 -0
- package/dist/browser-ai/adapters/tts/browser-synthesis.d.ts +5 -0
- package/dist/browser-ai/adapters/tts/browser-synthesis.d.ts.map +1 -1
- package/dist/browser-ai/adapters/tts/browser-synthesis.js +83 -55
- package/dist/components/command-palette/CommandPalette.svelte +75 -0
- package/dist/components/command-palette/CommandPalette.svelte.d.ts +22 -0
- package/dist/components/command-palette/CommandPalette.svelte.d.ts.map +1 -0
- package/dist/components/command-palette/CommandPaletteDialog.svelte +406 -0
- package/dist/components/command-palette/CommandPaletteDialog.svelte.d.ts +18 -0
- package/dist/components/command-palette/CommandPaletteDialog.svelte.d.ts.map +1 -0
- package/dist/components/command-palette/CommandPaletteTrigger.svelte +91 -0
- package/dist/components/command-palette/CommandPaletteTrigger.svelte.d.ts +17 -0
- package/dist/components/command-palette/CommandPaletteTrigger.svelte.d.ts.map +1 -0
- package/dist/components/command-palette/context.d.ts +18 -0
- package/dist/components/command-palette/context.d.ts.map +1 -0
- package/dist/components/command-palette/context.js +38 -0
- package/dist/components/command-palette/controller.svelte.d.ts +70 -0
- package/dist/components/command-palette/controller.svelte.d.ts.map +1 -0
- package/dist/components/command-palette/controller.svelte.js +379 -0
- package/dist/components/command-palette/hotkeys.d.ts +30 -0
- package/dist/components/command-palette/hotkeys.d.ts.map +1 -0
- package/dist/components/command-palette/hotkeys.js +161 -0
- package/dist/components/command-palette/index.d.ts +19 -0
- package/dist/components/command-palette/index.d.ts.map +1 -0
- package/dist/components/command-palette/index.js +17 -0
- package/dist/components/command-palette/match.d.ts +38 -0
- package/dist/components/command-palette/match.d.ts.map +1 -0
- package/dist/components/command-palette/match.js +172 -0
- package/dist/components/command-palette/providers.d.ts +159 -0
- package/dist/components/command-palette/providers.d.ts.map +1 -0
- package/dist/components/command-palette/providers.js +345 -0
- package/dist/components/command-palette/rank.d.ts +20 -0
- package/dist/components/command-palette/rank.d.ts.map +1 -0
- package/dist/components/command-palette/rank.js +74 -0
- package/dist/components/command-palette/types.d.ts +119 -0
- package/dist/components/command-palette/types.d.ts.map +1 -0
- package/dist/components/command-palette/types.js +10 -0
- package/dist/components/command-palette/use-provider.svelte.d.ts +14 -0
- package/dist/components/command-palette/use-provider.svelte.d.ts.map +1 -0
- package/dist/components/command-palette/use-provider.svelte.js +23 -0
- package/dist/components/import-export/ImportExport.svelte +678 -0
- package/dist/components/import-export/ImportExport.svelte.d.ts +5 -0
- package/dist/components/import-export/ImportExport.svelte.d.ts.map +1 -0
- package/dist/components/import-export/collection-adapter.d.ts +35 -0
- package/dist/components/import-export/collection-adapter.d.ts.map +1 -0
- package/dist/components/import-export/collection-adapter.js +42 -0
- package/dist/components/import-export/csv.d.ts +60 -0
- package/dist/components/import-export/csv.d.ts.map +1 -0
- package/dist/components/import-export/csv.js +192 -0
- package/dist/components/import-export/download.d.ts +4 -0
- package/dist/components/import-export/download.d.ts.map +1 -0
- package/dist/components/import-export/download.js +17 -0
- package/dist/components/import-export/export.d.ts +25 -0
- package/dist/components/import-export/export.d.ts.map +1 -0
- package/dist/components/import-export/export.js +68 -0
- package/dist/components/import-export/fields.d.ts +48 -0
- package/dist/components/import-export/fields.d.ts.map +1 -0
- package/dist/components/import-export/fields.js +103 -0
- package/dist/components/import-export/index.d.ts +12 -0
- package/dist/components/import-export/index.d.ts.map +1 -0
- package/dist/components/import-export/index.js +9 -0
- package/dist/components/import-export/mapping.d.ts +12 -0
- package/dist/components/import-export/mapping.d.ts.map +1 -0
- package/dist/components/import-export/mapping.js +38 -0
- package/dist/components/import-export/props.d.ts +34 -0
- package/dist/components/import-export/props.d.ts.map +1 -0
- package/dist/components/import-export/props.js +1 -0
- package/dist/components/import-export/report.d.ts +13 -0
- package/dist/components/import-export/report.d.ts.map +1 -0
- package/dist/components/import-export/report.js +50 -0
- package/dist/components/import-export/runner.d.ts +17 -0
- package/dist/components/import-export/runner.d.ts.map +1 -0
- package/dist/components/import-export/runner.js +39 -0
- package/dist/components/import-export/types.d.ts +100 -0
- package/dist/components/import-export/types.d.ts.map +1 -0
- package/dist/components/import-export/types.js +6 -0
- package/dist/components/import-export/validate.d.ts +39 -0
- package/dist/components/import-export/validate.d.ts.map +1 -0
- package/dist/components/import-export/validate.js +268 -0
- package/dist/components/overview/OverviewGrid.svelte +579 -0
- package/dist/components/overview/OverviewGrid.svelte.d.ts +5 -0
- package/dist/components/overview/OverviewGrid.svelte.d.ts.map +1 -0
- package/dist/components/overview/WidgetOptionsForm.svelte +193 -0
- package/dist/components/overview/WidgetOptionsForm.svelte.d.ts +5 -0
- package/dist/components/overview/WidgetOptionsForm.svelte.d.ts.map +1 -0
- package/dist/components/overview/controller.svelte.d.ts +92 -0
- package/dist/components/overview/controller.svelte.d.ts.map +1 -0
- package/dist/components/overview/controller.svelte.js +336 -0
- package/dist/components/overview/format.d.ts +13 -0
- package/dist/components/overview/format.d.ts.map +1 -0
- package/dist/components/overview/format.js +45 -0
- package/dist/components/overview/grid-types.d.ts +52 -0
- package/dist/components/overview/grid-types.d.ts.map +1 -0
- package/dist/components/overview/grid-types.js +1 -0
- package/dist/components/overview/index.d.ts +24 -0
- package/dist/components/overview/index.d.ts.map +1 -0
- package/dist/components/overview/index.js +22 -0
- package/dist/components/overview/load.d.ts +30 -0
- package/dist/components/overview/load.d.ts.map +1 -0
- package/dist/components/overview/load.js +92 -0
- package/dist/components/overview/markdown.d.ts +53 -0
- package/dist/components/overview/markdown.d.ts.map +1 -0
- package/dist/components/overview/markdown.js +203 -0
- package/dist/components/overview/model.d.ts +100 -0
- package/dist/components/overview/model.d.ts.map +1 -0
- package/dist/components/overview/model.js +460 -0
- package/dist/components/overview/recipe-widgets.d.ts +77 -0
- package/dist/components/overview/recipe-widgets.d.ts.map +1 -0
- package/dist/components/overview/recipe-widgets.js +151 -0
- package/dist/components/overview/registry.d.ts +45 -0
- package/dist/components/overview/registry.d.ts.map +1 -0
- package/dist/components/overview/registry.js +112 -0
- package/dist/components/overview/resize.d.ts +25 -0
- package/dist/components/overview/resize.d.ts.map +1 -0
- package/dist/components/overview/resize.js +41 -0
- package/dist/components/overview/schema.d.ts +34 -0
- package/dist/components/overview/schema.d.ts.map +1 -0
- package/dist/components/overview/schema.js +180 -0
- package/dist/components/overview/server.d.ts +14 -0
- package/dist/components/overview/server.d.ts.map +1 -0
- package/dist/components/overview/server.js +13 -0
- package/dist/components/overview/types.d.ts +235 -0
- package/dist/components/overview/types.d.ts.map +1 -0
- package/dist/components/overview/types.js +17 -0
- package/dist/components/overview/widgets/ChartWidget.svelte +111 -0
- package/dist/components/overview/widgets/ChartWidget.svelte.d.ts +6 -0
- package/dist/components/overview/widgets/ChartWidget.svelte.d.ts.map +1 -0
- package/dist/components/overview/widgets/MetricWidget.svelte +86 -0
- package/dist/components/overview/widgets/MetricWidget.svelte.d.ts +6 -0
- package/dist/components/overview/widgets/MetricWidget.svelte.d.ts.map +1 -0
- package/dist/components/overview/widgets/NoteWidget.svelte +61 -0
- package/dist/components/overview/widgets/NoteWidget.svelte.d.ts +5 -0
- package/dist/components/overview/widgets/NoteWidget.svelte.d.ts.map +1 -0
- package/dist/components/overview/widgets/RecordListWidget.svelte +91 -0
- package/dist/components/overview/widgets/RecordListWidget.svelte.d.ts +6 -0
- package/dist/components/overview/widgets/RecordListWidget.svelte.d.ts.map +1 -0
- package/dist/components/overview/widgets/ShortcutsWidget.svelte +80 -0
- package/dist/components/overview/widgets/ShortcutsWidget.svelte.d.ts +6 -0
- package/dist/components/overview/widgets/ShortcutsWidget.svelte.d.ts.map +1 -0
- package/dist/components/overview/widgets/core.d.ts +44 -0
- package/dist/components/overview/widgets/core.d.ts.map +1 -0
- package/dist/components/overview/widgets/core.js +222 -0
- package/dist/components/overview/widgets/data.d.ts +76 -0
- package/dist/components/overview/widgets/data.d.ts.map +1 -0
- package/dist/components/overview/widgets/data.js +40 -0
- package/dist/components/screens/DetailScreen.svelte +220 -0
- package/dist/components/screens/DetailScreen.svelte.d.ts +5 -0
- package/dist/components/screens/DetailScreen.svelte.d.ts.map +1 -0
- package/dist/components/screens/EditForm.svelte +313 -0
- package/dist/components/screens/EditForm.svelte.d.ts +5 -0
- package/dist/components/screens/EditForm.svelte.d.ts.map +1 -0
- package/dist/components/screens/ListScreen.svelte +191 -0
- package/dist/components/screens/ListScreen.svelte.d.ts +5 -0
- package/dist/components/screens/ListScreen.svelte.d.ts.map +1 -0
- package/dist/components/screens/RecipeScreens.svelte +237 -0
- package/dist/components/screens/RecipeScreens.svelte.d.ts +5 -0
- package/dist/components/screens/RecipeScreens.svelte.d.ts.map +1 -0
- package/dist/components/screens/fields.d.ts +54 -0
- package/dist/components/screens/fields.d.ts.map +1 -0
- package/dist/components/screens/fields.js +229 -0
- package/dist/components/screens/index.d.ts +8 -0
- package/dist/components/screens/index.d.ts.map +1 -0
- package/dist/components/screens/index.js +6 -0
- package/dist/components/screens/types.d.ts +215 -0
- package/dist/components/screens/types.d.ts.map +1 -0
- package/dist/components/screens/types.js +1 -0
- package/dist/components/screens/values.d.ts +62 -0
- package/dist/components/screens/values.d.ts.map +1 -0
- package/dist/components/screens/values.js +289 -0
- package/dist/components/sortable/controller.svelte.d.ts +10 -0
- package/dist/components/sortable/controller.svelte.d.ts.map +1 -1
- package/dist/components/sortable/controller.svelte.js +29 -7
- package/dist/components/workspace/manifest-nav.d.ts +20 -0
- package/dist/components/workspace/manifest-nav.d.ts.map +1 -1
- package/dist/components/workspace/manifest-nav.js +42 -13
- package/dist/i18n/server.d.ts +6 -0
- package/dist/i18n/server.d.ts.map +1 -1
- package/dist/i18n/server.js +6 -0
- package/dist/i18n/strings.import-export.d.ts +88 -0
- package/dist/i18n/strings.import-export.d.ts.map +1 -0
- package/dist/i18n/strings.import-export.js +88 -0
- package/dist/i18n/strings.overview.d.ts +100 -0
- package/dist/i18n/strings.overview.d.ts.map +1 -0
- package/dist/i18n/strings.overview.js +107 -0
- package/dist/i18n/strings.palette.d.ts +18 -0
- package/dist/i18n/strings.palette.d.ts.map +1 -0
- package/dist/i18n/strings.palette.js +18 -0
- package/dist/i18n/strings.screens.d.ts +31 -0
- package/dist/i18n/strings.screens.d.ts.map +1 -0
- package/dist/i18n/strings.screens.js +31 -0
- package/package.json +45 -16
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure value handling for the manifest-derived record screens (#3718):
|
|
3
|
+
* draft <-> payload conversion for edit forms and display formatting for list
|
|
4
|
+
* and view screens. No DOM and no i18n: components map error codes and the
|
|
5
|
+
* Yes/No labels through `useI18n`.
|
|
6
|
+
*
|
|
7
|
+
* Money is integer minor units end to end. Editing shows major units, but the
|
|
8
|
+
* conversion is exact string math (never `* 100` on a float), and anything
|
|
9
|
+
* that is not a JavaScript-safe integer is rejected rather than rounded.
|
|
10
|
+
*/
|
|
11
|
+
import { ISO_4217_MINOR_UNITS } from '@happyvertical/smrt-ui/currency';
|
|
12
|
+
/** Currency used for money fields when the screen is not told otherwise. */
|
|
13
|
+
export const DEFAULT_SCREEN_CURRENCY = 'USD';
|
|
14
|
+
/** Decimal places of a currency's minor unit (2 for an unknown code). */
|
|
15
|
+
export function currencyMinorDigits(currency) {
|
|
16
|
+
return ISO_4217_MINOR_UNITS.get(currency.trim().toUpperCase()) ?? 2;
|
|
17
|
+
}
|
|
18
|
+
/** `1999`, 2 digits -> `19.99`. Exact; `null` for a non-safe integer. */
|
|
19
|
+
export function minorUnitsToMajorString(minor, digits) {
|
|
20
|
+
if (typeof minor !== 'number' || !Number.isSafeInteger(minor))
|
|
21
|
+
return null;
|
|
22
|
+
const negative = minor < 0;
|
|
23
|
+
const absolute = String(Math.abs(minor));
|
|
24
|
+
let text;
|
|
25
|
+
if (digits <= 0) {
|
|
26
|
+
text = absolute;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
const padded = absolute.padStart(digits + 1, '0');
|
|
30
|
+
text = `${padded.slice(0, -digits)}.${padded.slice(-digits)}`;
|
|
31
|
+
}
|
|
32
|
+
return negative ? `-${text}` : text;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* `19.99`, 2 digits -> `1999`. Accepts a leading sign and `,` grouping;
|
|
36
|
+
* rejects more fraction digits than the currency has and non-safe integers.
|
|
37
|
+
*/
|
|
38
|
+
export function majorStringToMinorUnits(text, digits) {
|
|
39
|
+
const cleaned = text.trim().replace(/[,\s]/g, '');
|
|
40
|
+
const pattern = digits > 0 ? /^(-?)(\d+)(?:\.(\d*))?$/ : /^(-?)(\d+)$/;
|
|
41
|
+
const match = pattern.exec(cleaned);
|
|
42
|
+
if (!match)
|
|
43
|
+
return null;
|
|
44
|
+
const [, sign, whole, fraction = ''] = match;
|
|
45
|
+
if (fraction.length > Math.max(0, digits))
|
|
46
|
+
return null;
|
|
47
|
+
const minor = Number(`${whole}${fraction.padEnd(Math.max(0, digits), '0')}`);
|
|
48
|
+
if (!Number.isSafeInteger(minor))
|
|
49
|
+
return null;
|
|
50
|
+
return sign === '-' && minor !== 0 ? -minor : minor;
|
|
51
|
+
}
|
|
52
|
+
function pad(value) {
|
|
53
|
+
return String(value).padStart(2, '0');
|
|
54
|
+
}
|
|
55
|
+
/** A record datetime as a `datetime-local` input value (local time). */
|
|
56
|
+
export function toDatetimeLocal(value) {
|
|
57
|
+
if (value === null || value === undefined || value === '')
|
|
58
|
+
return '';
|
|
59
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
60
|
+
if (Number.isNaN(date.getTime()))
|
|
61
|
+
return '';
|
|
62
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
63
|
+
}
|
|
64
|
+
/** One field's value as the draft representation its control edits. */
|
|
65
|
+
export function toDraftValue(field, value, context = {}) {
|
|
66
|
+
if (field.kind === 'boolean')
|
|
67
|
+
return value === true || value === 'true';
|
|
68
|
+
if (value === null || value === undefined)
|
|
69
|
+
return '';
|
|
70
|
+
switch (field.kind) {
|
|
71
|
+
case 'money':
|
|
72
|
+
return (minorUnitsToMajorString(value, currencyMinorDigits(context.currency ?? DEFAULT_SCREEN_CURRENCY)) ?? '');
|
|
73
|
+
case 'datetime':
|
|
74
|
+
return toDatetimeLocal(value);
|
|
75
|
+
case 'json':
|
|
76
|
+
return typeof value === 'string' ? value : JSON.stringify(value, null, 2);
|
|
77
|
+
default:
|
|
78
|
+
return String(value);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/** Draft for editing an existing record. */
|
|
82
|
+
export function draftFromRecord(fields, record, context = {}) {
|
|
83
|
+
const draft = {};
|
|
84
|
+
for (const field of fields) {
|
|
85
|
+
draft[field.name] = toDraftValue(field, record[field.name], context);
|
|
86
|
+
}
|
|
87
|
+
return draft;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Draft for a new record: the resolved policy default when one resolved
|
|
91
|
+
* (an explicit `null` default included), else the manifest default.
|
|
92
|
+
*/
|
|
93
|
+
export function draftForCreate(fields, policy, context = {}) {
|
|
94
|
+
const draft = {};
|
|
95
|
+
for (const field of fields) {
|
|
96
|
+
const policyField = policy?.fields[field.name];
|
|
97
|
+
const seeded = policyField?.hasDefault === true
|
|
98
|
+
? policyField.defaultValue
|
|
99
|
+
: field.definition.default;
|
|
100
|
+
draft[field.name] = toDraftValue(field, seeded, context);
|
|
101
|
+
}
|
|
102
|
+
return draft;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Convert a draft into a write payload. An empty optional text field becomes
|
|
106
|
+
* `null` when the field is nullable and `''` otherwise; every other empty
|
|
107
|
+
* optional field becomes `null`. A required empty field is an error.
|
|
108
|
+
*/
|
|
109
|
+
export function parseDraft(fields, draft, context = {}) {
|
|
110
|
+
const values = {};
|
|
111
|
+
const errors = {};
|
|
112
|
+
const digits = currencyMinorDigits(context.currency ?? DEFAULT_SCREEN_CURRENCY);
|
|
113
|
+
for (const field of fields) {
|
|
114
|
+
const raw = draft[field.name];
|
|
115
|
+
if (field.kind === 'boolean') {
|
|
116
|
+
values[field.name] = raw === true || raw === 'true';
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
const text = typeof raw === 'string' ? raw : '';
|
|
120
|
+
const trimmed = text.trim();
|
|
121
|
+
if (trimmed === '') {
|
|
122
|
+
if (field.required) {
|
|
123
|
+
errors[field.name] = 'required';
|
|
124
|
+
}
|
|
125
|
+
else if ((field.kind === 'text' ||
|
|
126
|
+
field.kind === 'textarea' ||
|
|
127
|
+
field.kind === 'email' ||
|
|
128
|
+
field.kind === 'url' ||
|
|
129
|
+
field.kind === 'tel') &&
|
|
130
|
+
field.definition.nullable !== true) {
|
|
131
|
+
values[field.name] = '';
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
values[field.name] = null;
|
|
135
|
+
}
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
switch (field.kind) {
|
|
139
|
+
case 'integer': {
|
|
140
|
+
const parsed = /^-?\d+$/.test(trimmed) ? Number(trimmed) : Number.NaN;
|
|
141
|
+
if (Number.isSafeInteger(parsed))
|
|
142
|
+
values[field.name] = parsed;
|
|
143
|
+
else
|
|
144
|
+
errors[field.name] = 'invalid_integer';
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
case 'decimal': {
|
|
148
|
+
const parsed = Number(trimmed);
|
|
149
|
+
if (Number.isFinite(parsed))
|
|
150
|
+
values[field.name] = parsed;
|
|
151
|
+
else
|
|
152
|
+
errors[field.name] = 'invalid_decimal';
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
case 'money': {
|
|
156
|
+
const minor = majorStringToMinorUnits(trimmed, digits);
|
|
157
|
+
if (minor === null)
|
|
158
|
+
errors[field.name] = 'invalid_money';
|
|
159
|
+
else
|
|
160
|
+
values[field.name] = minor;
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
case 'datetime': {
|
|
164
|
+
const original = context.record?.[field.name];
|
|
165
|
+
const originalDate = original === null || original === undefined || original === ''
|
|
166
|
+
? null
|
|
167
|
+
: original instanceof Date
|
|
168
|
+
? original
|
|
169
|
+
: new Date(original);
|
|
170
|
+
if (originalDate &&
|
|
171
|
+
!Number.isNaN(originalDate.getTime()) &&
|
|
172
|
+
trimmed === toDatetimeLocal(originalDate)) {
|
|
173
|
+
// Unchanged at the control's precision: keep the full-precision
|
|
174
|
+
// original instead of truncating to the minute.
|
|
175
|
+
values[field.name] = originalDate.toISOString();
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
const date = new Date(trimmed);
|
|
179
|
+
if (Number.isNaN(date.getTime()))
|
|
180
|
+
errors[field.name] = 'invalid_datetime';
|
|
181
|
+
else
|
|
182
|
+
values[field.name] = date.toISOString();
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
case 'json': {
|
|
186
|
+
try {
|
|
187
|
+
values[field.name] = JSON.parse(trimmed);
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
errors[field.name] = 'invalid_json';
|
|
191
|
+
}
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
case 'reference':
|
|
195
|
+
values[field.name] = trimmed;
|
|
196
|
+
break;
|
|
197
|
+
default:
|
|
198
|
+
// Free text keeps the user's whitespace.
|
|
199
|
+
values[field.name] = text;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return { values, errors };
|
|
203
|
+
}
|
|
204
|
+
/** A record value as display text for a list cell or a view row. */
|
|
205
|
+
export function formatScreenValue(field, value, context = {}) {
|
|
206
|
+
if (field.kind === 'boolean') {
|
|
207
|
+
if (value === null || value === undefined)
|
|
208
|
+
return '';
|
|
209
|
+
return value === true || value === 'true'
|
|
210
|
+
? (context.yes ?? 'Yes')
|
|
211
|
+
: (context.no ?? 'No');
|
|
212
|
+
}
|
|
213
|
+
if (value === null || value === undefined || value === '')
|
|
214
|
+
return '';
|
|
215
|
+
try {
|
|
216
|
+
switch (field.kind) {
|
|
217
|
+
case 'integer':
|
|
218
|
+
return typeof value === 'number'
|
|
219
|
+
? new Intl.NumberFormat(context.locale, {
|
|
220
|
+
maximumFractionDigits: 0,
|
|
221
|
+
}).format(value)
|
|
222
|
+
: String(value);
|
|
223
|
+
case 'decimal':
|
|
224
|
+
return typeof value === 'number'
|
|
225
|
+
? new Intl.NumberFormat(context.locale, {
|
|
226
|
+
maximumFractionDigits: 6,
|
|
227
|
+
}).format(value)
|
|
228
|
+
: String(value);
|
|
229
|
+
case 'money': {
|
|
230
|
+
const currency = (context.currency ?? DEFAULT_SCREEN_CURRENCY)
|
|
231
|
+
.trim()
|
|
232
|
+
.toUpperCase();
|
|
233
|
+
const digits = currencyMinorDigits(currency);
|
|
234
|
+
if (typeof value !== 'number' || !Number.isSafeInteger(value)) {
|
|
235
|
+
return String(value);
|
|
236
|
+
}
|
|
237
|
+
return new Intl.NumberFormat(context.locale, {
|
|
238
|
+
style: 'currency',
|
|
239
|
+
currency,
|
|
240
|
+
}).format(value / 10 ** digits);
|
|
241
|
+
}
|
|
242
|
+
case 'datetime': {
|
|
243
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
244
|
+
if (Number.isNaN(date.getTime()))
|
|
245
|
+
return String(value);
|
|
246
|
+
return new Intl.DateTimeFormat(context.locale, {
|
|
247
|
+
dateStyle: 'medium',
|
|
248
|
+
timeStyle: 'short',
|
|
249
|
+
...(context.timeZone ? { timeZone: context.timeZone } : {}),
|
|
250
|
+
}).format(date);
|
|
251
|
+
}
|
|
252
|
+
case 'json':
|
|
253
|
+
return typeof value === 'string' ? value : JSON.stringify(value);
|
|
254
|
+
default:
|
|
255
|
+
return String(value);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
catch {
|
|
259
|
+
// An unsupported currency code or locale must not break a row render.
|
|
260
|
+
return String(value);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Order two record values for a list column: empty values last (whichever
|
|
265
|
+
* way the column sorts), numbers numerically, everything else as text.
|
|
266
|
+
*/
|
|
267
|
+
export function compareScreenValues(left, right, direction) {
|
|
268
|
+
if (!direction)
|
|
269
|
+
return 0;
|
|
270
|
+
const leftEmpty = left === null || left === undefined || left === '';
|
|
271
|
+
const rightEmpty = right === null || right === undefined || right === '';
|
|
272
|
+
if (leftEmpty && rightEmpty)
|
|
273
|
+
return 0;
|
|
274
|
+
if (leftEmpty)
|
|
275
|
+
return 1;
|
|
276
|
+
if (rightEmpty)
|
|
277
|
+
return -1;
|
|
278
|
+
let result;
|
|
279
|
+
if (typeof left === 'number' && typeof right === 'number') {
|
|
280
|
+
result = left - right;
|
|
281
|
+
}
|
|
282
|
+
else if (typeof left === 'boolean' && typeof right === 'boolean') {
|
|
283
|
+
result = Number(left) - Number(right);
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
result = String(left).localeCompare(String(right));
|
|
287
|
+
}
|
|
288
|
+
return direction === 'asc' ? result : -result;
|
|
289
|
+
}
|
|
@@ -76,6 +76,15 @@ export interface SortableControllerOptions {
|
|
|
76
76
|
* adjacent container at either end.
|
|
77
77
|
*/
|
|
78
78
|
orientation?: () => 'horizontal' | 'vertical';
|
|
79
|
+
/**
|
|
80
|
+
* `true` for a single list laid out as a wrapping flow (a CSS grid of
|
|
81
|
+
* tiles): every arrow key steps one position along the reading order
|
|
82
|
+
* (Left/Right mirrored in right-to-left), and a pointer drop over an item
|
|
83
|
+
* that shares its row with others decides before/after by the horizontal
|
|
84
|
+
* midpoint; an item that fills the row (stacked layouts) still uses the
|
|
85
|
+
* vertical midpoint.
|
|
86
|
+
*/
|
|
87
|
+
flow?: () => boolean;
|
|
79
88
|
/**
|
|
80
89
|
* Persist a move. May be async; a rejection restores the presentation and
|
|
81
90
|
* is announced. The engine allows the next move only after it settles.
|
|
@@ -113,6 +122,7 @@ export declare class SortableController {
|
|
|
113
122
|
pickup(itemId: string, mode: DragState['mode']): void;
|
|
114
123
|
private announcePosition;
|
|
115
124
|
private moveKeyboardTarget;
|
|
125
|
+
private isRtl;
|
|
116
126
|
drop(): Promise<void>;
|
|
117
127
|
/** Cancel the move in flight. Focus returns to the item when `restoreFocus`. */
|
|
118
128
|
cancel(announce?: boolean, restoreFocus?: boolean): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/sortable/controller.svelte.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"controller.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/sortable/controller.svelte.ts"],"names":[],"mappings":"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"}
|
|
@@ -112,6 +112,14 @@ export class SortableController {
|
|
|
112
112
|
return;
|
|
113
113
|
const vertical = this.options.orientation?.() === 'vertical';
|
|
114
114
|
const target = { ...drag.target };
|
|
115
|
+
if (this.options.flow?.()) {
|
|
116
|
+
const mirrored = direction === 'horizontal' && this.isRtl();
|
|
117
|
+
const max = this.itemsIn(target.containerId, drag.itemId).length;
|
|
118
|
+
target.index = clamp(target.index + (mirrored ? -delta : delta), max);
|
|
119
|
+
this.drag = { ...drag, target };
|
|
120
|
+
this.announcePosition(this.drag);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
115
123
|
// With same-container reordering off, the source container pins the
|
|
116
124
|
// position (as it does for pointer moves): a vertical step leaves it.
|
|
117
125
|
const pinned = !this.options.allowSameContainerReorder() &&
|
|
@@ -160,6 +168,12 @@ export class SortableController {
|
|
|
160
168
|
this.drag = { ...drag, target };
|
|
161
169
|
this.announcePosition(this.drag);
|
|
162
170
|
}
|
|
171
|
+
isRtl() {
|
|
172
|
+
const root = this.options.root();
|
|
173
|
+
return (root !== undefined &&
|
|
174
|
+
typeof getComputedStyle === 'function' &&
|
|
175
|
+
getComputedStyle(root).direction === 'rtl');
|
|
176
|
+
}
|
|
163
177
|
async drop() {
|
|
164
178
|
const state = this.drag;
|
|
165
179
|
if (!state)
|
|
@@ -325,7 +339,7 @@ export class SortableController {
|
|
|
325
339
|
return (document.elementFromPoint?.(event.clientX, event.clientY) ??
|
|
326
340
|
event.target);
|
|
327
341
|
}
|
|
328
|
-
setPointerTargetFromElement(element, clientY) {
|
|
342
|
+
setPointerTargetFromElement(element, clientY, clientX) {
|
|
329
343
|
// Container ids belong to the host's domain and may repeat in another
|
|
330
344
|
// instance. Pointer hit-testing must never escape this one's root.
|
|
331
345
|
const root = this.options.root();
|
|
@@ -347,13 +361,21 @@ export class SortableController {
|
|
|
347
361
|
const rawIndex = this.itemsIn(containerId).indexOf(itemElement.dataset[selectors.itemKey] ?? '');
|
|
348
362
|
if (rawIndex < 0)
|
|
349
363
|
return container;
|
|
350
|
-
this.pointerTarget(containerId, this.insertionIndex(containerId, rawIndex, itemElement, clientY));
|
|
364
|
+
this.pointerTarget(containerId, this.insertionIndex(containerId, rawIndex, itemElement, clientY, clientX));
|
|
351
365
|
return container;
|
|
352
366
|
}
|
|
353
367
|
/** Index to insert at when hovering item `rawIndex`, after removing the dragged item. */
|
|
354
|
-
insertionIndex(containerId, rawIndex, itemElement, clientY) {
|
|
368
|
+
insertionIndex(containerId, rawIndex, itemElement, clientY, clientX) {
|
|
355
369
|
const rect = itemElement.getBoundingClientRect();
|
|
356
|
-
|
|
370
|
+
let before = clientY < rect.top + rect.height / 2;
|
|
371
|
+
if (this.options.flow?.() && clientX !== undefined) {
|
|
372
|
+
const rootWidth = this.options.root()?.getBoundingClientRect().width ?? 0;
|
|
373
|
+
// A tile narrower than the list shares its row: order is horizontal.
|
|
374
|
+
if (rect.width < rootWidth * 0.95) {
|
|
375
|
+
const mid = rect.left + rect.width / 2;
|
|
376
|
+
before = this.isRtl() ? clientX > mid : clientX < mid;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
357
379
|
let targetIndex = rawIndex + (before ? 0 : 1);
|
|
358
380
|
const drag = this.drag;
|
|
359
381
|
if (drag?.source.containerId === containerId &&
|
|
@@ -375,7 +397,7 @@ export class SortableController {
|
|
|
375
397
|
this.cancel();
|
|
376
398
|
return;
|
|
377
399
|
}
|
|
378
|
-
const container = this.setPointerTargetFromElement(this.elementAtPointer(event), event.clientY);
|
|
400
|
+
const container = this.setPointerTargetFromElement(this.elementAtPointer(event), event.clientY, event.clientX);
|
|
379
401
|
if (container?.disabled) {
|
|
380
402
|
this.say({ type: 'unavailable', container: container.label });
|
|
381
403
|
this.cancel(false);
|
|
@@ -405,7 +427,7 @@ export class SortableController {
|
|
|
405
427
|
this.pointerSession = { ...session, active: true };
|
|
406
428
|
}
|
|
407
429
|
event.preventDefault();
|
|
408
|
-
this.setPointerTargetFromElement(this.elementAtPointer(event), event.clientY);
|
|
430
|
+
this.setPointerTargetFromElement(this.elementAtPointer(event), event.clientY, event.clientX);
|
|
409
431
|
}
|
|
410
432
|
pointerTarget(containerId, index) {
|
|
411
433
|
const drag = this.drag;
|
|
@@ -431,7 +453,7 @@ export class SortableController {
|
|
|
431
453
|
this.cancel(false);
|
|
432
454
|
return;
|
|
433
455
|
}
|
|
434
|
-
this.pointerTarget(containerId, this.insertionIndex(containerId, rawIndex, event.currentTarget, event.clientY));
|
|
456
|
+
this.pointerTarget(containerId, this.insertionIndex(containerId, rawIndex, event.currentTarget, event.clientY, event.clientX));
|
|
435
457
|
void this.drop();
|
|
436
458
|
}
|
|
437
459
|
/** Native drop on a container's empty space: append. */
|
|
@@ -137,6 +137,26 @@ export interface NavTreeFromManifestOptions {
|
|
|
137
137
|
* `navTreeFromManifest` apply it.
|
|
138
138
|
*/
|
|
139
139
|
export declare function pluralizeClassName(name: string): string;
|
|
140
|
+
/** A manifest entry that passed the navigation filters, with what it exposes. */
|
|
141
|
+
export interface NavigableManifestEntry<E extends SmrtManifestEntryLike = SmrtManifestEntryLike> {
|
|
142
|
+
entry: E;
|
|
143
|
+
/** Qualified name, or the synthesised `package:Class`. */
|
|
144
|
+
qualifier: string;
|
|
145
|
+
/** Whether the REST `create` route is generated. */
|
|
146
|
+
creatable: boolean;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* The manifest entries admin navigation would list (the same filters as
|
|
150
|
+
* {@link navTreeFromManifest}: no collection classes, internal/test visibility,
|
|
151
|
+
* routeless `api`, or STI subtypes of a shared route), so other manifest-driven
|
|
152
|
+
* surfaces such as the command palette agree with the nav on what exists.
|
|
153
|
+
* Order is manifest order; sort for display.
|
|
154
|
+
*/
|
|
155
|
+
export declare function navigableManifestEntries<E extends SmrtManifestEntryLike>(manifest: {
|
|
156
|
+
objects: Record<string, E>;
|
|
157
|
+
}, options?: {
|
|
158
|
+
permittedResources?: readonly string[];
|
|
159
|
+
}): NavigableManifestEntry<E>[];
|
|
140
160
|
/**
|
|
141
161
|
* Walk a SMRT manifest and emit the `NavSection[]` shape that
|
|
142
162
|
* `<NavTree items={...}>` and `RoleConfig.sections` consume.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest-nav.d.ts","sourceRoot":"","sources":["../../../src/components/workspace/manifest-nav.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAQH;;;;GAIG;AACH,KAAK,kBAAkB,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,CAAC;AAEzD,mEAAmE;AACnE,MAAM,WAAW,qBAAqB;IACpC,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,kBAAkB,CAAC;IAChC;;;;OAIG;IACH,eAAe,CAAC,EAAE;QAChB,EAAE,CAAC,EAAE;YACH,IAAI,CAAC,EAAE,MAAM,CAAC;YACd,KAAK,CAAC,EAAE,MAAM,CAAC;SAChB,CAAC;QACF;;;;;WAKG;QACH,GAAG,CAAC,EACA,OAAO,GACP;YAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;YAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;YAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;SAAE,CAAC;QACvE;;;WAGG;QACH,UAAU,CAAC,EAAE,kBAAkB,CAAC;QAChC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;CACH;AAED,uCAAuC;AACvC,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;CAChD;AAWD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC;AAEjC,uDAAuD;AACvD,MAAM,WAAW,0BAA0B;IACzC;;;;;;;;;OASG;IACH,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAWD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAevD;
|
|
1
|
+
{"version":3,"file":"manifest-nav.d.ts","sourceRoot":"","sources":["../../../src/components/workspace/manifest-nav.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAQH;;;;GAIG;AACH,KAAK,kBAAkB,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,CAAC;AAEzD,mEAAmE;AACnE,MAAM,WAAW,qBAAqB;IACpC,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,kBAAkB,CAAC;IAChC;;;;OAIG;IACH,eAAe,CAAC,EAAE;QAChB,EAAE,CAAC,EAAE;YACH,IAAI,CAAC,EAAE,MAAM,CAAC;YACd,KAAK,CAAC,EAAE,MAAM,CAAC;SAChB,CAAC;QACF;;;;;WAKG;QACH,GAAG,CAAC,EACA,OAAO,GACP;YAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;YAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;YAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;SAAE,CAAC;QACvE;;;WAGG;QACH,UAAU,CAAC,EAAE,kBAAkB,CAAC;QAChC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;CACH;AAED,uCAAuC;AACvC,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;CAChD;AAWD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC;AAEjC,uDAAuD;AACvD,MAAM,WAAW,0BAA0B;IACzC;;;;;;;;;OASG;IACH,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAWD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAevD;AAqPD,iFAAiF;AACjF,MAAM,WAAW,sBAAsB,CACrC,CAAC,SAAS,qBAAqB,GAAG,qBAAqB;IAEvD,KAAK,EAAE,CAAC,CAAC;IACT,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,SAAS,EAAE,OAAO,CAAC;CACpB;AAgBD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,qBAAqB,EACtE,QAAQ,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;CAAE,EACxC,OAAO,GAAE;IAAE,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAO,GACvD,sBAAsB,CAAC,CAAC,CAAC,EAAE,CAc7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,GAAE,0BAA+B,GACvC,UAAU,EAAE,CA4Dd"}
|
|
@@ -185,6 +185,13 @@ function entryIndexByClassName(manifest) {
|
|
|
185
185
|
* - `{ exclude: [...] }` → all except listed routes
|
|
186
186
|
*/
|
|
187
187
|
function hasListRoute(entry) {
|
|
188
|
+
return hasApiRoute(entry, 'list');
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Whether an entry exposes the named REST route (`list`, `create`, ...), per
|
|
192
|
+
* the same `@smrt({ api })` shapes {@link hasListRoute} documents.
|
|
193
|
+
*/
|
|
194
|
+
function hasApiRoute(entry, route) {
|
|
188
195
|
const api = entry.decoratorConfig?.api;
|
|
189
196
|
if (api === undefined || api === true)
|
|
190
197
|
return true;
|
|
@@ -194,10 +201,10 @@ function hasListRoute(entry) {
|
|
|
194
201
|
return true;
|
|
195
202
|
const obj = api;
|
|
196
203
|
if (Array.isArray(obj.include)) {
|
|
197
|
-
return obj.include.includes(
|
|
204
|
+
return obj.include.includes(route);
|
|
198
205
|
}
|
|
199
206
|
if (Array.isArray(obj.exclude)) {
|
|
200
|
-
return !obj.exclude.includes(
|
|
207
|
+
return !obj.exclude.includes(route);
|
|
201
208
|
}
|
|
202
209
|
return true;
|
|
203
210
|
}
|
|
@@ -282,6 +289,38 @@ function expandPermittedThroughStiParents(permitted, manifest) {
|
|
|
282
289
|
}
|
|
283
290
|
return expanded;
|
|
284
291
|
}
|
|
292
|
+
function* listNavigableManifestEntries(manifest, permitted) {
|
|
293
|
+
for (const entry of Object.values(manifest.objects)) {
|
|
294
|
+
if (looksLikeCollectionClass(entry))
|
|
295
|
+
continue;
|
|
296
|
+
if (!isPublicEntry(entry))
|
|
297
|
+
continue;
|
|
298
|
+
if (!hasListRoute(entry))
|
|
299
|
+
continue;
|
|
300
|
+
if (looksLikeStiSubtypeOfParentRoute(entry, manifest))
|
|
301
|
+
continue;
|
|
302
|
+
if (permitted && !permitted.has(entryQualifier(entry)))
|
|
303
|
+
continue;
|
|
304
|
+
yield entry;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* The manifest entries admin navigation would list (the same filters as
|
|
309
|
+
* {@link navTreeFromManifest}: no collection classes, internal/test visibility,
|
|
310
|
+
* routeless `api`, or STI subtypes of a shared route), so other manifest-driven
|
|
311
|
+
* surfaces such as the command palette agree with the nav on what exists.
|
|
312
|
+
* Order is manifest order; sort for display.
|
|
313
|
+
*/
|
|
314
|
+
export function navigableManifestEntries(manifest, options = {}) {
|
|
315
|
+
const permitted = options.permittedResources
|
|
316
|
+
? expandPermittedThroughStiParents(new Set(options.permittedResources), manifest)
|
|
317
|
+
: undefined;
|
|
318
|
+
return [...listNavigableManifestEntries(manifest, permitted)].map((entry) => ({
|
|
319
|
+
entry: entry,
|
|
320
|
+
qualifier: entryQualifier(entry),
|
|
321
|
+
creatable: hasApiRoute(entry, 'create'),
|
|
322
|
+
}));
|
|
323
|
+
}
|
|
285
324
|
/**
|
|
286
325
|
* Walk a SMRT manifest and emit the `NavSection[]` shape that
|
|
287
326
|
* `<NavTree items={...}>` and `RoleConfig.sections` consume.
|
|
@@ -360,18 +399,8 @@ export function navTreeFromManifest(manifest, options = {}) {
|
|
|
360
399
|
// order, but we sort the final output anyway so callers don't have to
|
|
361
400
|
// care about it.
|
|
362
401
|
const sectionMap = new Map();
|
|
363
|
-
for (const entry of
|
|
364
|
-
if (looksLikeCollectionClass(entry))
|
|
365
|
-
continue;
|
|
366
|
-
if (!isPublicEntry(entry))
|
|
367
|
-
continue;
|
|
368
|
-
if (!hasListRoute(entry))
|
|
369
|
-
continue;
|
|
370
|
-
if (looksLikeStiSubtypeOfParentRoute(entry, manifest))
|
|
371
|
-
continue;
|
|
402
|
+
for (const entry of listNavigableManifestEntries(manifest, permitted)) {
|
|
372
403
|
const qualifier = entryQualifier(entry);
|
|
373
|
-
if (permitted && !permitted.has(qualifier))
|
|
374
|
-
continue;
|
|
375
404
|
const ui = entry.decoratorConfig?.ui;
|
|
376
405
|
const label = ui?.label ?? pluralizeClassName(entry.className);
|
|
377
406
|
const slug = entry.collection ?? classNameToKebab(entry.className);
|
package/dist/i18n/server.d.ts
CHANGED
|
@@ -22,7 +22,13 @@ import './strings.forms.js';
|
|
|
22
22
|
import './strings.board.js';
|
|
23
23
|
import './strings.sortable.js';
|
|
24
24
|
import './strings.audit.js';
|
|
25
|
+
import './strings.import-export.js';
|
|
25
26
|
import './strings.workspace.js';
|
|
27
|
+
import './strings.screens.js';
|
|
28
|
+
import './strings.palette.js';
|
|
29
|
+
import './strings.overview.js';
|
|
30
|
+
import './strings.settings.js';
|
|
31
|
+
import './strings.browser-ai.js';
|
|
26
32
|
import '../mcp-apps/strings.js';
|
|
27
33
|
export interface BuildI18nSnapshotOptions {
|
|
28
34
|
/** Target locale (BCP-47-ish, e.g. `fr-CA`). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/i18n/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAGL,KAAK,4BAA4B,EAElC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAEL,KAAK,YAAY,EAClB,MAAM,6BAA6B,CAAC;AAMrC,OAAO,6BAA6B,CAAC;AACrC,OAAO,oBAAoB,CAAC;AAC5B,OAAO,oBAAoB,CAAC;AAC5B,OAAO,uBAAuB,CAAC;AAC/B,OAAO,oBAAoB,CAAC;AAC5B,OAAO,wBAAwB,CAAC;AAChC,OAAO,wBAAwB,CAAC;AAEhC,MAAM,WAAW,wBAAwB;IACvC,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,4BAA4B,CAAC,UAAU,CAAC,CAAC;IACpD;;;OAGG;IACH,EAAE,CAAC,EAAE,4BAA4B,CAAC,IAAI,CAAC,CAAC;IACxC;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,YAAY,CAAC,CA4BvB"}
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/i18n/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAGL,KAAK,4BAA4B,EAElC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAEL,KAAK,YAAY,EAClB,MAAM,6BAA6B,CAAC;AAMrC,OAAO,6BAA6B,CAAC;AACrC,OAAO,oBAAoB,CAAC;AAC5B,OAAO,oBAAoB,CAAC;AAC5B,OAAO,uBAAuB,CAAC;AAC/B,OAAO,oBAAoB,CAAC;AAC5B,OAAO,4BAA4B,CAAC;AACpC,OAAO,wBAAwB,CAAC;AAChC,OAAO,sBAAsB,CAAC;AAC9B,OAAO,sBAAsB,CAAC;AAC9B,OAAO,uBAAuB,CAAC;AAC/B,OAAO,uBAAuB,CAAC;AAC/B,OAAO,yBAAyB,CAAC;AACjC,OAAO,wBAAwB,CAAC;AAEhC,MAAM,WAAW,wBAAwB;IACvC,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,4BAA4B,CAAC,UAAU,CAAC,CAAC;IACpD;;;OAGG;IACH,EAAE,CAAC,EAAE,4BAA4B,CAAC,IAAI,CAAC,CAAC;IACxC;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,YAAY,CAAC,CA4BvB"}
|
package/dist/i18n/server.js
CHANGED
|
@@ -27,7 +27,13 @@ import './strings.forms.js';
|
|
|
27
27
|
import './strings.board.js';
|
|
28
28
|
import './strings.sortable.js';
|
|
29
29
|
import './strings.audit.js';
|
|
30
|
+
import './strings.import-export.js';
|
|
30
31
|
import './strings.workspace.js';
|
|
32
|
+
import './strings.screens.js';
|
|
33
|
+
import './strings.palette.js';
|
|
34
|
+
import './strings.overview.js';
|
|
35
|
+
import './strings.settings.js';
|
|
36
|
+
import './strings.browser-ai.js';
|
|
31
37
|
import '../mcp-apps/strings.js';
|
|
32
38
|
/**
|
|
33
39
|
* Resolve a per-locale dictionary of message **templates** for the keys an app
|