@dbosoft/nextjs-uicore 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,36 +1,47 @@
1
- # @dbosoft/nextjs-uicore
2
-
3
- ## 1.1.0
4
-
5
- ### Minor Changes
6
-
7
- - 7a843e1: darkmode support for subnav
8
-
9
- ## 1.0.3
10
-
11
- ### Patch Changes
12
-
13
- - 5fc59bc: fixed missing navigation for github links in subnav
14
-
15
- ## 1.0.2
16
-
17
- ### Patch Changes
18
-
19
- - 4122817: fixed subnav titlelink
20
-
21
- ## 1.0.1
22
-
23
- ### Patch Changes
24
-
25
- - ec24215: update @heroicons/react to v2
26
-
27
- ## 1.0.0
28
-
29
- ### Major Changes
30
-
31
- - restructured nextjs components
32
-
33
- ### Patch Changes
34
-
35
- - Updated dependencies
36
- - @dbosoft/react-uicore@1.0.0
1
+ # @dbosoft/nextjs-uicore
2
+
3
+ ## 1.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 676c725: Server side download pages
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [676c725]
12
+ - @dbosoft/react-uicore@1.1.0
13
+
14
+ ## 1.1.0
15
+
16
+ ### Minor Changes
17
+
18
+ - 7a843e1: darkmode support for subnav
19
+
20
+ ## 1.0.3
21
+
22
+ ### Patch Changes
23
+
24
+ - 5fc59bc: fixed missing navigation for github links in subnav
25
+
26
+ ## 1.0.2
27
+
28
+ ### Patch Changes
29
+
30
+ - 4122817: fixed subnav titlelink
31
+
32
+ ## 1.0.1
33
+
34
+ ### Patch Changes
35
+
36
+ - ec24215: update @heroicons/react to v2
37
+
38
+ ## 1.0.0
39
+
40
+ ### Major Changes
41
+
42
+ - restructured nextjs components
43
+
44
+ ### Patch Changes
45
+
46
+ - Updated dependencies
47
+ - @dbosoft/react-uicore@1.0.0
package/package.json CHANGED
@@ -2,13 +2,14 @@
2
2
  "name": "@dbosoft/nextjs-uicore",
3
3
  "description": "Core UI components for Next.js",
4
4
  "author": "dbosoft",
5
- "version": "1.1.0",
5
+ "version": "1.2.0",
6
6
  "sideEffects": false,
7
7
  "license": "MIT",
8
8
  "exports": {
9
9
  ".": "./src",
10
10
  "./head": "./src/head/index.tsx",
11
- "./tabs": "./src/tabs/index.tsx",
11
+ "./tabs": "./src/tabs/index.ts",
12
+ "./tabs/server": "./src/tabs/server.ts",
12
13
  "./subnav": "./src/subnav/index.tsx",
13
14
  "./themeselector": "./src/themeselector/index.tsx"
14
15
  },
@@ -20,21 +21,21 @@
20
21
  "react": "^18.2.0",
21
22
  "typescript": "^5.3.3",
22
23
  "@dbosoft/eslint-config": "1.0.0",
23
- "@dbosoft/typescript-config": "1.0.0",
24
- "@dbosoft/web-types": "1.0.0"
24
+ "@dbosoft/web-types": "1.0.0",
25
+ "@dbosoft/typescript-config": "1.0.0"
25
26
  },
26
27
  "publishConfig": {
27
28
  "access": "public"
28
29
  },
29
30
  "dependencies": {
30
- "@headlessui/react": "^1.4.3",
31
+ "@headlessui/react": "^2.2.1",
31
32
  "@heroicons/react": "^2.1.3",
32
33
  "classnames": "^2.3.1",
33
34
  "clsx": "^2.1.0",
34
35
  "isomorphic-unfetch": "^4.0.2",
35
36
  "next-themes": "^0.4.3",
36
37
  "unfetch": "^4.2.0",
37
- "@dbosoft/react-uicore": "1.0.0"
38
+ "@dbosoft/react-uicore": "1.1.0"
38
39
  },
