@hanzo/rooms 0.1.91 → 0.1.93

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/dist/lib/title.js CHANGED
@@ -34,3 +34,8 @@ export function tidy(title, max = 80, fallback = 'Untitled') {
34
34
  return fallback;
35
35
  return t.length > max ? `${t.slice(0, max - 1).trimEnd()}…` : t;
36
36
  }
37
+ /** A name's first word, its first letter capitalised ("z" → "Z", "ada lovelace" → "Ada"), or '' for none. */
38
+ export function given(name) {
39
+ const w = name.trim().split(/\s+/)[0] ?? '';
40
+ return w ? w[0].toUpperCase() + w.slice(1) : '';
41
+ }
package/dist/seek.d.ts CHANGED
@@ -15,32 +15,25 @@ export interface Group<T extends Hit = Hit> {
15
15
  }
16
16
  /** The most rows one group shows for a query. */
17
17
  export declare const CAP = 5;
18
- /** The chats an empty field lists. */
19
- export declare const RECENT = 8;
18
+ /** The rows Recent lists on an empty field. */
19
+ export declare const RECENT = 6;
20
20
  /**
21
21
  * How well a row answers a query: 0 drops it, more ranks it higher. Every word
22
22
  * of the query must be found, in the label or the row's other words; each counts
23
23
  * most where the label starts with it, then where a word of the label does, then
24
- * anywhere in the label, then in the other words alone. The label read whole
25
- * outranks everything.
24
+ * anywhere in the label, then in the other words, then spelled out in order
25
+ * within a word of the label (a typo's fuzz). The label read whole outranks
26
+ * everything.
26
27
  */
27
28
  export declare function fit(row: Hit, query: string): number;
28
29
  /** The rows a query keeps, best first, ties in the order they came, at most `cap`. */
29
30
  export declare function rank<T extends Hit>(rows: T[], query: string, cap?: number): T[];
30
31
  /**
31
- * What the palette lists. An empty field: the newest chats, under Recent chats.
32
- * A query: Chats, then each other group in its order, each cut to its best
33
- * `CAP`, a group with nothing left out.
32
+ * What the palette lists. An empty field: the newest `RECENT` of `recent` under
33
+ * Recent, then `idle` as it is. A query: every group of `all` cut to its best
34
+ * `CAP`, a group with nothing left out, and the group with the best answer
35
+ * first, ties in the order given.
34
36
  */
35
- export declare function find<T extends Hit>(query: string, chats: T[], groups: Group<T>[]): Group<T>[];
36
- /**
37
- * The same search for any product: an empty field lists the newest `RECENT` of
38
- * `recent` under its label (a product's own recents: Chat's conversations, Dev's
39
- * runs), and a query ranks every group in the order given.
40
- */
41
- export declare function findIn<T extends Hit>(query: string, recent: {
42
- label: string;
43
- items: T[];
44
- }, groups: Group<T>[]): Group<T>[];
37
+ export declare function find<T extends Hit>(query: string, recent: T[], idle: Group<T>[], all: Group<T>[]): Group<T>[];
45
38
  /** Whether a key press opens the palette: ⌘K or Ctrl+K, once a press, from anywhere, a field included. */
46
39
  export declare const summons: (e: Press) => boolean;
package/dist/seek.js CHANGED
@@ -3,14 +3,23 @@
3
3
  // so a spec reads them as they are.
4
4
  /** The most rows one group shows for a query. */
5
5
  export const CAP = 5;
6
- /** The chats an empty field lists. */
7
- export const RECENT = 8;
6
+ /** The rows Recent lists on an empty field. */
7
+ export const RECENT = 6;
8
+ /** Whether `term`'s letters stand in `word` in order: "sttngs" in "settings". */
9
+ const spelled = (word, term) => {
10
+ let i = 0;
11
+ for (const c of word)
12
+ if (c === term[i])
13
+ i++;
14
+ return i === term.length;
15
+ };
8
16
  /**
9
17
  * How well a row answers a query: 0 drops it, more ranks it higher. Every word
10
18
  * of the query must be found, in the label or the row's other words; each counts
11
19
  * most where the label starts with it, then where a word of the label does, then
12
- * anywhere in the label, then in the other words alone. The label read whole
13
- * outranks everything.
20
+ * anywhere in the label, then in the other words, then spelled out in order
21
+ * within a word of the label (a typo's fuzz). The label read whole outranks
22
+ * everything.
14
23
  */
