@astryxdesign/cli 0.7.12-canary.e0821c1 → 0.7.12-canary.e171d97
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/api/build/blocks/blocks.d.mts +41 -0
- package/api/build/blocks/blocks.mjs +118 -68
- package/api/component/__fixtures__/resolutions/modules.txt +3 -3
- package/api/icon/_authoring.mjs +8 -1
- package/api/icon/add/add.mjs +45 -5
- package/api/icon/icon.type.d.mts +24 -0
- package/api/icon/icon.type.mjs +6 -0
- package/api/icon/iconAdd.doc.mjs +1 -1
- package/api/icon/map/map.mjs +11 -4
- package/api/integration/add-helpers.d.mts +5 -1
- package/api/integration/add-helpers.mjs +1 -1
- package/api/render/_adapter.mjs +9 -0
- package/api/render/render.doc.mjs +3 -3
- package/api/render/render.type.d.mts +1 -1
- package/api/render/render.type.mjs +1 -1
- package/api/search/ORDERING.md +3 -0
- package/api/search/_adapter.d.mts +10 -2
- package/api/search/_adapter.mjs +13 -2
- package/api/search/_fit-order.d.mts +47 -0
- package/api/search/_fit-order.mjs +257 -0
- package/api/search/_main-searcher.mjs +15 -5
- package/api/swizzle/_moduleGraph.d.mts +7 -0
- package/api/swizzle/_moduleGraph.mjs +191 -83
- package/api/swizzle/copy/copy.mjs +28 -6
- package/api/template/template.mjs +1 -0
- package/assets/discover/official-packages.json +16 -0
- package/assets/docs/styling-overview.doc.mjs +3 -3
- package/assets/docs/tree/icon-sets.doc.mjs +4 -4
- package/assets/docs/tree/render-pages.doc.mjs +2 -2
- package/assets/docs/tree/tailwind.doc.mjs +41 -1
- package/assets/docs/tree/type-scale.doc.mjs +19 -2
- package/assets/templates/blocks/components/Hooks/useInputStatusIconHookUsage.tsx +1 -0
- package/assets/templates/blocks/components/Hooks/useInteractiveRoleHookUsage.doc.mjs +14 -0
- package/assets/templates/blocks/components/Hooks/useInteractiveRoleHookUsage.tsx +56 -0
- package/assets/templates/blocks/components/Hooks/useStreamingTextHookUsage.doc.mjs +2 -2
- package/assets/templates/blocks/components/Hooks/useStreamingTextHookUsage.tsx +66 -10
- package/assets/templates/blocks/components/Link/useLinkifyHookUsage.doc.mjs +14 -0
- package/assets/templates/blocks/components/Link/useLinkifyHookUsage.tsx +39 -0
- package/assets/templates/blocks/components/PowerSearch/usePowerSearchConfigHookUsage.doc.mjs +14 -0
- package/assets/templates/blocks/components/PowerSearch/usePowerSearchConfigHookUsage.tsx +83 -0
- package/assets/templates/blocks/components/Table/RowsVirtualizationHookUsage.doc.mjs +14 -0
- package/assets/templates/blocks/components/Table/RowsVirtualizationHookUsage.tsx +35 -0
- package/assets/templates/blocks/components/Table/useTableColumnSettingsStateHookUsage.doc.mjs +14 -0
- package/assets/templates/blocks/components/Table/useTableColumnSettingsStateHookUsage.tsx +97 -0
- package/assets/templates/pages/table-filter/page.tsx +15 -23
- package/assets/templates/pages/table-inbox/page.tsx +3 -6
- package/assets/templates/themes/butter/butterTheme.ts +1 -1
- package/assets/templates/themes/gothic/gothicTheme.ts +16 -0
- package/assets/templates/themes/neutral/neutralTheme.ts +6 -0
- package/clients/cli/commands/experimental/icon.mjs +25 -4
- package/clients/cli/commands/experimental-render.doc.mjs +1 -1
- package/clients/cli/lib/resolve-theme.mjs +16 -7
- package/foundation/discovery/hook-discovery.mjs +31 -8
- package/foundation/discovery/icon-set-writer.d.mts +21 -5
- package/foundation/discovery/icon-set-writer.mjs +114 -13
- package/foundation/doc-compiler/import.d.mts +5 -1
- package/foundation/doc-compiler/import.mjs +40 -6
- package/foundation/fs/import-url.d.mts +20 -0
- package/foundation/fs/import-url.mjs +22 -0
- package/foundation/fs/module-loader.d.mts +24 -3
- package/foundation/fs/module-loader.mjs +69 -47
- package/foundation/render/embedded-imports.d.mts +7 -7
- package/foundation/render/embedded-imports.mjs +63 -54
- package/foundation/render/page-host.d.mts +4 -0
- package/foundation/render/page-host.mjs +45 -0
- package/foundation/render/page-worker.mjs +114 -57
- package/foundation/render/render-page.d.mts +11 -6
- package/foundation/render/render-page.mjs +138 -44
- package/foundation/render/ts-paths.d.mts +63 -0
- package/foundation/render/ts-paths.mjs +138 -0
- package/foundation/response/error-codes.doc.mjs +3 -3
- package/foundation/response/error-codes.mjs +3 -2
- package/foundation/text/levenshtein.d.mts +6 -1
- package/foundation/text/levenshtein.mjs +25 -9
- package/foundation/text/suggest-order.d.mts +8 -1
- package/foundation/text/suggest-order.mjs +72 -6
- package/package.json +6 -6
|
@@ -22,6 +22,47 @@ export function wordsOf(text: string): string[];
|
|
|
22
22
|
* @returns {string[]}
|
|
23
23
|
*/
|
|
24
24
|
export function termsOf(text: string): string[];
|
|
25
|
+
/**
|
|
26
|
+
* A text's docs side for `matchOf`: its word vector and that vector through
|
|
27
|
+
* the doc matrix. Search scores its entries' own docs with it.
|
|
28
|
+
* @param {string} text
|
|
29
|
+
* @param {BlockPickerWeights} weights
|
|
30
|
+
* @returns {{vector: Map<number, number>, projected: Float64Array}}
|
|
31
|
+
*/
|
|
32
|
+
export function docSideOf(text: string, weights: BlockPickerWeights): {
|
|
33
|
+
vector: Map<number, number>;
|
|
34
|
+
projected: Float64Array;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* A request's side for `matchOf`: its word vector and that vector through the
|
|
38
|
+
* request matrix.
|
|
39
|
+
* @param {string} request
|
|
40
|
+
* @param {BlockPickerWeights} weights
|
|
41
|
+
* @returns {{vector: Map<number, number>, projected: Float64Array}}
|
|
42
|
+
*/
|
|
43
|
+
export function requestSideOf(request: string, weights: BlockPickerWeights): {
|
|
44
|
+
vector: Map<number, number>;
|
|
45
|
+
projected: Float64Array;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* The picker's match of a request to a docs text: their projections' dot
|
|
49
|
+
* product plus the lexical weight times their plain overlap (the cosine of
|
|
50
|
+
* their word vectors). Build's ranking also reads the overlap alone.
|
|
51
|
+
* @param {{vector: Map<number, number>, projected: Float64Array}} request
|
|
52
|
+
* @param {{vector: Map<number, number>, projected: Float64Array}} doc
|
|
53
|
+
* @param {BlockPickerWeights} weights
|
|
54
|
+
* @returns {{match: number, overlap: number}}
|
|
55
|
+
*/
|
|
56
|
+
export function matchOf(request: {
|
|
57
|
+
vector: Map<number, number>;
|
|
58
|
+
projected: Float64Array;
|
|
59
|
+
}, doc: {
|
|
60
|
+
vector: Map<number, number>;
|
|
61
|
+
projected: Float64Array;
|
|
62
|
+
}, weights: BlockPickerWeights): {
|
|
63
|
+
match: number;
|
|
64
|
+
overlap: number;
|
|
65
|
+
};
|
|
25
66
|
/**
|
|
26
67
|
* The blocks build names for a request, ranked by the picker.
|
|
27
68
|
* @param {string} request
|
|
@@ -163,34 +163,10 @@ export function termsOf(text) {
|
|
|
163
163
|
return out;
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
-
/**
|
|
167
|
-
* The weights, decoded once per weights object.
|
|
168
|
-
* @type {WeakMap<BlockPickerWeights, {index: Map<string, number>, idf: Float64Array, request: Int8Array, doc: Int8Array}>}
|
|
169
|
-
*/
|
|
170
|
-
const decoded = new WeakMap();
|
|
171
|
-
|
|
172
|
-
/** @param {BlockPickerWeights} weights */
|
|
173
|
-
function decode(weights) {
|
|
174
|
-
let d = decoded.get(weights);
|
|
175
|
-
if (!d) {
|
|
176
|
-
// Each byte is a signed weight stored offset by 128.
|
|
177
|
-
const bytes = (/** @type {string} */ s) =>
|
|
178
|
-
Int8Array.from(Buffer.from(s, 'base64'), b => b - 128);
|
|
179
|
-
d = {
|
|
180
|
-
index: new Map(weights.vocab.map((w, i) => [w, i])),
|
|
181
|
-
idf: Float64Array.from(weights.idf, x => x / 1024),
|
|
182
|
-
request: bytes(weights.request),
|
|
183
|
-
doc: bytes(weights.doc),
|
|
184
|
-
};
|
|
185
|
-
decoded.set(weights, d);
|
|
186
|
-
}
|
|
187
|
-
return d;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
166
|
/**
|
|
191
167
|
* A text's sparse unit vector over the vocabulary: (1 + ln count) x idf.
|
|
192
168
|
* @param {string[]} terms
|
|
193
|
-
* @param {
|
|
169
|
+
* @param {{index: Map<string, number>, idf: Float64Array}} d
|
|
194
170
|
* @returns {Map<number, number>}
|
|
195
171
|
*/
|
|
196
172
|
function vectorOf(terms, d) {
|
|
@@ -214,20 +190,116 @@ function vectorOf(terms, d) {
|
|
|
214
190
|
}
|
|
215
191
|
|
|
216
192
|
/**
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
* @
|
|
193
|
+
* The vocabulary index and idf, read once per weights object, and each matrix
|
|
194
|
+
* row decoded when a side first uses it.
|
|
195
|
+
* @type {WeakMap<BlockPickerWeights, {index: Map<string, number>, idf: Float64Array, rows: Map<string, Int8Array>}>}
|
|
196
|
+
*/
|
|
197
|
+
const vocabularies = new WeakMap();
|
|
198
|
+
|
|
199
|
+
/** @param {BlockPickerWeights} weights */
|
|
200
|
+
function vocabularyOf(weights) {
|
|
201
|
+
let v = vocabularies.get(weights);
|
|
202
|
+
if (!v) {
|
|
203
|
+
v = {
|
|
204
|
+
index: new Map(weights.vocab.map((w, i) => [w, i])),
|
|
205
|
+
idf: Float64Array.from(weights.idf, x => x / 1024),
|
|
206
|
+
rows: new Map(),
|
|
207
|
+
};
|
|
208
|
+
vocabularies.set(weights, v);
|
|
209
|
+
}
|
|
210
|
+
return v;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* One row of a byte matrix, decoded from the base64 text alone: four
|
|
215
|
+
* characters hold three bytes, so the row's bytes sit inside the characters
|
|
216
|
+
* from its first byte's group to its last byte's group.
|
|
217
|
+
* @param {BlockPickerWeights} weights
|
|
218
|
+
* @param {'request' | 'doc'} matrix
|
|
219
|
+
* @param {number} i
|
|
220
|
+
* @returns {Int8Array}
|
|
221
|
+
*/
|
|
222
|
+
function rowOf(weights, matrix, i) {
|
|
223
|
+
const {rows} = vocabularyOf(weights);
|
|
224
|
+
const key = `${matrix}:${i}`;
|
|
225
|
+
let row = rows.get(key);
|
|
226
|
+
if (!row) {
|
|
227
|
+
const {dims} = weights;
|
|
228
|
+
const first = Math.floor((i * dims) / 3);
|
|
229
|
+
const last = Math.ceil(((i + 1) * dims) / 3);
|
|
230
|
+
const bytes = Buffer.from(
|
|
231
|
+
weights[matrix].slice(first * 4, last * 4),
|
|
232
|
+
'base64',
|
|
233
|
+
).subarray(i * dims - first * 3, i * dims - first * 3 + dims);
|
|
234
|
+
// Each byte is a signed weight stored offset by 128.
|
|
235
|
+
row = Int8Array.from(bytes, b => b - 128);
|
|
236
|
+
rows.set(key, row);
|
|
237
|
+
}
|
|
238
|
+
return row;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* A text's side for `matchOf` through one matrix: its word vector, and that
|
|
243
|
+
* vector times the matrix rows its words use, scaled.
|
|
244
|
+
* @param {string} text
|
|
245
|
+
* @param {BlockPickerWeights} weights
|
|
246
|
+
* @param {'request' | 'doc'} matrix
|
|
220
247
|
* @param {number} scale
|
|
221
|
-
* @
|
|
248
|
+
* @returns {{vector: Map<number, number>, projected: Float64Array}}
|
|
222
249
|
*/
|
|
223
|
-
function
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
250
|
+
function sideOf(text, weights, matrix, scale) {
|
|
251
|
+
const vector = vectorOf(termsOf(text), vocabularyOf(weights));
|
|
252
|
+
const {dims} = weights;
|
|
253
|
+
const projected = new Float64Array(dims);
|
|
254
|
+
for (const [i, x] of vector) {
|
|
255
|
+
const row = rowOf(weights, matrix, i);
|
|
256
|
+
for (let k = 0; k < dims; k++) projected[k] += x * row[k];
|
|
228
257
|
}
|
|
229
|
-
for (let k = 0; k < dims; k++)
|
|
230
|
-
return
|
|
258
|
+
for (let k = 0; k < dims; k++) projected[k] *= scale;
|
|
259
|
+
return {vector, projected};
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* A text's docs side for `matchOf`: its word vector and that vector through
|
|
264
|
+
* the doc matrix. Search scores its entries' own docs with it.
|
|
265
|
+
* @param {string} text
|
|
266
|
+
* @param {BlockPickerWeights} weights
|
|
267
|
+
* @returns {{vector: Map<number, number>, projected: Float64Array}}
|
|
268
|
+
*/
|
|
269
|
+
export function docSideOf(text, weights) {
|
|
270
|
+
return sideOf(text, weights, 'doc', weights.docScale);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* A request's side for `matchOf`: its word vector and that vector through the
|
|
275
|
+
* request matrix.
|
|
276
|
+
* @param {string} request
|
|
277
|
+
* @param {BlockPickerWeights} weights
|
|
278
|
+
* @returns {{vector: Map<number, number>, projected: Float64Array}}
|
|
279
|
+
*/
|
|
280
|
+
export function requestSideOf(request, weights) {
|
|
281
|
+
return sideOf(request, weights, 'request', weights.requestScale);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* The picker's match of a request to a docs text: their projections' dot
|
|
286
|
+
* product plus the lexical weight times their plain overlap (the cosine of
|
|
287
|
+
* their word vectors). Build's ranking also reads the overlap alone.
|
|
288
|
+
* @param {{vector: Map<number, number>, projected: Float64Array}} request
|
|
289
|
+
* @param {{vector: Map<number, number>, projected: Float64Array}} doc
|
|
290
|
+
* @param {BlockPickerWeights} weights
|
|
291
|
+
* @returns {{match: number, overlap: number}}
|
|
292
|
+
*/
|
|
293
|
+
export function matchOf(request, doc, weights) {
|
|
294
|
+
let s = 0;
|
|
295
|
+
for (let k = 0; k < weights.dims; k++)
|
|
296
|
+
s += request.projected[k] * doc.projected[k];
|
|
297
|
+
let overlap = 0;
|
|
298
|
+
for (const [i, x] of request.vector) {
|
|
299
|
+
const y = doc.vector.get(i);
|
|
300
|
+
if (y !== undefined) overlap += x * y;
|
|
301
|
+
}
|
|
302
|
+
return {match: s + weights.lexical * overlap, overlap};
|
|
231
303
|
}
|
|
232
304
|
|
|
233
305
|
/**
|
|
@@ -261,7 +333,6 @@ function readCatalog(catalog, components, weights) {
|
|
|
261
333
|
]);
|
|
262
334
|
const cached = catalogs.get(weights);
|
|
263
335
|
if (cached && cached.key === key) return cached;
|
|
264
|
-
const d = decode(weights);
|
|
265
336
|
const names = components.map(c => c.name).sort((a, b) => b.length - a.length);
|
|
266
337
|
const keywords = new Map(components.map(c => [c.name, c.keywords ?? []]));
|
|
267
338
|
/** @type {Map<string, {component: string, vector: Map<number, number>, projected: Float64Array}>} */
|
|
@@ -276,12 +347,7 @@ function readCatalog(catalog, components, weights) {
|
|
|
276
347
|
wordsOf(component).join(' '),
|
|
277
348
|
(keywords.get(component) ?? []).join(' '),
|
|
278
349
|
].join(' ');
|
|
279
|
-
|
|
280
|
-
blocks.set(b.name, {
|
|
281
|
-
component,
|
|
282
|
-
vector,
|
|
283
|
-
projected: project(vector, d.doc, weights.docScale, weights.dims),
|
|
284
|
-
});
|
|
350
|
+
blocks.set(b.name, {component, ...docSideOf(text, weights)});
|
|
285
351
|
}
|
|
286
352
|
// A component is named by its own words, or by a keyword at most three
|
|
287
353
|
// components share (weighted by how few share it).
|
|
@@ -378,26 +444,12 @@ export function pickBlocks(request, signals, weights) {
|
|
|
378
444
|
/** @type {Map<string, SearchResultEntry>} */
|
|
379
445
|
const entries = new Map();
|
|
380
446
|
if (own.length === 0) return {names: [], entries};
|
|
381
|
-
const d = decode(weights);
|
|
382
447
|
const cat = readCatalog(signals.catalog, signals.components, weights);
|
|
383
|
-
const
|
|
384
|
-
const eq = project(q, d.request, weights.requestScale, weights.dims);
|
|
385
|
-
const dot = (/** @type {Map<number, number>} */ v) => {
|
|
386
|
-
let s = 0;
|
|
387
|
-
for (const [i, x] of q) {
|
|
388
|
-
const y = v.get(i);
|
|
389
|
-
if (y !== undefined) s += x * y;
|
|
390
|
-
}
|
|
391
|
-
return s;
|
|
392
|
-
};
|
|
448
|
+
const side = requestSideOf(request, weights);
|
|
393
449
|
/** @type {Map<string, {match: number, overlap: number}>} */
|
|
394
450
|
const scored = new Map();
|
|
395
|
-
for (const [name, b] of cat.blocks)
|
|
396
|
-
|
|
397
|
-
for (let k = 0; k < weights.dims; k++) s += eq[k] * b.projected[k];
|
|
398
|
-
const overlap = dot(b.vector);
|
|
399
|
-
scored.set(name, {match: s + weights.lexical * overlap, overlap});
|
|
400
|
-
}
|
|
451
|
+
for (const [name, b] of cat.blocks)
|
|
452
|
+
scored.set(name, matchOf(side, b, weights));
|
|
401
453
|
const get = (/** @type {string} */ b) =>
|
|
402
454
|
scored.get(b) ?? {match: -Infinity, overlap: 0};
|
|
403
455
|
const ranked = [...scored.keys()].sort((a, b) => get(b).match - get(a).match);
|
|
@@ -480,7 +532,7 @@ export function pickBlocks(request, signals, weights) {
|
|
|
480
532
|
name,
|
|
481
533
|
package: block.package ?? '',
|
|
482
534
|
score: Math.max(1, Math.round(100 * Math.exp(x.score - max))),
|
|
483
|
-
reason: reasonFor(request, cat.blocks.get(name),
|
|
535
|
+
reason: reasonFor(request, side, cat.blocks.get(name), weights),
|
|
484
536
|
description: block.description ?? '',
|
|
485
537
|
displayName: block.displayName,
|
|
486
538
|
kind: 'block',
|
|
@@ -493,11 +545,11 @@ export function pickBlocks(request, signals, weights) {
|
|
|
493
545
|
/**
|
|
494
546
|
* Why a block fits: the request words that tie it to its docs most.
|
|
495
547
|
* @param {string} request
|
|
548
|
+
* @param {{vector: Map<number, number>, projected: Float64Array}} side the request's side
|
|
496
549
|
* @param {{vector: Map<number, number>, projected: Float64Array} | undefined} block
|
|
497
|
-
* @param {ReturnType<typeof decode>} d
|
|
498
550
|
* @param {BlockPickerWeights} weights
|
|
499
551
|
*/
|
|
500
|
-
function reasonFor(request,
|
|
552
|
+
function reasonFor(request, side, block, weights) {
|
|
501
553
|
if (!block) return 'fits by meaning';
|
|
502
554
|
const raw =
|
|
503
555
|
String(request)
|
|
@@ -507,16 +559,14 @@ function reasonFor(request, block, d, weights) {
|
|
|
507
559
|
const wordOf = new Map();
|
|
508
560
|
for (const w of raw)
|
|
509
561
|
if (!STOP.has(w) && !wordOf.has(stemOf(w))) wordOf.set(stemOf(w), w);
|
|
510
|
-
const q = vectorOf(termsOf(request), d);
|
|
511
562
|
/** @type {[string, number][]} */
|
|
512
563
|
const parts = [];
|
|
513
|
-
for (const [i, x] of
|
|
564
|
+
for (const [i, x] of side.vector) {
|
|
514
565
|
const term = weights.vocab[i];
|
|
515
566
|
if (term.includes('_')) continue;
|
|
567
|
+
const row = rowOf(weights, 'request', i);
|
|
516
568
|
let s = 0;
|
|
517
|
-
|
|
518
|
-
for (let k = 0; k < weights.dims; k++)
|
|
519
|
-
s += d.request[row + k] * block.projected[k];
|
|
569
|
+
for (let k = 0; k < weights.dims; k++) s += row[k] * block.projected[k];
|
|
520
570
|
s =
|
|
521
571
|
x * s * weights.requestScale +
|
|
522
572
|
weights.lexical * x * (block.vector.get(i) ?? 0);
|
|
@@ -271,7 +271,7 @@ useIsomorphicLayoutEffect useIsomorphicLayoutEffect hooks/useAnimatedLayout.doc.
|
|
|
271
271
|
useLayerDismissal useLayerDismissal Layer/Layer.doc.mjs Layer/useLayerDismissal.ts
|
|
272
272
|
useLightbox useLightbox Lightbox/useLightbox.doc.mjs Lightbox/useLightbox.tsx
|
|
273
273
|
useLinkComponent useLinkComponent Link/useLinkComponent.doc.mjs Link/useLinkComponent.ts
|
|
274
|
-
useLinkify useLinkify Link/
|
|
274
|
+
useLinkify useLinkify Link/useLinkify.doc.mjs Link/useLinkify.tsx
|
|
275
275
|
useListFormatter useListFormatter i18n/InternationalizationProvider.doc.mjs i18n/useListFormatter.ts
|
|
276
276
|
useMenuDrillIn useMenuDrillIn DropdownMenu/DropdownMenu.doc.mjs DropdownMenu/useMenuDrillIn.tsx
|
|
277
277
|
useMenuHover useMenuHover hooks/useAnimatedLayout.doc.mjs hooks/useMenuHover.ts
|
|
@@ -282,7 +282,7 @@ useOverlay useOverlay Overlay/useOverlay.doc.mjs Overlay/useOverlay.tsx
|
|
|
282
282
|
useOwnScrollGesture useOwnScrollGesture DateInput/DateInput.doc.mjs DateInput/useOwnScrollGesture.ts
|
|
283
283
|
usePager usePager hooks/useAnimatedLayout.doc.mjs hooks/usePager.ts
|
|
284
284
|
usePointerDragScroll usePointerDragScroll DateInput/DateInput.doc.mjs DateInput/usePointerDragScroll.ts
|
|
285
|
-
usePowerSearchConfig usePowerSearchConfig PowerSearch/
|
|
285
|
+
usePowerSearchConfig usePowerSearchConfig PowerSearch/usePowerSearchConfig.doc.mjs PowerSearch/usePowerSearchConfig.ts
|
|
286
286
|
usePowerSearchSource usePowerSearchSource PowerSearch/PowerSearch.doc.mjs PowerSearch/usePowerSearchSource.ts
|
|
287
287
|
useRenamedProp useRenamedProp hooks/useAnimatedLayout.doc.mjs hooks/useRenamedProp.ts
|
|
288
288
|
useResolvedRequired useResolvedRequired hooks/useAnimatedLayout.doc.mjs hooks/useResolvedRequired.ts
|
|
@@ -298,7 +298,7 @@ useSpeechRecognition useSpeechRecognition Chat/Chat.doc.mjs Chat/useSpeechRecogn
|
|
|
298
298
|
useSwipeAction useSwipeAction Item/Item.doc.mjs Item/useSwipeAction.ts
|
|
299
299
|
useSwitchTouch useSwitchTouch Switch/Switch.doc.mjs Switch/useSwitchTouch.ts
|
|
300
300
|
useTableCellStyles useTableCellStyles Table/Table.doc.mjs Table/useTableCellStyles.ts
|
|
301
|
-
useTableColumnSettingsState useTableColumnSettingsState Table/
|
|
301
|
+
useTableColumnSettingsState useTableColumnSettingsState Table/plugins/columnSettings/useTableColumnSettingsState.doc.mjs Table/plugins/columnSettings/useTableColumnSettingsState.tsx
|
|
302
302
|
useTableSortableState useTableSortableState Table/plugins/sortable/useTableSortableState.doc.mjs Table/plugins/sortable/useTableSortableState.tsx
|
|
303
303
|
useToastGesture useToastGesture Toast/Toast.doc.mjs Toast/useToastGesture.ts
|
|
304
304
|
useTouchTrigger useTouchTrigger Layer/Layer.doc.mjs Layer/useTouchTrigger.ts
|
package/api/icon/_authoring.mjs
CHANGED
|
@@ -691,6 +691,7 @@ async function redeclareIconSet(
|
|
|
691
691
|
);
|
|
692
692
|
result.data.icons = set.data.icons.length;
|
|
693
693
|
result.data.updated = true;
|
|
694
|
+
if (where.moduleUpdate) result.data.moduleUpdate = where.moduleUpdate;
|
|
694
695
|
// A look the icons' own library draws comes from that library, so its
|
|
695
696
|
// command runs as printed; any other look comes from a module the
|
|
696
697
|
// author names.
|
|
@@ -1388,6 +1389,7 @@ async function refreshIconSet(
|
|
|
1388
1389
|
);
|
|
1389
1390
|
result.data.icons = icons.length;
|
|
1390
1391
|
result.data.refreshed = true;
|
|
1392
|
+
if (where.moduleUpdate) result.data.moduleUpdate = where.moduleUpdate;
|
|
1391
1393
|
// Every entry an exact name gives, kept or new, so a refresh lists
|
|
1392
1394
|
// them for review again.
|
|
1393
1395
|
const byName = Object.fromEntries(
|
|
@@ -1542,7 +1544,7 @@ export async function addIconDefinition(name, options) {
|
|
|
1542
1544
|
throw error;
|
|
1543
1545
|
}
|
|
1544
1546
|
}
|
|
1545
|
-
|
|
1547
|
+
const result = receipt(
|
|
1546
1548
|
'icon-definition',
|
|
1547
1549
|
doc.name,
|
|
1548
1550
|
{
|
|
@@ -1559,5 +1561,10 @@ export async function addIconDefinition(name, options) {
|
|
|
1559
1561
|
files,
|
|
1560
1562
|
dryRun,
|
|
1561
1563
|
);
|
|
1564
|
+
// Only a new definition with an icon writes the data file.
|
|
1565
|
+
if (icon != null && where.moduleUpdate) {
|
|
1566
|
+
result.data.moduleUpdate = where.moduleUpdate;
|
|
1567
|
+
}
|
|
1568
|
+
return result;
|
|
1562
1569
|
});
|
|
1563
1570
|
}
|
package/api/icon/add/add.mjs
CHANGED
|
@@ -147,6 +147,15 @@ export async function iconAdd(exportName, options) {
|
|
|
147
147
|
);
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
|
+
// An export name cannot start with a digit, and an id the author gives has
|
|
151
|
+
// no library prefix to keep.
|
|
152
|
+
if (givenId != null && /^[0-9]/u.test(givenId)) {
|
|
153
|
+
throw new AstryxError(
|
|
154
|
+
`The icon id "${givenId}" starts with a digit, and an export name cannot. Pass --id with an id that starts with a letter.`,
|
|
155
|
+
undefined,
|
|
156
|
+
ERROR_CODES.ERR_INVALID_ARGUMENT,
|
|
157
|
+
);
|
|
158
|
+
}
|
|
150
159
|
if (all) {
|
|
151
160
|
return authoring(() => addVariantForAll({cwd, from, selector, variant}));
|
|
152
161
|
}
|
|
@@ -386,6 +395,8 @@ export async function iconAdd(exportName, options) {
|
|
|
386
395
|
map,
|
|
387
396
|
icons,
|
|
388
397
|
};
|
|
398
|
+
const dataChanged =
|
|
399
|
+
JSON.stringify(next) !== JSON.stringify(set.data) || where.moduleRenamed;
|
|
389
400
|
/** @type {string[]} */
|
|
390
401
|
const files = [];
|
|
391
402
|
// Every write happens inside this try, so any failure undoes the ones
|
|
@@ -413,7 +424,7 @@ export async function iconAdd(exportName, options) {
|
|
|
413
424
|
.join('/'),
|
|
414
425
|
);
|
|
415
426
|
}
|
|
416
|
-
if (
|
|
427
|
+
if (dataChanged) {
|
|
417
428
|
writeIconSetData(set, next, {
|
|
418
429
|
extraDefinitions: created ? [created.name] : [],
|
|
419
430
|
});
|
|
@@ -433,10 +444,12 @@ export async function iconAdd(exportName, options) {
|
|
|
433
444
|
}
|
|
434
445
|
throw error;
|
|
435
446
|
}
|
|
436
|
-
|
|
447
|
+
// A renamed package's new name alone is not an added icon.
|
|
448
|
+
const added =
|
|
437
449
|
JSON.stringify(next) !== JSON.stringify(set.data) ||
|
|
438
450
|
created != null ||
|
|
439
451
|
generatedChanged;
|
|
452
|
+
const changed = dataChanged || added;
|
|
440
453
|
// A ./ file publishes only when package.json `files` lists it; the
|
|
441
454
|
// author adds it (architecture:cli-surface INV16).
|
|
442
455
|
const note =
|
|
@@ -457,6 +470,8 @@ export async function iconAdd(exportName, options) {
|
|
|
457
470
|
...(created ? {newDefinition: created.name} : {}),
|
|
458
471
|
files,
|
|
459
472
|
changed,
|
|
473
|
+
added,
|
|
474
|
+
...(where.moduleUpdate ? {moduleUpdate: where.moduleUpdate} : {}),
|
|
460
475
|
...(note ? {note} : {}),
|
|
461
476
|
},
|
|
462
477
|
};
|
|
@@ -638,8 +653,27 @@ async function addVariantForAll({cwd, from, selector, variant}) {
|
|
|
638
653
|
);
|
|
639
654
|
// Only icons from the same package as the variant module can have a
|
|
640
655
|
// variant there: an icon from your own `./` file, or from another library,
|
|
641
|
-
// is left as it is and never listed as missing.
|
|
656
|
+
// is left as it is and never listed as missing. Some libraries ship each
|
|
657
|
+
// look as its own package (Font Awesome's solid and regular packages): an
|
|
658
|
+
// icon from another package meets its variant only under the same export
|
|
659
|
+
// name and of the same kind, a component or data for the adapter. Once
|
|
660
|
+
// one icon of a package meets its twin, that package is a look package of
|
|
661
|
+
// the variant module, so its other icons are listed as missing.
|
|
642
662
|
const variantPackage = iconModulePackage(source.module);
|
|
663
|
+
/** @param {{module: string, source: string, adapt: boolean}} origin */
|
|
664
|
+
const otherPackageTwin = origin => {
|
|
665
|
+
if (origin.module.startsWith('.')) return false;
|
|
666
|
+
const twin = byLibraryExport.get(origin.source);
|
|
667
|
+
return twin != null && twin.adapt === origin.adapt;
|
|
668
|
+
};
|
|
669
|
+
const lookPackages = new Set(
|
|
670
|
+
set.data.icons.flatMap(icon => {
|
|
671
|
+
const origin = origins.get(icon.export);
|
|
672
|
+
return origin && otherPackageTwin(origin)
|
|
673
|
+
? [iconModulePackage(origin.module)]
|
|
674
|
+
: [];
|
|
675
|
+
}),
|
|
676
|
+
);
|
|
643
677
|
const generated = generatedModulePath(set, packageDir);
|
|
644
678
|
/** @type {import('../../../foundation/discovery/icon-set-writer.mjs').GeneratedIcon[]} */
|
|
645
679
|
const toWrite = [];
|
|
@@ -653,7 +687,11 @@ async function addVariantForAll({cwd, from, selector, variant}) {
|
|
|
653
687
|
const own = [];
|
|
654
688
|
const icons = set.data.icons.map(icon => {
|
|
655
689
|
const origin = origins.get(icon.export);
|
|
656
|
-
if (
|
|
690
|
+
if (
|
|
691
|
+
origin &&
|
|
692
|
+
iconModulePackage(origin.module) !== variantPackage &&
|
|
693
|
+
!lookPackages.has(iconModulePackage(origin.module))
|
|
694
|
+
) {
|
|
657
695
|
return icon;
|
|
658
696
|
}
|
|
659
697
|
const librarySource =
|
|
@@ -742,7 +780,8 @@ async function addVariantForAll({cwd, from, selector, variant}) {
|
|
|
742
780
|
const files = [];
|
|
743
781
|
const written = writeGeneratedIcons(packageDir, generated, next, toWrite);
|
|
744
782
|
files.push(...written.files);
|
|
745
|
-
const dataChanged =
|
|
783
|
+
const dataChanged =
|
|
784
|
+
JSON.stringify(next) !== JSON.stringify(set.data) || where.moduleRenamed;
|
|
746
785
|
if (dataChanged) {
|
|
747
786
|
try {
|
|
748
787
|
writeIconSetData(set, next);
|
|
@@ -766,6 +805,7 @@ async function addVariantForAll({cwd, from, selector, variant}) {
|
|
|
766
805
|
missing,
|
|
767
806
|
files,
|
|
768
807
|
changed: dataChanged || written.changed,
|
|
808
|
+
...(where.moduleUpdate ? {moduleUpdate: where.moduleUpdate} : {}),
|
|
769
809
|
},
|
|
770
810
|
};
|
|
771
811
|
}
|
package/api/icon/icon.type.d.mts
CHANGED
|
@@ -223,6 +223,10 @@ export type IconMapManyResponse = {
|
|
|
223
223
|
changed: boolean;
|
|
224
224
|
}>;
|
|
225
225
|
changed: boolean;
|
|
226
|
+
moduleUpdate?: {
|
|
227
|
+
previous: string;
|
|
228
|
+
module: string;
|
|
229
|
+
} | undefined;
|
|
226
230
|
files?: string[] | undefined;
|
|
227
231
|
};
|
|
228
232
|
};
|
|
@@ -239,6 +243,10 @@ export type IconMapResponse = {
|
|
|
239
243
|
icon: string | null;
|
|
240
244
|
previous: string | null;
|
|
241
245
|
changed: boolean;
|
|
246
|
+
moduleUpdate?: {
|
|
247
|
+
previous: string;
|
|
248
|
+
module: string;
|
|
249
|
+
} | undefined;
|
|
242
250
|
files?: string[] | undefined;
|
|
243
251
|
};
|
|
244
252
|
};
|
|
@@ -303,6 +311,10 @@ export type IconAddVariantsResponse = {
|
|
|
303
311
|
missing: string[];
|
|
304
312
|
files: string[];
|
|
305
313
|
changed: boolean;
|
|
314
|
+
moduleUpdate?: {
|
|
315
|
+
previous: string;
|
|
316
|
+
module: string;
|
|
317
|
+
} | undefined;
|
|
306
318
|
};
|
|
307
319
|
};
|
|
308
320
|
/**
|
|
@@ -323,6 +335,11 @@ export type IconAddResponse = {
|
|
|
323
335
|
newDefinition?: string | undefined;
|
|
324
336
|
files: string[];
|
|
325
337
|
changed: boolean;
|
|
338
|
+
added: boolean;
|
|
339
|
+
moduleUpdate?: {
|
|
340
|
+
previous: string;
|
|
341
|
+
module: string;
|
|
342
|
+
} | undefined;
|
|
326
343
|
note?: string | undefined;
|
|
327
344
|
};
|
|
328
345
|
};
|
|
@@ -557,6 +574,13 @@ export type IconNewData = {
|
|
|
557
574
|
* - What the author does next, including each change the package needs that the CLI never makes itself (its entry, peers, scripts), as text to copy.
|
|
558
575
|
*/
|
|
559
576
|
notes?: string[] | undefined;
|
|
577
|
+
/**
|
|
578
|
+
* - On a refresh, an update, or a new definition with `icon`: the data file's `module` before and after this command, when the package was renamed and the command writes its new name.
|
|
579
|
+
*/
|
|
580
|
+
moduleUpdate?: {
|
|
581
|
+
previous: string;
|
|
582
|
+
module: string;
|
|
583
|
+
} | undefined;
|
|
560
584
|
};
|
|
561
585
|
/**
|
|
562
586
|
* `astryx --json experimental icon new-set <name>`.
|
package/api/icon/icon.type.mjs
CHANGED
|
@@ -156,6 +156,7 @@
|
|
|
156
156
|
* @property {string} data.file - The data file, relative to the package.
|
|
157
157
|
* @property {Array<{definition: string, icon: string, previous: string | null, changed: boolean}>} data.entries - Each pair, in order, and what it replaced.
|
|
158
158
|
* @property {boolean} data.changed - Whether the file was written.
|
|
159
|
+
* @property {{previous: string, module: string}} [data.moduleUpdate] - The data file's `module` before and after this command, when the package was renamed and the command wrote its new name.
|
|
159
160
|
* @property {string[]} [data.files] - The generated module and its types, when its theme map was rewritten.
|
|
160
161
|
*/
|
|
161
162
|
|
|
@@ -172,6 +173,7 @@
|
|
|
172
173
|
* @property {string | null} data.icon - The id of the icon now mapped (the icon may be named by any name `map` accepts); null after `remove`.
|
|
173
174
|
* @property {string | null} data.previous - The icon id it replaced.
|
|
174
175
|
* @property {boolean} data.changed - Whether the file was written.
|
|
176
|
+
* @property {{previous: string, module: string}} [data.moduleUpdate] - The data file's `module` before and after this command, when the package was renamed and the command wrote its new name.
|
|
175
177
|
* @property {string[]} [data.files] - The generated module and its types, when its theme map was rewritten.
|
|
176
178
|
*/
|
|
177
179
|
|
|
@@ -207,6 +209,7 @@
|
|
|
207
209
|
* @property {string[]} data.missing - Ids of icons `from` has no export for; they keep no such variant.
|
|
208
210
|
* @property {string[]} data.files - Files written, relative to the package.
|
|
209
211
|
* @property {boolean} data.changed
|
|
212
|
+
* @property {{previous: string, module: string}} [data.moduleUpdate] - The data file's `module` before and after this command, when the package was renamed and the command wrote its new name.
|
|
210
213
|
*/
|
|
211
214
|
|
|
212
215
|
/**
|
|
@@ -223,6 +226,8 @@
|
|
|
223
226
|
* @property {string} [data.newDefinition] - The set's own definition the command wrote.
|
|
224
227
|
* @property {string[]} data.files - Files written, relative to the package.
|
|
225
228
|
* @property {boolean} data.changed - Whether anything was written.
|
|
229
|
+
* @property {boolean} data.added - Whether the icon, its variant, its `map` entry, or a new definition was added. False when the set already had them, even when `changed` is true because the command wrote a renamed package's new name.
|
|
230
|
+
* @property {{previous: string, module: string}} [data.moduleUpdate] - The data file's `module` before and after this command, when the package was renamed and the command wrote its new name.
|
|
226
231
|
* @property {string} [data.note] - What the package still needs, as text to copy: the entry line that exports the icon from the set's module, and the package.json `files` that publishes a `./` source.
|
|
227
232
|
*/
|
|
228
233
|
|
|
@@ -332,6 +337,7 @@
|
|
|
332
337
|
* @property {Array<{definition: string, icon: string}>} [mapped] - With `from`: the `map` entries an icon with the definition's exact name gives (on a refresh, every such entry, kept or new); check each.
|
|
333
338
|
* @property {Array<{definition: string, icon: string, word: string}>} [suggestions] - With `from`: for each unmapped Astryx definition, up to three icons it might map to, best first: the definition's name in another spelling or as another name of an icon, ids that start with it, an id or another name that is one of its words, then two-word ids that are a one-word word sized, shaped, or numbered (`grid-2x2`); never a negated form, the opposite direction, or an icon already mapped. `word` is the name or word that matched. Never written.
|
|
334
339
|
* @property {string[]} [notes] - What the author does next, including each change the package needs that the CLI never makes itself (its entry, peers, scripts), as text to copy.
|
|
340
|
+
* @property {{previous: string, module: string}} [moduleUpdate] - On a refresh, an update, or a new definition with `icon`: the data file's `module` before and after this command, when the package was renamed and the command writes its new name.
|
|
335
341
|
*/
|
|
336
342
|
|
|
337
343
|
/**
|
package/api/icon/iconAdd.doc.mjs
CHANGED
|
@@ -119,7 +119,7 @@ export const doc = {
|
|
|
119
119
|
},
|
|
120
120
|
{
|
|
121
121
|
code: 'ERR_INVALID_ARGUMENT',
|
|
122
|
-
when: "the export is data rather than a component, a new definition is named like an Astryx one, or the variant is not one the set declares, is the look each icon's own export already draws, or is no look word of a library whose export names encode looks",
|
|
122
|
+
when: "the export is data rather than a component, a new definition is named like an Astryx one, or the variant is not one the set declares, is the look each icon's own export already draws, or is no look word of a library whose export names encode looks, or `id` starts with a digit",
|
|
123
123
|
},
|
|
124
124
|
{code: 'ERR_FILE_EXISTS', when: 'another icon already has the id'},
|
|
125
125
|
{
|
package/api/icon/map/map.mjs
CHANGED
|
@@ -77,7 +77,8 @@ export async function iconMap(definition, icon, options = {}) {
|
|
|
77
77
|
ERROR_CODES.ERR_MISSING_ARGUMENT,
|
|
78
78
|
);
|
|
79
79
|
}
|
|
80
|
-
const {packageDir, set} =
|
|
80
|
+
const {packageDir, set, moduleRenamed, moduleUpdate} =
|
|
81
|
+
await findLocalIconSet(cwd, selector);
|
|
81
82
|
// The docs' kebab id (`eye-slash`) names the same definition, and a
|
|
82
83
|
// library's other name for an icon (`trash-2`) names the same icon.
|
|
83
84
|
definition = definitionNameOf(definition, mappableDefinitions(set));
|
|
@@ -112,7 +113,8 @@ export async function iconMap(definition, icon, options = {}) {
|
|
|
112
113
|
}
|
|
113
114
|
map[definition] = /** @type {string} */ (icon);
|
|
114
115
|
}
|
|
115
|
-
const changed =
|
|
116
|
+
const changed =
|
|
117
|
+
(remove ? previous != null : previous !== icon) || moduleRenamed;
|
|
116
118
|
/** @type {string[]} */
|
|
117
119
|
const files = [];
|
|
118
120
|
if (changed) {
|
|
@@ -139,6 +141,7 @@ export async function iconMap(definition, icon, options = {}) {
|
|
|
139
141
|
icon: remove ? null : /** @type {string} */ (icon),
|
|
140
142
|
previous,
|
|
141
143
|
changed,
|
|
144
|
+
...(moduleUpdate ? {moduleUpdate} : {}),
|
|
142
145
|
...(files.length > 0 ? {files} : {}),
|
|
143
146
|
},
|
|
144
147
|
};
|
|
@@ -161,7 +164,10 @@ async function mapMany({cwd, selector, pairs}) {
|
|
|
161
164
|
ERROR_CODES.ERR_MISSING_ARGUMENT,
|
|
162
165
|
);
|
|
163
166
|
}
|
|
164
|
-
const {packageDir, set} = await findLocalIconSet(
|
|
167
|
+
const {packageDir, set, moduleRenamed, moduleUpdate} = await findLocalIconSet(
|
|
168
|
+
cwd,
|
|
169
|
+
selector,
|
|
170
|
+
);
|
|
165
171
|
const known = mappableDefinitions(set);
|
|
166
172
|
const ids = set.data.icons.map(each => each.id);
|
|
167
173
|
const map = {...(set.data.map ?? {})};
|
|
@@ -204,7 +210,7 @@ async function mapMany({cwd, selector, pairs}) {
|
|
|
204
210
|
changed: previous !== id,
|
|
205
211
|
});
|
|
206
212
|
}
|
|
207
|
-
const changed = entries.some(each => each.changed);
|
|
213
|
+
const changed = entries.some(each => each.changed) || moduleRenamed;
|
|
208
214
|
/** @type {string[]} */
|
|
209
215
|
const files = [];
|
|
210
216
|
if (changed) {
|
|
@@ -228,6 +234,7 @@ async function mapMany({cwd, selector, pairs}) {
|
|
|
228
234
|
file: path.relative(packageDir, set.dataPath).split(path.sep).join('/'),
|
|
229
235
|
entries,
|
|
230
236
|
changed,
|
|
237
|
+
...(moduleUpdate ? {moduleUpdate} : {}),
|
|
231
238
|
...(files.length > 0 ? {files} : {}),
|
|
232
239
|
},
|
|
233
240
|
};
|
|
@@ -92,7 +92,7 @@ export function loadCurrentManifest(manifestFile: string, manifestExists: boolea
|
|
|
92
92
|
* @param {string} manifestPath
|
|
93
93
|
* @param {string[]} files
|
|
94
94
|
* @param {boolean} dryRun
|
|
95
|
-
* @returns {{type: 'integration.add', data: Omit<import('./integration-authoring.type.mjs').IntegrationAddData, 'kind'> & {kind: K, icons?: number, refreshed?: boolean, updated?: boolean, renamed?: Array<{from: string, to: string}>, moved?: Array<{id: string, from: string, to: string}>, licenseNoticeMissing?: {library: string, path: string}, mapped?: Array<{definition: string, icon: string}>, suggestions?: Array<{definition: string, icon: string, word: string}>, notes?: string[]}}}
|
|
95
|
+
* @returns {{type: 'integration.add', data: Omit<import('./integration-authoring.type.mjs').IntegrationAddData, 'kind'> & {kind: K, icons?: number, refreshed?: boolean, updated?: boolean, renamed?: Array<{from: string, to: string}>, moved?: Array<{id: string, from: string, to: string}>, licenseNoticeMissing?: {library: string, path: string}, mapped?: Array<{definition: string, icon: string}>, suggestions?: Array<{definition: string, icon: string, word: string}>, notes?: string[], moduleUpdate?: {previous: string, module: string}}}}
|
|
96
96
|
*/
|
|
97
97
|
export function receipt<K extends import("./integration-authoring.type.mjs").IntegrationAddData["kind"] | import("../icon/icon.type.mjs").IconNewData["kind"]>(kind: K, name: string, root: {
|
|
98
98
|
path: string;
|
|
@@ -127,6 +127,10 @@ export function receipt<K extends import("./integration-authoring.type.mjs").Int
|
|
|
127
127
|
word: string;
|
|
128
128
|
}>;
|
|
129
129
|
notes?: string[];
|
|
130
|
+
moduleUpdate?: {
|
|
131
|
+
previous: string;
|
|
132
|
+
module: string;
|
|
133
|
+
};
|
|
130
134
|
};
|
|
131
135
|
};
|
|
132
136
|
/** @param {string} slug */
|