@octaviaflow/mdx-components 1.1.3

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.
Files changed (119) hide show
  1. package/README.md +215 -0
  2. package/components/_utils.scss +18 -0
  3. package/components/accordion/_accordion.scss +35 -0
  4. package/components/accordion/accordion.stories.jsx +33 -0
  5. package/components/accordion/accordion.tsx +55 -0
  6. package/components/anchor-links/_anchor-links.scss +67 -0
  7. package/components/anchor-links/anchor-link.tsx +50 -0
  8. package/components/anchor-links/anchor-links.stories.jsx +51 -0
  9. package/components/anchor-links/anchor-links.tsx +73 -0
  10. package/components/art-direction/art-direction.stories.jsx +44 -0
  11. package/components/art-direction/art-direction.tsx +63 -0
  12. package/components/art-direction/desktop.jpg +0 -0
  13. package/components/art-direction/mobile.jpg +0 -0
  14. package/components/art-direction/tablet.jpg +0 -0
  15. package/components/article-card/_article-card.scss +98 -0
  16. package/components/article-card/article-card.stories.jsx +59 -0
  17. package/components/article-card/article-card.tsx +208 -0
  18. package/components/article-card/article06.png +0 -0
  19. package/components/aside/_aside.scss +56 -0
  20. package/components/aside/aside.stories.jsx +50 -0
  21. package/components/aside/aside.tsx +72 -0
  22. package/components/caption/_caption.scss +30 -0
  23. package/components/caption/caption.stories.jsx +33 -0
  24. package/components/caption/caption.tsx +47 -0
  25. package/components/card-group/_card-group.scss +44 -0
  26. package/components/card-group/card-group.stories.jsx +85 -0
  27. package/components/card-group/card-group.tsx +65 -0
  28. package/components/card-group/sketch-icon.png +0 -0
  29. package/components/code/_code.scss +110 -0
  30. package/components/code/code.stories.jsx +32 -0
  31. package/components/code/code.tsx +71 -0
  32. package/components/code/inline-code.tsx +55 -0
  33. package/components/code/path.tsx +56 -0
  34. package/components/divider/_divider.scss +67 -0
  35. package/components/divider/divider.stories.jsx +74 -0
  36. package/components/divider/divider.tsx +54 -0
  37. package/components/do-dont/_do-dont.scss +191 -0
  38. package/components/do-dont/do-dont-row.tsx +51 -0
  39. package/components/do-dont/do-dont.stories.jsx +53 -0
  40. package/components/do-dont/do-dont.tsx +161 -0
  41. package/components/do-dont/light-theme.jpg +0 -0
  42. package/components/gif-player/_gif-player.scss +64 -0
  43. package/components/gif-player/cloud.gif +0 -0
  44. package/components/gif-player/cloud.jpg +0 -0
  45. package/components/gif-player/gif-player.stories.jsx +45 -0
  46. package/components/gif-player/gif-player.tsx +150 -0
  47. package/components/grid-transform/_grid.scss +13 -0
  48. package/components/grid-transform/column.tsx +102 -0
  49. package/components/grid-transform/grid.stories.jsx +72 -0
  50. package/components/grid-transform/grid.tsx +52 -0
  51. package/components/grid-transform/row.tsx +92 -0
  52. package/components/image-wrapper/_image-wrapper.scss +32 -0
  53. package/components/image-wrapper/accordion-style-3.png +0 -0
  54. package/components/image-wrapper/image-wrapper.stories.jsx +40 -0
  55. package/components/image-wrapper/image-wrapper.tsx +56 -0
  56. package/components/index.scss +31 -0
  57. package/components/inline-notification/_inline-notification.scss +29 -0
  58. package/components/inline-notification/inline-notification.stories.jsx +67 -0
  59. package/components/inline-notification/inline-notification.tsx +98 -0
  60. package/components/interfaces.ts +31 -0
  61. package/components/link/_link.scss +13 -0
  62. package/components/link/link.stories.jsx +36 -0
  63. package/components/link/link.tsx +51 -0
  64. package/components/markdown/_markdown.scss +140 -0
  65. package/components/markdown/autolink-header/_autolink-header.scss +57 -0
  66. package/components/markdown/autolink-header/autolink-header.tsx +107 -0
  67. package/components/markdown/blockquote.stories.jsx +38 -0
  68. package/components/markdown/blockquote.tsx +53 -0
  69. package/components/markdown/h1.tsx +92 -0
  70. package/components/markdown/h2.tsx +85 -0
  71. package/components/markdown/h3.tsx +72 -0
  72. package/components/markdown/h4.tsx +73 -0
  73. package/components/markdown/h5.tsx +59 -0
  74. package/components/markdown/h6.tsx +59 -0
  75. package/components/markdown/headings.stories.jsx +52 -0
  76. package/components/markdown/li.tsx +55 -0
  77. package/components/markdown/ol.stories.jsx +47 -0
  78. package/components/markdown/ol.tsx +93 -0
  79. package/components/markdown/p.stories.jsx +36 -0
  80. package/components/markdown/p.tsx +65 -0
  81. package/components/markdown/ul.stories.jsx +46 -0
  82. package/components/markdown/ul.tsx +93 -0
  83. package/components/mini-card/_mini-card.scss +55 -0
  84. package/components/mini-card/mini-card.stories.jsx +72 -0
  85. package/components/mini-card/mini-card.tsx +132 -0
  86. package/components/page-description/_page-description.scss +38 -0
  87. package/components/page-description/page-description.stories.jsx +36 -0
  88. package/components/page-description/page-description.tsx +61 -0
  89. package/components/page-table/_page-table.scss +51 -0
  90. package/components/page-table/page-table.stories.jsx +56 -0
  91. package/components/page-table/page-table.tsx +88 -0
  92. package/components/preview/_preview.scss +16 -0
  93. package/components/preview/preview.stories.jsx +41 -0
  94. package/components/preview/preview.tsx +80 -0
  95. package/components/resource-card/_resource-card.scss +165 -0
  96. package/components/resource-card/resource-card.stories.jsx +100 -0
  97. package/components/resource-card/resource-card.tsx +201 -0
  98. package/components/storybook-demo/_storybook-demo.scss +57 -0
  99. package/components/storybook-demo/storybook-demo.stories.jsx +70 -0
  100. package/components/storybook-demo/storybook-demo.tsx +190 -0
  101. package/components/tabs/_tabs.scss +98 -0
  102. package/components/tabs/select.tsx +60 -0
  103. package/components/tabs/tab-list.tsx +48 -0
  104. package/components/tabs/tab.tsx +125 -0
  105. package/components/tabs/tabs.stories.jsx +54 -0
  106. package/components/tabs/tabs.tsx +78 -0
  107. package/components/title/title.stories.jsx +43 -0
  108. package/components/title/title.tsx +47 -0
  109. package/components/utils.ts +102 -0
  110. package/components/video/_video.scss +89 -0
  111. package/components/video/local-poster.jpeg +0 -0
  112. package/components/video/local-video.mp4 +0 -0
  113. package/components/video/video.stories.jsx +45 -0
  114. package/components/video/video.tsx +255 -0
  115. package/es/index.js +71714 -0
  116. package/index.ts +59 -0
  117. package/lib/index.js +71767 -0
  118. package/package.json +64 -0
  119. package/telemetry.yml +21 -0
