@thewhatmatters/wmds 0.4.40 → 0.4.43
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/CHANGELOG.md +39 -1
- package/dist/components/molecules/Combobox/Combobox.d.ts +56 -0
- package/dist/components/molecules/Combobox/Combobox.d.ts.map +1 -0
- package/dist/components/molecules/Combobox/Combobox.js +154 -0
- package/dist/components/molecules/Combobox/comboboxFilter.d.ts +14 -0
- package/dist/components/molecules/Combobox/comboboxFilter.d.ts.map +1 -0
- package/dist/components/molecules/Combobox/comboboxFilter.js +26 -0
- package/dist/components/molecules/Dropdown/useDropdownMenu.d.ts +6 -1
- package/dist/components/molecules/Dropdown/useDropdownMenu.d.ts.map +1 -1
- package/dist/components/molecules/Dropdown/useDropdownMenu.js +90 -64
- package/dist/components/molecules/Dropdown/useOverflowMenu.d.ts.map +1 -1
- package/dist/components/molecules/Notice/Notice.d.ts +47 -0
- package/dist/components/molecules/Notice/Notice.d.ts.map +1 -0
- package/dist/components/molecules/Notice/Notice.js +97 -0
- package/dist/components/molecules/Notice/noticeStyles.d.ts +17 -0
- package/dist/components/molecules/Notice/noticeStyles.d.ts.map +1 -0
- package/dist/components/molecules/Notice/noticeStyles.js +18 -0
- package/dist/components/organisms/AppShell/AppShell.d.ts +10 -2
- package/dist/components/organisms/AppShell/AppShell.d.ts.map +1 -1
- package/dist/components/organisms/AppShell/AppShell.js +237 -198
- package/dist/components/organisms/AppShell/appShellStyles.d.ts +11 -0
- package/dist/components/organisms/AppShell/appShellStyles.d.ts.map +1 -1
- package/dist/components/organisms/AppShell/appShellStyles.js +2 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +79 -75
- package/dist/lib/compositionAudit.d.ts.map +1 -1
- package/dist/styles.css +1 -1
- package/docs/components.md +1 -1
- package/docs/exports.json +28 -1
- package/docs/patterns/components-accordion--flush.tsx +1 -1
- package/docs/patterns/components-appshell--portal-dashboard-pattern.tsx +1 -1
- package/docs/patterns/components-avatar--dropdown-row.tsx +1 -1
- package/docs/patterns/components-badge--outline-tags.tsx +1 -1
- package/docs/patterns/components-badge--status-pill.tsx +1 -1
- package/docs/patterns/components-badge--with-avatar.tsx +1 -1
- package/docs/patterns/components-band--page-in-bands.tsx +1 -1
- package/docs/patterns/components-breadcrumb--editorial.tsx +1 -1
- package/docs/patterns/components-breadcrumb--long-path.tsx +1 -1
- package/docs/patterns/components-breadcrumb--path.tsx +1 -1
- package/docs/patterns/components-breadcrumb--router-links.tsx +1 -1
- package/docs/patterns/components-button-button--copy-button.tsx +1 -1
- package/docs/patterns/components-button-button--destructive-action.tsx +1 -1
- package/docs/patterns/components-button-button--external-link.tsx +1 -1
- package/docs/patterns/components-button-button--ghost-action.tsx +1 -1
- package/docs/patterns/components-button-button--inverse-action.tsx +1 -1
- package/docs/patterns/components-button-button--link-render.tsx +1 -1
- package/docs/patterns/components-button-button--multi-state-badge.tsx +1 -1
- package/docs/patterns/components-button-button--outline-mono.tsx +1 -1
- package/docs/patterns/components-button-button--primary-action.tsx +1 -1
- package/docs/patterns/components-button-button--row-hug.tsx +1 -1
- package/docs/patterns/components-button-button--row-layout.tsx +1 -1
- package/docs/patterns/components-button-button--secondary-action.tsx +1 -1
- package/docs/patterns/components-button-button--suggestion-pills.tsx +1 -1
- package/docs/patterns/components-button-button--with-count.tsx +1 -1
- package/docs/patterns/components-button-button--with-icon.tsx +1 -1
- package/docs/patterns/components-button-floatingactionbutton--vertical-actions.tsx +1 -1
- package/docs/patterns/components-calembed--pattern-skip-above.tsx +1 -1
- package/docs/patterns/components-card-card--body-slot-occupancy-history.tsx +1 -1
- package/docs/patterns/components-card-card--headerless-media.tsx +1 -1
- package/docs/patterns/components-card-card--outlined-layout.tsx +1 -1
- package/docs/patterns/components-card-card--pinned-height.tsx +1 -1
- package/docs/patterns/components-card-card--terminal-frame.tsx +1 -1
- package/docs/patterns/components-card-selectablecard--selectable-cards-pattern.tsx +1 -1
- package/docs/patterns/components-carousel--image-carousel.tsx +1 -1
- package/docs/patterns/components-chart--audience-activity-heatmap.tsx +1 -1
- package/docs/patterns/components-chart--cartesian-no-data-gaps.tsx +1 -1
- package/docs/patterns/components-chart--occupancy-history-in-card.tsx +1 -1
- package/docs/patterns/components-chart--occupancy-in-card.tsx +1 -1
- package/docs/patterns/components-chart--post-reach-distribution.tsx +1 -1
- package/docs/patterns/components-chart--ranked-audience-breakdown.tsx +1 -1
- package/docs/patterns/components-chart--revenue-by-line.tsx +1 -1
- package/docs/patterns/components-chart--segmented-ring-pattern.tsx +1 -1
- package/docs/patterns/components-chart--unit-grid-composition.tsx +1 -1
- package/docs/patterns/components-chatdock--pattern-chat-dock.tsx +1 -1
- package/docs/patterns/components-chatdock--pattern-start-project-gate.tsx +1 -1
- package/docs/patterns/components-chatqa--pattern-qa-with-reply.tsx +1 -1
- package/docs/patterns/components-checkbox-checkbox--default.tsx +1 -1
- package/docs/patterns/components-checkbox-checkbox--with-count.tsx +1 -1
- package/docs/patterns/components-checkbox-checkbox--with-description.tsx +1 -1
- package/docs/patterns/components-checkbox-checkboxgroup--default.tsx +1 -1
- package/docs/patterns/components-checkbox-checkboxgroup--option-counts.tsx +1 -1
- package/docs/patterns/components-copyfield--clipboard-blocked.tsx +1 -1
- package/docs/patterns/components-copyfield--copied.tsx +1 -1
- package/docs/patterns/components-copyfield--copy-key.tsx +1 -1
- package/docs/patterns/components-copyfield--on-navy.tsx +1 -1
- package/docs/patterns/components-descriptionlist--details.tsx +1 -1
- package/docs/patterns/components-descriptionlist--post-metadata.tsx +1 -1
- package/docs/patterns/components-dialog--alert-dialog-destructive.tsx +1 -1
- package/docs/patterns/components-dialog--alert-dialog-typed-confirmation.tsx +1 -1
- package/docs/patterns/components-dialog--default-dialog.tsx +1 -1
- package/docs/patterns/components-dialog--form-dialog.tsx +1 -1
- package/docs/patterns/components-displaycontrols--page-utilities.tsx +1 -1
- package/docs/patterns/components-displaycontrols--theme-switch.tsx +1 -1
- package/docs/patterns/components-errorsummary--contact-form.tsx +1 -1
- package/docs/patterns/components-field--horizontal-input.tsx +1 -1
- package/docs/patterns/components-field--horizontal-text-area.tsx +1 -1
- package/docs/patterns/components-field--multi-control.tsx +1 -1
- package/docs/patterns/components-filterpanel--panel.tsx +1 -1
- package/docs/patterns/components-footerreveal--marketing-hero-pattern.tsx +1 -1
- package/docs/patterns/components-footerreveal--marketing-hero-ruled-pattern.tsx +1 -1
- package/docs/patterns/components-footerreveal--marketing-hero-with-gallery-intro.tsx +1 -1
- package/docs/patterns/components-footerreveal--marketing-page-pattern.tsx +1 -1
- package/docs/patterns/components-footerreveal--ruled-grid-footer-pattern.tsx +1 -1
- package/docs/patterns/components-footerreveal--sequenced-marketing-hero.tsx +1 -1
- package/docs/patterns/components-herointro--two-line-intro.tsx +1 -1
- package/docs/patterns/components-herointro--with-actions.tsx +1 -1
- package/docs/patterns/components-herotilestack--marketing-hero-pattern.tsx +1 -1
- package/docs/patterns/components-herotilestack--marketing-hero-text-sequence.tsx +1 -1
- package/docs/patterns/components-herotilestack--marketing-hero-with-gallery-intro.tsx +1 -1
- package/docs/patterns/components-indexlist--post-index.tsx +1 -1
- package/docs/patterns/components-intakeconfirmation--booked-pattern.tsx +1 -1
- package/docs/patterns/components-intakeconfirmation--emailed-pattern.tsx +1 -1
- package/docs/patterns/components-intakeform--about-you-pattern.tsx +1 -1
- package/docs/patterns/components-intakeform--short-form-pattern.tsx +1 -1
- package/docs/patterns/components-intakemodal--intake-modal-pattern.tsx +1 -1
- package/docs/patterns/components-kbd--command-row.tsx +1 -1
- package/docs/patterns/components-kbd--numbered-choices.tsx +1 -1
- package/docs/patterns/components-kbd--shortcut.tsx +1 -1
- package/docs/patterns/components-linktile--resource-tile.tsx +1 -1
- package/docs/patterns/components-linktile--router-link.tsx +1 -1
- package/docs/patterns/components-logview--detail-pane.tsx +1 -1
- package/docs/patterns/components-logview--log-viewer.tsx +1 -1
- package/docs/patterns/components-moremenu--action-menu.tsx +1 -1
- package/docs/patterns/components-moremenu--in-card-header.tsx +1 -1
- package/docs/patterns/components-navlist--app-sidebar.tsx +1 -1
- package/docs/patterns/components-navlist--side-nav-settings.tsx +1 -1
- package/docs/patterns/components-notice--account-not-connected.tsx +21 -0
- package/docs/patterns/components-notice--holiday-closure.tsx +18 -0
- package/docs/patterns/components-notice--private-buyout.tsx +17 -0
- package/docs/patterns/components-notice--sync-failed.tsx +13 -0
- package/docs/patterns/components-pageheader--app-header-pattern.tsx +1 -1
- package/docs/patterns/components-pageheader--page-section-header.tsx +1 -1
- package/docs/patterns/components-pageheader--toolbar-header.tsx +1 -1
- package/docs/patterns/components-panel--end-detail-rail.tsx +1 -1
- package/docs/patterns/components-pillgroup--pill-group-pattern.tsx +1 -1
- package/docs/patterns/components-promptbar--pattern-prompt-bar.tsx +1 -1
- package/docs/patterns/components-prose--article-body.tsx +1 -1
- package/docs/patterns/components-radio-radiogroup--default.tsx +1 -1
- package/docs/patterns/components-scrollhorizontal--project-gallery-pattern.tsx +1 -1
- package/docs/patterns/components-scrollhorizontal--with-intro.tsx +1 -1
- package/docs/patterns/components-sectioncaption--column-caption.tsx +1 -1
- package/docs/patterns/components-sectioncaption--with-action.tsx +1 -1
- package/docs/patterns/components-sheet--bottom-sheet.tsx +1 -1
- package/docs/patterns/components-sheet--end-sheet.tsx +1 -1
- package/docs/patterns/components-sheet--side-sheet-header-actions.tsx +1 -1
- package/docs/patterns/components-sheet--side-sheet-url-deep-link.tsx +1 -1
- package/docs/patterns/components-sheet--side-sheet.tsx +1 -1
- package/docs/patterns/components-sitenav--brand-and-cta.tsx +1 -1
- package/docs/patterns/components-sitenav--centered-links.tsx +1 -1
- package/docs/patterns/components-sitenav--compact.tsx +1 -1
- package/docs/patterns/components-sitenav--marketing-header.tsx +1 -1
- package/docs/patterns/components-sitenav--mega-menu.tsx +1 -1
- package/docs/patterns/components-stat--hero-stat.tsx +1 -1
- package/docs/patterns/components-stat--insights-row.tsx +1 -1
- package/docs/patterns/components-stepprogress--step-progress-pattern.tsx +1 -1
- package/docs/patterns/components-switch--default.tsx +1 -1
- package/docs/patterns/components-switch--settings-row.tsx +1 -1
- package/docs/patterns/components-tab--settings-pages.tsx +1 -1
- package/docs/patterns/components-table--approvals-with-sheet.tsx +1 -1
- package/docs/patterns/components-table--approvals.tsx +1 -1
- package/docs/patterns/components-table--basic.tsx +1 -1
- package/docs/patterns/components-taskrows--action-details.tsx +1 -1
- package/docs/patterns/components-taskrows--capsules.tsx +1 -1
- package/docs/patterns/components-taskrows--card-with-status-rows.tsx +1 -1
- package/docs/patterns/components-taskrows--controlled-expand.tsx +1 -1
- package/docs/patterns/components-taskrows--custom-slots.tsx +1 -1
- package/docs/patterns/components-taskrows--needs-you-table.tsx +1 -1
- package/docs/patterns/components-taskrows--status-list.tsx +1 -1
- package/docs/patterns/components-taskrows--tag-chips.tsx +1 -1
- package/docs/patterns/components-textarea--save-status.tsx +1 -1
- package/docs/patterns/components-textlink--external-destination.tsx +1 -1
- package/docs/patterns/components-textlink--inline-prose.tsx +1 -1
- package/docs/patterns/components-textlink--quiet-title.tsx +1 -1
- package/docs/patterns/components-textlink--supporting-copy.tsx +1 -1
- package/docs/patterns/components-textsequence--default.tsx +1 -1
- package/docs/patterns/components-textsequence--reduced-motion.tsx +1 -1
- package/docs/patterns/components-textsequence--shapes.tsx +1 -1
- package/docs/patterns/components-tilegrid--masonry.tsx +1 -1
- package/docs/patterns/components-toast--stacked-notifications.tsx +1 -1
- package/docs/patterns/components-tooltip--controlled.tsx +1 -1
- package/docs/patterns/components-tooltip--disabled-control.tsx +1 -1
- package/docs/patterns/components-tooltip--icon-action.tsx +1 -1
- package/docs/patterns/components-tooltip--keyboard-shortcut.tsx +1 -1
- package/docs/patterns/components-tooltip--placement.tsx +1 -1
- package/docs/patterns/foundations-scroll-fade--horizontal-rail.tsx +1 -1
- package/docs/patterns/foundations-scroll-fade--overflowing-list.tsx +1 -1
- package/docs/patterns/guides-chart-explorations--comparison-gallery.tsx +1 -1
- package/docs/patterns/guides-filter-panel--filtered-grid.tsx +1 -1
- package/docs/patterns/guides-filter-panel--filtered-index.tsx +1 -1
- package/docs/patterns/guides-overlay-flows--notification-preferences.tsx +1 -1
- package/docs/patterns/guides-post-page--post-page.tsx +1 -1
- package/docs/patterns/guides-profile-typography--editorial-profile.tsx +1 -1
- package/docs/patterns/guides-resource-detail--detail.tsx +1 -1
- package/docs/patterns/index.json +33 -1
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,45 @@ Every release of `@thewhatmatters/wmds` is listed here, newest first.
|
|
|
5
5
|
- **Versions follow semver.** While the major version is `0`, a minor bump (`0.3.0`) can break an app and a patch bump (`0.2.1`) does not. Apps depend on `^0.2.0`, which accepts patches only.
|
|
6
6
|
- **Every release has a Consumer actions section**: the exact steps an app takes when it moves to that version. It says **None** when there are none. Agents upgrading an app read every Consumer actions section between the old and new version, oldest first.
|
|
7
7
|
- **Pasted patterns:** when a release changes a **Pattern — …** story's Show code, it is named under Consumer actions so apps re-copy it.
|
|
8
|
-
- **How to add an entry** (contributors):
|
|
8
|
+
- **How to add an entry** (contributors): don't edit this file on a feature branch. Add a release note as `changes/<topic>.md` (format in `changes/README.md`). The release step, `npm run release:prepare` on its own **Release 0.x.y** branch, folds every note into one new entry here and bumps the version once. `npm run check:changelog` checks this file and the notes.
|
|
9
|
+
|
|
10
|
+
## 0.4.43
|
|
11
|
+
|
|
12
|
+
**AppShell `asideMode="inset"` and a `toolbar` slot.** From `lg`, an inset aside is a raised card floating inside the page surface, under the title bar and the toolbar, 12px from the end and bottom edges (radius-surface-md, border, shadow-lg). The page narrows beside it and is never covered. Its header is the title bar's 56px band, with the title and description centred. The new `toolbar` prop / **AppShell.Toolbar** slot is a full-width band under the title bar; with an inset aside it spans above both. Below `lg` the aside is the overlay **Panel**, as in the other modes. New `asideFooter`: actions pinned under the aside's scrolling body (Copy, Reset), in every mode (the **Panel** `footer` in overlay). Fixed for docked and inset asides that start open: the server and the first paint no longer render the overlay **Panel** before the desktop query runs (it caused a hydration mismatch and a flash of the overlay). Story **Components/AppShell → State — aside inset, with a toolbar** (interaction test: inside the surface, under the toolbar, 12px gap, 56px header, page not covered, footer pinned).
|
|
13
|
+
|
|
14
|
+
**Contributors: release notes as files, and releasing as its own step.**
|
|
15
|
+
|
|
16
|
+
- Feature branches add a release note as `changes/<topic>.md` instead of editing `CHANGELOG.md` and the version, so two open branches no longer conflict. `npm run release:prepare` folds the notes into one entry and bumps the version once, on its own **Release 0.x.y** branch. `npm run check:changelog` also checks the notes. See `AGENTS.md` → **Releases**.
|
|
17
|
+
- The **report-wmds-gap** skill's contributing steps say to add a `changes/` note.
|
|
18
|
+
- `src/package.manifest.ts` lists one component per line, sorted.
|
|
19
|
+
|
|
20
|
+
### Consumer actions
|
|
21
|
+
|
|
22
|
+
None required. For a live-controls panel that should sit inside the page (the patterns gallery's Type panel), pass `asideMode="inset"`, move the view toolbar into `toolbar`, and put the button that opens the aside at the toolbar's end.
|
|
23
|
+
|
|
24
|
+
## 0.4.42
|
|
25
|
+
|
|
26
|
+
**Notice: an inline callout for page notes and failed sends.**
|
|
27
|
+
|
|
28
|
+
- **Notice** (new) — an inline callout for closures, buyouts, "account not connected", "sync failed" and a form that couldn't send. `tone` = `neutral` \| `info` \| `success` \| `warning` \| `error`, with `title`, copy as `children`, and an `action` slot (a **TextLink**, a small **Button**, or a row of them). The fill is the tone mixed into the current surface, so it reads in dark mode and in toned sections. `live` announces a notice that appears after load (`alert` for `error`, `status` otherwise), or pass `live="alert"` / `live="status"` to choose. `dismissible` adds a Dismiss button that hands focus to the next control; `dismissKey` remembers the dismissal in `localStorage` (`wmds-notice:<key>`). See **ADR-0050**.
|
|
29
|
+
- Patterns: **Components/Notice → Pattern — holiday closure**, **Pattern — private buyout**, **Pattern — account not connected**, **Pattern — sync failed**.
|
|
30
|
+
- The sketch request story's failed-send message (IntakeModal) is now an error **Notice** instead of a hand-built red block.
|
|
31
|
+
|
|
32
|
+
### Consumer actions
|
|
33
|
+
|
|
34
|
+
- None. Apps with a hand-built `role="alert"` block can swap it for `<Notice tone="error" live>`.
|
|
35
|
+
|
|
36
|
+
## 0.4.41
|
|
37
|
+
|
|
38
|
+
**Combobox: a searchable select for long lists.**
|
|
39
|
+
|
|
40
|
+
- **Combobox** (new): the **Input** pill with a search icon over a **Dropdown** listbox that narrows as people type, for lists of 16 or more (Dropdowns C7): fonts, countries, industries. WAI-ARIA combobox with list autocomplete: focus stays in the field, ↓ / ↑ move, Enter picks, Escape closes and then clears, and a polite live region says how many results there are. Same `label`, `description`, `size`, `width`, `status` and `message` as **Input**; options take **Dropdown.Item** `start` / `end` slots and hidden `keywords`. It renders the first `maxResults` (50) matches, so a list of thousands stays quick, and says how many more there are. `allowCustom` keeps typed text that matches nothing; `name` adds a hidden input for forms. New exports `Combobox`, `filterComboboxOptions`, `ComboboxOption`, `ComboboxProps`.
|
|
41
|
+
- **useDropdownMenu** (internal) `editable`: a text-field trigger keeps its characters, Space, Home and End.
|
|
42
|
+
- Stories **Combobox → Default**, **Long list (1,800 options)**, **Validation**, with interaction tests (keyboard path, filtering, Escape twice, focus stays in the field, a pick leaves other controls alone).
|
|
43
|
+
|
|
44
|
+
### Consumer actions
|
|
45
|
+
|
|
46
|
+
- None. To replace an **Input** + `<datalist>`: `<Combobox label="Headings font" options={fonts} value={family} onValueChange={setFamily} />`.
|
|
9
47
|
|
|
10
48
|
## 0.4.40
|
|
11
49
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { type FieldWidth, type InputMessagePosition, type InputSize, type InputStatus } from "../../atoms/Input/Input";
|
|
3
|
+
export { filterComboboxOptions } from "./comboboxFilter";
|
|
4
|
+
/** Layout-only — width, margin, grid placement. */
|
|
5
|
+
export type ComboboxLayoutClassName = string;
|
|
6
|
+
export type ComboboxOption = {
|
|
7
|
+
value: string;
|
|
8
|
+
label: string;
|
|
9
|
+
/** Leading slot — icon, swatch (**Dropdown.Item** `start`). */
|
|
10
|
+
start?: ReactNode;
|
|
11
|
+
/** Trailing slot — a category or a count (**Dropdown.Item** `end`); the selected row shows a check instead. */
|
|
12
|
+
end?: ReactNode;
|
|
13
|
+
/** Extra words that match the typed text but aren't shown (a category, a former name). */
|
|
14
|
+
keywords?: readonly string[];
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
};
|
|
17
|
+
export interface ComboboxProps {
|
|
18
|
+
options: readonly ComboboxOption[];
|
|
19
|
+
/** The chosen option's `value` (or the typed text with `allowCustom`). */
|
|
20
|
+
value?: string;
|
|
21
|
+
defaultValue?: string;
|
|
22
|
+
onValueChange?: (value: string) => void;
|
|
23
|
+
/** Controlled text in the field while typing. Default: the component keeps it. */
|
|
24
|
+
inputValue?: string;
|
|
25
|
+
onInputChange?: (text: string) => void;
|
|
26
|
+
/** Replace the default filter (starts with, then a word starts with, then contains). */
|
|
27
|
+
filter?: (options: readonly ComboboxOption[], query: string) => readonly ComboboxOption[];
|
|
28
|
+
/** Said and shown when nothing matches. */
|
|
29
|
+
emptyText?: string;
|
|
30
|
+
/** Rows rendered at once; type to narrow the rest. Default 50, so a list of thousands stays quick. */
|
|
31
|
+
maxResults?: number;
|
|
32
|
+
/** Take what was typed as the value when it matches no option (Enter or leaving the field). */
|
|
33
|
+
allowCustom?: boolean;
|
|
34
|
+
label?: string;
|
|
35
|
+
"aria-label"?: string;
|
|
36
|
+
description?: string;
|
|
37
|
+
placeholder?: string;
|
|
38
|
+
size?: InputSize;
|
|
39
|
+
width?: FieldWidth;
|
|
40
|
+
status?: InputStatus;
|
|
41
|
+
message?: string;
|
|
42
|
+
messagePosition?: InputMessagePosition;
|
|
43
|
+
disabled?: boolean;
|
|
44
|
+
required?: boolean;
|
|
45
|
+
/** Form name: a hidden input carries the chosen value on submit. */
|
|
46
|
+
name?: string;
|
|
47
|
+
id?: string;
|
|
48
|
+
className?: ComboboxLayoutClassName;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Searchable select — the **Input** pill with a search icon over a **Dropdown** listbox that narrows as
|
|
52
|
+
* people type (Dropdowns C7: lists of 16 or more). WAI-ARIA combobox with list autocomplete: focus stays
|
|
53
|
+
* in the field, ↓ / ↑ move through the results, Enter picks, Escape closes and then clears.
|
|
54
|
+
*/
|
|
55
|
+
export declare function Combobox({ options, value: valueProp, defaultValue, onValueChange, inputValue: inputValueProp, onInputChange, filter, emptyText, maxResults, allowCustom, label, "aria-label": ariaLabel, description, placeholder, size, width, status, message, messagePosition, disabled, required, name, id: idProp, className, }: ComboboxProps): import("react").JSX.Element;
|
|
56
|
+
//# sourceMappingURL=Combobox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Combobox.d.ts","sourceRoot":"","sources":["../../../../src/components/molecules/Combobox/Combobox.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA0E,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAI/G,OAAO,EAAS,KAAK,UAAU,EAAE,KAAK,oBAAoB,EAAE,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAO9H,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,mDAAmD;AACnD,MAAM,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAE7C,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,+GAA+G;IAC/G,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,SAAS,cAAc,EAAE,CAAC;IACnC,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,kFAAkF;IAClF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,wFAAwF;IACxF,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,SAAS,cAAc,EAAE,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,cAAc,EAAE,CAAC;IAC1F,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sGAAsG;IACtG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+FAA+F;IAC/F,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,oBAAoB,CAAC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,uBAAuB,CAAC;CACrC;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,EACvB,OAAO,EACP,KAAK,EAAE,SAAS,EAChB,YAAY,EACZ,aAAa,EACb,UAAU,EAAE,cAAc,EAC1B,aAAa,EACb,MAA8B,EAC9B,SAAwB,EACxB,UAAe,EACf,WAAmB,EACnB,KAAK,EACL,YAAY,EAAE,SAAS,EACvB,WAAW,EACX,WAAW,EACX,IAAW,EACX,KAAc,EACd,MAAM,EACN,OAAO,EACP,eAAe,EACf,QAAgB,EAChB,QAAQ,EACR,IAAI,EACJ,EAAE,EAAE,MAAM,EACV,SAAS,GACV,EAAE,aAAa,+BAiLf"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn as e } from "../../../lib/cn.js";
|
|
3
|
+
import { typographyClass as t } from "../../../lib/typography.js";
|
|
4
|
+
import { Input as n } from "../../atoms/Input/Input.js";
|
|
5
|
+
import { dropdownMenuClasses as r, dropdownMenuListClasses as i } from "../Dropdown/dropdownStyles.js";
|
|
6
|
+
import { Dropdown as a } from "../Dropdown/Dropdown.js";
|
|
7
|
+
import { measureDropdownMenuStyle as ee } from "../Dropdown/dropdownMenuPosition.js";
|
|
8
|
+
import { useDropdownMenu as o } from "../Dropdown/useDropdownMenu.js";
|
|
9
|
+
import { comboboxResultsMessage as s, filterComboboxOptions as c } from "./comboboxFilter.js";
|
|
10
|
+
import { useId as l, useMemo as u, useRef as d, useState as f } from "react";
|
|
11
|
+
import { Search as p } from "lucide-react";
|
|
12
|
+
import { jsx as m, jsxs as h } from "react/jsx-runtime";
|
|
13
|
+
//#region src/components/molecules/Combobox/Combobox.tsx
|
|
14
|
+
function g({ options: g, value: _, defaultValue: v, onValueChange: y, inputValue: b, onInputChange: x, filter: S = c, emptyText: C = "No matches", maxResults: w = 50, allowCustom: T = !1, label: E, "aria-label": D, description: te, placeholder: ne, size: re = "md", width: ie = "full", status: ae, message: O, messagePosition: k, disabled: A = !1, required: j, name: M, id: N, className: P }) {
|
|
15
|
+
let F = l(), I = N ?? F, L = `${I}-results`, R = d(null), [z, B] = f(v), [V, H] = f(null);
|
|
16
|
+
E == null && D == null && console.warn("[WMDS Combobox] Provide `label` or `aria-label`.");
|
|
17
|
+
let U = _ === void 0 ? z : _, W = g.find((e) => e.value === U)?.label ?? (T ? U ?? "" : ""), G = b ?? V ?? W, K = V ?? "", q = u(() => S(g, K), [
|
|
18
|
+
S,
|
|
19
|
+
g,
|
|
20
|
+
K
|
|
21
|
+
]), J = u(() => q.slice(0, Math.max(1, w)), [q, w]), oe = s(q.length, J.length, C);
|
|
22
|
+
function Y(e) {
|
|
23
|
+
H(e), x?.(e ?? "");
|
|
24
|
+
}
|
|
25
|
+
function X(e) {
|
|
26
|
+
_ === void 0 && B(e), e !== U && y?.(e);
|
|
27
|
+
}
|
|
28
|
+
function Z(e) {
|
|
29
|
+
X(e.value), Y(null), $.close(), R.current?.focus();
|
|
30
|
+
}
|
|
31
|
+
function Q() {
|
|
32
|
+
if (V == null) return;
|
|
33
|
+
let e = V.trim(), t = g.find((t) => t.label.toLowerCase() === e.toLowerCase() && !t.disabled);
|
|
34
|
+
t == null ? T && e !== "" ? X(e) : e === "" && !j && X("") : X(t.value), Y(null);
|
|
35
|
+
}
|
|
36
|
+
let $ = o({
|
|
37
|
+
rows: J,
|
|
38
|
+
triggerRef: R,
|
|
39
|
+
focus: "trigger",
|
|
40
|
+
editable: !0,
|
|
41
|
+
initialIndex: J.findIndex((e) => e.value === U),
|
|
42
|
+
measure: () => {
|
|
43
|
+
let e = R.current?.parentElement;
|
|
44
|
+
return e == null ? null : ee(e, []);
|
|
45
|
+
},
|
|
46
|
+
onChoose: (e) => {
|
|
47
|
+
let t = J[e];
|
|
48
|
+
t != null && Z(t);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
function se(e) {
|
|
52
|
+
Y(e.target.value), $.openMenu("first");
|
|
53
|
+
}
|
|
54
|
+
function ce(e) {
|
|
55
|
+
e.nativeEvent.isComposing || (e.key === "Escape" && !$.open && G !== "" ? (e.preventDefault(), Y("")) : e.key === "Enter" && (!$.open || J.length === 0) && (V != null && e.preventDefault(), Q(), $.close()));
|
|
56
|
+
}
|
|
57
|
+
let le = $.open && $.activeIndex < J.length ? $.triggerProps["aria-activedescendant"] : void 0;
|
|
58
|
+
return /* @__PURE__ */ h("div", {
|
|
59
|
+
...$.rootProps,
|
|
60
|
+
onBlur: (e) => {
|
|
61
|
+
$.rootProps.onBlur(e);
|
|
62
|
+
let t = e.relatedTarget;
|
|
63
|
+
(t == null || !e.currentTarget.contains(t)) && Q();
|
|
64
|
+
},
|
|
65
|
+
className: e("relative min-w-0", P),
|
|
66
|
+
children: [
|
|
67
|
+
/* @__PURE__ */ m(n, {
|
|
68
|
+
ref: R,
|
|
69
|
+
id: I,
|
|
70
|
+
role: "combobox",
|
|
71
|
+
type: "text",
|
|
72
|
+
autoComplete: "off",
|
|
73
|
+
autoCorrect: "off",
|
|
74
|
+
spellCheck: !1,
|
|
75
|
+
"aria-autocomplete": "list",
|
|
76
|
+
"aria-expanded": $.open,
|
|
77
|
+
"aria-controls": $.open ? $.menuProps.id : void 0,
|
|
78
|
+
"aria-activedescendant": le,
|
|
79
|
+
"aria-label": E == null ? D : void 0,
|
|
80
|
+
"aria-describedby": L,
|
|
81
|
+
"aria-required": j || void 0,
|
|
82
|
+
label: E,
|
|
83
|
+
description: te,
|
|
84
|
+
placeholder: ne,
|
|
85
|
+
size: re,
|
|
86
|
+
width: ie,
|
|
87
|
+
status: ae,
|
|
88
|
+
message: O,
|
|
89
|
+
messagePosition: k,
|
|
90
|
+
disabled: A,
|
|
91
|
+
icon: /* @__PURE__ */ m(p, { strokeWidth: 2 }),
|
|
92
|
+
value: G,
|
|
93
|
+
onChange: se,
|
|
94
|
+
onKeyDown: ce,
|
|
95
|
+
onClick: () => {
|
|
96
|
+
!$.open && !A && $.openMenu("initial");
|
|
97
|
+
}
|
|
98
|
+
}),
|
|
99
|
+
M == null ? null : /* @__PURE__ */ m("input", {
|
|
100
|
+
type: "hidden",
|
|
101
|
+
name: M,
|
|
102
|
+
value: U ?? ""
|
|
103
|
+
}),
|
|
104
|
+
/* @__PURE__ */ m("span", {
|
|
105
|
+
id: L,
|
|
106
|
+
role: "status",
|
|
107
|
+
className: "sr-only",
|
|
108
|
+
children: $.open ? oe : ""
|
|
109
|
+
}),
|
|
110
|
+
$.open && $.menuStyle != null ? /* @__PURE__ */ h("div", {
|
|
111
|
+
ref: $.menuProps.ref,
|
|
112
|
+
style: $.menuProps.style,
|
|
113
|
+
className: r,
|
|
114
|
+
children: [J.length > 0 ? /* @__PURE__ */ m("ul", {
|
|
115
|
+
id: $.menuProps.id,
|
|
116
|
+
role: "listbox",
|
|
117
|
+
"aria-label": E ?? D,
|
|
118
|
+
className: i,
|
|
119
|
+
children: J.map((e, t) => {
|
|
120
|
+
let n = e.value === U;
|
|
121
|
+
return /* @__PURE__ */ m("li", {
|
|
122
|
+
role: "presentation",
|
|
123
|
+
children: /* @__PURE__ */ m(a.Item, {
|
|
124
|
+
...$.rowProps(t),
|
|
125
|
+
role: "option",
|
|
126
|
+
"aria-selected": n,
|
|
127
|
+
"aria-disabled": e.disabled || void 0,
|
|
128
|
+
selected: n,
|
|
129
|
+
disabled: e.disabled,
|
|
130
|
+
truncate: !1,
|
|
131
|
+
start: e.start,
|
|
132
|
+
end: e.end,
|
|
133
|
+
className: "pointer-coarse:min-h-11",
|
|
134
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
135
|
+
onClick: () => Z(e),
|
|
136
|
+
children: e.label
|
|
137
|
+
})
|
|
138
|
+
}, e.value);
|
|
139
|
+
})
|
|
140
|
+
}) : /* @__PURE__ */ m("p", {
|
|
141
|
+
id: $.menuProps.id,
|
|
142
|
+
className: e(t("body"), "m-0 px-3.5 py-2 text-muted"),
|
|
143
|
+
children: C
|
|
144
|
+
}), J.length < q.length ? /* @__PURE__ */ m("p", {
|
|
145
|
+
"aria-hidden": !0,
|
|
146
|
+
className: e(t("caption"), "m-0 px-3.5 py-2 text-muted"),
|
|
147
|
+
children: `${(q.length - J.length).toLocaleString("en-US")} more. Keep typing to narrow.`
|
|
148
|
+
}) : null]
|
|
149
|
+
}) : null
|
|
150
|
+
]
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
//#endregion
|
|
154
|
+
export { g as Combobox, c as filterComboboxOptions };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type ComboboxFilterOption = {
|
|
2
|
+
label: string;
|
|
3
|
+
/** Extra words that match but aren't shown (a category, a former name). */
|
|
4
|
+
keywords?: readonly string[];
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Default **Combobox** filter, case-insensitive: labels that start with the query, then labels with a
|
|
8
|
+
* word that starts with it, then labels that contain it; keywords match after labels. Options keep
|
|
9
|
+
* their given order within a rank. An empty query returns every option.
|
|
10
|
+
*/
|
|
11
|
+
export declare function filterComboboxOptions<T extends ComboboxFilterOption>(options: readonly T[], query: string): T[];
|
|
12
|
+
/** What the polite live region says after the list changes. */
|
|
13
|
+
export declare function comboboxResultsMessage(total: number, shown: number, emptyText: string): string;
|
|
14
|
+
//# sourceMappingURL=comboboxFilter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comboboxFilter.d.ts","sourceRoot":"","sources":["../../../../src/components/molecules/Combobox/comboboxFilter.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9B,CAAC;AAWF;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,oBAAoB,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,EAAE,CAa/G;AAED,+DAA+D;AAC/D,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAK9F"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
//#region src/components/molecules/Combobox/comboboxFilter.ts
|
|
3
|
+
function e(e, t) {
|
|
4
|
+
let n = e.toLowerCase();
|
|
5
|
+
return n.startsWith(t) ? 0 : n.split(/[\s\-_/]+/).some((e) => e.startsWith(t)) ? 1 : n.includes(t) ? 2 : null;
|
|
6
|
+
}
|
|
7
|
+
function t(t, n) {
|
|
8
|
+
let r = n.trim().toLowerCase();
|
|
9
|
+
if (r === "") return [...t];
|
|
10
|
+
let i = [];
|
|
11
|
+
return t.forEach((t, n) => {
|
|
12
|
+
let a = e(t.label, r), o = (t.keywords ?? []).map((t) => e(t, r)).filter((e) => e != null), s = a ?? (o.length > 0 ? 3 + Math.min(...o) : null);
|
|
13
|
+
s != null && i.push({
|
|
14
|
+
option: t,
|
|
15
|
+
rank: s,
|
|
16
|
+
index: n
|
|
17
|
+
});
|
|
18
|
+
}), i.sort((e, t) => e.rank - t.rank || e.index - t.index), i.map((e) => e.option);
|
|
19
|
+
}
|
|
20
|
+
function n(e, t, n) {
|
|
21
|
+
if (e === 0) return n;
|
|
22
|
+
let r = e === 1 ? "result" : "results";
|
|
23
|
+
return t < e ? `${e.toLocaleString("en-US")} ${r}, first ${t} shown. Keep typing to narrow.` : `${e.toLocaleString("en-US")} ${r}`;
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { n as comboboxResultsMessage, t as filterComboboxOptions };
|
|
@@ -24,6 +24,11 @@ export interface DropdownMenuOptions {
|
|
|
24
24
|
initialIndex?: number;
|
|
25
25
|
/** `trigger` focus only: Enter or Space on the trigger chooses the active row. */
|
|
26
26
|
onChoose?: (index: number) => void;
|
|
27
|
+
/**
|
|
28
|
+
* `trigger` focus only: the trigger is a text field (**Combobox**). Typed characters, Space, Home and
|
|
29
|
+
* End belong to the field, so there is no type-ahead and only ↓ / ↑ open the menu; Enter chooses.
|
|
30
|
+
*/
|
|
31
|
+
editable?: boolean;
|
|
27
32
|
}
|
|
28
33
|
/**
|
|
29
34
|
* Open state, dismissal, keyboard, and position for every WMDS dropdown menu (Select, MoreMenu,
|
|
@@ -33,7 +38,7 @@ export interface DropdownMenuOptions {
|
|
|
33
38
|
* Dismissal: Escape (handled here, `preventDefault` so an enclosing Dialog or Sheet stays open), a
|
|
34
39
|
* pointer press outside, focus leaving (Tab), and choosing a row. Scroll and resize reposition the menu.
|
|
35
40
|
*/
|
|
36
|
-
export declare function useDropdownMenu({ rows, triggerRef, measure, focus, initialIndex, onChoose, }: DropdownMenuOptions): {
|
|
41
|
+
export declare function useDropdownMenu({ rows, triggerRef, measure, focus, initialIndex, onChoose, editable, }: DropdownMenuOptions): {
|
|
37
42
|
open: boolean;
|
|
38
43
|
activeIndex: number;
|
|
39
44
|
menuStyle: CSSProperties | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDropdownMenu.d.ts","sourceRoot":"","sources":["../../../../src/components/molecules/Dropdown/useDropdownMenu.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,MAAM,MAAM,eAAe,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAEpE;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,OAAO,CAAC;AAEpD,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;AAEvE,MAAM,WAAW,mBAAmB;IAClC,yFAAyF;IACzF,IAAI,EAAE,SAAS,eAAe,EAAE,CAAC;IACjC,2DAA2D;IAC3D,UAAU,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC1C,oGAAoG;IACpG,OAAO,EAAE,MAAM,aAAa,GAAG,IAAI,CAAC;IACpC,KAAK,EAAE,iBAAiB,CAAC;IACzB,uGAAuG;IACvG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kFAAkF;IAClF,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"useDropdownMenu.d.ts","sourceRoot":"","sources":["../../../../src/components/molecules/Dropdown/useDropdownMenu.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,MAAM,MAAM,eAAe,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAEpE;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,OAAO,CAAC;AAEpD,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;AAEvE,MAAM,WAAW,mBAAmB;IAClC,yFAAyF;IACzF,IAAI,EAAE,SAAS,eAAe,EAAE,CAAC;IACjC,2DAA2D;IAC3D,UAAU,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC1C,oGAAoG;IACpG,OAAO,EAAE,MAAM,aAAa,GAAG,IAAI,CAAC;IACpC,KAAK,EAAE,iBAAiB,CAAC;IACzB,uGAAuG;IACvG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kFAAkF;IAClF,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAID;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,UAAU,EACV,OAAO,EACP,KAAK,EACL,YAAY,EACZ,QAAQ,EACR,QAAgB,GACjB,EAAE,mBAAmB;;;;oBA8Bb,kBAAkB;8BASG;QAAE,WAAW,CAAC,EAAE,OAAO,CAAA;KAAE;;;oBA+KrC,WAAW,GAAG,IAAI;2BA5GJ,aAAa,CAAC,WAAW,CAAC;wBAgG7B,UAAU,CAAC,WAAW,CAAC;;;;;;;;;oBAyBlC,WAAW,GAAG,IAAI;;;sBAKd,MAAM;;oBAEV,WAAW,GAAG,IAAI;;;;;EAUnC;AAED,mGAAmG;AACnG,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,eAAe,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAQrG"}
|
|
@@ -2,142 +2,168 @@
|
|
|
2
2
|
import { useCallback as e, useEffect as t, useId as n, useLayoutEffect as r, useRef as i, useState as a } from "react";
|
|
3
3
|
//#region src/components/molecules/Dropdown/useDropdownMenu.ts
|
|
4
4
|
var o = 500;
|
|
5
|
-
function s({ rows: s, triggerRef: l, measure: u, focus: d, initialIndex: f, onChoose: p }) {
|
|
6
|
-
let
|
|
5
|
+
function s({ rows: s, triggerRef: l, measure: u, focus: d, initialIndex: f, onChoose: p, editable: m = !1 }) {
|
|
6
|
+
let h = n(), g = i(null), _ = i(null), v = i([]), y = i({
|
|
7
7
|
text: "",
|
|
8
8
|
at: 0
|
|
9
|
-
}), [
|
|
9
|
+
}), [b, x] = a(!1), [S, C] = a(0), [w, T] = a(null), E = i(u);
|
|
10
10
|
t(() => {
|
|
11
|
-
|
|
11
|
+
E.current = u;
|
|
12
12
|
});
|
|
13
|
-
let
|
|
14
|
-
|
|
15
|
-
}, [
|
|
16
|
-
|
|
13
|
+
let D = e((e) => `${h}-row-${e}`, [h]), O = e((e) => typeof e == "number" ? e : e === "last" ? c(s, s.length, -1) : e === "initial" && f != null && f >= 0 && !s[f]?.disabled ? f : c(s, -1, 1), [f, s]), k = e((e = "initial") => {
|
|
14
|
+
T(E.current()), C(O(e)), x(!0);
|
|
15
|
+
}, [O]), A = e(({ returnFocus: e = !1 } = {}) => {
|
|
16
|
+
x(!1), T(null), y.current = {
|
|
17
17
|
text: "",
|
|
18
18
|
at: 0
|
|
19
19
|
}, e && l.current?.focus();
|
|
20
|
-
}, [l]),
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
}, [l]), j = e(() => b ? A() : k(), [
|
|
21
|
+
A,
|
|
22
|
+
b,
|
|
23
|
+
k
|
|
24
24
|
]);
|
|
25
25
|
r(() => {
|
|
26
|
-
if (!
|
|
27
|
-
let e = () =>
|
|
26
|
+
if (!b) return;
|
|
27
|
+
let e = () => T(E.current());
|
|
28
28
|
return window.addEventListener("resize", e), window.addEventListener("scroll", e, !0), () => {
|
|
29
29
|
window.removeEventListener("resize", e), window.removeEventListener("scroll", e, !0);
|
|
30
30
|
};
|
|
31
|
-
}, [
|
|
32
|
-
if (!
|
|
31
|
+
}, [b]), t(() => {
|
|
32
|
+
if (!b) return;
|
|
33
33
|
function e(e) {
|
|
34
|
-
|
|
34
|
+
M(e.target) || A();
|
|
35
35
|
}
|
|
36
36
|
return document.addEventListener("pointerdown", e), () => document.removeEventListener("pointerdown", e);
|
|
37
37
|
}), r(() => {
|
|
38
|
-
!
|
|
38
|
+
!b || d !== "items" || w == null || v.current[S]?.focus({ preventScroll: !0 });
|
|
39
39
|
}, [
|
|
40
|
-
|
|
40
|
+
S,
|
|
41
41
|
d,
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
w,
|
|
43
|
+
b
|
|
44
44
|
]), r(() => {
|
|
45
|
-
!
|
|
45
|
+
!b || d !== "trigger" || v.current[S]?.scrollIntoView?.({ block: "nearest" });
|
|
46
46
|
}, [
|
|
47
|
-
|
|
47
|
+
S,
|
|
48
48
|
d,
|
|
49
|
-
|
|
49
|
+
b
|
|
50
50
|
]);
|
|
51
|
-
function j(e) {
|
|
52
|
-
return e != null && (h.current?.contains(e) === !0 || g.current?.contains(e) === !0);
|
|
53
|
-
}
|
|
54
51
|
function M(e) {
|
|
55
|
-
|
|
52
|
+
return e != null && (g.current?.contains(e) === !0 || _.current?.contains(e) === !0);
|
|
53
|
+
}
|
|
54
|
+
function N(e) {
|
|
55
|
+
let t = Date.now(), n = y.current;
|
|
56
56
|
n.text = t - n.at > o ? e : n.text + e, n.at = t;
|
|
57
|
-
let r = n.text.toLowerCase(), i = r.length > 1 && [...r].every((e) => e === r[0]), a = i ? r[0] : r, c =
|
|
57
|
+
let r = n.text.toLowerCase(), i = r.length > 1 && [...r].every((e) => e === r[0]), a = i ? r[0] : r, c = b ? S + (i || r.length === 1 ? 1 : 0) : 0;
|
|
58
58
|
for (let e = 0; e < s.length; e += 1) {
|
|
59
59
|
let t = (c + e) % s.length, n = s[t];
|
|
60
60
|
if (n != null && !n.disabled && n.label.toLowerCase().startsWith(a)) return t;
|
|
61
61
|
}
|
|
62
62
|
return null;
|
|
63
63
|
}
|
|
64
|
-
function
|
|
64
|
+
function P(e) {
|
|
65
65
|
if (e.nativeEvent.isComposing) return;
|
|
66
66
|
let { key: t } = e, n = t.length === 1 && t !== " " && !e.metaKey && !e.ctrlKey && !e.altKey, r = l.current?.contains(e.target) === !0;
|
|
67
|
-
if (
|
|
67
|
+
if (m) {
|
|
68
|
+
F(e, r);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (!b) {
|
|
68
72
|
if (!r) return;
|
|
69
|
-
if (t === "ArrowDown" || t === "ArrowUp") e.preventDefault(),
|
|
70
|
-
else if (d === "trigger" && (t === "Home" || t === "End")) e.preventDefault(),
|
|
71
|
-
else if (d === "trigger" && (t === "Enter" || t === " ")) e.preventDefault(),
|
|
73
|
+
if (t === "ArrowDown" || t === "ArrowUp") e.preventDefault(), k(d === "trigger" ? "initial" : t === "ArrowDown" ? "first" : "last");
|
|
74
|
+
else if (d === "trigger" && (t === "Home" || t === "End")) e.preventDefault(), k(t === "Home" ? "first" : "last");
|
|
75
|
+
else if (d === "trigger" && (t === "Enter" || t === " ")) e.preventDefault(), k();
|
|
72
76
|
else if (d === "trigger" && n) {
|
|
73
|
-
let e =
|
|
74
|
-
e != null &&
|
|
77
|
+
let e = N(t);
|
|
78
|
+
e != null && k(e);
|
|
75
79
|
}
|
|
76
80
|
return;
|
|
77
81
|
}
|
|
78
82
|
switch (t) {
|
|
79
83
|
case "Escape":
|
|
80
|
-
e.preventDefault(),
|
|
84
|
+
e.preventDefault(), A({ returnFocus: !0 });
|
|
81
85
|
return;
|
|
82
86
|
case "Tab":
|
|
83
|
-
|
|
87
|
+
A();
|
|
84
88
|
return;
|
|
85
89
|
case "ArrowDown":
|
|
86
90
|
case "ArrowUp":
|
|
87
|
-
e.preventDefault(),
|
|
91
|
+
e.preventDefault(), C((e) => c(s, e, t === "ArrowDown" ? 1 : -1));
|
|
88
92
|
return;
|
|
89
93
|
case "Home":
|
|
90
94
|
case "End":
|
|
91
|
-
e.preventDefault(),
|
|
95
|
+
e.preventDefault(), C(O(t === "Home" ? "first" : "last"));
|
|
92
96
|
return;
|
|
93
97
|
case "Enter":
|
|
94
98
|
case " ":
|
|
95
|
-
d === "trigger" ? (e.preventDefault(), s[
|
|
99
|
+
d === "trigger" ? (e.preventDefault(), s[S]?.disabled || p?.(S)) : t === " " && !r && (e.preventDefault(), v.current[S]?.click());
|
|
96
100
|
return;
|
|
97
101
|
default: if (n) {
|
|
98
|
-
let e =
|
|
99
|
-
e != null &&
|
|
102
|
+
let e = N(t);
|
|
103
|
+
e != null && C(e);
|
|
100
104
|
}
|
|
101
105
|
}
|
|
102
106
|
}
|
|
103
|
-
function
|
|
104
|
-
|
|
107
|
+
function F(e, t) {
|
|
108
|
+
let { key: n } = e;
|
|
109
|
+
if (!b) {
|
|
110
|
+
t && (n === "ArrowDown" || n === "ArrowUp") && (e.preventDefault(), k(n === "ArrowDown" ? "initial" : "last"));
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
switch (n) {
|
|
114
|
+
case "Escape":
|
|
115
|
+
e.preventDefault(), A({ returnFocus: !0 });
|
|
116
|
+
return;
|
|
117
|
+
case "Tab":
|
|
118
|
+
A();
|
|
119
|
+
return;
|
|
120
|
+
case "ArrowDown":
|
|
121
|
+
case "ArrowUp":
|
|
122
|
+
e.preventDefault(), C((e) => c(s, e, n === "ArrowDown" ? 1 : -1));
|
|
123
|
+
return;
|
|
124
|
+
case "Enter":
|
|
125
|
+
e.preventDefault(), s.length > 0 && !s[S]?.disabled && p?.(S);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function I(e) {
|
|
130
|
+
b && !M(e.relatedTarget) && A();
|
|
105
131
|
}
|
|
106
132
|
return {
|
|
107
|
-
open:
|
|
108
|
-
activeIndex:
|
|
109
|
-
menuStyle:
|
|
110
|
-
openMenu:
|
|
111
|
-
close:
|
|
112
|
-
toggle:
|
|
133
|
+
open: b,
|
|
134
|
+
activeIndex: S,
|
|
135
|
+
menuStyle: w,
|
|
136
|
+
openMenu: k,
|
|
137
|
+
close: A,
|
|
138
|
+
toggle: j,
|
|
113
139
|
rootProps: {
|
|
114
140
|
ref: (e) => {
|
|
115
|
-
|
|
141
|
+
g.current = e;
|
|
116
142
|
},
|
|
117
|
-
onKeyDown:
|
|
118
|
-
onBlur:
|
|
143
|
+
onKeyDown: P,
|
|
144
|
+
onBlur: I
|
|
119
145
|
},
|
|
120
146
|
triggerProps: {
|
|
121
|
-
"aria-expanded":
|
|
122
|
-
"aria-controls":
|
|
123
|
-
"aria-activedescendant": d === "trigger" &&
|
|
147
|
+
"aria-expanded": b,
|
|
148
|
+
"aria-controls": b ? h : void 0,
|
|
149
|
+
"aria-activedescendant": d === "trigger" && b ? D(S) : void 0
|
|
124
150
|
},
|
|
125
151
|
menuProps: {
|
|
126
|
-
id:
|
|
152
|
+
id: h,
|
|
127
153
|
ref: (e) => {
|
|
128
|
-
|
|
154
|
+
_.current = e;
|
|
129
155
|
},
|
|
130
|
-
style:
|
|
156
|
+
style: w ?? void 0
|
|
131
157
|
},
|
|
132
158
|
rowProps: (e) => ({
|
|
133
|
-
id:
|
|
159
|
+
id: D(e),
|
|
134
160
|
ref: (t) => {
|
|
135
|
-
|
|
161
|
+
v.current[e] = t;
|
|
136
162
|
},
|
|
137
163
|
tabIndex: -1,
|
|
138
|
-
active: e ===
|
|
164
|
+
active: e === S,
|
|
139
165
|
onMouseEnter: () => {
|
|
140
|
-
s[e]?.disabled ||
|
|
166
|
+
s[e]?.disabled || C(e);
|
|
141
167
|
}
|
|
142
168
|
})
|
|
143
169
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useOverflowMenu.d.ts","sourceRoot":"","sources":["../../../../src/components/molecules/Dropdown/useOverflowMenu.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACvG,OAAO,EAA4B,KAAK,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAE/F,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAE1E,MAAM,WAAW,mBAAmB;IAClC,wCAAwC;IACxC,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;IACvB,mFAAmF;IACnF,QAAQ,EAAE,MAAM,CAAC;IACjB,gGAAgG;IAChG,UAAU,EAAE,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,KAAK,eAAe,EAAE,CAAC;IAClE,gFAAgF;IAChF,aAAa,CAAC,EAAE,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,KAAK,sBAAsB,EAAE,CAAC;CAC9E;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAE,EAAE,mBAAmB;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"useOverflowMenu.d.ts","sourceRoot":"","sources":["../../../../src/components/molecules/Dropdown/useOverflowMenu.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACvG,OAAO,EAA4B,KAAK,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAE/F,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAE1E,MAAM,WAAW,mBAAmB;IAClC,wCAAwC;IACxC,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;IACvB,mFAAmF;IACnF,QAAQ,EAAE,MAAM,CAAC;IACjB,gGAAgG;IAChG,UAAU,EAAE,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,KAAK,eAAe,EAAE,CAAC;IAClE,gFAAgF;IAChF,aAAa,CAAC,EAAE,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,KAAK,sBAAsB,EAAE,CAAC;CAC9E;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAE,EAAE,mBAAmB;;;;;;;;;;uBAmEzE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;IATrB,0FAA0F;;oBAG5E,WAAW,GAAG,IAAI;;;;IAKhC,4DAA4D;qBAC3C,MAAM,MAAM,MAAM,WAAW,GAAG,IAAI;IAIrD,yDAAyD;2BAClC,WAAW,GAAG,IAAI;EAI5C;AAED,4DAA4D;AAC5D,wBAAgB,MAAM,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAK9C"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type ReactElement, type ReactNode } from "react";
|
|
2
|
+
import { type NoticeTone } from "./noticeStyles";
|
|
3
|
+
export { noticeTones, type NoticeTone } from "./noticeStyles";
|
|
4
|
+
/** Layout-only — width, margin, grid placement. Not for colour or type. */
|
|
5
|
+
export type NoticeLayoutClassName = string;
|
|
6
|
+
/** `localStorage` key prefix for a notice dismissed with `dismissKey`. */
|
|
7
|
+
export declare const noticeStoragePrefix = "wmds-notice:";
|
|
8
|
+
/** `alert` interrupts the screen reader; `status` waits for a pause. */
|
|
9
|
+
export type NoticeLiveRole = "alert" | "status";
|
|
10
|
+
export interface NoticeProps {
|
|
11
|
+
/** Default `neutral`. `error` is for something that failed, not for emphasis. */
|
|
12
|
+
tone?: NoticeTone;
|
|
13
|
+
/** Short lead line in `ui-label`. */
|
|
14
|
+
title?: ReactNode;
|
|
15
|
+
/** Supporting copy in `caption`. */
|
|
16
|
+
children?: ReactNode;
|
|
17
|
+
/** A **TextLink** or a small **Button** under the copy. */
|
|
18
|
+
action?: ReactNode;
|
|
19
|
+
/**
|
|
20
|
+
* Replace the tone's icon (a Lucide element), or `false` for none. Default: Info, CircleCheck,
|
|
21
|
+
* TriangleAlert or CircleX by tone.
|
|
22
|
+
*/
|
|
23
|
+
icon?: ReactElement | false;
|
|
24
|
+
/** Show a Dismiss button. */
|
|
25
|
+
dismissible?: boolean;
|
|
26
|
+
/** Accessible name of the Dismiss button. @default "Dismiss" */
|
|
27
|
+
dismissLabel?: string;
|
|
28
|
+
/** Called once when the visitor dismisses the notice. */
|
|
29
|
+
onDismiss?: () => void;
|
|
30
|
+
/**
|
|
31
|
+
* Remember the dismissal in `localStorage` under `wmds-notice:<key>`, so the notice stays hidden
|
|
32
|
+
* on later visits. Change the key (for example `holiday-2026`) to show a new notice again.
|
|
33
|
+
* Server HTML always includes the notice; a visitor who dismissed it sees it removed on hydration.
|
|
34
|
+
*/
|
|
35
|
+
dismissKey?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Announce the notice when it appears after load (a sync failure, a form result). `error` uses
|
|
38
|
+
* `role="alert"`, the others `role="status"`; pass `"alert"` or `"status"` to choose the role
|
|
39
|
+
* yourself. Leave off for a notice that is part of the page.
|
|
40
|
+
*/
|
|
41
|
+
live?: boolean | NoticeLiveRole;
|
|
42
|
+
id?: string;
|
|
43
|
+
className?: NoticeLayoutClassName;
|
|
44
|
+
}
|
|
45
|
+
/** Inline callout: closures, buyouts, "account not connected", "sync failed". */
|
|
46
|
+
export declare function Notice({ tone, title, children, action, icon, dismissible, dismissLabel, onDismiss, dismissKey, live, id, className, }: NoticeProps): import("react").JSX.Element | null;
|
|
47
|
+
//# sourceMappingURL=Notice.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Notice.d.ts","sourceRoot":"","sources":["../../../../src/components/molecules/Notice/Notice.tsx"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAKf,OAAO,EASL,KAAK,UAAU,EAChB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,WAAW,EAAE,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE9D,2EAA2E;AAC3E,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAE3C,0EAA0E;AAC1E,eAAO,MAAM,mBAAmB,iBAAiB,CAAC;AAElD,wEAAwE;AACxE,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEhD,MAAM,WAAW,WAAW;IAC1B,iFAAiF;IACjF,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,qCAAqC;IACrC,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB;;;OAGG;IACH,IAAI,CAAC,EAAE,YAAY,GAAG,KAAK,CAAC;IAC5B,6BAA6B;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,gEAAgE;IAChE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,GAAG,cAAc,CAAC;IAChC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,qBAAqB,CAAC;CACnC;AAgED,iFAAiF;AACjF,wBAAgB,MAAM,CAAC,EACrB,IAAgB,EAChB,KAAK,EACL,QAAQ,EACR,MAAM,EACN,IAAI,EACJ,WAAmB,EACnB,YAAwB,EACxB,SAAS,EACT,UAAU,EACV,IAAY,EACZ,EAAE,EACF,SAAS,GACV,EAAE,WAAW,sCAmEb"}
|