@thewhatmatters/wmds 0.4.40 → 0.4.42
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 +24 -0
- 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/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 +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,30 @@ Every release of `@thewhatmatters/wmds` is listed here, newest 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
8
|
- **How to add an entry** (contributors): add your change to the top entry. If that version is already on npm (`npm view @thewhatmatters/wmds versions`), start a new entry above it and bump `version` in `package.json` to match. `npm run check:changelog` enforces the format.
|
|
9
9
|
|
|
10
|
+
## 0.4.42
|
|
11
|
+
|
|
12
|
+
**Notice: an inline callout for page notes and failed sends.**
|
|
13
|
+
|
|
14
|
+
- **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**.
|
|
15
|
+
- Patterns: **Components/Notice → Pattern — holiday closure**, **Pattern — private buyout**, **Pattern — account not connected**, **Pattern — sync failed**.
|
|
16
|
+
- The sketch request story's failed-send message (IntakeModal) is now an error **Notice** instead of a hand-built red block.
|
|
17
|
+
|
|
18
|
+
### Consumer actions
|
|
19
|
+
|
|
20
|
+
- None. Apps with a hand-built `role="alert"` block can swap it for `<Notice tone="error" live>`.
|
|
21
|
+
|
|
22
|
+
## 0.4.41
|
|
23
|
+
|
|
24
|
+
**Combobox: a searchable select for long lists.**
|
|
25
|
+
|
|
26
|
+
- **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`.
|
|
27
|
+
- **useDropdownMenu** (internal) `editable`: a text-field trigger keeps its characters, Space, Home and End.
|
|
28
|
+
- 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).
|
|
29
|
+
|
|
30
|
+
### Consumer actions
|
|
31
|
+
|
|
32
|
+
- None. To replace an **Input** + `<datalist>`: `<Combobox label="Headings font" options={fonts} value={family} onValueChange={setFamily} />`.
|
|
33
|
+
|
|
10
34
|
## 0.4.40
|
|
11
35
|
|
|
12
36
|
**AppShell: the phone page picker stays on one line.**
|
|
@@ -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"}
|