@@ -0,0 +1,201 @@
1
+ /**
2
+ * Copyright OctaviaFlow
3
+ * Author: Vishal Kumar
4
+ * Created: 11/November/2025
5
+ *
6
+ * This source code is licensed under the Apache-2.0 license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+
10
+ /*
11
+ * Copyright OctaviaFlow 2022, 2025
12
+ *
13
+ * This source code is licensed under the Apache-2.0 license found in the
14
+ * LICENSE file in the root directory of this source tree.
15
+ */
16
+
17
+ import { AspectRatio, Theme } from "@octaviaflow/react";
18
+ import {
19
+ ArrowRight,
20
+ Calendar,
21
+ Download,
22
+ Email,
23
+ Error,
24
+ Launch,
25
+ } from "@octaviaflow/icons-react";
26
+ import { clsx } from "clsx";
27
+ import PropTypes from "prop-types";
28
+ import React, { ReactNode } from "react";
29
+
30
+ import { MdxComponent } from "../interfaces";
31
+ import { mediaQueries, useMatchMedia, withPrefix } from "../utils";
32
+
33
+ type Color = "light" | "dark";
34
+ type ActionIcon = "launch" | "arrowRight" | "download" | "email" | "calendar";
35
+ type AspectRatio = "2:1" | "1:1" | "16:9" | "4:3";
36
+
37
+ interface ResourceCardProps {
38
+ children: ReactNode;
39
+ component?: ReactNode | null;
40
+ className?: string | null;
41
+ href?: string | null;
42
+ subTitle?: string | null;
43
+ title?: string | null;
44
+ color?: Color | null;
45
+ disabled?: boolean | null;
46
+ actionIcon?: ActionIcon | null;
47
+ aspectRatio?: AspectRatio | null;
48
+ }
49
+
50
+ /**
51
+ * The `<ResourceCard>` component should be wrapped within the `<CardGroup>` component,
52
+ * this grid wrapper component will add correct spacing and borders between cards.
53
+ *
54
+ *```
55
+ * <CardGroup>
56
+ * <Column lg={4}>
57
+ * <ResourceCard props>
58
+ *
59
+ * ![](img.png)
60
+ *
61
+ * </ResourceCard>
62
+ * </Column>
63
+ * </CardGroup>
64
+ * ```
65
+ */
66
+ export const ResourceCard: MdxComponent<ResourceCardProps> = (props) => {
67
+ const {
68
+ children,
69
+ href,
70
+ subTitle,
71
+ title,
72
+ color,
73
+ disabled,
74
+ aspectRatio: aspectRatioProp,
75
+ actionIcon,
76
+ className,
77
+ component,
78
+ ...rest
79
+ } = props;
80
+
81
+ const isLg = useMatchMedia(mediaQueries.lg);
82
+ const isXlg = useMatchMedia(mediaQueries.xlg);
83
+
84
+ const ResourceCardClassNames = clsx(className, withPrefix("resource-card"), {
85
+ [withPrefix("disabled")]: disabled,
86
+ });
87
+
88
+ // if aspectRatio is not specified and it's a card with title displaying at Lg breakpoint,
89
+ // default aspectRatio to 16:9, all other cases default to 2:1
90
+ const aspectRatio =
91
+ aspectRatioProp || (!!title && isLg && !isXlg ? "16:9" : "2:1");
92
+
93
+ const carbonTileclassNames = clsx(["ods--tile"], {
94
+ "ods--tile--clickable": href !== undefined,
95
+ [withPrefix("card-with-title")]: !!title,
96
+ [withPrefix("card-with-component")]: !!component,
97
+ });
98
+
99
+ const cardContent = (
100
+ <>
101
+ {subTitle && <h5 className={withPrefix("subtitle")}>{subTitle}</h5>}
102
+ {title && <h4 className={withPrefix("title")}>{title}</h4>}
103
+ {component && (
104
+ <div className={withPrefix("child-component")}>{component}</div>
105
+ )}
106
+ <div className={withPrefix("icon-img")}>{children}</div>
107
+ <div className={withPrefix("icon-action")}>
108
+ {!disabled &&
109
+ actionIcon &&
110
+ {
111
+ launch: <Launch size={20} aria-label="Open resource" />,
112
+ arrowRight: <ArrowRight size={20} aria-label="Open resource" />,
113
+ download: <Download size={20} aria-label="Download" />,
114
+ email: <Email size={20} aria-label="Email" />,
115
+ calendar: <Calendar size={20} aria-label="Calendar" />,
116
+ disabled: <Error size={20} aria-label="disabled" />,
117
+ }[actionIcon]}
118
+ {disabled === true && <Error size={20} aria-label="disabled" />}
119
+ </div>
120
+ </>
121
+ );
122
+
123
+ let cardContainer;
124
+ if (disabled === true || href === undefined) {
125
+ cardContainer = <div className={carbonTileclassNames}>{cardContent}</div>;
126
+ } else {
127
+ cardContainer = (
128
+ <a href={href!} className={carbonTileclassNames} {...rest}>
129
+ {cardContent}
130
+ </a>
131
+ );
132
+ }
133
+
134
+ return (
135
+ <Theme theme={color === "dark" ? "g100" : "g10"}>
136
+ <div className={ResourceCardClassNames}>
137
+ {/* @ts-ignore -- output string equals type */}
138
+ <AspectRatio ratio={`${aspectRatio.replace(":", "x")}`}>
139
+ <div className="ods--aspect-ratio--object">{cardContainer}</div>
140
+ </AspectRatio>
141
+ </div>
142
+ </Theme>
143
+ );
144
+ };
145
+
146
+ ResourceCard.propTypes = {
147
+ /**
148
+ * Action icon
149
+ */
150
+ actionIcon: PropTypes.oneOf<ActionIcon>([
151
+ "launch",
152
+ "arrowRight",
153
+ "download",
154
+ "email",
155
+ "calendar",
156
+ ]).isRequired,
157
+ /**
158
+ * Set card aspect ratio
159
+ */
160
+ aspectRatio: PropTypes.oneOf<AspectRatio>(["2:1", "1:1", "16:9", "4:3"]),
161
+ /**
162
+ * Add an image to display in lower left
163
+ */
164
+ children: PropTypes.node as unknown as React.Validator<React.ReactNode>,
165
+ /**
166
+ * Optional class name
167
+ */
168
+ className: PropTypes.string,
169
+ /**
170
+ * set to "dark" for dark background card
171
+ */
172
+ color: PropTypes.oneOf<Color>(["light", "dark"]),
173
+
174
+ /**
175
+ * Optional component to render in top right
176
+ */
177
+ component: PropTypes.element,
178
+
179
+ /**
180
+ * Use for disabled card
181
+ */
182
+ disabled: PropTypes.bool,
183
+ /**
184
+ * Set url for card
185
+ */
186
+ href: PropTypes.string,
187
+ /**
188
+ * Smaller heading
189
+ */
190
+ subTitle: PropTypes.string,
191
+ /**
192
+ * Large heading
193
+ */
194
+ title: PropTypes.string,
195
+ };
196
+
197
+ ResourceCard.defaultProps = {
198
+ color: "light",
199
+ disabled: false,
200
+ actionIcon: "launch",
201
+ };
@@ -0,0 +1,57 @@
1
+ /*
2
+ * Copyright OctaviaFlow 2022, 2025
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ @use '@carbon/react/scss/spacing' as spacing;
9
+ @use '@carbon/react/scss/theme' as theme;
10
+ @use '@carbon/react/scss/type' as type;
11
+ @use '@carbon/react/scss/utilities/convert' as convert;
12
+
13
+ @use '../utils' as *;
14
+
15
+ .#{with-prefix('demo-dropdowns')} {
16
+ // override carbon, label inset-inline-start padding
17
+ .ods--label {
18
+ padding-inline-start: spacing.$spacing-05;
19
+ }
20
+
21
+ .ods--dropdown {
22
+ border-block-end: 1px solid theme.$layer-selected-01;
23
+ }
24
+ }
25
+
26
+ .#{with-prefix('theme-selector')} {
27
+ :global(.ods--dropdown)::after {
28
+ position: absolute;
29
+ display: block;
30
+ background-color: theme.$layer-selected;
31
+ block-size: convert.rem(40px);
32
+ content: '';
33
+ inline-size: 1px;
34
+ inset-block-start: 0;
35
+ inset-inline-end: -1px;
36
+ }
37
+ }
38
+
39
+ .#{with-prefix('storybook-demo')} {
40
+ padding: spacing.$spacing-03;
41
+ background: theme.$layer-01;
42
+ block-size: convert.rem(320px);
43
+ }
44
+
45
+ .#{with-prefix('tall')},
46
+ .#{with-prefix('wide')} {
47
+ block-size: convert.rem(480px);
48
+ }
49
+
50
+ .#{with-prefix('wide')}.#{with-prefix('tall')} {
51
+ block-size: convert.rem(640px);
52
+ }
53
+
54
+ .#{with-prefix('iframe')} {
55
+ block-size: 100%;
56
+ inline-size: 100%;
57
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Copyright OctaviaFlow
3
+ * Author: Vishal Kumar
4
+ * Created: 11/November/2025
5
+ *
6
+ * This source code is licensed under the Apache-2.0 license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+
10
+ /*
11
+ * Copyright IBM Corp. 2022, 2025
12
+ *
13
+ * This source code is licensed under the Apache-2.0 license found in the
14
+ * LICENSE file in the root directory of this source tree.
15
+ */
16
+
17
+ import React from "react";
18
+ import { StorybookDemo } from "./storybook-demo";
19
+
20
+ export default {
21
+ title: "Components/MDX Components/StorybookDemo",
22
+ component: StorybookDemo,
23
+ };
24
+
25
+ const Template = (args) => (
26
+ <StorybookDemo
27
+ {...args}
28
+ themeSelector={true}
29
+ wide
30
+ tall
31
+ url="https://react.carbondesignsystem.com"
32
+ variants={[
33
+ {
34
+ label: "Button",
35
+ variant: "components-button--default",
36
+ },
37
+ {
38
+ label: "Secondary",
39
+ variant: "components-button--secondary",
40
+ },
41
+ {
42
+ label: "Tertiary",
43
+ variant: "components-button--tertiary",
44
+ },
45
+ {
46
+ label: "Ghost",
47
+ variant: "components-button--ghost",
48
+ },
49
+ {
50
+ label: "Danger",
51
+ variant: "components-button--danger",
52
+ },
53
+ {
54
+ label: "Icon button",
55
+ variant: "components-button--icon-button",
56
+ },
57
+ {
58
+ label: "Set of buttons",
59
+ variant: "components-button--set-of-buttons",
60
+ },
61
+ {
62
+ label: "Skeleton",
63
+ variant: "components-button--skeleton",
64
+ },
65
+ ]}
66
+ />
67
+ );
68
+
69
+ export const Default = Template.bind({});
70
+ Default.args = {};
@@ -0,0 +1,190 @@
1
+ /**
2
+ * Copyright OctaviaFlow
3
+ * Author: Vishal Kumar
4
+ * Created: 11/November/2025
5
+ *
6
+ * This source code is licensed under the Apache-2.0 license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+
10
+ /*
11
+ * Copyright OctaviaFlow 2022, 2025
12
+ *
13
+ * This source code is licensed under the Apache-2.0 license found in the
14
+ * LICENSE file in the root directory of this source tree.
15
+ */
16
+
17
+ import { Column, Dropdown, Grid, Link } from "@octaviaflow/react";
18
+ import { clsx } from "clsx";
19
+ import PropTypes from "prop-types";
20
+ import React, { useState } from "react";
21
+
22
+ import { Caption } from "../caption/caption";
23
+ import { MdxComponent } from "../interfaces";
24
+ import { withPrefix } from "../utils";
25
+
26
+ interface StorybookDemoProps {
27
+ tall?: boolean | null;
28
+ themeSelector?: boolean | null;
29
+ wide?: boolean | null;
30
+ url: string;
31
+ variants?: Array<{
32
+ label: string;
33
+ variant: string;
34
+ }> | null;
35
+ }
36
+
37
+ /**
38
+ * The `<StorybookDemo>` component displays an iframe embed for the storybook story
39
+ * for a component. It has the option to show different variants and themes. It also has a
40
+ * `wide` prop to span the full width, and `tall` for larger components. If you would like
41
+ * to use the theme selector, please use the Carbon React Storybook url,
42
+ * https://react.carbondesignsystem.com/?path=/story/components-button--default&globals=theme:g10
43
+ * as an example. The `themeSelector` appends `&globals=theme:g10` to the url.
44
+ */
45
+ export const StorybookDemo: MdxComponent<StorybookDemoProps> = ({
46
+ tall,
47
+ themeSelector,
48
+ wide,
49
+ url,
50
+ variants,
51
+ }) => {
52
+ const themeItems = [
53
+ {
54
+ id: "white",
55
+ label: "White",
56
+ src: "white",
57
+ },
58
+ {
59
+ id: "g10",
60
+ label: "Gray 10",
61
+ src: "g10",
62
+ },
63
+ {
64
+ id: "g90",
65
+ label: "Gray 90",
66
+ src: "g90",
67
+ },
68
+ {
69
+ id: "g100",
70
+ label: "Gray 100",
71
+ src: "g100",
72
+ },
73
+ ];
74
+
75
+ const columnWidth = wide ? 12 : 8;
76
+
77
+ const demoClassNames = clsx(withPrefix("storybook-demo"), {
78
+ [withPrefix("tall")]: tall,
79
+ [withPrefix("wide")]: wide,
80
+ });
81
+
82
+ const [theme, setTheme] = useState(themeItems[0]!.src);
83
+ const onThemeChange = (item: {
84
+ selectedItem: { src: React.SetStateAction<string> };
85
+ }) => {
86
+ setTheme(item.selectedItem.src);
87
+ };
88
+
89
+ const multipleVariants = variants && variants.length > 1;
90
+
91
+ const [variant, setVariant] = useState(variants?.[0]?.variant);
92
+
93
+ const onVariantChange = (item: { selectedItem: { variant: string } }) => {
94
+ setVariant(item.selectedItem.variant);
95
+ };
96
+
97
+ const iframeUrl =
98
+ url + "/iframe.html?id=" + variant + "&globals=theme:" + theme;
99
+
100
+ // Only add border when theme and variant selectors are being displayed
101
+ const border = clsx({
102
+ [withPrefix("theme-selector")]: multipleVariants,
103
+ });
104
+
105
+ return (
106
+ <>
107
+ <Grid condensed className={withPrefix("demo-dropdowns")}>
108
+ {themeSelector && (
109
+ <Column sm={2} md={4}>
110
+ <Dropdown
111
+ id="theme-selector"
112
+ titleText="Theme selector"
113
+ label="theme"
114
+ items={themeItems}
115
+ onChange={onThemeChange}
116
+ initialSelectedItem={themeItems[0]}
117
+ className={border}
118
+ />
119
+ </Column>
120
+ )}
121
+ {multipleVariants && (
122
+ <Column sm={2} md={4}>
123
+ <Dropdown
124
+ id="variant-selector"
125
+ titleText="Variant selector"
126
+ label="variant"
127
+ items={variants}
128
+ initialSelectedItem={{ variant: variants[0]?.label }}
129
+ onChange={onVariantChange}
130
+ />
131
+ </Column>
132
+ )}
133
+ </Grid>
134
+ <Grid condensed>
135
+ <Column sm={4} md={8} lg={columnWidth} className={demoClassNames}>
136
+ <iframe
137
+ title="Component demo"
138
+ className={withPrefix("iframe")}
139
+ src={iframeUrl}
140
+ frameBorder="no"
141
+ sandbox="allow-forms allow-scripts allow-same-origin"
142
+ />
143
+ </Column>
144
+ </Grid>
145
+ <Grid>
146
+ <Column sm={4} md={7}>
147
+ <Caption>
148
+ This live demo contains only a preview of functionality and styles
149
+ available for this component. View the{" "}
150
+ <Link
151
+ href={`${url}/?path=/story/${variant}&globals=theme:${theme}`}
152
+ >
153
+ full demo
154
+ </Link>{" "}
155
+ on Storybook for additional information such as its version,
156
+ controls, and API documentation.
157
+ </Caption>
158
+ </Column>
159
+ </Grid>
160
+ </>
161
+ );
162
+ };
163
+
164
+ StorybookDemo.propTypes = {
165
+ /**
166
+ * Storybook demo height
167
+ */
168
+ tall: PropTypes.bool,
169
+ /**
170
+ * Storybook demo display or hide theme selector
171
+ */
172
+ themeSelector: PropTypes.bool,
173
+ /**
174
+ * Storybook demo url to change themes and variants
175
+ */
176
+ url: PropTypes.string.isRequired,
177
+ /**
178
+ * Storybook demo variants for the specified component
179
+ */
180
+ variants: PropTypes.arrayOf(
181
+ PropTypes.shape({
182
+ label: PropTypes.string.isRequired,
183
+ variant: PropTypes.string.isRequired,
184
+ }).isRequired,
185
+ ),
186
+ /**
187
+ * Storybook demo width
188
+ */
189
+ wide: PropTypes.bool,
190
+ };
@@ -0,0 +1,98 @@
1
+ /*
2
+ * Copyright OctaviaFlow 2022, 2025
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ @use '@carbon/react/scss/spacing' as spacing;
9
+ @use '@carbon/react/scss/motion' as motion;
10
+ @use '@carbon/react/scss/breakpoint' as breakpoint;
11
+ @use '@carbon/react/scss/type' as type;
12
+ @use '@carbon/react/scss/theme' as theme;
13
+
14
+ @use '../utils' as *;
15
+
16
+ .#{with-prefix('tab-dropdown')},
17
+ .#{with-prefix('tab-list')} {
18
+ margin-block-start: spacing.$spacing-06;
19
+ }
20
+
21
+ .#{with-prefix('tab-list')} {
22
+ display: flex;
23
+ border-block-end: 1px solid theme.$border-subtle-01;
24
+ max-inline-size: min-content;
25
+ overflow-x: auto;
26
+ scrollbar-width: none;
27
+
28
+ @include breakpoint.breakpoint('md') {
29
+ overflow: visible;
30
+ }
31
+ }
32
+
33
+ .#{with-prefix('tab-panel')} {
34
+ padding: spacing.$spacing-05;
35
+ background: theme.$layer-01;
36
+
37
+ color: theme.$text-primary;
38
+ margin-block-start: 0;
39
+ padding-block-end: spacing.$spacing-08;
40
+
41
+ &[hidden] {
42
+ display: none;
43
+ }
44
+ }
45
+
46
+ .#{with-prefix('tab')} {
47
+ @include type.type-style('body-short-01');
48
+
49
+ position: relative;
50
+ display: inline-block;
51
+ align-items: center;
52
+ padding: spacing.$spacing-03 spacing.$spacing-05;
53
+ border: none;
54
+ margin: 0;
55
+ background-color: theme.$layer-01;
56
+ block-size: 3rem;
57
+ border-inline-end: 1px solid theme.$layer-03;
58
+ color: theme.$text-primary;
59
+
60
+ cursor: pointer;
61
+ min-inline-size: 0;
62
+ outline-color: transparent;
63
+ text-align: start;
64
+ transition: color motion.$duration-fast-02,
65
+ background-color motion.$duration-fast-02,
66
+ border-color motion.$duration-fast-02,
67
+ outline-color motion.$duration-fast-02;
68
+ white-space: nowrap;
69
+
70
+ &::-moz-focus-inner {
71
+ border: 0;
72
+ }
73
+
74
+ &:focus {
75
+ // allows overflow to be above subsequent tab
76
+ z-index: 1;
77
+ border-inline-end: 1px solid theme.$border-inverse;
78
+ outline: 1px solid theme.$focus-inverse;
79
+ outline-offset: -4px;
80
+ }
81
+
82
+ &:hover {
83
+ background-color: theme.$background-hover;
84
+ }
85
+
86
+ @media screen and (prefers-reduced-motion: reduce) {
87
+ transition: none;
88
+ }
89
+ }
90
+
91
+ .#{with-prefix('tab')}[aria-selected='true'] {
92
+ background-color: theme.$layer-selected-inverse;
93
+ color: theme.$focus-inset;
94
+ }
95
+
96
+ .#{with-prefix('tab-list')} li:last-of-type #{with-prefix('.tab')} {
97
+ border-inline-end: none;
98
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Copyright OctaviaFlow
3
+ * Author: Vishal Kumar
4
+ * Created: 11/November/2025
5
+ *
6
+ * This source code is licensed under the Apache-2.0 license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+
10
+ /*
11
+ * Copyright OctaviaFlow 2022, 2025
12
+ *
13
+ * This source code is licensed under the Apache-2.0 license found in the
14
+ * LICENSE file in the root directory of this source tree.
15
+ */
16
+ import { Dropdown } from "@octaviaflow/react";
17
+ import PropTypes from "prop-types";
18
+ import React, { useContext } from "react";
19
+
20
+ import { MdxComponent, NonScalarNode } from "../interfaces";
21
+ import { withPrefix } from "../utils";
22
+ import { TabContext } from "./tabs";
23
+
24
+ interface SelectProps {
25
+ _id: string;
26
+ children: NonScalarNode;
27
+ }
28
+
29
+ export const Select: MdxComponent<SelectProps> = ({ children, _id }) => {
30
+ const { setActiveTab } = useContext(TabContext);
31
+ const items = React.Children.map(children, (child, index) => ({
32
+ index,
33
+ label: child.props.label,
34
+ }));
35
+
36
+ return (
37
+ // @ts-ignore
38
+ <Dropdown
39
+ size="md"
40
+ onChange={({ selectedItem }: { selectedItem: { index: number } }) =>
41
+ setActiveTab(selectedItem.index)
42
+ }
43
+ initialSelectedItem={items?.[0]}
44
+ label="tab selection"
45
+ items={items}
46
+ id={_id}
47
+ className={withPrefix("tab-dropdown")}
48
+ />
49
+ );
50
+ };
51
+
52
+ Select.propTypes = {
53
+ _id: PropTypes.string.isRequired,
54
+ children: PropTypes.oneOfType([
55
+ PropTypes.element.isRequired,
56
+ PropTypes.arrayOf(PropTypes.element.isRequired).isRequired,
57
+ ]).isRequired,
58
+ };
59
+
60
+ export default Select;