@aiquants/contact-map 0.8.0 → 0.10.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/README.md +25 -15
- package/dist/client.d.mts +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js +2 -2
- package/dist/client.mjs +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/server.d.mts +1 -1
- package/dist/server.d.ts +1 -1
- package/package.json +11 -11
- /package/dist/{wire-hAxBVVH6.d.mts → wire-BghOEeyw.d.mts} +0 -0
- /package/dist/{wire-hAxBVVH6.d.ts → wire-BghOEeyw.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -173,26 +173,36 @@ Worker を作れないか Worker が落ちると、250 ms 後と 500 ms 後の 2
|
|
|
173
173
|
|
|
174
174
|
## Search Normalization / 検索語の正規化
|
|
175
175
|
|
|
176
|
-
The search
|
|
176
|
+
The search box reads its text as keywords. Each whitespace-separated word is a keyword of its own, and the words between two quotation marks (`"`, `"`, `“`, `”`; any of them opens or closes a group, and a group left open runs to the end) are one keyword.
|
|
177
|
+
The page searches every keyword with `@aiquants/fuzzy-search`: `useFuzzySearch`'s `querySetsOf` reads the term with `parseQuerySets`, and `FuzzySearchManager.searchSets` searches one query set per keyword. The AND / OR button next to the search box combines the keywords' answers: AND keeps the contacts every keyword finds (intersection), OR the contacts any keyword finds (union). The button starts at OR, and switching it searches the current term again without rebuilding the index.
|
|
178
|
+
A quoted keyword is matched by fuzzy-search's multi-word matching, whose operator is the settings tab's "Operator for words inside quotes" select (`multiTermOperator`, AND at first): AND requires every word of the group to appear in some search field, OR does not. A keyword of one word matches the same under either operator.
|
|
179
|
+
A "Maximum results" cap of the index or Levenshtein settings (no limit at first) applies to each keyword's answer before the keywords are combined, so with a cap an AND search can miss a contact that one keyword's capped answer left out.
|
|
177
180
|
|
|
178
|
-
|
|
181
|
+
The search page normalizes the typed text with `normalizeSearchInput` (exported from `@aiquants/contact-map`) into the fuzzy search term. The contact fields (name, company, department, title, email, phone numbers) are matched as stored. Every keyword is therefore only brought into a form those fields can hold:
|
|
182
|
+
|
|
183
|
+
- Invisible characters (U+200B, U+FEFF) are removed before the keywords are read, and each keyword's surrounding whitespace (U+3000 and U+00A0 included) is trimmed.
|
|
179
184
|
- Width, kana (hiragana → katakana) and case are unified with select-box's `normalizeText` (`ABC商事` → `abc商事`, `さとう` → `サトウ`). Kana stays as written (`つづき` → `ツヅキ`).
|
|
180
|
-
- The
|
|
181
|
-
- Mixed text, digits and symbols, and words that do not read completely keep their width / kana / case form (`user@example.com`, `営業部 tanaka`, `tanaka1`, `ke-su`, `sony`).
|
|
185
|
+
- The keywords are replaced by their katakana readings only when every keyword is romaji that reads completely. Each must hold only Latin letters and whitespace, and select-box's `romajiToKatakana` must leave no letter untransliterated (`tanaka` → `タナカ`, `yamada taro` → `ヤマダ タロ`, `"yamada taro" suzuki` → `"ヤマダ タロ" スズキ`, `tsuduki` → `ツヅキ`).
|
|
186
|
+
- Mixed text, digits and symbols, and words that do not read completely keep their width / kana / case form, and so does every other keyword of the text (`user@example.com`, `営業部 tanaka`, `tanaka1`, `ke-su`, `sony`, `"yamada taro" sony`).
|
|
187
|
+
- The keywords are written back with fuzzy-search's `formatQuerySets`: single spaces between them, a keyword holding whitespace in ASCII quotation marks (`"ABC 商事"` → `"abc 商事"`), and neither a blank keyword nor a keyword that normalization made equal to an earlier one. `parseQuerySets` therefore reads exactly these keywords from the term. Text without quotation marks becomes its whitespace-separated words, each normalized as above and written once, separated by single spaces.
|
|
182
188
|
|
|
183
|
-
The result highlight and the exact-match ranking are one derivation from the
|
|
184
|
-
`HighlightedText` marks its matches, and `createExactMatchRanker(query, fields)` moves the results with a match in one of the fields to the top, keeping the fuzzy order within each group. A field is therefore highlighted exactly when it ranks its record as an exact match. A kana reading is marked only when
|
|
189
|
+
The result highlight and the exact-match ranking are one derivation from the text as typed. `createSearchQueryPattern(query)` finds the spellings that `getSearchQuerySpellings(query)` lists (select-box's `getNormalizedVariants` of each word of the text's keywords and of its normalized form's keywords, read with fuzzy-search's `parseQuerySets`, so a quotation mark is never part of a spelling), longest first and case-insensitively.
|
|
190
|
+
`HighlightedText` marks its matches, and `createExactMatchRanker(query, fields)` moves the results with a match in one of the fields to the top, keeping the fuzzy order within each group. A field is therefore highlighted exactly when it ranks its record as an exact match. A kana reading is marked only when every keyword reads as romaji.
|
|
185
191
|
|
|
186
192
|
The typed query is used because normalization can drop a spelling it holds. select-box reads a prolonged sound mark that follows no kana as a hyphen, so `ーヒー` (the middle of `コーヒー`) becomes the search term `-ヒー`, while the highlight and the ranking still find `ーヒー`. The search outlet context carries both: `searchQuery` (as typed) and `searchTerm` (`normalizeSearchInput(searchQuery)`). The select-box peer range is ^0.11.0, expanded from `workspace:^` at publish.
|
|
187
193
|
|
|
188
|
-
|
|
194
|
+
検索欄はテキストをキーワードとして読む。空白で区切った語はそれぞれ 1 つのキーワードで、2 つの引用符 (`"`・`"`・`“`・`”`。どれでも組を開き閉じ、開いたままの組は終わりまで続く) の間の語はまとめて 1 つのキーワード。ページはどのキーワードも `@aiquants/fuzzy-search` で検索する: `useFuzzySearch` の `querySetsOf` が `parseQuerySets` で検索語を読み、`FuzzySearchManager.searchSets` がキーワードごとに 1 つの問い合わせのセットを検索する。検索欄の隣の AND / OR ボタンはキーワードの答えをまとめ、AND はどのキーワードも見つけた連絡先 (積集合)、OR はどれかのキーワードが見つけた連絡先 (和集合) を残す。ボタンは OR で始まり、切り替えると索引を建て直さずに今の検索語を検索し直す。
|
|
195
|
+
引用符で囲んだキーワードは fuzzy-search の複数語の照合で照合し、その演算子は設定タブの「引用符の中の語の演算子」セレクト (`multiTermOperator`。最初は AND): AND は組のどの語もいずれかの検索フィールドに現れることを求め、OR は求めない。1 語のキーワードはどちらの演算子でも同じに照合する。
|
|
196
|
+
|
|
197
|
+
検索ページは入力されたテキストを `normalizeSearchInput` (`@aiquants/contact-map` から公開) で正規化し、あいまい検索の検索語にする。連絡先のフィールド (氏名・会社・部署・役職・メール・電話番号) は保存されたままの値で照合する。そのため各キーワードは、それらのフィールドが持ちうる形に揃えるだけ:
|
|
189
198
|
|
|
190
|
-
-
|
|
199
|
+
- キーワードを読む前に不可視文字 (U+200B・U+FEFF) を除き、各キーワードの端の空白 (U+3000・U+00A0 を含む) を除く。
|
|
191
200
|
- select-box の `normalizeText` で全角/半角・かな (ひらがな → カタカナ)・大文字小文字を統一する (`ABC商事` → `abc商事`、`さとう` → `サトウ`)。かなは書いたまま (`つづき` → `ツヅキ`)。
|
|
192
|
-
-
|
|
193
|
-
-
|
|
201
|
+
- どのキーワードも完全に読めるローマ字のときだけ、各キーワードをカタカナの読みに置き換える。どれもラテン文字と空白だけで、select-box の `romajiToKatakana` が音訳しない文字を残さないことが条件 (`tanaka` → `タナカ`、`yamada taro` → `ヤマダ タロ`、`"yamada taro" suzuki` → `"ヤマダ タロ" スズキ`、`tsuduki` → `ツヅキ`)。
|
|
202
|
+
- 混在テキスト・数字や記号・完全には読めない語は全角/半角・かな・大文字小文字の形のままで、そのテキストのほかのキーワードも同じ (`user@example.com`、`営業部 tanaka`、`tanaka1`、`ke-su`、`sony`、`"yamada taro" sony`)。
|
|
203
|
+
- キーワードは fuzzy-search の `formatQuerySets` で書き戻す: キーワードの間は 1 つの空白、空白を持つキーワードは ASCII の引用符で囲み (`"ABC 商事"` → `"abc 商事"`)、空のキーワードと、正規化で先のキーワードと等しくなったキーワードは書かない。そのため `parseQuerySets` は検索語からちょうどこれらのキーワードを読む。引用符の無いテキストは、空白で区切った各語を上のとおり正規化して 1 度ずつ並べ、1 つの空白で区切ったものになる。
|
|
194
204
|
|
|
195
|
-
|
|
205
|
+
検索結果のハイライトと完全一致による並べ替えは、入力されたままのテキストからの 1 つの導出。`createSearchQueryPattern(query)` は `getSearchQuerySpellings(query)` が並べる表記 (テキストのキーワードとその正規化形のキーワードの各語に対する select-box の `getNormalizedVariants`。語は fuzzy-search の `parseQuerySets` で読むため、引用符は表記の一部にならない) を、最長のものから大文字小文字を区別せずに探す。`HighlightedText` はその一致に印を付け、`createExactMatchRanker(query, fields)` はいずれかのフィールドに一致を持つ結果を先頭へ移す (各グループ内ではあいまい検索の順序を保つ)。そのため、フィールドにハイライトが付くのは、そのフィールドがレコードを完全一致として並べさせるときちょうど。かなの読みに印が付くのはどのキーワードもローマ字として読めるときだけ。
|
|
196
206
|
|
|
197
207
|
入力されたままの検索語を使うのは、正規化が検索語の持つ表記を落とすことがあるため。select-box はかなに続かない長音記号をハイフンと読むので、`ーヒー` (`コーヒー` の途中) は検索語 `-ヒー` になるが、ハイライトと並べ替えは `ーヒー` を探し続ける。検索のアウトレットコンテキストは両方を運ぶ: `searchQuery` (入力されたまま) と `searchTerm` (`normalizeSearchInput(searchQuery)`)。select-box のピア範囲は ^0.11.0 (公開時に `workspace:^` から展開)。
|
|
198
208
|
|
|
@@ -437,10 +447,10 @@ Function keys are shown with their arguments; the cells show sample output (`cou
|
|
|
437
447
|
| `basicCaseSensitive` | `"Case-sensitive"` | `"大文字小文字を区別"` |
|
|
438
448
|
| `basicHighlight` | `"Highlight matches"` | `"ハイライト表示"` |
|
|
439
449
|
| `basicOpenEmailsWithGmail` | `"Open email addresses in Gmail compose"` | `"メールアドレスを Gmail の作成画面で開く"` |
|
|
440
|
-
| `basicMultiTermOperator` | `"
|
|
441
|
-
| `basicOperatorOr` | `"OR (any
|
|
442
|
-
| `basicOperatorAnd` | `"AND (all
|
|
443
|
-
| `basicMultiTermHint` | `
|
|
450
|
+
| `basicMultiTermOperator` | `"Operator for words inside quotes"` | `"引用符の中の語の演算子"` |
|
|
451
|
+
| `basicOperatorOr` | `"OR (any word matches)"` | `"OR (いずれか一致)"` |
|
|
452
|
+
| `basicOperatorAnd` | `"AND (all words match)"` | `"AND (すべて一致)"` |
|
|
453
|
+
| `basicMultiTermHint` | `'How words between quotation marks ("tanaka taro") are combined (default: AND). Words outside quotation marks are separate keywords combined by the AND / OR button'` | `'引用符で囲んだ語 ("田中 太郎") の結合方法 (既定は AND)。引用符の外の語はそれぞれ別のキーワードで、AND / OR ボタンで結合する'` |
|
|
444
454
|
| `basicSortHeading` | `"Sorting"` | `"ソート設定"` |
|
|
445
455
|
| `basicSortBy` | `"Sort by"` | `"ソート基準"` |
|
|
446
456
|
| `basicSortByScore` | `"Score"` | `"スコア"` |
|
package/dist/client.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from "react";
|
|
2
2
|
import { CSSProperties, ReactNode, RefObject, PointerEvent, MouseEvent } from "react";
|
|
3
3
|
import { UseFuzzySearchOptions } from "@aiquants/fuzzy-search/react";
|
|
4
|
-
import { C as ContactRecord, a as ContactMapStreamPhase, b as ContactMapSearchOutletContext, c as ContactMapOutletContext, d as ContactMapLogger, S as SerializedContactStreamRow } from "./wire-
|
|
4
|
+
import { C as ContactRecord, a as ContactMapStreamPhase, b as ContactMapSearchOutletContext, c as ContactMapOutletContext, d as ContactMapLogger, S as SerializedContactStreamRow } from "./wire-BghOEeyw.mjs";
|
|
5
5
|
import { DirectoryTreeLabels, DirectoryTreeVirtualScrollOptions } from "@aiquants/directory-tree";
|
|
6
6
|
import * as _aiquants_virtualscroll from "@aiquants/virtualscroll";
|
|
7
7
|
import { VirtualScrollLocale } from "@aiquants/virtualscroll";
|
package/dist/client.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from "react";
|
|
2
2
|
import { CSSProperties, ReactNode, RefObject, PointerEvent, MouseEvent } from "react";
|
|
3
3
|
import { UseFuzzySearchOptions } from "@aiquants/fuzzy-search/react";
|
|
4
|
-
import { C as ContactRecord, a as ContactMapStreamPhase, b as ContactMapSearchOutletContext, c as ContactMapOutletContext, d as ContactMapLogger, S as SerializedContactStreamRow } from "./wire-
|
|
4
|
+
import { C as ContactRecord, a as ContactMapStreamPhase, b as ContactMapSearchOutletContext, c as ContactMapOutletContext, d as ContactMapLogger, S as SerializedContactStreamRow } from "./wire-BghOEeyw.js";
|
|
5
5
|
import { DirectoryTreeLabels, DirectoryTreeVirtualScrollOptions } from "@aiquants/directory-tree";
|
|
6
6
|
import * as _aiquants_virtualscroll from "@aiquants/virtualscroll";
|
|
7
7
|
import { VirtualScrollLocale } from "@aiquants/virtualscroll";
|