@ankhorage/surface 5.0.0 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +2 -2
- package/dist/{components/modal → features/modal/adapters/inbound}/Modal.d.ts +2 -1
- package/dist/features/modal/adapters/inbound/Modal.d.ts.map +1 -0
- package/dist/features/modal/adapters/inbound/Modal.js +51 -0
- package/dist/features/modal/adapters/inbound/Modal.js.map +1 -0
- package/dist/features/modal/public.d.ts +3 -0
- package/dist/features/modal/public.d.ts.map +1 -0
- package/dist/features/modal/public.js +2 -0
- package/dist/features/modal/public.js.map +1 -0
- package/dist/features/tabs/adapters/inbound/Tab.d.ts +5 -0
- package/dist/features/tabs/adapters/inbound/Tab.d.ts.map +1 -0
- package/dist/features/tabs/adapters/inbound/Tab.js +33 -0
- package/dist/features/tabs/adapters/inbound/Tab.js.map +1 -0
- package/dist/features/tabs/adapters/inbound/TabList.d.ts +5 -0
- package/dist/features/tabs/adapters/inbound/TabList.d.ts.map +1 -0
- package/dist/features/tabs/adapters/inbound/TabList.js +42 -0
- package/dist/features/tabs/adapters/inbound/TabList.js.map +1 -0
- package/dist/features/tabs/adapters/inbound/TabPanel.d.ts +5 -0
- package/dist/features/tabs/adapters/inbound/TabPanel.d.ts.map +1 -0
- package/dist/features/tabs/adapters/inbound/TabPanel.js +14 -0
- package/dist/features/tabs/adapters/inbound/TabPanel.js.map +1 -0
- package/dist/features/tabs/adapters/inbound/Tabs.d.ts +5 -0
- package/dist/features/tabs/adapters/inbound/Tabs.d.ts.map +1 -0
- package/dist/features/tabs/adapters/inbound/Tabs.js +12 -0
- package/dist/features/tabs/adapters/inbound/Tabs.js.map +1 -0
- package/dist/features/tabs/composition/TabsContext.d.ts +4 -0
- package/dist/features/tabs/composition/TabsContext.d.ts.map +1 -0
- package/dist/features/tabs/composition/TabsContext.js +3 -0
- package/dist/features/tabs/composition/TabsContext.js.map +1 -0
- package/dist/features/tabs/composition/useTabRegistration.d.ts +7 -0
- package/dist/features/tabs/composition/useTabRegistration.d.ts.map +1 -0
- package/dist/features/tabs/composition/useTabRegistration.js +20 -0
- package/dist/features/tabs/composition/useTabRegistration.js.map +1 -0
- package/dist/features/tabs/composition/useTabsContext.d.ts +4 -0
- package/dist/features/tabs/composition/useTabsContext.d.ts.map +1 -0
- package/dist/{components/tabs/context.js → features/tabs/composition/useTabsContext.js} +4 -4
- package/dist/features/tabs/composition/useTabsContext.js.map +1 -0
- package/dist/features/tabs/composition/useTabsController.d.ts +4 -0
- package/dist/features/tabs/composition/useTabsController.d.ts.map +1 -0
- package/dist/features/tabs/composition/useTabsController.js +43 -0
- package/dist/features/tabs/composition/useTabsController.js.map +1 -0
- package/dist/features/tabs/public.d.ts +6 -0
- package/dist/features/tabs/public.d.ts.map +1 -0
- package/dist/features/tabs/public.js +5 -0
- package/dist/features/tabs/public.js.map +1 -0
- package/dist/features/tabs/utils/resolveNextTabValue.d.ts +4 -0
- package/dist/features/tabs/utils/resolveNextTabValue.d.ts.map +1 -0
- package/dist/{components/tabs/navigation.js → features/tabs/utils/resolveNextTabValue.js} +10 -13
- package/dist/features/tabs/utils/resolveNextTabValue.js.map +1 -0
- package/dist/features/tabs/utils/resolveTabElementId.d.ts +3 -0
- package/dist/features/tabs/utils/resolveTabElementId.d.ts.map +1 -0
- package/dist/features/tabs/utils/resolveTabElementId.js +10 -0
- package/dist/features/tabs/utils/resolveTabElementId.js.map +1 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/{components/modal/types.d.ts → types/modal.d.ts} +2 -2
- package/dist/types/modal.d.ts.map +1 -0
- package/dist/types/modal.js +2 -0
- package/dist/types/modal.js.map +1 -0
- package/dist/types/tabs.d.ts +43 -0
- package/dist/types/tabs.d.ts.map +1 -0
- package/dist/types/tabs.js +2 -0
- package/dist/types/tabs.js.map +1 -0
- package/package.json +1 -1
- package/src/features/modal/adapters/inbound/Modal.tsx +74 -0
- package/src/features/modal/public.ts +2 -0
- package/src/features/tabs/adapters/inbound/Tab.tsx +67 -0
- package/src/features/tabs/adapters/inbound/TabList.tsx +50 -0
- package/src/{components/tabs → features/tabs/adapters/inbound}/TabPanel.tsx +6 -10
- package/src/features/tabs/adapters/inbound/Tabs.tsx +17 -0
- package/src/features/tabs/composition/TabsContext.tsx +5 -0
- package/src/features/tabs/composition/useTabRegistration.ts +27 -0
- package/src/features/tabs/composition/useTabsContext.ts +13 -0
- package/src/features/tabs/composition/useTabsController.ts +55 -0
- package/src/features/tabs/public.ts +5 -0
- package/src/{components/tabs/navigation.test.ts → features/tabs/utils/resolveNextTabValue.test.ts} +2 -2
- package/src/features/tabs/utils/resolveNextTabValue.ts +24 -0
- package/src/features/tabs/utils/resolveTabElementId.test.ts +19 -0
- package/src/features/tabs/utils/resolveTabElementId.ts +14 -0
- package/src/index.test.ts +4 -2
- package/src/index.ts +4 -4
- package/src/{components/modal/types.ts → types/modal.ts} +1 -1
- package/src/types/tabs.ts +51 -0
- package/dist/components/modal/Modal.d.ts.map +0 -1
- package/dist/components/modal/Modal.js +0 -59
- package/dist/components/modal/Modal.js.map +0 -1
- package/dist/components/modal/index.d.ts +0 -3
- package/dist/components/modal/index.d.ts.map +0 -1
- package/dist/components/modal/index.js +0 -2
- package/dist/components/modal/index.js.map +0 -1
- package/dist/components/modal/types.d.ts.map +0 -1
- package/dist/components/modal/types.js +0 -2
- package/dist/components/modal/types.js.map +0 -1
- package/dist/components/tabs/Tab.d.ts +0 -4
- package/dist/components/tabs/Tab.d.ts.map +0 -1
- package/dist/components/tabs/Tab.js +0 -48
- package/dist/components/tabs/Tab.js.map +0 -1
- package/dist/components/tabs/TabList.d.ts +0 -4
- package/dist/components/tabs/TabList.d.ts.map +0 -1
- package/dist/components/tabs/TabList.js +0 -37
- package/dist/components/tabs/TabList.js.map +0 -1
- package/dist/components/tabs/TabPanel.d.ts +0 -4
- package/dist/components/tabs/TabPanel.d.ts.map +0 -1
- package/dist/components/tabs/TabPanel.js +0 -16
- package/dist/components/tabs/TabPanel.js.map +0 -1
- package/dist/components/tabs/Tabs.d.ts +0 -4
- package/dist/components/tabs/Tabs.d.ts.map +0 -1
- package/dist/components/tabs/Tabs.js +0 -54
- package/dist/components/tabs/Tabs.js.map +0 -1
- package/dist/components/tabs/a11y.d.ts +0 -3
- package/dist/components/tabs/a11y.d.ts.map +0 -1
- package/dist/components/tabs/a11y.js +0 -13
- package/dist/components/tabs/a11y.js.map +0 -1
- package/dist/components/tabs/context.d.ts +0 -20
- package/dist/components/tabs/context.d.ts.map +0 -1
- package/dist/components/tabs/context.js.map +0 -1
- package/dist/components/tabs/index.d.ts +0 -6
- package/dist/components/tabs/index.d.ts.map +0 -1
- package/dist/components/tabs/index.js +0 -5
- package/dist/components/tabs/index.js.map +0 -1
- package/dist/components/tabs/navigation.d.ts +0 -3
- package/dist/components/tabs/navigation.d.ts.map +0 -1
- package/dist/components/tabs/navigation.js.map +0 -1
- package/dist/components/tabs/types.d.ts +0 -26
- package/dist/components/tabs/types.d.ts.map +0 -1
- package/dist/components/tabs/types.js +0 -2
- package/dist/components/tabs/types.js.map +0 -1
- package/src/components/modal/Modal.tsx +0 -96
- package/src/components/modal/index.ts +0 -2
- package/src/components/tabs/Tab.tsx +0 -89
- package/src/components/tabs/TabList.tsx +0 -51
- package/src/components/tabs/Tabs.tsx +0 -67
- package/src/components/tabs/a11y.test.ts +0 -15
- package/src/components/tabs/a11y.ts +0 -15
- package/src/components/tabs/context.tsx +0 -31
- package/src/components/tabs/index.ts +0 -5
- package/src/components/tabs/navigation.ts +0 -32
- package/src/components/tabs/types.ts +0 -30
package/dist/index.d.ts
CHANGED
|
@@ -6,12 +6,8 @@ export type { LabelProps } from './components/label';
|
|
|
6
6
|
export { Label } from './components/label';
|
|
7
7
|
export type { ListItemProps } from './components/list-item';
|
|
8
8
|
export { ListItem } from './components/list-item';
|
|
9
|
-
export type { ModalProps } from './components/modal';
|
|
10
|
-
export { Modal } from './components/modal';
|
|
11
9
|
export type { SwitchProps } from './components/switch';
|
|
12
10
|
export { Switch } from './components/switch';
|
|
13
|
-
export type { TabListProps, TabPanelProps, TabProps, TabsProps } from './components/tabs';
|
|
14
|
-
export { Tab, TabList, TabPanel, Tabs } from './components/tabs';
|
|
15
11
|
export type { TextareaProps } from './components/textarea';
|
|
16
12
|
export { Textarea } from './components/textarea';
|
|
17
13
|
export type { FontRuntime } from './context/FontContext';
|
|
@@ -41,12 +37,16 @@ export type { KeyboardAvoidingViewBehavior, KeyboardAvoidingViewProps, } from '.
|
|
|
41
37
|
export { KeyboardAvoidingView } from './features/keyboard-avoiding-view/public';
|
|
42
38
|
export type { BoxProps, ContainerProps, DividerProps, GridProps, StackProps, } from './features/layout/public';
|
|
43
39
|
export { Box, Container, Divider, Grid, Stack } from './features/layout/public';
|
|
40
|
+
export type { ModalProps } from './features/modal/public';
|
|
41
|
+
export { Modal } from './features/modal/public';
|
|
44
42
|
export type { PopoverAnchorRenderProps, PopoverPlacement, PopoverProps, } from './features/popover/public';
|
|
45
43
|
export { Popover } from './features/popover/public';
|
|
46
44
|
export type { PopoverMenuAction, PopoverMenuActionIntent, PopoverMenuProps, } from './features/popover-menu/public';
|
|
47
45
|
export { PopoverMenu } from './features/popover-menu/public';
|
|
48
46
|
export type { SurfaceProps, SurfaceVariant } from './features/surface/public';
|
|
49
47
|
export { Surface } from './features/surface/public';
|
|
48
|
+
export type { TabListProps, TabPanelProps, TabProps, TabsProps } from './features/tabs/public';
|
|
49
|
+
export { Tab, TabList, TabPanel, Tabs } from './features/tabs/public';
|
|
50
50
|
export type { ToastController, ToastOptions, ToastProps, ToastProviderProps, ToastStatus, } from './features/toast/public';
|
|
51
51
|
export { Toast, ToastProvider, useToast } from './features/toast/public';
|
|
52
52
|
export type { TooltipProps } from './features/tooltip/public';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,YAAY,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -2,9 +2,7 @@ export { Field } from './components/field';
|
|
|
2
2
|
export { HelperText } from './components/helper-text';
|
|
3
3
|
export { Label } from './components/label';
|
|
4
4
|
export { ListItem } from './components/list-item';
|
|
5
|
-
export { Modal } from './components/modal';
|
|
6
5
|
export { Switch } from './components/switch';
|
|
7
|
-
export { Tab, TabList, TabPanel, Tabs } from './components/tabs';
|
|
8
6
|
export { Textarea } from './components/textarea';
|
|
9
7
|
export { FontProvider, useFontContext } from './context/FontContext';
|
|
10
8
|
export { TranslationProvider, useTranslationContext } from './context/TranslationContext';
|
|
@@ -20,9 +18,11 @@ export { Icon, SUPPORTED_ICON_PROVIDERS } from './features/icon/public';
|
|
|
20
18
|
export { Image } from './features/image/public';
|
|
21
19
|
export { KeyboardAvoidingView } from './features/keyboard-avoiding-view/public';
|
|
22
20
|
export { Box, Container, Divider, Grid, Stack } from './features/layout/public';
|
|
21
|
+
export { Modal } from './features/modal/public';
|
|
23
22
|
export { Popover } from './features/popover/public';
|
|
24
23
|
export { PopoverMenu } from './features/popover-menu/public';
|
|
25
24
|
export { Surface } from './features/surface/public';
|
|
25
|
+
export { Tab, TabList, TabPanel, Tabs } from './features/tabs/public';
|
|
26
26
|
export { Toast, ToastProvider, useToast } from './features/toast/public';
|
|
27
27
|
export { Tooltip } from './features/tooltip/public';
|
|
28
28
|
export { Heading, Text } from './features/typography/public';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAElD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAElD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAErE,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAC1F,cAAc,mBAAmB,CAAC;AAUlC,OAAO,EACL,SAAS,EACT,gBAAgB,EAChB,aAAa,EACb,gBAAgB,GACjB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAEhD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE9D,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAE9C,OAAO,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAE3D,OAAO,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAC;AAErD,OAAO,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAS9D,OAAO,EAAE,IAAI,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAExE,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAKhD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0CAA0C,CAAC;AAQhF,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAEhF,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAMhD,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAMpD,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAE7D,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAEpD,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAQtE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEzE,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAEpD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;AAE7D,cAAc,UAAU,CAAC;AAEzB,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAOtD,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC","sourcesContent":["export type { FieldProps } from './components/field';\nexport { Field } from './components/field';\nexport type { HelperTextProps } from './components/helper-text';\nexport { HelperText } from './components/helper-text';\nexport type { LabelProps } from './components/label';\nexport { Label } from './components/label';\nexport type { ListItemProps } from './components/list-item';\nexport { ListItem } from './components/list-item';\nexport type { SwitchProps } from './components/switch';\nexport { Switch } from './components/switch';\nexport type { TextareaProps } from './components/textarea';\nexport { Textarea } from './components/textarea';\nexport type { FontRuntime } from './context/FontContext';\nexport { FontProvider, useFontContext } from './context/FontContext';\nexport type { I18nInstance, TranslationRuntime, Translator } from './context/TranslationContext';\nexport { TranslationProvider, useTranslationContext } from './context/TranslationContext';\nexport * from './core/responsive';\nexport type {\n AccordionContentProps,\n AccordionItemProps,\n AccordionMode,\n AccordionMultipleProps,\n AccordionProps,\n AccordionSingleProps,\n AccordionTriggerProps,\n} from './features/accordion/public';\nexport {\n Accordion,\n AccordionContent,\n AccordionItem,\n AccordionTrigger,\n} from './features/accordion/public';\nexport type { BadgeProps } from './features/badge/public';\nexport { Badge } from './features/badge/public';\nexport type { ButtonIconSpec, ButtonProps, IconButtonProps } from './features/button/public';\nexport { Button, IconButton } from './features/button/public';\nexport type { CardProps } from './features/card/public';\nexport { Card } from './features/card/public';\nexport type { CheckboxProps } from './features/form/checkbox/public';\nexport { Checkbox } from './features/form/checkbox/public';\nexport type { RadioProps } from './features/form/radio/public';\nexport { Radio } from './features/form/radio/public';\nexport type { TextInputProps } from './features/form/text-input/public';\nexport { TextInput } from './features/form/text-input/public';\nexport type {\n FontIconSource,\n IconProps,\n IconProvider,\n IconSource,\n IconVariant,\n SvgIconSource,\n} from './features/icon/public';\nexport { Icon, SUPPORTED_ICON_PROVIDERS } from './features/icon/public';\nexport type { ImageFit, ImageProps, SurfaceImageSource } from './features/image/public';\nexport { Image } from './features/image/public';\nexport type {\n KeyboardAvoidingViewBehavior,\n KeyboardAvoidingViewProps,\n} from './features/keyboard-avoiding-view/public';\nexport { KeyboardAvoidingView } from './features/keyboard-avoiding-view/public';\nexport type {\n BoxProps,\n ContainerProps,\n DividerProps,\n GridProps,\n StackProps,\n} from './features/layout/public';\nexport { Box, Container, Divider, Grid, Stack } from './features/layout/public';\nexport type { ModalProps } from './features/modal/public';\nexport { Modal } from './features/modal/public';\nexport type {\n PopoverAnchorRenderProps,\n PopoverPlacement,\n PopoverProps,\n} from './features/popover/public';\nexport { Popover } from './features/popover/public';\nexport type {\n PopoverMenuAction,\n PopoverMenuActionIntent,\n PopoverMenuProps,\n} from './features/popover-menu/public';\nexport { PopoverMenu } from './features/popover-menu/public';\nexport type { SurfaceProps, SurfaceVariant } from './features/surface/public';\nexport { Surface } from './features/surface/public';\nexport type { TabListProps, TabPanelProps, TabProps, TabsProps } from './features/tabs/public';\nexport { Tab, TabList, TabPanel, Tabs } from './features/tabs/public';\nexport type {\n ToastController,\n ToastOptions,\n ToastProps,\n ToastProviderProps,\n ToastStatus,\n} from './features/toast/public';\nexport { Toast, ToastProvider, useToast } from './features/toast/public';\nexport type { TooltipProps } from './features/tooltip/public';\nexport { Tooltip } from './features/tooltip/public';\nexport type { HeadingLevel, HeadingProps, TextProps } from './features/typography/public';\nexport { Heading, Text } from './features/typography/public';\nexport type { InteractionPolicy, InteractionPolicyProps } from './interactionPolicy';\nexport * from './layout';\nexport type { ButtonBaseProps } from './primitives/button-base';\nexport { ButtonBase } from './primitives/button-base';\nexport type {\n SurfaceColor,\n SurfaceEmphasis,\n SurfacePaletteColor,\n SurfaceStatusColor,\n} from './surfaceColor';\nexport {\n SURFACE_COLORS,\n SURFACE_EMPHASES,\n SURFACE_PALETTE_COLORS,\n SURFACE_STATUS_COLORS,\n} from './surfaceColor';\nexport * from './theme';\nexport { isDeepEqual } from './utils/deepEqual';\nexport { deepMerge } from './utils/deepMerge';\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
|
-
import type { InteractionPolicy } from '
|
|
2
|
+
import type { InteractionPolicy } from '../interactionPolicy';
|
|
3
3
|
export interface ModalProps {
|
|
4
4
|
visible: boolean;
|
|
5
5
|
onDismiss?: (() => void) | undefined;
|
|
@@ -8,4 +8,4 @@ export interface ModalProps {
|
|
|
8
8
|
interactionPolicy?: InteractionPolicy;
|
|
9
9
|
testID?: string;
|
|
10
10
|
}
|
|
11
|
-
//# sourceMappingURL=
|
|
11
|
+
//# sourceMappingURL=modal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modal.d.ts","sourceRoot":"","sources":["../../src/types/modal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modal.js","sourceRoot":"","sources":["../../src/types/modal.ts"],"names":[],"mappings":"","sourcesContent":["import type React from 'react';\n\nimport type { InteractionPolicy } from '../interactionPolicy';\n\nexport interface ModalProps {\n visible: boolean;\n onDismiss?: (() => void) | undefined;\n children?: React.ReactNode;\n closeOnBackdrop?: boolean;\n interactionPolicy?: InteractionPolicy;\n testID?: string;\n}\n"]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import type { InteractionPolicy } from '../interactionPolicy';
|
|
3
|
+
export interface TabsProps {
|
|
4
|
+
children?: React.ReactNode;
|
|
5
|
+
value?: string;
|
|
6
|
+
defaultValue?: string;
|
|
7
|
+
onValueChange?: ((value: string) => void) | undefined;
|
|
8
|
+
testID?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface TabListProps {
|
|
11
|
+
children?: React.ReactNode;
|
|
12
|
+
testID?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface TabProps {
|
|
15
|
+
value: string;
|
|
16
|
+
children?: React.ReactNode;
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
interactionPolicy?: InteractionPolicy;
|
|
19
|
+
testID?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface TabPanelProps {
|
|
22
|
+
value: string;
|
|
23
|
+
children?: React.ReactNode;
|
|
24
|
+
testID?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface TabRegistration {
|
|
27
|
+
disabled: boolean;
|
|
28
|
+
focus: () => void;
|
|
29
|
+
value: string;
|
|
30
|
+
}
|
|
31
|
+
export interface TabsContextValue {
|
|
32
|
+
activeValue: string | undefined;
|
|
33
|
+
focusedValue: string | undefined;
|
|
34
|
+
getPanelId: (value: string) => string;
|
|
35
|
+
getTabId: (value: string) => string;
|
|
36
|
+
registerTab: (tab: TabRegistration) => void;
|
|
37
|
+
setActiveValue: (value: string) => void;
|
|
38
|
+
setFocusedValue: (value: string | undefined) => void;
|
|
39
|
+
tabs: readonly TabRegistration[];
|
|
40
|
+
unregisterTab: (value: string) => void;
|
|
41
|
+
}
|
|
42
|
+
export type TabNavigationKey = 'ArrowLeft' | 'ArrowRight' | 'ArrowUp' | 'ArrowDown' | 'Home' | 'End';
|
|
43
|
+
//# sourceMappingURL=tabs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["../../src/types/tabs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,WAAW,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,CAAC;IAC5C,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IACrD,IAAI,EAAE,SAAS,eAAe,EAAE,CAAC;IACjC,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AAED,MAAM,MAAM,gBAAgB,GAC1B,WAAW,GAAG,YAAY,GAAG,SAAS,GAAG,WAAW,GAAG,MAAM,GAAG,KAAK,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tabs.js","sourceRoot":"","sources":["../../src/types/tabs.ts"],"names":[],"mappings":"","sourcesContent":["import type React from 'react';\n\nimport type { InteractionPolicy } from '../interactionPolicy';\n\nexport interface TabsProps {\n children?: React.ReactNode;\n value?: string;\n defaultValue?: string;\n onValueChange?: ((value: string) => void) | undefined;\n testID?: string;\n}\n\nexport interface TabListProps {\n children?: React.ReactNode;\n testID?: string;\n}\n\nexport interface TabProps {\n value: string;\n children?: React.ReactNode;\n disabled?: boolean;\n interactionPolicy?: InteractionPolicy;\n testID?: string;\n}\n\nexport interface TabPanelProps {\n value: string;\n children?: React.ReactNode;\n testID?: string;\n}\n\nexport interface TabRegistration {\n disabled: boolean;\n focus: () => void;\n value: string;\n}\n\nexport interface TabsContextValue {\n activeValue: string | undefined;\n focusedValue: string | undefined;\n getPanelId: (value: string) => string;\n getTabId: (value: string) => string;\n registerTab: (tab: TabRegistration) => void;\n setActiveValue: (value: string) => void;\n setFocusedValue: (value: string | undefined) => void;\n tabs: readonly TabRegistration[];\n unregisterTab: (value: string) => void;\n}\n\nexport type TabNavigationKey =\n 'ArrowLeft' | 'ArrowRight' | 'ArrowUp' | 'ArrowDown' | 'Home' | 'End';\n"]}
|
package/package.json
CHANGED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Pressable, StyleSheet, View, type ViewStyle } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { FocusScope } from '../../../../internal/focus/FocusScope';
|
|
5
|
+
import { Portal } from '../../../../internal/overlay/Portal';
|
|
6
|
+
import { resolvePointerEvents } from '../../../../internal/resolvePointerEvents';
|
|
7
|
+
import { resolveOverlayAnimation } from '../../../../internal/resolvers';
|
|
8
|
+
import { Center } from '../../../../layout';
|
|
9
|
+
import { useTheme } from '../../../../theme/ThemeContext';
|
|
10
|
+
import type { ModalProps } from '../../../../types/modal';
|
|
11
|
+
import { Surface } from '../../../surface/public';
|
|
12
|
+
|
|
13
|
+
const boxNonePointerEvents = resolvePointerEvents('box-none');
|
|
14
|
+
|
|
15
|
+
/*** Renders the generic Surface modal overlay and focus boundary. */
|
|
16
|
+
export function Modal({
|
|
17
|
+
visible,
|
|
18
|
+
onDismiss,
|
|
19
|
+
children,
|
|
20
|
+
closeOnBackdrop = true,
|
|
21
|
+
interactionPolicy = 'enabled',
|
|
22
|
+
testID,
|
|
23
|
+
}: ModalProps) {
|
|
24
|
+
const { theme } = useTheme();
|
|
25
|
+
const animation = resolveOverlayAnimation('modal');
|
|
26
|
+
const passive = interactionPolicy === 'passive';
|
|
27
|
+
const backdropPress = passive || !closeOnBackdrop ? undefined : onDismiss;
|
|
28
|
+
|
|
29
|
+
if (!visible) return null;
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<Portal layer="modal" visible={visible}>
|
|
33
|
+
<View {...boxNonePointerEvents.props} style={[boxNonePointerEvents.style, styles.fill]}>
|
|
34
|
+
<Pressable
|
|
35
|
+
onPress={backdropPress}
|
|
36
|
+
style={[
|
|
37
|
+
styles.fill,
|
|
38
|
+
resolveBackdropStyle(theme.semantics.neutral.text, animation.backdropOpacity),
|
|
39
|
+
]}
|
|
40
|
+
testID={testID ? `${testID}-backdrop` : undefined}
|
|
41
|
+
/>
|
|
42
|
+
<FocusScope
|
|
43
|
+
active={visible}
|
|
44
|
+
onEscape={passive ? undefined : onDismiss}
|
|
45
|
+
testID={testID ? `${testID}-focus` : undefined}
|
|
46
|
+
>
|
|
47
|
+
<Center p="l" style={styles.center}>
|
|
48
|
+
<View accessible accessibilityViewIsModal style={styles.content}>
|
|
49
|
+
<Surface p="l" style={styles.surface} testID={testID} variant="raised">
|
|
50
|
+
{children}
|
|
51
|
+
</Surface>
|
|
52
|
+
</View>
|
|
53
|
+
</Center>
|
|
54
|
+
</FocusScope>
|
|
55
|
+
</View>
|
|
56
|
+
</Portal>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/*** Resolves the runtime backdrop color and opacity without inline JSX styles. */
|
|
61
|
+
function resolveBackdropStyle(backgroundColor: string, opacity: number): ViewStyle {
|
|
62
|
+
return { backgroundColor, opacity };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const styles = StyleSheet.create({
|
|
66
|
+
center: { flex: 1 },
|
|
67
|
+
content: { maxWidth: 560, width: '100%' },
|
|
68
|
+
fill: { bottom: 0, left: 0, position: 'absolute', right: 0, top: 0 },
|
|
69
|
+
surface: {
|
|
70
|
+
shadowOffset: { height: 8, width: 0 },
|
|
71
|
+
shadowOpacity: 0.14,
|
|
72
|
+
shadowRadius: 18,
|
|
73
|
+
},
|
|
74
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Pressable, type ViewStyle } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { useTheme } from '../../../../theme/ThemeContext';
|
|
5
|
+
import type { TabProps } from '../../../../types/tabs';
|
|
6
|
+
import { Box } from '../../../layout/public';
|
|
7
|
+
import { Text } from '../../../typography/public';
|
|
8
|
+
import { useTabRegistration } from '../../composition/useTabRegistration';
|
|
9
|
+
import { useTabsContext } from '../../composition/useTabsContext';
|
|
10
|
+
|
|
11
|
+
/*** Renders one accessible selectable tab inside a Tabs context. */
|
|
12
|
+
export function Tab({
|
|
13
|
+
value,
|
|
14
|
+
children,
|
|
15
|
+
disabled = false,
|
|
16
|
+
interactionPolicy = 'enabled',
|
|
17
|
+
testID,
|
|
18
|
+
}: TabProps) {
|
|
19
|
+
const { theme } = useTheme();
|
|
20
|
+
const { activeValue, getPanelId, getTabId, setActiveValue, setFocusedValue } = useTabsContext();
|
|
21
|
+
const pressableRef = useTabRegistration({ disabled, value });
|
|
22
|
+
const selected = activeValue === value;
|
|
23
|
+
const passive = interactionPolicy === 'passive';
|
|
24
|
+
const onPress = passive || disabled ? undefined : () => setActiveValue(value);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<Pressable
|
|
28
|
+
accessibilityLabel={undefined}
|
|
29
|
+
accessibilityRole="tab"
|
|
30
|
+
accessibilityState={{ disabled, selected }}
|
|
31
|
+
aria-controls={getPanelId(value)}
|
|
32
|
+
disabled={disabled}
|
|
33
|
+
nativeID={getTabId(value)}
|
|
34
|
+
onBlur={() => setFocusedValue(undefined)}
|
|
35
|
+
onFocus={() => setFocusedValue(value)}
|
|
36
|
+
onPress={onPress}
|
|
37
|
+
ref={pressableRef}
|
|
38
|
+
testID={testID}
|
|
39
|
+
>
|
|
40
|
+
<Box
|
|
41
|
+
px="m"
|
|
42
|
+
py="s"
|
|
43
|
+
style={resolveTabStyle({
|
|
44
|
+
borderColor: selected
|
|
45
|
+
? theme.semantics.action.primary.base
|
|
46
|
+
: theme.semantics.border.default,
|
|
47
|
+
disabled,
|
|
48
|
+
})}
|
|
49
|
+
>
|
|
50
|
+
<Text color={selected ? 'primary' : undefined} variant="label" weight="medium">
|
|
51
|
+
{children}
|
|
52
|
+
</Text>
|
|
53
|
+
</Box>
|
|
54
|
+
</Pressable>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/*** Resolves active and disabled visual state without inline JSX styles. */
|
|
59
|
+
function resolveTabStyle({
|
|
60
|
+
borderColor,
|
|
61
|
+
disabled,
|
|
62
|
+
}: {
|
|
63
|
+
borderColor: string;
|
|
64
|
+
disabled: boolean;
|
|
65
|
+
}): ViewStyle {
|
|
66
|
+
return { borderBottomColor: borderColor, borderBottomWidth: 2, opacity: disabled ? 0.64 : 1 };
|
|
67
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { StyleSheet } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { useFocusManager } from '../../../../internal/focus/useFocusManager';
|
|
5
|
+
import type { TabListProps, TabNavigationKey } from '../../../../types/tabs';
|
|
6
|
+
import { Box } from '../../../layout/public';
|
|
7
|
+
import { useTabsContext } from '../../composition/useTabsContext';
|
|
8
|
+
import { resolveNextTabValue } from '../../utils/resolveNextTabValue';
|
|
9
|
+
|
|
10
|
+
const navigationKeys: readonly string[] = [
|
|
11
|
+
'ArrowLeft',
|
|
12
|
+
'ArrowRight',
|
|
13
|
+
'ArrowUp',
|
|
14
|
+
'ArrowDown',
|
|
15
|
+
'Home',
|
|
16
|
+
'End',
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
/*** Renders the accessible tab list and owns keyboard focus navigation. */
|
|
20
|
+
export function TabList({ children, testID }: TabListProps) {
|
|
21
|
+
const { bindKeydown } = useFocusManager();
|
|
22
|
+
const { focusedValue, setActiveValue, tabs } = useTabsContext();
|
|
23
|
+
|
|
24
|
+
React.useEffect(() => {
|
|
25
|
+
if (!focusedValue) return undefined;
|
|
26
|
+
|
|
27
|
+
return bindKeydown((event) => {
|
|
28
|
+
if (!isTabNavigationKey(event.key)) return;
|
|
29
|
+
const nextValue = resolveNextTabValue(tabs, focusedValue, event.key);
|
|
30
|
+
if (!nextValue) return;
|
|
31
|
+
|
|
32
|
+
event.preventDefault();
|
|
33
|
+
tabs.find((tab) => tab.value === nextValue)?.focus();
|
|
34
|
+
setActiveValue(nextValue);
|
|
35
|
+
});
|
|
36
|
+
}, [bindKeydown, focusedValue, setActiveValue, tabs]);
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<Box accessibilityRole="tablist" style={styles.list} testID={testID}>
|
|
40
|
+
{children}
|
|
41
|
+
</Box>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/*** Narrows keyboard event keys to the tab navigation key contract. */
|
|
46
|
+
function isTabNavigationKey(key: string | undefined): key is TabNavigationKey {
|
|
47
|
+
return key !== undefined && navigationKeys.includes(key);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const styles = StyleSheet.create({ list: { flexDirection: 'row' } });
|
|
@@ -1,26 +1,22 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { View } from 'react-native';
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
4
|
+
import type { TabPanelProps } from '../../../../types/tabs';
|
|
5
|
+
import { useTabsContext } from '../../composition/useTabsContext';
|
|
6
6
|
|
|
7
7
|
const TAB_PANEL_ROLE = 'tabpanel' as React.ComponentProps<typeof View>['accessibilityRole'];
|
|
8
8
|
|
|
9
|
+
/*** Renders the content panel associated with the active tab value. */
|
|
9
10
|
export function TabPanel({ value, children, testID }: TabPanelProps) {
|
|
10
11
|
const { activeValue, getPanelId, getTabId } = useTabsContext();
|
|
11
12
|
|
|
12
|
-
if (activeValue !== value)
|
|
13
|
-
return null;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const tabId = getTabId(value);
|
|
17
|
-
const panelId = getPanelId(value);
|
|
13
|
+
if (activeValue !== value) return null;
|
|
18
14
|
|
|
19
15
|
return (
|
|
20
16
|
<View
|
|
21
|
-
accessibilityLabelledBy={
|
|
17
|
+
accessibilityLabelledBy={getTabId(value)}
|
|
22
18
|
accessibilityRole={TAB_PANEL_ROLE}
|
|
23
|
-
nativeID={
|
|
19
|
+
nativeID={getPanelId(value)}
|
|
24
20
|
testID={testID}
|
|
25
21
|
>
|
|
26
22
|
{children}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { TabsProps } from '../../../../types/tabs';
|
|
4
|
+
import { Box } from '../../../layout/public';
|
|
5
|
+
import { TabsContext } from '../../composition/TabsContext';
|
|
6
|
+
import { useTabsController } from '../../composition/useTabsController';
|
|
7
|
+
|
|
8
|
+
/*** Provides accessible tab selection state to TabList, Tab, and TabPanel children. */
|
|
9
|
+
export function Tabs({ children, ...props }: TabsProps) {
|
|
10
|
+
const contextValue = useTabsController(props);
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<TabsContext value={contextValue}>
|
|
14
|
+
<Box testID={props.testID}>{children}</Box>
|
|
15
|
+
</TabsContext>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { Pressable } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { useTabsContext } from './useTabsContext';
|
|
5
|
+
|
|
6
|
+
/*** Registers one focusable tab with the owning Tabs context. */
|
|
7
|
+
export function useTabRegistration({ disabled, value }: { disabled: boolean; value: string }) {
|
|
8
|
+
const { registerTab, unregisterTab } = useTabsContext();
|
|
9
|
+
const pressableRef = React.useRef<React.ElementRef<typeof Pressable> | null>(null);
|
|
10
|
+
|
|
11
|
+
React.useEffect(() => {
|
|
12
|
+
registerTab({
|
|
13
|
+
disabled,
|
|
14
|
+
focus: () => {
|
|
15
|
+
const focusable = pressableRef.current as unknown as {
|
|
16
|
+
focus?: (() => void) | undefined;
|
|
17
|
+
} | null;
|
|
18
|
+
focusable?.focus?.();
|
|
19
|
+
},
|
|
20
|
+
value,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
return () => unregisterTab(value);
|
|
24
|
+
}, [disabled, registerTab, unregisterTab, value]);
|
|
25
|
+
|
|
26
|
+
return pressableRef;
|
|
27
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { TabsContextValue } from '../../../types/tabs';
|
|
4
|
+
import { TabsContext } from './TabsContext';
|
|
5
|
+
|
|
6
|
+
/*** Returns the active Tabs feature context. */
|
|
7
|
+
export function useTabsContext(): TabsContextValue {
|
|
8
|
+
const value = React.use(TabsContext);
|
|
9
|
+
|
|
10
|
+
if (!value) throw new Error('Tabs components must be used within <Tabs>.');
|
|
11
|
+
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { useControllableState } from '../../../internal/useControllableState';
|
|
4
|
+
import type { TabRegistration, TabsContextValue, TabsProps } from '../../../types/tabs';
|
|
5
|
+
import { resolveTabElementId } from '../utils/resolveTabElementId';
|
|
6
|
+
|
|
7
|
+
/*** Owns controlled state, registration, focus state, and ids for one Tabs instance. */
|
|
8
|
+
export function useTabsController({
|
|
9
|
+
defaultValue,
|
|
10
|
+
onValueChange,
|
|
11
|
+
testID,
|
|
12
|
+
value,
|
|
13
|
+
}: Pick<TabsProps, 'defaultValue' | 'onValueChange' | 'testID' | 'value'>): TabsContextValue {
|
|
14
|
+
const [activeValue, setActiveValue] = useControllableState<string | undefined>({
|
|
15
|
+
defaultValue,
|
|
16
|
+
onChange: (nextValue) => {
|
|
17
|
+
if (nextValue !== undefined) onValueChange?.(nextValue);
|
|
18
|
+
},
|
|
19
|
+
value,
|
|
20
|
+
});
|
|
21
|
+
const [focusedValue, setFocusedValue] = React.useState<string | undefined>(undefined);
|
|
22
|
+
const [tabs, setTabs] = React.useState<readonly TabRegistration[]>([]);
|
|
23
|
+
|
|
24
|
+
const registerTab = React.useCallback((tab: TabRegistration) => {
|
|
25
|
+
setTabs((current) =>
|
|
26
|
+
current.some((entry) => entry.value === tab.value)
|
|
27
|
+
? current.map((entry) => (entry.value === tab.value ? tab : entry))
|
|
28
|
+
: [...current, tab],
|
|
29
|
+
);
|
|
30
|
+
}, []);
|
|
31
|
+
const unregisterTab = React.useCallback((valueToRemove: string) => {
|
|
32
|
+
setTabs((current) => current.filter((entry) => entry.value !== valueToRemove));
|
|
33
|
+
}, []);
|
|
34
|
+
|
|
35
|
+
React.useEffect(() => {
|
|
36
|
+
if (activeValue !== undefined) return;
|
|
37
|
+
const firstEnabledTab = tabs.find((entry) => !entry.disabled);
|
|
38
|
+
if (firstEnabledTab) setActiveValue(firstEnabledTab.value);
|
|
39
|
+
}, [activeValue, setActiveValue, tabs]);
|
|
40
|
+
|
|
41
|
+
return React.useMemo(
|
|
42
|
+
() => ({
|
|
43
|
+
activeValue,
|
|
44
|
+
focusedValue,
|
|
45
|
+
getPanelId: (tabValue: string) => resolveTabElementId('panel', testID, tabValue),
|
|
46
|
+
getTabId: (tabValue: string) => resolveTabElementId('tab', testID, tabValue),
|
|
47
|
+
registerTab,
|
|
48
|
+
setActiveValue: (nextValue: string) => setActiveValue(nextValue),
|
|
49
|
+
setFocusedValue,
|
|
50
|
+
tabs,
|
|
51
|
+
unregisterTab,
|
|
52
|
+
}),
|
|
53
|
+
[activeValue, focusedValue, registerTab, setActiveValue, tabs, testID, unregisterTab],
|
|
54
|
+
);
|
|
55
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { TabListProps, TabPanelProps, TabProps, TabsProps } from '../../types/tabs';
|
|
2
|
+
export { Tab } from './adapters/inbound/Tab';
|
|
3
|
+
export { TabList } from './adapters/inbound/TabList';
|
|
4
|
+
export { TabPanel } from './adapters/inbound/TabPanel';
|
|
5
|
+
export { Tabs } from './adapters/inbound/Tabs';
|
package/src/{components/tabs/navigation.test.ts → features/tabs/utils/resolveNextTabValue.test.ts}
RENAMED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { describe, expect, it } from 'bun:test';
|
|
2
2
|
|
|
3
|
-
import { resolveNextTabValue } from './
|
|
3
|
+
import { resolveNextTabValue } from './resolveNextTabValue';
|
|
4
4
|
|
|
5
5
|
const tabs = [
|
|
6
6
|
{ disabled: false, focus: () => undefined, value: 'overview' },
|
|
7
7
|
{ disabled: true, focus: () => undefined, value: 'disabled' },
|
|
8
8
|
{ disabled: false, focus: () => undefined, value: 'details' },
|
|
9
|
-
];
|
|
9
|
+
] as const;
|
|
10
10
|
|
|
11
11
|
describe('resolveNextTabValue', () => {
|
|
12
12
|
it('skips disabled tabs when cycling', () => {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { TabNavigationKey, TabRegistration } from '../../../types/tabs';
|
|
2
|
+
|
|
3
|
+
/*** Resolves the next enabled tab for keyboard focus navigation. */
|
|
4
|
+
export function resolveNextTabValue(
|
|
5
|
+
tabs: readonly TabRegistration[],
|
|
6
|
+
currentValue: string | undefined,
|
|
7
|
+
key: TabNavigationKey,
|
|
8
|
+
): string | undefined {
|
|
9
|
+
const enabledTabs = tabs.filter((tab) => !tab.disabled);
|
|
10
|
+
if (enabledTabs.length === 0) return undefined;
|
|
11
|
+
|
|
12
|
+
if (key === 'Home') return enabledTabs.at(0)?.value;
|
|
13
|
+
if (key === 'End') return enabledTabs.at(-1)?.value;
|
|
14
|
+
|
|
15
|
+
const currentIndex = enabledTabs.findIndex((tab) => tab.value === currentValue);
|
|
16
|
+
if (currentIndex === -1) return enabledTabs.at(0)?.value;
|
|
17
|
+
|
|
18
|
+
const nextIndex =
|
|
19
|
+
key === 'ArrowLeft' || key === 'ArrowUp'
|
|
20
|
+
? (currentIndex - 1 + enabledTabs.length) % enabledTabs.length
|
|
21
|
+
: (currentIndex + 1) % enabledTabs.length;
|
|
22
|
+
|
|
23
|
+
return enabledTabs.at(nextIndex)?.value;
|
|
24
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { describe, expect, it } from 'bun:test';
|
|
2
|
+
|
|
3
|
+
import { resolveTabElementId } from './resolveTabElementId';
|
|
4
|
+
|
|
5
|
+
describe('resolveTabElementId', () => {
|
|
6
|
+
it('creates stable ids from tab values', () => {
|
|
7
|
+
expect(resolveTabElementId('tab', undefined, 'Account Settings')).toBe(
|
|
8
|
+
'tabs-tab-Account-Settings',
|
|
9
|
+
);
|
|
10
|
+
expect(resolveTabElementId('panel', undefined, 'Account Settings')).toBe(
|
|
11
|
+
'tabs-panel-Account-Settings',
|
|
12
|
+
);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('namespaces ids by tabs testID when provided', () => {
|
|
16
|
+
expect(resolveTabElementId('tab', 'settings', 'billing')).toBe('settings-tabs-tab-billing');
|
|
17
|
+
expect(resolveTabElementId('panel', 'settings', 'billing')).toBe('settings-tabs-panel-billing');
|
|
18
|
+
});
|
|
19
|
+
});
|