feat: publish Regex Tools 0.2.0

This commit is contained in:
2026-07-27 01:06:57 +02:00
parent 873b9b218d
commit 4951c966d4
180 changed files with 35344 additions and 503 deletions

View File

@@ -1,30 +1,44 @@
import { useMemo, useState } from "react";
import { ECMASCRIPT_REFERENCE } from "../regex/reference/token-reference";
import type { RegexFlavourId } from "../regex/model/flavour";
import {
ECMASCRIPT_REFERENCE,
PCRE2_REFERENCE,
} from "../regex/reference/token-reference";
export function QuickReference({
onInsert,
onUsePattern,
onClose,
flavour = "ecmascript",
}: {
readonly onInsert: (syntax: string) => void;
readonly onUsePattern: (syntax: string) => void;
readonly onClose?: () => void;
readonly flavour?: RegexFlavourId;
}) {
const [query, setQuery] = useState("");
const reference =
flavour === "pcre2" ? PCRE2_REFERENCE : ECMASCRIPT_REFERENCE;
const entries = useMemo(() => {
const needle = query.toLocaleLowerCase();
const normalizeSearchText = (value: string) =>
value
.toLocaleLowerCase()
.replaceAll(/[^\p{L}\p{N}]+/gu, " ")
.trim();
const needle = normalizeSearchText(query);
return needle
? ECMASCRIPT_REFERENCE.filter((entry) =>
[
entry.construct,
entry.syntax,
entry.explanation,
entry.example,
entry.flags.join(" "),
entry.source,
]
.join(" ")
.toLocaleLowerCase()
.includes(needle),
? reference.filter((entry) =>
normalizeSearchText(
[
entry.construct,
entry.syntax,
entry.explanation,
entry.example,
entry.flags.join(" "),
entry.source,
].join(" "),
).includes(needle),
)
: ECMASCRIPT_REFERENCE;
}, [query]);
: reference;
}, [query, reference]);
return (
<section
className="panel reference-panel"
@@ -32,9 +46,27 @@ export function QuickReference({
>
<header className="panel-heading">
<div>
<p className="eyebrow">Original ECMAScript reference</p>
<p className="eyebrow">
Original {flavour === "pcre2" ? "PCRE2" : "ECMAScript"} reference
</p>
<h2 id="reference-heading">Quick reference</h2>
</div>
<div className="panel-heading-actions">
<span>
{entries.length} of {reference.length} constructs
</span>
{onClose ? (
<button
type="button"
className="icon-button"
aria-label="Close quick reference"
data-dialog-initial-focus
onClick={onClose}
>
×
</button>
) : null}
</div>
</header>
<label className="stacked-control">
<span>Filter constructs</span>
@@ -44,51 +76,57 @@ export function QuickReference({
onChange={(event) => setQuery(event.target.value)}
/>
</label>
<ul className="reference-list">
{entries.map((entry) => (
<li key={entry.id}>
<div>
<strong>{entry.construct}</strong>
<code>{entry.syntax}</code>
</div>
<p>{entry.explanation}</p>
<dl className="reference-meta">
{entries.length > 0 ? (
<ul className="reference-list">
{entries.map((entry) => (
<li key={entry.id}>
<div>
<dt>Flavour</dt>
<dd>{entry.flavours.join(", ")}</dd>
<strong>{entry.construct}</strong>
<code>{entry.syntax}</code>
</div>
<div>
<dt>Relevant flags</dt>
<dd>
{entry.flags.length > 0 ? entry.flags.join(", ") : "None"}
</dd>
</div>
<div>
<dt>Example</dt>
<dd>
<code>{entry.example}</code>
</dd>
</div>
<div>
<dt>Source</dt>
<dd>
<a href={entry.sourceUrl} target="_blank" rel="noreferrer">
{entry.source}
</a>
</dd>
</div>
</dl>
{entry.caveat ? <small>{entry.caveat}</small> : null}
<button
type="button"
className="secondary-button"
onClick={() => onInsert(entry.example)}
>
Insert example
</button>
</li>
))}
</ul>
<p>{entry.explanation}</p>
<dl className="reference-meta">
<div>
<dt>Flavour</dt>
<dd>{entry.flavours.join(", ")}</dd>
</div>
<div>
<dt>Relevant flags</dt>
<dd>
{entry.flags.length > 0 ? entry.flags.join(", ") : "None"}
</dd>
</div>
<div>
<dt>Example</dt>
<dd>
<code>{entry.example}</code>
</dd>
</div>
<div>
<dt>Source</dt>
<dd>
<a href={entry.sourceUrl} target="_blank" rel="noreferrer">
{entry.source}
</a>
</dd>
</div>
</dl>
{entry.caveat ? <small>{entry.caveat}</small> : null}
<button
type="button"
className="secondary-button"
onClick={() => onUsePattern(entry.example)}
>
Use example as pattern
</button>
</li>
))}
</ul>
) : (
<p className="empty-state" role="status">
No reference constructs match {query.trim()}.
</p>
)}
</section>
);
}