15
24
  export function fit(row, query) {
16
25
  const terms = query.trim().toLowerCase().split(/\s+/).filter(Boolean);
@@ -21,7 +30,17 @@ export function fit(row, query) {
21
30
  const more = (row.keywords ?? []).join(' ').toLowerCase();
22
31
  let total = label === terms.join(' ') ? 10 : 0;
23
32
  for (const t of terms) {
24
- const s = label.startsWith(t) ? 4 : words.some((w) => w.startsWith(t)) ? 3 : label.includes(t) ? 2 : more.includes(t) ? 1 : 0;
33
+ const s = label.startsWith(t)
34
+ ? 4
35
+ : words.some((w) => w.startsWith(t))
36
+ ? 3
37
+ : label.includes(t)
38
+ ? 2
39
+ : more.includes(t)
40
+ ? 1
41
+ : t.length > 2 && words.some((w) => w[0] === t[0] && spelled(w, t))
42
+ ? 0.5
43
+ : 0;
25
44
  if (!s)
26
45
  return 0;
27
46
  total += s;
@@ -38,24 +57,22 @@ export function rank(rows, query, cap = CAP) {
38
57
  .map((x) => x.row);
39
58
  }
40
59
  /**
41
- * What the palette lists. An empty field: the newest chats, under Recent chats.
42
- * A query: Chats, then each other group in its order, each cut to its best
43
- * `CAP`, a group with nothing left out.
60
+ * What the palette lists. An empty field: the newest `RECENT` of `recent` under
61
+ * Recent, then `idle` as it is. A query: every group of `all` cut to its best
62
+ * `CAP`, a group with nothing left out, and the group with the best answer
63
+ * first, ties in the order given.
44
64
  */
45
- export function find(query, chats, groups) {
46
- return findIn(query, { label: 'Recent chats', items: chats }, [{ id: 'chats', label: 'Chats', items: chats }, ...groups]);
47
- }
48
- /**
49
- * The same search for any product: an empty field lists the newest `RECENT` of
50
- * `recent` under its label (a product's own recents: Chat's conversations, Dev's
51
- * runs), and a query ranks every group in the order given.
52
- */
53
- export function findIn(query, recent, groups) {
65
+ export function find(query, recent, idle, all) {
54
66
  if (!query.trim()) {
55
- const newest = [...recent.items].sort((a, b) => (b.at ?? '').localeCompare(a.at ?? '')).slice(0, RECENT);
56
- return newest.length ? [{ id: 'recent', label: recent.label, items: newest }] : [];
67
+ const newest = [...recent].sort((a, b) => (b.at ?? '').localeCompare(a.at ?? '')).slice(0, RECENT);
68
+ return [{ id: 'recent', label: 'Recent', items: newest }, ...idle].filter((g) => g.items.length);
57
69
  }
58
- return groups.map((g) => ({ ...g, items: rank(g.items, query) })).filter((g) => g.items.length);
70
+ return all
71
+ .map((g) => ({ ...g, items: rank(g.items, query) }))
72
+ .filter((g) => g.items.length)
73
+ .map((g, i) => ({ g, i, best: fit(g.items[0], query) }))
74
+ .sort((a, b) => b.best - a.best || a.i - b.i)
75
+ .map((x) => x.g);
59
76
  }
60
77
  /** Whether a key press opens the palette: ⌘K or Ctrl+K, once a press, from anywhere, a field included. */
61
78
  export const summons = (e) => (e.metaKey || e.ctrlKey) && !e.altKey && !e.shiftKey && !e.repeat && !e.isComposing && (e.key ?? '').toLowerCase() === 'k';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanzo/rooms",
3
- "version": "0.1.91",
3
+ "version": "0.1.93",
4
4
  "description": "The workspace rooms — Home, Chat, Inbox, Contacts, Meet, Cal, Drive, Board, Work, Bots — and the frame that holds them, once, for every Hanzo surface.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -49,7 +49,7 @@
49
49
  "peerDependencies": {
50
50
  "@hanzo/ai": ">=0.6.23",
51
51
  "@hanzo/appearance": ">=0.2.6",
52
- "@hanzo/build": ">=0.2.77",
52
+ "@hanzo/build": ">=0.2.79",
53
53
  "@hanzo/composer": ">=0.2.0",
54
54
  "@hanzo/event": ">=0.3.56",
55
55
  "@hanzo/gui": "^8.3.5",
@@ -68,7 +68,7 @@
68
68
  "devDependencies": {
69
69
  "@hanzo/ai": "0.6.23",
70
70
  "@hanzo/appearance": "0.2.8",
71
- "@hanzo/build": "0.2.77",
71
+ "@hanzo/build": "0.2.79",
72
72
  "@hanzo/composer": "0.2.0",
73
73
  "@hanzo/design": "0.5.34",
74
74
  "@hanzo/event": "0.3.56",