@hawiyah/react 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +73 -0
- package/NOTICE +19 -0
- package/PORTAL.md +74 -0
- package/README.md +461 -2
- package/dist/calendar.d.ts +52 -0
- package/dist/calendar.d.ts.map +1 -0
- package/dist/calendar.js +148 -0
- package/dist/calendar.js.map +1 -0
- package/dist/content-navigation.d.ts +15 -0
- package/dist/content-navigation.d.ts.map +1 -0
- package/dist/content-navigation.js +29 -0
- package/dist/content-navigation.js.map +1 -0
- package/dist/display.d.ts +421 -0
- package/dist/display.d.ts.map +1 -0
- package/dist/display.js +208 -0
- package/dist/display.js.map +1 -0
- package/dist/expanded-content.d.ts +217 -0
- package/dist/expanded-content.d.ts.map +1 -0
- package/dist/expanded-content.js +124 -0
- package/dist/expanded-content.js.map +1 -0
- package/dist/expanded-controls.d.ts +107 -0
- package/dist/expanded-controls.d.ts.map +1 -0
- package/dist/expanded-controls.js +142 -0
- package/dist/expanded-controls.js.map +1 -0
- package/dist/expanded-interactive.d.ts +116 -0
- package/dist/expanded-interactive.d.ts.map +1 -0
- package/dist/expanded-interactive.js +204 -0
- package/dist/expanded-interactive.js.map +1 -0
- package/dist/expanded-layout.d.ts +80 -0
- package/dist/expanded-layout.d.ts.map +1 -0
- package/dist/expanded-layout.js +26 -0
- package/dist/expanded-layout.js.map +1 -0
- package/dist/expanded-shared.d.ts +3 -0
- package/dist/expanded-shared.d.ts.map +1 -0
- package/dist/expanded-shared.js +14 -0
- package/dist/expanded-shared.js.map +1 -0
- package/dist/file-upload-list.d.ts +10 -0
- package/dist/file-upload-list.d.ts.map +1 -0
- package/dist/file-upload-list.js +7 -0
- package/dist/file-upload-list.js.map +1 -0
- package/dist/forms.d.ts +34 -0
- package/dist/forms.d.ts.map +1 -0
- package/dist/forms.js +65 -0
- package/dist/forms.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/interactive.d.ts +60 -0
- package/dist/interactive.d.ts.map +1 -0
- package/dist/interactive.js +321 -0
- package/dist/interactive.js.map +1 -0
- package/dist/mobile-top-bar.d.ts +14 -0
- package/dist/mobile-top-bar.d.ts.map +1 -0
- package/dist/mobile-top-bar.js +8 -0
- package/dist/mobile-top-bar.js.map +1 -0
- package/dist/navigation-drawer.d.ts +20 -0
- package/dist/navigation-drawer.d.ts.map +1 -0
- package/dist/navigation-drawer.js +37 -0
- package/dist/navigation-drawer.js.map +1 -0
- package/dist/portal.d.ts +27 -0
- package/dist/portal.d.ts.map +1 -0
- package/dist/portal.js +16 -0
- package/dist/portal.js.map +1 -0
- package/dist/search-field.d.ts +15 -0
- package/dist/search-field.d.ts.map +1 -0
- package/dist/search-field.js +113 -0
- package/dist/search-field.js.map +1 -0
- package/dist/shared.d.ts +35 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +78 -0
- package/dist/shared.js.map +1 -0
- package/dist/site-verification.d.ts +10 -0
- package/dist/site-verification.d.ts.map +1 -0
- package/dist/site-verification.js +16 -0
- package/dist/site-verification.js.map +1 -0
- package/package.json +54 -3
package/dist/forms.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ComponentPropsWithRef, ReactNode } from 'react';
|
|
2
|
+
import type { FieldDecoration } from './shared.js';
|
|
3
|
+
import { type Option } from '@hawiyah/core';
|
|
4
|
+
export interface ButtonProps extends ComponentPropsWithRef<'button'> {
|
|
5
|
+
variant?: 'primary' | 'default' | 'secondary' | 'outline' | 'outline-white' | 'light' | 'danger' | 'ghost' | 'soft' | 'link';
|
|
6
|
+
size?: 'sm' | 'md' | 'lg';
|
|
7
|
+
loading?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function Button({ variant, size, loading, disabled, type, className, children, ...props }: ButtonProps): import("react").JSX.Element;
|
|
10
|
+
export interface TextFieldProps extends ComponentPropsWithRef<'input'>, FieldDecoration {
|
|
11
|
+
}
|
|
12
|
+
export declare function TextField({ label, hint, error, ...props }: TextFieldProps): import("react").JSX.Element;
|
|
13
|
+
export interface TextareaProps extends ComponentPropsWithRef<'textarea'>, FieldDecoration {
|
|
14
|
+
}
|
|
15
|
+
export declare function Textarea({ label, hint, error, ...props }: TextareaProps): import("react").JSX.Element;
|
|
16
|
+
export interface SelectProps extends ComponentPropsWithRef<'select'>, FieldDecoration {
|
|
17
|
+
options?: readonly Option[];
|
|
18
|
+
placeholder?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function Select({ label, hint, error, ...props }: SelectProps): import("react").JSX.Element;
|
|
21
|
+
export interface CheckboxProps extends Omit<ComponentPropsWithRef<'input'>, 'type'>, FieldDecoration {
|
|
22
|
+
indeterminate?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export declare function Checkbox(props: CheckboxProps): import("react").JSX.Element;
|
|
25
|
+
export type RadioProps = Omit<CheckboxProps, 'indeterminate'>;
|
|
26
|
+
export declare function Radio(props: RadioProps): import("react").JSX.Element;
|
|
27
|
+
export type SwitchProps = Omit<CheckboxProps, 'indeterminate'>;
|
|
28
|
+
export declare function Switch(props: SwitchProps): import("react").JSX.Element;
|
|
29
|
+
export interface FileUploadProps extends Omit<TextFieldProps, 'type' | 'value' | 'defaultValue'> {
|
|
30
|
+
onFilesChange?: (files: File[]) => void;
|
|
31
|
+
children?: ReactNode;
|
|
32
|
+
}
|
|
33
|
+
export declare function FileUpload({ label, hint, error, onFilesChange, onChange, children, className, ...props }: FileUploadProps): import("react").JSX.Element;
|
|
34
|
+
//# sourceMappingURL=forms.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forms.d.ts","sourceRoot":"","sources":["../src/forms.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAE9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAqC,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAE/E,MAAM,WAAW,WAAY,SAAQ,qBAAqB,CAAC,QAAQ,CAAC;IAClE,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,eAAe,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IAC7H,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AACD,wBAAgB,MAAM,CAAC,EAAE,OAAmB,EAAE,IAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAe,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,WAAW,+BAE1I;AACD,MAAM,WAAW,cAAe,SAAQ,qBAAqB,CAAC,OAAO,CAAC,EAAE,eAAe;CAAG;AAM1F,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,+BAGzE;AACD,MAAM,WAAW,aAAc,SAAQ,qBAAqB,CAAC,UAAU,CAAC,EAAE,eAAe;CAAG;AAM5F,wBAAgB,QAAQ,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,EAAE,aAAa,+BAGvE;AACD,MAAM,WAAW,WAAY,SAAQ,qBAAqB,CAAC,QAAQ,CAAC,EAAE,eAAe;IAAG,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE;AAO3I,wBAAgB,MAAM,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,EAAE,WAAW,+BAGnE;AACD,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,EAAE,eAAe;IAAG,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE;AAyBhI,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,+BAAmD;AAChG,MAAM,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC;AAC9D,wBAAgB,KAAK,CAAC,KAAK,EAAE,UAAU,+BAAgD;AACvF,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC;AAC/D,wBAAgB,MAAM,CAAC,KAAK,EAAE,WAAW,+BAAiD;AAC1F,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,GAAG,cAAc,CAAC;IAC9F,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;IACxC,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AACD,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,eAAe,+BAMzH"}
|
package/dist/forms.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Children, isValidElement, useEffect, useId, useRef } from 'react';
|
|
3
|
+
import { assignRef, cx, ControlField, Field, useFieldControl, useFieldValueRef } from './shared.js';
|
|
4
|
+
import { observeReadonlyChoice, isDisabled } from '@hawiyah/core';
|
|
5
|
+
export function Button({ variant = 'primary', size = 'md', loading, disabled, type = 'button', className, children, ...props }) {
|
|
6
|
+
return _jsx("button", { ...props, type: type, disabled: disabled || loading, "aria-busy": loading || props['aria-busy'], className: cx('hw-button', className), "data-variant": variant, "data-size": size, children: children });
|
|
7
|
+
}
|
|
8
|
+
function InputControl(props) {
|
|
9
|
+
const field = useFieldControl(props);
|
|
10
|
+
const ref = useFieldValueRef(props.ref);
|
|
11
|
+
return _jsx("input", { ...props, ...field, ref: ref, className: cx('hw-input', props.className) });
|
|
12
|
+
}
|
|
13
|
+
export function TextField({ label, hint, error, ...props }) {
|
|
14
|
+
if (label == null && hint == null && error == null)
|
|
15
|
+
return _jsx(InputControl, { ...props });
|
|
16
|
+
return _jsx(ControlField, { label: label, hint: hint, error: error, required: props.required, controlId: props.id, children: _jsx(InputControl, { ...props }) });
|
|
17
|
+
}
|
|
18
|
+
function TextareaControl(props) {
|
|
19
|
+
const field = useFieldControl(props);
|
|
20
|
+
const ref = useFieldValueRef(props.ref);
|
|
21
|
+
return _jsx("textarea", { ...props, ...field, ref: ref, className: cx('hw-textarea', props.className) });
|
|
22
|
+
}
|
|
23
|
+
export function Textarea({ label, hint, error, ...props }) {
|
|
24
|
+
if (label == null && hint == null && error == null)
|
|
25
|
+
return _jsx(TextareaControl, { ...props });
|
|
26
|
+
return _jsx(ControlField, { label: label, hint: hint, error: error, required: props.required, controlId: props.id, children: _jsx(TextareaControl, { ...props }) });
|
|
27
|
+
}
|
|
28
|
+
function SelectControl({ options, children, placeholder, ...props }) {
|
|
29
|
+
const field = useFieldControl(props);
|
|
30
|
+
const ref = useFieldValueRef(props.ref);
|
|
31
|
+
const hasEmptyOption = options?.some(option => option.value === '') || Children.toArray(children).some(child => isValidElement(child) && child.type === 'option' && child.props.value === '');
|
|
32
|
+
return _jsxs("select", { ...props, ...field, ref: ref, className: cx('hw-select', props.className), children: [placeholder && !props.multiple && !hasEmptyOption && _jsx("option", { value: "", children: placeholder }), options?.map(option => _jsx("option", { value: option.value, disabled: option.disabled, children: option.label }, option.value)), children] });
|
|
33
|
+
}
|
|
34
|
+
export function Select({ label, hint, error, ...props }) {
|
|
35
|
+
if (label == null && hint == null && error == null)
|
|
36
|
+
return _jsx(SelectControl, { ...props });
|
|
37
|
+
return _jsx(ControlField, { label: label, hint: hint, error: error, required: props.required, controlId: props.id, children: _jsx(SelectControl, { ...props }) });
|
|
38
|
+
}
|
|
39
|
+
function Choice({ kind, label, hint, error, className, indeterminate, ref, onClick, onKeyDown, onChange, ...props }) {
|
|
40
|
+
const field = useFieldControl(props);
|
|
41
|
+
const input = useRef(null);
|
|
42
|
+
const hintId = hint ? `${field.id}-hint` : undefined;
|
|
43
|
+
const errorId = error ? `${field.id}-error` : undefined;
|
|
44
|
+
useEffect(() => { if (input.current)
|
|
45
|
+
input.current.indeterminate = Boolean(indeterminate); }, [indeterminate]);
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
if (!input.current)
|
|
48
|
+
return;
|
|
49
|
+
const guard = observeReadonlyChoice(input.current);
|
|
50
|
+
return () => guard.destroy();
|
|
51
|
+
});
|
|
52
|
+
return _jsxs("div", { className: "hw-field", children: [_jsxs("label", { className: "hw-choice", htmlFor: field.id, children: [_jsx("input", { ...props, ...field, ref: node => { input.current = node; assignRef(ref, node); }, type: kind === 'radio' ? 'radio' : 'checkbox', role: kind === 'switch' ? 'switch' : props.role, className: cx(`hw-${kind}`, className), "aria-disabled": props.readOnly || props['aria-disabled'], "aria-invalid": error ? true : field['aria-invalid'], "aria-describedby": [field['aria-describedby'], hintId, errorId].filter(Boolean).join(' ') || undefined, onClick: event => { onClick?.(event); if (props.readOnly || isDisabled(event.currentTarget)) {
|
|
53
|
+
event.preventDefault();
|
|
54
|
+
} }, onKeyDown: event => { onKeyDown?.(event); if (props.readOnly && (event.key === ' ' || kind === 'radio' && ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(event.key)))
|
|
55
|
+
event.preventDefault(); }, onChange: event => { if (!props.readOnly && !isDisabled(event.currentTarget))
|
|
56
|
+
onChange?.(event); } }), label] }), hint && _jsx("span", { id: hintId, className: "hw-hint", children: hint }), error && _jsx("span", { id: errorId, className: "hw-error", children: error })] });
|
|
57
|
+
}
|
|
58
|
+
export function Checkbox(props) { return _jsx(Choice, { ...props, kind: "checkbox" }); }
|
|
59
|
+
export function Radio(props) { return _jsx(Choice, { ...props, kind: "radio" }); }
|
|
60
|
+
export function Switch(props) { return _jsx(Choice, { ...props, kind: "switch" }); }
|
|
61
|
+
export function FileUpload({ label, hint, error, onFilesChange, onChange, children, className, ...props }) {
|
|
62
|
+
const id = useId();
|
|
63
|
+
return _jsxs(Field, { label: label, hint: hint, error: error, required: props.required, controlId: props.id ?? id, className: "hw-upload", children: [_jsx(InputControl, { ...props, className: className, type: "file", onChange: event => { onChange?.(event); onFilesChange?.(Array.from(event.currentTarget.files ?? [])); } }), children] });
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=forms.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forms.js","sourceRoot":"","sources":["../src/forms.tsx"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Native React components. Import @hawiyah/styles/styles.css once in the application. */
|
|
2
|
+
export { Field } from './shared.js';
|
|
3
|
+
export type { FieldProps, FieldDecoration } from './shared.js';
|
|
4
|
+
export * from './forms.js';
|
|
5
|
+
export * from './interactive.js';
|
|
6
|
+
export * from './display.js';
|
|
7
|
+
export type { Direction, Orientation, Option } from '@hawiyah/core';
|
|
8
|
+
export * from './expanded-controls.js';
|
|
9
|
+
export * from './calendar.js';
|
|
10
|
+
export * from './expanded-interactive.js';
|
|
11
|
+
export * from './expanded-content.js';
|
|
12
|
+
export * from './expanded-layout.js';
|
|
13
|
+
export * from './portal.js';
|
|
14
|
+
export type { CalendarSystem } from '@hawiyah/core';
|
|
15
|
+
export * from './mobile-top-bar.js';
|
|
16
|
+
export * from './navigation-drawer.js';
|
|
17
|
+
export * from './site-verification.js';
|
|
18
|
+
export * from './content-navigation.js';
|
|
19
|
+
export * from './file-upload-list.js';
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC/D,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACpE,cAAc,wBAAwB,CAAC;AACvC,cAAc,eAAe,CAAC;AAC9B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,aAAa,CAAC;AAC5B,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC;AAEvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AAExC,cAAc,uBAAuB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Native React components. Import @hawiyah/styles/styles.css once in the application. */
|
|
2
|
+
export { Field } from './shared.js';
|
|
3
|
+
export * from './forms.js';
|
|
4
|
+
export * from './interactive.js';
|
|
5
|
+
export * from './display.js';
|
|
6
|
+
export * from './expanded-controls.js';
|
|
7
|
+
export * from './calendar.js';
|
|
8
|
+
export * from './expanded-interactive.js';
|
|
9
|
+
export * from './expanded-content.js';
|
|
10
|
+
export * from './expanded-layout.js';
|
|
11
|
+
export * from './portal.js';
|
|
12
|
+
export * from './mobile-top-bar.js';
|
|
13
|
+
export * from './navigation-drawer.js';
|
|
14
|
+
export * from './site-verification.js';
|
|
15
|
+
export * from './content-navigation.js';
|
|
16
|
+
export * from './file-upload-list.js';
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAE7B,cAAc,wBAAwB,CAAC;AACvC,cAAc,eAAe,CAAC;AAC9B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,aAAa,CAAC;AAE5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC;AAEvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AAExC,cAAc,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { ButtonHTMLAttributes, ComponentPropsWithRef, HTMLAttributes, ReactElement, ReactNode } from 'react';
|
|
2
|
+
import type { Option, Orientation } from '@hawiyah/core';
|
|
3
|
+
import type { FieldDecoration } from './shared.js';
|
|
4
|
+
export interface TabItem {
|
|
5
|
+
value: string;
|
|
6
|
+
label: ReactNode;
|
|
7
|
+
content: ReactNode;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface TabsProps extends Omit<ComponentPropsWithRef<'div'>, 'defaultValue' | 'onChange'> {
|
|
11
|
+
items: readonly TabItem[];
|
|
12
|
+
value?: string;
|
|
13
|
+
defaultValue?: string;
|
|
14
|
+
onValueChange?: (value: string) => void;
|
|
15
|
+
label: string;
|
|
16
|
+
orientation?: Orientation;
|
|
17
|
+
activationMode?: 'automatic' | 'manual';
|
|
18
|
+
overflow?: 'menu' | 'scroll';
|
|
19
|
+
overflowLabel?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function Tabs({ items, value, defaultValue, onValueChange, label, orientation, activationMode, overflow, overflowLabel, className, ...props }: TabsProps): import("react").JSX.Element;
|
|
22
|
+
export interface DialogProps extends Omit<ComponentPropsWithRef<'dialog'>, 'open' | 'children' | 'title'> {
|
|
23
|
+
open?: boolean;
|
|
24
|
+
defaultOpen?: boolean;
|
|
25
|
+
onOpenChange?: (open: boolean) => void;
|
|
26
|
+
title: ReactNode;
|
|
27
|
+
description?: ReactNode;
|
|
28
|
+
trigger?: ReactElement<ButtonHTMLAttributes<HTMLButtonElement>>;
|
|
29
|
+
children?: ReactNode | ((context: {
|
|
30
|
+
close: () => void;
|
|
31
|
+
}) => ReactNode);
|
|
32
|
+
footer?: ReactNode | ((context: {
|
|
33
|
+
close: () => void;
|
|
34
|
+
}) => ReactNode);
|
|
35
|
+
closeOnBackdrop?: boolean;
|
|
36
|
+
closeLabel?: string;
|
|
37
|
+
}
|
|
38
|
+
export declare function Dialog({ open: controlled, defaultOpen, onOpenChange, title, description, trigger, children, footer, closeOnBackdrop, closeLabel, ref, className, onCancel, onClose, onClick, onPointerDown, onPointerCancel, ...props }: DialogProps): import("react").JSX.Element;
|
|
39
|
+
export interface ComboboxProps extends Omit<ComponentPropsWithRef<'input'>, 'value' | 'defaultValue' | 'onChange' | 'type' | 'children'>, FieldDecoration {
|
|
40
|
+
options: readonly Option[];
|
|
41
|
+
value?: string;
|
|
42
|
+
defaultValue?: string;
|
|
43
|
+
onValueChange?: (value: string, option?: Option) => void;
|
|
44
|
+
onInputChange?: (query: string) => void;
|
|
45
|
+
open?: boolean;
|
|
46
|
+
defaultOpen?: boolean;
|
|
47
|
+
onOpenChange?: (open: boolean) => void;
|
|
48
|
+
emptyMessage?: string;
|
|
49
|
+
getResultsMessage?: (count: number) => string;
|
|
50
|
+
requiredMessage?: string;
|
|
51
|
+
}
|
|
52
|
+
export declare function Combobox({ label, hint, error, ...props }: ComboboxProps): import("react").JSX.Element;
|
|
53
|
+
export interface TooltipProps extends Omit<ComponentPropsWithRef<'span'>, 'children' | 'content'> {
|
|
54
|
+
children: ReactElement<HTMLAttributes<HTMLElement>>;
|
|
55
|
+
content: string;
|
|
56
|
+
placement?: 'top' | 'bottom' | 'start' | 'end';
|
|
57
|
+
align?: 'start' | 'center' | 'end';
|
|
58
|
+
}
|
|
59
|
+
export declare function Tooltip({ children, content, placement, align, className, ref, onMouseEnter, onMouseLeave, onFocus, onBlur, onKeyDown, ...props }: TooltipProps): import("react").JSX.Element;
|
|
60
|
+
//# sourceMappingURL=interactive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../src/interactive.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { cloneElement, useEffect, useId, useRef, useState } from 'react';
|
|
3
|
+
import { createComboboxState, getComboboxOptions, getDirection, getNextEnabledIndex, isDisabled, observeTabOverflow, transitionCombobox } from '@hawiyah/core';
|
|
4
|
+
import { assignRef, cx, Field, useControllable, useFieldControl, useFieldValueRef } from './shared.js';
|
|
5
|
+
import { Button } from './forms.js';
|
|
6
|
+
export function Tabs({ items, value, defaultValue, onValueChange, label, orientation = 'horizontal', activationMode = 'automatic', overflow = 'menu', overflowLabel = 'المزيد من التبويبات', className, ...props }) {
|
|
7
|
+
const id = useId();
|
|
8
|
+
const [selected, select] = useControllable(value, defaultValue ?? items.find(item => !item.disabled)?.value ?? '', onValueChange);
|
|
9
|
+
const [focused, setFocused] = useState();
|
|
10
|
+
const buttons = useRef(new Map());
|
|
11
|
+
const bar = useRef(null);
|
|
12
|
+
const disclosure = useRef(null);
|
|
13
|
+
const [hidden, setHidden] = useState([]);
|
|
14
|
+
const observer = useRef(undefined);
|
|
15
|
+
const latest = useRef({ items, overflow, orientation });
|
|
16
|
+
latest.current = { items, overflow, orientation };
|
|
17
|
+
const pendingFocus = useRef(undefined);
|
|
18
|
+
const active = items.find(item => item.value === selected && !item.disabled)?.value ?? items.find(item => !item.disabled)?.value;
|
|
19
|
+
const visible = items.filter((item, index) => !hidden.includes(index) && !item.disabled);
|
|
20
|
+
const focusValue = visible.find(item => item.value === focused)?.value ?? visible.find(item => item.value === active)?.value ?? visible[0]?.value;
|
|
21
|
+
const close = () => { if (disclosure.current)
|
|
22
|
+
disclosure.current.open = false; };
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
const node = bar.current;
|
|
25
|
+
if (!node)
|
|
26
|
+
return;
|
|
27
|
+
observer.current = observeTabOverflow({ container: node,
|
|
28
|
+
tabs: () => latest.current.items.map(item => buttons.current.get(item.value)).filter(Boolean),
|
|
29
|
+
enabled: () => latest.current.overflow === 'menu' && latest.current.orientation === 'horizontal',
|
|
30
|
+
onChange: next => {
|
|
31
|
+
const focusedElement = node.ownerDocument.activeElement;
|
|
32
|
+
const menuValue = focusedElement?.dataset.hwOverflowValue;
|
|
33
|
+
const itemIndex = latest.current.items.findIndex(item => item.value === menuValue);
|
|
34
|
+
if (menuValue !== undefined && itemIndex >= 0 && next.includes(itemIndex))
|
|
35
|
+
pendingFocus.current = { kind: 'menu', value: menuValue };
|
|
36
|
+
else {
|
|
37
|
+
if (menuValue !== undefined && itemIndex >= 0)
|
|
38
|
+
pendingFocus.current = { kind: 'tab', value: menuValue };
|
|
39
|
+
else if (next.some(index => buttons.current.get(latest.current.items[index]?.value ?? '') === focusedElement))
|
|
40
|
+
pendingFocus.current = { kind: 'summary' };
|
|
41
|
+
else if (disclosure.current?.contains(focusedElement))
|
|
42
|
+
pendingFocus.current = { kind: next.length ? 'summary' : 'tab' };
|
|
43
|
+
close();
|
|
44
|
+
}
|
|
45
|
+
setHidden(next);
|
|
46
|
+
} });
|
|
47
|
+
const outside = (event) => { if (!node.contains(event.target))
|
|
48
|
+
close(); };
|
|
49
|
+
node.ownerDocument.addEventListener('click', outside);
|
|
50
|
+
return () => { observer.current?.destroy(); node.ownerDocument.removeEventListener('click', outside); };
|
|
51
|
+
}, []);
|
|
52
|
+
useEffect(() => { observer.current?.refresh(); const focusedElement = bar.current?.ownerDocument.activeElement; if (focusedElement?.getAttribute('data-hw-overflow-hidden') === 'true' && bar.current?.contains(focusedElement))
|
|
53
|
+
disclosure.current?.querySelector('summary')?.focus(); }, [items, overflow, orientation]);
|
|
54
|
+
useEffect(() => { close(); }, [active]);
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
const destination = pendingFocus.current;
|
|
57
|
+
pendingFocus.current = undefined;
|
|
58
|
+
if (destination?.kind === 'summary')
|
|
59
|
+
disclosure.current?.querySelector('summary')?.focus();
|
|
60
|
+
else if (destination?.kind === 'tab' && (destination.value ?? focusValue))
|
|
61
|
+
buttons.current.get(destination.value ?? focusValue)?.focus();
|
|
62
|
+
else if (destination?.kind === 'menu')
|
|
63
|
+
[...(disclosure.current?.querySelectorAll('[data-hw-overflow-value]') ?? [])].find(button => button.dataset.hwOverflowValue === destination.value)?.focus();
|
|
64
|
+
}, [hidden, focusValue]);
|
|
65
|
+
return _jsxs("div", { ...props, className: cx('hw-tabs', className), children: [_jsxs("div", { className: "hw-tab-bar", ref: bar, "data-hw-overflow": overflow, "data-orientation": orientation, children: [_jsx("div", { className: "hw-tab-list", "data-hw-overflow": overflow, role: "tablist", "aria-label": label, "aria-orientation": orientation, "aria-hidden": hidden.length === items.length || undefined, children: items.map((item, index) => _jsx("button", { type: "button", role: "tab", className: "hw-tab", id: `${id}-tab-${index}`, "aria-controls": `${id}-panel-${index}`, "aria-selected": active === item.value, "aria-hidden": hidden.includes(index) || undefined, "data-hw-overflow-hidden": hidden.includes(index) || undefined, tabIndex: !hidden.includes(index) && focusValue === item.value ? 0 : -1, disabled: item.disabled, ref: node => { if (node)
|
|
66
|
+
buttons.current.set(item.value, node);
|
|
67
|
+
else
|
|
68
|
+
buttons.current.delete(item.value); }, onFocus: () => setFocused(item.value), onClick: () => { if (!item.disabled)
|
|
69
|
+
select(item.value); }, onKeyDown: event => {
|
|
70
|
+
if (event.altKey || event.ctrlKey || event.metaKey || event.nativeEvent.isComposing)
|
|
71
|
+
return;
|
|
72
|
+
const keys = orientation === 'vertical' ? ['ArrowDown', 'ArrowUp', 'Home', 'End'] : ['ArrowRight', 'ArrowLeft', 'Home', 'End'];
|
|
73
|
+
if (!keys.includes(event.key))
|
|
74
|
+
return;
|
|
75
|
+
event.preventDefault();
|
|
76
|
+
const next = items[getNextEnabledIndex(index, event.key, items.map((candidate, i) => ({ disabled: candidate.disabled || hidden.includes(i) })), getDirection(event.currentTarget), orientation)];
|
|
77
|
+
if (!next)
|
|
78
|
+
return;
|
|
79
|
+
setFocused(next.value);
|
|
80
|
+
buttons.current.get(next.value)?.focus();
|
|
81
|
+
if (activationMode === 'automatic')
|
|
82
|
+
select(next.value);
|
|
83
|
+
}, children: item.label }, item.value)) }), _jsxs("details", { ref: disclosure, className: "hw-tabs-overflow", hidden: !hidden.length, onKeyDown: event => { if (event.key === 'Escape' && event.currentTarget.open) {
|
|
84
|
+
event.preventDefault();
|
|
85
|
+
close();
|
|
86
|
+
event.currentTarget.querySelector('summary')?.focus();
|
|
87
|
+
} }, children: [_jsx("summary", { className: "hw-tab-overflow-trigger", "aria-label": overflowLabel, "data-active": hidden.some(index => items[index]?.value === active) || undefined, children: "\u2026" }), _jsx("div", { className: "hw-tab-overflow-menu", children: hidden.map(index => { const item = items[index]; return item && _jsx("button", { type: "button", className: "hw-tab-overflow-item", "data-hw-overflow-value": item.value, disabled: item.disabled, "aria-pressed": item.value === active, onClick: () => { if (item.disabled)
|
|
88
|
+
return; select(item.value); close(); disclosure.current?.querySelector('summary')?.focus(); }, children: item.label }, item.value); }) })] })] }), items.map((item, index) => _jsx("section", { className: "hw-tab-panel", id: `${id}-panel-${index}`, role: "tabpanel", "aria-labelledby": `${id}-tab-${index}`, tabIndex: 0, hidden: active !== item.value, children: item.content }, item.value))] });
|
|
89
|
+
}
|
|
90
|
+
export function Dialog({ open: controlled, defaultOpen = false, onOpenChange, title, description, trigger, children, footer, closeOnBackdrop = true, closeLabel = 'Close', ref, className, onCancel, onClose, onClick, onPointerDown, onPointerCancel, ...props }) {
|
|
91
|
+
const id = useId();
|
|
92
|
+
const [open, setOpen] = useControllable(controlled, defaultOpen, onOpenChange);
|
|
93
|
+
const [nativeCloseVersion, setNativeCloseVersion] = useState(0);
|
|
94
|
+
const dialog = useRef(null);
|
|
95
|
+
const previousFocus = useRef(null);
|
|
96
|
+
const backdropStarted = useRef(false);
|
|
97
|
+
const close = () => { backdropStarted.current = false; setOpen(false); };
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
const node = dialog.current;
|
|
100
|
+
if (!node)
|
|
101
|
+
return;
|
|
102
|
+
if (open && !node.open) {
|
|
103
|
+
backdropStarted.current = false;
|
|
104
|
+
previousFocus.current = node.ownerDocument.activeElement;
|
|
105
|
+
node.showModal();
|
|
106
|
+
}
|
|
107
|
+
else if (!open && node.open) {
|
|
108
|
+
backdropStarted.current = false;
|
|
109
|
+
node.close();
|
|
110
|
+
if (previousFocus.current?.isConnected)
|
|
111
|
+
previousFocus.current.focus();
|
|
112
|
+
}
|
|
113
|
+
}, [open, nativeCloseVersion]);
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
const node = dialog.current;
|
|
116
|
+
return () => {
|
|
117
|
+
if (node?.open) {
|
|
118
|
+
node.close();
|
|
119
|
+
if (previousFocus.current?.isConnected)
|
|
120
|
+
previousFocus.current.focus();
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}, []);
|
|
124
|
+
const context = { close };
|
|
125
|
+
return _jsxs(_Fragment, { children: [trigger && cloneElement(trigger, { onClick: event => { trigger.props.onClick?.(event); if (!event.defaultPrevented)
|
|
126
|
+
setOpen(true); }, 'aria-haspopup': 'dialog' }), _jsxs("dialog", { ...props, ref: node => { dialog.current = node; assignRef(ref, node); }, className: cx('hw-dialog', className), "aria-labelledby": props['aria-labelledby'] ?? `${id}-title`, "aria-describedby": props['aria-describedby'] ?? (description ? `${id}-description` : undefined), onCancel: event => { backdropStarted.current = false; onCancel?.(event); if (!event.defaultPrevented) {
|
|
127
|
+
event.preventDefault();
|
|
128
|
+
close();
|
|
129
|
+
} }, onClose: event => {
|
|
130
|
+
backdropStarted.current = false;
|
|
131
|
+
onClose?.(event);
|
|
132
|
+
if (open && !event.currentTarget.open) {
|
|
133
|
+
close();
|
|
134
|
+
if (controlled !== undefined)
|
|
135
|
+
setNativeCloseVersion(version => version + 1);
|
|
136
|
+
}
|
|
137
|
+
}, onPointerDown: event => {
|
|
138
|
+
onPointerDown?.(event);
|
|
139
|
+
const bounds = event.currentTarget.getBoundingClientRect();
|
|
140
|
+
backdropStarted.current = !event.defaultPrevented && event.button === 0 && event.target === event.currentTarget &&
|
|
141
|
+
(event.clientX < bounds.left || event.clientX > bounds.right || event.clientY < bounds.top || event.clientY > bounds.bottom);
|
|
142
|
+
}, onPointerCancel: event => { backdropStarted.current = false; onPointerCancel?.(event); }, onClick: event => {
|
|
143
|
+
const started = backdropStarted.current;
|
|
144
|
+
backdropStarted.current = false;
|
|
145
|
+
onClick?.(event);
|
|
146
|
+
if (event.defaultPrevented || !closeOnBackdrop || !started || event.target !== event.currentTarget)
|
|
147
|
+
return;
|
|
148
|
+
const bounds = event.currentTarget.getBoundingClientRect();
|
|
149
|
+
if (event.clientX < bounds.left || event.clientX > bounds.right || event.clientY < bounds.top || event.clientY > bounds.bottom)
|
|
150
|
+
close();
|
|
151
|
+
}, children: [_jsxs("header", { className: "hw-dialog-header", children: [_jsx("h2", { id: `${id}-title`, children: title }), _jsx(Button, { variant: "ghost", "aria-label": closeLabel, onClick: close, children: "\u00D7" })] }), _jsxs("div", { className: "hw-dialog-body", children: [description && _jsx("p", { id: `${id}-description`, children: description }), typeof children === 'function' ? children(context) : children] }), footer && _jsx("footer", { className: "hw-dialog-footer", children: typeof footer === 'function' ? footer(context) : footer })] })] });
|
|
152
|
+
}
|
|
153
|
+
function ComboboxControl({ options, value, defaultValue = '', onValueChange, onInputChange, open: controlledOpen, defaultOpen = false, onOpenChange, emptyMessage = 'No options found', getResultsMessage = count => `${count} results available`, requiredMessage = 'Choose an option from the list.', className, ref, onKeyDown, onFocus, onBlur, onClick, name, form, disabled, ...props }) {
|
|
154
|
+
const field = useFieldControl(props);
|
|
155
|
+
const [state, setState] = useState(() => ({ ...createComboboxState(options, value ?? defaultValue), open: controlledOpen ?? defaultOpen }));
|
|
156
|
+
const input = useRef(null);
|
|
157
|
+
const presenceRef = useFieldValueRef((node) => { input.current = node; assignRef(ref, node); });
|
|
158
|
+
const [ancestorDisabled, setAncestorDisabled] = useState(false);
|
|
159
|
+
const blocked = () => disabled || props.readOnly || !!(input.current && isDisabled(input.current));
|
|
160
|
+
const requestedValue = value ?? state.value;
|
|
161
|
+
const selected = options.some(option => option.value === requestedValue && !option.disabled) ? requestedValue : '';
|
|
162
|
+
const open = !disabled && !ancestorDisabled && !props.readOnly && (controlledOpen ?? state.open);
|
|
163
|
+
const query = value !== undefined && state.value && state.value !== selected ? options.find(option => option.value === selected)?.label ?? '' : state.query;
|
|
164
|
+
const effectiveState = { ...state, value: selected, query, open };
|
|
165
|
+
const results = getComboboxOptions(effectiveState, options);
|
|
166
|
+
const active = results[state.activeIndex];
|
|
167
|
+
const listId = `${field.id}-listbox`;
|
|
168
|
+
const statusId = `${field.id}-status`;
|
|
169
|
+
const lastEmittedValue = useRef(undefined);
|
|
170
|
+
const latestOptions = useRef(options);
|
|
171
|
+
const previousOptions = useRef(options);
|
|
172
|
+
latestOptions.current = options;
|
|
173
|
+
useEffect(() => {
|
|
174
|
+
const element = input.current;
|
|
175
|
+
if (!element)
|
|
176
|
+
return;
|
|
177
|
+
const refresh = () => setAncestorDisabled(isDisabled(element));
|
|
178
|
+
const Observer = element.ownerDocument.defaultView?.MutationObserver;
|
|
179
|
+
const observer = Observer ? new Observer(refresh) : undefined;
|
|
180
|
+
for (let ancestor = element.parentElement; ancestor; ancestor = ancestor.parentElement) {
|
|
181
|
+
if (ancestor.localName === 'fieldset')
|
|
182
|
+
observer?.observe(ancestor, { attributes: true, attributeFilter: ['disabled'] });
|
|
183
|
+
}
|
|
184
|
+
refresh();
|
|
185
|
+
return () => observer?.disconnect();
|
|
186
|
+
}, []);
|
|
187
|
+
useEffect(() => {
|
|
188
|
+
if (disabled || ancestorDisabled || props.readOnly)
|
|
189
|
+
setState(current => ({ ...current, open: false, activeIndex: -1 }));
|
|
190
|
+
}, [disabled, ancestorDisabled, props.readOnly]);
|
|
191
|
+
useEffect(() => {
|
|
192
|
+
if (value === undefined)
|
|
193
|
+
return;
|
|
194
|
+
if (value === lastEmittedValue.current) {
|
|
195
|
+
lastEmittedValue.current = undefined;
|
|
196
|
+
setState(current => ({ ...current, value }));
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
setState(current => ({ ...createComboboxState(latestOptions.current, value), open: current.open }));
|
|
200
|
+
}
|
|
201
|
+
}, [value]);
|
|
202
|
+
useEffect(() => {
|
|
203
|
+
const previousLabel = previousOptions.current.find(option => option.value === selected)?.label;
|
|
204
|
+
const nextLabel = options.find(option => option.value === selected)?.label;
|
|
205
|
+
previousOptions.current = options;
|
|
206
|
+
if (!selected || nextLabel === undefined || previousLabel === nextLabel)
|
|
207
|
+
return;
|
|
208
|
+
setState(current => current.value === selected && current.query === previousLabel
|
|
209
|
+
? { ...current, query: nextLabel, activeIndex: -1 } : current);
|
|
210
|
+
}, [options, selected]);
|
|
211
|
+
useEffect(() => {
|
|
212
|
+
input.current?.setCustomValidity(field.required && !selected ? requiredMessage : '');
|
|
213
|
+
}, [field.required, selected, requiredMessage]);
|
|
214
|
+
useEffect(() => {
|
|
215
|
+
const formElement = input.current?.form;
|
|
216
|
+
let mounted = true;
|
|
217
|
+
const reset = (event) => {
|
|
218
|
+
queueMicrotask(() => {
|
|
219
|
+
if (mounted && !event.defaultPrevented && value === undefined)
|
|
220
|
+
setState(createComboboxState(latestOptions.current, defaultValue));
|
|
221
|
+
});
|
|
222
|
+
};
|
|
223
|
+
formElement?.addEventListener('reset', reset);
|
|
224
|
+
return () => { mounted = false; formElement?.removeEventListener('reset', reset); };
|
|
225
|
+
}, [value, defaultValue, form]);
|
|
226
|
+
useEffect(() => {
|
|
227
|
+
if (open && state.activeIndex >= 0)
|
|
228
|
+
input.current?.ownerDocument.getElementById(`${field.id}-option-${state.activeIndex}`)?.scrollIntoView?.({ block: 'nearest' });
|
|
229
|
+
}, [open, state.activeIndex, field.id]);
|
|
230
|
+
function dispatch(event) {
|
|
231
|
+
if (blocked() && event.type !== 'close' && event.type !== 'reset')
|
|
232
|
+
return;
|
|
233
|
+
const next = transitionCombobox(effectiveState, event, options);
|
|
234
|
+
setState(next);
|
|
235
|
+
if (next.value !== selected) {
|
|
236
|
+
lastEmittedValue.current = next.value;
|
|
237
|
+
onValueChange?.(next.value, options.find(option => option.value === next.value));
|
|
238
|
+
}
|
|
239
|
+
if (next.open !== open)
|
|
240
|
+
onOpenChange?.(next.open);
|
|
241
|
+
}
|
|
242
|
+
return _jsxs("div", { className: "hw-combobox", onBlur: event => { if (!event.currentTarget.contains(event.relatedTarget))
|
|
243
|
+
dispatch({ type: 'close' }); }, children: [_jsx("input", { ...props, ...field, ref: presenceRef, form: form, disabled: disabled, className: cx('hw-input', className), type: "text", role: "combobox", autoComplete: "off", "aria-autocomplete": "list", "aria-readonly": props.readOnly || undefined, "aria-expanded": open, "aria-controls": listId, "aria-activedescendant": open && active && !active.disabled ? `${field.id}-option-${state.activeIndex}` : undefined, value: query, onChange: event => { if (blocked()) {
|
|
244
|
+
event.currentTarget.value = query;
|
|
245
|
+
return;
|
|
246
|
+
} dispatch({ type: 'input', query: event.currentTarget.value }); onInputChange?.(event.currentTarget.value); }, onFocus: event => { onFocus?.(event); if (!event.defaultPrevented)
|
|
247
|
+
dispatch({ type: 'open' }); }, onBlur: onBlur, onClick: event => { onClick?.(event); if (!event.defaultPrevented && !open)
|
|
248
|
+
dispatch({ type: 'open' }); }, onKeyDown: event => {
|
|
249
|
+
onKeyDown?.(event);
|
|
250
|
+
if (event.defaultPrevented || event.nativeEvent.isComposing || blocked())
|
|
251
|
+
return;
|
|
252
|
+
if (['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(event.key)) {
|
|
253
|
+
if (!open && (event.key === 'Home' || event.key === 'End'))
|
|
254
|
+
return;
|
|
255
|
+
event.preventDefault();
|
|
256
|
+
dispatch({ type: 'navigate', key: event.key });
|
|
257
|
+
}
|
|
258
|
+
else if (event.key === 'Enter' && open && active && !active.disabled) {
|
|
259
|
+
event.preventDefault();
|
|
260
|
+
dispatch({ type: 'select', value: active.value });
|
|
261
|
+
}
|
|
262
|
+
else if (event.key === 'Escape' && open) {
|
|
263
|
+
event.preventDefault();
|
|
264
|
+
event.stopPropagation();
|
|
265
|
+
dispatch({ type: 'close' });
|
|
266
|
+
}
|
|
267
|
+
else if (event.key === 'Tab')
|
|
268
|
+
dispatch({ type: 'close' });
|
|
269
|
+
} }), _jsx("input", { type: "hidden", name: name, form: form, value: selected, disabled: disabled }), _jsxs("ul", { className: "hw-listbox", id: listId, role: "listbox", "aria-label": props['aria-label'], "aria-labelledby": field['aria-labelledby'], hidden: !open, children: [results.map((option, index) => _jsx("li", { id: `${field.id}-option-${index}`, className: "hw-option", role: "option", "aria-selected": selected === option.value, "aria-disabled": option.disabled || undefined, "data-active": state.activeIndex === index ? 'true' : undefined, "data-state": state.activeIndex === index ? 'active' : undefined, onPointerDown: event => event.preventDefault(), onClick: () => { if (!option.disabled) {
|
|
270
|
+
dispatch({ type: 'select', value: option.value });
|
|
271
|
+
input.current?.focus();
|
|
272
|
+
} }, children: option.label }, option.value)), !results.length && _jsx("li", { role: "presentation", className: "hw-hint", children: emptyMessage })] }), _jsx("span", { id: statusId, className: "hw-sr-only", role: "status", "aria-live": "polite", "aria-atomic": "true", children: open ? getResultsMessage(results.length) : '' })] });
|
|
273
|
+
}
|
|
274
|
+
export function Combobox({ label, hint, error, ...props }) {
|
|
275
|
+
const id = useId();
|
|
276
|
+
if (label == null && hint == null && error == null)
|
|
277
|
+
return _jsx(ComboboxControl, { ...props });
|
|
278
|
+
return _jsx(Field, { label: label, hint: hint, error: error, required: props.required, controlId: props.id ?? id, children: _jsx(ComboboxControl, { ...props }) });
|
|
279
|
+
}
|
|
280
|
+
export function Tooltip({ children, content, placement = 'top', align = 'start', className, ref, onMouseEnter, onMouseLeave, onFocus, onBlur, onKeyDown, ...props }) {
|
|
281
|
+
const id = useId();
|
|
282
|
+
const root = useRef(null);
|
|
283
|
+
const [open, setOpen] = useState(false);
|
|
284
|
+
const hovered = useRef(false);
|
|
285
|
+
const focused = useRef(false);
|
|
286
|
+
const hideTimer = useRef(undefined);
|
|
287
|
+
const show = () => { clearTimeout(hideTimer.current); setOpen(true); };
|
|
288
|
+
const hideAfterPointerTravel = () => {
|
|
289
|
+
clearTimeout(hideTimer.current);
|
|
290
|
+
if (!hovered.current && !focused.current)
|
|
291
|
+
hideTimer.current = setTimeout(() => setOpen(false), 120);
|
|
292
|
+
};
|
|
293
|
+
useEffect(() => () => clearTimeout(hideTimer.current), []);
|
|
294
|
+
useEffect(() => {
|
|
295
|
+
const doc = root.current?.ownerDocument;
|
|
296
|
+
if (!open || !doc)
|
|
297
|
+
return;
|
|
298
|
+
const escape = (event) => {
|
|
299
|
+
if (event.key !== 'Escape' || event.defaultPrevented)
|
|
300
|
+
return;
|
|
301
|
+
event.preventDefault();
|
|
302
|
+
event.stopPropagation();
|
|
303
|
+
clearTimeout(hideTimer.current);
|
|
304
|
+
setOpen(false);
|
|
305
|
+
};
|
|
306
|
+
doc.addEventListener('keydown', escape);
|
|
307
|
+
return () => doc.removeEventListener('keydown', escape);
|
|
308
|
+
}, [open]);
|
|
309
|
+
return _jsxs("span", { ...props, "data-hw": "tooltip", className: className, ref: node => { root.current = node; assignRef(ref, node); }, onMouseEnter: event => { onMouseEnter?.(event); hovered.current = true; if (!event.defaultPrevented)
|
|
310
|
+
show(); }, onMouseLeave: event => { onMouseLeave?.(event); hovered.current = false; hideAfterPointerTravel(); }, onFocus: event => { onFocus?.(event); focused.current = true; if (!event.defaultPrevented)
|
|
311
|
+
show(); }, onBlur: event => { onBlur?.(event); if (!event.currentTarget.contains(event.relatedTarget)) {
|
|
312
|
+
focused.current = false;
|
|
313
|
+
hideAfterPointerTravel();
|
|
314
|
+
} }, onKeyDown: event => { onKeyDown?.(event); if (event.key === 'Escape' && open && !event.defaultPrevented) {
|
|
315
|
+
event.preventDefault();
|
|
316
|
+
event.stopPropagation();
|
|
317
|
+
clearTimeout(hideTimer.current);
|
|
318
|
+
setOpen(false);
|
|
319
|
+
} }, children: [cloneElement(children, { 'aria-describedby': [children.props['aria-describedby'], id].filter(Boolean).join(' ') }), _jsx("span", { className: "hw-tooltip", role: "tooltip", id: id, "data-placement": placement, "data-align": align, hidden: !open, children: content })] });
|
|
320
|
+
}
|
|
321
|
+
//# sourceMappingURL=interactive.js.map
|