39
40
  "scripts": {
40
41
  "lint": "eslint . --max-warnings 0",
@@ -1,4 +1,4 @@
1
- import { Disclosure } from '@headlessui/react'
1
+ import { Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/react'
2
2
  import { Bars3Icon, XMarkIcon } from '@heroicons/react/24/outline'
3
3
  import type { LinkType, Variant } from '@dbosoft/react-uicore/linkbutton'
4
4
  import MenuItemsOverflow from './partials/MenuItemsOverflow'
@@ -92,20 +92,20 @@ function Subnav({
92
92
 
93
93
  <div className="-mr-2 flex items-center sm:hidden ">
94
94
  {/* Mobile menu button */}
95
- <Disclosure.Button className="bg-white inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-secondary">
95
+ <DisclosureButton className="bg-white inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-secondary">
96
96
  <span className="sr-only">Open main menu</span>
97
97
  {open ? (
98
98
  <XMarkIcon aria-hidden="true" className="block h-6 w-6" />
99
99
  ) : (
100
100
  <Bars3Icon aria-hidden="true" className="block h-6 w-6" />
101
101
  )}
102
- </Disclosure.Button>
102
+ </DisclosureButton>
103
103
  </div>
104
104
  </div>
105
105
 
106
106
  </div>
107
107
 
108
- <Disclosure.Panel className="sm:hidden">
108
+ <DisclosurePanel className="sm:hidden">
109
109
  <div className="pt-2 pb-3 space-y-1">
110
110
  <MenuItemsOverflow
111
111
  ctaLinks={ctaLinks}
@@ -113,7 +113,7 @@ function Subnav({
113
113
  menuItems={menuItems}
114
114
  /> </div>
115
115
 
116
- </Disclosure.Panel>
116
+ </DisclosurePanel>
117
117
  </>
118
118
  )}
119
119
  </Disclosure>
@@ -0,0 +1,50 @@
1
+ import { TabList, Tab, TabPanels, TabPanel, TabGroup } from "@headlessui/react"
2
+ import { FC, Suspense } from "react"
3
+
4
+ import TabsClient, { TabConfig, TabLink } from "./TabsClient"
5
+
6
+
7
+ export const TabsContent: FC<{
8
+ tabs: TabConfig[],
9
+ tabNames: string[]
10
+ }> = ({
11
+ tabs,
12
+ tabNames
13
+ }) => {
14
+
15
+ return <>
16
+ <TabList className={` pt-2 flex justify-center`}>
17
+ {tabs.map((tab, index) => <Suspense key={tab.name}><Tab as={TabLink} className={tab.className} index={index} tabs={tabNames}>{tab.displayName}</Tab></Suspense>)}
18
+ </TabList>
19
+ <TabPanels className={`mt-4 pt-0 border-t-2 border-brand-light dark:border-brand-dark`}>
20
+ {tabs.map((tab, index) => <TabPanel className={`py-4`} key={index}>{tab.content}</TabPanel>)}
21
+ </TabPanels>
22
+ </>
23
+ }
24
+
25
+
26
+ const Tabs: FC<{
27
+ tabs: TabConfig[],
28
+ currentTab: string | undefined
29
+ }> = ({
30
+ tabs,
31
+ currentTab
32
+ }) => {
33
+ let selectedTab = currentTab ? tabs.findIndex(tab => tab.name === currentTab) : 0;
34
+ if (selectedTab == -1)
35
+ selectedTab = 0;
36
+
37
+ const tabNames = tabs.map(tab => tab.name);
38
+
39
+
40
+ return <div className="pb-8"><Suspense fallback={<TabGroup selectedIndex={selectedTab}>
41
+ <TabsContent tabs={tabs} tabNames={tabNames} /></TabGroup>}>
42
+ <TabsClient initialTab={selectedTab} tabs={tabNames}>
43
+ <TabsContent tabs={tabs} tabNames={tabNames} />
44
+ </TabsClient>
45
+ </Suspense>
46
+ </div>
47
+
48
+ }
49
+
50
+ export default Tabs;
@@ -0,0 +1,75 @@
1
+ "use client"
2
+
3
+ import { usePathname, useRouter, useSearchParams } from "next/navigation";
4
+ import { FC, ReactNode, forwardRef, useState } from "react";
5
+ import { TabGroup } from "@headlessui/react"
6
+ import Link from "next/link";
7
+ import clsx from "clsx";
8
+
9
+ export type TabConfig = {
10
+ name: string,
11
+ displayName: string
12
+ className?: string
13
+ content: ReactNode
14
+ }
15
+
16
+ export const createNavUrl = (index: number, tabs: string[], pathname: string, searchParams: URLSearchParams) => {
17
+ const lastSegment = pathname.split(`/`).pop();
18
+ let newPath = pathname;
19
+
20
+ if (lastSegment && tabs.includes(lastSegment)) {
21
+ newPath = pathname.substring(0, pathname.lastIndexOf(`/`));
22
+ }
23
+
24
+ const newTab = index > 0 ? tabs[index] : ``;
25
+ newPath = newPath + `/` + newTab;
26
+
27
+ const query = searchParams.toString();
28
+
29
+ if (query)
30
+ return (newPath + `?` + query);
31
+ else
32
+ return newPath;
33
+ }
34
+
35
+ export const TabLink = forwardRef<HTMLAnchorElement, React.PropsWithChildren<{
36
+ index: number, tabs: string[], className: string
37
+ }>>((props, ref) => {
38
+
39
+ const pathname = usePathname()
40
+ const searchParams = useSearchParams()
41
+
42
+ return <Link prefetch={false} role="tab" {...props} className={clsx(`data-[selected]:border-secondary data-[selected]:text-link-light dark:data-[selected]:text-sky-300`,
43
+ `border-transparent text-content-secondary hover:border-secondary hover:text-sky-600 dark:hover:text-sky-200 `,
44
+ `whitespace-nowrap border-b-2 mx-3 px-2 py-2 text-base font-semibold`)} ref={ref} href={createNavUrl(props.index, props.tabs, pathname, searchParams)}
45
+ >
46
+ {props.children}
47
+ </Link >
48
+ });
49
+
50
+ TabLink.displayName = `TabLink`;
51
+
52
+ const TabsClient: FC<{
53
+ children: ReactNode,
54
+ initialTab: number,
55
+ tabs: string[]
56
+ }> = ({
57
+ children,
58
+ tabs,
59
+ initialTab
60
+ }) => {
61
+ const router = useRouter();
62
+ const pathname = usePathname();
63
+ const searchParams = useSearchParams();
64
+ const [selectedTab, setSelectedTab] = useState(initialTab);
65
+
66
+ return <TabGroup className="text-content-primary" manual selectedIndex={selectedTab}
67
+ defaultIndex={initialTab} onChange={(index) => {
68
+ router.push(createNavUrl(index, tabs, pathname, searchParams));
69
+ setSelectedTab(index);
70
+ }}>
71
+ {children}
72
+ </TabGroup>
73
+ }
74
+
75
+ export default TabsClient
@@ -0,0 +1,3 @@
1
+ // Client-safe exports — can be imported from 'use client' components
2
+ export type { TabConfig } from './TabsClient'
3
+ export { default as TabsClient, createNavUrl, TabLink } from './TabsClient'
@@ -0,0 +1,2 @@
1
+ // Server-only exports — must NOT be imported from 'use client' components
2
+ export { default as Tabs, TabsContent } from './Tabs'
@@ -1,6 +1,6 @@
1
1
  import { useEffect, useState } from 'react'
2
2
  import { useTheme } from 'next-themes'
3
- import { Listbox } from '@headlessui/react'
3
+ import { Listbox, ListboxButton, ListboxLabel, ListboxOption, ListboxOptions } from '@headlessui/react'
4
4
  import clsx from 'clsx'
5
5
 
6
6
  const themes = [
@@ -61,8 +61,8 @@ export function ThemeSelector(
61
61
 
62
62
  return (
63
63
  <Listbox as="div" value={theme} onChange={setTheme} {...props}>
64
- <Listbox.Label className="sr-only">Theme</Listbox.Label>
65
- <Listbox.Button
64
+ <ListboxLabel className="sr-only">Theme</ListboxLabel>
65
+ <ListboxButton
66
66
  className="flex h-9 w-12 mt-3 items-center justify-center rounded-lg shadow-md shadow-black/5 ring-1 ring-black/5 dark:bg-slate-700 dark:ring-inset dark:ring-white/5"
67
67
  aria-label="Theme"
68
68
  >
@@ -78,20 +78,20 @@ export function ThemeSelector(
78
78
  theme === 'system' ? 'fill-slate-400' : 'fill-sky-400',
79
79
  )}
80
80
  />
81
- </Listbox.Button>
82
- <Listbox.Options className="absolute left-1/2 top-full mt-3 w-36 -translate-x-1/2 space-y-1 rounded-xl bg-white p-3 text-sm font-medium shadow-md shadow-black/5 ring-1 ring-black/5 dark:bg-slate-800 dark:ring-white/5">
81
+ </ListboxButton>
82
+ <ListboxOptions className="absolute left-1/2 top-full mt-3 w-36 -translate-x-1/2 space-y-1 rounded-xl bg-white p-3 text-sm font-medium shadow-md shadow-black/5 ring-1 ring-black/5 dark:bg-slate-800 dark:ring-white/5">
83
83
  {themes.map((theme) => (
84
- <Listbox.Option
84
+ <ListboxOption
85
85
  key={theme.value}
86
86
  value={theme.value}
87
- className={({ active, selected }) =>
87
+ className={({ focus, selected }) =>
88
88
  clsx(
89
89
  'flex cursor-pointer select-none items-center rounded-[0.625rem] p-1',
90
90
  {
91
91
  'text-sky-500': selected,
92
- 'text-slate-900 dark:text-white': active && !selected,
93
- 'text-slate-700 dark:text-slate-400': !active && !selected,
94
- 'bg-slate-100 dark:bg-slate-900/40': active,
92
+ 'text-slate-900 dark:text-white': focus && !selected,
93
+ 'text-slate-700 dark:text-slate-400': !focus && !selected,
94
+ 'bg-slate-100 dark:bg-slate-900/40': focus,
95
95
  },
96
96
  )
97
97
  }
@@ -111,9 +111,9 @@ export function ThemeSelector(
111
111
  <div className="ml-3">{theme.name}</div>
112
112
  </>
113
113
  )}
114
- </Listbox.Option>
114
+ </ListboxOption>
115
115
  ))}
116
- </Listbox.Options>
116
+ </ListboxOptions>
117
117
  </Listbox>
118
118
  )
119
119
  }
@@ -1,27 +0,0 @@
1
- import { useState, useEffect, useRef, MutableRefObject } from 'react'
2
-
3
- export default function useScrollLeft(): [
4
- scrollRef: MutableRefObject<$TSFixMe>,
5
- scrollLeft: number
6
- ] {
7
- const scrollRef = useRef(null)
8
- const [scrollLeft, setScrollLeft] = useState()
9
-
10
- useEffect(() => {
11
- const scrollElem = scrollRef.current as $TSFixMe;
12
- // Handler to call when scrollLeft may be affected
13
- function handleScroll() {
14
- if (!scrollRef.current) return null
15
- // Set scroll data to state
16
- setScrollLeft((scrollRef.current as $TSFixMe).scrollLeft)
17
- }
18
- // Add event listener
19
- scrollElem.addEventListener('scroll', handleScroll)
20
- // Call handler right away so state gets updated with initial scroll position
21
- handleScroll()
22
- // Remove event listener on cleanup
23
- return () => scrollElem.removeEventListener('scroll', handleScroll)
24
- }, [scrollRef])
25
-
26
- return [scrollRef, 0]
27
- }
@@ -1,33 +0,0 @@
1
- import { useState, useEffect } from 'react'
2
-
3
- // https://usehooks.com/useWindowSize/
4
- export default function useWindowSize() {
5
- // Initialize state with undefined width/height so server and client renders match
6
- // Learn more here: https://joshwcomeau.com/react/the-perils-of-rehydration/
7
- const [windowSize, setWindowSize] = useState({
8
- width: undefined,
9
- height: undefined,
10
- })
11
-
12
- useEffect(() => {
13
- // Handler to call on window resize
14
- function handleResize() {
15
- // Set window width/height to state
16
- setWindowSize({
17
- width: window.innerWidth,
18
- height: window.innerHeight,
19
- })
20
- }
21
-
22
- // Add event listener
23
- window.addEventListener('resize', handleResize)
24
-
25
- // Call handler right away so state gets updated with initial window size
26
- handleResize()
27
-
28
- // Remove event listener on cleanup
29
- return () => window.removeEventListener('resize', handleResize)
30
- }, []) // Empty array ensures that effect is only run on mount
31
-
32
- return windowSize
33
- }
@@ -1 +0,0 @@
1
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M9 18l6-6-6-6" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
@@ -1 +0,0 @@
1
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M9.09 9a3 3 0 015.83 1c0 2-3 3-3 3" stroke="var(--gray-4)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path clip-rule="evenodd" d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z" stroke="var(--gray-4)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M12 17.387a.379.379 0 100-.758.379.379 0 000 .758z" fill="var(--gray-4)" stroke="var(--gray-4)" stroke-width="1.5" stroke-linejoin="round"/></svg>
@@ -1,102 +0,0 @@
1
- import React, { useState, useEffect } from 'react'
2
- import { TabTriggerType } from './partials/tab-trigger'
3
- import TabTriggers from './partials/tab-triggers'
4
- import TabProvider, { useTabGroups } from './provider'
5
- import s from './style.module.css'
6
-
7
- interface TabChildProps {
8
- /** Renders the tab contents. */
9
- children: React.ReactElement
10
- /** Plain text used for the tab heading. */
11
- heading: string
12
- /** Accepts a string such that, when the tab is active, other Tab elements outside the instance with a matching `group` value will automatically be shown. Note that `TabProvider` is required in order for this feature to function.v */
13
- group?: string
14
- /** Plain text displayed in a tooltip beside the tab heading. */
15
- tooltip?: string
16
- }
17
-
18
- function Tab({ children }: TabChildProps): React.ReactElement {
19
- return <>{children}</>
20
- }
21
-
22
- interface TabsProps {
23
- /** Children to be displayed as tabs. Each child accepts the props `{ children: ReactElement, heading: string, tooltip?: string, group?: string }` */
24
- children: Array<React.ReactElement<TabChildProps>>
25
- /** If set to true, the tabs are centered in their container. Default is left-aligned. */
26
- centered?: boolean
27
- /** Optional className to add to the root element. */
28
- className?: string
29
- /** Set the default tab by its index. If not set, or if out of range, will default to the first tab, at index 0. */
30
- defaultTabIdx?: number
31
- /** If set to true, the bottom border underneath the tabs will fill the available width. Default border fills the constrained `.g-grid-container`. */
32
- fullWidthBorder?: boolean
33
- /** Optional callback which is executed when a new tab is selected. */
34
- onChange?: (targetTabIdx: number, targetTabGroup?: string) => void
35
- }
36
-
37
- function Tabs({
38
- children,
39
- className,
40
- defaultTabIdx = 0,
41
- centered = false,
42
- fullWidthBorder = false,
43
- onChange,
44
- }: TabsProps): React.ReactElement {
45
- // Ensures a single child object converts to an array
46
- children = Array.prototype.concat(children)
47
-
48
- const isDefaultOutOfBounds =
49
- defaultTabIdx >= children.length || defaultTabIdx < 0
50
-
51
- const [activeTabIdx, setActiveTabIdx] = useState(
52
- // if specified default is out of bounds (ie, it's determined at runtime),
53
- // fallback to 0 to avoid throwing an error
54
- isDefaultOutOfBounds ? 0 : defaultTabIdx
55
- )
56
- const groupCtx = useTabGroups()
57
-
58
- function setActiveTab(targetIdx : number, groupId?:string) {
59
- setActiveTabIdx(targetIdx)
60
- if (onChange) onChange(targetIdx, groupId)
61
- if (groupCtx) groupCtx.setActiveTabGroup(groupId)
62
- }
63
-
64
- useEffect(() => {
65
- const hasGroups = children.filter((tab) => tab.props.group).length > 0
66
- if (
67
- process.env.NODE_ENV !== 'production' &&
68
- hasGroups &&
69
- groupCtx === undefined
70
- ) {
71
- console.warn(
72
- '@dbosoft/react-tabs: The `TabProvider` cannot be accessed. Make sure it wraps the `Tabs` components so Tab Groups can work properly.'
73
- )
74
- }
75
- }, [children, groupCtx])
76
-
77
- if (!children) {
78
- process.env.NODE_ENV !== 'production' &&
79
- console.warn(
80
- '@dbosoft/react-tabs: There are no `Tab` children for the `Tabs` component to render.'
81
- )
82
- }
83
-
84
- return (
85
- <section className={className}>
86
- <TabTriggers
87
- tabs={children.map((tab, index) => {
88
- const { heading, group, tooltip } = tab.props
89
- return { index, heading, group, tooltip } as TabTriggerType
90
- })}
91
- centered={centered}
92
- fullWidthBorder={fullWidthBorder}
93
- activeTabIdx={activeTabIdx}
94
- setActiveTab={setActiveTab}
95
- />
96
- <div className={s.content}>{children[activeTabIdx].props.children}</div>
97
- </section>
98
- )
99
- }
100
-
101
- export default Tabs
102
- export { TabProvider, useTabGroups, Tab }
@@ -1,66 +0,0 @@
1
- import React, { useEffect } from 'react'
2
- import TooltipIcon from '../../icons/tooltip.svg'
3
- import Tooltip from '../tooltip'
4
- import { useTabGroups } from '../../provider.js'
5
- import s from './style.module.scss'
6
- import clsx from 'clsx'
7
-
8
- export interface TabTriggerType {
9
- index: number
10
- group: string
11
- heading: string
12
- tooltip?: string
13
- }
14
-
15
- interface TabTriggerProps {
16
- tab: TabTriggerType
17
- hasOverflow: boolean
18
- activeTabIdx: number
19
- setActiveTab: (tabIndex: number, tabGroup?: string) => void
20
- }
21
-
22
- function TabTrigger({
23
- tab,
24
- hasOverflow,
25
- activeTabIdx,
26
- setActiveTab,
27
- }: TabTriggerProps): React.ReactElement {
28
- const groupCtx = useTabGroups()
29
- const activeGroup = groupCtx?.activeTabGroup
30
- const isInActiveGroup = groupCtx && tab.group && tab.group === activeGroup
31
- const isActiveIndex = tab.index === activeTabIdx
32
- const isActiveTab = isInActiveGroup || isActiveIndex ? true : false
33
-
34
- useEffect(() => {
35
- // if the tab is active based on group and the
36
- // index doesn't match, update the active index
37
- if (isInActiveGroup) !isActiveIndex && setActiveTab(tab.index)
38
- }, [isInActiveGroup, isActiveIndex, setActiveTab, tab.index])
39
-
40
- return (
41
- <button
42
- className={clsx(s.root, {
43
- [s.isActiveTab]: isActiveTab,
44
- [s.hasOverflow]: hasOverflow,
45
- })}
46
- data-tabindex={tab.index}
47
- onMouseDown={(e) => e.preventDefault()}
48
- onClick={() => setActiveTab(tab.index, tab.group)}
49
- >
50
- <span className={s.inner}>
51
- <span className="g-type-body-strong">{tab.heading}</span>
52
- {tab.tooltip && (
53
- <Tooltip label={tab.tooltip} aria-label={tab.tooltip}>
54
- <span
55
- data-testid="tooltip-icon"
56
- className={s.tooltipTrigger}
57
- dangerouslySetInnerHTML={{ __html: TooltipIcon }}
58
- />
59
- </Tooltip>
60
- )}
61
- </span>
62
- </button>
63
- )
64
- }
65
-
66
- export default TabTrigger
@@ -1,69 +0,0 @@
1
- .root {
2
- --inner-text-color: var(--gray-3);
3
- --inner-border-color: transparent;
4
- --inner-decoration: none;
5
-
6
- display: flex;
7
- align-items: center;
8
- background: none;
9
- border: none;
10
- outline: none;
11
- padding: 0 16px;
12
-
13
- @media (--medium-up) {
14
- padding: 0 24px;
15
- }
16
-
17
- &:first-of-type {
18
- padding-left: 0;
19
- }
20
-
21
- &:last-of-type {
22
- padding-right: 0;
23
-
24
- /* With overflow, add
25
- a bit of space to ensure tooltips
26
- are still easily hover-able */
27
- &.hasOverflow {
28
- padding-right: 24px;
29
- }
30
- }
31
-
32
- &:hover {
33
- cursor: pointer;
34
-
35
- --inner-text-color: var(--black);
36
- }
37
-
38
- &:focus {
39
- --inner-text-color: var(--black);
40
- --inner-decoration: underline;
41
- }
42
-
43
- &.isActiveTab {
44
- --inner-border-color: var(--black);
45
- --inner-text-color: var(--black);
46
- }
47
- }
48
-
49
- .inner {
50
- display: flex;
51
- align-items: center;
52
- padding: 18px 0 15px 0;
53
- border-bottom: 3px solid;
54
- border-color: var(--inner-border-color);
55
- color: var(--inner-text-color);
56
- transition: color 0.2s;
57
- white-space: nowrap;
58
- text-decoration: var(--inner-decoration);
59
- }
60
-
61
- .tooltipTrigger {
62
- margin-left: 0.5rem;
63
- margin-top: 1px;
64
- width: 1.125rem;
65
-
66
- & svg {
67
- width: 100%;
68
- }
69
- }