@accelint/design-toolkit 9.2.0 → 9.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -22
- package/catalog-info.yaml +4 -4
- package/dist/components/accordion/group.d.ts +2 -2
- package/dist/components/accordion/header.d.ts +2 -2
- package/dist/components/accordion/index.d.ts +2 -2
- package/dist/components/accordion/panel.d.ts +2 -2
- package/dist/components/accordion/trigger.d.ts +2 -2
- package/dist/components/action-bar/index.d.ts +10 -2
- package/dist/components/action-bar/index.js +8 -1
- package/dist/components/action-bar/index.js.map +1 -1
- package/dist/components/action-bar/styles.module.css +9 -1
- package/dist/components/action-bar/types.d.ts +1 -0
- package/dist/components/avatar/context.d.ts +4 -4
- package/dist/components/avatar/index.d.ts +2 -2
- package/dist/components/badge/context.d.ts +4 -4
- package/dist/components/badge/index.d.ts +2 -2
- package/dist/components/breadcrumbs/index.d.ts +2 -2
- package/dist/components/breadcrumbs/item.d.ts +2 -2
- package/dist/components/button/context.d.ts +8 -8
- package/dist/components/button/index.d.ts +2 -2
- package/dist/components/button/link.d.ts +2 -2
- package/dist/components/button/toggle.d.ts +2 -2
- package/dist/components/checkbox/context.d.ts +3 -3
- package/dist/components/checkbox/group.d.ts +2 -2
- package/dist/components/checkbox/index.d.ts +2 -2
- package/dist/components/chip/context.d.ts +4 -4
- package/dist/components/chip/deletable.d.ts +2 -2
- package/dist/components/chip/index.d.ts +2 -2
- package/dist/components/chip/list.d.ts +4 -4
- package/dist/components/chip/selectable.d.ts +2 -2
- package/dist/components/classification-badge/context.d.ts +4 -4
- package/dist/components/classification-badge/index.d.ts +2 -2
- package/dist/components/classification-banner/context.d.ts +4 -4
- package/dist/components/classification-banner/index.d.ts +2 -2
- package/dist/components/clock/index.d.ts +2 -2
- package/dist/components/color-picker/index.d.ts +2 -2
- package/dist/components/combobox-field/context.d.ts +4 -4
- package/dist/components/combobox-field/index.d.ts +2 -2
- package/dist/components/combobox-field/index.js +44 -37
- package/dist/components/combobox-field/index.js.map +1 -1
- package/dist/components/combobox-field/styles.module.css +5 -1
- package/dist/components/coordinate-field/context.d.ts +6 -6
- package/dist/components/coordinate-field/index.d.ts +2 -2
- package/dist/components/coordinate-field/index.js +3 -1
- package/dist/components/coordinate-field/index.js.map +1 -1
- package/dist/components/coordinate-field/segment.d.ts +3 -2
- package/dist/components/coordinate-field/segment.js +3 -1
- package/dist/components/coordinate-field/segment.js.map +1 -1
- package/dist/components/coordinate-field/styles.module.css +14 -0
- package/dist/components/coordinate-field/types.d.ts +2 -0
- package/dist/components/coordinate-field/types.js.map +1 -1
- package/dist/components/date-field/index.d.ts +3 -2
- package/dist/components/date-field/index.js +4 -2
- package/dist/components/date-field/index.js.map +1 -1
- package/dist/components/date-field/styles.module.css +4 -0
- package/dist/components/deferred-collection/index.d.ts +43 -0
- package/dist/components/deferred-collection/index.js +44 -0
- package/dist/components/deferred-collection/index.js.map +1 -0
- package/dist/components/deferred-collection/types.d.ts +26 -0
- package/dist/components/deferred-collection/types.js +12 -0
- package/dist/components/details-list/context.d.ts +4 -4
- package/dist/components/details-list/index.d.ts +2 -2
- package/dist/components/details-list/label.d.ts +2 -2
- package/dist/components/details-list/value.d.ts +2 -2
- package/dist/components/dialog/content.d.ts +2 -2
- package/dist/components/dialog/context.d.ts +2 -2
- package/dist/components/dialog/footer.d.ts +2 -2
- package/dist/components/dialog/index.d.ts +2 -2
- package/dist/components/dialog/title.d.ts +2 -2
- package/dist/components/divider/context.d.ts +4 -4
- package/dist/components/divider/index.d.ts +2 -2
- package/dist/components/drawer/back.d.ts +2 -2
- package/dist/components/drawer/close.d.ts +2 -2
- package/dist/components/drawer/content.d.ts +2 -2
- package/dist/components/drawer/context.d.ts +2 -2
- package/dist/components/drawer/footer.d.ts +2 -2
- package/dist/components/drawer/header-title.d.ts +2 -2
- package/dist/components/drawer/header.d.ts +2 -2
- package/dist/components/drawer/index.d.ts +2 -2
- package/dist/components/drawer/layout-main.d.ts +2 -2
- package/dist/components/drawer/layout.d.ts +2 -2
- package/dist/components/drawer/menu-item.d.ts +2 -2
- package/dist/components/drawer/menu.d.ts +2 -2
- package/dist/components/drawer/panel.d.ts +2 -2
- package/dist/components/drawer/styles.module.css +2 -2
- package/dist/components/drawer/trigger.d.ts +2 -2
- package/dist/components/drawer/view.d.ts +2 -2
- package/dist/components/flashcard/index.d.ts +9 -9
- package/dist/components/hero/context.d.ts +2 -2
- package/dist/components/hero/index.d.ts +2 -2
- package/dist/components/hero/subtitle.d.ts +2 -2
- package/dist/components/hero/title.d.ts +2 -2
- package/dist/components/hotkey/context.d.ts +4 -4
- package/dist/components/hotkey/index.d.ts +2 -2
- package/dist/components/hotkey/set.d.ts +2 -2
- package/dist/components/icon/context.d.ts +4 -4
- package/dist/components/icon/index.d.ts +2 -2
- package/dist/components/input/context.d.ts +2 -2
- package/dist/components/input/index.d.ts +2 -2
- package/dist/components/input/index.js +3 -2
- package/dist/components/input/index.js.map +1 -1
- package/dist/components/input/styles.module.css +5 -1
- package/dist/components/kanban/card-body.d.ts +2 -2
- package/dist/components/kanban/card-header-actions.d.ts +2 -2
- package/dist/components/kanban/card-header-title.d.ts +2 -2
- package/dist/components/kanban/card-header.d.ts +2 -2
- package/dist/components/kanban/card.d.ts +2 -2
- package/dist/components/kanban/column-actions.d.ts +2 -2
- package/dist/components/kanban/column-container.d.ts +2 -2
- package/dist/components/kanban/column-content.d.ts +2 -2
- package/dist/components/kanban/column-header-actions.d.ts +2 -2
- package/dist/components/kanban/column-header-drag-handle.d.ts +2 -2
- package/dist/components/kanban/column-header-title.d.ts +2 -2
- package/dist/components/kanban/column-header.d.ts +2 -2
- package/dist/components/kanban/column.d.ts +2 -2
- package/dist/components/kanban/context.d.ts +2 -2
- package/dist/components/kanban/header-actions.d.ts +2 -2
- package/dist/components/kanban/header-search.d.ts +2 -2
- package/dist/components/kanban/header-title.d.ts +2 -2
- package/dist/components/kanban/header.d.ts +2 -2
- package/dist/components/kanban/kanban.d.ts +4 -4
- package/dist/components/label/context.d.ts +4 -4
- package/dist/components/label/index.d.ts +2 -2
- package/dist/components/lines/index.d.ts +2 -2
- package/dist/components/link/context.d.ts +2 -2
- package/dist/components/link/index.d.ts +2 -2
- package/dist/components/list/context.d.ts +2 -2
- package/dist/components/list/index.d.ts +2 -2
- package/dist/components/list/item-content.d.ts +2 -2
- package/dist/components/list/item-description.d.ts +2 -2
- package/dist/components/list/item-title.d.ts +2 -2
- package/dist/components/list/item.d.ts +2 -2
- package/dist/components/menu/context.d.ts +2 -2
- package/dist/components/menu/index.d.ts +2 -2
- package/dist/components/menu/item-description.d.ts +2 -2
- package/dist/components/menu/item-label.d.ts +2 -2
- package/dist/components/menu/item.d.ts +2 -2
- package/dist/components/menu/section.d.ts +2 -2
- package/dist/components/menu/separator.d.ts +2 -2
- package/dist/components/menu/styles.module.css +62 -46
- package/dist/components/menu/submenu.d.ts +2 -2
- package/dist/components/notice/index.d.ts +2 -2
- package/dist/components/notice/list.d.ts +2 -2
- package/dist/components/notice/notice-icon.d.ts +2 -2
- package/dist/components/options/context.d.ts +2 -2
- package/dist/components/options/index.d.ts +2 -2
- package/dist/components/options/item-content.d.ts +2 -2
- package/dist/components/options/item-description.d.ts +2 -2
- package/dist/components/options/item-label.d.ts +2 -2
- package/dist/components/options/item.d.ts +2 -2
- package/dist/components/options/section.d.ts +2 -2
- package/dist/components/pagination/context.d.ts +2 -2
- package/dist/components/pagination/index.d.ts +2 -2
- package/dist/components/pagination/next.d.ts +2 -2
- package/dist/components/pagination/pages.d.ts +2 -2
- package/dist/components/pagination/prev.d.ts +2 -2
- package/dist/components/popover/content.d.ts +2 -2
- package/dist/components/popover/footer.d.ts +2 -2
- package/dist/components/popover/index.d.ts +2 -2
- package/dist/components/popover/title.d.ts +2 -2
- package/dist/components/popover/trigger.d.ts +2 -2
- package/dist/components/query-builder/action-element.d.ts +2 -2
- package/dist/components/query-builder/actions.d.ts +4 -4
- package/dist/components/query-builder/combinator-selector.d.ts +2 -2
- package/dist/components/query-builder/index.d.ts +2 -2
- package/dist/components/query-builder/rule-group.d.ts +4 -4
- package/dist/components/query-builder/rule.d.ts +2 -2
- package/dist/components/query-builder/value-editor.d.ts +2 -2
- package/dist/components/query-builder/value-selector.d.ts +2 -2
- package/dist/components/radio/context.d.ts +2 -2
- package/dist/components/radio/group.d.ts +2 -2
- package/dist/components/radio/index.d.ts +2 -2
- package/dist/components/search-field/context.d.ts +4 -4
- package/dist/components/search-field/index.d.ts +2 -2
- package/dist/components/select-field/context.d.ts +4 -4
- package/dist/components/select-field/index.d.ts +2 -2
- package/dist/components/select-field/index.js +10 -4
- package/dist/components/select-field/index.js.map +1 -1
- package/dist/components/select-field/styles.module.css +4 -0
- package/dist/components/select-field/types.d.ts +1 -0
- package/dist/components/sidenav/avatar.d.ts +2 -2
- package/dist/components/sidenav/content.d.ts +2 -2
- package/dist/components/sidenav/context.d.ts +2 -2
- package/dist/components/sidenav/footer.d.ts +2 -2
- package/dist/components/sidenav/header.d.ts +2 -2
- package/dist/components/sidenav/index.d.ts +2 -2
- package/dist/components/sidenav/item.d.ts +2 -2
- package/dist/components/sidenav/link.d.ts +2 -2
- package/dist/components/sidenav/menu-item.d.ts +2 -2
- package/dist/components/sidenav/menu.d.ts +2 -2
- package/dist/components/sidenav/trigger.d.ts +2 -2
- package/dist/components/skeleton/index.d.ts +2 -2
- package/dist/components/slider/index.d.ts +2 -2
- package/dist/components/switch/context.d.ts +4 -4
- package/dist/components/switch/index.d.ts +2 -2
- package/dist/components/table/body.d.ts +2 -2
- package/dist/components/table/cell.d.ts +2 -2
- package/dist/components/table/context.d.ts +2 -2
- package/dist/components/table/header-cell.d.ts +2 -2
- package/dist/components/table/header.d.ts +2 -2
- package/dist/components/table/index.d.ts +2 -2
- package/dist/components/table/row.d.ts +2 -2
- package/dist/components/tabs/context.d.ts +4 -4
- package/dist/components/tabs/index.d.ts +2 -2
- package/dist/components/tabs/list.d.ts +2 -2
- package/dist/components/tabs/panel.d.ts +2 -2
- package/dist/components/tabs/tab.d.ts +2 -2
- package/dist/components/text-area-field/context.d.ts +4 -4
- package/dist/components/text-area-field/index.d.ts +2 -2
- package/dist/components/text-area-field/styles.module.css +4 -0
- package/dist/components/text-field/context.d.ts +4 -4
- package/dist/components/text-field/index.d.ts +2 -2
- package/dist/components/time-field/index.d.ts +3 -2
- package/dist/components/time-field/index.js +4 -2
- package/dist/components/time-field/index.js.map +1 -1
- package/dist/components/time-field/styles.module.css +5 -2
- package/dist/components/tooltip/context.d.ts +2 -2
- package/dist/components/tooltip/index.d.ts +2 -2
- package/dist/components/tooltip/trigger.d.ts +2 -2
- package/dist/components/tree/context.d.ts +3 -3
- package/dist/components/tree/index.d.ts +2 -2
- package/dist/components/tree/item-actions.d.ts +2 -2
- package/dist/components/tree/item-content.d.ts +2 -2
- package/dist/components/tree/item-description.d.ts +2 -2
- package/dist/components/tree/item-label.d.ts +2 -2
- package/dist/components/tree/item-prefix-icon.d.ts +2 -2
- package/dist/components/tree/item.d.ts +2 -2
- package/dist/components/tree/lines.d.ts +2 -2
- package/dist/components/view-stack/context.d.ts +2 -2
- package/dist/components/view-stack/index.d.ts +2 -2
- package/dist/components/view-stack/trigger.d.ts +2 -2
- package/dist/components/view-stack/view.d.ts +2 -2
- package/dist/hooks/use-frame-delay/index.d.ts +38 -0
- package/dist/hooks/use-frame-delay/index.js +61 -0
- package/dist/hooks/use-frame-delay/index.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +3 -1
- package/dist/providers/portal.d.ts +2 -2
- package/dist/providers/theme-provider.d.ts +2 -2
- package/package.json +13 -10
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { ClassificationBadgeProps } from "./types.js";
|
|
14
14
|
import "client-only";
|
|
15
|
-
import * as
|
|
15
|
+
import * as react_jsx_runtime24 from "react/jsx-runtime";
|
|
16
16
|
|
|
17
17
|
//#region src/components/classification-badge/index.d.ts
|
|
18
18
|
/**
|
|
@@ -33,7 +33,7 @@ import * as react_jsx_runtime8 from "react/jsx-runtime";
|
|
|
33
33
|
declare function ClassificationBadge({
|
|
34
34
|
ref,
|
|
35
35
|
...props
|
|
36
|
-
}: ClassificationBadgeProps):
|
|
36
|
+
}: ClassificationBadgeProps): react_jsx_runtime24.JSX.Element;
|
|
37
37
|
//#endregion
|
|
38
38
|
export { ClassificationBadge };
|
|
39
39
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -13,16 +13,16 @@
|
|
|
13
13
|
import { ProviderProps } from "../../lib/types.js";
|
|
14
14
|
import { ClassificationBannerProps } from "./types.js";
|
|
15
15
|
import "client-only";
|
|
16
|
-
import * as
|
|
16
|
+
import * as react12 from "react";
|
|
17
17
|
import { ContextValue } from "react-aria-components";
|
|
18
|
-
import * as
|
|
18
|
+
import * as react_jsx_runtime28 from "react/jsx-runtime";
|
|
19
19
|
|
|
20
20
|
//#region src/components/classification-banner/context.d.ts
|
|
21
|
-
declare const ClassificationBannerContext:
|
|
21
|
+
declare const ClassificationBannerContext: react12.Context<ContextValue<ClassificationBannerProps, HTMLDivElement>>;
|
|
22
22
|
declare function ClassificationBannerProvider({
|
|
23
23
|
children,
|
|
24
24
|
...props
|
|
25
|
-
}: ProviderProps<ClassificationBannerProps>):
|
|
25
|
+
}: ProviderProps<ClassificationBannerProps>): react_jsx_runtime28.JSX.Element;
|
|
26
26
|
//#endregion
|
|
27
27
|
export { ClassificationBannerContext, ClassificationBannerProvider };
|
|
28
28
|
//# sourceMappingURL=context.d.ts.map
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { ClassificationBannerProps } from "./types.js";
|
|
14
14
|
import "client-only";
|
|
15
|
-
import * as
|
|
15
|
+
import * as react_jsx_runtime29 from "react/jsx-runtime";
|
|
16
16
|
|
|
17
17
|
//#region src/components/classification-banner/index.d.ts
|
|
18
18
|
/**
|
|
@@ -29,7 +29,7 @@ import * as react_jsx_runtime181 from "react/jsx-runtime";
|
|
|
29
29
|
declare function ClassificationBanner({
|
|
30
30
|
ref,
|
|
31
31
|
...props
|
|
32
|
-
}: ClassificationBannerProps):
|
|
32
|
+
}: ClassificationBannerProps): react_jsx_runtime29.JSX.Element;
|
|
33
33
|
//#endregion
|
|
34
34
|
export { ClassificationBanner };
|
|
35
35
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { ClockProps } from "./types.js";
|
|
14
14
|
import "client-only";
|
|
15
|
-
import * as
|
|
15
|
+
import * as react_jsx_runtime31 from "react/jsx-runtime";
|
|
16
16
|
|
|
17
17
|
//#region src/components/clock/index.d.ts
|
|
18
18
|
|
|
@@ -48,7 +48,7 @@ import * as react_jsx_runtime164 from "react/jsx-runtime";
|
|
|
48
48
|
declare function Clock({
|
|
49
49
|
formatter,
|
|
50
50
|
...rest
|
|
51
|
-
}: ClockProps):
|
|
51
|
+
}: ClockProps): react_jsx_runtime31.JSX.Element;
|
|
52
52
|
//#endregion
|
|
53
53
|
export { Clock };
|
|
54
54
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { ColorPickerProps } from "./types.js";
|
|
14
14
|
import "client-only";
|
|
15
|
-
import * as
|
|
15
|
+
import * as react_jsx_runtime25 from "react/jsx-runtime";
|
|
16
16
|
|
|
17
17
|
//#region src/components/color-picker/index.d.ts
|
|
18
18
|
|
|
@@ -60,7 +60,7 @@ declare function ColorPicker({
|
|
|
60
60
|
classNames,
|
|
61
61
|
items,
|
|
62
62
|
...rest
|
|
63
|
-
}: ColorPickerProps):
|
|
63
|
+
}: ColorPickerProps): react_jsx_runtime25.JSX.Element;
|
|
64
64
|
//#endregion
|
|
65
65
|
export { ColorPicker };
|
|
66
66
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -14,16 +14,16 @@ import { ProviderProps } from "../../lib/types.js";
|
|
|
14
14
|
import { OptionsDataItem } from "../options/types.js";
|
|
15
15
|
import { ComboBoxFieldProps } from "./types.js";
|
|
16
16
|
import "client-only";
|
|
17
|
-
import * as
|
|
17
|
+
import * as react7 from "react";
|
|
18
18
|
import { ContextValue } from "react-aria-components";
|
|
19
|
-
import * as
|
|
19
|
+
import * as react_jsx_runtime20 from "react/jsx-runtime";
|
|
20
20
|
|
|
21
21
|
//#region src/components/combobox-field/context.d.ts
|
|
22
|
-
declare const ComboBoxFieldContext:
|
|
22
|
+
declare const ComboBoxFieldContext: react7.Context<ContextValue<ComboBoxFieldProps<any>, HTMLDivElement>>;
|
|
23
23
|
declare function ComboBoxFieldProvider<T extends OptionsDataItem>({
|
|
24
24
|
children,
|
|
25
25
|
...props
|
|
26
|
-
}: ProviderProps<ComboBoxFieldProps<T>>):
|
|
26
|
+
}: ProviderProps<ComboBoxFieldProps<T>>): react_jsx_runtime20.JSX.Element;
|
|
27
27
|
//#endregion
|
|
28
28
|
export { ComboBoxFieldContext, ComboBoxFieldProvider };
|
|
29
29
|
//# sourceMappingURL=context.d.ts.map
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
import { OptionsDataItem } from "../options/types.js";
|
|
14
14
|
import { ComboBoxFieldProps } from "./types.js";
|
|
15
15
|
import "client-only";
|
|
16
|
-
import * as
|
|
16
|
+
import * as react_jsx_runtime30 from "react/jsx-runtime";
|
|
17
17
|
|
|
18
18
|
//#region src/components/combobox-field/index.d.ts
|
|
19
19
|
/**
|
|
@@ -30,7 +30,7 @@ import * as react_jsx_runtime155 from "react/jsx-runtime";
|
|
|
30
30
|
declare function ComboBoxField<T extends OptionsDataItem>({
|
|
31
31
|
ref,
|
|
32
32
|
...props
|
|
33
|
-
}: ComboBoxFieldProps<T>):
|
|
33
|
+
}: ComboBoxFieldProps<T>): react_jsx_runtime30.JSX.Element;
|
|
34
34
|
//#endregion
|
|
35
35
|
export { ComboBoxField };
|
|
36
36
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -38,7 +38,7 @@ import styles from "./styles.module.css";
|
|
|
38
38
|
*/
|
|
39
39
|
function ComboBoxField({ ref, ...props }) {
|
|
40
40
|
[props, ref] = useContextProps(props, ref ?? null, ComboBoxFieldContext);
|
|
41
|
-
const { children, classNames, description: descriptionProp, errorMessage: errorMessageProp, inputProps, label: labelProp, layoutOptions, menuTrigger = "focus", size = "medium", isInvalid: isInvalidProp, ...rest } = props;
|
|
41
|
+
const { children, classNames, description: descriptionProp, errorMessage: errorMessageProp, inputProps, label: labelProp, layoutOptions, menuTrigger = "focus", size = "medium", isInvalid: isInvalidProp, isReadOnly = false, ...rest } = props;
|
|
42
42
|
const errorMessage = errorMessageProp || null;
|
|
43
43
|
const isSmall = size === "small";
|
|
44
44
|
return /* @__PURE__ */ jsx(ComboBox, {
|
|
@@ -47,45 +47,52 @@ function ComboBoxField({ ref, ...props }) {
|
|
|
47
47
|
className: composeRenderProps(classNames?.field, (className) => clsx("group/combobox-field", styles.field, className)),
|
|
48
48
|
menuTrigger,
|
|
49
49
|
isInvalid: isInvalidProp || (errorMessage ? true : void 0),
|
|
50
|
+
isReadOnly,
|
|
50
51
|
"data-size": size,
|
|
51
|
-
children: ({ isDisabled, isInvalid, isRequired }) =>
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
52
|
+
children: ({ isDisabled, isInvalid, isRequired }) => {
|
|
53
|
+
const shouldShowDescription = !isReadOnly && !!descriptionProp && !(isSmall || isInvalid);
|
|
54
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
55
|
+
!!labelProp && !isSmall && /* @__PURE__ */ jsx(Label$1, {
|
|
56
|
+
className: clsx(styles.label, classNames?.label),
|
|
57
|
+
isDisabled,
|
|
58
|
+
isRequired,
|
|
59
|
+
children: labelProp
|
|
60
|
+
}),
|
|
61
|
+
/* @__PURE__ */ jsxs("div", {
|
|
62
|
+
className: clsx(styles.control, classNames?.control),
|
|
63
|
+
"data-readonly": isReadOnly || null,
|
|
64
|
+
children: [/* @__PURE__ */ jsx(Input, {
|
|
65
|
+
...inputProps,
|
|
66
|
+
tabIndex: isReadOnly ? -1 : 0,
|
|
67
|
+
className: composeRenderProps(classNames?.input, (className) => clsx(styles.input, className)),
|
|
68
|
+
title: inputProps?.value ? String(inputProps?.value) : ""
|
|
69
|
+
}), !isReadOnly && /* @__PURE__ */ jsx(Button, {
|
|
70
|
+
className: composeRenderProps(classNames?.trigger, (className) => clsx(styles.trigger, className)),
|
|
71
|
+
children: /* @__PURE__ */ jsx(Icon, {
|
|
72
|
+
size: "small",
|
|
73
|
+
children: /* @__PURE__ */ jsx(ChevronDown, {})
|
|
74
|
+
})
|
|
75
|
+
})]
|
|
76
|
+
}),
|
|
77
|
+
shouldShowDescription && /* @__PURE__ */ jsx(Text, {
|
|
78
|
+
className: clsx(styles.description, classNames?.description),
|
|
79
|
+
slot: "description",
|
|
80
|
+
children: descriptionProp
|
|
81
|
+
}),
|
|
82
|
+
/* @__PURE__ */ jsx(FieldError, {
|
|
83
|
+
className: composeRenderProps(classNames?.error, (className) => clsx(styles.error, className)),
|
|
84
|
+
children: errorMessage
|
|
85
|
+
}),
|
|
86
|
+
/* @__PURE__ */ jsx(Popover, {
|
|
87
|
+
className: composeRenderProps(classNames?.popover, (className) => clsx(styles.popover, className)),
|
|
88
|
+
children: /* @__PURE__ */ jsx(Virtualizer, {
|
|
89
|
+
layout: ListLayout,
|
|
90
|
+
layoutOptions,
|
|
91
|
+
children: /* @__PURE__ */ jsx(Options, { children })
|
|
68
92
|
})
|
|
69
|
-
})]
|
|
70
|
-
}),
|
|
71
|
-
!!descriptionProp && !(isSmall || isInvalid) && /* @__PURE__ */ jsx(Text, {
|
|
72
|
-
className: clsx(styles.description, classNames?.description),
|
|
73
|
-
slot: "description",
|
|
74
|
-
children: descriptionProp
|
|
75
|
-
}),
|
|
76
|
-
/* @__PURE__ */ jsx(FieldError, {
|
|
77
|
-
className: composeRenderProps(classNames?.error, (className) => clsx(styles.error, className)),
|
|
78
|
-
children: errorMessage
|
|
79
|
-
}),
|
|
80
|
-
/* @__PURE__ */ jsx(Popover, {
|
|
81
|
-
className: composeRenderProps(classNames?.popover, (className) => clsx(styles.popover, className)),
|
|
82
|
-
children: /* @__PURE__ */ jsx(Virtualizer, {
|
|
83
|
-
layout: ListLayout,
|
|
84
|
-
layoutOptions,
|
|
85
|
-
children: /* @__PURE__ */ jsx(Options, { children })
|
|
86
93
|
})
|
|
87
|
-
})
|
|
88
|
-
|
|
94
|
+
] });
|
|
95
|
+
}
|
|
89
96
|
});
|
|
90
97
|
}
|
|
91
98
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["Label"],"sources":["../../../src/components/combobox-field/index.tsx"],"sourcesContent":["/*\n * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n'use client';\n\nimport { ChevronDown } from '@accelint/icons';\nimport 'client-only';\nimport { clsx } from '@accelint/design-foundation/lib/utils';\nimport {\n Button,\n ComboBox,\n composeRenderProps,\n FieldError,\n Input,\n ListLayout,\n Popover,\n Text,\n useContextProps,\n Virtualizer,\n} from 'react-aria-components';\nimport { Icon } from '../icon';\nimport { Label } from '../label';\nimport { Options } from '../options';\nimport { ComboBoxFieldContext } from './context';\nimport styles from './styles.module.css';\nimport type { OptionsDataItem } from '../options/types';\nimport type { ComboBoxFieldProps } from './types';\n\n/**\n * ComboBoxField - Accessible searchable combobox with dropdown options\n *\n * A combobox field that provides a searchable input with virtualized dropdown\n * options and support for sections, icons, and rich content.\n *\n * @example\n * <ComboBoxField defaultItems={items}>\n * {(item) => <OptionsItem key={item.id} textValue={item.name}>{item.name}</OptionsItem>}\n * </ComboBoxField>\n */\nexport function ComboBoxField<T extends OptionsDataItem>({\n ref,\n ...props\n}: ComboBoxFieldProps<T>) {\n [props, ref] = useContextProps(props, ref ?? null, ComboBoxFieldContext);\n\n const {\n children,\n classNames,\n description: descriptionProp,\n errorMessage: errorMessageProp,\n inputProps,\n label: labelProp,\n layoutOptions,\n menuTrigger = 'focus',\n size = 'medium',\n isInvalid: isInvalidProp,\n ...rest\n } = props;\n const errorMessage = errorMessageProp || null; // Protect against empty string\n const isSmall = size === 'small';\n\n return (\n <ComboBox<T>\n {...rest}\n ref={ref}\n className={composeRenderProps(classNames?.field, (className) =>\n clsx('group/combobox-field', styles.field, className),\n )}\n menuTrigger={menuTrigger}\n isInvalid={isInvalidProp || (errorMessage ? true : undefined)} // Leave uncontrolled if possible to fallback to validation state\n data-size={size}\n >\n {(\n { isDisabled, isInvalid, isRequired }, // Rely on internal state, not props, since state could differ from props\n ) => (\n <>\n
|
|
1
|
+
{"version":3,"file":"index.js","names":["Label"],"sources":["../../../src/components/combobox-field/index.tsx"],"sourcesContent":["/*\n * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n'use client';\n\nimport { ChevronDown } from '@accelint/icons';\nimport 'client-only';\nimport { clsx } from '@accelint/design-foundation/lib/utils';\nimport {\n Button,\n ComboBox,\n composeRenderProps,\n FieldError,\n Input,\n ListLayout,\n Popover,\n Text,\n useContextProps,\n Virtualizer,\n} from 'react-aria-components';\nimport { Icon } from '../icon';\nimport { Label } from '../label';\nimport { Options } from '../options';\nimport { ComboBoxFieldContext } from './context';\nimport styles from './styles.module.css';\nimport type { OptionsDataItem } from '../options/types';\nimport type { ComboBoxFieldProps } from './types';\n\n/**\n * ComboBoxField - Accessible searchable combobox with dropdown options\n *\n * A combobox field that provides a searchable input with virtualized dropdown\n * options and support for sections, icons, and rich content.\n *\n * @example\n * <ComboBoxField defaultItems={items}>\n * {(item) => <OptionsItem key={item.id} textValue={item.name}>{item.name}</OptionsItem>}\n * </ComboBoxField>\n */\nexport function ComboBoxField<T extends OptionsDataItem>({\n ref,\n ...props\n}: ComboBoxFieldProps<T>) {\n [props, ref] = useContextProps(props, ref ?? null, ComboBoxFieldContext);\n\n const {\n children,\n classNames,\n description: descriptionProp,\n errorMessage: errorMessageProp,\n inputProps,\n label: labelProp,\n layoutOptions,\n menuTrigger = 'focus',\n size = 'medium',\n isInvalid: isInvalidProp,\n isReadOnly = false,\n ...rest\n } = props;\n const errorMessage = errorMessageProp || null; // Protect against empty string\n const isSmall = size === 'small';\n\n return (\n <ComboBox<T>\n {...rest}\n ref={ref}\n className={composeRenderProps(classNames?.field, (className) =>\n clsx('group/combobox-field', styles.field, className),\n )}\n menuTrigger={menuTrigger}\n isInvalid={isInvalidProp || (errorMessage ? true : undefined)} // Leave uncontrolled if possible to fallback to validation state\n isReadOnly={isReadOnly}\n data-size={size}\n >\n {(\n { isDisabled, isInvalid, isRequired }, // Rely on internal state, not props, since state could differ from props\n ) => {\n const shouldShowDescription =\n !isReadOnly && !!descriptionProp && !(isSmall || isInvalid);\n\n return (\n <>\n {!!labelProp && !isSmall && (\n <Label\n className={clsx(styles.label, classNames?.label)}\n isDisabled={isDisabled}\n isRequired={isRequired}\n >\n {labelProp}\n </Label>\n )}\n <div\n className={clsx(styles.control, classNames?.control)}\n data-readonly={isReadOnly || null}\n >\n <Input\n {...inputProps}\n tabIndex={isReadOnly ? -1 : 0}\n className={composeRenderProps(classNames?.input, (className) =>\n clsx(styles.input, className),\n )}\n title={inputProps?.value ? String(inputProps?.value) : ''}\n />\n {!isReadOnly && (\n <Button\n className={composeRenderProps(\n classNames?.trigger,\n (className) => clsx(styles.trigger, className),\n )}\n >\n <Icon size='small'>\n <ChevronDown />\n </Icon>\n </Button>\n )}\n </div>\n {shouldShowDescription && (\n <Text\n className={clsx(styles.description, classNames?.description)}\n slot='description'\n >\n {descriptionProp}\n </Text>\n )}\n <FieldError\n className={composeRenderProps(classNames?.error, (className) =>\n clsx(styles.error, className),\n )}\n >\n {errorMessage}\n </FieldError>\n <Popover\n className={composeRenderProps(classNames?.popover, (className) =>\n clsx(styles.popover, className),\n )}\n >\n <Virtualizer layout={ListLayout} layoutOptions={layoutOptions}>\n <Options>{children}</Options>\n </Virtualizer>\n </Popover>\n </>\n );\n }}\n </ComboBox>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+CA,SAAgB,cAAyC,EACvD,KACA,GAAG,SACqB;AACxB,EAAC,OAAO,OAAO,gBAAgB,OAAO,OAAO,MAAM,qBAAqB;CAExE,MAAM,EACJ,UACA,YACA,aAAa,iBACb,cAAc,kBACd,YACA,OAAO,WACP,eACA,cAAc,SACd,OAAO,UACP,WAAW,eACX,aAAa,OACb,GAAG,SACD;CACJ,MAAM,eAAe,oBAAoB;CACzC,MAAM,UAAU,SAAS;AAEzB,QACE,oBAAC;EACC,GAAI;EACC;EACL,WAAW,mBAAmB,YAAY,QAAQ,cAChD,KAAK,wBAAwB,OAAO,OAAO,UAAU,CACtD;EACY;EACb,WAAW,kBAAkB,eAAe,OAAO;EACvC;EACZ,aAAW;aAGT,EAAE,YAAY,WAAW,iBACtB;GACH,MAAM,wBACJ,CAAC,cAAc,CAAC,CAAC,mBAAmB,EAAE,WAAW;AAEnD,UACE;IACG,CAAC,CAAC,aAAa,CAAC,WACf,oBAACA;KACC,WAAW,KAAK,OAAO,OAAO,YAAY,MAAM;KACpC;KACA;eAEX;MACK;IAEV,qBAAC;KACC,WAAW,KAAK,OAAO,SAAS,YAAY,QAAQ;KACpD,iBAAe,cAAc;gBAE7B,oBAAC;MACC,GAAI;MACJ,UAAU,aAAa,KAAK;MAC5B,WAAW,mBAAmB,YAAY,QAAQ,cAChD,KAAK,OAAO,OAAO,UAAU,CAC9B;MACD,OAAO,YAAY,QAAQ,OAAO,YAAY,MAAM,GAAG;OACvD,EACD,CAAC,cACA,oBAAC;MACC,WAAW,mBACT,YAAY,UACX,cAAc,KAAK,OAAO,SAAS,UAAU,CAC/C;gBAED,oBAAC;OAAK,MAAK;iBACT,oBAAC,gBAAc;QACV;OACA;MAEP;IACL,yBACC,oBAAC;KACC,WAAW,KAAK,OAAO,aAAa,YAAY,YAAY;KAC5D,MAAK;eAEJ;MACI;IAET,oBAAC;KACC,WAAW,mBAAmB,YAAY,QAAQ,cAChD,KAAK,OAAO,OAAO,UAAU,CAC9B;eAEA;MACU;IACb,oBAAC;KACC,WAAW,mBAAmB,YAAY,UAAU,cAClD,KAAK,OAAO,SAAS,UAAU,CAChC;eAED,oBAAC;MAAY,QAAQ;MAA2B;gBAC9C,oBAAC,WAAS,WAAmB;OACjB;MACN;OACT;;GAGE"}
|
|
@@ -55,10 +55,14 @@
|
|
|
55
55
|
@variant group-disabled/combobox-field {
|
|
56
56
|
@apply fg-disabled outline-interactive-disabled;
|
|
57
57
|
}
|
|
58
|
+
|
|
59
|
+
@variant read-only {
|
|
60
|
+
@apply px-0 outline-none;
|
|
61
|
+
}
|
|
58
62
|
}
|
|
59
63
|
|
|
60
64
|
.input {
|
|
61
|
-
@apply font-display grow outline-none;
|
|
65
|
+
@apply font-display grow overflow-hidden text-ellipsis whitespace-nowrap outline-none;
|
|
62
66
|
|
|
63
67
|
@variant group-size-medium/combobox-field {
|
|
64
68
|
@apply text-body-s;
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
|
|
13
13
|
import { ProviderProps } from "../../lib/types.js";
|
|
14
14
|
import { CoordinateFieldProps, CoordinateFieldState } from "./types.js";
|
|
15
|
-
import * as
|
|
15
|
+
import * as react10 from "react";
|
|
16
16
|
import { ContextValue } from "react-aria-components";
|
|
17
|
-
import * as
|
|
17
|
+
import * as react_jsx_runtime26 from "react/jsx-runtime";
|
|
18
18
|
|
|
19
19
|
//#region src/components/coordinate-field/context.d.ts
|
|
20
20
|
|
|
@@ -48,7 +48,7 @@ import * as react_jsx_runtime158 from "react/jsx-runtime";
|
|
|
48
48
|
*
|
|
49
49
|
* @see CoordinateFieldStateContext for internal runtime state
|
|
50
50
|
*/
|
|
51
|
-
declare const CoordinateFieldContext:
|
|
51
|
+
declare const CoordinateFieldContext: react10.Context<ContextValue<CoordinateFieldProps, HTMLDivElement>>;
|
|
52
52
|
/**
|
|
53
53
|
* State Context for CoordinateField component.
|
|
54
54
|
*
|
|
@@ -66,7 +66,7 @@ declare const CoordinateFieldContext: react41.Context<ContextValue<CoordinateFie
|
|
|
66
66
|
* const state = useCoordinateFieldStateContext();
|
|
67
67
|
* const { segmentValues, isDisabled, registerTimeout } = state;
|
|
68
68
|
*/
|
|
69
|
-
declare const CoordinateFieldStateContext:
|
|
69
|
+
declare const CoordinateFieldStateContext: react10.Context<CoordinateFieldState | null>;
|
|
70
70
|
/**
|
|
71
71
|
* Provider component for CoordinateField context
|
|
72
72
|
* Wraps children with CoordinateFieldContext
|
|
@@ -74,7 +74,7 @@ declare const CoordinateFieldStateContext: react41.Context<CoordinateFieldState
|
|
|
74
74
|
declare function CoordinateFieldProvider({
|
|
75
75
|
children,
|
|
76
76
|
...props
|
|
77
|
-
}: ProviderProps<CoordinateFieldProps>):
|
|
77
|
+
}: ProviderProps<CoordinateFieldProps>): react_jsx_runtime26.JSX.Element;
|
|
78
78
|
/**
|
|
79
79
|
* Provider component for CoordinateField state context
|
|
80
80
|
* Wraps children with CoordinateFieldStateContext
|
|
@@ -85,7 +85,7 @@ declare function CoordinateFieldStateProvider({
|
|
|
85
85
|
}: {
|
|
86
86
|
children: React.ReactNode;
|
|
87
87
|
value: CoordinateFieldState;
|
|
88
|
-
}):
|
|
88
|
+
}): react_jsx_runtime26.JSX.Element;
|
|
89
89
|
/**
|
|
90
90
|
* Hook to access CoordinateField state context
|
|
91
91
|
* Must be used within a CoordinateField component
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { CoordinateFieldProps } from "./types.js";
|
|
14
14
|
import "client-only";
|
|
15
|
-
import * as
|
|
15
|
+
import * as react_jsx_runtime82 from "react/jsx-runtime";
|
|
16
16
|
|
|
17
17
|
//#region src/components/coordinate-field/index.d.ts
|
|
18
18
|
|
|
@@ -77,7 +77,7 @@ import * as react_jsx_runtime160 from "react/jsx-runtime";
|
|
|
77
77
|
declare function CoordinateField({
|
|
78
78
|
ref,
|
|
79
79
|
...props
|
|
80
|
-
}: CoordinateFieldProps):
|
|
80
|
+
}: CoordinateFieldProps): react_jsx_runtime82.JSX.Element;
|
|
81
81
|
//#endregion
|
|
82
82
|
export { CoordinateField };
|
|
83
83
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -107,7 +107,7 @@ import styles from "./styles.module.css";
|
|
|
107
107
|
*/
|
|
108
108
|
function CoordinateField({ ref, ...props }) {
|
|
109
109
|
[props, ref] = useContextProps(props, ref, CoordinateFieldContext);
|
|
110
|
-
const { classNames, description: descriptionProp, label: labelProp, format = "dd", size = "medium", variant = "inline", showFormatButton = true, isDisabled = false, isInvalid: isInvalidProp = false, isRequired = false, ...rest } = props;
|
|
110
|
+
const { classNames, description: descriptionProp, label: labelProp, format = "dd", size = "medium", variant = "inline", showFormatButton = true, isDisabled = false, isInvalid: isInvalidProp = false, isRequired = false, isReadOnly = false, ...rest } = props;
|
|
111
111
|
const isSmall = size === "small";
|
|
112
112
|
const DOMProps = filterDOMProps(rest, { global: true });
|
|
113
113
|
const ariaLabelForSmallSize = isSmall && labelProp ? labelProp : rest["aria-label"];
|
|
@@ -163,6 +163,7 @@ function CoordinateField({ ref, ...props }) {
|
|
|
163
163
|
/* @__PURE__ */ jsxs("div", {
|
|
164
164
|
style: { "--min-width": variant === "stacked" ? "unset" : minControlWidth },
|
|
165
165
|
className: clsx(styles.control, classNames?.control),
|
|
166
|
+
"data-readonly": isReadOnly || null,
|
|
166
167
|
children: [/* @__PURE__ */ jsx("div", {
|
|
167
168
|
className: clsx(styles.input, styles[variant], classNames?.input),
|
|
168
169
|
onPasteCapture: paste.handleInputPaste,
|
|
@@ -197,6 +198,7 @@ function CoordinateField({ ref, ...props }) {
|
|
|
197
198
|
pad: config.pad,
|
|
198
199
|
className: clsx(styles.segment, classNames?.segment),
|
|
199
200
|
isDisabled,
|
|
201
|
+
isReadOnly,
|
|
200
202
|
allowedChars: config.allowedChars,
|
|
201
203
|
segmentRef: focus.segmentRefs[editableIndex],
|
|
202
204
|
segmentIndex: editableIndex,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["Label","Button","Popover","AriaText","DialogTrigger","Dialog","RadioGroup","Radio"],"sources":["../../../src/components/coordinate-field/index.tsx"],"sourcesContent":["/*\n * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n'use client';\n\nimport { clsx } from '@accelint/design-foundation/lib/utils';\nimport Check from '@accelint/icons/check';\nimport CopyToClipboard from '@accelint/icons/copy-to-clipboard';\nimport GlobalShare from '@accelint/icons/global-share';\nimport { filterDOMProps } from '@react-aria/utils';\nimport 'client-only';\nimport {\n type CSSProperties,\n type ReactNode,\n useCallback,\n useMemo,\n useState,\n} from 'react';\nimport {\n Text as AriaText,\n composeRenderProps,\n FieldError,\n FieldErrorContext,\n GroupContext,\n LabelContext,\n Provider,\n TextContext,\n useContextProps,\n} from 'react-aria-components';\nimport { useCoordinateField } from '../../hooks/coordinate-field';\nimport { Button } from '../button';\nimport { Dialog } from '../dialog';\nimport { DialogContent } from '../dialog/content';\nimport { DialogFooter } from '../dialog/footer';\nimport { DialogTitle } from '../dialog/title';\nimport { DialogTrigger } from '../dialog/trigger';\nimport { Icon } from '../icon';\nimport { Label } from '../label';\nimport { Popover } from '../popover';\nimport { PopoverContent } from '../popover/content';\nimport { PopoverTitle } from '../popover/title';\nimport { PopoverTrigger } from '../popover/trigger';\nimport { Radio } from '../radio';\nimport { RadioGroup } from '../radio/group';\nimport { CoordinateFieldContext, CoordinateFieldStateContext } from './context';\nimport {\n type CoordinateFormatResult,\n getAllCoordinateFormats,\n} from './coordinate-utils';\nimport { CoordinateSegment } from './segment';\nimport { getSegmentLabel, GROUP_SEPARATOR } from './segment-configs';\nimport styles from './styles.module.css';\nimport type { CoordinateFieldProps } from './types';\nimport {\n COORDINATE_FORMAT_LABELS,\n COORDINATE_FORMAT_NAMES,\n COORDINATE_SYSTEMS,\n type CoordinateSystem,\n} from './types';\nimport { calculateMinControlWidth } from './width-utils';\n\n/**\n * CoordinateField - A comprehensive coordinate input component with multiple format support\n *\n * Provides accessible coordinate input functionality with support for multiple coordinate\n * systems (DD, DDM, DMS, MGRS, UTM). All values are normalized to Decimal Degrees internally\n * for consistency.\n *\n * @example\n * // Basic coordinate field\n * <CoordinateField label=\"Location\" />\n *\n * @example\n * // Coordinate field with validation\n * <CoordinateField\n * label=\"Target Coordinates\"\n * isRequired\n * isInvalid={hasError}\n * errorMessage=\"Please enter a valid coordinate\"\n * />\n *\n * @example\n * // Coordinate field with specific format\n * <CoordinateField\n * label=\"Position\"\n * format=\"dms\"\n * description=\"Enter coordinates in Degrees Minutes Seconds format\"\n * />\n *\n * @example\n * // Compact coordinate field\n * <CoordinateField\n * label=\"Coordinates\"\n * size=\"small\"\n * format=\"dd\"\n * />\n *\n * @example\n * // Controlled coordinate field\n * <CoordinateField\n * label=\"Selected Location\"\n * value={coordinates}\n * onChange={setCoordinates}\n * />\n *\n * @example\n * // Coordinate field with error handling\n * <CoordinateField\n * label=\"Target Coordinates\"\n * onError={(message, context) => {\n * // message will be \"Invalid coordinate value\" for validation errors\n * // or \"Invalid coordinate format\" for paste errors\n * setErrorMessage(message);\n * console.error(message, context);\n * }}\n * isInvalid={!!errorMessage}\n * errorMessage={errorMessage}\n * />\n */\nexport function CoordinateField({ ref, ...props }: CoordinateFieldProps) {\n [props, ref] = useContextProps(props, ref, CoordinateFieldContext);\n\n const {\n classNames,\n description: descriptionProp,\n label: labelProp,\n format = 'dd',\n size = 'medium',\n variant = 'inline',\n showFormatButton = true,\n isDisabled = false,\n isInvalid: isInvalidProp = false,\n isRequired = false,\n ...rest\n } = props;\n\n const isSmall = size === 'small';\n\n const DOMProps = filterDOMProps(rest, { global: true });\n\n // When size is small and label is hidden, use aria-label instead of aria-labelledby\n // to ensure screen readers have an accessible name\n const ariaLabelForSmallSize =\n isSmall && labelProp ? labelProp : rest['aria-label'];\n\n const {\n state,\n focus,\n paste,\n copy,\n registerTimeout,\n fieldProps,\n labelProps,\n descriptionProps,\n errorProps,\n validation,\n effectiveErrorMessage,\n isInvalid,\n } = useCoordinateField(\n props,\n ariaLabelForSmallSize,\n rest['aria-describedby'],\n rest['aria-details'],\n );\n\n const componentState = {\n segmentValues: state.segmentValues,\n format,\n currentValue: state.currentValue,\n validationErrors: state.validationErrors,\n isDisabled,\n isInvalid,\n isRequired,\n size,\n variant,\n registerTimeout,\n };\n\n // Store all coordinate formats, calculated only when popover opens\n const [allCoordinateFormats, setAllCoordinateFormats] = useState<Record<\n CoordinateSystem,\n CoordinateFormatResult\n > | null>(null);\n\n const handlePopoverOpenChange = useCallback(\n (isOpen: boolean) => {\n if (isOpen) {\n setAllCoordinateFormats(getAllCoordinateFormats(state.currentValue));\n }\n },\n [state.currentValue],\n );\n\n // Calculate the minimum width needed for the control container\n // This keeps the outlined container at a fixed width while segments animate\n const minControlWidth = useMemo(\n () =>\n calculateMinControlWidth(\n state.editableSegmentConfigs,\n state.segmentConfigs,\n showFormatButton,\n ),\n [state.editableSegmentConfigs, state.segmentConfigs, showFormatButton],\n );\n\n return (\n <Provider\n values={[\n [CoordinateFieldContext, props],\n [CoordinateFieldStateContext, componentState],\n [GroupContext, fieldProps],\n [LabelContext, labelProps],\n [\n TextContext,\n {\n slots: {\n description: descriptionProps,\n errorMessage: errorProps,\n },\n },\n ],\n [FieldErrorContext, validation],\n ]}\n >\n <div\n {...DOMProps}\n {...fieldProps}\n ref={ref}\n className={clsx(\n 'group/coordinate-field',\n styles.field,\n classNames?.field,\n )}\n data-size={size}\n data-disabled={isDisabled || null}\n data-invalid={isInvalid || null}\n >\n {!isSmall && labelProp && (\n <Label\n className={classNames?.label}\n isDisabled={isDisabled}\n isRequired={isRequired}\n >\n {labelProp}\n </Label>\n )}\n\n <div\n style={\n {\n '--min-width': variant === 'stacked' ? 'unset' : minControlWidth,\n } as CSSProperties\n }\n className={clsx(styles.control, classNames?.control)}\n >\n <div\n className={clsx(styles.input, styles[variant], classNames?.input)}\n onPasteCapture={paste.handleInputPaste}\n data-input-container\n >\n {state.segmentConfigs\n .reduce<ReactNode[][]>(\n (acc, config, configIndex) => {\n const currentGroupIndex = acc.length - 1;\n\n if (\n config.value === GROUP_SEPARATOR &&\n variant === 'stacked'\n ) {\n acc.push([]);\n\n return acc;\n }\n\n if (config.type === 'literal') {\n acc[currentGroupIndex]?.push(\n <span\n key={`${format}-literal-${configIndex}-${config.value}`}\n className={styles.literal}\n >\n {config.value}\n </span>,\n );\n\n return acc;\n }\n\n const editableIndex = state.segmentConfigs\n .slice(0, configIndex)\n .filter((c) => c.type !== 'literal').length;\n\n acc[currentGroupIndex]?.push(\n <CoordinateSegment\n key={`${format}-segment-${editableIndex}`}\n value={state.segmentValues[editableIndex] || ''}\n onChange={(newValue) =>\n state.handleSegmentChange(editableIndex, newValue)\n }\n onFocus={() =>\n focus.setFocusedSegmentIndex(editableIndex)\n }\n onBlur={() => {\n focus.setFocusedSegmentIndex(-1);\n state.flushPendingValidation();\n }}\n onKeyDown={(e) =>\n focus.handleSegmentKeyDown(editableIndex, e)\n }\n onAutoAdvance={() =>\n focus.focusNextSegment(editableIndex)\n }\n onAutoRetreat={() =>\n focus.focusPreviousSegment(editableIndex)\n }\n placeholder={config.placeholder}\n maxLength={config.maxLength}\n pad={config.pad}\n className={clsx(styles.segment, classNames?.segment)}\n isDisabled={isDisabled}\n allowedChars={config.allowedChars}\n segmentRef={focus.segmentRefs[editableIndex]}\n segmentIndex={editableIndex}\n totalSegments={state.editableSegmentConfigs.length}\n ariaLabel={getSegmentLabel(format, editableIndex)}\n />,\n );\n\n return acc;\n },\n [[]],\n )\n .map((group, groupIndex) => (\n <div\n className={clsx(styles.segmentGroup, styles[variant])}\n key={`${format}-group-${\n // biome-ignore lint/suspicious/noArrayIndexKey: intentional\n groupIndex\n }`}\n >\n {group}\n </div>\n ))}\n </div>\n\n {showFormatButton && (\n <PopoverTrigger onOpenChange={handlePopoverOpenChange}>\n <Button\n variant='icon'\n size={size}\n color='mono-bold'\n className={classNames?.formatButton}\n aria-label='View coordinate in all formats'\n isDisabled={!copy.isFormatButtonEnabled}\n >\n <Icon>\n <GlobalShare />\n </Icon>\n </Button>\n <Popover classNames={{ popover: styles.popover }}>\n <PopoverTitle className={styles.popoverTitle}>\n Copy Coordinates\n </PopoverTitle>\n <PopoverContent>\n {allCoordinateFormats &&\n COORDINATE_SYSTEMS.map((formatKey) => {\n const formatResult = allCoordinateFormats[formatKey];\n const isCopied = copy.copiedFormat === formatKey;\n\n return (\n <div key={formatKey} className={styles.formatRow}>\n <div className={styles.formatLabels}>\n <span className={styles.formatLabel}>\n {COORDINATE_FORMAT_LABELS[formatKey]}\n </span>\n <span\n className={styles.formatValue}\n title={formatResult.value}\n >\n {formatResult.value}\n </span>\n </div>\n <Button\n variant='icon'\n color='mono-bold'\n aria-label={`Copy ${COORDINATE_FORMAT_LABELS[formatKey]} format`}\n onClick={() => copy.handleCopyFormat(formatKey)}\n isDisabled={!formatResult.isValid}\n >\n <Icon>\n {isCopied ? <Check /> : <CopyToClipboard />}\n </Icon>\n </Button>\n </div>\n );\n })}\n </PopoverContent>\n </Popover>\n </PopoverTrigger>\n )}\n </div>\n\n {/* Description is hidden when field is invalid (unless disabled) to make room for error message */}\n {descriptionProp && !isSmall && (!isInvalid || isDisabled) && (\n <AriaText\n className={clsx(styles.description, classNames?.description)}\n slot='description'\n >\n {descriptionProp}\n </AriaText>\n )}\n\n <FieldError\n className={composeRenderProps(classNames?.error, (className) =>\n clsx(styles.error, className),\n )}\n >\n {effectiveErrorMessage}\n </FieldError>\n\n <DialogTrigger\n isOpen={paste.showDisambiguationModal}\n onOpenChange={paste.setShowDisambiguationModal}\n >\n <Button className='hidden'>Hidden Trigger</Button>\n <Dialog size='small'>\n <DialogTitle className={styles.modalTitle}>\n Select Coordinate Format\n </DialogTitle>\n <DialogContent>\n <p className={styles.modalDescription}>\n The pasted value matches multiple coordinate formats. Please\n select the correct interpretation:\n </p>\n\n <RadioGroup\n classNames={{ group: styles.formatOptions }}\n value={paste.selectedDisambiguationFormat}\n onChange={(value) =>\n paste.setSelectedDisambiguationFormat(\n value as CoordinateSystem,\n )\n }\n >\n {paste.disambiguationMatches.map((match) => (\n <Radio key={match.format} value={match.format}>\n <div className={styles.modalOptionContent}>\n <span className={styles.formatOptionLabel}>\n {COORDINATE_FORMAT_NAMES[match.format]}\n </span>\n <span className={styles.formatOptionValue}>\n {match.displayString}\n </span>\n </div>\n </Radio>\n ))}\n </RadioGroup>\n </DialogContent>\n <DialogFooter className={styles.modalActions}>\n <Button\n variant='flat'\n onPress={() => paste.setShowDisambiguationModal(false)}\n >\n Cancel\n </Button>\n <Button onPress={paste.handleDisambiguationSelect}>\n Apply Selected\n </Button>\n </DialogFooter>\n </Dialog>\n </DialogTrigger>\n </div>\n </Provider>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["Label","Button","Popover","AriaText","DialogTrigger","Dialog","RadioGroup","Radio"],"sources":["../../../src/components/coordinate-field/index.tsx"],"sourcesContent":["/*\n * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n'use client';\n\nimport { clsx } from '@accelint/design-foundation/lib/utils';\nimport Check from '@accelint/icons/check';\nimport CopyToClipboard from '@accelint/icons/copy-to-clipboard';\nimport GlobalShare from '@accelint/icons/global-share';\nimport { filterDOMProps } from '@react-aria/utils';\nimport 'client-only';\nimport {\n type CSSProperties,\n type ReactNode,\n useCallback,\n useMemo,\n useState,\n} from 'react';\nimport {\n Text as AriaText,\n composeRenderProps,\n FieldError,\n FieldErrorContext,\n GroupContext,\n LabelContext,\n Provider,\n TextContext,\n useContextProps,\n} from 'react-aria-components';\nimport { useCoordinateField } from '../../hooks/coordinate-field';\nimport { Button } from '../button';\nimport { Dialog } from '../dialog';\nimport { DialogContent } from '../dialog/content';\nimport { DialogFooter } from '../dialog/footer';\nimport { DialogTitle } from '../dialog/title';\nimport { DialogTrigger } from '../dialog/trigger';\nimport { Icon } from '../icon';\nimport { Label } from '../label';\nimport { Popover } from '../popover';\nimport { PopoverContent } from '../popover/content';\nimport { PopoverTitle } from '../popover/title';\nimport { PopoverTrigger } from '../popover/trigger';\nimport { Radio } from '../radio';\nimport { RadioGroup } from '../radio/group';\nimport { CoordinateFieldContext, CoordinateFieldStateContext } from './context';\nimport {\n type CoordinateFormatResult,\n getAllCoordinateFormats,\n} from './coordinate-utils';\nimport { CoordinateSegment } from './segment';\nimport { GROUP_SEPARATOR, getSegmentLabel } from './segment-configs';\nimport styles from './styles.module.css';\nimport {\n COORDINATE_FORMAT_LABELS,\n COORDINATE_FORMAT_NAMES,\n COORDINATE_SYSTEMS,\n type CoordinateSystem,\n} from './types';\nimport { calculateMinControlWidth } from './width-utils';\nimport type { CoordinateFieldProps } from './types';\n\n/**\n * CoordinateField - A comprehensive coordinate input component with multiple format support\n *\n * Provides accessible coordinate input functionality with support for multiple coordinate\n * systems (DD, DDM, DMS, MGRS, UTM). All values are normalized to Decimal Degrees internally\n * for consistency.\n *\n * @example\n * // Basic coordinate field\n * <CoordinateField label=\"Location\" />\n *\n * @example\n * // Coordinate field with validation\n * <CoordinateField\n * label=\"Target Coordinates\"\n * isRequired\n * isInvalid={hasError}\n * errorMessage=\"Please enter a valid coordinate\"\n * />\n *\n * @example\n * // Coordinate field with specific format\n * <CoordinateField\n * label=\"Position\"\n * format=\"dms\"\n * description=\"Enter coordinates in Degrees Minutes Seconds format\"\n * />\n *\n * @example\n * // Compact coordinate field\n * <CoordinateField\n * label=\"Coordinates\"\n * size=\"small\"\n * format=\"dd\"\n * />\n *\n * @example\n * // Controlled coordinate field\n * <CoordinateField\n * label=\"Selected Location\"\n * value={coordinates}\n * onChange={setCoordinates}\n * />\n *\n * @example\n * // Coordinate field with error handling\n * <CoordinateField\n * label=\"Target Coordinates\"\n * onError={(message, context) => {\n * // message will be \"Invalid coordinate value\" for validation errors\n * // or \"Invalid coordinate format\" for paste errors\n * setErrorMessage(message);\n * console.error(message, context);\n * }}\n * isInvalid={!!errorMessage}\n * errorMessage={errorMessage}\n * />\n */\nexport function CoordinateField({ ref, ...props }: CoordinateFieldProps) {\n [props, ref] = useContextProps(props, ref, CoordinateFieldContext);\n\n const {\n classNames,\n description: descriptionProp,\n label: labelProp,\n format = 'dd',\n size = 'medium',\n variant = 'inline',\n showFormatButton = true,\n isDisabled = false,\n isInvalid: isInvalidProp = false,\n isRequired = false,\n isReadOnly = false,\n ...rest\n } = props;\n\n const isSmall = size === 'small';\n\n const DOMProps = filterDOMProps(rest, { global: true });\n\n // When size is small and label is hidden, use aria-label instead of aria-labelledby\n // to ensure screen readers have an accessible name\n const ariaLabelForSmallSize =\n isSmall && labelProp ? labelProp : rest['aria-label'];\n\n const {\n state,\n focus,\n paste,\n copy,\n registerTimeout,\n fieldProps,\n labelProps,\n descriptionProps,\n errorProps,\n validation,\n effectiveErrorMessage,\n isInvalid,\n } = useCoordinateField(\n props,\n ariaLabelForSmallSize,\n rest['aria-describedby'],\n rest['aria-details'],\n );\n\n const componentState = {\n segmentValues: state.segmentValues,\n format,\n currentValue: state.currentValue,\n validationErrors: state.validationErrors,\n isDisabled,\n isInvalid,\n isRequired,\n size,\n variant,\n registerTimeout,\n };\n\n // Store all coordinate formats, calculated only when popover opens\n const [allCoordinateFormats, setAllCoordinateFormats] = useState<Record<\n CoordinateSystem,\n CoordinateFormatResult\n > | null>(null);\n\n const handlePopoverOpenChange = useCallback(\n (isOpen: boolean) => {\n if (isOpen) {\n setAllCoordinateFormats(getAllCoordinateFormats(state.currentValue));\n }\n },\n [state.currentValue],\n );\n\n // Calculate the minimum width needed for the control container\n // This keeps the outlined container at a fixed width while segments animate\n const minControlWidth = useMemo(\n () =>\n calculateMinControlWidth(\n state.editableSegmentConfigs,\n state.segmentConfigs,\n showFormatButton,\n ),\n [state.editableSegmentConfigs, state.segmentConfigs, showFormatButton],\n );\n\n return (\n <Provider\n values={[\n [CoordinateFieldContext, props],\n [CoordinateFieldStateContext, componentState],\n [GroupContext, fieldProps],\n [LabelContext, labelProps],\n [\n TextContext,\n {\n slots: {\n description: descriptionProps,\n errorMessage: errorProps,\n },\n },\n ],\n [FieldErrorContext, validation],\n ]}\n >\n <div\n {...DOMProps}\n {...fieldProps}\n ref={ref}\n className={clsx(\n 'group/coordinate-field',\n styles.field,\n classNames?.field,\n )}\n data-size={size}\n data-disabled={isDisabled || null}\n data-invalid={isInvalid || null}\n >\n {!isSmall && labelProp && (\n <Label\n className={classNames?.label}\n isDisabled={isDisabled}\n isRequired={isRequired}\n >\n {labelProp}\n </Label>\n )}\n\n <div\n style={\n {\n '--min-width': variant === 'stacked' ? 'unset' : minControlWidth,\n } as CSSProperties\n }\n className={clsx(styles.control, classNames?.control)}\n data-readonly={isReadOnly || null}\n >\n <div\n className={clsx(styles.input, styles[variant], classNames?.input)}\n onPasteCapture={paste.handleInputPaste}\n data-input-container\n >\n {state.segmentConfigs\n .reduce<ReactNode[][]>(\n (acc, config, configIndex) => {\n const currentGroupIndex = acc.length - 1;\n\n if (\n config.value === GROUP_SEPARATOR &&\n variant === 'stacked'\n ) {\n acc.push([]);\n\n return acc;\n }\n\n if (config.type === 'literal') {\n acc[currentGroupIndex]?.push(\n <span\n key={`${format}-literal-${configIndex}-${config.value}`}\n className={styles.literal}\n >\n {config.value}\n </span>,\n );\n\n return acc;\n }\n\n const editableIndex = state.segmentConfigs\n .slice(0, configIndex)\n .filter((c) => c.type !== 'literal').length;\n\n acc[currentGroupIndex]?.push(\n <CoordinateSegment\n key={`${format}-segment-${editableIndex}`}\n value={state.segmentValues[editableIndex] || ''}\n onChange={(newValue) =>\n state.handleSegmentChange(editableIndex, newValue)\n }\n onFocus={() =>\n focus.setFocusedSegmentIndex(editableIndex)\n }\n onBlur={() => {\n focus.setFocusedSegmentIndex(-1);\n state.flushPendingValidation();\n }}\n onKeyDown={(e) =>\n focus.handleSegmentKeyDown(editableIndex, e)\n }\n onAutoAdvance={() =>\n focus.focusNextSegment(editableIndex)\n }\n onAutoRetreat={() =>\n focus.focusPreviousSegment(editableIndex)\n }\n placeholder={config.placeholder}\n maxLength={config.maxLength}\n pad={config.pad}\n className={clsx(styles.segment, classNames?.segment)}\n isDisabled={isDisabled}\n isReadOnly={isReadOnly}\n allowedChars={config.allowedChars}\n segmentRef={focus.segmentRefs[editableIndex]}\n segmentIndex={editableIndex}\n totalSegments={state.editableSegmentConfigs.length}\n ariaLabel={getSegmentLabel(format, editableIndex)}\n />,\n );\n\n return acc;\n },\n [[]],\n )\n .map((group, groupIndex) => (\n <div\n className={clsx(styles.segmentGroup, styles[variant])}\n key={`${format}-group-${\n // biome-ignore lint/suspicious/noArrayIndexKey: intentional\n groupIndex\n }`}\n >\n {group}\n </div>\n ))}\n </div>\n\n {showFormatButton && (\n <PopoverTrigger onOpenChange={handlePopoverOpenChange}>\n <Button\n variant='icon'\n size={size}\n color='mono-bold'\n className={classNames?.formatButton}\n aria-label='View coordinate in all formats'\n isDisabled={!copy.isFormatButtonEnabled}\n >\n <Icon>\n <GlobalShare />\n </Icon>\n </Button>\n <Popover classNames={{ popover: styles.popover }}>\n <PopoverTitle className={styles.popoverTitle}>\n Copy Coordinates\n </PopoverTitle>\n <PopoverContent>\n {allCoordinateFormats &&\n COORDINATE_SYSTEMS.map((formatKey) => {\n const formatResult = allCoordinateFormats[formatKey];\n const isCopied = copy.copiedFormat === formatKey;\n\n return (\n <div key={formatKey} className={styles.formatRow}>\n <div className={styles.formatLabels}>\n <span className={styles.formatLabel}>\n {COORDINATE_FORMAT_LABELS[formatKey]}\n </span>\n <span\n className={styles.formatValue}\n title={formatResult.value}\n >\n {formatResult.value}\n </span>\n </div>\n <Button\n variant='icon'\n color='mono-bold'\n aria-label={`Copy ${COORDINATE_FORMAT_LABELS[formatKey]} format`}\n onClick={() => copy.handleCopyFormat(formatKey)}\n isDisabled={!formatResult.isValid}\n >\n <Icon>\n {isCopied ? <Check /> : <CopyToClipboard />}\n </Icon>\n </Button>\n </div>\n );\n })}\n </PopoverContent>\n </Popover>\n </PopoverTrigger>\n )}\n </div>\n\n {/* Description is hidden when field is invalid (unless disabled) to make room for error message */}\n {descriptionProp && !isSmall && (!isInvalid || isDisabled) && (\n <AriaText\n className={clsx(styles.description, classNames?.description)}\n slot='description'\n >\n {descriptionProp}\n </AriaText>\n )}\n\n <FieldError\n className={composeRenderProps(classNames?.error, (className) =>\n clsx(styles.error, className),\n )}\n >\n {effectiveErrorMessage}\n </FieldError>\n\n <DialogTrigger\n isOpen={paste.showDisambiguationModal}\n onOpenChange={paste.setShowDisambiguationModal}\n >\n <Button className='hidden'>Hidden Trigger</Button>\n <Dialog size='small'>\n <DialogTitle className={styles.modalTitle}>\n Select Coordinate Format\n </DialogTitle>\n <DialogContent>\n <p className={styles.modalDescription}>\n The pasted value matches multiple coordinate formats. Please\n select the correct interpretation:\n </p>\n\n <RadioGroup\n classNames={{ group: styles.formatOptions }}\n value={paste.selectedDisambiguationFormat}\n onChange={(value) =>\n paste.setSelectedDisambiguationFormat(\n value as CoordinateSystem,\n )\n }\n >\n {paste.disambiguationMatches.map((match) => (\n <Radio key={match.format} value={match.format}>\n <div className={styles.modalOptionContent}>\n <span className={styles.formatOptionLabel}>\n {COORDINATE_FORMAT_NAMES[match.format]}\n </span>\n <span className={styles.formatOptionValue}>\n {match.displayString}\n </span>\n </div>\n </Radio>\n ))}\n </RadioGroup>\n </DialogContent>\n <DialogFooter className={styles.modalActions}>\n <Button\n variant='flat'\n onPress={() => paste.setShowDisambiguationModal(false)}\n >\n Cancel\n </Button>\n <Button onPress={paste.handleDisambiguationSelect}>\n Apply Selected\n </Button>\n </DialogFooter>\n </Dialog>\n </DialogTrigger>\n </div>\n </Provider>\n );\n}\n"],"mappings":"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"}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { CoordinateSegmentProps } from "./types.js";
|
|
14
14
|
import "client-only";
|
|
15
|
-
import * as
|
|
15
|
+
import * as react_jsx_runtime69 from "react/jsx-runtime";
|
|
16
16
|
|
|
17
17
|
//#region src/components/coordinate-field/segment.d.ts
|
|
18
18
|
|
|
@@ -57,6 +57,7 @@ declare function CoordinateSegment({
|
|
|
57
57
|
maxLength,
|
|
58
58
|
className,
|
|
59
59
|
isDisabled,
|
|
60
|
+
isReadOnly,
|
|
60
61
|
allowedChars,
|
|
61
62
|
segmentRef,
|
|
62
63
|
segmentIndex,
|
|
@@ -65,7 +66,7 @@ declare function CoordinateSegment({
|
|
|
65
66
|
onAutoRetreat,
|
|
66
67
|
pad,
|
|
67
68
|
ariaLabel
|
|
68
|
-
}: CoordinateSegmentProps):
|
|
69
|
+
}: CoordinateSegmentProps): react_jsx_runtime69.JSX.Element;
|
|
69
70
|
//#endregion
|
|
70
71
|
export { CoordinateSegment };
|
|
71
72
|
//# sourceMappingURL=segment.d.ts.map
|
|
@@ -50,7 +50,7 @@ import { jsx } from "react/jsx-runtime";
|
|
|
50
50
|
* placeholder="N"
|
|
51
51
|
* />
|
|
52
52
|
*/
|
|
53
|
-
function CoordinateSegment({ value, onChange, onFocus, onBlur, onKeyDown, placeholder, maxLength, className, isDisabled, allowedChars, segmentRef, segmentIndex, totalSegments: _totalSegments, onAutoAdvance, onAutoRetreat, pad, ariaLabel }) {
|
|
53
|
+
function CoordinateSegment({ value, onChange, onFocus, onBlur, onKeyDown, placeholder, maxLength, className, isDisabled, isReadOnly, allowedChars, segmentRef, segmentIndex, totalSegments: _totalSegments, onAutoAdvance, onAutoRetreat, pad, ariaLabel }) {
|
|
54
54
|
const contextState = useCoordinateFieldStateContext();
|
|
55
55
|
const effectiveIsDisabled = contextState.isDisabled ?? isDisabled;
|
|
56
56
|
const dynamicWidth = useMemo(() => {
|
|
@@ -120,7 +120,9 @@ function CoordinateSegment({ value, onChange, onFocus, onBlur, onKeyDown, placeh
|
|
|
120
120
|
onBlur?.();
|
|
121
121
|
};
|
|
122
122
|
return /* @__PURE__ */ jsx("input", {
|
|
123
|
+
readOnly: isReadOnly,
|
|
123
124
|
ref: segmentRef,
|
|
125
|
+
tabIndex: isReadOnly ? -1 : 0,
|
|
124
126
|
type: "text",
|
|
125
127
|
value,
|
|
126
128
|
onChange: handleChange,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"segment.js","names":[],"sources":["../../../src/components/coordinate-field/segment.tsx"],"sourcesContent":["/*\n * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n'use client';\n\nimport 'client-only';\nimport { useMemo } from 'react';\nimport { useCoordinateFieldStateContext } from './context';\nimport type { ChangeEvent, FocusEvent, KeyboardEvent } from 'react';\nimport type { CoordinateSegmentProps } from './types';\n\n/**\n * CoordinateSegment - A controlled input component for a single coordinate segment\n *\n * This component represents one editable part of a coordinate (e.g., degrees, minutes, direction).\n * It handles character filtering, focus management, and keyboard navigation.\n *\n * Segment Types (determined by allowedChars):\n * - Numeric: \"[0-9\\\\-\\\\.]\" - for DD degrees, DDM/DMS degrees/minutes/seconds\n * - Directional: \"[NSEW]\" - for DDM/DMS direction indicators\n * - Alphanumeric: \"[0-9A-Z]\" - for MGRS/UTM zone identifiers\n *\n * @example\n * // Numeric segment (latitude degrees)\n * <CoordinateSegment\n * value={latDegrees}\n * onChange={setLatDegrees}\n * allowedChars=\"[0-9\\\\-\\\\.]\"\n * maxLength={10}\n * placeholder=\"00.00000\"\n * />\n *\n * @example\n * // Directional segment (latitude direction)\n * <CoordinateSegment\n * value={latDir}\n * onChange={setLatDir}\n * allowedChars=\"[NS]\"\n * maxLength={1}\n * placeholder=\"N\"\n * />\n */\nexport function CoordinateSegment({\n value,\n onChange,\n onFocus,\n onBlur,\n onKeyDown,\n placeholder,\n maxLength,\n className,\n isDisabled,\n allowedChars,\n segmentRef,\n segmentIndex,\n totalSegments: _totalSegments,\n onAutoAdvance,\n onAutoRetreat,\n pad,\n ariaLabel,\n}: CoordinateSegmentProps) {\n const contextState = useCoordinateFieldStateContext();\n\n const effectiveIsDisabled = contextState.isDisabled ?? isDisabled;\n\n // Calculate dynamic width based on focus state\n const dynamicWidth = useMemo(() => {\n if (maxLength === undefined) {\n return undefined;\n }\n\n // Default padding to 0.5 if not specified\n const padding = pad ?? 0.5;\n\n // When blurred, use value length (or maxLength if empty) + padding\n const contentLength = value.length > 0 ? value.length : maxLength;\n return contentLength + padding;\n }, [maxLength, pad, value.length]);\n\n const handleChange = (e: ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n\n if (allowedChars) {\n const regex = new RegExp(`^${allowedChars}*$`);\n if (!regex.test(newValue)) {\n return;\n }\n }\n\n if (maxLength && newValue.length > maxLength) {\n return;\n }\n\n onChange(newValue);\n\n if (maxLength && newValue.length === maxLength && onAutoAdvance) {\n const timeoutId = setTimeout(() => {\n onAutoAdvance();\n }, 0);\n contextState.registerTimeout(timeoutId);\n }\n };\n\n const handlePaste = (e: React.ClipboardEvent<HTMLInputElement>) => {\n const pastedText = e.clipboardData.getData('text');\n\n if (allowedChars) {\n const regex = new RegExp(`^${allowedChars}*$`);\n if (!regex.test(pastedText)) {\n e.preventDefault();\n return;\n }\n }\n\n if (maxLength && pastedText.length > maxLength) {\n e.preventDefault();\n onChange(pastedText.slice(0, maxLength));\n return;\n }\n };\n\n const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {\n const input = e.currentTarget;\n const cursorAtStart = input.selectionStart === 0;\n const cursorAtEnd = input.selectionStart === value.length;\n const isEmpty = value.length === 0;\n\n if (e.key === 'Backspace' && isEmpty && onAutoRetreat) {\n e.preventDefault();\n onAutoRetreat();\n return;\n }\n\n if (e.key === 'ArrowLeft' && cursorAtStart && onAutoRetreat) {\n e.preventDefault();\n onAutoRetreat();\n return;\n }\n\n if (e.key === 'ArrowRight' && cursorAtEnd && onAutoAdvance) {\n e.preventDefault();\n onAutoAdvance();\n return;\n }\n\n onKeyDown?.(e);\n };\n\n const handleFocus = (e: FocusEvent<HTMLInputElement>) => {\n e.target.select();\n onFocus?.();\n };\n\n const handleBlur = () => {\n onBlur?.();\n };\n\n return (\n <input\n ref={segmentRef}\n type='text'\n value={value}\n onChange={handleChange}\n onPaste={handlePaste}\n onKeyDown={handleKeyDown}\n onFocus={handleFocus}\n onBlur={handleBlur}\n placeholder={placeholder}\n maxLength={maxLength}\n className={className}\n disabled={effectiveIsDisabled}\n style={dynamicWidth ? { width: `${dynamicWidth}ch` } : undefined}\n aria-label={\n ariaLabel ||\n `Coordinate segment ${segmentIndex !== undefined ? segmentIndex + 1 : ''}`\n }\n aria-disabled={effectiveIsDisabled}\n autoComplete='off'\n inputMode={\n allowedChars?.includes('0-9')\n ? allowedChars.includes('\\\\-\\\\.')\n ? 'decimal'\n : 'numeric'\n : 'text'\n }\n />\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmDA,SAAgB,kBAAkB,EAChC,OACA,UACA,SACA,QACA,WACA,aACA,WACA,WACA,YACA,cACA,YACA,cACA,eAAe,gBACf,eACA,eACA,KACA,aACyB;CACzB,MAAM,eAAe,gCAAgC;CAErD,MAAM,sBAAsB,aAAa,cAAc;CAGvD,MAAM,eAAe,cAAc;AACjC,MAAI,cAAc,OAChB;EAIF,MAAM,UAAU,OAAO;AAIvB,UADsB,MAAM,SAAS,IAAI,MAAM,SAAS,aACjC;IACtB;EAAC;EAAW;EAAK,MAAM;EAAO,CAAC;CAElC,MAAM,gBAAgB,MAAqC;EACzD,MAAM,WAAW,EAAE,OAAO;AAE1B,MAAI,cAEF;OAAI,kBADU,IAAI,OAAO,IAAI,aAAa,IAAI,EACnC,KAAK,SAAS,CACvB;;AAIJ,MAAI,aAAa,SAAS,SAAS,UACjC;AAGF,WAAS,SAAS;AAElB,MAAI,aAAa,SAAS,WAAW,aAAa,eAAe;GAC/D,MAAM,YAAY,iBAAiB;AACjC,mBAAe;MACd,EAAE;AACL,gBAAa,gBAAgB,UAAU;;;CAI3C,MAAM,eAAe,MAA8C;EACjE,MAAM,aAAa,EAAE,cAAc,QAAQ,OAAO;AAElD,MAAI,cAEF;OAAI,kBADU,IAAI,OAAO,IAAI,aAAa,IAAI,EACnC,KAAK,WAAW,EAAE;AAC3B,MAAE,gBAAgB;AAClB;;;AAIJ,MAAI,aAAa,WAAW,SAAS,WAAW;AAC9C,KAAE,gBAAgB;AAClB,YAAS,WAAW,MAAM,GAAG,UAAU,CAAC;AACxC;;;CAIJ,MAAM,iBAAiB,MAAuC;EAC5D,MAAM,QAAQ,EAAE;EAChB,MAAM,gBAAgB,MAAM,mBAAmB;EAC/C,MAAM,cAAc,MAAM,mBAAmB,MAAM;EACnD,MAAM,UAAU,MAAM,WAAW;AAEjC,MAAI,EAAE,QAAQ,eAAe,WAAW,eAAe;AACrD,KAAE,gBAAgB;AAClB,kBAAe;AACf;;AAGF,MAAI,EAAE,QAAQ,eAAe,iBAAiB,eAAe;AAC3D,KAAE,gBAAgB;AAClB,kBAAe;AACf;;AAGF,MAAI,EAAE,QAAQ,gBAAgB,eAAe,eAAe;AAC1D,KAAE,gBAAgB;AAClB,kBAAe;AACf;;AAGF,cAAY,EAAE;;CAGhB,MAAM,eAAe,MAAoC;AACvD,IAAE,OAAO,QAAQ;AACjB,aAAW;;CAGb,MAAM,mBAAmB;AACvB,YAAU;;AAGZ,QACE,oBAAC;EACC,KAAK;EACL,MAAK;EACE;EACP,UAAU;EACV,SAAS;EACT,WAAW;EACX,SAAS;EACT,QAAQ;EACK;EACF;EACA;EACX,UAAU;EACV,OAAO,eAAe,EAAE,OAAO,GAAG,aAAa,KAAK,GAAG;EACvD,cACE,aACA,sBAAsB,iBAAiB,SAAY,eAAe,IAAI;EAExE,iBAAe;EACf,cAAa;EACb,WACE,cAAc,SAAS,MAAM,GACzB,aAAa,SAAS,SAAS,GAC7B,YACA,YACF;GAEN"}
|
|
1
|
+
{"version":3,"file":"segment.js","names":[],"sources":["../../../src/components/coordinate-field/segment.tsx"],"sourcesContent":["/*\n * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n'use client';\n\nimport 'client-only';\nimport { useMemo } from 'react';\nimport { useCoordinateFieldStateContext } from './context';\nimport type { ChangeEvent, FocusEvent, KeyboardEvent } from 'react';\nimport type { CoordinateSegmentProps } from './types';\n\n/**\n * CoordinateSegment - A controlled input component for a single coordinate segment\n *\n * This component represents one editable part of a coordinate (e.g., degrees, minutes, direction).\n * It handles character filtering, focus management, and keyboard navigation.\n *\n * Segment Types (determined by allowedChars):\n * - Numeric: \"[0-9\\\\-\\\\.]\" - for DD degrees, DDM/DMS degrees/minutes/seconds\n * - Directional: \"[NSEW]\" - for DDM/DMS direction indicators\n * - Alphanumeric: \"[0-9A-Z]\" - for MGRS/UTM zone identifiers\n *\n * @example\n * // Numeric segment (latitude degrees)\n * <CoordinateSegment\n * value={latDegrees}\n * onChange={setLatDegrees}\n * allowedChars=\"[0-9\\\\-\\\\.]\"\n * maxLength={10}\n * placeholder=\"00.00000\"\n * />\n *\n * @example\n * // Directional segment (latitude direction)\n * <CoordinateSegment\n * value={latDir}\n * onChange={setLatDir}\n * allowedChars=\"[NS]\"\n * maxLength={1}\n * placeholder=\"N\"\n * />\n */\nexport function CoordinateSegment({\n value,\n onChange,\n onFocus,\n onBlur,\n onKeyDown,\n placeholder,\n maxLength,\n className,\n isDisabled,\n isReadOnly,\n allowedChars,\n segmentRef,\n segmentIndex,\n totalSegments: _totalSegments,\n onAutoAdvance,\n onAutoRetreat,\n pad,\n ariaLabel,\n}: CoordinateSegmentProps) {\n const contextState = useCoordinateFieldStateContext();\n\n const effectiveIsDisabled = contextState.isDisabled ?? isDisabled;\n\n // Calculate dynamic width based on focus state\n const dynamicWidth = useMemo(() => {\n if (maxLength === undefined) {\n return undefined;\n }\n\n // Default padding to 0.5 if not specified\n const padding = pad ?? 0.5;\n\n // When blurred, use value length (or maxLength if empty) + padding\n const contentLength = value.length > 0 ? value.length : maxLength;\n return contentLength + padding;\n }, [maxLength, pad, value.length]);\n\n const handleChange = (e: ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n\n if (allowedChars) {\n const regex = new RegExp(`^${allowedChars}*$`);\n if (!regex.test(newValue)) {\n return;\n }\n }\n\n if (maxLength && newValue.length > maxLength) {\n return;\n }\n\n onChange(newValue);\n\n if (maxLength && newValue.length === maxLength && onAutoAdvance) {\n const timeoutId = setTimeout(() => {\n onAutoAdvance();\n }, 0);\n contextState.registerTimeout(timeoutId);\n }\n };\n\n const handlePaste = (e: React.ClipboardEvent<HTMLInputElement>) => {\n const pastedText = e.clipboardData.getData('text');\n\n if (allowedChars) {\n const regex = new RegExp(`^${allowedChars}*$`);\n if (!regex.test(pastedText)) {\n e.preventDefault();\n return;\n }\n }\n\n if (maxLength && pastedText.length > maxLength) {\n e.preventDefault();\n onChange(pastedText.slice(0, maxLength));\n return;\n }\n };\n\n const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {\n const input = e.currentTarget;\n const cursorAtStart = input.selectionStart === 0;\n const cursorAtEnd = input.selectionStart === value.length;\n const isEmpty = value.length === 0;\n\n if (e.key === 'Backspace' && isEmpty && onAutoRetreat) {\n e.preventDefault();\n onAutoRetreat();\n return;\n }\n\n if (e.key === 'ArrowLeft' && cursorAtStart && onAutoRetreat) {\n e.preventDefault();\n onAutoRetreat();\n return;\n }\n\n if (e.key === 'ArrowRight' && cursorAtEnd && onAutoAdvance) {\n e.preventDefault();\n onAutoAdvance();\n return;\n }\n\n onKeyDown?.(e);\n };\n\n const handleFocus = (e: FocusEvent<HTMLInputElement>) => {\n e.target.select();\n onFocus?.();\n };\n\n const handleBlur = () => {\n onBlur?.();\n };\n\n return (\n <input\n readOnly={isReadOnly}\n ref={segmentRef}\n tabIndex={isReadOnly ? -1 : 0}\n type='text'\n value={value}\n onChange={handleChange}\n onPaste={handlePaste}\n onKeyDown={handleKeyDown}\n onFocus={handleFocus}\n onBlur={handleBlur}\n placeholder={placeholder}\n maxLength={maxLength}\n className={className}\n disabled={effectiveIsDisabled}\n style={dynamicWidth ? { width: `${dynamicWidth}ch` } : undefined}\n aria-label={\n ariaLabel ||\n `Coordinate segment ${segmentIndex !== undefined ? segmentIndex + 1 : ''}`\n }\n aria-disabled={effectiveIsDisabled}\n autoComplete='off'\n inputMode={\n allowedChars?.includes('0-9')\n ? allowedChars.includes('\\\\-\\\\.')\n ? 'decimal'\n : 'numeric'\n : 'text'\n }\n />\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmDA,SAAgB,kBAAkB,EAChC,OACA,UACA,SACA,QACA,WACA,aACA,WACA,WACA,YACA,YACA,cACA,YACA,cACA,eAAe,gBACf,eACA,eACA,KACA,aACyB;CACzB,MAAM,eAAe,gCAAgC;CAErD,MAAM,sBAAsB,aAAa,cAAc;CAGvD,MAAM,eAAe,cAAc;AACjC,MAAI,cAAc,OAChB;EAIF,MAAM,UAAU,OAAO;AAIvB,UADsB,MAAM,SAAS,IAAI,MAAM,SAAS,aACjC;IACtB;EAAC;EAAW;EAAK,MAAM;EAAO,CAAC;CAElC,MAAM,gBAAgB,MAAqC;EACzD,MAAM,WAAW,EAAE,OAAO;AAE1B,MAAI,cAEF;OAAI,kBADU,IAAI,OAAO,IAAI,aAAa,IAAI,EACnC,KAAK,SAAS,CACvB;;AAIJ,MAAI,aAAa,SAAS,SAAS,UACjC;AAGF,WAAS,SAAS;AAElB,MAAI,aAAa,SAAS,WAAW,aAAa,eAAe;GAC/D,MAAM,YAAY,iBAAiB;AACjC,mBAAe;MACd,EAAE;AACL,gBAAa,gBAAgB,UAAU;;;CAI3C,MAAM,eAAe,MAA8C;EACjE,MAAM,aAAa,EAAE,cAAc,QAAQ,OAAO;AAElD,MAAI,cAEF;OAAI,kBADU,IAAI,OAAO,IAAI,aAAa,IAAI,EACnC,KAAK,WAAW,EAAE;AAC3B,MAAE,gBAAgB;AAClB;;;AAIJ,MAAI,aAAa,WAAW,SAAS,WAAW;AAC9C,KAAE,gBAAgB;AAClB,YAAS,WAAW,MAAM,GAAG,UAAU,CAAC;AACxC;;;CAIJ,MAAM,iBAAiB,MAAuC;EAC5D,MAAM,QAAQ,EAAE;EAChB,MAAM,gBAAgB,MAAM,mBAAmB;EAC/C,MAAM,cAAc,MAAM,mBAAmB,MAAM;EACnD,MAAM,UAAU,MAAM,WAAW;AAEjC,MAAI,EAAE,QAAQ,eAAe,WAAW,eAAe;AACrD,KAAE,gBAAgB;AAClB,kBAAe;AACf;;AAGF,MAAI,EAAE,QAAQ,eAAe,iBAAiB,eAAe;AAC3D,KAAE,gBAAgB;AAClB,kBAAe;AACf;;AAGF,MAAI,EAAE,QAAQ,gBAAgB,eAAe,eAAe;AAC1D,KAAE,gBAAgB;AAClB,kBAAe;AACf;;AAGF,cAAY,EAAE;;CAGhB,MAAM,eAAe,MAAoC;AACvD,IAAE,OAAO,QAAQ;AACjB,aAAW;;CAGb,MAAM,mBAAmB;AACvB,YAAU;;AAGZ,QACE,oBAAC;EACC,UAAU;EACV,KAAK;EACL,UAAU,aAAa,KAAK;EAC5B,MAAK;EACE;EACP,UAAU;EACV,SAAS;EACT,WAAW;EACX,SAAS;EACT,QAAQ;EACK;EACF;EACA;EACX,UAAU;EACV,OAAO,eAAe,EAAE,OAAO,GAAG,aAAa,KAAK,GAAG;EACvD,cACE,aACA,sBAAsB,iBAAiB,SAAY,eAAe,IAAI;EAExE,iBAAe;EACf,cAAa;EACb,WACE,cAAc,SAAS,MAAM,GACzB,aAAa,SAAS,SAAS,GAC7B,YACA,YACF;GAEN"}
|
|
@@ -41,6 +41,10 @@
|
|
|
41
41
|
@variant hover {
|
|
42
42
|
@apply outline-interactive-hover;
|
|
43
43
|
}
|
|
44
|
+
|
|
45
|
+
@variant read-only {
|
|
46
|
+
@apply px-0 outline-none;
|
|
47
|
+
}
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
.input {
|
|
@@ -73,6 +77,16 @@
|
|
|
73
77
|
@variant selection {
|
|
74
78
|
@apply fg-a11y-on-accent bg-accent-primary-bold;
|
|
75
79
|
}
|
|
80
|
+
|
|
81
|
+
@variant read-only {
|
|
82
|
+
@variant focus-visible {
|
|
83
|
+
@apply bg-surface-default;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@variant selection {
|
|
87
|
+
@apply bg-surface-default;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
76
90
|
}
|
|
77
91
|
|
|
78
92
|
.segmentGroup {
|
|
@@ -117,6 +117,8 @@ type CoordinateSegmentProps = {
|
|
|
117
117
|
className?: string;
|
|
118
118
|
/** Whether the segment is disabled */
|
|
119
119
|
isDisabled?: boolean;
|
|
120
|
+
/** Whether the segment is read-only */
|
|
121
|
+
isReadOnly?: boolean;
|
|
120
122
|
/** Regex pattern for allowed characters (e.g., "[0-9\\-\\.]" for numeric, "[NSEW]" for directional) */
|
|
121
123
|
allowedChars?: string;
|
|
122
124
|
/** Ref to the input element for programmatic focus management */
|